@acorex/platform 20.9.6 → 20.9.8

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.
@@ -3,7 +3,7 @@ import { signal, computed, effect, untracked, Injectable, inject, ElementRef, De
3
3
  import { isSelectionValueEqual, isFormValueEqual, extractValue, getSmart, summarizeFormContextDirtyDiff, AXPWidgetsCatalog } from '@acorex/platform/contracts';
4
4
  import { AXPPageStatus, AXPWidgetStatus, AXP_WIDGET_TOKEN, AXP_WIDGET_COLUMN_TOKEN, createStringProperty, createBooleanProperty, createSelectProperty, createNumberProperty, cloneProperty } from '@acorex/platform/layout/widget-core-contracts';
5
5
  import { convertArrayToDataSource, AXDataSource, AX_STYLE_COLOR_TYPES, AX_STYLE_LOOK_TYPES } from '@acorex/cdk/common';
6
- import { AXPContextStore, AXPDebugService, FORM_DIRTY_TRACE_NS, AXPDataSourceDefinitionProviderService, AXPExpressionEvaluatorService, OVERLAY_WIDGET_SETTLE_TRACE_NS } from '@acorex/platform/core';
6
+ import { AXPContextStore, AXPDebugService, FORM_DIRTY_TRACE_NS, AXPDataSourceQueryService, AXPExpressionEvaluatorService, OVERLAY_WIDGET_SETTLE_TRACE_NS } from '@acorex/platform/core';
7
7
  import { set, get, cloneDeep, isEqual, isNil, isUndefined, isObjectLike, merge, sum, isEmpty, isString } from 'lodash-es';
8
8
  import { Subject, BehaviorSubject, filter } from 'rxjs';
9
9
  import * as i1$1 from '@acorex/components/skeleton';
@@ -504,14 +504,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
504
504
  class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
505
505
  constructor() {
506
506
  super(...arguments);
507
- this.dataService = inject(AXPDataSourceDefinitionProviderService);
507
+ this.registryDataSourceQuery = inject(AXPDataSourceQueryService);
508
508
  this.textField = computed(() => this.options()['textField'] ?? 'title', ...(ngDevMode ? [{ debugName: "textField" }] : /* istanbul ignore next */ []));
509
509
  this.valueField = computed(() => this.options()['valueField'] ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : /* istanbul ignore next */ []));
510
510
  this.textTemplate = computed(() => isNil(this.options()['textTemplate'])
511
511
  ? undefined
512
512
  : this.options()['textTemplate'].replace(/{/g, '{{').replace(/}/g, '}}'), ...(ngDevMode ? [{ debugName: "textTemplate" }] : /* istanbul ignore next */ []));
513
513
  this.dataSource = signal(convertArrayToDataSource([]), ...(ngDevMode ? [{ debugName: "dataSource" }] : /* istanbul ignore next */ []));
514
+ /** Registry datasource name from options, when options.dataSource is a string or `{ id }` object. */
515
+ this.registryDataSourceName = computed(() => {
516
+ const rawValue = this.options()['dataSource'];
517
+ if (typeof rawValue === 'string') {
518
+ return rawValue;
519
+ }
520
+ if (rawValue && typeof rawValue === 'object' && 'id' in rawValue) {
521
+ return String(rawValue['id']);
522
+ }
523
+ return null;
524
+ }, ...(ngDevMode ? [{ debugName: "registryDataSourceName" }] : /* istanbul ignore next */ []));
514
525
  this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : /* istanbul ignore next */ []));
526
+ /** Reactive flag: registry datasource finished resolving (success or failure). */
527
+ this.registryDataSourceReady = signal(false, ...(ngDevMode ? [{ debugName: "registryDataSourceReady" }] : /* istanbul ignore next */ []));
528
+ /** Reactive bump to reload registry-backed datasources (e.g. after locale change). */
529
+ this.registryRefreshEpoch = signal(0, ...(ngDevMode ? [{ debugName: "registryRefreshEpoch" }] : /* istanbul ignore next */ []));
515
530
  //#region ---- DataSource Loading Effect ----
516
531
  /**
517
532
  * Track the last loaded string dataSource reference to prevent infinite loops
@@ -520,9 +535,14 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
520
535
  this.lastStringDataSourceRef = null;
521
536
  this.rf = effect(async () => {
522
537
  const rawValue = this.options()['dataSource'];
538
+ const registryId = this.registryDataSourceName();
539
+ this.registryRefreshEpoch();
523
540
  // For string datasources: prevent infinite loop by checking reference
524
541
  if (typeof rawValue === 'string') {
525
542
  if (rawValue === this.lastStringDataSourceRef) {
543
+ if (registryId) {
544
+ this.registryDataSourceReady.set(true);
545
+ }
526
546
  return;
527
547
  }
528
548
  this.lastStringDataSourceRef = rawValue;
@@ -531,6 +551,9 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
531
551
  // Reset string reference when dataSource changes to non-string
532
552
  this.lastStringDataSourceRef = null;
533
553
  }
554
+ if (registryId) {
555
+ this.registryDataSourceReady.set(false);
556
+ }
534
557
  this.beginHydration();
535
558
  try {
536
559
  // Process dataSource creation in untracked context
@@ -540,6 +563,7 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
540
563
  if (!isEqual(rawValue.config, this.dataSource().config)) {
541
564
  this.dataSource.set(rawValue);
542
565
  }
566
+ this.registryDataSourceReady.set(true);
543
567
  }
544
568
  // static array datasource - always recreate when options change
545
569
  else if (Array.isArray(rawValue)) {
@@ -562,35 +586,24 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
562
586
  },
563
587
  });
564
588
  this.dataSource.set(ds);
589
+ this.registryDataSourceReady.set(true);
565
590
  }
566
591
  // resolve data source by name (string or object with id)
567
- else if (rawValue && (typeof rawValue == 'string' || typeof rawValue == 'object')) {
568
- const id = typeof rawValue == 'object' ? rawValue['id'] : rawValue;
569
- const c = await this.dataService.get(id);
570
- if (this.mode == 'designer' && c?.samples?.length) {
571
- this.dataSource.set(convertArrayToDataSource(c.samples, {
572
- key: this.valueField(),
573
- pageSize: 500,
574
- }));
592
+ else if (registryId) {
593
+ const queryOptions = this.buildRegistryQueryOptions();
594
+ const result = await this.registryDataSourceQuery.resolve(registryId, queryOptions);
595
+ if (result.dataSource) {
596
+ this.dataSource.set(result.dataSource);
575
597
  }
576
598
  else {
577
- const ds = c?.source();
578
- if (ds && ds instanceof Promise) {
579
- const d = await ds;
580
- this.dataSource.set(d);
581
- }
582
- else if (ds) {
583
- this.dataSource.set(ds);
584
- }
585
- // empty datasource
586
- else {
587
- this.dataSource.set(convertArrayToDataSource([]));
588
- }
599
+ this.dataSource.set(convertArrayToDataSource([]));
589
600
  }
601
+ this.registryDataSourceReady.set(true);
590
602
  }
591
603
  // empty datasource
592
604
  else {
593
605
  this.dataSource.set(convertArrayToDataSource([]));
606
+ this.registryDataSourceReady.set(true);
594
607
  }
595
608
  });
596
609
  }
@@ -598,26 +611,51 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
598
611
  this.endHydration();
599
612
  }
600
613
  }, ...(ngDevMode ? [{ debugName: "rf" }] : /* istanbul ignore next */ []));
601
- this.effect2 = effect(async () => {
602
- this.beginHydration();
603
- try {
604
- //TODO: WHY IS THIS HAPPENING
605
- const value = this.resolveSelectedItemsValue();
606
- const items = [];
607
- if (Array.isArray(value)) {
608
- items.push(...(await Promise.all(value.map((item) => this.extractItem(item)))));
614
+ this.effect2 = effect(() => {
615
+ const registryName = this.registryDataSourceName();
616
+ const value = this.resolveSelectedItemsValue();
617
+ const registryReady = this.registryDataSourceReady();
618
+ this.dataSource();
619
+ if (registryName && !registryReady) {
620
+ return;
621
+ }
622
+ const resolveSelectedItems = async () => {
623
+ this.beginHydration();
624
+ try {
625
+ const items = [];
626
+ if (Array.isArray(value)) {
627
+ items.push(...(await Promise.all(value.map((item) => this.extractItem(item)))));
628
+ }
629
+ else {
630
+ items.push(await this.extractItem(value));
631
+ }
632
+ this.selectedItems.set(items.filter((c) => c != null));
609
633
  }
610
- else {
611
- items.push(await this.extractItem(value));
634
+ finally {
635
+ this.endHydration();
612
636
  }
613
- this.selectedItems.set(items.filter((c) => c != null));
614
- }
615
- finally {
616
- this.endHydration();
617
- }
637
+ };
638
+ void resolveSelectedItems();
618
639
  }, ...(ngDevMode ? [{ debugName: "effect2" }] : /* istanbul ignore next */ []));
619
640
  }
641
+ buildRegistryQueryOptions() {
642
+ return {
643
+ valueField: this.valueField(),
644
+ useSamples: this.mode === 'designer',
645
+ };
646
+ }
620
647
  //#endregion
648
+ /** Invalidates cached registry datasource and forces a reload on the next effect run. */
649
+ refreshRegistryDataSource() {
650
+ const registryId = this.registryDataSourceName();
651
+ if (!registryId) {
652
+ return;
653
+ }
654
+ this.registryDataSourceQuery.invalidate(registryId);
655
+ this.lastStringDataSourceRef = null;
656
+ this.registryDataSourceReady.set(false);
657
+ this.registryRefreshEpoch.update((epoch) => epoch + 1);
658
+ }
621
659
  async extractItem(item) {
622
660
  if (isNil(item)) {
623
661
  return null;
@@ -626,6 +664,13 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
626
664
  return item;
627
665
  }
628
666
  const key = extractValue(item, this.valueField());
667
+ const registryName = this.registryDataSourceName();
668
+ if (registryName) {
669
+ const found = await this.registryDataSourceQuery.queryByKey(registryName, key, this.buildRegistryQueryOptions());
670
+ if (found) {
671
+ return found;
672
+ }
673
+ }
629
674
  const ds = this.dataSource();
630
675
  if (ds.config?.byKey) {
631
676
  const found = await ds.config?.byKey(key);
@@ -645,16 +690,10 @@ class AXPDataListWidgetComponent extends AXPValueWidgetComponent {
645
690
  * widgets that wrap their value (e.g. filter mode) can override this to expose
646
691
  * the unwrapped scalar/array so item resolution receives a real key.
647
692
  */
648
- //TODO: WHY IS THIS HAPPENING
649
693
  resolveSelectedItemsValue() {
650
694
  return this.getValue();
651
695
  }
652
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataListWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
653
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataListWidgetComponent }); }
654
696
  }
655
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataListWidgetComponent, decorators: [{
656
- type: Injectable
657
- }] });
658
697
  class AXPColumnWidgetComponent {
659
698
  constructor() {
660
699
  this.token = inject(AXP_WIDGET_COLUMN_TOKEN);