@acorex/platform 21.0.0-next.88 → 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 +8 -2
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-VfmZct9H.mjs → acorex-platform-common-common-settings.provider-DilV4dql.mjs} +15 -42
- package/fesm2022/acorex-platform-common-common-settings.provider-DilV4dql.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3299 -3200
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +621 -26
- package/fesm2022/acorex-platform-core.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 +125 -26
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +4 -4
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-contracts.mjs +106 -12
- package/fesm2022/acorex-platform-layout-entity-contracts.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +419 -147
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +851 -162
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +378 -103
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-D4MOHEpI.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-D4MOHEpI.mjs.map → acorex-platform-layout-widgets-tabular-data-edit-popup.component-CZc2zFlg.mjs.map} +1 -1
- 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 +575 -239
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +221 -24
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-BUwPqwUS.mjs → acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs} +48 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-UyKdkeyk.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +103 -24
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-auth.d.ts +1 -0
- package/types/acorex-platform-common.d.ts +202 -151
- package/types/acorex-platform-core.d.ts +161 -6
- package/types/acorex-platform-layout-builder.d.ts +10 -20
- package/types/acorex-platform-layout-components.d.ts +14 -1
- package/types/acorex-platform-layout-entity-contracts.d.ts +27 -2
- package/types/acorex-platform-layout-entity.d.ts +61 -12
- package/types/acorex-platform-layout-views.d.ts +101 -19
- package/types/acorex-platform-layout-widget-core.d.ts +65 -9
- package/types/acorex-platform-layout-widgets.d.ts +48 -26
- package/types/acorex-platform-themes-default.d.ts +56 -5
- package/types/acorex-platform-themes-shared.d.ts +4 -0
- package/fesm2022/acorex-platform-common-common-settings.provider-VfmZct9H.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-BUwPqwUS.mjs.map +0 -1
|
@@ -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, untracked, 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 { AXPTabNavigationService, AXPStickyDirective, AXPCommonSettings, AXPHomePageService, AXPSettingsService, AXPTabPreviewService, AXPUnsavedChangesConfirmService, normalizeRouterUrl, AXP_HOME_TAB_KEY, axpResolveTabKey, axpIsEntityDetailsViewRoute, axpNavigateAppPath, AXPEntityCommandScope, AXPUnsavedChangesPopstateService, createUnsavedChangesCanDeactivateGuard } from '@acorex/platform/common';
|
|
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, AXPContextEvalFactory, normalizeKeyboardShortcuts, AXPContextStore, AXPBroadcastEventService, AXPKeyboardShortcutRegistry, AXPKeyboardShortcutPriority } from '@acorex/platform/core';
|
|
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 {
|
|
31
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
32
|
+
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
|
|
32
33
|
import { isEmpty, cloneDeep, get } from 'lodash-es';
|
|
34
|
+
import { filter } from 'rxjs/operators';
|
|
33
35
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
34
|
-
import * as
|
|
36
|
+
import * as i6$1 from '@acorex/platform/layout/widget-core';
|
|
35
37
|
import { AXPPageStatus, AXPWidgetContainerComponent, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
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
|
}
|
|
@@ -146,7 +146,7 @@ class AXPPageLayoutComponent {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPageLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
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\"\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:
|
|
150
150
|
//
|
|
151
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:
|
|
152
152
|
//
|
|
@@ -174,7 +174,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
174
174
|
AXPStickyDirective,
|
|
175
175
|
AXPThemeLayoutContainerComponent,
|
|
176
176
|
AXPStatusChipComponent,
|
|
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\"\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"] }]
|
|
178
178
|
}], propDecorators: { startSideDrawer: [{ type: i0.ViewChild, args: ['startSideDrawer', { isSignal: true }] }] } });
|
|
179
179
|
|
|
180
180
|
//#region ---- Page Unsaved Changes Utilities ----
|
|
@@ -223,7 +223,9 @@ class AXPPageLayoutBaseComponent {
|
|
|
223
223
|
this.tabNavigation = inject(AXPTabNavigationService);
|
|
224
224
|
this.tabPreviewService = inject(AXPTabPreviewService);
|
|
225
225
|
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
226
|
+
this.browserTitleService = inject(AXPBrowserTitleService);
|
|
226
227
|
this.router = inject(Router);
|
|
228
|
+
this.pageLayoutDestroyRef = inject(DestroyRef);
|
|
227
229
|
//#endregion
|
|
228
230
|
//#region ---------------- Signal to force recomputation ----------------
|
|
229
231
|
this._updateTrigger = signal(0, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : /* istanbul ignore next */ []));
|
|
@@ -298,6 +300,19 @@ class AXPPageLayoutBaseComponent {
|
|
|
298
300
|
return false;
|
|
299
301
|
}, ...(ngDevMode ? [{ debugName: "hasTitle" }] : /* istanbul ignore next */ []));
|
|
300
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 */ []));
|
|
301
316
|
//#endregion
|
|
302
317
|
//#region ---------------- Description ----------------
|
|
303
318
|
this.description = signal(null, ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
@@ -340,16 +355,17 @@ class AXPPageLayoutBaseComponent {
|
|
|
340
355
|
this.breadcrumbs.set(trail);
|
|
341
356
|
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
342
357
|
const tabKey = this.pageTabKey();
|
|
343
|
-
|
|
358
|
+
const tabTitleSegments = await this.resolveBreadcrumbTabTitleSegments(breadCrumbs);
|
|
359
|
+
let tabTitle = tabTitleSegments.length ? axpJoinTabTitleSegments(tabTitleSegments) : null;
|
|
344
360
|
if (!tabTitle) {
|
|
345
361
|
tabTitle = await this.resolvePageTitleForTab();
|
|
346
362
|
}
|
|
347
363
|
if (tabKey && tabTitle) {
|
|
348
|
-
this.tabNavigation.syncTabTitle(tabKey, tabTitle);
|
|
364
|
+
this.tabNavigation.syncTabTitle(tabKey, tabTitleSegments.length ? tabTitleSegments : tabTitle);
|
|
349
365
|
}
|
|
350
366
|
}
|
|
351
367
|
}, ...(ngDevMode ? [{ debugName: "#breadcrumbsEffect" }] : /* istanbul ignore next */ []));
|
|
352
|
-
this.hasBreadcrumbs = computed(() => this.breadcrumbs().length > 1
|
|
368
|
+
this.hasBreadcrumbs = computed(() => this.breadcrumbs().length > 1, ...(ngDevMode ? [{ debugName: "hasBreadcrumbs" }] : /* istanbul ignore next */ []));
|
|
353
369
|
//#endregion
|
|
354
370
|
//#region ---------------- Badge ----------------
|
|
355
371
|
this.badge = signal(null, ...(ngDevMode ? [{ debugName: "badge" }] : /* istanbul ignore next */ []));
|
|
@@ -409,6 +425,11 @@ class AXPPageLayoutBaseComponent {
|
|
|
409
425
|
this.translateService.langChanges$.subscribe(() => {
|
|
410
426
|
this.recompute();
|
|
411
427
|
});
|
|
428
|
+
this.router.events
|
|
429
|
+
.pipe(filter((event) => event instanceof NavigationEnd), takeUntilDestroyed(this.pageLayoutDestroyRef))
|
|
430
|
+
.subscribe(() => {
|
|
431
|
+
void this.publishBrowserTitleIfActive();
|
|
432
|
+
});
|
|
412
433
|
}
|
|
413
434
|
/** Maps the home-page route to the pinned home tab key instead of a path-based key. */
|
|
414
435
|
resolvePageTabKey() {
|
|
@@ -418,6 +439,10 @@ class AXPPageLayoutBaseComponent {
|
|
|
418
439
|
}
|
|
419
440
|
return axpResolveTabKey(this.router);
|
|
420
441
|
}
|
|
442
|
+
/** Stable tab key for this cached page instance (tabular mode). */
|
|
443
|
+
getPageTabKey() {
|
|
444
|
+
return this.pageTabKey();
|
|
445
|
+
}
|
|
421
446
|
//#endregion
|
|
422
447
|
//#region ---------------- Tab Title Sync ----------------
|
|
423
448
|
/** Refreshes tab title when this cached page becomes the active tab again. */
|
|
@@ -481,6 +506,33 @@ class AXPPageLayoutBaseComponent {
|
|
|
481
506
|
getPageIcon() {
|
|
482
507
|
return null;
|
|
483
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
|
+
}
|
|
484
536
|
#descriptionEffect;
|
|
485
537
|
getPageDescription() {
|
|
486
538
|
return null;
|
|
@@ -489,8 +541,8 @@ class AXPPageLayoutBaseComponent {
|
|
|
489
541
|
getPageBreadcrumbs() {
|
|
490
542
|
return [];
|
|
491
543
|
}
|
|
492
|
-
/**
|
|
493
|
-
async
|
|
544
|
+
/** Collects resolved breadcrumb labels (Home excluded upstream) for tab chrome. */
|
|
545
|
+
async resolveBreadcrumbTabTitleSegments(pageBreadcrumbs) {
|
|
494
546
|
const segments = [];
|
|
495
547
|
for (const item of pageBreadcrumbs) {
|
|
496
548
|
const title = await this.resolveBreadcrumbItemTitle(item);
|
|
@@ -498,10 +550,15 @@ class AXPPageLayoutBaseComponent {
|
|
|
498
550
|
segments.push(title);
|
|
499
551
|
}
|
|
500
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);
|
|
501
558
|
if (!segments.length) {
|
|
502
559
|
return null;
|
|
503
560
|
}
|
|
504
|
-
return segments
|
|
561
|
+
return axpJoinTabTitleSegments(segments);
|
|
505
562
|
}
|
|
506
563
|
/** Resolves a breadcrumb label the same way as page chrome (`t(item.title)`). */
|
|
507
564
|
async resolveBreadcrumbItemTitle(item) {
|
|
@@ -781,6 +838,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
781
838
|
}]
|
|
782
839
|
}], propDecorators: { layout: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPPopupLayoutComponent), { isSignal: true }] }] } });
|
|
783
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
|
+
|
|
784
847
|
//#region ---- Root-context widget expression resolution ----
|
|
785
848
|
/**
|
|
786
849
|
* Evaluates `{{ ... }}` strings inside `options.customFilterDefinitions` using `rootContext`
|
|
@@ -820,10 +883,11 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
820
883
|
const state = {
|
|
821
884
|
adapter: null,
|
|
822
885
|
rootContext: {},
|
|
886
|
+
savedContext: {},
|
|
823
887
|
previousContext: {},
|
|
824
888
|
context: {},
|
|
825
889
|
scope: null,
|
|
826
|
-
status: AXPPageStatus.
|
|
890
|
+
status: AXPPageStatus.Idle,
|
|
827
891
|
currentPage: null,
|
|
828
892
|
currentTab: null,
|
|
829
893
|
pageSelectedRows: [],
|
|
@@ -848,6 +912,10 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
848
912
|
//
|
|
849
913
|
isBusy: computed(() => store.status() == AXPPageStatus.Processing),
|
|
850
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),
|
|
851
919
|
isDirty: computed(() => {
|
|
852
920
|
if (store.currentPage()?.isReadonly) {
|
|
853
921
|
return false;
|
|
@@ -871,7 +939,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
871
939
|
const evaluatedByTab = store.evaluatedTabContentsById();
|
|
872
940
|
return evaluatedByTab[tab.id] ?? [];
|
|
873
941
|
}),
|
|
874
|
-
})), 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)) => {
|
|
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)) => {
|
|
875
943
|
const resolvePageFromId = (adapter, pageId) => {
|
|
876
944
|
if (pageId) {
|
|
877
945
|
return adapter.pages.find((p) => p.id === pageId) ?? null;
|
|
@@ -881,49 +949,140 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
881
949
|
}
|
|
882
950
|
return null;
|
|
883
951
|
};
|
|
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
|
+
});
|
|
884
971
|
/** Loads page data, context, and evaluated widgets for the target sidebar page. */
|
|
885
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) => {
|
|
886
978
|
const adapter = store.adapter();
|
|
887
979
|
if (!adapter) {
|
|
888
980
|
return;
|
|
889
981
|
}
|
|
890
|
-
const
|
|
891
|
-
const targetPageId = pageId ?? queryParams['page'];
|
|
982
|
+
const targetPageId = pageId ?? readPageQueryParam() ?? undefined;
|
|
892
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
|
+
}));
|
|
893
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
|
+
}));
|
|
894
995
|
return;
|
|
895
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
|
+
}));
|
|
1018
|
+
}
|
|
896
1019
|
patchState(store, {
|
|
897
1020
|
status: AXPPageStatus.Processing,
|
|
898
1021
|
});
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
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
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
finally {
|
|
1081
|
+
if (isSidebarSwitch) {
|
|
1082
|
+
layout.setNavigationLoading(false);
|
|
1083
|
+
}
|
|
1084
|
+
if (store.status() === AXPPageStatus.Processing) {
|
|
1085
|
+
patchState(store, { status: AXPPageStatus.Rendered });
|
|
927
1086
|
}
|
|
928
1087
|
}
|
|
929
1088
|
};
|
|
@@ -937,16 +1096,33 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
937
1096
|
if (!adapter) {
|
|
938
1097
|
return;
|
|
939
1098
|
}
|
|
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
|
+
}
|
|
940
1106
|
const pageId = params['page'];
|
|
941
|
-
|
|
942
|
-
|
|
1107
|
+
if (!pageId) {
|
|
1108
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'queryParams effect — skipped (no page param)', () => pageQueryTraceContext({
|
|
1109
|
+
params,
|
|
1110
|
+
}));
|
|
943
1111
|
return;
|
|
944
1112
|
}
|
|
945
|
-
|
|
946
|
-
if (store.currentPage()
|
|
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
|
+
}));
|
|
947
1119
|
return;
|
|
948
1120
|
}
|
|
949
|
-
|
|
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);
|
|
950
1126
|
});
|
|
951
1127
|
onCleanup(() => subscription.unsubscribe());
|
|
952
1128
|
});
|
|
@@ -1048,7 +1224,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1048
1224
|
async loadPage(pageId, forceRefresh) {
|
|
1049
1225
|
await activatePageById(pageId, forceRefresh);
|
|
1050
1226
|
},
|
|
1051
|
-
async load(adapter) {
|
|
1227
|
+
async load(adapter, forceRefresh, pageIdFromUrl) {
|
|
1052
1228
|
const scope = {
|
|
1053
1229
|
context: {
|
|
1054
1230
|
...contextEvalFactory.createLiveScope(() => store.context()),
|
|
@@ -1060,7 +1236,81 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1060
1236
|
});
|
|
1061
1237
|
//
|
|
1062
1238
|
await this.loadAdapter(adapter);
|
|
1063
|
-
|
|
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;
|
|
1064
1314
|
},
|
|
1065
1315
|
updateContext(context) {
|
|
1066
1316
|
patchState(store, {
|
|
@@ -1129,10 +1379,23 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1129
1379
|
},
|
|
1130
1380
|
setCurrentPage(page) {
|
|
1131
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
|
+
}));
|
|
1132
1386
|
if (page) {
|
|
1133
|
-
|
|
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
|
+
}));
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
const pageParam = readPageQueryParam();
|
|
1134
1394
|
const isSamePage = previousPage?.id === page.id && pageParam === page.id;
|
|
1135
1395
|
if (!isSamePage && axpIsEntityDetailsViewRoute(router)) {
|
|
1396
|
+
AXPDebugService.instance?.trace(DETAILS_VIEW_PAGE_TRACE_NS, 'viewmodel', 'setCurrentPage — navigate', () => pageQueryTraceContext({
|
|
1397
|
+
navigateToPageId: page.id,
|
|
1398
|
+
}));
|
|
1136
1399
|
const queryParams = { page: page.id };
|
|
1137
1400
|
if (previousPage?.id && previousPage.id !== page.id) {
|
|
1138
1401
|
queryParams['filters'] = null;
|
|
@@ -1144,6 +1407,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1144
1407
|
// Push history for desktop sidebar switches and mobile page-list picks.
|
|
1145
1408
|
replaceUrl: false,
|
|
1146
1409
|
});
|
|
1410
|
+
return;
|
|
1147
1411
|
}
|
|
1148
1412
|
void activatePageById(page.id);
|
|
1149
1413
|
}
|
|
@@ -1274,13 +1538,16 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1274
1538
|
const snapshot = cloneDeep(context);
|
|
1275
1539
|
patchState(store, {
|
|
1276
1540
|
context: snapshot,
|
|
1541
|
+
savedContext: snapshot,
|
|
1277
1542
|
previousContext: snapshot,
|
|
1278
1543
|
formDirty: false,
|
|
1279
1544
|
});
|
|
1280
1545
|
},
|
|
1281
1546
|
async discard() {
|
|
1547
|
+
const saved = cloneDeep(store.savedContext());
|
|
1282
1548
|
patchState(store, {
|
|
1283
|
-
context:
|
|
1549
|
+
context: saved,
|
|
1550
|
+
previousContext: saved,
|
|
1284
1551
|
formDirty: false,
|
|
1285
1552
|
});
|
|
1286
1553
|
},
|
|
@@ -1295,10 +1562,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1295
1562
|
});
|
|
1296
1563
|
try {
|
|
1297
1564
|
const result = await store.currentPage()?.execute?.(command, payload);
|
|
1298
|
-
// Clear submitting before post-save refresh so the footer is not left disabled.
|
|
1299
|
-
patchState(store, {
|
|
1300
|
-
status: AXPPageStatus.Rendered,
|
|
1301
|
-
});
|
|
1302
1565
|
const enableOperationToasts = await settingsService.get(AXPCommonSettings.EnableOperationToasts);
|
|
1303
1566
|
if (result?.success) {
|
|
1304
1567
|
try {
|
|
@@ -1309,6 +1572,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1309
1572
|
}
|
|
1310
1573
|
patchState(store, {
|
|
1311
1574
|
previousContext: store.context(),
|
|
1575
|
+
savedContext: cloneDeep(store.context()),
|
|
1312
1576
|
formDirty: false,
|
|
1313
1577
|
});
|
|
1314
1578
|
if (enableOperationToasts) {
|
|
@@ -1322,9 +1586,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1322
1586
|
timeOutProgress: true,
|
|
1323
1587
|
});
|
|
1324
1588
|
}
|
|
1325
|
-
patchState(store, {
|
|
1326
|
-
formDirty: false,
|
|
1327
|
-
});
|
|
1328
1589
|
return true;
|
|
1329
1590
|
}
|
|
1330
1591
|
const rawText = result?.message?.text;
|
|
@@ -1350,9 +1611,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1350
1611
|
const errorText = error instanceof Error
|
|
1351
1612
|
? error.message
|
|
1352
1613
|
: await translateService.translateAsync('@general:messages.generic.error.description');
|
|
1353
|
-
patchState(store, {
|
|
1354
|
-
status: AXPPageStatus.Rendered,
|
|
1355
|
-
});
|
|
1356
1614
|
toastService.show({
|
|
1357
1615
|
color: 'danger',
|
|
1358
1616
|
title: await translateService.translateAsync('@general:messages.generic.error.title'),
|
|
@@ -1365,17 +1623,15 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1365
1623
|
return false;
|
|
1366
1624
|
}
|
|
1367
1625
|
finally {
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1626
|
+
patchState(store, {
|
|
1627
|
+
status: AXPPageStatus.Rendered,
|
|
1628
|
+
});
|
|
1373
1629
|
}
|
|
1374
1630
|
},
|
|
1375
|
-
goToListPage() {
|
|
1631
|
+
async goToListPage() {
|
|
1376
1632
|
const exitUrl = store.adapter()?.exitUrl;
|
|
1377
1633
|
if (exitUrl) {
|
|
1378
|
-
|
|
1634
|
+
await axpNavigateAppPath(router, exitUrl);
|
|
1379
1635
|
}
|
|
1380
1636
|
},
|
|
1381
1637
|
};
|
|
@@ -1390,6 +1646,8 @@ const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
|
|
|
1390
1646
|
'update-entity': ['ctrl+s'],
|
|
1391
1647
|
discard: ['escape'],
|
|
1392
1648
|
};
|
|
1649
|
+
const SAVE_FOOTER_COMMAND_SUFFIX = ':Save';
|
|
1650
|
+
const DISCARD_FOOTER_COMMAND_SUFFIX = ':Discard';
|
|
1393
1651
|
/**
|
|
1394
1652
|
* Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
|
|
1395
1653
|
*/
|
|
@@ -1420,7 +1678,34 @@ function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
|
|
|
1420
1678
|
return chords.length ? chords : undefined;
|
|
1421
1679
|
}
|
|
1422
1680
|
const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
|
|
1423
|
-
|
|
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);
|
|
1424
1709
|
}
|
|
1425
1710
|
function flattenDetailsViewActionShortcuts(shortcuts) {
|
|
1426
1711
|
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
@@ -1582,7 +1867,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1582
1867
|
class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
1583
1868
|
constructor() {
|
|
1584
1869
|
super(...arguments);
|
|
1585
|
-
this.adapter = input.required(...(ngDevMode ? [{ debugName: "adapter" }] : /* istanbul ignore next */ []));
|
|
1586
1870
|
//
|
|
1587
1871
|
this.vm = inject(AXPLayoutDetailsViewViewModel);
|
|
1588
1872
|
this.route = inject(ActivatedRoute);
|
|
@@ -1591,13 +1875,21 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1591
1875
|
this.unsavedChangesPopstate = inject(AXPUnsavedChangesPopstateService);
|
|
1592
1876
|
this.pageComponentInstanceRegistry = inject(AXPPageComponentInstanceRegistryService);
|
|
1593
1877
|
this.shortcutRegistry = inject(AXPKeyboardShortcutRegistry);
|
|
1878
|
+
this.workflowService = inject(AXPWorkflowService);
|
|
1594
1879
|
this.destroyRef = inject(DestroyRef);
|
|
1595
1880
|
this.elementRef = inject((ElementRef));
|
|
1596
|
-
|
|
1597
|
-
|
|
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 */ []));
|
|
1598
1884
|
this.destroyed$ = new Subject();
|
|
1599
1885
|
this.footerActionsGeneration = 0;
|
|
1600
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;
|
|
1601
1893
|
/** Header actions with resolved shortcut chords, keyed by command name. */
|
|
1602
1894
|
this.actionShortcutEntries = signal(new Map(), ...(ngDevMode ? [{ debugName: "actionShortcutEntries" }] : /* istanbul ignore next */ []));
|
|
1603
1895
|
this.form = viewChild('form', ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
@@ -1616,6 +1908,11 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1616
1908
|
return;
|
|
1617
1909
|
}
|
|
1618
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
|
+
}));
|
|
1619
1916
|
this.sidebarTabChangeSuppressed = true;
|
|
1620
1917
|
try {
|
|
1621
1918
|
this.sidebarTabs()?.select(index);
|
|
@@ -1625,6 +1922,114 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1625
1922
|
}
|
|
1626
1923
|
}));
|
|
1627
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 */ []));
|
|
1628
2033
|
this.footerPrimaryActions = signal([], ...(ngDevMode ? [{ debugName: "footerPrimaryActions" }] : /* istanbul ignore next */ []));
|
|
1629
2034
|
this.footerSecondaryActions = signal([], ...(ngDevMode ? [{ debugName: "footerSecondaryActions" }] : /* istanbul ignore next */ []));
|
|
1630
2035
|
this.footerActions = computed(() => [...this.footerPrimaryActions(), ...this.footerSecondaryActions()], ...(ngDevMode ? [{ debugName: "footerActions" }] : /* istanbul ignore next */ []));
|
|
@@ -1648,7 +2053,14 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1648
2053
|
if (this.vm.currentPage()?.isReadonly || this.getActivePageComponentKey()) {
|
|
1649
2054
|
return false;
|
|
1650
2055
|
}
|
|
1651
|
-
|
|
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();
|
|
1652
2064
|
}, ...(ngDevMode ? [{ debugName: "liveFormIsDirty" }] : /* istanbul ignore next */ []));
|
|
1653
2065
|
this.hasVisibleFooterPrimaryActions = computed(() => {
|
|
1654
2066
|
if (this.showSaveDiscardFooter()) {
|
|
@@ -1665,11 +2077,25 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1665
2077
|
if (this.vm.currentPage()?.isReadonly || this.getActivePageComponentKey()) {
|
|
1666
2078
|
return;
|
|
1667
2079
|
}
|
|
1668
|
-
|
|
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();
|
|
1669
2091
|
if (this.vm.formDirty() === isDirty) {
|
|
1670
2092
|
return;
|
|
1671
2093
|
}
|
|
1672
2094
|
untracked(() => {
|
|
2095
|
+
this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'formDirty effect', () => ({
|
|
2096
|
+
isDirty,
|
|
2097
|
+
vmFormDirty: this.vm.formDirty(),
|
|
2098
|
+
}));
|
|
1673
2099
|
this.vm.setFormDirty(isDirty);
|
|
1674
2100
|
this.recompute();
|
|
1675
2101
|
});
|
|
@@ -1685,18 +2111,21 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1685
2111
|
const generation = ++this.footerActionsGeneration;
|
|
1686
2112
|
this.updateTrigger();
|
|
1687
2113
|
this.liveFormIsDirty();
|
|
1688
|
-
this.vm.
|
|
2114
|
+
this.vm.isOverlayBusy();
|
|
1689
2115
|
void this.refreshFooterActions(generation);
|
|
1690
2116
|
}, ...(ngDevMode ? [{ debugName: "#FooterActionsEffect" }] : /* istanbul ignore next */ []));
|
|
1691
2117
|
this.#keyboardShortcutsEffect = effect(() => {
|
|
1692
2118
|
const generation = ++this.keyboardShortcutRegistrationGeneration;
|
|
1693
2119
|
this.updateTrigger();
|
|
1694
2120
|
this.liveFormIsDirty();
|
|
1695
|
-
this.
|
|
2121
|
+
this.isActivePageComponentDirty();
|
|
2122
|
+
this.vm.isOverlayBusy();
|
|
1696
2123
|
this.vm.currentPage()?.id;
|
|
1697
2124
|
untracked(() => void this.refreshKeyboardShortcutRegistrations(generation));
|
|
1698
2125
|
}, ...(ngDevMode ? [{ debugName: "#keyboardShortcutsEffect" }] : /* istanbul ignore next */ []));
|
|
1699
2126
|
}
|
|
2127
|
+
/** Safety cap when widget ready detection does not settle. */
|
|
2128
|
+
static { this.overlayMaxWaitMs = 30_000; }
|
|
1700
2129
|
/** Save/discard use live {@link AXPLayoutDetailsViewViewModel.isDirty}; other actions use evaluated `visible`. */
|
|
1701
2130
|
static isTruthyActionFlag(value) {
|
|
1702
2131
|
if (value === true) {
|
|
@@ -1723,6 +2152,8 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1723
2152
|
}
|
|
1724
2153
|
/** Syncs the line indicator when the active page changes programmatically. */
|
|
1725
2154
|
#sidebarTabsIndicatorEffect;
|
|
2155
|
+
/** Clears the page overlay reactively once VM + widget hydration are both idle. */
|
|
2156
|
+
#overlayReleaseEffect;
|
|
1726
2157
|
isSaveDiscardFooterAction(action) {
|
|
1727
2158
|
const commandName = action.command?.name;
|
|
1728
2159
|
const acceptCommand = this.vm.currentPage()?.settings?.commands?.accept?.command?.name;
|
|
@@ -1741,35 +2172,43 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1741
2172
|
return AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.visible);
|
|
1742
2173
|
}
|
|
1743
2174
|
isFooterActionDisabled(action) {
|
|
1744
|
-
if (this.vm.
|
|
2175
|
+
if (this.vm.isOverlayBusy()) {
|
|
1745
2176
|
return true;
|
|
1746
2177
|
}
|
|
1747
2178
|
return AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.disabled);
|
|
1748
2179
|
}
|
|
1749
2180
|
/**
|
|
1750
|
-
*
|
|
2181
|
+
* Re-fetches the entity adapter and reloads the active page.
|
|
1751
2182
|
*/
|
|
1752
2183
|
async refreshLayout() {
|
|
1753
|
-
const router = this.router;
|
|
1754
|
-
const route = this.route;
|
|
1755
|
-
const now = Date.now();
|
|
1756
2184
|
this.unsavedChangesConfirm.markLeaveConfirmed();
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
2185
|
+
this.detailsLayoutReady.set(false);
|
|
2186
|
+
try {
|
|
2187
|
+
await this.vm.loadFromRoute(true);
|
|
2188
|
+
}
|
|
2189
|
+
finally {
|
|
2190
|
+
this.detailsLayoutReady.set(true);
|
|
2191
|
+
}
|
|
1763
2192
|
}
|
|
1764
2193
|
async ngOnInit() {
|
|
1765
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
|
+
}));
|
|
1766
2200
|
this.unsavedChangesPopstate.registerSource({
|
|
1767
2201
|
id: 'axp-layout-details-view',
|
|
1768
|
-
isDirty: () => this.
|
|
2202
|
+
isDirty: () => this.hasUnsavedChanges(),
|
|
1769
2203
|
});
|
|
2204
|
+
this.destroyRef.onDestroy(() => this.unsavedChangesPopstate.unregisterSource('axp-layout-details-view'));
|
|
1770
2205
|
//
|
|
1771
|
-
await this.vm.
|
|
1772
|
-
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);
|
|
1773
2212
|
void this.refreshKeyboardShortcutRegistrations(++this.keyboardShortcutRegistrationGeneration);
|
|
1774
2213
|
this.eventService
|
|
1775
2214
|
//TODO: Use the constant from the entity module
|
|
@@ -1780,6 +2219,37 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1780
2219
|
this.refreshLayout();
|
|
1781
2220
|
}
|
|
1782
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();
|
|
1783
2253
|
}
|
|
1784
2254
|
async ngAfterViewInit() {
|
|
1785
2255
|
const listWidget = (await this.widgetContainer()?.find('page-list_table'));
|
|
@@ -1794,9 +2264,12 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1794
2264
|
}
|
|
1795
2265
|
}
|
|
1796
2266
|
ngOnDestroy() {
|
|
1797
|
-
this.unsavedChangesPopstate.unregisterSource('axp-layout-details-view');
|
|
1798
2267
|
this.onSelectionChangeSubscription?.unsubscribe();
|
|
1799
2268
|
++this.keyboardShortcutRegistrationGeneration;
|
|
2269
|
+
this.clearOverlayFallback();
|
|
2270
|
+
this.overlayReleaseGeneration += 1;
|
|
2271
|
+
this.overlayReleasePromise = undefined;
|
|
2272
|
+
this.clearPageOverlay('ngOnDestroy');
|
|
1800
2273
|
this.destroyed$.next();
|
|
1801
2274
|
this.destroyed$.complete();
|
|
1802
2275
|
}
|
|
@@ -1817,28 +2290,171 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1817
2290
|
this.footerSecondaryActions.set(footerSecondaryActions);
|
|
1818
2291
|
}
|
|
1819
2292
|
handleOnContextChanged(e) {
|
|
1820
|
-
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
|
+
}
|
|
1821
2312
|
this.recompute();
|
|
1822
2313
|
}
|
|
1823
2314
|
getLiveFormContext() {
|
|
1824
2315
|
const container = this.widgetContainer();
|
|
1825
2316
|
return (container?.contextService.data() ?? this.vm.context());
|
|
1826
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
|
+
}
|
|
1827
2430
|
async finalizeSave() {
|
|
1828
2431
|
const container = this.widgetContainer();
|
|
1829
2432
|
if (!container) {
|
|
1830
2433
|
this.vm.setFormDirty(false);
|
|
1831
2434
|
return;
|
|
1832
2435
|
}
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
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
|
+
}
|
|
1836
2450
|
}
|
|
1837
2451
|
finalizeDiscard() {
|
|
2452
|
+
this.debug.trace(FORM_DIRTY_TRACE_NS, 'details-view', 'finalizeDiscard');
|
|
1838
2453
|
const container = this.widgetContainer();
|
|
1839
2454
|
if (container) {
|
|
1840
2455
|
container.revertAndSettle();
|
|
1841
|
-
|
|
2456
|
+
const saved = container.contextService.saved();
|
|
2457
|
+
this.vm.applySavedState(saved);
|
|
1842
2458
|
return;
|
|
1843
2459
|
}
|
|
1844
2460
|
void this.vm.discard();
|
|
@@ -1852,15 +2468,21 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1852
2468
|
* `ax-tabs` selects on click before we can confirm. Revert synchronously, then confirm + switch.
|
|
1853
2469
|
*/
|
|
1854
2470
|
handleSidebarTabChanged(event) {
|
|
1855
|
-
if (!this.detailsLayoutReady || this.sidebarTabChangeSuppressed) {
|
|
2471
|
+
if (!this.detailsLayoutReady() || this.sidebarTabChangeSuppressed) {
|
|
1856
2472
|
return;
|
|
1857
2473
|
}
|
|
1858
2474
|
const pages = this.vm.adapter()?.pages ?? [];
|
|
1859
2475
|
const target = pages[event.index];
|
|
1860
2476
|
const currentId = this.vm.currentPage()?.id;
|
|
1861
|
-
if (!target || target.id === currentId) {
|
|
2477
|
+
if (!currentId || !target || target.id === currentId) {
|
|
1862
2478
|
return;
|
|
1863
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
|
+
}));
|
|
1864
2486
|
const activeIndex = pages.findIndex((page) => page.id === currentId);
|
|
1865
2487
|
if (activeIndex >= 0) {
|
|
1866
2488
|
this.sidebarTabChangeSuppressed = true;
|
|
@@ -1943,13 +2565,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1943
2565
|
return this.vm.getBackButton();
|
|
1944
2566
|
}
|
|
1945
2567
|
hasUnsavedChanges() {
|
|
1946
|
-
|
|
1947
|
-
return false;
|
|
1948
|
-
}
|
|
1949
|
-
if (this.isActivePageComponentDirty()) {
|
|
1950
|
-
return true;
|
|
1951
|
-
}
|
|
1952
|
-
return this.liveFormIsDirty();
|
|
2568
|
+
return this.shouldPromptLeave();
|
|
1953
2569
|
}
|
|
1954
2570
|
async getPageBadge() {
|
|
1955
2571
|
if (this.vm.currentPage()?.isReadonly) {
|
|
@@ -1997,6 +2613,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1997
2613
|
}
|
|
1998
2614
|
/** Background tab close — confirm without discarding (the cached instance is destroyed). */
|
|
1999
2615
|
onBeforeTabClose() {
|
|
2616
|
+
if (this.unsavedChangesConfirm.hasLeaveConfirmed()) {
|
|
2617
|
+
return Promise.resolve(true);
|
|
2618
|
+
}
|
|
2000
2619
|
return this.unsavedChangesConfirm.confirmIfDirty(this.shouldPromptLeave(), {
|
|
2001
2620
|
approveLeaveOnConfirm: false,
|
|
2002
2621
|
});
|
|
@@ -2035,6 +2654,23 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2035
2654
|
isActivePageComponentDirty() {
|
|
2036
2655
|
return this.getActivePageComponentInstance()?.hasUnsavedChanges() ?? false;
|
|
2037
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
|
+
}
|
|
2038
2674
|
/** Whether the current details page has user-origin unsaved edits (form or component page). */
|
|
2039
2675
|
shouldPromptLeave() {
|
|
2040
2676
|
if (this.vm.currentPage()?.isReadonly) {
|
|
@@ -2043,7 +2679,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2043
2679
|
if (this.isActivePageComponentDirty()) {
|
|
2044
2680
|
return true;
|
|
2045
2681
|
}
|
|
2046
|
-
return this.
|
|
2682
|
+
return this.hasWidgetFormUnsavedChanges();
|
|
2047
2683
|
}
|
|
2048
2684
|
/** Single gate for leaving the page or switching details sub-pages when dirty. */
|
|
2049
2685
|
async confirmLeaveIfDirty() {
|
|
@@ -2168,17 +2804,59 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2168
2804
|
this.registerCoreKeyboardShortcuts();
|
|
2169
2805
|
this.registerActionKeyboardShortcuts(entries);
|
|
2170
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
|
+
}
|
|
2171
2834
|
async collectActionShortcutEntries() {
|
|
2172
2835
|
const map = new Map();
|
|
2173
2836
|
if (this.vm.showPages()) {
|
|
2174
2837
|
return map;
|
|
2175
2838
|
}
|
|
2176
|
-
const
|
|
2177
|
-
|
|
2178
|
-
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(),
|
|
2179
2845
|
]);
|
|
2180
|
-
for (const action of [
|
|
2181
|
-
|
|
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)) {
|
|
2182
2860
|
continue;
|
|
2183
2861
|
}
|
|
2184
2862
|
const commandName = action.command?.name;
|
|
@@ -2187,7 +2865,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2187
2865
|
continue;
|
|
2188
2866
|
}
|
|
2189
2867
|
const commandBaseName = getDetailsViewActionCommandBaseName(commandName);
|
|
2190
|
-
const chords =
|
|
2868
|
+
const chords = zone === 'footer'
|
|
2869
|
+
? resolvePageFooterActionShortcuts(commandBaseName, action.shortcuts)
|
|
2870
|
+
: resolveDetailsViewActionShortcuts(commandBaseName, action.shortcuts);
|
|
2191
2871
|
if (!chords?.length) {
|
|
2192
2872
|
continue;
|
|
2193
2873
|
}
|
|
@@ -2195,13 +2875,13 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2195
2875
|
command,
|
|
2196
2876
|
title: typeof action.title === 'string' ? action.title : '',
|
|
2197
2877
|
chords,
|
|
2198
|
-
visible: this.
|
|
2878
|
+
visible: this.isShortcutActionAvailable(action),
|
|
2199
2879
|
disabled: AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.disabled),
|
|
2200
2880
|
});
|
|
2201
2881
|
}
|
|
2202
2882
|
return map;
|
|
2203
2883
|
}
|
|
2204
|
-
|
|
2884
|
+
isShortcutActionAvailable(action) {
|
|
2205
2885
|
if (AXPLayoutDetailsViewComponent.isTruthyActionFlag(action.hidden)) {
|
|
2206
2886
|
return false;
|
|
2207
2887
|
}
|
|
@@ -2210,15 +2890,15 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2210
2890
|
}
|
|
2211
2891
|
return true;
|
|
2212
2892
|
}
|
|
2213
|
-
/** 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). */
|
|
2214
2894
|
isCoreSaveShortcutAvailable() {
|
|
2215
|
-
return !this.vm.currentPage()?.isReadonly && !!this.acceptFooterCommand();
|
|
2895
|
+
return this.isWidgetFormPrimaryPage() && !this.vm.currentPage()?.isReadonly && !!this.acceptFooterCommand();
|
|
2216
2896
|
}
|
|
2217
2897
|
isCoreDiscardShortcutAvailable() {
|
|
2218
|
-
return !this.vm.currentPage()?.isReadonly && !!this.rejectFooterCommand();
|
|
2898
|
+
return this.isWidgetFormPrimaryPage() && !this.vm.currentPage()?.isReadonly && !!this.rejectFooterCommand();
|
|
2219
2899
|
}
|
|
2220
2900
|
canExecuteSaveShortcut() {
|
|
2221
|
-
if (this.vm.currentPage()?.isReadonly || this.vm.
|
|
2901
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2222
2902
|
return false;
|
|
2223
2903
|
}
|
|
2224
2904
|
if (!this.acceptFooterCommand()) {
|
|
@@ -2227,7 +2907,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2227
2907
|
return this.shouldPromptLeave();
|
|
2228
2908
|
}
|
|
2229
2909
|
canExecuteDiscardShortcut() {
|
|
2230
|
-
if (this.vm.currentPage()?.isReadonly || this.vm.
|
|
2910
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2231
2911
|
return false;
|
|
2232
2912
|
}
|
|
2233
2913
|
if (this.unsavedChangesConfirm.isConfirmPending()) {
|
|
@@ -2252,8 +2932,31 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2252
2932
|
}
|
|
2253
2933
|
await this.execute({ name: rejectCommandName });
|
|
2254
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
|
+
}
|
|
2255
2958
|
isActionShortcutActive(entryId) {
|
|
2256
|
-
if (this.vm.currentPage()?.isReadonly || this.vm.
|
|
2959
|
+
if (this.vm.currentPage()?.isReadonly || this.vm.isOverlayBusy()) {
|
|
2257
2960
|
return false;
|
|
2258
2961
|
}
|
|
2259
2962
|
const entry = this.actionShortcutEntries().get(entryId);
|
|
@@ -2263,18 +2966,23 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2263
2966
|
return entry.visible && !entry.disabled;
|
|
2264
2967
|
}
|
|
2265
2968
|
registerCoreKeyboardShortcuts() {
|
|
2969
|
+
if (!this.isWidgetFormPrimaryPage()) {
|
|
2970
|
+
this.registerDetailsViewShortcutScope('layout-details-view-core', []);
|
|
2971
|
+
return;
|
|
2972
|
+
}
|
|
2266
2973
|
const accept = this.vm.currentPage()?.settings?.commands?.accept;
|
|
2267
2974
|
const reject = this.vm.currentPage()?.settings?.commands?.reject;
|
|
2268
2975
|
const acceptCommandName = accept?.command.name ?? 'update-entity';
|
|
2269
2976
|
const rejectCommandName = reject?.command.name ?? 'discard';
|
|
2270
2977
|
const saveKeys = resolveDetailsViewFooterCommandShortcuts(acceptCommandName, accept?.shortcuts);
|
|
2271
2978
|
const discardKeys = resolveDetailsViewFooterCommandShortcuts(rejectCommandName, reject?.shortcuts);
|
|
2979
|
+
const scope = this.getKeyboardShortcutScope();
|
|
2272
2980
|
const shortcuts = [];
|
|
2273
2981
|
if (saveKeys?.length && this.isCoreSaveShortcutAvailable()) {
|
|
2274
2982
|
shortcuts.push({
|
|
2275
2983
|
keys: saveKeys,
|
|
2276
2984
|
title: accept?.title ?? '@general:actions.save.title',
|
|
2277
|
-
group:
|
|
2985
|
+
group: scope,
|
|
2278
2986
|
allowInEditableFields: true,
|
|
2279
2987
|
when: () => this.canExecuteSaveShortcut(),
|
|
2280
2988
|
handler: () => {
|
|
@@ -2286,7 +2994,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2286
2994
|
shortcuts.push({
|
|
2287
2995
|
keys: discardKeys,
|
|
2288
2996
|
title: reject?.title ?? '@general:actions.discard.title',
|
|
2289
|
-
group:
|
|
2997
|
+
group: scope,
|
|
2290
2998
|
allowInEditableFields: true,
|
|
2291
2999
|
when: () => this.canExecuteDiscardShortcut(),
|
|
2292
3000
|
handler: () => {
|
|
@@ -2294,62 +3002,44 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2294
3002
|
},
|
|
2295
3003
|
});
|
|
2296
3004
|
}
|
|
2297
|
-
|
|
2298
|
-
return;
|
|
2299
|
-
}
|
|
2300
|
-
this.shortcutRegistry.register({
|
|
2301
|
-
owner: this.destroyRef,
|
|
2302
|
-
elementRef: this.elementRef,
|
|
2303
|
-
id: 'layout-details-view-core',
|
|
2304
|
-
priority: AXPKeyboardShortcutPriority.Page,
|
|
2305
|
-
scope: '@general:keyboard-shortcuts.groups.entity-details',
|
|
2306
|
-
shortcuts,
|
|
2307
|
-
});
|
|
3005
|
+
this.registerDetailsViewShortcutScope('layout-details-view-core', shortcuts);
|
|
2308
3006
|
}
|
|
2309
3007
|
registerActionKeyboardShortcuts(entries) {
|
|
3008
|
+
const scope = this.getKeyboardShortcutScope();
|
|
2310
3009
|
const shortcuts = [];
|
|
2311
3010
|
for (const [entryId, entry] of entries) {
|
|
2312
3011
|
for (const chord of entry.chords) {
|
|
2313
3012
|
shortcuts.push({
|
|
2314
3013
|
keys: [chord],
|
|
2315
3014
|
title: entry.title,
|
|
2316
|
-
group:
|
|
3015
|
+
group: scope,
|
|
3016
|
+
allowInEditableFields: entry.command.name ? isSaveFooterCommand(entry.command.name) || isDiscardFooterCommand(entry.command.name) : false,
|
|
2317
3017
|
when: () => this.isActionShortcutActive(entryId),
|
|
2318
3018
|
handler: () => {
|
|
2319
3019
|
if (!this.isActionShortcutActive(entryId)) {
|
|
2320
3020
|
return;
|
|
2321
3021
|
}
|
|
2322
|
-
void this.
|
|
3022
|
+
void this.executeActionShortcut(entry);
|
|
2323
3023
|
},
|
|
2324
3024
|
});
|
|
2325
3025
|
}
|
|
2326
3026
|
}
|
|
2327
|
-
|
|
2328
|
-
return;
|
|
2329
|
-
}
|
|
2330
|
-
this.shortcutRegistry.register({
|
|
2331
|
-
owner: this.destroyRef,
|
|
2332
|
-
elementRef: this.elementRef,
|
|
2333
|
-
id: 'layout-details-view-actions',
|
|
2334
|
-
priority: AXPKeyboardShortcutPriority.Page,
|
|
2335
|
-
scope: '@general:keyboard-shortcuts.groups.entity-details',
|
|
2336
|
-
shortcuts,
|
|
2337
|
-
});
|
|
3027
|
+
this.registerDetailsViewShortcutScope('layout-details-view-actions', shortcuts);
|
|
2338
3028
|
}
|
|
2339
3029
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutDetailsViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
2340
|
-
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: [
|
|
2341
3031
|
{
|
|
2342
3032
|
provide: AXPPageLayoutBase,
|
|
2343
3033
|
useExisting: AXPLayoutDetailsViewComponent,
|
|
2344
3034
|
},
|
|
2345
3035
|
AXPLayoutDetailsViewViewModel,
|
|
2346
|
-
], 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\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 pageContentTrackKey($any(item), $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:
|
|
2347
3037
|
// Angular
|
|
2348
3038
|
CommonModule }, { kind: "ngmodule", type:
|
|
2349
3039
|
// ACoreX
|
|
2350
|
-
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:
|
|
2351
3041
|
//
|
|
2352
|
-
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 }); }
|
|
2353
3043
|
}
|
|
2354
3044
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPLayoutDetailsViewComponent, decorators: [{
|
|
2355
3045
|
type: Component,
|
|
@@ -2364,7 +3054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2364
3054
|
AXDropdownModule,
|
|
2365
3055
|
AXTranslationModule,
|
|
2366
3056
|
AXDecoratorModule,
|
|
2367
|
-
AXLoadingModule,
|
|
2368
3057
|
AXBreadcrumbsModule,
|
|
2369
3058
|
AXBadgeModule,
|
|
2370
3059
|
AXSearchBoxModule,
|
|
@@ -2389,8 +3078,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2389
3078
|
useExisting: AXPLayoutDetailsViewComponent,
|
|
2390
3079
|
},
|
|
2391
3080
|
AXPLayoutDetailsViewViewModel,
|
|
2392
|
-
], 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\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 pageContentTrackKey($any(item), $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"] }]
|
|
2393
|
-
}], 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 }] }] } });
|
|
2394
3083
|
|
|
2395
3084
|
//#region ---- Details View Can Deactivate Guard ----
|
|
2396
3085
|
/**
|
|
@@ -2403,5 +3092,5 @@ const axpDetailsViewCanDeactivateGuard = createUnsavedChangesCanDeactivateGuard(
|
|
|
2403
3092
|
* Generated bundle index. Do not edit.
|
|
2404
3093
|
*/
|
|
2405
3094
|
|
|
2406
|
-
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 };
|
|
2407
3096
|
//# sourceMappingURL=acorex-platform-layout-views.mjs.map
|