@acorex/platform 20.6.0-next.22 → 20.6.0-next.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-layout-components.mjs +2 -2
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +1290 -342
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-DBysy2Ky.mjs → acorex-platform-themes-default-entity-master-list-view.component-Cym8pq0v.mjs} +3 -3
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-DBysy2Ky.mjs.map → acorex-platform-themes-default-entity-master-list-view.component-Cym8pq0v.mjs.map} +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +2 -2
- package/layout/entity/index.d.ts +73 -7
- package/package.json +5 -5
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { AXToastService } from '@acorex/components/toast';
|
|
2
2
|
import * as i6 from '@acorex/core/translation';
|
|
3
3
|
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
4
|
-
import * as i4 from '@acorex/platform/common';
|
|
4
|
+
import * as i4$1 from '@acorex/platform/common';
|
|
5
5
|
import { AXPSettingService, AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPRefreshEvent, AXPReloadEvent, AXPCommonSettings, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
|
|
6
|
-
import * as i1$
|
|
6
|
+
import * as i1$1 from '@acorex/platform/core';
|
|
7
7
|
import { AXPDeviceService, AXPBroadcastEventService, resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPPlatformScope, AXHighlightService, extractValue, setSmart, getChangedPaths, AXPSystemActionType } from '@acorex/platform/core';
|
|
8
8
|
import * as i0 from '@angular/core';
|
|
9
9
|
import { InjectionToken, inject, Injector, runInInjectionContext, Injectable, input, viewChild, signal, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, computed, effect, Input, afterNextRender, ViewEncapsulation, ChangeDetectorRef, viewChildren, linkedSignal, untracked, HostBinding, ViewChild, NgModule } from '@angular/core';
|
|
10
10
|
import { Subject, takeUntil } from 'rxjs';
|
|
11
11
|
import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
|
|
12
|
-
import { merge, castArray, get, cloneDeep, set, orderBy, isNil,
|
|
12
|
+
import { merge, castArray, get, cloneDeep, set, orderBy, isNil, isEmpty, isEqual, sortBy } from 'lodash-es';
|
|
13
13
|
import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
|
|
14
14
|
import { Router, RouterModule, ROUTES } from '@angular/router';
|
|
15
15
|
import * as i3 from '@acorex/components/button';
|
|
16
16
|
import { AXButtonModule } from '@acorex/components/button';
|
|
17
|
-
import * as
|
|
17
|
+
import * as i4 from '@acorex/components/loading';
|
|
18
18
|
import { AXLoadingModule } from '@acorex/components/loading';
|
|
19
19
|
import * as i2 from '@acorex/components/popover';
|
|
20
20
|
import { AXPopoverModule } from '@acorex/components/popover';
|
|
@@ -33,32 +33,33 @@ import { AXDialogService } from '@acorex/components/dialog';
|
|
|
33
33
|
import { AXLoadingDialogService } from '@acorex/components/loading-dialog';
|
|
34
34
|
import { AXPopupService } from '@acorex/components/popup';
|
|
35
35
|
import { AXPlatform } from '@acorex/core/platform';
|
|
36
|
+
import * as i2$1 from '@acorex/components/check-box';
|
|
36
37
|
import { AXCheckBoxModule } from '@acorex/components/check-box';
|
|
37
|
-
import * as
|
|
38
|
+
import * as i3$2 from '@acorex/components/decorators';
|
|
38
39
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
39
40
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
40
|
-
import * as
|
|
41
|
+
import * as i4$2 from '@acorex/components/search-box';
|
|
41
42
|
import { AXSearchBoxModule, AXSearchBoxComponent } from '@acorex/components/search-box';
|
|
42
|
-
import * as
|
|
43
|
+
import * as i5$1 from '@acorex/components/skeleton';
|
|
43
44
|
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
44
45
|
import { AXTreeViewComponent } from '@acorex/components/tree-view';
|
|
45
46
|
import { AXPStateMessageComponent, AXPDataSelectorService, AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/components';
|
|
46
|
-
import * as i1
|
|
47
|
+
import * as i1 from '@angular/forms';
|
|
47
48
|
import { FormsModule } from '@angular/forms';
|
|
48
49
|
import * as i2$2 from '@acorex/components/badge';
|
|
49
50
|
import { AXBadgeModule } from '@acorex/components/badge';
|
|
50
|
-
import * as i5$
|
|
51
|
+
import * as i5$2 from '@acorex/components/form';
|
|
51
52
|
import { AXFormModule } from '@acorex/components/form';
|
|
53
|
+
import * as i6$1 from '@acorex/components/tag-box';
|
|
54
|
+
import { AXTagBoxModule, AXTagBoxComponent } from '@acorex/components/tag-box';
|
|
52
55
|
import { AXValidationModule } from '@acorex/core/validation';
|
|
53
56
|
import { AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXP_NAME_PROPERTY, AXPFileUploaderWidgetService } from '@acorex/platform/layout/widgets';
|
|
54
|
-
import * as i4$
|
|
57
|
+
import * as i4$3 from '@acorex/components/dropdown';
|
|
55
58
|
import { AXDropdownModule } from '@acorex/components/dropdown';
|
|
56
59
|
import * as i7 from '@acorex/components/select-box';
|
|
57
60
|
import { AXSelectBoxModule } from '@acorex/components/select-box';
|
|
58
61
|
import * as i2$3 from '@acorex/components/text-box';
|
|
59
62
|
import { AXTextBoxModule, AXTextBoxComponent } from '@acorex/components/text-box';
|
|
60
|
-
import * as i6$1 from '@acorex/components/tag-box';
|
|
61
|
-
import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
|
|
62
63
|
import { transform, isEqual as isEqual$1 } from 'lodash';
|
|
63
64
|
|
|
64
65
|
function ensureListActions(ctx) {
|
|
@@ -1035,7 +1036,7 @@ class AXPCreateEntityCommand {
|
|
|
1035
1036
|
const entityRef = await this.entityService.resolve(moduleName, entityName);
|
|
1036
1037
|
let dialogRef;
|
|
1037
1038
|
try {
|
|
1038
|
-
let chain = this.entityForm.entity(`${moduleName}.${entityName}`).create(
|
|
1039
|
+
let chain = this.entityForm.entity(`${moduleName}.${entityName}`).create(data);
|
|
1039
1040
|
chain.actions((actions) => {
|
|
1040
1041
|
actions.cancel('@general:actions.cancel.title');
|
|
1041
1042
|
actions.submit('@general:actions.create.title');
|
|
@@ -1680,7 +1681,7 @@ class AXPEntityDetailPopoverComponent {
|
|
|
1680
1681
|
return importantProperties;
|
|
1681
1682
|
}
|
|
1682
1683
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityDetailPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1683
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityDetailPopoverComponent, isStandalone: true, selector: "axp-entity-detail-popover", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: true, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "detailPopover", first: true, predicate: ["detailPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n @if (entityDetails()?.entityData?.[textField()]) {\n {{ entityDetails()?.entityData[textField()] }}\n } @else {\n {{ item()?.[textField()] }}\n }\n </h3>\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of getEntityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button [color]=\"'primary'\" [look]=\"'solid'\" text=\"Open Details\" (click)=\"navigateToDetails()\"> </ax-button>\n </div>\n }\n </div>\n</ax-popover>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type:
|
|
1684
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityDetailPopoverComponent, isStandalone: true, selector: "axp-entity-detail-popover", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: true, transformFunction: null }, entityId: { classPropertyName: "entityId", publicName: "entityId", isSignal: true, isRequired: true, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "detailPopover", first: true, predicate: ["detailPopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<ax-popover [openOn]=\"'manual'\" #detailPopover (openChange)=\"onDetailPopoverOpenChange($event)\">\n <div class=\"ax-lightest-surface ax-border ax-rounded-lg ax-shadow-lg ax-p-4 ax-min-w-[400px]\">\n <div class=\"ax-mb-4 ax-border-b ax-pb-2\">\n <h3 class=\"ax-text-base ax-font-semibold ax-text-on-lightest-surface\">\n @if (entityDetails()?.entityData?.[textField()]) {\n {{ entityDetails()?.entityData[textField()] }}\n } @else {\n {{ item()?.[textField()] }}\n }\n </h3>\n </div>\n @if (isLoadingDetails()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-py-8\">\n <ax-loading>Loading details...</ax-loading>\n </div>\n } @else if (entityDetails()) {\n <div class=\"ax-space-y-3 ax-mb-4\">\n <!-- Important Entity Data -->\n @if (entityDetails()?.entityData) {\n <axp-widgets-container [context]=\"entityDetails()?.entityData\">\n <div class=\"ax-space-y-2\">\n @for (item of getEntityPropertiesWithWidgets(); track item.name) {\n <div class=\"ax-flex ax-justify-between ax-items-center\">\n <span class=\"ax-text-sm ax-font-medium\">{{ item.title | translate | async }}:</span>\n <div class=\"ax-flex-1 ax-ml-2 ax-max-w-48\">\n <ng-container axp-widget-renderer [node]=\"item.node\" [mode]=\"'view'\"></ng-container>\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n }\n </div>\n <div class=\"ax-flex ax-gap-2 ax-justify-end ax-sm\">\n <ax-button [color]=\"'primary'\" [look]=\"'solid'\" text=\"Open Details\" (click)=\"navigateToDetails()\"> </ax-button>\n </div>\n }\n </div>\n</ax-popover>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i3$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i3$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1684
1685
|
}
|
|
1685
1686
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityDetailPopoverComponent, decorators: [{
|
|
1686
1687
|
type: Component,
|
|
@@ -4324,24 +4325,48 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
4324
4325
|
message: {
|
|
4325
4326
|
code: 'ACTION_NOT_FOUND',
|
|
4326
4327
|
text: `Action ${commandName} not found`,
|
|
4327
|
-
}
|
|
4328
|
+
},
|
|
4328
4329
|
};
|
|
4329
4330
|
}
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4331
|
+
if (context.commandService.exists(commandName)) {
|
|
4332
|
+
// check options for evaluation
|
|
4333
|
+
await context.commandService.execute(commandName, {
|
|
4334
|
+
__context__: {
|
|
4335
|
+
entity: getEntityInfo(entityDef).source,
|
|
4336
|
+
entityInfo: {
|
|
4337
|
+
name: entityDef.name,
|
|
4338
|
+
module: entityDef.module,
|
|
4339
|
+
title: entityDef.title,
|
|
4340
|
+
parentKey: entityDef.parentKey,
|
|
4341
|
+
source: `${entityDef.module}.${entityDef.name}`,
|
|
4342
|
+
},
|
|
4343
|
+
data: action.scope == AXPEntityCommandScope.Selected
|
|
4344
|
+
? executeContext
|
|
4345
|
+
: action.options?.['process']?.data || null,
|
|
4346
|
+
options: action.options,
|
|
4347
|
+
metadata: action.metadata,
|
|
4348
|
+
},
|
|
4349
|
+
options: action.options,
|
|
4350
|
+
metadata: action.metadata,
|
|
4351
|
+
});
|
|
4352
|
+
}
|
|
4353
|
+
else {
|
|
4354
|
+
await context.workflowService.execute(commandName, {
|
|
4355
|
+
entity: getEntityInfo(entityDef).source,
|
|
4356
|
+
entityInfo: {
|
|
4357
|
+
name: entityDef.name,
|
|
4358
|
+
module: entityDef.module,
|
|
4359
|
+
title: entityDef.title,
|
|
4360
|
+
parentKey: entityDef.parentKey,
|
|
4361
|
+
source: `${entityDef.module}.${entityDef.name}`,
|
|
4362
|
+
},
|
|
4363
|
+
data: action.scope == AXPEntityCommandScope.Selected
|
|
4364
|
+
? executeContext
|
|
4365
|
+
: action.options?.['process']?.data || null,
|
|
4366
|
+
options: action.options,
|
|
4367
|
+
metadata: action.metadata,
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4345
4370
|
return { success: true };
|
|
4346
4371
|
}
|
|
4347
4372
|
catch (error) {
|
|
@@ -4368,6 +4393,7 @@ class AXPPageListConverter extends AXPBaseRelatedEntityConverter {
|
|
|
4368
4393
|
entity: relatedEntity.entity,
|
|
4369
4394
|
showEntityActions: false,
|
|
4370
4395
|
actions: evaluatedActions,
|
|
4396
|
+
includeColumns: relatedEntity.columns,
|
|
4371
4397
|
},
|
|
4372
4398
|
},
|
|
4373
4399
|
],
|
|
@@ -5275,7 +5301,7 @@ class AXPLayoutAdapterFactory {
|
|
|
5275
5301
|
const title = await dependencies.expressionEvaluator.evaluate(entity.interfaces?.master?.single?.title, rootContext);
|
|
5276
5302
|
return title;
|
|
5277
5303
|
}
|
|
5278
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }, { token: i4.AXPFilterOperatorMiddlewareService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5304
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutAdapterFactory, deps: [{ token: AXPRelatedEntityConverterFactory }, { token: AXPMainEntityContentBuilder }, { token: AXPLayoutAdapterBuilder }, { token: i4$1.AXPFilterOperatorMiddlewareService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5279
5305
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutAdapterFactory, providedIn: 'root' }); }
|
|
5280
5306
|
}
|
|
5281
5307
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutAdapterFactory, decorators: [{
|
|
@@ -5283,7 +5309,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
5283
5309
|
args: [{
|
|
5284
5310
|
providedIn: 'root',
|
|
5285
5311
|
}]
|
|
5286
|
-
}], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4.AXPFilterOperatorMiddlewareService }] });
|
|
5312
|
+
}], ctorParameters: () => [{ type: AXPRelatedEntityConverterFactory }, { type: AXPMainEntityContentBuilder }, { type: AXPLayoutAdapterBuilder }, { type: i4$1.AXPFilterOperatorMiddlewareService }] });
|
|
5287
5313
|
|
|
5288
5314
|
const AXPLayoutDetailsViewRouteResolver = async (route, state, entityResolver = inject(AXPEntityDefinitionRegistryService), expressionEvaluator = inject(AXPExpressionEvaluatorService), session = inject(AXPSessionService), formatService = inject(AXFormatService), workflowService = inject(AXPWorkflowService), commandService = inject(AXPCommandService), layoutAdapterFactory = inject(AXPLayoutAdapterFactory)) => {
|
|
5289
5315
|
const moduleName = route.parent?.paramMap.get('module');
|
|
@@ -5905,7 +5931,6 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
5905
5931
|
this.textField = signal('title', ...(ngDevMode ? [{ debugName: "textField" }] : []));
|
|
5906
5932
|
this.valueField = signal('id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
|
|
5907
5933
|
this.allowMultiple = signal(false, ...(ngDevMode ? [{ debugName: "allowMultiple" }] : []));
|
|
5908
|
-
this.selectionBehavior = signal('all', ...(ngDevMode ? [{ debugName: "selectionBehavior" }] : []));
|
|
5909
5934
|
this.selectedValues = signal([], ...(ngDevMode ? [{ debugName: "selectedValues" }] : []));
|
|
5910
5935
|
this.searchPlaceholder = signal('@general:terms.interface.category.search.placeholder', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
|
|
5911
5936
|
this.excludedNodeId = signal(undefined, ...(ngDevMode ? [{ debugName: "excludedNodeId" }] : [])); // Node ID to disable
|
|
@@ -5924,6 +5949,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
5924
5949
|
this.noRecordsTitle = signal('', ...(ngDevMode ? [{ debugName: "noRecordsTitle" }] : []));
|
|
5925
5950
|
this.currentSearchTerm = null;
|
|
5926
5951
|
this.isRefreshing = false;
|
|
5952
|
+
this.isUpdatingSelection = false; // Flag to prevent recursive updates during batch operations
|
|
5927
5953
|
/**
|
|
5928
5954
|
* Computed property to check if we should show the "no search results" empty state.
|
|
5929
5955
|
* Returns true when search is active, not searching, and no results found.
|
|
@@ -5943,6 +5969,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
5943
5969
|
this.relevantNodeIds = new Set(); // For search filtering
|
|
5944
5970
|
this.expandedNodesBeforeSearch = []; // Store expanded nodes before search to restore after
|
|
5945
5971
|
this.nodesExpandedDuringSearch = []; // Track nodes we expanded during search
|
|
5972
|
+
this.isInitializing = false; // Flag to track if we're in initialization phase
|
|
5946
5973
|
/** Datasource callback for tree-view component. */
|
|
5947
5974
|
this.datasource = async (id) => {
|
|
5948
5975
|
if (!this.treeData || !this.treeConfig) {
|
|
@@ -5994,15 +6021,42 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
5994
6021
|
this.markNodeAsSelectedIfNeeded(node);
|
|
5995
6022
|
});
|
|
5996
6023
|
// After children load, programmatically select pre-selected nodes
|
|
6024
|
+
// Use a small delay to ensure nodes are fully added to tree structure
|
|
5997
6025
|
const treeComponent = this.tree();
|
|
5998
6026
|
if (treeComponent) {
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
const
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6027
|
+
// Use setTimeout to ensure nodes are in tree structure before selecting
|
|
6028
|
+
setTimeout(() => {
|
|
6029
|
+
const selectedIds = this.selectedNodeIds();
|
|
6030
|
+
childNodes.forEach((node) => {
|
|
6031
|
+
const nodeId = String(node['id'] ?? '');
|
|
6032
|
+
if (nodeId && selectedIds.includes(nodeId) && nodeId !== 'all') {
|
|
6033
|
+
try {
|
|
6034
|
+
// Try to find and select the node
|
|
6035
|
+
const treeNode = treeComponent.findNode(nodeId);
|
|
6036
|
+
if (treeNode) {
|
|
6037
|
+
treeComponent.selectNode(nodeId);
|
|
6038
|
+
}
|
|
6039
|
+
else {
|
|
6040
|
+
// If node not found, try again after a short delay (might still be loading)
|
|
6041
|
+
setTimeout(() => {
|
|
6042
|
+
try {
|
|
6043
|
+
const retryNode = treeComponent.findNode(nodeId);
|
|
6044
|
+
if (retryNode) {
|
|
6045
|
+
treeComponent.selectNode(nodeId);
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
catch {
|
|
6049
|
+
// Node still not found, will be selected when it loads
|
|
6050
|
+
}
|
|
6051
|
+
}, 50);
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
catch (error) {
|
|
6055
|
+
// Node might not be in tree yet, will be selected when it loads
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
});
|
|
6059
|
+
}, 10);
|
|
6006
6060
|
}
|
|
6007
6061
|
return childNodes;
|
|
6008
6062
|
};
|
|
@@ -6021,6 +6075,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6021
6075
|
return;
|
|
6022
6076
|
}
|
|
6023
6077
|
this.loading.set(true);
|
|
6078
|
+
this.isInitializing = true; // Mark that we're in initialization phase
|
|
6024
6079
|
try {
|
|
6025
6080
|
this.treeConfig = {
|
|
6026
6081
|
entityKey: this.entityKey(),
|
|
@@ -6030,6 +6085,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6030
6085
|
this.treeData = await this.categoryTreeService.initializeCategoryTree(this.treeConfig);
|
|
6031
6086
|
if (!this.treeData) {
|
|
6032
6087
|
this.loading.set(false);
|
|
6088
|
+
this.isInitializing = false;
|
|
6033
6089
|
return;
|
|
6034
6090
|
}
|
|
6035
6091
|
// Get parentKey from entity definition
|
|
@@ -6037,13 +6093,22 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6037
6093
|
this.treeConfig.parentKey = this.treeData.categoryEntityDef.parentKey;
|
|
6038
6094
|
}
|
|
6039
6095
|
// Initialize selected nodes and load their data into cache
|
|
6096
|
+
// Wait for tree to be ready before syncing selection
|
|
6097
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
6040
6098
|
await this.updateSelectedNodes(this.selectedValues());
|
|
6099
|
+
// After initial sync, wait a bit more and sync again to catch any nodes that loaded late
|
|
6100
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
6101
|
+
const finalSelectedIds = this.selectedNodeIds();
|
|
6102
|
+
if (finalSelectedIds.length > 0) {
|
|
6103
|
+
await this.syncSelectionWithTree(finalSelectedIds);
|
|
6104
|
+
}
|
|
6041
6105
|
}
|
|
6042
6106
|
catch (error) {
|
|
6043
6107
|
console.error('Error loading entity definition:', error);
|
|
6044
6108
|
}
|
|
6045
6109
|
finally {
|
|
6046
6110
|
this.loading.set(false);
|
|
6111
|
+
this.isInitializing = false; // Mark initialization as complete
|
|
6047
6112
|
}
|
|
6048
6113
|
}
|
|
6049
6114
|
//#endregion
|
|
@@ -6499,11 +6564,22 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6499
6564
|
if (nodeData && typeof nodeData === 'object' && nodeData !== null && !Array.isArray(nodeData)) {
|
|
6500
6565
|
this.nodeDataCache.set(nodeId, nodeData);
|
|
6501
6566
|
}
|
|
6567
|
+
// NOTE: We do NOT call loadAndSelectChildrenRecursively here
|
|
6568
|
+
// The recursive selection should only happen when user explicitly selects a node via checkbox
|
|
6569
|
+
// (handled in handleCheckboxChange). This prevents intermediate parent states from
|
|
6570
|
+
// triggering unwanted sibling selections.
|
|
6502
6571
|
}
|
|
6503
6572
|
async onSelectionChange(event) {
|
|
6573
|
+
// Don't process during initialization or batch updates - let those handle it
|
|
6574
|
+
if (this.isInitializing || this.isUpdatingSelection) {
|
|
6575
|
+
return;
|
|
6576
|
+
}
|
|
6504
6577
|
// Update selected node IDs from the tree component's selection state
|
|
6578
|
+
// The tree component with intermediate-nested behavior automatically manages parent states
|
|
6505
6579
|
const selectedNodes = event.selectedNodes || [];
|
|
6506
6580
|
const selectedIds = selectedNodes.map((node) => String(node['id'] ?? '')).filter((id) => id && id !== 'all');
|
|
6581
|
+
// Sync with tree component's selection state
|
|
6582
|
+
// This includes parents that are automatically selected when all children are selected
|
|
6507
6583
|
this.selectedNodeIds.set(selectedIds);
|
|
6508
6584
|
// Cache node data for all selected nodes
|
|
6509
6585
|
selectedNodes.forEach((node) => {
|
|
@@ -6568,171 +6644,884 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6568
6644
|
}
|
|
6569
6645
|
/**
|
|
6570
6646
|
* Handles checkbox change event to toggle node selection
|
|
6647
|
+
* In multiple mode: recursively selects/deselects children
|
|
6648
|
+
* Parent states are handled automatically by tree component's intermediate-nested behavior
|
|
6571
6649
|
*/
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
// return;
|
|
6575
|
-
// }
|
|
6576
|
-
// const id = String(nodeId);
|
|
6577
|
-
// const treeComponent = this.tree();
|
|
6578
|
-
// if (!treeComponent) {
|
|
6579
|
-
// return;
|
|
6580
|
-
// }
|
|
6581
|
-
// if (checked) {
|
|
6582
|
-
// // Select the node
|
|
6583
|
-
// treeComponent.selectNode(id);
|
|
6584
|
-
// } else {
|
|
6585
|
-
// // Deselect the node
|
|
6586
|
-
// treeComponent.deselectNode(id);
|
|
6587
|
-
// }
|
|
6588
|
-
// }
|
|
6589
|
-
//#endregion
|
|
6590
|
-
async updateSelectedNodes(selectedIds) {
|
|
6591
|
-
if (!selectedIds || selectedIds.length === 0) {
|
|
6592
|
-
this.selectedNodeIds.set([]);
|
|
6650
|
+
async handleCheckboxChange(nodeId, checked) {
|
|
6651
|
+
if (!nodeId || nodeId === 'all') {
|
|
6593
6652
|
return;
|
|
6594
6653
|
}
|
|
6595
|
-
const
|
|
6596
|
-
this.
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6654
|
+
const id = String(nodeId);
|
|
6655
|
+
const treeComponent = this.tree();
|
|
6656
|
+
if (!treeComponent) {
|
|
6657
|
+
return;
|
|
6658
|
+
}
|
|
6659
|
+
if (checked) {
|
|
6660
|
+
// Select the node and recursively select all its children
|
|
6661
|
+
await this.selectNodeAndChildren(id);
|
|
6662
|
+
}
|
|
6663
|
+
else {
|
|
6664
|
+
// Deselect the node and recursively deselect all its children
|
|
6665
|
+
await this.deselectNodeAndChildren(id);
|
|
6666
|
+
}
|
|
6667
|
+
// Note: Parent states (select/intermediate) are handled automatically by the tree component
|
|
6668
|
+
// with selectionBehavior: 'intermediate-nested'. We don't need to manually update them.
|
|
6603
6669
|
}
|
|
6604
6670
|
/**
|
|
6605
|
-
*
|
|
6606
|
-
* This is critical for pre-selected values in collapsed branches.
|
|
6671
|
+
* Selects a node and recursively selects all its children
|
|
6607
6672
|
*/
|
|
6608
|
-
async
|
|
6609
|
-
|
|
6673
|
+
async selectNodeAndChildren(nodeId) {
|
|
6674
|
+
const treeComponent = this.tree();
|
|
6675
|
+
if (!treeComponent) {
|
|
6610
6676
|
return;
|
|
6611
6677
|
}
|
|
6612
|
-
//
|
|
6613
|
-
|
|
6614
|
-
|
|
6678
|
+
// Set flag to prevent recursive updates during batch operation
|
|
6679
|
+
this.isUpdatingSelection = true;
|
|
6680
|
+
try {
|
|
6681
|
+
// Collect all nodes to select (node + all descendants)
|
|
6682
|
+
const nodesToSelect = new Set([nodeId]);
|
|
6683
|
+
await this.collectAllDescendants(nodeId, nodesToSelect);
|
|
6684
|
+
// Batch update selectedNodeIds
|
|
6685
|
+
const currentSelected = this.selectedNodeIds();
|
|
6686
|
+
const newSelected = [...currentSelected];
|
|
6687
|
+
for (const id of nodesToSelect) {
|
|
6688
|
+
if (!newSelected.includes(id)) {
|
|
6689
|
+
newSelected.push(id);
|
|
6690
|
+
}
|
|
6691
|
+
}
|
|
6692
|
+
this.selectedNodeIds.set(newSelected);
|
|
6693
|
+
// Batch select in tree component (with small delays to prevent glitches)
|
|
6694
|
+
for (const id of nodesToSelect) {
|
|
6695
|
+
try {
|
|
6696
|
+
const node = treeComponent.findNode(id);
|
|
6697
|
+
if (node) {
|
|
6698
|
+
treeComponent.selectNode(id);
|
|
6699
|
+
// Small delay to prevent overwhelming the tree component
|
|
6700
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
catch {
|
|
6704
|
+
// Node might not be in tree yet
|
|
6705
|
+
}
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
finally {
|
|
6709
|
+
this.isUpdatingSelection = false;
|
|
6710
|
+
}
|
|
6711
|
+
}
|
|
6712
|
+
/**
|
|
6713
|
+
* Collects all descendant node IDs recursively
|
|
6714
|
+
*/
|
|
6715
|
+
async collectAllDescendants(parentId, collection) {
|
|
6716
|
+
if (!this.treeData || !this.treeConfig || !parentId || parentId === 'all') {
|
|
6615
6717
|
return;
|
|
6616
6718
|
}
|
|
6617
6719
|
try {
|
|
6618
|
-
const
|
|
6619
|
-
|
|
6620
|
-
if (!categoryEntityQueryFunc) {
|
|
6720
|
+
const childNodes = await this.datasource(parentId);
|
|
6721
|
+
if (!childNodes || childNodes.length === 0) {
|
|
6621
6722
|
return;
|
|
6622
6723
|
}
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
})),
|
|
6632
|
-
logic: 'or',
|
|
6633
|
-
},
|
|
6634
|
-
};
|
|
6635
|
-
const res = await categoryEntityQueryFunc(event);
|
|
6636
|
-
if (res?.items) {
|
|
6637
|
-
// Cache the fetched node data
|
|
6638
|
-
res.items.forEach((item) => {
|
|
6639
|
-
const itemId = String(item[valueField] ?? '');
|
|
6640
|
-
if (itemId) {
|
|
6641
|
-
this.nodeDataCache.set(itemId, item);
|
|
6724
|
+
for (const childNode of childNodes) {
|
|
6725
|
+
const childId = String(childNode['id'] ?? '');
|
|
6726
|
+
if (childId && childId !== 'all' && !collection.has(childId)) {
|
|
6727
|
+
collection.add(childId);
|
|
6728
|
+
// Cache node data
|
|
6729
|
+
const nodeData = childNode['data'];
|
|
6730
|
+
if (nodeData && typeof nodeData === 'object') {
|
|
6731
|
+
this.nodeDataCache.set(childId, nodeData);
|
|
6642
6732
|
}
|
|
6643
|
-
|
|
6733
|
+
else if (childNode && typeof childNode === 'object') {
|
|
6734
|
+
const valueField = this.treeConfig.valueField || 'id';
|
|
6735
|
+
const textField = this.treeConfig.textField || 'title';
|
|
6736
|
+
const dataObj = {
|
|
6737
|
+
[valueField]: childId,
|
|
6738
|
+
[textField]: childNode['title'] ?? '',
|
|
6739
|
+
...childNode,
|
|
6740
|
+
};
|
|
6741
|
+
this.nodeDataCache.set(childId, dataObj);
|
|
6742
|
+
}
|
|
6743
|
+
// Recursively collect descendants
|
|
6744
|
+
await this.collectAllDescendants(childId, collection);
|
|
6745
|
+
}
|
|
6644
6746
|
}
|
|
6645
6747
|
}
|
|
6646
6748
|
catch (error) {
|
|
6647
|
-
console.error(
|
|
6749
|
+
console.error(`Error collecting descendants for node ${parentId}:`, error);
|
|
6648
6750
|
}
|
|
6649
6751
|
}
|
|
6650
6752
|
/**
|
|
6651
|
-
*
|
|
6652
|
-
* This ensures pre-selected nodes appear selected when the tree is rendered.
|
|
6753
|
+
* Deselects a node and recursively deselects all its children
|
|
6653
6754
|
*/
|
|
6654
|
-
|
|
6655
|
-
const
|
|
6656
|
-
if (
|
|
6755
|
+
async deselectNodeAndChildren(nodeId) {
|
|
6756
|
+
const treeComponent = this.tree();
|
|
6757
|
+
if (!treeComponent) {
|
|
6657
6758
|
return;
|
|
6658
6759
|
}
|
|
6659
|
-
//
|
|
6660
|
-
this.
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6760
|
+
// Set flag to prevent recursive updates during batch operation
|
|
6761
|
+
this.isUpdatingSelection = true;
|
|
6762
|
+
try {
|
|
6763
|
+
// Collect all nodes to deselect (node + all descendants)
|
|
6764
|
+
const nodesToDeselect = new Set([nodeId]);
|
|
6765
|
+
await this.collectAllDescendants(nodeId, nodesToDeselect);
|
|
6766
|
+
// Batch update selectedNodeIds
|
|
6767
|
+
const currentSelected = this.selectedNodeIds();
|
|
6768
|
+
const newSelected = currentSelected.filter((id) => !nodesToDeselect.has(id));
|
|
6769
|
+
this.selectedNodeIds.set(newSelected);
|
|
6770
|
+
// Batch deselect in tree component (with small delays to prevent glitches)
|
|
6771
|
+
for (const id of nodesToDeselect) {
|
|
6772
|
+
try {
|
|
6773
|
+
const node = treeComponent.findNode(id);
|
|
6774
|
+
if (node) {
|
|
6775
|
+
treeComponent.deselectNode(id);
|
|
6776
|
+
// Small delay to prevent overwhelming the tree component
|
|
6777
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
catch {
|
|
6781
|
+
// Node might not be in tree
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6667
6784
|
}
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
* Marks a single node as selected if it's in the selectedNodeIds list.
|
|
6671
|
-
*/
|
|
6672
|
-
markNodeAsSelectedIfNeeded(node) {
|
|
6673
|
-
const selectedIds = this.selectedNodeIds();
|
|
6674
|
-
const nodeId = String(node['id'] ?? '');
|
|
6675
|
-
if (nodeId && selectedIds.includes(nodeId)) {
|
|
6676
|
-
node['selected'] = true;
|
|
6785
|
+
finally {
|
|
6786
|
+
this.isUpdatingSelection = false;
|
|
6677
6787
|
}
|
|
6678
6788
|
}
|
|
6679
6789
|
/**
|
|
6680
|
-
*
|
|
6790
|
+
* Recursively deselects all children of a parent node
|
|
6681
6791
|
*/
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
node['disabled'] = true;
|
|
6792
|
+
async loadAndDeselectChildrenRecursively(parentId) {
|
|
6793
|
+
if (!this.treeData || !this.treeConfig || !parentId || parentId === 'all') {
|
|
6794
|
+
return;
|
|
6686
6795
|
}
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6796
|
+
const treeComponent = this.tree();
|
|
6797
|
+
if (!treeComponent) {
|
|
6798
|
+
return;
|
|
6799
|
+
}
|
|
6800
|
+
try {
|
|
6801
|
+
// Load children using datasource
|
|
6802
|
+
const childNodes = await this.datasource(parentId);
|
|
6803
|
+
if (!childNodes || childNodes.length === 0) {
|
|
6804
|
+
return;
|
|
6805
|
+
}
|
|
6806
|
+
const childIdsToDeselect = [];
|
|
6807
|
+
// Collect all child IDs
|
|
6808
|
+
for (const childNode of childNodes) {
|
|
6809
|
+
const childId = String(childNode['id'] ?? '');
|
|
6810
|
+
if (childId && childId !== 'all') {
|
|
6811
|
+
childIdsToDeselect.push(childId);
|
|
6812
|
+
}
|
|
6813
|
+
}
|
|
6814
|
+
// Remove children from selectedNodeIds
|
|
6815
|
+
const currentSelected = this.selectedNodeIds();
|
|
6816
|
+
const updatedSelected = currentSelected.filter((id) => !childIdsToDeselect.includes(id));
|
|
6817
|
+
this.selectedNodeIds.set(updatedSelected);
|
|
6818
|
+
// Deselect in tree component
|
|
6819
|
+
for (const childId of childIdsToDeselect) {
|
|
6820
|
+
try {
|
|
6821
|
+
treeComponent.deselectNode(childId);
|
|
6822
|
+
}
|
|
6823
|
+
catch {
|
|
6824
|
+
// Node might not be in tree
|
|
6825
|
+
}
|
|
6826
|
+
}
|
|
6827
|
+
// Recursively deselect children of each child
|
|
6828
|
+
await Promise.all(childIdsToDeselect.map((childId) => this.loadAndDeselectChildrenRecursively(childId)));
|
|
6829
|
+
}
|
|
6830
|
+
catch (error) {
|
|
6831
|
+
console.error(`Error deselecting children for node ${parentId}:`, error);
|
|
6693
6832
|
}
|
|
6694
6833
|
}
|
|
6695
6834
|
/**
|
|
6696
|
-
*
|
|
6835
|
+
* Updates parent states based on children selection (select/intermediate)
|
|
6836
|
+
* Called after a node is selected/deselected to update parent checkbox states
|
|
6697
6837
|
*/
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6838
|
+
async updateParentStates(changedNodeId) {
|
|
6839
|
+
if (!this.treeData || !this.treeConfig || !this.allowMultiple()) {
|
|
6840
|
+
return;
|
|
6841
|
+
}
|
|
6842
|
+
const parentKey = this.treeData.categoryEntityDef?.parentKey;
|
|
6843
|
+
if (!parentKey) {
|
|
6844
|
+
return; // No parent key means flat structure
|
|
6702
6845
|
}
|
|
6703
|
-
this.markNodesAsSelected(rootNode);
|
|
6704
|
-
// Sync selection with tree component after a short delay to ensure tree is rendered
|
|
6705
6846
|
const treeComponent = this.tree();
|
|
6706
|
-
if (treeComponent) {
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6847
|
+
if (!treeComponent) {
|
|
6848
|
+
return;
|
|
6849
|
+
}
|
|
6850
|
+
// Start from the changed node's parent and work up the tree
|
|
6851
|
+
const processedParents = new Set();
|
|
6852
|
+
let currentId = changedNodeId;
|
|
6853
|
+
// Process all parents up to root
|
|
6854
|
+
while (currentId && currentId !== 'all') {
|
|
6855
|
+
const nodeData = this.nodeDataCache.get(currentId);
|
|
6856
|
+
if (!nodeData) {
|
|
6857
|
+
break;
|
|
6858
|
+
}
|
|
6859
|
+
const parentId = nodeData[parentKey];
|
|
6860
|
+
const parentIdStr = String(parentId);
|
|
6861
|
+
if (!parentId || parentId === 'all' || parentId === currentId || processedParents.has(parentIdStr)) {
|
|
6862
|
+
break;
|
|
6863
|
+
}
|
|
6864
|
+
processedParents.add(parentIdStr);
|
|
6865
|
+
// Load all children of this parent
|
|
6866
|
+
try {
|
|
6867
|
+
const childNodes = await this.datasource(parentIdStr);
|
|
6868
|
+
if (!childNodes || childNodes.length === 0) {
|
|
6869
|
+
currentId = parentIdStr;
|
|
6870
|
+
continue;
|
|
6871
|
+
}
|
|
6872
|
+
// Get current selection state (updated after each parent change)
|
|
6873
|
+
const currentSelected = this.selectedNodeIds();
|
|
6874
|
+
const selectedSet = new Set(currentSelected);
|
|
6875
|
+
let selectedCount = 0;
|
|
6876
|
+
let totalCount = 0;
|
|
6877
|
+
// Count selected children
|
|
6878
|
+
for (const childNode of childNodes) {
|
|
6879
|
+
const childId = String(childNode['id'] ?? '');
|
|
6880
|
+
if (childId && childId !== 'all') {
|
|
6881
|
+
totalCount++;
|
|
6882
|
+
if (selectedSet.has(childId)) {
|
|
6883
|
+
selectedCount++;
|
|
6884
|
+
}
|
|
6712
6885
|
}
|
|
6713
|
-
}
|
|
6714
|
-
|
|
6886
|
+
}
|
|
6887
|
+
// Update parent selection state
|
|
6888
|
+
const isParentSelected = currentSelected.includes(parentIdStr);
|
|
6889
|
+
if (totalCount > 0) {
|
|
6890
|
+
if (selectedCount === totalCount) {
|
|
6891
|
+
// All children selected - select parent
|
|
6892
|
+
if (!isParentSelected) {
|
|
6893
|
+
this.selectedNodeIds.set([...currentSelected, parentIdStr]);
|
|
6894
|
+
try {
|
|
6895
|
+
treeComponent.selectNode(parentIdStr);
|
|
6896
|
+
}
|
|
6897
|
+
catch {
|
|
6898
|
+
// Parent might not be in tree
|
|
6899
|
+
}
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
else if (selectedCount > 0) {
|
|
6903
|
+
// Some children selected - parent should be in intermediate state
|
|
6904
|
+
// The tree component handles intermediate state automatically via selectionBehavior
|
|
6905
|
+
// We just need to ensure parent is not fully selected
|
|
6906
|
+
if (isParentSelected) {
|
|
6907
|
+
// Deselect parent to show intermediate state
|
|
6908
|
+
this.selectedNodeIds.set(currentSelected.filter((id) => id !== parentIdStr));
|
|
6909
|
+
try {
|
|
6910
|
+
treeComponent.deselectNode(parentIdStr);
|
|
6911
|
+
}
|
|
6912
|
+
catch {
|
|
6913
|
+
// Parent might not be in tree
|
|
6914
|
+
}
|
|
6915
|
+
}
|
|
6916
|
+
}
|
|
6917
|
+
else {
|
|
6918
|
+
// No children selected - deselect parent
|
|
6919
|
+
if (isParentSelected) {
|
|
6920
|
+
this.selectedNodeIds.set(currentSelected.filter((id) => id !== parentIdStr));
|
|
6921
|
+
try {
|
|
6922
|
+
treeComponent.deselectNode(parentIdStr);
|
|
6923
|
+
}
|
|
6924
|
+
catch {
|
|
6925
|
+
// Parent might not be in tree
|
|
6926
|
+
}
|
|
6927
|
+
}
|
|
6928
|
+
}
|
|
6929
|
+
}
|
|
6930
|
+
// Cache parent data if not already cached
|
|
6931
|
+
if (!this.nodeDataCache.has(parentIdStr)) {
|
|
6932
|
+
const parentData = await this.fetchItemById(parentIdStr);
|
|
6933
|
+
if (parentData) {
|
|
6934
|
+
this.nodeDataCache.set(parentIdStr, parentData);
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
currentId = parentIdStr;
|
|
6938
|
+
}
|
|
6939
|
+
catch (error) {
|
|
6940
|
+
console.error(`Error updating parent state for ${parentIdStr}:`, error);
|
|
6941
|
+
break;
|
|
6942
|
+
}
|
|
6715
6943
|
}
|
|
6716
6944
|
}
|
|
6717
6945
|
/**
|
|
6718
|
-
*
|
|
6946
|
+
* Recursively loads and selects all children of a parent node using the datasource
|
|
6947
|
+
* This method directly calls datasource without expanding/collapsing nodes to avoid UI glitches
|
|
6719
6948
|
*/
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
const nodeId = String(node['id'] ?? '');
|
|
6725
|
-
if (excludedId && nodeId === excludedId) {
|
|
6726
|
-
node['disabled'] = true;
|
|
6727
|
-
}
|
|
6728
|
-
if (nodeId && selectedIds.includes(nodeId)) {
|
|
6729
|
-
node['selected'] = true;
|
|
6730
|
-
}
|
|
6731
|
-
});
|
|
6732
|
-
// Sync selection with tree component
|
|
6949
|
+
async loadAndSelectChildrenRecursively(parentId) {
|
|
6950
|
+
if (!this.treeData || !this.treeConfig || !parentId || parentId === 'all') {
|
|
6951
|
+
return;
|
|
6952
|
+
}
|
|
6733
6953
|
const treeComponent = this.tree();
|
|
6734
|
-
if (treeComponent) {
|
|
6735
|
-
|
|
6954
|
+
if (!treeComponent) {
|
|
6955
|
+
return;
|
|
6956
|
+
}
|
|
6957
|
+
try {
|
|
6958
|
+
// Directly call datasource to get children data without expanding the node
|
|
6959
|
+
// This avoids UI glitches from expand/collapse operations
|
|
6960
|
+
// If node has no children, datasource will return empty array
|
|
6961
|
+
const childNodes = await this.datasource(parentId);
|
|
6962
|
+
if (!childNodes || childNodes.length === 0) {
|
|
6963
|
+
return; // No children to process
|
|
6964
|
+
}
|
|
6965
|
+
// Collect all child IDs to add to selectedNodeIds
|
|
6966
|
+
const childIdsToSelect = [];
|
|
6967
|
+
// Process all children and cache their data
|
|
6968
|
+
for (const childNode of childNodes) {
|
|
6969
|
+
const childId = String(childNode['id'] ?? '');
|
|
6970
|
+
if (childId && childId !== 'all') {
|
|
6971
|
+
childIdsToSelect.push(childId);
|
|
6972
|
+
// Cache node data for getSelectedItems
|
|
6973
|
+
// Try to get data from 'data' property first, then fallback to node itself
|
|
6974
|
+
let nodeData = childNode['data'];
|
|
6975
|
+
// If no data property, try to extract data from the node
|
|
6976
|
+
if (!nodeData || typeof nodeData !== 'object') {
|
|
6977
|
+
// Create a data object from the node properties
|
|
6978
|
+
const valueField = this.treeConfig.valueField || 'id';
|
|
6979
|
+
const textField = this.treeConfig.textField || 'title';
|
|
6980
|
+
nodeData = {
|
|
6981
|
+
[valueField]: childId,
|
|
6982
|
+
[textField]: childNode['title'] ?? '',
|
|
6983
|
+
...childNode,
|
|
6984
|
+
};
|
|
6985
|
+
}
|
|
6986
|
+
// Cache the node data
|
|
6987
|
+
if (nodeData && typeof nodeData === 'object') {
|
|
6988
|
+
this.nodeDataCache.set(childId, nodeData);
|
|
6989
|
+
}
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6992
|
+
if (childIdsToSelect.length === 0) {
|
|
6993
|
+
return; // No valid children to select
|
|
6994
|
+
}
|
|
6995
|
+
// Update selectedNodeIds to include all children
|
|
6996
|
+
const currentSelected = this.selectedNodeIds();
|
|
6997
|
+
const newSelected = [...currentSelected];
|
|
6998
|
+
let hasNewSelections = false;
|
|
6999
|
+
for (const childId of childIdsToSelect) {
|
|
7000
|
+
if (!newSelected.includes(childId)) {
|
|
7001
|
+
newSelected.push(childId);
|
|
7002
|
+
hasNewSelections = true;
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
if (hasNewSelections) {
|
|
7006
|
+
this.selectedNodeIds.set(newSelected);
|
|
7007
|
+
}
|
|
7008
|
+
// Try to select children in tree component if they're already loaded
|
|
7009
|
+
// If not loaded yet, they'll be selected when the tree loads them (via markNodeAsSelectedIfNeeded)
|
|
7010
|
+
for (const childId of childIdsToSelect) {
|
|
7011
|
+
try {
|
|
7012
|
+
// Only try to select if node exists in tree (might not be loaded if parent isn't expanded)
|
|
7013
|
+
const node = treeComponent.findNode(childId);
|
|
7014
|
+
if (node) {
|
|
7015
|
+
treeComponent.selectNode(childId);
|
|
7016
|
+
}
|
|
7017
|
+
}
|
|
7018
|
+
catch {
|
|
7019
|
+
// If selection fails, it's okay - we've already added to selectedNodeIds
|
|
7020
|
+
// The tree will sync selection when the node is loaded via datasource callback
|
|
7021
|
+
}
|
|
7022
|
+
}
|
|
7023
|
+
// Recursively load and select children of each child
|
|
7024
|
+
// Use Promise.all for parallel processing to improve performance
|
|
7025
|
+
await Promise.all(childIdsToSelect.map((childId) => this.loadAndSelectChildrenRecursively(childId)));
|
|
7026
|
+
}
|
|
7027
|
+
catch (error) {
|
|
7028
|
+
console.error(`Error loading children for node ${parentId}:`, error);
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
//#endregion
|
|
7032
|
+
async updateSelectedNodes(selectedIds) {
|
|
7033
|
+
if (!selectedIds || selectedIds.length === 0) {
|
|
7034
|
+
this.selectedNodeIds.set([]);
|
|
7035
|
+
return;
|
|
7036
|
+
}
|
|
7037
|
+
const ids = selectedIds.filter((id) => id && id !== 'all');
|
|
7038
|
+
// Set flag to prevent recursive updates during initialization
|
|
7039
|
+
this.isUpdatingSelection = true;
|
|
7040
|
+
try {
|
|
7041
|
+
// Fetch node data for pre-selected items that aren't in the cache
|
|
7042
|
+
await this.loadMissingNodeData(ids);
|
|
7043
|
+
// Collect all nodes to select (pre-selected + all their descendants)
|
|
7044
|
+
const allNodesToSelect = new Set(ids);
|
|
7045
|
+
for (const nodeId of ids) {
|
|
7046
|
+
await this.collectAllDescendants(nodeId, allNodesToSelect);
|
|
7047
|
+
}
|
|
7048
|
+
// Set all selected nodes at once
|
|
7049
|
+
this.selectedNodeIds.set(Array.from(allNodesToSelect));
|
|
7050
|
+
// Expand parents of pre-selected nodes so they're visible in the tree
|
|
7051
|
+
await this.expandParentsOfSelectedNodes(Array.from(allNodesToSelect));
|
|
7052
|
+
// Sync selection with tree component - wait for tree to be ready
|
|
7053
|
+
await this.syncSelectionWithTree(Array.from(allNodesToSelect));
|
|
7054
|
+
}
|
|
7055
|
+
finally {
|
|
7056
|
+
this.isUpdatingSelection = false;
|
|
7057
|
+
}
|
|
7058
|
+
}
|
|
7059
|
+
/**
|
|
7060
|
+
* Updates all parent states based on their children's selection
|
|
7061
|
+
* Used during initialization to ensure proper parent states (select/intermediate)
|
|
7062
|
+
*/
|
|
7063
|
+
async updateAllParentStates(selectedIds) {
|
|
7064
|
+
if (!this.treeData || !this.treeConfig || !this.allowMultiple() || selectedIds.length === 0) {
|
|
7065
|
+
return;
|
|
7066
|
+
}
|
|
7067
|
+
const parentKey = this.treeData.categoryEntityDef?.parentKey;
|
|
7068
|
+
if (!parentKey) {
|
|
7069
|
+
return;
|
|
7070
|
+
}
|
|
7071
|
+
const treeComponent = this.tree();
|
|
7072
|
+
if (!treeComponent) {
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
7075
|
+
const selectedSet = new Set(selectedIds);
|
|
7076
|
+
const processedParents = new Set();
|
|
7077
|
+
// Collect all unique parent IDs
|
|
7078
|
+
for (const selectedId of selectedIds) {
|
|
7079
|
+
if (selectedId === 'all') {
|
|
7080
|
+
continue;
|
|
7081
|
+
}
|
|
7082
|
+
const nodeData = this.nodeDataCache.get(selectedId);
|
|
7083
|
+
if (!nodeData) {
|
|
7084
|
+
continue;
|
|
7085
|
+
}
|
|
7086
|
+
let currentId = selectedId;
|
|
7087
|
+
while (currentId && currentId !== 'all') {
|
|
7088
|
+
const currentNodeData = this.nodeDataCache.get(currentId);
|
|
7089
|
+
if (!currentNodeData) {
|
|
7090
|
+
break;
|
|
7091
|
+
}
|
|
7092
|
+
const parentId = currentNodeData[parentKey];
|
|
7093
|
+
const parentIdStr = String(parentId);
|
|
7094
|
+
if (!parentId || parentId === 'all' || parentId === currentId || processedParents.has(parentIdStr)) {
|
|
7095
|
+
break;
|
|
7096
|
+
}
|
|
7097
|
+
processedParents.add(parentIdStr);
|
|
7098
|
+
currentId = parentIdStr;
|
|
7099
|
+
}
|
|
7100
|
+
}
|
|
7101
|
+
// Process parents multiple times to handle cascading parent selections
|
|
7102
|
+
// (when a parent is selected, its parent might also need to be selected)
|
|
7103
|
+
let hasChanges = true;
|
|
7104
|
+
let iterations = 0;
|
|
7105
|
+
const maxIterations = 10; // Prevent infinite loops
|
|
7106
|
+
while (hasChanges && iterations < maxIterations) {
|
|
7107
|
+
iterations++;
|
|
7108
|
+
hasChanges = false;
|
|
7109
|
+
// Update selectedSet with current selectedNodeIds
|
|
7110
|
+
const currentSelected = this.selectedNodeIds();
|
|
7111
|
+
currentSelected.forEach((id) => selectedSet.add(id));
|
|
7112
|
+
// Update each parent's state
|
|
7113
|
+
for (const parentId of processedParents) {
|
|
7114
|
+
try {
|
|
7115
|
+
const childNodes = await this.datasource(parentId);
|
|
7116
|
+
if (!childNodes || childNodes.length === 0) {
|
|
7117
|
+
continue;
|
|
7118
|
+
}
|
|
7119
|
+
let selectedCount = 0;
|
|
7120
|
+
let totalCount = 0;
|
|
7121
|
+
for (const childNode of childNodes) {
|
|
7122
|
+
const childId = String(childNode['id'] ?? '');
|
|
7123
|
+
if (childId && childId !== 'all') {
|
|
7124
|
+
totalCount++;
|
|
7125
|
+
if (selectedSet.has(childId)) {
|
|
7126
|
+
selectedCount++;
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
const isParentSelected = currentSelected.includes(parentId);
|
|
7131
|
+
if (totalCount > 0) {
|
|
7132
|
+
if (selectedCount === totalCount) {
|
|
7133
|
+
// All children selected - select parent
|
|
7134
|
+
if (!isParentSelected) {
|
|
7135
|
+
this.selectedNodeIds.set([...currentSelected, parentId]);
|
|
7136
|
+
selectedSet.add(parentId);
|
|
7137
|
+
hasChanges = true;
|
|
7138
|
+
try {
|
|
7139
|
+
treeComponent.selectNode(parentId);
|
|
7140
|
+
}
|
|
7141
|
+
catch {
|
|
7142
|
+
// Parent might not be in tree
|
|
7143
|
+
}
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7146
|
+
else if (selectedCount > 0) {
|
|
7147
|
+
// Some children selected - parent should be in intermediate state
|
|
7148
|
+
if (isParentSelected) {
|
|
7149
|
+
// Deselect parent to show intermediate state
|
|
7150
|
+
this.selectedNodeIds.set(currentSelected.filter((id) => id !== parentId));
|
|
7151
|
+
selectedSet.delete(parentId);
|
|
7152
|
+
hasChanges = true;
|
|
7153
|
+
try {
|
|
7154
|
+
treeComponent.deselectNode(parentId);
|
|
7155
|
+
}
|
|
7156
|
+
catch {
|
|
7157
|
+
// Parent might not be in tree
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
}
|
|
7161
|
+
else {
|
|
7162
|
+
// No children selected - deselect parent
|
|
7163
|
+
if (isParentSelected) {
|
|
7164
|
+
this.selectedNodeIds.set(currentSelected.filter((id) => id !== parentId));
|
|
7165
|
+
selectedSet.delete(parentId);
|
|
7166
|
+
hasChanges = true;
|
|
7167
|
+
try {
|
|
7168
|
+
treeComponent.deselectNode(parentId);
|
|
7169
|
+
}
|
|
7170
|
+
catch {
|
|
7171
|
+
// Parent might not be in tree
|
|
7172
|
+
}
|
|
7173
|
+
}
|
|
7174
|
+
}
|
|
7175
|
+
}
|
|
7176
|
+
}
|
|
7177
|
+
catch (error) {
|
|
7178
|
+
console.error(`Error updating parent state for ${parentId}:`, error);
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7183
|
+
/**
|
|
7184
|
+
* Expands parents of selected nodes so they're visible when popup opens
|
|
7185
|
+
*/
|
|
7186
|
+
async expandParentsOfSelectedNodes(selectedIds) {
|
|
7187
|
+
if (!this.treeData || !this.treeConfig || selectedIds.length === 0) {
|
|
7188
|
+
return;
|
|
7189
|
+
}
|
|
7190
|
+
const parentKey = this.treeData.categoryEntityDef?.parentKey;
|
|
7191
|
+
if (!parentKey) {
|
|
7192
|
+
return; // No parent key means flat structure
|
|
7193
|
+
}
|
|
7194
|
+
const treeComponent = this.tree();
|
|
7195
|
+
if (!treeComponent) {
|
|
7196
|
+
return;
|
|
7197
|
+
}
|
|
7198
|
+
// Collect all unique parent IDs that need to be expanded
|
|
7199
|
+
const parentsToExpand = new Set();
|
|
7200
|
+
for (const selectedId of selectedIds) {
|
|
7201
|
+
if (selectedId === 'all') {
|
|
7202
|
+
continue;
|
|
7203
|
+
}
|
|
7204
|
+
const nodeData = this.nodeDataCache.get(selectedId);
|
|
7205
|
+
if (!nodeData) {
|
|
7206
|
+
continue;
|
|
7207
|
+
}
|
|
7208
|
+
const parentId = nodeData[parentKey];
|
|
7209
|
+
if (parentId && parentId !== 'all') {
|
|
7210
|
+
const parentIdStr = String(parentId);
|
|
7211
|
+
parentsToExpand.add(parentIdStr);
|
|
7212
|
+
// Also expand grandparents, etc.
|
|
7213
|
+
let currentParentId = parentIdStr;
|
|
7214
|
+
while (currentParentId) {
|
|
7215
|
+
const parentData = this.nodeDataCache.get(currentParentId);
|
|
7216
|
+
if (!parentData) {
|
|
7217
|
+
break;
|
|
7218
|
+
}
|
|
7219
|
+
const grandParentId = parentData[parentKey];
|
|
7220
|
+
if (grandParentId && grandParentId !== 'all' && grandParentId !== currentParentId) {
|
|
7221
|
+
parentsToExpand.add(String(grandParentId));
|
|
7222
|
+
currentParentId = String(grandParentId);
|
|
7223
|
+
}
|
|
7224
|
+
else {
|
|
7225
|
+
break;
|
|
7226
|
+
}
|
|
7227
|
+
}
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7230
|
+
// Expand all parents (starting from root to leaves)
|
|
7231
|
+
const sortedParents = Array.from(parentsToExpand).sort((a, b) => {
|
|
7232
|
+
// Simple sort - expand root nodes first
|
|
7233
|
+
return a.localeCompare(b);
|
|
7234
|
+
});
|
|
7235
|
+
for (const parentId of sortedParents) {
|
|
7236
|
+
try {
|
|
7237
|
+
if (!treeComponent.isNodeExpanded(parentId)) {
|
|
7238
|
+
await treeComponent.expandNode(parentId);
|
|
7239
|
+
// Small delay to ensure children are loaded
|
|
7240
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
7241
|
+
}
|
|
7242
|
+
}
|
|
7243
|
+
catch {
|
|
7244
|
+
// Parent might not be in tree yet, ignore
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7247
|
+
}
|
|
7248
|
+
/**
|
|
7249
|
+
* Selects parents whose all children are selected
|
|
7250
|
+
* This ensures that when all children of a parent are selected, the parent also appears selected
|
|
7251
|
+
*/
|
|
7252
|
+
async selectParentsWithAllChildrenSelected(selectedIds) {
|
|
7253
|
+
if (!this.treeData || !this.treeConfig || selectedIds.length === 0) {
|
|
7254
|
+
return;
|
|
7255
|
+
}
|
|
7256
|
+
const parentKey = this.treeData.categoryEntityDef?.parentKey;
|
|
7257
|
+
if (!parentKey) {
|
|
7258
|
+
return; // No parent key means flat structure
|
|
7259
|
+
}
|
|
7260
|
+
// Use current selectedNodeIds signal value (may have been updated)
|
|
7261
|
+
const currentSelectedIds = this.selectedNodeIds();
|
|
7262
|
+
const selectedSet = new Set(currentSelectedIds);
|
|
7263
|
+
const processedParents = new Set();
|
|
7264
|
+
const parentsToSelect = new Set();
|
|
7265
|
+
// For each selected node, check its parent
|
|
7266
|
+
for (const selectedId of currentSelectedIds) {
|
|
7267
|
+
if (selectedId === 'all') {
|
|
7268
|
+
continue;
|
|
7269
|
+
}
|
|
7270
|
+
// Get parent ID from cached data
|
|
7271
|
+
const nodeData = this.nodeDataCache.get(selectedId);
|
|
7272
|
+
if (!nodeData) {
|
|
7273
|
+
continue;
|
|
7274
|
+
}
|
|
7275
|
+
const parentId = nodeData[parentKey];
|
|
7276
|
+
if (!parentId || parentId === 'all' || processedParents.has(String(parentId))) {
|
|
7277
|
+
continue;
|
|
7278
|
+
}
|
|
7279
|
+
const parentIdStr = String(parentId);
|
|
7280
|
+
processedParents.add(parentIdStr);
|
|
7281
|
+
// Load all children of this parent
|
|
7282
|
+
try {
|
|
7283
|
+
const childNodes = await this.datasource(parentIdStr);
|
|
7284
|
+
if (!childNodes || childNodes.length === 0) {
|
|
7285
|
+
continue;
|
|
7286
|
+
}
|
|
7287
|
+
// Check if all children are selected
|
|
7288
|
+
let allChildrenSelected = true;
|
|
7289
|
+
let hasChildren = false;
|
|
7290
|
+
for (const childNode of childNodes) {
|
|
7291
|
+
const childId = String(childNode['id'] ?? '');
|
|
7292
|
+
if (childId && childId !== 'all') {
|
|
7293
|
+
hasChildren = true;
|
|
7294
|
+
if (!selectedSet.has(childId)) {
|
|
7295
|
+
allChildrenSelected = false;
|
|
7296
|
+
break;
|
|
7297
|
+
}
|
|
7298
|
+
}
|
|
7299
|
+
}
|
|
7300
|
+
// If parent has children and all are selected, mark parent for selection
|
|
7301
|
+
if (hasChildren && allChildrenSelected) {
|
|
7302
|
+
parentsToSelect.add(parentIdStr);
|
|
7303
|
+
// Cache parent data if not already cached
|
|
7304
|
+
if (!this.nodeDataCache.has(parentIdStr)) {
|
|
7305
|
+
const parentData = await this.fetchItemById(parentIdStr);
|
|
7306
|
+
if (parentData) {
|
|
7307
|
+
this.nodeDataCache.set(parentIdStr, parentData);
|
|
7308
|
+
}
|
|
7309
|
+
}
|
|
7310
|
+
}
|
|
7311
|
+
}
|
|
7312
|
+
catch (error) {
|
|
7313
|
+
console.error(`Error checking parent ${parentIdStr}:`, error);
|
|
7314
|
+
}
|
|
7315
|
+
}
|
|
7316
|
+
// Add parents to selectedNodeIds
|
|
7317
|
+
if (parentsToSelect.size > 0) {
|
|
7318
|
+
const currentSelected = this.selectedNodeIds();
|
|
7319
|
+
const newSelected = [...currentSelected];
|
|
7320
|
+
let hasNewSelections = false;
|
|
7321
|
+
for (const parentId of parentsToSelect) {
|
|
7322
|
+
if (!newSelected.includes(parentId)) {
|
|
7323
|
+
newSelected.push(parentId);
|
|
7324
|
+
hasNewSelections = true;
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
if (hasNewSelections) {
|
|
7328
|
+
this.selectedNodeIds.set(newSelected);
|
|
7329
|
+
// Recursively check parents of these parents
|
|
7330
|
+
const updatedSelected = this.selectedNodeIds();
|
|
7331
|
+
await this.selectParentsWithAllChildrenSelected(updatedSelected);
|
|
7332
|
+
}
|
|
7333
|
+
}
|
|
7334
|
+
}
|
|
7335
|
+
/**
|
|
7336
|
+
* Syncs selection state with the tree component
|
|
7337
|
+
* Handles cases where nodes might not be in the tree structure yet
|
|
7338
|
+
*/
|
|
7339
|
+
async syncSelectionWithTree(selectedIds) {
|
|
7340
|
+
const treeComponent = this.tree();
|
|
7341
|
+
if (!treeComponent || selectedIds.length === 0) {
|
|
7342
|
+
return;
|
|
7343
|
+
}
|
|
7344
|
+
// Wait for tree to be fully initialized and rendered
|
|
7345
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
7346
|
+
// Try multiple times to sync selection (nodes might load progressively)
|
|
7347
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
7348
|
+
let syncedCount = 0;
|
|
7349
|
+
selectedIds.forEach((id) => {
|
|
7350
|
+
if (id && id !== 'all') {
|
|
7351
|
+
try {
|
|
7352
|
+
const node = treeComponent.findNode(id);
|
|
7353
|
+
if (node) {
|
|
7354
|
+
// Node exists in tree, select it
|
|
7355
|
+
treeComponent.selectNode(id);
|
|
7356
|
+
syncedCount++;
|
|
7357
|
+
}
|
|
7358
|
+
}
|
|
7359
|
+
catch {
|
|
7360
|
+
// Node not in tree yet - will be selected when loaded via datasource callback
|
|
7361
|
+
}
|
|
7362
|
+
}
|
|
7363
|
+
});
|
|
7364
|
+
// If all nodes are synced, we're done
|
|
7365
|
+
if (syncedCount === selectedIds.length) {
|
|
7366
|
+
break;
|
|
7367
|
+
}
|
|
7368
|
+
// Wait a bit before next attempt
|
|
7369
|
+
if (attempt < 2) {
|
|
7370
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
// After syncing, read back from tree component to get any parents that were automatically selected
|
|
7374
|
+
// (due to intermediate-nested behavior when all children are selected)
|
|
7375
|
+
if (this.allowMultiple()) {
|
|
7376
|
+
try {
|
|
7377
|
+
const treeSelectedNodes = treeComponent.getSelectedNodes();
|
|
7378
|
+
const treeSelectedIds = treeSelectedNodes
|
|
7379
|
+
.map((node) => String(node['id'] ?? ''))
|
|
7380
|
+
.filter((id) => id && id !== 'all');
|
|
7381
|
+
// Update selectedNodeIds to match tree component's state (includes auto-selected parents)
|
|
7382
|
+
this.selectedNodeIds.set(treeSelectedIds);
|
|
7383
|
+
}
|
|
7384
|
+
catch {
|
|
7385
|
+
// Tree component might not be ready yet
|
|
7386
|
+
}
|
|
7387
|
+
}
|
|
7388
|
+
// Note: Selection state is maintained in selectedNodeIds signal
|
|
7389
|
+
// The tree component will sync selection state when nodes are loaded via datasource
|
|
7390
|
+
// We mark nodes as selected in the datasource callback by setting node.selected = true
|
|
7391
|
+
// Nodes that aren't in the tree yet will be selected when their parent is expanded
|
|
7392
|
+
}
|
|
7393
|
+
/**
|
|
7394
|
+
* Loads node data for IDs that are selected but not yet in the cache.
|
|
7395
|
+
* This is critical for pre-selected values in collapsed branches.
|
|
7396
|
+
*/
|
|
7397
|
+
async loadMissingNodeData(selectedIds) {
|
|
7398
|
+
if (!this.treeData || !this.treeConfig || selectedIds.length === 0) {
|
|
7399
|
+
return;
|
|
7400
|
+
}
|
|
7401
|
+
// Find IDs that are selected but not in cache
|
|
7402
|
+
const missingIds = selectedIds.filter((id) => !this.nodeDataCache.has(id));
|
|
7403
|
+
if (missingIds.length === 0) {
|
|
7404
|
+
return;
|
|
7405
|
+
}
|
|
7406
|
+
try {
|
|
7407
|
+
const valueField = this.treeConfig.valueField || 'id';
|
|
7408
|
+
const categoryEntityQueryFunc = this.treeData.categoryEntityQueryFunc;
|
|
7409
|
+
if (!categoryEntityQueryFunc) {
|
|
7410
|
+
return;
|
|
7411
|
+
}
|
|
7412
|
+
// Query for missing nodes by their IDs
|
|
7413
|
+
const event = {
|
|
7414
|
+
...this.treeData.basicQueryEvent,
|
|
7415
|
+
filter: {
|
|
7416
|
+
filters: missingIds.map((id) => ({
|
|
7417
|
+
field: valueField,
|
|
7418
|
+
value: id,
|
|
7419
|
+
operator: { type: 'equal' },
|
|
7420
|
+
})),
|
|
7421
|
+
logic: 'or',
|
|
7422
|
+
},
|
|
7423
|
+
};
|
|
7424
|
+
const res = await categoryEntityQueryFunc(event);
|
|
7425
|
+
if (res?.items) {
|
|
7426
|
+
// Cache the fetched node data
|
|
7427
|
+
res.items.forEach((item) => {
|
|
7428
|
+
const itemId = String(item[valueField] ?? '');
|
|
7429
|
+
if (itemId) {
|
|
7430
|
+
this.nodeDataCache.set(itemId, item);
|
|
7431
|
+
}
|
|
7432
|
+
});
|
|
7433
|
+
}
|
|
7434
|
+
}
|
|
7435
|
+
catch (error) {
|
|
7436
|
+
console.error('Error loading missing node data:', error);
|
|
7437
|
+
}
|
|
7438
|
+
}
|
|
7439
|
+
/**
|
|
7440
|
+
* Marks nodes as selected in the tree structure based on selectedNodeIds.
|
|
7441
|
+
* This ensures pre-selected nodes appear selected when the tree is rendered.
|
|
7442
|
+
*/
|
|
7443
|
+
markNodesAsSelected(node) {
|
|
7444
|
+
const selectedIds = this.selectedNodeIds();
|
|
7445
|
+
if (selectedIds.length === 0) {
|
|
7446
|
+
return;
|
|
7447
|
+
}
|
|
7448
|
+
// Mark the node itself if it's selected
|
|
7449
|
+
this.markNodeAsSelectedIfNeeded(node);
|
|
7450
|
+
// Recursively mark children
|
|
7451
|
+
const nodeChildren = node['children'];
|
|
7452
|
+
if (nodeChildren) {
|
|
7453
|
+
nodeChildren.forEach((child) => {
|
|
7454
|
+
this.markNodesAsSelected(child);
|
|
7455
|
+
});
|
|
7456
|
+
}
|
|
7457
|
+
}
|
|
7458
|
+
/**
|
|
7459
|
+
* Marks a single node as selected if it's in the selectedNodeIds list.
|
|
7460
|
+
*/
|
|
7461
|
+
markNodeAsSelectedIfNeeded(node) {
|
|
7462
|
+
const selectedIds = this.selectedNodeIds();
|
|
7463
|
+
const nodeId = String(node['id'] ?? '');
|
|
7464
|
+
if (nodeId && selectedIds.includes(nodeId)) {
|
|
7465
|
+
node['selected'] = true;
|
|
7466
|
+
}
|
|
7467
|
+
}
|
|
7468
|
+
/**
|
|
7469
|
+
* Marks a node and its children as disabled if the node ID matches the excluded ID.
|
|
7470
|
+
*/
|
|
7471
|
+
markNodeAsDisabled(node, excludedId) {
|
|
7472
|
+
const nodeId = String(node['id'] ?? '');
|
|
7473
|
+
if (nodeId === excludedId) {
|
|
7474
|
+
node['disabled'] = true;
|
|
7475
|
+
}
|
|
7476
|
+
// Recursively mark children
|
|
7477
|
+
const nodeChildren = node['children'];
|
|
7478
|
+
if (nodeChildren) {
|
|
7479
|
+
nodeChildren.forEach((child) => {
|
|
7480
|
+
this.markNodeAsDisabled(child, excludedId);
|
|
7481
|
+
});
|
|
7482
|
+
}
|
|
7483
|
+
}
|
|
7484
|
+
/**
|
|
7485
|
+
* Processes root node: marks excluded as disabled, marks selected, and syncs selection with tree component
|
|
7486
|
+
*/
|
|
7487
|
+
processRootNode(rootNode) {
|
|
7488
|
+
const excludedId = this.excludedNodeId();
|
|
7489
|
+
if (excludedId) {
|
|
7490
|
+
this.markNodeAsDisabled(rootNode, excludedId);
|
|
7491
|
+
}
|
|
7492
|
+
this.markNodesAsSelected(rootNode);
|
|
7493
|
+
// Sync selection with tree component after a short delay to ensure tree is rendered
|
|
7494
|
+
const treeComponent = this.tree();
|
|
7495
|
+
if (treeComponent) {
|
|
7496
|
+
setTimeout(() => {
|
|
7497
|
+
const selectedIds = this.selectedNodeIds();
|
|
7498
|
+
selectedIds.forEach((id) => {
|
|
7499
|
+
if (id && id !== 'all') {
|
|
7500
|
+
treeComponent.selectNode(id);
|
|
7501
|
+
}
|
|
7502
|
+
});
|
|
7503
|
+
}, 0);
|
|
7504
|
+
}
|
|
7505
|
+
}
|
|
7506
|
+
/**
|
|
7507
|
+
* Processes child nodes: marks excluded as disabled, marks selected, and syncs selection
|
|
7508
|
+
*/
|
|
7509
|
+
processChildNodes(childNodes) {
|
|
7510
|
+
const excludedId = this.excludedNodeId();
|
|
7511
|
+
const selectedIds = this.selectedNodeIds();
|
|
7512
|
+
childNodes.forEach((node) => {
|
|
7513
|
+
const nodeId = String(node['id'] ?? '');
|
|
7514
|
+
if (excludedId && nodeId === excludedId) {
|
|
7515
|
+
node['disabled'] = true;
|
|
7516
|
+
}
|
|
7517
|
+
if (nodeId && selectedIds.includes(nodeId)) {
|
|
7518
|
+
node['selected'] = true;
|
|
7519
|
+
}
|
|
7520
|
+
});
|
|
7521
|
+
// Sync selection with tree component
|
|
7522
|
+
const treeComponent = this.tree();
|
|
7523
|
+
if (treeComponent) {
|
|
7524
|
+
setTimeout(() => {
|
|
6736
7525
|
childNodes.forEach((node) => {
|
|
6737
7526
|
const nodeId = String(node['id'] ?? '');
|
|
6738
7527
|
if (nodeId && selectedIds.includes(nodeId) && nodeId !== 'all') {
|
|
@@ -6887,41 +7676,107 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6887
7676
|
const textField = this.treeConfig.textField || 'title';
|
|
6888
7677
|
return String(nodeData[textField] ?? '');
|
|
6889
7678
|
}
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
7679
|
+
/**
|
|
7680
|
+
* Checks if a node is a leaf node (has no children)
|
|
7681
|
+
*/
|
|
7682
|
+
async isLeafNode(nodeId, treeComponent) {
|
|
7683
|
+
if (!treeComponent) {
|
|
7684
|
+
// If no tree component, check if node has children by querying
|
|
7685
|
+
return await this.checkIfNodeHasChildren(nodeId);
|
|
7686
|
+
}
|
|
7687
|
+
try {
|
|
7688
|
+
const node = treeComponent.findNode(nodeId);
|
|
7689
|
+
if (!node) {
|
|
7690
|
+
// Node not found in tree, check via query
|
|
7691
|
+
return await this.checkIfNodeHasChildren(nodeId);
|
|
7692
|
+
}
|
|
7693
|
+
// Check if node has children
|
|
7694
|
+
const children = node['children'];
|
|
7695
|
+
const childrenCount = node['childrenCount'];
|
|
7696
|
+
// If children are loaded, check the array
|
|
7697
|
+
if (children !== undefined) {
|
|
7698
|
+
return !children || children.length === 0;
|
|
7699
|
+
}
|
|
7700
|
+
// If childrenCount is available, use it
|
|
7701
|
+
if (childrenCount !== undefined) {
|
|
7702
|
+
return childrenCount === 0;
|
|
7703
|
+
}
|
|
7704
|
+
// If neither is available, try to check via query
|
|
7705
|
+
return await this.checkIfNodeHasChildren(nodeId);
|
|
7706
|
+
}
|
|
7707
|
+
catch {
|
|
7708
|
+
// If findNode fails, check via query
|
|
7709
|
+
return await this.checkIfNodeHasChildren(nodeId);
|
|
7710
|
+
}
|
|
7711
|
+
}
|
|
7712
|
+
/**
|
|
7713
|
+
* Checks if a node has children by querying the data source
|
|
7714
|
+
*/
|
|
7715
|
+
async checkIfNodeHasChildren(nodeId) {
|
|
7716
|
+
if (!this.treeData?.categoryEntityQueryFunc || !this.treeConfig) {
|
|
7717
|
+
return true; // Assume leaf if we can't check
|
|
7718
|
+
}
|
|
7719
|
+
try {
|
|
7720
|
+
const parentKey = this.treeData.categoryEntityDef?.parentKey;
|
|
7721
|
+
if (!parentKey) {
|
|
7722
|
+
return true; // No parent key means flat structure, all nodes are leaves
|
|
7723
|
+
}
|
|
7724
|
+
const event = {
|
|
7725
|
+
...this.treeData.basicQueryEvent,
|
|
7726
|
+
filter: {
|
|
7727
|
+
field: parentKey,
|
|
7728
|
+
value: nodeId,
|
|
7729
|
+
operator: { type: 'equal' },
|
|
7730
|
+
},
|
|
7731
|
+
take: 1, // Only need to check if any children exist
|
|
7732
|
+
};
|
|
7733
|
+
const res = await this.treeData.categoryEntityQueryFunc(event);
|
|
7734
|
+
return !res?.items || res.items.length === 0;
|
|
6913
7735
|
}
|
|
6914
|
-
|
|
7736
|
+
catch {
|
|
7737
|
+
return true; // Assume leaf on error
|
|
7738
|
+
}
|
|
7739
|
+
}
|
|
7740
|
+
async getSelectedItems() {
|
|
7741
|
+
// Always use selectedNodeIds as the source of truth
|
|
7742
|
+
// This ensures we get all selected nodes, even if they're not in the tree structure yet
|
|
6915
7743
|
const selectedIds = this.selectedNodeIds();
|
|
6916
7744
|
if (selectedIds.length === 0) {
|
|
6917
7745
|
return [];
|
|
6918
7746
|
}
|
|
7747
|
+
const treeComponent = this.tree();
|
|
6919
7748
|
// Get node data from cache and calculate paths
|
|
7749
|
+
// For nodes not in cache, try to get from tree component
|
|
6920
7750
|
const items = await Promise.all(selectedIds.map(async (id) => {
|
|
6921
|
-
|
|
7751
|
+
// First try to get from cache
|
|
7752
|
+
let nodeData = this.nodeDataCache.get(id);
|
|
7753
|
+
// If not in cache, try to get from tree component
|
|
7754
|
+
if (!nodeData && treeComponent) {
|
|
7755
|
+
try {
|
|
7756
|
+
const node = treeComponent.findNode(id);
|
|
7757
|
+
if (node) {
|
|
7758
|
+
nodeData = node['data'] || node;
|
|
7759
|
+
// Cache it for future use
|
|
7760
|
+
if (nodeData && typeof nodeData === 'object') {
|
|
7761
|
+
this.nodeDataCache.set(id, nodeData);
|
|
7762
|
+
}
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
catch {
|
|
7766
|
+
// Node not found in tree, continue with cache lookup
|
|
7767
|
+
}
|
|
7768
|
+
}
|
|
7769
|
+
// If still no data, skip this node
|
|
6922
7770
|
if (!nodeData) {
|
|
6923
7771
|
return null;
|
|
6924
7772
|
}
|
|
7773
|
+
// When selectionBehavior is intermediate-nested, only return leaf nodes
|
|
7774
|
+
if (this.allowMultiple()) {
|
|
7775
|
+
const isLeaf = await this.isLeafNode(id, treeComponent ?? null);
|
|
7776
|
+
if (!isLeaf) {
|
|
7777
|
+
return null; // Skip non-leaf nodes
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
6925
7780
|
const path = await this.calculateNodePath(id, nodeData);
|
|
6926
7781
|
return {
|
|
6927
7782
|
...nodeData,
|
|
@@ -6936,9 +7791,9 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6936
7791
|
<div class="ax-flex ax-flex-col ax-h-full">
|
|
6937
7792
|
@if (loading()) {
|
|
6938
7793
|
<div class="ax-p-4 ax-flex ax-flex-col ax-gap-3">
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
7794
|
+
@for (i of [1, 2, 3, 4]; track i) {
|
|
7795
|
+
<ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
|
|
7796
|
+
}
|
|
6942
7797
|
</div>
|
|
6943
7798
|
} @else if (treeData) {
|
|
6944
7799
|
<div class="ax-flex ax-flex-col ax-flex-1 ax-min-h-0">
|
|
@@ -6976,14 +7831,14 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6976
7831
|
[datasource]="datasource"
|
|
6977
7832
|
[dragBehavior]="'none'"
|
|
6978
7833
|
[selectMode]="allowMultiple() ? 'multiple' : 'single'"
|
|
6979
|
-
[selectionBehavior]="
|
|
7834
|
+
[selectionBehavior]="allowMultiple() ? 'intermediate-nested' : 'all'"
|
|
6980
7835
|
[showIcons]="true"
|
|
6981
7836
|
[titleField]="textField()"
|
|
6982
7837
|
[idField]="valueField()"
|
|
6983
|
-
[nodeTemplate]="itemTemplate"
|
|
6984
7838
|
(onNodeSelect)="onNodeSelect($event)"
|
|
6985
7839
|
(onSelectionChange)="onSelectionChange($event)"
|
|
6986
7840
|
(onNodeToggle)="onNodeToggle($event)"
|
|
7841
|
+
[nodeTemplate]="itemTemplate"
|
|
6987
7842
|
#tree
|
|
6988
7843
|
>
|
|
6989
7844
|
</ax-tree-view>
|
|
@@ -6992,12 +7847,16 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
6992
7847
|
@if (node) {
|
|
6993
7848
|
@let item = node.data || node;
|
|
6994
7849
|
<div class="ax-flex ax-items-center ax-gap-2 ax-w-full ax-overflow-hidden ax-p-2 ax-pe-0">
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7850
|
+
@if (allowMultiple()) {
|
|
7851
|
+
<ax-check-box
|
|
7852
|
+
[ngModel]="node['indeterminate'] ? null : node['selected'] || false"
|
|
7853
|
+
[indeterminate]="node['indeterminate'] || false"
|
|
7854
|
+
(onValueChanged)="handleCheckboxChange(node.id, $event.value)"
|
|
7855
|
+
(click)="$event.stopPropagation()"
|
|
7856
|
+
(pointerdown)="$event.stopPropagation()"
|
|
7857
|
+
[disabled]="node.disabled || node.id === 'all'"
|
|
7858
|
+
></ax-check-box>
|
|
7859
|
+
}
|
|
7001
7860
|
<ax-icon
|
|
7002
7861
|
class="fas fa-folder"
|
|
7003
7862
|
[style.color]="item.color ?? 'rgba(var(--ax-sys-color-warning-500), 1)'"
|
|
@@ -7036,7 +7895,7 @@ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
|
|
|
7036
7895
|
></ax-button>
|
|
7037
7896
|
</ax-suffix>
|
|
7038
7897
|
</ax-footer>
|
|
7039
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type:
|
|
7898
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i2$1.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i4$2.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i5$1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "nodeTemplate", "idField", "titleField", "tooltipField", "iconField", "expandedField", "selectedField", "indeterminateField", "disabledField", "hiddenField", "childrenField", "childrenCountField", "dataField", "inheritDisabled", "expandOnDoubleClick"], outputs: ["datasourceChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "variant"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7040
7899
|
}
|
|
7041
7900
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, decorators: [{
|
|
7042
7901
|
type: Component,
|
|
@@ -7046,9 +7905,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
7046
7905
|
<div class="ax-flex ax-flex-col ax-h-full">
|
|
7047
7906
|
@if (loading()) {
|
|
7048
7907
|
<div class="ax-p-4 ax-flex ax-flex-col ax-gap-3">
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7908
|
+
@for (i of [1, 2, 3, 4]; track i) {
|
|
7909
|
+
<ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
|
|
7910
|
+
}
|
|
7052
7911
|
</div>
|
|
7053
7912
|
} @else if (treeData) {
|
|
7054
7913
|
<div class="ax-flex ax-flex-col ax-flex-1 ax-min-h-0">
|
|
@@ -7086,14 +7945,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
7086
7945
|
[datasource]="datasource"
|
|
7087
7946
|
[dragBehavior]="'none'"
|
|
7088
7947
|
[selectMode]="allowMultiple() ? 'multiple' : 'single'"
|
|
7089
|
-
[selectionBehavior]="
|
|
7948
|
+
[selectionBehavior]="allowMultiple() ? 'intermediate-nested' : 'all'"
|
|
7090
7949
|
[showIcons]="true"
|
|
7091
7950
|
[titleField]="textField()"
|
|
7092
7951
|
[idField]="valueField()"
|
|
7093
|
-
[nodeTemplate]="itemTemplate"
|
|
7094
7952
|
(onNodeSelect)="onNodeSelect($event)"
|
|
7095
7953
|
(onSelectionChange)="onSelectionChange($event)"
|
|
7096
7954
|
(onNodeToggle)="onNodeToggle($event)"
|
|
7955
|
+
[nodeTemplate]="itemTemplate"
|
|
7097
7956
|
#tree
|
|
7098
7957
|
>
|
|
7099
7958
|
</ax-tree-view>
|
|
@@ -7102,12 +7961,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
7102
7961
|
@if (node) {
|
|
7103
7962
|
@let item = node.data || node;
|
|
7104
7963
|
<div class="ax-flex ax-items-center ax-gap-2 ax-w-full ax-overflow-hidden ax-p-2 ax-pe-0">
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7964
|
+
@if (allowMultiple()) {
|
|
7965
|
+
<ax-check-box
|
|
7966
|
+
[ngModel]="node['indeterminate'] ? null : node['selected'] || false"
|
|
7967
|
+
[indeterminate]="node['indeterminate'] || false"
|
|
7968
|
+
(onValueChanged)="handleCheckboxChange(node.id, $event.value)"
|
|
7969
|
+
(click)="$event.stopPropagation()"
|
|
7970
|
+
(pointerdown)="$event.stopPropagation()"
|
|
7971
|
+
[disabled]="node.disabled || node.id === 'all'"
|
|
7972
|
+
></ax-check-box>
|
|
7973
|
+
}
|
|
7111
7974
|
<ax-icon
|
|
7112
7975
|
class="fas fa-folder"
|
|
7113
7976
|
[style.color]="item.color ?? 'rgba(var(--ax-sys-color-warning-500), 1)'"
|
|
@@ -7400,7 +8263,7 @@ class AXPEntityCategoryWidgetColumnComponent extends AXPColumnWidgetComponent {
|
|
|
7400
8263
|
</div>
|
|
7401
8264
|
}
|
|
7402
8265
|
</div>
|
|
7403
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type:
|
|
8266
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7404
8267
|
}
|
|
7405
8268
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetColumnComponent, decorators: [{
|
|
7406
8269
|
type: Component,
|
|
@@ -7741,7 +8604,7 @@ class AXPTruncatedBreadcrumbComponent {
|
|
|
7741
8604
|
}
|
|
7742
8605
|
}
|
|
7743
8606
|
</div>
|
|
7744
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type:
|
|
8607
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
7745
8608
|
}
|
|
7746
8609
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPTruncatedBreadcrumbComponent, decorators: [{
|
|
7747
8610
|
type: Component,
|
|
@@ -7858,6 +8721,8 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
7858
8721
|
this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
7859
8722
|
this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
7860
8723
|
this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
8724
|
+
this.tagBox = viewChild('tagBoxComponent', ...(ngDevMode ? [{ debugName: "tagBox" }] : []));
|
|
8725
|
+
this.searchTerm = signal(null, ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
7861
8726
|
//#endregion
|
|
7862
8727
|
//#region ---- Private Properties ----
|
|
7863
8728
|
this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
|
|
@@ -7912,13 +8777,62 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
7912
8777
|
handleAddClick(e) {
|
|
7913
8778
|
this.showTreeSelector();
|
|
7914
8779
|
}
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
8780
|
+
handleValueChange(e) {
|
|
8781
|
+
if (e.isUserInteraction) {
|
|
8782
|
+
if (isNil(e.value) || isEmpty(e.value)) {
|
|
8783
|
+
this.clear();
|
|
8784
|
+
}
|
|
8785
|
+
else {
|
|
8786
|
+
const items = Array.isArray(e.value) ? e.value : [e.value];
|
|
8787
|
+
this.setItems(items);
|
|
8788
|
+
}
|
|
8789
|
+
}
|
|
8790
|
+
}
|
|
8791
|
+
handleOnBlur(e) {
|
|
8792
|
+
setTimeout(() => {
|
|
8793
|
+
if (!this.isOpen()) {
|
|
8794
|
+
this.clearInput();
|
|
8795
|
+
}
|
|
8796
|
+
}, 100);
|
|
8797
|
+
}
|
|
8798
|
+
async handleKeyUp(e) {
|
|
8799
|
+
const keyEvent = e.nativeEvent;
|
|
8800
|
+
const value = this.tagBox()?.inputValue() ?? '';
|
|
8801
|
+
this.searchTerm.set(value);
|
|
8802
|
+
if ((keyEvent.code == 'Enter' || keyEvent.code == 'NumpadEnter') && value) {
|
|
8803
|
+
this.isLoading.set(true);
|
|
8804
|
+
// For category widget, always open selector on Enter
|
|
8805
|
+
this.showTreeSelector();
|
|
8806
|
+
this.isLoading.set(false);
|
|
8807
|
+
}
|
|
8808
|
+
if (keyEvent.code == 'ArrowDown') {
|
|
8809
|
+
this.showTreeSelector();
|
|
8810
|
+
}
|
|
7918
8811
|
}
|
|
7919
8812
|
handleClearClick() {
|
|
7920
8813
|
this.clear();
|
|
7921
8814
|
}
|
|
8815
|
+
async handleRemoveItem(event, index) {
|
|
8816
|
+
event.stopPropagation();
|
|
8817
|
+
if (this.disabled()) {
|
|
8818
|
+
return;
|
|
8819
|
+
}
|
|
8820
|
+
const currentItems = this.selectedItems();
|
|
8821
|
+
if (index < 0 || index >= currentItems.length) {
|
|
8822
|
+
return;
|
|
8823
|
+
}
|
|
8824
|
+
const filteredItems = currentItems.filter((_, i) => i !== index);
|
|
8825
|
+
if (filteredItems.length === 0) {
|
|
8826
|
+
this.clear();
|
|
8827
|
+
}
|
|
8828
|
+
else {
|
|
8829
|
+
await this.setItems(filteredItems);
|
|
8830
|
+
}
|
|
8831
|
+
}
|
|
8832
|
+
clearInput() {
|
|
8833
|
+
this.tagBox()?.inputValue.set('');
|
|
8834
|
+
this.searchTerm.set('');
|
|
8835
|
+
}
|
|
7922
8836
|
async showTreeSelector() {
|
|
7923
8837
|
this.isOpen.set(true);
|
|
7924
8838
|
const currentValue = this.getValue();
|
|
@@ -7989,24 +8903,12 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
7989
8903
|
}
|
|
7990
8904
|
finally {
|
|
7991
8905
|
this.isOpen.set(false);
|
|
7992
|
-
|
|
7993
|
-
}
|
|
7994
|
-
async removeItem(item) {
|
|
7995
|
-
if (this.disabled()) {
|
|
7996
|
-
return;
|
|
7997
|
-
}
|
|
7998
|
-
const currentItems = this.selectedItems();
|
|
7999
|
-
const itemId = get(item, this.valueField());
|
|
8000
|
-
const filteredItems = currentItems.filter((i) => get(i, this.valueField()) !== itemId);
|
|
8001
|
-
if (filteredItems.length === 0) {
|
|
8002
|
-
this.clear();
|
|
8003
|
-
}
|
|
8004
|
-
else {
|
|
8005
|
-
await this.setItems(filteredItems);
|
|
8906
|
+
this.tagBox()?.focus();
|
|
8006
8907
|
}
|
|
8007
8908
|
}
|
|
8008
8909
|
clear() {
|
|
8009
8910
|
this.setValue(null);
|
|
8911
|
+
this.clearInput();
|
|
8010
8912
|
this.selectedItems.set([]);
|
|
8011
8913
|
this.cdr.markForCheck();
|
|
8012
8914
|
}
|
|
@@ -8088,6 +8990,7 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
8088
8990
|
return;
|
|
8089
8991
|
}
|
|
8090
8992
|
items = castArray(items);
|
|
8993
|
+
this.clearInput();
|
|
8091
8994
|
// Ensure all items have paths
|
|
8092
8995
|
const itemsWithPaths = await Promise.all(items.map(async (item) => {
|
|
8093
8996
|
// If item already has a path array, return it as is
|
|
@@ -8229,47 +9132,78 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
8229
9132
|
return { ...item, path: pathArray };
|
|
8230
9133
|
}
|
|
8231
9134
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
8232
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityCategoryWidgetEditComponent, isStandalone: true, selector: "axp-entity-category-widget-edit", usesInheritance: true, ngImport: i0, template: `
|
|
8233
|
-
<
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
9135
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityCategoryWidgetEditComponent, isStandalone: true, selector: "axp-entity-category-widget-edit", viewQueries: [{ propertyName: "tagBox", first: true, predicate: ["tagBoxComponent"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
9136
|
+
<ax-tag-box
|
|
9137
|
+
#tagBoxComponent
|
|
9138
|
+
[tagTemplate]="tagTemplate"
|
|
9139
|
+
[ngModel]="selectedItems()"
|
|
9140
|
+
[textField]="displayField()"
|
|
9141
|
+
[valueField]="valueField()"
|
|
9142
|
+
(onValueChanged)="handleValueChange($event)"
|
|
9143
|
+
[placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
|
|
9144
|
+
[addOnEnter]="false"
|
|
9145
|
+
[addOnComma]="false"
|
|
9146
|
+
[readonly]="true"
|
|
9147
|
+
[disabled]="disabled()"
|
|
9148
|
+
(onKeyUp)="handleKeyUp($event)"
|
|
9149
|
+
(onBlur)="handleOnBlur($event)"
|
|
9150
|
+
>
|
|
9151
|
+
@for (validation of validationRules(); track $index) {
|
|
9152
|
+
<ax-validation-rule
|
|
9153
|
+
[rule]="validation.rule"
|
|
9154
|
+
[message]="validation.options?.message"
|
|
9155
|
+
[options]="validation.options"
|
|
9156
|
+
></ax-validation-rule>
|
|
9157
|
+
}
|
|
9158
|
+
@if (selectedItems().length > 1 || allowClear()) {
|
|
9159
|
+
<ax-clear-button (click)="handleClearClick()"></ax-clear-button>
|
|
8250
9160
|
}
|
|
8251
9161
|
|
|
8252
|
-
<
|
|
8253
|
-
<ax-button
|
|
8254
|
-
[text]="'@general:actions.add.title' | translate | async"
|
|
8255
|
-
color="primary"
|
|
8256
|
-
[disabled]="isLoading() || disabled()"
|
|
8257
|
-
(onClick)="handleAddClick($event)"
|
|
8258
|
-
>
|
|
9162
|
+
<ax-suffix>
|
|
9163
|
+
<ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleAddClick($event)">
|
|
8259
9164
|
@if (isLoading()) {
|
|
8260
9165
|
<ax-loading></ax-loading>
|
|
8261
9166
|
} @else {
|
|
8262
|
-
<ax-icon icon="far fa-
|
|
9167
|
+
<ax-icon icon="far fa-search"></ax-icon>
|
|
8263
9168
|
}
|
|
8264
9169
|
</ax-button>
|
|
8265
|
-
|
|
8266
|
-
|
|
8267
|
-
|
|
8268
|
-
|
|
8269
|
-
|
|
8270
|
-
|
|
9170
|
+
</ax-suffix>
|
|
9171
|
+
</ax-tag-box>
|
|
9172
|
+
<ng-template #tagTemplate let-item let-index="index">
|
|
9173
|
+
<div class="ax-inline-flex ax-items-center ax-gap-1.5 ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface">
|
|
9174
|
+
<axp-truncated-breadcrumb
|
|
9175
|
+
[attr.data-color]="item.color"
|
|
9176
|
+
[sections]="getItemPath(item)"
|
|
9177
|
+
[characterLimit]="characterLimit()"
|
|
9178
|
+
[sectionLimit]="sectionLimit()"
|
|
9179
|
+
></axp-truncated-breadcrumb>
|
|
9180
|
+
<button type="button" (click)="handleRemoveItem($event, index)">
|
|
9181
|
+
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
9182
|
+
</button>
|
|
8271
9183
|
</div>
|
|
8272
|
-
|
|
9184
|
+
</ng-template>
|
|
9185
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$2.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6$1.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPTruncatedBreadcrumbComponent, selector: "axp-truncated-breadcrumb", inputs: ["sections", "characterLimit", "sectionLimit", "separatorIcon", "ellipsisIcon", "eyeIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9186
|
+
}
|
|
9187
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetEditComponent, decorators: [{
|
|
9188
|
+
type: Component,
|
|
9189
|
+
args: [{
|
|
9190
|
+
selector: 'axp-entity-category-widget-edit',
|
|
9191
|
+
template: `
|
|
9192
|
+
<ax-tag-box
|
|
9193
|
+
#tagBoxComponent
|
|
9194
|
+
[tagTemplate]="tagTemplate"
|
|
9195
|
+
[ngModel]="selectedItems()"
|
|
9196
|
+
[textField]="displayField()"
|
|
9197
|
+
[valueField]="valueField()"
|
|
9198
|
+
(onValueChanged)="handleValueChange($event)"
|
|
9199
|
+
[placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
|
|
9200
|
+
[addOnEnter]="false"
|
|
9201
|
+
[addOnComma]="false"
|
|
9202
|
+
[readonly]="true"
|
|
9203
|
+
[disabled]="disabled()"
|
|
9204
|
+
(onKeyUp)="handleKeyUp($event)"
|
|
9205
|
+
(onBlur)="handleOnBlur($event)"
|
|
9206
|
+
>
|
|
8273
9207
|
@for (validation of validationRules(); track $index) {
|
|
8274
9208
|
<ax-validation-rule
|
|
8275
9209
|
[rule]="validation.rule"
|
|
@@ -8277,76 +9211,49 @@ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
8277
9211
|
[options]="validation.options"
|
|
8278
9212
|
></ax-validation-rule>
|
|
8279
9213
|
}
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
}
|
|
8283
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetEditComponent, decorators: [{
|
|
8284
|
-
type: Component,
|
|
8285
|
-
args: [{
|
|
8286
|
-
selector: 'axp-entity-category-widget-edit',
|
|
8287
|
-
template: `
|
|
8288
|
-
<div class="ax-flex ax-flex-col ax-gap-3">
|
|
8289
|
-
@if (selectedItems().length > 0) {
|
|
8290
|
-
<div class="ax-flex ax-flex-col ax-gap-2">
|
|
8291
|
-
@for (item of selectedItems(); track getItemId(item)) {
|
|
8292
|
-
<div class="ax-flex ax-items-center ax-gap-2 ax-p-2 ax-border ax-primary-lightest ax-rounded-xl">
|
|
8293
|
-
<axp-truncated-breadcrumb
|
|
8294
|
-
[sections]="getItemPath(item)"
|
|
8295
|
-
[characterLimit]="characterLimit()"
|
|
8296
|
-
[sectionLimit]="sectionLimit()"
|
|
8297
|
-
class="ax-flex-1"
|
|
8298
|
-
></axp-truncated-breadcrumb>
|
|
8299
|
-
<ax-button color="ghost" look="blank" class="ax-xs" (onClick)="handleRemoveItemClick($event, item)">
|
|
8300
|
-
<ax-icon icon="ax-icon ax-icon-close"></ax-icon>
|
|
8301
|
-
</ax-button>
|
|
8302
|
-
</div>
|
|
8303
|
-
}
|
|
8304
|
-
</div>
|
|
9214
|
+
@if (selectedItems().length > 1 || allowClear()) {
|
|
9215
|
+
<ax-clear-button (click)="handleClearClick()"></ax-clear-button>
|
|
8305
9216
|
}
|
|
8306
9217
|
|
|
8307
|
-
<
|
|
8308
|
-
<ax-button
|
|
8309
|
-
[text]="'@general:actions.add.title' | translate | async"
|
|
8310
|
-
color="primary"
|
|
8311
|
-
[disabled]="isLoading() || disabled()"
|
|
8312
|
-
(onClick)="handleAddClick($event)"
|
|
8313
|
-
>
|
|
9218
|
+
<ax-suffix>
|
|
9219
|
+
<ax-button color="ghost" look="blank" [disabled]="isLoading() || disabled()" (onClick)="handleAddClick($event)">
|
|
8314
9220
|
@if (isLoading()) {
|
|
8315
9221
|
<ax-loading></ax-loading>
|
|
8316
9222
|
} @else {
|
|
8317
|
-
<ax-icon icon="far fa-
|
|
9223
|
+
<ax-icon icon="far fa-search"></ax-icon>
|
|
8318
9224
|
}
|
|
8319
9225
|
</ax-button>
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
9226
|
+
</ax-suffix>
|
|
9227
|
+
</ax-tag-box>
|
|
9228
|
+
<ng-template #tagTemplate let-item let-index="index">
|
|
9229
|
+
<div class="ax-inline-flex ax-items-center ax-gap-1.5 ax-rounded-md ax-px-3 ax-py-1 ax-text-sm ax-surface">
|
|
9230
|
+
<axp-truncated-breadcrumb
|
|
9231
|
+
[attr.data-color]="item.color"
|
|
9232
|
+
[sections]="getItemPath(item)"
|
|
9233
|
+
[characterLimit]="characterLimit()"
|
|
9234
|
+
[sectionLimit]="sectionLimit()"
|
|
9235
|
+
></axp-truncated-breadcrumb>
|
|
9236
|
+
<button type="button" (click)="handleRemoveItem($event, index)">
|
|
9237
|
+
<ax-icon class="ax-icon ax-icon-close"></ax-icon>
|
|
9238
|
+
</button>
|
|
8326
9239
|
</div>
|
|
8327
|
-
|
|
8328
|
-
@for (validation of validationRules(); track $index) {
|
|
8329
|
-
<ax-validation-rule
|
|
8330
|
-
[rule]="validation.rule"
|
|
8331
|
-
[message]="validation.options?.message"
|
|
8332
|
-
[options]="validation.options"
|
|
8333
|
-
></ax-validation-rule>
|
|
8334
|
-
}
|
|
8335
|
-
</div>
|
|
9240
|
+
</ng-template>
|
|
8336
9241
|
`,
|
|
8337
9242
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
8338
9243
|
imports: [
|
|
8339
9244
|
CommonModule,
|
|
9245
|
+
FormsModule,
|
|
8340
9246
|
AXButtonModule,
|
|
8341
9247
|
AXDecoratorModule,
|
|
8342
9248
|
AXLoadingModule,
|
|
8343
9249
|
AXValidationModule,
|
|
8344
9250
|
AXFormModule,
|
|
9251
|
+
AXTagBoxModule,
|
|
8345
9252
|
AXTranslationModule,
|
|
8346
9253
|
AXPTruncatedBreadcrumbComponent,
|
|
8347
9254
|
],
|
|
8348
9255
|
}]
|
|
8349
|
-
}] });
|
|
9256
|
+
}], propDecorators: { tagBox: [{ type: i0.ViewChild, args: ['tagBoxComponent', { isSignal: true }] }] } });
|
|
8350
9257
|
|
|
8351
9258
|
var entityCategoryWidgetEdit_component = /*#__PURE__*/Object.freeze({
|
|
8352
9259
|
__proto__: null,
|
|
@@ -8448,7 +9355,7 @@ class AXPEntityCategoryWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
8448
9355
|
<span class="ax-text-muted">---</span>
|
|
8449
9356
|
}
|
|
8450
9357
|
}
|
|
8451
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type:
|
|
9358
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8452
9359
|
}
|
|
8453
9360
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetViewComponent, decorators: [{
|
|
8454
9361
|
type: Component,
|
|
@@ -8942,6 +9849,8 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
8942
9849
|
this.entityListTableService = inject(AXPEntityListTableService);
|
|
8943
9850
|
this.entityListToolbarService = inject(AXPEntityListToolbarService);
|
|
8944
9851
|
this.deviceService = inject(AXPDeviceService);
|
|
9852
|
+
this.commandService = inject(AXPCommandService);
|
|
9853
|
+
this.eventService = inject(AXPBroadcastEventService);
|
|
8945
9854
|
this.isMounted = signal(false, ...(ngDevMode ? [{ debugName: "isMounted" }] : []));
|
|
8946
9855
|
this.entity = signal(null, ...(ngDevMode ? [{ debugName: "entity" }] : []));
|
|
8947
9856
|
this.listNode = signal(null, ...(ngDevMode ? [{ debugName: "listNode" }] : []));
|
|
@@ -9024,17 +9933,21 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
9024
9933
|
return actions;
|
|
9025
9934
|
}, ...(ngDevMode ? [{ debugName: "secondaryActions" }] : []));
|
|
9026
9935
|
//#region ---- Query Change Handler ----
|
|
9936
|
+
this.queries = undefined;
|
|
9027
9937
|
this.#effect = effect(() => {
|
|
9028
|
-
|
|
9938
|
+
//TODO: this is a temporary solution to handle the query changes; this should be removed when the query changes are handled in the widget core;
|
|
9939
|
+
if (this.getValue()?.toolbar) {
|
|
9940
|
+
this.queries = this.getValue()?.toolbar;
|
|
9941
|
+
}
|
|
9029
9942
|
const listInstance = this.listWidget()?.instance;
|
|
9030
9943
|
// const dataSource = this.listWidget()?.options()['dataSource'] as AXDataSource;
|
|
9031
9944
|
const dataSource = listInstance?.options()?.['dataSource'];
|
|
9032
9945
|
const isMounted = this.isMounted();
|
|
9033
|
-
if (!this.hasRequiredDependencies(dataSource, queries, listInstance)) {
|
|
9946
|
+
if (!this.hasRequiredDependencies(dataSource, this.queries, listInstance)) {
|
|
9034
9947
|
return;
|
|
9035
9948
|
}
|
|
9036
9949
|
untracked(() => {
|
|
9037
|
-
this.handleQueryChanges(queries, dataSource, listInstance, isMounted);
|
|
9950
|
+
this.handleQueryChanges(this.queries, dataSource, listInstance, isMounted);
|
|
9038
9951
|
});
|
|
9039
9952
|
}, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
|
|
9040
9953
|
//#endregion
|
|
@@ -9067,23 +9980,43 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
9067
9980
|
});
|
|
9068
9981
|
const command = commandName.split('&')[0];
|
|
9069
9982
|
// const options = await this.evaluateExpressions(action?.options, data);
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9983
|
+
if (this.commandService.exists(command)) {
|
|
9984
|
+
await this.commandService.execute(command, {
|
|
9985
|
+
__context__: {
|
|
9986
|
+
entity: this.entitySource(),
|
|
9987
|
+
entityInfo: {
|
|
9988
|
+
name: this.entity()?.name,
|
|
9989
|
+
module: this.entity()?.module,
|
|
9990
|
+
title: this.entity()?.title,
|
|
9991
|
+
parentKey: this.entity()?.parentKey,
|
|
9992
|
+
source: `${this.entity()?.module}.${this.entity()?.name}`,
|
|
9993
|
+
},
|
|
9994
|
+
data: action?.scope == AXPEntityCommandScope.Selected
|
|
9995
|
+
? this.selectedItems()
|
|
9996
|
+
: action?.options?.['process']?.data || null,
|
|
9997
|
+
options: action?.options,
|
|
9998
|
+
metadata: action?.metadata,
|
|
9999
|
+
},
|
|
10000
|
+
});
|
|
10001
|
+
}
|
|
10002
|
+
else {
|
|
10003
|
+
await this.workflow.execute(command, {
|
|
10004
|
+
entity: this.entitySource(),
|
|
10005
|
+
entityInfo: {
|
|
10006
|
+
name: this.entity()?.name,
|
|
10007
|
+
module: this.entity()?.module,
|
|
10008
|
+
title: this.entity()?.title,
|
|
10009
|
+
parentKey: this.entity()?.parentKey,
|
|
10010
|
+
source: `${this.entity()?.module}.${this.entity()?.name}`,
|
|
10011
|
+
},
|
|
10012
|
+
data: action?.scope == AXPEntityCommandScope.Selected
|
|
10013
|
+
? this.selectedItems()
|
|
10014
|
+
: action?.options?.['process']?.data || null,
|
|
10015
|
+
options: action?.options,
|
|
10016
|
+
metadata: action?.metadata,
|
|
10017
|
+
});
|
|
10018
|
+
}
|
|
9085
10019
|
}
|
|
9086
|
-
//#region ---- Query Change Handler ----
|
|
9087
10020
|
#effect;
|
|
9088
10021
|
/**
|
|
9089
10022
|
* Validates that all required dependencies are available
|
|
@@ -9216,6 +10149,14 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
9216
10149
|
this.listWidget()?.instance.call('refresh');
|
|
9217
10150
|
}
|
|
9218
10151
|
});
|
|
10152
|
+
this.eventService
|
|
10153
|
+
.listen(AXPEntityEventsKeys.REFRESH_LAYOUT)
|
|
10154
|
+
.pipe(takeUntil(this.destroyed))
|
|
10155
|
+
.subscribe((e) => {
|
|
10156
|
+
if (e.data.name == `${this.entity()?.module}.${this.entity()?.name}`) {
|
|
10157
|
+
this.listWidget()?.instance.call('refresh');
|
|
10158
|
+
}
|
|
10159
|
+
});
|
|
9219
10160
|
const listWidget = (await this.layoutService.waitForWidget(`${this.entitySource()}-tab-list_table`, 500));
|
|
9220
10161
|
if (listWidget?.api && typeof listWidget.api === 'function') {
|
|
9221
10162
|
const onSelectionChange = listWidget.api()['onSelectionChange'];
|
|
@@ -9344,7 +10285,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
9344
10285
|
></ng-container>
|
|
9345
10286
|
}
|
|
9346
10287
|
</div>
|
|
9347
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type:
|
|
10288
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "directive", type: i3$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i3.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i3.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i4$3.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9348
10289
|
}
|
|
9349
10290
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
|
|
9350
10291
|
type: Component,
|
|
@@ -9915,7 +10856,7 @@ class AXPLookupWidgetViewComponent extends AXPValueWidgetComponent {
|
|
|
9915
10856
|
<span class="ax-text-muted">---</span>
|
|
9916
10857
|
}
|
|
9917
10858
|
}
|
|
9918
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type:
|
|
10859
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
9919
10860
|
}
|
|
9920
10861
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLookupWidgetViewComponent, decorators: [{
|
|
9921
10862
|
type: Component,
|
|
@@ -10167,6 +11108,7 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
10167
11108
|
this.disabled = computed(() => this.options()['disabled'], ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
10168
11109
|
this.columns = computed(() => this.options()['columns'] ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
10169
11110
|
this.textField = computed(() => this.options()['textField'] ?? '', ...(ngDevMode ? [{ debugName: "textField" }] : []));
|
|
11111
|
+
this.hasClearButton = computed(() => this.options()['hasClearButton'] ?? false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : []));
|
|
10170
11112
|
this.customFilter = computed(() => this.options()['filter'], ...(ngDevMode ? [{ debugName: "customFilter" }] : []));
|
|
10171
11113
|
this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : []));
|
|
10172
11114
|
this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : []));
|
|
@@ -10563,6 +11505,9 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
10563
11505
|
[multiple]="multiple()"
|
|
10564
11506
|
(onValueChanged)="selectBoxValueChange($event)"
|
|
10565
11507
|
>
|
|
11508
|
+
@if (hasClearButton()) {
|
|
11509
|
+
<ax-clear-button></ax-clear-button>
|
|
11510
|
+
}
|
|
10566
11511
|
<ax-search-box
|
|
10567
11512
|
[placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
|
|
10568
11513
|
(onValueChanged)="handleSearchInputChange($event)"
|
|
@@ -10631,9 +11576,9 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
10631
11576
|
</ng-template>
|
|
10632
11577
|
}
|
|
10633
11578
|
}
|
|
10634
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1
|
|
11579
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type:
|
|
10635
11580
|
//
|
|
10636
|
-
AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type:
|
|
11581
|
+
AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorClearButtonComponent, selector: "ax-clear-button", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$2.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i6$1.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues", "tagTemplate"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onTagClick", "onTagDblClick", "onTagContextMenu"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "component", type: i7.AXSelectBoxComponent, selector: "ax-select-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "minValue", "maxValue", "value", "state", "name", "id", "type", "look", "multiple", "valueField", "textField", "disabledField", "textTemplate", "selectedItems", "isItemTruncated", "showItemTooltip", "itemHeight", "maxVisibleItems", "dataSource", "minRecordsForSearch", "caption", "itemTemplate", "selectedTemplate", "emptyTemplate", "loadingTemplate", "dropdownWidth", "searchBoxAutoFocus"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onOpened", "onClosed", "onItemSelected", "onItemClick"] }, { kind: "component", type: AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10637
11582
|
}
|
|
10638
11583
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLookupWidgetEditComponent, decorators: [{
|
|
10639
11584
|
type: Component,
|
|
@@ -10652,6 +11597,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
10652
11597
|
[multiple]="multiple()"
|
|
10653
11598
|
(onValueChanged)="selectBoxValueChange($event)"
|
|
10654
11599
|
>
|
|
11600
|
+
@if (hasClearButton()) {
|
|
11601
|
+
<ax-clear-button></ax-clear-button>
|
|
11602
|
+
}
|
|
10655
11603
|
<ax-search-box
|
|
10656
11604
|
[placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
|
|
10657
11605
|
(onValueChanged)="handleSearchInputChange($event)"
|
|
@@ -11006,7 +11954,7 @@ class AXPWidgetSelectorWidgetEditComponent extends AXPValueWidgetComponent {
|
|
|
11006
11954
|
<axp-widget-property-viewer [widget]="selectedWidgetNode()!" (onChanged)="handleChangeWidget($event)">
|
|
11007
11955
|
</axp-widget-property-viewer>
|
|
11008
11956
|
}
|
|
11009
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1
|
|
11957
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXSelectBoxModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i2$3.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "mask-options", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3$2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3$2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i5$2.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "component", type: AXPWidgetPropertyViewerComponent, selector: "axp-widget-property-viewer", inputs: ["widget", "mode"], outputs: ["onChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
11010
11958
|
}
|
|
11011
11959
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPWidgetSelectorWidgetEditComponent, decorators: [{
|
|
11012
11960
|
type: Component,
|
|
@@ -11525,7 +12473,7 @@ class AXPEntityModule {
|
|
|
11525
12473
|
},
|
|
11526
12474
|
});
|
|
11527
12475
|
}
|
|
11528
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityModule, deps: [{ token: i1$
|
|
12476
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityModule, deps: [{ token: i1$1.AXPAppStartUpService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
11529
12477
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityModule, imports: [RouterModule, i2$4.AXPWorkflowModule, i3$1.AXPWidgetCoreModule] }); }
|
|
11530
12478
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityModule, providers: [
|
|
11531
12479
|
{
|
|
@@ -11717,7 +12665,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
11717
12665
|
]),
|
|
11718
12666
|
],
|
|
11719
12667
|
}]
|
|
11720
|
-
}], ctorParameters: () => [{ type: i1$
|
|
12668
|
+
}], ctorParameters: () => [{ type: i1$1.AXPAppStartUpService }, { type: i0.Injector }] });
|
|
11721
12669
|
|
|
11722
12670
|
//#endregion
|
|
11723
12671
|
//#region ---- Get Entity Details Query ----
|
|
@@ -11871,7 +12819,7 @@ function entityDetailsCreateActions(parentId) {
|
|
|
11871
12819
|
return {
|
|
11872
12820
|
title: '@general:actions.create.title',
|
|
11873
12821
|
command: {
|
|
11874
|
-
name: '
|
|
12822
|
+
name: 'Entity:Create',
|
|
11875
12823
|
options: {
|
|
11876
12824
|
process: {
|
|
11877
12825
|
redirect: false,
|
|
@@ -11948,7 +12896,7 @@ function entityDetailsReferenceCreateActions(type) {
|
|
|
11948
12896
|
{
|
|
11949
12897
|
title: '@general:actions.create.title',
|
|
11950
12898
|
command: {
|
|
11951
|
-
name: '
|
|
12899
|
+
name: 'Entity:Create',
|
|
11952
12900
|
options: {
|
|
11953
12901
|
process: {
|
|
11954
12902
|
redirect: false,
|