@acorex/platform 21.0.0-next.85 → 21.0.0-next.89
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/fesm2022/acorex-platform-auth.mjs +9 -3
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-Ytey9uhY.mjs → acorex-platform-common-common-settings.provider-DilV4dql.mjs} +16 -3
- package/fesm2022/acorex-platform-common-common-settings.provider-DilV4dql.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3426 -2488
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-contracts.mjs +1160 -9
- package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +826 -152
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain-contracts.mjs +58 -0
- package/fesm2022/acorex-platform-domain-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-domain.mjs +2 -50
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +98 -189
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs → acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs} +17 -4
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-RttFwaw9.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-components.mjs +181 -46
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +7 -6
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-contracts.mjs +1208 -0
- package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +1080 -889
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +1150 -247
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +388 -207
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +513 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs} +4 -4
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-XWRUVoL4.mjs.map} +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +1541 -394
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs → acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs} +2 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +956 -115
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs → acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs} +50 -3
- package/fesm2022/acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +104 -24
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +6 -8
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +9 -5
- package/types/acorex-platform-auth.d.ts +3 -1
- package/types/acorex-platform-common.d.ts +655 -1268
- package/types/acorex-platform-contracts.d.ts +1791 -260
- package/types/acorex-platform-core.d.ts +2302 -2800
- package/types/acorex-platform-domain-contracts.d.ts +416 -0
- package/types/acorex-platform-domain.d.ts +4 -415
- package/types/acorex-platform-layout-builder.d.ts +11 -20
- package/types/acorex-platform-layout-components.d.ts +29 -5
- package/types/acorex-platform-layout-designer.d.ts +2 -1
- package/types/acorex-platform-layout-entity-contracts.d.ts +889 -0
- package/types/acorex-platform-layout-entity.d.ts +143 -275
- package/types/acorex-platform-layout-views.d.ts +147 -31
- package/types/acorex-platform-layout-widget-core.d.ts +74 -14
- package/types/acorex-platform-layout-widgets.d.ts +136 -38
- package/types/acorex-platform-runtime.d.ts +1 -1
- package/types/acorex-platform-themes-default.d.ts +227 -73
- package/types/acorex-platform-themes-shared.d.ts +4 -0
- package/types/acorex-platform-workflow.d.ts +5 -18
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +0 -116
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map +0 -1
- package/fesm2022/acorex-platform-native.mjs +0 -155
- package/fesm2022/acorex-platform-native.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-BjuzSe0T.mjs.map +0 -1
- package/native/README.md +0 -4
- package/types/acorex-platform-native.d.ts +0 -28
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i2 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { inject, viewChild, afterNextRender, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, signal, computed, Injectable, input, output, ViewContainerRef, Directive,
|
|
4
|
+
import { inject, viewChild, afterNextRender, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, DestroyRef, signal, untracked, computed, InjectionToken, Injectable, input, output, ViewContainerRef, Directive, ElementRef } from '@angular/core';
|
|
5
5
|
import { AXCommonModule } from '@acorex/cdk/common';
|
|
6
6
|
import * as i4 from '@acorex/components/breadcrumbs';
|
|
7
7
|
import { AXBreadcrumbsModule } from '@acorex/components/breadcrumbs';
|
|
@@ -12,9 +12,9 @@ import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
|
12
12
|
import * as i5 from '@acorex/components/dropdown';
|
|
13
13
|
import { AXDropdownModule } from '@acorex/components/dropdown';
|
|
14
14
|
import { AXDropdownButtonModule } from '@acorex/components/dropdown-button';
|
|
15
|
-
import { AXPStickyDirective, AXPCommonSettings, AXPHomePageService, AXPSettingsService, axpIsEntityDetailsViewRoute, axpNavigateAppPath, AXPEntityCommandScope,
|
|
15
|
+
import { AXPTabNavigationService, AXPStickyDirective, AXPCommonSettings, AXPHomePageService, AXPSettingsService, AXPTabPreviewService, AXPUnsavedChangesConfirmService, AXPBrowserTitleService, axpJoinTabTitleSegments, normalizeRouterUrl, AXP_HOME_TAB_KEY, axpResolveTabKey, axpIsEntityDetailsViewRoute, axpNavigateAppPath, AXPEntityCommandScope, AXPNotFoundError, AXP_NOT_FOUND_ROUTE, AXPUnsavedChangesPopstateService, AXP_ENTITY_DELETED_WORKFLOW_EVENT_TYPE, createUnsavedChangesCanDeactivateGuard } from '@acorex/platform/common';
|
|
16
16
|
import * as i8 from '@acorex/platform/core';
|
|
17
|
-
import { AXPDeviceService, AXPComponentSlotModule, getSmart, AXPExpressionEvaluatorService,
|
|
17
|
+
import { AXPDeviceService, AXPComponentSlotModule, getSmart, AXPDebugService, OVERLAY_DETAILS_VIEW_TRACE_NS, AXPExpressionEvaluatorService, AXPContextEvalFactory, normalizeKeyboardShortcuts, AXPContextStore, AXPBroadcastEventService, AXPKeyboardShortcutRegistry, FORM_DIRTY_TRACE_NS, summarizeFormContextDirtyDiff, AXPKeyboardShortcutPriority } from '@acorex/platform/core';
|
|
18
18
|
import * as i1 from '@acorex/cdk/drawer';
|
|
19
19
|
import { AXDrawerDirectiveModule, AXDrawerContainerDirective } from '@acorex/cdk/drawer';
|
|
20
20
|
import { AXDrawerModule } from '@acorex/components/drawer';
|
|
@@ -28,25 +28,25 @@ import { AXPWorkflowService } from '@acorex/platform/workflow';
|
|
|
28
28
|
import { AXToastService } from '@acorex/components/toast';
|
|
29
29
|
import { AXFormatService, AXFormatModule } from '@acorex/core/format';
|
|
30
30
|
import { AXPSessionService } from '@acorex/platform/auth';
|
|
31
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
32
|
+
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
|
|
31
33
|
import { isEmpty, cloneDeep, get } from 'lodash-es';
|
|
34
|
+
import { filter } from 'rxjs/operators';
|
|
32
35
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
33
|
-
import * as
|
|
36
|
+
import * as i6$1 from '@acorex/platform/layout/widget-core';
|
|
34
37
|
import { AXPPageStatus, AXPWidgetContainerComponent, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
35
|
-
import { Router, ActivatedRoute } from '@angular/router';
|
|
36
38
|
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
|
37
39
|
import { AXBadgeModule } from '@acorex/components/badge';
|
|
38
40
|
import { AXButtonGroupModule } from '@acorex/components/button-group';
|
|
39
|
-
import * as i5$1 from '@acorex/components/loading';
|
|
40
|
-
import { AXLoadingModule } from '@acorex/components/loading';
|
|
41
41
|
import { AXMenuModule } from '@acorex/components/menu';
|
|
42
42
|
import { AXSearchBoxModule } from '@acorex/components/search-box';
|
|
43
43
|
import { AXDateTimeModule } from '@acorex/core/date-time';
|
|
44
44
|
import { AXFileModule } from '@acorex/core/file';
|
|
45
|
-
import * as
|
|
45
|
+
import * as i7 from '@acorex/components/form';
|
|
46
46
|
import { AXFormModule } from '@acorex/components/form';
|
|
47
|
-
import * as
|
|
47
|
+
import * as i5$1 from '@acorex/components/tabs';
|
|
48
48
|
import { AXTabsModule } from '@acorex/components/tabs';
|
|
49
|
-
import { Subject, takeUntil } from 'rxjs';
|
|
49
|
+
import { Subject, takeUntil, filter as filter$1 } from 'rxjs';
|
|
50
50
|
|
|
51
51
|
class AXPPageLayoutBase {
|
|
52
52
|
}
|
|
@@ -56,6 +56,7 @@ class AXPPageLayoutComponent {
|
|
|
56
56
|
this.page = inject(AXPPageLayoutBase, { optional: true });
|
|
57
57
|
this.layoutService = inject(AXPLayoutThemeService);
|
|
58
58
|
this.deviceService = inject(AXPDeviceService);
|
|
59
|
+
this.tabNavigation = inject(AXPTabNavigationService);
|
|
59
60
|
this.startSideDrawer = viewChild('startSideDrawer', ...(ngDevMode ? [{ debugName: "startSideDrawer" }] : /* istanbul ignore next */ []));
|
|
60
61
|
this.workflow = inject(AXPWorkflowService);
|
|
61
62
|
this.commandService = inject(AXPCommandService);
|
|
@@ -145,7 +146,7 @@ class AXPPageLayoutComponent {
|
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
148
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPageLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
148
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPageLayoutComponent, isStandalone: true, selector: "axp-page-layout", providers: [], viewQueries: [{ propertyName: "startSideDrawer", first: true, predicate: ["startSideDrawer"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.AXDrawerContainerDirective }], ngImport: i0, template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\"\n class=\"ax-z-50 ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div\n id=\"axp-page-badge\"\n class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\"\n [attr.aria-label]=\"page?.badge()?.title\"\n >\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){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-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type:
|
|
149
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPPageLayoutComponent, isStandalone: true, selector: "axp-page-layout", providers: [], viewQueries: [{ propertyName: "startSideDrawer", first: true, predicate: ["startSideDrawer"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.AXDrawerContainerDirective }], ngImport: i0, template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\" class=\"ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div id=\"axp-page-badge\" class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\" [attr.aria-label]=\"page?.badge()?.title\">\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){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-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type:
|
|
149
150
|
//
|
|
150
151
|
AXCommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.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: AXBreadcrumbsModule }, { kind: "component", type: i4.AXBreadCrumbsComponent, selector: "ax-breadcrumbs" }, { kind: "component", type: i4.AXBreadCrumbsItemComponent, selector: "ax-breadcrumbs-item", inputs: ["disabled", "active"] }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.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: i6.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i6.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "ngmodule", type: AXDrawerDirectiveModule }, { kind: "directive", type: i1.AXDrawerItemDirective, selector: "[axDrawerItem]", inputs: ["location", "collapsed", "backDrop", "mode", "transition", "closeOnBackdropClick", "backdropClass", "singleOpenMode"], outputs: ["collapseStateChanged", "locationChange", "collapsedChange", "backDropChange", "modeChange", "transitionChange", "closeOnBackdropClickChange", "backdropClassChange", "onBackdropClick", "singleOpenModeChange"], exportAs: ["axDrawerItem"] }, { kind: "ngmodule", type:
|
|
151
152
|
//
|
|
@@ -173,7 +174,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
173
174
|
AXPStickyDirective,
|
|
174
175
|
AXPThemeLayoutContainerComponent,
|
|
175
176
|
AXPStatusChipComponent,
|
|
176
|
-
], selector: 'axp-page-layout', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [AXDrawerContainerDirective], providers: [], template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\"\n class=\"ax-z-50 ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div\n id=\"axp-page-badge\"\n class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\"\n [attr.aria-label]=\"page?.badge()?.title\"\n >\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){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-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"] }]
|
|
177
|
+
], selector: 'axp-page-layout', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [AXDrawerContainerDirective], providers: [], template: "<!-------- Begin Start Side Drawer -------->\n<div id=\"axp-drawer-start\" [mode]=\"deviceService.isSmall() ? 'overlay' : 'push'\" [transition]=\"250\" axDrawerItem\n [backDrop]=\"true\" (onBackdropClick)=\"handleBackdropClick($event)\" #startSideDrawer=\"axDrawerItem\"\n [backdropClass]=\"'ax-bg-darkest/75'\" [collapsed]=\"deviceService.isSmall()\" drawerLocation=\"start\" class=\"ax-h-full\">\n <ng-content select=\"axp-layout-start-side\"></ng-content>\n</div>\n<!-------- Finish Start Side Drawer -------->\n<!--------------------------------------------------------------->\n<!-------- Begin Main Layout Container -------->\n<axp-layout-container id=\"axp-page-layout\" #container>\n <!-------- Begin Page Header -------->\n <axp-layout-header id=\"axp-page-header\" *translate=\"let t\" #sticky=\"axpSticky\" [axpSticky]=\"'axp-is-sticky'\"\n [stickyOffset]=\"50\" [stickyParent]=\"container.hostElement\">\n <!-------- Begin Back Button (Mobile Only) -------->\n @if (page?.hasBackButton() && deviceService.isSmall()) {\n <ax-button id=\"axp-btn-back\" [look]=\"'blank'\" class=\"ax-sm ax-w-fit ax-ms-1\" color=\"secondary\"\n (click)=\"page?.onBackButtonClick()\" [text]=\"(page?.backButton()?.title | translate | async) ?? ''\">\n <ax-prefix>\n <ax-icon icon=\"fa-solid fa-chevron-left rtl:ax-rotate-180\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n <!-------- Finish Back Button -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Bar -------->\n <axp-layout-title-bar id=\"axp-title-bar\">\n <!-------- Begin Title Section -------->\n <div class=\"ax-flex ax-flex-col ax-transition ax-shrink-1 ax-min-w-0\">\n <!-------- Begin Breadcrumbs -------->\n @if (page?.hasBreadcrumbs() && !deviceService.isSmall()) {\n <ax-breadcrumbs id=\"axp-breadcrumb\" class=\"ax-mb-1\">\n @for (item of page?.breadcrumbs(); track $index) {\n <ax-breadcrumbs-item [attr.id]=\"'axp-breadcrumb-item-' + $index\" [active]=\"$last\"\n (click)=\"!$last && item.command ? execute(item.command) : null\">\n @if (item.icon) {\n <i [class]=\"item.icon\"></i>\n }\n {{ t(item.title) | async }}\n </ax-breadcrumbs-item>\n }\n <ng-template #divider>\n <i class=\"fa-regular fa-chevron-right rtl:ax-rotate-180 fa-sm\"></i>\n </ng-template>\n </ax-breadcrumbs>\n }\n <!-------- Finish Breadcrumbs -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Container -------->\n <div class=\"__title-container\">\n <!-------- Begin Page Title -------->\n @if (page?.hasTitle()) {\n <axp-layout-title id=\"axp-page-title\">\n @if (page?.hasTitleIcon()) {\n <ax-icon [icon]=\"page?.titleIcon()!\" class=\"ax-me-2\"></ax-icon>\n }\n {{ page?.title() | translate | async }}\n </axp-layout-title>\n }\n <!-------- Finish Page Title -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Title Actions -------->\n @if (page?.hasTitleActions()) {\n <ax-button id=\"axp-btn-title-actions\" [look]=\"'blank'\" class=\"ax-sm -ax-mx-2\">\n <ax-prefix>\n <i class=\"fa-solid fa-caret-down fa-fw\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of page?.titleActions(); track $index) {\n <ng-container>\n <ax-button-item [attr.id]=\"'axp-btn-title-action-' + (sub.name || $index)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n [selected]=\"sub.command?.metadata?.['isSelected']\" (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n </ng-container>\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Title Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Status -------->\n\n @if (page?.hasStatus()) {\n <axp-status-chip [value]=\"page?.status()?.value ?? null\" [readonly]=\"page?.status()?.readonly || false\"\n [definitionKey]=\"page?.status()?.definitionKey ?? null\" [entityData]=\"getEntityData()\"\n (transitionExecuted)=\"handleStatusTransition($event)\" class=\"__title-status\"></axp-status-chip>\n }\n <!-------- Finish Page Status -------->\n\n <!-------- Begin Title Badge -------->\n @if (page?.hasBadge()) {\n <div id=\"axp-page-badge\" class=\"__title-badge --{{ page?.badge()?.color }}\"\n [attr.title]=\"page?.badge()?.description ?? page?.badge()?.title\" [attr.aria-label]=\"page?.badge()?.title\">\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n <span class=\"__title-badge-label\">{{ page?.badge()?.title }}</span>\n </div>\n }\n <!-------- Finish Title Badge -------->\n\n </div>\n <!-------- Finish Title Container -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Description -------->\n @if (page?.hasDescription()) {\n <axp-layout-description id=\"axp-page-description\">\n {{ page?.description() | translate | async }}</axp-layout-description>\n }\n <!-------- Finish Page Description -------->\n </div>\n <!-------- Finish Title Section -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Actions -------->\n <axp-layout-actions id=\"axp-page-actions\" class=\"ax-shrink-0\">\n <axp-component-slot name=\"page-header-actions\"></axp-component-slot>\n <!-------- Begin Primary Actions -------->\n @if (page?.hasPrimaryActions()) {\n @for (item of page?.primaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button [attr.id]=\"'axp-btn-primary-' + (item.name || item.title)\" [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\" [disabled]=\"item.disabled\" [text]=\"(t(item.title) | async)!\"\n [look]=\"'solid'\" [color]=\"item.color\" (onClick)=\"handleActionClick(item)\">\n <ax-prefix>\n <i class=\"{{ item.icon }}\"></i>\n </ax-prefix>\n @if (item?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of item?.items; track $index) {\n @if (sub.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-primary-' + (item.name || item.title) + '-' + (sub.name || sub.title)\"\n [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\" [disabled]=\"sub.disabled\"\n (onClick)=\"handleActionClick(sub)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n <!-------- Finish Primary Actions -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Secondary Actions -------->\n @if (page?.hasSecondaryActions()) {\n <ax-button id=\"axp-btn-secondary\" [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (item of page?.secondaryMenuItems(); track $index) {\n @if (item.visible != false) {\n <ax-button-item [attr.id]=\"'axp-btn-secondary-' + (item.name || item.title)\"\n [text]=\"(item.title | translate | async)!\" [color]=\"item.color\" [disabled]=\"item.disabled\"\n (onClick)=\"handleSecondaryActionClick(item)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (item.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n <!-------- Finish Secondary Actions -------->\n </axp-layout-actions>\n <!-------- Finish Page Actions -------->\n </axp-layout-title-bar>\n <!-------- Finish Title Bar -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Toolbar / Navbar -------->\n @if (!sticky.isSticky) {}\n <ng-content select=\"axp-page-toolbar\"></ng-content>\n <!-------- Finish Page Toolbar / Navbar -------->\n </axp-layout-header>\n <!-------- Finish Page Header -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Content -------->\n <ng-content select=\"axp-page-content\"></ng-content>\n <!-------- Finish Page Content -------->\n <!--------------------------------------------------------------->\n <!-------- Begin Page Footer -------->\n <axp-page-footer-container id=\"axp-page-footer-container\"\n [ngStyle]=\"{ display: tt.isEmpty() && prefixSlot.isEmpty() && suffixSlot.isEmpty() ? 'none' : 'block' }\">\n <axp-layout-container #tt>\n <ng-content select=\"axp-page-footer\"></ng-content>\n </axp-layout-container>\n <axp-page-footer id=\"axp-page-footer\">\n <axp-layout-prefix>\n <axp-component-slot name=\"page-footer-start\" #prefixSlot=\"slot\"></axp-component-slot>\n </axp-layout-prefix>\n <axp-layout-suffix>\n <axp-component-slot name=\"page-footer-end\" #suffixSlot=\"slot\"></axp-component-slot>\n </axp-layout-suffix>\n </axp-page-footer>\n </axp-page-footer-container>\n <!-------- Finish Page Footer -------->\n</axp-layout-container>\n<!-------- Finish Main Layout Container -------->", styles: ["@charset \"UTF-8\";.axp-status-icon{font-size:.875rem;line-height:1}.axp-status-chip{display:inline-flex}.axp-status-chip--primary{background-color:rgb(var(--ax-sys-color-primary-lighter-surface));color:rgb(var(--ax-sys-color-on-primary-lighter-surface))}.axp-status-icon--primary{color:rgb(var(--ax-sys-color-primary-dark-surface))}.axp-status-chip--secondary{background-color:rgb(var(--ax-sys-color-secondary-lighter-surface));color:rgb(var(--ax-sys-color-on-secondary-lighter-surface))}.axp-status-icon--secondary{color:rgb(var(--ax-sys-color-secondary-dark-surface))}.axp-status-chip--success{background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}.axp-status-icon--success{color:rgb(var(--ax-sys-color-success-dark-surface))}.axp-status-chip--warning{background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}.axp-status-icon--warning{color:rgb(var(--ax-sys-color-warning-dark-surface))}.axp-status-chip--danger{background-color:rgb(var(--ax-sys-color-danger-lighter-surface));color:rgb(var(--ax-sys-color-on-danger-lighter-surface))}.axp-status-icon--danger{color:rgb(var(--ax-sys-color-danger-dark-surface))}.axp-status-chip--info{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--info{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--accent1{background-color:rgb(var(--ax-sys-color-accent1-lighter-surface));color:rgb(var(--ax-sys-color-on-accent1-lighter-surface))}.axp-status-icon--accent1{color:rgb(var(--ax-sys-color-accent1-dark-surface))}.axp-status-chip--accent2{background-color:rgb(var(--ax-sys-color-accent2-lighter-surface));color:rgb(var(--ax-sys-color-on-accent2-lighter-surface))}.axp-status-icon--accent2{color:rgb(var(--ax-sys-color-accent2-dark-surface))}.axp-status-chip--accent3{background-color:rgb(var(--ax-sys-color-accent3-lighter-surface));color:rgb(var(--ax-sys-color-on-accent3-lighter-surface))}.axp-status-icon--accent3{color:rgb(var(--ax-sys-color-accent3-dark-surface))}.axp-status-chip--neutral{background-color:rgb(var(--ax-sys-color-neutral-lighter-surface));color:rgb(var(--ax-sys-color-on-neutral-lighter-surface))}.axp-status-icon--neutral{color:rgb(var(--ax-sys-color-neutral-dark-surface))}axp-layout-title{display:block;width:100%;font-weight:600}axp-layout-description{display:block;width:100%;font-size:.875rem;line-height:1.25rem;opacity:.65}axp-layout-actions{display:flex;align-items:center;gap:.75rem}axp-layout-actions axp-layout-actions-primary{display:flex;align-items:center;gap:.75rem}axp-layout-footer,axp-layout-toolbar,axp-layout-header,axp-page-header,axp-page-footer,axp-page-toolbar{display:flex;width:100%;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-prefix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-prefix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-prefix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-prefix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-prefix,axp-page-toolbar>axp-layout-suffix{display:flex;flex-direction:row;align-items:center;gap:.5rem}axp-layout-footer>axp-layout-prefix,axp-layout-toolbar>axp-layout-prefix,axp-layout-header>axp-layout-prefix,axp-page-header>axp-layout-prefix,axp-page-footer>axp-layout-prefix,axp-page-toolbar>axp-layout-prefix{order:-9999}axp-layout-footer>axp-layout-suffix,axp-layout-toolbar>axp-layout-suffix,axp-layout-header>axp-layout-suffix,axp-page-header>axp-layout-suffix,axp-page-footer>axp-layout-suffix,axp-page-toolbar>axp-layout-suffix{order:9999;margin-inline-start:auto}axp-layout-list{display:flex;flex-direction:column}axp-layout-list>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed}axp-layout-list:focus{outline:none}axp-layout-list-group{display:flex;flex-direction:column;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-group>axp-layout-title{padding-bottom:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:600}axp-layout-list-group>axp-layout-header{display:flex;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}axp-layout-list-item{margin-top:.25rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem;font-size:.875rem;line-height:1.25rem}axp-layout-list-item:focus{outline:none}axp-layout-list-item.axp-state-focused,axp-layout-list-item:hover{cursor:pointer;border-radius:.25rem;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-list-item>axp-layout-prefix{margin-inline-end:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-list-item>axp-layout-content{flex:1 1 0%}axp-layout-list-item>axp-layout-content axp-layout-description{margin-top:.25rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-list-item>axp-layout-suffix{margin-inline-start:auto;display:flex;flex-direction:row;gap:.5rem}axp-layout-sections{display:flex;flex-direction:column;gap:1rem}axp-layout-sections axp-layout-section{display:block;border-radius:.375rem;border-width:1px;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding:.5rem 1rem}@media(min-width:1280px){axp-layout-sections axp-layout-section>axp-layout-footer,axp-layout-sections axp-layout-section>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-layout-sections axp-layout-section>axp-layout-header{display:flex;flex-direction:column;gap:0px;border-top-left-radius:.375rem;border-top-right-radius:.375rem;border-bottom-width:1px}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-title{font-weight:700;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1))}axp-layout-sections axp-layout-section>axp-layout-header axp-layout-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem}axp-layout-sections axp-layout-section>axp-layout-footer{display:flex;align-items:center;justify-content:space-between;border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem;border-top-width:1px;padding:1rem}axp-layout-sections axp-layout-section>axp-layout-footer>axp-layout-suffix{margin-inline-start:auto;display:flex;gap:.5rem}axp-layout-sections axp-layout-section>axp-layout-footer{opacity:0;animation:fadeInDown .5s ease-out forwards}@keyframes fadeInDown{0%{opacity:0}to{opacity:1}}axp-page-layout{display:flex;width:100%;height:100%;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}axp-page-layout axp-layout-start-side,axp-page-layout axp-layout-end-side{display:flex;min-height:100%;min-width:16rem;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout axp-layout-start-side:is(.ax-dark *),axp-page-layout axp-layout-end-side:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-darker-surface));color:rgb(var(--ax-sys-color-on-darker-surface));border-color:rgb(var(--ax-sys-color-border-darker-surface))}axp-page-layout axp-layout-start-side axp-layout-header,axp-page-layout axp-layout-end-side axp-layout-header{display:flex;flex-direction:column;gap:.5rem;padding:1rem}axp-page-layout axp-layout-start-side axp-layout-header>axp-layout-title,axp-page-layout axp-layout-end-side axp-layout-header>axp-layout-title{font-size:1.125rem;line-height:1.75rem;font-weight:500}axp-page-layout axp-layout-start-side>axp-layout-content,axp-page-layout axp-layout-end-side>axp-layout-content{flex:1 1 0%}axp-page-layout>axp-layout-container{position:relative;display:flex;width:100%;height:100%;flex-direction:column;overflow:auto}axp-page-layout>axp-layout-container>axp-layout-header{position:sticky;top:0;z-index:20;display:flex;flex-direction:column;align-items:flex-start;gap:0px;padding-top:.5rem;padding-bottom:.5rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header:is(.ax-dark *){background-color:rgb(var(--ax-sys-color-dark-surface));color:rgb(var(--ax-sys-color-on-dark-surface));border-color:rgb(var(--ax-sys-color-border-dark-surface))}@media(min-width:768px){axp-page-layout>axp-layout-container>axp-layout-header{padding-top:1rem;padding-bottom:1rem}}axp-page-layout>axp-layout-container>axp-layout-header.axp-is-sticky{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-border-opacity, 1));--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item{font-size:.75rem;line-height:1rem}axp-page-layout>axp-layout-container>axp-layout-header ax-breadcrumbs ax-breadcrumbs-item.ax-state-active .ax-breadcrumb-item-content{cursor:default;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-on-lightest-surface),var(--tw-text-opacity, 1));opacity:.75}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{display:flex;width:100%;align-items:center;justify-content:space-between;padding-left:1rem;padding-right:1rem}@media(min-width:1280px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar{border-width:0px}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar ax-layout-nav-button{display:flex;align-items:center;justify-content:space-between}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container{display:flex;align-items:baseline;gap:.75rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{display:inline-block;width:fit-content;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:1.25rem;line-height:1.75rem;font-weight:500;line-height:1}@media(min-width:1024px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container axp-layout-title{font-size:1.5rem;line-height:2rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{display:inline-flex;--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));align-items:center;align-self:baseline;border-radius:.375rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:600;line-height:1}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin-inline-end:.25rem;line-height:1;font-size:.5rem}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning{background-color:rgb(var(--ax-sys-color-warning-lightest-surface));color:rgb(var(--ax-sys-color-on-warning-lightest-surface));border-color:rgb(var(--ax-sys-color-border-warning-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--warning i{color:rgb(var(--ax-sys-color-warning-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger{background-color:rgb(var(--ax-sys-color-danger-lightest-surface));color:rgb(var(--ax-sys-color-on-danger-lightest-surface));border-color:rgb(var(--ax-sys-color-border-danger-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--danger i{color:rgb(var(--ax-sys-color-danger-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success{background-color:rgb(var(--ax-sys-color-success-lightest-surface));color:rgb(var(--ax-sys-color-on-success-lightest-surface));border-color:rgb(var(--ax-sys-color-border-success-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--success i{color:rgb(var(--ax-sys-color-success-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary{background-color:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface));border-color:rgb(var(--ax-sys-color-border-primary-lightest-surface))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--primary i{color:rgb(var(--ax-sys-color-primary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--secondary i{color:rgb(var(--ax-sys-color-secondary-500))}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge.--default i{color:rgb(var(--ax-sys-color-on-surface)/.45)}@media(max-width:600px){axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));background-color:transparent;padding:0;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge .__title-badge-label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}axp-page-layout>axp-layout-container>axp-layout-header axp-layout-title-bar .__title-container .__title-badge i{margin:0;font-size:.625rem}}axp-page-layout>axp-layout-container>axp-layout-header axp-page-toolbar{margin-top:.5rem;padding-left:1rem;padding-right:1rem}axp-page-layout>axp-layout-container>axp-page-content{display:flex;width:100%;flex:1 1 0%;flex-direction:column;padding:.75rem 1rem}axp-page-layout>axp-layout-container>axp-page-content.--scrollable{padding-bottom:1rem}axp-page-layout>axp-layout-container>axp-page-footer-container{border-top-width:1px;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}axp-page-layout>axp-layout-container>axp-page-footer-container:is(.ax-dark *){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-page-layout>axp-layout-container>axp-page-footer-container{position:sticky;bottom:0;z-index:20;padding:.75rem;--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}@keyframes ax-fadeInUp{0%{transform:translate3d(0,100%,0);opacity:0}}axp-page-layout>axp-layout-container>axp-page-footer-container.--animated{animation:1s both ax-fadeInUp;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(0,0,.2,1)}\n"] }]
|
|
177
178
|
}], propDecorators: { startSideDrawer: [{ type: i0.ViewChild, args: ['startSideDrawer', { isSignal: true }] }] } });
|
|
178
179
|
|
|
179
180
|
//#region ---- Page Unsaved Changes Utilities ----
|
|
@@ -219,11 +220,57 @@ class AXPPageLayoutBaseComponent {
|
|
|
219
220
|
this.homePageService = inject(AXPHomePageService);
|
|
220
221
|
this.policyService = inject(AXPPolicyEngineService);
|
|
221
222
|
this.settingsService = inject(AXPSettingsService);
|
|
223
|
+
this.tabNavigation = inject(AXPTabNavigationService);
|
|
224
|
+
this.tabPreviewService = inject(AXPTabPreviewService);
|
|
225
|
+
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
226
|
+
this.browserTitleService = inject(AXPBrowserTitleService);
|
|
227
|
+
this.router = inject(Router);
|
|
228
|
+
this.pageLayoutDestroyRef = inject(DestroyRef);
|
|
222
229
|
//#endregion
|
|
223
230
|
//#region ---------------- Signal to force recomputation ----------------
|
|
224
231
|
this._updateTrigger = signal(0, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : /* istanbul ignore next */ []));
|
|
232
|
+
/** Tab key captured at page init — stable while the route instance is cached. */
|
|
233
|
+
this.pageTabKey = signal(null, ...(ngDevMode ? [{ debugName: "pageTabKey" }] : /* istanbul ignore next */ []));
|
|
225
234
|
this.updateTrigger = this._updateTrigger.asReadonly();
|
|
226
235
|
//#endregion
|
|
236
|
+
//#region ---------------- Tab Title Sync ----------------
|
|
237
|
+
/** Refreshes tab title when this cached page becomes the active tab again. */
|
|
238
|
+
this.#syncTabTitleOnActivate = effect(() => {
|
|
239
|
+
const activeKey = this.tabNavigation.activeKey();
|
|
240
|
+
const pageKey = this.pageTabKey();
|
|
241
|
+
if (!activeKey || !pageKey || activeKey !== pageKey) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (this.tabNavigation.effectiveMode() !== 'tabular') {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
untracked(() => {
|
|
248
|
+
this.recompute();
|
|
249
|
+
});
|
|
250
|
+
}, ...(ngDevMode ? [{ debugName: "#syncTabTitleOnActivate" }] : /* istanbul ignore next */ []));
|
|
251
|
+
/** Publishes structured tab preview (hover card + dirty badge) for this cached page. */
|
|
252
|
+
this.#syncTabStructuredPreview = effect(() => {
|
|
253
|
+
this.updateTrigger();
|
|
254
|
+
const tabKey = this.pageTabKey();
|
|
255
|
+
const titleValue = this.title();
|
|
256
|
+
const descriptionValue = this.description();
|
|
257
|
+
const icon = this.titleIcon();
|
|
258
|
+
const breadcrumbItems = this.breadcrumbs();
|
|
259
|
+
if (!tabKey || this.tabNavigation.effectiveMode() !== 'tabular') {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const isDirty = this.hasUnsavedChanges();
|
|
263
|
+
untracked(() => {
|
|
264
|
+
void this.publishTabStructuredPreview(tabKey, {
|
|
265
|
+
titleValue,
|
|
266
|
+
descriptionValue,
|
|
267
|
+
icon,
|
|
268
|
+
breadcrumbItems,
|
|
269
|
+
isDirty,
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
}, ...(ngDevMode ? [{ debugName: "#syncTabStructuredPreview" }] : /* istanbul ignore next */ []));
|
|
273
|
+
//#endregion
|
|
227
274
|
//#region ---------------- Title ----------------
|
|
228
275
|
this.title = signal('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
229
276
|
this.titleIcon = signal(null, ...(ngDevMode ? [{ debugName: "titleIcon" }] : /* istanbul ignore next */ []));
|
|
@@ -232,6 +279,12 @@ class AXPPageLayoutBaseComponent {
|
|
|
232
279
|
this.title.set(await this.getPageTitle());
|
|
233
280
|
const icon = await this.getPageIcon();
|
|
234
281
|
this.titleIcon.set(icon);
|
|
282
|
+
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
283
|
+
const tabKey = this.pageTabKey();
|
|
284
|
+
if (tabKey && icon) {
|
|
285
|
+
this.tabNavigation.syncTabIcon(tabKey, icon);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
235
288
|
}, ...(ngDevMode ? [{ debugName: "#titleEffect" }] : /* istanbul ignore next */ []));
|
|
236
289
|
this.hasTitle = computed(() => {
|
|
237
290
|
const value = this.title();
|
|
@@ -247,6 +300,19 @@ class AXPPageLayoutBaseComponent {
|
|
|
247
300
|
return false;
|
|
248
301
|
}, ...(ngDevMode ? [{ debugName: "hasTitle" }] : /* istanbul ignore next */ []));
|
|
249
302
|
this.hasTitleIcon = computed(() => this.titleIcon() !== null, ...(ngDevMode ? [{ debugName: "hasTitleIcon" }] : /* istanbul ignore next */ []));
|
|
303
|
+
this.#browserTitleEffect = effect(() => {
|
|
304
|
+
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (!this.isActivePageForBrowserTitle()) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
this.updateTrigger();
|
|
311
|
+
this.title();
|
|
312
|
+
untracked(() => {
|
|
313
|
+
void this.publishBrowserTitleIfActive();
|
|
314
|
+
});
|
|
315
|
+
}, ...(ngDevMode ? [{ debugName: "#browserTitleEffect" }] : /* istanbul ignore next */ []));
|
|
250
316
|
//#endregion
|
|
251
317
|
//#region ---------------- Description ----------------
|
|
252
318
|
this.description = signal(null, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
@@ -285,7 +351,19 @@ class AXPPageLayoutBaseComponent {
|
|
|
285
351
|
this.#breadcrumbsEffect = effect(async () => {
|
|
286
352
|
this.updateTrigger();
|
|
287
353
|
const breadCrumbs = await this.getPageBreadcrumbs();
|
|
288
|
-
|
|
354
|
+
const trail = [...this.defaultBreadCrumbs, ...breadCrumbs];
|
|
355
|
+
this.breadcrumbs.set(trail);
|
|
356
|
+
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
357
|
+
const tabKey = this.pageTabKey();
|
|
358
|
+
const tabTitleSegments = await this.resolveBreadcrumbTabTitleSegments(breadCrumbs);
|
|
359
|
+
let tabTitle = tabTitleSegments.length ? axpJoinTabTitleSegments(tabTitleSegments) : null;
|
|
360
|
+
if (!tabTitle) {
|
|
361
|
+
tabTitle = await this.resolvePageTitleForTab();
|
|
362
|
+
}
|
|
363
|
+
if (tabKey && tabTitle) {
|
|
364
|
+
this.tabNavigation.syncTabTitle(tabKey, tabTitleSegments.length ? tabTitleSegments : tabTitle);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
289
367
|
}, ...(ngDevMode ? [{ debugName: "#breadcrumbsEffect" }] : /* istanbul ignore next */ []));
|
|
290
368
|
this.hasBreadcrumbs = computed(() => this.breadcrumbs().length > 1, ...(ngDevMode ? [{ debugName: "hasBreadcrumbs" }] : /* istanbul ignore next */ []));
|
|
291
369
|
//#endregion
|
|
@@ -343,9 +421,83 @@ class AXPPageLayoutBaseComponent {
|
|
|
343
421
|
//#endregion
|
|
344
422
|
//#region ---------------- Lifecycle hooks ----------------
|
|
345
423
|
async ngOnInit() {
|
|
424
|
+
this.pageTabKey.set(this.resolvePageTabKey());
|
|
346
425
|
this.translateService.langChanges$.subscribe(() => {
|
|
347
426
|
this.recompute();
|
|
348
427
|
});
|
|
428
|
+
this.router.events
|
|
429
|
+
.pipe(filter((event) => event instanceof NavigationEnd), takeUntilDestroyed(this.pageLayoutDestroyRef))
|
|
430
|
+
.subscribe(() => {
|
|
431
|
+
void this.publishBrowserTitleIfActive();
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
/** Maps the home-page route to the pinned home tab key instead of a path-based key. */
|
|
435
|
+
resolvePageTabKey() {
|
|
436
|
+
const homePath = this.homePageService.getCurrent().path;
|
|
437
|
+
if (homePath && normalizeRouterUrl(homePath) === normalizeRouterUrl(this.router.url)) {
|
|
438
|
+
return AXP_HOME_TAB_KEY;
|
|
439
|
+
}
|
|
440
|
+
return axpResolveTabKey(this.router);
|
|
441
|
+
}
|
|
442
|
+
/** Stable tab key for this cached page instance (tabular mode). */
|
|
443
|
+
getPageTabKey() {
|
|
444
|
+
return this.pageTabKey();
|
|
445
|
+
}
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region ---------------- Tab Title Sync ----------------
|
|
448
|
+
/** Refreshes tab title when this cached page becomes the active tab again. */
|
|
449
|
+
#syncTabTitleOnActivate;
|
|
450
|
+
/** Publishes structured tab preview (hover card + dirty badge) for this cached page. */
|
|
451
|
+
#syncTabStructuredPreview;
|
|
452
|
+
async publishTabStructuredPreview(tabKey, input) {
|
|
453
|
+
const tab = this.tabNavigation.tabList().find((item) => item.key === tabKey);
|
|
454
|
+
const breadcrumbTrail = [];
|
|
455
|
+
for (const item of input.breadcrumbItems.slice(1)) {
|
|
456
|
+
const segment = await this.resolveBreadcrumbItemTitle(item);
|
|
457
|
+
if (segment && segment !== breadcrumbTrail[breadcrumbTrail.length - 1]) {
|
|
458
|
+
breadcrumbTrail.push(segment);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const fallbackTitle = await this.translateTextIfKey(breadcrumbTrail.join(' - ') || tab?.title || '');
|
|
462
|
+
const title = await this.resolveMultiLanguageText(input.titleValue, fallbackTitle);
|
|
463
|
+
const subtitle = await this.resolveMultiLanguageText(input.descriptionValue, '');
|
|
464
|
+
this.tabPreviewService.setPreview(tabKey, {
|
|
465
|
+
title,
|
|
466
|
+
subtitle: subtitle || undefined,
|
|
467
|
+
url: tab?.url ?? '',
|
|
468
|
+
icon: input.icon ?? tab?.icon,
|
|
469
|
+
isDirty: input.isDirty,
|
|
470
|
+
breadcrumbTrail,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
async resolveMultiLanguageText(value, fallback) {
|
|
474
|
+
const resolvedFallback = await this.translateTextIfKey(fallback);
|
|
475
|
+
if (value == null || value === '') {
|
|
476
|
+
return resolvedFallback;
|
|
477
|
+
}
|
|
478
|
+
if (typeof value === 'string') {
|
|
479
|
+
const trimmed = value.trim();
|
|
480
|
+
if (!trimmed) {
|
|
481
|
+
return resolvedFallback;
|
|
482
|
+
}
|
|
483
|
+
if (trimmed.startsWith('@')) {
|
|
484
|
+
return (await this.translateService.translateAsync(trimmed)) || resolvedFallback;
|
|
485
|
+
}
|
|
486
|
+
return trimmed;
|
|
487
|
+
}
|
|
488
|
+
const resolved = this.translateService.resolve(value);
|
|
489
|
+
return resolved || resolvedFallback;
|
|
490
|
+
}
|
|
491
|
+
/** Resolves i18n keys (`@scope:key`); returns plain text unchanged. */
|
|
492
|
+
async translateTextIfKey(text) {
|
|
493
|
+
const trimmed = text.trim();
|
|
494
|
+
if (!trimmed) {
|
|
495
|
+
return '';
|
|
496
|
+
}
|
|
497
|
+
if (trimmed.startsWith('@')) {
|
|
498
|
+
return (await this.translateService.translateAsync(trimmed)) || trimmed;
|
|
499
|
+
}
|
|
500
|
+
return trimmed;
|
|
349
501
|
}
|
|
350
502
|
#titleEffect;
|
|
351
503
|
getPageTitle() {
|
|
@@ -354,6 +506,33 @@ class AXPPageLayoutBaseComponent {
|
|
|
354
506
|
getPageIcon() {
|
|
355
507
|
return null;
|
|
356
508
|
}
|
|
509
|
+
#browserTitleEffect;
|
|
510
|
+
/** Publishes the page title to the browser tab when this instance is the active route. */
|
|
511
|
+
async publishBrowserTitleIfActive() {
|
|
512
|
+
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (!this.isActivePageForBrowserTitle()) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const routeKey = this.pageTabKey();
|
|
519
|
+
if (!routeKey) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const pageTitle = await this.resolvePageTitleForTab();
|
|
523
|
+
if (!this.isActivePageForBrowserTitle()) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
this.browserTitleService.setSimpleModePageTitle(pageTitle, routeKey);
|
|
527
|
+
}
|
|
528
|
+
/** True when this cached page instance matches the current router location. */
|
|
529
|
+
isActivePageForBrowserTitle() {
|
|
530
|
+
const pageKey = this.pageTabKey();
|
|
531
|
+
if (!pageKey) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
return pageKey === axpResolveTabKey(this.router);
|
|
535
|
+
}
|
|
357
536
|
#descriptionEffect;
|
|
358
537
|
getPageDescription() {
|
|
359
538
|
return null;
|
|
@@ -362,10 +541,83 @@ class AXPPageLayoutBaseComponent {
|
|
|
362
541
|
getPageBreadcrumbs() {
|
|
363
542
|
return [];
|
|
364
543
|
}
|
|
544
|
+
/** Collects resolved breadcrumb labels (Home excluded upstream) for tab chrome. */
|
|
545
|
+
async resolveBreadcrumbTabTitleSegments(pageBreadcrumbs) {
|
|
546
|
+
const segments = [];
|
|
547
|
+
for (const item of pageBreadcrumbs) {
|
|
548
|
+
const title = await this.resolveBreadcrumbItemTitle(item);
|
|
549
|
+
if (title && title !== segments[segments.length - 1]) {
|
|
550
|
+
segments.push(title);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return segments;
|
|
554
|
+
}
|
|
555
|
+
/** Joins breadcrumb segments as the stored tab title string. */
|
|
556
|
+
async resolveBreadcrumbTabTitle(pageBreadcrumbs) {
|
|
557
|
+
const segments = await this.resolveBreadcrumbTabTitleSegments(pageBreadcrumbs);
|
|
558
|
+
if (!segments.length) {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
return axpJoinTabTitleSegments(segments);
|
|
562
|
+
}
|
|
563
|
+
/** Resolves a breadcrumb label the same way as page chrome (`t(item.title)`). */
|
|
564
|
+
async resolveBreadcrumbItemTitle(item) {
|
|
565
|
+
const raw = item?.title;
|
|
566
|
+
if (raw == null || raw === '') {
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
569
|
+
if (typeof raw === 'string') {
|
|
570
|
+
const trimmed = raw.trim();
|
|
571
|
+
if (!trimmed) {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
if (trimmed.startsWith('@')) {
|
|
575
|
+
return (await this.translateService.translateAsync(trimmed)) || trimmed;
|
|
576
|
+
}
|
|
577
|
+
return trimmed;
|
|
578
|
+
}
|
|
579
|
+
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
580
|
+
if (this.translateService.isValidMultiLanguageObject(raw)) {
|
|
581
|
+
const resolved = this.translateService.resolve(raw);
|
|
582
|
+
return resolved || null;
|
|
583
|
+
}
|
|
584
|
+
const resolved = this.translateService.resolve(raw);
|
|
585
|
+
return resolved || null;
|
|
586
|
+
}
|
|
587
|
+
return String(raw);
|
|
588
|
+
}
|
|
589
|
+
/** Fallback tab label from the page title when breadcrumbs are not ready yet. */
|
|
590
|
+
async resolvePageTitleForTab() {
|
|
591
|
+
const raw = await Promise.resolve(this.getPageTitle());
|
|
592
|
+
if (raw == null || raw === '') {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
if (typeof raw === 'string') {
|
|
596
|
+
const trimmed = raw.trim();
|
|
597
|
+
if (trimmed.startsWith('@')) {
|
|
598
|
+
return (await this.translateService.translateAsync(trimmed)) || trimmed;
|
|
599
|
+
}
|
|
600
|
+
return trimmed;
|
|
601
|
+
}
|
|
602
|
+
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
603
|
+
const resolved = this.translateService.resolve(raw);
|
|
604
|
+
return resolved || null;
|
|
605
|
+
}
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
365
608
|
#badgeEffect;
|
|
366
609
|
hasUnsavedChanges() {
|
|
367
610
|
return false;
|
|
368
611
|
}
|
|
612
|
+
/**
|
|
613
|
+
* Confirms closing this page as a background tab (no router navigation).
|
|
614
|
+
* Override when dirty detection differs from {@link hasUnsavedChanges}.
|
|
615
|
+
*/
|
|
616
|
+
onBeforeTabClose() {
|
|
617
|
+
return this.unsavedChangesConfirm.confirmIfDirty(this.hasUnsavedChanges(), {
|
|
618
|
+
approveLeaveOnConfirm: false,
|
|
619
|
+
});
|
|
620
|
+
}
|
|
369
621
|
async getPageBadge() {
|
|
370
622
|
if (!this.hasUnsavedChanges()) {
|
|
371
623
|
return null;
|
|
@@ -586,6 +838,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
586
838
|
}]
|
|
587
839
|
}], propDecorators: { layout: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPopupLayoutComponent), { isSignal: true }] }] } });
|
|
588
840
|
|
|
841
|
+
const AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER = new InjectionToken('AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER');
|
|
842
|
+
//#endregion
|
|
843
|
+
|
|
844
|
+
/** Trace namespace for details-view page / URL sync diagnostics. */
|
|
845
|
+
const DETAILS_VIEW_PAGE_TRACE_NS = 'details-view-page';
|
|
846
|
+
|
|
589
847
|
//#region ---- Root-context widget expression resolution ----
|
|
590
848
|
/**
|
|
591
849
|
* Evaluates `{{ ... }}` strings inside `options.customFilterDefinitions` using `rootContext`
|
|
@@ -625,10 +883,11 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
625
883
|
const state = {
|
|
626
884
|
adapter: null,
|
|
627
885
|
rootContext: {},
|
|
886
|
+
savedContext: {},
|
|
628
887
|
previousContext: {},
|
|
629
888
|
context: {},
|
|
630
889
|
scope: null,
|
|
631
|
-
status: AXPPageStatus.
|
|
890
|
+
status: AXPPageStatus.Idle,
|
|
632
891
|
currentPage: null,
|
|
633
892
|
currentTab: null,
|
|
634
893
|
pageSelectedRows: [],
|
|
@@ -653,6 +912,10 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
653
912
|
//
|
|
654
913
|
isBusy: computed(() => store.status() == AXPPageStatus.Processing),
|
|
655
914
|
isSaving: computed(() => store.status() == AXPPageStatus.Submitting),
|
|
915
|
+
isOverlayBusy: computed(() => store.status() === AXPPageStatus.Processing || store.status() === AXPPageStatus.Submitting),
|
|
916
|
+
isPageReady: computed(() => store.adapter() != null &&
|
|
917
|
+
store.currentPage() != null &&
|
|
918
|
+
store.status() === AXPPageStatus.Rendered),
|
|
656
919
|
isDirty: computed(() => {
|
|
657
920
|
if (store.currentPage()?.isReadonly) {
|
|
658
921
|
return false;
|
|
@@ -676,64 +939,150 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
676
939
|
const evaluatedByTab = store.evaluatedTabContentsById();
|
|
677
940
|
return evaluatedByTab[tab.id] ?? [];
|
|
678
941
|
}),
|
|
679
|
-
})), withMethods((store, evaluatorService = inject(AXPExpressionEvaluatorService), router = inject(Router), route = inject(ActivatedRoute), deviceService = inject(AXPDeviceService), formatService = inject(AXFormatService), toastService = inject(AXToastService), translateService = inject(AXTranslationService), settingsService = inject(AXPSettingsService)) => {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const queryParams = router.routerState.snapshot.root.queryParams;
|
|
684
|
-
const targetPageId = pageId || queryParams['page'];
|
|
685
|
-
if (targetPageId) {
|
|
686
|
-
return adapter.pages.find((p) => p.id === targetPageId) ?? null;
|
|
942
|
+
})), withMethods((store, evaluatorService = inject(AXPExpressionEvaluatorService), contextEvalFactory = inject(AXPContextEvalFactory), router = inject(Router), route = inject(ActivatedRoute), deviceService = inject(AXPDeviceService), formatService = inject(AXFormatService), toastService = inject(AXToastService), translateService = inject(AXTranslationService), settingsService = inject(AXPSettingsService), layout = inject(AXPLayoutThemeService), adapterLoader = inject(AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER)) => {
|
|
943
|
+
const resolvePageFromId = (adapter, pageId) => {
|
|
944
|
+
if (pageId) {
|
|
945
|
+
return adapter.pages.find((p) => p.id === pageId) ?? null;
|
|
687
946
|
}
|
|
688
947
|
if (deviceService.isLarge() || adapter.pages.length === 1) {
|
|
689
|
-
return adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0];
|
|
948
|
+
return adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0] ?? null;
|
|
690
949
|
}
|
|
691
950
|
return null;
|
|
692
951
|
};
|
|
693
|
-
|
|
952
|
+
/** Serializes page activation so route sync and UI cannot run overlapping loads. */
|
|
953
|
+
let pageActivationChain = Promise.resolve();
|
|
954
|
+
/** Serializes route-driven adapter loads (initial navigation and layout refresh). */
|
|
955
|
+
let routeLoadChain = Promise.resolve();
|
|
956
|
+
/** `page` query param from the browser URL (reliable on hard refresh). */
|
|
957
|
+
const readPageQueryParam = () => {
|
|
958
|
+
const page = router.parseUrl(router.url).queryParams['page'];
|
|
959
|
+
return typeof page === 'string' && page.length > 0 ? page : null;
|
|
960
|
+
};
|
|
961
|
+
/** Snapshot of all page-query sources for trace logs. */
|
|
962
|
+
const pageQueryTraceContext = (extra = {}) => ({
|
|
963
|
+
routerUrl: router.url,
|
|
964
|
+
pageFromRouterUrl: readPageQueryParam(),
|
|
965
|
+
pageFromRouteSnapshot: route.snapshot.queryParamMap.get('page'),
|
|
966
|
+
pageFromRootSnapshot: router.routerState.snapshot.root.queryParams['page'] ?? null,
|
|
967
|
+
currentPageId: store.currentPage()?.id ?? null,
|
|
968
|
+
adapterPageIds: store.adapter()?.pages.map((p) => p.id) ?? [],
|
|
969
|
+
...extra,
|
|
970
|
+
});
|
|
971
|
+
/** Loads page data, context, and evaluated widgets for the target sidebar page. */
|
|
972
|
+
const activatePageById = async (pageId, forceRefresh) => {
|
|
973
|
+
const activation = pageActivationChain.then(() => runPageActivation(pageId, forceRefresh));
|
|
974
|
+
pageActivationChain = activation.catch(() => undefined);
|
|
975
|
+
await activation;
|
|
976
|
+
};
|
|
977
|
+
const runPageActivation = async (pageId, forceRefresh) => {
|
|
694
978
|
const adapter = store.adapter();
|
|
695
979
|
if (!adapter) {
|
|
696
|
-
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
const targetPageId = pageId ?? readPageQueryParam() ?? undefined;
|
|
983
|
+
const currentPage = resolvePageFromId(adapter, targetPageId);
|
|
984
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'runPageActivation', () => pageQueryTraceContext({
|
|
985
|
+
passedPageId: pageId ?? null,
|
|
986
|
+
targetPageId: targetPageId ?? null,
|
|
987
|
+
resolvedPageId: currentPage?.id ?? null,
|
|
988
|
+
forceRefresh: forceRefresh ?? false,
|
|
989
|
+
vmStatus: store.status(),
|
|
990
|
+
}));
|
|
991
|
+
if (!forceRefresh && currentPage?.id === store.currentPage()?.id && store.status() === AXPPageStatus.Rendered) {
|
|
992
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'runPageActivation skipped (already rendered)', () => pageQueryTraceContext({
|
|
993
|
+
resolvedPageId: currentPage?.id ?? null,
|
|
994
|
+
}));
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
const previousPageId = store.currentPage()?.id;
|
|
998
|
+
const isSidebarSwitch = previousPageId != null && previousPageId !== currentPage?.id;
|
|
999
|
+
if (isSidebarSwitch) {
|
|
1000
|
+
layout.setNavigationLoading(true);
|
|
1001
|
+
}
|
|
1002
|
+
const overlayAlreadyOn = layout.overlayTaskCount() > 0;
|
|
1003
|
+
if (!overlayAlreadyOn) {
|
|
1004
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'activatePage overlay ON', () => ({
|
|
1005
|
+
pageId: currentPage?.id,
|
|
1006
|
+
forceRefresh,
|
|
1007
|
+
isSidebarSwitch,
|
|
1008
|
+
}));
|
|
1009
|
+
layout.setOverlayLoading(true);
|
|
1010
|
+
}
|
|
1011
|
+
else {
|
|
1012
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'activatePage skipped overlay ON (task count > 0)', () => ({
|
|
1013
|
+
pageId: currentPage?.id,
|
|
1014
|
+
forceRefresh,
|
|
1015
|
+
isSidebarSwitch,
|
|
1016
|
+
taskCount: layout.overlayTaskCount(),
|
|
1017
|
+
}));
|
|
697
1018
|
}
|
|
698
|
-
const generation = ++pageLoadGeneration;
|
|
699
1019
|
patchState(store, {
|
|
700
1020
|
status: AXPPageStatus.Processing,
|
|
701
1021
|
});
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1022
|
+
try {
|
|
1023
|
+
let context = {};
|
|
1024
|
+
if (currentPage) {
|
|
1025
|
+
const currentPageIndex = adapter.pages.findIndex((p) => p.id === currentPage.id);
|
|
1026
|
+
const pageLoad = adapter.pages[currentPageIndex]?.load;
|
|
1027
|
+
if (typeof pageLoad === 'function') {
|
|
1028
|
+
const loadResult = await pageLoad({ forceRefresh });
|
|
1029
|
+
context = loadResult?.data ?? {};
|
|
1030
|
+
}
|
|
1031
|
+
else {
|
|
1032
|
+
// Component/list sidebar pages have no `load`; keep entity root context so widget
|
|
1033
|
+
// state is not cleared (Change History, etc. use `rootContext` instead).
|
|
1034
|
+
context = cloneDeep(store.rootContext());
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
const currentTab = currentPage?.tabs?.[0] ?? null;
|
|
1038
|
+
const shouldSyncRootContext = forceRefresh === true && currentPage?.isPrimary === true && !isEmpty(context);
|
|
1039
|
+
const rootCtx = shouldSyncRootContext
|
|
1040
|
+
? context
|
|
1041
|
+
: store.rootContext();
|
|
1042
|
+
const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(currentPage, rootCtx, evaluatorService);
|
|
1043
|
+
patchState(store, {
|
|
1044
|
+
previousContext: cloneDeep(context),
|
|
1045
|
+
context: cloneDeep(context),
|
|
1046
|
+
savedContext: cloneDeep(context),
|
|
1047
|
+
...(shouldSyncRootContext ? { rootContext: cloneDeep(context) } : {}),
|
|
1048
|
+
status: AXPPageStatus.Rendered,
|
|
1049
|
+
currentPage,
|
|
1050
|
+
currentTab,
|
|
1051
|
+
evaluatedPageContent,
|
|
1052
|
+
evaluatedTabContentsById,
|
|
1053
|
+
formDirty: false,
|
|
1054
|
+
});
|
|
1055
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'activatePage VM ready (Rendered)', () => ({
|
|
1056
|
+
pageId: currentPage?.id,
|
|
1057
|
+
forceRefresh,
|
|
1058
|
+
}));
|
|
1059
|
+
const urlPageParam = readPageQueryParam();
|
|
1060
|
+
if (currentPage && axpIsEntityDetailsViewRoute(router)) {
|
|
1061
|
+
if (!urlPageParam) {
|
|
1062
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'URL sync — add missing ?page=', () => pageQueryTraceContext({
|
|
1063
|
+
navigateToPageId: currentPage.id,
|
|
1064
|
+
}));
|
|
1065
|
+
router.navigate([], {
|
|
1066
|
+
relativeTo: route,
|
|
1067
|
+
queryParams: { page: currentPage.id },
|
|
1068
|
+
queryParamsHandling: 'merge',
|
|
1069
|
+
replaceUrl: true,
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'URL sync — skipped (page already in URL)', () => pageQueryTraceContext({
|
|
1074
|
+
urlPageParam,
|
|
1075
|
+
resolvedPageId: currentPage.id,
|
|
1076
|
+
}));
|
|
1077
|
+
}
|
|
709
1078
|
}
|
|
710
|
-
context = loadResult?.data ?? {};
|
|
711
|
-
}
|
|
712
|
-
const currentTab = currentPage?.tabs?.[0] ?? null;
|
|
713
|
-
const rootCtx = store.rootContext();
|
|
714
|
-
const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(currentPage, rootCtx, evaluatorService);
|
|
715
|
-
if (generation !== pageLoadGeneration) {
|
|
716
|
-
return;
|
|
717
1079
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
evaluatedPageContent,
|
|
725
|
-
evaluatedTabContentsById,
|
|
726
|
-
formDirty: false,
|
|
727
|
-
});
|
|
728
|
-
if (currentPage && axpIsEntityDetailsViewRoute(router)) {
|
|
729
|
-
const pageParam = route.snapshot.queryParamMap.get('page');
|
|
730
|
-
if (pageParam !== currentPage.id) {
|
|
731
|
-
router.navigate([], {
|
|
732
|
-
relativeTo: route,
|
|
733
|
-
queryParams: { page: currentPage.id },
|
|
734
|
-
queryParamsHandling: 'merge',
|
|
735
|
-
replaceUrl: true,
|
|
736
|
-
});
|
|
1080
|
+
finally {
|
|
1081
|
+
if (isSidebarSwitch) {
|
|
1082
|
+
layout.setNavigationLoading(false);
|
|
1083
|
+
}
|
|
1084
|
+
if (store.status() === AXPPageStatus.Processing) {
|
|
1085
|
+
patchState(store, { status: AXPPageStatus.Rendered });
|
|
737
1086
|
}
|
|
738
1087
|
}
|
|
739
1088
|
};
|
|
@@ -747,16 +1096,33 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
747
1096
|
if (!adapter) {
|
|
748
1097
|
return;
|
|
749
1098
|
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1099
|
+
// `load()` → `loadPage()` owns the first activation while `currentPage` is still null.
|
|
1100
|
+
if (store.currentPage() == null) {
|
|
1101
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (currentPage null)', () => pageQueryTraceContext({
|
|
1102
|
+
paramsPage: params['page'] ?? null,
|
|
1103
|
+
}));
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
const pageId = params['page'];
|
|
1107
|
+
if (!pageId) {
|
|
1108
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (no page param)', () => pageQueryTraceContext({
|
|
1109
|
+
params,
|
|
1110
|
+
}));
|
|
754
1111
|
return;
|
|
755
1112
|
}
|
|
756
|
-
|
|
1113
|
+
const targetPage = adapter.pages.find((p) => p.id === pageId);
|
|
1114
|
+
if (!targetPage || store.currentPage()?.id === targetPage.id) {
|
|
1115
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (same or unknown page)', () => pageQueryTraceContext({
|
|
1116
|
+
paramsPage: pageId,
|
|
1117
|
+
targetPageFound: !!targetPage,
|
|
1118
|
+
}));
|
|
757
1119
|
return;
|
|
758
1120
|
}
|
|
759
|
-
|
|
1121
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — activatePageById', () => pageQueryTraceContext({
|
|
1122
|
+
paramsPage: pageId,
|
|
1123
|
+
activatePageId: targetPage.id,
|
|
1124
|
+
}));
|
|
1125
|
+
void activatePageById(targetPage.id);
|
|
760
1126
|
});
|
|
761
1127
|
onCleanup(() => subscription.unsubscribe());
|
|
762
1128
|
});
|
|
@@ -817,7 +1183,12 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
817
1183
|
evaluated = await evaluatorService.evaluate(raw, evalScope);
|
|
818
1184
|
}
|
|
819
1185
|
else if (typeof sourceAfterPreLocale === 'string') {
|
|
820
|
-
|
|
1186
|
+
if (sourceAfterPreLocale.trim().startsWith('@')) {
|
|
1187
|
+
evaluated = await translateService.translateAsync(sourceAfterPreLocale);
|
|
1188
|
+
}
|
|
1189
|
+
else {
|
|
1190
|
+
evaluated = await formatService.format(sourceAfterPreLocale, 'string', formatContext);
|
|
1191
|
+
}
|
|
821
1192
|
}
|
|
822
1193
|
else {
|
|
823
1194
|
evaluated = await formatService.format(raw, 'string', formatContext);
|
|
@@ -851,15 +1222,12 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
851
1222
|
});
|
|
852
1223
|
},
|
|
853
1224
|
async loadPage(pageId, forceRefresh) {
|
|
854
|
-
await
|
|
1225
|
+
await activatePageById(pageId, forceRefresh);
|
|
855
1226
|
},
|
|
856
|
-
async load(adapter) {
|
|
857
|
-
// Setup expression evaluator scope
|
|
1227
|
+
async load(adapter, forceRefresh, pageIdFromUrl) {
|
|
858
1228
|
const scope = {
|
|
859
1229
|
context: {
|
|
860
|
-
|
|
861
|
-
return getSmart(store.context(), path);
|
|
862
|
-
},
|
|
1230
|
+
...contextEvalFactory.createLiveScope(() => store.context()),
|
|
863
1231
|
isDirty: () => store.isDirty(),
|
|
864
1232
|
},
|
|
865
1233
|
};
|
|
@@ -868,7 +1236,81 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
868
1236
|
});
|
|
869
1237
|
//
|
|
870
1238
|
await this.loadAdapter(adapter);
|
|
871
|
-
|
|
1239
|
+
const pageId = pageIdFromUrl ?? readPageQueryParam() ?? undefined;
|
|
1240
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'load — activate page', () => pageQueryTraceContext({
|
|
1241
|
+
pageIdFromUrl: pageIdFromUrl ?? null,
|
|
1242
|
+
resolvedPageId: pageId ?? null,
|
|
1243
|
+
forceRefresh: forceRefresh ?? false,
|
|
1244
|
+
}));
|
|
1245
|
+
await this.loadPage(pageId, forceRefresh);
|
|
1246
|
+
},
|
|
1247
|
+
async loadFromRoute(forceRefresh) {
|
|
1248
|
+
const run = async () => {
|
|
1249
|
+
const pageIdFromUrl = readPageQueryParam() ?? undefined;
|
|
1250
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'loadFromRoute start', () => pageQueryTraceContext({
|
|
1251
|
+
pageIdFromUrl: pageIdFromUrl ?? null,
|
|
1252
|
+
forceRefresh: forceRefresh ?? false,
|
|
1253
|
+
}));
|
|
1254
|
+
const moduleName = route.parent?.snapshot.paramMap.get('module');
|
|
1255
|
+
const entityName = route.snapshot.paramMap.get('entity');
|
|
1256
|
+
const id = route.snapshot.paramMap.get('id');
|
|
1257
|
+
if (!moduleName || !entityName || !id) {
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
layout.setNavigationLoading(true);
|
|
1261
|
+
if (layout.overlayTaskCount() === 0) {
|
|
1262
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'loadFromRoute overlay ON', () => ({
|
|
1263
|
+
moduleName,
|
|
1264
|
+
entityName,
|
|
1265
|
+
id,
|
|
1266
|
+
forceRefresh,
|
|
1267
|
+
}));
|
|
1268
|
+
layout.setOverlayLoading(true);
|
|
1269
|
+
}
|
|
1270
|
+
else {
|
|
1271
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'loadFromRoute skipped overlay ON (task count > 0)', () => ({
|
|
1272
|
+
moduleName,
|
|
1273
|
+
entityName,
|
|
1274
|
+
id,
|
|
1275
|
+
forceRefresh,
|
|
1276
|
+
taskCount: layout.overlayTaskCount(),
|
|
1277
|
+
}));
|
|
1278
|
+
}
|
|
1279
|
+
try {
|
|
1280
|
+
if (forceRefresh) {
|
|
1281
|
+
patchState(store, {
|
|
1282
|
+
currentPage: null,
|
|
1283
|
+
status: AXPPageStatus.Idle,
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
const adapter = await adapterLoader.load({ moduleName, entityName, id });
|
|
1287
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'adapter loaded (overlay still ON — details-view releases)', () => ({
|
|
1288
|
+
moduleName,
|
|
1289
|
+
entityName,
|
|
1290
|
+
id,
|
|
1291
|
+
}));
|
|
1292
|
+
await this.load(adapter, forceRefresh, pageIdFromUrl);
|
|
1293
|
+
}
|
|
1294
|
+
catch (error) {
|
|
1295
|
+
AXPDebugService.instance?.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'viewmodel', 'loadFromRoute overlay OFF (error)', () => ({
|
|
1296
|
+
moduleName,
|
|
1297
|
+
entityName,
|
|
1298
|
+
id,
|
|
1299
|
+
}));
|
|
1300
|
+
layout.setOverlayLoading(false);
|
|
1301
|
+
if (error instanceof AXPNotFoundError) {
|
|
1302
|
+
void router.navigateByUrl(AXP_NOT_FOUND_ROUTE);
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
throw error;
|
|
1306
|
+
}
|
|
1307
|
+
finally {
|
|
1308
|
+
layout.setNavigationLoading(false);
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
const load = routeLoadChain.then(run);
|
|
1312
|
+
routeLoadChain = load.catch(() => undefined);
|
|
1313
|
+
await load;
|
|
872
1314
|
},
|
|
873
1315
|
updateContext(context) {
|
|
874
1316
|
patchState(store, {
|
|
@@ -937,13 +1379,23 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
937
1379
|
},
|
|
938
1380
|
setCurrentPage(page) {
|
|
939
1381
|
const previousPage = store.currentPage();
|
|
1382
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage', () => pageQueryTraceContext({
|
|
1383
|
+
requestedPageId: page?.id ?? null,
|
|
1384
|
+
previousPageId: previousPage?.id ?? null,
|
|
1385
|
+
}));
|
|
940
1386
|
if (page) {
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1387
|
+
if (!previousPage) {
|
|
1388
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage — ignored (initial load in progress)', () => pageQueryTraceContext({
|
|
1389
|
+
requestedPageId: page.id,
|
|
1390
|
+
}));
|
|
944
1391
|
return;
|
|
945
1392
|
}
|
|
946
|
-
|
|
1393
|
+
const pageParam = readPageQueryParam();
|
|
1394
|
+
const isSamePage = previousPage?.id === page.id && pageParam === page.id;
|
|
1395
|
+
if (!isSamePage && axpIsEntityDetailsViewRoute(router)) {
|
|
1396
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage — navigate', () => pageQueryTraceContext({
|
|
1397
|
+
navigateToPageId: page.id,
|
|
1398
|
+
}));
|
|
947
1399
|
const queryParams = { page: page.id };
|
|
948
1400
|
if (previousPage?.id && previousPage.id !== page.id) {
|
|
949
1401
|
queryParams['filters'] = null;
|
|
@@ -955,17 +1407,16 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
955
1407
|
// Push history for desktop sidebar switches and mobile page-list picks.
|
|
956
1408
|
replaceUrl: false,
|
|
957
1409
|
});
|
|
1410
|
+
return;
|
|
958
1411
|
}
|
|
959
|
-
void
|
|
1412
|
+
void activatePageById(page.id);
|
|
960
1413
|
}
|
|
961
1414
|
else {
|
|
962
|
-
pageLoadGeneration += 1;
|
|
963
1415
|
patchState(store, {
|
|
964
1416
|
currentPage: null,
|
|
965
1417
|
currentTab: null,
|
|
966
1418
|
evaluatedPageContent: [],
|
|
967
1419
|
evaluatedTabContentsById: {},
|
|
968
|
-
status: AXPPageStatus.Rendered,
|
|
969
1420
|
});
|
|
970
1421
|
if (axpIsEntityDetailsViewRoute(router)) {
|
|
971
1422
|
const currentParams = { ...route.snapshot.queryParams };
|
|
@@ -1087,12 +1538,16 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1087
1538
|
const snapshot = cloneDeep(context);
|
|
1088
1539
|
patchState(store, {
|
|
1089
1540
|
context: snapshot,
|
|
1541
|
+
savedContext: snapshot,
|
|
1090
1542
|
previousContext: snapshot,
|
|
1091
1543
|
formDirty: false,
|
|
1092
1544
|
});
|
|
1093
1545
|
},
|
|
1094
1546
|
async discard() {
|
|
1547
|
+
const saved = cloneDeep(store.savedContext());
|
|
1095
1548
|
patchState(store, {
|
|
1549
|
+
context: saved,
|
|
1550
|
+
previousContext: saved,
|
|
1096
1551
|
formDirty: false,
|
|
1097
1552
|
});
|
|
1098
1553
|
},
|
|
@@ -1107,10 +1562,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1107
1562
|
});
|
|
1108
1563
|
try {
|
|
1109
1564
|
const result = await store.currentPage()?.execute?.(command, payload);
|
|
1110
|
-
// Clear submitting before post-save refresh so the footer is not left disabled.
|
|
1111
|
-
patchState(store, {
|
|
1112
|
-
status: AXPPageStatus.Rendered,
|
|
1113
|
-
});
|
|
1114
1565
|
const enableOperationToasts = await settingsService.get(AXPCommonSettings.EnableOperationToasts);
|
|
1115
1566
|
if (result?.success) {
|
|
1116
1567
|
try {
|
|
@@ -1121,6 +1572,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1121
1572
|
}
|
|
1122
1573
|
patchState(store, {
|
|
1123
1574
|
previousContext: store.context(),
|
|
1575
|
+
savedContext: cloneDeep(store.context()),
|
|
1124
1576
|
formDirty: false,
|
|
1125
1577
|
});
|
|
1126
1578
|
if (enableOperationToasts) {
|
|
@@ -1134,9 +1586,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1134
1586
|
timeOutProgress: true,
|
|
1135
1587
|
});
|
|
1136
1588
|
}
|
|
1137
|
-
patchState(store, {
|
|
1138
|
-
formDirty: false,
|
|
1139
|
-
});
|
|
1140
1589
|
return true;
|
|
1141
1590
|
}
|
|
1142
1591
|
const rawText = result?.message?.text;
|
|
@@ -1162,9 +1611,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1162
1611
|
const errorText = error instanceof Error
|
|
1163
1612
|
? error.message
|
|
1164
1613
|
: await translateService.translateAsync('@general:messages.generic.error.description');
|
|
1165
|
-
patchState(store, {
|
|
1166
|
-
status: AXPPageStatus.Rendered,
|
|
1167
|
-
});
|
|
1168
1614
|
toastService.show({
|
|
1169
1615
|
color: 'danger',
|
|
1170
1616
|
title: await translateService.translateAsync('@general:messages.generic.error.title'),
|
|
@@ -1177,22 +1623,109 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1177
1623
|
return false;
|
|
1178
1624
|
}
|
|
1179
1625
|
finally {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1626
|
+
patchState(store, {
|
|
1627
|
+
status: AXPPageStatus.Rendered,
|
|
1628
|
+
});
|
|
1185
1629
|
}
|
|
1186
1630
|
},
|
|
1187
|
-
goToListPage() {
|
|
1631
|
+
async goToListPage() {
|
|
1188
1632
|
const exitUrl = store.adapter()?.exitUrl;
|
|
1189
1633
|
if (exitUrl) {
|
|
1190
|
-
|
|
1634
|
+
await axpNavigateAppPath(router, exitUrl);
|
|
1191
1635
|
}
|
|
1192
1636
|
},
|
|
1193
1637
|
};
|
|
1194
1638
|
}));
|
|
1195
1639
|
|
|
1640
|
+
//#region ---- Details View Action Shortcut Utilities ----
|
|
1641
|
+
/** Platform defaults for known entity detail commands when `shortcuts` is omitted on the action. */
|
|
1642
|
+
const DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS = {
|
|
1643
|
+
'delete-entity': ['ctrl+shift+delete'],
|
|
1644
|
+
};
|
|
1645
|
+
const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
|
|
1646
|
+
'update-entity': ['ctrl+s'],
|
|
1647
|
+
discard: ['escape'],
|
|
1648
|
+
};
|
|
1649
|
+
const SAVE_FOOTER_COMMAND_SUFFIX = ':Save';
|
|
1650
|
+
const DISCARD_FOOTER_COMMAND_SUFFIX = ':Discard';
|
|
1651
|
+
/**
|
|
1652
|
+
* Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
|
|
1653
|
+
*/
|
|
1654
|
+
function getDetailsViewActionCommandBaseName(commandName) {
|
|
1655
|
+
if (!commandName) {
|
|
1656
|
+
return '';
|
|
1657
|
+
}
|
|
1658
|
+
return commandName.split('&')[0];
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Resolves keyboard shortcuts for a header entity action.
|
|
1662
|
+
* Explicit `shortcuts` wins; pass `[]` to disable. Otherwise known commands use platform defaults.
|
|
1663
|
+
*/
|
|
1664
|
+
function resolveDetailsViewActionShortcuts(commandBaseName, explicit) {
|
|
1665
|
+
if (explicit !== undefined) {
|
|
1666
|
+
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1667
|
+
return chords.length ? chords : undefined;
|
|
1668
|
+
}
|
|
1669
|
+
const defaults = DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS[commandBaseName];
|
|
1670
|
+
return defaults?.length ? [...defaults] : undefined;
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Resolves save/discard footer command shortcuts from page settings.
|
|
1674
|
+
*/
|
|
1675
|
+
function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
|
|
1676
|
+
if (explicit !== undefined) {
|
|
1677
|
+
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1678
|
+
return chords.length ? chords : undefined;
|
|
1679
|
+
}
|
|
1680
|
+
const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
|
|
1681
|
+
if (defaults?.length) {
|
|
1682
|
+
return [...defaults];
|
|
1683
|
+
}
|
|
1684
|
+
return resolvePageFooterActionDefaultShortcuts(commandName);
|
|
1685
|
+
}
|
|
1686
|
+
/**
|
|
1687
|
+
* Platform defaults for component-page footer save/discard commands (e.g. `MetaDataBuilder:Save`).
|
|
1688
|
+
*/
|
|
1689
|
+
function resolvePageFooterActionDefaultShortcuts(commandName) {
|
|
1690
|
+
if (isSaveFooterCommand(commandName)) {
|
|
1691
|
+
return [...DEFAULT_FOOTER_COMMAND_SHORTCUTS['update-entity']];
|
|
1692
|
+
}
|
|
1693
|
+
if (isDiscardFooterCommand(commandName)) {
|
|
1694
|
+
return [...DEFAULT_FOOTER_COMMAND_SHORTCUTS['discard']];
|
|
1695
|
+
}
|
|
1696
|
+
return undefined;
|
|
1697
|
+
}
|
|
1698
|
+
function isSaveFooterCommand(commandName) {
|
|
1699
|
+
return commandName === 'update-entity' || commandName.endsWith(SAVE_FOOTER_COMMAND_SUFFIX);
|
|
1700
|
+
}
|
|
1701
|
+
function isDiscardFooterCommand(commandName) {
|
|
1702
|
+
return commandName === 'discard' || commandName.endsWith(DISCARD_FOOTER_COMMAND_SUFFIX);
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Resolves keyboard shortcuts for a footer action on entity detail sub-pages.
|
|
1706
|
+
*/
|
|
1707
|
+
function resolvePageFooterActionShortcuts(commandName, explicit) {
|
|
1708
|
+
return resolveDetailsViewFooterCommandShortcuts(commandName, explicit);
|
|
1709
|
+
}
|
|
1710
|
+
function flattenDetailsViewActionShortcuts(shortcuts) {
|
|
1711
|
+
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
1712
|
+
return dedupeDetailsViewActionShortcuts(chords);
|
|
1713
|
+
}
|
|
1714
|
+
function dedupeDetailsViewActionShortcuts(shortcuts) {
|
|
1715
|
+
const seen = new Set();
|
|
1716
|
+
const result = [];
|
|
1717
|
+
for (const shortcut of shortcuts) {
|
|
1718
|
+
const token = shortcut.trim().toLowerCase();
|
|
1719
|
+
if (!token || seen.has(token)) {
|
|
1720
|
+
continue;
|
|
1721
|
+
}
|
|
1722
|
+
seen.add(token);
|
|
1723
|
+
result.push(shortcut.trim());
|
|
1724
|
+
}
|
|
1725
|
+
return result;
|
|
1726
|
+
}
|
|
1727
|
+
//#endregion
|
|
1728
|
+
|
|
1196
1729
|
/**
|
|
1197
1730
|
* Registry of rendered page component instances by component key.
|
|
1198
1731
|
* Used so page execute can delegate to the actual component instance in the view.
|
|
@@ -1331,87 +1864,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1331
1864
|
}]
|
|
1332
1865
|
}], propDecorators: { componentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentKey", required: true }] }], rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: false }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], componentReady: [{ type: i0.Output, args: ["componentReady"] }] } });
|
|
1333
1866
|
|
|
1334
|
-
//#region ---- Details View Action Shortcut Utilities ----
|
|
1335
|
-
/** Platform defaults for known entity detail commands when `shortcuts` is omitted on the action. */
|
|
1336
|
-
const DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS = {
|
|
1337
|
-
'delete-entity': ['ctrl+shift+delete'],
|
|
1338
|
-
};
|
|
1339
|
-
const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
|
|
1340
|
-
'update-entity': ['ctrl+s'],
|
|
1341
|
-
discard: ['escape'],
|
|
1342
|
-
};
|
|
1343
|
-
/**
|
|
1344
|
-
* Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
|
|
1345
|
-
*/
|
|
1346
|
-
function getDetailsViewActionCommandBaseName(commandName) {
|
|
1347
|
-
if (!commandName) {
|
|
1348
|
-
return '';
|
|
1349
|
-
}
|
|
1350
|
-
return commandName.split('&')[0];
|
|
1351
|
-
}
|
|
1352
|
-
/**
|
|
1353
|
-
* Resolves keyboard shortcuts for a header entity action.
|
|
1354
|
-
* Explicit `shortcuts` wins; pass `[]` to disable. Otherwise known commands use platform defaults.
|
|
1355
|
-
*/
|
|
1356
|
-
function resolveDetailsViewActionShortcuts(commandBaseName, explicit) {
|
|
1357
|
-
if (explicit !== undefined) {
|
|
1358
|
-
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1359
|
-
return chords.length ? chords : undefined;
|
|
1360
|
-
}
|
|
1361
|
-
const defaults = DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS[commandBaseName];
|
|
1362
|
-
return defaults?.length ? [...defaults] : undefined;
|
|
1363
|
-
}
|
|
1364
|
-
/**
|
|
1365
|
-
* Resolves save/discard footer command shortcuts from page settings.
|
|
1366
|
-
*/
|
|
1367
|
-
function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
|
|
1368
|
-
if (explicit !== undefined) {
|
|
1369
|
-
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1370
|
-
return chords.length ? chords : undefined;
|
|
1371
|
-
}
|
|
1372
|
-
const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
|
|
1373
|
-
return defaults?.length ? [...defaults] : undefined;
|
|
1374
|
-
}
|
|
1375
|
-
function flattenDetailsViewActionShortcuts(shortcuts) {
|
|
1376
|
-
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
1377
|
-
return dedupeDetailsViewActionShortcuts(chords);
|
|
1378
|
-
}
|
|
1379
|
-
function dedupeDetailsViewActionShortcuts(shortcuts) {
|
|
1380
|
-
const seen = new Set();
|
|
1381
|
-
const result = [];
|
|
1382
|
-
for (const shortcut of shortcuts) {
|
|
1383
|
-
const token = shortcut.trim().toLowerCase();
|
|
1384
|
-
if (!token || seen.has(token)) {
|
|
1385
|
-
continue;
|
|
1386
|
-
}
|
|
1387
|
-
seen.add(token);
|
|
1388
|
-
result.push(shortcut.trim());
|
|
1389
|
-
}
|
|
1390
|
-
return result;
|
|
1391
|
-
}
|
|
1392
|
-
//#endregion
|
|
1393
|
-
|
|
1394
1867
|
class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
1395
1868
|
constructor() {
|
|
1396
1869
|
super(...arguments);
|
|
1397
|
-
this.adapter = input.required(...(ngDevMode ? [{ debugName: "adapter" }] : /* istanbul ignore next */ []));
|
|
1398
1870
|
//
|
|
1399
1871
|
this.vm = inject(AXPLayoutDetailsViewViewModel);
|
|
1400
|
-
this.router = inject(Router);
|
|
1401
1872
|
this.route = inject(ActivatedRoute);
|
|
1402
1873
|
this.eventService = inject(AXPBroadcastEventService);
|
|
1403
1874
|
this.deviceService = inject(AXPDeviceService);
|
|
1404
|
-
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
1405
1875
|
this.unsavedChangesPopstate = inject(AXPUnsavedChangesPopstateService);
|
|
1406
1876
|
this.pageComponentInstanceRegistry = inject(AXPPageComponentInstanceRegistryService);
|
|
1407
1877
|
this.shortcutRegistry = inject(AXPKeyboardShortcutRegistry);
|
|
1878
|
+
this.workflowService = inject(AXPWorkflowService);
|
|
1408
1879
|
this.destroyRef = inject(DestroyRef);
|
|
1409
1880
|
this.elementRef = inject((ElementRef));
|
|
1410
|
-
|
|
1411
|
-
|
|
1881
|
+
this.debug = inject(AXPDebugService);
|
|
1882
|
+
/** Prevents sidebar tab init events from pushing history before the first page activation completes. */
|
|
1883
|
+
this.detailsLayoutReady = signal(false, ...(ngDevMode ? [{ debugName: "detailsLayoutReady" }] : /* istanbul ignore next */ []));
|
|
1412
1884
|
this.destroyed$ = new Subject();
|
|
1413
1885
|
this.footerActionsGeneration = 0;
|
|
1414
1886
|
this.keyboardShortcutRegistrationGeneration = 0;
|
|
1887
|
+
/** Page id the overlay release logic is bound to; reset on sidebar/page switch. */
|
|
1888
|
+
this.overlayTargetPageId = null;
|
|
1889
|
+
/** After a page switch, wait for widget registry to clear before accepting remounted widgets. */
|
|
1890
|
+
this.overlaySawZeroWidgetsAfterPageChange = false;
|
|
1891
|
+
/** Cancels in-flight overlay release when the page changes. */
|
|
1892
|
+
this.overlayReleaseGeneration = 0;
|
|
1415
1893
|
/** Header actions with resolved shortcut chords, keyed by command name. */
|
|
1416
1894
|
this.actionShortcutEntries = signal(new Map(), ...(ngDevMode ? [{ debugName: "actionShortcutEntries" }] : /* istanbul ignore next */ []));
|
|
1417
1895
|
this.form = viewChild('form', ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
@@ -1430,6 +1908,11 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1430
1908
|
return;
|
|
1431
1909
|
}
|
|
1432
1910
|
untracked(() => queueMicrotask(() => {
|
|
1911
|
+
this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'sidebarTabs select (sync indicator)', () => ({
|
|
1912
|
+
currentPageId: currentId,
|
|
1913
|
+
tabIndex: index,
|
|
1914
|
+
routerUrl: this.router.url,
|
|
1915
|
+
}));
|
|
1433
1916
|
this.sidebarTabChangeSuppressed = true;
|
|
1434
1917
|
try {
|
|
1435
1918
|
this.sidebarTabs()?.select(index);
|
|
@@ -1439,6 +1922,114 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1439
1922
|
}
|
|
1440
1923
|
}));
|
|
1441
1924
|
}, ...(ngDevMode ? [{ debugName: "#sidebarTabsIndicatorEffect" }] : /* istanbul ignore next */ []));
|
|
1925
|
+
/** Clears the page overlay reactively once VM + widget hydration are both idle. */
|
|
1926
|
+
this.#overlayReleaseEffect = effect(() => {
|
|
1927
|
+
const showPages = this.vm.showPages();
|
|
1928
|
+
const pageId = this.vm.currentPage()?.id;
|
|
1929
|
+
const isVmBusy = this.vm.isOverlayBusy();
|
|
1930
|
+
const isPageReady = this.vm.isPageReady();
|
|
1931
|
+
const container = this.widgetContainer();
|
|
1932
|
+
this.vm.currentPageContent();
|
|
1933
|
+
this.vm.activeTabContent();
|
|
1934
|
+
this.vm.context();
|
|
1935
|
+
container?.builderService.registeredWidgetsCount();
|
|
1936
|
+
container?.builderService.isHydrating();
|
|
1937
|
+
container?.isBusy();
|
|
1938
|
+
container?.isWidgetsReady();
|
|
1939
|
+
const widgetCount = container?.builderService.registeredWidgetsCount() ?? 0;
|
|
1940
|
+
const widgetsBusy = container?.isBusy() ?? false;
|
|
1941
|
+
const widgetsReady = container?.isWidgetsReady() ?? false;
|
|
1942
|
+
untracked(() => {
|
|
1943
|
+
const widgetSnapshot = container?.builderService.getWidgetStateSnapshot();
|
|
1944
|
+
if (pageId !== this.overlayTargetPageId) {
|
|
1945
|
+
const isInitialOverlayBind = this.overlayTargetPageId == null;
|
|
1946
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'page bind changed', () => ({
|
|
1947
|
+
pageId,
|
|
1948
|
+
previousPageId: this.overlayTargetPageId,
|
|
1949
|
+
isInitialOverlayBind,
|
|
1950
|
+
overlayReleaseGeneration: this.overlayReleaseGeneration + 1,
|
|
1951
|
+
}));
|
|
1952
|
+
this.overlayTargetPageId = pageId ?? null;
|
|
1953
|
+
// First bind: widgets mount without a prior page registry. Sidebar switch: require clear first.
|
|
1954
|
+
this.overlaySawZeroWidgetsAfterPageChange = isInitialOverlayBind;
|
|
1955
|
+
this.overlayReleaseGeneration += 1;
|
|
1956
|
+
this.overlayReleasePromise = undefined;
|
|
1957
|
+
this.clearOverlayFallback();
|
|
1958
|
+
}
|
|
1959
|
+
if (showPages) {
|
|
1960
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'showPages — release overlay', () => ({ isVmBusy }));
|
|
1961
|
+
this.overlayReleaseGeneration += 1;
|
|
1962
|
+
this.overlayReleasePromise = undefined;
|
|
1963
|
+
this.clearOverlayFallback();
|
|
1964
|
+
if (!isVmBusy) {
|
|
1965
|
+
this.clearPageOverlay('showPages — release overlay');
|
|
1966
|
+
}
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
if (isVmBusy || !isPageReady || !pageId) {
|
|
1970
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'waiting on VM', () => ({
|
|
1971
|
+
pageId,
|
|
1972
|
+
isVmBusy,
|
|
1973
|
+
isPageReady,
|
|
1974
|
+
}));
|
|
1975
|
+
this.overlayReleaseGeneration += 1;
|
|
1976
|
+
this.overlayReleasePromise = undefined;
|
|
1977
|
+
this.clearOverlayFallback();
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1980
|
+
if (this.getActivePageComponentKey()) {
|
|
1981
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'component page — release overlay', () => ({
|
|
1982
|
+
componentKey: this.getActivePageComponentKey(),
|
|
1983
|
+
}));
|
|
1984
|
+
this.overlayReleaseGeneration += 1;
|
|
1985
|
+
this.overlayReleasePromise = undefined;
|
|
1986
|
+
this.clearOverlayFallback();
|
|
1987
|
+
this.clearPageOverlay('component page — release overlay');
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
if (!this.pageHasWidgetNodes()) {
|
|
1991
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'no widget nodes — release overlay', () => ({ pageId }));
|
|
1992
|
+
this.overlayReleaseGeneration += 1;
|
|
1993
|
+
this.overlayReleasePromise = undefined;
|
|
1994
|
+
this.clearOverlayFallback();
|
|
1995
|
+
this.clearPageOverlay('no widget nodes — release overlay');
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
if (widgetCount === 0) {
|
|
1999
|
+
this.overlaySawZeroWidgetsAfterPageChange = true;
|
|
2000
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'widget registry cleared (remount gate open)', () => ({ pageId }));
|
|
2001
|
+
}
|
|
2002
|
+
if (!this.overlaySawZeroWidgetsAfterPageChange) {
|
|
2003
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'blocked: remount gate (await widgetCount=0)', () => ({
|
|
2004
|
+
pageId,
|
|
2005
|
+
widgetCount,
|
|
2006
|
+
...widgetSnapshot,
|
|
2007
|
+
}));
|
|
2008
|
+
this.scheduleOverlayFallback();
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
if (!widgetsReady || widgetsBusy) {
|
|
2012
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'blocked: widgets not ready', () => ({
|
|
2013
|
+
pageId,
|
|
2014
|
+
widgetsReady,
|
|
2015
|
+
widgetsBusy,
|
|
2016
|
+
overlaySawZero: this.overlaySawZeroWidgetsAfterPageChange,
|
|
2017
|
+
releaseInFlight: !!this.overlayReleasePromise,
|
|
2018
|
+
...widgetSnapshot,
|
|
2019
|
+
hydratingWidgets: widgetSnapshot?.widgets?.filter((w) => w.isHydrating).map((w) => w.id),
|
|
2020
|
+
renderingWidgets: widgetSnapshot?.widgets?.filter((w) => w.status === 'rendering').map((w) => w.id),
|
|
2021
|
+
}));
|
|
2022
|
+
this.scheduleOverlayFallback();
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'request overlay release', () => ({
|
|
2026
|
+
pageId,
|
|
2027
|
+
overlayReleaseGeneration: this.overlayReleaseGeneration,
|
|
2028
|
+
...widgetSnapshot,
|
|
2029
|
+
}));
|
|
2030
|
+
void this.requestOverlayRelease(pageId);
|
|
2031
|
+
});
|
|
2032
|
+
}, ...(ngDevMode ? [{ debugName: "#overlayReleaseEffect" }] : /* istanbul ignore next */ []));
|
|
1442
2033
|
this.footerPrimaryActions = signal([], ...(ngDevMode ? [{ debugName: "footerPrimaryActions" }] : /* istanbul ignore next */ []));
|
|
1443
2034
|
this.footerSecondaryActions = signal([], ...(ngDevMode ? [{ debugName: "footerSecondaryActions" }] : /* istanbul ignore next */ []));
|
|
1444
2035
|
this.footerActions = computed(() => [...this.footerPrimaryActions(), ...this.footerSecondaryActions()], ...(ngDevMode ? [{ debugName: "footerActions" }] : /* istanbul ignore next */ []));
|
|
@@ -1462,7 +2053,14 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1462
2053
|
if (this.vm.currentPage()?.isReadonly || this.getActivePageComponentKey()) {
|
|
1463
2054
|
return false;
|
|
1464
2055
|
}
|
|
1465
|
-
|
|
2056
|
+
if (this.vm.isOverlayBusy()) {
|
|
2057
|
+
return false;
|
|
2058
|
+
}
|
|
2059
|
+
const container = this.widgetContainer();
|
|
2060
|
+
if (!container?.isSavedCommitted()) {
|
|
2061
|
+
return false;
|
|
2062
|
+
}
|
|
2063
|
+
return container.isFormDirty();
|
|
1466
2064
|
}, ...(ngDevMode ? [{ debugName: "liveFormIsDirty" }] : /* istanbul ignore next */ []));
|
|
1467
2065
|
this.hasVisibleFooterPrimaryActions = computed(() => {
|
|
1468
2066
|
if (this.showSaveDiscardFooter()) {
|
|
@@ -1479,11 +2077,25 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1479
2077
|
if (this.vm.currentPage()?.isReadonly || this.getActivePageComponentKey()) {
|
|
1480
2078
|
return;
|
|
1481
2079
|
}
|
|
1482
|
-
|
|
2080
|
+
if (this.vm.isOverlayBusy()) {
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
const container = this.widgetContainer();
|
|
2084
|
+
if (!container?.isSavedCommitted()) {
|
|
2085
|
+
if (this.vm.formDirty()) {
|
|
2086
|
+
untracked(() => this.vm.setFormDirty(false));
|
|
2087
|
+
}
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
const isDirty = container.isFormDirty();
|
|
1483
2091
|
if (this.vm.formDirty() === isDirty) {
|
|
1484
2092
|
return;
|
|
1485
2093
|
}
|
|
1486
2094
|
untracked(() => {
|
|
2095
|
+
this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'formDirty effect', () => ({
|
|
2096
|
+
isDirty,
|
|
2097
|
+
vmFormDirty: this.vm.formDirty(),
|
|
2098
|
+
}));
|
|
1487
2099
|
this.vm.setFormDirty(isDirty);
|
|
1488
2100
|
this.recompute();
|
|
1489
2101
|
});
|
|
@@ -1499,18 +2111,21 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1499
2111
|
const generation = ++this.footerActionsGeneration;
|
|
1500
2112
|
this.updateTrigger();
|
|
1501
2113
|
this.liveFormIsDirty();
|
|
1502
|
-
this.vm.
|
|
2114
|
+
this.vm.isOverlayBusy();
|
|
1503
2115
|
void this.refreshFooterActions(generation);
|
|
1504
2116
|
}, ...(ngDevMode ? [{ debugName: "#FooterActionsEffect" }] : /* istanbul ignore next */ []));
|
|
1505
2117
|
this.#keyboardShortcutsEffect = effect(() => {
|
|
1506
2118
|
const generation = ++this.keyboardShortcutRegistrationGeneration;
|
|
1507
2119
|
this.updateTrigger();
|
|
1508
2120
|
this.liveFormIsDirty();
|
|
1509
|
-
this.
|
|
2121
|
+
this.isActivePageComponentDirty();
|
|
2122
|
+
this.vm.isOverlayBusy();
|
|
1510
2123
|
this.vm.currentPage()?.id;
|
|
1511
2124
|
untracked(() => void this.refreshKeyboardShortcutRegistrations(generation));
|
|
1512
2125
|
}, ...(ngDevMode ? [{ debugName: "#keyboardShortcutsEffect" }] : /* istanbul ignore next */ []));
|
|
1513
2126
|
}
|
|
2127
|
+
/** Safety cap when widget ready detection does not settle. */
|
|
2128
|
+
static { this.overlayMaxWaitMs = 30_000; }
|
|
1514
2129
|
/** Save/discard use live {@link AXPLayoutDetailsViewViewModel.isDirty}; other actions use evaluated `visible`. */
|
|
1515
2130
|
static isTruthyActionFlag(value) {
|
|
1516
2131
|
if (value === true) {
|
|
@@ -1537,6 +2152,8 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1537
2152
|
}
|
|
1538
2153
|
/** Syncs the line indicator when the active page changes programmatically. */
|
|
1539
2154
|
#sidebarTabsIndicatorEffect;
|
|
2155
|
+
/** Clears the page overlay reactively once VM + widget hydration are both idle. */
|
|
2156
|
+
#overlayReleaseEffect;
|
|
1540
2157
|
isSaveDiscardFooterAction(action) {
|
|
1541
2158
|
const commandName = action.command?.name;
|
|
1542
2159
|
const acceptCommand = this.vm.currentPage()?.settings?.commands?.accept?.command?.name;
|
|
@@ -1555,35 +2172,43 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1555
2172
|
return AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.visible);
|
|
1556
2173
|
}
|
|
1557
2174
|
isFooterActionDisabled(action) {
|
|
1558
|
-
if (this.vm.
|
|
2175
|
+
if (this.vm.isOverlayBusy()) {
|
|
1559
2176
|
return true;
|
|
1560
2177
|
}
|
|
1561
2178
|
return AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.disabled);
|
|
1562
2179
|
}
|
|
1563
2180
|
/**
|
|
1564
|
-
*
|
|
2181
|
+
* Re-fetches the entity adapter and reloads the active page.
|
|
1565
2182
|
*/
|
|
1566
2183
|
async refreshLayout() {
|
|
1567
|
-
const router = this.router;
|
|
1568
|
-
const route = this.route;
|
|
1569
|
-
const now = Date.now();
|
|
1570
2184
|
this.unsavedChangesConfirm.markLeaveConfirmed();
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
2185
|
+
this.detailsLayoutReady.set(false);
|
|
2186
|
+
try {
|
|
2187
|
+
await this.vm.loadFromRoute(true);
|
|
2188
|
+
}
|
|
2189
|
+
finally {
|
|
2190
|
+
this.detailsLayoutReady.set(true);
|
|
2191
|
+
}
|
|
1577
2192
|
}
|
|
1578
2193
|
async ngOnInit() {
|
|
1579
2194
|
await super.ngOnInit();
|
|
2195
|
+
this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'ngOnInit — before loadFromRoute', () => ({
|
|
2196
|
+
routerUrl: this.router.url,
|
|
2197
|
+
pageFromRouterUrl: this.router.parseUrl(this.router.url).queryParams['page'] ?? null,
|
|
2198
|
+
pageFromRouteSnapshot: this.route.snapshot.queryParamMap.get('page'),
|
|
2199
|
+
}));
|
|
1580
2200
|
this.unsavedChangesPopstate.registerSource({
|
|
1581
2201
|
id: 'axp-layout-details-view',
|
|
1582
|
-
isDirty: () => this.
|
|
2202
|
+
isDirty: () => this.hasUnsavedChanges(),
|
|
1583
2203
|
});
|
|
2204
|
+
this.destroyRef.onDestroy(() => this.unsavedChangesPopstate.unregisterSource('axp-layout-details-view'));
|
|
1584
2205
|
//
|
|
1585
|
-
await this.vm.
|
|
1586
|
-
this.
|
|
2206
|
+
await this.vm.loadFromRoute();
|
|
2207
|
+
this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'ngOnInit — after loadFromRoute', () => ({
|
|
2208
|
+
routerUrl: this.router.url,
|
|
2209
|
+
currentPageId: this.vm.currentPage()?.id ?? null,
|
|
2210
|
+
}));
|
|
2211
|
+
this.detailsLayoutReady.set(true);
|
|
1587
2212
|
void this.refreshKeyboardShortcutRegistrations(++this.keyboardShortcutRegistrationGeneration);
|
|
1588
2213
|
this.eventService
|
|
1589
2214
|
//TODO: Use the constant from the entity module
|
|
@@ -1594,6 +2219,37 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1594
2219
|
this.refreshLayout();
|
|
1595
2220
|
}
|
|
1596
2221
|
});
|
|
2222
|
+
this.workflowService.events$
|
|
2223
|
+
.pipe(filter$1((event) => event.type === AXP_ENTITY_DELETED_WORKFLOW_EVENT_TYPE), takeUntil(this.destroyed$))
|
|
2224
|
+
.subscribe((event) => {
|
|
2225
|
+
void this.handleEntityDeleted(event.payload);
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
/** Navigates to {@link AXPLayoutDetailsViewAdapter.exitUrl} when the open record was deleted. */
|
|
2229
|
+
async handleEntityDeleted(payload) {
|
|
2230
|
+
if (!payload?.entity || !payload.ids?.length) {
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2233
|
+
const adapterName = this.vm.adapter()?.name;
|
|
2234
|
+
const recordId = this.vm.context()?.['id'];
|
|
2235
|
+
if (!adapterName || recordId == null) {
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2238
|
+
const deletedIds = payload.ids.map((id) => String(id));
|
|
2239
|
+
if (payload.entity !== adapterName || !deletedIds.includes(String(recordId))) {
|
|
2240
|
+
return;
|
|
2241
|
+
}
|
|
2242
|
+
this.unsavedChangesConfirm.markLeaveConfirmed();
|
|
2243
|
+
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
2244
|
+
const tabKey = this.getPageTabKey();
|
|
2245
|
+
await this.vm.goToListPage();
|
|
2246
|
+
if (tabKey) {
|
|
2247
|
+
this.unsavedChangesConfirm.markLeaveConfirmed();
|
|
2248
|
+
await this.tabNavigation.closeTab(tabKey);
|
|
2249
|
+
}
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
await this.vm.goToListPage();
|
|
1597
2253
|
}
|
|
1598
2254
|
async ngAfterViewInit() {
|
|
1599
2255
|
const listWidget = (await this.widgetContainer()?.find('page-list_table'));
|
|
@@ -1608,9 +2264,12 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1608
2264
|
}
|
|
1609
2265
|
}
|
|
1610
2266
|
ngOnDestroy() {
|
|
1611
|
-
this.unsavedChangesPopstate.unregisterSource('axp-layout-details-view');
|
|
1612
2267
|
this.onSelectionChangeSubscription?.unsubscribe();
|
|
1613
2268
|
++this.keyboardShortcutRegistrationGeneration;
|
|
2269
|
+
this.clearOverlayFallback();
|
|
2270
|
+
this.overlayReleaseGeneration += 1;
|
|
2271
|
+
this.overlayReleasePromise = undefined;
|
|
2272
|
+
this.clearPageOverlay('ngOnDestroy');
|
|
1614
2273
|
this.destroyed$.next();
|
|
1615
2274
|
this.destroyed$.complete();
|
|
1616
2275
|
}
|
|
@@ -1631,44 +2290,199 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1631
2290
|
this.footerSecondaryActions.set(footerSecondaryActions);
|
|
1632
2291
|
}
|
|
1633
2292
|
handleOnContextChanged(e) {
|
|
1634
|
-
this.vm.
|
|
2293
|
+
if (!this.vm.currentPage()?.isReadonly &&
|
|
2294
|
+
!this.getActivePageComponentKey() &&
|
|
2295
|
+
this.widgetContainer()?.isSavedCommitted()) {
|
|
2296
|
+
const isDirty = e.isFormDirty ?? false;
|
|
2297
|
+
const container = this.widgetContainer();
|
|
2298
|
+
this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'handleOnContextChanged', () => ({
|
|
2299
|
+
isFormDirty: isDirty,
|
|
2300
|
+
vmFormDirty: this.vm.formDirty(),
|
|
2301
|
+
changePath: e.path,
|
|
2302
|
+
changeOrigin: e.origin,
|
|
2303
|
+
userEditedSinceCommit: container?.contextService.hasUserEditedSinceCommit(),
|
|
2304
|
+
dirtyPaths: container
|
|
2305
|
+
? summarizeFormContextDirtyDiff(container.contextService.data(), container.contextService.saved())
|
|
2306
|
+
: [],
|
|
2307
|
+
}));
|
|
2308
|
+
if (this.vm.formDirty() !== isDirty) {
|
|
2309
|
+
this.vm.setFormDirty(isDirty);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
1635
2312
|
this.recompute();
|
|
1636
2313
|
}
|
|
1637
2314
|
getLiveFormContext() {
|
|
1638
2315
|
const container = this.widgetContainer();
|
|
1639
2316
|
return (container?.contextService.data() ?? this.vm.context());
|
|
1640
2317
|
}
|
|
2318
|
+
/** Whether the active page renders widget nodes (not only hosted components). */
|
|
2319
|
+
pageHasWidgetNodes() {
|
|
2320
|
+
const pageWidgets = this.vm.currentPageContent();
|
|
2321
|
+
if (pageWidgets.some((item) => !('type' in item && item.type === 'component'))) {
|
|
2322
|
+
return true;
|
|
2323
|
+
}
|
|
2324
|
+
return this.vm.activeTabContent().length > 0;
|
|
2325
|
+
}
|
|
2326
|
+
/** Clears all overlay loading tasks once the page (or hosted view) is ready. */
|
|
2327
|
+
clearPageOverlay(reason) {
|
|
2328
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', reason, () => ({
|
|
2329
|
+
taskCount: this.layoutService.overlayTaskCount(),
|
|
2330
|
+
}));
|
|
2331
|
+
this.layoutService.clearOverlayLoading();
|
|
2332
|
+
}
|
|
2333
|
+
scheduleOverlayFallback() {
|
|
2334
|
+
if (this.overlayFallbackTimer) {
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'schedule fallback timer', () => ({
|
|
2338
|
+
timeoutMs: AXPLayoutDetailsViewComponent.overlayMaxWaitMs,
|
|
2339
|
+
pageId: this.overlayTargetPageId,
|
|
2340
|
+
}));
|
|
2341
|
+
this.overlayFallbackTimer = setTimeout(() => {
|
|
2342
|
+
this.overlayFallbackTimer = undefined;
|
|
2343
|
+
const isOverlayLoading = this.layoutService.isOverlayLoading();
|
|
2344
|
+
const isVmBusy = this.vm.isOverlayBusy();
|
|
2345
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'fallback timer fired', () => ({
|
|
2346
|
+
isOverlayLoading,
|
|
2347
|
+
isVmBusy,
|
|
2348
|
+
pageId: this.overlayTargetPageId,
|
|
2349
|
+
}));
|
|
2350
|
+
if (!isOverlayLoading) {
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
if (!isVmBusy) {
|
|
2354
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'fallback forcing overlay off', () => ({
|
|
2355
|
+
taskCount: this.layoutService.overlayTaskCount(),
|
|
2356
|
+
}));
|
|
2357
|
+
this.clearPageOverlay('fallback forcing overlay off');
|
|
2358
|
+
}
|
|
2359
|
+
}, AXPLayoutDetailsViewComponent.overlayMaxWaitMs);
|
|
2360
|
+
}
|
|
2361
|
+
clearOverlayFallback() {
|
|
2362
|
+
if (this.overlayFallbackTimer) {
|
|
2363
|
+
clearTimeout(this.overlayFallbackTimer);
|
|
2364
|
+
this.overlayFallbackTimer = undefined;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
/**
|
|
2368
|
+
* Hides overlay after the widget container reports continuous idle (same gate as saved baseline).
|
|
2369
|
+
*/
|
|
2370
|
+
requestOverlayRelease(pageId) {
|
|
2371
|
+
if (this.overlayReleasePromise) {
|
|
2372
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release skipped — already in flight', () => ({ pageId }));
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2375
|
+
const generation = this.overlayReleaseGeneration;
|
|
2376
|
+
const container = this.widgetContainer();
|
|
2377
|
+
if (!container) {
|
|
2378
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release skipped — no container', () => ({ pageId }));
|
|
2379
|
+
this.scheduleOverlayFallback();
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'waitUntilSettled started', () => ({ pageId, generation }));
|
|
2383
|
+
this.overlayReleasePromise = container
|
|
2384
|
+
.waitUntilSettled()
|
|
2385
|
+
.then(() => {
|
|
2386
|
+
const latest = this.widgetContainer();
|
|
2387
|
+
const snapshot = latest?.builderService.getWidgetStateSnapshot();
|
|
2388
|
+
if (generation !== this.overlayReleaseGeneration) {
|
|
2389
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — generation mismatch', () => ({
|
|
2390
|
+
pageId,
|
|
2391
|
+
generation,
|
|
2392
|
+
currentGeneration: this.overlayReleaseGeneration,
|
|
2393
|
+
}));
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
if (pageId !== this.overlayTargetPageId || pageId !== this.vm.currentPage()?.id) {
|
|
2397
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — page changed', () => ({
|
|
2398
|
+
pageId,
|
|
2399
|
+
overlayTargetPageId: this.overlayTargetPageId,
|
|
2400
|
+
currentPageId: this.vm.currentPage()?.id,
|
|
2401
|
+
}));
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
if (this.vm.isOverlayBusy()) {
|
|
2405
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — VM still busy', () => ({ pageId }));
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
if (!latest?.isWidgetsReady() || latest.isBusy()) {
|
|
2409
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release aborted — widgets not ready after settle', () => ({
|
|
2410
|
+
pageId,
|
|
2411
|
+
widgetsReady: latest?.isWidgetsReady(),
|
|
2412
|
+
widgetsBusy: latest?.isBusy(),
|
|
2413
|
+
...snapshot,
|
|
2414
|
+
}));
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
2417
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'release overlay OFF', () => ({
|
|
2418
|
+
pageId,
|
|
2419
|
+
generation,
|
|
2420
|
+
taskCount: this.layoutService.overlayTaskCount(),
|
|
2421
|
+
...snapshot,
|
|
2422
|
+
}));
|
|
2423
|
+
this.clearOverlayFallback();
|
|
2424
|
+
this.clearPageOverlay('widgets settled — release overlay');
|
|
2425
|
+
})
|
|
2426
|
+
.finally(() => {
|
|
2427
|
+
this.overlayReleasePromise = undefined;
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
1641
2430
|
async finalizeSave() {
|
|
1642
2431
|
const container = this.widgetContainer();
|
|
1643
2432
|
if (!container) {
|
|
1644
2433
|
this.vm.setFormDirty(false);
|
|
1645
2434
|
return;
|
|
1646
2435
|
}
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
2436
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'finalizeSave overlay ON');
|
|
2437
|
+
this.layoutService.setOverlayLoading(true);
|
|
2438
|
+
try {
|
|
2439
|
+
const savedContext = this.vm.context();
|
|
2440
|
+
await container.replaceContext(savedContext);
|
|
2441
|
+
this.vm.applySavedState(container.contextService.data());
|
|
2442
|
+
if (!this.getActivePageComponentKey()) {
|
|
2443
|
+
await container.settleSavedBaseline();
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
finally {
|
|
2447
|
+
this.debug.trace(OVERLAY_DETAILS_VIEW_TRACE_NS, 'details-view', 'finalizeSave overlay OFF');
|
|
2448
|
+
this.layoutService.setOverlayLoading(false);
|
|
2449
|
+
}
|
|
1650
2450
|
}
|
|
1651
2451
|
finalizeDiscard() {
|
|
2452
|
+
this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'finalizeDiscard');
|
|
1652
2453
|
const container = this.widgetContainer();
|
|
1653
|
-
if (
|
|
2454
|
+
if (container) {
|
|
2455
|
+
container.revertAndSettle();
|
|
2456
|
+
const saved = container.contextService.saved();
|
|
2457
|
+
this.vm.applySavedState(saved);
|
|
1654
2458
|
return;
|
|
1655
2459
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
2460
|
+
void this.vm.discard();
|
|
2461
|
+
}
|
|
2462
|
+
/** Reverts widget form state and view-model context to the last saved baseline. */
|
|
2463
|
+
async discardUnsavedChanges() {
|
|
2464
|
+
this.finalizeDiscard();
|
|
2465
|
+
this.recompute();
|
|
1658
2466
|
}
|
|
1659
2467
|
/**
|
|
1660
2468
|
* `ax-tabs` selects on click before we can confirm. Revert synchronously, then confirm + switch.
|
|
1661
2469
|
*/
|
|
1662
2470
|
handleSidebarTabChanged(event) {
|
|
1663
|
-
if (!this.detailsLayoutReady || this.sidebarTabChangeSuppressed) {
|
|
2471
|
+
if (!this.detailsLayoutReady() || this.sidebarTabChangeSuppressed) {
|
|
1664
2472
|
return;
|
|
1665
2473
|
}
|
|
1666
2474
|
const pages = this.vm.adapter()?.pages ?? [];
|
|
1667
2475
|
const target = pages[event.index];
|
|
1668
2476
|
const currentId = this.vm.currentPage()?.id;
|
|
1669
|
-
if (!target || target.id === currentId) {
|
|
2477
|
+
if (!currentId || !target || target.id === currentId) {
|
|
1670
2478
|
return;
|
|
1671
2479
|
}
|
|
2480
|
+
this.debug.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'details-view', 'handleSidebarTabChanged', () => ({
|
|
2481
|
+
routerUrl: this.router.url,
|
|
2482
|
+
targetPageId: target.id,
|
|
2483
|
+
currentPageId: currentId ?? null,
|
|
2484
|
+
tabIndex: event.index,
|
|
2485
|
+
}));
|
|
1672
2486
|
const activeIndex = pages.findIndex((page) => page.id === currentId);
|
|
1673
2487
|
if (activeIndex >= 0) {
|
|
1674
2488
|
this.sidebarTabChangeSuppressed = true;
|
|
@@ -1750,6 +2564,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1750
2564
|
async getBackButton() {
|
|
1751
2565
|
return this.vm.getBackButton();
|
|
1752
2566
|
}
|
|
2567
|
+
hasUnsavedChanges() {
|
|
2568
|
+
return this.shouldPromptLeave();
|
|
2569
|
+
}
|
|
1753
2570
|
async getPageBadge() {
|
|
1754
2571
|
if (this.vm.currentPage()?.isReadonly) {
|
|
1755
2572
|
return null;
|
|
@@ -1794,6 +2611,15 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1794
2611
|
}
|
|
1795
2612
|
return this.confirmLeaveIfDirty();
|
|
1796
2613
|
}
|
|
2614
|
+
/** Background tab close — confirm without discarding (the cached instance is destroyed). */
|
|
2615
|
+
onBeforeTabClose() {
|
|
2616
|
+
if (this.unsavedChangesConfirm.hasLeaveConfirmed()) {
|
|
2617
|
+
return Promise.resolve(true);
|
|
2618
|
+
}
|
|
2619
|
+
return this.unsavedChangesConfirm.confirmIfDirty(this.shouldPromptLeave(), {
|
|
2620
|
+
approveLeaveOnConfirm: false,
|
|
2621
|
+
});
|
|
2622
|
+
}
|
|
1797
2623
|
/** Active entity component page instance, when the current details sub-page is component-based. */
|
|
1798
2624
|
getActivePageComponentInstance() {
|
|
1799
2625
|
const componentKey = this.getActivePageComponentKey();
|
|
@@ -1818,10 +2644,33 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1818
2644
|
static isComponentPageContent(item) {
|
|
1819
2645
|
return 'type' in item && item.type === 'component';
|
|
1820
2646
|
}
|
|
2647
|
+
pageContentTrackKey(item, index) {
|
|
2648
|
+
if (AXPLayoutDetailsViewComponent.isComponentPageContent(item)) {
|
|
2649
|
+
return `component:${item.componentKey}`;
|
|
2650
|
+
}
|
|
2651
|
+
return item.name ?? `widget:${index}`;
|
|
2652
|
+
}
|
|
1821
2653
|
/** Whether the active component-based entity page has unsaved edits. */
|
|
1822
2654
|
isActivePageComponentDirty() {
|
|
1823
2655
|
return this.getActivePageComponentInstance()?.hasUnsavedChanges() ?? false;
|
|
1824
2656
|
}
|
|
2657
|
+
/**
|
|
2658
|
+
* Widget-form dirty state for leave guards (popstate, canDeactivate).
|
|
2659
|
+
* Unlike {@link liveFormIsDirty}, does not suppress dirty while overlay is busy.
|
|
2660
|
+
*/
|
|
2661
|
+
hasWidgetFormUnsavedChanges() {
|
|
2662
|
+
if (this.getActivePageComponentKey()) {
|
|
2663
|
+
return false;
|
|
2664
|
+
}
|
|
2665
|
+
const container = this.widgetContainer();
|
|
2666
|
+
if (!container) {
|
|
2667
|
+
return this.vm.formDirty();
|
|
2668
|
+
}
|
|
2669
|
+
if (container.isSavedCommitted()) {
|
|
2670
|
+
return container.isFormDirty();
|
|
2671
|
+
}
|
|
2672
|
+
return container.contextService.hasUserEditedSinceCommit() || this.vm.formDirty();
|
|
2673
|
+
}
|
|
1825
2674
|
/** Whether the current details page has user-origin unsaved edits (form or component page). */
|
|
1826
2675
|
shouldPromptLeave() {
|
|
1827
2676
|
if (this.vm.currentPage()?.isReadonly) {
|
|
@@ -1830,11 +2679,16 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1830
2679
|
if (this.isActivePageComponentDirty()) {
|
|
1831
2680
|
return true;
|
|
1832
2681
|
}
|
|
1833
|
-
return this.
|
|
2682
|
+
return this.hasWidgetFormUnsavedChanges();
|
|
1834
2683
|
}
|
|
1835
2684
|
/** Single gate for leaving the page or switching details sub-pages when dirty. */
|
|
1836
|
-
confirmLeaveIfDirty() {
|
|
1837
|
-
|
|
2685
|
+
async confirmLeaveIfDirty() {
|
|
2686
|
+
const shouldPrompt = this.shouldPromptLeave();
|
|
2687
|
+
const confirmed = await this.unsavedChangesConfirm.confirmIfDirty(shouldPrompt);
|
|
2688
|
+
if (confirmed && shouldPrompt) {
|
|
2689
|
+
await this.discardUnsavedChanges();
|
|
2690
|
+
}
|
|
2691
|
+
return confirmed;
|
|
1838
2692
|
}
|
|
1839
2693
|
//#endregion
|
|
1840
2694
|
//#region ---- Command Execution ----
|
|
@@ -1853,9 +2707,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1853
2707
|
return;
|
|
1854
2708
|
}
|
|
1855
2709
|
if (command.name == rejectCommand) {
|
|
1856
|
-
await this.
|
|
1857
|
-
this.finalizeDiscard();
|
|
1858
|
-
this.recompute();
|
|
2710
|
+
await this.discardUnsavedChanges();
|
|
1859
2711
|
return;
|
|
1860
2712
|
}
|
|
1861
2713
|
// Handle status update command
|
|
@@ -1918,9 +2770,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1918
2770
|
return;
|
|
1919
2771
|
}
|
|
1920
2772
|
if (isDiscardCommand(command.name, rejectCommand)) {
|
|
1921
|
-
await this.
|
|
1922
|
-
this.finalizeDiscard();
|
|
1923
|
-
this.recompute();
|
|
2773
|
+
await this.discardUnsavedChanges();
|
|
1924
2774
|
return;
|
|
1925
2775
|
}
|
|
1926
2776
|
if (!this.isActivePageComponentDirty()) {
|
|
@@ -1954,17 +2804,59 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1954
2804
|
this.registerCoreKeyboardShortcuts();
|
|
1955
2805
|
this.registerActionKeyboardShortcuts(entries);
|
|
1956
2806
|
}
|
|
2807
|
+
/** i18n scope label for the active details sub-page shortcut group in the help dialog. */
|
|
2808
|
+
getKeyboardShortcutScope() {
|
|
2809
|
+
const page = this.vm.currentPage();
|
|
2810
|
+
if (page?.isPrimary) {
|
|
2811
|
+
return '@general:keyboard-shortcuts.groups.entity-details';
|
|
2812
|
+
}
|
|
2813
|
+
const label = page?.label;
|
|
2814
|
+
if (typeof label === 'string' && label.length > 0) {
|
|
2815
|
+
return label;
|
|
2816
|
+
}
|
|
2817
|
+
return page?.id ?? '@general:keyboard-shortcuts.groups.entity-details';
|
|
2818
|
+
}
|
|
2819
|
+
/** Primary overview page backed by the entity widget form (not a component-hosted sub-page). */
|
|
2820
|
+
isWidgetFormPrimaryPage() {
|
|
2821
|
+
return !!this.vm.currentPage()?.isPrimary && !this.getActivePageComponentKey();
|
|
2822
|
+
}
|
|
2823
|
+
registerDetailsViewShortcutScope(id, shortcuts) {
|
|
2824
|
+
const scope = this.getKeyboardShortcutScope();
|
|
2825
|
+
this.shortcutRegistry.register({
|
|
2826
|
+
owner: this.destroyRef,
|
|
2827
|
+
elementRef: this.elementRef,
|
|
2828
|
+
id,
|
|
2829
|
+
priority: AXPKeyboardShortcutPriority.Page,
|
|
2830
|
+
scope,
|
|
2831
|
+
shortcuts,
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
1957
2834
|
async collectActionShortcutEntries() {
|
|
1958
2835
|
const map = new Map();
|
|
1959
2836
|
if (this.vm.showPages()) {
|
|
1960
2837
|
return map;
|
|
1961
2838
|
}
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
this.
|
|
2839
|
+
const includeAdapterActions = this.isWidgetFormPrimaryPage();
|
|
2840
|
+
const [adapterPrimaryActions, adapterSecondaryActions, pagePrimaryActions, pageSecondaryActions] = await Promise.all([
|
|
2841
|
+
includeAdapterActions ? this.vm.primaryActions() : Promise.resolve([]),
|
|
2842
|
+
includeAdapterActions ? this.vm.secondaryActions() : Promise.resolve([]),
|
|
2843
|
+
this.vm.currentPagePrimaryActions(),
|
|
2844
|
+
this.vm.currentPageSecondaryActions(),
|
|
1965
2845
|
]);
|
|
1966
|
-
for (const action of [
|
|
1967
|
-
|
|
2846
|
+
for (const action of [
|
|
2847
|
+
...adapterPrimaryActions,
|
|
2848
|
+
...adapterSecondaryActions,
|
|
2849
|
+
...pagePrimaryActions,
|
|
2850
|
+
...pageSecondaryActions,
|
|
2851
|
+
]) {
|
|
2852
|
+
const zone = action.zone ?? 'header';
|
|
2853
|
+
if (zone !== 'header' && zone !== 'footer') {
|
|
2854
|
+
continue;
|
|
2855
|
+
}
|
|
2856
|
+
if (zone === 'footer' && this.isWidgetFormPrimaryPage() && this.isSaveDiscardFooterAction(action)) {
|
|
2857
|
+
continue;
|
|
2858
|
+
}
|
|
2859
|
+
if (zone === 'header' && this.isSaveDiscardFooterAction(action)) {
|
|
1968
2860
|
continue;
|
|
1969
2861
|
}
|
|
1970
2862
|
const commandName = action.command?.name;
|
|
@@ -1973,7 +2865,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1973
2865
|
continue;
|
|
1974
2866
|
}
|
|
1975
2867
|
const commandBaseName = getDetailsViewActionCommandBaseName(commandName);
|
|
1976
|
-
const chords =
|
|
2868
|
+
const chords = zone === 'footer'
|
|
2869
|
+
? resolvePageFooterActionShortcuts(commandBaseName, action.shortcuts)
|
|
2870
|
+
: resolveDetailsViewActionShortcuts(commandBaseName, action.shortcuts);
|
|
1977
2871
|
if (!chords?.length) {
|
|
1978
2872
|
continue;
|
|
1979
2873
|
}
|
|
@@ -1981,13 +2875,13 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1981
2875
|
command,
|
|
1982
2876
|
title: typeof action.title === 'string' ? action.title : '',
|
|
1983
2877
|
chords,
|
|
1984
|
-
visible: this.
|
|
2878
|
+
visible: this.isShortcutActionAvailable(action),
|
|
1985
2879
|
disabled: AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.disabled),
|
|
1986
2880
|
});
|
|
1987
2881
|
}
|
|
1988
2882
|
return map;
|
|
1989
2883
|
}
|
|
1990
|
-
|
|
2884
|
+
isShortcutActionAvailable(action) {
|
|
1991
2885
|
if (AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.hidden)) {
|
|
1992
2886
|
return false;
|
|
1993
2887
|
}
|
|
@@ -1996,15 +2890,15 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1996
2890
|
}
|
|
1997
2891
|
return true;
|
|
1998
2892
|
}
|
|
1999
|
-
/** Whether save/discard core shortcuts are listed in the help dialog (page
|
|
2893
|
+
/** Whether save/discard core shortcuts are listed in the help dialog (widget overview page only). */
|
|
2000
2894
|
isCoreSaveShortcutAvailable() {
|
|
2001
|
-
return !this.vm.currentPage()?.isReadonly && !!this.acceptFooterCommand();
|
|
2895
|
+
return this.isWidgetFormPrimaryPage() && !this.vm.currentPage()?.isReadonly && !!this.acceptFooterCommand();
|
|
2002
2896
|
}
|
|
2003
2897
|
isCoreDiscardShortcutAvailable() {
|
|
2004
|
-
return !this.vm.currentPage()?.isReadonly && !!this.rejectFooterCommand();
|
|
2898
|
+
return this.isWidgetFormPrimaryPage() && !this.vm.currentPage()?.isReadonly && !!this.rejectFooterCommand();
|
|
2005
2899
|
}
|
|
2006
2900
|
canExecuteSaveShortcut() {
|
|
2007
|
-
if (this.vm.currentPage()?.isReadonly || this.vm.
|
|
2901
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2008
2902
|
return false;
|
|
2009
2903
|
}
|
|
2010
2904
|
if (!this.acceptFooterCommand()) {
|
|
@@ -2013,7 +2907,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2013
2907
|
return this.shouldPromptLeave();
|
|
2014
2908
|
}
|
|
2015
2909
|
canExecuteDiscardShortcut() {
|
|
2016
|
-
if (this.vm.currentPage()?.isReadonly || this.vm.
|
|
2910
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2017
2911
|
return false;
|
|
2018
2912
|
}
|
|
2019
2913
|
if (this.unsavedChangesConfirm.isConfirmPending()) {
|
|
@@ -2038,8 +2932,31 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2038
2932
|
}
|
|
2039
2933
|
await this.execute({ name: rejectCommandName });
|
|
2040
2934
|
}
|
|
2935
|
+
async executeActionShortcut(entry) {
|
|
2936
|
+
const commandName = entry.command.name;
|
|
2937
|
+
if (isDiscardFooterCommand(commandName)) {
|
|
2938
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2939
|
+
return;
|
|
2940
|
+
}
|
|
2941
|
+
if (this.unsavedChangesConfirm.isConfirmPending()) {
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
if (!this.shouldPromptLeave()) {
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
const confirmed = await this.unsavedChangesConfirm.confirmIfDirty(true, {
|
|
2948
|
+
title: '@general:messages.unsaved-changes.title',
|
|
2949
|
+
message: '@general:messages.discard-changes.message',
|
|
2950
|
+
approveLeaveOnConfirm: false,
|
|
2951
|
+
});
|
|
2952
|
+
if (!confirmed) {
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
await this.execute(entry.command);
|
|
2957
|
+
}
|
|
2041
2958
|
isActionShortcutActive(entryId) {
|
|
2042
|
-
if (this.vm.currentPage()?.isReadonly || this.vm.
|
|
2959
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2043
2960
|
return false;
|
|
2044
2961
|
}
|
|
2045
2962
|
const entry = this.actionShortcutEntries().get(entryId);
|
|
@@ -2049,18 +2966,23 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2049
2966
|
return entry.visible && !entry.disabled;
|
|
2050
2967
|
}
|
|
2051
2968
|
registerCoreKeyboardShortcuts() {
|
|
2969
|
+
if (!this.isWidgetFormPrimaryPage()) {
|
|
2970
|
+
this.registerDetailsViewShortcutScope('layout-details-view-core', []);
|
|
2971
|
+
return;
|
|
2972
|
+
}
|
|
2052
2973
|
const accept = this.vm.currentPage()?.settings?.commands?.accept;
|
|
2053
2974
|
const reject = this.vm.currentPage()?.settings?.commands?.reject;
|
|
2054
2975
|
const acceptCommandName = accept?.command.name ?? 'update-entity';
|
|
2055
2976
|
const rejectCommandName = reject?.command.name ?? 'discard';
|
|
2056
2977
|
const saveKeys = resolveDetailsViewFooterCommandShortcuts(acceptCommandName, accept?.shortcuts);
|
|
2057
2978
|
const discardKeys = resolveDetailsViewFooterCommandShortcuts(rejectCommandName, reject?.shortcuts);
|
|
2979
|
+
const scope = this.getKeyboardShortcutScope();
|
|
2058
2980
|
const shortcuts = [];
|
|
2059
2981
|
if (saveKeys?.length && this.isCoreSaveShortcutAvailable()) {
|
|
2060
2982
|
shortcuts.push({
|
|
2061
2983
|
keys: saveKeys,
|
|
2062
2984
|
title: accept?.title ?? '@general:actions.save.title',
|
|
2063
|
-
group:
|
|
2985
|
+
group: scope,
|
|
2064
2986
|
allowInEditableFields: true,
|
|
2065
2987
|
when: () => this.canExecuteSaveShortcut(),
|
|
2066
2988
|
handler: () => {
|
|
@@ -2072,7 +2994,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2072
2994
|
shortcuts.push({
|
|
2073
2995
|
keys: discardKeys,
|
|
2074
2996
|
title: reject?.title ?? '@general:actions.discard.title',
|
|
2075
|
-
group:
|
|
2997
|
+
group: scope,
|
|
2076
2998
|
allowInEditableFields: true,
|
|
2077
2999
|
when: () => this.canExecuteDiscardShortcut(),
|
|
2078
3000
|
handler: () => {
|
|
@@ -2080,62 +3002,44 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2080
3002
|
},
|
|
2081
3003
|
});
|
|
2082
3004
|
}
|
|
2083
|
-
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
this.shortcutRegistry.register({
|
|
2087
|
-
owner: this.destroyRef,
|
|
2088
|
-
elementRef: this.elementRef,
|
|
2089
|
-
id: 'layout-details-view-core',
|
|
2090
|
-
priority: AXPKeyboardShortcutPriority.Page,
|
|
2091
|
-
scope: '@general:keyboard-shortcuts.groups.entity-details',
|
|
2092
|
-
shortcuts,
|
|
2093
|
-
});
|
|
3005
|
+
this.registerDetailsViewShortcutScope('layout-details-view-core', shortcuts);
|
|
2094
3006
|
}
|
|
2095
3007
|
registerActionKeyboardShortcuts(entries) {
|
|
3008
|
+
const scope = this.getKeyboardShortcutScope();
|
|
2096
3009
|
const shortcuts = [];
|
|
2097
3010
|
for (const [entryId, entry] of entries) {
|
|
2098
3011
|
for (const chord of entry.chords) {
|
|
2099
3012
|
shortcuts.push({
|
|
2100
3013
|
keys: [chord],
|
|
2101
3014
|
title: entry.title,
|
|
2102
|
-
group:
|
|
3015
|
+
group: scope,
|
|
3016
|
+
allowInEditableFields: entry.command.name ? isSaveFooterCommand(entry.command.name) || isDiscardFooterCommand(entry.command.name) : false,
|
|
2103
3017
|
when: () => this.isActionShortcutActive(entryId),
|
|
2104
3018
|
handler: () => {
|
|
2105
3019
|
if (!this.isActionShortcutActive(entryId)) {
|
|
2106
3020
|
return;
|
|
2107
3021
|
}
|
|
2108
|
-
void this.
|
|
3022
|
+
void this.executeActionShortcut(entry);
|
|
2109
3023
|
},
|
|
2110
3024
|
});
|
|
2111
3025
|
}
|
|
2112
3026
|
}
|
|
2113
|
-
|
|
2114
|
-
return;
|
|
2115
|
-
}
|
|
2116
|
-
this.shortcutRegistry.register({
|
|
2117
|
-
owner: this.destroyRef,
|
|
2118
|
-
elementRef: this.elementRef,
|
|
2119
|
-
id: 'layout-details-view-actions',
|
|
2120
|
-
priority: AXPKeyboardShortcutPriority.Page,
|
|
2121
|
-
scope: '@general:keyboard-shortcuts.groups.entity-details',
|
|
2122
|
-
shortcuts,
|
|
2123
|
-
});
|
|
3027
|
+
this.registerDetailsViewShortcutScope('layout-details-view-actions', shortcuts);
|
|
2124
3028
|
}
|
|
2125
3029
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutDetailsViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
2126
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLayoutDetailsViewComponent, isStandalone: true, selector: "axp-layout-details-view",
|
|
3030
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPLayoutDetailsViewComponent, isStandalone: true, selector: "axp-layout-details-view", providers: [
|
|
2127
3031
|
{
|
|
2128
3032
|
provide: AXPPageLayoutBase,
|
|
2129
3033
|
useExisting: AXPLayoutDetailsViewComponent,
|
|
2130
3034
|
},
|
|
2131
3035
|
AXPLayoutDetailsViewViewModel,
|
|
2132
|
-
], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "sidebarTabs", first: true, predicate: ["sidebarTabs"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n (formatService.format(vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''), 'string', vm.rootContext())\n | translate\n | async)\n }}</axp-layout-title>\n <axp-layout-description>{{\n (formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async)\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs\n #sidebarTabs\n class=\"axp-vertical-tabs\"\n [look]=\"'with-line-color'\"\n [location]=\"'end'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\"\n >\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item\n [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n @if (vm.isBusy()) {\n <div class=\"ax-flex ax-h-full ax-w-full ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container\n #widgetsContainerRef\n [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\"\n >\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track $index) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div\n axp-page-component-renderer\n [componentKey]=\"$any(item).componentKey\"\n [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\"\n [options]=\"$any(item).options\"\n (componentReady)=\"recompute()\"\n ></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item\n (onClick)=\"vm.setCurrentTab(tab)\"\n [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\"\n [color]=\"'default'\"\n >\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item\n [text]=\"(t(action.title) | async)!\"\n [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(reject.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"reject.color\"\n (onClick)=\"execute(reject.command)\"\n >\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(accept.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"accept.color\"\n (onClick)=\"execute(accept.command)\"\n >\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item\n [text]=\"(t(sub.title) | async)!\"\n [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\"\n (onClick)=\"execute(sub.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>\n", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"], dependencies: [{ kind: "ngmodule", type:
|
|
3036
|
+
], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "sidebarTabs", first: true, predicate: ["sidebarTabs"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n formatService.format(\n vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''),\n 'string',\n vm.rootContext()\n )\n | translate\n | async\n }}</axp-layout-title>\n <axp-layout-description>{{\n formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs #sidebarTabs class=\"axp-vertical-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\">\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container #widgetsContainerRef [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\">\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track pageContentTrackKey($any(item), $index)) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div axp-page-component-renderer [componentKey]=\"$any(item).componentKey\" [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\" [options]=\"$any(item).options\" (componentReady)=\"recompute()\"></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item (onClick)=\"vm.setCurrentTab(tab)\" [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item [text]=\"(t(action.title) | async)!\" [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\" (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(reject.title) | async)!\" [look]=\"'solid'\" [color]=\"reject.color\" (onClick)=\"execute(reject.command)\">\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(accept.title) | async)!\" [look]=\"'solid'\" [color]=\"accept.color\" (onClick)=\"execute(accept.command)\">\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\" [look]=\"'solid'\" [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\" (onClick)=\"execute(sub.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"], dependencies: [{ kind: "ngmodule", type:
|
|
2133
3037
|
// Angular
|
|
2134
3038
|
CommonModule }, { kind: "ngmodule", type:
|
|
2135
3039
|
// ACoreX
|
|
2136
|
-
AXMenuModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.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: i6.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i6.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.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:
|
|
3040
|
+
AXMenuModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.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: i6.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i6.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXButtonGroupModule }, { kind: "ngmodule", type: AXDropdownButtonModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.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: AXBreadcrumbsModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "ngmodule", type: AXFormatModule }, { kind: "ngmodule", type: AXFileModule }, { kind: "ngmodule", type: AXDateTimeModule }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i5$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i5$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "component", type:
|
|
2137
3041
|
//
|
|
2138
|
-
AXPThemeLayoutListComponent, selector: "axp-layout-list" }, { kind: "component", type: AXPThemeLayoutListItemComponent, selector: "axp-layout-list-item" }, { 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: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type:
|
|
3042
|
+
AXPThemeLayoutListComponent, selector: "axp-layout-list" }, { kind: "component", type: AXPThemeLayoutListItemComponent, selector: "axp-layout-list-item" }, { 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: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i6$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i6$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "component", type: AXPThemeLayoutStartSideComponent, selector: "axp-layout-page-start-side, axp-layout-start-side" }, { kind: "component", type: AXPThemeLayoutHeaderComponent, selector: "axp-layout-header" }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i7.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }, { kind: "directive", type: AXPPageComponentRendererDirective, selector: "[axp-page-component-renderer]", inputs: ["componentKey", "rootContext", "pageConfig", "options"], outputs: ["componentReady"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
2139
3043
|
}
|
|
2140
3044
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutDetailsViewComponent, decorators: [{
|
|
2141
3045
|
type: Component,
|
|
@@ -2150,7 +3054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2150
3054
|
AXDropdownModule,
|
|
2151
3055
|
AXTranslationModule,
|
|
2152
3056
|
AXDecoratorModule,
|
|
2153
|
-
AXLoadingModule,
|
|
2154
3057
|
AXBreadcrumbsModule,
|
|
2155
3058
|
AXBadgeModule,
|
|
2156
3059
|
AXSearchBoxModule,
|
|
@@ -2175,8 +3078,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2175
3078
|
useExisting: AXPLayoutDetailsViewComponent,
|
|
2176
3079
|
},
|
|
2177
3080
|
AXPLayoutDetailsViewViewModel,
|
|
2178
|
-
], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n (formatService.format(vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''), 'string', vm.rootContext())\n | translate\n | async)\n }}</axp-layout-title>\n <axp-layout-description>{{\n (formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async)\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs\n #sidebarTabs\n class=\"axp-vertical-tabs\"\n [look]=\"'with-line-color'\"\n [location]=\"'end'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\"\n >\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item\n [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n @if (vm.isBusy()) {\n <div class=\"ax-flex ax-h-full ax-w-full ax-items-center ax-justify-center\">\n <ax-loading></ax-loading>\n </div>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container\n #widgetsContainerRef\n [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\"\n >\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track $index) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div\n axp-page-component-renderer\n [componentKey]=\"$any(item).componentKey\"\n [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\"\n [options]=\"$any(item).options\"\n (componentReady)=\"recompute()\"\n ></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item\n (onClick)=\"vm.setCurrentTab(tab)\"\n [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\"\n [color]=\"'default'\"\n >\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item\n [text]=\"(t(action.title) | async)!\"\n [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(reject.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"reject.color\"\n (onClick)=\"execute(reject.command)\"\n >\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"vm.isSaving()\"\n [text]=\"(t(accept.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"accept.color\"\n (onClick)=\"execute(accept.command)\"\n >\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button\n [class.ax-sm]=\"deviceService.isSmall()\"\n [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\"\n [look]=\"'solid'\"\n [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\"\n >\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item\n [text]=\"(t(sub.title) | async)!\"\n [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\"\n (onClick)=\"execute(sub.command!)\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>\n", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"] }]
|
|
2179
|
-
}], propDecorators: {
|
|
3081
|
+
], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n formatService.format(\n vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''),\n 'string',\n vm.rootContext()\n )\n | translate\n | async\n }}</axp-layout-title>\n <axp-layout-description>{{\n formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs #sidebarTabs class=\"axp-vertical-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\">\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container #widgetsContainerRef [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\">\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track pageContentTrackKey($any(item), $index)) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div axp-page-component-renderer [componentKey]=\"$any(item).componentKey\" [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\" [options]=\"$any(item).options\" (componentReady)=\"recompute()\"></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item (onClick)=\"vm.setCurrentTab(tab)\" [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\">\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n </axp-page-content>\n\n <!-- Footer Section -->\n @if (hasFooter()) {\n <axp-page-footer class=\"--animated\">\n <axp-layout-suffix>\n <!-- secondary footer actions -->\n @if (hasVisibleFooterSecondaryActions()) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [iconOnly]=\"deviceService.isSmall()\"\n [text]=\"'@general:terms.interface.actions' | translate | async\"\n [look]=\"deviceService.isSmall() ? 'blank' : 'solid'\" [color]=\"'default'\">\n <ax-prefix>\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </ax-prefix>\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (action of footerSecondaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button-item [text]=\"(t(action.title) | async)!\" [color]=\"action.color\"\n [disabled]=\"isFooterActionDisabled(action)\" (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ action.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (action.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n </ax-button>\n }\n\n @if (hasVisibleFooterPrimaryActions()) {\n @if (showSaveDiscardFooter()) {\n @if (rejectFooterCommand(); as reject) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(reject.title) | async)!\" [look]=\"'solid'\" [color]=\"reject.color\" (onClick)=\"execute(reject.command)\">\n <ax-prefix>\n <i class=\"{{ reject.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (acceptFooterCommand(); as accept) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"vm.isOverlayBusy()\"\n [text]=\"(t(accept.title) | async)!\" [look]=\"'solid'\" [color]=\"accept.color\" (onClick)=\"execute(accept.command)\">\n <ax-prefix>\n <i class=\"{{ accept.icon }}\"></i>\n </ax-prefix>\n </ax-button>\n }\n }\n @for (action of footerPrimaryActions(); track $index) {\n @if (isFooterActionVisible(action)) {\n <ax-button [class.ax-sm]=\"deviceService.isSmall()\" [disabled]=\"isFooterActionDisabled(action)\"\n [text]=\"(t(action.title) | async)!\" [look]=\"'solid'\" [color]=\"action.color\"\n (onClick)=\"execute(action.command!)\">\n <ax-prefix>\n <i class=\"{{ action.icon }}\"></i>\n </ax-prefix>\n @if (action?.items) {\n <ax-dropdown-panel #panel>\n <ax-button-item-list>\n @for (sub of action?.items; track $index) {\n @if (isFooterActionVisible(sub)) {\n <ax-button-item [text]=\"(t(sub.title) | async)!\" [color]=\"sub.color\"\n [disabled]=\"isFooterActionDisabled(sub)\" (onClick)=\"execute(sub.command!)\">\n <ax-prefix>\n <ax-icon icon=\"fa-light {{ sub.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-button-item>\n @if (sub.break) {\n <ax-divider></ax-divider>\n }\n }\n }\n </ax-button-item-list>\n </ax-dropdown-panel>\n }\n </ax-button>\n }\n }\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>", styles: ["axp-layout-details-view .axp-vertical-tabs{--ax-comp-tabs-default-border-radius: 0}axp-layout-details-view .axp-vertical-tabs ax-tab-item{margin-top:0!important;margin-bottom:0!important;padding-top:.75rem!important;padding-bottom:.75rem!important;font-weight:600!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div{display:flex!important;align-items:center!important}axp-layout-details-view .axp-vertical-tabs ax-tab-item>div .ax-tab-item-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}axp-layout-details-view .axp-horizontal-tabs{display:flex;width:100%;flex-direction:column}axp-layout-details-view .axp-horizontal-tabs .content{margin-top:1rem;margin-bottom:1rem;display:block;width:100%}axp-layout-details-view axp-layout-section axp-layout-content{display:flex;width:100%;flex-direction:column}axp-layout-details-view axp-layout-section axp-layout-content>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse));border-style:dashed;--tw-divide-opacity: 1;border-color:rgba(var(--ax-sys-color-border-lightest-surface),var(--tw-divide-opacity, 1))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{align-items:center;gap:1rem;padding:1rem}@media(min-width:1024px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:1280px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2rem;padding-right:2rem}}@media(min-width:1536px){axp-layout-details-view axp-layout-section axp-layout-content .--item-container{padding-left:2.5rem;padding-right:2.5rem}}axp-layout-details-view axp-layout-section axp-layout-content .--item-container{display:grid;grid-template-columns:repeat(12,minmax(0,1fr))}axp-layout-details-view axp-layout-section axp-layout-content .--item-container axp-layout-description{margin-top:.5rem!important;font-size:.75rem!important;line-height:1rem!important}axp-layout-details-view axp-page-content ax-form form{height:100%}axp-layout-details-view axp-layout-start-side{border-inline-end-width:1px}\n"] }]
|
|
3082
|
+
}], propDecorators: { form: [{ type: i0.ViewChild, args: ['form', { isSignal: true }] }], widgetContainer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPWidgetContainerComponent), { isSignal: true }] }], sidebarTabs: [{ type: i0.ViewChild, args: ['sidebarTabs', { isSignal: true }] }] } });
|
|
2180
3083
|
|
|
2181
3084
|
//#region ---- Details View Can Deactivate Guard ----
|
|
2182
3085
|
/**
|
|
@@ -2189,5 +3092,5 @@ const axpDetailsViewCanDeactivateGuard = createUnsavedChangesCanDeactivateGuard(
|
|
|
2189
3092
|
* Generated bundle index. Do not edit.
|
|
2190
3093
|
*/
|
|
2191
3094
|
|
|
2192
|
-
export { AXPLayoutDetailsViewComponent, AXPLayoutDetailsViewViewModel, AXPPageComponentInstanceRegistryService, AXPPageComponentRendererDirective, AXPPageLayoutBase, AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPopupLayoutBase, AXPPopupLayoutBaseComponent, AXPPopupLayoutComponent, axpDetailsViewCanDeactivateGuard, buildNotSavedPageBadge, getDetailsViewActionCommandBaseName, isDiscardCommand, resolveDetailsViewActionShortcuts, resolveDetailsViewFooterCommandShortcuts };
|
|
3095
|
+
export { AXPLayoutDetailsViewComponent, AXPLayoutDetailsViewViewModel, AXPPageComponentInstanceRegistryService, AXPPageComponentRendererDirective, AXPPageLayoutBase, AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPopupLayoutBase, AXPPopupLayoutBaseComponent, AXPPopupLayoutComponent, AXP_LAYOUT_DETAILS_VIEW_ADAPTER_LOADER, axpDetailsViewCanDeactivateGuard, buildNotSavedPageBadge, getDetailsViewActionCommandBaseName, isDiscardCommand, isDiscardFooterCommand, isSaveFooterCommand, resolveDetailsViewActionShortcuts, resolveDetailsViewFooterCommandShortcuts, resolvePageFooterActionDefaultShortcuts, resolvePageFooterActionShortcuts };
|
|
2193
3096
|
//# sourceMappingURL=acorex-platform-layout-views.mjs.map
|