@acorex/platform 20.7.10 → 20.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/index.d.ts +1 -0
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +340 -178
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +70 -63
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +158 -55
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/layout/components/index.d.ts +207 -44
- package/layout/entity/index.d.ts +1 -2
- package/layout/widgets/index.d.ts +12 -0
- package/package.json +5 -5
|
@@ -15,7 +15,7 @@ import { AXPWorkflowService } from '@acorex/platform/workflow';
|
|
|
15
15
|
import * as i1 from '@angular/common';
|
|
16
16
|
import { CommonModule, NgTemplateOutlet, AsyncPipe } from '@angular/common';
|
|
17
17
|
import * as i0 from '@angular/core';
|
|
18
|
-
import { input, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, signal, effect, InjectionToken, computed, Injectable, Directive, viewChild, contentChild, ElementRef, output, afterNextRender, model, Injector, ViewContainerRef, runInInjectionContext, Optional, Inject, NgModule, linkedSignal, untracked, HostListener, ViewChildren, Input, EventEmitter, Output } from '@angular/core';
|
|
18
|
+
import { input, ChangeDetectionStrategy, ViewEncapsulation, Component, inject, signal, effect, InjectionToken, computed, Injectable, Directive, viewChild, contentChild, ElementRef, output, afterNextRender, model, Injector, ViewContainerRef, runInInjectionContext, Optional, Inject, NgModule, linkedSignal, untracked, HostListener, ViewChildren, DestroyRef, Input, EventEmitter, Output } from '@angular/core';
|
|
19
19
|
import { AXAccordionCdkModule } from '@acorex/cdk/accordion';
|
|
20
20
|
import { AXTagModule } from '@acorex/components/tag';
|
|
21
21
|
import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
|
|
@@ -66,7 +66,6 @@ import { AXDialogService } from '@acorex/components/dialog';
|
|
|
66
66
|
import { AXToastService } from '@acorex/components/toast';
|
|
67
67
|
import { AXTreeViewComponent } from '@acorex/components/tree-view';
|
|
68
68
|
import { AXPLayoutBuilderService, AXPLayoutRendererComponent } from '@acorex/platform/layout/builder';
|
|
69
|
-
import { Subject, BehaviorSubject, timer, takeUntil } from 'rxjs';
|
|
70
69
|
import * as i2$6 from '@acorex/components/image';
|
|
71
70
|
import { AXImageModule } from '@acorex/components/image';
|
|
72
71
|
import { AXPlatform } from '@acorex/core/platform';
|
|
@@ -75,6 +74,7 @@ import { AXAccordionModule } from '@acorex/components/accordion';
|
|
|
75
74
|
import { AXButtonGroupModule } from '@acorex/components/button-group';
|
|
76
75
|
import * as i5$3 from '@acorex/components/tabs';
|
|
77
76
|
import { AXTabsModule } from '@acorex/components/tabs';
|
|
77
|
+
import { BehaviorSubject, timer, Subject, takeUntil } from 'rxjs';
|
|
78
78
|
import { tap } from 'rxjs/operators';
|
|
79
79
|
import * as i1$7 from '@acorex/components/avatar';
|
|
80
80
|
import { AXAvatarModule } from '@acorex/components/avatar';
|
|
@@ -2900,7 +2900,26 @@ const AXP_MENU_CUSTOMIZER_SERVICE = new InjectionToken('AXP_MENU_CUSTOMIZER_SERV
|
|
|
2900
2900
|
* and manage menu items using a tree-like interface.
|
|
2901
2901
|
* Can be used standalone or within popups/dialogs.
|
|
2902
2902
|
*
|
|
2903
|
-
*
|
|
2903
|
+
* @description
|
|
2904
|
+
* This component provides a visual interface for customizing menu structures.
|
|
2905
|
+
* It supports:
|
|
2906
|
+
* - Drag and drop reordering of menu items
|
|
2907
|
+
* - Showing/hiding menu items
|
|
2908
|
+
* - Adding custom menu items
|
|
2909
|
+
* - Editing menu item properties
|
|
2910
|
+
* - Resetting customizations to defaults
|
|
2911
|
+
*
|
|
2912
|
+
* @example
|
|
2913
|
+
* ```html
|
|
2914
|
+
* <axp-menu-customizer
|
|
2915
|
+
* [scopeKey]="'edition:my-edition'"
|
|
2916
|
+
* [showToolbar]="true"
|
|
2917
|
+
* [allowAddItems]="true"
|
|
2918
|
+
* (saved)="onSaved()"
|
|
2919
|
+
* />
|
|
2920
|
+
* ```
|
|
2921
|
+
*
|
|
2922
|
+
* @requires AXP_MENU_CUSTOMIZER_SERVICE - Must provide an implementation of AXPMenuCustomizerService
|
|
2904
2923
|
*/
|
|
2905
2924
|
class AXPMenuCustomizerComponent {
|
|
2906
2925
|
constructor() {
|
|
@@ -2910,6 +2929,7 @@ class AXPMenuCustomizerComponent {
|
|
|
2910
2929
|
this.dialogService = inject(AXDialogService);
|
|
2911
2930
|
this.toastService = inject(AXToastService);
|
|
2912
2931
|
this.translationService = inject(AXTranslationService);
|
|
2932
|
+
this.destroyRef = inject(DestroyRef);
|
|
2913
2933
|
//#endregion
|
|
2914
2934
|
//#region ---- Inputs & Outputs ----
|
|
2915
2935
|
/** The scope key for loading/saving menu customizations (e.g., 'edition:{id}', 'tenant:{id}') */
|
|
@@ -2918,9 +2938,9 @@ class AXPMenuCustomizerComponent {
|
|
|
2918
2938
|
this.showToolbar = input(true, ...(ngDevMode ? [{ debugName: "showToolbar" }] : []));
|
|
2919
2939
|
/** Whether to allow adding custom menu items */
|
|
2920
2940
|
this.allowAddItems = input(true, ...(ngDevMode ? [{ debugName: "allowAddItems" }] : []));
|
|
2921
|
-
/** Drag behavior for the tree view: 'none' | 'move' | '
|
|
2941
|
+
/** Drag behavior for the tree view: 'none' | 'order-only' | 'move' | 'both' */
|
|
2922
2942
|
this.dragBehavior = input('both', ...(ngDevMode ? [{ debugName: "dragBehavior" }] : []));
|
|
2923
|
-
/** Drag area for the tree view: '
|
|
2943
|
+
/** Drag area for the tree view: 'handler' | 'item' */
|
|
2924
2944
|
this.dragArea = input('handler', ...(ngDevMode ? [{ debugName: "dragArea" }] : []));
|
|
2925
2945
|
/** Emitted when changes are saved */
|
|
2926
2946
|
this.saved = output();
|
|
@@ -2928,88 +2948,136 @@ class AXPMenuCustomizerComponent {
|
|
|
2928
2948
|
this.cancelled = output();
|
|
2929
2949
|
//#endregion
|
|
2930
2950
|
//#region ---- Component State ----
|
|
2951
|
+
/** Reference to the tree view component */
|
|
2931
2952
|
this.tree = viewChild(AXTreeViewComponent, ...(ngDevMode ? [{ debugName: "tree" }] : []));
|
|
2953
|
+
/** Tree nodes data source */
|
|
2932
2954
|
this.treeNodes = signal([], ...(ngDevMode ? [{ debugName: "treeNodes" }] : []));
|
|
2933
|
-
|
|
2934
|
-
this.
|
|
2955
|
+
/** Current loading/error state */
|
|
2956
|
+
this.state = signal({ status: 'idle' }, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
2957
|
+
/** Flag to prevent concurrent sync operations */
|
|
2935
2958
|
this.isSyncing = false;
|
|
2936
|
-
|
|
2959
|
+
//#endregion
|
|
2960
|
+
//#region ---- Computed Properties ----
|
|
2961
|
+
/** Whether the component is currently loading */
|
|
2962
|
+
this.isLoading = computed(() => this.state().status === 'loading', ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
2963
|
+
/** Whether there is an error state */
|
|
2964
|
+
this.hasError = computed(() => this.state().status === 'error', ...(ngDevMode ? [{ debugName: "hasError" }] : []));
|
|
2965
|
+
/** The current error message, if any */
|
|
2966
|
+
this.errorMessage = computed(() => {
|
|
2967
|
+
const currentState = this.state();
|
|
2968
|
+
return currentState.status === 'error' ? currentState.message : '';
|
|
2969
|
+
}, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
2970
|
+
/** Whether the tree has nodes to display */
|
|
2971
|
+
this.hasNodes = computed(() => this.treeNodes().length > 0, ...(ngDevMode ? [{ debugName: "hasNodes" }] : []));
|
|
2972
|
+
/** Whether to show the content (tree view) */
|
|
2973
|
+
this.showContent = computed(() => !this.isLoading() && !this.hasError() && this.hasNodes(), ...(ngDevMode ? [{ debugName: "showContent" }] : []));
|
|
2974
|
+
/** Whether to show the empty state */
|
|
2975
|
+
this.showEmptyState = computed(() => !this.isLoading() && !this.hasError() && !this.hasNodes(), ...(ngDevMode ? [{ debugName: "showEmptyState" }] : []));
|
|
2976
|
+
this.eff = effect(() => {
|
|
2977
|
+
console.log('treeNodes', this.treeNodes());
|
|
2978
|
+
}, ...(ngDevMode ? [{ debugName: "eff" }] : []));
|
|
2979
|
+
this.eff2 = effect(() => {
|
|
2980
|
+
console.log('datasource', this.tree()?.datasource());
|
|
2981
|
+
}, ...(ngDevMode ? [{ debugName: "eff2" }] : []));
|
|
2937
2982
|
}
|
|
2938
2983
|
//#endregion
|
|
2939
2984
|
//#region ---- Lifecycle ----
|
|
2940
2985
|
async ngOnInit() {
|
|
2941
2986
|
await this.loadMenuItems();
|
|
2942
2987
|
}
|
|
2943
|
-
ngOnDestroy() {
|
|
2944
|
-
this.destroy$.next();
|
|
2945
|
-
this.destroy$.complete();
|
|
2946
|
-
}
|
|
2947
2988
|
//#endregion
|
|
2948
2989
|
//#region ---- Event Handlers ----
|
|
2949
2990
|
/**
|
|
2950
|
-
* Handle before drop validation
|
|
2991
|
+
* Handle before drop validation.
|
|
2992
|
+
* Prevents dropping into items with paths (leaf nodes that can't have children).
|
|
2993
|
+
*
|
|
2994
|
+
* @param event - The before drop event from tree view
|
|
2951
2995
|
*/
|
|
2952
|
-
|
|
2953
|
-
const targetParent =
|
|
2996
|
+
handleBeforeDrop(event) {
|
|
2997
|
+
const targetParent = event.currentParent?.['data'];
|
|
2954
2998
|
// Prevent dropping into items with paths (leaf nodes)
|
|
2955
2999
|
if (targetParent?.menuItem?.path) {
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
this.toastService.warning(message);
|
|
2959
|
-
return;
|
|
3000
|
+
event.canceled = true;
|
|
3001
|
+
this.showWarningMessage('@platform-management:menu-management.messages.error.move');
|
|
2960
3002
|
}
|
|
2961
3003
|
}
|
|
2962
3004
|
/**
|
|
2963
|
-
* Handle
|
|
2964
|
-
*
|
|
3005
|
+
* Handle order change event (reordering within the same parent).
|
|
3006
|
+
*
|
|
3007
|
+
* @param event - The drop event from tree view
|
|
2965
3008
|
*/
|
|
2966
|
-
async
|
|
2967
|
-
|
|
3009
|
+
async handleOrderChange(event) {
|
|
3010
|
+
console.log('Order changed:', {
|
|
3011
|
+
node: event.node?.['id'],
|
|
3012
|
+
previousIndex: event.previousIndex,
|
|
3013
|
+
currentIndex: event.currentIndex,
|
|
3014
|
+
parent: event.currentParent?.['id'] ?? 'root',
|
|
3015
|
+
});
|
|
3016
|
+
// Use setTimeout to ensure tree view has finished updating the datasource
|
|
3017
|
+
setTimeout(() => this.syncTreeChanges(), 0);
|
|
3018
|
+
}
|
|
3019
|
+
/**
|
|
3020
|
+
* Handle move change event (moving to a different parent).
|
|
3021
|
+
*
|
|
3022
|
+
* @param event - The drop event from tree view
|
|
3023
|
+
*/
|
|
3024
|
+
async handleMoveChange(event) {
|
|
3025
|
+
console.log('Move changed:', {
|
|
3026
|
+
node: event.node?.['id'],
|
|
3027
|
+
previousParent: event.previousParent?.['id'] ?? 'root',
|
|
3028
|
+
currentParent: event.currentParent?.['id'] ?? 'root',
|
|
3029
|
+
currentIndex: event.currentIndex,
|
|
3030
|
+
});
|
|
3031
|
+
// Use setTimeout to ensure tree view has finished updating the datasource
|
|
3032
|
+
setTimeout(() => this.syncTreeChanges(), 0);
|
|
2968
3033
|
}
|
|
2969
3034
|
//#endregion
|
|
2970
3035
|
//#region ---- Data Loading ----
|
|
2971
3036
|
/**
|
|
2972
|
-
* Load menu tree for current scope
|
|
3037
|
+
* Load menu tree for current scope.
|
|
3038
|
+
* Updates the component state to loading, then success or error.
|
|
3039
|
+
* Creates new array reference to ensure UI updates.
|
|
2973
3040
|
*/
|
|
2974
3041
|
async loadMenuItems() {
|
|
2975
3042
|
try {
|
|
2976
|
-
this.
|
|
2977
|
-
this.error.set('');
|
|
3043
|
+
this.state.set({ status: 'loading' });
|
|
2978
3044
|
const treeNodes = await this.menuCustomizerService.getMenuTree(this.scopeKey());
|
|
2979
|
-
|
|
3045
|
+
// Create new array reference to ensure tree view detects the change
|
|
3046
|
+
this.treeNodes.set([...treeNodes]);
|
|
3047
|
+
this.state.set({ status: 'success' });
|
|
2980
3048
|
}
|
|
2981
3049
|
catch (error) {
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
this.
|
|
2985
|
-
}
|
|
2986
|
-
finally {
|
|
2987
|
-
this.isLoading.set(false);
|
|
3050
|
+
const message = error instanceof Error ? error.message : 'Failed to load menu items';
|
|
3051
|
+
this.state.set({ status: 'error', message });
|
|
3052
|
+
this.showErrorMessage('@platform-management:menu-management.messages.error.load');
|
|
2988
3053
|
}
|
|
2989
3054
|
}
|
|
2990
3055
|
/**
|
|
2991
|
-
* Sync tree changes to backend
|
|
3056
|
+
* Sync tree changes to backend.
|
|
3057
|
+
* Prevents concurrent sync operations using the isSyncing flag.
|
|
3058
|
+
* Reloads data with new reference after successful sync.
|
|
2992
3059
|
*/
|
|
2993
3060
|
async syncTreeChanges() {
|
|
2994
3061
|
if (this.isSyncing) {
|
|
2995
3062
|
return;
|
|
2996
3063
|
}
|
|
3064
|
+
// Get nodes from the tree component's datasource directly
|
|
3065
|
+
// This ensures we get the most up-to-date structure after drag-drop
|
|
3066
|
+
const treeComponent = this.tree();
|
|
3067
|
+
const nodes = treeComponent?.getRootNodes() ?? this.treeNodes();
|
|
3068
|
+
if (!nodes || nodes.length === 0) {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
2997
3071
|
try {
|
|
2998
3072
|
this.isSyncing = true;
|
|
2999
|
-
// Get nodes from signal - the tree component mutates the array in place
|
|
3000
|
-
// so this.treeNodes() will have the updated structure after drag-drop
|
|
3001
|
-
const nodes = this.treeNodes();
|
|
3002
|
-
if (!nodes || nodes.length === 0) {
|
|
3003
|
-
return;
|
|
3004
|
-
}
|
|
3005
3073
|
await this.menuCustomizerService.syncTreeChanges(this.scopeKey(), nodes);
|
|
3006
|
-
|
|
3007
|
-
|
|
3074
|
+
this.showSuccessMessage('@platform-management:menu-management.messages.success.reorder');
|
|
3075
|
+
// Reload with new array reference to ensure UI is in sync
|
|
3076
|
+
await this.loadMenuItems();
|
|
3008
3077
|
}
|
|
3009
3078
|
catch (error) {
|
|
3010
3079
|
console.error('Failed to sync tree changes:', error);
|
|
3011
|
-
|
|
3012
|
-
this.toastService.danger(message);
|
|
3080
|
+
this.showErrorMessage('@platform-management:menu-management.messages.error.sync');
|
|
3013
3081
|
}
|
|
3014
3082
|
finally {
|
|
3015
3083
|
this.isSyncing = false;
|
|
@@ -3018,72 +3086,77 @@ class AXPMenuCustomizerComponent {
|
|
|
3018
3086
|
//#endregion
|
|
3019
3087
|
//#region ---- Public Methods ----
|
|
3020
3088
|
/**
|
|
3021
|
-
* Collapse all tree nodes
|
|
3089
|
+
* Collapse all tree nodes.
|
|
3022
3090
|
*/
|
|
3023
3091
|
collapseAll() {
|
|
3024
3092
|
this.tree()?.collapseAll();
|
|
3025
3093
|
}
|
|
3026
3094
|
/**
|
|
3027
|
-
* Expand all tree nodes
|
|
3095
|
+
* Expand all tree nodes.
|
|
3028
3096
|
*/
|
|
3029
|
-
expandAll() {
|
|
3030
|
-
this.tree()?.expandAll();
|
|
3097
|
+
async expandAll() {
|
|
3098
|
+
await this.tree()?.expandAll();
|
|
3031
3099
|
}
|
|
3032
3100
|
/**
|
|
3033
|
-
* Reset all customizations
|
|
3101
|
+
* Reset all customizations to defaults.
|
|
3102
|
+
* Shows a confirmation dialog before resetting.
|
|
3034
3103
|
*/
|
|
3035
3104
|
async resetCustomizations() {
|
|
3036
|
-
const
|
|
3037
|
-
const message = await this.translationService.translateAsync('@platform-management:menu-management.actions.reset.confirm.message');
|
|
3038
|
-
const confirmed = await this.dialogService.confirm(title, message);
|
|
3105
|
+
const confirmed = await this.confirmAction('@platform-management:menu-management.actions.reset.confirm.title', '@platform-management:menu-management.actions.reset.confirm.message');
|
|
3039
3106
|
if (!confirmed)
|
|
3040
3107
|
return;
|
|
3041
3108
|
try {
|
|
3042
3109
|
await this.menuCustomizerService.resetCustomizations(this.scopeKey());
|
|
3043
|
-
|
|
3044
|
-
this.toastService.success(successMessage);
|
|
3110
|
+
this.showSuccessMessage('@platform-management:menu-management.messages.success.reset');
|
|
3045
3111
|
}
|
|
3046
3112
|
catch (error) {
|
|
3047
3113
|
console.error('Failed to reset customizations:', error);
|
|
3048
|
-
|
|
3049
|
-
this.toastService.danger(errorMessage);
|
|
3114
|
+
this.showErrorMessage('@platform-management:menu-management.messages.error.reset');
|
|
3050
3115
|
}
|
|
3051
3116
|
finally {
|
|
3052
3117
|
await this.loadMenuItems();
|
|
3053
3118
|
}
|
|
3054
3119
|
}
|
|
3055
3120
|
/**
|
|
3056
|
-
* Add new root menu item
|
|
3121
|
+
* Add new root menu item.
|
|
3122
|
+
* Opens the menu item dialog without a parent.
|
|
3057
3123
|
*/
|
|
3058
3124
|
async addRootMenuItem() {
|
|
3059
3125
|
await this.showMenuItemDialog(null, null);
|
|
3060
3126
|
}
|
|
3127
|
+
/**
|
|
3128
|
+
* Reload the menu items from the service.
|
|
3129
|
+
* Useful for external refresh triggers.
|
|
3130
|
+
*/
|
|
3131
|
+
async refresh() {
|
|
3132
|
+
await this.loadMenuItems();
|
|
3133
|
+
}
|
|
3061
3134
|
//#endregion
|
|
3062
3135
|
//#region ---- Action Handlers ----
|
|
3063
3136
|
/**
|
|
3064
|
-
* Handle menu item action
|
|
3137
|
+
* Handle menu item action dispatched from the template.
|
|
3138
|
+
*
|
|
3139
|
+
* @param action - The action to perform
|
|
3140
|
+
* @param nodeData - The node data to perform the action on
|
|
3065
3141
|
*/
|
|
3066
3142
|
async onAction(action, nodeData) {
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
await this.deleteMenuItem(nodeData);
|
|
3079
|
-
break;
|
|
3080
|
-
case 'add-child':
|
|
3081
|
-
await this.addChildMenuItem(nodeData);
|
|
3082
|
-
break;
|
|
3143
|
+
const actionHandlers = {
|
|
3144
|
+
show: () => this.showMenuItem(nodeData),
|
|
3145
|
+
hide: () => this.hideMenuItem(nodeData),
|
|
3146
|
+
edit: () => this.editMenuItem(nodeData),
|
|
3147
|
+
delete: () => this.deleteMenuItem(nodeData),
|
|
3148
|
+
'add-child': () => this.addChildMenuItem(nodeData),
|
|
3149
|
+
move: () => Promise.resolve(), // Move is handled by drag-drop
|
|
3150
|
+
};
|
|
3151
|
+
const handler = actionHandlers[action];
|
|
3152
|
+
if (handler) {
|
|
3153
|
+
await handler();
|
|
3083
3154
|
}
|
|
3084
3155
|
}
|
|
3085
3156
|
/**
|
|
3086
|
-
* Add new child menu item
|
|
3157
|
+
* Add new child menu item to a parent.
|
|
3158
|
+
*
|
|
3159
|
+
* @param parentNodeData - The parent node data
|
|
3087
3160
|
*/
|
|
3088
3161
|
async addChildMenuItem(parentNodeData) {
|
|
3089
3162
|
await this.showMenuItemDialog(null, parentNodeData.menuItem.name ?? null);
|
|
@@ -3091,66 +3164,66 @@ class AXPMenuCustomizerComponent {
|
|
|
3091
3164
|
//#endregion
|
|
3092
3165
|
//#region ---- Menu Item Actions ----
|
|
3093
3166
|
/**
|
|
3094
|
-
* Show menu item
|
|
3167
|
+
* Show a hidden menu item.
|
|
3168
|
+
*
|
|
3169
|
+
* @param nodeData - The node data containing the menu item to show
|
|
3095
3170
|
*/
|
|
3096
3171
|
async showMenuItem(nodeData) {
|
|
3097
|
-
|
|
3172
|
+
const menuName = nodeData.menuItem.name;
|
|
3173
|
+
if (!menuName)
|
|
3174
|
+
return;
|
|
3175
|
+
await this.executeMenuAction(() => this.menuCustomizerService.showMenuItem(this.scopeKey(), menuName), '@platform-management:menu-management.messages.success.show', '@platform-management:menu-management.messages.error.show');
|
|
3098
3176
|
}
|
|
3099
3177
|
/**
|
|
3100
|
-
* Hide menu item
|
|
3178
|
+
* Hide a menu item.
|
|
3179
|
+
*
|
|
3180
|
+
* @param nodeData - The node data containing the menu item to hide
|
|
3101
3181
|
*/
|
|
3102
3182
|
async hideMenuItem(nodeData) {
|
|
3103
|
-
|
|
3183
|
+
const menuName = nodeData.menuItem.name;
|
|
3184
|
+
if (!menuName)
|
|
3185
|
+
return;
|
|
3186
|
+
await this.executeMenuAction(() => this.menuCustomizerService.hideMenuItem(this.scopeKey(), menuName), '@platform-management:menu-management.messages.success.hide', '@platform-management:menu-management.messages.error.hide');
|
|
3104
3187
|
}
|
|
3105
3188
|
/**
|
|
3106
|
-
* Edit menu item
|
|
3189
|
+
* Edit a menu item.
|
|
3190
|
+
*
|
|
3191
|
+
* @param nodeData - The node data containing the menu item to edit
|
|
3107
3192
|
*/
|
|
3108
3193
|
async editMenuItem(nodeData) {
|
|
3109
3194
|
await this.showMenuItemDialog(nodeData);
|
|
3110
3195
|
}
|
|
3111
3196
|
/**
|
|
3112
|
-
* Delete custom menu item
|
|
3197
|
+
* Delete a custom menu item.
|
|
3198
|
+
* Shows a confirmation dialog before deleting.
|
|
3199
|
+
*
|
|
3200
|
+
* @param nodeData - The node data containing the menu item to delete
|
|
3113
3201
|
*/
|
|
3114
3202
|
async deleteMenuItem(nodeData) {
|
|
3115
|
-
const
|
|
3116
|
-
|
|
3117
|
-
|
|
3203
|
+
const item = nodeData.menuItem;
|
|
3204
|
+
if (!item.name)
|
|
3205
|
+
return;
|
|
3206
|
+
const confirmed = await this.confirmAction('@general:actions.delete.title', '@platform-management:menu-management.actions.delete.confirm.message');
|
|
3118
3207
|
if (!confirmed)
|
|
3119
3208
|
return;
|
|
3120
|
-
|
|
3121
|
-
const item = nodeData.menuItem;
|
|
3122
|
-
if (!item.name)
|
|
3123
|
-
return;
|
|
3124
|
-
await this.menuCustomizerService.deleteCustomMenuItem(this.scopeKey(), item.name);
|
|
3125
|
-
const successMessage = await this.translationService.translateAsync('@platform-management:menu-management.messages.success.delete');
|
|
3126
|
-
this.toastService.success(successMessage);
|
|
3127
|
-
await this.loadMenuItems();
|
|
3128
|
-
}
|
|
3129
|
-
catch (error) {
|
|
3130
|
-
const errorMessage = await this.translationService.translateAsync('@platform-management:menu-management.messages.error.delete');
|
|
3131
|
-
this.toastService.danger(errorMessage);
|
|
3132
|
-
}
|
|
3209
|
+
await this.executeMenuAction(() => this.menuCustomizerService.deleteCustomMenuItem(this.scopeKey(), item.name), '@platform-management:menu-management.messages.success.delete', '@platform-management:menu-management.messages.error.delete');
|
|
3133
3210
|
}
|
|
3134
3211
|
//#endregion
|
|
3135
3212
|
//#region ---- Dialog Helpers ----
|
|
3136
3213
|
/**
|
|
3137
|
-
* Show menu item dialog (add/edit)
|
|
3214
|
+
* Show menu item dialog (add/edit).
|
|
3215
|
+
*
|
|
3216
|
+
* @param nodeData - The node data for editing, or null for adding
|
|
3217
|
+
* @param parentName - The parent menu name for adding child items
|
|
3138
3218
|
*/
|
|
3139
3219
|
async showMenuItemDialog(nodeData, parentName = null) {
|
|
3140
3220
|
const item = nodeData?.menuItem;
|
|
3141
3221
|
const isEdit = !!item;
|
|
3222
|
+
const isBuiltIn = nodeData?.metadata?.isBuiltIn ?? false;
|
|
3142
3223
|
const title = isEdit
|
|
3143
3224
|
? '@platform-management:menu-management.components.edit-dialog.title'
|
|
3144
3225
|
: '@platform-management:menu-management.components.add-dialog.title';
|
|
3145
|
-
const context =
|
|
3146
|
-
name: item?.name || '',
|
|
3147
|
-
text: item?.text || '',
|
|
3148
|
-
type: item?.type || 'menu',
|
|
3149
|
-
icon: item?.icon || '',
|
|
3150
|
-
path: item?.path || '',
|
|
3151
|
-
priority: item?.priority || 0,
|
|
3152
|
-
description: item?.description || '',
|
|
3153
|
-
};
|
|
3226
|
+
const context = this.buildDialogContext(item);
|
|
3154
3227
|
const dialogRef = await this.layoutBuilder
|
|
3155
3228
|
.create()
|
|
3156
3229
|
.dialog((dialog) => {
|
|
@@ -3158,48 +3231,7 @@ class AXPMenuCustomizerComponent {
|
|
|
3158
3231
|
.setTitle(title)
|
|
3159
3232
|
.setContext(context)
|
|
3160
3233
|
.content((flex) => {
|
|
3161
|
-
flex
|
|
3162
|
-
.setDirection('column')
|
|
3163
|
-
.formField('@platform-management:menu-management.fields.name', (field) => {
|
|
3164
|
-
field.path('name');
|
|
3165
|
-
field.textBox({
|
|
3166
|
-
placeholder: '@platform-management:menu-management.fields.name',
|
|
3167
|
-
validations: [{ rule: 'required' }],
|
|
3168
|
-
disabled: isEdit && nodeData?.metadata?.isBuiltIn,
|
|
3169
|
-
});
|
|
3170
|
-
})
|
|
3171
|
-
.formField('@platform-management:menu-management.fields.text', (field) => {
|
|
3172
|
-
field.path('text');
|
|
3173
|
-
field.textBox({
|
|
3174
|
-
placeholder: '@platform-management:menu-management.fields.text',
|
|
3175
|
-
validations: [{ rule: 'required' }],
|
|
3176
|
-
});
|
|
3177
|
-
})
|
|
3178
|
-
.formField('@platform-management:menu-management.fields.icon', (field) => {
|
|
3179
|
-
field.path('icon');
|
|
3180
|
-
field.customWidget('icon-chooser', {});
|
|
3181
|
-
})
|
|
3182
|
-
.formField('@platform-management:menu-management.fields.path', (field) => {
|
|
3183
|
-
field.path('path');
|
|
3184
|
-
field.textBox({
|
|
3185
|
-
placeholder: '@platform-management:menu-management.fields.path',
|
|
3186
|
-
disabled: isEdit && nodeData?.metadata?.isBuiltIn,
|
|
3187
|
-
});
|
|
3188
|
-
})
|
|
3189
|
-
.formField('@platform-management:menu-management.fields.priority', (field) => {
|
|
3190
|
-
field.path('priority');
|
|
3191
|
-
field.numberBox({
|
|
3192
|
-
placeholder: '@platform-management:menu-management.fields.priority',
|
|
3193
|
-
step: 10,
|
|
3194
|
-
});
|
|
3195
|
-
})
|
|
3196
|
-
.formField('@platform-management:menu-management.fields.description', (field) => {
|
|
3197
|
-
field.path('description');
|
|
3198
|
-
field.largeTextBox({
|
|
3199
|
-
placeholder: '@platform-management:menu-management.fields.description',
|
|
3200
|
-
rows: 3,
|
|
3201
|
-
});
|
|
3202
|
-
});
|
|
3234
|
+
this.buildDialogFields(flex, isEdit, isBuiltIn);
|
|
3203
3235
|
})
|
|
3204
3236
|
.setActions((actions) => {
|
|
3205
3237
|
actions.cancel('@general:actions.cancel.title').submit('@general:actions.save.title');
|
|
@@ -3213,60 +3245,189 @@ class AXPMenuCustomizerComponent {
|
|
|
3213
3245
|
}
|
|
3214
3246
|
const formData = dialogRef.context();
|
|
3215
3247
|
try {
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3248
|
+
await this.saveMenuItem(formData, nodeData, parentName, isEdit);
|
|
3249
|
+
this.showSuccessMessage('@platform-management:menu-management.messages.success.save');
|
|
3250
|
+
await this.loadMenuItems();
|
|
3251
|
+
dialogRef.close();
|
|
3252
|
+
}
|
|
3253
|
+
catch (error) {
|
|
3254
|
+
console.error('Failed to save menu item:', error);
|
|
3255
|
+
this.showErrorMessage('@platform-management:menu-management.messages.error.save');
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
/**
|
|
3259
|
+
* Build the dialog context for add/edit dialog.
|
|
3260
|
+
*
|
|
3261
|
+
* @param item - The menu item to build context for, or undefined for new items
|
|
3262
|
+
*/
|
|
3263
|
+
buildDialogContext(item) {
|
|
3264
|
+
return {
|
|
3265
|
+
name: item?.name ?? '',
|
|
3266
|
+
text: item?.text ?? '',
|
|
3267
|
+
type: item?.type ?? 'menu',
|
|
3268
|
+
icon: item?.icon ?? '',
|
|
3269
|
+
path: item?.path ?? '',
|
|
3270
|
+
description: item?.description ?? '',
|
|
3271
|
+
};
|
|
3272
|
+
}
|
|
3273
|
+
/**
|
|
3274
|
+
* Build the dialog form fields.
|
|
3275
|
+
* Note: Priority is not included as item order is controlled by drag-drop.
|
|
3276
|
+
*
|
|
3277
|
+
* @param flex - The flex layout builder
|
|
3278
|
+
* @param isEdit - Whether this is an edit operation
|
|
3279
|
+
* @param isBuiltIn - Whether the item is built-in
|
|
3280
|
+
*/
|
|
3281
|
+
buildDialogFields(flex, isEdit, isBuiltIn) {
|
|
3282
|
+
const I18N_PREFIX = '@platform-management:menu-management.fields';
|
|
3283
|
+
flex
|
|
3284
|
+
.setDirection('column')
|
|
3285
|
+
.formField(`${I18N_PREFIX}.name`, (field) => {
|
|
3286
|
+
field.path('name');
|
|
3287
|
+
field.textBox({
|
|
3288
|
+
placeholder: `${I18N_PREFIX}.name`,
|
|
3289
|
+
validations: [{ rule: 'required' }],
|
|
3290
|
+
disabled: isEdit && isBuiltIn,
|
|
3291
|
+
});
|
|
3292
|
+
})
|
|
3293
|
+
.formField(`${I18N_PREFIX}.text`, (field) => {
|
|
3294
|
+
field.path('text');
|
|
3295
|
+
field.textBox({
|
|
3296
|
+
placeholder: `${I18N_PREFIX}.text`,
|
|
3297
|
+
validations: [{ rule: 'required' }],
|
|
3298
|
+
});
|
|
3299
|
+
})
|
|
3300
|
+
.formField(`${I18N_PREFIX}.icon`, (field) => {
|
|
3301
|
+
field.path('icon');
|
|
3302
|
+
field.customWidget('icon-chooser', {});
|
|
3303
|
+
})
|
|
3304
|
+
.formField(`${I18N_PREFIX}.path`, (field) => {
|
|
3305
|
+
field.path('path');
|
|
3306
|
+
field.textBox({
|
|
3307
|
+
placeholder: `${I18N_PREFIX}.path`,
|
|
3308
|
+
disabled: isEdit && isBuiltIn,
|
|
3309
|
+
});
|
|
3310
|
+
})
|
|
3311
|
+
.formField(`${I18N_PREFIX}.description`, (field) => {
|
|
3312
|
+
field.path('description');
|
|
3313
|
+
field.largeTextBox({
|
|
3314
|
+
placeholder: `${I18N_PREFIX}.description`,
|
|
3315
|
+
rows: 3,
|
|
3316
|
+
});
|
|
3317
|
+
});
|
|
3318
|
+
}
|
|
3319
|
+
/**
|
|
3320
|
+
* Save menu item (create or update).
|
|
3321
|
+
*
|
|
3322
|
+
* @param formData - The form data from the dialog
|
|
3323
|
+
* @param nodeData - The original node data (for edit) or null (for add)
|
|
3324
|
+
* @param parentName - The parent menu name (for add child)
|
|
3325
|
+
* @param isEdit - Whether this is an edit operation
|
|
3326
|
+
*/
|
|
3327
|
+
async saveMenuItem(formData, nodeData, parentName, isEdit) {
|
|
3328
|
+
const scopeKey = this.scopeKey();
|
|
3329
|
+
if (isEdit && nodeData?.menuItem?.name) {
|
|
3330
|
+
const menuName = nodeData.menuItem.name;
|
|
3331
|
+
if (nodeData.metadata?.isCustom) {
|
|
3332
|
+
// For custom items, update the entire item (preserving priority from current position)
|
|
3333
|
+
const updatedItem = {
|
|
3334
|
+
...nodeData.menuItem,
|
|
3335
|
+
text: formData.text,
|
|
3336
|
+
icon: formData.icon,
|
|
3337
|
+
path: formData.path,
|
|
3338
|
+
description: formData.description,
|
|
3339
|
+
};
|
|
3340
|
+
await this.menuCustomizerService.updateCustomMenuItem(scopeKey, menuName, updatedItem);
|
|
3224
3341
|
}
|
|
3225
3342
|
else {
|
|
3226
|
-
//
|
|
3227
|
-
const
|
|
3228
|
-
name: formData.name,
|
|
3343
|
+
// For built-in items, only update allowed properties (text, icon, description)
|
|
3344
|
+
const properties = {
|
|
3229
3345
|
text: formData.text,
|
|
3230
3346
|
icon: formData.icon,
|
|
3231
|
-
path: formData.path,
|
|
3232
|
-
priority: formData.priority,
|
|
3233
3347
|
description: formData.description,
|
|
3234
3348
|
};
|
|
3235
|
-
await this.menuCustomizerService.
|
|
3349
|
+
await this.menuCustomizerService.updateMenuProperties(scopeKey, menuName, properties);
|
|
3236
3350
|
}
|
|
3237
|
-
const successMessage = await this.translationService.translateAsync('@platform-management:menu-management.messages.success.save');
|
|
3238
|
-
this.toastService.success(successMessage);
|
|
3239
|
-
await this.loadMenuItems();
|
|
3240
|
-
dialogRef.close();
|
|
3241
3351
|
}
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3352
|
+
else {
|
|
3353
|
+
// Add new custom item
|
|
3354
|
+
const newItem = {
|
|
3355
|
+
name: formData.name,
|
|
3356
|
+
text: formData.text,
|
|
3357
|
+
icon: formData.icon,
|
|
3358
|
+
path: formData.path,
|
|
3359
|
+
description: formData.description,
|
|
3360
|
+
};
|
|
3361
|
+
await this.menuCustomizerService.addCustomMenuItem(scopeKey, newItem, parentName);
|
|
3245
3362
|
}
|
|
3246
3363
|
}
|
|
3364
|
+
//#endregion
|
|
3365
|
+
//#region ---- Utility Methods ----
|
|
3247
3366
|
/**
|
|
3248
|
-
* Execute a menu action with common error handling
|
|
3367
|
+
* Execute a menu action with common error handling and reload.
|
|
3368
|
+
*
|
|
3369
|
+
* @param action - The action to execute
|
|
3370
|
+
* @param successMessageKey - The i18n key for success message
|
|
3371
|
+
* @param errorMessageKey - The i18n key for error message
|
|
3249
3372
|
*/
|
|
3250
3373
|
async executeMenuAction(action, successMessageKey, errorMessageKey) {
|
|
3251
3374
|
try {
|
|
3252
3375
|
await action();
|
|
3253
|
-
|
|
3254
|
-
this.toastService.success(message);
|
|
3376
|
+
this.showSuccessMessage(successMessageKey);
|
|
3255
3377
|
await this.loadMenuItems();
|
|
3256
3378
|
}
|
|
3257
3379
|
catch (error) {
|
|
3258
3380
|
console.error('Menu action failed:', error);
|
|
3259
|
-
|
|
3260
|
-
this.toastService.danger(message);
|
|
3381
|
+
this.showErrorMessage(errorMessageKey);
|
|
3261
3382
|
}
|
|
3262
3383
|
}
|
|
3384
|
+
/**
|
|
3385
|
+
* Show a confirmation dialog.
|
|
3386
|
+
*
|
|
3387
|
+
* @param titleKey - The i18n key for the dialog title
|
|
3388
|
+
* @param messageKey - The i18n key for the dialog message
|
|
3389
|
+
* @returns True if confirmed, false otherwise
|
|
3390
|
+
*/
|
|
3391
|
+
async confirmAction(titleKey, messageKey) {
|
|
3392
|
+
const [title, message] = await Promise.all([
|
|
3393
|
+
this.translationService.translateAsync(titleKey),
|
|
3394
|
+
this.translationService.translateAsync(messageKey),
|
|
3395
|
+
]);
|
|
3396
|
+
return (await this.dialogService.confirm(title, message)).result;
|
|
3397
|
+
}
|
|
3398
|
+
/**
|
|
3399
|
+
* Show a success toast message.
|
|
3400
|
+
*
|
|
3401
|
+
* @param messageKey - The i18n key for the message
|
|
3402
|
+
*/
|
|
3403
|
+
async showSuccessMessage(messageKey) {
|
|
3404
|
+
const message = await this.translationService.translateAsync(messageKey);
|
|
3405
|
+
this.toastService.success(message);
|
|
3406
|
+
}
|
|
3407
|
+
/**
|
|
3408
|
+
* Show an error toast message.
|
|
3409
|
+
*
|
|
3410
|
+
* @param messageKey - The i18n key for the message
|
|
3411
|
+
*/
|
|
3412
|
+
async showErrorMessage(messageKey) {
|
|
3413
|
+
const message = await this.translationService.translateAsync(messageKey);
|
|
3414
|
+
this.toastService.danger(message);
|
|
3415
|
+
}
|
|
3416
|
+
/**
|
|
3417
|
+
* Show a warning toast message.
|
|
3418
|
+
*
|
|
3419
|
+
* @param messageKey - The i18n key for the message
|
|
3420
|
+
*/
|
|
3421
|
+
async showWarningMessage(messageKey) {
|
|
3422
|
+
const message = await this.translationService.translateAsync(messageKey);
|
|
3423
|
+
this.toastService.warning(message);
|
|
3424
|
+
}
|
|
3263
3425
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPMenuCustomizerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3264
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPMenuCustomizerComponent, isStandalone: true, selector: "axp-menu-customizer", inputs: { scopeKey: { classPropertyName: "scopeKey", publicName: "scopeKey", isSignal: true, isRequired: true, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, allowAddItems: { classPropertyName: "allowAddItems", publicName: "allowAddItems", isSignal: true, isRequired: false, transformFunction: null }, dragBehavior: { classPropertyName: "dragBehavior", publicName: "dragBehavior", isSignal: true, isRequired: false, transformFunction: null }, dragArea: { classPropertyName: "dragArea", publicName: "dragArea", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, host: { classAttribute: "axp-menu-customizer" }, viewQueries: [{ propertyName: "tree", first: true, predicate: AXTreeViewComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@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' | translate | 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 @if (allowAddItems()) {\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 }\n </axp-state-message>\n} @else {\n <!-- Toolbar -->\n @if (showToolbar()) {\n <div class=\"axp-menu-customizer__toolbar\">\n @if (allowAddItems()) {\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.add-root.title' | translate | async\"\n [look]=\"'solid'\"\n [color]=\"'primary'\"\n (onClick)=\"addRootMenuItem()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button>\n }\n\n <div class=\"axp-menu-customizer__toolbar-spacer\"></div>\n\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.collapse.title' | translate | async\"\n [look]=\"'outline'\"\n (onClick)=\"collapseAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-minus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.expand.title' | translate | async\"\n [look]=\"'outline'\"\n (onClick)=\"expandAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.reset.title' | translate | async\"\n [look]=\"'outline'\"\n [color]=\"'danger'\"\n (onClick)=\"resetCustomizations()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-prefix>\n </ax-button>\n </div>\n }\n\n <!-- Menu Tree Content -->\n <div class=\"axp-menu-customizer__container\">\n <div class=\"axp-menu-customizer__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n [look]=\"'default'\"\n [nodeTemplate]=\"itemTemplate\"\n [selectMode]=\"'none'\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"dragBehavior()\"\n [dragArea]=\"dragArea()\"\n (onItemsChange)=\"handleAfterDrop($event)\"\n ></ax-tree-view>\n </div>\n </div>\n}\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=\"axp-menu-customizer__item\"\n [class.axp-menu-customizer__item--hidden]=\"metadata.isHidden\"\n [class.axp-menu-customizer__item--custom]=\"metadata.isCustom\"\n [class.axp-menu-customizer__item--group]=\"item.type === 'group'\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && item.type !== 'group') {\n <i class=\"axp-menu-customizer__item-icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Text or Info -->\n @if (item.type === 'group') {\n <!-- Group Heading -->\n <span class=\"axp-menu-customizer__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=\"axp-menu-customizer__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=\"axp-menu-customizer__item-text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <!-- Path-only Item -->\n <span class=\"axp-menu-customizer__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=\"axp-menu-customizer__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=\"axp-menu-customizer__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) && allowAddItems()) {\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: [".axp-menu-customizer{display:flex;height:100%;flex-direction:column}.axp-menu-customizer__toolbar{display:flex;align-items:center;gap:.5rem;padding:1rem;border-bottom-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1))}.axp-menu-customizer__toolbar-spacer{flex:1 1 0%}.axp-menu-customizer__container{display:flex;flex:1 1 0%;flex-direction:column;gap:1rem;overflow:auto;padding:1rem}.axp-menu-customizer__tree{display:flex;flex-direction:column;gap:.5rem}.axp-menu-customizer__item{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}.axp-menu-customizer__item: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))}.axp-menu-customizer__item--hidden{opacity:.5}.axp-menu-customizer__item--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axp-menu-customizer__item--group{padding-top:.75rem;padding-bottom:.75rem}.axp-menu-customizer__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))}.axp-menu-customizer__item-text{flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-menu-customizer__item-group,.axp-menu-customizer__item-divider,.axp-menu-customizer__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))}.axp-menu-customizer__item-divider i,.axp-menu-customizer__item-path i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__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}.axp-menu-customizer__item-actions{margin-left:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.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$1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.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: i6.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: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "variant"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3426
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AXPMenuCustomizerComponent, isStandalone: true, selector: "axp-menu-customizer", inputs: { scopeKey: { classPropertyName: "scopeKey", publicName: "scopeKey", isSignal: true, isRequired: true, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, allowAddItems: { classPropertyName: "allowAddItems", publicName: "allowAddItems", isSignal: true, isRequired: false, transformFunction: null }, dragBehavior: { classPropertyName: "dragBehavior", publicName: "dragBehavior", isSignal: true, isRequired: false, transformFunction: null }, dragArea: { classPropertyName: "dragArea", publicName: "dragArea", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { saved: "saved", cancelled: "cancelled" }, host: { classAttribute: "axp-menu-customizer" }, viewQueries: [{ propertyName: "tree", first: true, predicate: AXTreeViewComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- i18n path constants -->\n@let i18nBase = '@platform-management:menu-management';\n@let i18nEmptyStates = i18nBase + '.components.menu-list.empty-states';\n@let i18nActions = i18nBase + '.actions';\n\n<!-- Loading State -->\n@if (isLoading()) {\n <axp-state-message\n mode=\"loading\"\n icon=\"fa-light fa-spinner-third fa-spin\"\n [title]=\"(i18nEmptyStates + '.loading.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.loading.description' | translate | async)!\"\n />\n}\n\n<!-- Error State -->\n@else if (hasError()) {\n <axp-state-message\n mode=\"error\"\n icon=\"fa-light fa-circle-exclamation\"\n [title]=\"(i18nEmptyStates + '.error.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.error.description' | translate | async)!\"\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}\n\n<!-- Empty State -->\n@else if (showEmptyState()) {\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"(i18nEmptyStates + '.no-data.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.no-data.description' | translate | async)!\"\n >\n @if (allowAddItems()) {\n <ax-button\n slot=\"actions\"\n [text]=\"i18nActions + '.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 }\n </axp-state-message>\n}\n\n<!-- Main Content -->\n@else if (showContent()) {\n <!-- Toolbar -->\n @if (showToolbar()) {\n <div class=\"axp-menu-customizer__toolbar\">\n @if (allowAddItems()) {\n <ax-button\n [text]=\"i18nActions + '.add-root.title' | translate | async\"\n look=\"solid\"\n color=\"primary\"\n (onClick)=\"addRootMenuItem()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button>\n }\n\n <div class=\"axp-menu-customizer__toolbar-spacer\"></div>\n <!-- \n <ax-button\n [text]=\"i18nActions + '.collapse.title' | translate | async\"\n look=\"outline\"\n (onClick)=\"collapseAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-minus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"i18nActions + '.expand.title' | translate | async\"\n look=\"outline\"\n (onClick)=\"expandAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus-square\"></i>\n </ax-prefix>\n </ax-button> -->\n\n <ax-button\n [text]=\"i18nActions + '.reset.title' | translate | async\"\n look=\"outline\"\n color=\"danger\"\n (onClick)=\"resetCustomizations()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-prefix>\n </ax-button>\n </div>\n }\n\n <!-- Menu Tree -->\n <div class=\"axp-menu-customizer__container\">\n <div class=\"axp-menu-customizer__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n look=\"default\"\n [nodeTemplate]=\"itemTemplate\"\n selectMode=\"none\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"dragBehavior()\"\n [dragArea]=\"dragArea()\"\n (onBeforeDrop)=\"handleBeforeDrop($event)\"\n (onOrderChange)=\"handleOrderChange($event)\"\n (onMoveChange)=\"handleMoveChange($event)\"\n />\n </div>\n </div>\n}\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 @let isGroup = item.type === 'group';\n @let isBreak = item.type === 'break';\n @let isMenu = item.type === 'menu' || !item.type;\n @let canAddChild = !item.path && isMenu && allowAddItems();\n @let canToggleVisibility = item.name && metadata.isBuiltIn;\n @let canDelete = item.name && metadata.isCustom;\n @let i18nStates = '@platform-management:menu-management.states';\n\n <div\n class=\"axp-menu-customizer__item\"\n [class.axp-menu-customizer__item--hidden]=\"metadata.isHidden\"\n [class.axp-menu-customizer__item--custom]=\"metadata.isCustom\"\n [class.axp-menu-customizer__item--group]=\"isGroup\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && !isGroup) {\n <i class=\"axp-menu-customizer__item-icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Content based on item type -->\n @if (isGroup) {\n <span class=\"axp-menu-customizer__item-group\">\n <i class=\"fa-light fa-layer-group\"></i>\n {{ item.text | translate | async }}\n </span>\n } @else if (isBreak) {\n <span class=\"axp-menu-customizer__item-divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ i18nStates + '.divider' | translate | async }}\n </span>\n } @else if (item.text) {\n <span class=\"axp-menu-customizer__item-text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <span class=\"axp-menu-customizer__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=\"axp-menu-customizer__item-name\">{{ item.name }}</code>\n }\n\n <!-- Status Badges -->\n @if (metadata.isHidden) {\n <ax-badge [text]=\"(i18nStates + '.hidden' | translate | async)!\" color=\"danger\" />\n } @else if (metadata.isCustom) {\n <ax-badge [text]=\"(i18nStates + '.custom' | translate | async)!\" color=\"success\" />\n } @else if (metadata.isBuiltIn) {\n <ax-badge [text]=\"(i18nStates + '.built-in' | translate | async)!\" color=\"primary\" />\n }\n\n <!-- Actions Dropdown -->\n <ax-button class=\"axp-menu-customizer__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 built-in items with names) -->\n @if (canToggleVisibility) {\n @if (metadata.isHidden) {\n <ax-button-item\n [text]=\"(i18nActions + '.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]=\"(i18nActions + '.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 <!-- Add Child -->\n @if (canAddChild) {\n <ax-button-item\n [text]=\"(i18nActions + '.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 (canDelete) {\n <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 />\n <div class=\"ax-p-2 ax-text-xs ax-text-neutral-500 ax-italic\">\n {{ i18nBase + '.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: [".axp-menu-customizer{display:flex;height:100%;min-height:0px;flex-direction:column}.axp-menu-customizer__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;padding:1rem;border-bottom-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));flex-shrink:0}.axp-menu-customizer__toolbar-spacer{min-width:1rem;flex:1 1 0%}.axp-menu-customizer__container{display:flex;flex-direction:column;gap:1rem;padding:1rem;min-height:0px;flex:1 1 0%;overflow:auto}.axp-menu-customizer__tree{display:flex;flex-direction:column;gap:.5rem}.axp-menu-customizer__tree ax-tree-view{flex:1 1 0%}.axp-menu-customizer__item{display:flex;flex:1 1 0%;align-items:center;gap:.75rem;border-radius:.375rem;padding:.5rem .75rem;border-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;animation-duration:.15s}.axp-menu-customizer__item:hover{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.axp-menu-customizer__item--hidden{opacity:.5}.axp-menu-customizer__item--hidden .axp-menu-customizer__item-text,.axp-menu-customizer__item--hidden .axp-menu-customizer__item-icon{text-decoration-line:line-through}.axp-menu-customizer__item--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-200),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-50),.3)}.axp-menu-customizer__item--group{padding-top:.75rem;padding-bottom:.75rem;--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.axp-menu-customizer__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-600),var(--tw-text-opacity, 1));flex-shrink:0}.axp-menu-customizer__item-text{min-width:0px;flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-menu-customizer__item-group{display:flex;flex:1 1 0%;align-items:center;gap:.5rem;font-size:.75rem;line-height:1rem;text-transform:uppercase;font-style:italic;--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1));letter-spacing:.025em}.axp-menu-customizer__item-group i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__item-divider,.axp-menu-customizer__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));min-width:0px}.axp-menu-customizer__item-divider i,.axp-menu-customizer__item-path i{flex-shrink:0;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__item-name{display:inline-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(82 82 82 / 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));-webkit-user-select:all;user-select:all;max-width:12rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.axp-menu-customizer__item-actions{margin-left:auto;flex-shrink:0;opacity:.6;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;animation-duration:.15s}.axp-menu-customizer__item:hover .axp-menu-customizer__item-actions{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$1.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$1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1$1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.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: i6.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: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "variant"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3265
3427
|
}
|
|
3266
3428
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXPMenuCustomizerComponent, decorators: [{
|
|
3267
3429
|
type: Component,
|
|
3268
3430
|
args: [{ selector: 'axp-menu-customizer', imports: [
|
|
3269
|
-
CommonModule,
|
|
3270
3431
|
AXButtonModule,
|
|
3271
3432
|
AXDecoratorModule,
|
|
3272
3433
|
AXDropdownButtonModule,
|
|
@@ -3275,7 +3436,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3275
3436
|
AXTreeViewComponent,
|
|
3276
3437
|
AXPStateMessageComponent,
|
|
3277
3438
|
AXBadgeModule,
|
|
3278
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axp-menu-customizer' }, template: "@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' | translate | 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 @if (allowAddItems()) {\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 }\n </axp-state-message>\n} @else {\n <!-- Toolbar -->\n @if (showToolbar()) {\n <div class=\"axp-menu-customizer__toolbar\">\n @if (allowAddItems()) {\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.add-root.title' | translate | async\"\n [look]=\"'solid'\"\n [color]=\"'primary'\"\n (onClick)=\"addRootMenuItem()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button>\n }\n\n <div class=\"axp-menu-customizer__toolbar-spacer\"></div>\n\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.collapse.title' | translate | async\"\n [look]=\"'outline'\"\n (onClick)=\"collapseAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-minus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.expand.title' | translate | async\"\n [look]=\"'outline'\"\n (onClick)=\"expandAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"'@platform-management:menu-management.actions.reset.title' | translate | async\"\n [look]=\"'outline'\"\n [color]=\"'danger'\"\n (onClick)=\"resetCustomizations()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-prefix>\n </ax-button>\n </div>\n }\n\n <!-- Menu Tree Content -->\n <div class=\"axp-menu-customizer__container\">\n <div class=\"axp-menu-customizer__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n [look]=\"'default'\"\n [nodeTemplate]=\"itemTemplate\"\n [selectMode]=\"'none'\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"dragBehavior()\"\n [dragArea]=\"dragArea()\"\n (onItemsChange)=\"handleAfterDrop($event)\"\n ></ax-tree-view>\n </div>\n </div>\n}\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=\"axp-menu-customizer__item\"\n [class.axp-menu-customizer__item--hidden]=\"metadata.isHidden\"\n [class.axp-menu-customizer__item--custom]=\"metadata.isCustom\"\n [class.axp-menu-customizer__item--group]=\"item.type === 'group'\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && item.type !== 'group') {\n <i class=\"axp-menu-customizer__item-icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Text or Info -->\n @if (item.type === 'group') {\n <!-- Group Heading -->\n <span class=\"axp-menu-customizer__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=\"axp-menu-customizer__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=\"axp-menu-customizer__item-text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <!-- Path-only Item -->\n <span class=\"axp-menu-customizer__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=\"axp-menu-customizer__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=\"axp-menu-customizer__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) && allowAddItems()) {\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: [".axp-menu-customizer{display:flex;height:100%;flex-direction:column}.axp-menu-customizer__toolbar{display:flex;align-items:center;gap:.5rem;padding:1rem;border-bottom-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1))}.axp-menu-customizer__toolbar-spacer{flex:1 1 0%}.axp-menu-customizer__container{display:flex;flex:1 1 0%;flex-direction:column;gap:1rem;overflow:auto;padding:1rem}.axp-menu-customizer__tree{display:flex;flex-direction:column;gap:.5rem}.axp-menu-customizer__item{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}.axp-menu-customizer__item: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))}.axp-menu-customizer__item--hidden{opacity:.5}.axp-menu-customizer__item--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-500),var(--tw-border-opacity, 1))}.axp-menu-customizer__item--group{padding-top:.75rem;padding-bottom:.75rem}.axp-menu-customizer__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))}.axp-menu-customizer__item-text{flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500}.axp-menu-customizer__item-group,.axp-menu-customizer__item-divider,.axp-menu-customizer__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))}.axp-menu-customizer__item-divider i,.axp-menu-customizer__item-path i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__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}.axp-menu-customizer__item-actions{margin-left:.5rem}\n"] }]
|
|
3439
|
+
AsyncPipe,
|
|
3440
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'axp-menu-customizer' }, template: "<!-- i18n path constants -->\n@let i18nBase = '@platform-management:menu-management';\n@let i18nEmptyStates = i18nBase + '.components.menu-list.empty-states';\n@let i18nActions = i18nBase + '.actions';\n\n<!-- Loading State -->\n@if (isLoading()) {\n <axp-state-message\n mode=\"loading\"\n icon=\"fa-light fa-spinner-third fa-spin\"\n [title]=\"(i18nEmptyStates + '.loading.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.loading.description' | translate | async)!\"\n />\n}\n\n<!-- Error State -->\n@else if (hasError()) {\n <axp-state-message\n mode=\"error\"\n icon=\"fa-light fa-circle-exclamation\"\n [title]=\"(i18nEmptyStates + '.error.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.error.description' | translate | async)!\"\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}\n\n<!-- Empty State -->\n@else if (showEmptyState()) {\n <axp-state-message\n mode=\"empty\"\n icon=\"fa-light fa-bars\"\n [title]=\"(i18nEmptyStates + '.no-data.title' | translate | async)!\"\n [description]=\"(i18nEmptyStates + '.no-data.description' | translate | async)!\"\n >\n @if (allowAddItems()) {\n <ax-button\n slot=\"actions\"\n [text]=\"i18nActions + '.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 }\n </axp-state-message>\n}\n\n<!-- Main Content -->\n@else if (showContent()) {\n <!-- Toolbar -->\n @if (showToolbar()) {\n <div class=\"axp-menu-customizer__toolbar\">\n @if (allowAddItems()) {\n <ax-button\n [text]=\"i18nActions + '.add-root.title' | translate | async\"\n look=\"solid\"\n color=\"primary\"\n (onClick)=\"addRootMenuItem()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus\"></i>\n </ax-prefix>\n </ax-button>\n }\n\n <div class=\"axp-menu-customizer__toolbar-spacer\"></div>\n <!-- \n <ax-button\n [text]=\"i18nActions + '.collapse.title' | translate | async\"\n look=\"outline\"\n (onClick)=\"collapseAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-minus-square\"></i>\n </ax-prefix>\n </ax-button>\n\n <ax-button\n [text]=\"i18nActions + '.expand.title' | translate | async\"\n look=\"outline\"\n (onClick)=\"expandAll()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-plus-square\"></i>\n </ax-prefix>\n </ax-button> -->\n\n <ax-button\n [text]=\"i18nActions + '.reset.title' | translate | async\"\n look=\"outline\"\n color=\"danger\"\n (onClick)=\"resetCustomizations()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-rotate-left\"></i>\n </ax-prefix>\n </ax-button>\n </div>\n }\n\n <!-- Menu Tree -->\n <div class=\"axp-menu-customizer__container\">\n <div class=\"axp-menu-customizer__tree\">\n <ax-tree-view\n [(datasource)]=\"treeNodes\"\n look=\"default\"\n [nodeTemplate]=\"itemTemplate\"\n selectMode=\"none\"\n [showIcons]=\"false\"\n [showChildrenBadge]=\"false\"\n [dragBehavior]=\"dragBehavior()\"\n [dragArea]=\"dragArea()\"\n (onBeforeDrop)=\"handleBeforeDrop($event)\"\n (onOrderChange)=\"handleOrderChange($event)\"\n (onMoveChange)=\"handleMoveChange($event)\"\n />\n </div>\n </div>\n}\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 @let isGroup = item.type === 'group';\n @let isBreak = item.type === 'break';\n @let isMenu = item.type === 'menu' || !item.type;\n @let canAddChild = !item.path && isMenu && allowAddItems();\n @let canToggleVisibility = item.name && metadata.isBuiltIn;\n @let canDelete = item.name && metadata.isCustom;\n @let i18nStates = '@platform-management:menu-management.states';\n\n <div\n class=\"axp-menu-customizer__item\"\n [class.axp-menu-customizer__item--hidden]=\"metadata.isHidden\"\n [class.axp-menu-customizer__item--custom]=\"metadata.isCustom\"\n [class.axp-menu-customizer__item--group]=\"isGroup\"\n >\n <!-- Icon (hidden for groups) -->\n @if (item.icon && !isGroup) {\n <i class=\"axp-menu-customizer__item-icon\" [class]=\"item.icon\"></i>\n }\n\n <!-- Content based on item type -->\n @if (isGroup) {\n <span class=\"axp-menu-customizer__item-group\">\n <i class=\"fa-light fa-layer-group\"></i>\n {{ item.text | translate | async }}\n </span>\n } @else if (isBreak) {\n <span class=\"axp-menu-customizer__item-divider\">\n <i class=\"fa-light fa-minus\"></i>\n {{ i18nStates + '.divider' | translate | async }}\n </span>\n } @else if (item.text) {\n <span class=\"axp-menu-customizer__item-text\">\n {{ item.text | translate | async }}\n </span>\n } @else if (item.path) {\n <span class=\"axp-menu-customizer__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=\"axp-menu-customizer__item-name\">{{ item.name }}</code>\n }\n\n <!-- Status Badges -->\n @if (metadata.isHidden) {\n <ax-badge [text]=\"(i18nStates + '.hidden' | translate | async)!\" color=\"danger\" />\n } @else if (metadata.isCustom) {\n <ax-badge [text]=\"(i18nStates + '.custom' | translate | async)!\" color=\"success\" />\n } @else if (metadata.isBuiltIn) {\n <ax-badge [text]=\"(i18nStates + '.built-in' | translate | async)!\" color=\"primary\" />\n }\n\n <!-- Actions Dropdown -->\n <ax-button class=\"axp-menu-customizer__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 built-in items with names) -->\n @if (canToggleVisibility) {\n @if (metadata.isHidden) {\n <ax-button-item\n [text]=\"(i18nActions + '.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]=\"(i18nActions + '.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 <!-- Add Child -->\n @if (canAddChild) {\n <ax-button-item\n [text]=\"(i18nActions + '.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 (canDelete) {\n <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 />\n <div class=\"ax-p-2 ax-text-xs ax-text-neutral-500 ax-italic\">\n {{ i18nBase + '.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: [".axp-menu-customizer{display:flex;height:100%;min-height:0px;flex-direction:column}.axp-menu-customizer__toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;padding:1rem;border-bottom-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));flex-shrink:0}.axp-menu-customizer__toolbar-spacer{min-width:1rem;flex:1 1 0%}.axp-menu-customizer__container{display:flex;flex-direction:column;gap:1rem;padding:1rem;min-height:0px;flex:1 1 0%;overflow:auto}.axp-menu-customizer__tree{display:flex;flex-direction:column;gap:.5rem}.axp-menu-customizer__tree ax-tree-view{flex:1 1 0%}.axp-menu-customizer__item{display:flex;flex:1 1 0%;align-items:center;gap:.75rem;border-radius:.375rem;padding:.5rem .75rem;border-width:1px;border-style:solid;--tw-border-opacity: 1;border-color:rgb(229 229 229 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;animation-duration:.15s}.axp-menu-customizer__item:hover{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.axp-menu-customizer__item--hidden{opacity:.5}.axp-menu-customizer__item--hidden .axp-menu-customizer__item-text,.axp-menu-customizer__item--hidden .axp-menu-customizer__item-icon{text-decoration-line:line-through}.axp-menu-customizer__item--custom{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-primary-200),var(--tw-border-opacity, 1));background-color:rgba(var(--ax-sys-color-primary-50),.3)}.axp-menu-customizer__item--group{padding-top:.75rem;padding-bottom:.75rem;--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity, 1))}.axp-menu-customizer__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-600),var(--tw-text-opacity, 1));flex-shrink:0}.axp-menu-customizer__item-text{min-width:0px;flex:1 1 0%;font-size:.875rem;line-height:1.25rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.axp-menu-customizer__item-group{display:flex;flex:1 1 0%;align-items:center;gap:.5rem;font-size:.75rem;line-height:1rem;text-transform:uppercase;font-style:italic;--tw-text-opacity: 1;color:rgb(115 115 115 / var(--tw-text-opacity, 1));letter-spacing:.025em}.axp-menu-customizer__item-group i{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__item-divider,.axp-menu-customizer__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));min-width:0px}.axp-menu-customizer__item-divider i,.axp-menu-customizer__item-path i{flex-shrink:0;--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.axp-menu-customizer__item-name{display:inline-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(82 82 82 / 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));-webkit-user-select:all;user-select:all;max-width:12rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.axp-menu-customizer__item-actions{margin-left:auto;flex-shrink:0;opacity:.6;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;animation-duration:.15s}.axp-menu-customizer__item:hover .axp-menu-customizer__item-actions{opacity:1}\n"] }]
|
|
3279
3441
|
}], propDecorators: { scopeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeKey", required: true }] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToolbar", required: false }] }], allowAddItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAddItems", required: false }] }], dragBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragBehavior", required: false }] }], dragArea: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragArea", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }], tree: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXTreeViewComponent), { isSignal: true }] }] } });
|
|
3280
3442
|
|
|
3281
3443
|
//#region ---- Component Definition ----
|