@acorex/modules 20.7.7 → 20.7.9

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 (68) hide show
  1. package/auth/index.d.ts +16 -2
  2. package/document-management/index.d.ts +33 -10
  3. package/fesm2022/acorex-modules-application-management.mjs +16 -1
  4. package/fesm2022/acorex-modules-application-management.mjs.map +1 -1
  5. package/fesm2022/{acorex-modules-auth-acorex-modules-auth-CyabqFR8.mjs → acorex-modules-auth-acorex-modules-auth-Dg9sg98-.mjs} +32 -13
  6. package/fesm2022/acorex-modules-auth-acorex-modules-auth-Dg9sg98-.mjs.map +1 -0
  7. package/fesm2022/{acorex-modules-auth-app-chooser.component-CizgE3Bb.mjs → acorex-modules-auth-app-chooser.component-Dr8EZ7ZX.mjs} +2 -2
  8. package/fesm2022/{acorex-modules-auth-app-chooser.component-CizgE3Bb.mjs.map → acorex-modules-auth-app-chooser.component-Dr8EZ7ZX.mjs.map} +1 -1
  9. package/fesm2022/{acorex-modules-auth-login.module-DRVqUojm.mjs → acorex-modules-auth-login.module-C7Rt6tLk.mjs} +6 -4
  10. package/fesm2022/acorex-modules-auth-login.module-C7Rt6tLk.mjs.map +1 -0
  11. package/fesm2022/{acorex-modules-auth-master.layout-C1zCbrQh.mjs → acorex-modules-auth-master.layout-CgD5kk65.mjs} +2 -2
  12. package/fesm2022/{acorex-modules-auth-master.layout-C1zCbrQh.mjs.map → acorex-modules-auth-master.layout-CgD5kk65.mjs.map} +1 -1
  13. package/fesm2022/{acorex-modules-auth-oauth-callback.component-DmNV6zL4.mjs → acorex-modules-auth-oauth-callback.component-CuGIGBVO.mjs} +2 -2
  14. package/fesm2022/{acorex-modules-auth-oauth-callback.component-DmNV6zL4.mjs.map → acorex-modules-auth-oauth-callback.component-CuGIGBVO.mjs.map} +1 -1
  15. package/fesm2022/{acorex-modules-auth-password.component-BmTCzp3t.mjs → acorex-modules-auth-password.component-C6TCAUm4.mjs} +2 -2
  16. package/fesm2022/{acorex-modules-auth-password.component-BmTCzp3t.mjs.map → acorex-modules-auth-password.component-C6TCAUm4.mjs.map} +1 -1
  17. package/fesm2022/{acorex-modules-auth-password.component-DSysOOu9.mjs → acorex-modules-auth-password.component-DmohsIxt.mjs} +2 -2
  18. package/fesm2022/{acorex-modules-auth-password.component-DSysOOu9.mjs.map → acorex-modules-auth-password.component-DmohsIxt.mjs.map} +1 -1
  19. package/fesm2022/{acorex-modules-auth-routes-oYfOJjLO.mjs → acorex-modules-auth-routes-C3162bwa.mjs} +2 -2
  20. package/fesm2022/{acorex-modules-auth-routes-oYfOJjLO.mjs.map → acorex-modules-auth-routes-C3162bwa.mjs.map} +1 -1
  21. package/fesm2022/{acorex-modules-auth-tenant-chooser.component-DqrZiwp6.mjs → acorex-modules-auth-tenant-chooser.component-Ce-n3WC9.mjs} +2 -2
  22. package/fesm2022/{acorex-modules-auth-tenant-chooser.component-DqrZiwp6.mjs.map → acorex-modules-auth-tenant-chooser.component-Ce-n3WC9.mjs.map} +1 -1
  23. package/fesm2022/{acorex-modules-auth-two-factor.module-Cc3x-76V.mjs → acorex-modules-auth-two-factor.module-B2nPzX-3.mjs} +2 -2
  24. package/fesm2022/{acorex-modules-auth-two-factor.module-Cc3x-76V.mjs.map → acorex-modules-auth-two-factor.module-B2nPzX-3.mjs.map} +1 -1
  25. package/fesm2022/{acorex-modules-auth-user-sessions.component-CiGEYKgb.mjs → acorex-modules-auth-user-sessions.component-wVKJ2KIm.mjs} +2 -2
  26. package/fesm2022/{acorex-modules-auth-user-sessions.component-CiGEYKgb.mjs.map → acorex-modules-auth-user-sessions.component-wVKJ2KIm.mjs.map} +1 -1
  27. package/fesm2022/acorex-modules-auth.mjs +1 -1
  28. package/fesm2022/acorex-modules-content-management.mjs +3 -3
  29. package/fesm2022/acorex-modules-content-management.mjs.map +1 -1
  30. package/fesm2022/acorex-modules-dashboard-management.mjs +24 -23
  31. package/fesm2022/acorex-modules-dashboard-management.mjs.map +1 -1
  32. package/fesm2022/acorex-modules-data-management.mjs +68 -61
  33. package/fesm2022/acorex-modules-data-management.mjs.map +1 -1
  34. package/fesm2022/{acorex-modules-document-management-drive-choose.component-CJRrn2XH.mjs → acorex-modules-document-management-drive-choose.component-ovwhHP2n.mjs} +4 -4
  35. package/fesm2022/{acorex-modules-document-management-drive-choose.component-CJRrn2XH.mjs.map → acorex-modules-document-management-drive-choose.component-ovwhHP2n.mjs.map} +1 -1
  36. package/fesm2022/acorex-modules-document-management.mjs +363 -231
  37. package/fesm2022/acorex-modules-document-management.mjs.map +1 -1
  38. package/fesm2022/{acorex-modules-help-desk-acorex-modules-help-desk-DGgHWrL0.mjs → acorex-modules-help-desk-acorex-modules-help-desk-CydmGF5Q.mjs} +8 -4
  39. package/fesm2022/{acorex-modules-help-desk-acorex-modules-help-desk-DGgHWrL0.mjs.map → acorex-modules-help-desk-acorex-modules-help-desk-CydmGF5Q.mjs.map} +1 -1
  40. package/fesm2022/{acorex-modules-help-desk-capture-screen.component-CAknGKEK.mjs → acorex-modules-help-desk-capture-screen.component-Bsq1FJId.mjs} +2 -2
  41. package/fesm2022/{acorex-modules-help-desk-capture-screen.component-CAknGKEK.mjs.map → acorex-modules-help-desk-capture-screen.component-Bsq1FJId.mjs.map} +1 -1
  42. package/fesm2022/acorex-modules-help-desk.mjs +1 -1
  43. package/fesm2022/acorex-modules-human-capital-management.mjs +41 -26
  44. package/fesm2022/acorex-modules-human-capital-management.mjs.map +1 -1
  45. package/fesm2022/{acorex-modules-organization-management-org-chart.page-C85uluWf.mjs → acorex-modules-organization-management-org-chart.page-Ca_aJDbu.mjs} +19 -13
  46. package/fesm2022/acorex-modules-organization-management-org-chart.page-Ca_aJDbu.mjs.map +1 -0
  47. package/fesm2022/acorex-modules-organization-management.mjs +2 -2
  48. package/fesm2022/{acorex-modules-person-management-person.entity-BtaGNj8n.mjs → acorex-modules-person-management-person.entity-CaEVw1mL.mjs} +2 -2
  49. package/fesm2022/acorex-modules-person-management-person.entity-CaEVw1mL.mjs.map +1 -0
  50. package/fesm2022/acorex-modules-person-management.mjs +1 -1
  51. package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-DEx13GSy.mjs → acorex-modules-platform-management-acorex-modules-platform-management-DVkP3JKC.mjs} +1188 -341
  52. package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-DVkP3JKC.mjs.map +1 -0
  53. package/fesm2022/acorex-modules-platform-management-menu-list.component-C_mdsuRc.mjs +519 -0
  54. package/fesm2022/acorex-modules-platform-management-menu-list.component-C_mdsuRc.mjs.map +1 -0
  55. package/fesm2022/acorex-modules-platform-management.mjs +1 -1
  56. package/fesm2022/acorex-modules-report-management.mjs +27 -6
  57. package/fesm2022/acorex-modules-report-management.mjs.map +1 -1
  58. package/fesm2022/acorex-modules-workflow-management.mjs +15 -9
  59. package/fesm2022/acorex-modules-workflow-management.mjs.map +1 -1
  60. package/package.json +2 -2
  61. package/platform-management/index.d.ts +12 -1
  62. package/fesm2022/acorex-modules-auth-acorex-modules-auth-CyabqFR8.mjs.map +0 -1
  63. package/fesm2022/acorex-modules-auth-login.module-DRVqUojm.mjs.map +0 -1
  64. package/fesm2022/acorex-modules-organization-management-org-chart.page-C85uluWf.mjs.map +0 -1
  65. package/fesm2022/acorex-modules-person-management-person.entity-BtaGNj8n.mjs.map +0 -1
  66. package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-DEx13GSy.mjs.map +0 -1
  67. package/fesm2022/acorex-modules-platform-management-menu-list.component-DLg61Nf8.mjs +0 -853
  68. package/fesm2022/acorex-modules-platform-management-menu-list.component-DLg61Nf8.mjs.map +0 -1
@@ -1,853 +0,0 @@
1
- import * as i4 from '@acorex/components/badge';
2
- import { AXBadgeModule } from '@acorex/components/badge';
3
- import * as i1 from '@acorex/components/button';
4
- import { AXButtonModule } from '@acorex/components/button';
5
- import * as i2 from '@acorex/components/decorators';
6
- import { AXDecoratorModule } from '@acorex/components/decorators';
7
- import { AXDialogService } from '@acorex/components/dialog';
8
- import * as i3 from '@acorex/components/dropdown';
9
- import { AXDropdownModule } from '@acorex/components/dropdown';
10
- import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
11
- import { AXToastService } from '@acorex/components/toast';
12
- import { AXTreeViewComponent } from '@acorex/components/tree-view';
13
- import * as i6 from '@acorex/core/translation';
14
- import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
15
- import { AXPPlatformScope } from '@acorex/platform/core';
16
- import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
17
- import { AXPThemeLayoutBlockComponent, AXPStateMessageComponent } from '@acorex/platform/layout/components';
18
- import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
19
- import * as i5 from '@angular/common';
20
- import { CommonModule } from '@angular/common';
21
- import * as i0 from '@angular/core';
22
- import { inject, Injectable, viewChild, signal, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
23
- import { ActivatedRoute } from '@angular/router';
24
- import { Subject, takeUntil } from 'rxjs';
25
- import { AXPSettingsService, AXPMenuProviderService } from '@acorex/platform/common';
26
- import { cloneDeep } from 'lodash-es';
27
- import { A as AXP_MENU_CUSTOMIZATION_KEY, a as AXP_MENU_CUSTOMIZATION_DEFAULT } from './acorex-modules-platform-management-acorex-modules-platform-management-DEx13GSy.mjs';
28
-
29
- //#region ---- Menu Management Service ----
30
- /**
31
- * Constants for priority calculation
32
- */
33
- const PRIORITY_BASE_ROOT = 0;
34
- const PRIORITY_BASE_NESTED = 1000;
35
- const PRIORITY_STEP = 10;
36
- class AXPMenuManagementService {
37
- constructor() {
38
- //#region ---- Dependencies ----
39
- this.settingsService = inject(AXPSettingsService);
40
- this.menuProviderService = inject(AXPMenuProviderService);
41
- }
42
- //#endregion
43
- //#region ---- Public Methods ----
44
- /**
45
- * Get menu tree as AXTreeViewNode[] for ax-tree-view component
46
- */
47
- async getMenuTree(scope) {
48
- // Get RAW menu items WITHOUT middleware (for management purposes)
49
- const baseItems = await this.menuProviderService.rawItems();
50
- // Load customizations for the given scope
51
- const customization = await this.loadCustomization(scope);
52
- // Merge custom items with base items
53
- const allItems = [...baseItems, ...customization.customItems];
54
- // Apply parent overrides to restructure items BEFORE building tree
55
- const restructuredItems = this.applyParentOverrides(allItems, customization);
56
- // Convert to tree nodes with metadata
57
- return this.convertToTreeNodes(restructuredItems, customization);
58
- }
59
- /**
60
- * Sync tree changes back to customization
61
- * Called automatically when tree structure changes via drag-drop
62
- */
63
- async syncTreeChanges(scope, treeNodes) {
64
- const customization = await this.loadCustomization(scope);
65
- // Extract and update priorities and parent relationships from tree structure
66
- this.updateCustomizationFromTree(treeNodes, customization);
67
- await this.saveCustomization(scope, customization);
68
- }
69
- /**
70
- * Load menu customization for a specific scope
71
- */
72
- async loadCustomization(scope) {
73
- try {
74
- const scopedSettings = this.settingsService.scope(scope);
75
- const saved = await scopedSettings.get(AXP_MENU_CUSTOMIZATION_KEY);
76
- if (saved && saved.version) {
77
- return saved;
78
- }
79
- return cloneDeep(AXP_MENU_CUSTOMIZATION_DEFAULT);
80
- }
81
- catch (error) {
82
- console.warn('Failed to load menu customization, using defaults', error);
83
- return cloneDeep(AXP_MENU_CUSTOMIZATION_DEFAULT);
84
- }
85
- }
86
- /**
87
- * Save menu customization for a specific scope
88
- */
89
- async saveCustomization(scope, customization) {
90
- const scopedSettings = this.settingsService.scope(scope);
91
- await scopedSettings.set(AXP_MENU_CUSTOMIZATION_KEY, customization);
92
- // Clear menu cache to force reload
93
- this.menuProviderService.clearCache();
94
- }
95
- /**
96
- * Hide a menu item
97
- */
98
- async hideMenuItem(scope, menuName) {
99
- this.validateMenuName(menuName, 'hide');
100
- const customization = await this.loadCustomization(scope);
101
- this.ensureOverrideExists(customization, menuName);
102
- customization.overrides[menuName].hidden = true;
103
- await this.saveCustomization(scope, customization);
104
- }
105
- /**
106
- * Show a menu item
107
- */
108
- async showMenuItem(scope, menuName) {
109
- this.validateMenuName(menuName, 'show');
110
- const customization = await this.loadCustomization(scope);
111
- if (customization.overrides[menuName]) {
112
- delete customization.overrides[menuName].hidden;
113
- this.cleanupEmptyOverride(customization, menuName);
114
- }
115
- await this.saveCustomization(scope, customization);
116
- }
117
- /**
118
- * Update menu item priority
119
- */
120
- async updateMenuPriority(scope, menuName, priority) {
121
- this.validateMenuName(menuName, 'update priority for');
122
- const customization = await this.loadCustomization(scope);
123
- this.ensureOverrideExists(customization, menuName);
124
- customization.overrides[menuName].priority = priority;
125
- await this.saveCustomization(scope, customization);
126
- }
127
- /**
128
- * Update menu item properties
129
- */
130
- async updateMenuProperties(scope, menuName, properties) {
131
- this.validateMenuName(menuName, 'update properties for');
132
- const customization = await this.loadCustomization(scope);
133
- this.ensureOverrideExists(customization, menuName);
134
- customization.overrides[menuName].properties = {
135
- ...customization.overrides[menuName].properties,
136
- ...properties,
137
- };
138
- await this.saveCustomization(scope, customization);
139
- }
140
- /**
141
- * Add custom menu item
142
- */
143
- async addCustomMenuItem(scope, menuItem, parent) {
144
- const customization = await this.loadCustomization(scope);
145
- // Generate unique name if not provided
146
- if (!menuItem.name) {
147
- menuItem.name = `custom-menu-${Date.now()}`;
148
- }
149
- customization.customItems.push(menuItem);
150
- await this.saveCustomization(scope, customization);
151
- }
152
- /**
153
- * Update custom menu item
154
- */
155
- async updateCustomMenuItem(scope, menuName, menuItem) {
156
- this.validateMenuName(menuName, 'update');
157
- const customization = await this.loadCustomization(scope);
158
- const index = customization.customItems.findIndex((item) => item.name === menuName);
159
- if (index === -1) {
160
- throw new Error(`Custom menu item '${menuName}' not found`);
161
- }
162
- customization.customItems[index] = menuItem;
163
- await this.saveCustomization(scope, customization);
164
- }
165
- /**
166
- * Delete custom menu item
167
- */
168
- async deleteCustomMenuItem(scope, menuName) {
169
- this.validateMenuName(menuName, 'delete');
170
- const customization = await this.loadCustomization(scope);
171
- const initialLength = customization.customItems.length;
172
- customization.customItems = customization.customItems.filter((item) => item.name !== menuName);
173
- if (customization.customItems.length === initialLength) {
174
- throw new Error(`Custom menu item '${menuName}' not found`);
175
- }
176
- await this.saveCustomization(scope, customization);
177
- }
178
- /**
179
- * Reset all customizations for a scope
180
- */
181
- async resetCustomizations(scope) {
182
- await this.saveCustomization(scope, cloneDeep(AXP_MENU_CUSTOMIZATION_DEFAULT));
183
- }
184
- //#endregion
185
- //#region ---- Private Methods ----
186
- /**
187
- * Apply parent overrides from customization to restructure menu items
188
- * This ensures the tree reflects saved parent changes (moves)
189
- */
190
- applyParentOverrides(items, customization) {
191
- // First, flatten all items into a map for easy lookup
192
- const itemMap = this.flattenMenuItems(items);
193
- // Build new structure based on effective parent relationships
194
- const rootItems = [];
195
- const childrenMap = new Map();
196
- for (const [itemName, item] of itemMap.entries()) {
197
- const override = customization.overrides[itemName];
198
- // Determine effective parent (override takes precedence)
199
- let effectiveParent;
200
- if (override?.parentName !== undefined) {
201
- // parentName is explicitly set (could be null for root, or a parent name)
202
- effectiveParent = override.parentName;
203
- }
204
- else {
205
- // No override - find original parent by searching original structure
206
- effectiveParent = this.findOriginalParent(items, itemName);
207
- }
208
- if (effectiveParent === null || effectiveParent === undefined) {
209
- // Root level item
210
- rootItems.push(item);
211
- }
212
- else {
213
- // Child item - add to parent's children
214
- if (!childrenMap.has(effectiveParent)) {
215
- childrenMap.set(effectiveParent, []);
216
- }
217
- childrenMap.get(effectiveParent).push(item);
218
- }
219
- }
220
- // Attach children to their parents recursively
221
- const attachChildren = (item) => {
222
- if (item.name && childrenMap.has(item.name)) {
223
- item.children = childrenMap.get(item.name);
224
- item.children?.forEach(attachChildren);
225
- }
226
- };
227
- rootItems.forEach(attachChildren);
228
- return rootItems;
229
- }
230
- /**
231
- * Find the original parent name of an item in the original structure
232
- * Returns undefined for root items, string for items with parents, null for not found
233
- */
234
- findOriginalParent(items, targetName, currentParent) {
235
- for (const item of items) {
236
- if (item.name === targetName) {
237
- return currentParent; // undefined if root, string if has parent
238
- }
239
- if (item.children) {
240
- const found = this.findOriginalParent(item.children, targetName, item.name);
241
- if (found !== null) {
242
- // Found in children (could be undefined for root of subtree, or string for nested item)
243
- return found;
244
- }
245
- // found === null means not found in this subtree, continue searching
246
- }
247
- }
248
- return null; // Not found in this level or any children
249
- }
250
- /**
251
- * Convert menu items to AXTreeNode[] with metadata
252
- */
253
- convertToTreeNodes(items, customization, parentName) {
254
- const nodes = items.map((item) => {
255
- const itemName = item.name;
256
- const override = itemName ? customization.overrides[itemName] : undefined;
257
- const isCustom = itemName ? customization.customItems.some((ci) => ci.name === itemName) : false;
258
- // Create metadata
259
- const metadata = {
260
- isBuiltIn: !isCustom,
261
- isCustom,
262
- isHidden: override?.hidden || false,
263
- originalPriority: item.priority,
264
- originalParentName: parentName,
265
- };
266
- // Apply priority override
267
- const effectivePriority = override?.priority !== undefined ? override.priority : item.priority;
268
- const itemWithPriority = { ...item, priority: effectivePriority };
269
- // Create tree node data
270
- const nodeData = {
271
- menuItem: itemWithPriority,
272
- metadata,
273
- };
274
- // Create tree node
275
- const treeNode = {
276
- id: itemName || item.path || this.generateNodeId(),
277
- title: item.text || item.path || 'Unnamed',
278
- icon: item.icon,
279
- expanded: false,
280
- selected: false,
281
- ['children']: item.children ? this.convertToTreeNodes(item.children, customization, itemName) : undefined,
282
- childrenCount: item.children?.length,
283
- data: nodeData,
284
- };
285
- return treeNode;
286
- });
287
- // Sort by priority
288
- nodes.sort((a, b) => {
289
- const aPriority = a['data']?.menuItem.priority ?? 0;
290
- const bPriority = b['data']?.menuItem.priority ?? 0;
291
- return aPriority - bPriority;
292
- });
293
- return nodes;
294
- }
295
- /**
296
- * Update customization from tree structure
297
- * Extracts priorities and parent relationships from tree nodes
298
- */
299
- updateCustomizationFromTree(treeNodes, customization, parentName) {
300
- // Calculate base priority for this level to maintain relative ordering
301
- const basePriority = parentName ? PRIORITY_BASE_NESTED : PRIORITY_BASE_ROOT;
302
- const priorityStep = PRIORITY_STEP;
303
- treeNodes.forEach((node, index) => {
304
- const nodeData = node['data'] || null;
305
- const menuItem = nodeData?.menuItem;
306
- if (menuItem?.name) {
307
- this.ensureOverrideExists(customization, menuItem.name);
308
- // Calculate new priority based on current position
309
- const newPriority = basePriority + index * priorityStep;
310
- // Get current effective priority (considering existing overrides)
311
- const currentEffectivePriority = customization.overrides[menuItem.name]?.priority ?? nodeData.metadata.originalPriority ?? 0;
312
- // Always update priority to reflect current position in tree
313
- // This ensures reordering works correctly even after multiple moves
314
- if (newPriority !== currentEffectivePriority) {
315
- customization.overrides[menuItem.name].priority = newPriority;
316
- }
317
- // Determine current effective parent (considering existing overrides)
318
- const currentEffectiveParent = customization.overrides[menuItem.name]?.parentName ?? nodeData.metadata.originalParentName;
319
- // Update parent relationship if it changed from current effective parent
320
- if (parentName !== currentEffectiveParent) {
321
- if (parentName) {
322
- customization.overrides[menuItem.name].parentName = parentName;
323
- }
324
- else {
325
- // Moving to root - set to null (not undefined) so middleware will process it
326
- // moveTo(null) moves the item to root level
327
- customization.overrides[menuItem.name].parentName = null;
328
- }
329
- }
330
- // Clean up empty overrides
331
- this.cleanupEmptyOverride(customization, menuItem.name);
332
- // Recursively process children
333
- const nodeChildren = node['children'];
334
- if (nodeChildren && nodeChildren.length > 0) {
335
- this.updateCustomizationFromTree(nodeChildren, customization, menuItem.name);
336
- }
337
- }
338
- });
339
- }
340
- /**
341
- * Validate menu name before operations
342
- */
343
- validateMenuName(menuName, operation) {
344
- if (!menuName) {
345
- throw new Error(`Menu item must have a name to be ${operation}`);
346
- }
347
- }
348
- /**
349
- * Ensure override object exists for a menu item
350
- */
351
- ensureOverrideExists(customization, menuName) {
352
- if (!customization.overrides[menuName]) {
353
- customization.overrides[menuName] = {};
354
- }
355
- }
356
- /**
357
- * Clean up empty override objects
358
- */
359
- cleanupEmptyOverride(customization, menuName) {
360
- if (Object.keys(customization.overrides[menuName] || {}).length === 0) {
361
- delete customization.overrides[menuName];
362
- }
363
- }
364
- /**
365
- * Flatten menu items recursively into a map
366
- */
367
- flattenMenuItems(items) {
368
- const itemMap = new Map();
369
- const flatten = (itemList) => {
370
- for (const item of itemList) {
371
- if (item.name) {
372
- // Clone item without children to rebuild structure
373
- itemMap.set(item.name, { ...item, children: undefined });
374
- }
375
- if (item.children) {
376
- flatten(item.children);
377
- }
378
- }
379
- };
380
- flatten(items);
381
- return itemMap;
382
- }
383
- /**
384
- * Generate unique ID for tree nodes
385
- */
386
- generateNodeId() {
387
- return `node-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
388
- }
389
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPMenuManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
390
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPMenuManagementService, providedIn: 'root' }); }
391
- }
392
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPMenuManagementService, decorators: [{
393
- type: Injectable,
394
- args: [{ providedIn: 'root' }]
395
- }] });
396
-
397
- //#region ---- Menu List Component ----
398
- class AXMMenuListComponent extends AXPPageLayoutBaseComponent {
399
- constructor() {
400
- super(...arguments);
401
- //#region ---- Dependencies ----
402
- this.menuManagementService = inject(AXPMenuManagementService);
403
- this.layoutBuilder = inject(AXPLayoutBuilderService);
404
- this.dialogService = inject(AXDialogService);
405
- this.toastService = inject(AXToastService);
406
- this.translationService = inject(AXTranslationService);
407
- this.route = inject(ActivatedRoute);
408
- //#endregion
409
- //#region ---- Component State ----
410
- this.tree = viewChild(AXTreeViewComponent, ...(ngDevMode ? [{ debugName: "tree" }] : []));
411
- this.treeNodes = signal([], ...(ngDevMode ? [{ debugName: "treeNodes" }] : []));
412
- this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
413
- this.error = signal('', ...(ngDevMode ? [{ debugName: "error" }] : []));
414
- this.currentScope = signal(AXPPlatformScope.User, ...(ngDevMode ? [{ debugName: "currentScope" }] : []));
415
- this.isSyncing = false; // Prevent concurrent sync operations
416
- this.destroy$ = new Subject(); // For subscription cleanup
417
- }
418
- //#endregion
419
- //#region ---- Lifecycle ----
420
- async ngOnInit() {
421
- await super.ngOnInit();
422
- // Get scope from route (with memory leak prevention)
423
- this.route.params.pipe(takeUntil(this.destroy$)).subscribe(async (params) => {
424
- const scope = params['scope'];
425
- if (scope) {
426
- this.currentScope.set(scope);
427
- await this.loadMenuItems();
428
- this.recompute(); // Update page header after loading
429
- }
430
- });
431
- }
432
- ngOnDestroy() {
433
- this.destroy$.next();
434
- this.destroy$.complete();
435
- }
436
- //#endregion
437
- //#region ---- Event Handlers ----
438
- /**
439
- * Handle before drop validation
440
- */
441
- async handleBeforeDrop(e) {
442
- const targetParent = e.currentParent?.['data'] || null;
443
- // Prevent dropping into items with paths (leaf nodes)
444
- if (targetParent?.menuItem?.path) {
445
- e.canceled = true;
446
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.move');
447
- this.toastService.warning(message);
448
- return;
449
- }
450
- // Note: Circular reference validation is handled by the tree component itself
451
- // Additional validation can be added here if needed based on business rules
452
- }
453
- /**
454
- * Handle after drop event to sync changes
455
- */
456
- async handleAfterDrop() {
457
- await this.syncTreeChanges();
458
- }
459
- //#endregion
460
- //#region ---- Data Loading ----
461
- /**
462
- * Load menu tree for current scope
463
- */
464
- async loadMenuItems() {
465
- try {
466
- this.isLoading.set(true);
467
- this.error.set('');
468
- const treeNodes = await this.menuManagementService.getMenuTree(this.currentScope());
469
- this.treeNodes.set(treeNodes);
470
- this.recompute();
471
- }
472
- catch (error) {
473
- this.error.set(error instanceof Error ? error.message : 'Failed to load menu items');
474
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.load');
475
- this.toastService.danger(message);
476
- }
477
- finally {
478
- this.isLoading.set(false);
479
- }
480
- }
481
- /**
482
- * Sync tree changes to backend
483
- */
484
- async syncTreeChanges() {
485
- // Prevent concurrent sync operations
486
- if (this.isSyncing) {
487
- return;
488
- }
489
- try {
490
- this.isSyncing = true;
491
- const nodes = this.treeNodes();
492
- const scope = this.currentScope();
493
- if (nodes.length === 0) {
494
- return;
495
- }
496
- await this.menuManagementService.syncTreeChanges(scope, nodes);
497
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.success.reorder');
498
- this.toastService.success(message);
499
- }
500
- catch (error) {
501
- console.error('Failed to sync tree changes:', error);
502
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.sync');
503
- this.toastService.danger(message);
504
- }
505
- finally {
506
- this.isSyncing = false;
507
- }
508
- }
509
- //#endregion
510
- //#region ---- Page Layout Interface ----
511
- /**
512
- * Get page title
513
- */
514
- async getPageTitle() {
515
- const scopeName = this.currentScope();
516
- const scopeKey = scopeName === AXPPlatformScope.User ? 'user' : 'tenant';
517
- return this.translationService.translateAsync(`@platform-management:menu-management.menus.${scopeKey}.title`);
518
- }
519
- /**
520
- * Get page description
521
- */
522
- async getPageDescription() {
523
- return this.translationService.translateAsync('@platform-management:menu-management.components.menu-list.description');
524
- }
525
- /**
526
- * Get primary menu items (actions)
527
- */
528
- async getPrimaryMenuItems() {
529
- return [
530
- {
531
- title: await this.translationService.translateAsync('@platform-management:menu-management.actions.add-root.title'),
532
- icon: 'fa-light fa-plus',
533
- color: 'primary',
534
- command: { name: 'add-root' },
535
- },
536
- ];
537
- }
538
- /**
539
- * Get secondary menu items
540
- */
541
- async getSecondaryMenuItems() {
542
- return [
543
- {
544
- title: await this.translationService.translateAsync('@platform-management:menu-management.actions.collapse.title'),
545
- icon: 'fa-light fa-minus-square',
546
- command: { name: 'collapse' },
547
- },
548
- {
549
- title: await this.translationService.translateAsync('@platform-management:menu-management.actions.expand.title'),
550
- icon: 'fa-light fa-plus-square',
551
- command: { name: 'expand' },
552
- break: true,
553
- },
554
- {
555
- title: await this.translationService.translateAsync('@platform-management:menu-management.actions.reset.title'),
556
- icon: 'fa-light fa-rotate-left',
557
- color: 'danger',
558
- command: { name: 'reset' },
559
- },
560
- ];
561
- }
562
- /**
563
- * Execute commands from page actions
564
- */
565
- async execute(command) {
566
- switch (command.name) {
567
- case 'add-root':
568
- await this.addRootMenuItem();
569
- break;
570
- case 'collapse':
571
- this.tree()?.collapseAll();
572
- break;
573
- case 'expand':
574
- this.tree()?.expandAll();
575
- break;
576
- case 'reset':
577
- await this.resetCustomizations();
578
- break;
579
- }
580
- }
581
- //#endregion
582
- //#region ---- Action Handlers ----
583
- /**
584
- * Handle menu item action
585
- */
586
- async onAction(action, nodeData) {
587
- switch (action) {
588
- case 'show':
589
- await this.showMenuItem(nodeData);
590
- break;
591
- case 'hide':
592
- await this.hideMenuItem(nodeData);
593
- break;
594
- case 'edit':
595
- await this.editMenuItem(nodeData);
596
- break;
597
- case 'delete':
598
- await this.deleteMenuItem(nodeData);
599
- break;
600
- case 'add-child':
601
- await this.addChildMenuItem(nodeData);
602
- break;
603
- }
604
- }
605
- /**
606
- * Add new root menu item
607
- */
608
- async addRootMenuItem() {
609
- await this.showMenuItemDialog(null, null);
610
- }
611
- /**
612
- * Add new child menu item
613
- */
614
- async addChildMenuItem(parentNodeData) {
615
- await this.showMenuItemDialog(null, parentNodeData.menuItem.name);
616
- }
617
- /**
618
- * Reset customizations
619
- */
620
- async resetCustomizations() {
621
- const title = await this.translationService.translateAsync('@platform-management:menu-management.actions.reset.confirm.title');
622
- const message = await this.translationService.translateAsync('@platform-management:menu-management.actions.reset.confirm.message');
623
- const confirmed = await this.dialogService.confirm(title, message);
624
- if (!confirmed)
625
- return;
626
- try {
627
- // Reset customizations for current scope
628
- await this.menuManagementService.resetCustomizations(this.currentScope());
629
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.success.reset');
630
- this.toastService.success(message);
631
- }
632
- catch (error) {
633
- console.error('Failed to reset customizations:', error);
634
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.reset');
635
- this.toastService.danger(message);
636
- }
637
- finally {
638
- // Reload anyway to show current state
639
- await this.loadMenuItems();
640
- }
641
- }
642
- //#endregion
643
- //#region ---- Menu Item Actions ----
644
- /**
645
- * Show menu item
646
- */
647
- async showMenuItem(nodeData) {
648
- await this.executeMenuAction(() => this.menuManagementService.showMenuItem(this.currentScope(), nodeData.menuItem.name), '@platform-management:menu-management.messages.success.show', '@platform-management:menu-management.messages.error.show');
649
- }
650
- /**
651
- * Hide menu item
652
- */
653
- async hideMenuItem(nodeData) {
654
- await this.executeMenuAction(() => this.menuManagementService.hideMenuItem(this.currentScope(), nodeData.menuItem.name), '@platform-management:menu-management.messages.success.hide', '@platform-management:menu-management.messages.error.hide');
655
- }
656
- /**
657
- * Edit menu item
658
- */
659
- async editMenuItem(nodeData) {
660
- await this.showMenuItemDialog(nodeData);
661
- }
662
- /**
663
- * Delete custom menu item
664
- */
665
- async deleteMenuItem(nodeData) {
666
- const title = await this.translationService.translateAsync('@general:actions.delete.title');
667
- const message = await this.translationService.translateAsync('@platform-management:menu-management.actions.delete.confirm.message');
668
- const confirmed = await this.dialogService.confirm(title, message);
669
- if (!confirmed)
670
- return;
671
- try {
672
- const item = nodeData.menuItem;
673
- if (!item.name)
674
- return;
675
- await this.menuManagementService.deleteCustomMenuItem(this.currentScope(), item.name);
676
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.success.delete');
677
- this.toastService.success(message);
678
- await this.loadMenuItems();
679
- }
680
- catch (error) {
681
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.delete');
682
- this.toastService.danger(message);
683
- }
684
- }
685
- //#endregion
686
- //#region ---- Dialog Helpers ----
687
- /**
688
- * Show menu item dialog (add/edit)
689
- */
690
- async showMenuItemDialog(nodeData, parentName = null) {
691
- const item = nodeData?.menuItem;
692
- const isEdit = !!item;
693
- const title = isEdit
694
- ? '@platform-management:menu-management.components.edit-dialog.title'
695
- : '@platform-management:menu-management.components.add-dialog.title';
696
- const context = {
697
- name: item?.name || '',
698
- text: item?.text || '',
699
- type: item?.type || 'menu',
700
- icon: item?.icon || '',
701
- path: item?.path || '',
702
- priority: item?.priority || 0,
703
- description: item?.description || '',
704
- };
705
- const dialogRef = await this.layoutBuilder
706
- .create()
707
- .dialog((dialog) => {
708
- dialog
709
- .setTitle(title)
710
- .setContext(context)
711
- .content((flex) => {
712
- flex
713
- .setDirection('column')
714
- .formField('@platform-management:menu-management.fields.name', (field) => {
715
- field.path('name');
716
- field.textBox({
717
- placeholder: '@platform-management:menu-management.fields.name',
718
- validations: [{ rule: 'required' }],
719
- disabled: isEdit && nodeData?.metadata?.isBuiltIn,
720
- });
721
- })
722
- .formField('@platform-management:menu-management.fields.text', (field) => {
723
- field.path('text');
724
- field.textBox({
725
- placeholder: '@platform-management:menu-management.fields.text',
726
- validations: [{ rule: 'required' }],
727
- });
728
- })
729
- .formField('@platform-management:menu-management.fields.icon', (field) => {
730
- field.path('icon');
731
- field.customWidget('icon-chooser', {});
732
- })
733
- .formField('@platform-management:menu-management.fields.path', (field) => {
734
- field.path('path');
735
- field.textBox({
736
- placeholder: '@platform-management:menu-management.fields.path',
737
- disabled: isEdit && nodeData?.metadata?.isBuiltIn,
738
- });
739
- })
740
- .formField('@platform-management:menu-management.fields.priority', (field) => {
741
- field.path('priority');
742
- field.numberBox({
743
- placeholder: '@platform-management:menu-management.fields.priority',
744
- step: 10,
745
- });
746
- })
747
- .formField('@platform-management:menu-management.fields.description', (field) => {
748
- field.path('description');
749
- field.largeTextBox({
750
- placeholder: '@platform-management:menu-management.fields.description',
751
- rows: 3,
752
- });
753
- });
754
- })
755
- .setActions((actions) => {
756
- actions.cancel('@general:actions.cancel.title').submit('@general:actions.save.title');
757
- });
758
- })
759
- .show();
760
- const action = dialogRef.action();
761
- if (action === 'cancel') {
762
- dialogRef.close();
763
- return;
764
- }
765
- const formData = dialogRef.context();
766
- try {
767
- if (isEdit && item?.name) {
768
- // Update existing item
769
- if (nodeData?.metadata?.isCustom) {
770
- await this.menuManagementService.updateCustomMenuItem(this.currentScope(), item.name, formData);
771
- }
772
- else {
773
- await this.menuManagementService.updateMenuProperties(this.currentScope(), item.name, formData);
774
- }
775
- }
776
- else {
777
- // Add new custom item
778
- const newItem = {
779
- name: formData.name,
780
- text: formData.text,
781
- icon: formData.icon,
782
- path: formData.path,
783
- priority: formData.priority,
784
- description: formData.description,
785
- };
786
- // If parent is specified, add as child
787
- if (parentName) {
788
- // Add custom item as child of parent
789
- await this.menuManagementService.addCustomMenuItem(this.currentScope(), newItem, parentName);
790
- }
791
- else {
792
- // Add as root level item
793
- await this.menuManagementService.addCustomMenuItem(this.currentScope(), newItem, null);
794
- }
795
- }
796
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.success.save');
797
- this.toastService.success(message);
798
- await this.loadMenuItems();
799
- dialogRef.close();
800
- }
801
- catch (error) {
802
- const message = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.save');
803
- this.toastService.danger(message);
804
- }
805
- }
806
- /**
807
- * Execute a menu action with common error handling
808
- */
809
- async executeMenuAction(action, successMessageKey, errorMessageKey) {
810
- try {
811
- await action();
812
- const message = await this.translationService.translateAsync(successMessageKey);
813
- this.toastService.success(message);
814
- await this.loadMenuItems();
815
- }
816
- catch (error) {
817
- console.error('Menu action failed:', error);
818
- const message = await this.translationService.translateAsync(errorMessageKey);
819
- this.toastService.danger(message);
820
- }
821
- }
822
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXMMenuListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
823
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXMMenuListComponent, isStandalone: true, selector: "axm-menu-list", host: { classAttribute: "axm-menu-list-page" }, providers: [
824
- {
825
- provide: AXPPageLayoutBase,
826
- useExisting: AXMMenuListComponent,
827
- },
828
- ], viewQueries: [{ propertyName: "tree", first: true, predicate: AXTreeViewComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout>\n <axp-page-content>\n @if (isLoading()) {\n <!-- Loading State -->\n <axp-state-message\n mode=\"loading\"\n icon=\"fa-light fa-spinner-third fa-spin\"\n [title]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.loading.title' | translate | async)!\n \"\n [description]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.loading.description'\n | translate\n | async)!\n \"\n />\n } @else if (error()) {\n <!-- Error State -->\n <axp-state-message\n mode=\"error\"\n icon=\"fa-light fa-circle-exclamation\"\n [title]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.error.title' | translate | async)!\n \"\n [description]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.error.description'\n | translate\n | async)!\n \"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@general:actions.retry.title' | translate | async\"\n [look]=\"'outline'\"\n [color]=\"'primary'\"\n (onClick)=\"loadMenuItems()\"\n >\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-button>\n </axp-state-message>\n } @else if (treeNodes().length === 0) {\n <!-- Empty State -->\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.no-data.title' | translate | async)!\n \"\n [description]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.no-data.description'\n | translate\n | async)!\n \"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@platform-management:menu-management.actions.add-root.title' | translate | async\"\n [look]=\"'solid'\"\n [color]=\"'primary'\"\n (onClick)=\"addRootMenuItem()\"\n >\n <i class=\"fa-light fa-plus\"></i>\n </ax-button>\n </axp-state-message>\n } @else {\n <!-- Menu Tree Content -->\n <div class=\"axm-menu-list__container\">\n <!-- Menu Tree -->\n <div class=\"axm-menu-list__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n [look]=\"'default'\"\n [nodeTemplate]=\"itemTemplate\"\n [selectMode]=\"'none'\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragArea]=\"'handler'\"\n (onBeforeDrop)=\"handleBeforeDrop($event)\"\n (onItemsChange)=\"handleAfterDrop()\"\n ></ax-tree-view>\n </div>\n </div>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Custom Item Template -->\n<ng-template #itemTemplate let-node=\"node\" let-level=\"level\">\n @let nodeData = node['data'];\n @let item = nodeData.menuItem;\n @let metadata = nodeData.metadata;\n <div\n class=\"axm-menu-tree-item__wrapper\"\n [class.axm-menu-tree-item__wrapper--hidden]=\"metadata.isHidden\"\n [class.axm-menu-tree-item__wrapper--custom]=\"metadata.isCustom\"\n [class.axm-menu-tree-item__wrapper--group]=\"item.type === 'group'\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && item.type !== 'group') {\n <i class=\"axm-menu-tree-item__icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Text or Info -->\n @if (item.type === 'group') {\n <!-- Group Heading -->\n <span class=\"axm-menu-tree-item__group\">\n <i class=\"fa-light fa-layer-group\"></i>\n {{ item.text | translate | async }}\n </span>\n } @else if (item.type === 'break') {\n <!-- Divider -->\n <span class=\"axm-menu-tree-item__divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ '@platform-management:menu-management.states.divider' | translate | async }}\n </span>\n } @else if (item.text) {\n <!-- Regular Menu Item -->\n <span class=\"axm-menu-tree-item__text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <!-- Path-only Item -->\n <span class=\"axm-menu-tree-item__path\">\n <i class=\"fa-light fa-link\"></i>\n {{ item.path }}\n </span>\n }\n\n <!-- Menu Name/Key -->\n @if (item.name) {\n <code class=\"axm-menu-tree-item__name\">{{ item.name }}</code>\n }\n\n <!-- Status Badges -->\n @if (metadata.isHidden) {\n <ax-badge\n [text]=\"('@platform-management:menu-management.states.hidden' | translate | async)!\"\n color=\"danger\"\n ></ax-badge>\n } @else if (metadata.isCustom) {\n <ax-badge\n [text]=\"('@platform-management:menu-management.states.custom' | translate | async)!\"\n color=\"success\"\n ></ax-badge>\n } @else if (metadata.isBuiltIn) {\n <ax-badge\n [text]=\"('@platform-management:menu-management.states.built-in' | translate | async)!\"\n color=\"primary\"\n ></ax-badge>\n }\n\n <!-- Actions Dropdown -->\n <ax-button class=\"axm-menu-tree-item__actions\" [look]=\"'blank'\" [size]=\"'sm'\" [iconOnly]=\"true\">\n <ax-prefix>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </ax-prefix>\n\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n <!-- Edit (only for items with names) -->\n @if (item.name) {\n <ax-button-item\n [text]=\"('@general:actions.edit.title' | translate | async)!\"\n (onClick)=\"onAction('edit', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-edit\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Show/Hide (only for items with names) -->\n @if (item.name && metadata.isBuiltIn) {\n @if (metadata.isHidden) {\n <ax-button-item\n [text]=\"('@platform-management:menu-management.actions.show.title' | translate | async)!\"\n (onClick)=\"onAction('show', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-eye\"></i>\n </ax-prefix>\n </ax-button-item>\n } @else {\n <ax-button-item\n [text]=\"('@platform-management:menu-management.actions.hide.title' | translate | async)!\"\n (onClick)=\"onAction('hide', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-eye-slash\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n }\n\n @if (!item.path && (item.type === 'menu' || !item.type)) {\n <!-- Add Child -->\n <ax-button-item\n [text]=\"('@platform-management:menu-management.actions.add-child.title' | translate | async)!\"\n (onClick)=\"onAction('add-child', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Delete (only for custom items with names) -->\n @if (item.name && metadata.isCustom) {\n <ax-divider></ax-divider>\n <ax-button-item\n [color]=\"'danger'\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\"\n (onClick)=\"onAction('delete', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-trash\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Info message for items without names -->\n @if (!item.name) {\n <ax-divider></ax-divider>\n <div class=\"ax-p-2 ax-text-xs ax-text-neutral-500 ax-italic\">\n {{ '@platform-management:menu-management.messages.info.no-name' | translate | async }}\n </div>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n</ng-template>\n", styles: [".axm-menu-list-page .axm-menu-list__container{display:flex;flex-direction:column;gap:1rem;padding:1.5rem}.axm-menu-list-page .axm-menu-list__tree{display:flex;flex-direction:column;gap:.5rem}.axm-menu-list-page .axm-menu-tree-item__wrapper{display:flex;flex:1 1 0%;align-items:center;gap:1rem;border-radius:.375rem;padding:.5rem;border-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));transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.axm-menu-list-page .axm-menu-tree-item__wrapper:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}.axm-menu-list-page .axm-menu-tree-item__wrapper--hidden{opacity:.5}.axm-menu-list-page .axm-menu-tree-item__wrapper--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__wrapper--group{padding-top:.75rem;padding-bottom:.75rem}.axm-menu-list-page .axm-menu-tree-item__icon{display:flex;align-items:center;justify-content:center;height:1.5rem;width:1.5rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-500),var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__text{flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500}.axm-menu-list-page .axm-menu-tree-item__group,.axm-menu-list-page .axm-menu-tree-item__divider,.axm-menu-list-page .axm-menu-tree-item__path{display:flex;flex:1 1 0%;align-items:center;gap:.5rem;font-size:.75rem;line-height:1rem;font-style:italic;--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__divider i,.axm-menu-list-page .axm-menu-tree-item__path i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__name{display:flex;align-items:center;border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(64 64 64 / var(--tw-text-opacity, 1));font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:400;border-width:1px;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));white-space:nowrap;-webkit-user-select:all;user-select:all}.axm-menu-list-page .axm-menu-tree-item__actions{margin-left:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.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: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { 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: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i3.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { 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: "component", type: 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: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "variant"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i4.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
829
- }
830
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXMMenuListComponent, decorators: [{
831
- type: Component,
832
- args: [{ selector: 'axm-menu-list', imports: [
833
- CommonModule,
834
- AXButtonModule,
835
- AXDecoratorModule,
836
- AXDropdownButtonModule,
837
- AXDropdownModule,
838
- AXTranslationModule,
839
- AXTreeViewComponent,
840
- AXPPageLayoutComponent,
841
- AXPThemeLayoutBlockComponent,
842
- AXPStateMessageComponent,
843
- AXBadgeModule,
844
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
845
- {
846
- provide: AXPPageLayoutBase,
847
- useExisting: AXMMenuListComponent,
848
- },
849
- ], host: { class: 'axm-menu-list-page' }, template: "<axp-page-layout>\n <axp-page-content>\n @if (isLoading()) {\n <!-- Loading State -->\n <axp-state-message\n mode=\"loading\"\n icon=\"fa-light fa-spinner-third fa-spin\"\n [title]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.loading.title' | translate | async)!\n \"\n [description]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.loading.description'\n | translate\n | async)!\n \"\n />\n } @else if (error()) {\n <!-- Error State -->\n <axp-state-message\n mode=\"error\"\n icon=\"fa-light fa-circle-exclamation\"\n [title]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.error.title' | translate | async)!\n \"\n [description]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.error.description'\n | translate\n | async)!\n \"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@general:actions.retry.title' | translate | async\"\n [look]=\"'outline'\"\n [color]=\"'primary'\"\n (onClick)=\"loadMenuItems()\"\n >\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-button>\n </axp-state-message>\n } @else if (treeNodes().length === 0) {\n <!-- Empty State -->\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.no-data.title' | translate | async)!\n \"\n [description]=\"\n ('@platform-management:menu-management.components.menu-list.empty-states.no-data.description'\n | translate\n | async)!\n \"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@platform-management:menu-management.actions.add-root.title' | translate | async\"\n [look]=\"'solid'\"\n [color]=\"'primary'\"\n (onClick)=\"addRootMenuItem()\"\n >\n <i class=\"fa-light fa-plus\"></i>\n </ax-button>\n </axp-state-message>\n } @else {\n <!-- Menu Tree Content -->\n <div class=\"axm-menu-list__container\">\n <!-- Menu Tree -->\n <div class=\"axm-menu-list__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n [look]=\"'default'\"\n [nodeTemplate]=\"itemTemplate\"\n [selectMode]=\"'none'\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragArea]=\"'handler'\"\n (onBeforeDrop)=\"handleBeforeDrop($event)\"\n (onItemsChange)=\"handleAfterDrop()\"\n ></ax-tree-view>\n </div>\n </div>\n }\n </axp-page-content>\n</axp-page-layout>\n\n<!-- Custom Item Template -->\n<ng-template #itemTemplate let-node=\"node\" let-level=\"level\">\n @let nodeData = node['data'];\n @let item = nodeData.menuItem;\n @let metadata = nodeData.metadata;\n <div\n class=\"axm-menu-tree-item__wrapper\"\n [class.axm-menu-tree-item__wrapper--hidden]=\"metadata.isHidden\"\n [class.axm-menu-tree-item__wrapper--custom]=\"metadata.isCustom\"\n [class.axm-menu-tree-item__wrapper--group]=\"item.type === 'group'\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && item.type !== 'group') {\n <i class=\"axm-menu-tree-item__icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Text or Info -->\n @if (item.type === 'group') {\n <!-- Group Heading -->\n <span class=\"axm-menu-tree-item__group\">\n <i class=\"fa-light fa-layer-group\"></i>\n {{ item.text | translate | async }}\n </span>\n } @else if (item.type === 'break') {\n <!-- Divider -->\n <span class=\"axm-menu-tree-item__divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ '@platform-management:menu-management.states.divider' | translate | async }}\n </span>\n } @else if (item.text) {\n <!-- Regular Menu Item -->\n <span class=\"axm-menu-tree-item__text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <!-- Path-only Item -->\n <span class=\"axm-menu-tree-item__path\">\n <i class=\"fa-light fa-link\"></i>\n {{ item.path }}\n </span>\n }\n\n <!-- Menu Name/Key -->\n @if (item.name) {\n <code class=\"axm-menu-tree-item__name\">{{ item.name }}</code>\n }\n\n <!-- Status Badges -->\n @if (metadata.isHidden) {\n <ax-badge\n [text]=\"('@platform-management:menu-management.states.hidden' | translate | async)!\"\n color=\"danger\"\n ></ax-badge>\n } @else if (metadata.isCustom) {\n <ax-badge\n [text]=\"('@platform-management:menu-management.states.custom' | translate | async)!\"\n color=\"success\"\n ></ax-badge>\n } @else if (metadata.isBuiltIn) {\n <ax-badge\n [text]=\"('@platform-management:menu-management.states.built-in' | translate | async)!\"\n color=\"primary\"\n ></ax-badge>\n }\n\n <!-- Actions Dropdown -->\n <ax-button class=\"axm-menu-tree-item__actions\" [look]=\"'blank'\" [size]=\"'sm'\" [iconOnly]=\"true\">\n <ax-prefix>\n <i class=\"fa-light fa-ellipsis-vertical\"></i>\n </ax-prefix>\n\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n <!-- Edit (only for items with names) -->\n @if (item.name) {\n <ax-button-item\n [text]=\"('@general:actions.edit.title' | translate | async)!\"\n (onClick)=\"onAction('edit', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-edit\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Show/Hide (only for items with names) -->\n @if (item.name && metadata.isBuiltIn) {\n @if (metadata.isHidden) {\n <ax-button-item\n [text]=\"('@platform-management:menu-management.actions.show.title' | translate | async)!\"\n (onClick)=\"onAction('show', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-eye\"></i>\n </ax-prefix>\n </ax-button-item>\n } @else {\n <ax-button-item\n [text]=\"('@platform-management:menu-management.actions.hide.title' | translate | async)!\"\n (onClick)=\"onAction('hide', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-eye-slash\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n }\n\n @if (!item.path && (item.type === 'menu' || !item.type)) {\n <!-- Add Child -->\n <ax-button-item\n [text]=\"('@platform-management:menu-management.actions.add-child.title' | translate | async)!\"\n (onClick)=\"onAction('add-child', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Delete (only for custom items with names) -->\n @if (item.name && metadata.isCustom) {\n <ax-divider></ax-divider>\n <ax-button-item\n [color]=\"'danger'\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\"\n (onClick)=\"onAction('delete', nodeData); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-trash\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Info message for items without names -->\n @if (!item.name) {\n <ax-divider></ax-divider>\n <div class=\"ax-p-2 ax-text-xs ax-text-neutral-500 ax-italic\">\n {{ '@platform-management:menu-management.messages.info.no-name' | translate | async }}\n </div>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n</ng-template>\n", styles: [".axm-menu-list-page .axm-menu-list__container{display:flex;flex-direction:column;gap:1rem;padding:1.5rem}.axm-menu-list-page .axm-menu-list__tree{display:flex;flex-direction:column;gap:.5rem}.axm-menu-list-page .axm-menu-tree-item__wrapper{display:flex;flex:1 1 0%;align-items:center;gap:1rem;border-radius:.375rem;padding:.5rem;border-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));transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.axm-menu-list-page .axm-menu-tree-item__wrapper:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}.axm-menu-list-page .axm-menu-tree-item__wrapper--hidden{opacity:.5}.axm-menu-list-page .axm-menu-tree-item__wrapper--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__wrapper--group{padding-top:.75rem;padding-bottom:.75rem}.axm-menu-list-page .axm-menu-tree-item__icon{display:flex;align-items:center;justify-content:center;height:1.5rem;width:1.5rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-500),var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__text{flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500}.axm-menu-list-page .axm-menu-tree-item__group,.axm-menu-list-page .axm-menu-tree-item__divider,.axm-menu-list-page .axm-menu-tree-item__path{display:flex;flex:1 1 0%;align-items:center;gap:.5rem;font-size:.75rem;line-height:1rem;font-style:italic;--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__divider i,.axm-menu-list-page .axm-menu-tree-item__path i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-tree-item__name{display:flex;align-items:center;border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(64 64 64 / var(--tw-text-opacity, 1));font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:400;border-width:1px;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));white-space:nowrap;-webkit-user-select:all;user-select:all}.axm-menu-list-page .axm-menu-tree-item__actions{margin-left:.5rem}\n"] }]
850
- }], propDecorators: { tree: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXTreeViewComponent), { isSignal: true }] }] } });
851
-
852
- export { AXMMenuListComponent };
853
- //# sourceMappingURL=acorex-modules-platform-management-menu-list.component-DLg61Nf8.mjs.map