@acorex/platform 21.0.0-next.76 → 21.0.0-next.79
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-common-common-settings.provider-ChoT4m4k.mjs → acorex-platform-common-common-settings.provider-Ytey9uhY.mjs} +1 -42
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +580 -1445
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-contracts.mjs +1 -1330
- package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +5 -208
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs → acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs} +3 -3
- package/fesm2022/{acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs.map → acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-layout-entity-file-list-popup.component-_yrP5SQe.mjs → acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs} +4 -4
- package/fesm2022/{acorex-platform-layout-entity-file-list-popup.component-_yrP5SQe.mjs.map → acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs.map} +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +694 -733
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +171 -372
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +103 -3
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +116 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +6 -11
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs → acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs} +3 -2
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +52 -643
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +8 -5
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-common.d.ts +1056 -337
- package/types/acorex-platform-contracts.d.ts +4 -1679
- package/types/acorex-platform-core.d.ts +181 -92
- package/types/acorex-platform-layout-components.d.ts +1 -2
- package/types/acorex-platform-layout-entity.d.ts +221 -99
- package/types/acorex-platform-layout-views.d.ts +5 -39
- package/types/acorex-platform-layout-widget-core.d.ts +3 -2
- package/types/acorex-platform-layout-widgets.d.ts +4 -11
- package/types/acorex-platform-themes-default.d.ts +57 -120
- package/types/acorex-platform-workflow.d.ts +18 -5
- package/fesm2022/acorex-platform-common-common-settings.provider-ChoT4m4k.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +0 -513
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.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,
|
|
4
|
+
import { inject, viewChild, afterNextRender, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, signal, computed, Injectable, input, output, ViewContainerRef, Directive, DestroyRef, ElementRef, untracked } 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 {
|
|
15
|
+
import { AXPStickyDirective, AXPCommonSettings, AXPHomePageService, AXPSettingsService, axpNavigateAppPath, AXPEntityCommandScope, axpIsEntityDetailsViewRoute, AXPUnsavedChangesConfirmService, AXPUnsavedChangesPopstateService, createUnsavedChangesCanDeactivateGuard } from '@acorex/platform/common';
|
|
16
16
|
import * as i8 from '@acorex/platform/core';
|
|
17
|
-
import { AXPDeviceService, AXPComponentSlotModule, getSmart, AXPExpressionEvaluatorService,
|
|
17
|
+
import { AXPDeviceService, AXPComponentSlotModule, getSmart, AXPExpressionEvaluatorService, AXPContextStore, normalizeKeyboardShortcuts, AXPBroadcastEventService, AXPKeyboardShortcutRegistry, 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,11 +28,11 @@ 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 { Router, ActivatedRoute } from '@angular/router';
|
|
32
31
|
import { isEmpty, cloneDeep, get } from 'lodash-es';
|
|
33
32
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
34
33
|
import * as i6$1 from '@acorex/platform/layout/widget-core';
|
|
35
34
|
import { AXPPageStatus, AXPWidgetContainerComponent, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
35
|
+
import { Router, ActivatedRoute } from '@angular/router';
|
|
36
36
|
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
|
37
37
|
import { AXBadgeModule } from '@acorex/components/badge';
|
|
38
38
|
import { AXButtonGroupModule } from '@acorex/components/button-group';
|
|
@@ -55,7 +55,6 @@ class AXPPageLayoutComponent {
|
|
|
55
55
|
this.page = inject(AXPPageLayoutBase, { optional: true });
|
|
56
56
|
this.layoutService = inject(AXPLayoutThemeService);
|
|
57
57
|
this.deviceService = inject(AXPDeviceService);
|
|
58
|
-
this.tabNavigation = inject(AXPTabNavigationService);
|
|
59
58
|
this.startSideDrawer = viewChild('startSideDrawer', ...(ngDevMode ? [{ debugName: "startSideDrawer" }] : /* istanbul ignore next */ []));
|
|
60
59
|
this.workflow = inject(AXPWorkflowService);
|
|
61
60
|
this.commandService = inject(AXPCommandService);
|
|
@@ -219,55 +218,11 @@ class AXPPageLayoutBaseComponent {
|
|
|
219
218
|
this.homePageService = inject(AXPHomePageService);
|
|
220
219
|
this.policyService = inject(AXPPolicyEngineService);
|
|
221
220
|
this.settingsService = inject(AXPSettingsService);
|
|
222
|
-
this.tabNavigation = inject(AXPTabNavigationService);
|
|
223
|
-
this.tabPreviewService = inject(AXPTabPreviewService);
|
|
224
|
-
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
225
|
-
this.router = inject(Router);
|
|
226
221
|
//#endregion
|
|
227
222
|
//#region ---------------- Signal to force recomputation ----------------
|
|
228
223
|
this._updateTrigger = signal(0, ...(ngDevMode ? [{ debugName: "_updateTrigger" }] : /* istanbul ignore next */ []));
|
|
229
|
-
/** Tab key captured at page init — stable while the route instance is cached. */
|
|
230
|
-
this.pageTabKey = signal(null, ...(ngDevMode ? [{ debugName: "pageTabKey" }] : /* istanbul ignore next */ []));
|
|
231
224
|
this.updateTrigger = this._updateTrigger.asReadonly();
|
|
232
225
|
//#endregion
|
|
233
|
-
//#region ---------------- Tab Title Sync ----------------
|
|
234
|
-
/** Refreshes tab title when this cached page becomes the active tab again. */
|
|
235
|
-
this.#syncTabTitleOnActivate = effect(() => {
|
|
236
|
-
const activeKey = this.tabNavigation.activeKey();
|
|
237
|
-
const pageKey = this.pageTabKey();
|
|
238
|
-
if (!activeKey || !pageKey || activeKey !== pageKey) {
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (this.tabNavigation.effectiveMode() !== 'tabular') {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
untracked(() => {
|
|
245
|
-
this.recompute();
|
|
246
|
-
});
|
|
247
|
-
}, ...(ngDevMode ? [{ debugName: "#syncTabTitleOnActivate" }] : /* istanbul ignore next */ []));
|
|
248
|
-
/** Publishes structured tab preview (hover card + dirty badge) for this cached page. */
|
|
249
|
-
this.#syncTabStructuredPreview = effect(() => {
|
|
250
|
-
this.updateTrigger();
|
|
251
|
-
const tabKey = this.pageTabKey();
|
|
252
|
-
const titleValue = this.title();
|
|
253
|
-
const descriptionValue = this.description();
|
|
254
|
-
const icon = this.titleIcon();
|
|
255
|
-
const breadcrumbItems = this.breadcrumbs();
|
|
256
|
-
if (!tabKey || this.tabNavigation.effectiveMode() !== 'tabular') {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
const isDirty = this.hasUnsavedChanges();
|
|
260
|
-
untracked(() => {
|
|
261
|
-
void this.publishTabStructuredPreview(tabKey, {
|
|
262
|
-
titleValue,
|
|
263
|
-
descriptionValue,
|
|
264
|
-
icon,
|
|
265
|
-
breadcrumbItems,
|
|
266
|
-
isDirty,
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
}, ...(ngDevMode ? [{ debugName: "#syncTabStructuredPreview" }] : /* istanbul ignore next */ []));
|
|
270
|
-
//#endregion
|
|
271
226
|
//#region ---------------- Title ----------------
|
|
272
227
|
this.title = signal('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
273
228
|
this.titleIcon = signal(null, ...(ngDevMode ? [{ debugName: "titleIcon" }] : /* istanbul ignore next */ []));
|
|
@@ -276,12 +231,6 @@ class AXPPageLayoutBaseComponent {
|
|
|
276
231
|
this.title.set(await this.getPageTitle());
|
|
277
232
|
const icon = await this.getPageIcon();
|
|
278
233
|
this.titleIcon.set(icon);
|
|
279
|
-
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
280
|
-
const tabKey = this.pageTabKey();
|
|
281
|
-
if (tabKey && icon) {
|
|
282
|
-
this.tabNavigation.syncTabIcon(tabKey, icon);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
234
|
}, ...(ngDevMode ? [{ debugName: "#titleEffect" }] : /* istanbul ignore next */ []));
|
|
286
235
|
this.hasTitle = computed(() => {
|
|
287
236
|
const value = this.title();
|
|
@@ -335,20 +284,9 @@ class AXPPageLayoutBaseComponent {
|
|
|
335
284
|
this.#breadcrumbsEffect = effect(async () => {
|
|
336
285
|
this.updateTrigger();
|
|
337
286
|
const breadCrumbs = await this.getPageBreadcrumbs();
|
|
338
|
-
|
|
339
|
-
this.breadcrumbs.set(trail);
|
|
340
|
-
if (this.tabNavigation.effectiveMode() === 'tabular') {
|
|
341
|
-
const tabKey = this.pageTabKey();
|
|
342
|
-
let tabTitle = await this.resolveBreadcrumbTabTitle(breadCrumbs);
|
|
343
|
-
if (!tabTitle) {
|
|
344
|
-
tabTitle = await this.resolvePageTitleForTab();
|
|
345
|
-
}
|
|
346
|
-
if (tabKey && tabTitle) {
|
|
347
|
-
this.tabNavigation.syncTabTitle(tabKey, tabTitle);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
287
|
+
this.breadcrumbs.set([...this.defaultBreadCrumbs, ...breadCrumbs]);
|
|
350
288
|
}, ...(ngDevMode ? [{ debugName: "#breadcrumbsEffect" }] : /* istanbul ignore next */ []));
|
|
351
|
-
this.hasBreadcrumbs = computed(() => this.breadcrumbs().length > 1
|
|
289
|
+
this.hasBreadcrumbs = computed(() => this.breadcrumbs().length > 1, ...(ngDevMode ? [{ debugName: "hasBreadcrumbs" }] : /* istanbul ignore next */ []));
|
|
352
290
|
//#endregion
|
|
353
291
|
//#region ---------------- Badge ----------------
|
|
354
292
|
this.badge = signal(null, ...(ngDevMode ? [{ debugName: "badge" }] : /* istanbul ignore next */ []));
|
|
@@ -404,75 +342,10 @@ class AXPPageLayoutBaseComponent {
|
|
|
404
342
|
//#endregion
|
|
405
343
|
//#region ---------------- Lifecycle hooks ----------------
|
|
406
344
|
async ngOnInit() {
|
|
407
|
-
this.pageTabKey.set(this.resolvePageTabKey());
|
|
408
345
|
this.translateService.langChanges$.subscribe(() => {
|
|
409
346
|
this.recompute();
|
|
410
347
|
});
|
|
411
348
|
}
|
|
412
|
-
/** Maps the home-page route to the pinned home tab key instead of a path-based key. */
|
|
413
|
-
resolvePageTabKey() {
|
|
414
|
-
const homePath = this.homePageService.getCurrent().path;
|
|
415
|
-
if (homePath && normalizeRouterUrl(homePath) === normalizeRouterUrl(this.router.url)) {
|
|
416
|
-
return AXP_HOME_TAB_KEY;
|
|
417
|
-
}
|
|
418
|
-
return axpResolveTabKey(this.router);
|
|
419
|
-
}
|
|
420
|
-
//#endregion
|
|
421
|
-
//#region ---------------- Tab Title Sync ----------------
|
|
422
|
-
/** Refreshes tab title when this cached page becomes the active tab again. */
|
|
423
|
-
#syncTabTitleOnActivate;
|
|
424
|
-
/** Publishes structured tab preview (hover card + dirty badge) for this cached page. */
|
|
425
|
-
#syncTabStructuredPreview;
|
|
426
|
-
async publishTabStructuredPreview(tabKey, input) {
|
|
427
|
-
const tab = this.tabNavigation.tabList().find((item) => item.key === tabKey);
|
|
428
|
-
const breadcrumbTrail = [];
|
|
429
|
-
for (const item of input.breadcrumbItems.slice(1)) {
|
|
430
|
-
const segment = await this.resolveBreadcrumbItemTitle(item);
|
|
431
|
-
if (segment && segment !== breadcrumbTrail[breadcrumbTrail.length - 1]) {
|
|
432
|
-
breadcrumbTrail.push(segment);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const fallbackTitle = await this.translateTextIfKey(breadcrumbTrail.join(' - ') || tab?.title || '');
|
|
436
|
-
const title = await this.resolveMultiLanguageText(input.titleValue, fallbackTitle);
|
|
437
|
-
const subtitle = await this.resolveMultiLanguageText(input.descriptionValue, '');
|
|
438
|
-
this.tabPreviewService.setPreview(tabKey, {
|
|
439
|
-
title,
|
|
440
|
-
subtitle: subtitle || undefined,
|
|
441
|
-
url: tab?.url ?? '',
|
|
442
|
-
icon: input.icon ?? tab?.icon,
|
|
443
|
-
isDirty: input.isDirty,
|
|
444
|
-
breadcrumbTrail,
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
async resolveMultiLanguageText(value, fallback) {
|
|
448
|
-
const resolvedFallback = await this.translateTextIfKey(fallback);
|
|
449
|
-
if (value == null || value === '') {
|
|
450
|
-
return resolvedFallback;
|
|
451
|
-
}
|
|
452
|
-
if (typeof value === 'string') {
|
|
453
|
-
const trimmed = value.trim();
|
|
454
|
-
if (!trimmed) {
|
|
455
|
-
return resolvedFallback;
|
|
456
|
-
}
|
|
457
|
-
if (trimmed.startsWith('@')) {
|
|
458
|
-
return (await this.translateService.translateAsync(trimmed)) || resolvedFallback;
|
|
459
|
-
}
|
|
460
|
-
return trimmed;
|
|
461
|
-
}
|
|
462
|
-
const resolved = this.translateService.resolve(value);
|
|
463
|
-
return resolved || resolvedFallback;
|
|
464
|
-
}
|
|
465
|
-
/** Resolves i18n keys (`@scope:key`); returns plain text unchanged. */
|
|
466
|
-
async translateTextIfKey(text) {
|
|
467
|
-
const trimmed = text.trim();
|
|
468
|
-
if (!trimmed) {
|
|
469
|
-
return '';
|
|
470
|
-
}
|
|
471
|
-
if (trimmed.startsWith('@')) {
|
|
472
|
-
return (await this.translateService.translateAsync(trimmed)) || trimmed;
|
|
473
|
-
}
|
|
474
|
-
return trimmed;
|
|
475
|
-
}
|
|
476
349
|
#titleEffect;
|
|
477
350
|
getPageTitle() {
|
|
478
351
|
return '';
|
|
@@ -488,78 +361,10 @@ class AXPPageLayoutBaseComponent {
|
|
|
488
361
|
getPageBreadcrumbs() {
|
|
489
362
|
return [];
|
|
490
363
|
}
|
|
491
|
-
/** Joins all page breadcrumbs (Home is excluded upstream) as the tab label. */
|
|
492
|
-
async resolveBreadcrumbTabTitle(pageBreadcrumbs) {
|
|
493
|
-
const segments = [];
|
|
494
|
-
for (const item of pageBreadcrumbs) {
|
|
495
|
-
const title = await this.resolveBreadcrumbItemTitle(item);
|
|
496
|
-
if (title && title !== segments[segments.length - 1]) {
|
|
497
|
-
segments.push(title);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
if (!segments.length) {
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
return segments.join(' - ');
|
|
504
|
-
}
|
|
505
|
-
/** Resolves a breadcrumb label the same way as page chrome (`t(item.title)`). */
|
|
506
|
-
async resolveBreadcrumbItemTitle(item) {
|
|
507
|
-
const raw = item?.title;
|
|
508
|
-
if (raw == null || raw === '') {
|
|
509
|
-
return null;
|
|
510
|
-
}
|
|
511
|
-
if (typeof raw === 'string') {
|
|
512
|
-
const trimmed = raw.trim();
|
|
513
|
-
if (!trimmed) {
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
|
-
if (trimmed.startsWith('@')) {
|
|
517
|
-
return (await this.translateService.translateAsync(trimmed)) || trimmed;
|
|
518
|
-
}
|
|
519
|
-
return trimmed;
|
|
520
|
-
}
|
|
521
|
-
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
522
|
-
if (this.translateService.isValidMultiLanguageObject(raw)) {
|
|
523
|
-
const resolved = this.translateService.resolve(raw);
|
|
524
|
-
return resolved || null;
|
|
525
|
-
}
|
|
526
|
-
const resolved = this.translateService.resolve(raw);
|
|
527
|
-
return resolved || null;
|
|
528
|
-
}
|
|
529
|
-
return String(raw);
|
|
530
|
-
}
|
|
531
|
-
/** Fallback tab label from the page title when breadcrumbs are not ready yet. */
|
|
532
|
-
async resolvePageTitleForTab() {
|
|
533
|
-
const raw = await Promise.resolve(this.getPageTitle());
|
|
534
|
-
if (raw == null || raw === '') {
|
|
535
|
-
return null;
|
|
536
|
-
}
|
|
537
|
-
if (typeof raw === 'string') {
|
|
538
|
-
const trimmed = raw.trim();
|
|
539
|
-
if (trimmed.startsWith('@')) {
|
|
540
|
-
return (await this.translateService.translateAsync(trimmed)) || trimmed;
|
|
541
|
-
}
|
|
542
|
-
return trimmed;
|
|
543
|
-
}
|
|
544
|
-
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
545
|
-
const resolved = this.translateService.resolve(raw);
|
|
546
|
-
return resolved || null;
|
|
547
|
-
}
|
|
548
|
-
return null;
|
|
549
|
-
}
|
|
550
364
|
#badgeEffect;
|
|
551
365
|
hasUnsavedChanges() {
|
|
552
366
|
return false;
|
|
553
367
|
}
|
|
554
|
-
/**
|
|
555
|
-
* Confirms closing this page as a background tab (no router navigation).
|
|
556
|
-
* Override when dirty detection differs from {@link hasUnsavedChanges}.
|
|
557
|
-
*/
|
|
558
|
-
onBeforeTabClose() {
|
|
559
|
-
return this.unsavedChangesConfirm.confirmIfDirty(this.hasUnsavedChanges(), {
|
|
560
|
-
approveLeaveOnConfirm: false,
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
368
|
async getPageBadge() {
|
|
564
369
|
if (!this.hasUnsavedChanges()) {
|
|
565
370
|
return null;
|
|
@@ -870,63 +675,14 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
870
675
|
const evaluatedByTab = store.evaluatedTabContentsById();
|
|
871
676
|
return evaluatedByTab[tab.id] ?? [];
|
|
872
677
|
}),
|
|
873
|
-
})), withMethods((store, evaluatorService = inject(AXPExpressionEvaluatorService),
|
|
874
|
-
const
|
|
875
|
-
if (pageId) {
|
|
876
|
-
return adapter.pages.find((p) => p.id === pageId) ?? null;
|
|
877
|
-
}
|
|
878
|
-
if (deviceService.isLarge() || adapter.pages.length === 1) {
|
|
879
|
-
return adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0] ?? null;
|
|
880
|
-
}
|
|
881
|
-
return null;
|
|
882
|
-
};
|
|
883
|
-
/** Loads page data, context, and evaluated widgets for the target sidebar page. */
|
|
884
|
-
const activatePageById = async (pageId, forceRefresh) => {
|
|
885
|
-
const adapter = store.adapter();
|
|
886
|
-
if (!adapter) {
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
889
|
-
const queryParams = router.routerState.snapshot.root.queryParams;
|
|
890
|
-
const targetPageId = pageId ?? queryParams['page'];
|
|
891
|
-
const currentPage = resolvePageFromId(adapter, targetPageId);
|
|
892
|
-
if (!forceRefresh &&
|
|
893
|
-
currentPage?.id === store.currentPage()?.id &&
|
|
894
|
-
store.status() === AXPPageStatus.Rendered) {
|
|
895
|
-
return;
|
|
896
|
-
}
|
|
897
|
-
patchState(store, {
|
|
898
|
-
status: AXPPageStatus.Processing,
|
|
899
|
-
});
|
|
900
|
-
let context = {};
|
|
901
|
-
if (currentPage) {
|
|
902
|
-
const currentPageIndex = adapter.pages.findIndex((p) => p.id === currentPage.id);
|
|
903
|
-
const loadResult = await adapter.pages[currentPageIndex]?.load?.({ forceRefresh });
|
|
904
|
-
context = loadResult?.data ?? {};
|
|
905
|
-
}
|
|
906
|
-
const currentTab = currentPage?.tabs?.[0] ?? null;
|
|
678
|
+
})), withMethods((store, evaluatorService = inject(AXPExpressionEvaluatorService), router = inject(Router), route = inject(ActivatedRoute), deviceService = inject(AXPDeviceService), formatService = inject(AXFormatService), toastService = inject(AXToastService), translateService = inject(AXTranslationService), settingsService = inject(AXPSettingsService)) => {
|
|
679
|
+
const refreshEvaluatedPageContents = async (page) => {
|
|
907
680
|
const rootCtx = store.rootContext();
|
|
908
|
-
const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(
|
|
681
|
+
const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(page, rootCtx, evaluatorService);
|
|
909
682
|
patchState(store, {
|
|
910
|
-
previousContext: cloneDeep(context),
|
|
911
|
-
context: cloneDeep(context),
|
|
912
|
-
status: AXPPageStatus.Rendered,
|
|
913
|
-
currentPage,
|
|
914
|
-
currentTab,
|
|
915
683
|
evaluatedPageContent,
|
|
916
684
|
evaluatedTabContentsById,
|
|
917
|
-
formDirty: false,
|
|
918
685
|
});
|
|
919
|
-
if (currentPage && axpIsEntityDetailsViewRoute(router)) {
|
|
920
|
-
const pageParam = route.snapshot.queryParamMap.get('page');
|
|
921
|
-
if (pageParam !== currentPage.id) {
|
|
922
|
-
router.navigate([], {
|
|
923
|
-
relativeTo: route,
|
|
924
|
-
queryParams: { page: currentPage.id },
|
|
925
|
-
queryParamsHandling: 'merge',
|
|
926
|
-
replaceUrl: true,
|
|
927
|
-
});
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
686
|
};
|
|
931
687
|
// Sync sidebar page from route query params
|
|
932
688
|
effect((onCleanup) => {
|
|
@@ -934,20 +690,30 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
934
690
|
return;
|
|
935
691
|
}
|
|
936
692
|
const subscription = route.queryParams.subscribe((params) => {
|
|
693
|
+
const pageId = params['page'];
|
|
937
694
|
const adapter = store.adapter();
|
|
938
695
|
if (!adapter) {
|
|
939
696
|
return;
|
|
940
697
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
return;
|
|
698
|
+
let currentPage = null;
|
|
699
|
+
if (pageId) {
|
|
700
|
+
currentPage = adapter.pages.find((p) => p.id === pageId) ?? null;
|
|
945
701
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
702
|
+
else if (deviceService.isLarge() || adapter.pages.length === 1) {
|
|
703
|
+
currentPage = adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0];
|
|
704
|
+
}
|
|
705
|
+
const currentTab = currentPage?.tabs?.[0] ?? null;
|
|
706
|
+
if (store.currentPage()?.id !== currentPage?.id) {
|
|
707
|
+
// `load()` → `loadPage` owns initial hydration when both sides are still null.
|
|
708
|
+
if (store.currentPage() == null && currentPage == null) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
patchState(store, {
|
|
712
|
+
currentPage,
|
|
713
|
+
currentTab,
|
|
714
|
+
});
|
|
715
|
+
void refreshEvaluatedPageContents(currentPage);
|
|
949
716
|
}
|
|
950
|
-
void activatePageById(targetPage?.id);
|
|
951
717
|
});
|
|
952
718
|
onCleanup(() => subscription.unsubscribe());
|
|
953
719
|
});
|
|
@@ -1008,12 +774,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1008
774
|
evaluated = await evaluatorService.evaluate(raw, evalScope);
|
|
1009
775
|
}
|
|
1010
776
|
else if (typeof sourceAfterPreLocale === 'string') {
|
|
1011
|
-
|
|
1012
|
-
evaluated = await translateService.translateAsync(sourceAfterPreLocale);
|
|
1013
|
-
}
|
|
1014
|
-
else {
|
|
1015
|
-
evaluated = await formatService.format(sourceAfterPreLocale, 'string', formatContext);
|
|
1016
|
-
}
|
|
777
|
+
evaluated = await formatService.format(sourceAfterPreLocale, 'string', formatContext);
|
|
1017
778
|
}
|
|
1018
779
|
else {
|
|
1019
780
|
evaluated = await formatService.format(raw, 'string', formatContext);
|
|
@@ -1047,12 +808,71 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1047
808
|
});
|
|
1048
809
|
},
|
|
1049
810
|
async loadPage(pageId, forceRefresh) {
|
|
1050
|
-
|
|
811
|
+
const adapter = store.adapter();
|
|
812
|
+
if (!adapter) {
|
|
813
|
+
throw new Error('Adapter must be loaded before loading page');
|
|
814
|
+
}
|
|
815
|
+
patchState(store, {
|
|
816
|
+
status: AXPPageStatus.Processing,
|
|
817
|
+
});
|
|
818
|
+
// Get page ID from parameter or query params
|
|
819
|
+
const queryParams = router.routerState.snapshot.root.queryParams;
|
|
820
|
+
const targetPageId = pageId || queryParams['page'];
|
|
821
|
+
// Find current page from page ID or conditionally default to first page
|
|
822
|
+
let currentPage = null;
|
|
823
|
+
if (targetPageId) {
|
|
824
|
+
const foundPage = adapter.pages.find((p) => p.id === targetPageId);
|
|
825
|
+
if (foundPage) {
|
|
826
|
+
currentPage = foundPage;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
else {
|
|
830
|
+
// Only auto-select primary page if layout is large
|
|
831
|
+
if (deviceService.isLarge() || adapter.pages.length == 1) {
|
|
832
|
+
const primaryPage = adapter.pages.find((p) => p.isPrimary) ?? adapter.pages[0];
|
|
833
|
+
currentPage = primaryPage;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// Load page data if current page exists
|
|
837
|
+
let context = {};
|
|
838
|
+
if (currentPage) {
|
|
839
|
+
const currentPageIndex = adapter.pages.findIndex((p) => p.id === currentPage.id);
|
|
840
|
+
const loadResult = await adapter.pages[currentPageIndex]?.load?.({ forceRefresh });
|
|
841
|
+
context = loadResult?.data ?? {};
|
|
842
|
+
}
|
|
843
|
+
// Set current tab to first tab of the current page (internal state only)
|
|
844
|
+
let currentTab = currentPage?.tabs?.[0] ?? null;
|
|
845
|
+
const rootCtx = store.rootContext();
|
|
846
|
+
const { evaluatedPageContent, evaluatedTabContentsById } = await buildEvaluatedPageContentsForRootContext(currentPage, rootCtx, evaluatorService);
|
|
847
|
+
patchState(store, {
|
|
848
|
+
previousContext: cloneDeep(context),
|
|
849
|
+
context: cloneDeep(context),
|
|
850
|
+
status: AXPPageStatus.Rendered,
|
|
851
|
+
currentPage,
|
|
852
|
+
currentTab,
|
|
853
|
+
evaluatedPageContent,
|
|
854
|
+
evaluatedTabContentsById,
|
|
855
|
+
formDirty: false,
|
|
856
|
+
});
|
|
857
|
+
if (currentPage && axpIsEntityDetailsViewRoute(router)) {
|
|
858
|
+
const pageParam = route.snapshot.queryParamMap.get('page');
|
|
859
|
+
if (pageParam !== currentPage.id) {
|
|
860
|
+
router.navigate([], {
|
|
861
|
+
relativeTo: route,
|
|
862
|
+
queryParams: { page: currentPage.id },
|
|
863
|
+
queryParamsHandling: 'merge',
|
|
864
|
+
replaceUrl: true,
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
}
|
|
1051
868
|
},
|
|
1052
869
|
async load(adapter) {
|
|
870
|
+
// Setup expression evaluator scope
|
|
1053
871
|
const scope = {
|
|
1054
872
|
context: {
|
|
1055
|
-
|
|
873
|
+
eval: (path) => {
|
|
874
|
+
return getSmart(store.context(), path);
|
|
875
|
+
},
|
|
1056
876
|
isDirty: () => store.isDirty(),
|
|
1057
877
|
},
|
|
1058
878
|
};
|
|
@@ -1131,8 +951,14 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1131
951
|
setCurrentPage(page) {
|
|
1132
952
|
const previousPage = store.currentPage();
|
|
1133
953
|
if (page) {
|
|
954
|
+
const firstTab = page.tabs?.[0] ?? null;
|
|
1134
955
|
const pageParam = route.snapshot.queryParamMap.get('page');
|
|
1135
956
|
const isSamePage = previousPage?.id === page.id && pageParam === page.id;
|
|
957
|
+
patchState(store, {
|
|
958
|
+
currentPage: page,
|
|
959
|
+
currentTab: firstTab,
|
|
960
|
+
...(page.isReadonly ? { formDirty: false } : {}),
|
|
961
|
+
});
|
|
1136
962
|
if (!isSamePage && axpIsEntityDetailsViewRoute(router)) {
|
|
1137
963
|
const queryParams = { page: page.id };
|
|
1138
964
|
if (previousPage?.id && previousPage.id !== page.id) {
|
|
@@ -1146,7 +972,7 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1146
972
|
replaceUrl: false,
|
|
1147
973
|
});
|
|
1148
974
|
}
|
|
1149
|
-
void
|
|
975
|
+
void refreshEvaluatedPageContents(page);
|
|
1150
976
|
}
|
|
1151
977
|
else {
|
|
1152
978
|
patchState(store, {
|
|
@@ -1281,7 +1107,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1281
1107
|
},
|
|
1282
1108
|
async discard() {
|
|
1283
1109
|
patchState(store, {
|
|
1284
|
-
context: cloneDeep(store.previousContext()),
|
|
1285
1110
|
formDirty: false,
|
|
1286
1111
|
});
|
|
1287
1112
|
},
|
|
@@ -1382,66 +1207,6 @@ const AXPLayoutDetailsViewViewModel = signalStore(withState(() => {
|
|
|
1382
1207
|
};
|
|
1383
1208
|
}));
|
|
1384
1209
|
|
|
1385
|
-
//#region ---- Details View Action Shortcut Utilities ----
|
|
1386
|
-
/** Platform defaults for known entity detail commands when `shortcuts` is omitted on the action. */
|
|
1387
|
-
const DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS = {
|
|
1388
|
-
'delete-entity': ['ctrl+shift+delete'],
|
|
1389
|
-
};
|
|
1390
|
-
const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
|
|
1391
|
-
'update-entity': ['ctrl+s'],
|
|
1392
|
-
discard: ['escape'],
|
|
1393
|
-
};
|
|
1394
|
-
/**
|
|
1395
|
-
* Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
|
|
1396
|
-
*/
|
|
1397
|
-
function getDetailsViewActionCommandBaseName(commandName) {
|
|
1398
|
-
if (!commandName) {
|
|
1399
|
-
return '';
|
|
1400
|
-
}
|
|
1401
|
-
return commandName.split('&')[0];
|
|
1402
|
-
}
|
|
1403
|
-
/**
|
|
1404
|
-
* Resolves keyboard shortcuts for a header entity action.
|
|
1405
|
-
* Explicit `shortcuts` wins; pass `[]` to disable. Otherwise known commands use platform defaults.
|
|
1406
|
-
*/
|
|
1407
|
-
function resolveDetailsViewActionShortcuts(commandBaseName, explicit) {
|
|
1408
|
-
if (explicit !== undefined) {
|
|
1409
|
-
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1410
|
-
return chords.length ? chords : undefined;
|
|
1411
|
-
}
|
|
1412
|
-
const defaults = DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS[commandBaseName];
|
|
1413
|
-
return defaults?.length ? [...defaults] : undefined;
|
|
1414
|
-
}
|
|
1415
|
-
/**
|
|
1416
|
-
* Resolves save/discard footer command shortcuts from page settings.
|
|
1417
|
-
*/
|
|
1418
|
-
function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
|
|
1419
|
-
if (explicit !== undefined) {
|
|
1420
|
-
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1421
|
-
return chords.length ? chords : undefined;
|
|
1422
|
-
}
|
|
1423
|
-
const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
|
|
1424
|
-
return defaults?.length ? [...defaults] : undefined;
|
|
1425
|
-
}
|
|
1426
|
-
function flattenDetailsViewActionShortcuts(shortcuts) {
|
|
1427
|
-
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
1428
|
-
return dedupeDetailsViewActionShortcuts(chords);
|
|
1429
|
-
}
|
|
1430
|
-
function dedupeDetailsViewActionShortcuts(shortcuts) {
|
|
1431
|
-
const seen = new Set();
|
|
1432
|
-
const result = [];
|
|
1433
|
-
for (const shortcut of shortcuts) {
|
|
1434
|
-
const token = shortcut.trim().toLowerCase();
|
|
1435
|
-
if (!token || seen.has(token)) {
|
|
1436
|
-
continue;
|
|
1437
|
-
}
|
|
1438
|
-
seen.add(token);
|
|
1439
|
-
result.push(shortcut.trim());
|
|
1440
|
-
}
|
|
1441
|
-
return result;
|
|
1442
|
-
}
|
|
1443
|
-
//#endregion
|
|
1444
|
-
|
|
1445
1210
|
/**
|
|
1446
1211
|
* Registry of rendered page component instances by component key.
|
|
1447
1212
|
* Used so page execute can delegate to the actual component instance in the view.
|
|
@@ -1580,15 +1345,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1580
1345
|
}]
|
|
1581
1346
|
}], propDecorators: { componentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentKey", required: true }] }], rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: false }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], componentReady: [{ type: i0.Output, args: ["componentReady"] }] } });
|
|
1582
1347
|
|
|
1348
|
+
//#region ---- Details View Action Shortcut Utilities ----
|
|
1349
|
+
/** Platform defaults for known entity detail commands when `shortcuts` is omitted on the action. */
|
|
1350
|
+
const DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS = {
|
|
1351
|
+
'delete-entity': ['ctrl+shift+delete'],
|
|
1352
|
+
};
|
|
1353
|
+
const DEFAULT_FOOTER_COMMAND_SHORTCUTS = {
|
|
1354
|
+
'update-entity': ['ctrl+s'],
|
|
1355
|
+
discard: ['escape'],
|
|
1356
|
+
};
|
|
1357
|
+
/**
|
|
1358
|
+
* Returns the base workflow/command name from a composite entity action command id (`cmd&actionName`).
|
|
1359
|
+
*/
|
|
1360
|
+
function getDetailsViewActionCommandBaseName(commandName) {
|
|
1361
|
+
if (!commandName) {
|
|
1362
|
+
return '';
|
|
1363
|
+
}
|
|
1364
|
+
return commandName.split('&')[0];
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Resolves keyboard shortcuts for a header entity action.
|
|
1368
|
+
* Explicit `shortcuts` wins; pass `[]` to disable. Otherwise known commands use platform defaults.
|
|
1369
|
+
*/
|
|
1370
|
+
function resolveDetailsViewActionShortcuts(commandBaseName, explicit) {
|
|
1371
|
+
if (explicit !== undefined) {
|
|
1372
|
+
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1373
|
+
return chords.length ? chords : undefined;
|
|
1374
|
+
}
|
|
1375
|
+
const defaults = DEFAULT_ENTITY_DETAIL_ACTION_SHORTCUTS[commandBaseName];
|
|
1376
|
+
return defaults?.length ? [...defaults] : undefined;
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Resolves save/discard footer command shortcuts from page settings.
|
|
1380
|
+
*/
|
|
1381
|
+
function resolveDetailsViewFooterCommandShortcuts(commandName, explicit) {
|
|
1382
|
+
if (explicit !== undefined) {
|
|
1383
|
+
const chords = flattenDetailsViewActionShortcuts(explicit);
|
|
1384
|
+
return chords.length ? chords : undefined;
|
|
1385
|
+
}
|
|
1386
|
+
const defaults = DEFAULT_FOOTER_COMMAND_SHORTCUTS[commandName];
|
|
1387
|
+
return defaults?.length ? [...defaults] : undefined;
|
|
1388
|
+
}
|
|
1389
|
+
function flattenDetailsViewActionShortcuts(shortcuts) {
|
|
1390
|
+
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
1391
|
+
return dedupeDetailsViewActionShortcuts(chords);
|
|
1392
|
+
}
|
|
1393
|
+
function dedupeDetailsViewActionShortcuts(shortcuts) {
|
|
1394
|
+
const seen = new Set();
|
|
1395
|
+
const result = [];
|
|
1396
|
+
for (const shortcut of shortcuts) {
|
|
1397
|
+
const token = shortcut.trim().toLowerCase();
|
|
1398
|
+
if (!token || seen.has(token)) {
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
seen.add(token);
|
|
1402
|
+
result.push(shortcut.trim());
|
|
1403
|
+
}
|
|
1404
|
+
return result;
|
|
1405
|
+
}
|
|
1406
|
+
//#endregion
|
|
1407
|
+
|
|
1583
1408
|
class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
1584
1409
|
constructor() {
|
|
1585
1410
|
super(...arguments);
|
|
1586
1411
|
this.adapter = input.required(...(ngDevMode ? [{ debugName: "adapter" }] : /* istanbul ignore next */ []));
|
|
1587
1412
|
//
|
|
1588
1413
|
this.vm = inject(AXPLayoutDetailsViewViewModel);
|
|
1414
|
+
this.router = inject(Router);
|
|
1589
1415
|
this.route = inject(ActivatedRoute);
|
|
1590
1416
|
this.eventService = inject(AXPBroadcastEventService);
|
|
1591
1417
|
this.deviceService = inject(AXPDeviceService);
|
|
1418
|
+
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
1592
1419
|
this.unsavedChangesPopstate = inject(AXPUnsavedChangesPopstateService);
|
|
1593
1420
|
this.pageComponentInstanceRegistry = inject(AXPPageComponentInstanceRegistryService);
|
|
1594
1421
|
this.shortcutRegistry = inject(AXPKeyboardShortcutRegistry);
|
|
@@ -1837,17 +1664,11 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1837
1664
|
}
|
|
1838
1665
|
finalizeDiscard() {
|
|
1839
1666
|
const container = this.widgetContainer();
|
|
1840
|
-
if (container) {
|
|
1841
|
-
container.revertAndSettle();
|
|
1842
|
-
this.vm.applySavedState(container.contextService.data());
|
|
1667
|
+
if (!container) {
|
|
1843
1668
|
return;
|
|
1844
1669
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
/** Reverts widget form state and view-model context to the last saved baseline. */
|
|
1848
|
-
async discardUnsavedChanges() {
|
|
1849
|
-
this.finalizeDiscard();
|
|
1850
|
-
this.recompute();
|
|
1670
|
+
container.revertAndSettle();
|
|
1671
|
+
this.vm.applySavedState(container.contextService.data());
|
|
1851
1672
|
}
|
|
1852
1673
|
/**
|
|
1853
1674
|
* `ax-tabs` selects on click before we can confirm. Revert synchronously, then confirm + switch.
|
|
@@ -1943,15 +1764,6 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1943
1764
|
async getBackButton() {
|
|
1944
1765
|
return this.vm.getBackButton();
|
|
1945
1766
|
}
|
|
1946
|
-
hasUnsavedChanges() {
|
|
1947
|
-
if (this.vm.currentPage()?.isReadonly) {
|
|
1948
|
-
return false;
|
|
1949
|
-
}
|
|
1950
|
-
if (this.isActivePageComponentDirty()) {
|
|
1951
|
-
return true;
|
|
1952
|
-
}
|
|
1953
|
-
return this.liveFormIsDirty();
|
|
1954
|
-
}
|
|
1955
1767
|
async getPageBadge() {
|
|
1956
1768
|
if (this.vm.currentPage()?.isReadonly) {
|
|
1957
1769
|
return null;
|
|
@@ -1996,12 +1808,6 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
1996
1808
|
}
|
|
1997
1809
|
return this.confirmLeaveIfDirty();
|
|
1998
1810
|
}
|
|
1999
|
-
/** Background tab close — confirm without discarding (the cached instance is destroyed). */
|
|
2000
|
-
onBeforeTabClose() {
|
|
2001
|
-
return this.unsavedChangesConfirm.confirmIfDirty(this.shouldPromptLeave(), {
|
|
2002
|
-
approveLeaveOnConfirm: false,
|
|
2003
|
-
});
|
|
2004
|
-
}
|
|
2005
1811
|
/** Active entity component page instance, when the current details sub-page is component-based. */
|
|
2006
1812
|
getActivePageComponentInstance() {
|
|
2007
1813
|
const componentKey = this.getActivePageComponentKey();
|
|
@@ -2026,12 +1832,6 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2026
1832
|
static isComponentPageContent(item) {
|
|
2027
1833
|
return 'type' in item && item.type === 'component';
|
|
2028
1834
|
}
|
|
2029
|
-
pageContentTrackKey(item, index) {
|
|
2030
|
-
if (AXPLayoutDetailsViewComponent.isComponentPageContent(item)) {
|
|
2031
|
-
return `component:${item.componentKey}`;
|
|
2032
|
-
}
|
|
2033
|
-
return item.name ?? `widget:${index}`;
|
|
2034
|
-
}
|
|
2035
1835
|
/** Whether the active component-based entity page has unsaved edits. */
|
|
2036
1836
|
isActivePageComponentDirty() {
|
|
2037
1837
|
return this.getActivePageComponentInstance()?.hasUnsavedChanges() ?? false;
|
|
@@ -2047,13 +1847,8 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2047
1847
|
return this.liveFormIsDirty();
|
|
2048
1848
|
}
|
|
2049
1849
|
/** Single gate for leaving the page or switching details sub-pages when dirty. */
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
const confirmed = await this.unsavedChangesConfirm.confirmIfDirty(shouldPrompt);
|
|
2053
|
-
if (confirmed && shouldPrompt) {
|
|
2054
|
-
await this.discardUnsavedChanges();
|
|
2055
|
-
}
|
|
2056
|
-
return confirmed;
|
|
1850
|
+
confirmLeaveIfDirty() {
|
|
1851
|
+
return this.unsavedChangesConfirm.confirmIfDirty(this.shouldPromptLeave());
|
|
2057
1852
|
}
|
|
2058
1853
|
//#endregion
|
|
2059
1854
|
//#region ---- Command Execution ----
|
|
@@ -2072,7 +1867,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2072
1867
|
return;
|
|
2073
1868
|
}
|
|
2074
1869
|
if (command.name == rejectCommand) {
|
|
2075
|
-
await this.
|
|
1870
|
+
await this.vm.discard();
|
|
1871
|
+
this.finalizeDiscard();
|
|
1872
|
+
this.recompute();
|
|
2076
1873
|
return;
|
|
2077
1874
|
}
|
|
2078
1875
|
// Handle status update command
|
|
@@ -2135,7 +1932,9 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2135
1932
|
return;
|
|
2136
1933
|
}
|
|
2137
1934
|
if (isDiscardCommand(command.name, rejectCommand)) {
|
|
2138
|
-
await this.
|
|
1935
|
+
await this.vm.discard();
|
|
1936
|
+
this.finalizeDiscard();
|
|
1937
|
+
this.recompute();
|
|
2139
1938
|
return;
|
|
2140
1939
|
}
|
|
2141
1940
|
if (!this.isActivePageComponentDirty()) {
|
|
@@ -2344,7 +2143,7 @@ class AXPLayoutDetailsViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2344
2143
|
useExisting: AXPLayoutDetailsViewComponent,
|
|
2345
2144
|
},
|
|
2346
2145
|
AXPLayoutDetailsViewViewModel,
|
|
2347
|
-
], 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 <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 </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:
|
|
2146
|
+
], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }, { propertyName: "sidebarTabs", first: true, predicate: ["sidebarTabs"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n (formatService.format(vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''), 'string', vm.rootContext())\n | translate\n | async)\n }}</axp-layout-title>\n <axp-layout-description>{{\n (formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async)\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs\n #sidebarTabs\n class=\"axp-vertical-tabs\"\n [look]=\"'with-line-color'\"\n [location]=\"'end'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\"\n >\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item\n [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container\n #widgetsContainerRef\n [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\"\n >\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track $index) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div\n axp-page-component-renderer\n [componentKey]=\"$any(item).componentKey\"\n [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\"\n [options]=\"$any(item).options\"\n (componentReady)=\"recompute()\"\n ></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item\n (onClick)=\"vm.setCurrentTab(tab)\"\n [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n </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:
|
|
2348
2147
|
// Angular
|
|
2349
2148
|
CommonModule }, { kind: "ngmodule", type:
|
|
2350
2149
|
// ACoreX
|
|
@@ -2390,7 +2189,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2390
2189
|
useExisting: AXPLayoutDetailsViewComponent,
|
|
2391
2190
|
},
|
|
2392
2191
|
AXPLayoutDetailsViewViewModel,
|
|
2393
|
-
], 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 <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 </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"] }]
|
|
2192
|
+
], template: "<axp-page-layout *translate=\"let t\">\n @if (vm.adapter()?.pages?.length! > 1 && vm.isLarge()) {\n <axp-layout-start-side>\n <axp-layout-header>\n <axp-layout-title>{{\n (formatService.format(vm.showPages() ? (vm.adapter()?.title ?? '') : (vm.adapter()?.label ?? ''), 'string', vm.rootContext())\n | translate\n | async)\n }}</axp-layout-title>\n <axp-layout-description>{{\n (formatService.format(vm.adapter()?.description ?? '', 'string', vm.rootContext()) | translate | async)\n }}</axp-layout-description>\n </axp-layout-header>\n <axp-layout-content>\n <ax-tabs\n #sidebarTabs\n class=\"axp-vertical-tabs\"\n [look]=\"'with-line-color'\"\n [location]=\"'end'\"\n [fitParent]=\"true\"\n (onActiveTabChanged)=\"handleSidebarTabChanged($event)\"\n >\n @for (item of vm.adapter()?.pages; track item.id) {\n <ax-tab-item\n [key]=\"item.id\"\n [text]=\"(formatService.format(item.label, 'string', vm.rootContext()) | translate | async)!\"\n [active]=\"vm.currentPage()?.id === item.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n </axp-layout-content>\n </axp-layout-start-side>\n }\n <!-- Content Section -->\n <axp-page-content class=\"ax-flex ax-flex-row ax-gap-4\">\n @if (vm.showPages()) {\n <axp-layout-list class=\"ax-w-full\">\n @for (item of vm.adapter()?.pages; track $index) {\n <axp-layout-list-item (click)=\"handleSelectPage(item)\">\n <axp-layout-prefix>\n <ax-icon icon=\"far ${{ item.icon }}\" class=\"ax-text-gray-500\"></ax-icon>\n </axp-layout-prefix>\n <axp-layout-content>\n <a class=\"ax-font-semibold\">{{\n formatService.format(item.label, 'string', vm.rootContext()) | translate | async\n }}</a>\n </axp-layout-content>\n <axp-layout-suffix>\n <ax-icon icon=\" far fa-chevron-right\" class=\"ax-text-gray-400\"></ax-icon>\n </axp-layout-suffix>\n </axp-layout-list-item>\n }\n </axp-layout-list>\n } @else {\n <ax-form class=\"ax-h-full ax-w-full\" #form>\n <axp-widgets-container\n #widgetsContainerRef\n [context]=\"vm.context()\"\n (onContextChanged)=\"handleOnContextChanged($event)\"\n >\n <div class=\"ax-flex ax-flex-col ax-w-full ax-gap-4 ax-h-full\">\n @for (item of vm.currentPageContent(); track $index) {\n @if ('type' in item && item.type === 'component') {\n <!-- Component-based content -->\n <div\n axp-page-component-renderer\n [componentKey]=\"$any(item).componentKey\"\n [rootContext]=\"vm.rootContext()\"\n [pageConfig]=\"$any(item).pageConfig\"\n [options]=\"$any(item).options\"\n (componentReady)=\"recompute()\"\n ></div>\n } @else {\n <!-- Widget-based content -->\n <ng-container axp-widget-renderer [node]=\"$any(item)\" [mode]=\"$any(item).mode ?? 'view'\"></ng-container>\n }\n }\n @if (vm.currentPage()?.tabs?.length) {\n <div class=\"axp-horizontal-tabs\">\n <ax-tabs [location]=\"'bottom'\" [fitParent]=\"false\" look=\"classic\">\n @for (tab of vm.currentPageTabs(); track $index) {\n <ax-tab-item\n (onClick)=\"vm.setCurrentTab(tab)\"\n [text]=\"(tab.title | translate | async)!\"\n [active]=\"vm.currentTab()?.id === tab.id\"\n >\n <ax-prefix>\n <ax-icon icon=\"far ${{ tab.icon }}\"></ax-icon>\n </ax-prefix>\n </ax-tab-item>\n }\n </ax-tabs>\n <div class=\"content\">\n @if (vm.currentTab()) {\n @for (content of vm.activeTabContent(); track content.name) {\n <ng-container axp-widget-renderer [node]=\"content\" [mode]=\"content.mode ?? 'view'\">\n </ng-container>\n }\n }\n </div>\n </div>\n }\n </div>\n </axp-widgets-container>\n </ax-form>\n }\n </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"] }]
|
|
2394
2193
|
}], propDecorators: { adapter: [{ type: i0.Input, args: [{ isSignal: true, alias: "adapter", required: true }] }], 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 }] }] } });
|
|
2395
2194
|
|
|
2396
2195
|
//#region ---- Details View Can Deactivate Guard ----
|