@acorex/platform 20.6.0-next.15 → 20.6.0-next.16

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.
@@ -1,6 +1,6 @@
1
1
  import { AXPSessionService, AXPAuthGuard } from '@acorex/platform/auth';
2
2
  import * as i0 from '@angular/core';
3
- import { inject, Injectable, input, viewChild, signal, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, InjectionToken, computed, Injector, runInInjectionContext, viewChildren, linkedSignal, effect, untracked, HostBinding, ViewChild, NgModule } from '@angular/core';
3
+ import { inject, Injectable, input, viewChild, signal, ElementRef, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent, InjectionToken, computed, Injector, runInInjectionContext, ChangeDetectorRef, effect, viewChildren, linkedSignal, untracked, HostBinding, ViewChild, NgModule } from '@angular/core';
4
4
  import { Router, RouterModule, ROUTES } from '@angular/router';
5
5
  import * as i3 from '@acorex/components/button';
6
6
  import { AXButtonModule } from '@acorex/components/button';
@@ -11,17 +11,17 @@ import { AXPopoverModule } from '@acorex/components/popover';
11
11
  import * as i6 from '@acorex/core/translation';
12
12
  import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
13
13
  import * as i3$1 from '@acorex/platform/layout/widget-core';
14
- import { AXPWidgetsCatalog, AXPWidgetCoreModule, AXPPageStatus, AXPWidgetRegistryService, AXPValueWidgetComponent, AXPWidgetRendererDirective, AXPWidgetGroupEnum, AXPLayoutBaseWidgetComponent, AXPColumnWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/widget-core';
14
+ import { AXPWidgetsCatalog, AXPWidgetCoreModule, AXPPageStatus, AXPWidgetRegistryService, AXPColumnWidgetComponent, AXPValueWidgetComponent, AXPWidgetGroupEnum, AXPWidgetRendererDirective, AXPLayoutBaseWidgetComponent, AXP_WIDGETS_EDITOR_CATEGORY } from '@acorex/platform/layout/widget-core';
15
15
  import { AXPCommandService, AXPQueryService, provideCommandSetups, provideQuerySetups } from '@acorex/platform/runtime';
16
16
  import * as i5 from '@angular/common';
17
17
  import { CommonModule } from '@angular/common';
18
- import { castArray, get, cloneDeep, set, merge, orderBy, isEqual, isNil, isEmpty, sortBy } from 'lodash-es';
18
+ import { castArray, get, cloneDeep, set, merge, orderBy, isNil, isEqual, isEmpty, sortBy } from 'lodash-es';
19
19
  import { AXDataSource } from '@acorex/cdk/common';
20
20
  import { AXFormatService } from '@acorex/core/format';
21
21
  import * as i4$1 from '@acorex/platform/common';
22
22
  import { AXPFilterOperatorMiddlewareService, AXPEntityCommandScope, getEntityInfo, AXPSettingService, AXPRefreshEvent, AXPReloadEvent, AXPCommonSettings, AXPCleanNestedFilters, AXPWorkflowNavigateAction, AXPToastAction, AXP_SEARCH_DEFINITION_PROVIDER } from '@acorex/platform/common';
23
23
  import * as i1$1 from '@acorex/platform/core';
24
- import { resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPBroadcastEventService, AXPPlatformScope, AXPDeviceService, getChangedPaths, extractValue, setSmart, AXPSystemActionType } from '@acorex/platform/core';
24
+ import { resolveActionLook, AXPExpressionEvaluatorService, AXPDistributedEventListenerService, AXPBroadcastEventService, AXPPlatformScope, extractValue, setSmart, AXPDeviceService, getChangedPaths, AXPSystemActionType } from '@acorex/platform/core';
25
25
  import * as i2$3 from '@acorex/platform/workflow';
26
26
  import { AXPWorkflowService, ofType, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule } from '@acorex/platform/workflow';
27
27
  import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
@@ -33,23 +33,28 @@ import { AXPopupService } from '@acorex/components/popup';
33
33
  import { AXPlatform } from '@acorex/core/platform';
34
34
  import * as i3$2 from '@acorex/components/decorators';
35
35
  import { AXDecoratorModule } from '@acorex/components/decorators';
36
- import * as i4$2 from '@acorex/components/dropdown';
37
- import { AXDropdownModule } from '@acorex/components/dropdown';
38
- import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DISABLED_PROPERTY, AXP_ALLOW_CLEAR_PROPERTY, AXP_DATA_PROPERTY_GROUP, AXP_ALLOW_MULTIPLE_PROPERTY, AXPFileUploaderWidgetService } from '@acorex/platform/layout/widgets';
39
- import * as i1 from '@angular/forms';
40
- import { FormsModule } from '@angular/forms';
36
+ import { AXBasePageComponent } from '@acorex/components/page';
37
+ import * as i3$3 from '@acorex/components/search-box';
38
+ import { AXSearchBoxModule, AXSearchBoxComponent } from '@acorex/components/search-box';
39
+ import * as i4$2 from '@acorex/components/skeleton';
40
+ import { AXSkeletonModule } from '@acorex/components/skeleton';
41
+ import { AXTreeViewComponent } from '@acorex/components/tree-view';
42
+ import * as i2$1 from '@acorex/components/badge';
43
+ import { AXBadgeModule } from '@acorex/components/badge';
41
44
  import * as i5$1 from '@acorex/components/form';
42
45
  import { AXFormModule } from '@acorex/components/form';
43
46
  import * as i7 from '@acorex/components/select-box';
44
47
  import { AXSelectBoxModule } from '@acorex/components/select-box';
48
+ import * as i6$1 from '@acorex/components/tag-box';
49
+ import { AXTagBoxModule, AXTagBoxComponent } from '@acorex/components/tag-box';
50
+ import { AXValidationModule } from '@acorex/core/validation';
51
+ import * as i1 from '@angular/forms';
52
+ import { FormsModule } from '@angular/forms';
53
+ 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$3 from '@acorex/components/dropdown';
55
+ import { AXDropdownModule } from '@acorex/components/dropdown';
45
56
  import * as i2$2 from '@acorex/components/text-box';
46
57
  import { AXTextBoxModule, AXTextBoxComponent } from '@acorex/components/text-box';
47
- import { AXValidationModule } from '@acorex/core/validation';
48
- import * as i2$1 from '@acorex/components/badge';
49
- import { AXBadgeModule } from '@acorex/components/badge';
50
- import { AXSearchBoxComponent } from '@acorex/components/search-box';
51
- import * as i6$1 from '@acorex/components/tag-box';
52
- import { AXTagBoxComponent, AXTagBoxModule } from '@acorex/components/tag-box';
53
58
  import { AXPDataSelectorService, AXPWidgetPropertyViewerComponent } from '@acorex/platform/layout/components';
54
59
  import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
55
60
  import { transform, isEqual as isEqual$1 } from 'lodash';
@@ -4788,6 +4793,1468 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
4788
4793
  type: Injectable
4789
4794
  }] });
4790
4795
 
4796
+ //#endregion
4797
+ class AXPCategoryTreeService {
4798
+ constructor() {
4799
+ //#region ---- Services & Dependencies ----
4800
+ this.entityResolver = inject(AXPEntityResolver);
4801
+ this.translate = inject(AXTranslationService);
4802
+ }
4803
+ //#endregion
4804
+ //#region ---- Public Methods ----
4805
+ /**
4806
+ * Initialize category tree data source
4807
+ */
4808
+ async initializeCategoryTree(config) {
4809
+ const { entityKey } = config;
4810
+ if (!entityKey) {
4811
+ return null;
4812
+ }
4813
+ try {
4814
+ const [module, entity] = entityKey.split('.');
4815
+ if (!module || !entity) {
4816
+ return null;
4817
+ }
4818
+ const categoryEntityDef = await this.entityResolver.get(module, entity);
4819
+ if (!categoryEntityDef?.queries.list?.execute) {
4820
+ return null;
4821
+ }
4822
+ const categoryEntityQueryFunc = categoryEntityDef.queries.list.execute;
4823
+ const basicQueryEvent = {
4824
+ skip: 0,
4825
+ take: 1000,
4826
+ };
4827
+ return {
4828
+ categoryEntityDef,
4829
+ categoryEntityQueryFunc,
4830
+ basicQueryEvent,
4831
+ };
4832
+ }
4833
+ catch (error) {
4834
+ console.error('Error initializing category tree:', error);
4835
+ return null;
4836
+ }
4837
+ }
4838
+ /**
4839
+ * Create root node with children from items
4840
+ */
4841
+ async createRootNode(items, config) {
4842
+ const textField = config.textField ?? 'title';
4843
+ const valueField = config.valueField ?? 'id';
4844
+ const allItemsLabel = await this.translate.translateAsync('@general:terms.interface.selection.all-items');
4845
+ const rootNode = {
4846
+ id: 'all',
4847
+ label: allItemsLabel,
4848
+ icon: 'fa-solid fa-folder',
4849
+ childrenCount: items.length,
4850
+ expanded: true,
4851
+ data: { [valueField]: 'all', [textField]: allItemsLabel },
4852
+ };
4853
+ const childNodes = items.map((item) => this.convertToTreeNode(item, config));
4854
+ rootNode.children = childNodes;
4855
+ return rootNode;
4856
+ }
4857
+ /**
4858
+ * Convert entity item to AXTreeNode format
4859
+ */
4860
+ convertToTreeNode(item, config) {
4861
+ const textField = config.textField ?? 'title';
4862
+ const valueField = config.valueField ?? 'id';
4863
+ return {
4864
+ id: String(item[valueField] ?? ''),
4865
+ label: String(item[textField] ?? ''),
4866
+ icon: 'fa-solid fa-folder',
4867
+ childrenCount: item['childrenCount'] || item['children']?.length || 0,
4868
+ expanded: false,
4869
+ data: item,
4870
+ };
4871
+ }
4872
+ /**
4873
+ * Load root categories
4874
+ */
4875
+ async loadRootCategories(treeData, config) {
4876
+ if (!treeData.categoryEntityQueryFunc) {
4877
+ return null;
4878
+ }
4879
+ try {
4880
+ const res = await treeData.categoryEntityQueryFunc(treeData.basicQueryEvent);
4881
+ return res?.items ?? null;
4882
+ }
4883
+ catch (error) {
4884
+ console.error('Error loading root categories:', error);
4885
+ return null;
4886
+ }
4887
+ }
4888
+ /**
4889
+ * Load children for a given node
4890
+ */
4891
+ async loadChildren(node, treeData, config) {
4892
+ if (!treeData.categoryEntityQueryFunc || !treeData.categoryEntityDef?.parentKey) {
4893
+ return [];
4894
+ }
4895
+ try {
4896
+ const event = {
4897
+ ...treeData.basicQueryEvent,
4898
+ filter: {
4899
+ field: treeData.categoryEntityDef.parentKey,
4900
+ value: node.id,
4901
+ operator: { type: 'equal' },
4902
+ },
4903
+ };
4904
+ const res = await treeData.categoryEntityQueryFunc(event);
4905
+ if (!res?.items) {
4906
+ return [];
4907
+ }
4908
+ return res.items.map((item) => this.convertToTreeNode(item, config));
4909
+ }
4910
+ catch (error) {
4911
+ console.error('Error loading children:', error);
4912
+ return [];
4913
+ }
4914
+ }
4915
+ /**
4916
+ * Search categories
4917
+ */
4918
+ async searchCategories(searchValue, treeData, config) {
4919
+ if (!treeData.categoryEntityDef || !treeData.categoryEntityQueryFunc) {
4920
+ return null;
4921
+ }
4922
+ try {
4923
+ const categoryInlineFilters = treeData.categoryEntityDef.properties.filter((p) => p.options?.filter?.inline?.enabled);
4924
+ const event = {
4925
+ ...treeData.basicQueryEvent,
4926
+ filter: {
4927
+ filters: [
4928
+ {
4929
+ filters: categoryInlineFilters.map((cif) => ({
4930
+ field: cif.name,
4931
+ operator: {
4932
+ type: 'contains',
4933
+ },
4934
+ value: searchValue,
4935
+ })),
4936
+ logic: 'or',
4937
+ },
4938
+ {
4939
+ value: true,
4940
+ field: treeData.categoryEntityDef.parentKey,
4941
+ operator: {
4942
+ type: 'isEmpty',
4943
+ },
4944
+ },
4945
+ ],
4946
+ logic: 'and',
4947
+ },
4948
+ };
4949
+ const res = await treeData.categoryEntityQueryFunc(event);
4950
+ return res?.items ?? null;
4951
+ }
4952
+ catch (error) {
4953
+ console.error('Error searching categories:', error);
4954
+ return null;
4955
+ }
4956
+ }
4957
+ /**
4958
+ * Update children at a specific node in the tree
4959
+ */
4960
+ updateChildrenAtPath(nodes, targetId, childNodes) {
4961
+ return nodes.map((node) => {
4962
+ if (node.id === targetId) {
4963
+ return { ...node, children: childNodes, childrenCount: childNodes.length };
4964
+ }
4965
+ if (node.children?.length) {
4966
+ return { ...node, children: this.updateChildrenAtPath(node.children, targetId, childNodes) };
4967
+ }
4968
+ return node;
4969
+ });
4970
+ }
4971
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPCategoryTreeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4972
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPCategoryTreeService, providedIn: 'root' }); }
4973
+ }
4974
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPCategoryTreeService, decorators: [{
4975
+ type: Injectable,
4976
+ args: [{
4977
+ providedIn: 'root',
4978
+ }]
4979
+ }] });
4980
+
4981
+ class AXPEntityCategoryTreeSelectorComponent extends AXBasePageComponent {
4982
+ constructor() {
4983
+ super(...arguments);
4984
+ //#region ---- Services & Dependencies ----
4985
+ this.categoryTreeService = inject(AXPCategoryTreeService);
4986
+ //#endregion
4987
+ //#region ---- Properties (Set by popup service) ----
4988
+ this.entityKey = signal('', ...(ngDevMode ? [{ debugName: "entityKey" }] : []));
4989
+ this.textField = signal('title', ...(ngDevMode ? [{ debugName: "textField" }] : []));
4990
+ this.valueField = signal('id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
4991
+ this.allowMultiple = signal(false, ...(ngDevMode ? [{ debugName: "allowMultiple" }] : []));
4992
+ this.selectedValues = signal([], ...(ngDevMode ? [{ debugName: "selectedValues" }] : []));
4993
+ this.searchPlaceholder = signal('@general:terms.interface.category.search.placeholder', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : []));
4994
+ //#endregion
4995
+ //#region ---- View Queries ----
4996
+ this.tree = viewChild('tree', ...(ngDevMode ? [{ debugName: "tree" }] : []));
4997
+ //#endregion
4998
+ //#region ---- Component State ----
4999
+ this.loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
5000
+ this.selectedNodeIds = signal([], ...(ngDevMode ? [{ debugName: "selectedNodeIds" }] : []));
5001
+ //#endregion
5002
+ //#region ---- Private Properties ----
5003
+ this.treeData = null;
5004
+ this.treeConfig = null;
5005
+ this.searchResults = null;
5006
+ this.nodeDataCache = new Map(); // Cache node data by id for getSelectedItems
5007
+ /** Datasource callback for tree-view component. */
5008
+ this.datasource = async (id) => {
5009
+ if (!this.treeData || !this.treeConfig) {
5010
+ return [];
5011
+ }
5012
+ // If no id provided, return root nodes (or search results if available)
5013
+ if (!id) {
5014
+ // If we have search results, use them
5015
+ if (this.searchResults) {
5016
+ const rootNode = await this.categoryTreeService.createRootNode(this.searchResults, this.treeConfig);
5017
+ return [rootNode];
5018
+ }
5019
+ // Otherwise load root categories
5020
+ const items = await this.categoryTreeService.loadRootCategories(this.treeData, this.treeConfig);
5021
+ if (!items) {
5022
+ return [];
5023
+ }
5024
+ // Cache node data for getSelectedItems
5025
+ items.forEach((item) => {
5026
+ const itemId = item[this.treeConfig.valueField || 'id'];
5027
+ if (itemId) {
5028
+ this.nodeDataCache.set(itemId, item);
5029
+ }
5030
+ });
5031
+ const rootNode = await this.categoryTreeService.createRootNode(items, this.treeConfig);
5032
+ return [rootNode];
5033
+ }
5034
+ // Create a minimal node object with just the id (loadChildren only needs node.id)
5035
+ const targetNode = {
5036
+ id,
5037
+ label: '',
5038
+ data: {},
5039
+ };
5040
+ const childNodes = await this.categoryTreeService.loadChildren(targetNode, this.treeData, this.treeConfig);
5041
+ // Cache child node data for getSelectedItems
5042
+ childNodes.forEach((node) => {
5043
+ if (node.data && node.id) {
5044
+ this.nodeDataCache.set(node.id, node.data);
5045
+ }
5046
+ });
5047
+ return childNodes;
5048
+ };
5049
+ }
5050
+ //#endregion
5051
+ //#region ---- Lifecycle Methods ----
5052
+ ngOnInit() {
5053
+ super.ngOnInit();
5054
+ this.initializeTree();
5055
+ }
5056
+ //#endregion
5057
+ //#region ---- Private Methods ----
5058
+ async initializeTree() {
5059
+ if (!this.entityKey()) {
5060
+ this.loading.set(false);
5061
+ return;
5062
+ }
5063
+ this.loading.set(true);
5064
+ try {
5065
+ this.treeConfig = {
5066
+ entityKey: this.entityKey(),
5067
+ textField: this.textField(),
5068
+ valueField: this.valueField(),
5069
+ };
5070
+ this.treeData = await this.categoryTreeService.initializeCategoryTree(this.treeConfig);
5071
+ if (!this.treeData) {
5072
+ this.loading.set(false);
5073
+ return;
5074
+ }
5075
+ // Get parentKey from entity definition
5076
+ if (this.treeData.categoryEntityDef?.parentKey) {
5077
+ this.treeConfig.parentKey = this.treeData.categoryEntityDef.parentKey;
5078
+ }
5079
+ // Initialize selected nodes and load their data into cache
5080
+ await this.updateSelectedNodes(this.selectedValues());
5081
+ }
5082
+ catch (error) {
5083
+ console.error('Error loading entity definition:', error);
5084
+ }
5085
+ finally {
5086
+ this.loading.set(false);
5087
+ }
5088
+ }
5089
+ //#endregion
5090
+ //#region ---- Public Methods ----
5091
+ async handleSearchChange(e) {
5092
+ if (!this.treeData || !this.treeConfig) {
5093
+ return;
5094
+ }
5095
+ this.loading.set(true);
5096
+ try {
5097
+ const items = await this.categoryTreeService.searchCategories(e.value, this.treeData, this.treeConfig);
5098
+ if (!items) {
5099
+ this.searchResults = null;
5100
+ return;
5101
+ }
5102
+ // Store search results for datasource callback
5103
+ this.searchResults = items;
5104
+ // Cache node data for getSelectedItems
5105
+ items.forEach((item) => {
5106
+ const id = item[this.treeConfig.valueField || 'id'];
5107
+ if (id) {
5108
+ this.nodeDataCache.set(id, item);
5109
+ }
5110
+ });
5111
+ // Trigger tree refresh
5112
+ const treeComponent = this.tree();
5113
+ if (treeComponent) {
5114
+ treeComponent.refresh?.();
5115
+ }
5116
+ }
5117
+ catch (error) {
5118
+ console.error('Error searching categories:', error);
5119
+ }
5120
+ finally {
5121
+ this.loading.set(false);
5122
+ }
5123
+ }
5124
+ async onNodeToggle(event) {
5125
+ // Tree component handles lazy loading via datasource callback
5126
+ }
5127
+ async onNodeSelect(event) {
5128
+ const node = event.node;
5129
+ if (!node || node.id === 'all') {
5130
+ return;
5131
+ }
5132
+ // Cache node data for getSelectedItems
5133
+ if (node.data) {
5134
+ this.nodeDataCache.set(node.id, node.data);
5135
+ }
5136
+ const currentIds = this.selectedNodeIds();
5137
+ if (node.selected) {
5138
+ // Add to selection if not already selected
5139
+ if (!currentIds.includes(node.id)) {
5140
+ this.selectedNodeIds.set([...currentIds, node.id]);
5141
+ }
5142
+ }
5143
+ else {
5144
+ // Remove from selection
5145
+ this.selectedNodeIds.set(currentIds.filter((id) => id !== node.id));
5146
+ }
5147
+ }
5148
+ handleNodeClick(event) {
5149
+ // Extract node from event - could be { node: AXTreeNode } or just AXTreeNode
5150
+ const node = event?.node || event;
5151
+ if (!node || node.id === 'all') {
5152
+ return;
5153
+ }
5154
+ // Cache node data for getSelectedItems
5155
+ if (node.data) {
5156
+ this.nodeDataCache.set(node.id, node.data);
5157
+ }
5158
+ if (this.allowMultiple()) {
5159
+ // In multiple mode with checkboxes, clicking the node should toggle the checkbox
5160
+ // The checkbox state is handled by onNodeSelect, so we just sync the selection here
5161
+ const currentIds = this.selectedNodeIds();
5162
+ const isSelected = currentIds.includes(node.id);
5163
+ // Toggle selection state
5164
+ if (isSelected) {
5165
+ this.selectedNodeIds.set(currentIds.filter((id) => id !== node.id));
5166
+ }
5167
+ else {
5168
+ this.selectedNodeIds.set([...currentIds, node.id]);
5169
+ }
5170
+ }
5171
+ else {
5172
+ // Single selection - auto-confirm on click
5173
+ this.selectedNodeIds.set([node.id]);
5174
+ this.close({ selected: this.getSelectedItems() });
5175
+ }
5176
+ }
5177
+ async onConfirm() {
5178
+ this.close({ selected: this.getSelectedItems() });
5179
+ }
5180
+ async onCancel() {
5181
+ await this.close();
5182
+ }
5183
+ //#endregion
5184
+ async updateSelectedNodes(selectedIds) {
5185
+ if (!selectedIds || selectedIds.length === 0) {
5186
+ this.selectedNodeIds.set([]);
5187
+ return;
5188
+ }
5189
+ const ids = selectedIds.filter((id) => id && id !== 'all');
5190
+ this.selectedNodeIds.set(ids);
5191
+ // Fetch node data for pre-selected items that aren't in the cache
5192
+ // This ensures getSelectedItems() can retrieve them even if their branches aren't expanded
5193
+ await this.loadMissingNodeData(ids);
5194
+ // Note: Selection syncing is now handled by the tree component
5195
+ // The tree component should handle the selected state based on selectedNodeIds
5196
+ // If the tree component requires manual syncing, we may need to trigger a refresh
5197
+ }
5198
+ /**
5199
+ * Loads node data for IDs that are selected but not yet in the cache.
5200
+ * This is critical for pre-selected values in collapsed branches.
5201
+ */
5202
+ async loadMissingNodeData(selectedIds) {
5203
+ if (!this.treeData || !this.treeConfig || selectedIds.length === 0) {
5204
+ return;
5205
+ }
5206
+ // Find IDs that are selected but not in cache
5207
+ const missingIds = selectedIds.filter((id) => !this.nodeDataCache.has(id));
5208
+ if (missingIds.length === 0) {
5209
+ return;
5210
+ }
5211
+ try {
5212
+ const valueField = this.treeConfig.valueField || 'id';
5213
+ const categoryEntityQueryFunc = this.treeData.categoryEntityQueryFunc;
5214
+ if (!categoryEntityQueryFunc) {
5215
+ return;
5216
+ }
5217
+ // Query for missing nodes by their IDs
5218
+ const event = {
5219
+ ...this.treeData.basicQueryEvent,
5220
+ filter: {
5221
+ filters: missingIds.map((id) => ({
5222
+ field: valueField,
5223
+ value: id,
5224
+ operator: { type: 'equal' },
5225
+ })),
5226
+ logic: 'or',
5227
+ },
5228
+ };
5229
+ const res = await categoryEntityQueryFunc(event);
5230
+ if (res?.items) {
5231
+ // Cache the fetched node data
5232
+ res.items.forEach((item) => {
5233
+ const itemId = item[valueField];
5234
+ if (itemId) {
5235
+ this.nodeDataCache.set(itemId, item);
5236
+ }
5237
+ });
5238
+ }
5239
+ }
5240
+ catch (error) {
5241
+ console.error('Error loading missing node data:', error);
5242
+ }
5243
+ }
5244
+ getSelectedItems() {
5245
+ const selectedIds = this.selectedNodeIds();
5246
+ if (selectedIds.length === 0) {
5247
+ return [];
5248
+ }
5249
+ // Get node data from cache
5250
+ return selectedIds.map((id) => this.nodeDataCache.get(id)).filter((item) => item != null);
5251
+ }
5252
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5253
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityCategoryTreeSelectorComponent, isStandalone: true, selector: "axp-entity-category-tree-selector", viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
5254
+ <div class="ax-flex ax-flex-col ax-h-full">
5255
+ @if (loading()) {
5256
+ <div class="ax-p-4 ax-flex ax-flex-col ax-gap-3">
5257
+ <ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
5258
+ <ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
5259
+ <ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
5260
+ </div>
5261
+ } @else if (treeData) {
5262
+ <div class="ax-flex ax-flex-col ax-flex-1 ax-min-h-0">
5263
+ <div class="ax-p-4 ax-border-b">
5264
+ <ax-search-box
5265
+ (onValueChanged)="handleSearchChange($event)"
5266
+ [delayTime]="300"
5267
+ [placeholder]="searchPlaceholder()"
5268
+ ></ax-search-box>
5269
+ </div>
5270
+ <div class="ax-flex-1 ax-overflow-auto ax-p-4">
5271
+ <ax-tree-view
5272
+ [datasource]="datasource"
5273
+ [showCheckbox]="allowMultiple()"
5274
+ [showIcons]="true"
5275
+ (onNodeSelect)="onNodeSelect($event)"
5276
+ (onNodeToggle)="onNodeToggle($event)"
5277
+ (onNodeClick)="handleNodeClick($event)"
5278
+ #tree
5279
+ >
5280
+ </ax-tree-view>
5281
+ </div>
5282
+ </div>
5283
+ } @else {
5284
+ <div class="ax-p-4 ax-text-center ax-text-muted">
5285
+ <span>---</span>
5286
+ </div>
5287
+ }
5288
+ </div>
5289
+ @if (allowMultiple()) {
5290
+ <ax-footer>
5291
+ <ax-suffix>
5292
+ <ax-button
5293
+ look="solid"
5294
+ [text]="'@general:actions.cancel.title' | translate | async"
5295
+ (onClick)="onCancel()"
5296
+ ></ax-button>
5297
+ <ax-button
5298
+ look="solid"
5299
+ color="primary"
5300
+ [text]="'@general:actions.ok.title' | translate | async"
5301
+ (onClick)="onConfirm()"
5302
+ ></ax-button>
5303
+ </ax-suffix>
5304
+ </ax-footer>
5305
+ }
5306
+ `, 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: 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" }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i3$3.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: i4$2.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXTreeViewComponent, selector: "ax-tree-view", inputs: ["datasource", "selectMode", "showCheckbox", "checkChildrenOnSelect", "intermediateState", "checkOnClick", "dragMode", "dragOperationType", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "nodeHeight", "look", "itemTemplate"], outputs: ["datasourceChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5307
+ }
5308
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryTreeSelectorComponent, decorators: [{
5309
+ type: Component,
5310
+ args: [{
5311
+ selector: 'axp-entity-category-tree-selector',
5312
+ template: `
5313
+ <div class="ax-flex ax-flex-col ax-h-full">
5314
+ @if (loading()) {
5315
+ <div class="ax-p-4 ax-flex ax-flex-col ax-gap-3">
5316
+ <ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
5317
+ <ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
5318
+ <ax-skeleton class="ax-w-full ax-h-6 ax-rounded-md"></ax-skeleton>
5319
+ </div>
5320
+ } @else if (treeData) {
5321
+ <div class="ax-flex ax-flex-col ax-flex-1 ax-min-h-0">
5322
+ <div class="ax-p-4 ax-border-b">
5323
+ <ax-search-box
5324
+ (onValueChanged)="handleSearchChange($event)"
5325
+ [delayTime]="300"
5326
+ [placeholder]="searchPlaceholder()"
5327
+ ></ax-search-box>
5328
+ </div>
5329
+ <div class="ax-flex-1 ax-overflow-auto ax-p-4">
5330
+ <ax-tree-view
5331
+ [datasource]="datasource"
5332
+ [showCheckbox]="allowMultiple()"
5333
+ [showIcons]="true"
5334
+ (onNodeSelect)="onNodeSelect($event)"
5335
+ (onNodeToggle)="onNodeToggle($event)"
5336
+ (onNodeClick)="handleNodeClick($event)"
5337
+ #tree
5338
+ >
5339
+ </ax-tree-view>
5340
+ </div>
5341
+ </div>
5342
+ } @else {
5343
+ <div class="ax-p-4 ax-text-center ax-text-muted">
5344
+ <span>---</span>
5345
+ </div>
5346
+ }
5347
+ </div>
5348
+ @if (allowMultiple()) {
5349
+ <ax-footer>
5350
+ <ax-suffix>
5351
+ <ax-button
5352
+ look="solid"
5353
+ [text]="'@general:actions.cancel.title' | translate | async"
5354
+ (onClick)="onCancel()"
5355
+ ></ax-button>
5356
+ <ax-button
5357
+ look="solid"
5358
+ color="primary"
5359
+ [text]="'@general:actions.ok.title' | translate | async"
5360
+ (onClick)="onConfirm()"
5361
+ ></ax-button>
5362
+ </ax-suffix>
5363
+ </ax-footer>
5364
+ }
5365
+ `,
5366
+ changeDetection: ChangeDetectionStrategy.OnPush,
5367
+ imports: [
5368
+ CommonModule,
5369
+ AXButtonModule,
5370
+ AXDecoratorModule,
5371
+ AXSearchBoxModule,
5372
+ AXSkeletonModule,
5373
+ AXTreeViewComponent,
5374
+ AXTranslationModule,
5375
+ ],
5376
+ }]
5377
+ }], propDecorators: { tree: [{ type: i0.ViewChild, args: ['tree', { isSignal: true }] }] } });
5378
+
5379
+ class AXPEntityCategoryWidgetColumnComponent extends AXPColumnWidgetComponent {
5380
+ constructor() {
5381
+ super(...arguments);
5382
+ //#region ---- Dependencies ----
5383
+ this.entityDetailPopoverService = inject(AXPEntityDetailPopoverService);
5384
+ this.formatService = inject(AXFormatService);
5385
+ //#endregion
5386
+ //#region ---- View Children ----
5387
+ this.moreButton = viewChild('moreButton', ...(ngDevMode ? [{ debugName: "moreButton" }] : []));
5388
+ this.morePopover = viewChild('morePopover', ...(ngDevMode ? [{ debugName: "morePopover" }] : []));
5389
+ //#endregion
5390
+ //#region ---- Properties ----
5391
+ this.host = inject(ElementRef);
5392
+ this.valueField = this.options['valueField'] ?? 'id';
5393
+ this.textField = this.options['textField'] ?? 'title';
5394
+ this.entity = this.options['entity'] ?? '';
5395
+ this.columnName = this.options['columnName'] ?? '';
5396
+ this.maxVisible = this.options['maxVisible'] ?? 2;
5397
+ //#endregion
5398
+ //#region ---- Signals ----
5399
+ this.isMorePopoverOpen = signal(false, ...(ngDevMode ? [{ debugName: "isMorePopoverOpen" }] : []));
5400
+ this.selectedItemIndex = signal(-1, ...(ngDevMode ? [{ debugName: "selectedItemIndex" }] : []));
5401
+ //#endregion
5402
+ //#region ---- Computed Properties ----
5403
+ this.displayItems = computed(() => isNil(this.rawValue)
5404
+ ? []
5405
+ : castArray(this.rawValue)
5406
+ .map((item) => this.extractItem(item))
5407
+ .filter((c) => c != null), ...(ngDevMode ? [{ debugName: "displayItems" }] : []));
5408
+ this.allItems = computed(() => this.displayItems(), ...(ngDevMode ? [{ debugName: "allItems" }] : []));
5409
+ this.visibleItems = computed(() => {
5410
+ const items = this.allItems();
5411
+ return items.slice(0, this.maxVisible);
5412
+ }, ...(ngDevMode ? [{ debugName: "visibleItems" }] : []));
5413
+ this.remainingItems = computed(() => {
5414
+ const items = this.allItems();
5415
+ return items.slice(this.maxVisible);
5416
+ }, ...(ngDevMode ? [{ debugName: "remainingItems" }] : []));
5417
+ this.hasMoreItems = computed(() => {
5418
+ return this.allItems().length > this.maxVisible;
5419
+ }, ...(ngDevMode ? [{ debugName: "hasMoreItems" }] : []));
5420
+ this.remainingItemsCount = computed(() => {
5421
+ return this.allItems().length - this.maxVisible;
5422
+ }, ...(ngDevMode ? [{ debugName: "remainingItemsCount" }] : []));
5423
+ }
5424
+ //#endregion
5425
+ //#region ---- Public Methods ----
5426
+ showMoreItems() {
5427
+ this.entityDetailPopoverService.hide();
5428
+ this.openMorePopover();
5429
+ }
5430
+ onMorePopoverOpenChange(event) {
5431
+ this.isMorePopoverOpen.set(event);
5432
+ }
5433
+ async showItemDetail(item, index) {
5434
+ const columnData = this.rowData[this.columnName];
5435
+ const id = Array.isArray(columnData) ? columnData[index] : columnData;
5436
+ this.selectedItemIndex.set(index);
5437
+ this.closeMorePopover();
5438
+ if (this.entity && id) {
5439
+ await this.entityDetailPopoverService.show(this.host, {
5440
+ entity: this.entity,
5441
+ id: id,
5442
+ textField: this.textField,
5443
+ valueField: this.valueField,
5444
+ item,
5445
+ });
5446
+ }
5447
+ }
5448
+ handleItemClick(index) {
5449
+ const items = this.allItems();
5450
+ if (index < items.length) {
5451
+ const item = items[index];
5452
+ this.showItemDetail(item, index);
5453
+ }
5454
+ }
5455
+ //#endregion
5456
+ //#region ---- Private Methods ----
5457
+ openMorePopover() {
5458
+ if (this.morePopover() && this.moreButton()) {
5459
+ this.morePopover().target = this.moreButton().nativeElement;
5460
+ this.morePopover().open();
5461
+ this.isMorePopoverOpen.set(true);
5462
+ }
5463
+ }
5464
+ closeMorePopover() {
5465
+ if (this.morePopover()) {
5466
+ this.morePopover().close();
5467
+ this.isMorePopoverOpen.set(false);
5468
+ }
5469
+ }
5470
+ extractItem(item) {
5471
+ if (isNil(item)) {
5472
+ return null;
5473
+ }
5474
+ if (typeof item === 'object') {
5475
+ return item;
5476
+ }
5477
+ return {
5478
+ [this.valueField]: item,
5479
+ [this.textField]: item,
5480
+ };
5481
+ }
5482
+ getDisplayText(item) {
5483
+ if (!item) {
5484
+ return '';
5485
+ }
5486
+ return item?.[this.textField] ?? String(item);
5487
+ }
5488
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5489
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityCategoryWidgetColumnComponent, isStandalone: true, selector: "axp-entity-category-widget-column", inputs: { rawValue: "rawValue", rowData: "rowData" }, viewQueries: [{ propertyName: "moreButton", first: true, predicate: ["moreButton"], descendants: true, isSignal: true }, { propertyName: "morePopover", first: true, predicate: ["morePopover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
5490
+ <div class="ax-flex ax-items-center ax-gap-1 ax-flex-wrap">
5491
+ @for (item of visibleItems(); track $index) {
5492
+ <ax-badge
5493
+ class="ax-p-0.5 ax-cursor-pointer"
5494
+ [text]="getDisplayText(item)"
5495
+ (click)="handleItemClick($index)"
5496
+ ></ax-badge>
5497
+ }
5498
+ @if (hasMoreItems()) {
5499
+ <span class="ax-cursor-pointer ax-px-1" (click)="showMoreItems()" #moreButton>
5500
+ <i class="fas fa-ellipsis-h"></i>
5501
+ </span>
5502
+ <ax-popover #morePopover [openOn]="'manual'" (openChange)="onMorePopoverOpenChange($event)">
5503
+ <div class="ax-p-2 ax-flex ax-flex-col ax-gap-1">
5504
+ @for (item of remainingItems(); track $index) {
5505
+ <ax-badge
5506
+ class="ax-p-0.5 ax-cursor-pointer"
5507
+ [text]="getDisplayText(item)"
5508
+ (click)="handleItemClick(visibleItems().length + $index)"
5509
+ ></ax-badge>
5510
+ }
5511
+ </div>
5512
+ </ax-popover>
5513
+ }
5514
+ </div>
5515
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXButtonModule }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5516
+ }
5517
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetColumnComponent, decorators: [{
5518
+ type: Component,
5519
+ args: [{
5520
+ selector: 'axp-entity-category-widget-column',
5521
+ template: `
5522
+ <div class="ax-flex ax-items-center ax-gap-1 ax-flex-wrap">
5523
+ @for (item of visibleItems(); track $index) {
5524
+ <ax-badge
5525
+ class="ax-p-0.5 ax-cursor-pointer"
5526
+ [text]="getDisplayText(item)"
5527
+ (click)="handleItemClick($index)"
5528
+ ></ax-badge>
5529
+ }
5530
+ @if (hasMoreItems()) {
5531
+ <span class="ax-cursor-pointer ax-px-1" (click)="showMoreItems()" #moreButton>
5532
+ <i class="fas fa-ellipsis-h"></i>
5533
+ </span>
5534
+ <ax-popover #morePopover [openOn]="'manual'" (openChange)="onMorePopoverOpenChange($event)">
5535
+ <div class="ax-p-2 ax-flex ax-flex-col ax-gap-1">
5536
+ @for (item of remainingItems(); track $index) {
5537
+ <ax-badge
5538
+ class="ax-p-0.5 ax-cursor-pointer"
5539
+ [text]="getDisplayText(item)"
5540
+ (click)="handleItemClick(visibleItems().length + $index)"
5541
+ ></ax-badge>
5542
+ }
5543
+ </div>
5544
+ </ax-popover>
5545
+ }
5546
+ </div>
5547
+ `,
5548
+ changeDetection: ChangeDetectionStrategy.OnPush,
5549
+ imports: [CommonModule, AXBadgeModule, AXButtonModule, AXPopoverModule],
5550
+ inputs: ['rawValue', 'rowData'],
5551
+ }]
5552
+ }], propDecorators: { moreButton: [{ type: i0.ViewChild, args: ['moreButton', { isSignal: true }] }], morePopover: [{ type: i0.ViewChild, args: ['morePopover', { isSignal: true }] }] } });
5553
+
5554
+ var entityCategoryWidgetColumn_component = /*#__PURE__*/Object.freeze({
5555
+ __proto__: null,
5556
+ AXPEntityCategoryWidgetColumnComponent: AXPEntityCategoryWidgetColumnComponent
5557
+ });
5558
+
5559
+ class AXPEntityCategoryWidgetEditComponent extends AXPValueWidgetComponent {
5560
+ constructor() {
5561
+ super(...arguments);
5562
+ //#region ---- Services & Dependencies ----
5563
+ this.entityResolver = inject(AXPEntityResolver);
5564
+ this.formatService = inject(AXFormatService);
5565
+ this.popupService = inject(AXPopupService);
5566
+ this.translateService = inject(AXTranslationService);
5567
+ this.cdr = inject(ChangeDetectorRef);
5568
+ //#endregion
5569
+ //#region ---- View Queries ----
5570
+ this.selectBox = viewChild('selectBox', ...(ngDevMode ? [{ debugName: "selectBox" }] : []));
5571
+ this.tagBox = viewChild('tagBoxComponent', ...(ngDevMode ? [{ debugName: "tagBox" }] : []));
5572
+ //#endregion
5573
+ //#region ---- Computed Properties ----
5574
+ this.entity = computed(() => this.options()['entity'] ?? '', ...(ngDevMode ? [{ debugName: "entity" }] : []));
5575
+ this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : []));
5576
+ this.disabled = computed(() => (this.options()['disabled'] ?? false), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5577
+ this.textField = computed(() => this.options()['textField'] ?? 'title', ...(ngDevMode ? [{ debugName: "textField" }] : []));
5578
+ this.valueField = computed(() => this.options()['valueField'] ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
5579
+ this.expose = computed(() => this.options()['expose'], ...(ngDevMode ? [{ debugName: "expose" }] : []));
5580
+ this.allowClear = computed(() => (this.options()['allowClear'] ?? false), ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
5581
+ this.look = computed(() => this.options()['look'] ?? 'lookup', ...(ngDevMode ? [{ debugName: "look" }] : []));
5582
+ this.defaultTextField = computed(() => {
5583
+ const textField = this.entityDef()?.formats.lookup ?? this.entityDef()?.properties.find((c) => c.name != 'id')?.name ?? 'title';
5584
+ return textField;
5585
+ }, ...(ngDevMode ? [{ debugName: "defaultTextField" }] : []));
5586
+ this.displayField = computed(() => {
5587
+ if (this.textField()) {
5588
+ return this.textField();
5589
+ }
5590
+ return this.defaultTextField();
5591
+ }, ...(ngDevMode ? [{ debugName: "displayField" }] : []));
5592
+ this.searchPlaceholderText = signal('', ...(ngDevMode ? [{ debugName: "searchPlaceholderText" }] : []));
5593
+ //#endregion
5594
+ //#region ---- Component State ----
5595
+ this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
5596
+ this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
5597
+ this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
5598
+ this.searchTerm = signal(null, ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
5599
+ //#endregion
5600
+ //#region ---- Private Properties ----
5601
+ this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
5602
+ this.dataSource = computed(() => {
5603
+ const entity = this.entityDef();
5604
+ if (!entity)
5605
+ return null;
5606
+ return new AXDataSource({
5607
+ byKey: (key) => {
5608
+ const func = entity.queries.byKey.execute;
5609
+ return func();
5610
+ },
5611
+ load: (e) => {
5612
+ const func = entity.queries.list?.execute;
5613
+ return func(e);
5614
+ },
5615
+ pageSize: 10,
5616
+ key: 'id',
5617
+ });
5618
+ }, ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
5619
+ //#endregion
5620
+ //#region ---- Effects ----
5621
+ this.#efEntity = effect(async () => {
5622
+ const entityKey = this.entity();
5623
+ if (!entityKey)
5624
+ return;
5625
+ const [module, entity] = entityKey.split('.');
5626
+ this.entityDef.set(await this.entityResolver.get(module, entity));
5627
+ }, ...(ngDevMode ? [{ debugName: "#efEntity" }] : []));
5628
+ this.#efValue = effect(() => {
5629
+ if (this.getValue()) {
5630
+ this.findByValue();
5631
+ }
5632
+ else {
5633
+ this.clear();
5634
+ }
5635
+ }, ...(ngDevMode ? [{ debugName: "#efValue" }] : []));
5636
+ this.#efSearchPlaceholder = effect(async () => {
5637
+ const entity = this.entityDef();
5638
+ if (!entity) {
5639
+ this.searchPlaceholderText.set('');
5640
+ return;
5641
+ }
5642
+ const displayFieldName = this.displayField();
5643
+ const displayProperty = entity.properties.find((property) => property.name === displayFieldName);
5644
+ if (displayProperty) {
5645
+ const translated = await this.translateService.translateAsync(displayProperty.title || displayProperty.name);
5646
+ this.searchPlaceholderText.set(translated ? `Search in ${translated}...` : '');
5647
+ }
5648
+ else {
5649
+ const fallback = await this.translateService.translateAsync('@general:actions.search.title');
5650
+ this.searchPlaceholderText.set(fallback ? `${fallback}...` : '');
5651
+ }
5652
+ }, ...(ngDevMode ? [{ debugName: "#efSearchPlaceholder" }] : []));
5653
+ }
5654
+ //#endregion
5655
+ //#region ---- Effects ----
5656
+ #efEntity;
5657
+ #efValue;
5658
+ #efSearchPlaceholder;
5659
+ //#endregion
5660
+ //#region ---- Public Methods ----
5661
+ handleOnClick(e) {
5662
+ this.showTreeSelector();
5663
+ }
5664
+ async showTreeSelector() {
5665
+ this.isOpen.set(true);
5666
+ const currentValue = this.getValue();
5667
+ const selectedIds = currentValue
5668
+ ? (this.multiple() ? castArray(currentValue) : [currentValue])
5669
+ .map((v) => String(extractValue(v, this.valueField())))
5670
+ .filter((id) => id && id !== 'all')
5671
+ : [];
5672
+ try {
5673
+ const result = await this.popupService.open(AXPEntityCategoryTreeSelectorComponent, {
5674
+ title: `${this.translateService.translateSync('@general:widgets.lookup.search')} ${this.translateService.translateSync(this.entityDef()?.formats.plural ?? '')}`,
5675
+ size: 'lg',
5676
+ data: {
5677
+ entityKey: signal(this.entity()),
5678
+ textField: signal(this.textField()),
5679
+ valueField: signal(this.valueField()),
5680
+ allowMultiple: signal(this.multiple() ?? false),
5681
+ selectedValues: signal(selectedIds),
5682
+ searchPlaceholder: signal(this.searchPlaceholderText()),
5683
+ },
5684
+ });
5685
+ if (result?.data?.selected && Array.isArray(result.data.selected)) {
5686
+ this.setItems(result.data.selected);
5687
+ }
5688
+ }
5689
+ catch (error) {
5690
+ console.error('Error opening category tree selector:', error);
5691
+ }
5692
+ finally {
5693
+ this.isOpen.set(false);
5694
+ this.selectBox()?.focus();
5695
+ }
5696
+ }
5697
+ selectBoxValueChange(e) {
5698
+ const items = e.component.selectedItems;
5699
+ this.setItems(items);
5700
+ }
5701
+ handleValueChange(e) {
5702
+ if (e.isUserInteraction) {
5703
+ if (isNil(e.value) || (Array.isArray(e.value) && e.value.length === 0)) {
5704
+ this.clear();
5705
+ }
5706
+ else {
5707
+ this.setValue(this.singleOrMultiple(e.value));
5708
+ }
5709
+ }
5710
+ }
5711
+ handleSearchInputChange(e) {
5712
+ if (e.isUserInteraction) {
5713
+ this.searchTerm.set(e.value ?? '');
5714
+ }
5715
+ }
5716
+ handleKeyUp(e) {
5717
+ const keyEvent = e.nativeEvent;
5718
+ if (keyEvent.code == 'ArrowDown') {
5719
+ this.showTreeSelector();
5720
+ }
5721
+ }
5722
+ handleOnBlur(e) {
5723
+ setTimeout(() => {
5724
+ if (!this.isOpen()) {
5725
+ this.clearInput();
5726
+ }
5727
+ }, 100);
5728
+ }
5729
+ handleClearClick() {
5730
+ this.clear();
5731
+ }
5732
+ clear() {
5733
+ this.setValue(null);
5734
+ this.clearInput();
5735
+ this.selectedItems.set([]);
5736
+ }
5737
+ clearInput() {
5738
+ this.tagBox()?.inputValue.set('');
5739
+ this.searchTerm.set('');
5740
+ }
5741
+ //#endregion
5742
+ //#region ---- Private Methods ----
5743
+ async findByValue() {
5744
+ this.isLoading.set(true);
5745
+ const rawValue = this.getValue();
5746
+ const values = castArray(rawValue);
5747
+ const byKey = this.entityDef()?.queries.byKey?.execute;
5748
+ if (byKey && values.length) {
5749
+ if (this.multiple()) {
5750
+ const items = await Promise.all(values.map((value) => byKey(extractValue(value, this.valueField()))));
5751
+ this.setItems(items);
5752
+ }
5753
+ else {
5754
+ const id = extractValue(values[0], this.valueField());
5755
+ const item = await byKey(id);
5756
+ this.setItems(item);
5757
+ }
5758
+ }
5759
+ else {
5760
+ this.setItems([]);
5761
+ }
5762
+ this.isLoading.set(false);
5763
+ }
5764
+ setItems(items) {
5765
+ if (!items || items.length == 0) {
5766
+ this.selectedItems.set([]);
5767
+ this.setValue(null);
5768
+ this.cdr.markForCheck();
5769
+ return;
5770
+ }
5771
+ items = castArray(items);
5772
+ this.clearInput();
5773
+ this.selectedItems.set(items);
5774
+ const keys = items.map((item) => get(item, this.valueField()));
5775
+ const text = items.map((item) => get(item, this.displayField()));
5776
+ // Extract data from valueField and set context by expose path
5777
+ if (this.expose()) {
5778
+ const exposeValue = castArray(this.expose());
5779
+ const itemToExpose = {};
5780
+ exposeValue.forEach((i) => {
5781
+ if (typeof i == 'string') {
5782
+ const values = items.map((item) => set({}, i, get(item, i)));
5783
+ setSmart(itemToExpose, i, this.singleOrMultiple(values));
5784
+ }
5785
+ else {
5786
+ // Extract data from item by source path and set context by target path
5787
+ const values = this.multiple()
5788
+ ? items.map((item) => set({}, i.source, get(item, i.source)))
5789
+ : items.map((item) => get(item, i.source));
5790
+ setSmart(itemToExpose, i.target, this.singleOrMultiple(values));
5791
+ }
5792
+ });
5793
+ this.contextService.patch(itemToExpose);
5794
+ // Fire triggers
5795
+ this.setValue(this.singleOrMultiple(keys));
5796
+ }
5797
+ else {
5798
+ this.setValue(this.singleOrMultiple(keys));
5799
+ }
5800
+ // Trigger change detection to update selectbox/tagbox
5801
+ this.cdr.markForCheck();
5802
+ }
5803
+ singleOrMultiple(values) {
5804
+ return this.multiple() ? values : values[0];
5805
+ }
5806
+ getTagLabel(item) {
5807
+ if (!item) {
5808
+ return '';
5809
+ }
5810
+ return get(item, this.displayField()) ?? '';
5811
+ }
5812
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5813
+ 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: "selectBox", first: true, predicate: ["selectBox"], descendants: true, isSignal: true }, { propertyName: "tagBox", first: true, predicate: ["tagBoxComponent"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
5814
+ @if (dataSource()) {
5815
+ @if (look() == 'select') {
5816
+ <ax-select-box
5817
+ #selectBox
5818
+ [dataSource]="dataSource()!"
5819
+ [ngModel]="selectedItems()"
5820
+ [textField]="displayField()"
5821
+ [valueField]="valueField()"
5822
+ [disabled]="disabled()"
5823
+ [multiple]="multiple()"
5824
+ (onValueChanged)="selectBoxValueChange($event)"
5825
+ >
5826
+ <ax-search-box
5827
+ [placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
5828
+ (onValueChanged)="handleSearchInputChange($event)"
5829
+ >
5830
+ <ax-clear-button></ax-clear-button>
5831
+ </ax-search-box>
5832
+ @for (validation of validationRules(); track $index) {
5833
+ <ax-validation-rule
5834
+ [rule]="validation.rule"
5835
+ [message]="validation.options?.message"
5836
+ [options]="validation.options"
5837
+ ></ax-validation-rule>
5838
+ }
5839
+ @if (allowClear()) {
5840
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5841
+ }
5842
+ <ax-suffix>
5843
+ <ax-button
5844
+ color="ghost"
5845
+ look="blank"
5846
+ [disabled]="isLoading() || disabled()"
5847
+ (onClick)="handleOnClick($event)"
5848
+ >
5849
+ @if (isLoading()) {
5850
+ <ax-loading></ax-loading>
5851
+ } @else {
5852
+ <ax-icon icon="far fa-search"></ax-icon>
5853
+ }
5854
+ </ax-button>
5855
+ </ax-suffix>
5856
+ </ax-select-box>
5857
+ } @else {
5858
+ <ax-tag-box
5859
+ #tagBoxComponent
5860
+ [tagTemplate]="tagTemplate"
5861
+ [ngModel]="selectedItems()"
5862
+ [textField]="displayField()"
5863
+ [valueField]="valueField()"
5864
+ (onValueChanged)="handleValueChange($event)"
5865
+ [placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
5866
+ [addOnEnter]="false"
5867
+ [addOnComma]="false"
5868
+ [disabled]="disabled()"
5869
+ (onKeyUp)="handleKeyUp($event)"
5870
+ (onBlur)="handleOnBlur($event)"
5871
+ >
5872
+ @for (validation of validationRules(); track $index) {
5873
+ <ax-validation-rule
5874
+ [rule]="validation.rule"
5875
+ [message]="validation.options?.message"
5876
+ [options]="validation.options"
5877
+ ></ax-validation-rule>
5878
+ }
5879
+ @if (selectedItems().length > 1 || allowClear()) {
5880
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5881
+ }
5882
+
5883
+ <ax-suffix>
5884
+ <ax-button
5885
+ color="ghost"
5886
+ look="blank"
5887
+ [disabled]="isLoading() || disabled()"
5888
+ (onClick)="handleOnClick($event)"
5889
+ >
5890
+ @if (isLoading()) {
5891
+ <ax-loading></ax-loading>
5892
+ } @else {
5893
+ <ax-icon icon="far fa-search"></ax-icon>
5894
+ }
5895
+ </ax-button>
5896
+ </ax-suffix>
5897
+ </ax-tag-box>
5898
+ <ng-template #tagTemplate let-item let-index="index">
5899
+ <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">
5900
+ <span>{{ getTagLabel(item) }}</span>
5901
+ <button type="button" (click)="tagBoxComponent.removeItem(index)">
5902
+ <ax-icon class="ax-icon ax-icon-close"></ax-icon>
5903
+ </button>
5904
+ </div>
5905
+ </ng-template>
5906
+ }
5907
+ }
5908
+ `, 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$1.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 }); }
5909
+ }
5910
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetEditComponent, decorators: [{
5911
+ type: Component,
5912
+ args: [{
5913
+ selector: 'axp-entity-category-widget-edit',
5914
+ template: `
5915
+ @if (dataSource()) {
5916
+ @if (look() == 'select') {
5917
+ <ax-select-box
5918
+ #selectBox
5919
+ [dataSource]="dataSource()!"
5920
+ [ngModel]="selectedItems()"
5921
+ [textField]="displayField()"
5922
+ [valueField]="valueField()"
5923
+ [disabled]="disabled()"
5924
+ [multiple]="multiple()"
5925
+ (onValueChanged)="selectBoxValueChange($event)"
5926
+ >
5927
+ <ax-search-box
5928
+ [placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
5929
+ (onValueChanged)="handleSearchInputChange($event)"
5930
+ >
5931
+ <ax-clear-button></ax-clear-button>
5932
+ </ax-search-box>
5933
+ @for (validation of validationRules(); track $index) {
5934
+ <ax-validation-rule
5935
+ [rule]="validation.rule"
5936
+ [message]="validation.options?.message"
5937
+ [options]="validation.options"
5938
+ ></ax-validation-rule>
5939
+ }
5940
+ @if (allowClear()) {
5941
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5942
+ }
5943
+ <ax-suffix>
5944
+ <ax-button
5945
+ color="ghost"
5946
+ look="blank"
5947
+ [disabled]="isLoading() || disabled()"
5948
+ (onClick)="handleOnClick($event)"
5949
+ >
5950
+ @if (isLoading()) {
5951
+ <ax-loading></ax-loading>
5952
+ } @else {
5953
+ <ax-icon icon="far fa-search"></ax-icon>
5954
+ }
5955
+ </ax-button>
5956
+ </ax-suffix>
5957
+ </ax-select-box>
5958
+ } @else {
5959
+ <ax-tag-box
5960
+ #tagBoxComponent
5961
+ [tagTemplate]="tagTemplate"
5962
+ [ngModel]="selectedItems()"
5963
+ [textField]="displayField()"
5964
+ [valueField]="valueField()"
5965
+ (onValueChanged)="handleValueChange($event)"
5966
+ [placeholder]="selectedItems().length ? '' : searchPlaceholderText()"
5967
+ [addOnEnter]="false"
5968
+ [addOnComma]="false"
5969
+ [disabled]="disabled()"
5970
+ (onKeyUp)="handleKeyUp($event)"
5971
+ (onBlur)="handleOnBlur($event)"
5972
+ >
5973
+ @for (validation of validationRules(); track $index) {
5974
+ <ax-validation-rule
5975
+ [rule]="validation.rule"
5976
+ [message]="validation.options?.message"
5977
+ [options]="validation.options"
5978
+ ></ax-validation-rule>
5979
+ }
5980
+ @if (selectedItems().length > 1 || allowClear()) {
5981
+ <ax-clear-button (click)="handleClearClick()"></ax-clear-button>
5982
+ }
5983
+
5984
+ <ax-suffix>
5985
+ <ax-button
5986
+ color="ghost"
5987
+ look="blank"
5988
+ [disabled]="isLoading() || disabled()"
5989
+ (onClick)="handleOnClick($event)"
5990
+ >
5991
+ @if (isLoading()) {
5992
+ <ax-loading></ax-loading>
5993
+ } @else {
5994
+ <ax-icon icon="far fa-search"></ax-icon>
5995
+ }
5996
+ </ax-button>
5997
+ </ax-suffix>
5998
+ </ax-tag-box>
5999
+ <ng-template #tagTemplate let-item let-index="index">
6000
+ <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">
6001
+ <span>{{ getTagLabel(item) }}</span>
6002
+ <button type="button" (click)="tagBoxComponent.removeItem(index)">
6003
+ <ax-icon class="ax-icon ax-icon-close"></ax-icon>
6004
+ </button>
6005
+ </div>
6006
+ </ng-template>
6007
+ }
6008
+ }
6009
+ `,
6010
+ changeDetection: ChangeDetectionStrategy.OnPush,
6011
+ imports: [
6012
+ CommonModule,
6013
+ FormsModule,
6014
+ AXButtonModule,
6015
+ AXDecoratorModule,
6016
+ AXLoadingModule,
6017
+ AXValidationModule,
6018
+ AXFormModule,
6019
+ AXTagBoxModule,
6020
+ AXTranslationModule,
6021
+ AXSelectBoxModule,
6022
+ AXSearchBoxComponent,
6023
+ ],
6024
+ }]
6025
+ }], propDecorators: { selectBox: [{ type: i0.ViewChild, args: ['selectBox', { isSignal: true }] }], tagBox: [{ type: i0.ViewChild, args: ['tagBoxComponent', { isSignal: true }] }] } });
6026
+
6027
+ var entityCategoryWidgetEdit_component = /*#__PURE__*/Object.freeze({
6028
+ __proto__: null,
6029
+ AXPEntityCategoryWidgetEditComponent: AXPEntityCategoryWidgetEditComponent
6030
+ });
6031
+
6032
+ class AXPEntityCategoryWidgetViewComponent extends AXPValueWidgetComponent {
6033
+ constructor() {
6034
+ super(...arguments);
6035
+ //#region ---- Services & Dependencies ----
6036
+ this.formatService = inject(AXFormatService);
6037
+ this.entityResolver = inject(AXPEntityResolver);
6038
+ //#endregion
6039
+ //#region ---- Computed Properties ----
6040
+ this.entity = computed(() => this.options()['entity'] ?? '', ...(ngDevMode ? [{ debugName: "entity" }] : []));
6041
+ this.multiple = computed(() => (this.options()['multiple'] ?? false), ...(ngDevMode ? [{ debugName: "multiple" }] : []));
6042
+ this.valueField = computed(() => this.options()['valueField'] ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
6043
+ this.textField = computed(() => this.options()['textField'] ?? 'title', ...(ngDevMode ? [{ debugName: "textField" }] : []));
6044
+ this.badgeClass = computed(() => this.options()['badgeClass'] ?? 'ax-accent1', ...(ngDevMode ? [{ debugName: "badgeClass" }] : []));
6045
+ this.displayField = computed(() => {
6046
+ return (this.textField() ??
6047
+ this.entityDef()?.formats.lookup ??
6048
+ this.entityDef()?.properties.find((c) => c.name != 'id')?.name ??
6049
+ 'title');
6050
+ }, ...(ngDevMode ? [{ debugName: "displayField" }] : []));
6051
+ //#endregion
6052
+ //#region ---- Component State ----
6053
+ this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
6054
+ this.entityDef = signal(null, ...(ngDevMode ? [{ debugName: "entityDef" }] : []));
6055
+ this.displayItems = signal([], ...(ngDevMode ? [{ debugName: "displayItems" }] : []));
6056
+ //#endregion
6057
+ //#region ---- Effects ----
6058
+ this.efEntity = effect(async () => {
6059
+ const entityKey = this.entity();
6060
+ if (!entityKey) {
6061
+ return;
6062
+ }
6063
+ const [module, entity] = entityKey.split('.');
6064
+ if (!module || !entity) {
6065
+ return;
6066
+ }
6067
+ this.entityDef.set(await this.entityResolver.get(module, entity));
6068
+ }, ...(ngDevMode ? [{ debugName: "efEntity" }] : []));
6069
+ this.efDisplay = effect(async () => {
6070
+ const value = this.getValue();
6071
+ if (isNil(value)) {
6072
+ this.displayItems.set([]);
6073
+ }
6074
+ else {
6075
+ const items = castArray(value).map(async (item) => await this.extractItem(item));
6076
+ this.displayItems.set(await Promise.all(items));
6077
+ }
6078
+ }, ...(ngDevMode ? [{ debugName: "efDisplay" }] : []));
6079
+ }
6080
+ //#endregion
6081
+ //#region ---- Private Methods ----
6082
+ async extractItem(item) {
6083
+ if (typeof item == 'object') {
6084
+ return {
6085
+ id: item[this.valueField()],
6086
+ text: this.getDisplayText(item),
6087
+ };
6088
+ }
6089
+ const def = this.entityDef();
6090
+ const byKey = def?.queries.byKey?.execute;
6091
+ if (byKey) {
6092
+ this.loading.set(true);
6093
+ try {
6094
+ const fetchedItem = await byKey(item);
6095
+ return {
6096
+ id: fetchedItem[this.valueField()],
6097
+ text: this.getDisplayText(fetchedItem),
6098
+ };
6099
+ }
6100
+ finally {
6101
+ this.loading.set(false);
6102
+ }
6103
+ }
6104
+ return {
6105
+ id: item,
6106
+ text: String(item),
6107
+ };
6108
+ }
6109
+ getDisplayText(item) {
6110
+ return this.formatService.format(this.displayField(), 'string', item);
6111
+ }
6112
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
6113
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPEntityCategoryWidgetViewComponent, isStandalone: true, selector: "axp-entity-category-widget-view", usesInheritance: true, ngImport: i0, template: `
6114
+ @if (loading()) {
6115
+ <ax-loading></ax-loading>
6116
+ } @else {
6117
+ @if (displayItems().length > 1) {
6118
+ @for (item of displayItems(); track $index) {
6119
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="item.text"></ax-badge>
6120
+ }
6121
+ } @else if (displayItems().length == 1) {
6122
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="displayItems()[0].text"></ax-badge>
6123
+ } @else {
6124
+ <span class="ax-text-muted">---</span>
6125
+ }
6126
+ }
6127
+ `, 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$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6128
+ }
6129
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityCategoryWidgetViewComponent, decorators: [{
6130
+ type: Component,
6131
+ args: [{
6132
+ selector: 'axp-entity-category-widget-view',
6133
+ template: `
6134
+ @if (loading()) {
6135
+ <ax-loading></ax-loading>
6136
+ } @else {
6137
+ @if (displayItems().length > 1) {
6138
+ @for (item of displayItems(); track $index) {
6139
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="item.text"></ax-badge>
6140
+ }
6141
+ } @else if (displayItems().length == 1) {
6142
+ <ax-badge class="ax-p-0.5 {{ badgeClass() }}" [text]="displayItems()[0].text"></ax-badge>
6143
+ } @else {
6144
+ <span class="ax-text-muted">---</span>
6145
+ }
6146
+ }
6147
+ `,
6148
+ changeDetection: ChangeDetectionStrategy.OnPush,
6149
+ imports: [AXLoadingModule, AXBadgeModule],
6150
+ }]
6151
+ }] });
6152
+
6153
+ var entityCategoryWidgetView_component = /*#__PURE__*/Object.freeze({
6154
+ __proto__: null,
6155
+ AXPEntityCategoryWidgetViewComponent: AXPEntityCategoryWidgetViewComponent
6156
+ });
6157
+
6158
+ const AXPEntityCategoryWidget = {
6159
+ name: 'entity-category-editor',
6160
+ title: 'Entity Category',
6161
+ categories: [],
6162
+ groups: [AXPWidgetGroupEnum.EntityWidget],
6163
+ defaultFilterWidgetName: 'lookup-filter',
6164
+ type: 'editor',
6165
+ icon: 'fa-light fa-sitemap',
6166
+ properties: [
6167
+ AXP_DISABLED_PROPERTY,
6168
+ AXP_ALLOW_CLEAR_PROPERTY,
6169
+ AXP_DATA_PATH_PROPERTY,
6170
+ {
6171
+ name: 'entity',
6172
+ title: 'Entity',
6173
+ group: AXP_DATA_PROPERTY_GROUP,
6174
+ schema: {
6175
+ dataType: 'string',
6176
+ interface: {
6177
+ name: 'entity',
6178
+ path: 'options.entity',
6179
+ type: AXPWidgetsCatalog.text,
6180
+ },
6181
+ },
6182
+ visible: true,
6183
+ },
6184
+ AXP_ALLOW_MULTIPLE_PROPERTY,
6185
+ {
6186
+ name: 'textField',
6187
+ title: 'Text Field',
6188
+ group: AXP_DATA_PROPERTY_GROUP,
6189
+ schema: {
6190
+ dataType: 'string',
6191
+ interface: {
6192
+ name: 'textField',
6193
+ path: 'options.textField',
6194
+ type: AXPWidgetsCatalog.text,
6195
+ },
6196
+ },
6197
+ visible: true,
6198
+ },
6199
+ {
6200
+ name: 'valueField',
6201
+ title: 'Value Field',
6202
+ group: AXP_DATA_PROPERTY_GROUP,
6203
+ schema: {
6204
+ dataType: 'string',
6205
+ interface: {
6206
+ name: 'valueField',
6207
+ path: 'options.valueField',
6208
+ type: AXPWidgetsCatalog.text,
6209
+ },
6210
+ },
6211
+ visible: true,
6212
+ },
6213
+ {
6214
+ name: 'parentKey',
6215
+ title: 'Parent Key',
6216
+ group: AXP_DATA_PROPERTY_GROUP,
6217
+ schema: {
6218
+ dataType: 'string',
6219
+ interface: {
6220
+ name: 'parentKey',
6221
+ path: 'options.parentKey',
6222
+ type: AXPWidgetsCatalog.text,
6223
+ },
6224
+ },
6225
+ visible: true,
6226
+ },
6227
+ {
6228
+ name: 'expose',
6229
+ title: 'Expose',
6230
+ group: AXP_DATA_PROPERTY_GROUP,
6231
+ schema: {
6232
+ dataType: 'string',
6233
+ interface: {
6234
+ name: 'expose',
6235
+ path: 'options.expose',
6236
+ type: AXPWidgetsCatalog.select,
6237
+ },
6238
+ },
6239
+ visible: true,
6240
+ },
6241
+ ],
6242
+ components: {
6243
+ view: {
6244
+ component: () => Promise.resolve().then(function () { return entityCategoryWidgetView_component; }).then((c) => c.AXPEntityCategoryWidgetViewComponent),
6245
+ },
6246
+ edit: {
6247
+ component: () => Promise.resolve().then(function () { return entityCategoryWidgetEdit_component; }).then((c) => c.AXPEntityCategoryWidgetEditComponent),
6248
+ },
6249
+ column: {
6250
+ component: () => Promise.resolve().then(function () { return entityCategoryWidgetColumn_component; }).then((c) => c.AXPEntityCategoryWidgetColumnComponent),
6251
+ },
6252
+ designer: {
6253
+ component: () => Promise.resolve().then(function () { return entityCategoryWidgetEdit_component; }).then((c) => c.AXPEntityCategoryWidgetEditComponent),
6254
+ },
6255
+ },
6256
+ };
6257
+
4791
6258
  //#region ---- Column Mapping Helpers ----
4792
6259
  /**
4793
6260
  * Maps an entity property to a list widget column configuration.
@@ -5553,7 +7020,7 @@ class AXPEntityListWidgetViewComponent extends AXPValueWidgetComponent {
5553
7020
  ></ng-container>
5554
7021
  }
5555
7022
  </div>
5556
- `, 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$2.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 }); }
7023
+ `, 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 }); }
5557
7024
  }
5558
7025
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPEntityListWidgetViewComponent, decorators: [{
5559
7026
  type: Component,
@@ -7815,6 +9282,7 @@ class AXPEntityModule {
7815
9282
  AXPWidgetSelectorWidget,
7816
9283
  AXPEntityListWidget,
7817
9284
  AXPEntityReferenceWidget,
9285
+ AXPEntityCategoryWidget,
7818
9286
  ],
7819
9287
  })] }); }
7820
9288
  }
@@ -7857,6 +9325,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
7857
9325
  AXPWidgetSelectorWidget,
7858
9326
  AXPEntityListWidget,
7859
9327
  AXPEntityReferenceWidget,
9328
+ AXPEntityCategoryWidget,
7860
9329
  ],
7861
9330
  }),
7862
9331
  ],
@@ -8465,5 +9934,5 @@ function detectEntityChanges(oldObj, newObj) {
8465
9934
  * Generated bundle index. Do not edit.
8466
9935
  */
8467
9936
 
8468
- export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityDynamicDialogService, AXPEntityEventDispatcherService, AXPEntityListTableService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityReferenceWidget, AXPEntityReferenceWidgetColumnComponent, AXPEntityReferenceWidgetDesignerComponent, AXPEntityReferenceWidgetEditComponent, AXPEntityReferenceWidgetPrintComponent, AXPEntityReferenceWidgetViewComponent, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPGetEntityDetailsQuery, AXPLookupFilterWidget, AXPLookupFilterWidgetEditComponent, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPWidgetSelectorWidget, AXPWidgetSelectorWidgetEditComponent, AXPWidgetSelectorWidgetViewComponent, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, DEFAULT_COLUMN_WIDTHS, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, actionExists, columnWidthMiddlewareFactory, columnWidthMiddlewareProvider, createColumnWidthMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, isAXPMiddlewareAbortError, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider };
9937
+ export { AXMEntityCrudService, AXMEntityCrudServiceImpl, AXPCategoryTreeService, AXPCreateEntityWorkflow, AXPDataSeederService, AXPDeleteEntityWorkflow, AXPEntityApplyUpdatesAction, AXPEntityCategoryTreeSelectorComponent, AXPEntityCategoryWidget, AXPEntityCategoryWidgetColumnComponent, AXPEntityCategoryWidgetEditComponent, AXPEntityCategoryWidgetViewComponent, AXPEntityCommandTriggerViewModel, AXPEntityCreateEvent, AXPEntityCreatePopupAction, AXPEntityCreateSubmittedAction, AXPEntityCreateViewElementViewModel, AXPEntityCreateViewModelFactory, AXPEntityCreateViewSectionViewModel, AXPEntityDataProvider, AXPEntityDataProviderImpl, AXPEntityDataSelectorService, AXPEntityDefinitionRegistryService, AXPEntityDeletedEvent, AXPEntityDetailListViewModel, AXPEntityDetailPopoverComponent, AXPEntityDetailPopoverService, AXPEntityDetailViewModelFactory, AXPEntityDetailViewModelResolver, AXPEntityDynamicDialogService, AXPEntityEventDispatcherService, AXPEntityListTableService, AXPEntityListViewColumnViewModel, AXPEntityListViewModelFactory, AXPEntityListViewModelResolver, AXPEntityListWidget, AXPEntityListWidgetViewComponent, AXPEntityMasterCreateViewModel, AXPEntityMasterListViewModel, AXPEntityMasterListViewQueryViewModel, AXPEntityMasterSingleElementViewModel, AXPEntityMasterSingleViewGroupViewModel, AXPEntityMasterSingleViewModel, AXPEntityMasterUpdateElementViewModel, AXPEntityMasterUpdateViewModel, AXPEntityMasterUpdateViewModelFactory, AXPEntityMiddleware, AXPEntityModifyConfirmedAction, AXPEntityModifyEvent, AXPEntityModifySectionPopupAction, AXPEntityModule, AXPEntityPerformDeleteAction, AXPEntityReferenceWidget, AXPEntityReferenceWidgetColumnComponent, AXPEntityReferenceWidgetDesignerComponent, AXPEntityReferenceWidgetEditComponent, AXPEntityReferenceWidgetPrintComponent, AXPEntityReferenceWidgetViewComponent, AXPEntityResolver, AXPEntityService, AXPEntityStorageService, AXPEntityUpdateViewSectionViewModel, AXPGetEntityDetailsQuery, AXPLookupFilterWidget, AXPLookupFilterWidgetEditComponent, AXPLookupWidget, AXPLookupWidgetColumnComponent, AXPLookupWidgetEditComponent, AXPLookupWidgetViewComponent, AXPMiddlewareAbortError, AXPMiddlewareEntityStorageService, AXPModifyEntitySectionWorkflow, AXPOpenEntityDetailsCommand, AXPQuickEntityModifyPopupAction, AXPQuickModifyEntityWorkflow, AXPShowDetailViewAction, AXPShowDetailsViewWorkflow, AXPShowListViewAction, AXPShowListViewWorkflow, AXPWidgetSelectorWidget, AXPWidgetSelectorWidgetEditComponent, AXPWidgetSelectorWidgetViewComponent, AXP_DATA_SEEDER_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_MODIFIER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, DEFAULT_COLUMN_WIDTHS, DEFAULT_PROPERTY_ORDER, DEFAULT_SECTION_ORDER, actionExists, columnWidthMiddlewareFactory, columnWidthMiddlewareProvider, createColumnWidthMiddlewareProvider, createLayoutOrderingMiddlewareProvider, createModifierContext, detectEntityChanges, ensureListActions, entityDetailsCreateActions, entityDetailsCrudActions, entityDetailsEditAction, entityDetailsReferenceCondition, entityDetailsReferenceCreateActions, entityDetailsSimpleCondition, entityMasterBulkDeleteAction, entityMasterCreateAction, entityMasterCrudActions, entityMasterDeleteAction, entityMasterRecordActions, entityMasterViewAction, entityOverrideDetailsViewAction, eventDispatchMiddleware, isAXPMiddlewareAbortError, layoutOrderingMiddlewareFactory, layoutOrderingMiddlewareProvider };
8469
9938
  //# sourceMappingURL=acorex-platform-layout-entity.mjs.map