@acorex/platform 20.9.9 → 20.9.11
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 +18 -0
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +40 -9
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +72 -47
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +34 -29
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +19 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +145 -22
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-common.d.ts +6 -0
- package/types/acorex-platform-core.d.ts +34 -7
- package/types/acorex-platform-layout-entity.d.ts +4 -2
- package/types/acorex-platform-layout-widget-core.d.ts +5 -0
- package/types/acorex-platform-layout-widgets.d.ts +34 -0
|
@@ -7182,6 +7182,9 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7182
7182
|
this.destroyRef = inject(DestroyRef);
|
|
7183
7183
|
/** Toggled to force ax-select-box to re-render after locale / language changes. */
|
|
7184
7184
|
this.selectBoxKey = signal(true, ...(ngDevMode ? [{ debugName: "selectBoxKey" }] : /* istanbul ignore next */ []));
|
|
7185
|
+
/** Registry list query runs only after the user interacts (not on form mount). */
|
|
7186
|
+
this.listLoadEnabled = signal(false, ...(ngDevMode ? [{ debugName: "listLoadEnabled" }] : /* istanbul ignore next */ []));
|
|
7187
|
+
this.isLazyRegistrySelect = computed(() => !this.filterMode() && !!this.registryDataSourceName(), ...(ngDevMode ? [{ debugName: "isLazyRegistrySelect" }] : /* istanbul ignore next */ []));
|
|
7185
7188
|
this.selectBoxLocaleChanged = merge(this.translationService.langChanges$, this.localeService.profileChanged$)
|
|
7186
7189
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
7187
7190
|
.subscribe(() => this.rerenderSelectBox());
|
|
@@ -7203,6 +7206,33 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7203
7206
|
this.isItemTruncated = computed(() => this.options()['isItemTruncated'] ?? true, ...(ngDevMode ? [{ debugName: "isItemTruncated" }] : /* istanbul ignore next */ []));
|
|
7204
7207
|
this.filter = computed(() => this.options()['filter'], ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
|
|
7205
7208
|
this.filterMode = computed(() => this.options()['filterMode'] ?? false, ...(ngDevMode ? [{ debugName: "filterMode" }] : /* istanbul ignore next */ []));
|
|
7209
|
+
/**
|
|
7210
|
+
* True when a cascade/parent filter is configured but required values are still empty
|
|
7211
|
+
* (e.g. state select before country is chosen).
|
|
7212
|
+
*/
|
|
7213
|
+
this.hasPendingCascadeFilter = computed(() => {
|
|
7214
|
+
if (this.filterMode()) {
|
|
7215
|
+
return false;
|
|
7216
|
+
}
|
|
7217
|
+
const rawFilter = this.filter();
|
|
7218
|
+
if (!rawFilter) {
|
|
7219
|
+
return false;
|
|
7220
|
+
}
|
|
7221
|
+
return AXPCleanNestedFilters([rawFilter]).length === 0;
|
|
7222
|
+
}, ...(ngDevMode ? [{ debugName: "hasPendingCascadeFilter" }] : /* istanbul ignore next */ []));
|
|
7223
|
+
/**
|
|
7224
|
+
* Registry-backed selects defer list loading until the user opens the dropdown.
|
|
7225
|
+
* Existing values are still resolved via `byKey` in the base widget.
|
|
7226
|
+
*/
|
|
7227
|
+
this.shouldDeferListLoad = computed(() => this.isLazyRegistrySelect() && !this.listLoadEnabled(), ...(ngDevMode ? [{ debugName: "shouldDeferListLoad" }] : /* istanbul ignore next */ []));
|
|
7228
|
+
/** Only swap datasource when cascade parent is missing; defer load via patched `load` instead. */
|
|
7229
|
+
this.effectiveDataSource = computed(() => {
|
|
7230
|
+
if (this.hasPendingCascadeFilter()) {
|
|
7231
|
+
return AXPSelectBoxWidgetEditComponent.emptyDataSource;
|
|
7232
|
+
}
|
|
7233
|
+
return this.dataSource();
|
|
7234
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveDataSource" }] : /* istanbul ignore next */ []));
|
|
7235
|
+
this.isSelectBoxDisabled = computed(() => this.disabled() || this.hasPendingCascadeFilter(), ...(ngDevMode ? [{ debugName: "isSelectBoxDisabled" }] : /* istanbul ignore next */ []));
|
|
7206
7236
|
/** For filter mode: display valueField from object to avoid [object Object] when value is stored as full item */
|
|
7207
7237
|
this.selectFilterDisplayValue = computed(() => {
|
|
7208
7238
|
const raw = this.getValue();
|
|
@@ -7269,21 +7299,31 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7269
7299
|
}
|
|
7270
7300
|
}
|
|
7271
7301
|
}, ...(ngDevMode ? [{ debugName: "#focusEffect" }] : /* istanbul ignore next */ []));
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
const normalized = this.filterMode()
|
|
7279
|
-
? this.normalizeFilterValues(cleanedFilters[0])
|
|
7280
|
-
: cleanedFilters[0];
|
|
7281
|
-
this.dataSource()?.filter(normalized);
|
|
7282
|
-
});
|
|
7283
|
-
});
|
|
7284
|
-
}
|
|
7302
|
+
/** Applies widget filter to the isolated datasource whenever options change (cascade parent id). */
|
|
7303
|
+
this.#filterEffect = effect(() => {
|
|
7304
|
+
const filterOption = this.filter();
|
|
7305
|
+
const registryReady = this.registryDataSourceReady();
|
|
7306
|
+
if (!registryReady || !filterOption || this.filterMode() || this.hasPendingCascadeFilter()) {
|
|
7307
|
+
return;
|
|
7285
7308
|
}
|
|
7286
|
-
|
|
7309
|
+
const widgetFilter = this.resolveActiveWidgetFilter();
|
|
7310
|
+
if (!widgetFilter) {
|
|
7311
|
+
return;
|
|
7312
|
+
}
|
|
7313
|
+
untracked(() => {
|
|
7314
|
+
this.dataSource()?.filter(widgetFilter);
|
|
7315
|
+
});
|
|
7316
|
+
}, ...(ngDevMode ? [{ debugName: "#filterEffect" }] : /* istanbul ignore next */ []));
|
|
7317
|
+
this.#registryDataSourceEffect = effect(() => {
|
|
7318
|
+
const registryReady = this.registryDataSourceReady();
|
|
7319
|
+
const registryName = this.registryDataSourceName();
|
|
7320
|
+
if (!registryReady || !registryName || this.filterMode()) {
|
|
7321
|
+
return;
|
|
7322
|
+
}
|
|
7323
|
+
untracked(() => {
|
|
7324
|
+
this.patchRegistryDataSourceLoad();
|
|
7325
|
+
});
|
|
7326
|
+
}, ...(ngDevMode ? [{ debugName: "#registryDataSourceEffect" }] : /* istanbul ignore next */ []));
|
|
7287
7327
|
this.#clearOnDataSourceChangedEffect = effect(() => {
|
|
7288
7328
|
const currentDataSource = this.options()['dataSource'];
|
|
7289
7329
|
if (!this.hasSeenDataSource) {
|
|
@@ -7301,6 +7341,7 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7301
7341
|
this.refresh();
|
|
7302
7342
|
}, ...(ngDevMode ? [{ debugName: "#clearOnDataSourceChangedEffect" }] : /* istanbul ignore next */ []));
|
|
7303
7343
|
}
|
|
7344
|
+
static { this.emptyDataSource = convertArrayToDataSource([]); }
|
|
7304
7345
|
/**
|
|
7305
7346
|
* In filter mode the stored value is wrapped as `{ value, operation, displayText }`.
|
|
7306
7347
|
* Item resolution in the base widget needs the unwrapped key(s), so expose the same
|
|
@@ -7428,12 +7469,15 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7428
7469
|
handleSearchValueChange(e) {
|
|
7429
7470
|
if (e.isUserInteraction) {
|
|
7430
7471
|
this.searchValue.set(e.value);
|
|
7472
|
+
if (this.shouldDeferListLoad()) {
|
|
7473
|
+
return;
|
|
7474
|
+
}
|
|
7475
|
+
const baseFilter = this.resolveActiveWidgetFilter();
|
|
7431
7476
|
const searchFilter = this.filterOperatorMiddleware.transformFilter({
|
|
7432
7477
|
field: this.textField(),
|
|
7433
7478
|
operator: { type: 'contains' },
|
|
7434
7479
|
value: e.value,
|
|
7435
7480
|
});
|
|
7436
|
-
const baseFilter = this.filter() ? AXPCleanNestedFilters([this.filter()])[0] : null;
|
|
7437
7481
|
let mergedFilter = searchFilter;
|
|
7438
7482
|
if (baseFilter) {
|
|
7439
7483
|
if (this.searchValue() !== undefined) {
|
|
@@ -7453,20 +7497,74 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7453
7497
|
this.dataSource()?.refresh();
|
|
7454
7498
|
}
|
|
7455
7499
|
}
|
|
7456
|
-
|
|
7500
|
+
/** Normalized, middleware-ready filter for the current widget options (or null). */
|
|
7501
|
+
resolveActiveWidgetFilter() {
|
|
7502
|
+
const filterOption = this.filter();
|
|
7503
|
+
if (!filterOption) {
|
|
7504
|
+
return null;
|
|
7505
|
+
}
|
|
7506
|
+
const cleanedFilters = AXPCleanNestedFilters([filterOption]);
|
|
7507
|
+
if (cleanedFilters.length === 0) {
|
|
7508
|
+
return null;
|
|
7509
|
+
}
|
|
7510
|
+
return this.filterOperatorMiddleware.transformFilter(this.normalizeDataSourceFilter(cleanedFilters[0]));
|
|
7511
|
+
}
|
|
7512
|
+
/** Applies widget filter to the isolated datasource whenever options change (cascade parent id). */
|
|
7513
|
+
#filterEffect;
|
|
7514
|
+
#registryDataSourceEffect;
|
|
7515
|
+
/**
|
|
7516
|
+
* Patches registry `load` to defer list fetch until the user opens the dropdown.
|
|
7517
|
+
* Filtering is handled via {@link #filterEffect} on the datasource (lookup-select pattern).
|
|
7518
|
+
*/
|
|
7519
|
+
patchRegistryDataSourceLoad() {
|
|
7520
|
+
const ds = this.dataSource();
|
|
7521
|
+
const config = ds?.config;
|
|
7522
|
+
if (!config?.load || config.__axpSelectFilterPatched) {
|
|
7523
|
+
return;
|
|
7524
|
+
}
|
|
7525
|
+
const originalLoad = config.load.bind(ds);
|
|
7526
|
+
config.load = async (event) => {
|
|
7527
|
+
if (this.shouldDeferListLoad() || this.hasPendingCascadeFilter()) {
|
|
7528
|
+
return { items: [], total: 0 };
|
|
7529
|
+
}
|
|
7530
|
+
return originalLoad(event);
|
|
7531
|
+
};
|
|
7532
|
+
config.__axpSelectFilterPatched = true;
|
|
7533
|
+
}
|
|
7457
7534
|
#clearOnDataSourceChangedEffect;
|
|
7535
|
+
// TODO: Duplicate registry list API calls — opening a cascade select (or country-change refresh)
|
|
7536
|
+
// currently triggers two loads (e.g. dataSource.refresh + selectBox.refresh, and/or #filterEffect
|
|
7537
|
+
// plus refresh/enableListLoad). Coalesce to a single load path without breaking cascade filter refresh.
|
|
7458
7538
|
refresh() {
|
|
7459
7539
|
setTimeout(() => {
|
|
7460
7540
|
this.searchValue.set(undefined);
|
|
7541
|
+
this.applyActiveFilterToDataSource();
|
|
7542
|
+
this.listLoadEnabled.set(true);
|
|
7543
|
+
this.dataSource()?.refresh();
|
|
7461
7544
|
this.selectBox()?.refresh();
|
|
7462
|
-
},
|
|
7545
|
+
}, 0);
|
|
7546
|
+
}
|
|
7547
|
+
/** Push the current widget filter onto the isolated datasource. */
|
|
7548
|
+
applyActiveFilterToDataSource() {
|
|
7549
|
+
const widgetFilter = this.resolveActiveWidgetFilter();
|
|
7550
|
+
if (widgetFilter) {
|
|
7551
|
+
this.dataSource()?.filter(widgetFilter);
|
|
7552
|
+
}
|
|
7553
|
+
}
|
|
7554
|
+
/** Allow the patched datasource `load` before the dropdown panel opens. */
|
|
7555
|
+
enableListLoad() {
|
|
7556
|
+
if (this.filterMode() || this.hasPendingCascadeFilter() || !this.isLazyRegistrySelect()) {
|
|
7557
|
+
return;
|
|
7558
|
+
}
|
|
7559
|
+
this.listLoadEnabled.set(true);
|
|
7560
|
+
this.applyActiveFilterToDataSource();
|
|
7463
7561
|
}
|
|
7464
7562
|
/** Re-mount ax-select-box so translate pipe picks up the active locale. */
|
|
7465
7563
|
rerenderSelectBox() {
|
|
7466
7564
|
this.refreshRegistryDataSource();
|
|
7565
|
+
this.listLoadEnabled.set(false);
|
|
7467
7566
|
this.selectBoxKey.set(false);
|
|
7468
7567
|
setTimeout(() => {
|
|
7469
|
-
this.dataSource()?.refresh();
|
|
7470
7568
|
this.selectBoxKey.set(true);
|
|
7471
7569
|
setTimeout(() => this.selectBox()?.refresh(), 0);
|
|
7472
7570
|
}, 0);
|
|
@@ -7510,6 +7608,27 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7510
7608
|
singleOrMultiple(values) {
|
|
7511
7609
|
return this.multiple() ? values : values[0];
|
|
7512
7610
|
}
|
|
7611
|
+
/**
|
|
7612
|
+
* Normalizes filter payloads for datasource queries: unwraps filter-mode values and
|
|
7613
|
+
* reduces selected row objects to scalar keys (default `id`).
|
|
7614
|
+
*/
|
|
7615
|
+
normalizeDataSourceFilter(filter) {
|
|
7616
|
+
if (!filter) {
|
|
7617
|
+
return filter;
|
|
7618
|
+
}
|
|
7619
|
+
let normalized = this.filterMode() ? this.normalizeFilterValues(filter) : filter;
|
|
7620
|
+
if (Array.isArray(normalized.filters) && normalized.filters.length > 0) {
|
|
7621
|
+
return {
|
|
7622
|
+
...normalized,
|
|
7623
|
+
filters: normalized.filters.map((entry) => this.normalizeDataSourceFilter(entry)),
|
|
7624
|
+
};
|
|
7625
|
+
}
|
|
7626
|
+
const extracted = extractValue(normalized.value, 'id');
|
|
7627
|
+
if (extracted != null && extracted !== normalized.value) {
|
|
7628
|
+
normalized = { ...normalized, value: extracted };
|
|
7629
|
+
}
|
|
7630
|
+
return normalized;
|
|
7631
|
+
}
|
|
7513
7632
|
/**
|
|
7514
7633
|
* In filterMode, widget context stores values as `{ value, operation, displayText }`.
|
|
7515
7634
|
* DataSource filtering expects the raw scalar/array value, so unwrap `value.value`.
|
|
@@ -7540,8 +7659,8 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7540
7659
|
} @else if (selectBoxKey()) {
|
|
7541
7660
|
<ax-select-box
|
|
7542
7661
|
[placeholder]="(placeholder() | translate | async) ?? ''"
|
|
7543
|
-
[dataSource]="
|
|
7544
|
-
[disabled]="
|
|
7662
|
+
[dataSource]="effectiveDataSource()"
|
|
7663
|
+
[disabled]="isSelectBoxDisabled()"
|
|
7545
7664
|
[valueField]="valueField()"
|
|
7546
7665
|
[textField]="textField()"
|
|
7547
7666
|
[textTemplate]="textTemplate()"
|
|
@@ -7550,6 +7669,8 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
|
|
|
7550
7669
|
[showItemTooltip]="showItemTooltip()"
|
|
7551
7670
|
[isItemTruncated]="isItemTruncated()"
|
|
7552
7671
|
[ngModel]="selectBoxModel()"
|
|
7672
|
+
(mousedown)="enableListLoad()"
|
|
7673
|
+
(focus)="enableListLoad()"
|
|
7553
7674
|
(onValueChanged)="handleValueChange($event)"
|
|
7554
7675
|
>
|
|
7555
7676
|
@if (allowSearch()) {
|
|
@@ -7579,8 +7700,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
7579
7700
|
} @else if (selectBoxKey()) {
|
|
7580
7701
|
<ax-select-box
|
|
7581
7702
|
[placeholder]="(placeholder() | translate | async) ?? ''"
|
|
7582
|
-
[dataSource]="
|
|
7583
|
-
[disabled]="
|
|
7703
|
+
[dataSource]="effectiveDataSource()"
|
|
7704
|
+
[disabled]="isSelectBoxDisabled()"
|
|
7584
7705
|
[valueField]="valueField()"
|
|
7585
7706
|
[textField]="textField()"
|
|
7586
7707
|
[textTemplate]="textTemplate()"
|
|
@@ -7589,6 +7710,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
7589
7710
|
[showItemTooltip]="showItemTooltip()"
|
|
7590
7711
|
[isItemTruncated]="isItemTruncated()"
|
|
7591
7712
|
[ngModel]="selectBoxModel()"
|
|
7713
|
+
(mousedown)="enableListLoad()"
|
|
7714
|
+
(focus)="enableListLoad()"
|
|
7592
7715
|
(onValueChanged)="handleValueChange($event)"
|
|
7593
7716
|
>
|
|
7594
7717
|
@if (allowSearch()) {
|