Render priorities and statuses with same display renderer

pull/6336/head
Oliver Günther 7 years ago
parent a101a67374
commit 85b2ef6c87
No known key found for this signature in database
GPG Key ID: 88872239EB414F99
  1. 4
      app/assets/stylesheets/content/work_packages/inplace_editing/_display_fields.sass
  2. 2
      frontend/app/angular4-modules.ts
  3. 5
      frontend/app/components/common/path-helper/apiv3/apiv3-paths.ts
  4. 64
      frontend/app/components/priorities/priority-cache.service.ts
  5. 4
      frontend/app/components/states.service.ts
  6. 49
      frontend/app/components/wp-display/field-types/wp-display-colored-element-field.module.ts
  7. 6
      frontend/app/components/wp-display/wp-display-field/wp-display-field.config.ts
  8. 3
      frontend/app/components/wp-fast-table/state/wp-table-additional-elements.service.ts
  9. 53
      frontend/app/modules/hal/dm-services/priority-dm.service.ts
  10. 2
      frontend/app/modules/hal/openproject-hal.module.ts
  11. 3
      lib/api/v3/priorities/priority_representer.rb

@ -1,4 +1,4 @@
.wp-display-field--status-color
.wp-display-field--color
display: inline-block
width: 10px
height: 10px
@ -7,5 +7,5 @@
// Overridden when defined for status
background: transparent
.wp-display-field--status-text
.wp-display-field--color-text
font-weight: bold

@ -222,6 +222,7 @@ import {AccessibleClickDirective} from "core-components/a11y/accessible-click.di
import {WorkPackageChildrenQueryComponent} from 'core-components/wp-relations/wp-relation-children/wp-children-query.component';
import {StatusCacheService} from 'core-components/status/status-cache.service';
import {ColorsAutocompleter} from 'core-components/colors/colors-autocompleter.component';
import {PriorityCacheService} from 'core-components/priorities/priority-cache.service';
@NgModule({
imports: [
@ -260,6 +261,7 @@ import {ColorsAutocompleter} from 'core-components/colors/colors-autocompleter.c
ProjectCacheService,
UserCacheService,
StatusCacheService,
PriorityCacheService,
upgradeService('states', States),
PaginationService,
upgradeService('keepTab', KeepTabService),

@ -50,7 +50,10 @@ export class ApiV3Paths {
// /api/v3/statuses
public readonly statuses = new SimpleResourceCollection(this.apiV3Base, 'statuses');
// /api/v3/statuses
// /api/v3/priorities
public readonly priorities = new SimpleResourceCollection(this.apiV3Base, 'priorities');
// /api/v3/types
public readonly types = new SimpleResourceCollection(this.apiV3Base, 'types');
// /api/v3/work_packages

@ -0,0 +1,64 @@
// -- 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 {MultiInputState} from "reactivestates";
import {Injectable} from '@angular/core';
import {UserResource} from 'core-app/modules/hal/resources/user-resource';
import {StateCacheService} from 'core-components/states/state-cache.service';
import {States} from 'core-components/states.service';
import {StatusResource} from 'core-app/modules/hal/resources/status-resource';
import {StatusDmService} from './../../modules/hal/dm-services/status-dm.service';
import {PriorityDmService} from "core-app/modules/hal/dm-services/priority-dm.service";
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
@Injectable()
export class PriorityCacheService extends StateCacheService<HalResource> {
constructor(readonly states:States,
readonly priorityDm:PriorityDmService) {
super();
}
public requireAllStatuses() {
return this.loadAll([]);
}
protected async load(id:string):Promise<HalResource> {
return this.priorityDm.load(id);
}
protected async loadAll(_ids:string[]):Promise<undefined> {
return this.priorityDm.loadAll().then((results) => {
results.elements.map(el => this.multiState.get(el.id).putValue(el));
return undefined;
});
}
protected get multiState():MultiInputState<HalResource> {
return this.states.priorities;
}
}

@ -12,6 +12,7 @@ import {QueryColumn} from './wp-query/query-column';
import {TypeResource} from 'core-app/modules/hal/resources/type-resource';
import {UserResource} from 'core-app/modules/hal/resources/user-resource';
import {ProjectResource} from 'core-app/modules/hal/resources/project-resource';
import {HalResource} from 'core-app/modules/hal/resources/hal-resource';
export class States extends StatesGroup {
@ -35,6 +36,9 @@ export class States extends StatesGroup {
/* /api/v3/statuses */
statuses = multiInput<StatusResource>();
/* /api/v3/statuses */
priorities = multiInput<HalResource>();
// Work Package query states
query = new QueryStates();

@ -29,42 +29,67 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module";
import {StatusResource} from 'core-app/modules/hal/resources/status-resource';
import {States} from "core-components/states.service";
import {HalResource} from "app/modules/hal/resources/hal-resource";
export class StatusDisplayField extends DisplayField {
interface ColoredHalResource extends HalResource {
name:string;
color?:string;
}
// We need the loaded resource for the given resource since the color
// is not always embedded. Thus restrict attributes to what we can load beforehand.
export type ColoredAttributes = 'status' | 'priority';
export class ColoredDisplayField extends DisplayField {
constructor(public resource:HalResource,
public coloredAttribute:ColoredAttributes,
public schema:op.FieldSchema) {
super(resource, coloredAttribute, schema);
}
readonly states:States = this.$injector.get(States);
public get value():StatusResource {
return this.resource.status;
public get value():ColoredHalResource {
return this.resource[this.name];
}
public get valueString() {
return this.value.name;
}
public get statusId() {
public get coloredResourceCache():string {
return {
status: 'statuses',
priority: 'priorities'
}[this.coloredAttribute];
}
public get resourceId() {
return this.value.idFromLink;
}
public get loadedStatus():StatusResource {
return this.states.statuses.get(this.statusId).getValueOr(this.value);
public get loadedColorResource():ColoredHalResource {
return (this.states as any)[this.coloredResourceCache]
.get(this.resourceId)
.getValueOr(this.value);
}
public render(element:HTMLElement, displayText:string):void {
const status = this.loadedStatus;
const colored = this.loadedColorResource;
element.setAttribute('title', displayText);
const color = document.createElement('span');
color.classList.add('wp-display-field--status-color');
color.classList.add('wp-display-field--color');
const text = document.createElement('span');
text.classList.add('wp-display-field--status-text');
text.classList.add('wp-display-field--color-text');
text.textContent = displayText;
if (status.color) {
color.style.backgroundColor = status.color;
text.style.color = status.color;
if (colored.color) {
color.style.backgroundColor = colored.color;
text.style.color = colored.color;
}
element.appendChild(color);

@ -42,7 +42,7 @@ import {SpentTimeDisplayField} from '../field-types/wp-display-spent-time-field.
import {IntegerDisplayField} from "../field-types/wp-display-integer-field.module";
import {WorkPackageDisplayField} from "../field-types/wp-display-work-package-field.module";
import {FloatDisplayField} from '../field-types/wp-display-float-field.module';
import {StatusDisplayField} from 'core-components/wp-display/field-types/wp-display-status-field.module';
import {ColoredDisplayField} from 'core-components/wp-display/field-types/wp-display-colored-element-field.module';
openprojectModule
.run((wpDisplayField:WorkPackageDisplayFieldService) => {
@ -51,12 +51,10 @@ openprojectModule
.addFieldType(TextDisplayField, 'text', ['String'])
.addFieldType(FloatDisplayField, 'float', ['Float'])
.addFieldType(IntegerDisplayField, 'integer', ['Integer'])
.addFieldType(StatusDisplayField, 'status', ['status'])
.addFieldType(ColoredDisplayField, 'colored', ['status', 'priority'])
.addFieldType(ResourceDisplayField, 'resource', ['User',
'Project',
'Type',
'Status',
'Priority',
'Version',
'Category',
'CustomOption'])

@ -44,6 +44,7 @@ import {Inject, Injectable} from '@angular/core';
import {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
import {StatusDmService} from 'core-app/modules/hal/dm-services/status-dm.service';
import {StatusCacheService} from 'core-app/components/status/status-cache.service';
import {PriorityCacheService} from 'core-components/priorities/priority-cache.service';
@Injectable()
export class WorkPackageTableAdditionalElementsService {
@ -54,6 +55,7 @@ export class WorkPackageTableAdditionalElementsService {
readonly wpNotificationsService:WorkPackageNotificationService,
readonly halResourceService:HalResourceService,
readonly statusCache:StatusCacheService,
readonly priorityCache:PriorityCacheService,
readonly wpCacheService:WorkPackageCacheService,
readonly wpRelations:WorkPackageRelationsService) {
}
@ -62,6 +64,7 @@ export class WorkPackageTableAdditionalElementsService {
// Add relations to the stack
Promise.all([
this.statusCache.requireAllStatuses().then(() => []),
this.priorityCache.requireAllStatuses().then(() => []),
this.requireInvolvedRelations(rows.map(el => el.id)),
this.requireHierarchyElements(rows)
]).then((results:string[][]) => {

@ -0,0 +1,53 @@
//-- 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 {HalResourceService} from 'core-app/modules/hal/services/hal-resource.service';
import {CollectionResource} from 'core-app/modules/hal/resources/collection-resource';
import {HelpTextResource} from 'core-app/modules/hal/resources/help-text-resource';
import {PathHelperService} from 'core-components/common/path-helper/path-helper.service';
import {Injectable} from '@angular/core';
import {HalResource} from 'app/modules/hal/resources/hal-resource';
@Injectable()
export class PriorityDmService {
constructor(protected halResourceService:HalResourceService,
protected pathHelper:PathHelperService) {
}
public async loadAll():Promise<CollectionResource<HalResource>> {
return this.halResourceService
.get<CollectionResource<HalResource>>(this.pathHelper.api.v3.priorities.toString())
.toPromise();
}
public async load(id:string):Promise<HalResource> {
return this.halResourceService
.get<HalResource>(this.pathHelper.api.v3.priorities.id(id).toString())
.toPromise();
}
}

@ -45,6 +45,7 @@ import {OpenProjectHeaderInterceptor} from 'core-app/modules/hal/http/openprojec
import {UserDmService} from 'core-app/modules/hal/dm-services/user-dm.service';
import {ProjectDmService} from 'core-app/modules/hal/dm-services/project-dm.service';
import {StatusDmService} from 'core-app/modules/hal/dm-services/status-dm.service';
import {PriorityDmService} from 'core-app/modules/hal/dm-services/priority-dm.service';
@NgModule({
imports: [
@ -66,6 +67,7 @@ import {StatusDmService} from 'core-app/modules/hal/dm-services/status-dm.servic
RootDmService,
TypeDmService,
StatusDmService,
PriorityDmService,
]
})
export class OpenprojectHalModule { }

@ -41,6 +41,9 @@ module API
property :id, render_nil: true
property :name
property :position
property :color,
getter: -> (*) { color.hexcode if color },
render_nil: true
property :is_default
property :active, as: :isActive

Loading…
Cancel
Save