@praxisui/table 8.0.0-beta.26 → 8.0.0-beta.27

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.
@@ -10,6 +10,8 @@ import * as i15 from '@angular/material/progress-bar';
10
10
  import { MatProgressBarModule } from '@angular/material/progress-bar';
11
11
  import * as i5 from '@angular/material/icon';
12
12
  import { MatIconModule } from '@angular/material/icon';
13
+ import * as i10 from '@angular/material/tooltip';
14
+ import { MatTooltipModule } from '@angular/material/tooltip';
13
15
  import { PraxisFilterForm } from '@praxisui/dynamic-form';
14
16
 
15
17
  class FilterFormDialogHostComponent {
@@ -20,6 +22,7 @@ class FilterFormDialogHostComponent {
20
22
  lastValue = {};
21
23
  formGroup = null;
22
24
  canSave = false;
25
+ saving = false;
23
26
  constructor(data, ref) {
24
27
  this.data = data;
25
28
  this.ref = ref;
@@ -32,10 +35,10 @@ class FilterFormDialogHostComponent {
32
35
  ev.formGroup.patchValue(dto, { emitEvent: false });
33
36
  }
34
37
  this.lastValue = this.formGroup?.getRawValue?.() ?? this.lastValue;
35
- this.updateCanSave();
36
38
  }
37
39
  catch { }
38
40
  this.ready = true;
41
+ this.updateCanSave();
39
42
  }
40
43
  onChange(ev) {
41
44
  this.lastValue = ev?.formData ?? {};
@@ -64,20 +67,42 @@ class FilterFormDialogHostComponent {
64
67
  }
65
68
  buildDtoForSave() {
66
69
  const base = this.data?.initialDto || {};
67
- const merged = { ...base, ...(this.lastValue || {}) };
70
+ const current = this.formGroup?.getRawValue?.() ?? this.lastValue ?? {};
71
+ const merged = { ...base, ...current };
68
72
  return this.clean(merged);
69
73
  }
70
74
  updateCanSave() {
71
- this.canSave = Object.keys(this.buildDtoForSave() || {}).length > 0;
75
+ this.canSave =
76
+ this.ready &&
77
+ this.valid &&
78
+ Object.keys(this.buildDtoForSave() || {}).length > 0;
79
+ }
80
+ saveShortcutTooltip() {
81
+ if (this.saving) {
82
+ return this.data.i18n?.shortcutSaving || 'Salvando atalho...';
83
+ }
84
+ if (!this.valid) {
85
+ return this.data.i18n?.shortcutInvalid || 'Corrija os filtros antes de salvar o atalho.';
86
+ }
87
+ if (!Object.keys(this.buildDtoForSave() || {}).length) {
88
+ return this.data.i18n?.shortcutRequiresFilter || 'Preencha ao menos um filtro para salvar um atalho.';
89
+ }
90
+ return '';
72
91
  }
73
92
  saveShortcut() {
93
+ if (!this.canSave || this.saving)
94
+ return;
95
+ const dto = this.buildDtoForSave();
96
+ if (!Object.keys(dto).length)
97
+ return;
98
+ this.saving = true;
74
99
  try {
75
- const dto = this.buildDtoForSave();
76
- if (!Object.keys(dto).length)
77
- return;
78
100
  this.data?.onSaveShortcut?.(dto);
79
101
  }
80
- catch { }
102
+ finally {
103
+ this.saving = false;
104
+ this.updateCanSave();
105
+ }
81
106
  }
82
107
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilterFormDialogHostComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
83
108
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: FilterFormDialogHostComponent, isStandalone: true, selector: "praxis-filter-form-dialog-host", ngImport: i0, template: `
@@ -116,10 +141,14 @@ class FilterFormDialogHostComponent {
116
141
  <p *ngIf="!data?.config && !data?.schemaLoading" class="pfx-empty-state">{{ data.i18n?.noData || 'Nenhum dado' }}</p>
117
142
  </mat-dialog-content>
118
143
  <mat-dialog-actions align="end" class="pfx-dialog-actions">
119
- <button mat-button type="button"
144
+ <button mat-stroked-button type="button"
145
+ class="pfx-save-shortcut-button"
120
146
  *ngIf="data?.allowSaveTags"
121
- [disabled]="!canSave"
147
+ [disabled]="!canSave || saving"
148
+ [matTooltip]="saveShortcutTooltip()"
149
+ [matTooltipDisabled]="canSave && !saving"
122
150
  (click)="saveShortcut()">
151
+ <mat-icon aria-hidden="true">{{ saving ? 'hourglass_empty' : 'bookmark_add' }}</mat-icon>
123
152
  {{ data.i18n?.saveAsShortcut || 'Salvar como atalho' }}
124
153
  </button>
125
154
  <button mat-stroked-button type="button" (click)="close()">{{ data.i18n?.cancel || 'Cancelar' }}</button>
@@ -127,11 +156,11 @@ class FilterFormDialogHostComponent {
127
156
  {{ data.i18n?.apply || 'Aplicar' }}
128
157
  </button>
129
158
  </mat-dialog-actions>
130
- `, isInline: true, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--mdc-dialog-subhead-color, var(--md-sys-color-on-surface))}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant))}.pfx-dialog-loading{display:flex;flex-direction:column;gap:10px;min-height:128px;justify-content:center;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant));font-size:.875rem}.pfx-form-pending{height:0;overflow:hidden;visibility:hidden;pointer-events:none}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i15.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "requestSearch", "validityChange"] }] });
159
+ `, isInline: true, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--mdc-dialog-subhead-color, var(--md-sys-color-on-surface))}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant))}.pfx-dialog-loading{display:flex;flex-direction:column;gap:10px;min-height:128px;justify-content:center;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant));font-size:.875rem}.pfx-form-pending{height:0;overflow:hidden;visibility:hidden;pointer-events:none}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}.pfx-save-shortcut-button{margin-right:auto}.pfx-save-shortcut-button mat-icon{margin-right:6px;width:18px;height:18px;font-size:18px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i15.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "requestSearch", "validityChange"] }] });
131
160
  }
132
161
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilterFormDialogHostComponent, decorators: [{
133
162
  type: Component,
134
- args: [{ selector: 'praxis-filter-form-dialog-host', standalone: true, imports: [CommonModule, MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, PraxisFilterForm], template: `
163
+ args: [{ selector: 'praxis-filter-form-dialog-host', standalone: true, imports: [CommonModule, MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, MatTooltipModule, PraxisFilterForm], template: `
135
164
  <div mat-dialog-title class="pfx-dialog-title" id="filterDialogTitle">
136
165
  <div class="pfx-dialog-title-text">
137
166
  <mat-icon>tune</mat-icon>
@@ -167,10 +196,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
167
196
  <p *ngIf="!data?.config && !data?.schemaLoading" class="pfx-empty-state">{{ data.i18n?.noData || 'Nenhum dado' }}</p>
168
197
  </mat-dialog-content>
169
198
  <mat-dialog-actions align="end" class="pfx-dialog-actions">
170
- <button mat-button type="button"
199
+ <button mat-stroked-button type="button"
200
+ class="pfx-save-shortcut-button"
171
201
  *ngIf="data?.allowSaveTags"
172
- [disabled]="!canSave"
202
+ [disabled]="!canSave || saving"
203
+ [matTooltip]="saveShortcutTooltip()"
204
+ [matTooltipDisabled]="canSave && !saving"
173
205
  (click)="saveShortcut()">
206
+ <mat-icon aria-hidden="true">{{ saving ? 'hourglass_empty' : 'bookmark_add' }}</mat-icon>
174
207
  {{ data.i18n?.saveAsShortcut || 'Salvar como atalho' }}
175
208
  </button>
176
209
  <button mat-stroked-button type="button" (click)="close()">{{ data.i18n?.cancel || 'Cancelar' }}</button>
@@ -178,7 +211,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
178
211
  {{ data.i18n?.apply || 'Aplicar' }}
179
212
  </button>
180
213
  </mat-dialog-actions>
181
- `, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--mdc-dialog-subhead-color, var(--md-sys-color-on-surface))}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant))}.pfx-dialog-loading{display:flex;flex-direction:column;gap:10px;min-height:128px;justify-content:center;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant));font-size:.875rem}.pfx-form-pending{height:0;overflow:hidden;visibility:hidden;pointer-events:none}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}\n"] }]
214
+ `, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--mdc-dialog-subhead-color, var(--md-sys-color-on-surface))}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant))}.pfx-dialog-loading{display:flex;flex-direction:column;gap:10px;min-height:128px;justify-content:center;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant));font-size:.875rem}.pfx-form-pending{height:0;overflow:hidden;visibility:hidden;pointer-events:none}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}.pfx-save-shortcut-button{margin-right:auto}.pfx-save-shortcut-button mat-icon{margin-right:6px;width:18px;height:18px;font-size:18px}\n"] }]
182
215
  }], ctorParameters: () => [{ type: undefined, decorators: [{
183
216
  type: Inject,
184
217
  args: [MAT_DIALOG_DATA]
@@ -1,4 +1,5 @@
1
1
  import { firstValueFrom } from 'rxjs';
2
+ import { shouldRoutePromptToGovernedDecision } from '@praxisui/ai';
2
3
 
3
4
  class TableAgenticAuthoringTurnFlow {
4
5
  adapter;
@@ -273,28 +274,7 @@ class TableAgenticAuthoringTurnFlow {
273
274
  };
274
275
  }
275
276
  shouldRouteToGovernedDecision(prompt, contextHints) {
276
- const normalized = prompt.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
277
- const recommendedFlow = this.toRecord(contextHints?.['domainCatalog'])?.['recommendedAuthoringFlow'];
278
- if (recommendedFlow === 'shared_rule_authoring')
279
- return true;
280
- return [
281
- 'regra',
282
- 'politica',
283
- 'policy',
284
- 'compliance',
285
- 'lgpd',
286
- 'privacidade',
287
- 'aprovacao',
288
- 'aprovar',
289
- 'publicar',
290
- 'materializar',
291
- 'enforcement',
292
- 'validacao de negocio',
293
- 'validar negocio',
294
- 'elegibilidade',
295
- 'permissao',
296
- 'acesso',
297
- ].some((term) => normalized.includes(term));
277
+ return shouldRoutePromptToGovernedDecision(prompt, contextHints);
298
278
  }
299
279
  toGovernedDecisionHandoff(prompt, request) {
300
280
  const message = 'Esse pedido parece alterar uma decisao de negocio compartilhada. A tabela pode ajudar a descrever o alvo, mas a regra deve seguir pelo fluxo governado de domain-rules antes de qualquer materializacao runtime.';
@@ -36051,7 +36051,7 @@ class PraxisFilter {
36051
36051
  this.advancedOpen = true;
36052
36052
  this.saveConfig();
36053
36053
  try {
36054
- const { FilterFormDialogHostComponent } = await import('./praxisui-table-filter-form-dialog-host.component-CX2ga9Pq.mjs');
36054
+ const { FilterFormDialogHostComponent } = await import('./praxisui-table-filter-form-dialog-host.component-CN9JWFoa.mjs');
36055
36055
  const formId = this.formId || this.filterId || 'filter';
36056
36056
  const ref = this.dialog.open(FilterFormDialogHostComponent, {
36057
36057
  width: '780px',
@@ -38679,6 +38679,78 @@ class PraxisTable {
38679
38679
  }
38680
38680
  catch { }
38681
38681
  }
38682
+ mergePersistedTableConfigWithInput(storedConfig, inputConfig) {
38683
+ const merged = fillUndefined(storedConfig, inputConfig);
38684
+ return this.reconcileHostDeclaredTableContract(merged, storedConfig, inputConfig);
38685
+ }
38686
+ reconcileHostDeclaredTableContract(mergedConfig, storedConfig, inputConfig) {
38687
+ const withColumns = this.reconcileHostDeclaredColumns(mergedConfig, storedConfig, inputConfig);
38688
+ return this.reconcileHostDeclaredRowActions(withColumns, storedConfig, inputConfig);
38689
+ }
38690
+ reconcileHostDeclaredColumns(mergedConfig, storedConfig, inputConfig) {
38691
+ const inputColumns = Array.isArray(inputConfig?.columns)
38692
+ ? inputConfig.columns
38693
+ : null;
38694
+ if (!inputColumns || inputColumns.length === 0) {
38695
+ return mergedConfig;
38696
+ }
38697
+ const storedColumns = Array.isArray(storedConfig?.columns)
38698
+ ? storedConfig.columns
38699
+ : null;
38700
+ const hostIds = this.normalizePersistedColumnIds(inputColumns);
38701
+ const storedIds = storedColumns ? this.normalizePersistedColumnIds(storedColumns) : [];
38702
+ const columnContractChanged = hostIds.length > 0 && hostIds.join('|') !== storedIds.join('|');
38703
+ if (!columnContractChanged) {
38704
+ return mergedConfig;
38705
+ }
38706
+ const next = this.clonePlainObject(mergedConfig);
38707
+ next.columns = this.clonePlainObject(inputColumns);
38708
+ return next;
38709
+ }
38710
+ reconcileHostDeclaredRowActions(mergedConfig, storedConfig, inputConfig) {
38711
+ const inputRow = inputConfig?.actions?.row;
38712
+ if (!inputRow || typeof inputRow !== 'object' || Array.isArray(inputRow)) {
38713
+ return mergedConfig;
38714
+ }
38715
+ const hostActions = Array.isArray(inputRow.actions) ? inputRow.actions : null;
38716
+ const storedActions = Array.isArray(storedConfig?.actions?.row?.actions)
38717
+ ? storedConfig.actions.row.actions
38718
+ : null;
38719
+ const hostIds = hostActions ? this.normalizePersistedRowActionIds(hostActions) : [];
38720
+ const storedIds = storedActions ? this.normalizePersistedRowActionIds(storedActions) : [];
38721
+ const actionContractChanged = hostIds.length > 0 && hostIds.join('|') !== storedIds.join('|');
38722
+ const storedRow = storedConfig?.actions?.row;
38723
+ const next = this.clonePlainObject(mergedConfig);
38724
+ next.actions = next.actions || {};
38725
+ if (!storedRow || actionContractChanged) {
38726
+ next.actions.row = this.clonePlainObject(inputRow);
38727
+ return next;
38728
+ }
38729
+ next.actions.row = {
38730
+ ...this.clonePlainObject(inputRow),
38731
+ ...this.clonePlainObject(storedRow),
38732
+ actions: hostActions ? this.clonePlainObject(hostActions) : undefined,
38733
+ };
38734
+ return next;
38735
+ }
38736
+ normalizePersistedRowActionIds(actions) {
38737
+ return actions
38738
+ .map((action) => String(action?.action || action?.id || action?.code || action?.key || '').trim().toLowerCase())
38739
+ .filter((id) => id.length > 0);
38740
+ }
38741
+ normalizePersistedColumnIds(columns) {
38742
+ return columns
38743
+ .map((column) => String(column?.field || column?.id || column?.name || '').trim().toLowerCase())
38744
+ .filter((id) => id.length > 0);
38745
+ }
38746
+ clonePlainObject(value) {
38747
+ try {
38748
+ return JSON.parse(JSON.stringify(value));
38749
+ }
38750
+ catch {
38751
+ return value;
38752
+ }
38753
+ }
38682
38754
  setShowToolbar(next, deferChangeDetection = false) {
38683
38755
  if (this.showToolbar === next)
38684
38756
  return;
@@ -38867,7 +38939,7 @@ class PraxisTable {
38867
38939
  initializeAiAssistantController() {
38868
38940
  if (!this.aiAdapter || this.aiAssistantController)
38869
38941
  return;
38870
- import('./praxisui-table-table-agentic-authoring-turn-flow-DRuE55Mi.mjs')
38942
+ import('./praxisui-table-table-agentic-authoring-turn-flow-001PEVYJ.mjs')
38871
38943
  .then(({ TableAgenticAuthoringTurnFlow }) => {
38872
38944
  if (this.aiAssistantController || !this.aiAdapter)
38873
38945
  return;
@@ -39228,7 +39300,7 @@ class PraxisTable {
39228
39300
  try {
39229
39301
  const storedConfig = await firstValueFrom(this.asyncConfigStorage.loadConfig(cfgKey));
39230
39302
  if (storedConfig) {
39231
- this.config = fillUndefined(storedConfig, this.config);
39303
+ this.config = this.mergePersistedTableConfigWithInput(storedConfig, this.config);
39232
39304
  }
39233
39305
  }
39234
39306
  catch (e) {
@@ -39290,6 +39362,9 @@ class PraxisTable {
39290
39362
  this.applyAppearanceVariables();
39291
39363
  }
39292
39364
  ngOnChanges(changes) {
39365
+ if (changes['config']?.currentValue && this.config) {
39366
+ this.config = this.reconcileHostDeclaredTableContract(this.config, changes['config'].previousValue, changes['config'].currentValue);
39367
+ }
39293
39368
  this.ensureConfigDefaults();
39294
39369
  this.enforceUnsupportedFeatureGuards();
39295
39370
  this.syncPaginatorIntl();
package/index.d.ts CHANGED
@@ -1203,6 +1203,13 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterCont
1203
1203
  private tableConfigKey;
1204
1204
  private filterConfigKey;
1205
1205
  private ensureConfigDefaults;
1206
+ private mergePersistedTableConfigWithInput;
1207
+ private reconcileHostDeclaredTableContract;
1208
+ private reconcileHostDeclaredColumns;
1209
+ private reconcileHostDeclaredRowActions;
1210
+ private normalizePersistedRowActionIds;
1211
+ private normalizePersistedColumnIds;
1212
+ private clonePlainObject;
1206
1213
  private setShowToolbar;
1207
1214
  private shouldExposeToolbar;
1208
1215
  constructor(cdr: ChangeDetectorRef, settingsPanel: SettingsPanelService, crudService: GenericCrudService<any, any>, tableDefaultsProvider: TableDefaultsProvider, filterConfig: FilterConfigService, formattingService: DataFormattingService, pxDialog: PraxisDialog, snackBar: MatSnackBar, asyncConfigStorage: AsyncConfigStorage, connectionStorage: ConnectionStorage, hostRef: ElementRef<HTMLElement>, global: GlobalConfigService, resourceDiscovery: ResourceDiscoveryService, componentKeys: ComponentKeyService, loadingOrchestrator: LoadingOrchestrator, globalActions: GlobalActionService, loadingRenderer?: PraxisLoadingRenderer | undefined, route?: ActivatedRoute | undefined, logger?: LoggerService | undefined, analyticsStatsApi?: AnalyticsTableStatsApiService | undefined);
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "@praxisui/table",
3
- "version": "8.0.0-beta.26",
3
+ "version": "8.0.0-beta.27",
4
4
  "description": "Advanced data table for Angular (Praxis UI) with editing, filtering, sorting, virtualization, and settings panel integration.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^20.0.0",
7
7
  "@angular/core": "^20.0.0",
8
- "@praxisui/ai": "^8.0.0-beta.26",
9
- "@praxisui/core": "^8.0.0-beta.26",
10
- "@praxisui/dynamic-fields": "^8.0.0-beta.26",
11
- "@praxisui/dynamic-form": "^8.0.0-beta.26",
12
- "@praxisui/metadata-editor": "^8.0.0-beta.26",
13
- "@praxisui/rich-content": "^8.0.0-beta.26",
14
- "@praxisui/settings-panel": "^8.0.0-beta.26",
15
- "@praxisui/table-rule-builder": "^8.0.0-beta.26",
8
+ "@praxisui/ai": "^8.0.0-beta.27",
9
+ "@praxisui/core": "^8.0.0-beta.27",
10
+ "@praxisui/dynamic-fields": "^8.0.0-beta.27",
11
+ "@praxisui/dynamic-form": "^8.0.0-beta.27",
12
+ "@praxisui/metadata-editor": "^8.0.0-beta.27",
13
+ "@praxisui/rich-content": "^8.0.0-beta.27",
14
+ "@praxisui/settings-panel": "^8.0.0-beta.27",
15
+ "@praxisui/table-rule-builder": "^8.0.0-beta.27",
16
16
  "@angular/cdk": "^20.0.0",
17
17
  "@angular/forms": "^20.0.0",
18
18
  "@angular/material": "^20.0.0",
19
19
  "@angular/router": "^20.0.0",
20
- "@praxisui/dialog": "^8.0.0-beta.26",
20
+ "@praxisui/dialog": "^8.0.0-beta.27",
21
21
  "rxjs": "~7.8.0"
22
22
  },
23
23
  "dependencies": {