@acorex/modules 20.5.0-next.0 → 20.5.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1046 +0,0 @@
1
- import { CdkDrag, CdkDragHandle, CdkDropList, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
2
- import * as i4 from '@angular/common';
3
- import { CommonModule } from '@angular/common';
4
- import * as i0 from '@angular/core';
5
- import { input, output, signal, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, Injectable } from '@angular/core';
6
- import { ActivatedRoute } from '@angular/router';
7
- import * as i1 from '@acorex/components/button';
8
- import { AXButtonModule } from '@acorex/components/button';
9
- import { AXDialogService } from '@acorex/components/dialog';
10
- import { AXToastService } from '@acorex/components/toast';
11
- import * as i5 from '@acorex/core/translation';
12
- import { AXTranslationModule, AXTranslationService } from '@acorex/core/translation';
13
- import { AXPPlatformScope } from '@acorex/platform/core';
14
- import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
15
- import { AXPThemeLayoutBlockComponent, AXPStateMessageComponent } from '@acorex/platform/layout/components';
16
- import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
17
- import * as i2 from '@acorex/components/decorators';
18
- import { AXDecoratorModule } from '@acorex/components/decorators';
19
- import * as i3 from '@acorex/components/dropdown';
20
- import { AXDropdownModule } from '@acorex/components/dropdown';
21
- import { AXPSettingService, AXPMenuProviderService, AXPMenuService } from '@acorex/platform/common';
22
- import { cloneDeep, sortBy } from 'lodash-es';
23
- import { A as AXP_MENU_CUSTOMIZATION_KEY, a as AXP_MENU_CUSTOMIZATION_DEFAULT } from './acorex-modules-application-management-acorex-modules-application-management-CQMnhxLa.mjs';
24
-
25
- //#region ---- Menu Tree Item Component ----
26
- class AXMMenuTreeItemComponent {
27
- constructor() {
28
- //#region ---- Inputs ----
29
- this.item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
30
- this.level = input(0, ...(ngDevMode ? [{ debugName: "level" }] : []));
31
- this.canDelete = input(false, ...(ngDevMode ? [{ debugName: "canDelete" }] : []));
32
- this.connectedDropLists = input([], ...(ngDevMode ? [{ debugName: "connectedDropLists" }] : []));
33
- this.canMoveUp = input(false, ...(ngDevMode ? [{ debugName: "canMoveUp" }] : []));
34
- this.canMoveDown = input(false, ...(ngDevMode ? [{ debugName: "canMoveDown" }] : []));
35
- this.canMoveToParent = input(false, ...(ngDevMode ? [{ debugName: "canMoveToParent" }] : []));
36
- //#endregion
37
- //#region ---- Outputs ----
38
- this.actionTriggered = output();
39
- this.itemDropped = output();
40
- //#endregion
41
- //#region ---- Component State ----
42
- this.isExpanded = signal(true, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
43
- }
44
- //#endregion
45
- //#region ---- Helper Methods ----
46
- /**
47
- * Get unique drop list ID for this item's children
48
- */
49
- getDropListId() {
50
- const item = this.item();
51
- return `menu-${item.name || item.path || 'unnamed'}`;
52
- }
53
- /**
54
- * Get children array, ensuring it's always initialized
55
- * This allows drop zones to exist even for items with no children yet
56
- */
57
- getChildrenArray() {
58
- const item = this.item();
59
- if (!item.children) {
60
- // Initialize children array if it doesn't exist
61
- item.children = [];
62
- }
63
- return item.children;
64
- }
65
- //#endregion
66
- //#region ---- Event Handlers ----
67
- /**
68
- * Toggle expand/collapse
69
- */
70
- toggleExpand() {
71
- this.isExpanded.update((expanded) => !expanded);
72
- }
73
- /**
74
- * Handle action trigger
75
- */
76
- onAction(action) {
77
- this.actionTriggered.emit({ action, item: this.item() });
78
- }
79
- /**
80
- * Handle drop event
81
- */
82
- onDrop(event) {
83
- this.itemDropped.emit(event);
84
- }
85
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMMenuTreeItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
86
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: AXMMenuTreeItemComponent, isStandalone: true, selector: "axm-menu-tree-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, canDelete: { classPropertyName: "canDelete", publicName: "canDelete", isSignal: true, isRequired: false, transformFunction: null }, connectedDropLists: { classPropertyName: "connectedDropLists", publicName: "connectedDropLists", isSignal: true, isRequired: false, transformFunction: null }, canMoveUp: { classPropertyName: "canMoveUp", publicName: "canMoveUp", isSignal: true, isRequired: false, transformFunction: null }, canMoveDown: { classPropertyName: "canMoveDown", publicName: "canMoveDown", isSignal: true, isRequired: false, transformFunction: null }, canMoveToParent: { classPropertyName: "canMoveToParent", publicName: "canMoveToParent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionTriggered: "actionTriggered", itemDropped: "itemDropped" }, host: { classAttribute: "axm-menu-tree-item" }, ngImport: i0, template: "<div class=\"axm-menu-tree-item__container\" [style.padding-left.rem]=\"level()\">\n <div\n class=\"axm-menu-tree-item__content\"\n cdkDrag\n [cdkDragData]=\"item()\"\n [class.--hidden]=\"item().isHidden\"\n [class.--custom]=\"item().isCustom\"\n >\n <!-- Drag Handle -->\n <div class=\"axm-menu-tree-item__drag-handle\" cdkDragHandle>\n <i class=\"fa-light fa-grip-dots-vertical\"></i>\n </div>\n\n <!-- Expand/Collapse Button -->\n @if (item().children && item().children!.length > 0) {\n <ax-button class=\"axm-menu-tree-item__expand-btn\" [look]=\"'blank'\" [size]=\"'sm'\" (onClick)=\"toggleExpand()\">\n <i [class]=\"isExpanded() ? 'fa-light fa-chevron-down' : 'fa-light fa-chevron-right'\"></i>\n </ax-button>\n } @else {\n <div class=\"axm-menu-tree-item__spacer\"></div>\n }\n\n <!-- Icon -->\n @if (item().icon) {\n <i class=\"axm-menu-tree-item__icon\" [class]=\"item().icon\"></i>\n }\n\n <!-- Text or Info -->\n @if (item().text) {\n <span class=\"axm-menu-tree-item__text\">\n {{ item().text | translate | async }}\n </span>\n } @else if (item().path) {\n <span class=\"axm-menu-tree-item__path\">\n <i class=\"fa-light fa-link\"></i>\n {{ item().path }}\n </span>\n } @else {\n <span class=\"axm-menu-tree-item__divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ '@application-management:menu-management.badge.divider' | translate | async }}\n </span>\n }\n\n <!-- Menu Name/Key -->\n @if (item().name) {\n <code class=\"axm-menu-tree-item__name\">\n {{ item().name }}\n </code>\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 <!-- Show/Hide (only for items with names) -->\n @if (item().name && item().isBuiltIn) {\n @if (item().isHidden) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.show' | translate | async)!\"\n (onClick)=\"onAction('show'); 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]=\"('@application-management:menu-management.actions.hide' | translate | async)!\"\n (onClick)=\"onAction('hide'); 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 <!-- 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'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-edit\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Add Child -->\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.add-child' | translate | async)!\"\n (onClick)=\"onAction('add-child'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button-item>\n\n <!-- Move Actions -->\n @if (canMoveUp() || canMoveDown() || canMoveToParent()) {\n <ax-divider></ax-divider>\n\n <!-- Move Up -->\n @if (canMoveUp()) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.move-up' | translate | async)!\"\n (onClick)=\"onAction('move-up'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-arrow-up\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Move Down -->\n @if (canMoveDown()) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.move-down' | translate | async)!\"\n (onClick)=\"onAction('move-down'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-arrow-down\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Move to Parent -->\n @if (canMoveToParent()) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.move-to-parent' | translate | async)!\"\n (onClick)=\"onAction('move-to-parent'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-level-up\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n }\n\n <!-- Delete (only for custom items with names) -->\n @if (item().name && item().isCustom && canDelete()) {\n <ax-divider></ax-divider>\n <ax-button-item\n [color]=\"'danger'\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\"\n (onClick)=\"onAction('delete'); 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 {{ '@application-management:menu-management.messages.no-name-info' | translate | async }}\n </div>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n\n <!-- Children Drop Zone - Always render the drop list even when collapsed -->\n <!-- The drop list must exist for items to be draggable FROM this container -->\n <div\n class=\"axm-menu-tree-item__children\"\n cdkDropList\n [id]=\"getDropListId()\"\n [cdkDropListData]=\"getChildrenArray()\"\n [cdkDropListConnectedTo]=\"connectedDropLists()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n [class.--collapsed]=\"!isExpanded()\"\n >\n @if (isExpanded()) {\n @for (child of getChildrenArray(); track child.name || child.path || $index; let i = $index) {\n <axm-menu-tree-item\n [item]=\"child\"\n [level]=\"level() + 1\"\n [canDelete]=\"canDelete()\"\n [connectedDropLists]=\"connectedDropLists()\"\n [canMoveUp]=\"i > 0\"\n [canMoveDown]=\"i < getChildrenArray().length - 1\"\n [canMoveToParent]=\"true\"\n (actionTriggered)=\"actionTriggered.emit($event)\"\n (itemDropped)=\"itemDropped.emit($event)\"\n />\n }\n }\n </div>\n</div>\n", styles: [".axm-menu-tree-item__container{display:flex;flex-direction:column}.axm-menu-tree-item__content{display:flex;align-items:center;gap:.5rem;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-tree-item__content: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-tree-item__content.--hidden{--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1));opacity:.5;--tw-border-opacity: 1;border-color:rgb(212 212 212 / var(--tw-border-opacity, 1))}.axm-menu-tree-item__content.--hidden .axm-menu-tree-item__icon{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axm-menu-tree-item__content.--hidden .axm-menu-tree-item__name{--tw-bg-opacity: 1;background-color:rgb(229 229 229 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1))}.axm-menu-tree-item__content.--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axm-menu-tree-item__content.cdk-drag-preview{--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-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));border-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axm-menu-tree-item__drag-handle{display:flex;align-items:center;justify-content:center;height:1.5rem;width:1.5rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1));cursor:move}.axm-menu-tree-item__drag-handle:hover{--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axm-menu-tree-item__expand-btn{height:1.5rem;width:1.5rem}.axm-menu-tree-item__spacer{width:1.5rem}.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-tree-item__text{flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500}.axm-menu-tree-item__divider,.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-tree-item__divider i,.axm-menu-tree-item__path i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.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;-moz-user-select:all;user-select:all}.axm-menu-tree-item__actions{margin-left:.5rem}.axm-menu-tree-item__children{display:flex;flex-direction:column;gap:.5rem;margin-top:.5rem;padding-left:1rem;border-left-width:2px;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1))}.axm-menu-tree-item__children.--collapsed{display:none}\n"], dependencies: [{ kind: "component", type: AXMMenuTreeItemComponent, selector: "axm-menu-tree-item", inputs: ["item", "level", "canDelete", "connectedDropLists", "canMoveUp", "canMoveDown", "canMoveToParent"], outputs: ["actionTriggered", "itemDropped"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { 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"], 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: 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: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
87
- }
88
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMMenuTreeItemComponent, decorators: [{
89
- type: Component,
90
- args: [{ selector: 'axm-menu-tree-item', imports: [
91
- CommonModule,
92
- CdkDrag,
93
- CdkDragHandle,
94
- CdkDropList,
95
- AXButtonModule,
96
- AXDecoratorModule,
97
- AXDropdownModule,
98
- AXTranslationModule,
99
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axm-menu-tree-item' }, template: "<div class=\"axm-menu-tree-item__container\" [style.padding-left.rem]=\"level()\">\n <div\n class=\"axm-menu-tree-item__content\"\n cdkDrag\n [cdkDragData]=\"item()\"\n [class.--hidden]=\"item().isHidden\"\n [class.--custom]=\"item().isCustom\"\n >\n <!-- Drag Handle -->\n <div class=\"axm-menu-tree-item__drag-handle\" cdkDragHandle>\n <i class=\"fa-light fa-grip-dots-vertical\"></i>\n </div>\n\n <!-- Expand/Collapse Button -->\n @if (item().children && item().children!.length > 0) {\n <ax-button class=\"axm-menu-tree-item__expand-btn\" [look]=\"'blank'\" [size]=\"'sm'\" (onClick)=\"toggleExpand()\">\n <i [class]=\"isExpanded() ? 'fa-light fa-chevron-down' : 'fa-light fa-chevron-right'\"></i>\n </ax-button>\n } @else {\n <div class=\"axm-menu-tree-item__spacer\"></div>\n }\n\n <!-- Icon -->\n @if (item().icon) {\n <i class=\"axm-menu-tree-item__icon\" [class]=\"item().icon\"></i>\n }\n\n <!-- Text or Info -->\n @if (item().text) {\n <span class=\"axm-menu-tree-item__text\">\n {{ item().text | translate | async }}\n </span>\n } @else if (item().path) {\n <span class=\"axm-menu-tree-item__path\">\n <i class=\"fa-light fa-link\"></i>\n {{ item().path }}\n </span>\n } @else {\n <span class=\"axm-menu-tree-item__divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ '@application-management:menu-management.badge.divider' | translate | async }}\n </span>\n }\n\n <!-- Menu Name/Key -->\n @if (item().name) {\n <code class=\"axm-menu-tree-item__name\">\n {{ item().name }}\n </code>\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 <!-- Show/Hide (only for items with names) -->\n @if (item().name && item().isBuiltIn) {\n @if (item().isHidden) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.show' | translate | async)!\"\n (onClick)=\"onAction('show'); 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]=\"('@application-management:menu-management.actions.hide' | translate | async)!\"\n (onClick)=\"onAction('hide'); 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 <!-- 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'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-edit\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Add Child -->\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.add-child' | translate | async)!\"\n (onClick)=\"onAction('add-child'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button-item>\n\n <!-- Move Actions -->\n @if (canMoveUp() || canMoveDown() || canMoveToParent()) {\n <ax-divider></ax-divider>\n\n <!-- Move Up -->\n @if (canMoveUp()) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.move-up' | translate | async)!\"\n (onClick)=\"onAction('move-up'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-arrow-up\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Move Down -->\n @if (canMoveDown()) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.move-down' | translate | async)!\"\n (onClick)=\"onAction('move-down'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-arrow-down\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n\n <!-- Move to Parent -->\n @if (canMoveToParent()) {\n <ax-button-item\n [text]=\"('@application-management:menu-management.actions.move-to-parent' | translate | async)!\"\n (onClick)=\"onAction('move-to-parent'); panel.close()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-level-up\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n }\n\n <!-- Delete (only for custom items with names) -->\n @if (item().name && item().isCustom && canDelete()) {\n <ax-divider></ax-divider>\n <ax-button-item\n [color]=\"'danger'\"\n [text]=\"('@general:actions.delete.title' | translate | async)!\"\n (onClick)=\"onAction('delete'); 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 {{ '@application-management:menu-management.messages.no-name-info' | translate | async }}\n </div>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n </div>\n\n <!-- Children Drop Zone - Always render the drop list even when collapsed -->\n <!-- The drop list must exist for items to be draggable FROM this container -->\n <div\n class=\"axm-menu-tree-item__children\"\n cdkDropList\n [id]=\"getDropListId()\"\n [cdkDropListData]=\"getChildrenArray()\"\n [cdkDropListConnectedTo]=\"connectedDropLists()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n [class.--collapsed]=\"!isExpanded()\"\n >\n @if (isExpanded()) {\n @for (child of getChildrenArray(); track child.name || child.path || $index; let i = $index) {\n <axm-menu-tree-item\n [item]=\"child\"\n [level]=\"level() + 1\"\n [canDelete]=\"canDelete()\"\n [connectedDropLists]=\"connectedDropLists()\"\n [canMoveUp]=\"i > 0\"\n [canMoveDown]=\"i < getChildrenArray().length - 1\"\n [canMoveToParent]=\"true\"\n (actionTriggered)=\"actionTriggered.emit($event)\"\n (itemDropped)=\"itemDropped.emit($event)\"\n />\n }\n }\n </div>\n</div>\n", styles: [".axm-menu-tree-item__container{display:flex;flex-direction:column}.axm-menu-tree-item__content{display:flex;align-items:center;gap:.5rem;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-tree-item__content: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-tree-item__content.--hidden{--tw-bg-opacity: 1;background-color:rgb(245 245 245 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1));opacity:.5;--tw-border-opacity: 1;border-color:rgb(212 212 212 / var(--tw-border-opacity, 1))}.axm-menu-tree-item__content.--hidden .axm-menu-tree-item__icon{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axm-menu-tree-item__content.--hidden .axm-menu-tree-item__name{--tw-bg-opacity: 1;background-color:rgb(229 229 229 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1))}.axm-menu-tree-item__content.--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axm-menu-tree-item__content.cdk-drag-preview{--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-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));border-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axm-menu-tree-item__drag-handle{display:flex;align-items:center;justify-content:center;height:1.5rem;width:1.5rem;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1));cursor:move}.axm-menu-tree-item__drag-handle:hover{--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}.axm-menu-tree-item__expand-btn{height:1.5rem;width:1.5rem}.axm-menu-tree-item__spacer{width:1.5rem}.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-tree-item__text{flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500}.axm-menu-tree-item__divider,.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-tree-item__divider i,.axm-menu-tree-item__path i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.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;-moz-user-select:all;user-select:all}.axm-menu-tree-item__actions{margin-left:.5rem}.axm-menu-tree-item__children{display:flex;flex-direction:column;gap:.5rem;margin-top:.5rem;padding-left:1rem;border-left-width:2px;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1))}.axm-menu-tree-item__children.--collapsed{display:none}\n"] }]
100
- }] });
101
-
102
- //#region ---- Menu Management Service ----
103
- class AXPMenuManagementService {
104
- constructor() {
105
- //#region ---- Dependencies ----
106
- this.settingService = inject(AXPSettingService);
107
- this.menuProviderService = inject(AXPMenuProviderService);
108
- this.menuService = inject(AXPMenuService);
109
- }
110
- //#endregion
111
- //#region ---- Public Methods ----
112
- /**
113
- * Get all menu items with customization metadata
114
- */
115
- async getMenuTree(scope) {
116
- // Get RAW menu items (all items including hidden ones) - NO middleware to avoid duplicates
117
- const rawItems = await this.menuProviderService.rawItems();
118
- // Load customizations for the given scope
119
- const customization = await this.loadCustomization(scope);
120
- // Convert raw items to nodes
121
- const nodes = this.convertToNodes(rawItems, customization);
122
- // Add custom items to the management view
123
- const customNodes = this.convertCustomItemsToNodes(customization.customItems, customization);
124
- nodes.push(...customNodes);
125
- // Apply parent overrides to restructure the tree (this will move Sample 1 under Profile)
126
- const finalNodes = this.applyParentOverrides(nodes, customization);
127
- // Apply the EXACT same sorting logic as the sidebar for perfect synchronization
128
- const sortedNodes = this.applySidebarSorting(finalNodes);
129
- return sortedNodes;
130
- }
131
- /**
132
- * Load menu customization for a specific scope
133
- */
134
- async loadCustomization(scope) {
135
- try {
136
- const scopedSettings = this.settingService.scope(scope);
137
- const saved = await scopedSettings.get(AXP_MENU_CUSTOMIZATION_KEY);
138
- if (saved && saved.version) {
139
- return saved;
140
- }
141
- return cloneDeep(AXP_MENU_CUSTOMIZATION_DEFAULT);
142
- }
143
- catch (error) {
144
- return cloneDeep(AXP_MENU_CUSTOMIZATION_DEFAULT);
145
- }
146
- }
147
- /**
148
- * Save menu customization for a specific scope
149
- */
150
- async saveCustomization(scope, customization) {
151
- const scopedSettings = this.settingService.scope(scope);
152
- await scopedSettings.set(AXP_MENU_CUSTOMIZATION_KEY, customization);
153
- // Clear menu cache to force reload
154
- this.menuProviderService.clearCache();
155
- // Refresh the menu store to update the sidebar immediately
156
- const freshItems = await this.menuProviderService.items();
157
- this.menuService.setMenuItems(freshItems);
158
- // Force a small delay to ensure the signal update propagates
159
- await new Promise(resolve => setTimeout(resolve, 100));
160
- }
161
- /**
162
- * Hide a menu item
163
- */
164
- async hideMenuItem(scope, menuName) {
165
- if (!menuName) {
166
- throw new Error('Menu item must have a name to be hidden');
167
- }
168
- const customization = await this.loadCustomization(scope);
169
- if (!customization.overrides[menuName]) {
170
- customization.overrides[menuName] = {};
171
- }
172
- customization.overrides[menuName].hidden = true;
173
- await this.saveCustomization(scope, customization);
174
- }
175
- /**
176
- * Show a menu item
177
- */
178
- async showMenuItem(scope, menuName) {
179
- if (!menuName) {
180
- throw new Error('Menu item must have a name to be shown');
181
- }
182
- const customization = await this.loadCustomization(scope);
183
- if (customization.overrides[menuName]) {
184
- delete customization.overrides[menuName].hidden;
185
- // Clean up if no other overrides exist
186
- if (Object.keys(customization.overrides[menuName]).length === 0) {
187
- delete customization.overrides[menuName];
188
- }
189
- }
190
- await this.saveCustomization(scope, customization);
191
- }
192
- /**
193
- * Update menu item priority
194
- */
195
- async updateMenuPriority(scope, menuName, priority) {
196
- const customization = await this.loadCustomization(scope);
197
- if (!customization.overrides[menuName]) {
198
- customization.overrides[menuName] = {};
199
- }
200
- customization.overrides[menuName].priority = priority;
201
- await this.saveCustomization(scope, customization);
202
- }
203
- /**
204
- * Move menu item to different parent
205
- */
206
- async moveMenuItem(scope, menuName, newParentName) {
207
- const customization = await this.loadCustomization(scope);
208
- if (!customization.overrides[menuName]) {
209
- customization.overrides[menuName] = {};
210
- }
211
- if (newParentName) {
212
- customization.overrides[menuName].parentName = newParentName;
213
- }
214
- else {
215
- delete customization.overrides[menuName].parentName;
216
- }
217
- await this.saveCustomization(scope, customization);
218
- }
219
- /**
220
- * Update menu item properties
221
- */
222
- async updateMenuProperties(scope, menuName, properties) {
223
- const customization = await this.loadCustomization(scope);
224
- if (!customization.overrides[menuName]) {
225
- customization.overrides[menuName] = {};
226
- }
227
- customization.overrides[menuName].properties = {
228
- ...customization.overrides[menuName].properties,
229
- ...properties,
230
- };
231
- await this.saveCustomization(scope, customization);
232
- }
233
- /**
234
- * Add custom menu item
235
- */
236
- async addCustomMenuItem(scope, menuItem) {
237
- const customization = await this.loadCustomization(scope);
238
- // Generate unique name if not provided
239
- if (!menuItem.name) {
240
- menuItem.name = `custom-menu-${Date.now()}`;
241
- }
242
- customization.customItems.push(menuItem);
243
- await this.saveCustomization(scope, customization);
244
- }
245
- /**
246
- * Add custom menu item as child of existing item
247
- */
248
- async addCustomMenuItemAsChild(scope, menuItem, parentName) {
249
- const customization = await this.loadCustomization(scope);
250
- // Generate unique name if not provided
251
- if (!menuItem.name) {
252
- menuItem.name = `custom-menu-${Date.now()}`;
253
- }
254
- // Add custom item
255
- customization.customItems.push(menuItem);
256
- // Set parent override to move it under the specified parent
257
- if (!customization.overrides[menuItem.name]) {
258
- customization.overrides[menuItem.name] = {};
259
- }
260
- customization.overrides[menuItem.name].parentName = parentName;
261
- await this.saveCustomization(scope, customization);
262
- }
263
- /**
264
- * Update custom menu item
265
- */
266
- async updateCustomMenuItem(scope, menuName, menuItem) {
267
- const customization = await this.loadCustomization(scope);
268
- const index = customization.customItems.findIndex((item) => item.name === menuName);
269
- if (index !== -1) {
270
- customization.customItems[index] = menuItem;
271
- await this.saveCustomization(scope, customization);
272
- }
273
- }
274
- /**
275
- * Delete custom menu item
276
- */
277
- async deleteCustomMenuItem(scope, menuName) {
278
- const customization = await this.loadCustomization(scope);
279
- customization.customItems = customization.customItems.filter((item) => item.name !== menuName);
280
- await this.saveCustomization(scope, customization);
281
- }
282
- /**
283
- * Reset all customizations for a scope
284
- */
285
- async resetCustomizations(scope) {
286
- await this.saveCustomization(scope, cloneDeep(AXP_MENU_CUSTOMIZATION_DEFAULT));
287
- }
288
- /**
289
- * Reorder menu items based on drag-drop
290
- */
291
- async reorderMenuItems(scope, items, parentName) {
292
- const customization = await this.loadCustomization(scope);
293
- // Update priorities for all items at this level (only for items with names)
294
- items.forEach((item, index) => {
295
- if (item.name) {
296
- if (!customization.overrides[item.name]) {
297
- customization.overrides[item.name] = {};
298
- }
299
- // Set priority based on index
300
- customization.overrides[item.name].priority = index * 100;
301
- // Update parentName to reflect the new parent
302
- // Use empty string for root level, actual name for nested items
303
- customization.overrides[item.name].parentName = parentName || '';
304
- }
305
- });
306
- await this.saveCustomization(scope, customization);
307
- }
308
- //#endregion
309
- //#region ---- Private Methods ----
310
- /**
311
- * Apply the EXACT same sorting logic as the sidebar for perfect synchronization
312
- * Uses the same sortBy logic: [(c) => c.priority ?? 0, (c) => c.text]
313
- */
314
- applySidebarSorting(nodes) {
315
- return sortBy(nodes, [(c) => c.priority ?? 0, (c) => c.text]).map(node => ({
316
- ...node,
317
- children: node.children ? this.applySidebarSorting(node.children) : undefined
318
- }));
319
- }
320
- /**
321
- * Convert custom items to nodes with metadata
322
- */
323
- convertCustomItemsToNodes(customItems, customization) {
324
- return customItems.map((item) => {
325
- const override = item.name ? customization.overrides[item.name] : undefined;
326
- const node = {
327
- ...item,
328
- name: item.name,
329
- isBuiltIn: false,
330
- isCustom: true,
331
- isHidden: override?.hidden || false,
332
- originalPriority: item.priority,
333
- originalParentName: undefined,
334
- // Apply priority override if it exists
335
- priority: override?.priority !== undefined ? override.priority : item.priority,
336
- // Apply icon override if it exists
337
- icon: override?.properties?.icon !== undefined ? override.properties.icon : item.icon,
338
- // Apply text override if it exists
339
- text: override?.properties?.text !== undefined ? override.properties.text : item.text,
340
- // Apply path override if it exists
341
- path: override?.properties?.path !== undefined ? override.properties.path : item.path,
342
- children: item.children ? this.convertToNodes(item.children, customization) : undefined,
343
- };
344
- return node;
345
- });
346
- }
347
- /**
348
- * Apply parentName overrides to restructure the tree
349
- */
350
- applyParentOverrides(nodes, customization) {
351
- // Check if there are any parentName overrides (even if value is undefined)
352
- const hasParentOverrides = Object.values(customization.overrides).some((override) => 'parentName' in override);
353
- if (!hasParentOverrides) {
354
- return nodes;
355
- }
356
- // Clone the tree to avoid mutations
357
- const clonedNodes = this.deepCloneNodes(nodes);
358
- // Find items that need to be moved based on parentName overrides
359
- Object.entries(customization.overrides).forEach(([itemName, override]) => {
360
- // Check if the override has a parentName property (even if it's an empty string)
361
- if ('parentName' in override) {
362
- const isRootLevel = !override.parentName || override.parentName === '';
363
- // Find and remove the item from its current location
364
- const removedItem = this.removeAndReturnNode(clonedNodes, itemName);
365
- if (removedItem) {
366
- if (isRootLevel) {
367
- // Move to root level
368
- clonedNodes.push(removedItem);
369
- }
370
- else {
371
- // Move to specified parent
372
- const newParent = this.findNodeByName(clonedNodes, override.parentName);
373
- if (newParent) {
374
- if (!newParent.children) {
375
- newParent.children = [];
376
- }
377
- newParent.children.push(removedItem);
378
- }
379
- else {
380
- // Fallback: add to root if parent not found
381
- clonedNodes.push(removedItem);
382
- }
383
- }
384
- }
385
- }
386
- });
387
- // Re-sort after restructuring
388
- this.sortNodesRecursive(clonedNodes);
389
- return clonedNodes;
390
- }
391
- /**
392
- * Remove a node from tree and return it
393
- */
394
- removeAndReturnNode(nodes, name) {
395
- for (let i = 0; i < nodes.length; i++) {
396
- if (nodes[i].name === name) {
397
- const [removed] = nodes.splice(i, 1);
398
- return removed;
399
- }
400
- if (nodes[i].children) {
401
- const found = this.removeAndReturnNode(nodes[i].children, name);
402
- if (found) {
403
- return found;
404
- }
405
- }
406
- }
407
- return null;
408
- }
409
- /**
410
- * Deep clone nodes array
411
- */
412
- deepCloneNodes(nodes) {
413
- return nodes.map((node) => ({
414
- ...node,
415
- children: node.children ? this.deepCloneNodes(node.children) : undefined,
416
- }));
417
- }
418
- /**
419
- * Find a node by name in the tree
420
- */
421
- findNodeByName(nodes, name) {
422
- for (const node of nodes) {
423
- if (node.name === name) {
424
- return node;
425
- }
426
- if (node.children) {
427
- const found = this.findNodeByName(node.children, name);
428
- if (found) {
429
- return found;
430
- }
431
- }
432
- }
433
- return null;
434
- }
435
- /**
436
- * Sort nodes recursively by priority first, then by text (same as sidebar)
437
- */
438
- sortNodesRecursive(nodes) {
439
- // Sort by priority first, then by text (same as sidebar)
440
- const sorted = sortBy(nodes, [(c) => c.priority ?? 0, (c) => c.text]);
441
- nodes.length = 0;
442
- nodes.push(...sorted);
443
- nodes.forEach((node) => {
444
- if (node.children) {
445
- this.sortNodesRecursive(node.children);
446
- }
447
- });
448
- }
449
- /**
450
- * Convert menu items to nodes with metadata
451
- */
452
- convertToNodes(items, customization) {
453
- const nodes = items.map((item) => {
454
- // Only use items that have a proper name property
455
- const itemName = item.name;
456
- const override = itemName ? customization.overrides[itemName] : undefined;
457
- const isCustom = itemName ? customization.customItems.some((ci) => ci.name === itemName) : false;
458
- const node = {
459
- ...item,
460
- name: itemName,
461
- isBuiltIn: !isCustom,
462
- isCustom,
463
- isHidden: override?.hidden || false,
464
- originalPriority: item.priority,
465
- originalParentName: undefined,
466
- // Apply priority override if it exists
467
- priority: override?.priority !== undefined ? override.priority : item.priority,
468
- // Apply icon override if it exists
469
- icon: override?.properties?.icon !== undefined ? override.properties.icon : item.icon,
470
- // Apply text override if it exists
471
- text: override?.properties?.text !== undefined ? override.properties.text : item.text,
472
- // Apply path override if it exists
473
- path: override?.properties?.path !== undefined ? override.properties.path : item.path,
474
- children: item.children ? this.convertToNodes(item.children, customization) : undefined,
475
- };
476
- return node;
477
- });
478
- // Don't sort here - sorting is applied at the top level in getMenuTree
479
- return nodes;
480
- }
481
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPMenuManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
482
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPMenuManagementService, providedIn: 'root' }); }
483
- }
484
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPMenuManagementService, decorators: [{
485
- type: Injectable,
486
- args: [{ providedIn: 'root' }]
487
- }] });
488
-
489
- //#region ---- Menu List Component ----
490
- class AXMMenuListComponent extends AXPPageLayoutBaseComponent {
491
- constructor() {
492
- super(...arguments);
493
- //#region ---- Dependencies ----
494
- this.menuManagementService = inject(AXPMenuManagementService);
495
- this.layoutBuilder = inject(AXPLayoutBuilderService);
496
- this.dialogService = inject(AXDialogService);
497
- this.toastService = inject(AXToastService);
498
- this.translationService = inject(AXTranslationService);
499
- this.route = inject(ActivatedRoute);
500
- //#endregion
501
- //#region ---- Component State ----
502
- this.menuItems = signal([], ...(ngDevMode ? [{ debugName: "menuItems" }] : []));
503
- this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
504
- this.error = signal('', ...(ngDevMode ? [{ debugName: "error" }] : []));
505
- this.currentScope = signal(AXPPlatformScope.User, ...(ngDevMode ? [{ debugName: "currentScope" }] : []));
506
- this.allDropListIds = signal([], ...(ngDevMode ? [{ debugName: "allDropListIds" }] : []));
507
- }
508
- //#endregion
509
- //#region ---- Lifecycle ----
510
- async ngOnInit() {
511
- await super.ngOnInit();
512
- // Get scope from route
513
- this.route.params.subscribe(async (params) => {
514
- const scope = params['scope'];
515
- if (scope) {
516
- this.currentScope.set(scope);
517
- await this.loadMenuItems();
518
- this.recompute(); // Update page header after loading
519
- }
520
- });
521
- }
522
- //#endregion
523
- //#region ---- Data Loading ----
524
- /**
525
- * Load menu items for current scope
526
- */
527
- async loadMenuItems() {
528
- try {
529
- this.isLoading.set(true);
530
- this.error.set('');
531
- const items = await this.menuManagementService.getMenuTree(this.currentScope());
532
- this.menuItems.set(items);
533
- // Collect all drop list IDs for connecting them
534
- const dropListIds = this.collectDropListIds(items);
535
- this.allDropListIds.set(dropListIds);
536
- this.recompute();
537
- }
538
- catch (error) {
539
- this.error.set(error instanceof Error ? error.message : 'Failed to load menu items');
540
- this.toastService.danger('@application-management:menu-management.messages.load-error');
541
- }
542
- finally {
543
- this.isLoading.set(false);
544
- }
545
- }
546
- /**
547
- * Recursively collect all drop list IDs from menu tree
548
- * Includes drop zones for all items, even those without children
549
- */
550
- collectDropListIds(items, ids = []) {
551
- // Add root only once at the start
552
- if (ids.length === 0) {
553
- ids.push('menu-root');
554
- }
555
- items.forEach((item) => {
556
- // Add drop list ID for every item (they all can have children dropped into them)
557
- const dropListId = `menu-${item.name || item.path || 'unnamed'}`;
558
- if (!ids.includes(dropListId)) {
559
- ids.push(dropListId);
560
- }
561
- // Recursively collect from children if they exist
562
- if (item.children && item.children.length > 0) {
563
- this.collectDropListIds(item.children, ids);
564
- }
565
- });
566
- return ids;
567
- }
568
- //#endregion
569
- //#region ---- Page Layout Interface ----
570
- /**
571
- * Get page title
572
- */
573
- async getPageTitle() {
574
- const scopeName = this.currentScope();
575
- const scopeKey = scopeName === AXPPlatformScope.User ? 'user' : 'tenant';
576
- return this.translationService.translateAsync(`@application-management:menu-management.${scopeKey}.title`);
577
- }
578
- /**
579
- * Get page description
580
- */
581
- async getPageDescription() {
582
- return this.translationService.translateAsync('@application-management:menu-management.description');
583
- }
584
- /**
585
- * Get primary menu items (actions)
586
- */
587
- async getPrimaryMenuItems() {
588
- return [
589
- {
590
- title: await this.translationService.translateAsync('@application-management:menu-management.actions.add-root'),
591
- icon: 'fa-light fa-plus',
592
- color: 'primary',
593
- command: { name: 'add-root' },
594
- },
595
- ];
596
- }
597
- /**
598
- * Get secondary menu items
599
- */
600
- async getSecondaryMenuItems() {
601
- return [
602
- {
603
- title: await this.translationService.translateAsync('@application-management:menu-management.actions.reset'),
604
- icon: 'fa-light fa-rotate-left',
605
- color: 'danger',
606
- command: { name: 'reset' },
607
- },
608
- ];
609
- }
610
- /**
611
- * Execute commands from page actions
612
- */
613
- async execute(command) {
614
- switch (command.name) {
615
- case 'add-root':
616
- await this.addRootMenuItem();
617
- break;
618
- case 'reset':
619
- await this.resetCustomizations();
620
- break;
621
- }
622
- }
623
- //#endregion
624
- //#region ---- Event Handlers ----
625
- /**
626
- * Handle menu item action
627
- */
628
- async onActionTriggered(event) {
629
- const { action, item } = event;
630
- switch (action) {
631
- case 'show':
632
- await this.showMenuItem(item);
633
- break;
634
- case 'hide':
635
- await this.hideMenuItem(item);
636
- break;
637
- case 'edit':
638
- await this.editMenuItem(item);
639
- break;
640
- case 'delete':
641
- await this.deleteMenuItem(item);
642
- break;
643
- case 'add-child':
644
- await this.addChildMenuItem(item);
645
- break;
646
- case 'move-up':
647
- await this.moveItemUp(item);
648
- break;
649
- case 'move-down':
650
- await this.moveItemDown(item);
651
- break;
652
- case 'move-to-parent':
653
- await this.moveItemToParent(item);
654
- break;
655
- }
656
- }
657
- /**
658
- * Handle drag and drop
659
- */
660
- async onItemDropped(event) {
661
- try {
662
- // IMPORTANT: Find parent containers BEFORE modifying arrays
663
- const targetParent = this.findParentOfContainer(event.container.data, this.menuItems());
664
- const targetParentName = targetParent?.name ?? null;
665
- const sourceParent = this.findParentOfContainer(event.previousContainer.data, this.menuItems());
666
- const sourceParentName = sourceParent?.name ?? null;
667
- // Now perform the array operations
668
- if (event.previousContainer === event.container) {
669
- // Same container - just reorder
670
- moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
671
- }
672
- else {
673
- // Different container - move between parents
674
- transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
675
- }
676
- // Update signal to reflect the new order immediately
677
- this.menuItems.set([...this.menuItems()]);
678
- // Save the target container with correct parent context
679
- await this.menuManagementService.reorderMenuItems(this.currentScope(), event.container.data, targetParentName);
680
- // If moved between containers, also update the source container
681
- if (event.previousContainer !== event.container) {
682
- // Only reorder source if it still has items
683
- if (event.previousContainer.data.length > 0) {
684
- await this.menuManagementService.reorderMenuItems(this.currentScope(), event.previousContainer.data, sourceParentName);
685
- }
686
- }
687
- this.toastService.success('@application-management:menu-management.messages.reorder-success');
688
- // Force change detection by updating the signal
689
- // This ensures the UI reflects the changes without reloading from service
690
- this.menuItems.set([...this.menuItems()]);
691
- }
692
- catch (error) {
693
- this.toastService.danger('@application-management:menu-management.messages.reorder-error');
694
- // Reload on error to revert changes
695
- await this.loadMenuItems();
696
- }
697
- }
698
- /**
699
- * Find the parent item that owns a given children array
700
- * Returns the parent node, or null if the container is at root level
701
- */
702
- findParentOfContainer(containerData, items) {
703
- // Check if this is the root level
704
- if (containerData === items) {
705
- return null; // Root level has no parent
706
- }
707
- // Recursively search for the parent
708
- for (const item of items) {
709
- // Check if this item's children array is the target container
710
- if (item.children === containerData) {
711
- return item;
712
- }
713
- // Recursively search in children
714
- if (item.children && item.children.length > 0) {
715
- const found = this.findParentOfContainer(containerData, item.children);
716
- if (found !== null) {
717
- return found;
718
- }
719
- }
720
- }
721
- // Not found - this shouldn't happen in normal operation
722
- return null;
723
- }
724
- /**
725
- * Find an item in the tree and return its parent, container, and index
726
- */
727
- findItemAndParent(targetItem, items, parent = null) {
728
- // Search in current level
729
- const index = items.findIndex(item => item === targetItem);
730
- if (index !== -1) {
731
- return { parent, container: items, index };
732
- }
733
- // Search in children
734
- for (const item of items) {
735
- if (item.children && item.children.length > 0) {
736
- const found = this.findItemAndParent(targetItem, item.children, item);
737
- if (found) {
738
- return found;
739
- }
740
- }
741
- }
742
- return null;
743
- }
744
- /**
745
- * Add new root menu item
746
- */
747
- async addRootMenuItem() {
748
- await this.showMenuItemDialog(null);
749
- }
750
- /**
751
- * Reset customizations
752
- */
753
- async resetCustomizations() {
754
- const confirmed = await this.dialogService.confirm('@application-management:menu-management.reset.title', '@application-management:menu-management.reset.message');
755
- if (!confirmed)
756
- return;
757
- try {
758
- await this.menuManagementService.resetCustomizations(this.currentScope());
759
- this.toastService.success('@application-management:menu-management.messages.reset-success');
760
- await this.loadMenuItems();
761
- }
762
- catch (error) {
763
- this.toastService.danger('@application-management:menu-management.messages.reset-error');
764
- }
765
- }
766
- //#endregion
767
- //#region ---- Menu Item Actions ----
768
- /**
769
- * Show menu item
770
- */
771
- async showMenuItem(item) {
772
- try {
773
- if (!item.name)
774
- return;
775
- await this.menuManagementService.showMenuItem(this.currentScope(), item.name);
776
- this.toastService.success('@application-management:menu-management.messages.show-success');
777
- await this.loadMenuItems();
778
- }
779
- catch (error) {
780
- this.toastService.danger('@application-management:menu-management.messages.show-error');
781
- }
782
- }
783
- /**
784
- * Hide menu item
785
- */
786
- async hideMenuItem(item) {
787
- try {
788
- if (!item.name)
789
- return;
790
- await this.menuManagementService.hideMenuItem(this.currentScope(), item.name);
791
- this.toastService.success('@application-management:menu-management.messages.hide-success');
792
- await this.loadMenuItems();
793
- }
794
- catch (error) {
795
- this.toastService.danger('@application-management:menu-management.messages.hide-error');
796
- }
797
- }
798
- /**
799
- * Edit menu item
800
- */
801
- async editMenuItem(item) {
802
- await this.showMenuItemDialog(item);
803
- }
804
- /**
805
- * Delete custom menu item
806
- */
807
- async deleteMenuItem(item) {
808
- const confirmed = await this.dialogService.confirm('@general:actions.delete.title', '@application-management:menu-management.delete.message');
809
- if (!confirmed)
810
- return;
811
- try {
812
- if (!item.name)
813
- return;
814
- await this.menuManagementService.deleteCustomMenuItem(this.currentScope(), item.name);
815
- this.toastService.success('@application-management:menu-management.messages.delete-success');
816
- await this.loadMenuItems();
817
- }
818
- catch (error) {
819
- this.toastService.danger('@application-management:menu-management.messages.delete-error');
820
- }
821
- }
822
- /**
823
- * Add child menu item
824
- */
825
- async addChildMenuItem(parent) {
826
- await this.showMenuItemDialog(null, parent);
827
- }
828
- /**
829
- * Move item up in its parent container
830
- */
831
- async moveItemUp(item) {
832
- try {
833
- const result = this.findItemAndParent(item, this.menuItems());
834
- if (!result)
835
- return;
836
- const { parent, container, index } = result;
837
- if (index <= 0)
838
- return; // Already at top
839
- // Swap with previous item
840
- moveItemInArray(container, index, index - 1);
841
- // Update signal to reflect the change
842
- this.menuItems.set([...this.menuItems()]);
843
- // Save the reordered container
844
- const parentName = parent?.name ?? null;
845
- await this.menuManagementService.reorderMenuItems(this.currentScope(), container, parentName);
846
- this.toastService.success('@application-management:menu-management.messages.reorder-success');
847
- }
848
- catch (error) {
849
- this.toastService.danger('@application-management:menu-management.messages.reorder-error');
850
- await this.loadMenuItems();
851
- }
852
- }
853
- /**
854
- * Move item down in its parent container
855
- */
856
- async moveItemDown(item) {
857
- try {
858
- const result = this.findItemAndParent(item, this.menuItems());
859
- if (!result)
860
- return;
861
- const { parent, container, index } = result;
862
- if (index >= container.length - 1)
863
- return; // Already at bottom
864
- // Swap with next item
865
- moveItemInArray(container, index, index + 1);
866
- // Update signal to reflect the change
867
- this.menuItems.set([...this.menuItems()]);
868
- // Save the reordered container
869
- const parentName = parent?.name ?? null;
870
- await this.menuManagementService.reorderMenuItems(this.currentScope(), container, parentName);
871
- this.toastService.success('@application-management:menu-management.messages.reorder-success');
872
- }
873
- catch (error) {
874
- this.toastService.danger('@application-management:menu-management.messages.reorder-error');
875
- await this.loadMenuItems();
876
- }
877
- }
878
- /**
879
- * Move item to its parent's level (move out of nested level)
880
- */
881
- async moveItemToParent(item) {
882
- try {
883
- const result = this.findItemAndParent(item, this.menuItems());
884
- if (!result || !result.parent)
885
- return; // No parent to move to
886
- const { parent, container, index } = result;
887
- // Find the grandparent container
888
- const grandParentResult = this.findItemAndParent(parent, this.menuItems());
889
- const targetContainer = grandParentResult ? grandParentResult.container : this.menuItems();
890
- const parentIndexInGrandparent = grandParentResult ? grandParentResult.index : this.menuItems().indexOf(parent);
891
- // Remove from current container
892
- const [movedItem] = container.splice(index, 1);
893
- // Insert after parent in grandparent container
894
- targetContainer.splice(parentIndexInGrandparent + 1, 0, movedItem);
895
- // Update signal to reflect the change
896
- this.menuItems.set([...this.menuItems()]);
897
- // Save both containers
898
- const parentName = parent?.name ?? null;
899
- await this.menuManagementService.reorderMenuItems(this.currentScope(), container, parentName);
900
- const grandParentName = grandParentResult?.parent?.name ?? null;
901
- await this.menuManagementService.reorderMenuItems(this.currentScope(), targetContainer, grandParentName);
902
- this.toastService.success('@application-management:menu-management.messages.reorder-success');
903
- }
904
- catch (error) {
905
- this.toastService.danger('@application-management:menu-management.messages.reorder-error');
906
- await this.loadMenuItems();
907
- }
908
- }
909
- //#endregion
910
- //#region ---- Dialog Helpers ----
911
- /**
912
- * Show menu item dialog (add/edit)
913
- */
914
- async showMenuItemDialog(item, parent) {
915
- const isEdit = !!item;
916
- const title = isEdit
917
- ? '@application-management:menu-management.edit-dialog.title'
918
- : '@application-management:menu-management.add-dialog.title';
919
- const context = {
920
- name: item?.name || '',
921
- text: item?.text || '',
922
- icon: item?.icon || '',
923
- path: item?.path || '',
924
- description: item?.description || '',
925
- };
926
- const dialogRef = await this.layoutBuilder
927
- .create()
928
- .dialog((dialog) => {
929
- dialog
930
- .setTitle(title)
931
- .setContext(context)
932
- .content((flex) => {
933
- flex
934
- .setDirection('column')
935
- .formField('@application-management:menu-management.fields.name', (field) => {
936
- field.path('name');
937
- field.textBox({
938
- placeholder: '@application-management:menu-management.fields.name',
939
- validations: [{ rule: 'required' }],
940
- disabled: isEdit && item?.isBuiltIn,
941
- });
942
- })
943
- .formField('@application-management:menu-management.fields.text', (field) => {
944
- field.path('text');
945
- field.textBox({
946
- placeholder: '@application-management:menu-management.fields.text',
947
- validations: [{ rule: 'required' }],
948
- });
949
- })
950
- .formField('@application-management:menu-management.fields.icon', (field) => {
951
- field.path('icon');
952
- field.customWidget('icon-chooser', {});
953
- })
954
- .formField('@application-management:menu-management.fields.path', (field) => {
955
- field.path('path');
956
- field.textBox({
957
- placeholder: '@application-management:menu-management.fields.path',
958
- disabled: isEdit && item?.isBuiltIn,
959
- });
960
- })
961
- .formField('@application-management:menu-management.fields.description', (field) => {
962
- field.path('description');
963
- field.largeTextBox({
964
- placeholder: '@application-management:menu-management.fields.description',
965
- rows: 3,
966
- });
967
- });
968
- })
969
- .setActions((actions) => {
970
- actions.cancel('@general:actions.cancel.title').submit('@general:actions.save.title');
971
- });
972
- })
973
- .show();
974
- const action = dialogRef.action();
975
- if (action === 'cancel') {
976
- dialogRef.close();
977
- return;
978
- }
979
- const formData = dialogRef.context();
980
- try {
981
- if (isEdit && item?.name) {
982
- // Update existing item
983
- if (item.isCustom) {
984
- await this.menuManagementService.updateCustomMenuItem(this.currentScope(), item.name, formData);
985
- }
986
- else {
987
- await this.menuManagementService.updateMenuProperties(this.currentScope(), item.name, formData);
988
- }
989
- }
990
- else {
991
- // Add new custom item
992
- const newItem = {
993
- name: formData.name,
994
- text: formData.text,
995
- icon: formData.icon,
996
- path: formData.path,
997
- priority: formData.priority,
998
- description: formData.description,
999
- };
1000
- // If parent is specified, add as child
1001
- if (parent?.name) {
1002
- // Add custom item as child of parent
1003
- await this.menuManagementService.addCustomMenuItemAsChild(this.currentScope(), newItem, parent.name);
1004
- }
1005
- else {
1006
- // Add as root level item
1007
- await this.menuManagementService.addCustomMenuItem(this.currentScope(), newItem);
1008
- }
1009
- }
1010
- this.toastService.success('@application-management:menu-management.messages.save-success');
1011
- await this.loadMenuItems();
1012
- dialogRef.close();
1013
- }
1014
- catch (error) {
1015
- this.toastService.danger('@application-management:menu-management.messages.save-error');
1016
- }
1017
- }
1018
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMMenuListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1019
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: AXMMenuListComponent, isStandalone: true, selector: "axm-menu-list", host: { classAttribute: "axm-menu-list-page" }, providers: [
1020
- {
1021
- provide: AXPPageLayoutBase,
1022
- useExisting: AXMMenuListComponent,
1023
- },
1024
- ], 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]=\"('@application-management:menu-management.loading.title' | translate | async) || 'Loading...'\"\n [description]=\"\n ('@application-management:menu-management.loading.description' | translate | async) || 'Please wait'\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]=\"('@application-management:menu-management.error.title' | translate | async) || 'Error'\"\n [description]=\"error() || 'An error occurred'\"\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 (menuItems().length === 0) {\n <!-- Empty State -->\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"('@application-management:menu-management.empty-state.title' | translate | async) || 'No menu items'\"\n [description]=\"\n ('@application-management:menu-management.empty-state.description' | translate | async) ||\n 'Add a new menu item to get started'\n \"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@application-management:menu-management.actions.add-root' | 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\n class=\"axm-menu-list__tree\"\n cdkDropList\n id=\"menu-root\"\n [cdkDropListData]=\"menuItems()\"\n [cdkDropListConnectedTo]=\"allDropListIds()\"\n (cdkDropListDropped)=\"onItemDropped($event)\"\n >\n @for (item of menuItems(); track item.name || item.path || $index; let i = $index) {\n <axm-menu-tree-item\n [item]=\"item\"\n [level]=\"0\"\n [canDelete]=\"true\"\n [connectedDropLists]=\"allDropListIds()\"\n [canMoveUp]=\"i > 0\"\n [canMoveDown]=\"i < menuItems().length - 1\"\n [canMoveToParent]=\"false\"\n (actionTriggered)=\"onActionTriggered($event)\"\n (itemDropped)=\"onItemDropped($event)\"\n />\n }\n </div>\n </div>\n }\n </axp-page-content>\n</axp-page-layout>\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__info-banner{display:flex;align-items:center;gap:.75rem;border-radius:.375rem;padding:1rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-primary-500),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-list__info-banner i{font-size:1.125rem;line-height:1.75rem}.axm-menu-list-page .axm-menu-list__info-banner span{font-size:.875rem;line-height:1.25rem}.axm-menu-list-page .axm-menu-list__tree{display:flex;flex-direction:column;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { 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: "ngmodule", type: AXTranslationModule }, { 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: "component", type: AXMMenuTreeItemComponent, selector: "axm-menu-tree-item", inputs: ["item", "level", "canDelete", "connectedDropLists", "canMoveUp", "canMoveDown", "canMoveToParent"], outputs: ["actionTriggered", "itemDropped"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1025
- }
1026
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMMenuListComponent, decorators: [{
1027
- type: Component,
1028
- args: [{ selector: 'axm-menu-list', standalone: true, imports: [
1029
- CommonModule,
1030
- CdkDropList,
1031
- AXButtonModule,
1032
- AXTranslationModule,
1033
- AXPPageLayoutComponent,
1034
- AXPThemeLayoutBlockComponent,
1035
- AXPStateMessageComponent,
1036
- AXMMenuTreeItemComponent,
1037
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
1038
- {
1039
- provide: AXPPageLayoutBase,
1040
- useExisting: AXMMenuListComponent,
1041
- },
1042
- ], 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]=\"('@application-management:menu-management.loading.title' | translate | async) || 'Loading...'\"\n [description]=\"\n ('@application-management:menu-management.loading.description' | translate | async) || 'Please wait'\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]=\"('@application-management:menu-management.error.title' | translate | async) || 'Error'\"\n [description]=\"error() || 'An error occurred'\"\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 (menuItems().length === 0) {\n <!-- Empty State -->\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"('@application-management:menu-management.empty-state.title' | translate | async) || 'No menu items'\"\n [description]=\"\n ('@application-management:menu-management.empty-state.description' | translate | async) ||\n 'Add a new menu item to get started'\n \"\n >\n <ax-button\n slot=\"actions\"\n [text]=\"'@application-management:menu-management.actions.add-root' | 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\n class=\"axm-menu-list__tree\"\n cdkDropList\n id=\"menu-root\"\n [cdkDropListData]=\"menuItems()\"\n [cdkDropListConnectedTo]=\"allDropListIds()\"\n (cdkDropListDropped)=\"onItemDropped($event)\"\n >\n @for (item of menuItems(); track item.name || item.path || $index; let i = $index) {\n <axm-menu-tree-item\n [item]=\"item\"\n [level]=\"0\"\n [canDelete]=\"true\"\n [connectedDropLists]=\"allDropListIds()\"\n [canMoveUp]=\"i > 0\"\n [canMoveDown]=\"i < menuItems().length - 1\"\n [canMoveToParent]=\"false\"\n (actionTriggered)=\"onActionTriggered($event)\"\n (itemDropped)=\"onItemDropped($event)\"\n />\n }\n </div>\n </div>\n }\n </axp-page-content>\n</axp-page-layout>\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__info-banner{display:flex;align-items:center;gap:.75rem;border-radius:.375rem;padding:1rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-primary-500),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.axm-menu-list-page .axm-menu-list__info-banner i{font-size:1.125rem;line-height:1.75rem}.axm-menu-list-page .axm-menu-list__info-banner span{font-size:.875rem;line-height:1.25rem}.axm-menu-list-page .axm-menu-list__tree{display:flex;flex-direction:column;gap:.5rem}\n"] }]
1043
- }] });
1044
-
1045
- export { AXMMenuListComponent };
1046
- //# sourceMappingURL=acorex-modules-application-management-menu-list.component-BMbl5rtn.mjs.map