try to save highlighted attributes

pull/6715/head
Oliver Günther 6 years ago committed by Wieland Lindenthal
parent 6541cbe073
commit 1a8090402f
  1. 1
      app/models/queries/work_packages/columns/work_package_column.rb
  2. 7
      app/models/query/highlighting.rb
  3. 1
      app/services/update_query_from_params_service.rb
  4. 2
      frontend/src/app/components/wp-fast-table/builders/highlighting/row-highlight-render-pass.ts
  5. 44
      frontend/src/app/components/wp-fast-table/state/wp-table-highlighting.service.ts
  6. 49
      frontend/src/app/components/wp-fast-table/wp-table-highlight.ts
  7. 12
      frontend/src/app/components/wp-query/url-params-helper.ts
  8. 6
      frontend/src/app/components/wp-table/configuration-modal/tabs/highlighting-tab.component.html
  9. 36
      frontend/src/app/components/wp-table/configuration-modal/tabs/highlighting-tab.component.ts
  10. 3
      frontend/src/app/components/wp-table/table-state/table-state.ts
  11. 53
      frontend/src/app/modules/common/enterprise/banners.service.ts
  12. 2
      frontend/src/app/modules/common/multi-toggled-select/multi-toggled-select.component.ts
  13. 2
      frontend/src/app/modules/common/openproject-common.module.ts
  14. 5
      frontend/src/app/modules/hal/hal-link/hal-link.ts
  15. 1
      frontend/src/app/modules/hal/resources/query-resource.ts

@ -29,7 +29,6 @@
#++
class Queries::WorkPackages::Columns::WorkPackageColumn < Queries::Columns::Base
attr_accessor :highlightable
alias_method :highlightable?, :highlightable

@ -42,11 +42,10 @@ module Query::Highlighting
allow_blank: true
validates_inclusion_of :highlighted_attributes,
in: ->(*) { self.available_highlighting_columns.map{ |col| col.name.to_sym } },
in: ->(*) { available_highlighting_columns.map { |col| col.name.to_sym } },
allow_nil: true,
allow_blank: true
def available_highlighting_columns
@available_highlighting_columns ||= available_columns.select(&:highlightable?)
end
@ -59,6 +58,10 @@ module Query::Highlighting
.uniq
end
def highlighted_attributes
super.presence || []
end
def highlighting_mode
return :none unless EnterpriseToken.allows_to?(:conditional_highlighting)

@ -98,6 +98,7 @@ class UpdateQueryFromParamsService
def apply_highlighting(params)
query.highlighting_mode = params[:highlighting_mode] if params.key?(:highlighting_mode)
query.highlighted_attributes = params[:highlighted_attributes] if params.key?(:highlighted_attributes)
end
def disable_hierarchy_when_only_grouped_by(params)

@ -21,7 +21,7 @@ export class HighlightingRenderPass {
return;
}
const highlightAttribute = this.wpTableHighlighting.current;
const highlightAttribute = this.wpTableHighlighting.current.mode;
// Get the computed style to identify bright properties
const styles = window.getComputedStyle(document.body);

@ -5,36 +5,37 @@ import {Injectable} from '@angular/core';
import {States} from 'core-components/states.service';
import {HighlightingMode} from "core-components/wp-fast-table/builders/highlighting/highlighting-mode.const";
import {DynamicCssService} from "../../../modules/common/dynamic-css/dynamic-css.service";
import {WorkPackageTableHighlight} from "core-components/wp-fast-table/wp-table-highlight";
import {BannersService} from "core-app/modules/common/enterprise/banners.service";
@Injectable()
export class WorkPackageTableHighlightingService extends WorkPackageTableBaseService<HighlightingMode> implements WorkPackageQueryStateService {
public eeShowBanners:boolean = false;
export class WorkPackageTableHighlightingService extends WorkPackageTableBaseService<WorkPackageTableHighlight> implements WorkPackageQueryStateService {
public constructor(readonly states:States,
readonly Banners:BannersService,
readonly dynamicCssService:DynamicCssService,
readonly tableState:TableState) {
super(tableState);
this.eeShowBanners = jQuery('body').hasClass('ee-banners-visible');
}
public get state() {
return this.tableState.highlighting;
}
public get current():HighlightingMode {
return this.filteredMode(this.state.getValueOr('inline'));
public get current():WorkPackageTableHighlight {
let value = this.state.getValueOr(new WorkPackageTableHighlight('inline'));
return this.filteredValue(value);
}
public get isInline() {
return this.current === 'inline';
return this.current.mode === 'inline';
}
public get isDisabled() {
return this.current === 'none';
return this.current.mode === 'none';
}
public update(value:HighlightingMode) {
super.update(this.filteredMode(value));
public update(value:WorkPackageTableHighlight) {
super.update(this.filteredValue(value));
// Load dynamic highlighting CSS if enabled
if (!this.isDisabled) {
@ -42,25 +43,28 @@ export class WorkPackageTableHighlightingService extends WorkPackageTableBaseSer
}
}
public valueFromQuery(query:QueryResource):HighlightingMode {
return query.highlightingMode || this.filteredMode('inline');
public valueFromQuery(query:QueryResource):WorkPackageTableHighlight {
return this.filteredValue(new WorkPackageTableHighlight(query.highlightingMode, query.highlightedAttributes));
}
public hasChanged(query:QueryResource) {
return query.highlightingMode !== this.current;
return query.highlightingMode !== this.current.mode ||
!_.isEqual(query.highlightedAttributes, this.current.selectedAttributes);
}
public applyToQuery(query:QueryResource):boolean {
query.highlightingMode = this.current;
const current = this.current;
query.highlightingMode = current.mode;
if (current.selectedAttributes) {
query.highlightedAttributes = current.selectedAttributes;
}
return false;
}
private filteredMode(mode:HighlightingMode):HighlightingMode {
if (this.eeShowBanners) {
return 'none';
} else {
return mode;
}
private filteredValue(value:WorkPackageTableHighlight):WorkPackageTableHighlight {
this.Banners.conditional(() => value.mode = 'none');
return value;
}
}

@ -0,0 +1,49 @@
// -- 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 'core-app/modules/hal/resources/query-resource';
import {HighlightingMode} from "core-components/wp-fast-table/builders/highlighting/highlighting-mode.const";
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
export class WorkPackageTableHighlight {
constructor(public mode:HighlightingMode = 'inline',
public selectedAttributes:HalResource[]|undefined = undefined) {
}
public update(query:QueryResource|null) {
if (!query) {
this.mode = 'inline';
this.selectedAttributes = undefined;
return;
}
this.mode = query.highlightingMode;
this.selectedAttributes = query.selectedAttributes;
}
}

@ -86,6 +86,10 @@ export class UrlParamsHelperService {
paramsData.hl = query.highlightingMode;
}
if (query.highlightingMode === 'inline' && query.highlightedAttributes) {
paramsData.hla = query.highlightedAttributes.map(el => el.href);
}
paramsData.hi = !!query.showHierarchies;
paramsData.g = _.get(query.groupBy, 'id', '');
if (query.sortBy) {
@ -153,6 +157,10 @@ export class UrlParamsHelperService {
queryData.highlightingMode = properties.hl;
}
if (properties.hla) {
queryData.highlightedAttributes = properties.hla;
}
if (properties.hi === false || properties.hi === true) {
queryData.showHierarchies = properties.hi;
}
@ -212,6 +220,10 @@ export class UrlParamsHelperService {
queryData.highlightingMode = query.highlightingMode;
}
if (query.highlightedAttributes && query.highlightingMode === 'inline') {
queryData.highlightedAttributes = query.highlightedAttributes.map(el => el.href);
}
queryData.showHierarchies = !!query.showHierarchies;
queryData.groupBy = _.get(query.groupBy, 'id', '');

@ -24,9 +24,9 @@
{{ text.highlighting_mode.inline }}
&nbsp;
<multi-toggled-select [isDisabled]="highlightingMode !== 'inline'"
[availableOptions]="availableHighlightedAttributes"
[initialSelection]="selectedInlineOption"
(onValueChange)="selectedInlineOption = $event">
[availableOptions]="availableMappedHighlightedAttributes"
[initialSelection]="selectedAttributes"
(onValueChange)="selectedAttributes = $event">
</multi-toggled-select>
</label>
</div>

@ -6,6 +6,7 @@ import {HighlightingMode} from "core-components/wp-fast-table/builders/highlight
import {MultiToggledSelectOption} from "core-app/modules/common/multi-toggled-select/multi-toggled-select.component";
import {HalResource} from "core-app/modules/hal/resources/hal-resource";
import {States} from "core-app/components/states.service";
import {WorkPackageTableHighlight} from "core-components/wp-fast-table/wp-table-highlight";
@Component({
templateUrl: './highlighting-tab.component.html'
@ -13,13 +14,13 @@ import {States} from "core-app/components/states.service";
export class WpTableConfigurationHighlightingTab implements TabComponent {
// Display mode
public highlightingMode:HighlightingMode|'entire-row' = 'inline';
public highlightingMode:HighlightingMode = 'inline';
public entireRowMode:boolean = false;
public lastEntireRowAttribute:HighlightingMode = 'status';
public eeShowBanners:boolean = false;
public availableHighlightedAttributes:MultiToggledSelectOption[] = [];
public selectedInlineOption:MultiToggledSelectOption|MultiToggledSelectOption[] = [];
public availableMappedHighlightedAttributes:MultiToggledSelectOption[] = [];
public selectedAttributes:undefined|MultiToggledSelectOption|MultiToggledSelectOption[] = [];
public text = {
title: this.I18n.t('js.work_packages.table_configuration.highlighting'),
@ -45,11 +46,17 @@ export class WpTableConfigurationHighlightingTab implements TabComponent {
}
public onSave() {
this.wpTableHighlight.update(this.highlightingMode as HighlightingMode);
if (!Array.isArray(this.selectedInlineOption) && this.selectedInlineOption.value === 'all') {
let mode = this.highlightingMode;
let selectedAttributes:HalResource[]|undefined = undefined;
if (this.selectedAttributes !== undefined && _.get(this.selectedAttributes, 'value') !== 'all') {
selectedAttributes = _.castArray(this.selectedAttributes)
.map(el => _.find(this.availableHighlightedAttributes, 'href', el.value)!);
}
const newValue = new WorkPackageTableHighlight(mode, selectedAttributes);
this.wpTableHighlight.update(newValue);
}
public updateMode(mode:HighlightingMode|'entire-row') {
@ -72,19 +79,24 @@ export class WpTableConfigurationHighlightingTab implements TabComponent {
}
ngOnInit() {
this.availableHighlightedAttributes =
[this.allAttributesOption].concat(this.getAvailableAttributes(this.states.query.form.value!.schema));
this.selectedInlineOption = this.availableHighlightedAttributes[0];
this.availableMappedHighlightedAttributes =
[this.allAttributesOption].concat(this.getAvailableAttributes());
this.selectedAttributes = this.availableMappedHighlightedAttributes[0];
this.eeShowBanners = jQuery('body').hasClass('ee-banners-visible');
this.updateMode(this.wpTableHighlight.current);
this.updateMode(this.wpTableHighlight.current.mode);
if (this.eeShowBanners) {
this.updateMode('none');
}
}
public getAvailableAttributes(schema:any):MultiToggledSelectOption[] {
return schema.highlightedAttributes.allowedValues.map((el:HalResource) => ({ name: el.name, value: el.id }));
public get availableHighlightedAttributes():HalResource[] {
const schema = this.states.query.form.value!.schema;
return schema.highlightedAttributes.allowedValues;
}
public getAvailableAttributes():MultiToggledSelectOption[] {
return this.availableHighlightedAttributes.map((el:HalResource) => ({ name: el.name, value: el.href! }));
}
private get allAttributesOption():MultiToggledSelectOption {

@ -21,6 +21,7 @@ import {
} from 'core-app/modules/hal/resources/wp-collection-resource';
import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource';
import {HighlightingMode} from "core-components/wp-fast-table/builders/highlighting/highlighting-mode.const";
import {WorkPackageTableHighlight} from "core-components/wp-fast-table/wp-table-highlight";
@Injectable()
export class TableState extends StatesGroup {
@ -60,7 +61,7 @@ export class TableState extends StatesGroup {
// Hierarchies of table
hierarchies = input<WorkPackageTableHierarchies>();
// Highlighting mode
highlighting = input<HighlightingMode>();
highlighting = input<WorkPackageTableHighlight>();
// State to be updated when the table is up to date
rendered = input<RenderedRow[]>();

@ -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 {Inject, Injectable} from '@angular/core';
import {DOCUMENT} from "@angular/common";
import {PathHelperService} from "../path-helper/path-helper.service";
@Injectable()
export class BannersService {
private readonly _banners:boolean = true;
constructor(@Inject(DOCUMENT) protected documentElement:Document) {
this._banners = documentElement.body.classList.contains('ee-banners-visible');
}
public get eeShowBanners():boolean {
return this._banners;
}
public conditional(bannersVisible?:() => void, bannersNotVisible?:() => void) {
this._banners ? this.callMaybe(bannersVisible) : this.callMaybe(bannersNotVisible);
}
private callMaybe(func?:Function) {
func && func();
}
}

@ -31,7 +31,7 @@ import {I18nService} from "core-app/modules/common/i18n/i18n.service";
export interface MultiToggledSelectOption {
name:string;
singleOnly:true|undefined;
singleOnly?:true;
value:any;
}

@ -64,6 +64,7 @@ import {CKEditorPreviewService} from "core-app/modules/common/ckeditor/ckeditor-
import {ColorsAutocompleter} from "core-app/modules/common/colors/colors-autocompleter.component";
import {DynamicCssService} from "./dynamic-css/dynamic-css.service";
import {MultiToggledSelectComponent} from "core-app/modules/common/multi-toggled-select/multi-toggled-select.component";
import {BannersService} from "core-app/modules/common/enterprise/banners.service";
export function bootstrapModule(injector:Injector) {
return () => {
@ -159,6 +160,7 @@ export function bootstrapModule(injector:Injector) {
{ provide: APP_INITIALIZER, useFactory: bootstrapModule, deps: [Injector], multi: true },
I18nService,
DynamicCssService,
BannersService,
NotificationsService,
FocusHelperService,
LoadingIndicatorService,

@ -42,6 +42,11 @@ export interface HalLinkInterface {
identifier?:string;
}
export interface HalLinkSource {
href:string|null;
title:string;
}
export interface CallableHalLink extends HalLinkInterface {
$link:this;
data?:Promise<HalResource>;

@ -66,6 +66,7 @@ export class QueryResource extends HalResource {
public timelineVisible:boolean;
public timelineZoomLevel:TimelineZoomLevel;
public highlightingMode:HighlightingMode;
public highlightedAttributes:HalResource[]|undefined;
public timelineLabels:TimelineLabels;
public showHierarchies:boolean;
public public:boolean;

Loading…
Cancel
Save