@praxisui/dynamic-form 9.0.0-beta.72 → 9.0.0-beta.74
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/ai/component-registry.json +2 -2
- package/fesm2022/{praxisui-dynamic-form-dynamic-form-agentic-authoring-turn-flow-CmFfx-VR.mjs → praxisui-dynamic-form-dynamic-form-agentic-authoring-turn-flow-w9V0aQ9B.mjs} +205 -22
- package/fesm2022/praxisui-dynamic-form.mjs +235 -41
- package/package.json +8 -8
- package/src/lib/praxis-dynamic-form.json-api.md +5 -2
- package/types/praxisui-dynamic-form.d.ts +10 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-07-
|
|
3
|
+
"generatedAt": "2026-07-16T21:05:04.797Z",
|
|
4
4
|
"packageName": "@praxisui/dynamic-form",
|
|
5
|
-
"packageVersion": "9.0.0-beta.
|
|
5
|
+
"packageVersion": "9.0.0-beta.74",
|
|
6
6
|
"sourceRegistry": "praxis-component-registry-ingestion",
|
|
7
7
|
"sourceRegistryVersion": "1.0.0",
|
|
8
8
|
"componentCount": 2,
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { withAuthoringScopePolicy } from '@praxisui/ai';
|
|
2
3
|
|
|
3
4
|
class DynamicFormAgenticAuthoringTurnFlow {
|
|
4
5
|
adapter;
|
|
5
|
-
|
|
6
|
+
turnClient;
|
|
6
7
|
mode = 'agentic-authoring';
|
|
7
|
-
constructor(adapter,
|
|
8
|
+
constructor(adapter, turnClient) {
|
|
8
9
|
this.adapter = adapter;
|
|
9
|
-
this.
|
|
10
|
+
this.turnClient = turnClient;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
submit(request) {
|
|
12
13
|
const prompt = (request.prompt ?? '').trim();
|
|
13
14
|
if (!prompt) {
|
|
14
|
-
return {
|
|
15
|
+
return Promise.resolve({
|
|
15
16
|
state: 'listening',
|
|
16
17
|
phase: 'capture',
|
|
17
18
|
statusText: '',
|
|
18
|
-
};
|
|
19
|
+
});
|
|
19
20
|
}
|
|
20
21
|
const componentId = this.adapter.componentId || request.componentId || 'praxis-dynamic-form';
|
|
21
22
|
const componentType = this.adapter.componentType || request.componentType || 'form';
|
|
@@ -23,25 +24,207 @@ class DynamicFormAgenticAuthoringTurnFlow {
|
|
|
23
24
|
const runtimeState = this.optionalJsonObject(this.adapter.getRuntimeState?.());
|
|
24
25
|
const contextHints = this.mergeJsonObjects(this.optionalJsonObject(this.adapter.getAuthoringContext?.()), this.optionalJsonObject(request.action?.contextHints));
|
|
25
26
|
if (this.shouldRestrictToInlineHelp(contextHints)) {
|
|
26
|
-
return this.toInlineHelpOnlyResult(prompt, request, contextHints);
|
|
27
|
+
return Promise.resolve(this.toInlineHelpOnlyResult(prompt, request, contextHints));
|
|
27
28
|
}
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const buildRequest = async () => {
|
|
30
|
+
await this.adapter.prepareAuthoringContext?.();
|
|
31
|
+
const preparedRuntimeState = this.optionalJsonObject(this.adapter.getRuntimeState?.()) ?? runtimeState;
|
|
32
|
+
const preparedContextHints = this.mergeJsonObjects(this.optionalJsonObject(this.adapter.getAuthoringContext?.()), this.optionalJsonObject(request.action?.contextHints));
|
|
33
|
+
const dataProfile = this.optionalJsonObject(this.adapter.getDataProfile?.());
|
|
34
|
+
const schemaFields = this.adapter.getSchemaFields?.()
|
|
35
|
+
?.map((field) => this.toAiJsonObject(field))
|
|
36
|
+
.filter((field) => Object.keys(field).length > 0);
|
|
37
|
+
const patchRequest = withAuthoringScopePolicy({
|
|
38
|
+
componentId,
|
|
39
|
+
componentType,
|
|
40
|
+
userPrompt: prompt,
|
|
41
|
+
sessionId: request.sessionId,
|
|
42
|
+
clientTurnId: request.clientTurnId,
|
|
43
|
+
messages: this.toChatMessages(request.messages, prompt),
|
|
44
|
+
currentState,
|
|
45
|
+
currentStateDigest: this.buildCurrentStateDigest(currentState, preparedRuntimeState),
|
|
46
|
+
uiContextRef: {
|
|
47
|
+
componentId,
|
|
48
|
+
componentType,
|
|
49
|
+
},
|
|
50
|
+
...(dataProfile ? { dataProfile } : {}),
|
|
51
|
+
...(preparedRuntimeState ? { runtimeState: preparedRuntimeState } : {}),
|
|
52
|
+
...(schemaFields?.length ? { schemaFields } : {}),
|
|
53
|
+
...(preparedContextHints ? { contextHints: preparedContextHints } : {}),
|
|
54
|
+
}, {
|
|
38
55
|
componentId,
|
|
39
56
|
componentType,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
componentLabel: this.adapter.componentName || 'formulário',
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
...patchRequest,
|
|
61
|
+
targetApp: 'praxis-ui-angular',
|
|
62
|
+
targetComponentId: componentId,
|
|
63
|
+
currentPage: currentState,
|
|
64
|
+
conversationMessages: this.toConversationMessages(request.messages),
|
|
65
|
+
pendingClarification: this.toPendingClarification(request),
|
|
66
|
+
attachmentSummaries: this.toAttachmentSummaries(request),
|
|
67
|
+
activeSemanticDecision: this.optionalJsonObject(request.activeSemanticDecision ?? request.action?.activeSemanticDecision),
|
|
68
|
+
contextHints: patchRequest.contextHints ?? null,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
return this.submitViaAgenticStream(request, buildRequest);
|
|
72
|
+
}
|
|
73
|
+
submitViaAgenticStream(request, buildRequest) {
|
|
74
|
+
return new Observable((subscriber) => {
|
|
75
|
+
let closed = false;
|
|
76
|
+
let subscription = null;
|
|
77
|
+
const close = () => {
|
|
78
|
+
closed = true;
|
|
79
|
+
subscription?.unsubscribe();
|
|
80
|
+
subscription = null;
|
|
81
|
+
};
|
|
82
|
+
void buildRequest()
|
|
83
|
+
.then((turnRequest) => {
|
|
84
|
+
if (closed)
|
|
85
|
+
return;
|
|
86
|
+
subscription = this.turnClient.streamEvents(turnRequest, {
|
|
87
|
+
initialStatusText: 'Preparando o contexto seguro do formulário.',
|
|
88
|
+
resultTimeoutMs: 90_000,
|
|
89
|
+
streamTimeoutMs: 90_000,
|
|
90
|
+
}).subscribe({
|
|
91
|
+
next: (event) => {
|
|
92
|
+
if (closed)
|
|
93
|
+
return;
|
|
94
|
+
const result = this.toAgenticStreamTurnResult(event, request);
|
|
95
|
+
subscriber.next(result);
|
|
96
|
+
if (result.state !== 'processing') {
|
|
97
|
+
subscriber.complete();
|
|
98
|
+
close();
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
error: (error) => {
|
|
102
|
+
if (closed)
|
|
103
|
+
return;
|
|
104
|
+
subscriber.next(this.toAssistantErrorResult(error));
|
|
105
|
+
subscriber.complete();
|
|
106
|
+
close();
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
})
|
|
110
|
+
.catch((error) => {
|
|
111
|
+
if (closed)
|
|
112
|
+
return;
|
|
113
|
+
subscriber.next(this.toAssistantErrorResult(error));
|
|
114
|
+
subscriber.complete();
|
|
115
|
+
close();
|
|
116
|
+
});
|
|
117
|
+
return () => close();
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
toAgenticStreamTurnResult(event, request) {
|
|
121
|
+
if (event.kind === 'stream-started') {
|
|
122
|
+
return {
|
|
123
|
+
state: 'processing',
|
|
124
|
+
phase: 'contextualize',
|
|
125
|
+
statusText: 'Analisando o formulário e suas capacidades.',
|
|
126
|
+
sessionId: event.start.threadId,
|
|
127
|
+
clientTurnId: request.clientTurnId ?? event.start.turnId,
|
|
128
|
+
observationId: event.start.observationId ?? null,
|
|
129
|
+
canApply: false,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (event.kind === 'stream-lifecycle') {
|
|
133
|
+
return {
|
|
134
|
+
state: 'processing',
|
|
135
|
+
phase: 'contextualize',
|
|
136
|
+
statusText: event.statusText,
|
|
137
|
+
sessionId: event.start.threadId,
|
|
138
|
+
clientTurnId: request.clientTurnId ?? event.start.turnId,
|
|
139
|
+
observationId: event.start.observationId ?? null,
|
|
140
|
+
canApply: false,
|
|
141
|
+
diagnostics: event.diagnostics
|
|
142
|
+
? { streamLifecycle: { phase: event.phase, ...event.diagnostics } }
|
|
143
|
+
: undefined,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (event.event.type === 'result') {
|
|
147
|
+
const payload = this.toRecord(event.event.payload) ?? {};
|
|
148
|
+
const rawResponse = this.toRecord(payload['response']) ?? payload;
|
|
149
|
+
const response = this.normalizeAgenticResponse(rawResponse);
|
|
150
|
+
return {
|
|
151
|
+
...this.toTurnResult(this.compileAdapterResponse(response), request),
|
|
152
|
+
sessionId: event.event.threadId || request.sessionId,
|
|
153
|
+
clientTurnId: request.clientTurnId ?? event.event.turnId,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return this.turnClient.toTurnResult(event.event, request.clientTurnId);
|
|
157
|
+
}
|
|
158
|
+
normalizeAgenticResponse(response) {
|
|
159
|
+
const type = response['type'];
|
|
160
|
+
const normalizedType = type === 'patch'
|
|
161
|
+
|| type === 'clarification'
|
|
162
|
+
|| type === 'error'
|
|
163
|
+
|| type === 'info'
|
|
164
|
+
? type
|
|
165
|
+
: this.toRecord(response['patch']) || this.toRecord(response['compiledPatch'])
|
|
166
|
+
? 'patch'
|
|
167
|
+
: 'info';
|
|
168
|
+
const patch = this.toRecord(response['patch']) ?? this.toRecord(response['compiledPatch']) ?? undefined;
|
|
169
|
+
const message = typeof response['message'] === 'string'
|
|
170
|
+
? response['message']
|
|
171
|
+
: typeof response['assistantMessage'] === 'string'
|
|
172
|
+
? response['assistantMessage']
|
|
173
|
+
: undefined;
|
|
174
|
+
return {
|
|
175
|
+
...response,
|
|
176
|
+
type: normalizedType,
|
|
177
|
+
...(patch ? { patch } : {}),
|
|
178
|
+
...(message ? { message } : {}),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
toConversationMessages(messages) {
|
|
182
|
+
return (messages ?? [])
|
|
183
|
+
.filter((message) => message.role === 'user' || message.role === 'assistant' || message.role === 'system')
|
|
184
|
+
.map((message) => ({
|
|
185
|
+
id: message.id,
|
|
186
|
+
role: message.role,
|
|
187
|
+
text: message.text,
|
|
188
|
+
}))
|
|
189
|
+
.filter((message) => message.text.trim().length > 0);
|
|
190
|
+
}
|
|
191
|
+
toPendingClarification(request) {
|
|
192
|
+
const pending = request.pendingClarification;
|
|
193
|
+
if (!pending?.sourcePrompt?.trim())
|
|
194
|
+
return null;
|
|
195
|
+
return {
|
|
196
|
+
sourcePrompt: pending.sourcePrompt,
|
|
197
|
+
questions: pending.questions.map((question) => question.label).filter(Boolean),
|
|
198
|
+
assistantMessage: pending.assistantMessage ?? null,
|
|
199
|
+
clientTurnId: pending.clientTurnId ?? null,
|
|
200
|
+
diagnostics: this.optionalJsonObject(pending.diagnostics) ?? null,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
toAttachmentSummaries(request) {
|
|
204
|
+
return (request.attachments ?? []).map((attachment) => ({
|
|
205
|
+
id: attachment.id,
|
|
206
|
+
name: attachment.name,
|
|
207
|
+
kind: attachment.kind,
|
|
208
|
+
mimeType: attachment.mimeType ?? null,
|
|
209
|
+
sizeBytes: attachment.sizeBytes ?? null,
|
|
210
|
+
source: attachment.source ?? null,
|
|
211
|
+
hasPreview: !!attachment.previewUrl,
|
|
43
212
|
}));
|
|
44
|
-
|
|
213
|
+
}
|
|
214
|
+
toAssistantErrorResult(error) {
|
|
215
|
+
const message = error instanceof Error
|
|
216
|
+
? error.message
|
|
217
|
+
: typeof error === 'string' && error.trim()
|
|
218
|
+
? error
|
|
219
|
+
: 'Não foi possível concluir o pedido do formulário.';
|
|
220
|
+
return {
|
|
221
|
+
state: 'error',
|
|
222
|
+
phase: 'capture',
|
|
223
|
+
assistantMessage: `Não consegui concluir este pedido. ${message}`,
|
|
224
|
+
errorText: message,
|
|
225
|
+
canApply: false,
|
|
226
|
+
pendingPatch: null,
|
|
227
|
+
};
|
|
45
228
|
}
|
|
46
229
|
async apply(request) {
|
|
47
230
|
const contextHints = this.optionalJsonObject(this.adapter.getAuthoringContext?.());
|
|
@@ -26,7 +26,7 @@ import * as i1 from '@praxisui/core';
|
|
|
26
26
|
import { serializeEntityLookupValueForPayload, PraxisI18nService, PraxisIconDirective, providePraxisI18nConfig, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, migrateFormLayoutRule, PraxisJsonLogicService, normalizeFormLayoutItems, deepMerge, createDefaultFormConfig, normalizeFormConfig as normalizeFormConfig$1, ensureIds, createEmptyRichContentDocument, isPraxisRuntimeGlobalActionEffect, ASYNC_CONFIG_STORAGE, withFormConfigSections, createFieldLayoutItem, getFormLayoutFieldNames, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, GlobalActionService, ResourceQuickConnectComponent, composeHeadersWithVersion, buildApiUrl, mapFieldDefinitionsToMetadata, reconcileFormConfig, materializeFormLayoutFromMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, evaluateFieldAccess, normalizeControlTypeKey, normalizePraxisEffectPolicy, buildPraxisEffectDistinctKey, getFormColumnFieldNames, resolveSpan, resolveOffset, resolveOrder, resolveHidden, buildSchemaIdStorageKeySegment, buildSchemaId, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, CONNECTION_STORAGE, API_URL, PRAXIS_LOADING_RENDERER, FORM_HOOKS_PRESETS, EmptyStateCardComponent, isValidFormConfig, ComponentMetadataRegistry, FieldControlType, isRequiredGlobalActionPayloadMissing, GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, getRequiredGlobalActionPayloadKeys, hasMeaningfulGlobalActionPayloadValue, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, validateGlobalActionRefs, normalizeFormMetadata } from '@praxisui/core';
|
|
27
27
|
import * as i1$1 from '@praxisui/dynamic-fields';
|
|
28
28
|
import { getControlTypeCatalog, ConfirmDialogComponent, DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
|
|
29
|
-
import { BaseAiAdapter,
|
|
29
|
+
import { BaseAiAdapter, AgenticAuthoringTurnClientService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnOrchestratorService, createPraxisAssistantViewportLayout, PraxisAiAssistantShellComponent } from '@praxisui/ai';
|
|
30
30
|
import { PraxisRichContent, PraxisRichContentConfigEditor } from '@praxisui/rich-content';
|
|
31
31
|
import * as i6 from '@angular/material/menu';
|
|
32
32
|
import { MatMenuModule } from '@angular/material/menu';
|
|
@@ -243,6 +243,12 @@ function normalizeSubmitPayload(data) {
|
|
|
243
243
|
return normalizeTemporalStrings(normalizeDateArrays(data));
|
|
244
244
|
}
|
|
245
245
|
function normalizeTemporalStrings(value) {
|
|
246
|
+
// Date-only fields are converted by the field-aware submit pipeline. Keep
|
|
247
|
+
// native Date values intact here instead of treating them as generic records
|
|
248
|
+
// (which would otherwise turn them into an empty object).
|
|
249
|
+
if (value instanceof Date) {
|
|
250
|
+
return value;
|
|
251
|
+
}
|
|
246
252
|
if (Array.isArray(value)) {
|
|
247
253
|
return value.map((item) => normalizeTemporalStrings(item));
|
|
248
254
|
}
|
|
@@ -373,9 +379,73 @@ function filterRecordForSubmit(value, fields, dirtyFields, scopePath) {
|
|
|
373
379
|
return payload;
|
|
374
380
|
}
|
|
375
381
|
function normalizeFieldValueForSubmit(field, value, dirtyFields, fieldPath) {
|
|
376
|
-
const
|
|
382
|
+
const normalizedDateValue = normalizeDateOnlyFieldValueForSubmit(field, value);
|
|
383
|
+
const normalizedEntityLookupValue = normalizeEntityLookupValueForSubmit(field, normalizedDateValue);
|
|
377
384
|
return filterNestedArrayForSubmit(field, normalizedEntityLookupValue, dirtyFields, fieldPath);
|
|
378
385
|
}
|
|
386
|
+
/**
|
|
387
|
+
* Projects date-only controls into the ISO-8601 representation required by
|
|
388
|
+
* OpenAPI `format: date` / Java `LocalDate` contracts. A date field may hold
|
|
389
|
+
* a native Date (calendar selection) or its locale display value (manual
|
|
390
|
+
* masked input); neither presentation value should leak into the request.
|
|
391
|
+
*/
|
|
392
|
+
function normalizeDateOnlyFieldValueForSubmit(field, value) {
|
|
393
|
+
if (!isDateOnlyField(field) || value === null || value === undefined || value === '') {
|
|
394
|
+
return value;
|
|
395
|
+
}
|
|
396
|
+
if (value instanceof Date) {
|
|
397
|
+
return isValidDate(value) ? formatLocalIsoDate(value) : value;
|
|
398
|
+
}
|
|
399
|
+
if (typeof value !== 'string') {
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
402
|
+
const trimmed = value.trim();
|
|
403
|
+
if (isIsoDate(trimmed)) {
|
|
404
|
+
return trimmed;
|
|
405
|
+
}
|
|
406
|
+
const parsed = parseDayFirstDate(trimmed, field);
|
|
407
|
+
return parsed ? formatLocalIsoDate(parsed) : value;
|
|
408
|
+
}
|
|
409
|
+
function isDateOnlyField(field) {
|
|
410
|
+
const dataType = String(field.dataType ?? '').trim().toLowerCase();
|
|
411
|
+
if (dataType === 'date') {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
const controlType = String(field.controlType ?? '').trim().toLowerCase();
|
|
415
|
+
return controlType === 'date' || controlType === 'datepicker' || controlType === 'date_picker';
|
|
416
|
+
}
|
|
417
|
+
function isIsoDate(value) {
|
|
418
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(value);
|
|
419
|
+
}
|
|
420
|
+
function parseDayFirstDate(value, field) {
|
|
421
|
+
const displayFormat = String(field.displayFormat ?? field.mask ?? '').toLowerCase();
|
|
422
|
+
if (!displayFormat.includes('dd') || !displayFormat.includes('mm') || !displayFormat.includes('yyyy')) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
const match = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/.exec(value);
|
|
426
|
+
if (!match) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
const day = Number(match[1]);
|
|
430
|
+
const month = Number(match[2]);
|
|
431
|
+
const year = Number(match[3]);
|
|
432
|
+
const parsed = new Date(year, month - 1, day);
|
|
433
|
+
return isValidDate(parsed) &&
|
|
434
|
+
parsed.getFullYear() === year &&
|
|
435
|
+
parsed.getMonth() === month - 1 &&
|
|
436
|
+
parsed.getDate() === day
|
|
437
|
+
? parsed
|
|
438
|
+
: null;
|
|
439
|
+
}
|
|
440
|
+
function isValidDate(value) {
|
|
441
|
+
return !Number.isNaN(value.getTime());
|
|
442
|
+
}
|
|
443
|
+
function formatLocalIsoDate(value) {
|
|
444
|
+
const year = value.getFullYear();
|
|
445
|
+
const month = String(value.getMonth() + 1).padStart(2, '0');
|
|
446
|
+
const day = String(value.getDate()).padStart(2, '0');
|
|
447
|
+
return `${year}-${month}-${day}`;
|
|
448
|
+
}
|
|
379
449
|
function normalizeEntityLookupValueForSubmit(field, value) {
|
|
380
450
|
if (!isEntityLookupField(field)) {
|
|
381
451
|
return value;
|
|
@@ -1795,10 +1865,14 @@ class PraxisFormActionsComponent {
|
|
|
1795
1865
|
}
|
|
1796
1866
|
const buttons = [];
|
|
1797
1867
|
const submitBtn = {
|
|
1798
|
-
id: 'submit',
|
|
1799
|
-
type: 'submit',
|
|
1800
1868
|
color: 'primary',
|
|
1801
1869
|
...actions.submit,
|
|
1870
|
+
// `actions.submit` is the reserved submit slot. Its visual configuration
|
|
1871
|
+
// may be customized, but its runtime identity must remain canonical so a
|
|
1872
|
+
// persisted editorial id cannot turn a submit button into a no-op custom
|
|
1873
|
+
// action while its native submit event is prevented below.
|
|
1874
|
+
id: 'submit',
|
|
1875
|
+
type: 'submit',
|
|
1802
1876
|
visible: actions.submit?.visible ?? actions.showSaveButton !== false,
|
|
1803
1877
|
label: actions.submitButtonLabel || actions.submit?.label || 'ENVIAR',
|
|
1804
1878
|
};
|
|
@@ -2008,6 +2082,8 @@ class PraxisFormActionsComponent {
|
|
|
2008
2082
|
});
|
|
2009
2083
|
}
|
|
2010
2084
|
resolveButtonActionId(button) {
|
|
2085
|
+
if (button.type === 'submit')
|
|
2086
|
+
return 'submit';
|
|
2011
2087
|
const id = button.id?.trim();
|
|
2012
2088
|
if (id === 'submit' || id === 'cancel' || id === 'reset')
|
|
2013
2089
|
return id;
|
|
@@ -7168,6 +7244,36 @@ class FormAiAdapter extends BaseAiAdapter {
|
|
|
7168
7244
|
filledFields: filledCount,
|
|
7169
7245
|
};
|
|
7170
7246
|
}
|
|
7247
|
+
getDataProfile() {
|
|
7248
|
+
const config = this.host.config;
|
|
7249
|
+
const actions = config?.actions;
|
|
7250
|
+
return {
|
|
7251
|
+
sectionCount: config?.sections?.length ?? 0,
|
|
7252
|
+
fieldCount: config?.fieldMetadata?.length ?? 0,
|
|
7253
|
+
ruleCount: config?.formRules?.length ?? 0,
|
|
7254
|
+
actionCount: [
|
|
7255
|
+
actions?.submit,
|
|
7256
|
+
actions?.cancel,
|
|
7257
|
+
actions?.reset,
|
|
7258
|
+
...(actions?.custom ?? []),
|
|
7259
|
+
].filter(Boolean).length,
|
|
7260
|
+
};
|
|
7261
|
+
}
|
|
7262
|
+
getSchemaFields() {
|
|
7263
|
+
return (this.host.config?.fieldMetadata ?? [])
|
|
7264
|
+
.map((field) => ({
|
|
7265
|
+
name: field.name,
|
|
7266
|
+
label: field.label,
|
|
7267
|
+
type: field.dataType ?? field.controlType,
|
|
7268
|
+
controlType: field.controlType,
|
|
7269
|
+
source: field.source ?? 'schema',
|
|
7270
|
+
required: field.required === true,
|
|
7271
|
+
readonly: field.readOnly === true,
|
|
7272
|
+
disabled: field.disabled === true,
|
|
7273
|
+
hidden: field.hidden === true,
|
|
7274
|
+
}))
|
|
7275
|
+
.filter((field) => typeof field.name === 'string' && !!field.name.trim());
|
|
7276
|
+
}
|
|
7171
7277
|
getAuthoringContext() {
|
|
7172
7278
|
const manifest = PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST;
|
|
7173
7279
|
return {
|
|
@@ -10442,7 +10548,7 @@ class PraxisDynamicForm {
|
|
|
10442
10548
|
enterpriseRuntimeContext;
|
|
10443
10549
|
i18n = inject(PraxisI18nService);
|
|
10444
10550
|
injector = inject(Injector);
|
|
10445
|
-
|
|
10551
|
+
agenticTurnClient = inject(AgenticAuthoringTurnClientService);
|
|
10446
10552
|
assistantSessions = inject(PraxisAssistantSessionRegistryService);
|
|
10447
10553
|
aiTurnOrchestrator = inject(PraxisAssistantTurnOrchestratorService);
|
|
10448
10554
|
jsonLogic = inject(PraxisJsonLogicService);
|
|
@@ -10630,7 +10736,16 @@ class PraxisDynamicForm {
|
|
|
10630
10736
|
: this.presentationModeGlobal === true;
|
|
10631
10737
|
}
|
|
10632
10738
|
getRenderableFieldsForLoader(fields) {
|
|
10633
|
-
return fields.map((field) =>
|
|
10739
|
+
return fields.map((field) => {
|
|
10740
|
+
const materialized = this.materializeFieldPresentationPolicy(field);
|
|
10741
|
+
if (!this.apiUrlEntry || materialized.apiUrlEntry === this.apiUrlEntry) {
|
|
10742
|
+
return materialized;
|
|
10743
|
+
}
|
|
10744
|
+
// Dynamic field controls own their CRUD clients. Carry the resolved entry in the
|
|
10745
|
+
// runtime-only metadata so option sources opened in detached hosts (dialogs,
|
|
10746
|
+
// drawers, overlays) resolve against the same API as the form itself.
|
|
10747
|
+
return { ...materialized, apiUrlEntry: this.apiUrlEntry };
|
|
10748
|
+
});
|
|
10634
10749
|
}
|
|
10635
10750
|
materializeFieldPresentationPolicy(field) {
|
|
10636
10751
|
let next = null;
|
|
@@ -10808,6 +10923,10 @@ class PraxisDynamicForm {
|
|
|
10808
10923
|
entityHydrationPending = false;
|
|
10809
10924
|
schemaCache = null;
|
|
10810
10925
|
lastSchemaMeta;
|
|
10926
|
+
schemaMetaPersistenceQueues = new Map();
|
|
10927
|
+
formConfigPersistenceQueues = new Map();
|
|
10928
|
+
formConfigPersistenceGenerations = new Map();
|
|
10929
|
+
formConfigConflictBlockThrough = new Map();
|
|
10811
10930
|
schemaRootHooks;
|
|
10812
10931
|
destroy$ = new Subject();
|
|
10813
10932
|
formValueChangesSubscription = null;
|
|
@@ -11999,11 +12118,12 @@ class PraxisDynamicForm {
|
|
|
11999
12118
|
persistFormConfig(key, cfg) {
|
|
12000
12119
|
if (!key) {
|
|
12001
12120
|
this.warnMissingId();
|
|
12002
|
-
return;
|
|
12121
|
+
return Promise.resolve();
|
|
12003
12122
|
}
|
|
12004
12123
|
const toSave = this.removeEmptyContainersOnSave
|
|
12005
12124
|
? this.dynamicLayout.pruneEmptyContainers(cfg).config
|
|
12006
12125
|
: cfg;
|
|
12126
|
+
const snapshot = this.cloneFormConfigForPatch(toSave);
|
|
12007
12127
|
try {
|
|
12008
12128
|
const sections = Array.isArray(toSave.sections) ? toSave.sections.length : 0;
|
|
12009
12129
|
const fields = Array.isArray(toSave.fieldMetadata) ? toSave.fieldMetadata.length : 0;
|
|
@@ -12013,11 +12133,50 @@ class PraxisDynamicForm {
|
|
|
12013
12133
|
this.debugLog('[PDF] persistFormConfig: begin', { key, sections, fields, fieldNames });
|
|
12014
12134
|
}
|
|
12015
12135
|
catch { }
|
|
12016
|
-
this.
|
|
12017
|
-
|
|
12018
|
-
|
|
12019
|
-
|
|
12020
|
-
|
|
12136
|
+
const generation = (this.formConfigPersistenceGenerations.get(key) ?? 0) + 1;
|
|
12137
|
+
this.formConfigPersistenceGenerations.set(key, generation);
|
|
12138
|
+
const previous = this.formConfigPersistenceQueues.get(key) ?? Promise.resolve();
|
|
12139
|
+
const pending = previous
|
|
12140
|
+
.catch(() => undefined)
|
|
12141
|
+
.then(async () => {
|
|
12142
|
+
if (generation <= (this.formConfigConflictBlockThrough.get(key) ?? 0))
|
|
12143
|
+
return;
|
|
12144
|
+
try {
|
|
12145
|
+
await firstValueFrom(this.asyncConfigStorage.saveConfig(key, snapshot));
|
|
12146
|
+
try {
|
|
12147
|
+
this.debugLog('[PDF] persistFormConfig: done', { key });
|
|
12148
|
+
}
|
|
12149
|
+
catch { }
|
|
12150
|
+
}
|
|
12151
|
+
catch (error) {
|
|
12152
|
+
const status = Number(error?.status);
|
|
12153
|
+
if (status !== 409 && status !== 412) {
|
|
12154
|
+
this.warnLog('[PDF] persistFormConfig: not acknowledged', error);
|
|
12155
|
+
return;
|
|
12156
|
+
}
|
|
12157
|
+
this.formConfigConflictBlockThrough.set(key, this.formConfigPersistenceGenerations.get(key) ?? generation);
|
|
12158
|
+
const remote = await firstValueFrom(this.asyncConfigStorage.loadConfig(key))
|
|
12159
|
+
.catch(() => null);
|
|
12160
|
+
const source = String(snapshot.metadata?.source || '').trim().toLowerCase();
|
|
12161
|
+
if (remote && source === 'default') {
|
|
12162
|
+
this.config = normalizeFormConfig$1(remote);
|
|
12163
|
+
this.columnFieldsCache.clear();
|
|
12164
|
+
this.cdr.markForCheck();
|
|
12165
|
+
}
|
|
12166
|
+
this.warnLog('[PDF] persistFormConfig: concurrent version preserved', {
|
|
12167
|
+
key,
|
|
12168
|
+
status,
|
|
12169
|
+
resolution: remote ? 'remote-reloaded' : 'remote-unavailable',
|
|
12170
|
+
});
|
|
12171
|
+
}
|
|
12172
|
+
});
|
|
12173
|
+
this.formConfigPersistenceQueues.set(key, pending);
|
|
12174
|
+
void pending.finally(() => {
|
|
12175
|
+
if (this.formConfigPersistenceQueues.get(key) === pending) {
|
|
12176
|
+
this.formConfigPersistenceQueues.delete(key);
|
|
12177
|
+
}
|
|
12178
|
+
});
|
|
12179
|
+
return pending;
|
|
12021
12180
|
}
|
|
12022
12181
|
async createDefaultConfig() {
|
|
12023
12182
|
try {
|
|
@@ -14562,6 +14721,11 @@ class PraxisDynamicForm {
|
|
|
14562
14721
|
}
|
|
14563
14722
|
}
|
|
14564
14723
|
getFormActionEventId(button) {
|
|
14724
|
+
// Native submit buttons are reserved form semantics. Do not let an
|
|
14725
|
+
// editorial/persisted id reroute them to customAction after the browser
|
|
14726
|
+
// submit event has been intentionally prevented by praxis-form-actions.
|
|
14727
|
+
if (button.type === 'submit')
|
|
14728
|
+
return 'submit';
|
|
14565
14729
|
const id = button.id?.trim();
|
|
14566
14730
|
if (id === 'submit' || id === 'cancel' || id === 'reset')
|
|
14567
14731
|
return id;
|
|
@@ -14933,11 +15097,11 @@ class PraxisDynamicForm {
|
|
|
14933
15097
|
initializeAiAssistantController() {
|
|
14934
15098
|
if (this.aiAssistantController)
|
|
14935
15099
|
return;
|
|
14936
|
-
import('./praxisui-dynamic-form-dynamic-form-agentic-authoring-turn-flow-
|
|
15100
|
+
import('./praxisui-dynamic-form-dynamic-form-agentic-authoring-turn-flow-w9V0aQ9B.mjs')
|
|
14937
15101
|
.then(({ DynamicFormAgenticAuthoringTurnFlow }) => {
|
|
14938
15102
|
if (this.aiAssistantController)
|
|
14939
15103
|
return;
|
|
14940
|
-
const flow = new DynamicFormAgenticAuthoringTurnFlow(this.aiAdapter, this.
|
|
15104
|
+
const flow = new DynamicFormAgenticAuthoringTurnFlow(this.aiAdapter, this.agenticTurnClient);
|
|
14941
15105
|
const controller = this.aiTurnOrchestrator.createController(flow, {
|
|
14942
15106
|
componentId: this.aiAdapter.componentId || 'praxis-dynamic-form',
|
|
14943
15107
|
componentType: this.aiAdapter.componentType || 'form',
|
|
@@ -15375,28 +15539,61 @@ class PraxisDynamicForm {
|
|
|
15375
15539
|
.then((value) => value ?? undefined)
|
|
15376
15540
|
.catch(() => undefined);
|
|
15377
15541
|
}
|
|
15542
|
+
persistSchemaMeta(key, candidate) {
|
|
15543
|
+
return this.enqueueSchemaMetaPersistence(key, candidate, (stored, pending) => {
|
|
15544
|
+
const current = stored && typeof stored === 'object' && !Array.isArray(stored)
|
|
15545
|
+
? stored
|
|
15546
|
+
: {};
|
|
15547
|
+
const currentTimestamp = Date.parse(String(current['lastVerifiedAt'] || '')) || 0;
|
|
15548
|
+
const pendingTimestamp = Date.parse(String(pending['lastVerifiedAt'] || '')) || 0;
|
|
15549
|
+
return currentTimestamp > pendingTimestamp
|
|
15550
|
+
? { ...pending, ...current }
|
|
15551
|
+
: { ...current, ...pending };
|
|
15552
|
+
});
|
|
15553
|
+
}
|
|
15554
|
+
enqueueSchemaMetaPersistence(key, candidate, merge) {
|
|
15555
|
+
const previous = this.schemaMetaPersistenceQueues.get(key) ?? Promise.resolve();
|
|
15556
|
+
const pending = previous
|
|
15557
|
+
.catch(() => undefined)
|
|
15558
|
+
.then(() => this.reconcileSchemaMetaPersistence(key, candidate, merge));
|
|
15559
|
+
this.schemaMetaPersistenceQueues.set(key, pending);
|
|
15560
|
+
void pending.finally(() => {
|
|
15561
|
+
if (this.schemaMetaPersistenceQueues.get(key) === pending) {
|
|
15562
|
+
this.schemaMetaPersistenceQueues.delete(key);
|
|
15563
|
+
}
|
|
15564
|
+
});
|
|
15565
|
+
return pending;
|
|
15566
|
+
}
|
|
15567
|
+
async reconcileSchemaMetaPersistence(key, candidate, merge) {
|
|
15568
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
15569
|
+
const stored = await firstValueFrom(this.asyncConfigStorage.loadConfig(key))
|
|
15570
|
+
.catch(() => null);
|
|
15571
|
+
const reconciled = merge(stored, candidate);
|
|
15572
|
+
if (JSON.stringify(stored) === JSON.stringify(reconciled))
|
|
15573
|
+
return;
|
|
15574
|
+
try {
|
|
15575
|
+
await firstValueFrom(this.asyncConfigStorage.saveConfig(key, reconciled));
|
|
15576
|
+
return;
|
|
15577
|
+
}
|
|
15578
|
+
catch (error) {
|
|
15579
|
+
const status = Number(error?.status);
|
|
15580
|
+
if ((status !== 409 && status !== 412) || attempt === 2)
|
|
15581
|
+
return;
|
|
15582
|
+
}
|
|
15583
|
+
}
|
|
15584
|
+
}
|
|
15378
15585
|
rememberSchemaMetaContext(schemaId) {
|
|
15379
15586
|
const id = String(schemaId || '').trim();
|
|
15380
15587
|
if (!id)
|
|
15381
|
-
return;
|
|
15588
|
+
return Promise.resolve();
|
|
15382
15589
|
const indexKey = this.getSchemaMetaIndexKey();
|
|
15383
15590
|
if (!indexKey)
|
|
15384
|
-
return;
|
|
15385
|
-
this.
|
|
15386
|
-
.
|
|
15387
|
-
|
|
15388
|
-
|
|
15389
|
-
|
|
15390
|
-
const unique = new Set((Array.isArray(stored) ? stored : [])
|
|
15391
|
-
.map((item) => String(item || '').trim())
|
|
15392
|
-
.filter((item) => !!item));
|
|
15393
|
-
unique.add(id);
|
|
15394
|
-
this.asyncConfigStorage
|
|
15395
|
-
.saveConfig(indexKey, Array.from(unique))
|
|
15396
|
-
.pipe(take(1))
|
|
15397
|
-
.subscribe({ error: () => { } });
|
|
15398
|
-
},
|
|
15399
|
-
error: () => { },
|
|
15591
|
+
return Promise.resolve();
|
|
15592
|
+
return this.enqueueSchemaMetaPersistence(indexKey, [id], (stored, pending) => {
|
|
15593
|
+
const unique = new Set([...(Array.isArray(stored) ? stored : []), ...pending]
|
|
15594
|
+
.map((item) => String(item || '').trim())
|
|
15595
|
+
.filter((item) => !!item));
|
|
15596
|
+
return Array.from(unique);
|
|
15400
15597
|
});
|
|
15401
15598
|
}
|
|
15402
15599
|
isSameSchemaContext(left, right) {
|
|
@@ -15661,8 +15858,8 @@ class PraxisDynamicForm {
|
|
|
15661
15858
|
metaToSave.serverHash = previousHash;
|
|
15662
15859
|
}
|
|
15663
15860
|
if (res.status === 304) {
|
|
15664
|
-
this.
|
|
15665
|
-
this.rememberSchemaMetaContext(currentSchemaId);
|
|
15861
|
+
await this.persistSchemaMeta(scopedMetaKey, metaToSave);
|
|
15862
|
+
await this.rememberSchemaMetaContext(currentSchemaId);
|
|
15666
15863
|
// Mirror meta in memory (config.metadata) without persisting config
|
|
15667
15864
|
try {
|
|
15668
15865
|
const mem = { ...(this.config.metadata || {}) };
|
|
@@ -15685,8 +15882,8 @@ class PraxisDynamicForm {
|
|
|
15685
15882
|
// status === 200: server hash changed (or first verification without hash). Do not apply schema here.
|
|
15686
15883
|
const newHash = res.schemaHash;
|
|
15687
15884
|
metaToSave.serverHash = newHash;
|
|
15688
|
-
this.
|
|
15689
|
-
this.rememberSchemaMetaContext(currentSchemaId);
|
|
15885
|
+
await this.persistSchemaMeta(scopedMetaKey, metaToSave);
|
|
15886
|
+
await this.rememberSchemaMetaContext(currentSchemaId);
|
|
15690
15887
|
// Mirror meta in memory (config.metadata) without persisting config
|
|
15691
15888
|
try {
|
|
15692
15889
|
const mem = { ...(this.config.metadata || {}) };
|
|
@@ -18902,16 +19099,13 @@ class PraxisDynamicForm {
|
|
|
18902
19099
|
this.getSchemaMetaKey();
|
|
18903
19100
|
if (metaKey) {
|
|
18904
19101
|
const nowIso = new Date().toISOString();
|
|
18905
|
-
this.
|
|
18906
|
-
.saveConfig(metaKey, {
|
|
19102
|
+
await this.persistSchemaMeta(metaKey, {
|
|
18907
19103
|
schemaId,
|
|
18908
19104
|
schemaContext,
|
|
18909
19105
|
serverHash: entry.schemaHash,
|
|
18910
19106
|
lastVerifiedAt: nowIso,
|
|
18911
|
-
})
|
|
18912
|
-
|
|
18913
|
-
.subscribe({ error: () => { } });
|
|
18914
|
-
this.rememberSchemaMetaContext(schemaId);
|
|
19107
|
+
});
|
|
19108
|
+
await this.rememberSchemaMetaContext(schemaId);
|
|
18915
19109
|
}
|
|
18916
19110
|
}
|
|
18917
19111
|
catch { }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/dynamic-form",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.74",
|
|
4
4
|
"description": "Angular dynamic form engine for Praxis UI: metadata-driven forms, hooks, and services integrating @praxisui/* packages.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^21.0.0",
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"@angular/forms": "^21.0.0",
|
|
10
10
|
"@angular/material": "^21.0.0",
|
|
11
11
|
"@angular/router": "^21.0.0",
|
|
12
|
-
"@praxisui/ai": "^9.0.0-beta.
|
|
13
|
-
"@praxisui/dynamic-fields": "^9.0.0-beta.
|
|
14
|
-
"@praxisui/metadata-editor": "^9.0.0-beta.
|
|
15
|
-
"@praxisui/rich-content": "^9.0.0-beta.
|
|
16
|
-
"@praxisui/settings-panel": "^9.0.0-beta.
|
|
17
|
-
"@praxisui/visual-builder": "^9.0.0-beta.
|
|
18
|
-
"@praxisui/core": "^9.0.0-beta.
|
|
12
|
+
"@praxisui/ai": "^9.0.0-beta.74",
|
|
13
|
+
"@praxisui/dynamic-fields": "^9.0.0-beta.74",
|
|
14
|
+
"@praxisui/metadata-editor": "^9.0.0-beta.74",
|
|
15
|
+
"@praxisui/rich-content": "^9.0.0-beta.74",
|
|
16
|
+
"@praxisui/settings-panel": "^9.0.0-beta.74",
|
|
17
|
+
"@praxisui/visual-builder": "^9.0.0-beta.74",
|
|
18
|
+
"@praxisui/core": "^9.0.0-beta.74",
|
|
19
19
|
"rxjs": "^7.8.0"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
@@ -24,6 +24,7 @@ source_of_truth:
|
|
|
24
24
|
- "projects/praxis-dynamic-form/src/lib/ai/form-ai.adapter.ts"
|
|
25
25
|
- "projects/praxis-ai/src/lib/core/models/assistant-context.models.ts"
|
|
26
26
|
- "projects/praxis-ai/src/lib/core/services/assistant-session-registry.service.ts"
|
|
27
|
+
- "projects/praxis-ai/src/lib/core/services/agentic-authoring-turn-client.service.ts"
|
|
27
28
|
- "projects/praxis-dynamic-form/src/lib/config-editor/praxis-dynamic-form-config-editor.ts"
|
|
28
29
|
- "projects/praxis-dynamic-form/src/lib/utils/prepare-submit-payload.ts"
|
|
29
30
|
- "projects/praxis-dynamic-fields/src/lib/directives/dynamic-field-loader.directive.ts"
|
|
@@ -34,8 +35,8 @@ source_of_truth:
|
|
|
34
35
|
- "projects/praxis-core/src/lib/services/dynamic-form.service.ts"
|
|
35
36
|
- "projects/praxis-core/src/lib/models/form/rule-property.schema.ts"
|
|
36
37
|
- "projects/praxis-dynamic-form/docs/layout-items-visual-blocks.md"
|
|
37
|
-
source_of_truth_last_verified: "2026-
|
|
38
|
-
last_updated: "2026-
|
|
38
|
+
source_of_truth_last_verified: "2026-07-16"
|
|
39
|
+
last_updated: "2026-07-16"
|
|
39
40
|
toc: true
|
|
40
41
|
sidebar: true
|
|
41
42
|
tags:
|
|
@@ -82,6 +83,8 @@ Contrato operacional:
|
|
|
82
83
|
- a identidade canonica da sessao segue `form:{routeKey}:{componentInstanceId || formId || 'form'}`;
|
|
83
84
|
- o contexto assistivel publico e `PraxisAssistantContextSnapshot`, com `identity`, `target`, `contextItems`, `authoringManifestRef`, `resourcePath`, `schemaFields`, digests seguros e hints de governanca;
|
|
84
85
|
- o snapshot pode apontar para `field`, `schemaBackedField`, `localField`, `section`, `row`, `column`, `visualBlock`, `formAction`, `message` ou `rule`, mas nao deve transportar `form.value`, `rawFormData`, config completa, notas privadas, estado runtime bruto, diagnostics arbitrarios, `pendingPatch`, `File`, `Blob`, bytes, base64 ou `previewUrl`;
|
|
86
|
+
- turnos do assistente usam `AgenticAuthoringTurnClientService` e `/api/praxis/config/ai/authoring/turn/stream/**`; indisponibilidade do transporte falha de forma fechada e nao reabre o caminho legado `getPatch`;
|
|
87
|
+
- o grounding do turno pode incluir `schemaFields` e `dataProfile` estruturais produzidos pelo adapter, mas nunca valores dos controles; anexos sao reduzidos a nome, tipo, MIME, tamanho, origem e indicador de preview;
|
|
85
88
|
- edicao local so pode ser aplicada quando a resposta for compilada para `componentEditPlan` validado pelo manifesto autoral do componente;
|
|
86
89
|
- patches livres retornados por backend/LLM sem plano compilado sao rejeitados pelo turn flow;
|
|
87
90
|
- pedidos sobre regra de negocio compartilhada, elegibilidade, compliance, LGPD, politica, acesso, aprovacao, publicacao, materializacao ou enforcement devem virar handoff governado para `domain-rules`, nao patch local de formulario;
|
|
@@ -486,6 +486,8 @@ declare class FormAiAdapter extends BaseAiAdapter<FormConfig> {
|
|
|
486
486
|
getCapabilities(): AiCapability[];
|
|
487
487
|
getTaskPresets(): Record<string, string[]>;
|
|
488
488
|
getRuntimeState(): Record<string, any>;
|
|
489
|
+
getDataProfile(): Record<string, any>;
|
|
490
|
+
getSchemaFields(): Record<string, any>[];
|
|
489
491
|
getAuthoringContext(): Record<string, any>;
|
|
490
492
|
compileAiResponse(response: Record<string, unknown>): AiResponseCompileResult | null;
|
|
491
493
|
createSnapshot(): FormConfig;
|
|
@@ -692,7 +694,7 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
|
|
|
692
694
|
private enterpriseRuntimeContext?;
|
|
693
695
|
private readonly i18n;
|
|
694
696
|
private readonly injector;
|
|
695
|
-
private readonly
|
|
697
|
+
private readonly agenticTurnClient;
|
|
696
698
|
private readonly assistantSessions;
|
|
697
699
|
private readonly aiTurnOrchestrator;
|
|
698
700
|
private readonly jsonLogic;
|
|
@@ -871,6 +873,10 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
|
|
|
871
873
|
protected entityHydrationPending: boolean;
|
|
872
874
|
private schemaCache;
|
|
873
875
|
private lastSchemaMeta?;
|
|
876
|
+
private readonly schemaMetaPersistenceQueues;
|
|
877
|
+
private readonly formConfigPersistenceQueues;
|
|
878
|
+
private readonly formConfigPersistenceGenerations;
|
|
879
|
+
private readonly formConfigConflictBlockThrough;
|
|
874
880
|
private schemaRootHooks?;
|
|
875
881
|
private destroy$;
|
|
876
882
|
private formValueChangesSubscription;
|
|
@@ -1230,6 +1236,9 @@ declare class PraxisDynamicForm implements OnInit, OnChanges, OnDestroy {
|
|
|
1230
1236
|
private getSchemaMetaKeyForSchemaId;
|
|
1231
1237
|
private getSchemaMetaKeyForContext;
|
|
1232
1238
|
private loadStoredSchemaMeta;
|
|
1239
|
+
private persistSchemaMeta;
|
|
1240
|
+
private enqueueSchemaMetaPersistence;
|
|
1241
|
+
private reconcileSchemaMetaPersistence;
|
|
1233
1242
|
private rememberSchemaMetaContext;
|
|
1234
1243
|
private isSameSchemaContext;
|
|
1235
1244
|
private isStoredSchemaMetaForContext;
|