From fed8b9c27fd15e6de36a7dc35597c202ead8a852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=B0=D1=83=D1=84=20=D0=9B=D0=B0=D1=82=D1=8B=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 24 Apr 2025 23:45:17 +0300 Subject: [PATCH] =?UTF-8?q?SUPPORT-9133:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=20=D0=B8=D0=B7=20ervu-dashboard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/enum/TreeValuesCacheStrategy.ts | 5 + .../field/DropdownTreeViewComponent.ts | 149 ++++++++++++++++-- 2 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 frontend/src/ts/component/enum/TreeValuesCacheStrategy.ts diff --git a/frontend/src/ts/component/enum/TreeValuesCacheStrategy.ts b/frontend/src/ts/component/enum/TreeValuesCacheStrategy.ts new file mode 100644 index 0000000..92b5cef --- /dev/null +++ b/frontend/src/ts/component/enum/TreeValuesCacheStrategy.ts @@ -0,0 +1,5 @@ +export enum TreeValuesCacheStrategy { + BY_PAGE_OBJECT_ID = "BY_PAGE_OBJECT_ID", + BY_OBJECT_NAME = "BY_OBJECT_NAME", + BY_CUSTOM_NAME = "BY_CUSTOM_NAME", +} diff --git a/frontend/src/ts/component/field/DropdownTreeViewComponent.ts b/frontend/src/ts/component/field/DropdownTreeViewComponent.ts index c946e03..a3730a1 100644 --- a/frontend/src/ts/component/field/DropdownTreeViewComponent.ts +++ b/frontend/src/ts/component/field/DropdownTreeViewComponent.ts @@ -2,19 +2,29 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - ElementRef + ElementRef, + Input } from "@angular/core"; import { + AdvancedProperty, Event, InputControl, - UserService, - Visible + LocalStorageService, + NotNull, + PageContextHolder, + PageObjectUtils, + TaskParamsProvider, + Visible, + WebbpmStorage } from "@webbpm/base-package"; import {TreeItemDto} from "../../generated/component/model/TreeItemDto"; import {TreeItemRpcService} from "../../generated/component/rpc/TreeItemRpcService"; -import {DropdownTreeviewSelectI18n} from "../external/ngx-treeview/dropdown-treeview-select/dropdown-treeview-select-i18n"; +import { + DropdownTreeviewSelectI18n +} from "../external/ngx-treeview/dropdown-treeview-select/dropdown-treeview-select-i18n"; import {TreeItem, TreeviewItem} from "ngx-treeview"; +import {TreeValuesCacheStrategy} from "../enum/TreeValuesCacheStrategy"; @Component({ moduleId: module.id, @@ -26,44 +36,118 @@ import {TreeItem, TreeviewItem} from "ngx-treeview"; changeDetection: ChangeDetectionStrategy.OnPush }) export class DropdownTreeViewComponent extends InputControl { + @Input() + @AdvancedProperty() + public treeValuesCacheStrategy: TreeValuesCacheStrategy; + @Visible("treeValuesCacheStrategy == TreeValuesCacheStrategy.BY_CUSTOM_NAME") + @NotNull("treeValuesCacheStrategy == TreeValuesCacheStrategy.BY_CUSTOM_NAME") + @AdvancedProperty() + public treeValuesCustomName: string; + @Visible("false") + public cachedValue: TreeItemDto; public collapseLevel: number; public maxHeight: number; @Visible("false") public items: TreeviewItem[]; @Visible("false") - public value: any; + public value: TreeItemDto; @Visible("false") public valueChangeEvent: Event = new Event(); private rpcService: TreeItemRpcService; - constructor(el: ElementRef, cd: ChangeDetectorRef, - private i18n: DropdownTreeviewSelectI18n) { + private localStorageService: LocalStorageService; + private taskParamsProvider: TaskParamsProvider; + private pageContextHolder: PageContextHolder; + private webbpmStorage: WebbpmStorage; + private storageKey: string; + private rootValues: TreeItemDto[]; + + constructor(el: ElementRef, cd: ChangeDetectorRef, private i18n: DropdownTreeviewSelectI18n) { super(el, cd); } public initialize() { super.initialize(); this.rpcService = this.getScript(TreeItemRpcService); + + this.taskParamsProvider = this.injector.get(TaskParamsProvider); + this.localStorageService = this.injector.get(LocalStorageService); + this.pageContextHolder = this.injector.get(PageContextHolder); + this.webbpmStorage = + this.getTreeValuesStorage(this.treeValuesCacheStrategy, this.treeValuesCustomName); + this.cachedValue = this.getCachedValue(); this.loadTreeItems(); } + private getTreeValuesStorage(treeValuesCacheStrategy: TreeValuesCacheStrategy, + customKeyName: string) { + if (!treeValuesCacheStrategy) { + return null; + } + switch (treeValuesCacheStrategy) { + case TreeValuesCacheStrategy.BY_PAGE_OBJECT_ID: + this.storageKey = PageObjectUtils.getPageObjectKey(this); + return this.readWebbpmStorage(this.storageKey); + case TreeValuesCacheStrategy.BY_OBJECT_NAME: + this.storageKey = this.getObjectName(); + return this.readWebbpmStorage(this.storageKey); + case TreeValuesCacheStrategy.BY_CUSTOM_NAME: + this.storageKey = customKeyName; + return this.readWebbpmStorage(this.storageKey); + default: + throw new Error("Unknown tree values storage type = " + treeValuesCacheStrategy) + } + } + + readWebbpmStorage(treeStorageKey: string) { + if (this.pageContextHolder.isPageInBpmnContext()) { + treeStorageKey = treeStorageKey + "$" + this.taskParamsProvider.processInstanceId + } + return this.localStorageService.readTemporalWebbpmStorage(treeStorageKey); + } + @Visible() public loadTreeItems(): void { this.rpcService.loadTreeData() .then((res: TreeItemDto[]) => { this.items = res.map(value => new TreeviewItem(this.createTreeItem(value))); + this.rootValues = res; const rootItem = this.items[0]; - this.i18n.selectedItem = rootItem; - this.value = rootItem ? rootItem.value : rootItem; + if (this.cachedValue) { + const matchedItem = this.findTreeItemByValue(this.items, this.cachedValue); + if (matchedItem) { + this.i18n.selectedItem = matchedItem; + this.value = matchedItem.value; + } + } + else { + this.i18n.selectedItem = rootItem; + this.value = rootItem.value; + } this.doCollapseLevel(); this.onValueChange(this.value); this.cd.markForCheck(); }); } + private findTreeItemByValue(rootItems: TreeviewItem[], valueToFind: any): TreeviewItem | null { + for (const item of rootItems) { + if (JSON.stringify(item.value) === JSON.stringify(valueToFind)) { + return item; + } + if (item.children) { + const found = this.findTreeItemByValue(item.children, valueToFind); + if (found) { + return found; + } + } + } + return null; + } + private createTreeItem(treeItemDto: TreeItemDto): TreeItem { let treeItem: TreeItem; if (treeItemDto) { @@ -84,6 +168,7 @@ export class DropdownTreeViewComponent extends InputControl { } public onValueChange($event: any) { + this.setCachedValue(this.value); this.valueChangeEvent.trigger($event); this.applyListener(this.changeListeners); } @@ -113,20 +198,51 @@ export class DropdownTreeViewComponent extends InputControl { } } + protected setCachedValue(newValue: TreeItemDto): void { + if (this.webbpmStorage) { + this.webbpmStorage.put(this.storageKey, newValue); + } + } + + protected getCachedValue(): TreeItemDto { + if (this.webbpmStorage) { + return this.webbpmStorage.get(this.storageKey); + } + return null; + } + getPresentationValue(): string | number | boolean { - return this.value; + return this.value ? this.value.label : ''; } getValue(): any { - return this.value; + return this.value ? this.value.id : this.value; } - getValueAsModel(): any { + getValueAsModel(): TreeItemDto { return this.value ? this.value : null; } - setValue(value: any): any { - this.value = value; + setValue(value: any): void { + const foundValue: TreeItemDto = this.findValueInRootsById(value); + if (foundValue) { + this.value = foundValue; + this.onValueChange(this.value); + } + } + + private findValueInRootsById(id: any): TreeItemDto { + let searchArray: TreeItemDto[] = this.rootValues.slice(); + while (searchArray.length > 0) { + const current = searchArray.shift(); + if (current.id == id) { + return current; + } + if (current.children && current.children.length > 0) { + searchArray.push(...current.children); + } + } + return undefined; } onChange() { @@ -134,6 +250,11 @@ export class DropdownTreeViewComponent extends InputControl { this.valueChangeEvent.trigger(this.value); } + addChangeListener(onChangeFunction: Function): void { + super.addChangeListener(onChangeFunction); + onChangeFunction(); + } + subscribeToModelChange() { //empty because there is no ngModel here }