OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
openproject/frontend/app/components/wp-list/wp-list.service.ts

366 lines
12 KiB

// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 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.
// ++
import {QueryResource} from "../api/api-v3/hal-resources/query-resource.service";
import {QueryFormResource} from "../api/api-v3/hal-resources/query-form-resource.service";
import {PaginationObject, QueryDmService} from "../api/api-v3/hal-resource-dms/query-dm.service";
import {QueryFormDmService} from "../api/api-v3/hal-resource-dms/query-form-dm.service";
import {States} from "../states.service";
import {SchemaResource} from "../api/api-v3/hal-resources/schema-resource.service";
import {ErrorResource} from "../api/api-v3/hal-resources/error-resource.service";
import {WorkPackageCollectionResource} from "../api/api-v3/hal-resources/wp-collection-resource.service";
import {QuerySchemaResourceInterface} from "../api/api-v3/hal-resources/query-schema-resource.service";
import {QueryFilterInstanceSchemaResource} from "../api/api-v3/hal-resources/query-filter-instance-schema-resource.service";
import {WorkPackageCacheService} from "../work-packages/work-package-cache.service";
import {WorkPackageTableColumnsService} from "../wp-fast-table/state/wp-table-columns.service";
import {WorkPackageTableSortByService} from "../wp-fast-table/state/wp-table-sort-by.service";
import {WorkPackageTableGroupByService} from "../wp-fast-table/state/wp-table-group-by.service";
import {WorkPackageTableFiltersService} from "../wp-fast-table/state/wp-table-filters.service";
import {WorkPackageTableSumService} from "../wp-fast-table/state/wp-table-sum.service";
import {WorkPackageTablePaginationService} from "../wp-fast-table/state/wp-table-pagination.service";
import {WorkPackagesListInvalidQueryService} from "./wp-list-invalid-query.service";
import {WorkPackageTableTimelineService} from "./../wp-fast-table/state/wp-table-timeline.service";
import {WorkPackageTableHierarchiesService} from "./../wp-fast-table/state/wp-table-hierarchy.service";
import {SchemaCacheService} from "../schemas/schema-cache.service";
import {Observable} from "rxjs";
import {WorkPackageStatesInitializationService} from './wp-states-initialization.service';
export class WorkPackagesListService {
constructor(protected NotificationsService:any,
protected UrlParamsHelper:any,
protected AuthorisationService:any,
protected $q:ng.IQService,
protected $state:any,
protected QueryDm:QueryDmService,
protected QueryFormDm:QueryFormDmService,
protected states:States,
protected wpTablePagination:WorkPackageTablePaginationService,
protected wpStatesInitialization:WorkPackageStatesInitializationService,
protected wpListInvalidQueryService:WorkPackagesListInvalidQueryService,
protected I18n:op.I18n,
protected queryMenuItemFactory:any) {
}
/**
* Load a query.
* The query is either a persisted query, identified by the query_id parameter, or the default query. Both will be modified by the parameters in the query_props parameter.
*/
public fromQueryParams(queryParams:any, projectIdentifier ?:string):ng.IPromise<QueryResource> {
const queryData = this.UrlParamsHelper.buildV3GetQueryFromJsonParams(queryParams.query_props);
const wpListPromise = this.QueryDm.find(queryData, queryParams.query_id, projectIdentifier);
const promise = this.updateStatesFromQueryOnPromise(wpListPromise);
promise
.catch(error => {
const queryProps = this.UrlParamsHelper.buildV3GetQueryFromJsonParams(queryParams.query_props);
return this.handleQueryLoadingError(error, queryProps, queryParams.query_id, projectIdentifier);
});
return this.conditionallyLoadForm(promise);
}
/**
* Load the default query.
*/
public loadDefaultQuery(projectIdentifier ?:string):ng.IPromise<QueryResource> {
return this.fromQueryParams({}, projectIdentifier);
}
/**
* Reloads the current query and set the pagination to the first page.
*/
public reloadQuery(query:QueryResource):ng.IPromise<QueryResource> {
let pagination = this.getPaginationInfo();
pagination.offset = 1;
let wpListPromise = this.QueryDm.reload(query, pagination);
let promise = this.updateStatesFromQueryOnPromise(wpListPromise);
promise
.catch(error => {
let projectIdentifier = query.project && query.project.id;
return this.handleQueryLoadingError(error, {}, query.id, projectIdentifier);
});
return this.conditionallyLoadForm(promise);
}
/**
* Update the list from an existing query object.
*/
public loadResultsList(query:QueryResource, additionalParams:PaginationObject):ng.IPromise<WorkPackageCollectionResource> {
let wpListPromise = this.QueryDm.loadResults(query, additionalParams);
return this.updateStatesFromWPListOnPromise(query, wpListPromise);
}
/**
* Reload the list of work packages for the current query keeping the
* pagination options.
*/
public reloadCurrentResultsList():ng.IPromise<WorkPackageCollectionResource> {
let pagination = this.getPaginationInfo();
let query = this.currentQuery;
return this.loadResultsList(query, pagination);
}
/**
* Reload the first page of work packages for the current query
*/
public loadCurrentResultsListFirstPage():ng.IPromise<WorkPackageCollectionResource> {
let pagination = this.getPaginationInfo();
pagination.offset = 1;
let query = this.currentQuery;
return this.loadResultsList(query, pagination);
}
public loadForm(query:QueryResource):ng.IPromise<QueryFormResource> {
return this.QueryFormDm.load(query).then((form:QueryFormResource) => {
this.wpStatesInitialization.updateStatesFromForm(query, form);
return form;
});
}
/**
* Persist the current query in the backend.
* After the update, the new query is reloaded (e.g. for the work packages)
*/
public create(name:string) {
let query = this.currentQuery;
let form = this.states.table.form.value!;
query.name = name;
let promise = this.QueryDm.create(query, form);
promise
.then(query => {
this.NotificationsService.addSuccess(this.I18n.t('js.notice_successful_create'));
this.reloadQuery(query);
});
return promise;
}
/**
* Destroy the current query.
*/
public delete() {
let query = this.currentQuery;
let promise = this.QueryDm.delete(query);
promise
.then(() => {
this.NotificationsService.addSuccess(this.I18n.t('js.notice_successful_delete'));
this.removeMenuItem(query);
let id;
if (query.project) {
id = query.project.$href!.split('/').pop();
}
this.loadDefaultQuery(id);
});
return promise;
}
public save(query?:QueryResource) {
query = query || this.currentQuery;
let form = this.states.table.form.value!;
let promise = this.QueryDm.save(query, form);
promise
.then(() => {
this.NotificationsService.addSuccess(this.I18n.t('js.notice_successful_update'));
this
.queryMenuItemFactory
.renameMenuItem(query!.id, query!.name);
// We should actually put the query newly received
// from the backend in here.
// But the backend does currently not return work packages (results).
this.states.table.query.putValue(query!);
})
.catch((error:ErrorResource) => {
this.NotificationsService.addError(error.message);
});
return promise;
}
public toggleStarred() {
let query = this.currentQuery;
let promise = this.QueryDm.toggleStarred(query);
let starred = !query.starred;
promise.then((query) => {
this.states.table.query.putValue(query);
this.NotificationsService.addSuccess(this.I18n.t('js.notice_successful_update'));
this.updateQueryMenu();
});
return promise;
}
private getPaginationInfo() {
let pagination = this.wpTablePagination.current;
return {
pageSize: pagination.perPage,
offset: pagination.page
};
}
private conditionallyLoadForm(promise:ng.IPromise<QueryResource>):ng.IPromise<QueryResource> {
promise.then(query => {
let currentForm = this.states.table.form.value;
if (!currentForm || query.$links.update.$href !== currentForm.$href) {
this.loadForm(query);
}
return query;
});
return promise;
}
private updateStatesFromQueryOnPromise(promise:ng.IPromise<QueryResource>):ng.IPromise<QueryResource> {
promise
.then(query => {
this.states.table.context.doAndTransition('Query loaded', () => {
this.wpStatesInitialization.initialize(query, query.results);
return this.states.tableRendering.onQueryUpdated.valuesPromise();
});
return query;
});
return promise;
}
private updateStatesFromWPListOnPromise(query:QueryResource, promise:ng.IPromise<WorkPackageCollectionResource>):ng.IPromise<WorkPackageCollectionResource> {
return promise.then((results) => {
this.states.table.context.doAndTransition('Query loaded', () => {
this.wpStatesInitialization.updateFromResults(results);
return this.states.tableRendering.onQueryUpdated.valuesPromise();
});
return results;
});
}
private get currentQuery() {
return this.states.table.query.value!;
}
private updateQueryMenu() {
let query = this.currentQuery;
if (query.starred) {
this.createMenuItem(query);
} else {
this.removeMenuItem(query);
}
this.activateMenuItem();
}
private handleQueryLoadingError(error:ErrorResource, queryProps:any, queryId:number, projectIdentifier?:string) {
let deferred = this.$q.defer();
this.NotificationsService.addError(this.I18n.t('js.work_packages.faulty_query.description'), error.message);
this.QueryFormDm.loadWithParams(queryProps, queryId, projectIdentifier)
.then(form => {
this.QueryDm.findDefault({pageSize: 0}, projectIdentifier)
.then((query:QueryResource) => {
this.wpListInvalidQueryService.restoreQuery(query, form);
query.results.pageSize = queryProps.pageSize;
query.results.total = 0;
if (queryId) {
query.id = queryId;
}
this.states.table.context.doAndTransition('Query loaded', () => {
this.wpStatesInitialization.initialize(query, query.results);
this.wpStatesInitialization.updateStatesFromForm(query, form);
return this.states.tableRendering.onQueryUpdated.valuesPromise();
});
deferred.resolve(query);
});
});
return deferred.promise;
}
private createMenuItem(query:QueryResource) {
this
.queryMenuItemFactory
.generateMenuItem(query.name,
this.$state.href('work-packages.list', {query_id: query.id}),
query.id);
}
private removeMenuItem(query:QueryResource) {
this
.queryMenuItemFactory
.removeMenuItem(query.id);
}
private activateMenuItem() {
this
.queryMenuItemFactory
.activateMenuItem();
}
}
angular
.module('openproject.workPackages.services')
.service('wpListService', WorkPackagesListService);