@acorex/platform 20.8.5 → 21.0.0-beta.0

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.
Files changed (125) hide show
  1. package/fesm2022/acorex-platform-auth.mjs +121 -27
  2. package/fesm2022/acorex-platform-auth.mjs.map +1 -1
  3. package/fesm2022/{acorex-platform-common-common-settings.provider-41RhWqb4.mjs → acorex-platform-common-common-settings.provider-G9XcXXOG.mjs} +4 -4
  4. package/fesm2022/acorex-platform-common-common-settings.provider-G9XcXXOG.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-common.mjs +669 -268
  6. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-core.mjs +333 -140
  8. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-domain.mjs +557 -826
  10. package/fesm2022/acorex-platform-domain.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-layout-builder.mjs +539 -110
  12. package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
  13. package/fesm2022/{acorex-platform-layout-components-binding-expression-editor-popup.component-CSxCnzwU.mjs → acorex-platform-layout-components-binding-expression-editor-popup.component-CWV4XD36.mjs} +15 -15
  14. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CWV4XD36.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-layout-components.mjs +3285 -1035
  16. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  17. package/fesm2022/acorex-platform-layout-designer.mjs +488 -284
  18. package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
  19. package/fesm2022/acorex-platform-layout-entity.mjs +15955 -11978
  20. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  21. package/fesm2022/acorex-platform-layout-views.mjs +410 -170
  22. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  23. package/fesm2022/acorex-platform-layout-widget-core.mjs +548 -474
  24. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  25. package/fesm2022/{acorex-platform-layout-widgets-button-widget-designer.component-CPBzE96V.mjs → acorex-platform-layout-widgets-button-widget-designer.component-fLjWiSFE.mjs} +11 -11
  26. package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-fLjWiSFE.mjs.map +1 -0
  27. package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-Dtv6U3df.mjs → acorex-platform-layout-widgets-file-list-popup.component-3oRAKxTo.mjs} +22 -77
  28. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-3oRAKxTo.mjs.map +1 -0
  29. package/fesm2022/{acorex-platform-layout-widgets-image-preview.popup-QxJfswhK.mjs → acorex-platform-layout-widgets-image-preview.popup-CazpERbX.mjs} +8 -9
  30. package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-CazpERbX.mjs.map +1 -0
  31. package/fesm2022/{acorex-platform-layout-widgets-page-widget-designer.component-CVdssZBD.mjs → acorex-platform-layout-widgets-page-widget-designer.component-BQ4G6aYf.mjs} +17 -17
  32. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-BQ4G6aYf.mjs.map +1 -0
  33. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-DWuWxUF_.mjs +116 -0
  34. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-DWuWxUF_.mjs.map +1 -0
  35. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DVaZN9QN.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-fV94u3t2.mjs} +25 -19
  36. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-fV94u3t2.mjs.map +1 -0
  37. package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DPGHgXa6.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-DyuvQhgN.mjs} +9 -9
  38. package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-DyuvQhgN.mjs.map +1 -0
  39. package/fesm2022/{acorex-platform-layout-widgets-text-block-widget-designer.component-CdiNW691.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-EJMMdpIs.mjs} +7 -7
  40. package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-EJMMdpIs.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-layout-widgets.mjs +6396 -4058
  42. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  43. package/fesm2022/acorex-platform-native.mjs +8 -7
  44. package/fesm2022/acorex-platform-native.mjs.map +1 -1
  45. package/fesm2022/acorex-platform-runtime.mjs +328 -166
  46. package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
  47. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CkptOSO3.mjs +160 -0
  48. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-CkptOSO3.mjs.map +1 -0
  49. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DXC2qtvK.mjs +120 -0
  50. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DXC2qtvK.mjs.map +1 -0
  51. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-rGsMVAZj.mjs → acorex-platform-themes-default-entity-master-single-view.component-DYyunzKZ.mjs} +16 -23
  52. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DYyunzKZ.mjs.map +1 -0
  53. package/fesm2022/acorex-platform-themes-default-error-401.component-C5lQECDP.mjs +31 -0
  54. package/fesm2022/acorex-platform-themes-default-error-401.component-C5lQECDP.mjs.map +1 -0
  55. package/fesm2022/acorex-platform-themes-default-error-404.component-D5wBXAB-.mjs +25 -0
  56. package/fesm2022/acorex-platform-themes-default-error-404.component-D5wBXAB-.mjs.map +1 -0
  57. package/fesm2022/acorex-platform-themes-default-error-offline.component-AhDiY3DI.mjs +19 -0
  58. package/fesm2022/acorex-platform-themes-default-error-offline.component-AhDiY3DI.mjs.map +1 -0
  59. package/fesm2022/acorex-platform-themes-default.mjs +1687 -69
  60. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  61. package/fesm2022/{acorex-platform-themes-shared-icon-chooser-column.component-TJ9PWHMY.mjs → acorex-platform-themes-shared-icon-chooser-column.component-QL2-ZUVg.mjs} +8 -8
  62. package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-QL2-ZUVg.mjs.map +1 -0
  63. package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-BHcKkIx0.mjs → acorex-platform-themes-shared-icon-chooser-view.component-BXydqPt_.mjs} +8 -8
  64. package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BXydqPt_.mjs.map +1 -0
  65. package/fesm2022/{acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs → acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs} +2 -2
  66. package/fesm2022/acorex-platform-themes-shared-settings.provider-D13QB3Hr.mjs.map +1 -0
  67. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-Cb9iY6k9.mjs +88 -0
  68. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-Cb9iY6k9.mjs.map +1 -0
  69. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-KP4-BND5.mjs +80 -0
  70. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-KP4-BND5.mjs.map +1 -0
  71. package/fesm2022/acorex-platform-themes-shared.mjs +572 -465
  72. package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
  73. package/fesm2022/acorex-platform-workflow.mjs +276 -98
  74. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  75. package/fesm2022/acorex-platform.mjs.map +1 -1
  76. package/package.json +33 -33
  77. package/{auth/index.d.ts → types/acorex-platform-auth.d.ts} +14 -2
  78. package/{common/index.d.ts → types/acorex-platform-common.d.ts} +261 -24
  79. package/{core/index.d.ts → types/acorex-platform-core.d.ts} +163 -42
  80. package/{domain/index.d.ts → types/acorex-platform-domain.d.ts} +744 -412
  81. package/{layout/builder/index.d.ts → types/acorex-platform-layout-builder.d.ts} +137 -38
  82. package/{layout/components/index.d.ts → types/acorex-platform-layout-components.d.ts} +808 -131
  83. package/{layout/designer/index.d.ts → types/acorex-platform-layout-designer.d.ts} +96 -18
  84. package/{layout/entity/index.d.ts → types/acorex-platform-layout-entity.d.ts} +686 -61
  85. package/{layout/views/index.d.ts → types/acorex-platform-layout-views.d.ts} +80 -47
  86. package/{layout/widget-core/index.d.ts → types/acorex-platform-layout-widget-core.d.ts} +274 -197
  87. package/{layout/widgets/index.d.ts → types/acorex-platform-layout-widgets.d.ts} +583 -104
  88. package/{native/index.d.ts → types/acorex-platform-native.d.ts} +0 -7
  89. package/types/acorex-platform-runtime.d.ts +565 -0
  90. package/{themes/default/index.d.ts → types/acorex-platform-themes-default.d.ts} +105 -4
  91. package/{themes/shared/index.d.ts → types/acorex-platform-themes-shared.d.ts} +14 -5
  92. package/{workflow/index.d.ts → types/acorex-platform-workflow.d.ts} +96 -81
  93. package/fesm2022/acorex-platform-common-common-settings.provider-41RhWqb4.mjs.map +0 -1
  94. package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CSxCnzwU.mjs.map +0 -1
  95. package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-CPBzE96V.mjs.map +0 -1
  96. package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-Dtv6U3df.mjs.map +0 -1
  97. package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-QxJfswhK.mjs.map +0 -1
  98. package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-CVdssZBD.mjs.map +0 -1
  99. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BCxE0RTB.mjs +0 -111
  100. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BCxE0RTB.mjs.map +0 -1
  101. package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DVaZN9QN.mjs.map +0 -1
  102. package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-DPGHgXa6.mjs.map +0 -1
  103. package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-CdiNW691.mjs.map +0 -1
  104. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-D4hU2SCE.mjs +0 -160
  105. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-D4hU2SCE.mjs.map +0 -1
  106. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CLDoygoI.mjs +0 -1610
  107. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CLDoygoI.mjs.map +0 -1
  108. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BVTklnzs.mjs +0 -120
  109. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BVTklnzs.mjs.map +0 -1
  110. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-rGsMVAZj.mjs.map +0 -1
  111. package/fesm2022/acorex-platform-themes-default-error-401.component-53VB-PS_.mjs +0 -31
  112. package/fesm2022/acorex-platform-themes-default-error-401.component-53VB-PS_.mjs.map +0 -1
  113. package/fesm2022/acorex-platform-themes-default-error-404.component-DVF9soT5.mjs +0 -25
  114. package/fesm2022/acorex-platform-themes-default-error-404.component-DVF9soT5.mjs.map +0 -1
  115. package/fesm2022/acorex-platform-themes-default-error-offline.component-CwNNHzZn.mjs +0 -19
  116. package/fesm2022/acorex-platform-themes-default-error-offline.component-CwNNHzZn.mjs.map +0 -1
  117. package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-TJ9PWHMY.mjs.map +0 -1
  118. package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BHcKkIx0.mjs.map +0 -1
  119. package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +0 -1
  120. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-BUPs84MI.mjs +0 -65
  121. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-BUPs84MI.mjs.map +0 -1
  122. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BotknoHn.mjs +0 -64
  123. package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BotknoHn.mjs.map +0 -1
  124. package/runtime/index.d.ts +0 -307
  125. /package/{index.d.ts → types/acorex-platform.d.ts} +0 -0
@@ -1,1610 +0,0 @@
1
- import { AXActionSheetModule } from '@acorex/components/action-sheet';
2
- import * as i7 from '@acorex/components/data-table';
3
- import { AXDataTableModule } from '@acorex/components/data-table';
4
- import { AXDrawerModule } from '@acorex/components/drawer';
5
- import * as i1$1 from '@acorex/core/platform';
6
- import * as i0 from '@angular/core';
7
- import { inject, input, viewChild, signal, computed, afterNextRender, ViewEncapsulation, Component, effect, Input, ChangeDetectionStrategy } from '@angular/core';
8
- import { Router, ActivatedRoute, RouterModule } from '@angular/router';
9
- import { AXBadgeModule } from '@acorex/components/badge';
10
- import { AXBreadcrumbsModule } from '@acorex/components/breadcrumbs';
11
- import * as i3 from '@acorex/components/button';
12
- import { AXButtonModule } from '@acorex/components/button';
13
- import * as i2 from '@acorex/components/decorators';
14
- import { AXDecoratorModule } from '@acorex/components/decorators';
15
- import { AXDialogModule } from '@acorex/components/dialog';
16
- import * as i5 from '@acorex/components/dropdown';
17
- import { AXDropdownModule } from '@acorex/components/dropdown';
18
- import { AXFormModule } from '@acorex/components/form';
19
- import { AXLoadingModule } from '@acorex/components/loading';
20
- import * as i3$1 from '@acorex/components/popover';
21
- import { AXPopoverModule } from '@acorex/components/popover';
22
- import * as i6 from '@acorex/components/search-box';
23
- import { AXSearchBoxModule } from '@acorex/components/search-box';
24
- import { AXTabsModule } from '@acorex/components/tabs';
25
- import { AXTooltipModule } from '@acorex/components/tooltip';
26
- import * as i10 from '@acorex/core/translation';
27
- import { AXTranslationService, AXTranslationModule, translateSync } from '@acorex/core/translation';
28
- import { AXPAuthModule } from '@acorex/platform/auth';
29
- import { AXPThemeLayoutBlockComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutToolbarComponent, AXPStateMessageComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewsComponent, AXPQueryColumnsComponent, AXPThemeLayoutStartSideComponent } from '@acorex/platform/layout/components';
30
- import * as i7$1 from '@acorex/platform/layout/widget-core';
31
- import { AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
32
- import { AXPWidgetsModule } from '@acorex/platform/layout/widgets';
33
- import { DragDropModule } from '@angular/cdk/drag-drop';
34
- import * as i1 from '@angular/common';
35
- import { CommonModule } from '@angular/common';
36
- import { FormsModule } from '@angular/forms';
37
- import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
38
- import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
39
- import { AXPLayoutThemeService } from '@acorex/platform/themes/shared';
40
- import * as i2$1 from '@acorex/components/skeleton';
41
- import { AXSkeletonModule } from '@acorex/components/skeleton';
42
- import { AXTreeViewModule, AXTreeViewComponent } from '@acorex/components/tree-view';
43
- import { AXPRefreshEvent, AXPSettingsService, AXPCommonSettings } from '@acorex/platform/common';
44
- import { AXHighlightService, AXPDeviceService } from '@acorex/platform/core';
45
- import { AXPCategoryTreeService, AXPEntityListViewColumnViewModel } from '@acorex/platform/layout/entity';
46
- import { AXPWorkflowService, ofType } from '@acorex/platform/workflow';
47
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
48
- import { isEqual } from 'lodash-es';
49
-
50
- //#region ---- Constants ----
51
- const ROOT_NODE_ID = 'all';
52
- const LOADING_DELAY_MS = 300;
53
- const DEFAULT_TEXT_FIELD = 'title';
54
- const DEFAULT_VALUE_FIELD = 'id';
55
- //#endregion
56
- class AXPEntityCategoryComponent {
57
- //#endregion
58
- //#region ---- Constructor & Lifecycle ----
59
- constructor() {
60
- //#region ---- Services & Dependencies ----
61
- this.translate = inject(AXTranslationService);
62
- this.workflow = inject(AXPWorkflowService);
63
- this.categoryTreeService = inject(AXPCategoryTreeService);
64
- this.highlightService = inject(AXHighlightService);
65
- //#endregion
66
- //#region ---- Component Inputs & View Queries ----
67
- this.vm = input.required(...(ngDevMode ? [{ debugName: "vm" }] : []));
68
- this.tree = viewChild('tree', ...(ngDevMode ? [{ debugName: "tree" }] : []));
69
- this.searchValue = input('', ...(ngDevMode ? [{ debugName: "searchValue" }] : []));
70
- // Tree view inputs with defaults
71
- this.selectMode = input('single', ...(ngDevMode ? [{ debugName: "selectMode" }] : []));
72
- this.selectionBehavior = input('intermediate', ...(ngDevMode ? [{ debugName: "selectionBehavior" }] : []));
73
- this.dragArea = input('handler', ...(ngDevMode ? [{ debugName: "dragArea" }] : []));
74
- this.dragBehavior = input('none', ...(ngDevMode ? [{ debugName: "dragBehavior" }] : []));
75
- this.showIcons = input(true, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
76
- this.showChildrenBadge = input(false, ...(ngDevMode ? [{ debugName: "showChildrenBadge" }] : []));
77
- this.expandedIcon = input('fa-solid fa-chevron-down', ...(ngDevMode ? [{ debugName: "expandedIcon" }] : []));
78
- this.collapsedIcon = input('fa-solid fa-chevron-right', ...(ngDevMode ? [{ debugName: "collapsedIcon" }] : []));
79
- this.indentSize = input(16, ...(ngDevMode ? [{ debugName: "indentSize" }] : []));
80
- this.look = input('default', ...(ngDevMode ? [{ debugName: "look" }] : []));
81
- this.searchWithChildren = input(true, ...(ngDevMode ? [{ debugName: "searchWithChildren" }] : [])); // Include children of search results
82
- //#endregion
83
- //#region ---- Component State ----
84
- this.isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
85
- this.isSearching = signal(false, ...(ngDevMode ? [{ debugName: "isSearching" }] : []));
86
- this.searchResultCount = signal(0, ...(ngDevMode ? [{ debugName: "searchResultCount" }] : []));
87
- this.currentSearchValue = signal('', ...(ngDevMode ? [{ debugName: "currentSearchValue" }] : []));
88
- this.resultsFoundText = signal('', ...(ngDevMode ? [{ debugName: "resultsFoundText" }] : []));
89
- //#endregion
90
- //#region ---- Private Properties ----
91
- this.loadingTimeoutId = null;
92
- this.treeData = null;
93
- this.treeConfig = null;
94
- this.matchingNodeIds = new Set();
95
- this.relevantNodeIds = new Set(); // For search filtering
96
- this.nodeDataCache = new Map(); // Cache parent data from search results
97
- this.expandedNodesBeforeSearch = [];
98
- this.nodesExpandedDuringSearch = [];
99
- this.currentSearchTerm = null;
100
- //#endregion
101
- //#region ---- Computed Properties ----
102
- this.textField = computed(() => this.vm().entityDef.category?.textField || DEFAULT_TEXT_FIELD, ...(ngDevMode ? [{ debugName: "textField" }] : []));
103
- this.valueField = computed(() => this.vm().entityDef.category?.valueField || DEFAULT_VALUE_FIELD, ...(ngDevMode ? [{ debugName: "valueField" }] : []));
104
- /** When true, add/edit/delete category actions are hidden (from category plugin readonly option). */
105
- this.categoryReadonly = computed(() => this.vm().entityDef?.extensions?.category?.readonly === true, ...(ngDevMode ? [{ debugName: "categoryReadonly" }] : []));
106
- /**
107
- * Computed property to check if we should show the "no search results" empty state.
108
- * Returns true when search is active, not searching, and no results found.
109
- */
110
- this.showNoSearchResults = computed(() => {
111
- const searchValue = this.currentSearchValue().trim();
112
- const isSearching = this.isSearching();
113
- const resultCount = this.searchResultCount();
114
- return searchValue.length > 0 && !isSearching && resultCount === 0;
115
- }, ...(ngDevMode ? [{ debugName: "showNoSearchResults" }] : []));
116
- this.categoryEntityKey = computed(() => {
117
- const key = this.vm().entityDef.category?.entity;
118
- if (!key) {
119
- throw new Error('Category entity is not configured');
120
- }
121
- return key;
122
- }, ...(ngDevMode ? [{ debugName: "categoryEntityKey" }] : []));
123
- // protected toggleExpand(e: AXTreeViewNodeDoubleClickEvent) {
124
- // (e.component as AXTreeViewComponent).toggleNodeExpansion(String(e.node[this.valueField()] ?? ''));
125
- // }
126
- //#endregion
127
- //#region ---- Tree Data Source ----
128
- /**
129
- * Datasource callback for tree-view component.
130
- * Provides lazy loading support for tree nodes.
131
- */
132
- this.datasource = async (parentId) => {
133
- if (!this.isTreeInitialized()) {
134
- return [];
135
- }
136
- // Load root nodes if no parent ID provided
137
- if (!parentId) {
138
- return await this.loadRootNodes();
139
- }
140
- // Load children for the specified parent
141
- return await this.loadChildNodes(parentId);
142
- };
143
- afterNextRender(() => {
144
- this.initializeTree();
145
- });
146
- this.workflow.events$
147
- .pipe(ofType(AXPRefreshEvent))
148
- .pipe(takeUntilDestroyed())
149
- .subscribe((event) => {
150
- this.tree()?.reloadData();
151
- // this.tree()?.refresh();
152
- });
153
- }
154
- //#endregion
155
- //#region ---- Public Methods ----
156
- /**
157
- * Handles category search input changes - Uses server-side search for efficiency and reliability
158
- */
159
- async handleCategorySearchChange(event) {
160
- if (!this.isTreeInitialized()) {
161
- return;
162
- }
163
- const searchTerm = (event.value ?? '').trim().toLowerCase();
164
- const previousSearchTerm = this.currentSearchValue();
165
- // If search is cleared, reset tree
166
- if (!searchTerm) {
167
- if (previousSearchTerm || this.matchingNodeIds.size > 0) {
168
- this.currentSearchValue.set('');
169
- this.currentSearchTerm = null;
170
- await this.resetSearch();
171
- }
172
- return;
173
- }
174
- // For non-empty search, only process user interactions
175
- if (!event.isUserInteraction) {
176
- return;
177
- }
178
- // Prevent concurrent searches
179
- if (this.isSearching() && this.currentSearchTerm !== null) {
180
- if (this.currentSearchTerm === searchTerm) {
181
- return;
182
- }
183
- }
184
- this.currentSearchValue.set(event.value ?? '');
185
- this.currentSearchTerm = searchTerm;
186
- const treeComponent = this.tree();
187
- if (!treeComponent) {
188
- return;
189
- }
190
- // Store expanded nodes before starting a new search (only on first search)
191
- if (!previousSearchTerm && this.expandedNodesBeforeSearch.length === 0) {
192
- const expandedNodes = treeComponent.getExpandedNodes();
193
- this.expandedNodesBeforeSearch = expandedNodes
194
- .map((node) => String(node['id'] ?? ''))
195
- .filter((id) => id && id !== ROOT_NODE_ID);
196
- }
197
- // Collapse nodes from previous search before starting new search
198
- if (previousSearchTerm && this.nodesExpandedDuringSearch.length > 0) {
199
- const nodesToCollapse = [...this.nodesExpandedDuringSearch].reverse();
200
- this.nodesExpandedDuringSearch = [];
201
- for (const nodeId of nodesToCollapse) {
202
- // Only collapse if it wasn't originally expanded before search
203
- if (!this.expandedNodesBeforeSearch.includes(nodeId)) {
204
- try {
205
- treeComponent.collapseNode(nodeId);
206
- }
207
- catch {
208
- // Node might not exist anymore, ignore
209
- }
210
- }
211
- }
212
- }
213
- this.isSearching.set(true);
214
- try {
215
- // Step 1: Use server-side search to get matching items
216
- const searchResults = await this.categoryTreeService.searchCategories(searchTerm, this.treeData, this.treeConfig);
217
- // Check if search term changed during the API call
218
- if (this.currentSearchTerm !== searchTerm) {
219
- return;
220
- }
221
- if (!searchResults || searchResults.length === 0) {
222
- this.matchingNodeIds.clear();
223
- this.relevantNodeIds.clear();
224
- this.searchResultCount.set(0);
225
- await this.updateTranslatedMessages(0);
226
- // Clear highlighting and reload tree to show all nodes
227
- this.highlightService.clear();
228
- await treeComponent.reloadData();
229
- return;
230
- }
231
- // Store matching node IDs from search results
232
- this.matchingNodeIds.clear();
233
- const valueField = this.valueField();
234
- searchResults.forEach((item) => {
235
- const nodeId = String(item[valueField] ?? '');
236
- if (nodeId) {
237
- this.matchingNodeIds.add(nodeId);
238
- }
239
- });
240
- const resultCount = searchResults.length;
241
- this.searchResultCount.set(resultCount);
242
- // Update translated messages
243
- await this.updateTranslatedMessages(resultCount);
244
- // Step 2: Collect parent IDs (builds relevantNodeIds for filtering)
245
- const parentsToExpand = await this.collectParentIds(searchResults);
246
- // Step 2.5: Collect children IDs if searchWithChildren is enabled
247
- if (this.searchWithChildren()) {
248
- await this.collectChildrenIds(searchResults);
249
- }
250
- // Step 3: Reload tree to apply filtering
251
- await treeComponent.reloadData();
252
- // Step 4: Expand root node
253
- if (!treeComponent.isNodeExpanded(ROOT_NODE_ID)) {
254
- try {
255
- await treeComponent.expandNode(ROOT_NODE_ID);
256
- this.nodesExpandedDuringSearch.push(ROOT_NODE_ID);
257
- }
258
- catch {
259
- // Root might not exist
260
- }
261
- }
262
- // Step 4: Expand all parent nodes in order (from root to leaves)
263
- // Sort parents by their depth to expand in correct order
264
- const sortedParents = await this.sortParentsByDepth(Array.from(parentsToExpand));
265
- for (const parentId of sortedParents) {
266
- // Only expand if not already expanded
267
- if (!treeComponent.isNodeExpanded(parentId)) {
268
- try {
269
- await treeComponent.expandNode(parentId);
270
- this.nodesExpandedDuringSearch.push(parentId);
271
- // Small delay to prevent overwhelming the tree component
272
- await new Promise((resolve) => setTimeout(resolve, 10));
273
- }
274
- catch {
275
- // Node might not exist, ignore
276
- }
277
- }
278
- }
279
- // Step 5: Apply highlighting after tree is rendered
280
- // Use setTimeout to ensure DOM is updated after tree reload
281
- setTimeout(() => {
282
- if (this.currentSearchValue().trim()) {
283
- this.highlightService.highlight('ax-tree-view .ax-truncate', this.currentSearchValue().trim());
284
- }
285
- }, 100);
286
- }
287
- catch (error) {
288
- console.error('Error searching categories:', error);
289
- this.matchingNodeIds.clear();
290
- this.relevantNodeIds.clear();
291
- this.searchResultCount.set(0);
292
- this.highlightService.clear();
293
- // Reload tree to clear any filters
294
- const treeComponent = this.tree();
295
- if (treeComponent) {
296
- await treeComponent.reloadData();
297
- }
298
- }
299
- finally {
300
- if (this.currentSearchTerm === searchTerm) {
301
- this.currentSearchTerm = null;
302
- }
303
- this.isSearching.set(false);
304
- }
305
- }
306
- /**
307
- * Collects all parent IDs for the given search results
308
- * Handles both nested 'parent' object and 'parentId' field in search results
309
- * Recursively fetches parent nodes to build the full parent chain
310
- */
311
- async collectParentIds(items) {
312
- const parentsToExpand = new Set();
313
- const valueField = this.valueField();
314
- const parentKey = this.treeData?.categoryEntityDef?.parentKey || 'parentId';
315
- // Build relevantNodeIds = matching nodes + all parents
316
- this.relevantNodeIds.clear();
317
- this.matchingNodeIds.forEach((id) => this.relevantNodeIds.add(id));
318
- // Recursively extract all parent IDs
319
- const extractParentIds = async (item) => {
320
- // First, try to get parent from nested 'parent' object (if available)
321
- const parent = item['parent'];
322
- if (parent) {
323
- const parentId = String(parent[valueField] ?? parent['id'] ?? '');
324
- if (parentId && parentId !== ROOT_NODE_ID) {
325
- parentsToExpand.add(parentId);
326
- this.relevantNodeIds.add(parentId); // Add to filter set
327
- this.nodeDataCache.set(parentId, parent);
328
- await extractParentIds(parent);
329
- }
330
- }
331
- else {
332
- // Fallback: use parentId field and fetch parent from server
333
- // Try both parentKey from entity definition and common 'parentId' field
334
- const parentIdValue = item[parentKey] ?? item['parentId'];
335
- if (parentIdValue) {
336
- const parentId = String(parentIdValue);
337
- if (parentId && parentId !== ROOT_NODE_ID) {
338
- // Add to sets first
339
- parentsToExpand.add(parentId);
340
- this.relevantNodeIds.add(parentId);
341
- // Fetch parent from server if not already cached
342
- if (!this.nodeDataCache.has(parentId)) {
343
- const parentItem = await this.fetchItemById(parentId);
344
- if (parentItem) {
345
- this.nodeDataCache.set(parentId, parentItem);
346
- // Recursively fetch parent's parent
347
- await extractParentIds(parentItem);
348
- }
349
- }
350
- else {
351
- // Parent already in cache, recursively process it
352
- const cachedParent = this.nodeDataCache.get(parentId);
353
- if (cachedParent) {
354
- await extractParentIds(cachedParent);
355
- }
356
- }
357
- }
358
- }
359
- }
360
- };
361
- // Process all items
362
- for (const item of items) {
363
- await extractParentIds(item);
364
- }
365
- return parentsToExpand;
366
- }
367
- /**
368
- * Collects children IDs for matching search results recursively
369
- * Adds all descendants (children, grandchildren, etc.) to relevantNodeIds so they appear in the filtered tree
370
- */
371
- async collectChildrenIds(items) {
372
- if (!this.treeData?.categoryEntityQueryFunc || !this.treeConfig) {
373
- return;
374
- }
375
- const valueField = this.valueField();
376
- const parentKey = this.treeData.categoryEntityDef?.parentKey;
377
- if (!parentKey) {
378
- return;
379
- }
380
- // For each matching node, recursively fetch all its descendants
381
- for (const item of items) {
382
- const nodeId = String(item[valueField] ?? '');
383
- if (!nodeId || nodeId === ROOT_NODE_ID) {
384
- continue;
385
- }
386
- await this.collectChildrenRecursively(nodeId, valueField, parentKey);
387
- }
388
- }
389
- /**
390
- * Recursively collects all descendant IDs for a given node
391
- */
392
- async collectChildrenRecursively(nodeId, valueField, parentKey) {
393
- if (!this.treeData?.categoryEntityQueryFunc) {
394
- return;
395
- }
396
- try {
397
- // Fetch children for this node
398
- const event = {
399
- ...this.treeData.basicQueryEvent,
400
- filter: {
401
- field: parentKey,
402
- value: nodeId,
403
- operator: { type: 'equal' },
404
- },
405
- };
406
- const res = await this.treeData.categoryEntityQueryFunc(event);
407
- if (res?.items && res.items.length > 0) {
408
- // Add children IDs to relevantNodeIds so they appear in filtered tree
409
- for (const child of res.items) {
410
- const childId = String(child[valueField] ?? '');
411
- if (childId && childId !== ROOT_NODE_ID) {
412
- this.relevantNodeIds.add(childId);
413
- // Cache child data
414
- this.nodeDataCache.set(childId, child);
415
- // Recursively fetch children of this child
416
- await this.collectChildrenRecursively(childId, valueField, parentKey);
417
- }
418
- }
419
- }
420
- }
421
- catch (error) {
422
- console.error(`Error fetching children for node ${nodeId}:`, error);
423
- }
424
- }
425
- /**
426
- * Fetches a single item by ID from the server
427
- */
428
- async fetchItemById(id) {
429
- if (!this.treeData?.categoryEntityQueryFunc) {
430
- return null;
431
- }
432
- try {
433
- const valueField = this.valueField();
434
- const event = {
435
- ...this.treeData.basicQueryEvent,
436
- filter: {
437
- field: valueField,
438
- value: id,
439
- operator: { type: 'equal' },
440
- },
441
- };
442
- const res = await this.treeData.categoryEntityQueryFunc(event);
443
- return res?.items?.[0] ?? null;
444
- }
445
- catch (error) {
446
- console.error('Error fetching item by ID:', error);
447
- return null;
448
- }
449
- }
450
- /**
451
- * Sorts parent IDs by their depth (root first, leaves last)
452
- * Uses cached data from collectParentIds
453
- */
454
- async sortParentsByDepth(parentIds) {
455
- const parentKey = this.treeData?.categoryEntityDef?.parentKey;
456
- if (!parentKey || parentIds.length === 0) {
457
- return parentIds;
458
- }
459
- // Build depth map using cached data
460
- const depthMap = new Map();
461
- for (const parentId of parentIds) {
462
- if (depthMap.has(parentId)) {
463
- continue;
464
- }
465
- let depth = 0;
466
- let currentId = parentId;
467
- const visited = new Set();
468
- while (currentId && currentId !== ROOT_NODE_ID && !visited.has(currentId)) {
469
- visited.add(currentId);
470
- depth++;
471
- // Use nodeDataCache which was populated by collectParentIds
472
- const item = this.nodeDataCache.get(currentId);
473
- if (item) {
474
- currentId = item[parentKey] ? String(item[parentKey]) : null;
475
- }
476
- else {
477
- break;
478
- }
479
- }
480
- depthMap.set(parentId, depth);
481
- }
482
- // Sort by depth (lower depth = closer to root = expand first)
483
- return parentIds.sort((a, b) => {
484
- const depthA = depthMap.get(a) ?? 0;
485
- const depthB = depthMap.get(b) ?? 0;
486
- return depthA - depthB;
487
- });
488
- }
489
- /**
490
- * Updates translated messages for search results
491
- */
492
- async updateTranslatedMessages(resultCount) {
493
- if (resultCount > 0) {
494
- const key = resultCount === 1
495
- ? '@general:terms.interface.category.search.results-found.singular'
496
- : '@general:terms.interface.category.search.results-found.plural';
497
- const text = await this.translate.translateAsync(key, { params: { count: resultCount } });
498
- this.resultsFoundText.set(text);
499
- }
500
- else {
501
- this.resultsFoundText.set('');
502
- }
503
- }
504
- /**
505
- * Resets search state and restores tree to original expanded state
506
- */
507
- async resetSearch() {
508
- this.searchResultCount.set(0);
509
- this.resultsFoundText.set('');
510
- this.currentSearchTerm = null;
511
- this.isSearching.set(false);
512
- this.matchingNodeIds.clear();
513
- this.relevantNodeIds.clear();
514
- this.nodeDataCache.clear();
515
- // Clear highlighting
516
- this.highlightService.clear();
517
- const treeComponent = this.tree();
518
- if (!treeComponent) {
519
- this.expandedNodesBeforeSearch = [];
520
- this.nodesExpandedDuringSearch = [];
521
- return;
522
- }
523
- // Reload tree to show all nodes (no filtering)
524
- await treeComponent.reloadData();
525
- // Collapse nodes that were expanded during search (in reverse order - leaves first)
526
- const nodesToCollapse = [...this.nodesExpandedDuringSearch].reverse();
527
- this.nodesExpandedDuringSearch = [];
528
- for (const nodeId of nodesToCollapse) {
529
- // Only collapse if it wasn't originally expanded before search
530
- if (!this.expandedNodesBeforeSearch.includes(nodeId)) {
531
- try {
532
- treeComponent.collapseNode(nodeId);
533
- }
534
- catch {
535
- // Node might not exist anymore, ignore
536
- }
537
- }
538
- }
539
- // Clear the stored expanded nodes
540
- this.expandedNodesBeforeSearch = [];
541
- }
542
- /**
543
- * Checks if a node matches the current search term
544
- */
545
- isMatchingNode(nodeId) {
546
- return this.matchingNodeIds.has(nodeId);
547
- }
548
- /**
549
- * Handles node click events to apply category filters and track selected category for create command
550
- */
551
- handleNodeClick(node) {
552
- const nodeData = this.extractNodeData(node);
553
- const applyConditions = this.vm().entityDef.category?.applyConditions || [];
554
- const valueField = this.valueField();
555
- const textField = this.textField();
556
- const nodeId = String(nodeData[valueField] ?? node['id'] ?? '');
557
- // Track selected category for default category when creating new entities
558
- if (nodeId === 'all' || !nodeId) {
559
- this.vm().setSelectedCategory(null);
560
- }
561
- else {
562
- this.vm().setSelectedCategory({
563
- id: nodeId,
564
- title: String(nodeData[textField] ?? node['title'] ?? ''),
565
- });
566
- }
567
- const categoryFilters = this.buildCategoryFilters(nodeData, applyConditions);
568
- const viewFilters = this.buildViewFilters();
569
- this.vm().dataSource.filter({
570
- filters: [...viewFilters, ...categoryFilters],
571
- logic: 'and',
572
- });
573
- this.vm().dataSource.refresh();
574
- }
575
- /**
576
- * Handles node toggle events (expansion/collapse)
577
- */
578
- async onNodeToggle(_event) {
579
- // Tree component handles lazy loading via datasource callback
580
- }
581
- //#endregion
582
- //#region ---- CRUD Operations ----
583
- /**
584
- * Creates a new root category node
585
- */
586
- async handleCreateRootClick(event) {
587
- this.preventDefaultAndStopPropagation(event);
588
- try {
589
- const context = await this.executeCreateWorkflow(undefined);
590
- await this.handleCreateResult(context, undefined);
591
- }
592
- catch (error) {
593
- console.error('Error creating root category:', error);
594
- }
595
- }
596
- /**
597
- * Creates a new child category under the given parent node
598
- */
599
- async handleCreateChildClick(node, event) {
600
- this.preventDefaultAndStopPropagation(event);
601
- try {
602
- const parentId = this.extractNodeId(node);
603
- const context = await this.executeCreateWorkflow(parentId);
604
- await this.handleCreateResult(context, parentId);
605
- }
606
- catch (error) {
607
- console.error('Error creating child category:', error);
608
- }
609
- }
610
- /**
611
- * Updates an existing category node
612
- */
613
- async handleEditNodeClick(node, event) {
614
- this.preventDefaultAndStopPropagation(event);
615
- try {
616
- const nodeData = this.extractNodeData(node);
617
- const context = await this.executeModifyWorkflow(nodeData);
618
- await this.handleModifyResult(context, node);
619
- }
620
- catch (error) {
621
- console.error('Error editing category:', error);
622
- }
623
- }
624
- /**
625
- * Deletes a category node
626
- */
627
- async handleDeleteNodeClick(node, event) {
628
- this.preventDefaultAndStopPropagation(event);
629
- try {
630
- const nodeData = this.extractNodeData(node);
631
- const context = await this.executeDeleteWorkflow(nodeData);
632
- await this.handleDeleteResult(context, node);
633
- }
634
- catch (error) {
635
- console.error('Error deleting category:', error);
636
- }
637
- }
638
- //#endregion
639
- //#region ---- Private Tree Management Methods ----
640
- /**
641
- * Initializes the category tree data structure
642
- */
643
- async initializeTree() {
644
- this.setLoadingWithDelay(true);
645
- try {
646
- const entityKey = this.categoryEntityKey();
647
- this.treeConfig = {
648
- entityKey,
649
- textField: this.textField(),
650
- valueField: this.valueField(),
651
- };
652
- this.treeData = await this.categoryTreeService.initializeCategoryTree(this.treeConfig);
653
- if (!this.treeData) {
654
- this.clearLoadingState();
655
- return;
656
- }
657
- // Set parent key from entity definition
658
- if (this.treeData.categoryEntityDef?.parentKey) {
659
- this.treeConfig.parentKey = this.treeData.categoryEntityDef.parentKey;
660
- }
661
- }
662
- catch (error) {
663
- console.error('Error loading categories:', error);
664
- }
665
- finally {
666
- this.clearLoadingState();
667
- }
668
- }
669
- /**
670
- * Loads root nodes for the tree
671
- */
672
- async loadRootNodes() {
673
- if (!this.isTreeInitialized()) {
674
- return [];
675
- }
676
- // Load root categories
677
- const items = await this.categoryTreeService.loadRootCategories(this.treeData, this.treeConfig);
678
- if (!items) {
679
- return [];
680
- }
681
- const rootNode = await this.categoryTreeService.createRootNode(items, this.treeConfig);
682
- // Filter root's children when search is active
683
- if (this.relevantNodeIds.size > 0 && rootNode['children']) {
684
- rootNode['children'] = rootNode['children'].filter((child) => {
685
- const childId = String(child['id'] ?? '');
686
- return this.relevantNodeIds.has(childId);
687
- });
688
- rootNode['childrenCount'] = rootNode['children'].length;
689
- }
690
- return [rootNode];
691
- }
692
- /**
693
- * Loads child nodes for a given parent ID
694
- */
695
- async loadChildNodes(parentId) {
696
- if (!this.isTreeInitialized()) {
697
- return [];
698
- }
699
- // Create minimal node object - loadChildren only needs node.id
700
- const targetNode = {
701
- id: parentId,
702
- };
703
- let children = await this.categoryTreeService.loadChildren(targetNode, this.treeData, this.treeConfig);
704
- // Filter children when search is active
705
- if (this.relevantNodeIds.size > 0) {
706
- children = children.filter((child) => {
707
- const childId = String(child['id'] ?? '');
708
- return this.relevantNodeIds.has(childId);
709
- });
710
- }
711
- return children;
712
- }
713
- /**
714
- * Refreshes the tree view component
715
- */
716
- refreshTree() {
717
- const treeComponent = this.tree();
718
- if (treeComponent) {
719
- treeComponent.refresh();
720
- }
721
- }
722
- /**
723
- * Refreshes tree after CRUD operations
724
- */
725
- async refreshAfterChange(parentId) {
726
- this.refreshTree();
727
- }
728
- /**
729
- * Adds a new node to the tree after create operation
730
- */
731
- async addNodeToTree(entityData, parentId) {
732
- if (!this.isTreeInitialized()) {
733
- return;
734
- }
735
- const treeComponent = this.tree();
736
- if (!treeComponent) {
737
- return;
738
- }
739
- const newNode = this.categoryTreeService.convertToTreeNode(entityData, this.treeConfig);
740
- if (parentId) {
741
- await this.addChildNode(treeComponent, parentId, newNode);
742
- }
743
- else {
744
- await this.addRootNode(treeComponent, newNode);
745
- }
746
- }
747
- /**
748
- * Adds a child node to a parent node
749
- */
750
- async addChildNode(treeComponent, parentId, newNode) {
751
- const parentNode = treeComponent.findNode(parentId);
752
- if (!parentNode) {
753
- await this.refreshAfterChange(parentId);
754
- return;
755
- }
756
- if (!treeComponent.isNodeExpanded(parentId)) {
757
- await treeComponent.expandNode(parentId);
758
- }
759
- treeComponent.addChild(parentId, newNode);
760
- }
761
- /**
762
- * Adds a root node to the tree
763
- */
764
- async addRootNode(treeComponent, newNode) {
765
- const rootNode = treeComponent.findNode(ROOT_NODE_ID);
766
- if (!rootNode) {
767
- await this.refreshAfterChange();
768
- return;
769
- }
770
- if (!treeComponent.isNodeExpanded(ROOT_NODE_ID)) {
771
- await treeComponent.expandNode(ROOT_NODE_ID);
772
- }
773
- treeComponent.addChild(ROOT_NODE_ID, newNode);
774
- }
775
- /**
776
- * Updates an existing node in the tree after edit operation
777
- */
778
- async updateNodeInTree(nodeId, entityData) {
779
- if (!this.isTreeInitialized()) {
780
- return;
781
- }
782
- const treeComponent = this.tree();
783
- if (!treeComponent) {
784
- return;
785
- }
786
- const existingNode = treeComponent.findNode(nodeId);
787
- if (!existingNode) {
788
- await this.refreshNodeParent(entityData);
789
- return;
790
- }
791
- // Check if parent changed
792
- const parentKey = this.treeData?.categoryEntityDef?.parentKey;
793
- let newParentId = undefined;
794
- if (parentKey && entityData[parentKey]) {
795
- const parentValue = String(entityData[parentKey]);
796
- // 'all' means root, so treat it as undefined
797
- newParentId = parentValue !== 'all' && parentValue !== '' ? parentValue : undefined;
798
- }
799
- const currentParent = treeComponent.getParent(nodeId);
800
- const currentParentId = currentParent ? String(currentParent['id'] ?? '') : undefined;
801
- // Normalize current parent: 'all' means root (undefined)
802
- const normalizedCurrentParentId = currentParentId === 'all' || currentParentId === '' ? undefined : currentParentId;
803
- // Handle parent change: move node to new parent if parent changed
804
- if (newParentId !== normalizedCurrentParentId) {
805
- // If parent changed, move the node first
806
- const moved = treeComponent.moveNode(nodeId, newParentId);
807
- if (!moved) {
808
- // If move failed, refresh the tree to ensure consistency
809
- await this.refreshNodeParent(entityData);
810
- return;
811
- }
812
- // After moving, we need to ensure the new parent is expanded
813
- if (newParentId) {
814
- if (!treeComponent.isNodeExpanded(newParentId)) {
815
- await treeComponent.expandNode(newParentId);
816
- }
817
- }
818
- else {
819
- // Moving to root - ensure root is expanded
820
- if (!treeComponent.isNodeExpanded(ROOT_NODE_ID)) {
821
- await treeComponent.expandNode(ROOT_NODE_ID);
822
- }
823
- }
824
- }
825
- // Update node properties (title, data, etc.)
826
- const updatedNode = this.categoryTreeService.convertToTreeNode(entityData, this.treeConfig);
827
- const updates = {
828
- ['title']: updatedNode['title'],
829
- ['data']: updatedNode['data'],
830
- ['childrenCount']: updatedNode['childrenCount'],
831
- ['icon']: updatedNode['icon'],
832
- };
833
- treeComponent.editNode(nodeId, updates);
834
- }
835
- /**
836
- * Removes a node from the tree after delete operation
837
- */
838
- async removeNodeFromTree(nodeId) {
839
- const treeComponent = this.tree();
840
- if (!treeComponent) {
841
- return;
842
- }
843
- const nodeToDelete = treeComponent.findNode(nodeId);
844
- if (!nodeToDelete) {
845
- await this.refreshAfterChange();
846
- return;
847
- }
848
- treeComponent.removeNode(nodeId);
849
- }
850
- //#endregion
851
- //#region ---- Workflow Execution Methods ----
852
- /**
853
- * Executes the create entity workflow
854
- */
855
- async executeCreateWorkflow(parentId) {
856
- const entityKey = this.categoryEntityKey();
857
- const workflowData = {};
858
- if (parentId && this.treeData?.categoryEntityDef?.parentKey) {
859
- workflowData[this.treeData.categoryEntityDef.parentKey] = parentId;
860
- }
861
- return await this.workflow.execute('create-entity', {
862
- entity: entityKey,
863
- data: Object.keys(workflowData).length > 0 ? workflowData : undefined,
864
- options: { process: { redirect: false, canCreateNewOne: !!parentId } },
865
- });
866
- }
867
- /**
868
- * Executes the modify entity workflow
869
- */
870
- async executeModifyWorkflow(nodeData) {
871
- return await this.workflow.execute('quick-modify-entity', {
872
- entity: this.categoryEntityKey(),
873
- data: nodeData,
874
- options: { layout: { size: 'md' } },
875
- });
876
- }
877
- /**
878
- * Executes the delete entity workflow
879
- */
880
- async executeDeleteWorkflow(nodeData) {
881
- return await this.workflow.execute('delete-entity', {
882
- entity: this.categoryEntityKey(),
883
- data: nodeData,
884
- options: { process: { showResult: true } },
885
- });
886
- }
887
- /**
888
- * Handles the result of a create operation
889
- */
890
- async handleCreateResult(context, parentId) {
891
- const result = context.getOutput('result');
892
- if (!result || !this.isTreeInitialized()) {
893
- await this.refreshAfterChange(parentId);
894
- return;
895
- }
896
- const newEntityData = context.getVariable('data');
897
- if (newEntityData) {
898
- await this.addNodeToTree(newEntityData, parentId);
899
- }
900
- else {
901
- await this.refreshAfterChange(parentId);
902
- }
903
- }
904
- /**
905
- * Handles the result of a modify operation
906
- */
907
- async handleModifyResult(context, node) {
908
- const result = context.getOutput('result');
909
- if (!result || !this.isTreeInitialized()) {
910
- await this.refreshNodeParent(this.extractNodeData(node));
911
- return;
912
- }
913
- const updatedEntityData = context.getVariable('data');
914
- if (updatedEntityData) {
915
- await this.updateNodeInTree(this.extractNodeId(node), updatedEntityData);
916
- }
917
- else {
918
- await this.refreshNodeParent(this.extractNodeData(node));
919
- }
920
- }
921
- /**
922
- * Handles the result of a delete operation
923
- */
924
- async handleDeleteResult(context, node) {
925
- const result = context.getOutput('result');
926
- if (result) {
927
- await this.removeNodeFromTree(this.extractNodeId(node));
928
- }
929
- else {
930
- await this.refreshNodeParent(this.extractNodeData(node));
931
- }
932
- }
933
- //#endregion
934
- //#region ---- Utility Methods ----
935
- /**
936
- * Checks if tree data and config are initialized
937
- */
938
- isTreeInitialized() {
939
- return !!(this.treeData && this.treeConfig);
940
- }
941
- /**
942
- * Extracts node data from a tree node
943
- */
944
- extractNodeData(node) {
945
- return (node['data'] || node);
946
- }
947
- /**
948
- * Extracts node ID from a tree node
949
- */
950
- extractNodeId(node) {
951
- return String(node['id'] ?? '');
952
- }
953
- /**
954
- * Builds category filters from node data and apply conditions
955
- */
956
- buildCategoryFilters(nodeData, applyConditions) {
957
- return applyConditions
958
- .map((condition) => {
959
- const value = nodeData[condition.value];
960
- if (value === 'all' || value == null) {
961
- return null;
962
- }
963
- return {
964
- field: condition.name,
965
- value,
966
- operator: condition.operator,
967
- };
968
- })
969
- .filter((item) => item !== null);
970
- }
971
- /**
972
- * Builds view filters from view conditions
973
- */
974
- buildViewFilters() {
975
- return this.vm()
976
- .view()
977
- .conditions.map((condition) => ({ ...condition, field: condition.name }));
978
- }
979
- /**
980
- * Refreshes the parent node of the given entity data
981
- */
982
- async refreshNodeParent(entityData) {
983
- const parentKey = this.treeData?.categoryEntityDef?.parentKey;
984
- const parentId = parentKey && entityData[parentKey] ? entityData[parentKey] : undefined;
985
- await this.refreshAfterChange(parentId);
986
- }
987
- /**
988
- * Prevents default behavior and stops event propagation
989
- */
990
- preventDefaultAndStopPropagation(event) {
991
- event.nativeEvent.preventDefault();
992
- event.nativeEvent.stopPropagation();
993
- }
994
- //#endregion
995
- //#region ---- Loading State Management ----
996
- /**
997
- * Sets loading state with delay to avoid flickering for fast responses
998
- */
999
- setLoadingWithDelay(loading) {
1000
- if (!loading) {
1001
- return;
1002
- }
1003
- if (this.loadingTimeoutId) {
1004
- clearTimeout(this.loadingTimeoutId);
1005
- }
1006
- this.loadingTimeoutId = setTimeout(() => {
1007
- this.isLoading.set(true);
1008
- this.loadingTimeoutId = null;
1009
- }, LOADING_DELAY_MS);
1010
- }
1011
- /**
1012
- * Clears loading state and cancels any pending timeout
1013
- */
1014
- clearLoadingState() {
1015
- if (this.loadingTimeoutId) {
1016
- clearTimeout(this.loadingTimeoutId);
1017
- this.loadingTimeoutId = null;
1018
- }
1019
- this.isLoading.set(false);
1020
- }
1021
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPEntityCategoryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1022
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AXPEntityCategoryComponent, isStandalone: true, selector: "axp-entity-category", inputs: { vm: { classPropertyName: "vm", publicName: "vm", isSignal: true, isRequired: true, transformFunction: null }, searchValue: { classPropertyName: "searchValue", publicName: "searchValue", isSignal: true, isRequired: false, transformFunction: null }, selectMode: { classPropertyName: "selectMode", publicName: "selectMode", isSignal: true, isRequired: false, transformFunction: null }, selectionBehavior: { classPropertyName: "selectionBehavior", publicName: "selectionBehavior", isSignal: true, isRequired: false, transformFunction: null }, dragArea: { classPropertyName: "dragArea", publicName: "dragArea", isSignal: true, isRequired: false, transformFunction: null }, dragBehavior: { classPropertyName: "dragBehavior", publicName: "dragBehavior", isSignal: true, isRequired: false, transformFunction: null }, showIcons: { classPropertyName: "showIcons", publicName: "showIcons", isSignal: true, isRequired: false, transformFunction: null }, showChildrenBadge: { classPropertyName: "showChildrenBadge", publicName: "showChildrenBadge", isSignal: true, isRequired: false, transformFunction: null }, expandedIcon: { classPropertyName: "expandedIcon", publicName: "expandedIcon", isSignal: true, isRequired: false, transformFunction: null }, collapsedIcon: { classPropertyName: "collapsedIcon", publicName: "collapsedIcon", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, searchWithChildren: { classPropertyName: "searchWithChildren", publicName: "searchWithChildren", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true, isSignal: true }], ngImport: i0, template: "<axp-layout-header>\n <axp-layout-title>{{\n vm().entityDef.category?.title || '@general:terms.classification.category' | translate | async\n }}</axp-layout-title>\n <axp-layout-toolbar>\n <div class=\"ax-flex ax-flex-col ax-gap-1 ax-w-full\">\n <ax-search-box (onValueChanged)=\"handleCategorySearchChange($event)\" [delayTime]=\"300\"\n [placeholder]=\"'@general:terms.interface.category.search.placeholder' | translate | async\">\n </ax-search-box>\n @if (isSearching() && currentSearchValue().trim()) {\n <div class=\"ax-text-xs ax-text-muted ax-flex ax-items-center ax-gap-1\">\n <span>{{ '@general:terms.interface.category.search.searching' | translate | async }}</span>\n </div>\n } @else if (currentSearchValue().trim() && !isSearching()) {\n <div class=\"ax-text-xs ax-text-muted ax-flex ax-items-center ax-gap-1\">\n @if (searchResultCount() > 0) {\n <span>{{ resultsFoundText() }}</span>\n }\n </div>\n }\n </div>\n </axp-layout-toolbar>\n</axp-layout-header>\n<axp-layout-content>\n @if (isLoading()) {\n <div class=\"ax-p-4 ax-flex ax-flex-col ax-gap-3\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n </div>\n } @else if (showNoSearchResults()) {\n <div class=\"__empty-state\">\n <axp-state-message icon=\"fa-light fa-search\"\n [title]=\"'@general:terms.interface.category.search.no-results-found.title'\"\n [description]=\"'@general:terms.interface.category.search.no-results-found.description'\">\n </axp-state-message>\n </div>\n } @else if (treeData) {\n <div class=\"ax-px-4 ax-max-h-[calc(100vh-250px)] ax-overflow-auto\">\n <ax-tree-view [datasource]=\"datasource\" [selectMode]=\"selectMode()\" [selectionBehavior]=\"selectionBehavior()\"\n [dragArea]=\"dragArea()\" [dragBehavior]=\"dragBehavior()\" [showIcons]=\"showIcons()\"\n [showChildrenBadge]=\"showChildrenBadge()\" [expandedIcon]=\"expandedIcon()\" [collapsedIcon]=\"collapsedIcon()\"\n [indentSize]=\"indentSize()\" [look]=\"look()\" [titleField]=\"textField()\" [idField]=\"valueField()\"\n [expandOnDoubleClick]=\"true\" [nodeTemplate]=\"itemTemplate\" (onNodeToggle)=\"onNodeToggle($event)\"\n (onNodeClick)=\"handleNodeClick($event.node)\" #tree>\n </ax-tree-view>\n </div>\n } @else {\n <div class=\"__empty-state\">\n <axp-state-message icon=\"fa-light fa-folder-open\"\n [title]=\"'@general:terms.interface.category.search.no-records.title'\"\n [description]=\"'@general:terms.interface.category.search.no-records.description'\">\n @if (!categoryReadonly()) {\n <ax-button slot=\"actions\" (onClick)=\"handleCreateRootClick($event)\" look=\"solid\" color=\"primary\"\n [text]=\"'@general:actions.add-new.title' | translate | async\">\n <ax-icon class=\"fas fa-plus\"></ax-icon>\n </ax-button>\n }\n </axp-state-message>\n </div>\n }\n\n <ng-template #itemTemplate let-node=\"node\" let-level=\"level\">\n @let item = node.data || node;\n @let textField = vm().entityDef.category?.textField || 'title';\n @let valueField = vm().entityDef.category?.valueField || 'id';\n @let itemId = item[valueField] || node.id;\n @let itemTitle = item[textField] || node.title;\n <div class=\"ax-flex ax-items-center ax-justify-between ax-w-full ax-gap-2 ax-overflow-hidden ax-py-1\">\n <div class=\"ax-flex ax-items-center ax-gap-2 ax-min-w-0\">\n <ax-icon class=\"fas fa-folder\"\n [style.color]=\"item.color ?? 'rgba(var(--ax-sys-color-warning-500), 1)'\"></ax-icon>\n <span class=\"ax-truncate\">{{ itemTitle }}</span>\n </div>\n @if (itemId && itemId !== 'all' && !categoryReadonly()) {\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-button class=\"ax-xs\" color=\"default\" look=\"blank\" (onClick)=\"$event.nativeEvent.stopPropagation()\">\n <ax-icon class=\"fas fa-ellipsis-v\"></ax-icon>\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item (onClick)=\"handleCreateChildClick(node, $event)\" look=\"blank\" color=\"default\"\n [text]=\"('@general:actions.add-new-child.title' | translate | async)!\">\n <ax-icon class=\"fas fa-plus\"></ax-icon>\n </ax-button-item>\n <ax-button-item (onClick)=\"handleEditNodeClick(node, $event)\" look=\"blank\"\n [text]=\"('@general:actions.edit.title' | translate | async)!\">\n <ax-icon class=\"fas fa-pen\"></ax-icon>\n </ax-button-item>\n <ax-button-item (onClick)=\"handleDeleteNodeClick(node, $event)\" color=\"danger\" look=\"blank\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\">\n <ax-icon class=\"fas fa-trash\"></ax-icon>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n } @else if (itemId === 'all' && !categoryReadonly()) {\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-button class=\"ax-xs\" (onClick)=\"handleCreateRootClick($event)\" look=\"blank\" color=\"default\">\n <ax-icon class=\"fas fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </div>\n </ng-template>\n</axp-layout-content>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTreeViewModule }, { 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", "doubleClickDuration", "tooltipDelay"], outputs: ["datasourceChange", "onBeforeDrop", "onNodeToggle", "onNodeSelect", "onNodeDoubleClick", "onNodeClick", "onSelectionChange", "onOrderChange", "onMoveChange", "onItemsChange"] }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i2$1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i6.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: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "component", type: AXPThemeLayoutToolbarComponent, selector: "axp-layout-toolbar" }, { kind: "ngmodule", type: AXTranslationModule }, { 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: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "variant"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i10.AXTranslatorPipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); }
1023
- }
1024
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPEntityCategoryComponent, decorators: [{
1025
- type: Component,
1026
- args: [{ selector: 'axp-entity-category', standalone: true, encapsulation: ViewEncapsulation.None, imports: [
1027
- CommonModule,
1028
- AXDecoratorModule,
1029
- AXTreeViewModule,
1030
- AXTreeViewComponent,
1031
- AXSkeletonModule,
1032
- AXPThemeLayoutBlockComponent,
1033
- AXSearchBoxModule,
1034
- AXPThemeLayoutHeaderComponent,
1035
- AXPThemeLayoutToolbarComponent,
1036
- AXTranslationModule,
1037
- AXButtonModule,
1038
- AXDropdownModule,
1039
- AXPStateMessageComponent,
1040
- ], template: "<axp-layout-header>\n <axp-layout-title>{{\n vm().entityDef.category?.title || '@general:terms.classification.category' | translate | async\n }}</axp-layout-title>\n <axp-layout-toolbar>\n <div class=\"ax-flex ax-flex-col ax-gap-1 ax-w-full\">\n <ax-search-box (onValueChanged)=\"handleCategorySearchChange($event)\" [delayTime]=\"300\"\n [placeholder]=\"'@general:terms.interface.category.search.placeholder' | translate | async\">\n </ax-search-box>\n @if (isSearching() && currentSearchValue().trim()) {\n <div class=\"ax-text-xs ax-text-muted ax-flex ax-items-center ax-gap-1\">\n <span>{{ '@general:terms.interface.category.search.searching' | translate | async }}</span>\n </div>\n } @else if (currentSearchValue().trim() && !isSearching()) {\n <div class=\"ax-text-xs ax-text-muted ax-flex ax-items-center ax-gap-1\">\n @if (searchResultCount() > 0) {\n <span>{{ resultsFoundText() }}</span>\n }\n </div>\n }\n </div>\n </axp-layout-toolbar>\n</axp-layout-header>\n<axp-layout-content>\n @if (isLoading()) {\n <div class=\"ax-p-4 ax-flex ax-flex-col ax-gap-3\">\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n <ax-skeleton class=\"ax-w-full ax-h-6 ax-rounded-md\"></ax-skeleton>\n </div>\n } @else if (showNoSearchResults()) {\n <div class=\"__empty-state\">\n <axp-state-message icon=\"fa-light fa-search\"\n [title]=\"'@general:terms.interface.category.search.no-results-found.title'\"\n [description]=\"'@general:terms.interface.category.search.no-results-found.description'\">\n </axp-state-message>\n </div>\n } @else if (treeData) {\n <div class=\"ax-px-4 ax-max-h-[calc(100vh-250px)] ax-overflow-auto\">\n <ax-tree-view [datasource]=\"datasource\" [selectMode]=\"selectMode()\" [selectionBehavior]=\"selectionBehavior()\"\n [dragArea]=\"dragArea()\" [dragBehavior]=\"dragBehavior()\" [showIcons]=\"showIcons()\"\n [showChildrenBadge]=\"showChildrenBadge()\" [expandedIcon]=\"expandedIcon()\" [collapsedIcon]=\"collapsedIcon()\"\n [indentSize]=\"indentSize()\" [look]=\"look()\" [titleField]=\"textField()\" [idField]=\"valueField()\"\n [expandOnDoubleClick]=\"true\" [nodeTemplate]=\"itemTemplate\" (onNodeToggle)=\"onNodeToggle($event)\"\n (onNodeClick)=\"handleNodeClick($event.node)\" #tree>\n </ax-tree-view>\n </div>\n } @else {\n <div class=\"__empty-state\">\n <axp-state-message icon=\"fa-light fa-folder-open\"\n [title]=\"'@general:terms.interface.category.search.no-records.title'\"\n [description]=\"'@general:terms.interface.category.search.no-records.description'\">\n @if (!categoryReadonly()) {\n <ax-button slot=\"actions\" (onClick)=\"handleCreateRootClick($event)\" look=\"solid\" color=\"primary\"\n [text]=\"'@general:actions.add-new.title' | translate | async\">\n <ax-icon class=\"fas fa-plus\"></ax-icon>\n </ax-button>\n }\n </axp-state-message>\n </div>\n }\n\n <ng-template #itemTemplate let-node=\"node\" let-level=\"level\">\n @let item = node.data || node;\n @let textField = vm().entityDef.category?.textField || 'title';\n @let valueField = vm().entityDef.category?.valueField || 'id';\n @let itemId = item[valueField] || node.id;\n @let itemTitle = item[textField] || node.title;\n <div class=\"ax-flex ax-items-center ax-justify-between ax-w-full ax-gap-2 ax-overflow-hidden ax-py-1\">\n <div class=\"ax-flex ax-items-center ax-gap-2 ax-min-w-0\">\n <ax-icon class=\"fas fa-folder\"\n [style.color]=\"item.color ?? 'rgba(var(--ax-sys-color-warning-500), 1)'\"></ax-icon>\n <span class=\"ax-truncate\">{{ itemTitle }}</span>\n </div>\n @if (itemId && itemId !== 'all' && !categoryReadonly()) {\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-button class=\"ax-xs\" color=\"default\" look=\"blank\" (onClick)=\"$event.nativeEvent.stopPropagation()\">\n <ax-icon class=\"fas fa-ellipsis-v\"></ax-icon>\n <ax-dropdown-panel>\n <ax-button-item-list>\n <ax-button-item (onClick)=\"handleCreateChildClick(node, $event)\" look=\"blank\" color=\"default\"\n [text]=\"('@general:actions.add-new-child.title' | translate | async)!\">\n <ax-icon class=\"fas fa-plus\"></ax-icon>\n </ax-button-item>\n <ax-button-item (onClick)=\"handleEditNodeClick(node, $event)\" look=\"blank\"\n [text]=\"('@general:actions.edit.title' | translate | async)!\">\n <ax-icon class=\"fas fa-pen\"></ax-icon>\n </ax-button-item>\n <ax-button-item (onClick)=\"handleDeleteNodeClick(node, $event)\" color=\"danger\" look=\"blank\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\">\n <ax-icon class=\"fas fa-trash\"></ax-icon>\n </ax-button-item>\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n } @else if (itemId === 'all' && !categoryReadonly()) {\n <div class=\"ax-flex ax-items-center ax-gap-1\">\n <ax-button class=\"ax-xs\" (onClick)=\"handleCreateRootClick($event)\" look=\"blank\" color=\"default\">\n <ax-icon class=\"fas fa-plus\"></ax-icon>\n </ax-button>\n </div>\n }\n </div>\n </ng-template>\n</axp-layout-content>" }]
1041
- }], ctorParameters: () => [], propDecorators: { vm: [{ type: i0.Input, args: [{ isSignal: true, alias: "vm", required: true }] }], tree: [{ type: i0.ViewChild, args: ['tree', { isSignal: true }] }], searchValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchValue", required: false }] }], selectMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectMode", required: false }] }], selectionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionBehavior", required: false }] }], dragArea: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragArea", required: false }] }], dragBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragBehavior", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], showChildrenBadge: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChildrenBadge", required: false }] }], expandedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIcon", required: false }] }], collapsedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedIcon", required: false }] }], indentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentSize", required: false }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], searchWithChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchWithChildren", required: false }] }] } });
1042
-
1043
- class AXPEntityMasterToolbarViewComponent {
1044
- constructor() {
1045
- this.layoutService = inject(AXPLayoutThemeService);
1046
- this.deviceService = inject(AXPDeviceService);
1047
- this.parent = inject(AXPEntityMasterListViewComponent);
1048
- this.router = inject(Router);
1049
- this.activeRoute = inject(ActivatedRoute);
1050
- this.settingsService = inject(AXPSettingsService);
1051
- this.isInitializing = false;
1052
- this.pendingInitialFilters = true;
1053
- this.pendingInitialSorts = true;
1054
- this.filterTriggerMode = 'manual';
1055
- this.previousFilterQueries = signal([], ...(ngDevMode ? [{ debugName: "previousFilterQueries" }] : []));
1056
- this.initialFilters = signal([], ...(ngDevMode ? [{ debugName: "initialFilters" }] : []));
1057
- this.filtersDefinitions = signal([], ...(ngDevMode ? [{ debugName: "filtersDefinitions" }] : []));
1058
- this.viewQueries = computed(() => this.vm.views().map((v) => ({
1059
- name: v.name,
1060
- fixed: false,
1061
- title: v.title,
1062
- columns: v.columns,
1063
- conditions: v.conditions.map((c) => ({
1064
- field: c.name,
1065
- operator: c.operator,
1066
- value: c.value,
1067
- })),
1068
- sorts: v.sorts,
1069
- })), ...(ngDevMode ? [{ debugName: "viewQueries" }] : []));
1070
- this.selectedViewQuery = computed(() => ({
1071
- name: this.vm.view().name,
1072
- fixed: false,
1073
- title: this.vm.view().title,
1074
- columns: this.vm.view().columns,
1075
- conditions: this.vm.view().conditions.map((c) => ({
1076
- field: c.name,
1077
- operator: c.operator,
1078
- value: c.value,
1079
- })),
1080
- sorts: this.vm.view().sorts,
1081
- }), ...(ngDevMode ? [{ debugName: "selectedViewQuery" }] : []));
1082
- this.isFiltersDirty = computed(() => !isEqual(this.vm.filterQueries(), this.previousFilterQueries()), ...(ngDevMode ? [{ debugName: "isFiltersDirty" }] : []));
1083
- // Debounced apply to coalesce multiple UI changes (filters/sorts/columns)
1084
- this.applyTimer = null;
1085
- this.#effect = effect(() => {
1086
- // Keep definitions up to date; initial filters are set explicitly from settings or view
1087
- this.filtersDefinitions.set(this.vm.filtersDef);
1088
- }, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
1089
- this.sortQueries = computed(() => this.vm
1090
- .sortedFields()
1091
- .filter((s) => !!s.dir)
1092
- .map((s) => ({ name: s.name, dir: s.dir })), ...(ngDevMode ? [{ debugName: "sortQueries" }] : []));
1093
- this.sortDefinitions = computed(() => this.vm.sortableFields().map((s) => ({
1094
- name: s.name,
1095
- title: s.title,
1096
- dir: s.dir,
1097
- })), ...(ngDevMode ? [{ debugName: "sortDefinitions" }] : []));
1098
- }
1099
- async ngOnInit() {
1100
- // Prefer saved settings (view/columns/sorts/filters) if available, then apply
1101
- await this.loadSettings();
1102
- await this.vm.setView();
1103
- this.filtersDefinitions.set(this.vm.filtersDef);
1104
- this.isInitializing = true;
1105
- // this.pendingInitialFilters = true;
1106
- // this.pendingInitialSorts = true;
1107
- this.setInitialFiltersFromSettingsOrView();
1108
- // Ensure initial load even when filters/sorts are absent
1109
- setTimeout(() => {
1110
- this.isInitializing = false;
1111
- this.scheduleApply();
1112
- }, 0);
1113
- }
1114
- async loadSettings() {
1115
- const filterTriggerMode = await this.settingsService.get(AXPCommonSettings.EntityFilterApplyMode);
1116
- this.filterTriggerMode = (filterTriggerMode?.value ?? 'auto');
1117
- }
1118
- scheduleApply() {
1119
- clearTimeout(this.applyTimer);
1120
- this.applyTimer = setTimeout(() => {
1121
- this.vm.applyFilterAndSort();
1122
- }, 50);
1123
- }
1124
- async onViewChanged(view) {
1125
- await this.vm.setView(view.name);
1126
- // Sync query param immediately on tab change
1127
- this.router.navigate([], {
1128
- relativeTo: this.activeRoute,
1129
- queryParams: { view: view.name },
1130
- queryParamsHandling: 'merge',
1131
- replaceUrl: true,
1132
- });
1133
- this.isInitializing = true;
1134
- this.pendingInitialFilters = true;
1135
- this.pendingInitialSorts = true;
1136
- this.setInitialFiltersFromSettingsOrView();
1137
- // Ensure initial load after view change
1138
- setTimeout(() => {
1139
- this.isInitializing = false;
1140
- this.scheduleApply();
1141
- }, 0);
1142
- }
1143
- #effect;
1144
- setInitialFiltersFromSettingsOrView() {
1145
- const saved = this.vm.filterQueries();
1146
- this.previousFilterQueries.set(saved);
1147
- const viewConditions = this.vm.view().conditions.map((c) => c.name);
1148
- if (saved && saved.length) {
1149
- this.initialFilters.set(saved.map((s) => ({ ...s, hidden: viewConditions.includes(s.field) })));
1150
- return;
1151
- }
1152
- this.initialFilters.set(this.vm.view().conditions.map((c) => ({
1153
- field: c.name,
1154
- operator: c.operator,
1155
- value: c.value,
1156
- hidden: true,
1157
- })));
1158
- }
1159
- onFiltersChanged(filters) {
1160
- if (this.isInitializing || this.pendingInitialFilters) {
1161
- this.pendingInitialFilters = false;
1162
- return;
1163
- }
1164
- this.vm.filterQueries.set(filters);
1165
- if (this.filterTriggerMode === 'auto') {
1166
- this.applyFilters();
1167
- }
1168
- }
1169
- applyFilters() {
1170
- this.previousFilterQueries.set(this.vm.filterQueries());
1171
- this.vm.saveSettings('filters', this.vm.filterQueries());
1172
- this.scheduleApply();
1173
- }
1174
- onSortQueriesChange(e) {
1175
- if (this.isInitializing || this.pendingInitialSorts) {
1176
- this.pendingInitialSorts = false;
1177
- return;
1178
- }
1179
- this.vm.sortedFields.set(e.map((s) => ({
1180
- name: s.name,
1181
- title: s.name,
1182
- dir: s.dir,
1183
- })));
1184
- // Persist sorts per module/entity/view
1185
- this.vm.saveSettings('sorts', e);
1186
- this.scheduleApply();
1187
- }
1188
- onColumnsChange(columns) {
1189
- const keyOf = (c) => c.column?.options?.dataPath ?? c.name;
1190
- this.vm.columns.update((prev) => {
1191
- const byKey = new Map(prev.map((c) => [keyOf(c), c]));
1192
- return columns.map((newColumn) => {
1193
- const existing = byKey.get(keyOf(newColumn));
1194
- return new AXPEntityListViewColumnViewModel(existing.property, {
1195
- ...existing.column,
1196
- options: {
1197
- ...existing.column.options,
1198
- visible: newColumn.visible,
1199
- },
1200
- });
1201
- });
1202
- });
1203
- // Persist column order/visibility
1204
- this.vm.onColumnsChanged(this.vm.columns());
1205
- // Use debounced apply to avoid triple refresh when combined with sorts/filters
1206
- // this.scheduleApply();
1207
- }
1208
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPEntityMasterToolbarViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1209
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AXPEntityMasterToolbarViewComponent, isStandalone: true, selector: "axp-entity-master-toolbar-view", inputs: { vm: ["viewModel", "vm"] }, host: { classAttribute: "ax-w-full" }, ngImport: i0, template: "<!-- <axp-entity-view-toolbar [viewModel]=\"vm\"></axp-entity-view-toolbar> -->\n<axp-query-views\n id=\"axp-toolbar-view-selector\"\n [views]=\"viewQueries()\"\n [selectedView]=\"selectedViewQuery()\"\n (selectedViewChange)=\"onViewChanged($event)\"\n></axp-query-views>\n<div class=\"ax-flex ax-items-center ax-gap-2 ax-border-b ax-border-light w-full\">\n <!-- <axp-entity-filter-toolbar [viewModel]=\"vm\"></axp-entity-filter-toolbar> -->\n <axp-query-filters\n id=\"axp-toolbar-filters\"\n [filtersDefinitions]=\"filtersDefinitions()\"\n [initialFilters]=\"initialFilters()\"\n (onFiltersChanged)=\"onFiltersChanged($event)\"\n ></axp-query-filters>\n\n <div class=\"ax-flex ax-items-center ax-gap-2 md:ax-gap-2\">\n @if (filterTriggerMode === 'manual' && isFiltersDirty()) {\n <ax-button\n id=\"axp-toolbar-btn-filter\"\n [title]=\"'@general:actions.apply.title'\"\n [iconOnly]=\"true\"\n #filterButton\n [color]=\"'primary'\"\n (onClick)=\"applyFilters()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-search\"></i>\n </ax-prefix>\n </ax-button>\n }\n <div>\n <ax-button id=\"axp-toolbar-btn-columns\" [iconOnly]=\"true\" #columnButton [color]=\"'default'\">\n <i class=\"fa-light fa-table-columns\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-columns\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"columnButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #popover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.columns' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <axp-query-columns [columns]=\"vm.columns()\" (columnsChange)=\"onColumnsChange($event)\"></axp-query-columns>\n <!-- <axp-list-view-option-columns [viewModel]=\"vm\"></axp-list-view-option-columns> -->\n </div>\n </div>\n </ax-popover>\n </div>\n\n @if (vm.canSort()) {\n <div>\n <ax-button id=\"axp-toolbar-btn-sort\" [iconOnly]=\"true\" [text]=\"'Sorts'\" #sortButton [color]=\"'default'\">\n <i class=\"fa-light fa-sort-amount-up\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-sort\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"sortButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #popover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.sorts' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <!-- <axp-list-view-option-sorting [viewModel]=\"vm\"></axp-list-view-option-sorting> -->\n <axp-query-sorts\n [sortDefinitions]=\"sortDefinitions()\"\n (sortQueriesChange)=\"onSortQueriesChange($event)\"\n [initialSortQueries]=\"sortQueries()\"\n ></axp-query-sorts>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n @if (deviceService.isSmall()) {\n <ax-button\n id=\"axp-toolbar-btn-category\"\n (onClick)=\"parent.toggleCategoryDrawer()\"\n [iconOnly]=\"true\"\n [color]=\"'default'\"\n >\n <i class=\"fa-light fa-bars\"></i>\n </ax-button>\n }\n </div>\n</div>\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: AXDecoratorModule }, { kind: "component", type: i2.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: AXTranslationModule }, { kind: "component", type: AXPQueryFiltersComponent, selector: "axp-query-filters", inputs: ["filtersDefinitions", "initialFilters"], outputs: ["onFiltersChanged"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i3$1.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "repositionOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "component", type: AXPQuerySortsComponent, selector: "axp-query-sorts", inputs: ["sortDefinitions", "initialSortQueries"], outputs: ["sortDefinitionsChange", "sortQueriesChange"] }, { kind: "component", type: AXPQueryViewsComponent, selector: "axp-query-views", inputs: ["views", "selectedView"], outputs: ["viewsChange", "selectedViewChange"] }, { kind: "component", type: AXPQueryColumnsComponent, selector: "axp-query-columns", inputs: ["columns"], outputs: ["columnsChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i10.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1210
- }
1211
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPEntityMasterToolbarViewComponent, decorators: [{
1212
- type: Component,
1213
- args: [{ selector: 'axp-entity-master-toolbar-view', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1214
- CommonModule,
1215
- AXButtonModule,
1216
- AXDecoratorModule,
1217
- AXTranslationModule,
1218
- AXPQueryFiltersComponent,
1219
- AXPopoverModule,
1220
- AXPQuerySortsComponent,
1221
- AXPQueryViewsComponent,
1222
- AXPQueryColumnsComponent,
1223
- ], host: {
1224
- class: 'ax-w-full',
1225
- }, template: "<!-- <axp-entity-view-toolbar [viewModel]=\"vm\"></axp-entity-view-toolbar> -->\n<axp-query-views\n id=\"axp-toolbar-view-selector\"\n [views]=\"viewQueries()\"\n [selectedView]=\"selectedViewQuery()\"\n (selectedViewChange)=\"onViewChanged($event)\"\n></axp-query-views>\n<div class=\"ax-flex ax-items-center ax-gap-2 ax-border-b ax-border-light w-full\">\n <!-- <axp-entity-filter-toolbar [viewModel]=\"vm\"></axp-entity-filter-toolbar> -->\n <axp-query-filters\n id=\"axp-toolbar-filters\"\n [filtersDefinitions]=\"filtersDefinitions()\"\n [initialFilters]=\"initialFilters()\"\n (onFiltersChanged)=\"onFiltersChanged($event)\"\n ></axp-query-filters>\n\n <div class=\"ax-flex ax-items-center ax-gap-2 md:ax-gap-2\">\n @if (filterTriggerMode === 'manual' && isFiltersDirty()) {\n <ax-button\n id=\"axp-toolbar-btn-filter\"\n [title]=\"'@general:actions.apply.title'\"\n [iconOnly]=\"true\"\n #filterButton\n [color]=\"'primary'\"\n (onClick)=\"applyFilters()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-search\"></i>\n </ax-prefix>\n </ax-button>\n }\n <div>\n <ax-button id=\"axp-toolbar-btn-columns\" [iconOnly]=\"true\" #columnButton [color]=\"'default'\">\n <i class=\"fa-light fa-table-columns\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-columns\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"columnButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #popover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.columns' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <axp-query-columns [columns]=\"vm.columns()\" (columnsChange)=\"onColumnsChange($event)\"></axp-query-columns>\n <!-- <axp-list-view-option-columns [viewModel]=\"vm\"></axp-list-view-option-columns> -->\n </div>\n </div>\n </ax-popover>\n </div>\n\n @if (vm.canSort()) {\n <div>\n <ax-button id=\"axp-toolbar-btn-sort\" [iconOnly]=\"true\" [text]=\"'Sorts'\" #sortButton [color]=\"'default'\">\n <i class=\"fa-light fa-sort-amount-up\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-sort\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"sortButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #popover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.sorts' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <!-- <axp-list-view-option-sorting [viewModel]=\"vm\"></axp-list-view-option-sorting> -->\n <axp-query-sorts\n [sortDefinitions]=\"sortDefinitions()\"\n (sortQueriesChange)=\"onSortQueriesChange($event)\"\n [initialSortQueries]=\"sortQueries()\"\n ></axp-query-sorts>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n @if (deviceService.isSmall()) {\n <ax-button\n id=\"axp-toolbar-btn-category\"\n (onClick)=\"parent.toggleCategoryDrawer()\"\n [iconOnly]=\"true\"\n [color]=\"'default'\"\n >\n <i class=\"fa-light fa-bars\"></i>\n </ax-button>\n }\n </div>\n</div>\n" }]
1226
- }], propDecorators: { vm: [{
1227
- type: Input,
1228
- args: ['viewModel']
1229
- }] } });
1230
-
1231
- class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
1232
- constructor(platform) {
1233
- super();
1234
- this.platform = platform;
1235
- this.activeRoute = inject(ActivatedRoute);
1236
- this.router = inject(Router);
1237
- this.vm = this.activeRoute.snapshot.data['vm'];
1238
- //
1239
- this.store = inject(AXPLayoutThemeService);
1240
- //
1241
- this.searchBarShown = signal(true, ...(ngDevMode ? [{ debugName: "searchBarShown" }] : []));
1242
- this.activeEndSideView = signal('column', ...(ngDevMode ? [{ debugName: "activeEndSideView" }] : []));
1243
- this.categorySearchValue = signal('', ...(ngDevMode ? [{ debugName: "categorySearchValue" }] : []));
1244
- // @ViewChild('grid', { static: true}) grid: AXDataTableComponent;
1245
- this.grid = viewChild('grid', ...(ngDevMode ? [{ debugName: "grid" }] : []));
1246
- this.initializedFromRoute = false;
1247
- this.lastEvaluatedViewName = null;
1248
- this.commandRowItems = computed(() => {
1249
- return this.vm.primaryRowActions().map((c) => {
1250
- return {
1251
- icon: c.icon,
1252
- name: c.name,
1253
- text: translateSync(c.title),
1254
- color: c.color,
1255
- disabled: c.disabled,
1256
- default: c.default,
1257
- };
1258
- });
1259
- }, ...(ngDevMode ? [{ debugName: "commandRowItems" }] : []));
1260
- this.getDropdownRowItems = (rowData) => {
1261
- return Promise.resolve(this.dropdownRowItems(rowData));
1262
- };
1263
- this.getCommandRowItems = () => {
1264
- return this.commandRowItems();
1265
- };
1266
- effect(() => {
1267
- if (this.grid()) {
1268
- this.grid().selectedRows = this.vm.selectedItems();
1269
- }
1270
- });
1271
- //
1272
- this.vm.events$.subscribe(async (e) => {
1273
- const refreshTargetId = e.meta?.refreshTargetId;
1274
- const resetPagination = e.meta?.resetPagination === true;
1275
- if (e.action == 'refresh') {
1276
- if (refreshTargetId) {
1277
- await this.grid()?.refreshItemChildren(refreshTargetId);
1278
- this.updateParentHasChildAfterRefresh(refreshTargetId);
1279
- }
1280
- else {
1281
- this.grid()?.refresh({
1282
- reset: resetPagination,
1283
- });
1284
- }
1285
- }
1286
- });
1287
- // Keep URL query param `view` in sync with current vm view
1288
- effect(() => {
1289
- if (!this.initializedFromRoute) {
1290
- return;
1291
- }
1292
- const currentViewName = this.vm.view().name;
1293
- const urlView = this.activeRoute.snapshot.queryParamMap.get('view');
1294
- if (currentViewName && currentViewName !== urlView) {
1295
- this.router.navigate([], {
1296
- relativeTo: this.activeRoute,
1297
- queryParams: { view: currentViewName },
1298
- queryParamsHandling: 'merge',
1299
- replaceUrl: true,
1300
- });
1301
- }
1302
- });
1303
- // Recompute page actions/title/etc. when view changes (expressions may depend on list.view()).
1304
- effect(() => {
1305
- const currentViewName = this.vm.view().name;
1306
- if (!this.initializedFromRoute) {
1307
- this.lastEvaluatedViewName = currentViewName;
1308
- return;
1309
- }
1310
- if (this.lastEvaluatedViewName !== currentViewName) {
1311
- this.lastEvaluatedViewName = currentViewName;
1312
- this.recompute();
1313
- }
1314
- });
1315
- }
1316
- async ngOnInit() {
1317
- // React to external URL changes (back/forward navigation or deep links)
1318
- this.queryParamSub = this.activeRoute.queryParamMap.subscribe(async (qp) => {
1319
- const viewFromUrl = qp.get('view');
1320
- await this.vm.setView(viewFromUrl);
1321
- });
1322
- }
1323
- async ngAfterViewInit() {
1324
- const viewFromUrl = this.activeRoute.snapshot.queryParamMap.get('view');
1325
- await this.vm.setView(viewFromUrl);
1326
- const resolvedView = this.vm.view().name;
1327
- const currentUrlView = this.activeRoute.snapshot.queryParamMap.get('view');
1328
- if (currentUrlView !== resolvedView) {
1329
- this.router.navigate([], {
1330
- relativeTo: this.activeRoute,
1331
- queryParams: { view: resolvedView },
1332
- queryParamsHandling: 'merge',
1333
- replaceUrl: true,
1334
- });
1335
- }
1336
- this.initializedFromRoute = true;
1337
- }
1338
- onColumnSizeChanged(e) {
1339
- if (e.isUserInteraction && e.type === 'end') {
1340
- this.vm.saveSettings('columnSizes', e.data);
1341
- }
1342
- }
1343
- onPageChanged(e) {
1344
- if (e.isUserInteraction) {
1345
- const pageSizeChanged = e.take != this.vm.dataSource.pageSize;
1346
- if (pageSizeChanged) {
1347
- this.vm.saveSettings('pageSize', e.take);
1348
- }
1349
- }
1350
- }
1351
- onColumnsOrderChanged(e) {
1352
- if (e.isUserInteraction) {
1353
- this.vm.onColumnsOrderChanged(e.data.event);
1354
- }
1355
- }
1356
- async dropdownRowItems(rowData) {
1357
- return (await this.vm.secondaryRowActions(rowData)).map((c) => ({
1358
- icon: c.icon,
1359
- name: c.name,
1360
- text: c.title,
1361
- color: c.color,
1362
- disabled: c.disabled,
1363
- default: c.default,
1364
- divided: c.separated,
1365
- }));
1366
- }
1367
- async handleRowDbClick(e) {
1368
- if (this.grid()?.dataSource.isLoading) {
1369
- return;
1370
- }
1371
- const allItems = [...this.commandRowItems(), ...(await this.dropdownRowItems(e.data))];
1372
- // const defaultAction = allItems.find((c) => (c as any).default) || allItems[0];
1373
- const defaultAction = allItems.find((c) => {
1374
- const commandName = c.name.split('&')[0];
1375
- return (c.default || commandName === 'open-entity') && !c.disabled;
1376
- });
1377
- if (!defaultAction) {
1378
- return;
1379
- }
1380
- const d = {
1381
- component: e.component,
1382
- name: defaultAction.name,
1383
- data: e.data,
1384
- };
1385
- this.handleRowCommandClick(d);
1386
- }
1387
- async handleRowCommandClick(e) {
1388
- if (this.grid()?.dataSource.isLoading) {
1389
- return;
1390
- }
1391
- if (e.setLoading) {
1392
- e.setLoading(true);
1393
- }
1394
- await this.vm.executeCommand(e.name, e.data);
1395
- if (e.setLoading) {
1396
- e.setLoading(false);
1397
- }
1398
- }
1399
- async handleSelectedRowsChange(rows) {
1400
- this.vm.selectedItems.set(rows);
1401
- }
1402
- /**
1403
- * After refreshing a row's children (e.g. when a new child was created), update the parent row's
1404
- * hasChild so the expand icon is shown. The list query sets hasChild from childrenCount only on
1405
- * initial load; refreshItemChildren does not re-fetch the parent, so we patch it here.
1406
- */
1407
- updateParentHasChildAfterRefresh(parentId) {
1408
- const gridRef = this.grid();
1409
- const ds = gridRef?.dataSource;
1410
- if (!ds?.cachedItems?.length) {
1411
- return;
1412
- }
1413
- const key = ds.config?.key ?? 'id';
1414
- const parent = this.findItemById(ds.cachedItems, String(parentId), key);
1415
- if (parent && typeof parent === 'object') {
1416
- parent['hasChild'] = true;
1417
- }
1418
- }
1419
- findItemById(items, id, key) {
1420
- for (const item of items) {
1421
- if (item && typeof item === 'object' && String(item[key]) === id) {
1422
- return item;
1423
- }
1424
- const rec = item;
1425
- const metaChildren = rec?.['__meta__']?.['children'];
1426
- const directChildren = rec?.['children'];
1427
- const childArr = Array.isArray(metaChildren)
1428
- ? metaChildren
1429
- : Array.isArray(directChildren)
1430
- ? directChildren
1431
- : null;
1432
- if (childArr?.length) {
1433
- const found = this.findItemById(childArr, id, key);
1434
- if (found)
1435
- return found;
1436
- }
1437
- }
1438
- return null;
1439
- }
1440
- makeResponsive(value) {
1441
- if (this.platform.is('Mobile') || this.platform.is('SM')) {
1442
- return '';
1443
- }
1444
- else {
1445
- return value;
1446
- }
1447
- }
1448
- toggleSideBar(sideBar) {
1449
- this.toggleEndSide();
1450
- if (sideBar) {
1451
- this.activeEndSideView.set(sideBar);
1452
- }
1453
- }
1454
- toggleSearchBar() {
1455
- this.searchBarShown.update((v) => !v);
1456
- }
1457
- handleResetClick(sideBar) {
1458
- switch (sideBar) {
1459
- case 'filter': {
1460
- this.vm.resetFilters();
1461
- break;
1462
- }
1463
- case 'sort': {
1464
- this.vm.resetSorts();
1465
- break;
1466
- }
1467
- case 'column': {
1468
- this.vm.resetColumns();
1469
- break;
1470
- }
1471
- }
1472
- }
1473
- // protected handleDiscardClick(sideBar: 'filter' | 'sort' | 'column') {
1474
- // switch (sideBar) {
1475
- // case 'filter': {
1476
- // this.vm.discardFilters();
1477
- // break;
1478
- // }
1479
- // case 'sort': {
1480
- // this.vm.resetSorts();
1481
- // break;
1482
- // }
1483
- // case 'column': {
1484
- // this.vm.resetColumns();
1485
- // break;
1486
- // }
1487
- // }
1488
- // }
1489
- handleApplyClick(sideBar) {
1490
- this.vm.applyFilterAndSort();
1491
- this.toggleEndSide();
1492
- }
1493
- ngOnDestroy() {
1494
- this.queryParamSub?.unsubscribe();
1495
- this.vm.destroy();
1496
- }
1497
- toggleCategoryDrawer() {
1498
- this.toggleStartSide();
1499
- }
1500
- getPageTitle() {
1501
- return this.vm.title();
1502
- }
1503
- async getPageDescription() {
1504
- const description = this.vm.description();
1505
- if (description) {
1506
- return this.translateService.translateAsync(description);
1507
- }
1508
- return '';
1509
- }
1510
- getPageBreadcrumbs() {
1511
- return this.vm.beardcrumbs();
1512
- }
1513
- async getPrimaryMenuItems() {
1514
- const actions = await this.vm.getPrimaryActions();
1515
- return actions.map((tr) => ({
1516
- name: tr.name,
1517
- title: tr.title,
1518
- icon: tr.icon,
1519
- color: tr.color,
1520
- disabled: tr.disabled,
1521
- command: {
1522
- name: tr.name,
1523
- options: tr.options,
1524
- metadata: tr.metadata,
1525
- },
1526
- }));
1527
- }
1528
- async getSecondaryMenuItems() {
1529
- return (await this.vm.getSecondaryActions()).map((tr) => ({
1530
- name: tr.name,
1531
- title: tr.title,
1532
- icon: tr.icon,
1533
- color: tr.color,
1534
- disabled: tr.disabled,
1535
- separated: tr.separated,
1536
- command: {
1537
- name: tr.name,
1538
- options: tr.options,
1539
- metadata: tr.metadata,
1540
- },
1541
- }));
1542
- }
1543
- async execute(command) {
1544
- if (command) {
1545
- this.vm.execute(command);
1546
- }
1547
- }
1548
- handleUnselectAll() {
1549
- this.vm.selectedItems.set([]);
1550
- }
1551
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPEntityMasterListViewComponent, deps: [{ token: i1$1.AXPlatform }], target: i0.ɵɵFactoryTarget.Component }); }
1552
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AXPEntityMasterListViewComponent, isStandalone: true, selector: "axp-entity-master-list", providers: [
1553
- {
1554
- provide: AXPPageLayoutBase,
1555
- useExisting: AXPEntityMasterListViewComponent,
1556
- },
1557
- ], viewQueries: [{ propertyName: "grid", first: true, predicate: ["grid"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.entityDef.category) {\n <axp-layout-start-side id=\"axp-entity-category-drawer\">\n <axp-entity-category id=\"axp-entity-category\" class=\"ax-w-80\" [vm]=\"vm\"\n [searchValue]=\"categorySearchValue()\"></axp-entity-category>\n </axp-layout-start-side>\n }\n <axp-page-toolbar id=\"axp-entity-toolbar\">\n <axp-entity-master-toolbar-view [viewModel]=\"vm\"></axp-entity-master-toolbar-view>\n </axp-page-toolbar>\n <axp-page-content class=\"ax-overflow-auto ax-pt-0\">\n <div class=\"ax-flex ax-items-center ax-justify-between ax-gap-1 ax-pb-1 ax-text-muted ax-text-sm\"\n [class.ax-invisible]=\"!grid.selectedRows.length\">\n <span>{{ grid.selectedRows.length }}\n <span>{{ '@general:terms.interface.items-selected' | translate | async }}</span>\n </span>\n <ax-button text=\"@general:terms.interface.unselect-all\" class=\"ax-xs\" (onClick)=\"handleUnselectAll()\"></ax-button>\n </div>\n <ax-data-table id=\"axp-entity-table\" [allowReordering]=\"true\"\n (onColumnsOrderChanged)=\"onColumnsOrderChanged($event)\" #grid [showFooter]=\"false\" class=\"ax-flex-1\"\n [paging]=\"true\" [fetchDataMode]=\"'manual'\" [parentField]=\"vm.parentKey()\"\n [loading]=\"{ enabled: true, animation: true }\" [dataSource]=\"vm.dataSource\"\n (selectedRowsChange)=\"handleSelectedRowsChange($event)\" (onRowDbClick)=\"handleRowDbClick($event)\"\n (onColumnSizeChanged)=\"onColumnSizeChanged($event)\" (onPageChanged)=\"onPageChanged($event)\">\n @if (vm.view().indexCol === true) {\n <ax-index-column\n id=\"axp-table-col-index\"\n [caption]=\"('@general:terms.common.row-number' | translate | async)!\"\n fixed=\"start\"\n [width]=\"'80px'\"\n [padZero]=\"true\"\n ></ax-index-column>\n }\n @if (vm.selectedScopeActionsCount()) {\n <ax-select-column id=\"axp-table-col-select\" fixed=\"start\" [width]=\"'60px'\"></ax-select-column>\n }\n @for (col of vm.columns(); track col.name) {\n @if (col.visible) {\n <axp-widget-column-renderer [attr.id]=\"'axp-table-col-' + col.name\"\n [expandHandler]=\"$index === 0 && vm.parentKey() ? true : false\" [caption]=\"(col.title | translate | async)!\"\n [node]=\"col.node()\" [customWidth]=\"col.width\"></axp-widget-column-renderer>\n }\n }\n @if (getCommandRowItems().length) {\n <ax-command-column id=\"axp-table-col-commands\" fixed=\"end\" [width]=\"getCommandRowItems().length * 70 + 'px'\"\n [items]=\"getCommandRowItems()\" (onItemClick)=\"handleRowCommandClick($event)\"></ax-command-column>\n }\n <ax-dropdown-command-column id=\"axp-table-col-dropdown-commands\" fixed=\"end\" [width]=\"'60px'\"\n [items]=\"getDropdownRowItems\" (onItemClick)=\"handleRowCommandClick($event)\"></ax-dropdown-command-column>\n </ax-data-table>\n </axp-page-content>\n</axp-page-layout>", styles: ["axp-entity-master-list axp-layout-start-side{min-width:20rem!important;border-inline-end-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-entity-master-list axp-layout-header{padding-bottom:.25rem!important}.cdk-drag-preview{border-radius:.375rem;border-width:1px;--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background:rgba(var(--ax-color-on-surface));padding:.5rem;height:max-content!important}.collapsed-search-box{margin-top:0;height:0px;opacity:0}.view-drawer{width:85vw}@media(min-width:768px){.view-drawer{width:45vw}}@media(min-width:1024px){.view-drawer{width:35vw}}@media(min-width:1536px){.view-drawer{width:20vw}}.view-drawer{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lightest-surface),var(--tw-bg-opacity, 1));border-inline-start-width:1px;border-inline-start-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));border-top-width:1px;--tw-border-opacity: 1;border-top-color:rgba(var(--ax-sys-color-primary-600),var(--tw-border-opacity, 1))}.view-drawer ax-header{display:flex;align-items:center;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lighter-surface),var(--tw-bg-opacity, 1));padding:.5rem 1rem}.view-drawer ax-header h2{font-size:1.25rem;line-height:1.75rem;font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lighter-surface),var(--tw-text-opacity, 1))}.view-drawer ax-footer{position:absolute!important;bottom:0!important;width:100%!important;justify-content:flex-start!important;border-top-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1))!important;padding:.5rem 1rem!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: RouterModule }, { 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: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXActionSheetModule }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "ngmodule", type: AXDialogModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "ngmodule", type: AXTooltipModule }, { kind: "ngmodule", type: AXBreadcrumbsModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "ngmodule", type: AXDataTableModule }, { kind: "component", type: i7.AXDataTableComponent, selector: "ax-data-table", inputs: ["dataSource", "selectedRows", "parentField", "hasChildrenField", "rowDetailsTemplate", "title", "rowTemplate", "emptyTemplate", "noDataTemplate", "alternative", "showHeader", "fixedHeader", "showFooter", "fixedFooter", "itemHeight", "allowReordering", "paging", "fetchDataMode", "loading", "focusedRow"], outputs: ["selectedRowsChange", "focusedRowChange", "onRowClick", "onRowDbClick", "onColumnsOrderChanged", "onColumnSizeChanged", "onPageChanged"] }, { kind: "component", type: i7.AXRowIndexColumnComponent, selector: "ax-index-column", inputs: ["width", "caption", "fixed", "footerTemplate", "padZero"] }, { kind: "component", type: i7.AXRowSelectColumnComponent, selector: "ax-select-column", inputs: ["width", "caption", "fixed"] }, { kind: "component", type: i7.AXRowCommandColumnComponent, selector: "ax-command-column", inputs: ["width", "caption", "fixed", "footerTemplate", "items"], outputs: ["onItemClick"] }, { kind: "component", type: i7.AXRowDropdownCommandColumnComponent, selector: "ax-dropdown-command-column", inputs: ["width", "caption", "fixed", "footerTemplate", "emptyStateTemplate", "emptyStateText", "items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i10.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: DragDropModule }, { kind: "ngmodule", type:
1558
- //
1559
- AXPWidgetCoreModule }, { kind: "component", type: i7$1.AXPWidgetColumnRendererComponent, selector: "axp-widget-column-renderer", inputs: ["caption", "customExpandIcon", "customCollapseIcon", "customWidth", "node", "footerTemplate", "expandHandler", "cellTemplate", "headerTemplate"] }, { kind: "ngmodule", type: AXPWidgetsModule }, { kind: "ngmodule", type: AXPAuthModule }, { kind: "component", type:
1560
- //
1561
- AXPEntityMasterToolbarViewComponent, selector: "axp-entity-master-toolbar-view", inputs: ["viewModel"] }, { kind: "component", type:
1562
- //
1563
- AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPEntityCategoryComponent, selector: "axp-entity-category", inputs: ["vm", "searchValue", "selectMode", "selectionBehavior", "dragArea", "dragBehavior", "showIcons", "showChildrenBadge", "expandedIcon", "collapsedIcon", "indentSize", "look", "searchWithChildren"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i10.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1564
- }
1565
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AXPEntityMasterListViewComponent, decorators: [{
1566
- type: Component,
1567
- args: [{ selector: 'axp-entity-master-list', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1568
- CommonModule,
1569
- FormsModule,
1570
- RouterModule,
1571
- AXButtonModule,
1572
- AXDecoratorModule,
1573
- AXBadgeModule,
1574
- AXDropdownModule,
1575
- AXPopoverModule,
1576
- AXFormModule,
1577
- AXActionSheetModule,
1578
- AXDrawerModule,
1579
- AXDialogModule,
1580
- AXLoadingModule,
1581
- AXTabsModule,
1582
- AXTooltipModule,
1583
- AXBreadcrumbsModule,
1584
- AXDropdownButtonModule,
1585
- AXSearchBoxModule,
1586
- AXDataTableModule,
1587
- AXTranslationModule,
1588
- DragDropModule,
1589
- //
1590
- AXPWidgetCoreModule,
1591
- AXPWidgetsModule,
1592
- AXPAuthModule,
1593
- //
1594
- AXPEntityMasterToolbarViewComponent,
1595
- //
1596
- AXPPageLayoutComponent,
1597
- AXPThemeLayoutBlockComponent,
1598
- AXDropdownButtonModule,
1599
- AXPThemeLayoutStartSideComponent,
1600
- AXPEntityCategoryComponent,
1601
- ], providers: [
1602
- {
1603
- provide: AXPPageLayoutBase,
1604
- useExisting: AXPEntityMasterListViewComponent,
1605
- },
1606
- ], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.entityDef.category) {\n <axp-layout-start-side id=\"axp-entity-category-drawer\">\n <axp-entity-category id=\"axp-entity-category\" class=\"ax-w-80\" [vm]=\"vm\"\n [searchValue]=\"categorySearchValue()\"></axp-entity-category>\n </axp-layout-start-side>\n }\n <axp-page-toolbar id=\"axp-entity-toolbar\">\n <axp-entity-master-toolbar-view [viewModel]=\"vm\"></axp-entity-master-toolbar-view>\n </axp-page-toolbar>\n <axp-page-content class=\"ax-overflow-auto ax-pt-0\">\n <div class=\"ax-flex ax-items-center ax-justify-between ax-gap-1 ax-pb-1 ax-text-muted ax-text-sm\"\n [class.ax-invisible]=\"!grid.selectedRows.length\">\n <span>{{ grid.selectedRows.length }}\n <span>{{ '@general:terms.interface.items-selected' | translate | async }}</span>\n </span>\n <ax-button text=\"@general:terms.interface.unselect-all\" class=\"ax-xs\" (onClick)=\"handleUnselectAll()\"></ax-button>\n </div>\n <ax-data-table id=\"axp-entity-table\" [allowReordering]=\"true\"\n (onColumnsOrderChanged)=\"onColumnsOrderChanged($event)\" #grid [showFooter]=\"false\" class=\"ax-flex-1\"\n [paging]=\"true\" [fetchDataMode]=\"'manual'\" [parentField]=\"vm.parentKey()\"\n [loading]=\"{ enabled: true, animation: true }\" [dataSource]=\"vm.dataSource\"\n (selectedRowsChange)=\"handleSelectedRowsChange($event)\" (onRowDbClick)=\"handleRowDbClick($event)\"\n (onColumnSizeChanged)=\"onColumnSizeChanged($event)\" (onPageChanged)=\"onPageChanged($event)\">\n @if (vm.view().indexCol === true) {\n <ax-index-column\n id=\"axp-table-col-index\"\n [caption]=\"('@general:terms.common.row-number' | translate | async)!\"\n fixed=\"start\"\n [width]=\"'80px'\"\n [padZero]=\"true\"\n ></ax-index-column>\n }\n @if (vm.selectedScopeActionsCount()) {\n <ax-select-column id=\"axp-table-col-select\" fixed=\"start\" [width]=\"'60px'\"></ax-select-column>\n }\n @for (col of vm.columns(); track col.name) {\n @if (col.visible) {\n <axp-widget-column-renderer [attr.id]=\"'axp-table-col-' + col.name\"\n [expandHandler]=\"$index === 0 && vm.parentKey() ? true : false\" [caption]=\"(col.title | translate | async)!\"\n [node]=\"col.node()\" [customWidth]=\"col.width\"></axp-widget-column-renderer>\n }\n }\n @if (getCommandRowItems().length) {\n <ax-command-column id=\"axp-table-col-commands\" fixed=\"end\" [width]=\"getCommandRowItems().length * 70 + 'px'\"\n [items]=\"getCommandRowItems()\" (onItemClick)=\"handleRowCommandClick($event)\"></ax-command-column>\n }\n <ax-dropdown-command-column id=\"axp-table-col-dropdown-commands\" fixed=\"end\" [width]=\"'60px'\"\n [items]=\"getDropdownRowItems\" (onItemClick)=\"handleRowCommandClick($event)\"></ax-dropdown-command-column>\n </ax-data-table>\n </axp-page-content>\n</axp-page-layout>", styles: ["axp-entity-master-list axp-layout-start-side{min-width:20rem!important;border-inline-end-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-entity-master-list axp-layout-header{padding-bottom:.25rem!important}.cdk-drag-preview{border-radius:.375rem;border-width:1px;--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background:rgba(var(--ax-color-on-surface));padding:.5rem;height:max-content!important}.collapsed-search-box{margin-top:0;height:0px;opacity:0}.view-drawer{width:85vw}@media(min-width:768px){.view-drawer{width:45vw}}@media(min-width:1024px){.view-drawer{width:35vw}}@media(min-width:1536px){.view-drawer{width:20vw}}.view-drawer{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lightest-surface),var(--tw-bg-opacity, 1));border-inline-start-width:1px;border-inline-start-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));border-top-width:1px;--tw-border-opacity: 1;border-top-color:rgba(var(--ax-sys-color-primary-600),var(--tw-border-opacity, 1))}.view-drawer ax-header{display:flex;align-items:center;border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-lighter-surface),var(--tw-bg-opacity, 1));padding:.5rem 1rem}.view-drawer ax-header h2{font-size:1.25rem;line-height:1.75rem;font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lighter-surface),var(--tw-text-opacity, 1))}.view-drawer ax-footer{position:absolute!important;bottom:0!important;width:100%!important;justify-content:flex-start!important;border-top-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1))!important;padding:.5rem 1rem!important}\n"] }]
1607
- }], ctorParameters: () => [{ type: i1$1.AXPlatform }], propDecorators: { grid: [{ type: i0.ViewChild, args: ['grid', { isSignal: true }] }] } });
1608
-
1609
- export { AXPEntityMasterListViewComponent };
1610
- //# sourceMappingURL=acorex-platform-themes-default-entity-master-list-view.component-CLDoygoI.mjs.map