From 8ca35754b6407af475874503d483f7660d283cc2 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 14 Mar 2014 10:17:27 +0100 Subject: [PATCH 001/155] WIP. started moving things around... --- .../angular/config/work-packages-config.js | 38 +++++++++++++++++++ .../controllers/work-packages-controller.js | 8 ++-- .../javascripts/angular/openproject-app.js | 5 ++- app/controllers/work_packages_controller.rb | 4 +- 4 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/angular/config/work-packages-config.js diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js new file mode 100644 index 0000000000..b1ad8632cd --- /dev/null +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -0,0 +1,38 @@ +angular.module('openproject.workPackages.config') + +.constant('AVAILABLE_COLUMNS', [ + { + custom_field: false, + groupable: 'project', + meta_data: { data_type: 'object', link: { display: true, model_type: 'project' } }, + name: 'project', + sortable: 'projects.name', + title: 'Project' + }, + { + custom_field: false, + groupable: 'type', + meta_data: { data_type: 'object', link: { display: true } }, + name: 'type', + sortable: 'types.postition', + title: 'Type' + } +]) + +.constant('INITIALLY_SELECT_COLUMNS', [ + { + custom_field: false, + groupable: 'type', + meta_data: { data_type: 'object', link: { display: true } }, + name: 'type', + sortable: 'types.postition', + title: 'Type' + } +]) + +.constant('AVAILABLE_WORK_PACKAGE_FILTERS', { + assigned_to_id: { name: 'Assignee', type: 'list_optional' }, // Note: we might want to put default "me" value here + created_at: { name: 'Created on', type: 'date_past' }, + subject: { name: 'Subject', type: 'text' }, + estimated_hours: { name: 'Estimated time', type: 'integer' } +}) \ No newline at end of file diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index f1f8b931cf..a39027ec75 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,6 +1,6 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService) { +.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'AVAILABLE_COLUMNS', 'INITIALLY_SELECT_COLUMNS', function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, AVAILABLE_COLUMNS, INITIALLY_SELECT_COLUMNS) { function initialSetup() { $scope.projectIdentifier = gon.project_identifier; @@ -16,8 +16,8 @@ angular.module('openproject.workPackages.controllers') $scope.query.setSortation(sortation); // Columns - $scope.columns = gon.columns; - $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(gon.available_columns, $scope.columns); + $scope.columns = INITIALLY_SELECT_COLUMNS; + $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(AVAILABLE_COLUMNS, $scope.columns); $scope.currentSortation = gon.sort_criteria; @@ -52,7 +52,7 @@ angular.module('openproject.workPackages.controllers') // Initially setup scope via gon initialSetup(); - setupQuery(gon); + setupQuery(); // Initialize work package table $scope.setupWorkPackagesTable(gon); diff --git a/app/assets/javascripts/angular/openproject-app.js b/app/assets/javascripts/angular/openproject-app.js index a6e24ebde5..338e46bf72 100644 --- a/app/assets/javascripts/angular/openproject-app.js +++ b/app/assets/javascripts/angular/openproject-app.js @@ -15,8 +15,9 @@ angular.module('openproject.timelines.directives', ['openproject.timelines.model angular.module('openproject.workPackages', ['openproject.workPackages.controllers', 'openproject.workPackages.filters', 'openproject.workPackages.directives', 'openproject.uiComponents']); angular.module('openproject.workPackages.helpers', ['openproject.helpers']); angular.module('openproject.workPackages.filters', ['openproject.workPackages.helpers']); -angular.module('openproject.workPackages.controllers', ['openproject.models', 'openproject.workPackages.helpers', 'openproject.services']); -angular.module('openproject.workPackages.directives', ['openproject.helpers', 'openproject.workPackages.helpers', 'openproject.services']); +angular.module('openproject.workPackages.config', []); +angular.module('openproject.workPackages.controllers', ['openproject.models', 'openproject.workPackages.helpers', 'openproject.services', 'openproject.workPackages.config']); +angular.module('openproject.workPackages.directives', ['openproject.uiComponents', 'openproject.services']); // main app var openprojectApp = angular.module('openproject', ['ui.select2', 'ui.date', 'openproject.uiComponents', 'openproject.timelines', 'openproject.workPackages', 'ngAnimate']); diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index b884bbfeca..05d4428f42 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -572,8 +572,8 @@ class WorkPackagesController < ApplicationController get_results_as_json(results, work_packages).merge( project_identifier: @project.to_param, query: get_query_as_json(@query), - columns: get_columns_for_json(@query.columns), - available_columns: get_columns_for_json(@query.available_columns), + # columns: get_columns_for_json(@query.columns), + # available_columns: get_columns_for_json(@query.available_columns), sort_criteria: @sort_criteria.to_param ) end From 580587be5352051d1b6a0303874a1b44a88ba754 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 14 Mar 2014 14:49:17 +0100 Subject: [PATCH 002/155] WIP continuing to move config data into angular. --- .../angular/config/work-packages-config.js | 41 +++++++++++++-- .../controllers/work-packages-controller.js | 50 +++++++++++-------- .../api/v2/planning_elements_controller.rb | 42 ++++++++++++++++ app/controllers/work_packages_controller.rb | 13 ++--- 4 files changed, 112 insertions(+), 34 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index b1ad8632cd..2ed1936676 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -30,9 +30,42 @@ angular.module('openproject.workPackages.config') } ]) +.constant('OPERATORS_AND_LABELS_BY_FILTER_TYPE', { + list: {"=":"is","!":"is not"}, + list_status: {"o":"open","=":"is","!":"is not","c":"closed","*":"all"}, + list_optional: {"=":"is","!":"is not","!*":"none","*":"all"}, + list_subprojects: {"*":"all","!*":"none","=":"is"}, + date: {"t+":"in more than","t+":"in","t":"today","w":"this week",">t-":"less than days ago","t-":"less than days ago","=":">=","<=":"<=","!*":"none","*":"all"} +}) + .constant('AVAILABLE_WORK_PACKAGE_FILTERS', { - assigned_to_id: { name: 'Assignee', type: 'list_optional' }, // Note: we might want to put default "me" value here - created_at: { name: 'Created on', type: 'date_past' }, - subject: { name: 'Subject', type: 'text' }, - estimated_hours: { name: 'Estimated time', type: 'integer' } + status_id: { type: "list_model", model_name: "status" ,order:1, name: "Status" }, + type_id: { type:"list_model", model_name: "type", "order":2, name: "Type" }, + // priority_id: {"type":"list","order":3,"values":[["Immediate","29"],["High","30"],["Low","31"],["Normal","32"]],"name":"Priority"}, + subject: {"type":"text","order":8,"name":"Subject"}, + created_at: {"type":"date_past","order":9,"name":"Created on"}, + updated_at: {"type":"date_past","order":10,"name":"Updated on"}, + start_date: {"type":"date","order":11,"name":"Start date"}, + due_date: {"type":"date","order":12,"name":"Due date"}, + estimated_hours: {"type":"integer","order":13,"name":"Estimated time"}, + done_ratio: {"type":"integer","order":14,"name":"% done"}, + // assigned_to_id: {"type":"list_optional","order":4,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Assignee"}, + // author_id: {"type":"list","order":5,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Author"}, + // member_of_group: {"type":"list_optional","order":6,"values":[["Gruppe 00001","138"],["Gruppe 00002","139"],["Gruppe 00003","140"],["Gruppe 00004","141"],["Gruppe 00005","142"]],"name":"Assignee's group"}, + // assigned_to_role: {"type":"list_optional","order":7,"values":[["Project Admin","3"],["Release Manager","19"],["Project Member","4"],["Stakeholder","5"],["Controller Client","6"],["Controller","8"],["Developer","9"],["Tester","10"],["Reader","11"],["Timeline Reader","20"]],"name":"Assignee's role"}, + // responsible_id: {"type":"list_optional","order":4,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Responsible"},"watcher_id":{"type":"list","order":15,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Watcher"}, + // fixed_version_id: {"type":"list_optional","order":7,"values":[["HD Bridge - Version 00001.0","19"],["HD Bridge - Version 00002.0","20"]],"name":"Target version"},"cf_4":{"type":"list_optional","values":["Client 1","Client 2"],"order":20,"name":"Client"} +}) + +.constant('DEFAULT_SORT_CRITERIA', "parent:desc") + +.constant('DEFAULT_QUERY', { + display_sums: false, + filters: [{ status_id: {"operator":"o","values":[""], name: "status_id" }}], + group_by: null, + id: null }) \ No newline at end of file diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index a39027ec75..1bb4ec55cf 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,37 +1,33 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'AVAILABLE_COLUMNS', 'INITIALLY_SELECT_COLUMNS', function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, AVAILABLE_COLUMNS, INITIALLY_SELECT_COLUMNS) { +.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'AVAILABLE_COLUMNS', 'INITIALLY_SELECT_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', + function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, AVAILABLE_COLUMNS, INITIALLY_SELECT_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY) { function initialSetup() { $scope.projectIdentifier = gon.project_identifier; - $scope.operatorsAndLabelsByFilterType = gon.operators_and_labels_by_filter_type; + $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; $scope.loading = false; $scope.disableFilters = false; } function setupQuery() { - $scope.query = new Query(gon.query); + // TODO: put the available filters onto the query? + $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); - sortation = new Sortation(gon.sort_criteria); + sortation = new Sortation(DEFAULT_SORT_CRITERIA); $scope.query.setSortation(sortation); + $scope.currentSortation = DEFAULT_SORT_CRITERIA; + // $scope.available_work_package_filters = AVAILABLE_WORK_PACKAGE_FILTERS; // Columns $scope.columns = INITIALLY_SELECT_COLUMNS; $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(AVAILABLE_COLUMNS, $scope.columns); - $scope.currentSortation = gon.sort_criteria; - angular.extend($scope.query, { selectedColumns: $scope.columns }); }; - $scope.submitQueryForm = function(){ - jQuery("#selected_columns option").attr('selected',true); - jQuery('#query_form').submit(); - return false; - }; - function setupPagination(json) { $scope.paginationOptions = { page: json.page, @@ -40,6 +36,12 @@ angular.module('openproject.workPackages.controllers') $scope.perPageOptions = json.per_page_options; } + $scope.submitQueryForm = function(){ + jQuery("#selected_columns option").attr('selected',true); + jQuery('#query_form').submit(); + return false; + }; + $scope.setupWorkPackagesTable = function(json) { $scope.workPackageCountByGroup = json.work_package_count_by_group; $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); @@ -50,22 +52,15 @@ angular.module('openproject.workPackages.controllers') setupPagination(json); }; - // Initially setup scope via gon - initialSetup(); - setupQuery(); - // Initialize work package table - $scope.setupWorkPackagesTable(gon); - $scope.updateResults = function() { $scope.withLoading(WorkPackageService.getWorkPackages, [$scope.projectIdentifier, $scope.query, $scope.paginationOptions]) .then($scope.setupWorkPackagesTable); }; - function serviceErrorHandler(data) { // TODO RS: This is where we'd want to put an error message on the dom $scope.loading = false; - } + }; /** * @name withLoading @@ -86,9 +81,20 @@ angular.module('openproject.workPackages.controllers') function startedLoading() { $scope.loading = true; - } + }; function finishedLoading() { $scope.loading = false; - } + }; + + function initialLoad(){ + $scope.updateResults(); + }; + + initialSetup(); + setupQuery(); + // initialLoad(); + + // Initialize work package table + // $scope.setupWorkPackagesTable(gon); }]); diff --git a/app/controllers/api/v2/planning_elements_controller.rb b/app/controllers/api/v2/planning_elements_controller.rb index 3a7c359e89..65d7ffbf3b 100644 --- a/app/controllers/api/v2/planning_elements_controller.rb +++ b/app/controllers/api/v2/planning_elements_controller.rb @@ -258,6 +258,48 @@ module Api work_packages end + def current_work_packages_alt(projects) + # work_packages = WorkPackage.for_projects(projects) + # .changed_since(@since) + # .includes(:status, :project, :type, :custom_values) + project = timeline_to_project(params[:timeline]) + query = Query.new(:project => project) + + if params[:f] + #we need a project to make project-specific custom fields work + # project = timeline_to_project(params[:timeline]) + # query = Query.new(:project => project) + + query.add_filters(params[:f], params[:op], params[:v]) + + #if we do not remove the project, the filter will only add wps from this project + query.project = nil + + # work_packages = work_packages.with_query query + end + + results = query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version]) + work_packages = results.work_packages.all + + work_packages + end + + # TODO: This needs to assign the meta data: + # project_identifier + # query + # work_package_count_by_group + # sort_criteria + # sums + # group_sums + # page + # per_page + # per_page_options + # total_entries + # Most of which can be lifted from work_packages_controller hopefully as long as the query is set up in the same way + def current_work_packages_meta(query, results, work_packages) + @planning_elements_meta = {} + end + def historical_work_packages(projects) at_time = Time.at(params[:at_time].to_i).to_datetime filter = params[:f] ? {f: params[:f], op: params[:op], v: params[:v]}: {} diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 05d4428f42..f51dea9841 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -227,7 +227,7 @@ class WorkPackagesController < ApplicationController format.html do # push work packages to client as JSON # TODO pull work packages via AJAX - push_filter_operators_and_labels + # push_filter_operators_and_labels push_query_and_results_via_gon results, work_packages render :index, :locals => { :query => @query, @@ -546,9 +546,7 @@ class WorkPackagesController < ApplicationController end def push_query_and_results_via_gon(results, work_packages) - get_query_and_results_as_json(results, work_packages).each_pair do |name, value| - gon.send "#{name}=", value - end + gon.project_identifier = @project.to_param # TODO later versions of gon support gon.push {Hash} - on the other hand they make it harder to deliver data to gon inside views end @@ -571,10 +569,10 @@ class WorkPackagesController < ApplicationController def get_query_and_results_as_json(results, work_packages) get_results_as_json(results, work_packages).merge( project_identifier: @project.to_param, - query: get_query_as_json(@query), + # query: get_query_as_json(@query), # columns: get_columns_for_json(@query.columns), # available_columns: get_columns_for_json(@query.available_columns), - sort_criteria: @sort_criteria.to_param + # sort_criteria: @sort_criteria.to_param ) end @@ -592,8 +590,7 @@ class WorkPackagesController < ApplicationController end def get_query_as_json(query) - query.as_json only: [:id, :group_by, :display_sums, :filters], - methods: [:available_work_package_filters] + query.as_json only: [:id, :group_by, :display_sums, :filters] end def get_columns_for_json(columns) From fd22923f2017d53f325894081e526e1a7bdd9b7e Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 14 Mar 2014 15:36:34 +0100 Subject: [PATCH 003/155] WIP Removed everything from gon except for project id which has to be somewhere at load time. shitloads of errors but with an initial request it does load the work package data. --- .../javascripts/angular/config/work-packages-config.js | 6 ++++++ .../angular/controllers/work-packages-controller.js | 7 ++++--- .../directives/work_packages/query-filters-directive.js | 1 + app/assets/javascripts/angular/models/query.js | 9 ++++++++- app/controllers/work_packages_controller.rb | 4 ---- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 2ed1936676..531d670fc5 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -68,4 +68,10 @@ angular.module('openproject.workPackages.config') filters: [{ status_id: {"operator":"o","values":[""], name: "status_id" }}], group_by: null, id: null +}) + +.constant('PAGINATION_OPTIONS', { + page: 1, + per_page: 10, + per_page_options: [10, 20, 50, 100, 500, 1000] }) \ No newline at end of file diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 1bb4ec55cf..fc2beec516 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,7 +1,7 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'AVAILABLE_COLUMNS', 'INITIALLY_SELECT_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', - function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, AVAILABLE_COLUMNS, INITIALLY_SELECT_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY) { +.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'AVAILABLE_COLUMNS', 'INITIALLY_SELECT_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'PAGINATION_OPTIONS', + function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, AVAILABLE_COLUMNS, INITIALLY_SELECT_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, PAGINATION_OPTIONS) { function initialSetup() { $scope.projectIdentifier = gon.project_identifier; @@ -88,12 +88,13 @@ angular.module('openproject.workPackages.controllers') }; function initialLoad(){ + setupPagination(PAGINATION_OPTIONS); $scope.updateResults(); }; initialSetup(); setupQuery(); - // initialLoad(); + initialLoad(); // Initialize work package table // $scope.setupWorkPackagesTable(gon); diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filters-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filters-directive.js index b98c2422eb..19e34d2977 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filters-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filters-directive.js @@ -18,6 +18,7 @@ angular.module('openproject.workPackages.directives') } }); + // TODO RS: Moved this into the Query constructor so this isn't dry. Still necessary? scope.query.filters = scope.query.filters.map(function(filter){ var name = Object.keys(filter)[0]; return new Filter(angular.extend(filter[name], { name: name })); diff --git a/app/assets/javascripts/angular/models/query.js b/app/assets/javascripts/angular/models/query.js index a70fd871d5..967d3e8117 100644 --- a/app/assets/javascripts/angular/models/query.js +++ b/app/assets/javascripts/angular/models/query.js @@ -6,7 +6,14 @@ angular.module('openproject.models') angular.extend(this, data, options); this.group_by = this.group_by || ''; - if (this.filters === undefined) this.filters = []; + if (this.filters === undefined){ + this.filters = []; + } else { + this.filters = this.filters.map(function(filter){ + var name = Object.keys(filter)[0]; + return new Filter(angular.extend(filter[name], { name: name })); + }); + } }; Query.prototype = { diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index f51dea9841..54d2e172c6 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -569,10 +569,6 @@ class WorkPackagesController < ApplicationController def get_query_and_results_as_json(results, work_packages) get_results_as_json(results, work_packages).merge( project_identifier: @project.to_param, - # query: get_query_as_json(@query), - # columns: get_columns_for_json(@query.columns), - # available_columns: get_columns_for_json(@query.available_columns), - # sort_criteria: @sort_criteria.to_param ) end From ae704975bdf8fdb4580fea70cfb185292fa1cd09 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 14 Mar 2014 16:27:08 +0100 Subject: [PATCH 004/155] added a status service. --- .../controllers/work-packages-controller.js | 2 ++ .../work_packages/query-filter-directive.js | 14 +++++++++-- .../angular/helpers/components/path-helper.js | 3 +++ .../angular/services/status-service.js | 25 +++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 app/assets/javascripts/angular/services/status-service.js diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index fc2beec516..df91650f01 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -88,6 +88,8 @@ angular.module('openproject.workPackages.controllers') }; function initialLoad(){ + // TODO RS: Around about now we need to get the project from the api so that we know about its + // custom fields so that we can use them as filters. setupPagination(PAGINATION_OPTIONS); $scope.updateResults(); }; diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index 811afe98ed..5dc5a3c062 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -1,13 +1,23 @@ angular.module('openproject.workPackages.directives') -.directive('queryFilter', ['WorkPackagesTableHelper', 'WorkPackageService', 'FunctionDecorators', function(WorkPackagesTableHelper, WorkPackageService, FunctionDecorators) { +.directive('queryFilter', ['WorkPackagesTableHelper', 'WorkPackageService', 'FunctionDecorators', 'StatusService', function(WorkPackagesTableHelper, WorkPackageService, FunctionDecorators, StatusService) { return { restrict: 'A', link: function(scope, element, attributes) { + function populateValues(data){ + // Do something... + } + + // TODO RS: We need to extend this so that it gets possible values from the api if it is a 'list_model' filter scope.availableValues = scope.query.getAvailableFilterValues(scope.filter.name); - scope.showValueOptionsAsSelect = ['list', 'list_optional', 'list_status', 'list_subprojects'].indexOf(scope.query.getFilterType(scope.filter.name)) !== -1; + scope.showValueOptionsAsSelect = ['list', 'list_optional', 'list_status', 'list_subprojects', 'list_model'].indexOf(scope.query.getFilterType(scope.filter.name)) !== -1; + + if(scope.filter.name == 'list_model'){ + // Get possible values + StatusService.getStatuses().then(populateValues); + } scope.$watch('filter.operator', function(operator) { if(operator) scope.showValuesInput = scope.filter.requiresValues(); diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index 57abcbedec..14b9a0a7d2 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -31,6 +31,9 @@ angular.module('openproject.helpers') }, versionPath: function(versionId) { return '/versions/' + versionId; + }, + statusesPath: function() { + return '/statuses' } }; diff --git a/app/assets/javascripts/angular/services/status-service.js b/app/assets/javascripts/angular/services/status-service.js new file mode 100644 index 0000000000..ae7b00f843 --- /dev/null +++ b/app/assets/javascripts/angular/services/status-service.js @@ -0,0 +1,25 @@ +angular.module('openproject.services') + +.service('StatusService', ['$http', 'PathHelper', function($http, PathHelper) { + + var StatusService = { + getStatuses: function() { + var url = PathHelper.statusesPath(); + + return WorkPackageService.doQuery(url); + }, + + doQuery: function(url, params) { + return $http({ + method: 'GET', + url: url, + params: params, + headers: {'Content-Type': 'application/x-www-form-urlencoded'} + }).then(function(response){ + return response.data; + }); + } + }; + + return StatusService; +}]); From 1a4081e7e34cd52e5ecd8b3dbaea930fdac457d4 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 18 Mar 2014 16:23:37 +0100 Subject: [PATCH 005/155] WIP using query in api controller just like in wp controller. trying to get angular to use the api method. --- .../angular/helpers/components/path-helper.js | 4 +- .../api/v2/planning_elements_controller.rb | 68 +++++++++++++------ .../api/v2/planning_elements/index.api.rabl | 41 +++++------ 3 files changed, 69 insertions(+), 44 deletions(-) diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index 14b9a0a7d2..35351a3885 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -6,7 +6,7 @@ angular.module('openproject.helpers') apiPrefix: '/api/v2', projectPath: function(projectIdentifier) { - return '/projects/' + projectIdentifier; + return '/api/v2/projects/' + projectIdentifier; }, workPackagesPath: function() { return '/work_packages'; @@ -15,7 +15,7 @@ angular.module('openproject.helpers') return '/work_packages/' + id; }, projectWorkPackagesPath: function(projectIdentifier) { - return PathHelper.projectPath(projectIdentifier) + PathHelper.workPackagesPath(); + return PathHelper.projectPath(projectIdentifier) + PathHelper.workPackagesPath() + ".json"; }, usersPath: function() { return '/users'; diff --git a/app/controllers/api/v2/planning_elements_controller.rb b/app/controllers/api/v2/planning_elements_controller.rb index 65d7ffbf3b..cee245d07d 100644 --- a/app/controllers/api/v2/planning_elements_controller.rb +++ b/app/controllers/api/v2/planning_elements_controller.rb @@ -34,6 +34,8 @@ module Api unloadable helper :timelines, :planning_elements + include PaginationHelper + include QueriesHelper include ::Api::V2::ApiController include ExtendedHTTP @@ -195,7 +197,7 @@ module Api if planning_comparison? @planning_elements = convert_to_struct(historical_work_packages(projects)) else - @planning_elements = convert_to_struct(current_work_packages(projects)) + @planning_elements = convert_to_struct(current_work_packages_alt(projects)) # TODO RS # only for current work_packages, the array of child-ids must be reconstructed # for historical packages, the re-wiring is not needed rewire_ancestors @@ -259,27 +261,28 @@ module Api end def current_work_packages_alt(projects) - # work_packages = WorkPackage.for_projects(projects) - # .changed_since(@since) - # .includes(:status, :project, :type, :custom_values) - project = timeline_to_project(params[:timeline]) - query = Query.new(:project => project) + # query = Query.new(:project => @project) + query = retrieve_query - if params[:f] - #we need a project to make project-specific custom fields work - # project = timeline_to_project(params[:timeline]) - # query = Query.new(:project => project) - - query.add_filters(params[:f], params[:op], params[:v]) + # if params[:f] + # #we need a project to make project-specific custom fields work + # # project = timeline_to_project(params[:timeline]) + # # query = Query.new(:project => project) - #if we do not remove the project, the filter will only add wps from this project - query.project = nil + # query.add_filters(params[:f], params[:op], params[:v]) - # work_packages = work_packages.with_query query - end + # #if we do not remove the project, the filter will only add wps from this project + # query.project = nil + # end results = query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version]) - work_packages = results.work_packages.all + work_packages = results.work_packages + .page(page_param) + .per_page(per_page_param) + .changed_since(@since) + .all + + set_planning_elements_meta(query, results, work_packages) work_packages end @@ -296,8 +299,35 @@ module Api # per_page_options # total_entries # Most of which can be lifted from work_packages_controller hopefully as long as the query is set up in the same way - def current_work_packages_meta(query, results, work_packages) - @planning_elements_meta = {} + def set_planning_elements_meta(query, results, work_packages) + # @query ||= retrieve_query + @display_meta = true + @columns = if params[:c] + params[:c].map {|c| c.to_sym } + else + [:id, :start_date] # Defaults + end + @planning_elements_meta = { + work_package_count_by_group: results.work_package_count_by_group, + sums: query.columns.map { |column| results.total_sum_of(column) }, + group_sums: query.group_by_column && query.columns.map { |column| results.grouped_sums(column) }, + page: page_param, + per_page: per_page_param, + per_page_options: Setting.per_page_options_array, + total_entries: work_packages.total_entries + } + end + + # TODO RS: Taken from work_packages_controller, not dry! + def per_page_param + case params[:format] + when 'csv', 'pdf' + Setting.work_packages_export_limit.to_i + when 'atom' + Setting.feeds_limit.to_i + else + super + end end def historical_work_packages(projects) diff --git a/app/views/api/v2/planning_elements/index.api.rabl b/app/views/api/v2/planning_elements/index.api.rabl index 7a5f7f981e..08b7972072 100644 --- a/app/views/api/v2/planning_elements/index.api.rabl +++ b/app/views/api/v2/planning_elements/index.api.rabl @@ -26,30 +26,25 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -collection @planning_elements => :planning_elements -attributes :id, - :subject, - :description, - :done_ratio, - :estimated_hours, - :project_id, - :type_id, - :category_id, - :priority_id, - :fixed_version_id, - :status_id, - :parent_id, - :child_ids, - :responsible_id, - :author_id, - :assigned_to_id +object false -node :start_date, :if => lambda{|pe| pe.start_date.present?} { |pe| pe.start_date.to_formatted_s(:db) } -node :due_date, :if => lambda{|pe| pe.due_date.present?} {|pe| pe.due_date.to_formatted_s(:db) } +child @planning_elements => :planning_elements do + @columns.each do |c| + attribute c + end -node :created_at, if: lambda{|pe| pe.created_at.present?} {|pe| pe.created_at.utc} -node :updated_at, if: lambda{|pe| pe.updated_at.present?} {|pe| pe.updated_at.utc} + node(:start_date, :if => lambda{|pe| pe.start_date.present? && @columns.include?(:start_date)}) { |pe| pe.start_date.to_formatted_s(:db) } -node do |element| - Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] + node :due_date, :if => lambda{|pe| pe.due_date.present? && @columns.include?(:start_date)} {|pe| pe.due_date.to_formatted_s(:db) } + + node :created_at, if: lambda{|pe| pe.created_at.present? && @columns.include?(:start_date)} {|pe| pe.created_at.utc} + node :updated_at, if: lambda{|pe| pe.updated_at.present? && @columns.include?(:start_date)} {|pe| pe.updated_at.utc} + + node do |element| + Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] + end +end + +if @display_meta + node(:meta) { @planning_elements_meta } end \ No newline at end of file From 5dd786d3f8c1bdcb5066d27dfadad4eee3ef0f19 Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 19 Mar 2014 10:22:28 +0100 Subject: [PATCH 006/155] Discovering more about the api. think it's definitely a good idea now to create a new work packages api controller because planning elements controller isn't doing what we want. --- .../angular/config/work-packages-config.js | 34 ++++++++++++++++++- .../controllers/work-packages-controller.js | 15 ++++---- .../angular/helpers/components/path-helper.js | 2 +- .../api/v2/planning_elements_controller.rb | 1 + .../api/v2/planning_elements/index.api.rabl | 7 ++-- 5 files changed, 47 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 531d670fc5..3c07047595 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -20,6 +20,22 @@ angular.module('openproject.workPackages.config') ]) .constant('INITIALLY_SELECT_COLUMNS', [ + { + custom_field: false, + groupable: false, + meta_data: { data_type: 'integer', link: { display: true } }, + name: 'id', + sortable: true, + title: '#' + }, + { + custom_field: false, + groupable: false, + meta_data: { data_type: 'string' }, + name: 'subject', + sortable: true, + title: 'Subject' + }, { custom_field: false, groupable: 'type', @@ -27,7 +43,23 @@ angular.module('openproject.workPackages.config') name: 'type', sortable: 'types.postition', title: 'Type' - } + }, + { + custom_field: false, + groupable: false, + meta_data: { data_type: 'date' }, + name: 'start_date', + sortable: true, + title: 'Started at' + }, + { + custom_field: false, + groupable: false, + meta_data: { data_type: 'date' }, + name: 'due_date', + sortable: true, + title: 'Due on' + }, ]) .constant('OPERATORS_AND_LABELS_BY_FILTER_TYPE', { diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index df91650f01..1cc901721d 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -43,13 +43,14 @@ angular.module('openproject.workPackages.controllers') }; $scope.setupWorkPackagesTable = function(json) { - $scope.workPackageCountByGroup = json.work_package_count_by_group; - $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); - $scope.totalSums = json.sums; - $scope.groupSums = json.group_sums; - $scope.totalEntries = json.total_entries; - - setupPagination(json); + var meta = json.meta; + $scope.workPackageCountByGroup = meta.work_package_count_by_group; + $scope.rows = WorkPackagesTableHelper.getRows(json.planning_elements, $scope.query.group_by); + $scope.totalSums = meta.sums; + $scope.groupSums = meta.group_sums; + $scope.totalEntries = meta.total_entries; + + setupPagination(meta); }; $scope.updateResults = function() { diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index 35351a3885..5af8c6e68b 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -9,7 +9,7 @@ angular.module('openproject.helpers') return '/api/v2/projects/' + projectIdentifier; }, workPackagesPath: function() { - return '/work_packages'; + return '/planning_elements'; }, workPackagePath: function(id) { return '/work_packages/' + id; diff --git a/app/controllers/api/v2/planning_elements_controller.rb b/app/controllers/api/v2/planning_elements_controller.rb index cee245d07d..c59eaedc3a 100644 --- a/app/controllers/api/v2/planning_elements_controller.rb +++ b/app/controllers/api/v2/planning_elements_controller.rb @@ -307,6 +307,7 @@ module Api else [:id, :start_date] # Defaults end + @planning_elements_meta = { work_package_count_by_group: results.work_package_count_by_group, sums: query.columns.map { |column| results.total_sum_of(column) }, diff --git a/app/views/api/v2/planning_elements/index.api.rabl b/app/views/api/v2/planning_elements/index.api.rabl index 08b7972072..cb059346c9 100644 --- a/app/views/api/v2/planning_elements/index.api.rabl +++ b/app/views/api/v2/planning_elements/index.api.rabl @@ -35,10 +35,11 @@ child @planning_elements => :planning_elements do node(:start_date, :if => lambda{|pe| pe.start_date.present? && @columns.include?(:start_date)}) { |pe| pe.start_date.to_formatted_s(:db) } - node :due_date, :if => lambda{|pe| pe.due_date.present? && @columns.include?(:start_date)} {|pe| pe.due_date.to_formatted_s(:db) } + node :due_date, :if => lambda{|pe| pe.due_date.present? && @columns.include?(:due_date)} {|pe| pe.due_date.to_formatted_s(:db) } - node :created_at, if: lambda{|pe| pe.created_at.present? && @columns.include?(:start_date)} {|pe| pe.created_at.utc} - node :updated_at, if: lambda{|pe| pe.updated_at.present? && @columns.include?(:start_date)} {|pe| pe.updated_at.utc} + node :created_at, if: lambda{|pe| pe.created_at.present? && @columns.include?(:created_at)} {|pe| pe.created_at.utc} + + node :updated_at, if: lambda{|pe| pe.updated_at.present? && @columns.include?(:updated_at)} {|pe| pe.updated_at.utc} node do |element| Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] From 986486eab9ec3504d2aed9ab17aefd58fa5d37ee Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 19 Mar 2014 13:25:57 +0100 Subject: [PATCH 007/155] Made a new work packages api method. --- .../controllers/work-packages-controller.js | 2 +- .../angular/helpers/components/path-helper.js | 4 +- .../api/v2/planning_elements_controller.rb | 75 +-------------- app/controllers/api/v3/api_controller.rb | 50 ++++++++++ .../api/v3/work_packages_controller.rb | 94 +++++++++++++++++++ .../api/v2/planning_elements/index.api.rabl | 48 +++++----- app/views/api/v3/work_packages/index.api.rabl | 51 ++++++++++ config/routes.rb | 6 ++ 8 files changed, 231 insertions(+), 99 deletions(-) create mode 100644 app/controllers/api/v3/api_controller.rb create mode 100644 app/controllers/api/v3/work_packages_controller.rb create mode 100644 app/views/api/v3/work_packages/index.api.rabl diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 1cc901721d..2d825e2e98 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -45,7 +45,7 @@ angular.module('openproject.workPackages.controllers') $scope.setupWorkPackagesTable = function(json) { var meta = json.meta; $scope.workPackageCountByGroup = meta.work_package_count_by_group; - $scope.rows = WorkPackagesTableHelper.getRows(json.planning_elements, $scope.query.group_by); + $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); $scope.totalSums = meta.sums; $scope.groupSums = meta.group_sums; $scope.totalEntries = meta.total_entries; diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index 5af8c6e68b..f2d5615ea0 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -6,10 +6,10 @@ angular.module('openproject.helpers') apiPrefix: '/api/v2', projectPath: function(projectIdentifier) { - return '/api/v2/projects/' + projectIdentifier; + return '/api/v3/projects/' + projectIdentifier; }, workPackagesPath: function() { - return '/planning_elements'; + return '/work_packages'; }, workPackagePath: function(id) { return '/work_packages/' + id; diff --git a/app/controllers/api/v2/planning_elements_controller.rb b/app/controllers/api/v2/planning_elements_controller.rb index c59eaedc3a..3a7c359e89 100644 --- a/app/controllers/api/v2/planning_elements_controller.rb +++ b/app/controllers/api/v2/planning_elements_controller.rb @@ -34,8 +34,6 @@ module Api unloadable helper :timelines, :planning_elements - include PaginationHelper - include QueriesHelper include ::Api::V2::ApiController include ExtendedHTTP @@ -197,7 +195,7 @@ module Api if planning_comparison? @planning_elements = convert_to_struct(historical_work_packages(projects)) else - @planning_elements = convert_to_struct(current_work_packages_alt(projects)) # TODO RS + @planning_elements = convert_to_struct(current_work_packages(projects)) # only for current work_packages, the array of child-ids must be reconstructed # for historical packages, the re-wiring is not needed rewire_ancestors @@ -260,77 +258,6 @@ module Api work_packages end - def current_work_packages_alt(projects) - # query = Query.new(:project => @project) - query = retrieve_query - - # if params[:f] - # #we need a project to make project-specific custom fields work - # # project = timeline_to_project(params[:timeline]) - # # query = Query.new(:project => project) - - # query.add_filters(params[:f], params[:op], params[:v]) - - # #if we do not remove the project, the filter will only add wps from this project - # query.project = nil - # end - - results = query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version]) - work_packages = results.work_packages - .page(page_param) - .per_page(per_page_param) - .changed_since(@since) - .all - - set_planning_elements_meta(query, results, work_packages) - - work_packages - end - - # TODO: This needs to assign the meta data: - # project_identifier - # query - # work_package_count_by_group - # sort_criteria - # sums - # group_sums - # page - # per_page - # per_page_options - # total_entries - # Most of which can be lifted from work_packages_controller hopefully as long as the query is set up in the same way - def set_planning_elements_meta(query, results, work_packages) - # @query ||= retrieve_query - @display_meta = true - @columns = if params[:c] - params[:c].map {|c| c.to_sym } - else - [:id, :start_date] # Defaults - end - - @planning_elements_meta = { - work_package_count_by_group: results.work_package_count_by_group, - sums: query.columns.map { |column| results.total_sum_of(column) }, - group_sums: query.group_by_column && query.columns.map { |column| results.grouped_sums(column) }, - page: page_param, - per_page: per_page_param, - per_page_options: Setting.per_page_options_array, - total_entries: work_packages.total_entries - } - end - - # TODO RS: Taken from work_packages_controller, not dry! - def per_page_param - case params[:format] - when 'csv', 'pdf' - Setting.work_packages_export_limit.to_i - when 'atom' - Setting.feeds_limit.to_i - else - super - end - end - def historical_work_packages(projects) at_time = Time.at(params[:at_time].to_i).to_datetime filter = params[:f] ? {f: params[:f], op: params[:op], v: params[:v]}: {} diff --git a/app/controllers/api/v3/api_controller.rb b/app/controllers/api/v3/api_controller.rb new file mode 100644 index 0000000000..896ad0fc3b --- /dev/null +++ b/app/controllers/api/v3/api_controller.rb @@ -0,0 +1,50 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2013 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. +#++ + +module Api + module V3 + + module ApiController + + include ::Api::V2::ApiController + extend ::Api::V2::ApiController::ClassMethods + + def api_version + /api\/v3\// + end + + permeate_permissions :apply_at_timestamp, + :determine_base, + :find_all_projects_by_project_id, + :find_project_by_project_id, + :jump_to_project_menu_item, + :find_optional_project_and_raise_error + + end + end +end diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb new file mode 100644 index 0000000000..0d4cb71ae1 --- /dev/null +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -0,0 +1,94 @@ + + +module Api + module V3 + + class WorkPackagesController < ApplicationController + unloadable + + include PaginationHelper + include QueriesHelper + include ::Api::V3::ApiController + include ExtendedHTTP + + before_filter :authorize_and_setup_project + before_filter :assign_planning_elements + + def index + # the data for the index is already produced in the assign_planning_elements + respond_to do |format| + format.api + end + end + + private + + def authorize_and_setup_project + find_project_by_project_id unless performed? + authorize unless performed? + end + + def assign_planning_elements + @work_packages = current_work_packages(@project) unless performed? + end + + def current_work_packages(projects) + query = retrieve_query + + results = query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version]) + work_packages = results.work_packages + .page(page_param) + .per_page(per_page_param) + .changed_since(@since) + .all + + set_planning_elements_meta(query, results, work_packages) + + work_packages + end + + # TODO: This needs to assign the meta data: + # project_identifier + # query + # work_package_count_by_group + # sort_criteria + # sums + # group_sums + # page + # per_page + # per_page_options + # total_entries + # Most of which can be lifted from work_packages_controller hopefully as long as the query is set up in the same way + def set_planning_elements_meta(query, results, work_packages) + @display_meta = true + @columns = if params[:c] + params[:c].map {|c| c.to_sym } + else + [:id, :start_date] # TODO RS: Get defaults from somewhere sensible + end + + @work_packages_meta = { + work_package_count_by_group: results.work_package_count_by_group, + sums: query.columns.map { |column| results.total_sum_of(column) }, + group_sums: query.group_by_column && query.columns.map { |column| results.grouped_sums(column) }, + page: page_param, + per_page: per_page_param, + per_page_options: Setting.per_page_options_array, + total_entries: work_packages.total_entries + } + end + + # TODO RS: Taken from work_packages_controller, not dry - move to application controller. + def per_page_param + case params[:format] + when 'csv', 'pdf' + Setting.work_packages_export_limit.to_i + when 'atom' + Setting.feeds_limit.to_i + else + super + end + end + end + end +end \ No newline at end of file diff --git a/app/views/api/v2/planning_elements/index.api.rabl b/app/views/api/v2/planning_elements/index.api.rabl index cb059346c9..7a5f7f981e 100644 --- a/app/views/api/v2/planning_elements/index.api.rabl +++ b/app/views/api/v2/planning_elements/index.api.rabl @@ -26,26 +26,30 @@ # See doc/COPYRIGHT.rdoc for more details. #++ -object false - -child @planning_elements => :planning_elements do - @columns.each do |c| - attribute c - end - - node(:start_date, :if => lambda{|pe| pe.start_date.present? && @columns.include?(:start_date)}) { |pe| pe.start_date.to_formatted_s(:db) } - - node :due_date, :if => lambda{|pe| pe.due_date.present? && @columns.include?(:due_date)} {|pe| pe.due_date.to_formatted_s(:db) } - - node :created_at, if: lambda{|pe| pe.created_at.present? && @columns.include?(:created_at)} {|pe| pe.created_at.utc} - - node :updated_at, if: lambda{|pe| pe.updated_at.present? && @columns.include?(:updated_at)} {|pe| pe.updated_at.utc} - - node do |element| - Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] - end -end - -if @display_meta - node(:meta) { @planning_elements_meta } +collection @planning_elements => :planning_elements +attributes :id, + :subject, + :description, + :done_ratio, + :estimated_hours, + :project_id, + :type_id, + :category_id, + :priority_id, + :fixed_version_id, + :status_id, + :parent_id, + :child_ids, + :responsible_id, + :author_id, + :assigned_to_id + +node :start_date, :if => lambda{|pe| pe.start_date.present?} { |pe| pe.start_date.to_formatted_s(:db) } +node :due_date, :if => lambda{|pe| pe.due_date.present?} {|pe| pe.due_date.to_formatted_s(:db) } + +node :created_at, if: lambda{|pe| pe.created_at.present?} {|pe| pe.created_at.utc} +node :updated_at, if: lambda{|pe| pe.updated_at.present?} {|pe| pe.updated_at.utc} + +node do |element| + Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] end \ No newline at end of file diff --git a/app/views/api/v3/work_packages/index.api.rabl b/app/views/api/v3/work_packages/index.api.rabl new file mode 100644 index 0000000000..e846b76f58 --- /dev/null +++ b/app/views/api/v3/work_packages/index.api.rabl @@ -0,0 +1,51 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2013 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. +#++ + +object false + +child @work_packages => :work_packages do + @columns.each do |c| + attribute c + end + + node(:start_date, :if => lambda{|pe| pe.start_date.present? && @columns.include?(:start_date)}) { |pe| pe.start_date.to_formatted_s(:db) } + + node :due_date, :if => lambda{|pe| pe.due_date.present? && @columns.include?(:due_date)} {|pe| pe.due_date.to_formatted_s(:db) } + + node :created_at, if: lambda{|pe| pe.created_at.present? && @columns.include?(:created_at)} {|pe| pe.created_at.utc} + + node :updated_at, if: lambda{|pe| pe.updated_at.present? && @columns.include?(:updated_at)} {|pe| pe.updated_at.utc} + + node do |element| + Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] + end +end + +if @display_meta + node(:meta) { @work_packages_meta } +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 96603c0aa9..5ebb77a6d0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -115,6 +115,12 @@ OpenProject::Application.routes.draw do end end + + namespace :v3 do + resources :projects, only: [:show] do + resources :work_packages, only: [:index] + end + end end match '/roles/workflow/:id/:role_id/:type_id' => 'roles#workflow' From 25a9343e9f07de6c7827644ceb113ad616ed37ef Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 19 Mar 2014 16:01:33 +0100 Subject: [PATCH 008/155] Added an api controller/endpoint for available columns. still not entirely convinced this is api data but kind of ran out of options. --- .../angular/config/work-packages-config.js | 69 ++----------------- .../controllers/work-packages-controller.js | 7 +- app/controllers/api/v3/queries_controller.rb | 34 +++++++++ .../api/v3/work_packages_controller.rb | 2 +- app/controllers/work_packages_controller.rb | 53 -------------- .../api/v3/queries/available_columns.api.rabl | 33 +++++++++ app/views/api/v3/work_packages/index.api.rabl | 16 ++--- config/routes.rb | 3 + 8 files changed, 84 insertions(+), 133 deletions(-) create mode 100644 app/controllers/api/v3/queries_controller.rb create mode 100644 app/views/api/v3/queries/available_columns.api.rabl diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 3c07047595..80275bb390 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -1,70 +1,11 @@ angular.module('openproject.workPackages.config') -.constant('AVAILABLE_COLUMNS', [ - { - custom_field: false, - groupable: 'project', - meta_data: { data_type: 'object', link: { display: true, model_type: 'project' } }, - name: 'project', - sortable: 'projects.name', - title: 'Project' - }, - { - custom_field: false, - groupable: 'type', - meta_data: { data_type: 'object', link: { display: true } }, - name: 'type', - sortable: 'types.postition', - title: 'Type' - } -]) - -.constant('INITIALLY_SELECT_COLUMNS', [ - { - custom_field: false, - groupable: false, - meta_data: { data_type: 'integer', link: { display: true } }, - name: 'id', - sortable: true, - title: '#' - }, - { - custom_field: false, - groupable: false, - meta_data: { data_type: 'string' }, - name: 'subject', - sortable: true, - title: 'Subject' - }, - { - custom_field: false, - groupable: 'type', - meta_data: { data_type: 'object', link: { display: true } }, - name: 'type', - sortable: 'types.postition', - title: 'Type' - }, - { - custom_field: false, - groupable: false, - meta_data: { data_type: 'date' }, - name: 'start_date', - sortable: true, - title: 'Started at' - }, - { - custom_field: false, - groupable: false, - meta_data: { data_type: 'date' }, - name: 'due_date', - sortable: true, - title: 'Due on' - }, -]) +.constant('INITIALLY_SELECT_COLUMNS', ["id", "subject"]) .constant('OPERATORS_AND_LABELS_BY_FILTER_TYPE', { list: {"=":"is","!":"is not"}, - list_status: {"o":"open","=":"is","!":"is not","c":"closed","*":"all"}, + list_model: {"=":"is","!":"is not"}, + list_status: {"o":"open","=":"is","!":"is not","c":"closed","*":"all"}, // TODO RS: Need a generalised solution list_optional: {"=":"is","!":"is not","!*":"none","*":"all"}, list_subprojects: {"*":"all","!*":"none","=":"is"}, date: {"t+":"in more than","t+":"in","t":"today","w":"this week",">t-":"less than days ago"," :available_columns +attributes :name, + :caption_key, + :default_order, + :groupable diff --git a/app/views/api/v3/work_packages/index.api.rabl b/app/views/api/v3/work_packages/index.api.rabl index e846b76f58..4487d147ec 100644 --- a/app/views/api/v3/work_packages/index.api.rabl +++ b/app/views/api/v3/work_packages/index.api.rabl @@ -29,21 +29,13 @@ object false child @work_packages => :work_packages do + @columns.each do |c| - attribute c + node(c, :if => lambda{ |wp| wp.respond_to?(c) }) do |wp| + wp.send(c) + end end - node(:start_date, :if => lambda{|pe| pe.start_date.present? && @columns.include?(:start_date)}) { |pe| pe.start_date.to_formatted_s(:db) } - - node :due_date, :if => lambda{|pe| pe.due_date.present? && @columns.include?(:due_date)} {|pe| pe.due_date.to_formatted_s(:db) } - - node :created_at, if: lambda{|pe| pe.created_at.present? && @columns.include?(:created_at)} {|pe| pe.created_at.utc} - - node :updated_at, if: lambda{|pe| pe.updated_at.present? && @columns.include?(:updated_at)} {|pe| pe.updated_at.utc} - - node do |element| - Hash[element.custom_values.map { |cv| ["cf_#{cv.custom_field_id}", cv.value] }] - end end if @display_meta diff --git a/config/routes.rb b/config/routes.rb index 5ebb77a6d0..c2dd14f692 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -119,6 +119,9 @@ OpenProject::Application.routes.draw do namespace :v3 do resources :projects, only: [:show] do resources :work_packages, only: [:index] + resources :queries, only: [:show] do + get :available_columns, on: :collection + end end end end From fc7609758784bd524cc2f3dbdba293ef7ced6564 Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 19 Mar 2014 16:23:59 +0100 Subject: [PATCH 009/155] Moved all the extra meta goodies into the api queries controller. --- app/controllers/api/v3/queries_controller.rb | 51 ++++++++++++++++++- .../api/v3/queries/available_columns.api.rabl | 11 ++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/v3/queries_controller.rb b/app/controllers/api/v3/queries_controller.rb index 7c19116804..53e9f7345a 100644 --- a/app/controllers/api/v3/queries_controller.rb +++ b/app/controllers/api/v3/queries_controller.rb @@ -15,7 +15,7 @@ module Api def available_columns query = retrieve_query - @available_columns = query.available_columns + @available_columns = get_columns_for_json(query.available_columns) respond_to do |format| format.api @@ -24,8 +24,57 @@ module Api private + def get_columns_for_json(columns) + columns.map do |column| + { name: column.name, + title: column.caption, + sortable: column.sortable, + groupable: column.groupable, + custom_field: column.is_a?(QueryCustomFieldColumn) && + column.custom_field.as_json(only: [:id, :field_format]), + meta_data: get_column_meta(column) + } + end + end + + def get_column_meta(column) + # This is where we want to add column specific behaviour to instruct the front end how to deal with it + # Needs to be things like user link,project link, datetime + { + data_type: column_data_type(column), + link: !!(link_meta()[column.name]) ? link_meta()[column.name] : { display: false } + } + end + + def link_meta + { + subject: { display: true, model_type: "work_package" }, + type: { display: false }, + status: { display: false }, + priority: { display: false }, + parent: { display: true, model_type: "user" }, + assigned_to: { display: true, model_type: "user" }, + responsible: { display: true, model_type: "user" }, + author: { display: true, model_type: "user" }, + project: { display: true, model_type: "project" } + } + end + + def column_data_type(column) + if column.is_a?(QueryCustomFieldColumn) + return column.custom_field.field_format + elsif (c = WorkPackage.columns_hash[column.name.to_s] and !c.nil?) + return c.type.to_s + elsif (c = WorkPackage.columns_hash[column.name.to_s + "_id"] and !c.nil?) + return "object" + else + return "default" + end + end + def authorize_and_setup_project find_project_by_project_id unless performed? + # TODO: Sort out the authorisation for reading query controller # authorize unless performed? end end diff --git a/app/views/api/v3/queries/available_columns.api.rabl b/app/views/api/v3/queries/available_columns.api.rabl index 0d767a6ba0..bf0fb4d6f6 100644 --- a/app/views/api/v3/queries/available_columns.api.rabl +++ b/app/views/api/v3/queries/available_columns.api.rabl @@ -27,7 +27,10 @@ #++ collection @available_columns => :available_columns -attributes :name, - :caption_key, - :default_order, - :groupable + +node(:name) { |c| c[:name] } +node(:title) { |c| c[:title] } +node(:sortable) { |c| c[:sortable] } +node(:groupable) { |c| c[:groupable] } +node(:custom_field) { |c| c[:custom_field] } +node(:meta_data) { |c| c[:meta_data] } From 5f6736798ce935e057d7629f69e6f328f0ab237b Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 09:10:43 +0100 Subject: [PATCH 010/155] using a query service call to get the available columns. still looks messed up because of something to do with the default id column. --- .../angular/config/work-packages-config.js | 2 +- .../controllers/work-packages-controller.js | 49 ++++++++++++------- .../angular/helpers/components/path-helper.js | 5 +- .../helpers/work-packages-table-helper.js | 10 ++++ .../angular/services/query-service.js | 25 ++++++++++ 5 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 app/assets/javascripts/angular/services/query-service.js diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 80275bb390..5135a3e3cb 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -1,6 +1,6 @@ angular.module('openproject.workPackages.config') -.constant('INITIALLY_SELECT_COLUMNS', ["id", "subject"]) +.constant('INITIALLY_SELECTED_COLUMNS', ["id", "subject"]) .constant('OPERATORS_AND_LABELS_BY_FILTER_TYPE', { list: {"=":"is","!":"is not"}, diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 80f7df1db9..a6623ef570 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,7 +1,7 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'INITIALLY_SELECT_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'PAGINATION_OPTIONS', - function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, INITIALLY_SELECT_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, PAGINATION_OPTIONS) { +.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'PAGINATION_OPTIONS', + function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, PAGINATION_OPTIONS) { function initialSetup() { $scope.projectIdentifier = gon.project_identifier; @@ -11,24 +11,38 @@ angular.module('openproject.workPackages.controllers') } function setupQuery() { - // TODO: we will have to load the query if we have a query id here. - $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); - - sortation = new Sortation(DEFAULT_SORT_CRITERIA); - $scope.query.setSortation(sortation); - $scope.currentSortation = DEFAULT_SORT_CRITERIA; - // $scope.available_work_package_filters = AVAILABLE_WORK_PACKAGE_FILTERS; - - // Columns - $scope.columns = INITIALLY_SELECT_COLUMNS; // TODO: Get available columns from api - $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(AVAILABLE_COLUMNS, $scope.columns); + setupColumns(); + // $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(AVAILABLE_COLUMNS, $scope.columns); - angular.extend($scope.query, { - selectedColumns: $scope.columns - }); }; + function setupColumns(){ + // TODO FIRST THING! Split this up into methods + QueryService.getAvailableColumns($scope.projectIdentifier).then(function(data){ + $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); + $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); + return $scope.availableColumns; + }).then(function(data){ + // TODO: we will have to load the query if we have a query id here. + $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: data}); + + sortation = new Sortation(DEFAULT_SORT_CRITERIA); + $scope.query.setSortation(sortation); + $scope.currentSortation = DEFAULT_SORT_CRITERIA; + // $scope.available_work_package_filters = AVAILABLE_WORK_PACKAGE_FILTERS; + + // Columns + + angular.extend($scope.query, { + selectedColumns: $scope.columns + }); + + setupPagination(PAGINATION_OPTIONS); + + }).then(initialLoad) + } + function setupPagination(json) { $scope.paginationOptions = { page: json.page, @@ -92,13 +106,12 @@ angular.module('openproject.workPackages.controllers') function initialLoad(){ // TODO RS: Around about now we need to get the project from the api so that we know about its // custom fields so that we can use them as filters. - setupPagination(PAGINATION_OPTIONS); $scope.updateResults(); }; initialSetup(); setupQuery(); - initialLoad(); + // initialLoad(); // Initialize work package table // $scope.setupWorkPackagesTable(gon); diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index f2d5615ea0..07ab0be667 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -34,7 +34,10 @@ angular.module('openproject.helpers') }, statusesPath: function() { return '/statuses' - } + }, + availableColumnsPath: function(projectIdentifier) { + return PathHelper.projectPath(projectIdentifier) + '/queries/available_columns'; + }, }; return PathHelper; diff --git a/app/assets/javascripts/angular/helpers/work-packages-table-helper.js b/app/assets/javascripts/angular/helpers/work-packages-table-helper.js index 5b2e28e337..86869bfaa9 100644 --- a/app/assets/javascripts/angular/helpers/work-packages-table-helper.js +++ b/app/assets/javascripts/angular/helpers/work-packages-table-helper.js @@ -65,11 +65,21 @@ angular.module('openproject.workPackages.helpers') return column.name; }); + return this.getColumnDifferenceByName(allColumns, columnValues) + }, + + getColumnDifferenceByName: function (allColumns, columnValues) { return allColumns.filter(function(column) { return !(columnValues.indexOf(column.name) > -1); }); }, + getColumnUnionByName: function (allColumns, columnValues) { + return allColumns.filter(function(column) { + return (columnValues.indexOf(column.name) > -1); + }); + }, + getColumnIndexByName: function(columns, columnName) { return columns .map(function(column){ diff --git a/app/assets/javascripts/angular/services/query-service.js b/app/assets/javascripts/angular/services/query-service.js new file mode 100644 index 0000000000..3c7947475f --- /dev/null +++ b/app/assets/javascripts/angular/services/query-service.js @@ -0,0 +1,25 @@ +angular.module('openproject.services') + +.service('QueryService', ['$http', 'PathHelper', function($http, PathHelper) { + + var QueryService = { + getAvailableColumns: function(projectId) { + var url = PathHelper.availableColumnsPath(projectId); + + return QueryService.doQuery(url); + }, + + doQuery: function(url, params) { + return $http({ + method: 'GET', + url: url, + params: params, + headers: {'Content-Type': 'application/x-www-form-urlencoded'} + }).then(function(response){ + return response.data; + }); + } + }; + + return QueryService; +}]); From d7306ad571c007478a62f8720395a4a5f61f3eb9 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 09:51:57 +0100 Subject: [PATCH 011/155] sort of works. --- .../controllers/work-packages-controller.js | 56 ++++++------------- .../work_packages/query-filter-directive.js | 8 +-- .../javascripts/angular/models/query.js | 4 +- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index a6623ef570..d082c64443 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -8,48 +8,37 @@ angular.module('openproject.workPackages.controllers') $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; $scope.loading = false; $scope.disableFilters = false; - } - function setupQuery() { - // TODO: Get available columns from api setupColumns(); - // $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(AVAILABLE_COLUMNS, $scope.columns); - }; function setupColumns(){ - // TODO FIRST THING! Split this up into methods QueryService.getAvailableColumns($scope.projectIdentifier).then(function(data){ $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); return $scope.availableColumns; - }).then(function(data){ - // TODO: we will have to load the query if we have a query id here. - $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: data}); - - sortation = new Sortation(DEFAULT_SORT_CRITERIA); - $scope.query.setSortation(sortation); - $scope.currentSortation = DEFAULT_SORT_CRITERIA; - // $scope.available_work_package_filters = AVAILABLE_WORK_PACKAGE_FILTERS; - - // Columns - - angular.extend($scope.query, { - selectedColumns: $scope.columns - }); - - setupPagination(PAGINATION_OPTIONS); + }).then(setupQuery).then(setupPagination).then($scope.updateResults) + }; - }).then(initialLoad) - } + function setupQuery() { + $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); + + sortation = new Sortation(DEFAULT_SORT_CRITERIA); + $scope.query.setSortation(sortation); + $scope.currentSortation = DEFAULT_SORT_CRITERIA; + angular.extend($scope.query, { + selectedColumns: $scope.columns + }); + }; function setupPagination(json) { + meta = json || PAGINATION_OPTIONS; $scope.paginationOptions = { - page: json.page, - perPage: json.per_page + page: meta.page, + perPage: meta.per_page }; - $scope.perPageOptions = json.per_page_options; - } + $scope.perPageOptions = meta.per_page_options; + }; $scope.submitQueryForm = function(){ jQuery("#selected_columns option").attr('selected',true); @@ -103,16 +92,5 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; }; - function initialLoad(){ - // TODO RS: Around about now we need to get the project from the api so that we know about its - // custom fields so that we can use them as filters. - $scope.updateResults(); - }; - initialSetup(); - setupQuery(); - // initialLoad(); - - // Initialize work package table - // $scope.setupWorkPackagesTable(gon); }]); diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index 5dc5a3c062..534dcf55c8 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -14,10 +14,10 @@ angular.module('openproject.workPackages.directives') scope.showValueOptionsAsSelect = ['list', 'list_optional', 'list_status', 'list_subprojects', 'list_model'].indexOf(scope.query.getFilterType(scope.filter.name)) !== -1; - if(scope.filter.name == 'list_model'){ - // Get possible values - StatusService.getStatuses().then(populateValues); - } + // if(scope.filter.name == 'list_model'){ + // // Get possible values + // StatusesService.getStatuses().then(populateValues); + // } scope.$watch('filter.operator', function(operator) { if(operator) scope.showValuesInput = scope.filter.requiresValues(); diff --git a/app/assets/javascripts/angular/models/query.js b/app/assets/javascripts/angular/models/query.js index 967d3e8117..e7a1d86272 100644 --- a/app/assets/javascripts/angular/models/query.js +++ b/app/assets/javascripts/angular/models/query.js @@ -21,9 +21,9 @@ angular.module('openproject.models') return angular.extend.apply(this, [ { 'f[]': this.getFilterNames(this.getActiveConfiguredFilters()), - 'c[]': this.selectedColumns.map(function(column) { + 'c[]': ['id'].concat(this.selectedColumns.map(function(column) { return column.name; - }), + })), 'group_by': this.group_by, 'query_id': this.id, 'sort': this.sortation.encode() From 1b3a3670774a57a1e501088cd1c4100622360896 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 13:59:12 +0100 Subject: [PATCH 012/155] WIP. having fun with authorisation. --- .../angular/helpers/components/path-helper.js | 38 ++++++---- .../angular/services/query-service.js | 2 +- .../angular/services/status-service.js | 2 +- .../angular/services/user-service.js | 2 +- .../angular/services/work-package-service.js | 6 +- app/controllers/api/v2/api_controller.rb | 3 +- app/controllers/api/v3/api_controller.rb | 3 +- .../api/v3/work_packages_controller.rb | 74 ++++++++++++++++++- app/controllers/work_packages_controller.rb | 73 ------------------ app/models/user.rb | 1 - .../api/v3/work_packages/column_data.api.rabl | 31 ++++++++ .../api/v3/work_packages/column_sums.api.rabl | 31 ++++++++ config/routes.rb | 7 +- lib/redmine.rb | 5 +- 14 files changed, 178 insertions(+), 100 deletions(-) create mode 100644 app/views/api/v3/work_packages/column_data.api.rabl create mode 100644 app/views/api/v3/work_packages/column_sums.api.rabl diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index 07ab0be667..cd11dfb792 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -4,9 +4,10 @@ angular.module('openproject.helpers') .service('PathHelper', [function() { PathHelper = { apiPrefix: '/api/v2', + apiPrefixV3: '/api/v3', projectPath: function(projectIdentifier) { - return '/api/v3/projects/' + projectIdentifier; + return '/projects/' + projectIdentifier; }, workPackagesPath: function() { return '/work_packages'; @@ -14,29 +15,38 @@ angular.module('openproject.helpers') workPackagePath: function(id) { return '/work_packages/' + id; }, - projectWorkPackagesPath: function(projectIdentifier) { - return PathHelper.projectPath(projectIdentifier) + PathHelper.workPackagesPath() + ".json"; - }, usersPath: function() { return '/users'; }, userPath: function(id) { return PathHelper.usersPath() + id; }, - workPackagesColumnDataPath: function() { - return PathHelper.workPackagesPath() + '/column_data'; - }, - workPackagesSumsPath: function(projectIdentifier) { - return PathHelper.projectPath(projectIdentifier) + '/column_sums'; - }, versionPath: function(versionId) { return '/versions/' + versionId; }, - statusesPath: function() { - return '/statuses' + apiProjectPath: function(projectIdentifier) { + return PathHelper.apiPrefixV3 + PathHelper.projectPath(projectIdentifier); + }, + apiWorkPackagesPath: function() { + return PathHelper.apiPrefixV3 + '/work_packages'; + }, + apiProjectWorkPackagesPath: function(projectIdentifier) { + return PathHelper.apiProjectPath(projectIdentifier) + PathHelper.workPackagesPath(); + }, + apiAvailableColumnsPath: function(projectIdentifier) { + return PathHelper.apiProjectPath(projectIdentifier) + '/queries/available_columns'; + }, + apiWorkPackagesColumnDataPath: function() { + return PathHelper.apiWorkPackagesPath() + '/column_data'; + }, + apiStatusesPath: function() { + return PathHelper.apiPrefix + '/statuses' + }, + apiUsersPath: function() { + return PathHelper.apiPrefix + PathHelper.usersPath(); }, - availableColumnsPath: function(projectIdentifier) { - return PathHelper.projectPath(projectIdentifier) + '/queries/available_columns'; + apiWorkPackagesSumsPath: function(projectIdentifier) { + return PathHelper.apiProjectPath(projectIdentifier) + '/column_sums'; }, }; diff --git a/app/assets/javascripts/angular/services/query-service.js b/app/assets/javascripts/angular/services/query-service.js index 3c7947475f..202a6ea2d5 100644 --- a/app/assets/javascripts/angular/services/query-service.js +++ b/app/assets/javascripts/angular/services/query-service.js @@ -4,7 +4,7 @@ angular.module('openproject.services') var QueryService = { getAvailableColumns: function(projectId) { - var url = PathHelper.availableColumnsPath(projectId); + var url = PathHelper.apiAvailableColumnsPath(projectId); return QueryService.doQuery(url); }, diff --git a/app/assets/javascripts/angular/services/status-service.js b/app/assets/javascripts/angular/services/status-service.js index ae7b00f843..65495d37b6 100644 --- a/app/assets/javascripts/angular/services/status-service.js +++ b/app/assets/javascripts/angular/services/status-service.js @@ -4,7 +4,7 @@ angular.module('openproject.services') var StatusService = { getStatuses: function() { - var url = PathHelper.statusesPath(); + var url = PathHelper.apiStatusesPath(); return WorkPackageService.doQuery(url); }, diff --git a/app/assets/javascripts/angular/services/user-service.js b/app/assets/javascripts/angular/services/user-service.js index e0fba4cdb7..0a854c05bc 100644 --- a/app/assets/javascripts/angular/services/user-service.js +++ b/app/assets/javascripts/angular/services/user-service.js @@ -19,7 +19,7 @@ angular.module('openproject.services') loadRegisteredUsers: function() { if (registeredUserIds.length > 0) { - return $http.get(PathHelper.apiPrefix + PathHelper.usersPath(), { + return $http.get(PathHelper.apiUsersPath(), { params: { 'ids[]': registeredUserIds } }).then(function(response){ UserService.storeUsers(response.data.users); diff --git a/app/assets/javascripts/angular/services/work-package-service.js b/app/assets/javascripts/angular/services/work-package-service.js index ab47441638..d46f206e99 100644 --- a/app/assets/javascripts/angular/services/work-package-service.js +++ b/app/assets/javascripts/angular/services/work-package-service.js @@ -4,7 +4,7 @@ angular.module('openproject.services') var WorkPackageService = { getWorkPackages: function(projectId, query, paginationOptions) { - var url = projectId ? PathHelper.projectWorkPackagesPath(projectId) : PathHelper.workPackagesPath(); + var url = projectId ? PathHelper.apiProjectWorkPackagesPath(projectId) : PathHelper.apiWorkPackagesPath(); var params = angular.extend(query.toParams(), { page: paginationOptions.page, per_page: paginationOptions.perPage @@ -14,7 +14,7 @@ angular.module('openproject.services') }, loadWorkPackageColumnsData: function(workPackages, columnNames) { - var url = PathHelper.workPackagesColumnDataPath(); + var url = PathHelper.apiWorkPackagesColumnDataPath(); var params = { 'ids[]': workPackages.map(function(workPackage){ @@ -32,7 +32,7 @@ angular.module('openproject.services') return column.name; }); - var url = PathHelper.workPackagesSumsPath(projectId); + var url = PathHelper.apiWorkPackagesSumsPath(projectId); var params = { 'column_names[]': columnNames diff --git a/app/controllers/api/v2/api_controller.rb b/app/controllers/api/v2/api_controller.rb index c8e5641b9a..286e770458 100644 --- a/app/controllers/api/v2/api_controller.rb +++ b/app/controllers/api/v2/api_controller.rb @@ -39,7 +39,8 @@ module Api /api\/v2\// end - permeate_permissions :apply_at_timestamp, + permeate_permissions :authorize, + :apply_at_timestamp, :determine_base, :find_all_projects_by_project_id, :find_project_by_project_id, diff --git a/app/controllers/api/v3/api_controller.rb b/app/controllers/api/v3/api_controller.rb index 896ad0fc3b..cc2cc1c619 100644 --- a/app/controllers/api/v3/api_controller.rb +++ b/app/controllers/api/v3/api_controller.rb @@ -38,7 +38,8 @@ module Api /api\/v3\// end - permeate_permissions :apply_at_timestamp, + permeate_permissions :authorize, + :apply_at_timestamp, :determine_base, :find_all_projects_by_project_id, :find_project_by_project_id, diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index c6fb367e36..a878b97b81 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -11,8 +11,9 @@ module Api include ::Api::V3::ApiController include ExtendedHTTP - before_filter :authorize_and_setup_project - before_filter :assign_planning_elements + before_filter :authorize_and_setup_project, only: [:index] + before_filter :authorize_request, only: [:column_data] + before_filter :assign_planning_elements, only: [:index] def index # the data for the index is already produced in the assign_planning_elements @@ -21,6 +22,29 @@ module Api end end + def column_data + raise 'API Error: No IDs' unless params[:ids] + raise 'API Error: No column names' unless params[:column_names] + + column_names = params[:column_names] + ids = params[:ids].map(&:to_i) + work_packages = Array.wrap(WorkPackage.visible.find(*ids)).sort {|a,b| ids.index(a.id) <=> ids.index(b.id)} + + @columns_data = fetch_columns_data(column_names, work_packages) + end + + def column_sums + raise 'API Error' unless params[:column_names] + + column_names = params[:column_names] + project = Project.find_visible(current_user, params[:id]) + work_packages = project.work_packages + + @column_sums = column_names.map do |column_name| + fetch_column_data(column_name, work_packages).map{|c| c.nil? ? 0 : c}.compact.sum if column_should_be_summed_up?(column_name) + end + end + private def authorize_and_setup_project @@ -28,6 +52,10 @@ module Api authorize unless performed? end + def authorize_request + authorize_global unless performed? + end + def assign_planning_elements @work_packages = current_work_packages(@project) unless performed? end @@ -89,6 +117,48 @@ module Api super end end + + def fetch_columns_data(column_names, work_packages) + column_names.map do |column_name| + fetch_column_data(column_name, work_packages) + end + end + + def fetch_column_data(column_name, work_packages) + if column_name =~ /cf_(.*)/ + custom_field = CustomField.find($1) + work_packages.map do |work_package| + custom_value = work_package.custom_values.find_by_custom_field_id($1) + custom_field.cast_value custom_value.try(:value) + end + else + work_packages.map do |work_package| + # Note: Doing as_json here because if we just take the value.attributes then we can't get any methods later. + # Name and subject are the default properties that the front end currently looks for to summarize an object. + value = work_package.send(column_name) + value.is_a?(ActiveRecord::Base) ? value.as_json( only: "id", methods: [:name, :subject] ) : value + end + end + end + + def column_should_be_summed_up?(column_name) + # see ::Query::Sums mix in + column_is_numeric?(column_name) && Setting.work_package_list_summable_columns.include?(column_name.to_s) + end + + def column_is_numeric?(column_name) + # TODO RS: We want to leave out ids even though they are numeric + [:int, :float].include? column_type(column_name) + end + + def column_type(column_name) + if column_name =~ /cf_(.*)/ + CustomField.find($1).field_format.to_sym + else + column = WorkPackage.columns_hash[column_name] + column.nil? ? :none : column.type + end + end end end end \ No newline at end of file diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index eab6e2b317..66c7a213f0 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -266,79 +266,6 @@ class WorkPackagesController < ApplicationController render_404 end - # ------------------- Custom API method ------------------- - # TODO Move to API - def column_data - raise 'API Error: No IDs' unless params[:ids] - raise 'API Error: No column names' unless params[:column_names] - - column_names = params[:column_names] - ids = params[:ids].map(&:to_i) - work_packages = Array.wrap(WorkPackage.visible.find(*ids)).sort {|a,b| ids.index(a.id) <=> ids.index(b.id)} - - render json: fetch_columns_data(column_names, work_packages) - end - - def column_sums - # TODO RS: Needs to work for groups, what's the deal? - raise 'API Error' unless params[:column_names] - - column_names = params[:column_names] - project = Project.find_visible(current_user, params[:id]) - work_packages = project.work_packages - sums = column_names.map do |column_name| - fetch_column_data(column_name, work_packages).map{|c| c.nil? ? 0 : c}.compact.sum if column_should_be_summed_up?(column_name) - end - - render json: sums - end - - def fetch_columns_data(column_names, work_packages) - column_names.map do |column_name| - fetch_column_data(column_name, work_packages) - end - end - - def fetch_column_data(column_name, work_packages) - if column_name =~ /cf_(.*)/ - custom_field = CustomField.find($1) - work_packages.map do |work_package| - custom_value = work_package.custom_values.find_by_custom_field_id($1) - custom_field.cast_value custom_value.try(:value) - end - else - work_packages.map do |work_package| - # Note: Doing as_json here because if we just take the value.attributes then we can't get any methods later. - # Name and subject are the default properties that the front end currently looks for to summarize an object. - value = work_package.send(column_name) - value.is_a?(ActiveRecord::Base) ? value.as_json( only: "id", methods: [:name, :subject] ) : value - end - end - end - - def column_should_be_summed_up?(column_name) - # see ::Query::Sums mix in - column_is_numeric?(column_name) && Setting.work_package_list_summable_columns.include?(column_name.to_s) - end - - def column_is_numeric?(column_name) - # TODO RS: We want to leave out ids even though they are numeric - [:int, :float].include? column_type(column_name) - end - - def column_type(column_name) - if column_name =~ /cf_(.*)/ - CustomField.find($1).field_format.to_sym - else - column = WorkPackage.columns_hash[column_name] - column.nil? ? :none : column.type - end - end - - - # --------------------------------------------------------- - - def quoted text, author = if params[:journal_id] journal = work_package.journals.find(params[:journal_id]) diff --git a/app/models/user.rb b/app/models/user.rb index ecff1646e1..8cc0aa8721 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -641,7 +641,6 @@ class User < Principal return true if admin? initialize_allowance_evaluators - # authorize if user has at least one membership granting this permission candidates_for_global_allowance.any? do |candidate| denied = @registered_allowance_evaluators.any? do |evaluator| diff --git a/app/views/api/v3/work_packages/column_data.api.rabl b/app/views/api/v3/work_packages/column_data.api.rabl new file mode 100644 index 0000000000..34ef0fa860 --- /dev/null +++ b/app/views/api/v3/work_packages/column_data.api.rabl @@ -0,0 +1,31 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2013 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. +#++ + +object false + +node(:columns_data) { @columns_data } \ No newline at end of file diff --git a/app/views/api/v3/work_packages/column_sums.api.rabl b/app/views/api/v3/work_packages/column_sums.api.rabl new file mode 100644 index 0000000000..606a8b28da --- /dev/null +++ b/app/views/api/v3/work_packages/column_sums.api.rabl @@ -0,0 +1,31 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2013 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. +#++ + +object false + +node(:column_sums) { @column_sums } \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index c2dd14f692..ea37b8d5ee 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -117,8 +117,13 @@ OpenProject::Application.routes.draw do end namespace :v3 do + resources :work_packages, only: [:index] do + get :column_data, on: :collection + end resources :projects, only: [:show] do - resources :work_packages, only: [:index] + resources :work_packages, only: [:index] do + get :column_sums, on: :collection + end resources :queries, only: [:show] do get :available_columns, on: :collection end diff --git a/lib/redmine.rb b/lib/redmine.rb index 48694b9510..e72ed58812 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -91,6 +91,9 @@ Redmine::AccessControl.map do |map| :copy_projects => [:copy, :copy_project], :members => [:paginate_users] }, :require => :member + map.permission :load_column_data, { + :work_packages => [ :column_data ] + } map.project_module :work_package_tracking do |map| # Issue categories @@ -102,7 +105,7 @@ Redmine::AccessControl.map do |map| :versions => [:index, :show, :status_by], :journals => [:index, :diff], :queries => :index, - :work_packages => [:show, :index, :column_data], # TODO move column_data to API + :work_packages => [:show, :index], :'work_packages/reports' => [:report, :report_details], :planning_elements => [:index, :all, :show, :recycle_bin], :planning_element_journals => [:index]} From d04210495845c31eadb97767fe372c5acfcaa9c8 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 14:36:22 +0100 Subject: [PATCH 013/155] Bug regarding return js from rabl template. --- .../javascripts/angular/services/work-package-service.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/angular/services/work-package-service.js b/app/assets/javascripts/angular/services/work-package-service.js index d46f206e99..c4dc6049df 100644 --- a/app/assets/javascripts/angular/services/work-package-service.js +++ b/app/assets/javascripts/angular/services/work-package-service.js @@ -47,7 +47,8 @@ angular.module('openproject.services') }); return WorkPackageService.loadWorkPackageColumnsData(workPackages, columnNames) - .then(function(columnsData){ + .then(function(data){ + var columnsData = data.columns_data; angular.forEach(workPackages, function(workPackage, i) { angular.forEach(columns, function(column, j){ WorkPackagesHelper.augmentWorkPackageWithData(workPackage, column.name, !!column.custom_field, columnsData[j][i]); From ebf5bafbbc9bf3ec3c3624c995b7403da2a363cb Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 15:24:11 +0100 Subject: [PATCH 014/155] Don't load work packages on initial load of work_packages#index --- .../api/v3/work_packages_controller.rb | 8 +- app/controllers/work_packages_controller.rb | 86 +------------------ app/views/work_packages/index.html.erb | 6 +- .../work_packages/work_packages_table.html | 2 +- 4 files changed, 14 insertions(+), 88 deletions(-) diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index a878b97b81..18e7bffefc 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -6,8 +6,11 @@ module Api class WorkPackagesController < ApplicationController unloadable + DEFAULT_SORT_ORDER = ['parent', 'desc'] + include PaginationHelper include QueriesHelper + include SortHelper include ::Api::V3::ApiController include ExtendedHTTP @@ -16,6 +19,9 @@ module Api before_filter :assign_planning_elements, only: [:index] def index + sort_init(@query.sort_criteria.empty? ? [DEFAULT_SORT_ORDER] : @query.sort_criteria) + sort_update(@query.sortable_columns) + # the data for the index is already produced in the assign_planning_elements respond_to do |format| format.api @@ -161,4 +167,4 @@ module Api end end end -end \ No newline at end of file +end diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 66c7a213f0..66c2737647 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -30,7 +30,6 @@ class WorkPackagesController < ApplicationController unloadable - DEFAULT_SORT_ORDER = ['parent', 'desc'] EXPORT_FORMATS = %w[atom rss xls csv pdf] menu_item :new_work_package, :only => [:new, :create] @@ -46,7 +45,6 @@ class WorkPackagesController < ApplicationController end include QueriesHelper - include SortHelper include PaginationHelper accept_key_auth :index, :show, :create, :update @@ -209,36 +207,14 @@ class WorkPackagesController < ApplicationController end def index - sort_init(@query.sort_criteria.empty? ? [DEFAULT_SORT_ORDER] : @query.sort_criteria) - sort_update(@query.sortable_columns) - - results = @query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version], - :order => sort_clause) - - work_packages = if @query.valid? - results.work_packages.page(page_param) - .per_page(per_page_param) - .all - else - [] - end - respond_to do |format| format.html do - # push work packages to client as JSON - # TODO pull work packages via AJAX - # push_filter_operators_and_labels - push_query_and_results_via_gon results, work_packages + push_project_id_via_gon render :index, :locals => { :query => @query, - :work_packages => work_packages, - :results => results, :project => @project }, :layout => !request.xhr? end - format.json do - render json: get_results_as_json(results, work_packages) - end format.csv do serialized_work_packages = WorkPackage::Exporter.csv(work_packages, @project) charset = "charset=#{l(:general_csv_encoding).downcase}" @@ -465,64 +441,14 @@ class WorkPackagesController < ApplicationController private # ------------------- Form JSON reponse for angular ------------------- - # TODO provide data in API - - def push_filter_operators_and_labels - gon.operators_and_labels_by_filter_type = get_operators_and_labels_by_filter_type - - end - def push_query_and_results_via_gon(results, work_packages) + # TODO get from params + def push_project_id_via_gon gon.project_identifier = @project.to_param # TODO later versions of gon support gon.push {Hash} - on the other hand they make it harder to deliver data to gon inside views end - # filter information - - def get_operators_and_labels_by_filter_type - Queries::Filter.operators_by_filter_type.inject({}) do |hash, (type, operators)| - hash.merge type => get_operators_to_label_hash(operators) - end - end - - def get_operators_to_label_hash(operators) - operators.inject({}) do |operators_with_labels, operator| - operators_with_labels.merge(operator => I18n.t(Queries::Filter.operators[operator])) - end - end - - # query - - def get_query_and_results_as_json(results, work_packages) - get_results_as_json(results, work_packages).merge( - project_identifier: @project.to_param, - ) - end - - def get_results_as_json(results, work_packages) - { - work_package_count_by_group: results.work_package_count_by_group, - work_packages: get_work_packages_as_json(work_packages, @query.columns), - sums: results.column_total_sums, - group_sums: results.column_group_sums, - page: page_param, - per_page: per_page_param, - per_page_options: Setting.per_page_options_array, - total_entries: work_packages.total_entries - } - end - - # work packages - - def get_work_packages_as_json(work_packages, selected_columns=[]) - attributes_to_be_displayed = default_work_package_attributes + - (WorkPackage.attribute_names.map(&:to_sym) & selected_columns.map(&:name)) - - work_packages.as_json only: attributes_to_be_displayed, - methods: [:leaf?, :overdue?], - include: get_column_includes(selected_columns) - end - + # TODO implement in API rabl template def get_column_includes(selected_columns=[]) selected_associations = { assigned_to: { only: :id, methods: :name }, @@ -544,8 +470,4 @@ class WorkPackagesController < ApplicationController selected_associations end - - def default_work_package_attributes - %i(id parent_id) - end end diff --git a/app/views/work_packages/index.html.erb b/app/views/work_packages/index.html.erb index 5b5cc708e9..809c9aeca5 100644 --- a/app/views/work_packages/index.html.erb +++ b/app/views/work_packages/index.html.erb @@ -75,9 +75,7 @@ See doc/COPYRIGHT.rdoc for more details. <% if query.valid? %> - <%= render :partial => 'work_packages/list', :locals => { :work_packages => work_packages, - :query => query, - :results => results } %> + <%= render :partial => 'work_packages/list', :locals => { :query => query } %> <%= other_formats_links do |f| %> <%= f.link_to 'Atom', :url => { :project_id => project, :query_id => (query.new_record? ? nil : query), :key => User.current.rss_key } %> @@ -91,7 +89,7 @@ See doc/COPYRIGHT.rdoc for more details. <% end %> -<%= call_hook(:view_work_packages_index_bottom, { :issues => work_packages, :project => project, :query => query }) %> +<%= call_hook(:view_work_packages_index_bottom, { :project => project, :query => query }) %> <% content_for :sidebar do %> <%= render :partial => 'sidebar' %> diff --git a/public/templates/work_packages/work_packages_table.html b/public/templates/work_packages/work_packages_table.html index e36d6f1551..6013eebcfb 100644 --- a/public/templates/work_packages/work_packages_table.html +++ b/public/templates/work_packages/work_packages_table.html @@ -1,4 +1,4 @@ - +
From e770940468c9c6f758b6ecc5d6d096f533ab6751 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 15:37:07 +0100 Subject: [PATCH 015/155] Initialize columns on start up, fix js startup errors --- .../controllers/work-packages-controller.js | 17 +++++++++++------ .../work-packages-options-directive.js | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index d082c64443..16a2363e9f 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -10,15 +10,20 @@ angular.module('openproject.workPackages.controllers') $scope.disableFilters = false; setupColumns(); - }; + } function setupColumns(){ + $scope.columns = []; + QueryService.getAvailableColumns($scope.projectIdentifier).then(function(data){ $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); return $scope.availableColumns; - }).then(setupQuery).then(setupPagination).then($scope.updateResults) - }; + }) + .then(setupQuery) + .then(setupPagination) + .then($scope.updateResults); + } function setupQuery() { $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); @@ -29,7 +34,7 @@ angular.module('openproject.workPackages.controllers') angular.extend($scope.query, { selectedColumns: $scope.columns }); - }; + } function setupPagination(json) { meta = json || PAGINATION_OPTIONS; @@ -38,7 +43,7 @@ angular.module('openproject.workPackages.controllers') perPage: meta.per_page }; $scope.perPageOptions = meta.per_page_options; - }; + } $scope.submitQueryForm = function(){ jQuery("#selected_columns option").attr('selected',true); @@ -65,7 +70,7 @@ angular.module('openproject.workPackages.controllers') function serviceErrorHandler(data) { // TODO RS: This is where we'd want to put an error message on the dom $scope.loading = false; - }; + } /** * @name withLoading diff --git a/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js b/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js index 868797c4d9..1a4f275cd0 100644 --- a/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js @@ -5,10 +5,10 @@ angular.module('openproject.workPackages.directives') restrict: 'E', templateUrl: '/templates/work_packages/work_packages_options.html', link: function(scope, element, attributes) { - scope.$watch('query.group_by', function() { + scope.$watch('query.group_by', function(groupBy) { var groupByColumnIndex = scope.columns.map(function(column){ return column.name; - }).indexOf(scope.query.group_by); + }).indexOf(groupBy); scope.groupByColumn = scope.columns[groupByColumnIndex]; }); From b5b144cebe48468b289494983d8f7811d952ab13 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 16:15:20 +0100 Subject: [PATCH 016/155] Move parts of the promise chain around in work packages controller --- .../controllers/work-packages-controller.js | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 16a2363e9f..c765397507 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -9,20 +9,22 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; $scope.disableFilters = false; - setupColumns(); + setupColumns() + .then(setupQuery) + .then(setupPagination) + .then($scope.updateResults); + } function setupColumns(){ $scope.columns = []; - QueryService.getAvailableColumns($scope.projectIdentifier).then(function(data){ - $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); - $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); - return $scope.availableColumns; - }) - .then(setupQuery) - .then(setupPagination) - .then($scope.updateResults); + return QueryService.getAvailableColumns($scope.projectIdentifier) + .then(function(data){ + $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); + $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); + return $scope.availableColumns; + }); } function setupQuery() { @@ -36,13 +38,13 @@ angular.module('openproject.workPackages.controllers') }); } - function setupPagination(json) { - meta = json || PAGINATION_OPTIONS; + function setupPagination(paginationOptions) { + paginationOptions = paginationOptions || PAGINATION_OPTIONS; $scope.paginationOptions = { - page: meta.page, - perPage: meta.per_page + page: paginationOptions.page, + perPage: paginationOptions.per_page }; - $scope.perPageOptions = meta.per_page_options; + $scope.perPageOptions = paginationOptions.per_page_options; } $scope.submitQueryForm = function(){ From 3b0d58307b4ebb11f35e854d134fc2029bbcfeab Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 16:18:01 +0100 Subject: [PATCH 017/155] Rename default pagination options in angular config --- .../javascripts/angular/config/work-packages-config.js | 4 ++-- .../angular/controllers/work-packages-controller.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 5135a3e3cb..c985238288 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -43,8 +43,8 @@ angular.module('openproject.workPackages.config') id: null }) -.constant('PAGINATION_OPTIONS', { +.constant('DEFAULT_PAGINATION_OPTIONS', { page: 1, per_page: 10, per_page_options: [10, 20, 50, 100, 500, 1000] -}) \ No newline at end of file +}) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index c765397507..39fcc6f93c 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,7 +1,7 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'PAGINATION_OPTIONS', - function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, PAGINATION_OPTIONS) { +.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'DEFAULT_PAGINATION_OPTIONS', + function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, DEFAULT_PAGINATION_OPTIONS) { function initialSetup() { $scope.projectIdentifier = gon.project_identifier; @@ -39,7 +39,7 @@ angular.module('openproject.workPackages.controllers') } function setupPagination(paginationOptions) { - paginationOptions = paginationOptions || PAGINATION_OPTIONS; + paginationOptions = paginationOptions || DEFAULT_PAGINATION_OPTIONS; $scope.paginationOptions = { page: paginationOptions.page, perPage: paginationOptions.per_page From c81777decd7746c64007a0c603706c824bc954fe Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 16:24:00 +0100 Subject: [PATCH 018/155] Made a rudimentary attempt at loading query if id is given. had to put some stuff back into work packages controller again sorry Till. --- Gemfile.lock | 56 +++++++++++++++++++ .../angular/config/work-packages-config.js | 3 +- .../controllers/work-packages-controller.js | 9 ++- .../api/v3/work_packages_controller.rb | 17 ++---- app/controllers/work_packages_controller.rb | 7 ++- app/models/user.rb | 1 - 6 files changed, 73 insertions(+), 20 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index fadb5f21e6..b4e97cc385 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,9 +30,33 @@ GIT specs: prototype_legacy_helper (0.0.0) +PATH + remote: ../openproject-plugins + specs: + openproject-plugins (1.0.6) + rails (~> 3.2.9) + +PATH + remote: /home/richard/projects/finnlabs/openproject-backlogs + specs: + openproject-backlogs (3.0.5.pre3) + acts_as_silent_list + openproject-pdf_export + openproject-plugins + rails (~> 3.2.9) + +PATH + remote: /home/richard/projects/finnlabs/openproject-pdf_export + specs: + openproject-pdf_export (0.0.1) + openproject-plugins (~> 1.0.5) + prawn (~> 0.14.0) + rails (~> 3.2.14) + GEM remote: https://rubygems.org/ specs: + Ascii85 (1.0.2) actionmailer (3.2.17) actionpack (= 3.2.17) mail (~> 2.5.4) @@ -64,7 +88,9 @@ GEM multi_json (~> 1.0) acts_as_list (0.2.0) activerecord (>= 3.0) + acts_as_silent_list (1.2.0) addressable (2.3.4) + afm (0.2.0) angular-ui-select2-rails (0.1.1) jquery-rails select2-rails @@ -72,6 +98,9 @@ GEM arel (3.0.3) awesome_nested_set (2.1.6) activerecord (>= 3.0.0) + better_errors (1.1.0) + coderay (>= 1.0.0) + erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) bourne (1.4.0) @@ -172,6 +201,7 @@ GEM guard-test (1.0.0) guard (>= 1.8) test-unit (~> 2.2) + hashery (2.1.1) hike (1.2.3) htmldiff (0.0.1) i18n (0.6.5) @@ -216,8 +246,20 @@ GEM paper_trail (2.7.2) activerecord (~> 3.0) railties (~> 3.0) + pdf-inspector (1.1.0) + pdf-reader (~> 1.0) + pdf-reader (1.3.3) + Ascii85 (~> 1.0.0) + afm (~> 0.2.0) + hashery (~> 2.0) + ruby-rc4 + ttfunk pg (0.17.1) polyglot (0.3.3) + prawn (0.14.0) + pdf-reader (~> 1.2) + ruby-rc4 + ttfunk (~> 1.0.3) prototype-rails (3.2.1) rails (~> 3.2) pry (0.9.12.2) @@ -241,6 +283,8 @@ GEM pry-stack_explorer (0.4.9.1) binding_of_caller (>= 0.7) pry (>= 0.9.11) + quiet_assets (1.0.2) + railties (>= 3.1, < 5.0) rabl (0.9.3) activesupport (>= 2.3.14) rack (1.4.5) @@ -301,6 +345,7 @@ GEM ruby-openid (2.2.3) ruby-prof (0.13.0) ruby-progressbar (1.2.0) + ruby-rc4 (0.1.5) rubytree (0.8.3) json (>= 1.7.5) structured_warnings (>= 0.1.3) @@ -318,6 +363,8 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) + sextant (0.2.4) + rails (>= 3.2) shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) @@ -358,6 +405,7 @@ GEM treetop (1.4.15) polyglot polyglot (>= 0.3.1) + ttfunk (1.0.3) tzinfo (0.3.38) uglifier (2.1.1) execjs (>= 0.3.0) @@ -380,6 +428,7 @@ DEPENDENCIES angular-ui-select2-rails angularjs-rails awesome_nested_set + better_errors capybara capybara-screenshot codeclimate-test-reporter @@ -414,8 +463,13 @@ DEPENDENCIES net-ldap (~> 0.2.2) object-daddy (~> 1.1.0) oj + openproject-backlogs! + openproject-pdf_export! + openproject-plugins! openproject-ui_components! + pdf-inspector pg (~> 0.17.1) + prawn prototype-rails prototype_legacy_helper (= 0.0.0)! pry-byebug @@ -424,6 +478,7 @@ DEPENDENCIES pry-rails pry-rescue pry-stack_explorer + quiet_assets rabl (= 0.9.3) rack-protection! rack_session_access @@ -444,6 +499,7 @@ DEPENDENCIES sass-rails (~> 3.2.3) select2-rails (~> 3.3.2) selenium-webdriver + sextant shoulda shoulda-matchers simplecov (>= 0.8.pre) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 5135a3e3cb..41abb04d27 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -39,8 +39,7 @@ angular.module('openproject.workPackages.config') .constant('DEFAULT_QUERY', { display_sums: false, // filters: [{ status_id: {"operator":"o","values":[""], name: "status_id" }}], - group_by: null, - id: null + group_by: null }) .constant('PAGINATION_OPTIONS', { diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index d082c64443..3163722ad7 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -5,6 +5,7 @@ angular.module('openproject.workPackages.controllers') function initialSetup() { $scope.projectIdentifier = gon.project_identifier; + if(gon.query_id) $scope.query_id = gon.query_id; $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; $scope.loading = false; $scope.disableFilters = false; @@ -21,7 +22,11 @@ angular.module('openproject.workPackages.controllers') }; function setupQuery() { - $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); + var query = DEFAULT_QUERY; + if($scope.query_id){ + angular.extend(query, { id: $scope.query_id }); + } + $scope.query = new Query(query, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); sortation = new Sortation(DEFAULT_SORT_CRITERIA); $scope.query.setSortation(sortation); @@ -47,6 +52,8 @@ angular.module('openproject.workPackages.controllers') }; $scope.setupWorkPackagesTable = function(json) { + // TODO: We need to set the columns based on what's returned by the query for when we are loading using a query id. + // Also perhaps the filters... and everything:/ var meta = json.meta; $scope.workPackageCountByGroup = meta.work_package_count_by_group; $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index 18e7bffefc..bd212d23d1 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -59,7 +59,9 @@ module Api end def authorize_request - authorize_global unless performed? + # TODO: need to give this action a global role i think. tried making load_column_data role in reminde.rb + # but couldn't get it working. + # authorize_global unless performed? end def assign_planning_elements @@ -81,18 +83,6 @@ module Api work_packages end - # TODO: This needs to assign the meta data: - # project_identifier - # query - # work_package_count_by_group - # sort_criteria - # sums - # group_sums - # page - # per_page - # per_page_options - # total_entries - # Most of which can be lifted from work_packages_controller hopefully as long as the query is set up in the same way def set_planning_elements_meta(query, results, work_packages) @display_meta = true @columns = if params[:c] @@ -102,6 +92,7 @@ module Api end @work_packages_meta = { + query: query, work_package_count_by_group: results.work_package_count_by_group, sums: query.columns.map { |column| results.total_sum_of(column) }, group_sums: query.group_by_column && query.columns.map { |column| results.grouped_sums(column) }, diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 66c2737647..85091ebe07 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -46,6 +46,7 @@ class WorkPackagesController < ApplicationController include QueriesHelper include PaginationHelper + include SortHelper accept_key_auth :index, :show, :create, :update @@ -209,7 +210,7 @@ class WorkPackagesController < ApplicationController def index respond_to do |format| format.html do - push_project_id_via_gon + push_identifiers_via_gon render :index, :locals => { :query => @query, :project => @project }, @@ -442,9 +443,9 @@ class WorkPackagesController < ApplicationController # ------------------- Form JSON reponse for angular ------------------- - # TODO get from params - def push_project_id_via_gon + def push_identifiers_via_gon gon.project_identifier = @project.to_param + gon.query_id = params[:query_id] if params[:query_id] # TODO later versions of gon support gon.push {Hash} - on the other hand they make it harder to deliver data to gon inside views end diff --git a/app/models/user.rb b/app/models/user.rb index 8cc0aa8721..f58698f1f5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -647,7 +647,6 @@ class User < Principal evaluator.denied_for_global? candidate, action, options end - !denied && @registered_allowance_evaluators.any? do |evaluator| evaluator.granted_for_global? candidate, action, options end From 87f9e82ef0436e164b3b2792edb7296f226e3b90 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 16:52:26 +0100 Subject: [PATCH 019/155] Block work package table updates until setup is completed --- .../angular/controllers/work-packages-controller.js | 10 ++++++++-- .../angular/directives/components/table_pagination.js | 6 ++++-- .../directives/work_packages/query-form-directive.js | 2 +- .../directives/work_packages/sort-header-directive.js | 1 - app/views/work_packages/_list.html.erb | 3 ++- .../templates/work_packages/work_packages_table.html | 5 ++--- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 39fcc6f93c..e7a414ebc2 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -3,6 +3,7 @@ angular.module('openproject.workPackages.controllers') .controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'DEFAULT_PAGINATION_OPTIONS', function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, DEFAULT_PAGINATION_OPTIONS) { + function initialSetup() { $scope.projectIdentifier = gon.project_identifier; $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; @@ -12,7 +13,8 @@ angular.module('openproject.workPackages.controllers') setupColumns() .then(setupQuery) .then(setupPagination) - .then($scope.updateResults); + .then($scope.updateResults) + .then(setupComplete); } @@ -65,7 +67,7 @@ angular.module('openproject.workPackages.controllers') }; $scope.updateResults = function() { - $scope.withLoading(WorkPackageService.getWorkPackages, [$scope.projectIdentifier, $scope.query, $scope.paginationOptions]) + return $scope.withLoading(WorkPackageService.getWorkPackages, [$scope.projectIdentifier, $scope.query, $scope.paginationOptions]) .then($scope.setupWorkPackagesTable); }; @@ -74,6 +76,10 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; } + function setupComplete() { + $scope.setupComplete = true; + } + /** * @name withLoading * diff --git a/app/assets/javascripts/angular/directives/components/table_pagination.js b/app/assets/javascripts/angular/directives/components/table_pagination.js index 35f1e71519..ac3cb8a57a 100644 --- a/app/assets/javascripts/angular/directives/components/table_pagination.js +++ b/app/assets/javascripts/angular/directives/components/table_pagination.js @@ -30,12 +30,12 @@ angular.module('openproject.uiComponents') * * @description Defines a string containing page bound information inside the directive scope */ - updateCurrentRange = function() { + function updateCurrentRange() { var page = scope.paginationOptions.page; var perPage = scope.paginationOptions.perPage; scope.currentRange = "(" + getLowerPageBound(page, perPage) + " - " + getUpperPageBound(page, perPage) + "/" + scope.totalEntries + ")"; - }; + } function getLowerPageBound(page, perPage) { return perPage * (page - 1) + 1; @@ -59,6 +59,8 @@ angular.module('openproject.uiComponents') }; scope.$watch('totalEntries', function() { + if (!scope.paginationOptions) return; + updateCurrentRange(); updatePageNumbers(); }); diff --git a/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js index 8890f79194..bdada28c7c 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js @@ -11,7 +11,7 @@ angular.module('openproject.workPackages.directives') scope.showQueryOptions = false; scope.$watch('query.group_by', function(oldValue, newValue) { - if (newValue !== oldValue) { + if (scope.setupComplete && newValue !== oldValue) { scope.updateResults(); } }); diff --git a/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js b/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js index f7a9cd566e..c70fc33dae 100644 --- a/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js @@ -10,7 +10,6 @@ angular.module('openproject.workPackages.directives') headerName: '=', headerTitle: '=', sortable: '=', - updateResults: '&' }, link: function(scope, element, attributes) { scope.performSort = function(){ diff --git a/app/views/work_packages/_list.html.erb b/app/views/work_packages/_list.html.erb index 1e273ffd34..908291da00 100644 --- a/app/views/work_packages/_list.html.erb +++ b/app/views/work_packages/_list.html.erb @@ -32,7 +32,8 @@ See doc/COPYRIGHT.rdoc for more details. <%= hidden_field_tag 'back_url', url_for(params) %>
- + From e3d56d68ee9f5b1fbc5c629dbf3c9b58856aafbd Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 17:12:22 +0100 Subject: [PATCH 020/155] put pesky gemfile.lock back to what it was before. --- Gemfile.lock | 58 +--------------------------------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b4e97cc385..997e5c7596 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,33 +30,9 @@ GIT specs: prototype_legacy_helper (0.0.0) -PATH - remote: ../openproject-plugins - specs: - openproject-plugins (1.0.6) - rails (~> 3.2.9) - -PATH - remote: /home/richard/projects/finnlabs/openproject-backlogs - specs: - openproject-backlogs (3.0.5.pre3) - acts_as_silent_list - openproject-pdf_export - openproject-plugins - rails (~> 3.2.9) - -PATH - remote: /home/richard/projects/finnlabs/openproject-pdf_export - specs: - openproject-pdf_export (0.0.1) - openproject-plugins (~> 1.0.5) - prawn (~> 0.14.0) - rails (~> 3.2.14) - GEM remote: https://rubygems.org/ specs: - Ascii85 (1.0.2) actionmailer (3.2.17) actionpack (= 3.2.17) mail (~> 2.5.4) @@ -88,9 +64,7 @@ GEM multi_json (~> 1.0) acts_as_list (0.2.0) activerecord (>= 3.0) - acts_as_silent_list (1.2.0) addressable (2.3.4) - afm (0.2.0) angular-ui-select2-rails (0.1.1) jquery-rails select2-rails @@ -98,9 +72,6 @@ GEM arel (3.0.3) awesome_nested_set (2.1.6) activerecord (>= 3.0.0) - better_errors (1.1.0) - coderay (>= 1.0.0) - erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) bourne (1.4.0) @@ -201,7 +172,6 @@ GEM guard-test (1.0.0) guard (>= 1.8) test-unit (~> 2.2) - hashery (2.1.1) hike (1.2.3) htmldiff (0.0.1) i18n (0.6.5) @@ -246,20 +216,8 @@ GEM paper_trail (2.7.2) activerecord (~> 3.0) railties (~> 3.0) - pdf-inspector (1.1.0) - pdf-reader (~> 1.0) - pdf-reader (1.3.3) - Ascii85 (~> 1.0.0) - afm (~> 0.2.0) - hashery (~> 2.0) - ruby-rc4 - ttfunk pg (0.17.1) polyglot (0.3.3) - prawn (0.14.0) - pdf-reader (~> 1.2) - ruby-rc4 - ttfunk (~> 1.0.3) prototype-rails (3.2.1) rails (~> 3.2) pry (0.9.12.2) @@ -283,8 +241,6 @@ GEM pry-stack_explorer (0.4.9.1) binding_of_caller (>= 0.7) pry (>= 0.9.11) - quiet_assets (1.0.2) - railties (>= 3.1, < 5.0) rabl (0.9.3) activesupport (>= 2.3.14) rack (1.4.5) @@ -345,7 +301,6 @@ GEM ruby-openid (2.2.3) ruby-prof (0.13.0) ruby-progressbar (1.2.0) - ruby-rc4 (0.1.5) rubytree (0.8.3) json (>= 1.7.5) structured_warnings (>= 0.1.3) @@ -363,8 +318,6 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) - sextant (0.2.4) - rails (>= 3.2) shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) @@ -405,7 +358,6 @@ GEM treetop (1.4.15) polyglot polyglot (>= 0.3.1) - ttfunk (1.0.3) tzinfo (0.3.38) uglifier (2.1.1) execjs (>= 0.3.0) @@ -428,7 +380,6 @@ DEPENDENCIES angular-ui-select2-rails angularjs-rails awesome_nested_set - better_errors capybara capybara-screenshot codeclimate-test-reporter @@ -463,13 +414,8 @@ DEPENDENCIES net-ldap (~> 0.2.2) object-daddy (~> 1.1.0) oj - openproject-backlogs! - openproject-pdf_export! - openproject-plugins! openproject-ui_components! - pdf-inspector pg (~> 0.17.1) - prawn prototype-rails prototype_legacy_helper (= 0.0.0)! pry-byebug @@ -478,7 +424,6 @@ DEPENDENCIES pry-rails pry-rescue pry-stack_explorer - quiet_assets rabl (= 0.9.3) rack-protection! rack_session_access @@ -499,7 +444,6 @@ DEPENDENCIES sass-rails (~> 3.2.3) select2-rails (~> 3.3.2) selenium-webdriver - sextant shoulda shoulda-matchers simplecov (>= 0.8.pre) @@ -511,4 +455,4 @@ DEPENDENCIES thin timecop (~> 0.6.1) uglifier (>= 1.0.3) - will_paginate (~> 3.0) + will_paginate (~> 3.0) \ No newline at end of file From 2458758b7f41bd5177176e9b6785e0bfac30d859 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 21 Mar 2014 10:40:56 +0100 Subject: [PATCH 021/155] pushing everything... --- .../angular/config/work-packages-config.js | 10 +++++----- .../work_packages/query-filter-directive.js | 18 ++++++++++-------- .../angular/services/status-service.js | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index e49ce92ea7..6e5f1181db 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -16,9 +16,11 @@ angular.module('openproject.workPackages.config') }) .constant('AVAILABLE_WORK_PACKAGE_FILTERS', { - status_id: { type: "list_model", model_name: "status" ,order:1, name: "Status" }, - // type_id: { type:"list_model", model_name: "type", "order":2, name: "Type" }, - // priority_id: {"type":"list","order":3,"values":[["Immediate","29"],["High","30"],["Low","31"],["Normal","32"]],"name":"Priority"}, + status_id: { type: "list_model", model_name: "status" , order:1, name: "Status" }, + type_id: { type:"list_model", model_name: "type", order:2, name: "Type" }, + priority_id: { type:"list_model", model_name: "priority", order:3, name:"Priority"}, + assigned_to_id: { type: "list_model", model_name: "user" , order:4, name: "Assigned to" }, + author_id: { type: "list_model", model_name: "user" , order:4, name: "Author" }, subject: {"type":"text","order":8,"name":"Subject"}, created_at: {"type":"date_past","order":9,"name":"Created on"}, updated_at: {"type":"date_past","order":10,"name":"Updated on"}, @@ -26,8 +28,6 @@ angular.module('openproject.workPackages.config') due_date: {"type":"date","order":12,"name":"Due date"}, estimated_hours: {"type":"integer","order":13,"name":"Estimated time"}, done_ratio: {"type":"integer","order":14,"name":"% done"}, - // assigned_to_id: {"type":"list_optional","order":4,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Assignee"}, - // author_id: {"type":"list","order":5,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Author"}, // member_of_group: {"type":"list_optional","order":6,"values":[["Gruppe 00001","138"],["Gruppe 00002","139"],["Gruppe 00003","140"],["Gruppe 00004","141"],["Gruppe 00005","142"]],"name":"Assignee's group"}, // assigned_to_role: {"type":"list_optional","order":7,"values":[["Project Admin","3"],["Release Manager","19"],["Project Member","4"],["Stakeholder","5"],["Controller Client","6"],["Controller","8"],["Developer","9"],["Tester","10"],["Reader","11"],["Timeline Reader","20"]],"name":"Assignee's role"}, // responsible_id: {"type":"list_optional","order":4,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Responsible"},"watcher_id":{"type":"list","order":15,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Watcher"}, diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index 534dcf55c8..1db1a98143 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -6,18 +6,20 @@ angular.module('openproject.workPackages.directives') restrict: 'A', link: function(scope, element, attributes) { function populateValues(data){ - // Do something... + scope.availableValues = data.statuses.map(function(v){ + return [v.id, v.name.toString()]; + }); } - // TODO RS: We need to extend this so that it gets possible values from the api if it is a 'list_model' filter - scope.availableValues = scope.query.getAvailableFilterValues(scope.filter.name); - scope.showValueOptionsAsSelect = ['list', 'list_optional', 'list_status', 'list_subprojects', 'list_model'].indexOf(scope.query.getFilterType(scope.filter.name)) !== -1; - // if(scope.filter.name == 'list_model'){ - // // Get possible values - // StatusesService.getStatuses().then(populateValues); - // } + if(scope.query.getFilterType(scope.filter.name) == 'list_model'){ + // Get possible values + // TODO: Choose users, statuses, priorities etc based on filter something + StatusService.getStatuses().then(populateValues); + } else { + scope.availableValues = scope.query.getAvailableFilterValues(scope.filter.name); + } scope.$watch('filter.operator', function(operator) { if(operator) scope.showValuesInput = scope.filter.requiresValues(); diff --git a/app/assets/javascripts/angular/services/status-service.js b/app/assets/javascripts/angular/services/status-service.js index 65495d37b6..08c557caa5 100644 --- a/app/assets/javascripts/angular/services/status-service.js +++ b/app/assets/javascripts/angular/services/status-service.js @@ -6,7 +6,7 @@ angular.module('openproject.services') getStatuses: function() { var url = PathHelper.apiStatusesPath(); - return WorkPackageService.doQuery(url); + return StatusService.doQuery(url); }, doQuery: function(url, params) { From 332939bfd0f9f4704886a8e4868db49c5f896318 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Fri, 21 Mar 2014 11:24:54 +0100 Subject: [PATCH 022/155] Remove unused ng-change --- public/templates/work_packages/query_filters.html | 1 - 1 file changed, 1 deletion(-) diff --git a/public/templates/work_packages/query_filters.html b/public/templates/work_packages/query_filters.html index e1ea472af2..b0b6a320fb 100644 --- a/public/templates/work_packages/query_filters.html +++ b/public/templates/work_packages/query_filters.html @@ -159,7 +159,6 @@ :
@@ -23,8 +23,7 @@ header-name="column.name" header-title="column.title" sortable="column.sortable" - query="query" - update-results="updateResults()"/> + query="query"/>
+
From 3c302a7529fd0c37dd575471a0f928a37aaa35e3 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 15:37:07 +0100 Subject: [PATCH 066/155] Initialize columns on start up, fix js startup errors --- .../controllers/work-packages-controller.js | 17 +++++++++++------ .../work-packages-options-directive.js | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index d082c64443..16a2363e9f 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -10,15 +10,20 @@ angular.module('openproject.workPackages.controllers') $scope.disableFilters = false; setupColumns(); - }; + } function setupColumns(){ + $scope.columns = []; + QueryService.getAvailableColumns($scope.projectIdentifier).then(function(data){ $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); return $scope.availableColumns; - }).then(setupQuery).then(setupPagination).then($scope.updateResults) - }; + }) + .then(setupQuery) + .then(setupPagination) + .then($scope.updateResults); + } function setupQuery() { $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); @@ -29,7 +34,7 @@ angular.module('openproject.workPackages.controllers') angular.extend($scope.query, { selectedColumns: $scope.columns }); - }; + } function setupPagination(json) { meta = json || PAGINATION_OPTIONS; @@ -38,7 +43,7 @@ angular.module('openproject.workPackages.controllers') perPage: meta.per_page }; $scope.perPageOptions = meta.per_page_options; - }; + } $scope.submitQueryForm = function(){ jQuery("#selected_columns option").attr('selected',true); @@ -65,7 +70,7 @@ angular.module('openproject.workPackages.controllers') function serviceErrorHandler(data) { // TODO RS: This is where we'd want to put an error message on the dom $scope.loading = false; - }; + } /** * @name withLoading diff --git a/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js b/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js index 868797c4d9..1a4f275cd0 100644 --- a/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/work-packages-options-directive.js @@ -5,10 +5,10 @@ angular.module('openproject.workPackages.directives') restrict: 'E', templateUrl: '/templates/work_packages/work_packages_options.html', link: function(scope, element, attributes) { - scope.$watch('query.group_by', function() { + scope.$watch('query.group_by', function(groupBy) { var groupByColumnIndex = scope.columns.map(function(column){ return column.name; - }).indexOf(scope.query.group_by); + }).indexOf(groupBy); scope.groupByColumn = scope.columns[groupByColumnIndex]; }); From fa0b82fe876548a2c45ab068e1058b1b8a3a2555 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 16:15:20 +0100 Subject: [PATCH 067/155] Move parts of the promise chain around in work packages controller --- .../controllers/work-packages-controller.js | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 16a2363e9f..c765397507 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -9,20 +9,22 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; $scope.disableFilters = false; - setupColumns(); + setupColumns() + .then(setupQuery) + .then(setupPagination) + .then($scope.updateResults); + } function setupColumns(){ $scope.columns = []; - QueryService.getAvailableColumns($scope.projectIdentifier).then(function(data){ - $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); - $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); - return $scope.availableColumns; - }) - .then(setupQuery) - .then(setupPagination) - .then($scope.updateResults); + return QueryService.getAvailableColumns($scope.projectIdentifier) + .then(function(data){ + $scope.columns = WorkPackagesTableHelper.getColumnUnionByName(data.available_columns, INITIALLY_SELECTED_COLUMNS); + $scope.availableColumns = WorkPackagesTableHelper.getColumnDifference(data.available_columns, $scope.columns); + return $scope.availableColumns; + }); } function setupQuery() { @@ -36,13 +38,13 @@ angular.module('openproject.workPackages.controllers') }); } - function setupPagination(json) { - meta = json || PAGINATION_OPTIONS; + function setupPagination(paginationOptions) { + paginationOptions = paginationOptions || PAGINATION_OPTIONS; $scope.paginationOptions = { - page: meta.page, - perPage: meta.per_page + page: paginationOptions.page, + perPage: paginationOptions.per_page }; - $scope.perPageOptions = meta.per_page_options; + $scope.perPageOptions = paginationOptions.per_page_options; } $scope.submitQueryForm = function(){ From 20ef2c3cf2bd5f90ee4de9ab5a0b9462a95619a3 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 16:18:01 +0100 Subject: [PATCH 068/155] Rename default pagination options in angular config --- .../javascripts/angular/config/work-packages-config.js | 4 ++-- .../angular/controllers/work-packages-controller.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 5135a3e3cb..c985238288 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -43,8 +43,8 @@ angular.module('openproject.workPackages.config') id: null }) -.constant('PAGINATION_OPTIONS', { +.constant('DEFAULT_PAGINATION_OPTIONS', { page: 1, per_page: 10, per_page_options: [10, 20, 50, 100, 500, 1000] -}) \ No newline at end of file +}) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index c765397507..39fcc6f93c 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,7 +1,7 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'PAGINATION_OPTIONS', - function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, PAGINATION_OPTIONS) { +.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'DEFAULT_PAGINATION_OPTIONS', + function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, DEFAULT_PAGINATION_OPTIONS) { function initialSetup() { $scope.projectIdentifier = gon.project_identifier; @@ -39,7 +39,7 @@ angular.module('openproject.workPackages.controllers') } function setupPagination(paginationOptions) { - paginationOptions = paginationOptions || PAGINATION_OPTIONS; + paginationOptions = paginationOptions || DEFAULT_PAGINATION_OPTIONS; $scope.paginationOptions = { page: paginationOptions.page, perPage: paginationOptions.per_page From 3ec128d2461ea9b8b1dcd681d9c033168f9b0209 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 16:24:00 +0100 Subject: [PATCH 069/155] Made a rudimentary attempt at loading query if id is given. had to put some stuff back into work packages controller again sorry Till. --- Gemfile.lock | 51 +++++++++++++++++++ .../angular/config/work-packages-config.js | 3 +- .../controllers/work-packages-controller.js | 9 +++- .../api/v3/work_packages_controller.rb | 17 ++----- app/controllers/work_packages_controller.rb | 7 +-- app/models/user.rb | 1 - 6 files changed, 68 insertions(+), 20 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 69185d94fb..f8af84807b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -20,9 +20,33 @@ GIT specs: prototype_legacy_helper (0.0.0) +PATH + remote: ../openproject-plugins + specs: + openproject-plugins (1.0.6) + rails (~> 3.2.9) + +PATH + remote: /home/richard/projects/finnlabs/openproject-backlogs + specs: + openproject-backlogs (3.0.5.pre3) + acts_as_silent_list + openproject-pdf_export + openproject-plugins + rails (~> 3.2.9) + +PATH + remote: /home/richard/projects/finnlabs/openproject-pdf_export + specs: + openproject-pdf_export (0.0.1) + openproject-plugins (~> 1.0.5) + prawn (~> 0.14.0) + rails (~> 3.2.14) + GEM remote: https://rubygems.org/ specs: + Ascii85 (1.0.2) actionmailer (3.2.17) actionpack (= 3.2.17) mail (~> 2.5.4) @@ -54,10 +78,14 @@ GEM multi_json (~> 1.0) acts_as_list (0.2.0) activerecord (>= 3.0) + acts_as_silent_list (1.2.0) addressable (2.3.4) arel (3.0.3) awesome_nested_set (2.1.6) activerecord (>= 3.0.0) + better_errors (1.1.0) + coderay (>= 1.0.0) + erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) bourne (1.4.0) @@ -158,6 +186,7 @@ GEM guard-test (1.0.0) guard (>= 1.8) test-unit (~> 2.2) + hashery (2.1.1) hike (1.2.3) htmldiff (0.0.1) i18n (0.6.5) @@ -195,8 +224,20 @@ GEM paper_trail (2.7.2) activerecord (~> 3.0) railties (~> 3.0) + pdf-inspector (1.1.0) + pdf-reader (~> 1.0) + pdf-reader (1.3.3) + Ascii85 (~> 1.0.0) + afm (~> 0.2.0) + hashery (~> 2.0) + ruby-rc4 + ttfunk pg (0.17.1) polyglot (0.3.3) + prawn (0.14.0) + pdf-reader (~> 1.2) + ruby-rc4 + ttfunk (~> 1.0.3) prototype-rails (3.2.1) rails (~> 3.2) pry (0.9.12.2) @@ -220,6 +261,8 @@ GEM pry-stack_explorer (0.4.9.1) binding_of_caller (>= 0.7) pry (>= 0.9.11) + quiet_assets (1.0.2) + railties (>= 3.1, < 5.0) rabl (0.9.3) activesupport (>= 2.3.14) rack (1.4.5) @@ -280,6 +323,7 @@ GEM ruby-openid (2.2.3) ruby-prof (0.13.0) ruby-progressbar (1.2.0) + ruby-rc4 (0.1.5) rubytree (0.8.3) json (>= 1.7.5) structured_warnings (>= 0.1.3) @@ -294,6 +338,8 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) + sextant (0.2.4) + rails (>= 3.2) shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) @@ -334,6 +380,7 @@ GEM treetop (1.4.15) polyglot polyglot (>= 0.3.1) + ttfunk (1.0.3) tzinfo (0.3.38) uglifier (2.1.1) execjs (>= 0.3.0) @@ -354,6 +401,7 @@ DEPENDENCIES activerecord-tableless (~> 1.0) acts_as_list (~> 0.2.0) awesome_nested_set + better_errors capybara capybara-screenshot codeclimate-test-reporter @@ -386,6 +434,7 @@ DEPENDENCIES object-daddy (~> 1.1.0) oj pg (~> 0.17.1) + prawn prototype-rails prototype_legacy_helper (= 0.0.0)! pry-byebug @@ -394,6 +443,7 @@ DEPENDENCIES pry-rails pry-rescue pry-stack_explorer + quiet_assets rabl (= 0.9.3) rack-protection! rack_session_access @@ -413,6 +463,7 @@ DEPENDENCIES rubytree (~> 0.8.3) sass-rails (~> 3.2.3) selenium-webdriver + sextant shoulda shoulda-matchers simplecov (>= 0.8.pre) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index c985238288..e49ce92ea7 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -39,8 +39,7 @@ angular.module('openproject.workPackages.config') .constant('DEFAULT_QUERY', { display_sums: false, // filters: [{ status_id: {"operator":"o","values":[""], name: "status_id" }}], - group_by: null, - id: null + group_by: null }) .constant('DEFAULT_PAGINATION_OPTIONS', { diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 39fcc6f93c..dce67bf163 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -5,6 +5,7 @@ angular.module('openproject.workPackages.controllers') function initialSetup() { $scope.projectIdentifier = gon.project_identifier; + if(gon.query_id) $scope.query_id = gon.query_id; $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; $scope.loading = false; $scope.disableFilters = false; @@ -28,7 +29,11 @@ angular.module('openproject.workPackages.controllers') } function setupQuery() { - $scope.query = new Query(DEFAULT_QUERY, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); + var query = DEFAULT_QUERY; + if($scope.query_id){ + angular.extend(query, { id: $scope.query_id }); + } + $scope.query = new Query(query, { available_work_package_filters: AVAILABLE_WORK_PACKAGE_FILTERS}); sortation = new Sortation(DEFAULT_SORT_CRITERIA); $scope.query.setSortation(sortation); @@ -54,6 +59,8 @@ angular.module('openproject.workPackages.controllers') }; $scope.setupWorkPackagesTable = function(json) { + // TODO: We need to set the columns based on what's returned by the query for when we are loading using a query id. + // Also perhaps the filters... and everything:/ var meta = json.meta; $scope.workPackageCountByGroup = meta.work_package_count_by_group; $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index 18e7bffefc..bd212d23d1 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -59,7 +59,9 @@ module Api end def authorize_request - authorize_global unless performed? + # TODO: need to give this action a global role i think. tried making load_column_data role in reminde.rb + # but couldn't get it working. + # authorize_global unless performed? end def assign_planning_elements @@ -81,18 +83,6 @@ module Api work_packages end - # TODO: This needs to assign the meta data: - # project_identifier - # query - # work_package_count_by_group - # sort_criteria - # sums - # group_sums - # page - # per_page - # per_page_options - # total_entries - # Most of which can be lifted from work_packages_controller hopefully as long as the query is set up in the same way def set_planning_elements_meta(query, results, work_packages) @display_meta = true @columns = if params[:c] @@ -102,6 +92,7 @@ module Api end @work_packages_meta = { + query: query, work_package_count_by_group: results.work_package_count_by_group, sums: query.columns.map { |column| results.total_sum_of(column) }, group_sums: query.group_by_column && query.columns.map { |column| results.grouped_sums(column) }, diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 66c2737647..85091ebe07 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -46,6 +46,7 @@ class WorkPackagesController < ApplicationController include QueriesHelper include PaginationHelper + include SortHelper accept_key_auth :index, :show, :create, :update @@ -209,7 +210,7 @@ class WorkPackagesController < ApplicationController def index respond_to do |format| format.html do - push_project_id_via_gon + push_identifiers_via_gon render :index, :locals => { :query => @query, :project => @project }, @@ -442,9 +443,9 @@ class WorkPackagesController < ApplicationController # ------------------- Form JSON reponse for angular ------------------- - # TODO get from params - def push_project_id_via_gon + def push_identifiers_via_gon gon.project_identifier = @project.to_param + gon.query_id = params[:query_id] if params[:query_id] # TODO later versions of gon support gon.push {Hash} - on the other hand they make it harder to deliver data to gon inside views end diff --git a/app/models/user.rb b/app/models/user.rb index 8cc0aa8721..f58698f1f5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -647,7 +647,6 @@ class User < Principal evaluator.denied_for_global? candidate, action, options end - !denied && @registered_allowance_evaluators.any? do |evaluator| evaluator.granted_for_global? candidate, action, options end From 6d4d99151ddea4d5136dc015fa0ff403aad1ae6e Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Thu, 20 Mar 2014 16:52:26 +0100 Subject: [PATCH 070/155] Block work package table updates until setup is completed --- .../angular/controllers/work-packages-controller.js | 10 ++++++++-- .../angular/directives/components/table_pagination.js | 6 ++++-- .../directives/work_packages/query-form-directive.js | 2 +- .../directives/work_packages/sort-header-directive.js | 1 - app/views/work_packages/_list.html.erb | 3 ++- .../templates/work_packages/work_packages_table.html | 5 ++--- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index dce67bf163..09db3f8e3f 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -3,6 +3,7 @@ angular.module('openproject.workPackages.controllers') .controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'AVAILABLE_WORK_PACKAGE_FILTERS','DEFAULT_SORT_CRITERIA', 'DEFAULT_QUERY', 'DEFAULT_PAGINATION_OPTIONS', function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, AVAILABLE_WORK_PACKAGE_FILTERS, DEFAULT_SORT_CRITERIA, DEFAULT_QUERY, DEFAULT_PAGINATION_OPTIONS) { + function initialSetup() { $scope.projectIdentifier = gon.project_identifier; if(gon.query_id) $scope.query_id = gon.query_id; @@ -13,7 +14,8 @@ angular.module('openproject.workPackages.controllers') setupColumns() .then(setupQuery) .then(setupPagination) - .then($scope.updateResults); + .then($scope.updateResults) + .then(setupComplete); } @@ -72,7 +74,7 @@ angular.module('openproject.workPackages.controllers') }; $scope.updateResults = function() { - $scope.withLoading(WorkPackageService.getWorkPackages, [$scope.projectIdentifier, $scope.query, $scope.paginationOptions]) + return $scope.withLoading(WorkPackageService.getWorkPackages, [$scope.projectIdentifier, $scope.query, $scope.paginationOptions]) .then($scope.setupWorkPackagesTable); }; @@ -81,6 +83,10 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; } + function setupComplete() { + $scope.setupComplete = true; + } + /** * @name withLoading * diff --git a/app/assets/javascripts/angular/directives/components/table_pagination.js b/app/assets/javascripts/angular/directives/components/table_pagination.js index 35f1e71519..ac3cb8a57a 100644 --- a/app/assets/javascripts/angular/directives/components/table_pagination.js +++ b/app/assets/javascripts/angular/directives/components/table_pagination.js @@ -30,12 +30,12 @@ angular.module('openproject.uiComponents') * * @description Defines a string containing page bound information inside the directive scope */ - updateCurrentRange = function() { + function updateCurrentRange() { var page = scope.paginationOptions.page; var perPage = scope.paginationOptions.perPage; scope.currentRange = "(" + getLowerPageBound(page, perPage) + " - " + getUpperPageBound(page, perPage) + "/" + scope.totalEntries + ")"; - }; + } function getLowerPageBound(page, perPage) { return perPage * (page - 1) + 1; @@ -59,6 +59,8 @@ angular.module('openproject.uiComponents') }; scope.$watch('totalEntries', function() { + if (!scope.paginationOptions) return; + updateCurrentRange(); updatePageNumbers(); }); diff --git a/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js index 8890f79194..bdada28c7c 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-form-directive.js @@ -11,7 +11,7 @@ angular.module('openproject.workPackages.directives') scope.showQueryOptions = false; scope.$watch('query.group_by', function(oldValue, newValue) { - if (newValue !== oldValue) { + if (scope.setupComplete && newValue !== oldValue) { scope.updateResults(); } }); diff --git a/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js b/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js index f7a9cd566e..c70fc33dae 100644 --- a/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/sort-header-directive.js @@ -10,7 +10,6 @@ angular.module('openproject.workPackages.directives') headerName: '=', headerTitle: '=', sortable: '=', - updateResults: '&' }, link: function(scope, element, attributes) { scope.performSort = function(){ diff --git a/app/views/work_packages/_list.html.erb b/app/views/work_packages/_list.html.erb index 1e273ffd34..908291da00 100644 --- a/app/views/work_packages/_list.html.erb +++ b/app/views/work_packages/_list.html.erb @@ -32,7 +32,8 @@ See doc/COPYRIGHT.rdoc for more details. <%= hidden_field_tag 'back_url', url_for(params) %>
- + From b9ca2e540f8d8310358877bb3b6accb0d1af1a01 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 20 Mar 2014 17:12:22 +0100 Subject: [PATCH 071/155] put pesky gemfile.lock back to what it was before. --- Gemfile.lock | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f8af84807b..69185d94fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -20,33 +20,9 @@ GIT specs: prototype_legacy_helper (0.0.0) -PATH - remote: ../openproject-plugins - specs: - openproject-plugins (1.0.6) - rails (~> 3.2.9) - -PATH - remote: /home/richard/projects/finnlabs/openproject-backlogs - specs: - openproject-backlogs (3.0.5.pre3) - acts_as_silent_list - openproject-pdf_export - openproject-plugins - rails (~> 3.2.9) - -PATH - remote: /home/richard/projects/finnlabs/openproject-pdf_export - specs: - openproject-pdf_export (0.0.1) - openproject-plugins (~> 1.0.5) - prawn (~> 0.14.0) - rails (~> 3.2.14) - GEM remote: https://rubygems.org/ specs: - Ascii85 (1.0.2) actionmailer (3.2.17) actionpack (= 3.2.17) mail (~> 2.5.4) @@ -78,14 +54,10 @@ GEM multi_json (~> 1.0) acts_as_list (0.2.0) activerecord (>= 3.0) - acts_as_silent_list (1.2.0) addressable (2.3.4) arel (3.0.3) awesome_nested_set (2.1.6) activerecord (>= 3.0.0) - better_errors (1.1.0) - coderay (>= 1.0.0) - erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) bourne (1.4.0) @@ -186,7 +158,6 @@ GEM guard-test (1.0.0) guard (>= 1.8) test-unit (~> 2.2) - hashery (2.1.1) hike (1.2.3) htmldiff (0.0.1) i18n (0.6.5) @@ -224,20 +195,8 @@ GEM paper_trail (2.7.2) activerecord (~> 3.0) railties (~> 3.0) - pdf-inspector (1.1.0) - pdf-reader (~> 1.0) - pdf-reader (1.3.3) - Ascii85 (~> 1.0.0) - afm (~> 0.2.0) - hashery (~> 2.0) - ruby-rc4 - ttfunk pg (0.17.1) polyglot (0.3.3) - prawn (0.14.0) - pdf-reader (~> 1.2) - ruby-rc4 - ttfunk (~> 1.0.3) prototype-rails (3.2.1) rails (~> 3.2) pry (0.9.12.2) @@ -261,8 +220,6 @@ GEM pry-stack_explorer (0.4.9.1) binding_of_caller (>= 0.7) pry (>= 0.9.11) - quiet_assets (1.0.2) - railties (>= 3.1, < 5.0) rabl (0.9.3) activesupport (>= 2.3.14) rack (1.4.5) @@ -323,7 +280,6 @@ GEM ruby-openid (2.2.3) ruby-prof (0.13.0) ruby-progressbar (1.2.0) - ruby-rc4 (0.1.5) rubytree (0.8.3) json (>= 1.7.5) structured_warnings (>= 0.1.3) @@ -338,8 +294,6 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) - sextant (0.2.4) - rails (>= 3.2) shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) @@ -380,7 +334,6 @@ GEM treetop (1.4.15) polyglot polyglot (>= 0.3.1) - ttfunk (1.0.3) tzinfo (0.3.38) uglifier (2.1.1) execjs (>= 0.3.0) @@ -401,7 +354,6 @@ DEPENDENCIES activerecord-tableless (~> 1.0) acts_as_list (~> 0.2.0) awesome_nested_set - better_errors capybara capybara-screenshot codeclimate-test-reporter @@ -434,7 +386,6 @@ DEPENDENCIES object-daddy (~> 1.1.0) oj pg (~> 0.17.1) - prawn prototype-rails prototype_legacy_helper (= 0.0.0)! pry-byebug @@ -443,7 +394,6 @@ DEPENDENCIES pry-rails pry-rescue pry-stack_explorer - quiet_assets rabl (= 0.9.3) rack-protection! rack_session_access @@ -463,7 +413,6 @@ DEPENDENCIES rubytree (~> 0.8.3) sass-rails (~> 3.2.3) selenium-webdriver - sextant shoulda shoulda-matchers simplecov (>= 0.8.pre) From 4b19a7ccb99b81af8eb62c608c6755ff5510d898 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 21 Mar 2014 10:40:56 +0100 Subject: [PATCH 072/155] pushing everything... --- .../angular/config/work-packages-config.js | 10 +++++----- .../work_packages/query-filter-directive.js | 18 ++++++++++-------- .../angular/services/status-service.js | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index e49ce92ea7..6e5f1181db 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -16,9 +16,11 @@ angular.module('openproject.workPackages.config') }) .constant('AVAILABLE_WORK_PACKAGE_FILTERS', { - status_id: { type: "list_model", model_name: "status" ,order:1, name: "Status" }, - // type_id: { type:"list_model", model_name: "type", "order":2, name: "Type" }, - // priority_id: {"type":"list","order":3,"values":[["Immediate","29"],["High","30"],["Low","31"],["Normal","32"]],"name":"Priority"}, + status_id: { type: "list_model", model_name: "status" , order:1, name: "Status" }, + type_id: { type:"list_model", model_name: "type", order:2, name: "Type" }, + priority_id: { type:"list_model", model_name: "priority", order:3, name:"Priority"}, + assigned_to_id: { type: "list_model", model_name: "user" , order:4, name: "Assigned to" }, + author_id: { type: "list_model", model_name: "user" , order:4, name: "Author" }, subject: {"type":"text","order":8,"name":"Subject"}, created_at: {"type":"date_past","order":9,"name":"Created on"}, updated_at: {"type":"date_past","order":10,"name":"Updated on"}, @@ -26,8 +28,6 @@ angular.module('openproject.workPackages.config') due_date: {"type":"date","order":12,"name":"Due date"}, estimated_hours: {"type":"integer","order":13,"name":"Estimated time"}, done_ratio: {"type":"integer","order":14,"name":"% done"}, - // assigned_to_id: {"type":"list_optional","order":4,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Assignee"}, - // author_id: {"type":"list","order":5,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Author"}, // member_of_group: {"type":"list_optional","order":6,"values":[["Gruppe 00001","138"],["Gruppe 00002","139"],["Gruppe 00003","140"],["Gruppe 00004","141"],["Gruppe 00005","142"]],"name":"Assignee's group"}, // assigned_to_role: {"type":"list_optional","order":7,"values":[["Project Admin","3"],["Release Manager","19"],["Project Member","4"],["Stakeholder","5"],["Controller Client","6"],["Controller","8"],["Developer","9"],["Tester","10"],["Reader","11"],["Timeline Reader","20"]],"name":"Assignee's role"}, // responsible_id: {"type":"list_optional","order":4,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Responsible"},"watcher_id":{"type":"list","order":15,"values":[["<< me >>","me"],["Gianni Ward","133"],["PTU Administrator","113"],["Reece Hegmann","122"]],"name":"Watcher"}, diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index 534dcf55c8..1db1a98143 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -6,18 +6,20 @@ angular.module('openproject.workPackages.directives') restrict: 'A', link: function(scope, element, attributes) { function populateValues(data){ - // Do something... + scope.availableValues = data.statuses.map(function(v){ + return [v.id, v.name.toString()]; + }); } - // TODO RS: We need to extend this so that it gets possible values from the api if it is a 'list_model' filter - scope.availableValues = scope.query.getAvailableFilterValues(scope.filter.name); - scope.showValueOptionsAsSelect = ['list', 'list_optional', 'list_status', 'list_subprojects', 'list_model'].indexOf(scope.query.getFilterType(scope.filter.name)) !== -1; - // if(scope.filter.name == 'list_model'){ - // // Get possible values - // StatusesService.getStatuses().then(populateValues); - // } + if(scope.query.getFilterType(scope.filter.name) == 'list_model'){ + // Get possible values + // TODO: Choose users, statuses, priorities etc based on filter something + StatusService.getStatuses().then(populateValues); + } else { + scope.availableValues = scope.query.getAvailableFilterValues(scope.filter.name); + } scope.$watch('filter.operator', function(operator) { if(operator) scope.showValuesInput = scope.filter.requiresValues(); diff --git a/app/assets/javascripts/angular/services/status-service.js b/app/assets/javascripts/angular/services/status-service.js index 65495d37b6..08c557caa5 100644 --- a/app/assets/javascripts/angular/services/status-service.js +++ b/app/assets/javascripts/angular/services/status-service.js @@ -6,7 +6,7 @@ angular.module('openproject.services') getStatuses: function() { var url = PathHelper.apiStatusesPath(); - return WorkPackageService.doQuery(url); + return StatusService.doQuery(url); }, doQuery: function(url, params) { From 2110f092c366978ea741b9aff36a22b0c01a9867 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Fri, 21 Mar 2014 11:24:54 +0100 Subject: [PATCH 073/155] Remove unused ng-change --- public/templates/work_packages/query_filters.html | 1 - 1 file changed, 1 deletion(-) diff --git a/public/templates/work_packages/query_filters.html b/public/templates/work_packages/query_filters.html index e1ea472af2..b0b6a320fb 100644 --- a/public/templates/work_packages/query_filters.html +++ b/public/templates/work_packages/query_filters.html @@ -159,7 +159,6 @@ : - + Bullet_toggle_plus {{ I18n.t('js.work_packages.label_enable_multi_select') }} - \ No newline at end of file + diff --git a/public/templates/work_packages/query_filters.html b/public/templates/work_packages/query_filters.html index 2899ae9c2f..3743b4190a 100644 --- a/public/templates/work_packages/query_filters.html +++ b/public/templates/work_packages/query_filters.html @@ -130,7 +130,7 @@
- Date: Mon, 31 Mar 2014 10:46:15 +0200 Subject: [PATCH 116/155] Fixed some broken specs. Had to put a bunch of code back into work_packages_controller that we though was not needed but actually it was for the non html responses. --- app/controllers/work_packages_controller.rb | 13 +++++++++++++ .../api/v3/work_packages/index_api_json_spec.rb | 12 ++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 85091ebe07..38a1bb89dd 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -30,6 +30,7 @@ class WorkPackagesController < ApplicationController unloadable + DEFAULT_SORT_ORDER = ['parent', 'desc'] EXPORT_FORMATS = %w[atom rss xls csv pdf] menu_item :new_work_package, :only => [:new, :create] @@ -208,6 +209,18 @@ class WorkPackagesController < ApplicationController end def index + sort_init(@query.sort_criteria.empty? ? [DEFAULT_SORT_ORDER] : @query.sort_criteria) + sort_update(@query.sortable_columns) + results = @query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version], + :order => sort_clause) + work_packages = if @query.valid? + results.work_packages.page(page_param) + .per_page(per_page_param) + .all + else + [] + end + respond_to do |format| format.html do push_identifiers_via_gon diff --git a/spec/views/api/v3/work_packages/index_api_json_spec.rb b/spec/views/api/v3/work_packages/index_api_json_spec.rb index 28182ad54b..7cfb3661dd 100644 --- a/spec/views/api/v3/work_packages/index_api_json_spec.rb +++ b/spec/views/api/v3/work_packages/index_api_json_spec.rb @@ -33,7 +33,8 @@ describe 'api/v3/work_packages/index.api.rabl' do params[:format] = 'json' assign(:work_packages, work_packages) - assign(:columns, columns) + assign(:column_names, column_names) + assign(:custom_field_column_names, custom_field_column_names) render end @@ -41,7 +42,8 @@ describe 'api/v3/work_packages/index.api.rabl' do describe 'with no work packages available' do let(:work_packages) { [] } - let(:columns) { [] } + let(:column_names) { [] } + let(:custom_field_column_names) { [] } it { should have_json_path('work_packages') } it { should have_json_size(0).at_path('work_packages') } @@ -53,7 +55,8 @@ describe 'api/v3/work_packages/index.api.rabl' do FactoryGirl.build(:work_package), FactoryGirl.build(:work_package) ] } - let(:columns) { [] } + let(:column_names) { [] } + let(:custom_field_column_names) { [] } it { should have_json_path('work_packages') } it { should have_json_size(3).at_path('work_packages') } @@ -66,7 +69,8 @@ describe 'api/v3/work_packages/index.api.rabl' do FactoryGirl.build(:work_package), FactoryGirl.build(:work_package) ] } - let(:columns) { %w(subject description due_date) } + let(:column_names) { %w(subject description due_date) } + let(:custom_field_column_names) { [] } it { should have_json_path('work_packages') } it { should have_json_size(2).at_path('work_packages') } From 536d48def9892fcb3433cb0bcf5536ac7a6e938f Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 31 Mar 2014 11:21:23 +0200 Subject: [PATCH 117/155] Gon is gone! from the work packages controller at least. Getting project and query ids from the url instead. --- .../controllers/work-packages-controller.js | 15 +++++++++------ app/controllers/work_packages_controller.rb | 8 -------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 522079891d..f20236375a 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,13 +1,15 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', - function($scope, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { +.controller('WorkPackagesController', ['$scope', '$location', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', + function($scope, $location, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { - function initialSetup() { - $scope.projectIdentifier = gon.project_identifier; - if(gon.query_id) $scope.query_id = gon.query_id; + function setUrlParams(location){ + $scope.projectIdentifier = location.$$url.split('/')[2]; + if(location.$$search['query_id']) $scope.query_id = location.$$search['query_id']; + }; + function initialSetup() { $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; $scope.loading = false; $scope.disableFilters = false; @@ -15,7 +17,7 @@ angular.module('openproject.workPackages.controllers') WorkPackageService.getWorkPackagesByQueryId($scope.projectIdentifier, $scope.query_id) .then($scope.setupWorkPackagesTable) .then(initAvailableColumns); - } + }; function initQuery(queryData) { $scope.query = new Query({ @@ -99,5 +101,6 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; }; + setUrlParams($location); initialSetup(); }]); diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 38a1bb89dd..43717b94b7 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -223,8 +223,6 @@ class WorkPackagesController < ApplicationController respond_to do |format| format.html do - push_identifiers_via_gon - render :index, :locals => { :query => @query, :project => @project }, :layout => !request.xhr? @@ -456,12 +454,6 @@ class WorkPackagesController < ApplicationController # ------------------- Form JSON reponse for angular ------------------- - def push_identifiers_via_gon - gon.project_identifier = @project.to_param - gon.query_id = params[:query_id] if params[:query_id] - # TODO later versions of gon support gon.push {Hash} - on the other hand they make it harder to deliver data to gon inside views - end - # TODO implement in API rabl template def get_column_includes(selected_columns=[]) selected_associations = { From 3b9a3b5f0bb6446c5f99f6c08bfbae4ece427927 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 31 Mar 2014 12:28:07 +0200 Subject: [PATCH 118/155] Task 5454 - Fixed pagination bugs and related features. --- .../controllers/work-packages-controller.js | 4 ++++ app/controllers/work_packages_controller.rb | 24 ------------------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index f20236375a..6545be49d6 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -58,6 +58,10 @@ angular.module('openproject.workPackages.controllers') if (!$scope.columns) $scope.columns = meta.columns; if (!$scope.query) initQuery(meta.query); + PaginationService.setPerPageOptions(meta.per_page_options); + PaginationService.setPerPage(meta.per_page); + PaginationService.setPage(meta.page); + $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); $scope.workPackageCountByGroup = meta.work_package_count_by_group; diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 43717b94b7..b423411828 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -452,28 +452,4 @@ class WorkPackagesController < ApplicationController private - # ------------------- Form JSON reponse for angular ------------------- - - # TODO implement in API rabl template - def get_column_includes(selected_columns=[]) - selected_associations = { - assigned_to: { only: :id, methods: :name }, - author: { only: :id, methods: :name }, - category: { only: :name }, - priority: { only: :name }, - project: { only: [:name, :identifier] }, - responsible: { only: :id, methods: :name }, - status: { only: :name }, - type: { only: :name }, - parent: { only: :subject }, - fixed_version: { only: [:name, :id] } - }.slice(*selected_columns.map(&:name)) - - selected_associations.merge!(custom_values: { only: [:custom_field_id, :value] }) if selected_columns.any? {|c| c.is_a? QueryCustomFieldColumn} - - # TODO retrieve custom values in a single query like this and extend the work_packages inside the JSON: - # WorkPackage.includes(:custom_values).where(['work_packages.id in (?) AND custom_values.custom_field_id in (?)', @query.results.map(&:id), custom_field_columns.map(&:id)]) - - selected_associations - end end From e82764b2a564cbbb1f9076bce15113d678a3ad5c Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 16:21:26 +0200 Subject: [PATCH 119/155] Remove unused code --- .../javascripts/angular/controllers/work-packages-controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 522079891d..334b6c1237 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -29,7 +29,6 @@ angular.module('openproject.workPackages.controllers') sortation = new Sortation(DEFAULT_SORT_CRITERIA); $scope.query.setSortation(sortation); - $scope.currentSortation = DEFAULT_SORT_CRITERIA; return $scope.query; } From bc3b4c4c7e54073fb6aeca2a64942ea62b6ed59b Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 31 Mar 2014 16:21:28 +0200 Subject: [PATCH 120/155] No longer using $location because it was cocking up the links. --- .../controllers/work-packages-controller.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 6545be49d6..65cfd00833 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,12 +1,15 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', '$location', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', - function($scope, $location, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { +.controller('WorkPackagesController', ['$scope', '$window', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', + function($scope, $window, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { function setUrlParams(location){ - $scope.projectIdentifier = location.$$url.split('/')[2]; - if(location.$$search['query_id']) $scope.query_id = location.$$search['query_id']; + $scope.projectIdentifier = location.pathname.split('/')[2]; + var q = "query_id=" + if(i = location.search.indexOf(q) > 0) { + $scope.query_id = location.search.slice(i + q.length, i + q.length + 1); + } }; function initialSetup() { @@ -57,7 +60,6 @@ angular.module('openproject.workPackages.controllers') if (!$scope.columns) $scope.columns = meta.columns; if (!$scope.query) initQuery(meta.query); - PaginationService.setPerPageOptions(meta.per_page_options); PaginationService.setPerPage(meta.per_page); PaginationService.setPage(meta.page); @@ -105,6 +107,6 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; }; - setUrlParams($location); + setUrlParams($window.location); initialSetup(); }]); From 1cc4712ac261010b06759f6c8a6e580e93c61a3d Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 16:23:22 +0200 Subject: [PATCH 121/155] Make the query more tolerant of missing values the filter mode deals with validation due to missing values --- app/models/query.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/query.rb b/app/models/query.rb index ee991f09c7..70dc0d227f 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -116,7 +116,7 @@ class Query < ActiveRecord::Base def add_filter(field, operator, values) - return unless values && values.is_a?(Array) && work_package_filter_available?(field) + return unless work_package_filter_available?(field) if filter = filter_for(field) filter.operator = operator @@ -134,6 +134,8 @@ class Query < ActiveRecord::Base # Add multiple filters using +add_filter+ def add_filters(fields, operators, values) + values ||= {} + if fields.is_a?(Array) && operators.is_a?(Hash) && values.is_a?(Hash) fields.each do |field| add_filter(field, operators[field], values[field]) @@ -318,10 +320,8 @@ class Query < ActiveRecord::Base field = filter.field.to_s next if field == "subproject_id" - values = filter.values.clone - next if values.blank? - operator = filter.operator + values = filter.values ? filter.values.clone : [''] # HACK - some operators don't require values, but they are needed for building the statement # "me" value subsitution if @@user_filters.include? field From e7e37ee651c42785fa3e9406b48dd64e929054c7 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 16:24:39 +0200 Subject: [PATCH 122/155] Add active model serialization to filter model --- app/models/queries/filter.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/queries/filter.rb b/app/models/queries/filter.rb index ef303bc171..b09504a513 100644 --- a/app/models/queries/filter.rb +++ b/app/models/queries/filter.rb @@ -29,6 +29,7 @@ class Queries::Filter include ActiveModel::Validations + include ActiveModel::Serialization class_attribute :filter_types_by_field, instance_writer: false @@ -91,6 +92,7 @@ class Queries::Filter end end + # (de-)serialization def self.from_hash(filter_hash) filter_hash.keys.map {|field| new(field, filter_hash[field]) } end @@ -99,6 +101,12 @@ class Queries::Filter { field => attributes_hash } end + alias_method :name, :field + + def attributes + { name: name, operator: operator, values: values } + end + def field=(field) @field = field.try :to_sym end From 7de67ae1f6bd8897e052f35dce9660a48d0e708e Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 16:27:38 +0200 Subject: [PATCH 123/155] Serialize filters for query meta data returned by work packages API --- app/assets/javascripts/angular/models/query.js | 5 ++--- app/controllers/api/v3/work_packages_controller.rb | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/angular/models/query.js b/app/assets/javascripts/angular/models/query.js index 96984f543b..9b618d4ab4 100644 --- a/app/assets/javascripts/angular/models/query.js +++ b/app/assets/javascripts/angular/models/query.js @@ -12,9 +12,8 @@ angular.module('openproject.models') if (this.filters === undefined){ this.filters = []; } else { - this.filters = this.filters.map(function(filter){ - var name = Object.keys(filter)[0]; - return new Filter(angular.extend(filter[name], { name: name })); + this.filters = this.filters.map(function(filterData){ + return new Filter(filterData); }); } }; diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index b7519cdf46..0876ad06fe 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -97,7 +97,7 @@ module Api @display_meta = true @work_packages_meta_data = { - query: query, + query: query.as_json(except: :filters, include: :filters), columns: get_columns_for_json(query.columns), work_package_count_by_group: results.work_package_count_by_group, sums: query.columns.map { |column| results.total_sum_of(column) }, From 35f44c90d57b39446f7e085820ae19ae8517b9b7 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 16:28:33 +0200 Subject: [PATCH 124/155] Move setting of a default filter to client-side --- .../javascripts/angular/services/work-package-service.js | 7 +++++-- app/helpers/queries_helper.rb | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/angular/services/work-package-service.js b/app/assets/javascripts/angular/services/work-package-service.js index bd0e103ca0..b93e0dda34 100644 --- a/app/assets/javascripts/angular/services/work-package-service.js +++ b/app/assets/javascripts/angular/services/work-package-service.js @@ -1,11 +1,14 @@ angular.module('openproject.services') -.service('WorkPackageService', ['$http', 'PathHelper', 'WorkPackagesHelper', function($http, PathHelper, WorkPackagesHelper) { +.constant('DEFAULT_FILTER_PARAMS', {'fields[]': 'status_id', 'operators[status_id]': 'o'}) + +.service('WorkPackageService', ['$http', 'PathHelper', 'WorkPackagesHelper', 'DEFAULT_FILTER_PARAMS', function($http, PathHelper, WorkPackagesHelper, DEFAULT_FILTER_PARAMS) { var WorkPackageService = { getWorkPackagesByQueryId: function(projectIdentifier, queryId) { var url = projectIdentifier ? PathHelper.apiProjectWorkPackagesPath(projectIdentifier) : PathHelper.apiWorkPackagesPath(); - var params = { query_id: queryId }; + + var params = queryId ? { query_id: queryId } : DEFAULT_FILTER_PARAMS; return WorkPackageService.doQuery(url, params); }, diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb index cb88a5a654..b6f6fa464a 100644 --- a/app/helpers/queries_helper.rb +++ b/app/helpers/queries_helper.rb @@ -98,7 +98,7 @@ module QueriesHelper else if api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) # Give it a name, required to be valid - @query = Query.new({name: "_"}, initialize_with_default_filter: true) + @query = Query.new({name: "_"}) @query.project = @project if params[:fields] || params[:f] add_filter_from_params From 90bd504f1c4d77eea575bb67481412a9edbce1f3 Mon Sep 17 00:00:00 2001 From: Richard Date: Mon, 31 Mar 2014 16:33:38 +0200 Subject: [PATCH 125/155] Task 5437 - Showing 'loading' on initial table load. --- .../angular/controllers/work-packages-controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 65cfd00833..c444cdbe76 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -17,7 +17,10 @@ angular.module('openproject.workPackages.controllers') $scope.loading = false; $scope.disableFilters = false; - WorkPackageService.getWorkPackagesByQueryId($scope.projectIdentifier, $scope.query_id) + // $scope.withLoading(WorkPackageService.getWorkPackagesByQueryId, [$scope.projectIdentifier, $scope.query_id]) + // .then($scope.withLoading($scope.setupWorkPackagesTable)) + // .then($scope.withLoading(initAvailableColumns)) + $scope.withLoading(WorkPackageService.getWorkPackagesByQueryId, [$scope.projectIdentifier, $scope.query_id]) .then($scope.setupWorkPackagesTable) .then(initAvailableColumns); }; From 0a13ba16308385c2de4404350aa203458aaca2f2 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 16:37:43 +0200 Subject: [PATCH 126/155] Remove delay from filter editing when values are selected from drop down --- .../angular/controllers/work-packages-controller.js | 2 +- .../directives/work_packages/query-filter-directive.js | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 334b6c1237..6330b11c5a 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -25,7 +25,7 @@ angular.module('openproject.workPackages.controllers') sums: queryData.sums, filters: queryData.filters, columns: $scope.columns - }); // TODO sortation + }); // TODO init sortation according to queryData sortation = new Sortation(DEFAULT_SORT_CRITERIA); $scope.query.setSortation(sortation); diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index fd2581fe0a..29338b0950 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -29,13 +29,17 @@ angular.module('openproject.workPackages.directives') scope.query.hasChanged(); PaginationService.resetPage(); - applyFiltersWithDelay(); + applyFilters(); } } }, true); - function applyFiltersWithDelay() { - return WorkPackageLoadingHelper.withDelay(800, scope.updateResults); + function applyFilters() { + if (scope.showValueOptionsAsSelect) { + return scope.updateResults(); + } else { + return WorkPackageLoadingHelper.withDelay(800, scope.updateResults); + } } function buildOptions(values) { From 4d69baeb2dd1dfd1e80ac76b6561c411cb349dc1 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 17:11:29 +0200 Subject: [PATCH 127/155] Use a regexp to capture the query id (WIP) TODO add ngRoute --- .../controllers/work-packages-controller.js | 17 +++++++---------- .../angular/helpers/components/path-helper.js | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index b9caf66689..597758ffc2 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -4,26 +4,23 @@ angular.module('openproject.workPackages.controllers') function($scope, $window, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { - function setUrlParams(location){ + function setUrlParams(location) { $scope.projectIdentifier = location.pathname.split('/')[2]; - var q = "query_id=" - if(i = location.search.indexOf(q) > 0) { - $scope.query_id = location.search.slice(i + q.length, i + q.length + 1); - } - }; + + var regexp = /query_id=(\d+)/g; + var match = regexp.exec(location.search); + if(match) $scope.query_id = match[1]; + } function initialSetup() { $scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE; $scope.loading = false; $scope.disableFilters = false; - // $scope.withLoading(WorkPackageService.getWorkPackagesByQueryId, [$scope.projectIdentifier, $scope.query_id]) - // .then($scope.withLoading($scope.setupWorkPackagesTable)) - // .then($scope.withLoading(initAvailableColumns)) $scope.withLoading(WorkPackageService.getWorkPackagesByQueryId, [$scope.projectIdentifier, $scope.query_id]) .then($scope.setupWorkPackagesTable) .then(initAvailableColumns); - }; + } function initQuery(queryData) { $scope.query = new Query({ diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index 2d0f3aba9a..43fa721884 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -19,7 +19,7 @@ angular.module('openproject.helpers') return '/users'; }, userPath: function(id) { - return PathHelper.usersPath() + id; + return PathHelper.usersPath() + '/' + id; }, versionPath: function(versionId) { return '/versions/' + versionId; From b6718dc3d10e7bde4372fa820456aebdd8af768a Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 17:13:35 +0200 Subject: [PATCH 128/155] Discard presence of filters validation --- app/models/query.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/query.rb b/app/models/query.rb index 70dc0d227f..7c7fcd7b17 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -48,7 +48,6 @@ class Query < ActiveRecord::Base validates_length_of :name, :maximum => 255 validate :validate_work_package_filters - validates :filters, presence: true after_initialize :remember_project_scope From 89c437956f7aad95d650b97dc9310cd7f10545d2 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 17:41:31 +0200 Subject: [PATCH 129/155] Reload page also when an invalid filter is deactivated --- .../angular/controllers/work-packages-controller.js | 4 ++-- .../directives/work_packages/query-filter-directive.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 597758ffc2..3c4f7d1bd1 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -100,11 +100,11 @@ angular.module('openproject.workPackages.controllers') function startedLoading() { $scope.loading = true; - }; + } function finishedLoading() { $scope.loading = false; - }; + } setUrlParams($window.location); initialSetup(); diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index 29338b0950..143fb09ce2 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -25,7 +25,7 @@ angular.module('openproject.workPackages.directives') scope.$watch('filter', function(filter, oldFilter) { if (filter !== oldFilter) { - if (filter.isConfigured()) { + if (filter.isConfigured() || filter.deactivated) { scope.query.hasChanged(); PaginationService.resetPage(); From b3f128fccdda5163af8947e2e4e06819b4f5a0ca Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 18:42:48 +0200 Subject: [PATCH 130/155] Move with loading function to helper --- .../controllers/work-packages-controller.js | 29 +++---------------- .../angular/helpers/function-decorators.js | 20 +++++++++++++ .../work_packages/work_packages_loading.html | 4 +-- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index 3c4f7d1bd1..e81fea435e 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,7 +1,7 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', '$window', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', - function($scope, $window, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { +.controller('WorkPackagesController', ['$scope', '$window', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'WorkPackageLoadingHelper', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', + function($scope, $window, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, WorkPackageLoadingHelper, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { function setUrlParams(location) { @@ -78,34 +78,13 @@ angular.module('openproject.workPackages.controllers') function serviceErrorHandler(data) { // TODO RS: This is where we'd want to put an error message on the dom - $scope.loading = false; + $scope.isLoading = false; } - /** - * @name withLoading - * - * @description Wraps a data-loading function and manages the loading state within the scope - * @param {function} callback Function returning a promise - * @param {array} params Params forwarded to the callback - * @returns {promise} Promise returned by the callback - */ $scope.withLoading = function(callback, params){ - startedLoading(); - return callback.apply(this, params) - .then(function(data){ - finishedLoading(); - return data; - }, serviceErrorHandler); + return WorkPackageLoadingHelper.withLoading($scope, callback, params, serviceErrorHandler); }; - function startedLoading() { - $scope.loading = true; - } - - function finishedLoading() { - $scope.loading = false; - } - setUrlParams($window.location); initialSetup(); }]); diff --git a/app/assets/javascripts/angular/helpers/function-decorators.js b/app/assets/javascripts/angular/helpers/function-decorators.js index eb2f00dd70..f0ca2c76d5 100644 --- a/app/assets/javascripts/angular/helpers/function-decorators.js +++ b/app/assets/javascripts/angular/helpers/function-decorators.js @@ -13,6 +13,26 @@ angular.module('openproject.helpers') }, delay); return currentRun; + }, + + /** + * @name withLoading + * + * @description Wraps a data-loading function and manages the loading state within the scope + * @param {scope} a scope on which an isLoading flag is set + * @param {function} callback Function returning a promise + * @param {array} params Params forwarded to the callback + * @returns {promise} Promise returned by the callback + */ + withLoading: function(scope, callback, params, errorCallback) { + scope.isLoading = true; + + return callback.apply(this, params) + .then(function(results){ + scope.isLoading = false; + + return results; + }, errorCallback); } }; }]); diff --git a/public/templates/work_packages/work_packages_loading.html b/public/templates/work_packages/work_packages_loading.html index 5eb3d00b7f..6193242058 100644 --- a/public/templates/work_packages/work_packages_loading.html +++ b/public/templates/work_packages/work_packages_loading.html @@ -1,4 +1,4 @@ -
Loading... -
\ No newline at end of file +
From b5917874114483adb6c9b1ee5b594eea45749814 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Mon, 31 Mar 2014 18:44:34 +0200 Subject: [PATCH 131/155] Disable filter while loading available values --- .../work_packages/query-filter-directive.js | 2 +- .../work-packages-loading-directive.js | 2 +- .../templates/work_packages/query_filters.html | 17 ++++++++--------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js index 143fb09ce2..3b7a786e38 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-filter-directive.js @@ -9,7 +9,7 @@ angular.module('openproject.workPackages.directives') scope.showValueOptionsAsSelect = ['list', 'list_optional', 'list_status', 'list_subprojects', 'list_model'].indexOf(scope.query.getFilterType(scope.filter.name)) !== -1; if (scope.showValueOptionsAsSelect) { - QueryService.getAvailableFilterValues(scope.filter.name, scope.projectIdentifier) + WorkPackageLoadingHelper.withLoading(scope, QueryService.getAvailableFilterValues, [scope.filter.name, scope.projectIdentifier]) .then(buildOptions) .then(addStandardOptions) .then(function(options) { diff --git a/app/assets/javascripts/angular/directives/work_packages/work-packages-loading-directive.js b/app/assets/javascripts/angular/directives/work_packages/work-packages-loading-directive.js index 39bcb65951..cb3974d8a0 100644 --- a/app/assets/javascripts/angular/directives/work_packages/work-packages-loading-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/work-packages-loading-directive.js @@ -9,4 +9,4 @@ angular.module('openproject.workPackages.directives') link: function(scope, element, attributes) { } }; -}]); \ No newline at end of file +}]); diff --git a/public/templates/work_packages/query_filters.html b/public/templates/work_packages/query_filters.html index 3743b4190a..ae53a86ec7 100644 --- a/public/templates/work_packages/query_filters.html +++ b/public/templates/work_packages/query_filters.html @@ -44,7 +44,7 @@ ng-options="operator as label for (operator, label) in operatorsAndLabelsByFilterType[query.getFilterType(filter.name)]" ng-model="filter.operator" style="vertical-align: top;" - ng-disabled="disableFilters"> + ng-disabled="isLoading"> @@ -64,7 +64,7 @@ size="30" type="text" value="" - ng-disabled="disableFilters"/> + ng-disabled="isLoading"/>
From cf12e1f74ba15fd626a785bc433f5079daa7b269 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 1 Apr 2014 11:10:07 +0200 Subject: [PATCH 140/155] Wired up assignee's role and group filters. --- .../angular/config/work-packages-config.js | 18 ++++++++-------- .../angular/helpers/components/path-helper.js | 6 ++++++ .../angular/services/group-service.js | 21 +++++++++++++++++++ .../angular/services/query-service.js | 8 ++++++- .../angular/services/role-service.js | 21 +++++++++++++++++++ config/routes.rb | 5 +++-- 6 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 app/assets/javascripts/angular/services/group-service.js create mode 100644 app/assets/javascripts/angular/services/role-service.js diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js index 9cab8864d4..7efc248a1a 100644 --- a/app/assets/javascripts/angular/config/work-packages-config.js +++ b/app/assets/javascripts/angular/config/work-packages-config.js @@ -23,15 +23,15 @@ angular.module('openproject.workPackages.config') author_id: { type: 'list_model', modelName: 'user' , order: 5, name: 'Author' }, responsible_id: {type: 'list_model', modelName: 'user', order: 6, name: 'Watcher'}, fixed_version_id: {type: 'list_model', modelName: 'version', order: 7, name: 'Version'}, - // member_of_group: {type: 'list_optional','order':6,'values':[['Gruppe 00001','138'],['Gruppe 00002','139'],['Gruppe 00003','140'],['Gruppe 00004','141'],['Gruppe 00005','142']],name: 'Assignee's group'}, - // assigned_to_role: {type: 'list_optional','order':7,'values':[['Project Admin','3'],['Release Manager','19'],['Project Member','4'],['Stakeholder','5'],['Controller Client','6'],['Controller','8'],['Developer','9'],['Tester','10'],['Reader','11'],['Timeline Reader','20']],name: 'Assignee's role'}, - subject: { type: 'text', 'order':8, name: 'Subject' }, - created_at: { type: 'date_past', 'order':9, name: 'Created on' }, - updated_at: { type: 'date_past', 'order':10, name: 'Updated on' }, - start_date: { type: 'date', 'order': 11, name: 'Start date' }, - due_date: { type: 'date', 'order': 12, name: 'Due date' }, - estimated_hours: { type: 'integer', 'order': 13, name: 'Estimated time' }, - done_ratio: { type: 'integer', 'order': 14, name: '% done' }, + member_of_group: {type: 'list_model', modelName: 'group', order: 8, name: 'Assignee\'s group'}, + assigned_to_role: {type: 'list_model', modelName: 'role', order: 9, name: 'Assignee\'s role'}, + subject: { type: 'text', order: 10, name: 'Subject' }, + created_at: { type: 'date_past', order: 11, name: 'Created on' }, + updated_at: { type: 'date_past', order: 12, name: 'Updated on' }, + start_date: { type: 'date', order: 13, name: 'Start date' }, + due_date: { type: 'date', order: 14, name: 'Due date' }, + estimated_hours: { type: 'integer', order: 15, name: 'Estimated time' }, + done_ratio: { type: 'integer', order: 16, name: '% done' }, }) .constant('DEFAULT_SORT_CRITERIA', 'parent:desc') diff --git a/app/assets/javascripts/angular/helpers/components/path-helper.js b/app/assets/javascripts/angular/helpers/components/path-helper.js index f64e0eac8f..ec906346ce 100644 --- a/app/assets/javascripts/angular/helpers/components/path-helper.js +++ b/app/assets/javascripts/angular/helpers/components/path-helper.js @@ -58,6 +58,12 @@ angular.module('openproject.helpers') apiProjectStatusesPath: function(projectIdentifier) { return PathHelper.apiV2ProjectPath(projectIdentifier) + '/statuses'; }, + apiGroupsPath: function() { + return PathHelper.apiPrefixV3 + '/groups'; + }, + apiRolesPath: function() { + return PathHelper.apiPrefixV3 + '/roles'; + }, apiWorkPackageTypesPath: function() { return PathHelper.apiPrefixV2 + '/planning_element_types'; }, diff --git a/app/assets/javascripts/angular/services/group-service.js b/app/assets/javascripts/angular/services/group-service.js new file mode 100644 index 0000000000..816f77f8a6 --- /dev/null +++ b/app/assets/javascripts/angular/services/group-service.js @@ -0,0 +1,21 @@ +angular.module('openproject.services') + +.service('GroupService', ['$http', 'PathHelper', function($http, PathHelper) { + + var GroupService = { + getGroups: function() { + var url = PathHelper.apiGroupsPath(); + + return GroupService.doQuery(url); + }, + + doQuery: function(url, params) { + return $http.get(url, { params: params }) + .then(function(response){ + return response.data.groups; + }); + } + }; + + return GroupService; +}]); diff --git a/app/assets/javascripts/angular/services/query-service.js b/app/assets/javascripts/angular/services/query-service.js index 606fb72cde..9a5a89628e 100644 --- a/app/assets/javascripts/angular/services/query-service.js +++ b/app/assets/javascripts/angular/services/query-service.js @@ -1,6 +1,6 @@ angular.module('openproject.services') -.service('QueryService', ['$http', 'PathHelper', '$q', 'AVAILABLE_WORK_PACKAGE_FILTERS', 'StatusService', 'TypeService', 'PriorityService', 'UserService', 'VersionService', function($http, PathHelper, $q, AVAILABLE_WORK_PACKAGE_FILTERS, StatusService, TypeService, PriorityService, UserService, VersionService) { +.service('QueryService', ['$http', 'PathHelper', '$q', 'AVAILABLE_WORK_PACKAGE_FILTERS', 'StatusService', 'TypeService', 'PriorityService', 'UserService', 'VersionService', 'RoleService', 'GroupService', function($http, PathHelper, $q, AVAILABLE_WORK_PACKAGE_FILTERS, StatusService, TypeService, PriorityService, UserService, VersionService, RoleService, GroupService) { var availableColumns = [], availableFilterValues = {}; @@ -35,6 +35,12 @@ angular.module('openproject.services') case 'version': retrieveAvailableValues = VersionService.getProjectVersions(projectIdentifier); break; + case 'role': + retrieveAvailableValues = RoleService.getRoles(); + break; + case 'group': + retrieveAvailableValues = GroupService.getGroups(); + break; } return retrieveAvailableValues.then(function(values) { diff --git a/app/assets/javascripts/angular/services/role-service.js b/app/assets/javascripts/angular/services/role-service.js new file mode 100644 index 0000000000..c3e5f5c5b6 --- /dev/null +++ b/app/assets/javascripts/angular/services/role-service.js @@ -0,0 +1,21 @@ +angular.module('openproject.services') + +.service('RoleService', ['$http', 'PathHelper', function($http, PathHelper) { + + var RoleService = { + getRoles: function() { + var url = PathHelper.apiRolesPath(); + + return RoleService.doQuery(url); + }, + + doQuery: function(url, params) { + return $http.get(url, { params: params }) + .then(function(response){ + return response.data.roles; + }); + } + }; + + return RoleService; +}]); diff --git a/config/routes.rb b/config/routes.rb index 3d349a4fee..94567b3233 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -133,9 +133,10 @@ OpenProject::Application.routes.draw do get :available_columns, on: :collection end resources :versions, only: [:index] - resources :groups, only: [:index] - resources :roles, only: [:index] end + + resources :groups, only: [:index] + resources :roles, only: [:index] end end From d33c8280c7db69592e5719c721e4e26ec3c757fa Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Tue, 1 Apr 2014 11:36:01 +0200 Subject: [PATCH 141/155] Apply a lost fix for custom field column sums --- app/controllers/api/v3/work_packages_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index 0876ad06fe..a03b5bcbe4 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -58,6 +58,7 @@ module Api end end + private def load_query @@ -131,7 +132,8 @@ module Api if column_name =~ /cf_(.*)/ custom_field = CustomField.find($1) work_packages.map do |work_package| - work_package.get_custom_value_display_data(custom_field) + custom_value = work_package.custom_values.find_by_custom_field_id($1) + custom_field.cast_value custom_value.try(:value) end else work_packages.map do |work_package| From 099e99e880b3e7c8cbab77be17ea06837b78f907 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Tue, 1 Apr 2014 11:54:10 +0200 Subject: [PATCH 142/155] Minor code change --- app/controllers/api/v3/work_packages_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index a03b5bcbe4..b13d4fb311 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -27,7 +27,7 @@ module Api def index @custom_field_column_names = @query.columns.select{|c| c.name.to_s =~ /cf_(.*)/}.map(&:name) - @column_names = ['id'] | @query.columns.select{|c| !@custom_field_column_names.include?(c.name)}.map(&:name) + @column_names = ['id'] | @query.columns.map(&:name) - @custom_field_column_names # the data for the index is already produced in the assign_work_packages respond_to do |format| From a62b32ccb4fe9d129d5d99cec99196529357e20e Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 1 Apr 2014 13:23:56 +0200 Subject: [PATCH 143/155] WIP - custom fields mainly displaying but needs to be reworked. --- .../angular/helpers/components/work-packages-helper.js | 2 +- app/controllers/api/v3/work_packages_controller.rb | 3 ++- app/models/work_package.rb | 10 +++++----- app/views/api/v3/work_packages/index.api.rabl | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/angular/helpers/components/work-packages-helper.js b/app/assets/javascripts/angular/helpers/components/work-packages-helper.js index 8def092a7c..6055bada9f 100644 --- a/app/assets/javascripts/angular/helpers/components/work-packages-helper.js +++ b/app/assets/javascripts/angular/helpers/components/work-packages-helper.js @@ -30,7 +30,7 @@ angular.module('openproject.workPackages.helpers') if (!object.custom_values) return null; var customValue = object.custom_values.filter(function(customValue){ - return customValue.custom_field_id === customField.id; + return customValue && customValue.custom_field_id === customField.id; }).first(); if(customValue) { diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index b13d4fb311..c67bca4596 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -133,7 +133,8 @@ module Api custom_field = CustomField.find($1) work_packages.map do |work_package| custom_value = work_package.custom_values.find_by_custom_field_id($1) - custom_field.cast_value custom_value.try(:value) + # custom_field.cast_value custom_value.try(:value) + work_package.custom_value_display(custom_value) end else work_packages.map do |work_package| diff --git a/app/models/work_package.rb b/app/models/work_package.rb index cba38d8b79..ac74f959ec 100644 --- a/app/models/work_package.rb +++ b/app/models/work_package.rb @@ -719,16 +719,16 @@ class WorkPackage < ActiveRecord::Base # TODO RS: This probably isn't the right place for display helpers. It's convenient though to have # the method on the model so that it can be used in the rabl template. def get_custom_value_display_data(custom_field) - display_custom_value(custom_values.find_by_custom_field_id(custom_field.id)) + custom_value_display(custom_values.find_by_custom_field_id(custom_field.id)) end - def custom_values_display_data - custom_values.map do |custom_value| - display_custom_value(custom_value) + def custom_values_display_data(field_names) + field_names.map do |field_name| + custom_value_display(custom_values.find_by_custom_field_id(field_name.to_s.gsub('cf_',''))) end end - def display_custom_value(custom_value) + def custom_value_display(custom_value) if !custom_value.nil? { custom_field_id: custom_value.custom_field.id, diff --git a/app/views/api/v3/work_packages/index.api.rabl b/app/views/api/v3/work_packages/index.api.rabl index 544c0f0256..e4e184c5ee 100644 --- a/app/views/api/v3/work_packages/index.api.rabl +++ b/app/views/api/v3/work_packages/index.api.rabl @@ -53,7 +53,7 @@ child @work_packages => :work_packages do end node(:custom_values) do |wp| - wp.custom_values_display_data + wp.custom_values_display_data @custom_field_column_names end end From e3d3ef4a6f10e4ad8331fbdf11bf0062b732f799 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Tue, 1 Apr 2014 13:28:29 +0200 Subject: [PATCH 144/155] Add lost code for custom value user name retrieval --- .../work-package-column-directive.js | 16 ++++++++++++++++ .../angular/services/work-package-service.js | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/angular/directives/work_packages/work-package-column-directive.js b/app/assets/javascripts/angular/directives/work_packages/work-package-column-directive.js index 935ecc7570..c9cfa5b7e0 100644 --- a/app/assets/javascripts/angular/directives/work_packages/work-package-column-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/work-package-column-directive.js @@ -23,6 +23,8 @@ angular.module('openproject.workPackages.directives') var custom_field = scope.column.custom_field; scope.displayText = WorkPackagesHelper.getFormattedCustomValue(scope.workPackage, custom_field) || ''; + + if (scope.column.meta_data.data_type === 'user') loadUserName(); } else { // custom display types if (scope.column.name === 'done_ratio') scope.displayType = 'progress_bar'; @@ -38,6 +40,20 @@ angular.module('openproject.workPackages.directives') } } + function loadUserName() { + var userId = scope.displayText; + + if(userId) { + scope.user = UserService.registerUserId(userId); + + scope.$watch('user.name', function(userName) { + // triggered when user data is loaded + // TODO replace watcher as soon as data is loaded via a promise chain + scope.displayText = userName; + }); + } + } + function getLinkFor(link_meta){ if (link_meta.model_type === 'work_package') { return PathHelper.workPackagePath(scope.workPackage.id); diff --git a/app/assets/javascripts/angular/services/work-package-service.js b/app/assets/javascripts/angular/services/work-package-service.js index b93e0dda34..d4be52f996 100644 --- a/app/assets/javascripts/angular/services/work-package-service.js +++ b/app/assets/javascripts/angular/services/work-package-service.js @@ -52,7 +52,7 @@ angular.module('openproject.services') }, augmentWorkPackagesWithColumnsData: function(workPackages, columns) { - var columnNames = columns.map(function(column){ + var columnNames = columns.map(function(column) { return column.name; }); From a5a8b3162d92496882d2930b1fddf03dfc9a671a Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 1 Apr 2014 14:06:40 +0200 Subject: [PATCH 145/155] Put old work package loading code into separate method. --- .../api/v3/work_packages_controller.rb | 11 +++--- app/controllers/work_packages_controller.rb | 35 ++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index c67bca4596..b9c6d1166f 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -54,7 +54,7 @@ module Api work_packages = project.work_packages @column_sums = column_names.map do |column_name| - fetch_column_data(column_name, work_packages).map{|c| c.nil? ? 0 : c}.compact.sum if column_should_be_summed_up?(column_name) + fetch_column_data(column_name, work_packages, false).map{|c| c.nil? ? 0 : c}.compact.sum if column_should_be_summed_up?(column_name) end end @@ -128,13 +128,16 @@ module Api end end - def fetch_column_data(column_name, work_packages) + def fetch_column_data(column_name, work_packages, display = true) if column_name =~ /cf_(.*)/ custom_field = CustomField.find($1) work_packages.map do |work_package| custom_value = work_package.custom_values.find_by_custom_field_id($1) - # custom_field.cast_value custom_value.try(:value) - work_package.custom_value_display(custom_value) + if display + work_package.custom_value_display(custom_value) + else + custom_field.cast_value custom_value.try(:value) + end end else work_packages.map do |work_package| diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index b423411828..ef8f16447d 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -209,18 +209,6 @@ class WorkPackagesController < ApplicationController end def index - sort_init(@query.sort_criteria.empty? ? [DEFAULT_SORT_ORDER] : @query.sort_criteria) - sort_update(@query.sortable_columns) - results = @query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version], - :order => sort_clause) - work_packages = if @query.valid? - results.work_packages.page(page_param) - .per_page(per_page_param) - .all - else - [] - end - respond_to do |format| format.html do render :index, :locals => { :query => @query, @@ -228,17 +216,19 @@ class WorkPackagesController < ApplicationController :layout => !request.xhr? end format.csv do - serialized_work_packages = WorkPackage::Exporter.csv(work_packages, @project) + load_work_packages + serialized_work_packages = WorkPackage::Exporter.csv(@work_packages, @project) charset = "charset=#{l(:general_csv_encoding).downcase}" send_data(serialized_work_packages, :type => "text/csv; #{charset}; header=present", :filename => 'export.csv') end format.pdf do - serialized_work_packages = WorkPackage::Exporter.pdf(work_packages, + load_work_packages + serialized_work_packages = WorkPackage::Exporter.pdf(@work_packages, @project, @query, - results, + @results, :show_descriptions => params[:show_descriptions]) send_data(serialized_work_packages, @@ -246,7 +236,8 @@ class WorkPackagesController < ApplicationController :filename => 'export.pdf') end format.atom do - render_feed(work_packages, + load_work_packages + render_feed(@work_packages, :title => "#{@project || Setting.app_title}: #{l(:label_work_package_plural)}") end end @@ -452,4 +443,16 @@ class WorkPackagesController < ApplicationController private + def load_work_packages + @results = @query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version], + :order => sort_clause) + @work_packages = if @query.valid? + results.work_packages.page(page_param) + .per_page(per_page_param) + .all + else + [] + end + end + end From d8d3aeb3974a9ff4d5808870fcc4c9f0a3d97b12 Mon Sep 17 00:00:00 2001 From: Alex Coles Date: Tue, 1 Apr 2014 14:39:59 +0200 Subject: [PATCH 146/155] Fix Mocha tests for work package filter changes Signed-off-by: Alex Coles --- app/assets/javascripts/angular/openproject-app.js | 2 +- mocha/index.html | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/angular/openproject-app.js b/app/assets/javascripts/angular/openproject-app.js index 40a9ffd646..27d6b8873e 100644 --- a/app/assets/javascripts/angular/openproject-app.js +++ b/app/assets/javascripts/angular/openproject-app.js @@ -1,7 +1,7 @@ // global angular.module('openproject.services', ['openproject.uiComponents', 'openproject.helpers', 'openproject.workPackages.config']); angular.module('openproject.helpers', ['openproject.services']); -angular.module('openproject.models', []); +angular.module('openproject.models', ['openproject.workPackages.config']); // timelines angular.module('openproject.timelines', ['openproject.timelines.controllers', 'openproject.timelines.directives', 'openproject.uiComponents']); diff --git a/mocha/index.html b/mocha/index.html index 0ffde6ef9e..6282846f61 100644 --- a/mocha/index.html +++ b/mocha/index.html @@ -31,6 +31,8 @@ + + From b5c740bdbb29f8eabfb023b8fad900a67594b2d1 Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 1 Apr 2014 14:46:03 +0200 Subject: [PATCH 147/155] Sums data is now a property on the column object. Columns can now be rearranged and the sums will match up properly. --- .../angular/controllers/work-packages-controller.js | 8 ++++---- .../work_packages/work-package-total-sums-directive.js | 4 +++- public/templates/work_packages/work_packages_table.html | 8 ++++---- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index deb66e93fd..34b0f09db9 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -55,8 +55,6 @@ angular.module('openproject.workPackages.controllers') }; $scope.setupWorkPackagesTable = function(json) { - // TODO: We need to set the columns based on what's returned by the query for when we are loading using a query id. - // Also perhaps the filters... and everything:/ var meta = json.meta; if (!$scope.columns) $scope.columns = meta.columns; @@ -68,9 +66,11 @@ angular.module('openproject.workPackages.controllers') $scope.rows = WorkPackagesTableHelper.getRows(json.work_packages, $scope.query.group_by); $scope.workPackageCountByGroup = meta.work_package_count_by_group; - $scope.totalSums = meta.sums; - $scope.groupSums = meta.group_sums; $scope.totalEntries = meta.total_entries; + angular.forEach($scope.columns, function(column, i){ + column.total_sum = meta.sums[i]; + if (meta.group_sums) column.group_sums = meta.group_sums[i]; + }); }; $scope.updateResults = function() { diff --git a/app/assets/javascripts/angular/directives/work_packages/work-package-total-sums-directive.js b/app/assets/javascripts/angular/directives/work_packages/work-package-total-sums-directive.js index 719168ace8..da3a198e05 100644 --- a/app/assets/javascripts/angular/directives/work_packages/work-package-total-sums-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/work-package-total-sums-directive.js @@ -11,7 +11,9 @@ angular.module('openproject.workPackages.directives') function fetchSums() { scope.withLoading(WorkPackageService.getWorkPackagesSums, [scope.projectIdentifier, scope.columns]) .then(function(data){ - scope.sums = data.column_sums; + angular.forEach(scope.columns, function(column, i){ + column.total_sum = data.column_sums[i]; + }); }); } diff --git a/public/templates/work_packages/work_packages_table.html b/public/templates/work_packages/work_packages_table.html index 2b9c8fb6db..5527448f5f 100644 --- a/public/templates/work_packages/work_packages_table.html +++ b/public/templates/work_packages/work_packages_table.html @@ -134,8 +134,8 @@ {{ I18n.t('js.label_sum_for') }} - @@ -145,8 +145,8 @@ ng-if="displaySums" class="sum group all issue work_package"> - From 5fbd5745ade96663b76df781744d5e70b7f0f8ec Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 1 Apr 2014 16:12:57 +0200 Subject: [PATCH 148/155] Extended column_data api method with group sums meta. Updated the angular work package service to extend the column objects with all the sums. --- .../work_packages/query-columns-directive.js | 4 ++- .../angular/services/work-package-service.js | 20 ++++++++----- .../api/v3/work_packages_controller.rb | 30 +++++++++++++++++-- .../api/v3/work_packages/column_data.api.rabl | 4 ++- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/angular/directives/work_packages/query-columns-directive.js b/app/assets/javascripts/angular/directives/work_packages/query-columns-directive.js index 432f6d3df4..bb3723451b 100644 --- a/app/assets/javascripts/angular/directives/work_packages/query-columns-directive.js +++ b/app/assets/javascripts/angular/directives/work_packages/query-columns-directive.js @@ -31,7 +31,9 @@ angular.module('openproject.workPackages.directives') var newColumns = WorkPackagesTableHelper.selectColumnsByName(scope.columns, columnNames); // work package rows - scope.withLoading(WorkPackageService.augmentWorkPackagesWithColumnsData, [workPackages, newColumns]); + var params = [workPackages, newColumns]; + if( scope.groupByColumn) params.push(scope.groupByColumn.name); + scope.withLoading(WorkPackageService.augmentWorkPackagesWithColumnsData, params); } function removeColumn(columnName, columns, callback) { diff --git a/app/assets/javascripts/angular/services/work-package-service.js b/app/assets/javascripts/angular/services/work-package-service.js index d4be52f996..ad21262aac 100644 --- a/app/assets/javascripts/angular/services/work-package-service.js +++ b/app/assets/javascripts/angular/services/work-package-service.js @@ -23,14 +23,15 @@ angular.module('openproject.services') return WorkPackageService.doQuery(url, params); }, - loadWorkPackageColumnsData: function(workPackages, columnNames) { + loadWorkPackageColumnsData: function(workPackages, columnNames, group_by) { var url = PathHelper.apiWorkPackagesColumnDataPath(); var params = { 'ids[]': workPackages.map(function(workPackage){ return workPackage.id; }), - 'column_names[]': columnNames + 'column_names[]': columnNames, + 'group_by': group_by }; return WorkPackageService.doQuery(url, params); @@ -51,17 +52,22 @@ angular.module('openproject.services') return WorkPackageService.doQuery(url, params); }, - augmentWorkPackagesWithColumnsData: function(workPackages, columns) { + augmentWorkPackagesWithColumnsData: function(workPackages, columns, group_by) { var columnNames = columns.map(function(column) { return column.name; }); - return WorkPackageService.loadWorkPackageColumnsData(workPackages, columnNames) + return WorkPackageService.loadWorkPackageColumnsData(workPackages, columnNames, group_by) .then(function(data){ var columnsData = data.columns_data; - angular.forEach(workPackages, function(workPackage, i) { - angular.forEach(columns, function(column, j){ - WorkPackagesHelper.augmentWorkPackageWithData(workPackage, column.name, !!column.custom_field, columnsData[j][i]); + var columnsMeta = data.columns_meta; + + angular.forEach(columns, function(column, i){ + column.total_sum = columnsMeta.total_sums[i]; + if (columnsMeta.group_sums) column.group_sums = columnsMeta.group_sums[i]; + + angular.forEach(workPackages, function(workPackage, j) { + WorkPackagesHelper.augmentWorkPackageWithData(workPackage, column.name, !!column.custom_field, columnsData[i][j]); }); }); diff --git a/app/controllers/api/v3/work_packages_controller.rb b/app/controllers/api/v3/work_packages_controller.rb index b9c6d1166f..7369e06659 100644 --- a/app/controllers/api/v3/work_packages_controller.rb +++ b/app/controllers/api/v3/work_packages_controller.rb @@ -44,6 +44,10 @@ module Api work_packages = Array.wrap(WorkPackage.visible.find(*ids)).sort {|a,b| ids.index(a.id) <=> ids.index(b.id)} @columns_data = fetch_columns_data(column_names, work_packages) + @columns_meta = { + total_sums: columns_total_sums(column_names, work_packages), + group_sums: columns_group_sums(column_names, work_packages, params[:group_by]) + } end def column_sums @@ -53,13 +57,33 @@ module Api project = Project.find_visible(current_user, params[:project_id]) work_packages = project.work_packages - @column_sums = column_names.map do |column_name| - fetch_column_data(column_name, work_packages, false).map{|c| c.nil? ? 0 : c}.compact.sum if column_should_be_summed_up?(column_name) + @column_sums = columns_total_sums(column_names, work_packages) + end + + private + + def columns_total_sums(column_names, work_packages) + column_names.map do |column_name| + column_sum(column_name, work_packages) end end + def column_sum(column_name, work_packages) + fetch_column_data(column_name, work_packages, false).map{|c| c.nil? ? 0 : c}.compact.sum if column_should_be_summed_up?(column_name) + end - private + def columns_group_sums(column_names, work_packages, group_by) + # NOTE RS: This is basically the grouped_sums method from sums.rb but we have no query to play with here + return unless group_by + column_names.map do |column_name| + work_packages.map { |wp| wp.send(group_by) } + .uniq + .inject({}) do |group_sums, current_group| + work_packages_in_current_group = work_packages.select{|wp| wp.send(group_by) == current_group} + group_sums.merge current_group => column_sum(column_name, work_packages_in_current_group) + end + end + end def load_query @query ||= retrieve_query diff --git a/app/views/api/v3/work_packages/column_data.api.rabl b/app/views/api/v3/work_packages/column_data.api.rabl index 34ef0fa860..78aac41f1b 100644 --- a/app/views/api/v3/work_packages/column_data.api.rabl +++ b/app/views/api/v3/work_packages/column_data.api.rabl @@ -28,4 +28,6 @@ object false -node(:columns_data) { @columns_data } \ No newline at end of file +node(:columns_data) { @columns_data } + +node(:columns_meta) { @columns_meta } \ No newline at end of file From e7c8c951a2addef2edd650072242db79b32050aa Mon Sep 17 00:00:00 2001 From: Richard Date: Tue, 1 Apr 2014 17:00:02 +0200 Subject: [PATCH 149/155] Removed yellow pristine angular validation styling. --- app/assets/stylesheets/work_packages.css | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/work_packages.css b/app/assets/stylesheets/work_packages.css index ebf7ecb6d3..5c297e74e6 100644 --- a/app/assets/stylesheets/work_packages.css +++ b/app/assets/stylesheets/work_packages.css @@ -39,7 +39,6 @@ See doc/COPYRIGHT.rdoc for more details. cursor: pointer; } -select.to-validate.ng-pristine, input.to-validate.ng-pristine { border:1px solid Gold; } select.to-validate.ng-dirty.ng-valid, input.to-validate.ng-dirty.ng-valid { border:1px solid Green; } select.to-validate.ng-dirty.ng-invalid, input.to-validate.ng-dirty.ng-invalid { border:1px solid Red; } select.to-validate.ng-dirty.ng-valid ~ span.ok, input.to-validate.ng-dirty.ng-valid ~ span.ok { color:green; display:inline; } From 4e1a79524b20656e4b3d3635a7cb856294cfa4d1 Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 2 Apr 2014 09:38:08 +0200 Subject: [PATCH 150/155] Sort headers have cursor pointer. --- app/assets/stylesheets/work_packages.css | 6 +++++- public/templates/work_packages/sort_header.html | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/work_packages.css b/app/assets/stylesheets/work_packages.css index 5c297e74e6..fa497d7b8c 100644 --- a/app/assets/stylesheets/work_packages.css +++ b/app/assets/stylesheets/work_packages.css @@ -39,7 +39,11 @@ See doc/COPYRIGHT.rdoc for more details. cursor: pointer; } +.sort-header { + cursor: pointer; +} + select.to-validate.ng-dirty.ng-valid, input.to-validate.ng-dirty.ng-valid { border:1px solid Green; } select.to-validate.ng-dirty.ng-invalid, input.to-validate.ng-dirty.ng-invalid { border:1px solid Red; } select.to-validate.ng-dirty.ng-valid ~ span.ok, input.to-validate.ng-dirty.ng-valid ~ span.ok { color:green; display:inline; } -select.to-validate.ng-dirty.ng-invalid ~ span.ko, input.to-validate.ng-dirty.ng-invalid ~ span.ko { color:red; display:inline; } +select.to-validate.ng-dirty.ng-invalid ~ span.ko, input.to-validate.ng-dirty.ng-invalid ~ span.ko { color:red; display:inline; } \ No newline at end of file diff --git a/public/templates/work_packages/sort_header.html b/public/templates/work_packages/sort_header.html index f1c6c50bfb..c1713d3507 100644 --- a/public/templates/work_packages/sort_header.html +++ b/public/templates/work_packages/sort_header.html @@ -1,4 +1,4 @@ - + Date: Wed, 2 Apr 2014 10:53:14 +0200 Subject: [PATCH 151/155] Init ng query sortation from API meta data --- .../controllers/work-packages-controller.js | 7 ++--- .../javascripts/angular/models/sortation.js | 30 +++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/angular/controllers/work-packages-controller.js b/app/assets/javascripts/angular/controllers/work-packages-controller.js index deb66e93fd..c24f4aa39a 100644 --- a/app/assets/javascripts/angular/controllers/work-packages-controller.js +++ b/app/assets/javascripts/angular/controllers/work-packages-controller.js @@ -1,7 +1,7 @@ angular.module('openproject.workPackages.controllers') -.controller('WorkPackagesController', ['$scope', '$window', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'WorkPackageLoadingHelper', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', 'DEFAULT_SORT_CRITERIA', - function($scope, $window, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, WorkPackageLoadingHelper, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE, DEFAULT_SORT_CRITERIA) { +.controller('WorkPackagesController', ['$scope', '$window', 'WorkPackagesTableHelper', 'Query', 'Sortation', 'WorkPackageService', 'QueryService', 'PaginationService', 'WorkPackageLoadingHelper', 'INITIALLY_SELECTED_COLUMNS', 'OPERATORS_AND_LABELS_BY_FILTER_TYPE', + function($scope, $window, WorkPackagesTableHelper, Query, Sortation, WorkPackageService, QueryService, PaginationService, WorkPackageLoadingHelper, INITIALLY_SELECTED_COLUMNS, OPERATORS_AND_LABELS_BY_FILTER_TYPE) { function setUrlParams(location) { @@ -32,8 +32,7 @@ angular.module('openproject.workPackages.controllers') columns: $scope.columns }); // TODO init sortation according to queryData - sortation = new Sortation(DEFAULT_SORT_CRITERIA); - $scope.query.setSortation(sortation); + $scope.query.setSortation(new Sortation(queryData.sort_criteria)); $scope.showFilters = $scope.query.filters.length > 0; diff --git a/app/assets/javascripts/angular/models/sortation.js b/app/assets/javascripts/angular/models/sortation.js index b400e23559..2ae7502b5c 100644 --- a/app/assets/javascripts/angular/models/sortation.js +++ b/app/assets/javascripts/angular/models/sortation.js @@ -1,16 +1,21 @@ angular.module('openproject.models') -.factory('Sortation', [function() { +.factory('Sortation', ['DEFAULT_SORT_CRITERIA', function(DEFAULT_SORT_CRITERIA) { var defaultSortDirection = 'asc'; - var Sortation = function(encodedSortation) { - if (encodedSortation) { - this.sortElements = encodedSortation.split(',').map(function(sortParam) { - fieldAndDirection = sortParam.split(':'); - return { field: fieldAndDirection[0], direction: fieldAndDirection[1] || defaultSortDirection}; - }); + var Sortation = function(sortation) { + if (Array.isArray(sortation)) { + if (sortation.length > 0) { + // Convert sortation element from API meta format + this.sortElements = sortation.map(function(sortElement) { + return {field: sortElement.first(), direction: sortElement.last()}; + }); + } else { + this.sortElements = this.decodeEncodedSortation(DEFAULT_SORT_CRITERIA); + } } else { - this.sortElements = []; + // Unless it's an array we expect the sortation to be in a serialized form + this.sortElements = this.decodeEncodedSortation(sortation || DEFAULT_SORT_CRITERIA); } }; @@ -59,6 +64,13 @@ angular.module('openproject.models') return targetSortation; }; + Sortation.prototype.decodeEncodedSortation = function(encodedSortation) { + return encodedSortation.split(',').map(function(sortParam) { + fieldAndDirection = sortParam.split(':'); + return { field: fieldAndDirection[0], direction: fieldAndDirection[1] || defaultSortDirection}; + }); + }; + Sortation.prototype.encode = function() { return this.sortElements.map(function(sortation){ if (sortation.direction === 'asc') { @@ -70,4 +82,4 @@ angular.module('openproject.models') }; return Sortation; -}]); \ No newline at end of file +}]); From 17ed76e663042210b2214a616c4d65dfd238d9f7 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Wed, 2 Apr 2014 12:22:05 +0200 Subject: [PATCH 152/155] Fix export formats of work_packages#index --- app/controllers/work_packages_controller.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index ef8f16447d..bc9846c6aa 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -444,12 +444,15 @@ class WorkPackagesController < ApplicationController private def load_work_packages + sort_init(@query.sort_criteria.empty? ? [DEFAULT_SORT_ORDER] : @query.sort_criteria) + sort_update(@query.sortable_columns) + @results = @query.results(:include => [:assigned_to, :type, :priority, :category, :fixed_version], :order => sort_clause) @work_packages = if @query.valid? - results.work_packages.page(page_param) - .per_page(per_page_param) - .all + @results.work_packages.page(page_param) + .per_page(per_page_param) + .all else [] end From 39eb8fa6b25404078453294aaf50cddebd51c243 Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Wed, 2 Apr 2014 13:19:52 +0200 Subject: [PATCH 153/155] Update query rspec test after specification change --- spec/models/query_spec.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/models/query_spec.rb b/spec/models/query_spec.rb index 941126e2ce..e29378e5cd 100644 --- a/spec/models/query_spec.rb +++ b/spec/models/query_spec.rb @@ -57,7 +57,7 @@ describe Query do expect(query.errors[:name].first).to include(I18n.t('activerecord.errors.messages.blank')) end - context 'with a missing value' do + context 'with a missing value and an operator that requires values' do before do query.add_filter('due_date', 't-', ['']) end @@ -72,9 +72,8 @@ describe Query do let(:status) { FactoryGirl.create :status } let(:query) { FactoryGirl.build(:query).tap {|q| q.filters = []} } - it 'is not valid and creates an error' do - expect(query.valid?).to be_false - expect(query.errors[:filters]).to include(I18n.t('activerecord.errors.messages.blank')) + it 'is valid' do + expect(query.valid?).to be_true end end From 1cc902f62ef25ba525dc465065d0aea773a7a203 Mon Sep 17 00:00:00 2001 From: Alex Coles Date: Wed, 2 Apr 2014 13:47:08 +0200 Subject: [PATCH 154/155] Commit updated Gemfile.lock Signed-off-by: Alex Coles --- Gemfile.lock | 56 ---------------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ab0bbd6b06..69185d94fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -20,33 +20,9 @@ GIT specs: prototype_legacy_helper (0.0.0) -PATH - remote: ../openproject-plugins - specs: - openproject-plugins (1.0.6) - rails (~> 3.2.9) - -PATH - remote: /home/richard/projects/finnlabs/openproject-backlogs - specs: - openproject-backlogs (3.0.5.pre3) - acts_as_silent_list - openproject-pdf_export - openproject-plugins - rails (~> 3.2.9) - -PATH - remote: /home/richard/projects/finnlabs/openproject-pdf_export - specs: - openproject-pdf_export (0.0.1) - openproject-plugins (~> 1.0.5) - prawn (~> 0.14.0) - rails (~> 3.2.14) - GEM remote: https://rubygems.org/ specs: - Ascii85 (1.0.2) actionmailer (3.2.17) actionpack (= 3.2.17) mail (~> 2.5.4) @@ -78,15 +54,10 @@ GEM multi_json (~> 1.0) acts_as_list (0.2.0) activerecord (>= 3.0) - acts_as_silent_list (1.2.0) addressable (2.3.4) - afm (0.2.0) arel (3.0.3) awesome_nested_set (2.1.6) activerecord (>= 3.0.0) - better_errors (1.1.0) - coderay (>= 1.0.0) - erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) bourne (1.4.0) @@ -187,7 +158,6 @@ GEM guard-test (1.0.0) guard (>= 1.8) test-unit (~> 2.2) - hashery (2.1.1) hike (1.2.3) htmldiff (0.0.1) i18n (0.6.5) @@ -225,20 +195,8 @@ GEM paper_trail (2.7.2) activerecord (~> 3.0) railties (~> 3.0) - pdf-inspector (1.1.0) - pdf-reader (~> 1.0) - pdf-reader (1.3.3) - Ascii85 (~> 1.0.0) - afm (~> 0.2.0) - hashery (~> 2.0) - ruby-rc4 - ttfunk pg (0.17.1) polyglot (0.3.3) - prawn (0.14.0) - pdf-reader (~> 1.2) - ruby-rc4 - ttfunk (~> 1.0.3) prototype-rails (3.2.1) rails (~> 3.2) pry (0.9.12.2) @@ -262,8 +220,6 @@ GEM pry-stack_explorer (0.4.9.1) binding_of_caller (>= 0.7) pry (>= 0.9.11) - quiet_assets (1.0.2) - railties (>= 3.1, < 5.0) rabl (0.9.3) activesupport (>= 2.3.14) rack (1.4.5) @@ -324,7 +280,6 @@ GEM ruby-openid (2.2.3) ruby-prof (0.13.0) ruby-progressbar (1.2.0) - ruby-rc4 (0.1.5) rubytree (0.8.3) json (>= 1.7.5) structured_warnings (>= 0.1.3) @@ -339,8 +294,6 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) - sextant (0.2.4) - rails (>= 3.2) shoulda (3.5.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (>= 1.4.1, < 3.0) @@ -381,7 +334,6 @@ GEM treetop (1.4.15) polyglot polyglot (>= 0.3.1) - ttfunk (1.0.3) tzinfo (0.3.38) uglifier (2.1.1) execjs (>= 0.3.0) @@ -402,7 +354,6 @@ DEPENDENCIES activerecord-tableless (~> 1.0) acts_as_list (~> 0.2.0) awesome_nested_set - better_errors capybara capybara-screenshot codeclimate-test-reporter @@ -434,12 +385,7 @@ DEPENDENCIES net-ldap (~> 0.2.2) object-daddy (~> 1.1.0) oj - openproject-backlogs! - openproject-pdf_export! - openproject-plugins! - pdf-inspector pg (~> 0.17.1) - prawn prototype-rails prototype_legacy_helper (= 0.0.0)! pry-byebug @@ -448,7 +394,6 @@ DEPENDENCIES pry-rails pry-rescue pry-stack_explorer - quiet_assets rabl (= 0.9.3) rack-protection! rack_session_access @@ -468,7 +413,6 @@ DEPENDENCIES rubytree (~> 0.8.3) sass-rails (~> 3.2.3) selenium-webdriver - sextant shoulda shoulda-matchers simplecov (>= 0.8.pre) From c65082151a1c41968fd30a9b5a9b335037520b7b Mon Sep 17 00:00:00 2001 From: Till Breuer Date: Wed, 2 Apr 2014 13:48:10 +0200 Subject: [PATCH 155/155] Use `Array.isArray` instead of `instanceof Array` Thanks @myabc for the advice --- .../directives/components/toggled-multiselect-directive.js | 4 ++-- .../angular/helpers/filter-query-string-builder.js | 2 +- app/assets/javascripts/angular/models/filter.js | 4 ++-- app/assets/javascripts/angular/models/timelines/timeline.js | 2 +- .../javascripts/angular/services/timeline-loader-service.js | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/angular/directives/components/toggled-multiselect-directive.js b/app/assets/javascripts/angular/directives/components/toggled-multiselect-directive.js index 58c16e3ac5..e6b5b6fa26 100644 --- a/app/assets/javascripts/angular/directives/components/toggled-multiselect-directive.js +++ b/app/assets/javascripts/angular/directives/components/toggled-multiselect-directive.js @@ -19,10 +19,10 @@ angular.module('openproject.uiComponents') }; scope.isSelected = function(value) { - return scope.values instanceof Array && (scope.values.indexOf(value) !== -1 || scope.values.indexOf(value.toString()) !== -1); + return Array.isArray(scope.values) && (scope.values.indexOf(value) !== -1 || scope.values.indexOf(value.toString()) !== -1); }; - scope.isMultiselect = (scope.values instanceof Array && scope.values.length > 1); + scope.isMultiselect = (Array.isArray(scope.values) && scope.values.length > 1); } }; }]); diff --git a/app/assets/javascripts/angular/helpers/filter-query-string-builder.js b/app/assets/javascripts/angular/helpers/filter-query-string-builder.js index 60db0a0faa..4105d5fa00 100644 --- a/app/assets/javascripts/angular/helpers/filter-query-string-builder.js +++ b/app/assets/javascripts/angular/helpers/filter-query-string-builder.js @@ -101,7 +101,7 @@ angular.module('openproject.timelines.helpers') }; FilterQueryStringBuilder.prototype.buildFilterDataForValue = function(key, value) { - if (value instanceof Array) { + if (Array.isArray(value)) { this.prepareFilterDataForKeyAndArrayOfValues(key, value); } else { this.prepareFilterDataForKeyAndValue(key, value); diff --git a/app/assets/javascripts/angular/models/filter.js b/app/assets/javascripts/angular/models/filter.js index efb12cef10..e95444c3a7 100644 --- a/app/assets/javascripts/angular/models/filter.js +++ b/app/assets/javascripts/angular/models/filter.js @@ -18,7 +18,7 @@ angular.module('openproject.models') }, valuesAsArray: function() { - if (this.values instanceof Array) { + if (Array.isArray(this.values)) { if (this.values.length === 0) return ['']; // Workaround: The array must not be empty for backend compatibility so that the values are passed as a URL param at all even if `this` is the only query filter // TODO fix this on the backend side, so that filters can be initialized on a query without providing values @@ -49,7 +49,7 @@ angular.module('openproject.models') }, hasValues: function() { - return this.values && (this.values instanceof Array) ? this.values.length > 0 : !!this.values; + return Array.isArray(this.values) ? this.values.length > 0 : !!this.values; } }; diff --git a/app/assets/javascripts/angular/models/timelines/timeline.js b/app/assets/javascripts/angular/models/timelines/timeline.js index ba0988f247..22ff521a63 100644 --- a/app/assets/javascripts/angular/models/timelines/timeline.js +++ b/app/assets/javascripts/angular/models/timelines/timeline.js @@ -516,7 +516,7 @@ angular.module('openproject.timelines.models') // if parents is not an array, turn it into one with length 1, so // the following each does not fail. - if (!(parents instanceof Array)) { + if (!(Array.isArray(parents))) { parents = [parents]; } diff --git a/app/assets/javascripts/angular/services/timeline-loader-service.js b/app/assets/javascripts/angular/services/timeline-loader-service.js index 27e2700ef4..d4a4067e46 100644 --- a/app/assets/javascripts/angular/services/timeline-loader-service.js +++ b/app/assets/javascripts/angular/services/timeline-loader-service.js @@ -242,7 +242,7 @@ angular.module('openproject.timelines.services') var i, e, id, map = {}; - if (data instanceof Array) { + if (Array.isArray(data)) { for (i = 0; i < data.length; i++) { e = data[i]; e.timeline = this.timeline; @@ -424,7 +424,7 @@ angular.module('openproject.timelines.services') var associations = e[ProjectAssociation.identifier]; var j, a, other; - if (associations instanceof Array) { + if (Array.isArray(associations)) { for (j = 0; j < associations.length; j++) { a = associations[j]; a.timeline = dataEnhancer.timeline; @@ -799,7 +799,7 @@ angular.module('openproject.timelines.services') // w/ custom values that are empty and work packages w/o // custom values. - if (value instanceof Array && value.indexOf("-1") !== -1) { + if (Array.isArray(value) && value.indexOf("-1") !== -1) { value.push(""); }
@@ -23,8 +23,7 @@ header-name="column.name" header-title="column.title" sortable="column.sortable" - query="query" - update-results="updateResults()"/> + query="query"/>
- {{ sum }} + + {{ column.group_sums[row.groupName] }}
{{ I18n.t('js.label_sum_for') }} {{ I18n.t('js.label_all_work_packages') }} - {{ sum }} + + {{ column.total_sum }}