@praxisui/table 8.0.0-beta.8 → 8.0.0-beta.81

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.
Files changed (45) hide show
  1. package/README.md +191 -11
  2. package/docs/DSL-Extensions-Guide.md +23 -0
  3. package/docs/adr/2026-03-dynamic-filter-cross-lib-coupling.md +107 -0
  4. package/docs/adr/2026-03-filter-drawer-adapter-light-entrypoint.md +105 -0
  5. package/docs/adr/2026-03-table-editor-idfield-decision.md +85 -0
  6. package/docs/column-resize-reorder-implementation-plan.md +338 -0
  7. package/docs/column-resize-reorder-review-prompt.md +34 -0
  8. package/docs/dynamic-filter-architecture-overview.md +207 -0
  9. package/docs/dynamic-filter-backend-contract-cheatsheet.md +167 -0
  10. package/docs/dynamic-filter-editor-settings-guide.md +229 -0
  11. package/docs/dynamic-filter-host-integration-guide.md +266 -0
  12. package/docs/dynamic-filter-payload-contract.md +332 -0
  13. package/docs/dynamic-filter-range-filters-guide.md +296 -0
  14. package/docs/dynamic-filter-troubleshooting-guide.md +257 -0
  15. package/docs/dynamic-inline-filter-catalog.md +147 -0
  16. package/docs/e2e-column-drag-playwright.md +62 -0
  17. package/docs/expandable-rows-enterprise-big-leagues-plan.md +1080 -0
  18. package/docs/json-logic-operators-and-helpers.md +57 -0
  19. package/docs/local-data-mode-precedence.md +12 -0
  20. package/docs/local-data-pre-implementation-baseline.md +22 -0
  21. package/docs/local-data-preimplementation-go-no-go.md +39 -0
  22. package/docs/local-data-support-implementation-plan.md +524 -0
  23. package/docs/local-data-support-pr-package.md +66 -0
  24. package/docs/localization-persistence-merge.md +22 -0
  25. package/docs/performance-hardening-v2-implementation-plan.md +479 -0
  26. package/docs/playground-scenario-curation-plan.md +482 -0
  27. package/docs/playground-scenario-second-opinion-prompt.md +121 -0
  28. package/docs/playground-scenario-second-opinion-review.md +234 -0
  29. package/docs/release-notes-p1-hardening.md +76 -0
  30. package/docs/table-authoring-document-completeness-checklist.md +120 -0
  31. package/docs/table-editor-capability-review-prompt.md +349 -0
  32. package/docs/visual-rules-editor-transition.md +29 -0
  33. package/fesm2022/praxisui-table-filter-form-dialog-host.component-DbwGIMjF.mjs +232 -0
  34. package/fesm2022/praxisui-table-praxisui-table-BigLNasG.mjs +59830 -0
  35. package/fesm2022/praxisui-table-table-agentic-authoring-turn-flow-CyJJHpMr.mjs +3014 -0
  36. package/fesm2022/praxisui-table-table-ai.adapter-D8fQSvC3.mjs +3624 -0
  37. package/fesm2022/praxisui-table.mjs +1 -51444
  38. package/filter-drawer-adapter/package.json +2 -1
  39. package/package.json +22 -15
  40. package/src/lib/praxis-table.json-api.md +1357 -0
  41. package/{index.d.ts → types/praxisui-table.d.ts} +548 -120
  42. package/fesm2022/praxisui-table-filter-form-dialog-host.component-Dm2f0muy.mjs +0 -165
  43. package/fesm2022/praxisui-table-table-agentic-authoring-turn-flow-tu7jtTwV.mjs +0 -280
  44. package/fesm2022/praxisui-table-table-ai.adapter-DxjDaQqy.mjs +0 -895
  45. /package/{filter-drawer-adapter/index.d.ts → types/praxisui-table-filter-drawer-adapter.d.ts} +0 -0
@@ -1,165 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { Inject, Component } from '@angular/core';
3
- import * as i2 from '@angular/common';
4
- import { CommonModule } from '@angular/common';
5
- import * as i1 from '@angular/material/dialog';
6
- import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
7
- import * as i3 from '@angular/material/button';
8
- import { MatButtonModule } from '@angular/material/button';
9
- import * as i15 from '@angular/material/progress-bar';
10
- import { MatProgressBarModule } from '@angular/material/progress-bar';
11
- import * as i5 from '@angular/material/icon';
12
- import { MatIconModule } from '@angular/material/icon';
13
- import { PraxisFilterForm } from '@praxisui/dynamic-form';
14
-
15
- class FilterFormDialogHostComponent {
16
- data;
17
- ref;
18
- valid = true;
19
- lastValue = {};
20
- formGroup = null;
21
- canSave = false;
22
- constructor(data, ref) {
23
- this.data = data;
24
- this.ref = ref;
25
- }
26
- onReady(ev) {
27
- try {
28
- this.formGroup = ev?.formGroup || null;
29
- const dto = this.data?.initialDto || {};
30
- if (ev?.formGroup && dto && Object.keys(dto).length) {
31
- ev.formGroup.patchValue(dto, { emitEvent: false });
32
- }
33
- this.lastValue = this.formGroup?.getRawValue?.() ?? this.lastValue;
34
- this.updateCanSave();
35
- }
36
- catch { }
37
- }
38
- onChange(ev) {
39
- this.lastValue = ev?.formData ?? {};
40
- this.updateCanSave();
41
- }
42
- onValidity(v) {
43
- this.valid = v;
44
- this.updateCanSave();
45
- }
46
- apply() {
47
- const formData = this.formGroup?.getRawValue?.() ??
48
- this.lastValue ??
49
- this.data?.initialDto ??
50
- {};
51
- this.ref.close({ formData });
52
- }
53
- close() { this.ref.close(); }
54
- clean(obj) {
55
- const out = {};
56
- Object.keys(obj || {}).forEach((k) => {
57
- const v = obj[k];
58
- if (v !== '' && v !== null && v !== undefined)
59
- out[k] = v;
60
- });
61
- return out;
62
- }
63
- buildDtoForSave() {
64
- const base = this.data?.initialDto || {};
65
- const merged = { ...base, ...(this.lastValue || {}) };
66
- return this.clean(merged);
67
- }
68
- updateCanSave() {
69
- this.canSave = Object.keys(this.buildDtoForSave() || {}).length > 0;
70
- }
71
- saveShortcut() {
72
- try {
73
- const dto = this.buildDtoForSave();
74
- if (!Object.keys(dto).length)
75
- return;
76
- this.data?.onSaveShortcut?.(dto);
77
- }
78
- catch { }
79
- }
80
- 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 });
81
- 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: `
82
- <div mat-dialog-title class="pfx-dialog-title" id="filterDialogTitle">
83
- <div class="pfx-dialog-title-text">
84
- <mat-icon>tune</mat-icon>
85
- <span>{{ data.title || 'Filtro avançado' }}</span>
86
- </div>
87
- <button mat-icon-button type="button" class="pfx-dialog-close" (click)="close()"
88
- [attr.aria-label]="data.i18n?.cancel || 'Fechar'">
89
- <mat-icon>close</mat-icon>
90
- </button>
91
- </div>
92
- <mat-dialog-content class="pfx-filter-dialog-content" aria-labelledby="filterDialogTitle">
93
- <mat-progress-bar *ngIf="data?.schemaLoading" mode="indeterminate"></mat-progress-bar>
94
- <praxis-filter-form
95
- *ngIf="data?.config"
96
- [formId]="data.formId"
97
- [resourcePath]="data.resourcePath"
98
- [mode]="'edit'"
99
- [config]="data.config"
100
- (formReady)="onReady($event)"
101
- (valueChange)="onChange($event)"
102
- (validityChange)="onValidity($event)"
103
- ></praxis-filter-form>
104
- <p *ngIf="!data?.config && !data?.schemaLoading" class="pfx-empty-state">{{ data.i18n?.noData || 'Nenhum dado' }}</p>
105
- </mat-dialog-content>
106
- <mat-dialog-actions align="end" class="pfx-dialog-actions">
107
- <button mat-button type="button"
108
- *ngIf="data?.allowSaveTags"
109
- [disabled]="!canSave"
110
- (click)="saveShortcut()">
111
- {{ data.i18n?.saveAsShortcut || 'Salvar como atalho' }}
112
- </button>
113
- <button mat-stroked-button type="button" (click)="close()">{{ data.i18n?.cancel || 'Cancelar' }}</button>
114
- <button mat-flat-button color="primary" (click)="apply()" [disabled]="!valid">
115
- {{ data.i18n?.apply || 'Aplicar' }}
116
- </button>
117
- </mat-dialog-actions>
118
- `, 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-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"] }] });
119
- }
120
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilterFormDialogHostComponent, decorators: [{
121
- type: Component,
122
- args: [{ selector: 'praxis-filter-form-dialog-host', standalone: true, imports: [CommonModule, MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, PraxisFilterForm], template: `
123
- <div mat-dialog-title class="pfx-dialog-title" id="filterDialogTitle">
124
- <div class="pfx-dialog-title-text">
125
- <mat-icon>tune</mat-icon>
126
- <span>{{ data.title || 'Filtro avançado' }}</span>
127
- </div>
128
- <button mat-icon-button type="button" class="pfx-dialog-close" (click)="close()"
129
- [attr.aria-label]="data.i18n?.cancel || 'Fechar'">
130
- <mat-icon>close</mat-icon>
131
- </button>
132
- </div>
133
- <mat-dialog-content class="pfx-filter-dialog-content" aria-labelledby="filterDialogTitle">
134
- <mat-progress-bar *ngIf="data?.schemaLoading" mode="indeterminate"></mat-progress-bar>
135
- <praxis-filter-form
136
- *ngIf="data?.config"
137
- [formId]="data.formId"
138
- [resourcePath]="data.resourcePath"
139
- [mode]="'edit'"
140
- [config]="data.config"
141
- (formReady)="onReady($event)"
142
- (valueChange)="onChange($event)"
143
- (validityChange)="onValidity($event)"
144
- ></praxis-filter-form>
145
- <p *ngIf="!data?.config && !data?.schemaLoading" class="pfx-empty-state">{{ data.i18n?.noData || 'Nenhum dado' }}</p>
146
- </mat-dialog-content>
147
- <mat-dialog-actions align="end" class="pfx-dialog-actions">
148
- <button mat-button type="button"
149
- *ngIf="data?.allowSaveTags"
150
- [disabled]="!canSave"
151
- (click)="saveShortcut()">
152
- {{ data.i18n?.saveAsShortcut || 'Salvar como atalho' }}
153
- </button>
154
- <button mat-stroked-button type="button" (click)="close()">{{ data.i18n?.cancel || 'Cancelar' }}</button>
155
- <button mat-flat-button color="primary" (click)="apply()" [disabled]="!valid">
156
- {{ data.i18n?.apply || 'Aplicar' }}
157
- </button>
158
- </mat-dialog-actions>
159
- `, 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-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"] }]
160
- }], ctorParameters: () => [{ type: undefined, decorators: [{
161
- type: Inject,
162
- args: [MAT_DIALOG_DATA]
163
- }] }, { type: i1.MatDialogRef }] });
164
-
165
- export { FilterFormDialogHostComponent };
@@ -1,280 +0,0 @@
1
- import { firstValueFrom } from 'rxjs';
2
-
3
- class TableAgenticAuthoringTurnFlow {
4
- adapter;
5
- aiApi;
6
- mode = 'config';
7
- constructor(adapter, aiApi) {
8
- this.adapter = adapter;
9
- this.aiApi = aiApi;
10
- }
11
- async submit(request) {
12
- const prompt = (request.prompt ?? '').trim();
13
- if (!prompt) {
14
- return {
15
- state: 'listening',
16
- phase: 'capture',
17
- statusText: '',
18
- };
19
- }
20
- const componentId = this.adapter.componentId || request.componentId || 'praxis-table';
21
- const componentType = this.adapter.componentType || request.componentType || 'table';
22
- const currentState = this.toAiJsonObject(this.adapter.getCurrentConfig());
23
- const dataProfile = this.optionalJsonObject(this.adapter.getDataProfile?.());
24
- const runtimeState = this.optionalJsonObject(this.adapter.getRuntimeState?.());
25
- const schemaFields = this.adapter.getSchemaFields?.()
26
- ?.map((field) => this.toAiJsonObject(field))
27
- .filter((field) => Object.keys(field).length > 0);
28
- const contextHints = this.optionalJsonObject(this.adapter.getAuthoringContext?.());
29
- const response = await firstValueFrom(this.aiApi.getPatch({
30
- componentId,
31
- componentType,
32
- userPrompt: prompt,
33
- sessionId: request.sessionId,
34
- clientTurnId: request.clientTurnId,
35
- messages: this.toChatMessages(request.messages, prompt),
36
- currentState,
37
- currentStateDigest: this.buildCurrentStateDigest(currentState, dataProfile),
38
- uiContextRef: {
39
- componentId,
40
- componentType,
41
- },
42
- ...(dataProfile ? { dataProfile } : {}),
43
- ...(runtimeState ? { runtimeState } : {}),
44
- ...(schemaFields?.length ? { schemaFields } : {}),
45
- ...(contextHints ? { contextHints } : {}),
46
- }));
47
- return this.toTurnResult(this.compileAdapterResponse(response), request);
48
- }
49
- async apply(request) {
50
- const patch = this.toRecord(request.pendingPatch);
51
- if (!patch) {
52
- return {
53
- state: 'error',
54
- phase: 'apply',
55
- assistantMessage: 'Nao ha alteracao de tabela pronta para aplicar.',
56
- errorText: 'Nao ha alteracao de tabela pronta para aplicar.',
57
- canApply: false,
58
- };
59
- }
60
- const result = await this.adapter.applyPatch(patch, request.prompt);
61
- if (!result.success) {
62
- return {
63
- state: 'error',
64
- phase: 'apply',
65
- assistantMessage: result.error || 'Nao foi possivel aplicar as alteracoes na tabela.',
66
- errorText: result.error || 'Nao foi possivel aplicar as alteracoes na tabela.',
67
- canApply: true,
68
- pendingPatch: patch,
69
- };
70
- }
71
- return {
72
- state: 'success',
73
- phase: 'summarize',
74
- assistantMessage: 'Alteracoes aplicadas na tabela.',
75
- statusText: 'Alteracoes aplicadas na tabela.',
76
- canApply: false,
77
- pendingPatch: null,
78
- diagnostics: result.warnings?.length ? { warnings: result.warnings } : undefined,
79
- };
80
- }
81
- cancel() {
82
- return Promise.resolve({
83
- state: 'listening',
84
- phase: 'capture',
85
- assistantMessage: 'Solicitacao cancelada.',
86
- statusText: '',
87
- canApply: false,
88
- pendingPatch: null,
89
- pendingClarification: null,
90
- });
91
- }
92
- retry(request) {
93
- const lastPrompt = [...(request.messages ?? [])].reverse()
94
- .find((message) => message.role === 'user')?.text;
95
- return this.submit({
96
- ...request,
97
- prompt: lastPrompt ?? request.prompt,
98
- action: { kind: 'retry' },
99
- });
100
- }
101
- toTurnResult(response, request) {
102
- if (!response) {
103
- return {
104
- state: 'error',
105
- phase: 'capture',
106
- assistantMessage: 'Resposta vazia da IA.',
107
- errorText: 'Resposta vazia da IA.',
108
- };
109
- }
110
- if (response.sessionId && response.sessionId !== request.sessionId) {
111
- request = { ...request, sessionId: response.sessionId };
112
- }
113
- if (response.type === 'clarification') {
114
- const questions = this.toClarificationQuestions(response);
115
- return {
116
- state: 'clarification',
117
- phase: 'clarify',
118
- sessionId: response.sessionId ?? request.sessionId,
119
- assistantMessage: response.message || 'Preciso de mais detalhes para continuar.',
120
- clarificationQuestions: questions,
121
- quickReplies: this.toQuickReplies(response),
122
- canApply: false,
123
- };
124
- }
125
- if (response.type === 'info') {
126
- const message = response.message || response.explanation || 'Informacao gerada.';
127
- return {
128
- state: 'success',
129
- phase: 'summarize',
130
- sessionId: response.sessionId ?? request.sessionId,
131
- assistantMessage: message,
132
- statusText: message,
133
- canApply: false,
134
- };
135
- }
136
- if (response.type === 'error') {
137
- const message = response.message || 'Falha ao gerar alteracao de tabela.';
138
- return {
139
- state: 'error',
140
- phase: 'capture',
141
- sessionId: response.sessionId ?? request.sessionId,
142
- assistantMessage: message,
143
- errorText: message,
144
- diagnostics: response.warnings?.length ? { warnings: response.warnings } : undefined,
145
- };
146
- }
147
- if (response.patch && Object.keys(response.patch).length > 0) {
148
- const warnings = response.warnings?.filter(Boolean) ?? [];
149
- const suffix = warnings.length ? ` Avisos: ${warnings.join('; ')}` : '';
150
- return {
151
- state: 'review',
152
- phase: 'review',
153
- sessionId: response.sessionId ?? request.sessionId,
154
- assistantMessage: `${response.explanation || 'Proposta de alteracao pronta para revisar.'}${suffix}`,
155
- statusText: 'Revise a proposta antes de aplicar.',
156
- canApply: true,
157
- pendingPatch: response.patch,
158
- preview: {
159
- kind: 'table-config-patch',
160
- diff: response.diff ?? [],
161
- },
162
- diagnostics: warnings.length ? { warnings } : undefined,
163
- };
164
- }
165
- return {
166
- state: 'success',
167
- phase: 'summarize',
168
- sessionId: response.sessionId ?? request.sessionId,
169
- assistantMessage: response.message || response.explanation || 'Nenhuma alteracao necessaria.',
170
- statusText: response.message || response.explanation || 'Nenhuma alteracao necessaria.',
171
- canApply: false,
172
- };
173
- }
174
- compileAdapterResponse(response) {
175
- const compiled = this.adapter.compileAiResponse?.(response);
176
- if (!compiled) {
177
- return response;
178
- }
179
- const warnings = [
180
- ...(response.warnings ?? []),
181
- ...(compiled.warnings ?? []),
182
- ];
183
- return {
184
- ...response,
185
- ...compiled,
186
- warnings: warnings.length ? warnings : undefined,
187
- };
188
- }
189
- toChatMessages(messages, prompt) {
190
- const supported = (messages ?? [])
191
- .filter((message) => message.role === 'user' || message.role === 'assistant' || message.role === 'system')
192
- .map((message) => ({
193
- role: message.role,
194
- content: message.text,
195
- }))
196
- .filter((message) => message.content.trim().length > 0);
197
- return supported.length ? supported : [{ role: 'user', content: prompt }];
198
- }
199
- toClarificationQuestions(response) {
200
- const labels = response.questions?.length
201
- ? response.questions
202
- : response.message
203
- ? [response.message]
204
- : ['Qual ajuste voce quer aplicar na tabela?'];
205
- const options = this.toQuickReplies(response).map((reply) => ({
206
- id: reply.id,
207
- label: reply.label,
208
- value: reply.prompt,
209
- }));
210
- return labels.map((label, index) => ({
211
- id: `table-clarification-${index + 1}`,
212
- type: options.length ? 'single-choice' : 'text',
213
- label,
214
- allowCustom: true,
215
- options,
216
- }));
217
- }
218
- toQuickReplies(response) {
219
- const payloads = response.optionPayloads ?? [];
220
- if (payloads.length) {
221
- return payloads
222
- .map((option, index) => {
223
- const label = option.label?.trim() || option.value?.trim() || `Opcao ${index + 1}`;
224
- const prompt = option.example?.trim() || option.value?.trim() || label;
225
- return {
226
- id: `option-${index + 1}`,
227
- label,
228
- prompt,
229
- kind: 'clarification-option',
230
- };
231
- });
232
- }
233
- return (response.options ?? [])
234
- .filter((option) => !!option?.trim())
235
- .map((option, index) => ({
236
- id: `option-${index + 1}`,
237
- label: option.trim(),
238
- prompt: option.trim(),
239
- kind: 'clarification-option',
240
- }));
241
- }
242
- buildCurrentStateDigest(currentState, dataProfile) {
243
- const columns = Array.isArray(currentState['columns'])
244
- ? currentState['columns']
245
- .map((column) => this.toRecord(column)?.['field'])
246
- .filter((field) => typeof field === 'string' && field.length > 0)
247
- : undefined;
248
- const rowCount = typeof dataProfile?.['rowCount'] === 'number' ? dataProfile['rowCount'] : undefined;
249
- return {
250
- ...(columns?.length ? { columns } : {}),
251
- ...(rowCount !== undefined ? { rowCount } : {}),
252
- };
253
- }
254
- optionalJsonObject(value) {
255
- if (value === undefined || value === null) {
256
- return undefined;
257
- }
258
- const object = this.toAiJsonObject(value);
259
- return Object.keys(object).length ? object : undefined;
260
- }
261
- toAiJsonObject(value) {
262
- const record = this.toRecord(value);
263
- if (!record) {
264
- return {};
265
- }
266
- try {
267
- return JSON.parse(JSON.stringify(record));
268
- }
269
- catch {
270
- return {};
271
- }
272
- }
273
- toRecord(value) {
274
- return value && typeof value === 'object' && !Array.isArray(value)
275
- ? value
276
- : null;
277
- }
278
- }
279
-
280
- export { TableAgenticAuthoringTurnFlow };