Merge branch 'spike/api-hyperagent' into feature/wire-up-detail-panels

Conflicts:
	public/templates/work_packages.list.details.html
pull/1539/head
Till Breuer 10 years ago
commit 6ae4b6dcf4
  1. 2
      Gemfile
  2. 16
      Gemfile.lock
  3. 21
      app/assets/javascripts/angular/api/hal-api-resource.js
  4. 10
      app/assets/javascripts/angular/openproject-app.js
  5. 12
      app/assets/javascripts/angular/services/work-package-service.js
  6. 9
      app/assets/javascripts/angular/work_packages/controllers/work-package-details-controller.js
  7. 4
      app/assets/javascripts/angular/work_packages/controllers/work-packages-list-controller.js
  8. 3
      app/assets/javascripts/application.js.erb
  9. 6
      bower.json
  10. 1
      config/application.rb
  11. 1
      config/environments/development.rb
  12. 1
      config/environments/test.rb
  13. 1
      config/initializers/non_digest_assets.rb
  14. 2
      config/locales/de.yml
  15. 22
      features/timelines/timeline_modal_views.feature
  16. 2
      karma.conf.js
  17. 61
      karma/tests/api/hal-api-resource-test.js
  18. 2
      karma/tests/controllers/work-package-details-controller-test.js
  19. 2
      karma/tests/controllers/work-packages-list-controller-test.js
  20. 2
      karma/tests/directives/work_packages/work-package-group-sums-directive-test.js
  21. 2
      karma/tests/directives/work_packages/work-package-total-sums-directive-test.js
  22. 39
      karma/tests/services/work-package-service-test.js
  23. 1
      karma/tests/work_packages/work-package-context-menu-test.js
  24. 46
      lib/api/v3/activities/activity_model.rb
  25. 91
      lib/api/v3/activities/activity_representer.rb
  26. 4
      lib/api/v3/queries/queries_api.rb
  27. 4
      lib/api/v3/queries/query_model.rb
  28. 8
      lib/api/v3/work_packages/work_package_model.rb
  29. 17
      lib/api/v3/work_packages/work_package_representer.rb
  30. 4
      lib/api/v3/work_packages/work_packages_api.rb
  31. 18
      public/templates/tabs/overview.html
  32. 2
      public/templates/timelines/timeline_table.html
  33. 8
      public/templates/work_packages.list.details.html
  34. 2
      spec/api/work_package_resource_spec.rb
  35. 4
      spec/features/work_packages/select_query_spec.rb
  36. 2
      spec/features/work_packages/work_packages_page.rb
  37. 2
      test/unit/helpers/application_helper_test.rb

@ -106,7 +106,7 @@ group :production do
end
gem 'sprockets', '2.2.2.backport2'
gem 'sprockets-rails', '2.0.0.backport1'
gem 'sprockets-rails', git: 'https://github.com/finnlabs/sprockets-rails.git', branch: 'backport'
gem 'non-stupid-digest-assets'
gem 'sass-rails', git: 'https://github.com/guilleiguaran/sass-rails.git', branch: 'backport'
gem 'sass', '~> 3.3.6'

@ -28,6 +28,16 @@ GIT
specs:
rspec-example_disabler (0.0.1)
GIT
remote: https://github.com/finnlabs/sprockets-rails.git
revision: e069c097056e28e3cd4adc4ee8bb2a895c71bfc1
branch: backport
specs:
sprockets-rails (2.0.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (= 2.2.2.backport2)
GIT
remote: https://github.com/fnando/i18n-js.git
revision: 4e5c525ff6e1ec4d3449852746fa5651a0577d68
@ -381,10 +391,6 @@ GEM
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.0.backport1)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.2.2.backport2)
sqlite3 (1.3.7)
strong_parameters (0.2.1)
actionpack (~> 3.0)
@ -506,7 +512,7 @@ DEPENDENCIES
shoulda-matchers
simplecov (= 0.8.0.pre)
sprockets (= 2.2.2.backport2)
sprockets-rails (= 2.0.0.backport1)
sprockets-rails!
sqlite3
strong_parameters
svg-graph

@ -0,0 +1,21 @@
angular.module('openproject.api')
.factory('HALAPIResource', ['$q', 'PathHelper', function HALAPIResource($q, PathHelper) {
'use strict';
var HALAPIResource = {
configure: function() {
Hyperagent.configure('defer', $q.defer);
},
setup: function(uri) {
HALAPIResource.configure();
return new Hyperagent.Resource({
url: PathHelper.apiPrefixV3 + '/' + uri,
});
}
}
return HALAPIResource;
}]);

@ -104,6 +104,8 @@ angular.module('openproject.timeEntries.controllers', []);
angular.module('openproject.layout', []);
angular.module('openproject.api', []);
// main app
var openprojectApp = angular.module('openproject', [
'ui.select2',
@ -121,7 +123,8 @@ var openprojectApp = angular.module('openproject', [
'truncate',
'feature-flags',
'openproject.layout',
'cgBusy'
'cgBusy',
'openproject.api'
]);
window.appBasePath = jQuery('meta[name=app_base_path]').attr('content') || '';
@ -154,4 +157,7 @@ openprojectApp
ConfigurationService.addConfiguration('accessibilityMode', OpenProject.Helpers.accessibilityModeEnabled());
flags.set($http.get('/javascripts/feature-flags.json'));
}]);
}])
.value('cgBusyDefaults', {
templateUrl: '/assets/angular-busy/angular-busy.html'
});

@ -34,10 +34,20 @@ angular.module('openproject.services')
'$http',
'PathHelper',
'WorkPackagesHelper',
'HALAPIResource',
'DEFAULT_FILTER_PARAMS',
function($http, PathHelper, WorkPackagesHelper, DEFAULT_FILTER_PARAMS) {
function($http, PathHelper, WorkPackagesHelper, HALAPIResource, DEFAULT_FILTER_PARAMS) {
var workPackage;
var WorkPackageService = {
getWorkPackage: function(id) {
var resource = HALAPIResource.setup("work_packages/" + id);
return resource.fetch().then(function (wp) {
workPackage = wp;
return workPackage;
});
},
getWorkPackagesByQueryId: function(projectIdentifier, queryId) {
var url = projectIdentifier ? PathHelper.apiProjectWorkPackagesPath(projectIdentifier) : PathHelper.apiWorkPackagesPath();

@ -31,16 +31,15 @@ angular.module('openproject.workPackages.controllers')
.controller('WorkPackageDetailsController', [
'$scope',
'$stateParams',
function($scope, $stateParams) {
'WorkPackageService',
function($scope, $stateParams, WorkPackageService) {
$scope.workPackageId = $stateParams.workPackageId;
$scope.$watch('rows', function(rows) {
if (rows && rows.length > 0) {
var row = $scope.rows.find(function(row) {
return row.object.id == $scope.workPackageId;
WorkPackageService.getWorkPackage($scope.workPackageId).then(function(workPackage) {
$scope.workPackage = workPackage;
});
$scope.workPackage = row ? row.object : {};
}
});
}

@ -42,17 +42,17 @@ angular.module('openproject.workPackages.controllers')
'PaginationService',
'AuthorisationService',
'WorkPackageLoadingHelper',
'HALAPIResource',
'INITIALLY_SELECTED_COLUMNS',
'OPERATORS_AND_LABELS_BY_FILTER_TYPE',
function($scope, $rootScope, $q, $location, $stateParams,
I18n, WorkPackagesTableService,
WorkPackageService, ProjectService, QueryService, PaginationService,
AuthorisationService, WorkPackageLoadingHelper, INITIALLY_SELECTED_COLUMNS,
AuthorisationService, WorkPackageLoadingHelper, HALAPIResource, INITIALLY_SELECTED_COLUMNS,
OPERATORS_AND_LABELS_BY_FILTER_TYPE) {
// Setup
function initialSetup() {
$scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE;
$scope.disableFilters = false;

@ -53,6 +53,9 @@
//= require warn_leaving_unsaved
//= require openproject_plugins
//= require versions
//= require uri.js/src/URI
//= require uri.js/src/URITemplate
//= require hyperagent/dist/hyperagent
//= require_tree ./specific
//= require angular

@ -24,7 +24,8 @@
"momentjs": "~2.6.0",
"moment-timezone": "~0.0.6",
"angular-context-menu": "0.1.2",
"angular-busy": "~4.0.4"
"angular-busy": "~4.0.4",
"hyperagent": "manwithtwowatches/hyperagent#feature/jquery-compatibility"
},
"devDependencies": {
"mocha": "~1.14.0",
@ -34,6 +35,7 @@
"jquery-mockjax": "~1.5.3"
},
"resolutions": {
"select2": "3.3.2"
"select2": "3.3.2",
"jquery": "1.11.0"
}
}

@ -123,6 +123,7 @@ module OpenProject
jquery-ui/themes/base/jquery-ui.css
select2/select2.css
angular-busy/dist/angular-busy.css
angular-busy/angular-busy.html
)
# Enable escaping HTML in JSON.

@ -69,4 +69,5 @@ OpenProject::Application.configure do
# Send mails to browser window
config.action_mailer.delivery_method = :letter_opener
config.action_controller.default_url_options = { host: 'localhost', port: 3000 }
end

@ -69,4 +69,5 @@ OpenProject::Application.configure do
# we use per process memory for caching in the test environment
config.cache_store = :memory_store
config.action_controller.default_url_options = { host: 'localhost', port: 3000 }
end

@ -2,4 +2,5 @@ NonStupidDigestAssets.whitelist = [
'styleguide.html',
/jquery-ui\/.*/,
/select2\/.*/,
'angular-busy/angular-busy.html'
]

@ -93,7 +93,7 @@ de:
from: "Arbeitspaket"
to: "Zugehöriges Arbeitspaket"
status:
is_closed: "Ticket geschlossen"
is_closed: "Arbeitspaket geschlossen"
journal:
notes: "Kommentare"
member:

@ -35,8 +35,17 @@ Feature: Timeline View Tests
| Name | Is Milestone | In aggregation |
| Phase | false | true |
| Milestone | true | true |
# Hack to ensure that the project is persisted before opening the
# timeline. Otherwise we regularly have
# Couldn't find Project with identifier=ecookbook
# errors.
# As far as I could figure it out, the:
# I am already logged in as "manager"
# will raise the bug when the project is not already persisted and he
# tries to reopen the page he had visited last in the test before.
When I go to the home page
And there are the following project types:
Given there are the following project types:
| Name |
| Standard Project |
| Extraordinary Project |
@ -53,6 +62,8 @@ Feature: Timeline View Tests
And there is a project named "ecookbook" of type "Standard Project"
And I am working in project "ecookbook"
And there is a timeline "Testline" for project "ecookbook"
And the following types are enabled for projects of type "Standard Project"
| Phase |
| Milestone |
@ -62,8 +73,6 @@ Feature: Timeline View Tests
And the user "manager" is a "manager"
And I am already logged in as "manager"
And there are the following work packages:
| Start date | Due date | description | responsible | Subject |
| 2012-01-01 | 2012-01-31 | #2 http://google.de | manager | January |
@ -72,10 +81,11 @@ Feature: Timeline View Tests
| 2012-04-01 | 2012-04-30 | Avocado Choquette | manager | April |
| 2012-04-01 | 2012-04-30 | Relish | manager | Test2 |
And I am already logged in as "manager"
@javascript
Scenario: planning element click should show modal window
When there is a timeline "Testline" for project "ecookbook"
And I go to the page of the timeline "Testline" of the project called "ecookbook"
When I go to the page of the timeline "Testline" of the project called "ecookbook"
And I wait for timeline to load table
And I click on the Planning Element with name "January"
Then I should see a modal window
@ -96,7 +106,6 @@ Feature: Timeline View Tests
| edit_timelines |
| view_work_packages |
| edit_work_packages |
And there is a timeline "Testline" for project "ecookbook"
And I go to the page of the timeline "Testline" of the project called "ecookbook"
And I wait for timeline to load table
And I click on the Planning Element with name "January"
@ -114,7 +123,6 @@ Feature: Timeline View Tests
| view_work_packages |
| edit_work_packages |
| manage_work_package_relations |
And there is a timeline "Testline" for project "ecookbook"
And I go to the page of the timeline "Testline" of the project called "ecookbook"
And I wait for timeline to load table
And I click on the Planning Element with name "January"

@ -31,6 +31,7 @@ module.exports = function(config) {
"vendor/assets/components/momentjs/moment.js",
"vendor/assets/components/angular-context-menu/dist/angular-context-menu.js",
'vendor/assets/components/select2/select2.js',
'vendor/assets/components/hyperagent/dist/hyperagent.js',
"vendor/assets/components/openproject-ui_components/app/assets/javascripts/angular/ui-components-app.js",
@ -43,6 +44,7 @@ module.exports = function(config) {
'app/assets/javascripts/angular/filters/**/*.js',
"app/assets/javascripts/angular/models/**/*.js",
"app/assets/javascripts/angular/directives/**/*.js",
'app/assets/javascripts/angular/api/**/*.js',
'app/assets/javascripts/angular/services/**/*.js',
"app/assets/javascripts/angular/layout/**/*.js",

@ -0,0 +1,61 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
/*jshint expr: true*/
describe('HALAPIResource', function() {
var HALAPIResource;
beforeEach(module('openproject.api', 'openproject.helpers'));
beforeEach(inject(function(_HALAPIResource_){
HALAPIResource = _HALAPIResource_;
}));
describe('setup', function() {
var workPackageUri = 'work_packages/1';
beforeEach(inject(function($q) {
apiResource = {
fetch: $q.when(function() { return { id: workPackageId }; })
}
}))
beforeEach(inject(function(HALAPIResource) {
resourceFunction = sinon.stub(Hyperagent, 'Resource').returns(apiResource);
}));
beforeEach(inject(function() {
HALAPIResource.setup(workPackageUri);
}))
it('makes an api setup call', function() {
expect(resourceFunction).to.have.been.calledWith({ url: "/api/v3/" + workPackageUri });
})
});
});

@ -32,7 +32,7 @@ describe('WorkPackageDetailsController', function() {
var scope;
var buildController;
beforeEach(module('openproject.workPackages.controllers'));
beforeEach(module('openproject.api', 'openproject.services', 'openproject.workPackages.controllers'));
beforeEach(inject(function($rootScope, $controller, $timeout) {
scope = $rootScope.$new();

@ -33,7 +33,7 @@ describe('WorkPackagesListController', function() {
testProjectService, testWorkPackageService, testQueryService, testPaginationService;
var buildController;
beforeEach(module('openproject.workPackages.controllers', 'openproject.workPackages.services', 'ng-context-menu', 'btford.modal'));
beforeEach(module('openproject.api', 'openproject.workPackages.controllers', 'openproject.workPackages.services', 'ng-context-menu', 'btford.modal'));
beforeEach(inject(function($rootScope, $controller, $timeout) {
scope = $rootScope.$new();
win = {

@ -30,7 +30,7 @@ describe('workPackageGroupSums Directive', function() {
var compile, element, rootScope, scope;
beforeEach(angular.mock.module('openproject.workPackages.directives'));
beforeEach(module('templates'));
beforeEach(module('openproject.api', 'templates'));
beforeEach(inject(function($rootScope, $compile) {
var html;

@ -30,7 +30,7 @@ describe('workPackageTotalSums Directive', function() {
var compile, element, rootScope, scope;
beforeEach(angular.mock.module('openproject.workPackages.directives'));
beforeEach(module('templates'));
beforeEach(module('openproject.api', 'templates'));
beforeEach(inject(function($rootScope, $compile) {
var html;

@ -31,9 +31,9 @@
describe('WorkPackageService', function() {
var WorkPackageService;
beforeEach(module('openproject.services', 'openproject.models'));
beforeEach(module('openproject.api', 'openproject.services', 'openproject.models'));
beforeEach(inject(function(_WorkPackageService_){
beforeEach(inject(function(_WorkPackageService_, _HALAPIResource_){
WorkPackageService = _WorkPackageService_;
}));
@ -61,4 +61,39 @@ describe('WorkPackageService', function() {
expect(deleteFunction).to.have.been.calledWith('/work_packages/bulk', { params: { 'ids[]': [1, 2] } });
});
});
describe('getWorkPackage', function() {
var setupFunction;
var workPackageId = 5;
var apiResource;
var apiFetchResource;
beforeEach(inject(function($q) {
apiResource = {
fetch: function() {
deferred = $q.defer();
deferred.resolve({ id: workPackageId } );
return deferred.promise;
}
}
}));
beforeEach(inject(function(HALAPIResource) {
setupFunction = sinon.stub(HALAPIResource, 'setup').returns(apiResource);
}));
beforeEach(inject(function() {
apiFetchResource = WorkPackageService.getWorkPackage(workPackageId);
}));
it('makes an api setup call', function() {
expect(setupFunction).to.have.been.calledWith("work_packages/" + workPackageId);
});
it('returns work package', function() {
apiFetchResource.then(function(wp){
expect(wp.id).to.equal(workPackageId);
});
});
});
});

@ -33,6 +33,7 @@ describe('workPackageContextMenu', function() {
var container, contextMenu, $rootScope;
beforeEach(module('ng-context-menu',
'openproject.api',
'openproject.workPackages',
'openproject.models',
'templates'));

@ -0,0 +1,46 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'reform'
require 'reform/form/coercion'
module API
module V3
module Activities
class ActivityModel < Reform::Form
include Composition
include Coercion
model :journal
property :user_id, on: :journal, type: Integer
end
end
end
end

@ -0,0 +1,91 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'roar/decorator'
require 'roar/representer/json/hal'
module API
module V3
module Activities
class ActivityRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
include Roar::Representer::Feature::Hypermedia
include Rails.application.routes.url_helpers
self.as_strategy = API::Utilities::CamelCasingStrategy.new
property :_type, exec_context: :decorator
link :self do
{ href: "#{root_url}/api/v3/activities/#{represented.journal.id}", title: "#{represented.journal.id}" }
end
link :work_package do
{ href: "#{root_url}/api/v3/work_packages/#{represented.journal.journable.id}", title: "#{represented.journal.journable.subject}" }
end
link :user do
{ href: "#{root_url}/api/v3/users/#{represented.journal.user.id}", title: "#{represented.journal.user.name} - #{represented.journal.user.login}" }
end
property :id, getter: -> (*) { journal.id }, render_nil: true
property :user_id, render_nil: true
property :user_name, getter: -> (*) { journal.user.try(:name) }, render_nil: true
property :user_login, getter: -> (*) { journal.user.try(:login) }, render_nil: true
property :user_mail, getter: -> (*) { journal.user.try(:mail) }, render_nil: true
property :messages, exec_context: :decorator, render_nil: true
property :version, getter: -> (*) { journal.version }, render_nil: true
property :created_at, getter: -> (*) { journal.created_at.utc.iso8601 }, render_nil: true
def _type
if represented.journal.notes.blank?
'Activity'
else
'Activity::Comment'
end
end
def messages
journal = represented.journal
if journal.notes.blank?
journal.details.map{ |d| journal.render_detail(d, no_html: true) }
else
[journal.notes]
end
end
private
def default_url_options
ActionController::Base.default_url_options
end
end
end
end
end

@ -12,8 +12,8 @@ module API
before do
@query = Query.find(params[:id])
model = QueryModel.new(query: @query)
@representer = QueryRepresenter.new(model)
model = ::API::V3::Queries::QueryModel.new(query: @query)
@representer = ::API::V3::Queries::QueryRepresenter.new(model)
end
helpers do

@ -48,6 +48,10 @@ module API
property :sort_criteria, on: :query, type: String
property :group_by, on: :query, type: String
property :display_sums, on: :query, type: String
def query
model[:query]
end
end
end
end

@ -51,6 +51,10 @@ module API
property :assigned_to_id, on: :work_package, type: Integer
property :fixed_version_id, on: :work_package, type: Integer
def work_package
model[:work_package]
end
def type
work_package.type.try(:name)
end
@ -99,6 +103,10 @@ module API
work_package.done_ratio = value
end
def activities
work_package.journals.map{ |journal| Activities::ActivityModel.new(journal: journal) }
end
validates_presence_of :subject, :project_id, :type, :author, :status
validates_length_of :subject, maximum: 255
end

@ -40,10 +40,15 @@ module API
self.as_strategy = API::Utilities::CamelCasingStrategy.new
def initialize(options = {}, *expand)
@expand = expand
super(options)
end
property :_type, exec_context: :decorator
link :self do
{ href: "http://localhost:3000/api/v3/work_packages/#{represented.work_package.id}", title: "#{represented.subject}" }
{ href: "#{root_url}/api/v3/work_packages/#{represented.work_package.id}", title: "#{represented.subject}" }
end
property :id, getter: -> (*) { work_package.id }, render_nil: true
@ -74,9 +79,17 @@ module API
property :created_at, getter: -> (*) { work_package.created_at.utc.iso8601}, render_nil: true
property :updated_at, getter: -> (*) { work_package.updated_at.utc.iso8601}, render_nil: true
collection :activities, embedded: true, class: Activities::ActivityModel, decorator: Activities::ActivityRepresenter
def _type
"WorkPackage"
'WorkPackage'
end
private
def default_url_options
ActionController::Base.default_url_options
end
end
end
end

@ -12,8 +12,8 @@ module API
before do
@work_package = WorkPackage.find(params[:id])
model = WorkPackageModel.new(work_package: @work_package)
@representer = WorkPackageRepresenter.new(model)
model = ::API::V3::WorkPackages::WorkPackageModel.new(work_package: @work_package)
@representer = ::API::V3::WorkPackages::WorkPackageRepresenter.new(model, :activities, :users)
end
get do

@ -2,7 +2,7 @@
<h3>Description</h3>
<div class="detail-panel-description-content">
{{ workPackage.description }}
{{ workPackage.props.description }}
</div>
</div>
@ -23,16 +23,16 @@
<div class="detail-panel-attributes" slide-toggle collapsed="hideFullDescription">
<ul>
<li><label>Status</label>{{ workPackage.status.name }}</li>
<li><label>Priortiy</label>{{ workPackage.priority.name }}</li>
<li><label>Date</label>{{ workPackage.start }} - {{ workPackage.end }}</li>
<li><label>Responsible</label><img class="avatar" src="images/avatar_logout.png" /><span class="user"><a href="#">{{ workPackage.responsible.name }}</a></span>
<span class="role">{{ workPackage.responsible.role }}</span>
<li><label>Status</label>{{ workPackage.props.status }}</li>
<li><label>Priortiy</label>{{ workPackage.props.priority }}</li>
<li><label>Date</label>{{ workPackage.props.startDate }} - {{ workPackage.props.dueDate }}</li>
<li><label>Responsible</label><img class="avatar" src="images/avatar_logout.png" /><span class="user"><a href="#">{{ workPackage.props.responsibleName }}</a></span>
<span class="role">{{ workPackage.props.responsibleRole }}</span>
</li>
<li><label>Assignee</label><img class="avatar" src="images/avatar_logout.png" /><span class="user"><a href="#">{{ workPackage.assignedTo.name }}</a></span>
<span class="role">{{ workPackage.assignedTo.role }}</span>
<li><label>Assignee</label><img class="avatar" src="images/avatar_logout.png" /><span class="user"><a href="#">{{ workPackage.props.assigneeName }}</a></span>
<span class="role">{{ workPackage.props.assigneeRole }}</span>
</li>
<li><label>% Done</label>{{ workPackage.doneRatio }} %</li>
<li><label>% Done</label>{{ workPackage.props.percentageDone }} %</li>
</ul>
</div>

@ -50,7 +50,7 @@
</span>
<span>
<a href="{{row.url}}" modal title="{{row.text}}" target="row.url" ng-class="{'tl-discreet-link': true, 'tl-project': rowObjectType === 'Project'}">{{row.text}}</a>
<a href="{{row.url}}" modal title="{{row.text}}" target="row.url" ng-class="{'tl-discreet-link': true, 'tl-project': rowObjectType === 'Project'}">{{ row.text | characters:40 }}</a>
</span>
<div ng-show="row.lastVisible" class="tl-invisible" style="height: 15px; width: 15px;"></div>

@ -19,10 +19,10 @@
</div>
<div class="detail-panel-content">
<div class="select-type">{{ workPackage.type.name }}:&nbsp;</div>
<div class="select-type">{{ workPackage.props.type }}:&nbsp;</div>
<h2>{{ workPackage.subject }}</h2>
<span class="subtitle"><i class="star icon-star1"></i><a href="#">#{{ workPackage.id }}</a>&nbsp;added by <a href="#">{{ workPackage.author.name }}</a>. Last updated on {{ workPackage.lastUpdated }}</span>
<h2>{{ workPackage.props.subject }}</h2>
<span class="subtitle"><i class="star icon-star1"></i><a href="#">#{{ workPackage.props.id }}</a>&nbsp;added by <a href="#">{{ workPackage.props.author.name }}</a>. Last updated on {{ workPackage.props.lastUpdated }}</span>
<div class="work-package-details-tab" ui-view></div>
@ -31,4 +31,4 @@
<div class="bottom-toolbar">
<button class="button"><i class="icon-left icon-edit"></i>Edit</button>
<button class="button">More<i class="icon-right icon-pulldown-arrow1"></i></button>
</div>
<div>

@ -68,7 +68,7 @@ describe 'API v3 Work package resource' do
it 'should respond with work package in HAL+JSON format' do
parsed_response = JSON.parse(last_response.body)
parsed_response.should eq(expected_response)
parsed_response['id'].should eq(work_package.id)
end
context 'requesting nonexistent work package' do

@ -36,6 +36,7 @@ describe 'Query selection' do
member_through_role: role }
let(:filter_name) { 'done_ratio' }
let(:i18n_filter_name) { WorkPackage.human_attribute_name(filter_name).to_sym }
let!(:query) do
query = FactoryGirl.build(:query, project: project, is_public: true)
query.filters = [Queries::WorkPackages::Filter.new(filter_name, operator: ">=", values: [10]) ]
@ -55,8 +56,7 @@ describe 'Query selection' do
end
it 'should show the filter', js: true do
expect(work_packages_page.selected_filter(filter_name)).not_to be_nil
expect(work_packages_page.selected_filter(filter_name)).to have_content(i18n_filter_name)
end
end
end

@ -63,7 +63,7 @@ class WorkPackagesPage
end
def selected_filter(filter_name)
find(".filter-fields #h_#{filter_name}", visible: false)
find(".filter-fields #tr_#{filter_name}")
end
private

@ -522,7 +522,7 @@ RAW
link_to_project(@project, :action => 'settings')
assert_equal %(<a href="/projects/#{p_id}/settings/members">#{p_name}</a>),
link_to_project(@project, :action => 'settings', :tab => 'members')
assert_equal %(<a href="http://test.host/projects/#{p_id}?jump=blah">#{p_name}</a>),
assert_equal %(<a href="#{root_url}projects/#{p_id}?jump=blah">#{p_name}</a>),
link_to_project(@project, {:only_path => false, :jump => 'blah'})
assert_equal %(<a href="/projects/#{p_id}/settings" class="project">#{p_name}</a>),
link_to_project(@project, {:action => 'settings'}, :class => "project")

Loading…
Cancel
Save