diff --git a/app/assets/javascripts/angular/config/work-packages-config.js b/app/assets/javascripts/angular/config/work-packages-config.js
index 2b3bed5a7e..3f807db6e0 100644
--- a/app/assets/javascripts/angular/config/work-packages-config.js
+++ b/app/assets/javascripts/angular/config/work-packages-config.js
@@ -28,7 +28,7 @@
angular.module('openproject.workPackages.config')
-.constant('INITIALLY_SELECTED_COLUMNS', ['id', 'project', 'type', 'status', 'priority', 'subject', 'assigned_to_id', 'updated_at'])
+.constant('INITIALLY_SELECTED_COLUMNS', [{ name: 'id' }, { name: 'project' }, { name: 'type' }, { name: 'status' }, { name: 'priority' }, { name: 'subject' }, { name: 'assigned_to_id' }, { name: 'updated_at' }])
.constant('OPERATORS_AND_LABELS_BY_FILTER_TYPE', {
list: [['=', 'label_equals'], ['!', 'label_not_equals']],
diff --git a/app/assets/javascripts/angular/controllers/dialogs/save.js b/app/assets/javascripts/angular/controllers/dialogs/save.js
index 969ee586da..3840bc0b7b 100644
--- a/app/assets/javascripts/angular/controllers/dialogs/save.js
+++ b/app/assets/javascripts/angular/controllers/dialogs/save.js
@@ -52,7 +52,7 @@ angular.module('openproject.workPackages.controllers')
.then(function(data){
// push query id to URL without reinitializing work-packages-list-controller
if (data.query) {
- $state.go('work-packages.list', { query_id: data.query.id }, { notify: false });
+ $state.go('work-packages.list', { query_id: data.query.id, query: null }, { notify: false });
AuthorisationService.initModelAuth("query", data.query._links);
}
diff --git a/app/assets/javascripts/angular/directives/components/table-pagination-directive.js b/app/assets/javascripts/angular/directives/components/table-pagination-directive.js
index 08759de63d..89c769b433 100644
--- a/app/assets/javascripts/angular/directives/components/table-pagination-directive.js
+++ b/app/assets/javascripts/angular/directives/components/table-pagination-directive.js
@@ -33,8 +33,7 @@ angular.module('openproject.uiComponents')
restrict: 'EA',
templateUrl: '/templates/components/table_pagination.html',
scope: {
- totalEntries: '=',
- updateResults: '&'
+ totalEntries: '='
},
link: function(scope, element, attributes) {
scope.I18n = I18n;
@@ -53,7 +52,7 @@ angular.module('openproject.uiComponents')
updateCurrentRangeLabel();
updatePageNumbers();
- scope.updateResults(); // update table
+ scope.$emit('workPackagesRefreshRequired');
};
/**
diff --git a/app/assets/javascripts/angular/helpers/url-params-helper.js b/app/assets/javascripts/angular/helpers/url-params-helper.js
index ada4f4757f..7582892643 100644
--- a/app/assets/javascripts/angular/helpers/url-params-helper.js
+++ b/app/assets/javascripts/angular/helpers/url-params-helper.js
@@ -51,6 +51,88 @@ angular.module('openproject.helpers')
return parts.join('&');
},
+ encodeQueryJsonParams: function(query) {
+ var paramsData = {
+ c: query.columns.map(function(column) { return column.name; })
+ };
+ if(!!query.displaySums) {
+ paramsData.s = query.displaySums;
+ }
+
+ if(!!query.projectId) {
+ paramsData.p = query.projectId;
+ }
+ if(!!query.groupBy) {
+ paramsData.g = query.groupBy;
+ }
+ if(!!query.getSortation()) {
+ paramsData.t = query.getSortation().encode()
+ }
+ if(query.filters && query.filters.length) {
+ paramsData.f = query.filters.filter(function(filter) {
+ return !filter.deactivated;
+ })
+ .map(function(filter) {
+ var filterData = {
+ n: filter.name,
+ m: filter.modelName,
+ o: encodeURIComponent(filter.operator),
+ t: filter.type
+ };
+ if(filter.values) {
+ angular.extend(filterData, { v: filter.values })
+ }
+ return filterData
+ });
+ }
+
+ return JSON.stringify(paramsData);
+ },
+
+ decodeQueryFromJsonParams: function(queryId, updateJson) {
+ var queryData = {};
+ if(queryId) {
+ queryData.id = queryId;
+ }
+
+ if(updateJson) {
+ var properties = JSON.parse(updateJson);
+
+ if(!!properties.c) {
+ queryData.columns = properties.c.map(function(column) { return { name: column }; });
+ }
+ if(!!properties.s) {
+ queryData.displaySums = properties.s;
+ }
+ if(!!properties.p) {
+ queryData.projectId = properties.p;
+ }
+ if(!!properties.g) {
+ queryData.groupBy = properties.g;
+ }
+ if(!!properties.f) {
+ queryData.filters = properties.f.map(function(urlFilter) {
+ var filterData = {
+ name: urlFilter.n,
+ modelName: urlFilter.m,
+ operator: decodeURIComponent(urlFilter.o),
+ type: urlFilter.t
+ };
+ if(urlFilter.v) {
+ var vs = Array.isArray(urlFilter.v) ? urlFilter.v : [urlFilter.v];
+ angular.extend(filterData, { values: vs });
+ }
+ return filterData;
+ });
+ }
+ if(!!properties.t) {
+ queryData.sortCriteria = properties.t;
+ }
+ }
+
+ return queryData;
+ },
+
buildQueryExportOptions: function(query){
var relativeUrl = "/work_packages";
if (query.project_id){
diff --git a/app/assets/javascripts/angular/models/query.js b/app/assets/javascripts/angular/models/query.js
index ba37562dc8..060b6ecb65 100644
--- a/app/assets/javascripts/angular/models/query.js
+++ b/app/assets/javascripts/angular/models/query.js
@@ -31,7 +31,8 @@ angular.module('openproject.models')
.factory('Query', ['Filter',
'Sortation',
'UrlParamsHelper',
- function(Filter, Sortation, UrlParamsHelper) {
+ 'INITIALLY_SELECTED_COLUMNS',
+ function(Filter, Sortation, UrlParamsHelper, INITIALLY_SELECTED_COLUMNS) {
Query = function (queryData, options) {
angular.extend(this, queryData, options);
@@ -39,7 +40,19 @@ angular.module('openproject.models')
this.filters = [];
this.groupBy = this.groupBy || '';
- if(queryData) this.setFilters(queryData.filters);
+ if(queryData.filters){
+ if(options && options.rawFilters) {
+ this.setRawFilters(queryData.filters);
+ } else {
+ this.setFilters(queryData.filters);
+ }
+ }
+
+ if(queryData.sortCriteria) this.setSortation(queryData.sortCriteria);
+
+ if(!this.columns) {
+ this.setColumns(INITIALLY_SELECTED_COLUMNS);
+ }
};
Query.prototype = {
@@ -56,7 +69,7 @@ angular.module('openproject.models')
'f[]': this.getFilterNames(this.getActiveConfiguredFilters()),
'c[]': this.getParamColumns(),
'group_by': this.groupBy,
- 'sort': this.sortation.encode(),
+ 'sort': this.getEncodedSortation(),
'display_sums': this.displaySums,
'name': this.name,
'is_public': this.isPublic
@@ -74,7 +87,7 @@ angular.module('openproject.models')
'f[]': this.getFilterNames(this.getActiveConfiguredFilters()),
'c[]': this.getParamColumns(),
'group_by': this.groupBy,
- 'sort': this.sortation.encode(),
+ 'sort': this.getEncodedSortation(),
'display_sums': this.displaySums,
'name': this.name,
'is_public': this.isPublic
@@ -87,6 +100,7 @@ angular.module('openproject.models')
save: function(data){
// Note: query has already been updated, only the id needs to be set
this.id = data.id;
+ this.dirty = false;
return this;
},
@@ -98,6 +112,19 @@ angular.module('openproject.models')
this.starred = false;
},
+ update: function(queryData) {
+ angular.extend(this, queryData);
+
+ if(queryData.filters){
+ this.filters = [];
+ this.setRawFilters(queryData.filters);
+ }
+ if(queryData.sortCriteria) this.setSortation(queryData.sortCriteria);
+ this.dirty = true;
+
+ return this;
+ },
+
getQueryString: function(){
return UrlParamsHelper.buildQueryString(this.toParams());
},
@@ -106,8 +133,8 @@ angular.module('openproject.models')
return this.sortation;
},
- setSortation: function(sortation){
- this.sortation = sortation;
+ setSortation: function(sortCriteria){
+ this.sortation = new Sortation(sortCriteria);
},
setGroupBy: function(groupBy) {
@@ -164,6 +191,20 @@ angular.module('openproject.models')
}
},
+ setRawFilters: function(filters) {
+ if (filters){
+ var self = this;
+
+ this.filters = filters.map(function(filterData){
+ return new Filter(filterData);
+ });
+ }
+ },
+
+ setColumns: function(columns) {
+ this.columns = columns;
+ },
+
/**
* @name isDefault
* @function
@@ -224,6 +265,10 @@ angular.module('openproject.models')
return selectedColumns;
},
+ getEncodedSortation: function() {
+ return !!this.sortation ? this.sortation.encode() : null;
+ },
+
getColumnNames: function() {
return this.columns.map(function(column) {
return column.name;
@@ -294,10 +339,14 @@ angular.module('openproject.models')
});
},
- isNew: function(){
+ isNew: function() {
return !this.id;
},
+ isDirty: function() {
+ return this.isNew() || this.dirty;
+ },
+
hasName: function() {
return !!this.name && !this.isDefault();
},
diff --git a/app/assets/javascripts/angular/services/query-service.js b/app/assets/javascripts/angular/services/query-service.js
index 08bb1b2c9f..e946390433 100644
--- a/app/assets/javascripts/angular/services/query-service.js
+++ b/app/assets/javascripts/angular/services/query-service.js
@@ -74,14 +74,15 @@ angular.module('openproject.services')
starred: queryData.starred,
links: queryData._links
});
- query.setSortation(new Sortation(queryData.sort_criteria));
+ query.setSortation(queryData.sort_criteria);
QueryService.getAvailableFilters(query.project_id)
.then(function(availableFilters) {
query.setAvailableWorkPackageFilters(availableFilters);
if (query.isDefault()) {
query.setDefaultFilter();
- } else {
+ }
+ if(queryData.filters && queryData.filters.length) {
query.setFilters(queryData.filters);
}
@@ -92,10 +93,45 @@ angular.module('openproject.services')
return query;
},
+ updateQuery: function(values, afterUpdate) {
+ var queryData = {
+ };
+ if(!!values.display_sums) {
+ queryData.displaySums = values.display_sums;
+ }
+ if(!!values.columns) {
+ queryData.columns = values.columns;
+ }
+ if(!!values.group_by) {
+ queryData.groupBy = values.group_by;
+ }
+ if(!!values.sort_criteria) {
+ queryData.sortCriteria = values.sort_criteria;
+ }
+ query.update(queryData);
+
+ QueryService.getAvailableFilters(query.project_id)
+ .then(function(availableFilters) {
+ query.setAvailableWorkPackageFilters(availableFilters);
+ if(queryData.filters && queryData.filters.length) {
+ query.setFilters(queryData.filters);
+ }
+
+ return query;
+ })
+ .then(afterUpdate);
+
+ return query;
+ },
+
getQuery: function() {
return query;
},
+ clearQuery: function() {
+ query = null;
+ },
+
getQueryName: function() {
if (query && query.hasName()) {
return query.name;
diff --git a/app/assets/javascripts/angular/services/work-package-service.js b/app/assets/javascripts/angular/services/work-package-service.js
index 925b999878..3a514a30d9 100644
--- a/app/assets/javascripts/angular/services/work-package-service.js
+++ b/app/assets/javascripts/angular/services/work-package-service.js
@@ -36,7 +36,8 @@ angular.module('openproject.services')
'WorkPackagesHelper',
'HALAPIResource',
'DEFAULT_FILTER_PARAMS',
- function($http, PathHelper, WorkPackagesHelper, HALAPIResource, DEFAULT_FILTER_PARAMS) {
+ 'DEFAULT_PAGINATION_OPTIONS',
+ function($http, PathHelper, WorkPackagesHelper, HALAPIResource, DEFAULT_FILTER_PARAMS, DEFAULT_PAGINATION_OPTIONS) {
var workPackage;
var WorkPackageService = {
@@ -56,20 +57,22 @@ angular.module('openproject.services')
return WorkPackageService.doQuery(url, params);
},
- getWorkPackagesFromUrlQueryParams: function(projectIdentifier, location) {
+ getWorkPackages: function(projectIdentifier, query, paginationOptions) {
var url = projectIdentifier ? PathHelper.apiProjectWorkPackagesPath(projectIdentifier) : PathHelper.apiWorkPackagesPath();
var params = {};
- angular.extend(params, location.search());
- return WorkPackageService.doQuery(url, params);
- },
+ if(query) {
+ angular.extend(params, query.toUpdateParams());
+ }
- getWorkPackages: function(projectIdentifier, query, paginationOptions) {
- var url = projectIdentifier ? PathHelper.apiProjectWorkPackagesPath(projectIdentifier) : PathHelper.apiWorkPackagesPath();
- var params = angular.extend(query.toUpdateParams(), {
- page: paginationOptions.page,
- per_page: paginationOptions.perPage
- });
+ if(paginationOptions) {
+ angular.extend(params, {
+ page: paginationOptions.page,
+ per_page: paginationOptions.perPage
+ });
+ } else {
+ angular.extend(params, DEFAULT_PAGINATION_OPTIONS);
+ }
return WorkPackageService.doQuery(url, params);
},
diff --git a/app/assets/javascripts/angular/work_packages/controllers/work-packages-list-controller.js b/app/assets/javascripts/angular/work_packages/controllers/work-packages-list-controller.js
index f7640590fe..be6da7efe2 100644
--- a/app/assets/javascripts/angular/work_packages/controllers/work-packages-list-controller.js
+++ b/app/assets/javascripts/angular/work_packages/controllers/work-packages-list-controller.js
@@ -31,10 +31,8 @@ angular.module('openproject.workPackages.controllers')
.controller('WorkPackagesListController', [
'$scope',
'$rootScope',
- '$q',
- '$location',
- '$stateParams',
'$state',
+ '$location',
'latestTab',
'I18n',
'WorkPackagesTableService',
@@ -43,14 +41,12 @@ angular.module('openproject.workPackages.controllers')
'QueryService',
'PaginationService',
'AuthorisationService',
- 'WorkPackageLoadingHelper',
- 'HALAPIResource',
- 'INITIALLY_SELECTED_COLUMNS',
+ 'UrlParamsHelper',
'OPERATORS_AND_LABELS_BY_FILTER_TYPE',
- function($scope, $rootScope, $q, $location, $stateParams, $state, latestTab,
+ function($scope, $rootScope, $state, $location, latestTab,
I18n, WorkPackagesTableService,
WorkPackageService, ProjectService, QueryService, PaginationService,
- AuthorisationService, WorkPackageLoadingHelper, HALAPIResource, INITIALLY_SELECTED_COLUMNS,
+ AuthorisationService, UrlParamsHelper,
OPERATORS_AND_LABELS_BY_FILTER_TYPE) {
@@ -59,12 +55,19 @@ angular.module('openproject.workPackages.controllers')
$scope.operatorsAndLabelsByFilterType = OPERATORS_AND_LABELS_BY_FILTER_TYPE;
$scope.disableFilters = false;
$scope.disableNewWorkPackage = true;
+ var queryParams = $location.search().query_props;
var fetchWorkPackages;
- if($scope.query_id){
- fetchWorkPackages = WorkPackageService.getWorkPackagesByQueryId($scope.projectIdentifier, $scope.query_id);
+ if(queryParams) {
+ // Attempt to build up query from URL params
+ fetchWorkPackages = fetchWorkPackagesFromUrlParams(queryParams);
+ } else if($state.params.query_id) {
+ // Load the query by id if present
+ fetchWorkPackages = WorkPackageService.getWorkPackagesByQueryId($scope.projectIdentifier, $state.params.query_id);
} else {
- fetchWorkPackages = WorkPackageService.getWorkPackagesFromUrlQueryParams($scope.projectIdentifier, $location);
+ // Clear the cached query and load the default
+ QueryService.clearQuery();
+ fetchWorkPackages = WorkPackageService.getWorkPackages($scope.projectIdentifier);
}
$scope.settingUpPage = fetchWorkPackages // put promise in scope for cg-busy
@@ -76,6 +79,28 @@ angular.module('openproject.workPackages.controllers')
});
}
+ function fetchWorkPackagesFromUrlParams(queryParams) {
+ try {
+ var queryData = UrlParamsHelper.decodeQueryFromJsonParams($state.params.query_id, queryParams);
+ var queryFromParams = new Query(queryData, { rawFilters: true });
+
+ return WorkPackageService.getWorkPackages($scope.projectIdentifier, queryFromParams);
+ } catch(e) {
+ $scope.$emit('flashMessage', {
+ isError: true,
+ text: I18n.t('js.work_packages.query.errors.unretrievable_query')
+ });
+ clearUrlQueryParams();
+
+ return WorkPackageService.getWorkPackages($scope.projectIdentifier);
+ }
+ }
+
+ function clearUrlQueryParams() {
+ $location.search('query_props', null);
+ $location.search('query_id', null);
+ }
+
function fetchProjectTypesAndQueries() {
if ($scope.projectIdentifier) {
ProjectService.getProject($scope.projectIdentifier)
@@ -98,21 +123,24 @@ angular.module('openproject.workPackages.controllers')
}
function initQuery(metaData) {
- var storedQuery = QueryService.getQuery();
+ var queryData = metaData.query,
+ columnData = metaData.columns;
- if (storedQuery && $stateParams.query_id !== null && storedQuery.id === $scope.query_id) {
- $scope.query = storedQuery;
- } else {
- var queryData = metaData.query,
- columnData = metaData.columns;
+ var cachedQuery = QueryService.getQuery();
+ var urlQueryId = $state.params.query_id;
- $scope.query = QueryService.initQuery($scope.query_id, queryData, columnData, metaData.export_formats, afterQuerySetupCallback);
+ if (cachedQuery && urlQueryId && cachedQuery.id == urlQueryId) {
+ // Augment current unsaved query with url param data
+ var updateData = angular.extend(queryData, { columns: columnData })
+ $scope.query = QueryService.updateQuery(updateData, afterQuerySetupCallback);
+ } else {
+ // Set up fresh query from retrieved query meta data
+ $scope.query = QueryService.initQuery($state.params.query_id, queryData, columnData, metaData.export_formats, afterQuerySetupCallback);
}
}
function afterQuerySetupCallback(query) {
$scope.showFiltersOptions = query.filters.length > 0;
- $scope.updateBackUrl();
}
function setupWorkPackagesTable(json) {
@@ -145,9 +173,6 @@ angular.module('openproject.workPackages.controllers')
$scope.workPackageCountByGroup = meta.work_package_count_by_group;
$scope.totalEntries = QueryService.getTotalEntries();
- // back url
- $scope.updateBackUrl();
-
// Authorisation
AuthorisationService.initModelAuth("work_package", meta._links);
AuthorisationService.initModelAuth("query", meta.query._links);
@@ -162,21 +187,30 @@ angular.module('openproject.workPackages.controllers')
// Updates
- $scope.updateBackUrl = function(){
- // Easier than trying to extract it from $location
+ $scope.maintainUrlQueryState = function(){
var relativeUrl = "/work_packages";
if ($scope.projectIdentifier){
relativeUrl = "/projects/" + $scope.projectIdentifier + relativeUrl;
}
- if($scope.query){
- relativeUrl = relativeUrl + "#?" + $scope.query.getQueryString();
+ if($scope.query) {
+ var queryString = UrlParamsHelper.encodeQueryJsonParams($scope.query);
+ $location.search('query_props', queryString);
+ relativeUrl = relativeUrl + "?query_props=" + queryString;
}
$scope.backUrl = relativeUrl;
};
- $scope.updateResults = function() {
+ $scope.loadQuery = function(queryId) {
+ // Clear unsaved changes to current query
+ clearUrlQueryParams();
+
+ // Load new query
+ $state.go('work-packages.list', { query_id: queryId });
+ };
+
+ function updateResults() {
$scope.$broadcast('openproject.workPackages.updateResults');
$scope.refreshWorkPackages = WorkPackageService.getWorkPackages($scope.projectIdentifier, $scope.query, PaginationService.getPaginationOptions())
@@ -185,10 +219,6 @@ angular.module('openproject.workPackages.controllers')
return $scope.refreshWorkPackages;
};
- $scope.setQueryState = function(query_id) {
- $state.go('work-packages.list', { query_id: query_id });
- };
-
// More
function serviceErrorHandler(data) {
@@ -208,6 +238,23 @@ angular.module('openproject.workPackages.controllers')
$scope.selectedTitle = queryName || I18n.t('js.toolbar.unselected_title');
});
+ $rootScope.$on('queryStateChange', function(event, message) {
+ $scope.maintainUrlQueryState();
+ });
+
+ $rootScope.$on('workPackagesRefreshRequired', function(event, message) {
+ updateResults();
+ });
+
+ $rootScope.$on('queryClearRequired', function(event, message) {
+ $location.search('query_props', null);
+ if($location.search().query_id) {
+ $location.search('query_id', null);
+ } else {
+ initialSetup();
+ }
+ });
+
$scope.openLatestTab = function() {
$state.go(latestTab.getStateName(), { workPackageId: $scope.preselectedWorkPackageId });
};
diff --git a/app/assets/javascripts/angular/work_packages/directives/filter-clear-directive.js b/app/assets/javascripts/angular/work_packages/directives/filter-clear-directive.js
index 30add2f591..68e12ab43c 100644
--- a/app/assets/javascripts/angular/work_packages/directives/filter-clear-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/filter-clear-directive.js
@@ -29,18 +29,18 @@
angular.module('openproject.workPackages.directives')
.directive('filterClear', [
- '$state',
+ '$location',
'I18n',
'QueryService',
- function($state, I18n, QueryService){
+ function($location, I18n, QueryService){
return {
restrict: 'E',
templateUrl: '/templates/work_packages/filter_clear.html',
scope: true,
link: function(scope, element, attributes) {
scope.I18n = I18n;
- scope.clearQuery = function(){
- $state.go('work-packages.list', { query_id: null }, { reload: true });
+ scope.clearQuery = function() {
+ scope.$emit('queryClearRequired')
};
}
};
diff --git a/app/assets/javascripts/angular/work_packages/directives/options-dropdown-directive.js b/app/assets/javascripts/angular/work_packages/directives/options-dropdown-directive.js
index 58dd4806a8..a075193f5f 100644
--- a/app/assets/javascripts/angular/work_packages/directives/options-dropdown-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/options-dropdown-directive.js
@@ -61,6 +61,7 @@ angular.module('openproject.workPackages.directives')
QueryService.saveQuery()
.then(function(data){
scope.$emit('flashMessage', data.status);
+ $state.go('work-packages.list', { query_id: scope.query.id, query: null }, { notify: false });
});
}
}
@@ -72,7 +73,7 @@ angular.module('openproject.workPackages.directives')
.then(function(data){
settingsModal.deactivate();
scope.$emit('flashMessage', data.status);
- $state.go('work-packages.list', { query_id: null }, { reload: true });
+ $state.go('work-packages.list', { query_id: null, query: null }, { reload: true });
});
}
};
diff --git a/app/assets/javascripts/angular/work_packages/directives/query-columns-directive.js b/app/assets/javascripts/angular/work_packages/directives/query-columns-directive.js
index 72108f1332..e50b4f4f5d 100644
--- a/app/assets/javascripts/angular/work_packages/directives/query-columns-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/query-columns-directive.js
@@ -76,7 +76,7 @@ angular.module('openproject.workPackages.directives')
var newColumns = WorkPackagesTableHelper.selectColumnsByName(scope.columns, columnNames);
WorkPackageService.augmentWorkPackagesWithColumnsData(workPackages, newColumns, groupBy)
- .then(scope.updateBackUrl);
+ .then(function(){ scope.$emit('queryStateChange') });
}
}
};
diff --git a/app/assets/javascripts/angular/work_packages/directives/query-filter-directive.js b/app/assets/javascripts/angular/work_packages/directives/query-filter-directive.js
index 66932e1852..2feb8abc11 100644
--- a/app/assets/javascripts/angular/work_packages/directives/query-filter-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/query-filter-directive.js
@@ -64,9 +64,8 @@ angular.module('openproject.workPackages.directives')
if (filter !== oldFilter) {
if (filter.isConfigured() && (filterChanged(filter, oldFilter) || valueReset(filter, oldFilter))) {
PaginationService.resetPage();
-
- applyFilters();
- scope.updateBackUrl();
+ scope.$emit('queryStateChange');
+ scope.$emit('workPackagesRefreshRequired');
}
}
}, true);
diff --git a/app/assets/javascripts/angular/work_packages/directives/query-filters-directive.js b/app/assets/javascripts/angular/work_packages/directives/query-filters-directive.js
index d9b70a30c8..1c0b66189b 100644
--- a/app/assets/javascripts/angular/work_packages/directives/query-filters-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/query-filters-directive.js
@@ -43,7 +43,6 @@ angular.module('openproject.workPackages.directives')
if (filterName) {
scope.query.addFilter(filterName);
scope.filterToBeAdded = undefined;
- scope.updateBackUrl();
}
});
diff --git a/app/assets/javascripts/angular/work_packages/directives/query-form-directive.js b/app/assets/javascripts/angular/work_packages/directives/query-form-directive.js
index 437004f7fd..7e6af7f31d 100644
--- a/app/assets/javascripts/angular/work_packages/directives/query-form-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/query-form-directive.js
@@ -55,6 +55,15 @@ angular.module('openproject.workPackages.directives')
return groupByChanged || sortElementsChanged;
}
+ function passiveQueryPropertiesChanged(currentProperties, formerProperties) {
+ if (formerProperties === undefined) return false;
+
+ var columnsChanged = JSON.stringify(currentProperties.columns) !== JSON.stringify(formerProperties.columns);
+ var displaySumsChanged = currentProperties.displaySums !== formerProperties.displaySums;
+
+ return columnsChanged || displaySumsChanged;
+ }
+
function observedQueryProperties() {
var query = scope.query;
@@ -69,14 +78,31 @@ angular.module('openproject.workPackages.directives')
}
}
+ function passiveQueryProperties() {
+ var query = scope.query;
+
+ if (query !== undefined) {
+ return {
+ columns: query.columns,
+ displaySums: query.displaySums
+ };
+ }
+ }
+
scope.$watch(observedQueryProperties, function(newProperties, oldProperties) {
if (!querySwitched(newProperties, oldProperties)) {
if (queryPropertiesChanged(newProperties, oldProperties)) {
- scope.updateResults();
- scope.updateBackUrl();
+ scope.$emit('queryStateChange');
+ scope.$emit('workPackagesRefreshRequired');
}
}
}, true);
+
+ scope.$watch(passiveQueryProperties, function(newProperties, oldProperties) {
+ if (passiveQueryPropertiesChanged(newProperties, oldProperties)) {
+ scope.$emit('queryStateChange');
+ }
+ }, true);
}
};
}
diff --git a/app/assets/javascripts/angular/work_packages/directives/work-package-group-sums-directive.js b/app/assets/javascripts/angular/work_packages/directives/work-package-group-sums-directive.js
index dbc1902a01..1f69625c3c 100644
--- a/app/assets/javascripts/angular/work_packages/directives/work-package-group-sums-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/work-package-group-sums-directive.js
@@ -48,7 +48,8 @@ angular.module('openproject.workPackages.directives')
scope.$watch('groupSums.length', function() {
// map columns to sums if the column data is a number
setSums();
- scope.updateBackUrl();
+ scope.$emit('queryStateChange');
+ scope.$emit('workPackagesRefreshRequired');
});
}
diff --git a/app/assets/javascripts/angular/work_packages/directives/work-package-total-sums-directive.js b/app/assets/javascripts/angular/work_packages/directives/work-package-total-sums-directive.js
index c16b519e54..fe5e63de73 100644
--- a/app/assets/javascripts/angular/work_packages/directives/work-package-total-sums-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/work-package-total-sums-directive.js
@@ -64,7 +64,7 @@ angular.module('openproject.workPackages.directives')
scope.$watch(columnNames, function(columnNames, formerNames) {
if (!angular.equals(columnNames, formerNames) && !totalSumsFetched()) {
fetchTotalSums();
- scope.updateBackUrl();
+ scope.$emit('queryStateChange');
}
}, true);
}
diff --git a/app/assets/javascripts/angular/work_packages/directives/work-packages-table-directive.js b/app/assets/javascripts/angular/work_packages/directives/work-packages-table-directive.js
index 048b54a9e0..b3aadc521f 100644
--- a/app/assets/javascripts/angular/work_packages/directives/work-packages-table-directive.js
+++ b/app/assets/javascripts/angular/work_packages/directives/work-packages-table-directive.js
@@ -50,9 +50,7 @@ angular.module('openproject.workPackages.directives')
groupByColumn: '=',
displaySums: '=',
totalSums: '=',
- groupSums: '=',
- updateResults: '&',
- updateBackUrl: '='
+ groupSums: '='
},
link: function(scope, element, attributes) {
var activeSelectionBorderIndex;
diff --git a/app/assets/javascripts/angular/work_packages/tabs/work-package-relations-directive.js b/app/assets/javascripts/angular/work_packages/tabs/work-package-relations-directive.js
index bf0f2b1c88..b1dfd8465c 100644
--- a/app/assets/javascripts/angular/work_packages/tabs/work-package-relations-directive.js
+++ b/app/assets/javascripts/angular/work_packages/tabs/work-package-relations-directive.js
@@ -72,7 +72,7 @@ angular.module('openproject.workPackages.tabs')
});
scope.$watch('expand', function(newVal, oldVal) {
- scope.stateClass = WorkPackagesHelper.collapseStateIcon(!newVal);
+ scope.stateClass = WorkPackagesHelper.collapseStateIcon(newVal);
});
scope.toggleExpand = function() {
diff --git a/config/locales/js-de.yml b/config/locales/js-de.yml
index 6a09e2a779..a765d4c494 100644
--- a/config/locales/js-de.yml
+++ b/config/locales/js-de.yml
@@ -301,6 +301,8 @@ de:
insert_columns: "Spalten hinzufügen ..."
filters: "Filter"
display_sums: "Summen anzeigen"
+ errors:
+ unretrievable_query: "Die URL enthält keine benutzerdefinierte Abfrage"
tabs:
overview: "Übersicht"
activity: "Aktivität"
diff --git a/config/locales/js-en.yml b/config/locales/js-en.yml
index 342ccade77..28ef452350 100644
--- a/config/locales/js-en.yml
+++ b/config/locales/js-en.yml
@@ -304,6 +304,8 @@ en:
insert_columns: "Insert columns ..."
filters: "Filters"
display_sums: "Display Sums"
+ errors:
+ unretrievable_query: "Unable to retrieve query from URL"
tabs:
overview: Overview
activity: Activity
diff --git a/karma/tests/controllers/work-packages-list-controller-test.js b/karma/tests/controllers/work-packages-list-controller-test.js
index adf05d7516..db3fb83cc6 100644
--- a/karma/tests/controllers/work-packages-list-controller-test.js
+++ b/karma/tests/controllers/work-packages-list-controller-test.js
@@ -31,6 +31,7 @@
describe('WorkPackagesListController', function() {
var scope, ctrl, win, testParams,
testProjectService, testWorkPackageService, testQueryService, testPaginationService;
+ var testQueries;
var buildController;
beforeEach(module('openproject.api', 'openproject.workPackages.controllers', 'openproject.workPackages.services', 'ng-context-menu', 'btford.modal', 'openproject.services'));
@@ -47,9 +48,24 @@ describe('WorkPackagesListController', function() {
location: { pathname: "" }
};
- var workPackageData = {
+ var defaultWorkPackagesData = {
meta: {
- }
+ query: {
+ _links: []
+ },
+ sums: [null]
+ },
+ work_packages: []
+ };
+ var workPackagesDataByQueryId = {
+ meta: {
+ query: {
+ props: { id: 1 },
+ _links: []
+ },
+ sums: [null]
+ },
+ work_packages: []
};
var columnData = {
};
@@ -58,6 +74,16 @@ describe('WorkPackagesListController', function() {
var projectData = { embedded: { types: [] } };
var projectsData = [ projectData ];
+ testQueries = {
+ '1': {
+ id: 1,
+ columns: ['type']
+ },
+ '2': {
+ id: 2,
+ columns: ['type']
+ },
+ };
testProjectService = {
getProject: function(identifier) {
@@ -74,15 +100,18 @@ describe('WorkPackagesListController', function() {
testWorkPackageService = {
getWorkPackages: function () {
+ return $timeout(function () {
+ return defaultWorkPackagesData;
+ }, 10);
},
getWorkPackagesByQueryId: function (params) {
return $timeout(function () {
- return workPackageData;
+ return workPackagesDataByQueryId;
}, 10);
},
getWorkPackagesFromUrlQueryParams: function () {
return $timeout(function () {
- return workPackageData;
+ return defaultWorkPackagesData;
}, 10);
}
};
@@ -93,8 +122,11 @@ describe('WorkPackagesListController', function() {
}
};
},
- initQuery: function () {
+ initQuery: function (id) {
+ var queryId = id || 1;
+ return testQueries[queryId];
},
+ clearQuery: function() {},
getAvailableOptions: function() {
return {};
},
@@ -130,11 +162,12 @@ describe('WorkPackagesListController', function() {
setPage: function () {
}
};
+ testAuthorisationService = {
+ initModelAuth: function(model, links) {
+ }
+ }
- testParams = {};
- testState = {};
-
- buildController = function() {
+ buildController = function(params, state, location) {
scope.projectIdentifier = 'test';
ctrl = $controller("WorkPackagesListController", {
@@ -142,19 +175,58 @@ describe('WorkPackagesListController', function() {
$window: win,
QueryService: testQueryService,
PaginationService: testPaginationService,
+ ProjectService: testProjectService,
WorkPackageService: testWorkPackageService,
- $stateParams: testParams,
- $state: testState,
+ $stateParams: params,
+ $state: state,
+ $location: location,
latestTab: {}
});
+
+ $timeout.flush();
};
}));
- describe('initialisation', function() {
+ describe('initialisation of default query', function() {
+ beforeEach(function(){
+ testParams = {};
+ testState = { params: {} };
+ testLocation = {
+ search: function() {
+ return {};
+ }
+ }
+
+ buildController(testParams, testState, testLocation);
+ });
+
it('should initialise', function() {
- buildController();
expect(scope.settingUpPage).to.be.defined;
+ expect(scope.operatorsAndLabelsByFilterType).to.be.defined;
+ expect(scope.disableFilters).to.eq(false);
+ expect(scope.disableNewWorkPackage).to.eq(true);
+ expect(scope.query.id).to.eq(testQueries['1'].id);
+ });
+ });
+
+ describe('initialisation of query by id', function() {
+ beforeEach(function(){
+ testParams = { };
+ testState = { params: {
+ query_id: testQueries['2'].id
+ } };
+ testLocation = {
+ search: function() {
+ return {};
+ }
+ }
+
+ buildController(testParams, testState, testLocation);
+ });
+
+ it('should initialise', function() {
+ expect(scope.query.id).to.eq(testQueries['2'].id);
});
});
});
diff --git a/karma/tests/directives/components/table_pagination-test.js b/karma/tests/directives/components/table_pagination-test.js
index 7d06918e94..eadc8047a7 100644
--- a/karma/tests/directives/components/table_pagination-test.js
+++ b/karma/tests/directives/components/table_pagination-test.js
@@ -34,7 +34,7 @@ describe('tablePagination Directive', function () {
beforeEach(inject(function ($rootScope, $compile, _I18n_) {
var html, I18n, t;;
- html = '