@acorex/platform 21.0.0-next.63 → 21.0.0-next.65

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.
@@ -4095,7 +4095,6 @@ class AXPEntityListViewColumnViewModel {
4095
4095
  this.name = this.property.name;
4096
4096
  this.title = this.column.title ?? this.property.title;
4097
4097
  this.visible = this.column?.options?.visible ?? true;
4098
- this.dir = this.column.sort?.dir;
4099
4098
  this.sortEnabled = this.property.options?.sort?.enabled;
4100
4099
  this.node = computed(() => {
4101
4100
  const widget = this.property.schema.interface;
@@ -5108,7 +5107,7 @@ class AXPEntityMasterListViewModel {
5108
5107
  this.events$.next({ action: 'refresh' });
5109
5108
  }
5110
5109
  });
5111
- this.sortedFields.set(this.sortableFields());
5110
+ this.sortedFields.set([]);
5112
5111
  void this.syncShowRowIndexColumnSetting();
5113
5112
  this.settings.onLoaded.pipe(takeUntil(this.destroyed)).subscribe(() => {
5114
5113
  void this.syncShowRowIndexColumnSetting();
@@ -5211,10 +5210,8 @@ class AXPEntityMasterListViewModel {
5211
5210
  .sort((a, b) => columns.findIndex((col) => col.name === (a.column?.options?.dataPath ?? a.name)) -
5212
5211
  columns.findIndex((col) => col.name === (b.column?.options?.dataPath ?? b.name))));
5213
5212
  }
5214
- if (Array.isArray(sorts)) {
5215
- // sorts are AXPSortQuery[]; ensure we map by name
5216
- const sortsMap = new Map(sorts.map((s) => [s.name, s.dir]));
5217
- this.sortedFields.update((prev) => prev.map((sf) => ({ ...sf, dir: sortsMap.get(sf.name) || sf.dir })));
5213
+ if (Array.isArray(sorts) && sorts.length) {
5214
+ this.setActiveSortsFromQueries(sorts);
5218
5215
  }
5219
5216
  // Don't override filters if they came from queryParams
5220
5217
  if (Array.isArray(filters) && !this.hasQueryParamsFilters) {
@@ -5731,18 +5728,80 @@ class AXPEntityMasterListViewModel {
5731
5728
  resetSorts() {
5732
5729
  this.applyViewSorts();
5733
5730
  }
5731
+ /**
5732
+ * Applies active sorts in the given order (click order, saved settings, or view defaults).
5733
+ */
5734
+ setActiveSortsFromQueries(sorts) {
5735
+ const sortableByName = new Map(this.sortableFields().map((f) => [f.name, f]));
5736
+ this.sortedFields.set(sorts
5737
+ .filter((s) => s.dir && sortableByName.has(s.name))
5738
+ .map((s) => ({
5739
+ name: s.name,
5740
+ title: sortableByName.get(s.name).title,
5741
+ dir: s.dir,
5742
+ })));
5743
+ }
5734
5744
  applyViewSorts() {
5735
- const viewSorts = this.view().sorts;
5736
- this.sortedFields.update((prev) => {
5737
- const viewSortsMap = new Map(viewSorts.map((vs) => [vs.name, vs]));
5738
- return prev.map((sf) => {
5739
- const updatedSort = viewSortsMap.get(sf.name);
5740
- if (updatedSort) {
5741
- return { ...updatedSort, title: sf.title };
5742
- }
5743
- return sf;
5744
- });
5745
- });
5745
+ const viewSorts = this.view().sorts ?? [];
5746
+ this.setActiveSortsFromQueries(viewSorts);
5747
+ }
5748
+ /**
5749
+ * Active sort direction for a column (synced with toolbar sort UI and dataSource).
5750
+ */
5751
+ getColumnSortDirection(columnName) {
5752
+ const dir = this.sortedFields().find((sf) => sf.name === columnName)?.dir;
5753
+ return dir === 'asc' || dir === 'desc' ? dir : undefined;
5754
+ }
5755
+ /**
5756
+ * 1-based priority index when multiple columns are sorted (Ctrl+click order).
5757
+ */
5758
+ getColumnSortIndex(columnName) {
5759
+ const index = this.sortedFields().findIndex((sf) => sf.name === columnName);
5760
+ return index >= 0 ? index + 1 : undefined;
5761
+ }
5762
+ /** True when active sorts still match the current view defaults (not yet customized). */
5763
+ isViewDefaultSorts(activeSorts) {
5764
+ const viewSorts = this.view().sorts ?? [];
5765
+ if (activeSorts.length !== viewSorts.length) {
5766
+ return false;
5767
+ }
5768
+ return activeSorts.every((s, i) => s.name === viewSorts[i]?.name && s.dir === viewSorts[i]?.dir);
5769
+ }
5770
+ /**
5771
+ * Toggles column sort (asc → desc → none). Without Ctrl, only one column is active.
5772
+ * With Ctrl/Cmd, multiple columns are sorted in click order (first clicked = primary).
5773
+ */
5774
+ async toggleColumnSort(columnName, multiSort) {
5775
+ const fieldMeta = this.sortableFields().find((f) => f.name === columnName);
5776
+ if (!fieldMeta) {
5777
+ return;
5778
+ }
5779
+ let activeSorts = [...this.sortedFields()];
5780
+ const index = activeSorts.findIndex((sf) => sf.name === columnName);
5781
+ const currentDir = index >= 0 ? activeSorts[index].dir : undefined;
5782
+ const newDir = currentDir === 'asc' ? 'desc' : currentDir === 'desc' ? undefined : 'asc';
5783
+ if (!multiSort) {
5784
+ activeSorts = newDir ? [{ name: columnName, title: fieldMeta.title, dir: newDir }] : [];
5785
+ }
5786
+ else if (index >= 0) {
5787
+ const [item] = activeSorts.splice(index, 1);
5788
+ if (newDir) {
5789
+ // Re-click moves column to end so click order can override view/default order.
5790
+ activeSorts.push({ ...item, title: fieldMeta.title, dir: newDir });
5791
+ }
5792
+ }
5793
+ else if (newDir) {
5794
+ if (this.isViewDefaultSorts(activeSorts)) {
5795
+ activeSorts = [{ name: columnName, title: fieldMeta.title, dir: newDir }];
5796
+ }
5797
+ else {
5798
+ activeSorts.push({ name: columnName, title: fieldMeta.title, dir: newDir });
5799
+ }
5800
+ }
5801
+ this.sortedFields.set(activeSorts);
5802
+ this.lastAppliedSortKey = null;
5803
+ await this.saveSettings('sorts', activeSorts.map((s) => ({ name: s.name, dir: s.dir })));
5804
+ await this.applyFilterAndSort();
5746
5805
  }
5747
5806
  //****************** Commands ******************//
5748
5807
  async executeCommand(commandName, data = null) {
@@ -13886,6 +13945,18 @@ class AXPLookupWidgetEditComponent extends AXPValueWidgetComponent {
13886
13945
  this.disabled = computed(() => this.filterMode() ? false : this.options()['disabled'], ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
13887
13946
  this.columns = computed(() => this.options()['columns'] ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
13888
13947
  this.textField = computed(() => this.options()['textField'] ?? '', ...(ngDevMode ? [{ debugName: "textField" }] : /* istanbul ignore next */ []));
13948
+ /**
13949
+ * Template for select look (`ax-select-box`). Uses `textTemplate` when set, otherwise
13950
+ * falls back to `displayFormat` (same as tagbox). Single braces are expanded to `{{ }}`
13951
+ * for the select box template engine (see `AXPDataListWidgetComponent.textTemplate`).
13952
+ */
13953
+ this.textTemplate = computed(() => {
13954
+ const explicit = this.options()['textTemplate'];
13955
+ if (explicit) {
13956
+ return explicit.replace(/\{/g, '{{').replace(/\}/g, '}}');
13957
+ }
13958
+ return this.displayFormat() ?? null;
13959
+ }, ...(ngDevMode ? [{ debugName: "textTemplate" }] : /* istanbul ignore next */ []));
13889
13960
  this.hasClearButton = computed(() => (!this.filterMode() && this.options()['hasClearButton']) ?? false, ...(ngDevMode ? [{ debugName: "hasClearButton" }] : /* istanbul ignore next */ []));
13890
13961
  this.showItemTooltip = computed(() => this.options()['showItemTooltip'] ?? false, ...(ngDevMode ? [{ debugName: "showItemTooltip" }] : /* istanbul ignore next */ []));
13891
13962
  this.isItemTruncated = computed(() => this.options()['isItemTruncated'] ?? true, ...(ngDevMode ? [{ debugName: "isItemTruncated" }] : /* istanbul ignore next */ []));