@acorex/platform 20.9.19 → 20.9.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/acorex-platform-common.mjs +43 -4
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +220 -43
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +70 -12
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-layout-entity.d.ts +49 -3
- package/types/acorex-platform-themes-default.d.ts +8 -0
|
@@ -1241,12 +1241,15 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1241
1241
|
this.deviceService = inject(AXPDeviceService);
|
|
1242
1242
|
this.parent = inject(AXPEntityMasterListViewComponent);
|
|
1243
1243
|
this.router = inject(Router);
|
|
1244
|
+
this.activeRoute = inject(ActivatedRoute);
|
|
1244
1245
|
this.settingsService = inject(AXPSettingsService);
|
|
1245
1246
|
this.injector = inject(Injector);
|
|
1246
1247
|
this.isInitializing = false;
|
|
1247
1248
|
this.pendingInitialSorts = true;
|
|
1248
1249
|
this.filterTriggerMode = 'manual';
|
|
1249
1250
|
this.previousFilterQueries = signal([], ...(ngDevMode ? [{ debugName: "previousFilterQueries" }] : /* istanbul ignore next */ []));
|
|
1251
|
+
/** Gates query-filters until `initialFilters` are seeded (prevents empty emit wiping persisted filters). */
|
|
1252
|
+
this.filtersReady = signal(false, ...(ngDevMode ? [{ debugName: "filtersReady" }] : /* istanbul ignore next */ []));
|
|
1250
1253
|
this.initialFilters = signal([], ...(ngDevMode ? [{ debugName: "initialFilters" }] : /* istanbul ignore next */ []));
|
|
1251
1254
|
this.filtersDefinitions = signal([], ...(ngDevMode ? [{ debugName: "filtersDefinitions" }] : /* istanbul ignore next */ []));
|
|
1252
1255
|
this.viewQueries = computed(() => this.vm.views().map((v) => ({
|
|
@@ -1291,7 +1294,10 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1291
1294
|
// Debounced apply to coalesce multiple UI changes (filters/sorts/columns)
|
|
1292
1295
|
this.applyTimer = null;
|
|
1293
1296
|
this.#effect = effect(() => {
|
|
1294
|
-
// Keep definitions up to date
|
|
1297
|
+
// Keep definitions up to date after the initial filter seed (initial filters are set explicitly)
|
|
1298
|
+
if (!this.filtersReady()) {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1295
1301
|
this.filtersDefinitions.set(this.vm.filterDefinitions());
|
|
1296
1302
|
}, ...(ngDevMode ? [{ debugName: "#effect" }] : /* istanbul ignore next */ []));
|
|
1297
1303
|
this.sortQueries = computed(() => this.vm
|
|
@@ -1321,11 +1327,10 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1321
1327
|
}, ...(ngDevMode ? [{ debugName: "sortDefinitions" }] : /* istanbul ignore next */ []));
|
|
1322
1328
|
}
|
|
1323
1329
|
async ngOnInit() {
|
|
1324
|
-
// Prefer saved settings
|
|
1330
|
+
// Prefer URL `view` over saved settings; fall back to settings when URL has no view.
|
|
1325
1331
|
await this.loadSettings();
|
|
1326
|
-
await this.vm.setView();
|
|
1332
|
+
await this.vm.setView(this.activeRoute.snapshot.queryParamMap.get('view'));
|
|
1327
1333
|
await this.vm.ensureListPagingResolved();
|
|
1328
|
-
this.filtersDefinitions.set(this.vm.filterDefinitions());
|
|
1329
1334
|
await this.runInitialListLoad();
|
|
1330
1335
|
}
|
|
1331
1336
|
/**
|
|
@@ -1336,9 +1341,12 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1336
1341
|
this.isInitializing = true;
|
|
1337
1342
|
this.pendingInitialSorts = true;
|
|
1338
1343
|
this.setInitialFiltersFromSettingsOrView();
|
|
1344
|
+
this.filtersDefinitions.set(this.vm.filterDefinitions());
|
|
1345
|
+
this.filtersReady.set(true);
|
|
1339
1346
|
await this.waitForQueryFiltersSync();
|
|
1340
1347
|
await this.vm.applyFilterAndSort();
|
|
1341
1348
|
this.previousFilterQueries.set(this.vm.filterQueries());
|
|
1349
|
+
this.stripFiltersFromRouteQueryParam();
|
|
1342
1350
|
this.isInitializing = false;
|
|
1343
1351
|
this.pendingInitialSorts = false;
|
|
1344
1352
|
}
|
|
@@ -1367,6 +1375,7 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1367
1375
|
async onViewChanged(view) {
|
|
1368
1376
|
await this.vm.setView(view.name);
|
|
1369
1377
|
if (axpIsEntityListRoute(this.router)) {
|
|
1378
|
+
this.vm.markRouteQueryContextSynced(this.activeRoute.snapshot.queryParamMap, { view: view.name });
|
|
1370
1379
|
axpReplaceEntityListRouteQueryParams(this.router, { view: view.name });
|
|
1371
1380
|
}
|
|
1372
1381
|
await this.runInitialListLoad();
|
|
@@ -1393,15 +1402,33 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1393
1402
|
this.previousFilterQueries.set(filters);
|
|
1394
1403
|
return;
|
|
1395
1404
|
}
|
|
1405
|
+
if (!this.filtersReady()) {
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1396
1408
|
this.vm.filterQueries.set(filters);
|
|
1397
1409
|
if (this.filterTriggerMode === 'auto') {
|
|
1398
|
-
this.applyFilters();
|
|
1410
|
+
void this.applyFilters();
|
|
1399
1411
|
}
|
|
1400
1412
|
}
|
|
1401
|
-
applyFilters() {
|
|
1413
|
+
async applyFilters() {
|
|
1414
|
+
const persistableFilters = this.vm.getPersistableFilterQueries();
|
|
1402
1415
|
this.previousFilterQueries.set(this.vm.filterQueries());
|
|
1403
|
-
this.vm.saveSettings('filters',
|
|
1404
|
-
|
|
1416
|
+
await this.vm.saveSettings('filters', persistableFilters);
|
|
1417
|
+
this.stripFiltersFromRouteQueryParam();
|
|
1418
|
+
await this.vm.applyFilterAndSort();
|
|
1419
|
+
}
|
|
1420
|
+
/** Removes `filters` from the entity list URL; filter state is persisted in user settings only. */
|
|
1421
|
+
stripFiltersFromRouteQueryParam() {
|
|
1422
|
+
if (!axpIsEntityListRoute(this.router)) {
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
const url = this.router.url;
|
|
1426
|
+
if (!url.includes('filters=')) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
// Mark the post-strip key first so queryParamMap emission does not trigger an extra list reload.
|
|
1430
|
+
this.vm.markRouteQueryContextSynced(this.activeRoute.snapshot.queryParamMap, { filters: null });
|
|
1431
|
+
axpReplaceEntityListRouteQueryParams(this.router, { filters: null });
|
|
1405
1432
|
}
|
|
1406
1433
|
onSortQueriesChange(e) {
|
|
1407
1434
|
if (this.isInitializing || this.pendingInitialSorts) {
|
|
@@ -1450,7 +1477,7 @@ class AXPEntityMasterToolbarViewComponent {
|
|
|
1450
1477
|
// this.scheduleApply();
|
|
1451
1478
|
}
|
|
1452
1479
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityMasterToolbarViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1453
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPEntityMasterToolbarViewComponent, isStandalone: true, selector: "axp-entity-master-toolbar-view", inputs: { vm: ["viewModel", "vm"] }, host: { classAttribute: "ax-w-full" }, viewQueries: [{ propertyName: "listDisplayModePopover", first: true, predicate: ["listDisplayModePopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- <axp-entity-view-toolbar [viewModel]=\"vm\"></axp-entity-view-toolbar> -->\n<axp-query-views\n id=\"axp-toolbar-view-selector\"\n [views]=\"viewQueries()\"\n [selectedView]=\"selectedViewQuery()\"\n (selectedViewChange)=\"onViewChanged($event)\"\n></axp-query-views>\n<div class=\"ax-flex ax-items-center ax-gap-2 ax-border-b ax-border-light w-full\">\n <!-- <axp-entity-filter-toolbar [viewModel]=\"vm\"></axp-entity-filter-toolbar> -->\n <axp-query-filters\n
|
|
1480
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXPEntityMasterToolbarViewComponent, isStandalone: true, selector: "axp-entity-master-toolbar-view", inputs: { vm: ["viewModel", "vm"] }, host: { classAttribute: "ax-w-full" }, viewQueries: [{ propertyName: "listDisplayModePopover", first: true, predicate: ["listDisplayModePopover"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- <axp-entity-view-toolbar [viewModel]=\"vm\"></axp-entity-view-toolbar> -->\n<axp-query-views\n id=\"axp-toolbar-view-selector\"\n [views]=\"viewQueries()\"\n [selectedView]=\"selectedViewQuery()\"\n (selectedViewChange)=\"onViewChanged($event)\"\n></axp-query-views>\n<div class=\"ax-flex ax-items-center ax-gap-2 ax-border-b ax-border-light w-full\">\n <!-- <axp-entity-filter-toolbar [viewModel]=\"vm\"></axp-entity-filter-toolbar> -->\n @if (filtersReady()) {\n <axp-query-filters\n id=\"axp-toolbar-filters\"\n [filtersDefinitions]=\"filtersDefinitions()\"\n [initialFilters]=\"initialFilters()\"\n (onFiltersChanged)=\"onFiltersChanged($event)\"\n ></axp-query-filters>\n }\n\n <div class=\"ax-flex ax-items-center ax-gap-2 md:ax-gap-2\">\n @if (filterTriggerMode === 'manual' && isFiltersDirty()) {\n <ax-button\n id=\"axp-toolbar-btn-filter\"\n [title]=\"'@general:actions.apply.title'\"\n [iconOnly]=\"true\"\n #filterButton\n [color]=\"'primary'\"\n (onClick)=\"applyFilters()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-search\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (vm.activeListLayout() === 'table') {\n <div>\n <ax-button id=\"axp-toolbar-btn-columns\" [iconOnly]=\"true\" #columnButton [color]=\"'default'\">\n <i class=\"fa-light fa-table-columns\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-columns\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"columnButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #columnsPopover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.columns' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <axp-query-columns [columns]=\"vm.columns()\" (columnsChange)=\"onColumnsChange($event)\"></axp-query-columns>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n\n @if (vm.canSort()) {\n <div>\n <ax-button id=\"axp-toolbar-btn-sort\" [iconOnly]=\"true\" [text]=\"'Sorts'\" #sortButton [color]=\"'default'\">\n <i class=\"fa-light fa-sort-amount-up\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-sort\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"sortButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #popover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.sorts' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <!-- <axp-list-view-option-sorting [viewModel]=\"vm\"></axp-list-view-option-sorting> -->\n <axp-query-sorts\n [sortDefinitions]=\"sortDefinitions()\"\n (sortQueriesChange)=\"onSortQueriesChange($event)\"\n [initialSortQueries]=\"sortQueries()\"\n ></axp-query-sorts>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n @if (deviceService.isSmall()) {\n <ax-button\n id=\"axp-toolbar-btn-category\"\n (onClick)=\"parent.toggleCategoryDrawer()\"\n [iconOnly]=\"true\"\n [color]=\"'default'\"\n >\n <i class=\"fa-light fa-bars\"></i>\n </ax-button>\n }\n\n @if (showListDisplayModeControl()) {\n <div>\n <ax-button id=\"axp-toolbar-btn-list-display\" [iconOnly]=\"true\" #listDisplayButton [color]=\"'default'\">\n <i [class]=\"listDisplayModeButtonIcon()\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-list-display\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"listDisplayButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #listDisplayModePopover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.interface.list-display' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-2\">\n <ax-button-item-list>\n @if (hasTableListDisplayOption()) {\n <ax-button-item\n [text]=\"('@general:terms.interface.table-view' | translate | async)!\"\n [selected]=\"listDisplayMode() === 'table'\"\n (onClick)=\"setListDisplayMode('table')\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-table\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n @if (hasTableListDisplayOption()) {\n <ax-divider />\n }\n <ax-button-item\n [text]=\"('@general:terms.interface.card-compact-view' | translate | async)!\"\n [selected]=\"listDisplayMode() === 'card-compact'\"\n (onClick)=\"setListDisplayMode('card-compact')\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-grip-lines\"></i>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item\n [text]=\"('@general:terms.interface.card-expanded-view' | translate | async)!\"\n [selected]=\"listDisplayMode() === 'card-expanded'\"\n (onClick)=\"setListDisplayMode('card-expanded')\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-grid-2\"></i>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i3.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i3.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items", "closeParentOnClick", "lockOnLoading"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPQueryFiltersComponent, selector: "axp-query-filters", inputs: ["filtersDefinitions", "initialFilters"], outputs: ["onFiltersChanged"] }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i3$2.AXPopoverComponent, selector: "ax-popover", inputs: ["width", "disablePanelClass", "disabled", "offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "closeOnScroll", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "component", type: AXPQuerySortsComponent, selector: "axp-query-sorts", inputs: ["sortDefinitions", "initialSortQueries"], outputs: ["sortDefinitionsChange", "sortQueriesChange"] }, { kind: "component", type: AXPQueryViewsComponent, selector: "axp-query-views", inputs: ["views", "selectedView"], outputs: ["viewsChange", "selectedViewChange"] }, { kind: "component", type: AXPQueryColumnsComponent, selector: "axp-query-columns", inputs: ["columns"], outputs: ["columnsChange"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1454
1481
|
}
|
|
1455
1482
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPEntityMasterToolbarViewComponent, decorators: [{
|
|
1456
1483
|
type: Component,
|
|
@@ -1467,7 +1494,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1467
1494
|
AXPQueryColumnsComponent,
|
|
1468
1495
|
], host: {
|
|
1469
1496
|
class: 'ax-w-full',
|
|
1470
|
-
}, template: "<!-- <axp-entity-view-toolbar [viewModel]=\"vm\"></axp-entity-view-toolbar> -->\n<axp-query-views\n id=\"axp-toolbar-view-selector\"\n [views]=\"viewQueries()\"\n [selectedView]=\"selectedViewQuery()\"\n (selectedViewChange)=\"onViewChanged($event)\"\n></axp-query-views>\n<div class=\"ax-flex ax-items-center ax-gap-2 ax-border-b ax-border-light w-full\">\n <!-- <axp-entity-filter-toolbar [viewModel]=\"vm\"></axp-entity-filter-toolbar> -->\n <axp-query-filters\n
|
|
1497
|
+
}, template: "<!-- <axp-entity-view-toolbar [viewModel]=\"vm\"></axp-entity-view-toolbar> -->\n<axp-query-views\n id=\"axp-toolbar-view-selector\"\n [views]=\"viewQueries()\"\n [selectedView]=\"selectedViewQuery()\"\n (selectedViewChange)=\"onViewChanged($event)\"\n></axp-query-views>\n<div class=\"ax-flex ax-items-center ax-gap-2 ax-border-b ax-border-light w-full\">\n <!-- <axp-entity-filter-toolbar [viewModel]=\"vm\"></axp-entity-filter-toolbar> -->\n @if (filtersReady()) {\n <axp-query-filters\n id=\"axp-toolbar-filters\"\n [filtersDefinitions]=\"filtersDefinitions()\"\n [initialFilters]=\"initialFilters()\"\n (onFiltersChanged)=\"onFiltersChanged($event)\"\n ></axp-query-filters>\n }\n\n <div class=\"ax-flex ax-items-center ax-gap-2 md:ax-gap-2\">\n @if (filterTriggerMode === 'manual' && isFiltersDirty()) {\n <ax-button\n id=\"axp-toolbar-btn-filter\"\n [title]=\"'@general:actions.apply.title'\"\n [iconOnly]=\"true\"\n #filterButton\n [color]=\"'primary'\"\n (onClick)=\"applyFilters()\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-search\"></i>\n </ax-prefix>\n </ax-button>\n }\n @if (vm.activeListLayout() === 'table') {\n <div>\n <ax-button id=\"axp-toolbar-btn-columns\" [iconOnly]=\"true\" #columnButton [color]=\"'default'\">\n <i class=\"fa-light fa-table-columns\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-columns\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"columnButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #columnsPopover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.columns' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <axp-query-columns [columns]=\"vm.columns()\" (columnsChange)=\"onColumnsChange($event)\"></axp-query-columns>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n\n @if (vm.canSort()) {\n <div>\n <ax-button id=\"axp-toolbar-btn-sort\" [iconOnly]=\"true\" [text]=\"'Sorts'\" #sortButton [color]=\"'default'\">\n <i class=\"fa-light fa-sort-amount-up\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-sort\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"sortButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #popover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.common.sorts' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-4\">\n <!-- <axp-list-view-option-sorting [viewModel]=\"vm\"></axp-list-view-option-sorting> -->\n <axp-query-sorts\n [sortDefinitions]=\"sortDefinitions()\"\n (sortQueriesChange)=\"onSortQueriesChange($event)\"\n [initialSortQueries]=\"sortQueries()\"\n ></axp-query-sorts>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n @if (deviceService.isSmall()) {\n <ax-button\n id=\"axp-toolbar-btn-category\"\n (onClick)=\"parent.toggleCategoryDrawer()\"\n [iconOnly]=\"true\"\n [color]=\"'default'\"\n >\n <i class=\"fa-light fa-bars\"></i>\n </ax-button>\n }\n\n @if (showListDisplayModeControl()) {\n <div>\n <ax-button id=\"axp-toolbar-btn-list-display\" [iconOnly]=\"true\" #listDisplayButton [color]=\"'default'\">\n <i [class]=\"listDisplayModeButtonIcon()\"></i>\n </ax-button>\n <ax-popover\n id=\"axp-popover-list-display\"\n [adaptivityEnabled]=\"true\"\n [offsetY]=\"10\"\n [target]=\"listDisplayButton\"\n [openOn]=\"'toggle'\"\n [closeOn]=\"'clickOut'\"\n #listDisplayModePopover\n >\n <div class=\"ax-lightest-surface ax-shadow-md ax-border md:ax-w-72 ax-w-full ax-rounded-md\">\n <ax-header class=\"ax-border-b ax-lighter-surface ax-rounded-t-md ax-p-4 ax-font-bold\">\n {{ '@general:terms.interface.list-display' | translate | async }}\n </ax-header>\n <div class=\"ax-py-2 ax-px-2\">\n <ax-button-item-list>\n @if (hasTableListDisplayOption()) {\n <ax-button-item\n [text]=\"('@general:terms.interface.table-view' | translate | async)!\"\n [selected]=\"listDisplayMode() === 'table'\"\n (onClick)=\"setListDisplayMode('table')\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-table\"></i>\n </ax-prefix>\n </ax-button-item>\n }\n @if (hasTableListDisplayOption()) {\n <ax-divider />\n }\n <ax-button-item\n [text]=\"('@general:terms.interface.card-compact-view' | translate | async)!\"\n [selected]=\"listDisplayMode() === 'card-compact'\"\n (onClick)=\"setListDisplayMode('card-compact')\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-grip-lines\"></i>\n </ax-prefix>\n </ax-button-item>\n <ax-button-item\n [text]=\"('@general:terms.interface.card-expanded-view' | translate | async)!\"\n [selected]=\"listDisplayMode() === 'card-expanded'\"\n (onClick)=\"setListDisplayMode('card-expanded')\"\n >\n <ax-prefix>\n <i class=\"fa-light fa-grid-2\"></i>\n </ax-prefix>\n </ax-button-item>\n </ax-button-item-list>\n </div>\n </div>\n </ax-popover>\n </div>\n }\n </div>\n</div>\n" }]
|
|
1471
1498
|
}], propDecorators: { vm: [{
|
|
1472
1499
|
type: Input,
|
|
1473
1500
|
args: ['viewModel']
|
|
@@ -2040,12 +2067,22 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2040
2067
|
this.restoreExpandedRowsScheduled = false;
|
|
2041
2068
|
/** Blocks deferred `replaceUrl` view sync after destroy or once details navigation has started. */
|
|
2042
2069
|
this.listQueryParamSyncDisabled = false;
|
|
2070
|
+
/** Tracks layout so card → table can reveal rows without a second fetch. */
|
|
2071
|
+
this.lastListLayout = this.vm.activeListLayout();
|
|
2043
2072
|
effect(() => {
|
|
2044
2073
|
const grid = this.grid();
|
|
2045
2074
|
if (grid) {
|
|
2046
2075
|
grid.selectedRows = this.vm.selectedItems();
|
|
2047
2076
|
}
|
|
2048
2077
|
});
|
|
2078
|
+
effect(() => {
|
|
2079
|
+
const layout = this.vm.activeListLayout();
|
|
2080
|
+
const previousLayout = untracked(() => this.lastListLayout);
|
|
2081
|
+
this.lastListLayout = layout;
|
|
2082
|
+
if (layout === 'table' && previousLayout === 'card') {
|
|
2083
|
+
untracked(() => this.acknowledgeManualTableReady());
|
|
2084
|
+
}
|
|
2085
|
+
});
|
|
2049
2086
|
this.vm.events$.subscribe(async (e) => {
|
|
2050
2087
|
const refreshTargetId = e.meta?.refreshTargetId;
|
|
2051
2088
|
const highlightRowId = e.meta?.highlightRowId;
|
|
@@ -2075,7 +2112,8 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2075
2112
|
}
|
|
2076
2113
|
const currentViewName = this.vm.view().name;
|
|
2077
2114
|
const urlView = this.activeRoute.snapshot.queryParamMap.get('view');
|
|
2078
|
-
|
|
2115
|
+
// Only fill a missing `view` query param. When URL and VM diverge, URL wins via queryParam sync.
|
|
2116
|
+
if (currentViewName && !urlView) {
|
|
2079
2117
|
this.syncListViewQueryParam(currentViewName);
|
|
2080
2118
|
}
|
|
2081
2119
|
});
|
|
@@ -2120,9 +2158,13 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2120
2158
|
const resolvedView = this.vm.view().name;
|
|
2121
2159
|
const currentUrlView = this.activeRoute.snapshot.queryParamMap.get('view');
|
|
2122
2160
|
if (currentUrlView !== resolvedView) {
|
|
2161
|
+
// Mark the post-replaceUrl key before navigating so the emission does not reload without filters.
|
|
2162
|
+
this.vm.markRouteQueryContextSynced(this.activeRoute.snapshot.queryParamMap, { view: resolvedView });
|
|
2123
2163
|
this.syncListViewQueryParam(resolvedView);
|
|
2124
2164
|
}
|
|
2125
|
-
|
|
2165
|
+
else {
|
|
2166
|
+
this.vm.markRouteQueryContextSynced(this.activeRoute.snapshot.queryParamMap);
|
|
2167
|
+
}
|
|
2126
2168
|
this.initializedFromRoute = true;
|
|
2127
2169
|
this.bindExpandedRowPersistence();
|
|
2128
2170
|
this.scheduleRestoreExpandedRows();
|
|
@@ -2260,6 +2302,7 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2260
2302
|
if (this.listQueryParamSyncDisabled) {
|
|
2261
2303
|
return;
|
|
2262
2304
|
}
|
|
2305
|
+
this.vm.markRouteQueryContextSynced(this.activeRoute.snapshot.queryParamMap, { view: viewName });
|
|
2263
2306
|
axpReplaceEntityListRouteQueryParams(this.router, { view: viewName });
|
|
2264
2307
|
});
|
|
2265
2308
|
}
|
|
@@ -2270,6 +2313,8 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2270
2313
|
}
|
|
2271
2314
|
if (this.vm.activeListLayout() === 'card') {
|
|
2272
2315
|
await this.cardList()?.reload(resetPagination);
|
|
2316
|
+
// Shared DS load updates table rows via onChanged but not isRefreshCalled; prepare for a later table switch.
|
|
2317
|
+
this.acknowledgeManualTableReady();
|
|
2273
2318
|
return;
|
|
2274
2319
|
}
|
|
2275
2320
|
const grid = this.grid();
|
|
@@ -2288,6 +2333,19 @@ class AXPEntityMasterListViewComponent extends AXPPageLayoutBaseComponent {
|
|
|
2288
2333
|
await dataReady;
|
|
2289
2334
|
}
|
|
2290
2335
|
}
|
|
2336
|
+
/**
|
|
2337
|
+
* Manual-mode table gates the body on `isRefreshCalled` (set only by `grid.refresh()`).
|
|
2338
|
+
* Card loads use shared `dataSource.refresh()`, so rows/totalCount update while the gate stays closed.
|
|
2339
|
+
* Opening the gate here avoids an extra network refresh when switching to table.
|
|
2340
|
+
*/
|
|
2341
|
+
acknowledgeManualTableReady() {
|
|
2342
|
+
// `isRefreshCalled` is private on AXDataTableComponent; runtime access is intentional (zero-fetch reveal).
|
|
2343
|
+
const grid = this.grid();
|
|
2344
|
+
if (!grid?.isRefreshCalled || grid.isRefreshCalled()) {
|
|
2345
|
+
return;
|
|
2346
|
+
}
|
|
2347
|
+
grid.isRefreshCalled.set(true);
|
|
2348
|
+
}
|
|
2291
2349
|
/**
|
|
2292
2350
|
* Waits until a `refresh()` load cycle completes (loading started, then finished with data).
|
|
2293
2351
|
*/
|