@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.
Files changed (44) hide show
  1. package/fesm2022/{acorex-platform-common-common-settings.provider-ChoT4m4k.mjs → acorex-platform-common-common-settings.provider-Ytey9uhY.mjs} +1 -42
  2. package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-common.mjs +580 -1445
  4. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-contracts.mjs +1 -1330
  6. package/fesm2022/acorex-platform-contracts.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-core.mjs +5 -208
  8. package/fesm2022/acorex-platform-core.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  10. package/fesm2022/{acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs → acorex-platform-layout-entity-attachments-page.component-CwG6n_Yb.mjs} +3 -3
  11. 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
  12. package/fesm2022/{acorex-platform-layout-entity-file-list-popup.component-_yrP5SQe.mjs → acorex-platform-layout-entity-file-list-popup.component--IeMZLIr.mjs} +4 -4
  13. 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
  14. package/fesm2022/acorex-platform-layout-entity.mjs +694 -733
  15. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  16. package/fesm2022/acorex-platform-layout-views.mjs +171 -372
  17. package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
  18. package/fesm2022/acorex-platform-layout-widget-core.mjs +103 -3
  19. package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
  20. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs +116 -0
  21. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-J0zcGKBX.mjs.map +1 -0
  22. package/fesm2022/acorex-platform-layout-widgets.mjs +6 -11
  23. package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
  24. 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
  25. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-Br9p5aXT.mjs.map +1 -0
  26. package/fesm2022/acorex-platform-themes-default.mjs +52 -643
  27. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  28. package/fesm2022/acorex-platform-workflow.mjs +8 -5
  29. package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
  30. package/package.json +1 -1
  31. package/types/acorex-platform-common.d.ts +1056 -337
  32. package/types/acorex-platform-contracts.d.ts +4 -1679
  33. package/types/acorex-platform-core.d.ts +181 -92
  34. package/types/acorex-platform-layout-components.d.ts +1 -2
  35. package/types/acorex-platform-layout-entity.d.ts +221 -99
  36. package/types/acorex-platform-layout-views.d.ts +5 -39
  37. package/types/acorex-platform-layout-widget-core.d.ts +3 -2
  38. package/types/acorex-platform-layout-widgets.d.ts +4 -11
  39. package/types/acorex-platform-themes-default.d.ts +57 -120
  40. package/types/acorex-platform-workflow.d.ts +18 -5
  41. package/fesm2022/acorex-platform-common-common-settings.provider-ChoT4m4k.mjs.map +0 -1
  42. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs +0 -513
  43. package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-CFyfix31.mjs.map +0 -1
  44. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-DrUwqKKA.mjs.map +0 -1
@@ -1,17 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, Injector, signal, DestroyRef, makeEnvironmentProviders, NgModule, computed, input, output, ViewEncapsulation, ChangeDetectionStrategy, Component, viewChild, ErrorHandler, EventEmitter, Input, Output, Directive, effect, Inject, runInInjectionContext, model, linkedSignal, afterNextRender } from '@angular/core';
3
- import { AXPRegionalSetting } from '@acorex/platform/contracts';
4
- export * from '@acorex/platform/contracts';
2
+ import { InjectionToken, inject, Injectable, Injector, signal, DestroyRef, makeEnvironmentProviders, NgModule, computed, input, output, ViewEncapsulation, ChangeDetectionStrategy, Component, viewChild, ErrorHandler, EventEmitter, Input, Output, Directive, Inject, runInInjectionContext, model, linkedSignal, afterNextRender } from '@angular/core';
3
+ import { kebabCase, merge, sortBy, cloneDeep, get, isNumber, isPlainObject, omit } from 'lodash-es';
5
4
  import { Router, NavigationEnd, NavigationStart, ROUTES, RedirectCommand, RouterModule } from '@angular/router';
6
5
  import { AXPSessionService, AXPSessionStatus, AXPAuthGuard } from '@acorex/platform/auth';
7
6
  import { Subject, distinctUntilChanged, merge as merge$1, first, switchMap, from, map } from 'rxjs';
8
- import * as i3$1 from '@acorex/platform/core';
9
- import { unwrapValueProperty, coerceUnknownToDate, coerceUnknownToFiniteNumber, coerceUnknownToBoolean, coerceUnknownToTrimmedString, AXPPlatformScope, AXPBroadcastEventService, objectKeyValueTransforms, AXPDataGenerator, AXPKeyboardShortcutRegistry, chordToKbdItemKeys, hasForegroundOverlayLayer, AXPKeyboardShortcutPriority, normalizeKeyboardShortcuts, AXPSystemActionType, normalizeExpressionTemplate, isLocaleStringMap, AXPExpressionEvaluatorService, AXPContextEvalFactory, AXPDeviceService, AXPModuleManifestModule, AXPComponentSlotModule, AXPAppStartUpProvider, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXPHookService, AXPModuleManifestRegistry } from '@acorex/platform/core';
10
- import { merge, sortBy, cloneDeep, get, isNumber, isNil, isObject, isString, isPlainObject, omit, defaultTo } from 'lodash-es';
7
+ import * as i2$1 from '@acorex/platform/core';
8
+ import { unwrapValueProperty, coerceUnknownToDate, coerceUnknownToFiniteNumber, coerceUnknownToBoolean, coerceUnknownToTrimmedString, AXPPlatformScope, AXPBroadcastEventService, objectKeyValueTransforms, AXPDataGenerator, AXPKeyboardShortcutRegistry, chordToKbdItemKeys, hasForegroundOverlayLayer, AXPKeyboardShortcutPriority, normalizeKeyboardShortcuts, AXPSystemActionType, isLocaleStringMap, AXPExpressionEvaluatorService, AXPModuleManifestModule, AXPComponentSlotModule, AXPAppStartUpProvider, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXPHookService, AXPModuleManifestRegistry } from '@acorex/platform/core';
11
9
  import { AXCalendarService, AXDateTimeModule } from '@acorex/core/date-time';
12
10
  import { AXDialogService } from '@acorex/components/dialog';
13
11
  import * as i5 from '@acorex/core/translation';
14
- import { AXTranslationService, AXTranslationModule, translateSync, resolveMultiLanguageString } from '@acorex/core/translation';
12
+ import { AXTranslationService, AXTranslationModule, resolveMultiLanguageString } from '@acorex/core/translation';
15
13
  import * as i4$1 from '@angular/common';
16
14
  import { Location, CommonModule, AsyncPipe, DOCUMENT } from '@angular/common';
17
15
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
@@ -26,15 +24,13 @@ import * as i3 from '@acorex/components/progress-bar';
26
24
  import { AXProgressBarModule } from '@acorex/components/progress-bar';
27
25
  import { AXPopupService, AXPopupModule } from '@acorex/components/popup';
28
26
  import { AXToastService, AXToastModule } from '@acorex/components/toast';
29
- import * as i2$1 from '@acorex/core/format';
30
- import { AXFormatService } from '@acorex/core/format';
31
- import * as i4$2 from '@acorex/platform/workflow';
27
+ import * as i3$1 from '@acorex/platform/workflow';
32
28
  import { AXPWorkflowService, createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowError, AXPWorkflowModule } from '@acorex/platform/workflow';
33
29
  import { AXKBDComponent, AXKBDItemComponent } from '@acorex/components/kbd';
34
30
  import { AXDataSource } from '@acorex/cdk/common';
35
31
  import { AXPCommandExecutor, AXPCommandService } from '@acorex/platform/runtime';
36
32
  import { signalStore, withState, withMethods, patchState, withHooks } from '@ngrx/signals';
37
- import { filter } from 'rxjs/operators';
33
+ import { AXFormatService } from '@acorex/core/format';
38
34
  import { AXFileService } from '@acorex/core/file';
39
35
  import { AXCheckBoxModule } from '@acorex/components/check-box';
40
36
  import * as i6 from '@acorex/components/color-box';
@@ -168,10 +164,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
168
164
  }]
169
165
  }] });
170
166
 
171
- /**
172
- * Entity definition types, query views, and related helpers.
173
- * Canonical definitions live in @acorex/platform/contracts.
174
- */
167
+ var AXPRelationshipKind;
168
+ (function (AXPRelationshipKind) {
169
+ AXPRelationshipKind[AXPRelationshipKind["Association"] = 0] = "Association";
170
+ AXPRelationshipKind[AXPRelationshipKind["Composition"] = 1] = "Composition";
171
+ AXPRelationshipKind[AXPRelationshipKind["Aggregation"] = 2] = "Aggregation";
172
+ })(AXPRelationshipKind || (AXPRelationshipKind = {}));
173
+ var AXPRelationshipCardinality;
174
+ (function (AXPRelationshipCardinality) {
175
+ AXPRelationshipCardinality[AXPRelationshipCardinality["OneToOne"] = 0] = "OneToOne";
176
+ AXPRelationshipCardinality[AXPRelationshipCardinality["OneToMany"] = 1] = "OneToMany";
177
+ AXPRelationshipCardinality[AXPRelationshipCardinality["ManyToMany"] = 2] = "ManyToMany";
178
+ })(AXPRelationshipCardinality || (AXPRelationshipCardinality = {}));
179
+ var AXPEntityCommandScope;
180
+ (function (AXPEntityCommandScope) {
181
+ AXPEntityCommandScope["TypeLevel"] = "typeLevel";
182
+ AXPEntityCommandScope["Selected"] = "selected";
183
+ AXPEntityCommandScope["Individual"] = "individual";
184
+ AXPEntityCommandScope["Section"] = "section";
185
+ })(AXPEntityCommandScope || (AXPEntityCommandScope = {}));
186
+ var AXPEntityQueryType;
187
+ (function (AXPEntityQueryType) {
188
+ AXPEntityQueryType["Single"] = "single";
189
+ AXPEntityQueryType["List"] = "list";
190
+ })(AXPEntityQueryType || (AXPEntityQueryType = {}));
191
+ /** Whether the card field is shown as a header badge (not in the card body). */
192
+ function isCardFieldBadgeDisplay(display) {
193
+ if (display === 'badge') {
194
+ return true;
195
+ }
196
+ return typeof display === 'object' && display !== null && display.type === 'badge';
197
+ }
198
+ /** Resolves static badge color config from {@link AXPCardField.display} and legacy {@link AXPCardField.badgeColor}. */
199
+ function resolveCardFieldBadgeColor(field) {
200
+ if (typeof field.display === 'object' && field.display.type === 'badge') {
201
+ return field.display.options?.color ?? field.badgeColor;
202
+ }
203
+ if (field.display === 'badge') {
204
+ return field.badgeColor;
205
+ }
206
+ return undefined;
207
+ }
208
+ function getEntityInfo(entity) {
209
+ return {
210
+ source: `${entity.module}.${entity.name}`,
211
+ module: {
212
+ route: kebabCase(entity.module),
213
+ },
214
+ entity: {
215
+ route: kebabCase(entity.name),
216
+ },
217
+ };
218
+ }
219
+ function createQueryView(name, title, fixed, params = {
220
+ columns: [],
221
+ conditions: [],
222
+ sorts: [],
223
+ }) {
224
+ params = Object.assign({ columns: [], sorts: [], conditions: [] }, params);
225
+ return {
226
+ name,
227
+ title,
228
+ fixed,
229
+ columns: params.columns ?? [],
230
+ conditions: params.conditions ?? [],
231
+ sorts: params.sorts ?? [],
232
+ };
233
+ }
234
+ function createAllQueryView(params = {
235
+ columns: [],
236
+ sorts: [],
237
+ conditions: [],
238
+ }) {
239
+ params = Object.assign({ columns: [], sorts: [], conditions: [] }, params);
240
+ return createQueryView('all', '@general:terms.interface.selection.all-items', true, {
241
+ columns: params.columns ?? [],
242
+ conditions: params.conditions ?? [],
243
+ sorts: params.sorts ?? [],
244
+ });
245
+ }
246
+ /** Resolves master list layouts that are currently enabled. */
247
+ function resolveEnabledMasterListLayouts(layouts) {
248
+ if (!layouts) {
249
+ return ['table'];
250
+ }
251
+ const enabled = [];
252
+ if (layouts.table?.enabled !== false) {
253
+ enabled.push('table');
254
+ }
255
+ if (layouts.card && layouts.card.enabled !== false) {
256
+ enabled.push('card');
257
+ }
258
+ return enabled.length > 0 ? enabled : ['table'];
259
+ }
260
+ /** First enabled layout; used as the default when no user preference is stored. */
261
+ function resolveDefaultMasterListLayout(layouts) {
262
+ return resolveEnabledMasterListLayouts(layouts)[0];
263
+ }
264
+ // new version
265
+ var AXPEntityType;
266
+ (function (AXPEntityType) {
267
+ AXPEntityType[AXPEntityType["Entity"] = 0] = "Entity";
268
+ AXPEntityType[AXPEntityType["AggregateRoot"] = 1] = "AggregateRoot";
269
+ AXPEntityType[AXPEntityType["ValueObject"] = 2] = "ValueObject";
270
+ })(AXPEntityType || (AXPEntityType = {}));
175
271
 
176
272
  const EQ_OPER = { name: 'equal', title: '@general:terms.operators.equal', hasValue: true };
177
273
  const NOT_EQ_OPER = { name: 'notEqual', title: '@general:terms.operators.not-equal', hasValue: true };
@@ -376,6 +472,38 @@ const AXP_HOME_PAGE_DEFAULT_KEY = new InjectionToken('AXP_HOME_PAGE_DEFAULT_KEY'
376
472
  factory: () => 'home'
377
473
  });
378
474
 
475
+ /**
476
+ * Regional and locale-related setting keys used by platform widgets and components.
477
+ * Most values use the `LocaleManagement:Setting:Regional.*` prefix; definitions live in the locale-management module where applicable.
478
+ */
479
+ var AXPRegionalSetting;
480
+ (function (AXPRegionalSetting) {
481
+ AXPRegionalSetting["LocaleProfile"] = "LocaleManagement:Setting:Regional.LocaleProfile";
482
+ AXPRegionalSetting["TimeZone"] = "LocaleManagement:Setting:Regional.TimeZone";
483
+ AXPRegionalSetting["Language"] = "LocaleManagement:Setting:Regional.Language";
484
+ AXPRegionalSetting["Country"] = "LocaleManagement:Setting:Regional.Country";
485
+ AXPRegionalSetting["Calendar"] = "LocaleManagement:Setting:Regional.Calendar";
486
+ /** User-selected holiday calendars shown on the task board and other calendar views. */
487
+ AXPRegionalSetting["CalendarEvents"] = "LocaleManagement:Setting:Regional.CalendarEvents";
488
+ AXPRegionalSetting["FirstDayOfWeek"] = "LocaleManagement:Setting:Regional.FirstDayOfWeek";
489
+ AXPRegionalSetting["WeekendDays"] = "LocaleManagement:Setting:Regional.WeekendDays";
490
+ AXPRegionalSetting["ShortDate"] = "LocaleManagement:Setting:Regional.ShortDate";
491
+ AXPRegionalSetting["MediumDate"] = "LocaleManagement:Setting:Regional.MediumDate";
492
+ AXPRegionalSetting["LongDate"] = "LocaleManagement:Setting:Regional.LongDate";
493
+ AXPRegionalSetting["ShortTime"] = "LocaleManagement:Setting:Regional.ShortTime";
494
+ AXPRegionalSetting["MediumTime"] = "LocaleManagement:Setting:Regional.MediumTime";
495
+ AXPRegionalSetting["LongTime"] = "LocaleManagement:Setting:Regional.LongTime";
496
+ AXPRegionalSetting["MeasurementUnits"] = "LocaleManagement:Setting:Regional.MeasurementUnits";
497
+ AXPRegionalSetting["TemperatureUnits"] = "LocaleManagement:Setting:Regional.TemperatureUnits";
498
+ AXPRegionalSetting["DistanceUnits"] = "LocaleManagement:Setting:Regional.DistanceUnits";
499
+ AXPRegionalSetting["WeightUnits"] = "LocaleManagement:Setting:Regional.WeightUnits";
500
+ AXPRegionalSetting["VolumeUnits"] = "LocaleManagement:Setting:Regional.VolumeUnits";
501
+ AXPRegionalSetting["SpeedUnits"] = "LocaleManagement:Setting:Regional.SpeedUnits";
502
+ AXPRegionalSetting["AreaUnits"] = "LocaleManagement:Setting:Regional.AreaUnits";
503
+ /** Default multi-language behavior for standard text field names; defined in locale-management `AXMRegionalSettingProvider`. */
504
+ AXPRegionalSetting["MultiLanguageSupport"] = "LocaleManagement:Setting:Regional.MultiLanguageSupport";
505
+ })(AXPRegionalSetting || (AXPRegionalSetting = {}));
506
+
379
507
  class AXPSettingDefinitionProviderContext {
380
508
  constructor() {
381
509
  this.rootGroups = [];
@@ -473,7 +601,6 @@ class AXPSettingDefinitionSectionBuilder {
473
601
  isRequired: setting.isRequired ?? false,
474
602
  isInherited: setting.isInherited ?? false,
475
603
  isEncrypted: setting.isEncrypted ?? false,
476
- requiresPageRefresh: setting.requiresPageRefresh ?? false,
477
604
  defaultValue: setting.defaultValue,
478
605
  scope: setting.scope ?? 'P',
479
606
  layout: setting.widget.layout,
@@ -608,26 +735,6 @@ class AXPSettingDefinitionProviderService {
608
735
  collect(this.cache);
609
736
  return scopes;
610
737
  }
611
- async requiresPageRefreshByKey() {
612
- const refreshByKey = {};
613
- const collect = (groups) => {
614
- groups.forEach((group) => {
615
- group.sections.forEach((section) => {
616
- section.settings.forEach((setting) => {
617
- if (setting.requiresPageRefresh) {
618
- refreshByKey[setting.name] = true;
619
- }
620
- });
621
- });
622
- collect(group.groups);
623
- });
624
- };
625
- if (!this.cache) {
626
- await this.load();
627
- }
628
- collect(this.cache);
629
- return refreshByKey;
630
- }
631
738
  findGroup(scope, groupName) {
632
739
  return this.searchRecursive(this.getList(scope), groupName, []); // Initialize with an empty breadcrumb
633
740
  }
@@ -1318,8 +1425,6 @@ var AXPCommonSettings;
1318
1425
  AXPCommonSettings["DebugMode"] = "PlatformDevTools:Setting:Developer.DebugMode";
1319
1426
  AXPCommonSettings["ShowRowIndexColumn"] = "Common:Setting:Entity.ShowRowIndexColumn";
1320
1427
  AXPCommonSettings["EntityListPersistenceMode"] = "Common:Setting:Entity.ListPersistenceMode";
1321
- AXPCommonSettings["NavigationMode"] = "Common:Setting:Navigation.Mode";
1322
- AXPCommonSettings["MaxOpenTabs"] = "Common:Setting:Navigation.MaxOpenTabs";
1323
1428
  })(AXPCommonSettings || (AXPCommonSettings = {}));
1324
1429
 
1325
1430
  //#endregion
@@ -1506,176 +1611,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1506
1611
  }]
1507
1612
  }], ctorParameters: () => [] });
1508
1613
 
1509
- //#endregion
1510
- /**
1511
- * Holds detached Angular route component instances keyed by tab key so tabular navigation can
1512
- * preserve a page's full state (data-table selection, scroll, unsaved form values, etc.) while it
1513
- * is in the background, then reattach it without re-rendering.
1514
- *
1515
- * The registry has no `Router` dependency on purpose: it is consumed by the {@link RouteReuseStrategy}
1516
- * implementation, so depending on `Router` here would create a construction-time cycle.
1517
- */
1518
- class AXPTabRouteCacheRegistry {
1519
- constructor() {
1520
- //#region ---- State ----
1521
- this.handles = new Map();
1522
- this.openKeys = new Set();
1523
- this.enabled = false;
1524
- this.deactivateGuardSuspended = false;
1525
- }
1526
- //#endregion
1527
- //#region ---- Deactivate Guard Suspension ----
1528
- /**
1529
- * Runs `action` while unsaved-changes `canDeactivate` guards are suspended, so switching between
1530
- * tabs preserves a dirty page without prompting. Closing a tab does not use this path, so the
1531
- * prompt still appears there.
1532
- */
1533
- async runWithSuspendedDeactivateGuards(action) {
1534
- const previous = this.deactivateGuardSuspended;
1535
- this.deactivateGuardSuspended = true;
1536
- try {
1537
- return await action();
1538
- }
1539
- finally {
1540
- this.deactivateGuardSuspended = previous;
1541
- }
1542
- }
1543
- isDeactivateGuardSuspended() {
1544
- return this.deactivateGuardSuspended;
1545
- }
1546
- //#endregion
1547
- //#region ---- Mode ----
1548
- /** Enables caching (tabular mode). Disabling clears and destroys every cached component. */
1549
- setEnabled(enabled) {
1550
- if (this.enabled === enabled) {
1551
- return;
1552
- }
1553
- this.enabled = enabled;
1554
- if (!enabled) {
1555
- this.clear();
1556
- }
1557
- }
1558
- isEnabled() {
1559
- return this.enabled;
1560
- }
1561
- //#endregion
1562
- //#region ---- Open Keys Sync ----
1563
- /**
1564
- * Reconciles open scoped tab keys and active tab URLs. Cached handles whose key is not an open
1565
- * scoped tab key, an active tab URL, or a child path under an open scoped tab are destroyed.
1566
- */
1567
- syncOpenKeys(scopedKeys, activeTabUrls = []) {
1568
- const scopedSet = new Set(scopedKeys);
1569
- const activePathSet = new Set(activeTabUrls.map((url) => url.split('?')[0].split('#')[0].replace(/\/+$/, '') || '/'));
1570
- for (const cacheKey of [...this.handles.keys()]) {
1571
- const normalizedCacheKey = cacheKey.replace(/\/+$/, '') || '/';
1572
- const keepsScopedKey = scopedSet.has(normalizedCacheKey);
1573
- const keepsActiveUrl = activePathSet.has(normalizedCacheKey);
1574
- const keepsUnderScopedTab = [...scopedSet].some((scopedKey) => normalizedCacheKey === scopedKey || normalizedCacheKey.startsWith(`${scopedKey}/`));
1575
- if (!keepsScopedKey && !keepsActiveUrl && !keepsUnderScopedTab) {
1576
- this.destroyHandle(this.handles.get(cacheKey));
1577
- this.handles.delete(cacheKey);
1578
- }
1579
- }
1580
- this.openKeys = scopedSet;
1581
- }
1582
- isOpen(key) {
1583
- return this.openKeys.has(key);
1584
- }
1585
- /**
1586
- * Returns the live component instance for a cached background tab, when available.
1587
- * Matches the tab key directly or any cached handle under a scoped tab prefix.
1588
- */
1589
- getComponentInstance(key) {
1590
- const normalizedKey = key.replace(/\/+$/, '') || '/';
1591
- const direct = this.handles.get(normalizedKey) ?? this.handles.get(key);
1592
- if (direct) {
1593
- return this.readComponentInstance(direct);
1594
- }
1595
- for (const [cacheKey, handle] of this.handles) {
1596
- const normalizedCacheKey = cacheKey.replace(/\/+$/, '') || '/';
1597
- if (normalizedCacheKey === normalizedKey || normalizedCacheKey.startsWith(`${normalizedKey}/`)) {
1598
- return this.readComponentInstance(handle);
1599
- }
1600
- }
1601
- return null;
1602
- }
1603
- //#endregion
1604
- //#region ---- Handle Store ----
1605
- /**
1606
- * Caches a detached background handle. Overwrites without destroying the previous handle: on a
1607
- * repeat visit Angular hands back a new handle object wrapping the same live `componentRef`, so
1608
- * destroying the old one would destroy the live component and corrupt the view (NG0922).
1609
- */
1610
- store(key, handle) {
1611
- this.handles.set(key, handle);
1612
- }
1613
- /**
1614
- * Returns the cached handle without mutating the map. Angular reads a handle twice per
1615
- * navigation (once while building the future state, once while attaching), so `retrieve` must be
1616
- * idempotent; the handle is released afterwards via {@link release} when Angular calls
1617
- * `store(snapshot, null)`.
1618
- */
1619
- retrieve(key) {
1620
- return this.handles.get(key) ?? null;
1621
- }
1622
- /**
1623
- * Drops a handle that the router has just reattached (it is now a live foreground view, so it
1624
- * must not be destroyed). The map keeps only truly backgrounded handles.
1625
- */
1626
- release(key) {
1627
- this.handles.delete(key);
1628
- }
1629
- has(key) {
1630
- return this.handles.has(key);
1631
- }
1632
- /** Destroys and removes a single cached handle (used when a tab closes). */
1633
- evict(key) {
1634
- this.destroyHandle(this.handles.get(key));
1635
- this.handles.delete(key);
1636
- }
1637
- /** Destroys and removes every cached handle. */
1638
- clear() {
1639
- for (const handle of this.handles.values()) {
1640
- this.destroyHandle(handle);
1641
- }
1642
- this.handles.clear();
1643
- this.openKeys.clear();
1644
- }
1645
- //#endregion
1646
- //#region ---- Utility Methods ----
1647
- readComponentInstance(handle) {
1648
- const componentRef = handle.componentRef;
1649
- return componentRef?.instance ?? null;
1650
- }
1651
- destroyHandle(handle) {
1652
- if (!handle) {
1653
- return;
1654
- }
1655
- const componentRef = handle.componentRef;
1656
- componentRef?.destroy?.();
1657
- }
1658
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabRouteCacheRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1659
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabRouteCacheRegistry, providedIn: 'root' }); }
1660
- }
1661
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabRouteCacheRegistry, decorators: [{
1662
- type: Injectable,
1663
- args: [{
1664
- providedIn: 'root',
1665
- }]
1666
- }] });
1667
-
1668
1614
  //#region ---- Unsaved Changes Can Deactivate Guard Factory ----
1669
1615
  function createUnsavedChangesCanDeactivateGuard() {
1670
- return (component) => {
1671
- // Tab switches keep the page alive in the background, so skip the prompt; closing a tab does not
1672
- // suspend guards and still prompts.
1673
- const tabCache = inject(AXPTabRouteCacheRegistry, { optional: true });
1674
- if (tabCache?.isDeactivateGuardSuspended()) {
1675
- return true;
1676
- }
1677
- return component.canDeactivate();
1678
- };
1616
+ return (component) => component.canDeactivate();
1679
1617
  }
1680
1618
  //#endregion
1681
1619
 
@@ -3053,56 +2991,6 @@ function axpRedirectToUnauthorized(router = inject(Router)) {
3053
2991
  return new RedirectCommand(router.parseUrl(AXP_UNAUTHORIZED_ROUTE));
3054
2992
  }
3055
2993
 
3056
- //#endregion
3057
- /**
3058
- * Platform formatter for display text: resolves ML objects, i18n keys (`@scope:key`), and primitives.
3059
- * Register via {@link AXPCommonModule} (auto) or `AXFormatModule.forRoot({ formatters: [AXPTranslateFormatter] })`.
3060
- */
3061
- class AXPTranslateFormatter {
3062
- constructor() {
3063
- //#region ---- Services & Dependencies ----
3064
- this.translationService = inject(AXTranslationService);
3065
- }
3066
- //#endregion
3067
- //#region ---- AXFormatter ----
3068
- get name() {
3069
- return 'translate';
3070
- }
3071
- format(value, options) {
3072
- if (isNil(value) || value === '') {
3073
- return '';
3074
- }
3075
- if (isObject(value) && !Array.isArray(value) && !(value instanceof Date)) {
3076
- const resolved = this.translationService.resolve(value);
3077
- return resolved?.trim() ?? '';
3078
- }
3079
- if (isString(value)) {
3080
- const text = value.trim();
3081
- if (!text) {
3082
- return '';
3083
- }
3084
- if (text.startsWith('@')) {
3085
- const translateOptions = typeof options === 'object' ? options : undefined;
3086
- const translated = translateSync(text, translateOptions);
3087
- return translated?.trim() ?? text;
3088
- }
3089
- return text;
3090
- }
3091
- if (typeof value === 'number' || typeof value === 'boolean') {
3092
- return String(value);
3093
- }
3094
- if (value instanceof Date) {
3095
- return value.toISOString();
3096
- }
3097
- return String(value).trim();
3098
- }
3099
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTranslateFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3100
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTranslateFormatter }); }
3101
- }
3102
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTranslateFormatter, decorators: [{
3103
- type: Injectable
3104
- }] });
3105
-
3106
2994
  class AXPFileStorageService {
3107
2995
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPFileStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3108
2996
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPFileStorageService }); }
@@ -4868,8 +4756,6 @@ class AXPMenuSearchDefinitionProvider {
4868
4756
  }
4869
4757
  }
4870
4758
 
4871
- const AXP_SEARCH_DEFINITION_LAZY_RESOLVER = new InjectionToken('AXP_SEARCH_DEFINITION_LAZY_RESOLVER');
4872
-
4873
4759
  class AXPSearchDefinitionProviderContext {
4874
4760
  constructor() {
4875
4761
  this.definitions = [];
@@ -4944,7 +4830,6 @@ const AXP_SEARCH_DEFINITION_PROVIDER = new InjectionToken('AXP_SEARCH_DEFINITION
4944
4830
  class AXPSearchDefinitionProviderService {
4945
4831
  constructor() {
4946
4832
  this.providers = inject(AXP_SEARCH_DEFINITION_PROVIDER, { optional: true });
4947
- this.lazyResolver = inject(AXP_SEARCH_DEFINITION_LAZY_RESOLVER, { optional: true });
4948
4833
  this.cache = null;
4949
4834
  }
4950
4835
  async load() {
@@ -4975,29 +4860,12 @@ class AXPSearchDefinitionProviderService {
4975
4860
  }
4976
4861
  }
4977
4862
  findDefinition(definitionName) {
4978
- const definition = this.getList().find((item) => item.name === definitionName);
4863
+ const definition = this.getList().find((definition) => definition.name === definitionName);
4979
4864
  if (!definition) {
4980
4865
  throw new Error(`Definition with name ${definitionName} not found`);
4981
4866
  }
4982
4867
  return definition;
4983
4868
  }
4984
- async findDefinitionAsync(definitionName) {
4985
- await this.load();
4986
- const existing = this.getList().find((item) => item.name === definitionName);
4987
- if (existing) {
4988
- return existing;
4989
- }
4990
- const lazy = this.lazyResolver;
4991
- if (!lazy) {
4992
- return null;
4993
- }
4994
- const resolved = await lazy.resolve(definitionName);
4995
- if (!resolved) {
4996
- return null;
4997
- }
4998
- this.cache = [...(this.cache ?? []), resolved];
4999
- return resolved;
5000
- }
5001
4869
  findDefinitionByGroup(definitionGroup) {
5002
4870
  const definition = this.getList().find((definition) => definition.group === definitionGroup);
5003
4871
  if (!definition) {
@@ -5016,8 +4884,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
5016
4884
  //#region ---- Imports ----
5017
4885
  //#endregion
5018
4886
  //#region ---- Template normalization ----
5019
- /** @see normalizeExpressionTemplate */
5020
- const normalizeEntityDisplayTemplate = normalizeExpressionTemplate;
4887
+ /**
4888
+ * Normalizes entity display templates for {@link AXPExpressionEvaluatorService}.
4889
+ * Converts `context.eval('path')`, single braces, and simple dot paths to `context.eval` segments.
4890
+ */
4891
+ function normalizeEntityDisplayTemplate(template) {
4892
+ let normalized = template.replace(/\{\{\s*context\.eval\(['"]([^'"]+)['"]\)\s*\}\}/g, '{{ context.eval("$1") }}');
4893
+ if (!normalized.includes('{{')) {
4894
+ normalized = normalized.replace(/\{/g, '{{').replace(/\}/g, '}}');
4895
+ }
4896
+ return normalized.replace(/\{\{\s*(?!context\.)([\w]+(?:\.[\w]+)*)\s*\}\}/g, '{{ context.eval("$1") }}');
4897
+ }
5021
4898
  /** True when formatted text still contains unresolved template markers. */
5022
4899
  function isUnresolvedEntityDisplayTemplate(value) {
5023
4900
  return /\{\{/.test(value) || /context\.eval\s*\(/.test(value) || value === '[object Object]';
@@ -5148,55 +5025,17 @@ function resolveEntityRowTitleTemplate(entity) {
5148
5025
  }
5149
5026
  return undefined;
5150
5027
  }
5151
- /**
5152
- * Record title template for modify popups: `interfaces.master.update.title` → `single.title`.
5153
- */
5154
- function resolveEntityModifyRecordTitleTemplate(entity) {
5155
- if (!entity) {
5156
- return undefined;
5157
- }
5158
- const updateTitle = entity.interfaces?.master?.update?.title?.trim();
5159
- if (updateTitle && isRowBoundTemplate(updateTitle)) {
5160
- return normalizeEntityDisplayTemplate(updateTitle);
5161
- }
5162
- const singleTitle = entity.interfaces?.master?.single?.title?.trim();
5163
- if (singleTitle && isRowBoundTemplate(singleTitle)) {
5164
- return normalizeEntityDisplayTemplate(singleTitle);
5165
- }
5166
- return undefined;
5167
- }
5168
- /**
5169
- * Modify/edit popup chrome: `{action} {individual} ({update.title ?? single.title})` when a record template exists.
5170
- */
5171
- async function resolveEntityModifyPopupTitle(entity, recordData, translationService, formatService, expressionEvaluator, contextEvalFactory, actionTitleKey = '@general:actions.modify.title') {
5172
- const actionPrefix = translationService.translateSync(actionTitleKey);
5173
- const entityLabel = translationService.translateSync(entity.formats.individual);
5174
- const baseTitle = `${actionPrefix} ${entityLabel}`.trim();
5175
- const recordTemplate = resolveEntityModifyRecordTitleTemplate(entity);
5176
- if (!recordTemplate) {
5177
- return baseTitle;
5178
- }
5179
- const locale = translationService.getActiveLang();
5180
- const resolved = await resolveSearchDisplayTemplate(recordTemplate, recordData, locale, translationService, formatService, expressionEvaluator, contextEvalFactory);
5181
- const recordTitle = sanitizeResolvedEntityDisplayTitle(typeof resolved === 'string'
5182
- ? resolved
5183
- : resolveSearchableText(resolved, locale, translationService));
5184
- if (!isMeaningfulEntityDisplayTitle(recordTitle)) {
5185
- return baseTitle;
5186
- }
5187
- return `${baseTitle} (${recordTitle})`;
5188
- }
5189
5028
  //#endregion
5190
5029
  //#region ---- Runtime resolution ----
5191
5030
  /**
5192
5031
  * Resolves an entity row title using entity-driven fallback templates and property paths.
5193
5032
  */
5194
- async function resolveEntitySearchTitleFallback(format, data, locale, translationService, formatService, expressionEvaluator, contextEvalFactory) {
5033
+ async function resolveEntitySearchTitleFallback(format, data, locale, translationService, formatService, expressionEvaluator) {
5195
5034
  if (data == null) {
5196
5035
  return '';
5197
5036
  }
5198
5037
  for (const template of format.titleFallbackTemplates ?? []) {
5199
- const resolved = await resolveSearchDisplayTemplate(template, data, locale, translationService, formatService, expressionEvaluator, contextEvalFactory);
5038
+ const resolved = await resolveSearchDisplayTemplate(template, data, locale, translationService, formatService, expressionEvaluator);
5200
5039
  const text = sanitizeResolvedEntityDisplayTitle(typeof resolved === 'string'
5201
5040
  ? resolved
5202
5041
  : resolveSearchableText(resolved, locale, translationService));
@@ -5237,8 +5076,13 @@ function resolveSearchableText(value, locale, translationService) {
5237
5076
  }
5238
5077
  return trimmed;
5239
5078
  }
5240
- if (isLocaleStringMap(value) || translationService.isValidMultiLanguageObject(value)) {
5241
- return resolveMultiLanguageString(value, locale).trim();
5079
+ if (isLocaleStringMap(value)) {
5080
+ return Object.values(value)
5081
+ .filter((entry) => (entry ?? '').trim() !== '')
5082
+ .join(' ');
5083
+ }
5084
+ if (translationService.isValidMultiLanguageObject(value)) {
5085
+ return resolveMultiLanguageString(value, locale);
5242
5086
  }
5243
5087
  return '';
5244
5088
  }
@@ -5250,11 +5094,6 @@ function searchInSearchableValue(value, query, locale, translationService) {
5250
5094
  if (!q) {
5251
5095
  return true;
5252
5096
  }
5253
- if (isLocaleStringMap(value)) {
5254
- return Object.values(value)
5255
- .filter((entry) => typeof entry === 'string' && entry.trim() !== '')
5256
- .some((entry) => entry.toLocaleLowerCase(locale).includes(q));
5257
- }
5258
5097
  const text = resolveSearchableText(value, locale, translationService).toLocaleLowerCase(locale);
5259
5098
  return text.includes(q);
5260
5099
  }
@@ -5287,31 +5126,26 @@ function searchInRecordValues(value, query, locale, translationService, depth =
5287
5126
  function countMustacheExpressions(template) {
5288
5127
  return (template.match(/\{\{/g) ?? []).length;
5289
5128
  }
5290
- /** Standard display-tier row scope for entity title/search templates. */
5291
- function createEntityRowExpressionScope(data, contextEvalFactory) {
5129
+ /** Standard row scope for entity title/search templates. */
5130
+ function createEntityRowExpressionScope(data) {
5292
5131
  return {
5293
- context: contextEvalFactory.createScope((data ?? {})),
5132
+ context: {
5133
+ eval: (path) => get(data, path),
5134
+ },
5294
5135
  };
5295
5136
  }
5296
- /**
5297
- * Coerces an evaluated display segment to plain text.
5298
- * Piped eval returns strings; unpiped MLS still resolves via compat fallback.
5299
- */
5300
- function formatDisplaySegment(segment, locale, translationService) {
5301
- if (segment === false || segment == null) {
5302
- return '';
5303
- }
5304
- if (isString(segment)) {
5305
- return segment.trim();
5306
- }
5307
- return resolveSearchableText(segment, locale, translationService);
5308
- }
5309
5137
  /**
5310
5138
  * Evaluates a normalized entity display template via {@link AXPExpressionEvaluatorService}.
5311
5139
  */
5312
- async function evaluateEntityDisplayTemplate(template, data, expressionEvaluator, locale, translationService, contextEvalFactory) {
5140
+ async function evaluateEntityDisplayTemplate(template, data, expressionEvaluator, locale, translationService) {
5313
5141
  const normalized = normalizeEntityDisplayTemplate(template);
5314
- const scope = createEntityRowExpressionScope(data, contextEvalFactory);
5142
+ const scope = createEntityRowExpressionScope(data);
5143
+ const formatSegment = (segment) => {
5144
+ if (segment === false || segment == null) {
5145
+ return '';
5146
+ }
5147
+ return resolveSearchableText(segment, locale, translationService);
5148
+ };
5315
5149
  if (!normalized.includes('{{')) {
5316
5150
  return normalized;
5317
5151
  }
@@ -5325,7 +5159,7 @@ async function evaluateEntityDisplayTemplate(template, data, expressionEvaluator
5325
5159
  for (const match of normalized.matchAll(regex)) {
5326
5160
  result += normalized.slice(lastIndex, match.index);
5327
5161
  const segment = await expressionEvaluator.evaluate(`{{ ${match[1].trim()} }}`, scope);
5328
- result += formatDisplaySegment(segment, locale, translationService);
5162
+ result += formatSegment(segment);
5329
5163
  lastIndex = (match.index ?? 0) + match[0].length;
5330
5164
  }
5331
5165
  result += normalized.slice(lastIndex);
@@ -5372,7 +5206,7 @@ function resolveQueryMatchingDisplayText(value, query, locale, translationServic
5372
5206
  /**
5373
5207
  * Resolves entity search display templates; coerces multi-language field values to readable text.
5374
5208
  */
5375
- async function resolveSearchDisplayTemplate(template, data, locale, translationService, formatService, expressionEvaluator, contextEvalFactory) {
5209
+ async function resolveSearchDisplayTemplate(template, data, locale, translationService, formatService, expressionEvaluator) {
5376
5210
  if (!template) {
5377
5211
  return '';
5378
5212
  }
@@ -5383,7 +5217,7 @@ async function resolveSearchDisplayTemplate(template, data, locale, translationS
5383
5217
  const formatted = formatService.format(template, 'string', data);
5384
5218
  return sanitizeResolvedEntityDisplayTitle(typeof formatted === 'string' ? formatted : String(formatted ?? ''));
5385
5219
  }
5386
- const evaluated = await evaluateEntityDisplayTemplate(template, data, expressionEvaluator, locale, translationService, contextEvalFactory);
5220
+ const evaluated = await evaluateEntityDisplayTemplate(template, data, expressionEvaluator, locale, translationService);
5387
5221
  return sanitizeResolvedEntityDisplayTitle(resolveSearchableText(evaluated, locale, translationService));
5388
5222
  }
5389
5223
  //#endregion
@@ -5408,7 +5242,6 @@ class AXPSearchService {
5408
5242
  this.formatService = inject(AXFormatService);
5409
5243
  this.translationService = inject(AXTranslationService);
5410
5244
  this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
5411
- this.contextEvalFactory = inject(AXPContextEvalFactory);
5412
5245
  }
5413
5246
  async search(text) {
5414
5247
  //TODO better handle this
@@ -5438,23 +5271,20 @@ class AXPSearchService {
5438
5271
  for (const resultArray of results) {
5439
5272
  for (const result of resultArray) {
5440
5273
  try {
5441
- const definition = await this.definitionService.findDefinitionAsync(result.group);
5442
- if (!definition) {
5443
- continue;
5444
- }
5274
+ const definition = this.definitionService.findDefinition(result.group);
5445
5275
  const resolvedTitle = result.title ??
5446
5276
  (definition.format.title
5447
- ? await resolveSearchDisplayTemplate(definition.format.title, result.data, locale, this.translationService, this.formatService, this.expressionEvaluator, this.contextEvalFactory)
5277
+ ? await resolveSearchDisplayTemplate(definition.format.title, result.data, locale, this.translationService, this.formatService, this.expressionEvaluator)
5448
5278
  : '');
5449
5279
  const resolvedDescription = result.description ??
5450
5280
  (definition.format.description
5451
- ? await resolveSearchDisplayTemplate(definition.format.description, result.data, locale, this.translationService, this.formatService, this.expressionEvaluator, this.contextEvalFactory)
5281
+ ? await resolveSearchDisplayTemplate(definition.format.description, result.data, locale, this.translationService, this.formatService, this.expressionEvaluator)
5452
5282
  : undefined);
5453
5283
  let titleText = sanitizeResolvedEntityDisplayTitle(typeof resolvedTitle === 'string'
5454
5284
  ? resolvedTitle
5455
5285
  : resolveSearchableText(resolvedTitle, locale, this.translationService));
5456
5286
  if (!isMeaningfulEntityDisplayTitle(titleText)) {
5457
- titleText = await resolveEntitySearchTitleFallback(definition.format, result.data, locale, this.translationService, this.formatService, this.expressionEvaluator, this.contextEvalFactory);
5287
+ titleText = await resolveEntitySearchTitleFallback(definition.format, result.data, locale, this.translationService, this.formatService, this.expressionEvaluator);
5458
5288
  }
5459
5289
  if (!isMeaningfulEntityDisplayTitle(titleText)) {
5460
5290
  continue;
@@ -5949,1090 +5779,36 @@ function axpReplaceEntityListRouteQueryParams(router, queryParams) {
5949
5779
  }
5950
5780
  //#endregion
5951
5781
 
5952
- //#region ---- Tab Key ----
5953
- /** Query params ignored when building a tab dedupe key. */
5954
- const IGNORED_QUERY_KEYS = new Set(['_ts']);
5955
- /**
5956
- * Builds a stable tab key from a router URL.
5957
- * Path segments define identity; query params are excluded so the same entity record
5958
- * or list reuses one tab even when filters or refresh tokens change.
5959
- */
5960
- function axpBuildTabKey(url) {
5961
- const normalized = normalizeRouterUrl(url);
5962
- const pathOnly = normalized.split('?')[0].split('#')[0];
5963
- return pathOnly;
5964
- }
5965
- /** Normalizes a router URL for storage and navigation. */
5966
- function normalizeRouterUrl(url) {
5967
- const trimmed = url.trim();
5968
- if (!trimmed.length) {
5969
- return '/';
5970
- }
5971
- const withLeadingSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
5972
- const [pathAndFragment, queryString = ''] = withLeadingSlash.split('?');
5973
- const [pathPart, fragment = ''] = pathAndFragment.split('#');
5974
- const normalizedPath = pathPart.replace(/\/+$/, '') || '/';
5975
- const filteredQuery = filterQueryString(queryString);
5976
- let result = normalizedPath;
5977
- if (filteredQuery) {
5978
- result += `?${filteredQuery}`;
5979
- }
5980
- if (fragment) {
5981
- result += `#${fragment}`;
5982
- }
5983
- return result;
5984
- }
5985
- function filterQueryString(queryString) {
5986
- if (!queryString) {
5987
- return '';
5988
- }
5989
- const params = new URLSearchParams(queryString);
5990
- const kept = [];
5991
- params.forEach((value, key) => {
5992
- if (!IGNORED_QUERY_KEYS.has(key)) {
5993
- kept.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
5994
- }
5995
- });
5996
- kept.sort();
5997
- return kept.join('&');
5998
- }
5999
- /** Human-readable fallback title from the URL path. */
6000
- function axpFallbackTabTitle(url) {
6001
- const pathOnly = url.split('?')[0].split('#')[0];
6002
- const segments = pathOnly.split('/').filter(Boolean);
6003
- const last = defaultTo(segments[segments.length - 1], 'Page');
6004
- return decodeURIComponent(last);
6005
- }
6006
- //#endregion
6007
-
6008
- //#region ---- Types ----
6009
- const AXP_HOME_TAB_KEY = 'axp:home';
6010
- /** Route `data` key for tab-navigation behavior (`data.tab`). */
6011
- const AXP_TAB_ROUTE_DATA_KEY = 'tab';
6012
- //#endregion
6013
-
6014
- //#region ---- Tab Preview Service ----
6015
- /**
6016
- * In-memory structured previews for tab hover cards and dirty indicators.
6017
- * Populated by active/cached pages via {@link AXPPageLayoutBaseComponent}.
6018
- */
6019
- class AXPTabPreviewService {
5782
+ //TODO Loading, Redirect, Drawer, Show toast
5783
+ const AXPRedirectEvent = createWorkFlowEvent('Redirect Event Fired');
5784
+ const AXPRefreshEvent = createWorkFlowEvent('Refresh Event Fired');
5785
+ const AXPReloadEvent = createWorkFlowEvent('Reload Event Fired');
5786
+ class AXPWorkflowNavigateAction extends AXPWorkflowAction {
6020
5787
  constructor() {
6021
- //#region ---- State ----
6022
- this.previewMap = signal({}, ...(ngDevMode ? [{ debugName: "previewMap" }] : /* istanbul ignore next */ []));
6023
- this.previews = this.previewMap.asReadonly();
6024
- }
6025
- //#endregion
6026
- //#region ---- Public API ----
6027
- setPreview(key, preview) {
6028
- this.previewMap.update((current) => ({
6029
- ...current,
6030
- [key]: preview,
6031
- }));
6032
- }
6033
- patchPreview(key, patch) {
6034
- this.previewMap.update((current) => {
6035
- const existing = current[key];
6036
- if (!existing) {
6037
- if (!patch.url) {
6038
- return current;
6039
- }
6040
- return {
6041
- ...current,
6042
- [key]: {
6043
- title: patch.title ?? '',
6044
- url: patch.url,
6045
- icon: patch.icon,
6046
- subtitle: patch.subtitle,
6047
- isDirty: patch.isDirty ?? false,
6048
- breadcrumbTrail: patch.breadcrumbTrail ?? [],
6049
- },
6050
- };
6051
- }
6052
- return {
6053
- ...current,
6054
- [key]: {
6055
- ...existing,
6056
- ...patch,
6057
- },
6058
- };
6059
- });
6060
- }
6061
- getPreview(key) {
6062
- return this.previewMap()[key];
6063
- }
6064
- isTabDirty(key) {
6065
- return !!this.previewMap()[key]?.isDirty;
6066
- }
6067
- clearPreview(key) {
6068
- this.previewMap.update((current) => {
6069
- if (!(key in current)) {
6070
- return current;
6071
- }
6072
- const next = { ...current };
6073
- delete next[key];
6074
- return next;
6075
- });
5788
+ super(...arguments);
5789
+ this.router = inject(Router);
6076
5790
  }
6077
- clearPreviews(keys) {
6078
- const keySet = new Set(keys);
6079
- if (!keySet.size) {
5791
+ async execute(context) {
5792
+ const payload = context.getVariable('payload');
5793
+ if (Array.isArray(payload.commands)) {
5794
+ await this.router.navigate(payload.commands, payload.extras);
6080
5795
  return;
6081
5796
  }
6082
- this.previewMap.update((current) => {
6083
- const next = { ...current };
6084
- let changed = false;
6085
- for (const key of keySet) {
6086
- if (key in next) {
6087
- delete next[key];
6088
- changed = true;
6089
- }
6090
- }
6091
- return changed ? next : current;
6092
- });
6093
- }
6094
- clearAll() {
6095
- this.previewMap.set({});
5797
+ const path = payload.commands;
5798
+ if (!path) {
5799
+ return;
5800
+ }
5801
+ if (path.toLowerCase().startsWith('http') || payload.target === 'blank') {
5802
+ window.open(path, '_blank');
5803
+ return;
5804
+ }
5805
+ await axpNavigateAppPath(this.router, path, payload.extras);
6096
5806
  }
6097
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabPreviewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6098
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabPreviewService, providedIn: 'root' }); }
5807
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowNavigateAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
5808
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowNavigateAction }); }
6099
5809
  }
6100
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabPreviewService, decorators: [{
6101
- type: Injectable,
6102
- args: [{
6103
- providedIn: 'root',
6104
- }]
6105
- }] });
6106
-
6107
- //#region ---- Tab Route Policy ----
6108
- const EXCLUDED_PATH_PREFIXES = ['/auth', '/error'];
6109
- const EXCLUDED_PATH_PATTERNS = [
6110
- /^\/assessment\/fill\//i,
6111
- /^\/forms\//i,
6112
- ];
6113
- /**
6114
- * Returns true when the URL represents an in-app page that may appear in the tab bar.
6115
- */
6116
- function axpIsTabEligibleUrl(url) {
6117
- const pathOnly = url.split('?')[0].split('#')[0].trim();
6118
- if (!pathOnly || pathOnly === '/') {
6119
- return false;
6120
- }
6121
- const normalized = pathOnly.startsWith('/') ? pathOnly : `/${pathOnly}`;
6122
- if (EXCLUDED_PATH_PREFIXES.some((prefix) => normalized.startsWith(prefix))) {
6123
- return false;
6124
- }
6125
- if (EXCLUDED_PATH_PATTERNS.some((pattern) => pattern.test(normalized))) {
6126
- return false;
6127
- }
6128
- return true;
6129
- }
6130
- //#endregion
6131
-
6132
- //#region ---- Route Data ----
6133
- /** True when the route declares itself as a scoped tab root (`data.tab = true`). */
6134
- function axpHasTabScope(data) {
6135
- return data?.[AXP_TAB_ROUTE_DATA_KEY] === true;
6136
- }
6137
- //#endregion
6138
- //#region ---- Snapshot Resolution ----
6139
- /** Resolved URL path for a snapshot (no query or fragment). */
6140
- function axpPathFromSnapshot(snapshot) {
6141
- const segments = snapshot.pathFromRoot
6142
- .flatMap((entry) => entry.url.map((segment) => segment.path))
6143
- .filter(Boolean);
6144
- return segments.length ? `/${segments.join('/')}` : '/';
6145
- }
6146
- /** Returns the leaf snapshot under the router state root. */
6147
- function axpGetLeafRouteSnapshot(root) {
6148
- let route = root;
6149
- while (route.firstChild) {
6150
- route = route.firstChild;
6151
- }
6152
- return route;
6153
- }
6154
- /**
6155
- * Resolves the tab dedupe key from an activated route tree.
6156
- * Uses the nearest ancestor with `data.tab = true`; otherwise the leaf path.
6157
- */
6158
- function axpResolveTabKeyFromSnapshot(leaf) {
6159
- const chain = leaf.pathFromRoot;
6160
- for (let index = chain.length - 1; index >= 0; index--) {
6161
- const snapshot = chain[index];
6162
- if (axpHasTabScope(snapshot.data)) {
6163
- return axpPathFromSnapshot(snapshot);
6164
- }
6165
- }
6166
- return axpPathFromSnapshot(leaf);
6167
- }
6168
- //#endregion
6169
- //#region ---- Router / URL Resolution ----
6170
- /**
6171
- * Resolves a tab key for the given URL (or the current router URL).
6172
- * Prefers the live route snapshot when it matches the target URL; otherwise matches route config.
6173
- */
6174
- function axpResolveTabKey(router, url) {
6175
- const normalized = normalizeRouterUrl(url ?? router.url);
6176
- const pathOnly = normalized.split('?')[0].split('#')[0];
6177
- const currentPath = normalizeRouterUrl(router.url).split('?')[0].split('#')[0];
6178
- if (!url || pathOnly === currentPath) {
6179
- const leaf = axpGetLeafRouteSnapshot(router.routerState.snapshot.root);
6180
- return axpResolveTabKeyFromSnapshot(leaf);
6181
- }
6182
- const fromConfig = axpResolveTabKeyFromRouteConfig(router.config, pathOnly);
6183
- if (fromConfig) {
6184
- return fromConfig;
6185
- }
6186
- return pathOnly.startsWith('/') ? pathOnly : `/${pathOnly}`;
6187
- }
6188
- /**
6189
- * Matches a URL path against registered routes and resolves the tab key from `data.tab`.
6190
- */
6191
- function axpResolveTabKeyFromRouteConfig(routes, pathOnly) {
6192
- const normalized = pathOnly.startsWith('/') ? pathOnly.replace(/\/+$/, '') || '/' : `/${pathOnly}`.replace(/\/+$/, '') || '/';
6193
- const segments = normalized === '/' ? [] : normalized.split('/').filter(Boolean);
6194
- const chain = matchRouteConfigChain(routes, segments, 0, {}, []);
6195
- if (!chain?.length) {
6196
- return null;
6197
- }
6198
- for (let index = chain.length - 1; index >= 0; index--) {
6199
- const level = chain[index];
6200
- if (axpHasTabScope(level.mergedData)) {
6201
- return level.path;
6202
- }
6203
- }
6204
- return chain[chain.length - 1]?.path ?? null;
6205
- }
6206
- function matchRouteConfigChain(routes, segments, startIndex, inheritedData, chain) {
6207
- let bestMatch = null;
6208
- for (const route of routes) {
6209
- if (route.redirectTo) {
6210
- continue;
6211
- }
6212
- const segmentMatch = matchRoutePath(route.path ?? '', segments, startIndex);
6213
- if (!segmentMatch) {
6214
- continue;
6215
- }
6216
- const pathSegments = [...segments.slice(0, startIndex), ...segments.slice(startIndex, startIndex + segmentMatch.consumed)];
6217
- const path = pathSegments.length ? `/${pathSegments.join('/')}` : '/';
6218
- const mergedData = { ...inheritedData, ...(route.data ?? {}) };
6219
- const level = { mergedData, path };
6220
- const nextChain = [...chain, level];
6221
- const nextIndex = startIndex + segmentMatch.consumed;
6222
- if (route.children?.length) {
6223
- const childMatch = matchRouteConfigChain(route.children, segments, nextIndex, mergedData, nextChain);
6224
- if (childMatch && (!bestMatch || childMatch.length > bestMatch.length)) {
6225
- bestMatch = childMatch;
6226
- }
6227
- }
6228
- if (nextIndex === segments.length) {
6229
- if (!bestMatch || nextChain.length > bestMatch.length) {
6230
- bestMatch = nextChain;
6231
- }
6232
- }
6233
- }
6234
- return bestMatch;
6235
- }
6236
- function matchRoutePath(routePath, segments, startIndex) {
6237
- if (routePath === '**') {
6238
- return { consumed: Math.max(0, segments.length - startIndex) };
6239
- }
6240
- const parts = routePath.split('/').filter(Boolean);
6241
- if (!parts.length) {
6242
- return { consumed: 0 };
6243
- }
6244
- let consumed = 0;
6245
- for (const part of parts) {
6246
- const segment = segments[startIndex + consumed];
6247
- if (segment === undefined) {
6248
- return null;
6249
- }
6250
- if (part.startsWith(':') || part === segment) {
6251
- consumed++;
6252
- continue;
6253
- }
6254
- return null;
6255
- }
6256
- return { consumed };
6257
- }
6258
- //#endregion
6259
-
6260
- //#region ---- Constants ----
6261
- const SESSION_STORAGE_PREFIX = 'AXP_TAB_NAV';
6262
- //#endregion
6263
- class AXPTabNavigationService {
6264
- //#endregion
6265
- //#region ---- Lifecycle ----
6266
- constructor() {
6267
- //#region ---- Services & Dependencies ----
6268
- this.router = inject(Router);
6269
- this.settingsService = inject(AXPSettingsService);
6270
- this.deviceService = inject(AXPDeviceService);
6271
- this.menuService = inject(AXPMenuService);
6272
- this.homePageService = inject(AXPHomePageService);
6273
- this.sessionService = inject(AXPSessionService);
6274
- this.routeCacheRegistry = inject(AXPTabRouteCacheRegistry);
6275
- this.tabPreviewService = inject(AXPTabPreviewService);
6276
- this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
6277
- this.destroyRef = inject(DestroyRef);
6278
- //#endregion
6279
- //#region ---- State ----
6280
- this.navigationMode = signal('simple', ...(ngDevMode ? [{ debugName: "navigationMode" }] : /* istanbul ignore next */ []));
6281
- this.maxOpenTabs = signal(5, ...(ngDevMode ? [{ debugName: "maxOpenTabs" }] : /* istanbul ignore next */ []));
6282
- this.tabs = signal([], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
6283
- this.activeTabKey = signal(null, ...(ngDevMode ? [{ debugName: "activeTabKey" }] : /* istanbul ignore next */ []));
6284
- this.suppressNavigationSync = false;
6285
- //#endregion
6286
- //#region ---- Computed ----
6287
- /** Effective mode: mobile always uses simple navigation. */
6288
- this.effectiveMode = computed(() => {
6289
- if (this.deviceService.isSmall()) {
6290
- return 'simple';
6291
- }
6292
- return this.navigationMode();
6293
- }, ...(ngDevMode ? [{ debugName: "effectiveMode" }] : /* istanbul ignore next */ []));
6294
- this.isTabBarVisible = computed(() => this.effectiveMode() === 'tabular' && this.tabs().length > 0, ...(ngDevMode ? [{ debugName: "isTabBarVisible" }] : /* istanbul ignore next */ []));
6295
- this.tabList = this.tabs.asReadonly();
6296
- this.activeKey = this.activeTabKey.asReadonly();
6297
- void this.loadSettings();
6298
- this.bindRouterEvents();
6299
- this.bindSettingsChanges();
6300
- this.bindSessionChanges();
6301
- this.bindRouteCacheSync();
6302
- }
6303
- //#endregion
6304
- //#region ---- Public API ----
6305
- /** Navigates to a path, opening or activating a tab when tabular mode is active. */
6306
- async navigate(path, extras) {
6307
- const normalizedPath = normalizeRouterUrl(path);
6308
- if (this.effectiveMode() === 'simple' || !axpIsTabEligibleUrl(normalizedPath)) {
6309
- return axpNavigateAppPath(this.router, normalizedPath, extras);
6310
- }
6311
- await this.openOrActivateTab(normalizedPath);
6312
- return true;
6313
- }
6314
- /** Opens a tab or activates an existing tab with the same key. */
6315
- async openOrActivateTab(url, title) {
6316
- if (this.effectiveMode() === 'simple') {
6317
- await axpNavigateAppPath(this.router, url);
6318
- return;
6319
- }
6320
- const normalizedUrl = normalizeRouterUrl(url);
6321
- if (!axpIsTabEligibleUrl(normalizedUrl)) {
6322
- await axpNavigateAppPath(this.router, normalizedUrl);
6323
- return;
6324
- }
6325
- await this.ensureHomeTab();
6326
- if (this.isHomePageUrl(normalizedUrl)) {
6327
- await this.activateTabKey(AXP_HOME_TAB_KEY, normalizedUrl);
6328
- return;
6329
- }
6330
- const resolvedKey = axpResolveTabKey(this.router, normalizedUrl);
6331
- const existing = this.findTabForUrl(normalizedUrl);
6332
- if (existing) {
6333
- if (existing.key !== resolvedKey) {
6334
- this.migrateTabKey(existing.key, resolvedKey);
6335
- }
6336
- this.updateTabUrl(resolvedKey, normalizedUrl);
6337
- await this.activateTabKey(resolvedKey, normalizedUrl);
6338
- return;
6339
- }
6340
- // Navigate first so scoped tab keys (`data.tab`) resolve from the live route snapshot.
6341
- this.suppressNavigationSync = true;
6342
- try {
6343
- await axpNavigateAppPath(this.router, normalizedUrl);
6344
- const key = axpResolveTabKey(this.router);
6345
- const postNavExisting = this.findTabForUrl(normalizedUrl);
6346
- if (postNavExisting) {
6347
- if (postNavExisting.key !== key) {
6348
- this.migrateTabKey(postNavExisting.key, key);
6349
- }
6350
- this.updateTabUrl(key, normalizedUrl);
6351
- this.touchTab(key);
6352
- this.activeTabKey.set(key);
6353
- this.persistSession();
6354
- return;
6355
- }
6356
- this.insertTab(this.createTabDescriptor(normalizedUrl, title, key));
6357
- this.activeTabKey.set(key);
6358
- this.persistSession();
6359
- }
6360
- finally {
6361
- this.suppressNavigationSync = false;
6362
- }
6363
- }
6364
- /**
6365
- * Activates a tab and navigates to its URL. The previously active page is detached and cached by
6366
- * the reuse strategy, so its state is preserved; this tab's cached instance is reattached when
6367
- * available instead of being re-rendered.
6368
- *
6369
- * @param suspendDeactivateGuard When true (default for tab switches), unsaved-changes prompts are
6370
- * skipped so switching tabs keeps a dirty page alive. Closing a tab passes false to keep the prompt.
6371
- */
6372
- async activateTabKey(key, urlOverride, suspendDeactivateGuard = true) {
6373
- const tab = this.tabs().find((item) => item.key === key);
6374
- if (!tab) {
6375
- return;
6376
- }
6377
- const targetUrl = urlOverride ?? tab.url;
6378
- this.touchTab(key);
6379
- this.activeTabKey.set(key);
6380
- this.persistSession();
6381
- const navigate = async () => {
6382
- this.suppressNavigationSync = true;
6383
- try {
6384
- await this.router.navigateByUrl(targetUrl);
6385
- }
6386
- finally {
6387
- this.suppressNavigationSync = false;
6388
- }
6389
- };
6390
- if (suspendDeactivateGuard) {
6391
- await this.routeCacheRegistry.runWithSuspendedDeactivateGuards(navigate);
6392
- return;
6393
- }
6394
- await navigate();
6395
- }
6396
- /** Closes a tab and navigates to a neighbor when the active tab is closed. */
6397
- async closeTab(key) {
6398
- await this.closeTabs([key]);
6399
- }
6400
- /** Closes every closable tab except the given key (pinned tabs are kept). */
6401
- async closeOtherTabs(keepKey) {
6402
- const keys = this.tabs()
6403
- .filter((tab) => tab.closable && !tab.pinned && tab.key !== keepKey)
6404
- .map((tab) => tab.key);
6405
- await this.closeTabs(keys);
6406
- }
6407
- /** Closes all closable tabs (pinned tabs are kept). */
6408
- async closeAllTabs() {
6409
- const keys = this.tabs()
6410
- .filter((tab) => tab.closable && !tab.pinned)
6411
- .map((tab) => tab.key);
6412
- await this.closeTabs(keys);
6413
- }
6414
- /** Toggles whether a tab stays pinned in the strip (home tab is always pinned). */
6415
- toggleTabPinned(key) {
6416
- if (key === AXP_HOME_TAB_KEY) {
6417
- return;
6418
- }
6419
- this.tabs.update((items) => {
6420
- const updated = items.map((tab) => {
6421
- if (tab.key !== key) {
6422
- return tab;
6423
- }
6424
- const pinned = !tab.pinned;
6425
- return {
6426
- ...tab,
6427
- pinned,
6428
- closable: !pinned,
6429
- };
6430
- });
6431
- return this.normalizeTabOrder(updated);
6432
- });
6433
- this.persistSession();
6434
- }
6435
- /**
6436
- * Reorders tabs after drag-and-drop. Home stays first; pinned and unpinned tabs cannot cross groups.
6437
- */
6438
- reorderTabs(previousIndex, currentIndex) {
6439
- if (previousIndex === currentIndex) {
6440
- return;
6441
- }
6442
- const items = this.tabs();
6443
- if (previousIndex < 0 || currentIndex < 0 || previousIndex >= items.length || currentIndex >= items.length) {
6444
- return;
6445
- }
6446
- const moving = items[previousIndex];
6447
- if (moving.key === AXP_HOME_TAB_KEY) {
6448
- return;
6449
- }
6450
- const lastPinnedIndex = this.getLastPinnedTabIndex(items);
6451
- let targetIndex = currentIndex;
6452
- if (moving.pinned) {
6453
- if (targetIndex === 0) {
6454
- return;
6455
- }
6456
- targetIndex = Math.max(1, Math.min(targetIndex, lastPinnedIndex));
6457
- }
6458
- else {
6459
- const firstUnpinnedIndex = lastPinnedIndex + 1;
6460
- if (firstUnpinnedIndex >= items.length) {
6461
- return;
6462
- }
6463
- targetIndex = Math.max(firstUnpinnedIndex, Math.min(targetIndex, items.length - 1));
6464
- }
6465
- if (previousIndex === targetIndex) {
6466
- return;
6467
- }
6468
- const next = [...items];
6469
- const [removed] = next.splice(previousIndex, 1);
6470
- next.splice(targetIndex, 0, removed);
6471
- this.tabs.set(next);
6472
- this.persistSession();
6473
- }
6474
- /** Updates a tab title from the current page chrome (e.g. breadcrumb trail). */
6475
- syncTabTitle(key, title) {
6476
- if (this.effectiveMode() === 'simple') {
6477
- return;
6478
- }
6479
- if (!this.tabs().some((tab) => tab.key === key)) {
6480
- return;
6481
- }
6482
- const normalized = title.trim();
6483
- if (!normalized || this.isGenericHomeTitle(normalized)) {
6484
- return;
6485
- }
6486
- this.updateTabTitle(key, normalized);
6487
- }
6488
- /** Updates a tab icon from the current page chrome or menu metadata. */
6489
- syncTabIcon(key, icon) {
6490
- if (this.effectiveMode() === 'simple') {
6491
- return;
6492
- }
6493
- if (!this.tabs().some((tab) => tab.key === key)) {
6494
- return;
6495
- }
6496
- const normalized = icon.trim();
6497
- if (!normalized) {
6498
- return;
6499
- }
6500
- this.updateTabIcon(key, normalized);
6501
- }
6502
- //#endregion
6503
- //#region ---- Bulk Tab Close ----
6504
- /** Closes multiple tabs in one update; navigates once when the active tab is closed. */
6505
- async closeTabs(keys) {
6506
- const uniqueKeys = [...new Set(keys)];
6507
- if (!uniqueKeys.length) {
6508
- return;
6509
- }
6510
- const closableKeySet = new Set(uniqueKeys.filter((key) => {
6511
- const tab = this.tabs().find((item) => item.key === key);
6512
- return !!tab?.closable && !tab.pinned;
6513
- }));
6514
- if (!closableKeySet.size) {
6515
- return;
6516
- }
6517
- const activeKey = this.activeTabKey();
6518
- const backgroundKeys = [...closableKeySet].filter((key) => key !== activeKey);
6519
- for (const key of backgroundKeys) {
6520
- if (!(await this.confirmBackgroundTabClose(key))) {
6521
- closableKeySet.delete(key);
6522
- }
6523
- }
6524
- if (!closableKeySet.size) {
6525
- return;
6526
- }
6527
- const currentTabs = this.tabs();
6528
- const wasActiveClosed = !!activeKey && closableKeySet.has(activeKey);
6529
- const closedActiveIndex = wasActiveClosed ? currentTabs.findIndex((item) => item.key === activeKey) : -1;
6530
- const nextTabs = currentTabs.filter((item) => !closableKeySet.has(item.key));
6531
- if (wasActiveClosed) {
6532
- const navigated = await this.navigateAwayBeforeClosingActiveTab(closedActiveIndex, nextTabs);
6533
- if (!navigated) {
6534
- return;
6535
- }
6536
- }
6537
- this.tabs.set(nextTabs);
6538
- this.tabPreviewService.clearPreviews(closableKeySet);
6539
- this.persistSession();
6540
- }
6541
- //#endregion
6542
- //#region ---- Tab Close Helpers ----
6543
- /**
6544
- * Prompts before closing a cached background tab. Uses the page's {@link AXPTabCloseConfirm}
6545
- * hook when available, otherwise falls back to the tab preview dirty flag.
6546
- */
6547
- async confirmBackgroundTabClose(key) {
6548
- const instance = this.routeCacheRegistry.getComponentInstance(key);
6549
- if (instance && typeof instance.onBeforeTabClose === 'function') {
6550
- return instance.onBeforeTabClose();
6551
- }
6552
- return this.unsavedChangesConfirm.confirmIfDirty(this.tabPreviewService.isTabDirty(key), {
6553
- approveLeaveOnConfirm: false,
6554
- });
6555
- }
6556
- //#endregion
6557
- //#region ---- Tab Close Navigation ----
6558
- /**
6559
- * Navigates away from the active tab before it is removed so canDeactivate runs while the tab is still visible.
6560
- * Returns false when navigation was cancelled (e.g. unsaved-changes confirmation declined).
6561
- */
6562
- async navigateAwayBeforeClosingActiveTab(closedActiveIndex, remainingTabs) {
6563
- const fallbackIndex = this.resolveFallbackTabIndex(closedActiveIndex, remainingTabs);
6564
- const fallback = fallbackIndex >= 0 ? remainingTabs[fallbackIndex] : undefined;
6565
- let targetKey;
6566
- let targetUrl;
6567
- if (fallback) {
6568
- targetKey = fallback.key;
6569
- targetUrl = fallback.url;
6570
- }
6571
- else {
6572
- await this.ensureHomeTab();
6573
- const home = this.tabs().find((item) => item.key === AXP_HOME_TAB_KEY);
6574
- if (!home) {
6575
- return false;
6576
- }
6577
- targetKey = home.key;
6578
- targetUrl = home.url;
6579
- }
6580
- this.suppressNavigationSync = true;
6581
- try {
6582
- const navigated = await this.router.navigateByUrl(targetUrl);
6583
- if (!navigated) {
6584
- return false;
6585
- }
6586
- }
6587
- finally {
6588
- this.suppressNavigationSync = false;
6589
- }
6590
- this.activeTabKey.set(targetKey);
6591
- this.touchTab(targetKey);
6592
- return true;
6593
- }
6594
- /** Prefers the tab to the right after removal, then the tab to the left (browser-like). */
6595
- resolveFallbackTabIndex(closedIndex, remainingTabs) {
6596
- if (!remainingTabs.length) {
6597
- return -1;
6598
- }
6599
- if (closedIndex < remainingTabs.length) {
6600
- return closedIndex;
6601
- }
6602
- return closedIndex - 1;
6603
- }
6604
- //#endregion
6605
- //#region ---- Route Cache Sync ----
6606
- /**
6607
- * Keeps the route cache registry aligned with the current navigation mode and the set of open
6608
- * tabs. Cached page instances for closed/evicted tabs are destroyed by the registry.
6609
- */
6610
- bindRouteCacheSync() {
6611
- effect(() => {
6612
- this.routeCacheRegistry.setEnabled(this.effectiveMode() === 'tabular');
6613
- this.routeCacheRegistry.syncOpenKeys(this.tabs().map((tab) => tab.key), this.tabs().map((tab) => tab.url));
6614
- });
6615
- }
6616
- //#endregion
6617
- //#region ---- Router Sync ----
6618
- bindRouterEvents() {
6619
- this.router.events
6620
- .pipe(filter((event) => event instanceof NavigationEnd), takeUntilDestroyed(this.destroyRef))
6621
- .subscribe((event) => {
6622
- void this.handleNavigationEnd(event.urlAfterRedirects);
6623
- });
6624
- }
6625
- async handleNavigationEnd(url) {
6626
- if (this.suppressNavigationSync) {
6627
- return;
6628
- }
6629
- if (this.effectiveMode() === 'simple') {
6630
- return;
6631
- }
6632
- const normalizedUrl = normalizeRouterUrl(url);
6633
- if (!axpIsTabEligibleUrl(normalizedUrl)) {
6634
- return;
6635
- }
6636
- await this.ensureHomeTab();
6637
- if (this.isHomePageUrl(normalizedUrl)) {
6638
- this.activateHomeTabForUrl(normalizedUrl);
6639
- return;
6640
- }
6641
- const key = axpResolveTabKey(this.router, normalizedUrl);
6642
- const existing = this.findTabForUrl(normalizedUrl);
6643
- if (existing) {
6644
- if (existing.key !== key) {
6645
- this.migrateTabKey(existing.key, key);
6646
- }
6647
- this.updateTabUrl(key, normalizedUrl);
6648
- this.touchTab(key);
6649
- this.activeTabKey.set(key);
6650
- this.persistSession();
6651
- return;
6652
- }
6653
- this.insertTab(this.createTabDescriptor(normalizedUrl, undefined, key));
6654
- this.activeTabKey.set(key);
6655
- this.persistSession();
6656
- }
6657
- //#endregion
6658
- //#region ---- Settings ----
6659
- async loadSettings() {
6660
- const [mode, maxTabs] = await Promise.all([
6661
- this.settingsService.get(AXPCommonSettings.NavigationMode),
6662
- this.settingsService.get(AXPCommonSettings.MaxOpenTabs),
6663
- ]);
6664
- this.navigationMode.set(mode === 'tabular' ? 'tabular' : 'simple');
6665
- this.maxOpenTabs.set(this.normalizeMaxTabs(maxTabs));
6666
- await this.restoreSessionIfNeeded();
6667
- }
6668
- bindSettingsChanges() {
6669
- this.settingsService.onChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
6670
- if (event.keys.includes(AXPCommonSettings.NavigationMode)) {
6671
- const raw = event.values[AXPCommonSettings.NavigationMode];
6672
- const newMode = raw === 'tabular' ? 'tabular' : 'simple';
6673
- if (newMode !== this.navigationMode()) {
6674
- this.navigationMode.set(newMode);
6675
- if (this.effectiveMode() === 'simple') {
6676
- this.clearSession();
6677
- }
6678
- else {
6679
- void this.ensureHomeTab().then(() => this.syncCurrentRouteAsTab());
6680
- }
6681
- }
6682
- }
6683
- if (event.keys.includes(AXPCommonSettings.MaxOpenTabs)) {
6684
- this.maxOpenTabs.set(this.normalizeMaxTabs(event.values[AXPCommonSettings.MaxOpenTabs]));
6685
- this.enforceMaxTabs();
6686
- this.persistSession();
6687
- }
6688
- });
6689
- }
6690
- bindSessionChanges() {
6691
- this.sessionService.user$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
6692
- void this.restoreSessionIfNeeded();
6693
- });
6694
- }
6695
- //#endregion
6696
- //#region ---- Tab Management ----
6697
- async ensureHomeTab() {
6698
- const homePath = this.resolveHomePath();
6699
- if (!homePath) {
6700
- return;
6701
- }
6702
- const homeUrl = normalizeRouterUrl(homePath);
6703
- const homeKey = AXP_HOME_TAB_KEY;
6704
- const existing = this.tabs().find((tab) => tab.key === homeKey);
6705
- if (existing) {
6706
- this.tabs.update((items) => items.map((tab) => tab.key === homeKey
6707
- ? {
6708
- ...tab,
6709
- url: homeUrl,
6710
- title: this.isGenericHomeTitle(tab.title) ? this.resolveHomeTitle() : tab.title,
6711
- icon: this.resolveTabIcon(homeUrl, 'fa-light fa-house'),
6712
- }
6713
- : tab));
6714
- return;
6715
- }
6716
- const now = Date.now();
6717
- const homeTab = {
6718
- key: homeKey,
6719
- url: homeUrl,
6720
- title: this.resolveHomeTitle(),
6721
- icon: this.resolveTabIcon(homeUrl, 'fa-light fa-house'),
6722
- pinned: true,
6723
- closable: false,
6724
- openedAt: now,
6725
- lastActivatedAt: now,
6726
- };
6727
- this.tabs.update((items) => this.normalizeTabOrder([homeTab, ...items.filter((tab) => tab.key !== homeKey)]));
6728
- }
6729
- insertTab(tab) {
6730
- if (this.isHomePageUrl(tab.url)) {
6731
- this.activateHomeTabForUrl(tab.url);
6732
- return;
6733
- }
6734
- this.tabs.update((items) => {
6735
- const withoutDuplicate = items.filter((item) => {
6736
- if (item.key === tab.key) {
6737
- return false;
6738
- }
6739
- return axpResolveTabKey(this.router, item.url) !== tab.key;
6740
- });
6741
- return this.normalizeTabOrder([...withoutDuplicate, tab]);
6742
- });
6743
- this.enforceMaxTabs();
6744
- }
6745
- /** Home first; preserves session order for the remaining tabs. */
6746
- ensureHomeTabFirst(items) {
6747
- const home = items.find((tab) => tab.key === AXP_HOME_TAB_KEY);
6748
- const others = items.filter((tab) => tab.key !== AXP_HOME_TAB_KEY);
6749
- return home ? [home, ...others] : items;
6750
- }
6751
- getLastPinnedTabIndex(items) {
6752
- for (let index = items.length - 1; index >= 0; index -= 1) {
6753
- if (items[index]?.pinned) {
6754
- return index;
6755
- }
6756
- }
6757
- return 0;
6758
- }
6759
- /** Home first, then other pinned tabs, then unpinned tabs (stable by openedAt within each group). */
6760
- normalizeTabOrder(items) {
6761
- const home = items.find((tab) => tab.key === AXP_HOME_TAB_KEY);
6762
- const pinned = items.filter((tab) => tab.key !== AXP_HOME_TAB_KEY && tab.pinned);
6763
- const unpinned = items.filter((tab) => tab.key !== AXP_HOME_TAB_KEY && !tab.pinned);
6764
- const byOpenedAt = (a, b) => a.openedAt - b.openedAt;
6765
- return [...(home ? [home] : []), ...pinned.sort(byOpenedAt), ...unpinned.sort(byOpenedAt)];
6766
- }
6767
- enforceMaxTabs() {
6768
- const limit = this.maxOpenTabs();
6769
- let current = this.tabs();
6770
- while (current.length > limit) {
6771
- const evictionCandidate = [...current]
6772
- .filter((tab) => tab.closable && !tab.pinned && tab.key !== this.activeTabKey())
6773
- .filter((tab) => !this.tabPreviewService.isTabDirty(tab.key))
6774
- .sort((a, b) => a.lastActivatedAt - b.lastActivatedAt)[0];
6775
- if (!evictionCandidate) {
6776
- break;
6777
- }
6778
- current = current.filter((tab) => tab.key !== evictionCandidate.key);
6779
- }
6780
- this.tabs.set(current);
6781
- }
6782
- createTabDescriptor(url, title, keyOverride) {
6783
- const now = Date.now();
6784
- const key = keyOverride ?? axpResolveTabKey(this.router, url);
6785
- return {
6786
- key,
6787
- url,
6788
- title: title ?? this.resolveTabTitle(url),
6789
- icon: this.resolveTabIcon(url),
6790
- pinned: false,
6791
- closable: true,
6792
- openedAt: now,
6793
- lastActivatedAt: now,
6794
- };
6795
- }
6796
- /** Finds a tab by scoped key or legacy full-path key for the same URL. */
6797
- findTabForUrl(url) {
6798
- if (this.isHomePageUrl(url)) {
6799
- return this.tabs().find((tab) => tab.key === AXP_HOME_TAB_KEY);
6800
- }
6801
- const resolvedKey = axpResolveTabKey(this.router, url);
6802
- return this.tabs().find((tab) => tab.key !== AXP_HOME_TAB_KEY &&
6803
- (tab.key === resolvedKey || axpResolveTabKey(this.router, tab.url) === resolvedKey));
6804
- }
6805
- /** True when the URL is the configured application home page (e.g. dashboard). */
6806
- isHomePageUrl(url) {
6807
- const homeUrl = this.resolveHomeUrl();
6808
- if (!homeUrl) {
6809
- return false;
6810
- }
6811
- return normalizeRouterUrl(url) === homeUrl;
6812
- }
6813
- resolveHomeUrl() {
6814
- const homePath = this.resolveHomePath();
6815
- if (!homePath) {
6816
- return null;
6817
- }
6818
- return normalizeRouterUrl(homePath);
6819
- }
6820
- /** Activates the pinned home tab for a home-page URL instead of opening a duplicate tab. */
6821
- activateHomeTabForUrl(url) {
6822
- this.updateTabUrl(AXP_HOME_TAB_KEY, normalizeRouterUrl(url));
6823
- this.touchTab(AXP_HOME_TAB_KEY);
6824
- this.activeTabKey.set(AXP_HOME_TAB_KEY);
6825
- this.persistSession();
6826
- }
6827
- /** Drops non-home tabs that duplicate the home page URL after session restore. */
6828
- removeDuplicateHomeUrlTabs(tabs) {
6829
- const homeUrl = this.resolveHomeUrl();
6830
- if (!homeUrl) {
6831
- return tabs;
6832
- }
6833
- return tabs.filter((tab) => tab.key === AXP_HOME_TAB_KEY || normalizeRouterUrl(tab.url) !== homeUrl);
6834
- }
6835
- /** Rewrites a tab key when route-scope resolution changes (e.g. profile sub-routes). */
6836
- migrateTabKey(fromKey, toKey) {
6837
- if (fromKey === toKey) {
6838
- return;
6839
- }
6840
- if (this.activeTabKey() === fromKey) {
6841
- this.activeTabKey.set(toKey);
6842
- }
6843
- this.tabs.update((items) => {
6844
- const tab = items.find((item) => item.key === fromKey);
6845
- if (!tab) {
6846
- return items;
6847
- }
6848
- const without = items.filter((item) => item.key !== fromKey && item.key !== toKey);
6849
- return this.normalizeTabOrder([...without, { ...tab, key: toKey }]);
6850
- });
6851
- }
6852
- /** Collapses restored tabs that share the same scoped route key. */
6853
- normalizeRestoredTabKeys(tabs) {
6854
- const byResolvedKey = new Map();
6855
- for (const tab of tabs) {
6856
- if (tab.key === AXP_HOME_TAB_KEY) {
6857
- byResolvedKey.set(AXP_HOME_TAB_KEY, tab);
6858
- continue;
6859
- }
6860
- const resolvedKey = axpResolveTabKey(this.router, tab.url);
6861
- const normalized = { ...tab, key: resolvedKey };
6862
- const existing = byResolvedKey.get(resolvedKey);
6863
- if (!existing || normalized.lastActivatedAt > existing.lastActivatedAt) {
6864
- byResolvedKey.set(resolvedKey, normalized);
6865
- }
6866
- }
6867
- return [...byResolvedKey.values()];
6868
- }
6869
- updateTabUrl(key, url) {
6870
- this.tabs.update((items) => items.map((tab) => (tab.key === key ? { ...tab, url } : tab)));
6871
- }
6872
- updateTabTitle(key, title) {
6873
- this.tabs.update((items) => items.map((tab) => (tab.key === key && tab.title !== title ? { ...tab, title } : tab)));
6874
- this.persistSession();
6875
- }
6876
- updateTabIcon(key, icon) {
6877
- this.tabs.update((items) => items.map((tab) => (tab.key === key && tab.icon !== icon ? { ...tab, icon } : tab)));
6878
- this.persistSession();
6879
- }
6880
- touchTab(key) {
6881
- const now = Date.now();
6882
- this.tabs.update((items) => items.map((tab) => (tab.key === key ? { ...tab, lastActivatedAt: now } : tab)));
6883
- }
6884
- resolveTabTitle(url, fallback) {
6885
- const match = axpFindMenuItemByRoute(this.menuService.items(), url);
6886
- if (match?.item.text) {
6887
- return match.item.text;
6888
- }
6889
- return fallback ?? axpFallbackTabTitle(url);
6890
- }
6891
- resolveTabIcon(url, fallback = 'fa-light fa-window') {
6892
- const match = axpFindMenuItemByRoute(this.menuService.items(), url);
6893
- if (match?.item.icon?.trim()) {
6894
- return match.item.icon.trim();
6895
- }
6896
- return fallback;
6897
- }
6898
- resolveHomePath() {
6899
- const current = this.homePageService.getCurrent();
6900
- return current.path ? normalizeRouterUrl(current.path) : '';
6901
- }
6902
- resolveHomeTitle() {
6903
- const current = this.homePageService.getCurrent();
6904
- return current.title || 'Home';
6905
- }
6906
- isGenericHomeTitle(title) {
6907
- if (title === '@general:terms.interface.navigation.home') {
6908
- return true;
6909
- }
6910
- const homeTitle = this.resolveHomeTitle().trim();
6911
- return title === homeTitle;
6912
- }
6913
- async syncCurrentRouteAsTab() {
6914
- if (this.effectiveMode() === 'simple') {
6915
- return;
6916
- }
6917
- await this.ensureHomeTab();
6918
- await this.handleNavigationEnd(this.router.url);
6919
- }
6920
- normalizeMaxTabs(value) {
6921
- const parsed = Number(value);
6922
- if (!Number.isFinite(parsed)) {
6923
- return 5;
6924
- }
6925
- return Math.min(20, Math.max(2, Math.round(parsed)));
6926
- }
6927
- //#endregion
6928
- //#region ---- Session Persistence ----
6929
- sessionStorageKey() {
6930
- const userId = this.sessionService.user?.id;
6931
- if (!userId) {
6932
- return null;
6933
- }
6934
- return `${SESSION_STORAGE_PREFIX}(${userId})`;
6935
- }
6936
- persistSession() {
6937
- const key = this.sessionStorageKey();
6938
- if (!key || this.effectiveMode() === 'simple') {
6939
- return;
6940
- }
6941
- const payload = {
6942
- tabs: cloneDeep(this.tabs()),
6943
- activeTabKey: this.activeTabKey(),
6944
- };
6945
- sessionStorage.setItem(key, JSON.stringify(payload));
6946
- }
6947
- clearSession() {
6948
- const key = this.sessionStorageKey();
6949
- if (key) {
6950
- sessionStorage.removeItem(key);
6951
- }
6952
- this.tabs.set([]);
6953
- this.activeTabKey.set(null);
6954
- this.tabPreviewService.clearAll();
6955
- }
6956
- async restoreSessionIfNeeded() {
6957
- if (this.effectiveMode() === 'simple') {
6958
- return;
6959
- }
6960
- const storageKey = this.sessionStorageKey();
6961
- if (!storageKey) {
6962
- await this.ensureHomeTab();
6963
- await this.syncCurrentRouteAsTab();
6964
- return;
6965
- }
6966
- const raw = sessionStorage.getItem(storageKey);
6967
- if (!raw) {
6968
- await this.ensureHomeTab();
6969
- await this.syncCurrentRouteAsTab();
6970
- return;
6971
- }
6972
- try {
6973
- const parsed = JSON.parse(raw);
6974
- const restoredTabs = this.removeDuplicateHomeUrlTabs(this.normalizeRestoredTabKeys(defaultTo(parsed.tabs, []).filter((tab) => tab?.key && tab?.url)));
6975
- this.tabs.set(this.ensureHomeTabFirst(restoredTabs));
6976
- await this.ensureHomeTab();
6977
- const activeKey = parsed.activeTabKey ?? this.tabs()[this.tabs().length - 1]?.key ?? AXP_HOME_TAB_KEY;
6978
- this.activeTabKey.set(activeKey);
6979
- const activeTab = this.tabs().find((tab) => tab.key === activeKey);
6980
- if (activeTab && normalizeRouterUrl(this.router.url) !== normalizeRouterUrl(activeTab.url)) {
6981
- this.suppressNavigationSync = true;
6982
- try {
6983
- await this.router.navigateByUrl(activeTab.url);
6984
- }
6985
- finally {
6986
- this.suppressNavigationSync = false;
6987
- }
6988
- }
6989
- }
6990
- catch {
6991
- await this.ensureHomeTab();
6992
- await this.syncCurrentRouteAsTab();
6993
- }
6994
- }
6995
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabNavigationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6996
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabNavigationService, providedIn: 'root' }); }
6997
- }
6998
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTabNavigationService, decorators: [{
6999
- type: Injectable,
7000
- args: [{
7001
- providedIn: 'root',
7002
- }]
7003
- }], ctorParameters: () => [] });
7004
-
7005
- //TODO Loading, Redirect, Drawer, Show toast
7006
- const AXPRedirectEvent = createWorkFlowEvent('Redirect Event Fired');
7007
- const AXPRefreshEvent = createWorkFlowEvent('Refresh Event Fired');
7008
- const AXPReloadEvent = createWorkFlowEvent('Reload Event Fired');
7009
- class AXPWorkflowNavigateAction extends AXPWorkflowAction {
7010
- constructor() {
7011
- super(...arguments);
7012
- this.router = inject(Router);
7013
- this.tabNavigation = inject(AXPTabNavigationService);
7014
- }
7015
- async execute(context) {
7016
- const payload = context.getVariable('payload');
7017
- if (Array.isArray(payload.commands)) {
7018
- await this.router.navigate(payload.commands, payload.extras);
7019
- return;
7020
- }
7021
- const path = payload.commands;
7022
- if (!path) {
7023
- return;
7024
- }
7025
- if (path.toLowerCase().startsWith('http') || payload.target === 'blank') {
7026
- window.open(path, '_blank');
7027
- return;
7028
- }
7029
- await this.tabNavigation.navigate(path, payload.extras);
7030
- }
7031
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowNavigateAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
7032
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowNavigateAction }); }
7033
- }
7034
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowNavigateAction, decorators: [{
7035
- type: Injectable
5810
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowNavigateAction, decorators: [{
5811
+ type: Injectable
7036
5812
  }] });
7037
5813
  class AXPDialogConfirmAction extends AXPWorkflowAction {
7038
5814
  constructor() {
@@ -7093,7 +5869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7093
5869
  class AXPWorkflowRouterNavigateAction extends AXPWorkflowAction {
7094
5870
  constructor() {
7095
5871
  super(...arguments);
7096
- this.tabNavigation = inject(AXPTabNavigationService);
5872
+ this.router = inject(Router);
7097
5873
  }
7098
5874
  async execute(context) {
7099
5875
  const command = context.getVariable();
@@ -7106,7 +5882,7 @@ class AXPWorkflowRouterNavigateAction extends AXPWorkflowAction {
7106
5882
  window.open(path, '_blank');
7107
5883
  }
7108
5884
  else {
7109
- await this.tabNavigation.navigate(path, command.options.extras);
5885
+ await axpNavigateAppPath(this.router, path, command.options.extras);
7110
5886
  }
7111
5887
  }
7112
5888
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPWorkflowRouterNavigateAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -7180,14 +5956,13 @@ class AXPCommonModule {
7180
5956
  /**
7181
5957
  * @ignore
7182
5958
  */
7183
- constructor(instances, _keyboardShortcutsHelp, formatterRegistry) {
7184
- formatterRegistry.register(AXPTranslateFormatter);
5959
+ constructor(instances, _keyboardShortcutsHelp) {
7185
5960
  instances.forEach((f) => {
7186
5961
  f();
7187
5962
  });
7188
5963
  }
7189
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPCommonModule, deps: [{ token: 'AXPCommonModuleFactory' }, { token: AXPKeyboardShortcutsHelpService }, { token: i2$1.AXFormatterRegistryService }], target: i0.ɵɵFactoryTarget.NgModule }); }
7190
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPCommonModule, imports: [i3$1.AXPComponentSlotModule, i4$2.AXPWorkflowModule, AXPopupModule,
5964
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPCommonModule, deps: [{ token: 'AXPCommonModuleFactory' }, { token: AXPKeyboardShortcutsHelpService }], target: i0.ɵɵFactoryTarget.NgModule }); }
5965
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPCommonModule, imports: [i2$1.AXPComponentSlotModule, i3$1.AXPWorkflowModule, AXPopupModule,
7191
5966
  AXDateTimeModule,
7192
5967
  AXToastModule,
7193
5968
  AXPModuleManifestModule], exports: [RouterModule] }); }
@@ -7234,7 +6009,7 @@ class AXPCommonModule {
7234
6009
  provide: AXP_SETTING_DEFINITION_PROVIDER,
7235
6010
  useFactory: async () => {
7236
6011
  const injector = inject(Injector);
7237
- const provider = (await import('./acorex-platform-common-common-settings.provider-ChoT4m4k.mjs')).AXPCommonSettingProvider;
6012
+ const provider = (await import('./acorex-platform-common-common-settings.provider-Ytey9uhY.mjs')).AXPCommonSettingProvider;
7238
6013
  return new provider(injector);
7239
6014
  },
7240
6015
  multi: true,
@@ -7335,7 +6110,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7335
6110
  provide: AXP_SETTING_DEFINITION_PROVIDER,
7336
6111
  useFactory: async () => {
7337
6112
  const injector = inject(Injector);
7338
- const provider = (await import('./acorex-platform-common-common-settings.provider-ChoT4m4k.mjs')).AXPCommonSettingProvider;
6113
+ const provider = (await import('./acorex-platform-common-common-settings.provider-Ytey9uhY.mjs')).AXPCommonSettingProvider;
7339
6114
  return new provider(injector);
7340
6115
  },
7341
6116
  multi: true,
@@ -7345,7 +6120,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7345
6120
  }], ctorParameters: () => [{ type: undefined, decorators: [{
7346
6121
  type: Inject,
7347
6122
  args: ['AXPCommonModuleFactory']
7348
- }] }, { type: AXPKeyboardShortcutsHelpService }, { type: i2$1.AXFormatterRegistryService }] });
6123
+ }] }, { type: AXPKeyboardShortcutsHelpService }] });
7349
6124
 
7350
6125
  const ENVIRONMENT = new InjectionToken('ENVIRONMENT');
7351
6126
  const AXP_PLATFORM_CONFIG_TOKEN = new InjectionToken('AXP_PLATFORM_CONFIG_TOKEN', {
@@ -7560,6 +6335,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7560
6335
  type: Injectable
7561
6336
  }] });
7562
6337
 
6338
+ /**
6339
+ * Status Definition Types
6340
+ * Defines the structure for status definitions and their transitions
6341
+ */
6342
+ /**
6343
+ * Abstract class for status providers
6344
+ * Similar to AXPTaskBadgeProvider pattern
6345
+ */
6346
+ class AXPStatusProvider {
6347
+ }
6348
+ //#endregion
6349
+
7563
6350
  //#region ---- Injection Token ----
7564
6351
  /**
7565
6352
  * Injection token for status providers
@@ -7771,8 +6558,356 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
7771
6558
  args: [{ providedIn: 'root' }]
7772
6559
  }] });
7773
6560
 
7774
- //#region ---- Types ----
7775
- //#endregion
6561
+ /**
6562
+ * Standard system status types
6563
+ * These are the predefined status values used across the platform
6564
+ */
6565
+ var AXPSystemStatusType;
6566
+ (function (AXPSystemStatusType) {
6567
+ AXPSystemStatusType["Todo"] = "todo";
6568
+ AXPSystemStatusType["InProgress"] = "in-progress";
6569
+ AXPSystemStatusType["InReview"] = "in-review";
6570
+ AXPSystemStatusType["Open"] = "open";
6571
+ AXPSystemStatusType["Closed"] = "closed";
6572
+ AXPSystemStatusType["Blocked"] = "blocked";
6573
+ AXPSystemStatusType["Done"] = "done";
6574
+ AXPSystemStatusType["Cancelled"] = "cancelled";
6575
+ AXPSystemStatusType["Draft"] = "draft";
6576
+ AXPSystemStatusType["PendingReview"] = "pending-review";
6577
+ AXPSystemStatusType["WaitingSignOff"] = "waiting-sign-off";
6578
+ AXPSystemStatusType["WaitingApproval"] = "waiting-approval";
6579
+ AXPSystemStatusType["Approved"] = "approved";
6580
+ AXPSystemStatusType["Published"] = "published";
6581
+ AXPSystemStatusType["Archived"] = "archived";
6582
+ AXPSystemStatusType["Rejected"] = "rejected";
6583
+ AXPSystemStatusType["Active"] = "active";
6584
+ AXPSystemStatusType["Inactive"] = "inactive";
6585
+ AXPSystemStatusType["Pending"] = "pending";
6586
+ AXPSystemStatusType["Completed"] = "completed";
6587
+ AXPSystemStatusType["Suspended"] = "suspended";
6588
+ AXPSystemStatusType["Failed"] = "failed";
6589
+ AXPSystemStatusType["Review"] = "review";
6590
+ AXPSystemStatusType["Expired"] = "expired";
6591
+ })(AXPSystemStatusType || (AXPSystemStatusType = {}));
6592
+ const i18n = (key) => `@general:statuses.${key}`;
6593
+ /**
6594
+ * Standard system status definitions
6595
+ * Provides consistent status definitions across the platform
6596
+ * Uses AXPStatusDefinition interface from status-definition.types.ts
6597
+ */
6598
+ const AXPSystemStatuses = Object.freeze({
6599
+ Open: {
6600
+ name: AXPSystemStatusType.Open,
6601
+ title: i18n('open.title'),
6602
+ icon: 'fa-light fa-circle',
6603
+ color: 'secondary',
6604
+ description: i18n('open.description'),
6605
+ order: 1,
6606
+ isInitial: true,
6607
+ isFinal: false,
6608
+ },
6609
+ Closed: {
6610
+ name: AXPSystemStatusType.Closed,
6611
+ title: i18n('closed.title'),
6612
+ icon: 'fa-light fa-circle',
6613
+ color: 'danger',
6614
+ description: i18n('closed.description'),
6615
+ order: 2,
6616
+ isInitial: false,
6617
+ isFinal: true,
6618
+ },
6619
+ Todo: {
6620
+ name: AXPSystemStatusType.Todo,
6621
+ title: i18n('todo.title'),
6622
+ icon: 'fa-light fa-circle',
6623
+ color: 'secondary',
6624
+ description: i18n('todo.description'),
6625
+ order: 1,
6626
+ isInitial: true,
6627
+ isFinal: false,
6628
+ },
6629
+ InProgress: {
6630
+ name: AXPSystemStatusType.InProgress,
6631
+ title: i18n('in-progress.title'),
6632
+ icon: 'fa-light fa-play',
6633
+ color: 'info',
6634
+ description: i18n('in-progress.description'),
6635
+ order: 2,
6636
+ isInitial: false,
6637
+ isFinal: false,
6638
+ },
6639
+ InReview: {
6640
+ name: AXPSystemStatusType.InReview,
6641
+ title: i18n('in-review.title'),
6642
+ icon: 'fa-light fa-eye',
6643
+ color: 'info',
6644
+ description: i18n('in-review.description'),
6645
+ order: 3,
6646
+ isInitial: false,
6647
+ isFinal: false,
6648
+ },
6649
+ Blocked: {
6650
+ name: AXPSystemStatusType.Blocked,
6651
+ title: i18n('blocked.title'),
6652
+ icon: 'fa-light fa-ban',
6653
+ color: 'danger',
6654
+ description: i18n('blocked.description'),
6655
+ order: 4,
6656
+ isInitial: false,
6657
+ isFinal: false,
6658
+ },
6659
+ Done: {
6660
+ name: AXPSystemStatusType.Done,
6661
+ title: i18n('done.title'),
6662
+ icon: 'fa-light fa-check-circle',
6663
+ color: 'success',
6664
+ description: i18n('done.description'),
6665
+ order: 5,
6666
+ isInitial: false,
6667
+ isFinal: true,
6668
+ },
6669
+ Cancelled: {
6670
+ name: AXPSystemStatusType.Cancelled,
6671
+ title: i18n('cancelled.title'),
6672
+ icon: 'fa-light fa-times-circle',
6673
+ color: 'neutral',
6674
+ description: i18n('cancelled.description'),
6675
+ order: 6,
6676
+ isInitial: false,
6677
+ isFinal: true,
6678
+ },
6679
+ Draft: {
6680
+ name: AXPSystemStatusType.Draft,
6681
+ title: i18n('draft.title'),
6682
+ icon: 'fa-light fa-file-pen',
6683
+ color: 'neutral',
6684
+ description: i18n('draft.description'),
6685
+ order: 1,
6686
+ isInitial: true,
6687
+ isFinal: false,
6688
+ },
6689
+ PendingReview: {
6690
+ name: AXPSystemStatusType.PendingReview,
6691
+ title: i18n('pending-review.title'),
6692
+ icon: 'fa-light fa-clock',
6693
+ color: 'warning',
6694
+ description: i18n('pending-review.description'),
6695
+ order: 2,
6696
+ isInitial: false,
6697
+ isFinal: false,
6698
+ },
6699
+ WaitingSignOff: {
6700
+ name: AXPSystemStatusType.WaitingSignOff,
6701
+ title: i18n('waiting-sign-off.title'),
6702
+ icon: 'fa-light fa-clock',
6703
+ color: 'warning',
6704
+ description: i18n('waiting-sign-off.description'),
6705
+ order: 3,
6706
+ isInitial: false,
6707
+ isFinal: false,
6708
+ },
6709
+ WaitingApproval: {
6710
+ name: AXPSystemStatusType.WaitingApproval,
6711
+ title: i18n('waiting-approval.title'),
6712
+ icon: 'fa-light fa-clock',
6713
+ color: 'warning',
6714
+ description: i18n('waiting-approval.description'),
6715
+ order: 1,
6716
+ isInitial: true,
6717
+ isFinal: false,
6718
+ },
6719
+ Approved: {
6720
+ name: AXPSystemStatusType.Approved,
6721
+ title: i18n('approved.title'),
6722
+ icon: 'fa-light fa-check-circle',
6723
+ color: 'success',
6724
+ description: i18n('approved.description'),
6725
+ order: 3,
6726
+ isInitial: false,
6727
+ isFinal: false,
6728
+ },
6729
+ Published: {
6730
+ name: AXPSystemStatusType.Published,
6731
+ title: i18n('published.title'),
6732
+ icon: 'fa-light fa-globe',
6733
+ color: 'primary',
6734
+ description: i18n('published.description'),
6735
+ order: 4,
6736
+ isInitial: false,
6737
+ isFinal: false,
6738
+ },
6739
+ Archived: {
6740
+ name: AXPSystemStatusType.Archived,
6741
+ title: i18n('archived.title'),
6742
+ icon: 'fa-light fa-archive',
6743
+ color: 'danger',
6744
+ description: i18n('archived.description'),
6745
+ order: 5,
6746
+ isInitial: false,
6747
+ isFinal: true,
6748
+ },
6749
+ Rejected: {
6750
+ name: AXPSystemStatusType.Rejected,
6751
+ title: i18n('rejected.title'),
6752
+ icon: 'fa-light fa-times-circle',
6753
+ color: 'danger',
6754
+ description: i18n('rejected.description'),
6755
+ order: 6,
6756
+ isInitial: false,
6757
+ isFinal: true,
6758
+ },
6759
+ Active: {
6760
+ name: AXPSystemStatusType.Active,
6761
+ title: i18n('active.title'),
6762
+ icon: 'fa-light fa-check-circle',
6763
+ color: 'success',
6764
+ description: i18n('active.description'),
6765
+ order: 1,
6766
+ isInitial: false,
6767
+ isFinal: false,
6768
+ },
6769
+ Inactive: {
6770
+ name: AXPSystemStatusType.Inactive,
6771
+ title: i18n('inactive.title'),
6772
+ icon: 'fa-light fa-circle',
6773
+ color: 'secondary',
6774
+ description: i18n('inactive.description'),
6775
+ order: 2,
6776
+ isInitial: false,
6777
+ isFinal: false,
6778
+ },
6779
+ Pending: {
6780
+ name: AXPSystemStatusType.Pending,
6781
+ title: i18n('pending.title'),
6782
+ icon: 'fa-light fa-clock',
6783
+ color: 'warning',
6784
+ description: i18n('pending.description'),
6785
+ order: 1,
6786
+ isInitial: true,
6787
+ isFinal: false,
6788
+ },
6789
+ Completed: {
6790
+ name: AXPSystemStatusType.Completed,
6791
+ title: i18n('completed.title'),
6792
+ icon: 'fa-light fa-check-circle',
6793
+ color: 'success',
6794
+ description: i18n('completed.description'),
6795
+ order: 10,
6796
+ isInitial: false,
6797
+ isFinal: true,
6798
+ },
6799
+ Suspended: {
6800
+ name: AXPSystemStatusType.Suspended,
6801
+ title: i18n('suspended.title'),
6802
+ icon: 'fa-light fa-pause-circle',
6803
+ color: 'neutral',
6804
+ description: i18n('suspended.description'),
6805
+ order: 5,
6806
+ isInitial: false,
6807
+ isFinal: false,
6808
+ },
6809
+ Failed: {
6810
+ name: AXPSystemStatusType.Failed,
6811
+ title: i18n('failed.title'),
6812
+ icon: 'fa-light fa-xmark-circle',
6813
+ color: 'danger',
6814
+ description: i18n('failed.description'),
6815
+ order: 10,
6816
+ isInitial: false,
6817
+ isFinal: true,
6818
+ },
6819
+ Review: {
6820
+ name: AXPSystemStatusType.Review,
6821
+ title: i18n('review.title'),
6822
+ icon: 'fa-light fa-eye',
6823
+ color: 'info',
6824
+ description: i18n('review.description'),
6825
+ order: 3,
6826
+ },
6827
+ Expired: {
6828
+ name: AXPSystemStatusType.Expired,
6829
+ title: i18n('expired.title'),
6830
+ icon: 'fa-light fa-clock',
6831
+ color: 'danger',
6832
+ description: i18n('expired.description'),
6833
+ order: 10,
6834
+ isInitial: false,
6835
+ isFinal: true,
6836
+ },
6837
+ });
6838
+ /**
6839
+ * Get system status definition by type
6840
+ * @param type - Status type
6841
+ * @returns System status definition or undefined
6842
+ */
6843
+ function getSystemStatus(type) {
6844
+ return Object.values(AXPSystemStatuses).find(status => status.name === type);
6845
+ }
6846
+ /**
6847
+ * Resolves the visual appearance (color and icon) for status
6848
+ * using the system statuses from the core module.
6849
+ * @param statusType - Status type string
6850
+ * @returns Color and icon for the status
6851
+ */
6852
+ function resolveStatusLook(statusType) {
6853
+ // Try to get system status first
6854
+ const systemStatusType = statusType;
6855
+ if (systemStatusType) {
6856
+ const systemStatus = getSystemStatus(systemStatusType);
6857
+ if (systemStatus) {
6858
+ // Convert hex color to semantic color type if needed
6859
+ // For now, return as-is and let the UI handle it
6860
+ return {
6861
+ color: systemStatus.color,
6862
+ icon: systemStatus.icon || ''
6863
+ };
6864
+ }
6865
+ }
6866
+ // Fallback for unknown statuses
6867
+ return {
6868
+ color: 'secondary',
6869
+ icon: ''
6870
+ };
6871
+ }
6872
+ /**
6873
+ * Resolves the complete status information (title, description, icon, color) for a status
6874
+ * using the system statuses from the core module.
6875
+ * @param statusType - Status type string
6876
+ * @returns Complete status information as AXPStatusDefinition
6877
+ */
6878
+ function getStatusInfo(statusType) {
6879
+ const systemStatusType = statusType;
6880
+ if (systemStatusType) {
6881
+ const systemStatus = getSystemStatus(systemStatusType);
6882
+ if (systemStatus) {
6883
+ return systemStatus;
6884
+ }
6885
+ }
6886
+ // Fallback for unknown statuses
6887
+ return {
6888
+ name: statusType,
6889
+ title: statusType,
6890
+ description: `Status: ${statusType}`,
6891
+ icon: '',
6892
+ color: 'secondary'
6893
+ };
6894
+ }
6895
+ /**
6896
+ * Get system status definition directly (no conversion needed since it's already AXPStatusDefinition)
6897
+ * @param statusType - Status type
6898
+ * @param overrides - Optional overrides for the status definition
6899
+ * @returns AXPStatusDefinition
6900
+ */
6901
+ function systemStatusToDefinition(statusType, overrides) {
6902
+ const systemStatus = getSystemStatus(statusType);
6903
+ if (!systemStatus) {
6904
+ throw new Error(`System status ${statusType} not found`);
6905
+ }
6906
+ return {
6907
+ ...systemStatus,
6908
+ ...overrides,
6909
+ };
6910
+ }
7776
6911
 
7777
6912
  class AXPClipBoardService {
7778
6913
  constructor() {
@@ -8455,5 +7590,5 @@ class AXPVersioningService {
8455
7590
  * Generated bundle index. Do not edit.
8456
7591
  */
8457
7592
 
8458
- export { ALL_DEFAULT_OPERATORS, AXMWorkflowErrorHandler, AXPAppVersionService, AXPBackgroundOperationCompletionService, AXPBackgroundOperationEntityStoreService, AXPBackgroundOperationHandler, AXPBackgroundOperationNotificationService, AXPBackgroundOperationProvider, AXPBackgroundOperationRootConfig, AXPBackgroundOperationService, AXPBackgroundOperationSlotComponent, AXPCleanNestedFilters, AXPClipBoardService, AXPCommonModule, AXPCommonSettings, AXPCustomOperatorService, AXPCustomOperatorServiceImpl, AXPDataProvider, AXPDebugService, AXPDefaultMultiLanguageConfigService, AXPDialogConfirmAction, AXPErrorHandlerRegistryService, AXPExportService, AXPFileActionsService, AXPFileStorageEvaluatorScopeProvider, AXPFileStorageService, AXPFileTypeProviderService, AXPFilterOperatorMiddlewareService, AXPFilterOperatorMiddlewareServiceImpl, AXPFooterTextSlotComponent, AXPGlobalErrorHandler, AXPHomePageModule, AXPHomePageService, AXPKeyboardShortcutsHelpComponent, AXPKeyboardShortcutsHelpService, AXPLockService, AXPMenuItemsDataSourceDefinition, AXPMenuKeyboardShortcutService, AXPMenuMiddlewareRegistry, AXPMenuProviderService, AXPMenuRouteAccessService, AXPMenuRouteGuard, AXPMenuSearchDefinitionProvider, AXPMenuSearchProvider, AXPMenuService, AXPMenuVisibilityService, AXPNavBarSlotComponent, AXPNavigateWorkflow, AXPNotFoundCatchAllRoute, AXPNotFoundError, AXPOutputContractTranscriptSegmentService, AXPPlatformCommonDataSourceKeys, AXPPlatformDefaultConfigs, AXPRedirectEvent, AXPRefreshEvent, AXPRegionalCalendarService, AXPReloadAction, AXPReloadEvent, AXPSearchCommandProvider, AXPSearchDefinitionActionBuilder, AXPSearchDefinitionBuilder, AXPSearchDefinitionProviderContext, AXPSearchDefinitionProviderService, AXPSearchService, AXPSettingDefaultValuesAggregatorService, AXPSettingDefinitionGroupBuilder, AXPSettingDefinitionProviderContext, AXPSettingDefinitionProviderService, AXPSettingDefinitionSectionBuilder, AXPSettingsEvaluatorScopeProvider, AXPSettingsService, AXPStatusDefinitionProviderService, AXPStickyDirective, AXPTabNavigationService, AXPTabPreviewService, AXPTabRouteCacheRegistry, AXPToastAction, AXPTokenDefinitionService, AXPTokenEvaluatorScopeProvider, AXPTranslateFormatter, AXPUnsavedChangesConfirmService, AXPUnsavedChangesPopstateService, AXPVersioningService, AXPWorkflowNavigateAction, AXPWorkflowRouterNavigateAction, AXP_AGENT_OUTPUT_CONTRACT_DEFAULT_STRUCTURED_RETRIES, AXP_APP_VERSION_PROVIDER, AXP_BACKGROUND_OPERATION_ENTITY_STORAGE, AXP_BACKGROUND_OPERATION_HANDLERS, AXP_BACKGROUND_OPERATION_PROVIDERS, AXP_FILE_ACTION_PROVIDER, AXP_FILE_TYPE_INFO_PROVIDER, AXP_HOME_PAGES, AXP_HOME_PAGE_DEFAULT_KEY, AXP_HOME_TAB_KEY, AXP_IN_APP_NOTIFICATION_SERVICE, AXP_LOCALE_MANAGEMENT_PORT, AXP_MENU_MIDDLEWARE, AXP_MENU_PROVIDER, AXP_NOT_FOUND_CATCH_ALL_ROUTE, AXP_NOT_FOUND_ROUTE, AXP_OUTPUT_CONTRACT_TRANSCRIPT_SEGMENT_PROVIDER, AXP_PLATFORM_CONFIG_TOKEN, AXP_PROTECTED_ROUTE_GUARDS, AXP_ROOT_CONFIG_TOKEN, AXP_SEARCH_DEFINITION_LAZY_RESOLVER, AXP_SEARCH_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER, AXP_SETTING_DEFAULT_VALUES_PROVIDERS, AXP_SETTING_DEFINITION_PROVIDER, AXP_SETTING_VALUE_PROVIDER, AXP_STATUS_PROVIDERS, AXP_TAB_ROUTE_DATA_KEY, AXP_TOKEN_DEFINITION_PROVIDER, AXP_UNAUTHORIZED_ROUTE, AXVChangeType, BETWEEN_OPER, BOOLEAN_OPERATORS, CONTAINS_OPER, DATE_OPERATORS, DEFAULT_DATE_FILTER_PRESETS, DEFAULT_MULTILANGUAGE_FIELD_NAMES, ENDS_WITH_OPER, ENTITY_LAYOUT_SINGLE_TITLE_PATH, ENTITY_ROW_POPUP_TITLE_OPTION, ENTITY_ROW_TITLE_TEMPLATE_OPTION, ENVIRONMENT, EQ_OPER, GTE_OPER, GT_OPER, IN_OPER, IS_EMPTY_OPER, IS_NOT_EMPTY_OPER, LTE_OPER, LT_OPER, MULTILANGUAGE_CAPABLE_WIDGET_TYPES, NOT_CONTAINS_OPER, NOT_EQ_OPER, NUMBER_OPERATORS, STARTS_WITH_OPER, STRING_OPERATORS, UploadFromComputerActionProvider, applyDateFilterPreset, axpBackgroundOperationCapabilities, axpBackgroundOperationDisplayTime, axpBackgroundOperationEntityName, axpBackgroundOperationEstimateEndDate, axpBackgroundOperationFailurePolicy, axpBackgroundOperationFromEntityModel, axpBackgroundOperationRemainingMs, axpBackgroundOperationToEntityModel, axpBuildBackgroundOperation, axpBuildTabKey, axpCoerceBackgroundOperationDate, axpCreateBackgroundOperationId, axpFallbackTabTitle, axpFindMenuItemByRoute, axpGetLeafRouteSnapshot, axpHasTabScope, axpIsActiveBackgroundOperationStatus, axpIsCompletedBackgroundOperationStatus, axpIsEntityDetailsPath, axpIsEntityDetailsViewRoute, axpIsEntityListPath, axpIsEntityListRoute, axpIsEntityRecordNotFound, axpIsTabEligibleUrl, axpMenuPathsMatch, axpNavigateAppPath, axpParseAppPath, axpPathFromSnapshot, axpRedirectToNotFound, axpRedirectToUnauthorized, axpReplaceEntityListRouteQueryParams, axpResolveTabKey, axpResolveTabKeyFromRouteConfig, axpResolveTabKeyFromSnapshot, backgroundOperationEntityFactory, buildEntitySearchTitleContext, coerceAXPSettingRawValue, coerceAXPSettingRawValueByKind, configPlatform, createBackgroundOperationStore, createEntityCommandOptions, createEntityRowExpressionScope, createEntitySearchCommand, createMenuContext, createMenuMiddleware, createUnsavedChangesCanDeactivateGuard, downloadGraphicFromElement, evaluateEntityDisplayTemplate, findManualPresetIdByOperation, formatEntityRowDisplayTitle, inferSettingCoercionKind, isMeaningfulEntityDisplayTitle, isUnresolvedEntityDisplayTemplate, normalizeEntityDisplayTemplate, normalizePositiveNumberOption, normalizeRouterUrl, peelSettingValueKey, printGraphicFromElement, provideDynamicHomePage, provideMenuMiddleware, resolveDateFilterPresets, resolveEntityModifyPopupTitle, resolveEntityModifyRecordTitleTemplate, resolveEntityRowDisplayText, resolveEntityRowDisplayTitle, resolveEntityRowDisplayTitleFromColumnContext, resolveEntityRowTitleTemplate, resolveEntitySearchTitleFallback, resolveGraphicElementSize, resolveGraphicPrintContent, resolveQueryMatchingDisplayText, resolveSearchDisplayTemplate, resolveSearchableText, sanitizeResolvedEntityDisplayTitle, searchInRecordValues, searchInSearchableValue, serializeSvgElement, shouldApplyDefaultMultiLanguageToEntityProperty, shouldApplyDefaultMultiLanguageToWidgetNode, shouldApplyDefaultMultiLanguageToWidgetProperty, triggerBrowserDownload, withDefaultMultiLanguageOnWidgetNodeTree, withDefaultMultiLanguageOnWidgetProperty };
7593
+ export { ALL_DEFAULT_OPERATORS, AXMWorkflowErrorHandler, AXPAppVersionService, AXPBackgroundOperationCompletionService, AXPBackgroundOperationEntityStoreService, AXPBackgroundOperationHandler, AXPBackgroundOperationNotificationService, AXPBackgroundOperationProvider, AXPBackgroundOperationRootConfig, AXPBackgroundOperationService, AXPBackgroundOperationSlotComponent, AXPCleanNestedFilters, AXPClipBoardService, AXPCommonModule, AXPCommonSettings, AXPCustomOperatorService, AXPCustomOperatorServiceImpl, AXPDataProvider, AXPDebugService, AXPDefaultMultiLanguageConfigService, AXPDialogConfirmAction, AXPEntityCommandScope, AXPEntityQueryType, AXPEntityType, AXPErrorHandlerRegistryService, AXPExportService, AXPFileActionsService, AXPFileStorageEvaluatorScopeProvider, AXPFileStorageService, AXPFileTypeProviderService, AXPFilterOperatorMiddlewareService, AXPFilterOperatorMiddlewareServiceImpl, AXPFooterTextSlotComponent, AXPGlobalErrorHandler, AXPHomePageModule, AXPHomePageService, AXPKeyboardShortcutsHelpComponent, AXPKeyboardShortcutsHelpService, AXPLockService, AXPMenuItemsDataSourceDefinition, AXPMenuKeyboardShortcutService, AXPMenuMiddlewareRegistry, AXPMenuProviderService, AXPMenuRouteAccessService, AXPMenuRouteGuard, AXPMenuSearchDefinitionProvider, AXPMenuSearchProvider, AXPMenuService, AXPMenuVisibilityService, AXPNavBarSlotComponent, AXPNavigateWorkflow, AXPNotFoundCatchAllRoute, AXPNotFoundError, AXPOutputContractTranscriptSegmentService, AXPPlatformCommonDataSourceKeys, AXPPlatformDefaultConfigs, AXPRedirectEvent, AXPRefreshEvent, AXPRegionalCalendarService, AXPRegionalSetting, AXPRelationshipCardinality, AXPRelationshipKind, AXPReloadAction, AXPReloadEvent, AXPSearchCommandProvider, AXPSearchDefinitionActionBuilder, AXPSearchDefinitionBuilder, AXPSearchDefinitionProviderContext, AXPSearchDefinitionProviderService, AXPSearchService, AXPSettingDefaultValuesAggregatorService, AXPSettingDefinitionGroupBuilder, AXPSettingDefinitionProviderContext, AXPSettingDefinitionProviderService, AXPSettingDefinitionSectionBuilder, AXPSettingsEvaluatorScopeProvider, AXPSettingsService, AXPStatusDefinitionProviderService, AXPStatusProvider, AXPStickyDirective, AXPSystemStatusType, AXPSystemStatuses, AXPToastAction, AXPTokenDefinitionService, AXPTokenEvaluatorScopeProvider, AXPUnsavedChangesConfirmService, AXPUnsavedChangesPopstateService, AXPVersioningService, AXPWorkflowNavigateAction, AXPWorkflowRouterNavigateAction, AXP_AGENT_OUTPUT_CONTRACT_DEFAULT_STRUCTURED_RETRIES, AXP_APP_VERSION_PROVIDER, AXP_BACKGROUND_OPERATION_ENTITY_STORAGE, AXP_BACKGROUND_OPERATION_HANDLERS, AXP_BACKGROUND_OPERATION_PROVIDERS, AXP_FILE_ACTION_PROVIDER, AXP_FILE_TYPE_INFO_PROVIDER, AXP_HOME_PAGES, AXP_HOME_PAGE_DEFAULT_KEY, AXP_IN_APP_NOTIFICATION_SERVICE, AXP_LOCALE_MANAGEMENT_PORT, AXP_MENU_MIDDLEWARE, AXP_MENU_PROVIDER, AXP_NOT_FOUND_CATCH_ALL_ROUTE, AXP_NOT_FOUND_ROUTE, AXP_OUTPUT_CONTRACT_TRANSCRIPT_SEGMENT_PROVIDER, AXP_PLATFORM_CONFIG_TOKEN, AXP_PROTECTED_ROUTE_GUARDS, AXP_ROOT_CONFIG_TOKEN, AXP_SEARCH_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER, AXP_SETTING_DEFAULT_VALUES_PROVIDERS, AXP_SETTING_DEFINITION_PROVIDER, AXP_SETTING_VALUE_PROVIDER, AXP_STATUS_PROVIDERS, AXP_TOKEN_DEFINITION_PROVIDER, AXP_UNAUTHORIZED_ROUTE, AXVChangeType, BETWEEN_OPER, BOOLEAN_OPERATORS, CONTAINS_OPER, DATE_OPERATORS, DEFAULT_DATE_FILTER_PRESETS, DEFAULT_MULTILANGUAGE_FIELD_NAMES, ENDS_WITH_OPER, ENTITY_LAYOUT_SINGLE_TITLE_PATH, ENTITY_ROW_POPUP_TITLE_OPTION, ENTITY_ROW_TITLE_TEMPLATE_OPTION, ENVIRONMENT, EQ_OPER, GTE_OPER, GT_OPER, IN_OPER, IS_EMPTY_OPER, IS_NOT_EMPTY_OPER, LTE_OPER, LT_OPER, MULTILANGUAGE_CAPABLE_WIDGET_TYPES, NOT_CONTAINS_OPER, NOT_EQ_OPER, NUMBER_OPERATORS, STARTS_WITH_OPER, STRING_OPERATORS, UploadFromComputerActionProvider, applyDateFilterPreset, axpBackgroundOperationCapabilities, axpBackgroundOperationDisplayTime, axpBackgroundOperationEntityName, axpBackgroundOperationEstimateEndDate, axpBackgroundOperationFailurePolicy, axpBackgroundOperationFromEntityModel, axpBackgroundOperationRemainingMs, axpBackgroundOperationToEntityModel, axpBuildBackgroundOperation, axpCoerceBackgroundOperationDate, axpCreateBackgroundOperationId, axpFindMenuItemByRoute, axpIsActiveBackgroundOperationStatus, axpIsCompletedBackgroundOperationStatus, axpIsEntityDetailsPath, axpIsEntityDetailsViewRoute, axpIsEntityListPath, axpIsEntityListRoute, axpIsEntityRecordNotFound, axpMenuPathsMatch, axpNavigateAppPath, axpParseAppPath, axpRedirectToNotFound, axpRedirectToUnauthorized, axpReplaceEntityListRouteQueryParams, backgroundOperationEntityFactory, buildEntitySearchTitleContext, coerceAXPSettingRawValue, coerceAXPSettingRawValueByKind, configPlatform, createAllQueryView, createBackgroundOperationStore, createEntityCommandOptions, createEntityRowExpressionScope, createEntitySearchCommand, createMenuContext, createMenuMiddleware, createQueryView, createUnsavedChangesCanDeactivateGuard, downloadGraphicFromElement, evaluateEntityDisplayTemplate, findManualPresetIdByOperation, formatEntityRowDisplayTitle, getEntityInfo, getStatusInfo, getSystemStatus, inferSettingCoercionKind, isCardFieldBadgeDisplay, isMeaningfulEntityDisplayTitle, isUnresolvedEntityDisplayTemplate, normalizeEntityDisplayTemplate, normalizePositiveNumberOption, peelSettingValueKey, printGraphicFromElement, provideDynamicHomePage, provideMenuMiddleware, resolveCardFieldBadgeColor, resolveDateFilterPresets, resolveDefaultMasterListLayout, resolveEnabledMasterListLayouts, resolveEntityRowDisplayText, resolveEntityRowDisplayTitle, resolveEntityRowDisplayTitleFromColumnContext, resolveEntityRowTitleTemplate, resolveEntitySearchTitleFallback, resolveGraphicElementSize, resolveGraphicPrintContent, resolveQueryMatchingDisplayText, resolveSearchDisplayTemplate, resolveSearchableText, resolveStatusLook, sanitizeResolvedEntityDisplayTitle, searchInRecordValues, searchInSearchableValue, serializeSvgElement, shouldApplyDefaultMultiLanguageToEntityProperty, shouldApplyDefaultMultiLanguageToWidgetNode, shouldApplyDefaultMultiLanguageToWidgetProperty, systemStatusToDefinition, triggerBrowserDownload, withDefaultMultiLanguageOnWidgetNodeTree, withDefaultMultiLanguageOnWidgetProperty };
8459
7594
  //# sourceMappingURL=acorex-platform-common.mjs.map