@praxisui/dynamic-form 1.0.0-beta.40 → 1.0.0-beta.41
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.
|
@@ -22,7 +22,7 @@ import { MatBadgeModule } from '@angular/material/badge';
|
|
|
22
22
|
import { firstValueFrom, BehaviorSubject, Subject, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs';
|
|
23
23
|
import { take, takeUntil, debounceTime, finalize, map } from 'rxjs/operators';
|
|
24
24
|
import * as i1$2 from '@praxisui/core';
|
|
25
|
-
import { PraxisIconDirective, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, deepMerge, ASYNC_CONFIG_STORAGE, migrateFormLayoutRule, ensureIds, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, ResourceQuickConnectComponent, normalizeFormConfig as normalizeFormConfig$1, mapFieldDefinitionsToMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, normalizeControlTypeKey, resolveSpan, resolveOffset, resolveOrder, resolveHidden, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient,
|
|
25
|
+
import { PraxisIconDirective, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, deepMerge, ASYNC_CONFIG_STORAGE, migrateFormLayoutRule, ensureIds, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, ResourceQuickConnectComponent, normalizeFormConfig as normalizeFormConfig$1, mapFieldDefinitionsToMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, normalizeControlTypeKey, resolveSpan, resolveOffset, resolveOrder, resolveHidden, buildSchemaId, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, CONNECTION_STORAGE, PRAXIS_LOADING_RENDERER, FORM_HOOKS_PRESETS, EmptyStateCardComponent, createDefaultFormConfig, isValidFormConfig, ComponentMetadataRegistry, FieldControlType, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, GLOBAL_ACTION_SPEC_CATALOG, getGlobalActionUiSchema } from '@praxisui/core';
|
|
26
26
|
import * as i1 from '@praxisui/dynamic-fields';
|
|
27
27
|
import { getControlTypeCatalog, ConfirmDialogComponent, DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
|
|
28
28
|
import { BaseAiAdapter, PraxisAiAssistantComponent } from '@praxisui/ai';
|
|
@@ -6190,6 +6190,79 @@ class PraxisDynamicForm {
|
|
|
6190
6190
|
const id = this.componentKeyId();
|
|
6191
6191
|
return id ? `form-schema-meta:${id}` : null;
|
|
6192
6192
|
}
|
|
6193
|
+
getSchemaMetaIndexKey() {
|
|
6194
|
+
const key = this.getSchemaMetaKey();
|
|
6195
|
+
return key ? `${key}:index` : null;
|
|
6196
|
+
}
|
|
6197
|
+
getSchemaMetaKeyForSchemaId(schemaId) {
|
|
6198
|
+
const scopeKey = this.getSchemaMetaKey();
|
|
6199
|
+
const id = String(schemaId || '').trim();
|
|
6200
|
+
if (!scopeKey || !id)
|
|
6201
|
+
return null;
|
|
6202
|
+
return `${scopeKey}:schema:${id}`;
|
|
6203
|
+
}
|
|
6204
|
+
getSchemaMetaKeyForContext(context) {
|
|
6205
|
+
try {
|
|
6206
|
+
const schemaId = buildSchemaId(context);
|
|
6207
|
+
return this.getSchemaMetaKeyForSchemaId(schemaId) || this.getSchemaMetaKey();
|
|
6208
|
+
}
|
|
6209
|
+
catch {
|
|
6210
|
+
return this.getSchemaMetaKey();
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
loadStoredSchemaMeta(key) {
|
|
6214
|
+
if (!key)
|
|
6215
|
+
return Promise.resolve(undefined);
|
|
6216
|
+
return firstValueFrom(this.asyncConfigStorage.loadConfig(key))
|
|
6217
|
+
.then((value) => value ?? undefined)
|
|
6218
|
+
.catch(() => undefined);
|
|
6219
|
+
}
|
|
6220
|
+
rememberSchemaMetaContext(schemaId) {
|
|
6221
|
+
const id = String(schemaId || '').trim();
|
|
6222
|
+
if (!id)
|
|
6223
|
+
return;
|
|
6224
|
+
const indexKey = this.getSchemaMetaIndexKey();
|
|
6225
|
+
if (!indexKey)
|
|
6226
|
+
return;
|
|
6227
|
+
this.asyncConfigStorage
|
|
6228
|
+
.loadConfig(indexKey)
|
|
6229
|
+
.pipe(take(1))
|
|
6230
|
+
.subscribe({
|
|
6231
|
+
next: (stored) => {
|
|
6232
|
+
const unique = new Set((Array.isArray(stored) ? stored : [])
|
|
6233
|
+
.map((item) => String(item || '').trim())
|
|
6234
|
+
.filter((item) => !!item));
|
|
6235
|
+
unique.add(id);
|
|
6236
|
+
this.asyncConfigStorage
|
|
6237
|
+
.saveConfig(indexKey, Array.from(unique))
|
|
6238
|
+
.pipe(take(1))
|
|
6239
|
+
.subscribe({ error: () => { } });
|
|
6240
|
+
},
|
|
6241
|
+
error: () => { },
|
|
6242
|
+
});
|
|
6243
|
+
}
|
|
6244
|
+
isSameSchemaContext(left, right) {
|
|
6245
|
+
if (!left || !right)
|
|
6246
|
+
return false;
|
|
6247
|
+
return (left.path === right.path &&
|
|
6248
|
+
left.operation === right.operation &&
|
|
6249
|
+
left.schemaType === right.schemaType &&
|
|
6250
|
+
left.includeInternalSchemas === right.includeInternalSchemas &&
|
|
6251
|
+
left.tenant === right.tenant &&
|
|
6252
|
+
left.locale === right.locale &&
|
|
6253
|
+
left.apiOrigin === right.apiOrigin);
|
|
6254
|
+
}
|
|
6255
|
+
isStoredSchemaMetaForContext(storedMeta, schemaId, context) {
|
|
6256
|
+
if (!storedMeta || typeof storedMeta !== 'object')
|
|
6257
|
+
return false;
|
|
6258
|
+
const storedSchemaId = String(storedMeta.schemaId || '').trim();
|
|
6259
|
+
if (storedSchemaId && storedSchemaId !== schemaId)
|
|
6260
|
+
return false;
|
|
6261
|
+
const storedContext = storedMeta.schemaContext;
|
|
6262
|
+
if (storedContext && !this.isSameSchemaContext(storedContext, context))
|
|
6263
|
+
return false;
|
|
6264
|
+
return true;
|
|
6265
|
+
}
|
|
6193
6266
|
getPrefsKey() {
|
|
6194
6267
|
const id = this.componentKeyId();
|
|
6195
6268
|
return id ? `form-schema-prefs:${id}` : null;
|
|
@@ -6362,13 +6435,27 @@ class PraxisDynamicForm {
|
|
|
6362
6435
|
// Verify-only using ETag without downloading schema body
|
|
6363
6436
|
async verifyServerSchemaVersion() {
|
|
6364
6437
|
try {
|
|
6365
|
-
|
|
6366
|
-
if (!this.resourcePath || !metaKey)
|
|
6438
|
+
if (!this.resourcePath)
|
|
6367
6439
|
return;
|
|
6368
6440
|
// Only verify when we already have a base configuration (sections)
|
|
6369
6441
|
if ((this.config?.sections?.length ?? 0) === 0)
|
|
6370
6442
|
return;
|
|
6371
6443
|
const ctx = this.buildSchemaContext();
|
|
6444
|
+
const schemaContext = {
|
|
6445
|
+
path: ctx.path,
|
|
6446
|
+
operation: ctx.operation,
|
|
6447
|
+
schemaType: ctx.schemaType,
|
|
6448
|
+
includeInternalSchemas: ctx.includeInternalSchemas,
|
|
6449
|
+
tenant: ctx.tenant,
|
|
6450
|
+
locale: ctx.locale,
|
|
6451
|
+
apiOrigin: ctx.apiOrigin,
|
|
6452
|
+
};
|
|
6453
|
+
const currentSchemaId = buildSchemaId(schemaContext);
|
|
6454
|
+
const scopedMetaKey = this.getSchemaMetaKeyForSchemaId(currentSchemaId) ||
|
|
6455
|
+
this.getSchemaMetaKeyForContext(schemaContext) ||
|
|
6456
|
+
this.getSchemaMetaKey();
|
|
6457
|
+
if (!scopedMetaKey)
|
|
6458
|
+
return;
|
|
6372
6459
|
const baseUrl = ctx.baseUrl;
|
|
6373
6460
|
const u = new URL(baseUrl);
|
|
6374
6461
|
u.searchParams.set('path', ctx.path);
|
|
@@ -6376,8 +6463,20 @@ class PraxisDynamicForm {
|
|
|
6376
6463
|
u.searchParams.set('schemaType', String(ctx.schemaType || 'response'));
|
|
6377
6464
|
u.searchParams.set('includeInternalSchemas', String(!!ctx.includeInternalSchemas));
|
|
6378
6465
|
// Load previously persisted meta (serverHash)
|
|
6379
|
-
const
|
|
6380
|
-
const
|
|
6466
|
+
const scopedMeta = await this.loadStoredSchemaMeta(scopedMetaKey);
|
|
6467
|
+
const legacyScopeKey = this.getSchemaMetaKey();
|
|
6468
|
+
const legacyMeta = legacyScopeKey && legacyScopeKey !== scopedMetaKey
|
|
6469
|
+
? await this.loadStoredSchemaMeta(legacyScopeKey)
|
|
6470
|
+
: undefined;
|
|
6471
|
+
const persistedMeta = this.isStoredSchemaMetaForContext(scopedMeta, currentSchemaId, schemaContext)
|
|
6472
|
+
? scopedMeta
|
|
6473
|
+
: this.isStoredSchemaMetaForContext(legacyMeta, currentSchemaId, schemaContext)
|
|
6474
|
+
? legacyMeta
|
|
6475
|
+
: undefined;
|
|
6476
|
+
const lastLocalHash = this.isSameSchemaContext(this.lastSchemaMeta?.context, schemaContext)
|
|
6477
|
+
? this.lastSchemaMeta?.serverHash
|
|
6478
|
+
: undefined;
|
|
6479
|
+
const previousHash = persistedMeta?.serverHash || lastLocalHash;
|
|
6381
6480
|
// If we have no prior hash and no base, skip verification (handled by initial fetch)
|
|
6382
6481
|
if (!previousHash && (this.config?.sections?.length ?? 0) === 0) {
|
|
6383
6482
|
return;
|
|
@@ -6397,14 +6496,22 @@ class PraxisDynamicForm {
|
|
|
6397
6496
|
const res = await fetchWithETag({ url: u.toString(), schemaHash: previousHash, tenant, locale });
|
|
6398
6497
|
const nowIso = new Date().toISOString();
|
|
6399
6498
|
const metaToSave = { ...(persistedMeta || {}) };
|
|
6499
|
+
metaToSave.schemaId = currentSchemaId;
|
|
6500
|
+
metaToSave.schemaContext = schemaContext;
|
|
6400
6501
|
metaToSave.lastVerifiedAt = nowIso;
|
|
6502
|
+
if (!metaToSave.serverHash && previousHash) {
|
|
6503
|
+
metaToSave.serverHash = previousHash;
|
|
6504
|
+
}
|
|
6401
6505
|
if (res.status === 304) {
|
|
6402
|
-
this.asyncConfigStorage.saveConfig(
|
|
6506
|
+
this.asyncConfigStorage.saveConfig(scopedMetaKey, metaToSave).subscribe();
|
|
6507
|
+
this.rememberSchemaMetaContext(currentSchemaId);
|
|
6403
6508
|
// Mirror meta in memory (config.metadata) without persisting config
|
|
6404
6509
|
try {
|
|
6405
6510
|
const mem = { ...(this.config.metadata || {}) };
|
|
6406
6511
|
if (metaToSave.serverHash)
|
|
6407
6512
|
mem.serverHash = metaToSave.serverHash;
|
|
6513
|
+
mem.schemaId = metaToSave.schemaId;
|
|
6514
|
+
mem.schemaContext = metaToSave.schemaContext;
|
|
6408
6515
|
mem.lastVerifiedAt = metaToSave.lastVerifiedAt;
|
|
6409
6516
|
this.config = { ...this.config, metadata: mem };
|
|
6410
6517
|
this.cdr.markForCheck();
|
|
@@ -6420,19 +6527,22 @@ class PraxisDynamicForm {
|
|
|
6420
6527
|
// status === 200: server hash changed (or first verification without hash). Do not apply schema here.
|
|
6421
6528
|
const newHash = res.schemaHash;
|
|
6422
6529
|
metaToSave.serverHash = newHash;
|
|
6423
|
-
this.asyncConfigStorage.saveConfig(
|
|
6530
|
+
this.asyncConfigStorage.saveConfig(scopedMetaKey, metaToSave).subscribe();
|
|
6531
|
+
this.rememberSchemaMetaContext(currentSchemaId);
|
|
6424
6532
|
// Mirror meta in memory (config.metadata) without persisting config
|
|
6425
6533
|
try {
|
|
6426
6534
|
const mem = { ...(this.config.metadata || {}) };
|
|
6427
6535
|
if (metaToSave.serverHash)
|
|
6428
6536
|
mem.serverHash = metaToSave.serverHash;
|
|
6537
|
+
mem.schemaId = metaToSave.schemaId;
|
|
6538
|
+
mem.schemaContext = metaToSave.schemaContext;
|
|
6429
6539
|
mem.lastVerifiedAt = metaToSave.lastVerifiedAt;
|
|
6430
6540
|
this.config = { ...this.config, metadata: mem };
|
|
6431
6541
|
this.cdr.markForCheck();
|
|
6432
6542
|
}
|
|
6433
6543
|
catch { }
|
|
6434
|
-
// Only mark outdated when there
|
|
6435
|
-
const hadBase =
|
|
6544
|
+
// Only mark outdated when there is a confirmed prior hash for this context.
|
|
6545
|
+
const hadBase = !!previousHash;
|
|
6436
6546
|
this.schemaOutdated = !!(this.editModeEnabled && hadBase);
|
|
6437
6547
|
this.schemaStatusChange.emit({ outdated: this.schemaOutdated, serverHash: newHash, lastVerifiedAt: metaToSave.lastVerifiedAt, formId: this.formId });
|
|
6438
6548
|
// Load state for new hash
|
|
@@ -9019,6 +9129,15 @@ class PraxisDynamicForm {
|
|
|
9019
9129
|
return this.schemaCache;
|
|
9020
9130
|
}
|
|
9021
9131
|
const ctx = this.buildSchemaContext();
|
|
9132
|
+
const schemaContext = {
|
|
9133
|
+
path: ctx.path,
|
|
9134
|
+
operation: ctx.operation,
|
|
9135
|
+
schemaType: ctx.schemaType,
|
|
9136
|
+
includeInternalSchemas: ctx.includeInternalSchemas,
|
|
9137
|
+
tenant: ctx.tenant,
|
|
9138
|
+
locale: ctx.locale,
|
|
9139
|
+
apiOrigin: ctx.apiOrigin,
|
|
9140
|
+
};
|
|
9022
9141
|
const loadingCtx = this.buildLoadingContext('schema', 'Carregando configuração…', true);
|
|
9023
9142
|
this.beginLoading(loadingCtx);
|
|
9024
9143
|
this.emitLoadingState('schema', 'loading', 'Carregando schema do formulário...');
|
|
@@ -9052,8 +9171,8 @@ class PraxisDynamicForm {
|
|
|
9052
9171
|
? legacyResult.pipe(take(1))
|
|
9053
9172
|
: legacyResult);
|
|
9054
9173
|
try {
|
|
9055
|
-
const schemaId = buildSchemaId(
|
|
9056
|
-
this.lastSchemaMeta = { schemaId,
|
|
9174
|
+
const schemaId = buildSchemaId(schemaContext);
|
|
9175
|
+
this.lastSchemaMeta = { schemaId, context: schemaContext };
|
|
9057
9176
|
}
|
|
9058
9177
|
catch { }
|
|
9059
9178
|
this.schemaCache = legacyDefs;
|
|
@@ -9089,19 +9208,27 @@ class PraxisDynamicForm {
|
|
|
9089
9208
|
}
|
|
9090
9209
|
}
|
|
9091
9210
|
catch { }
|
|
9092
|
-
const schemaId = buildSchemaId(
|
|
9093
|
-
this.lastSchemaMeta = { schemaId, serverHash: entry.schemaHash, context:
|
|
9211
|
+
const schemaId = buildSchemaId(schemaContext);
|
|
9212
|
+
this.lastSchemaMeta = { schemaId, serverHash: entry.schemaHash, context: schemaContext };
|
|
9094
9213
|
this.schemaCache = defs;
|
|
9095
9214
|
this.emitLoadingState('schema', 'success', 'Schema carregado.');
|
|
9096
9215
|
// Persist meta for future ETag verifications
|
|
9097
9216
|
try {
|
|
9098
|
-
const metaKey = this.
|
|
9217
|
+
const metaKey = this.getSchemaMetaKeyForSchemaId(schemaId) ||
|
|
9218
|
+
this.getSchemaMetaKeyForContext(schemaContext) ||
|
|
9219
|
+
this.getSchemaMetaKey();
|
|
9099
9220
|
if (metaKey) {
|
|
9100
9221
|
const nowIso = new Date().toISOString();
|
|
9101
9222
|
this.asyncConfigStorage
|
|
9102
|
-
.saveConfig(metaKey, {
|
|
9223
|
+
.saveConfig(metaKey, {
|
|
9224
|
+
schemaId,
|
|
9225
|
+
schemaContext,
|
|
9226
|
+
serverHash: entry.schemaHash,
|
|
9227
|
+
lastVerifiedAt: nowIso,
|
|
9228
|
+
})
|
|
9103
9229
|
.pipe(take(1))
|
|
9104
9230
|
.subscribe({ error: () => { } });
|
|
9231
|
+
this.rememberSchemaMetaContext(schemaId);
|
|
9105
9232
|
}
|
|
9106
9233
|
}
|
|
9107
9234
|
catch { }
|
|
@@ -15522,7 +15649,31 @@ class PraxisDynamicFormConfigEditor {
|
|
|
15522
15649
|
}
|
|
15523
15650
|
this.schemaPrefs = { ...this.schemaPrefs, ...allowed };
|
|
15524
15651
|
}
|
|
15525
|
-
|
|
15652
|
+
const schemaScopeKey = `form-schema-meta:${key}`;
|
|
15653
|
+
const schemaId = String(this.editedConfig?.metadata?.schemaId ||
|
|
15654
|
+
this.initialConfig?.metadata?.schemaId ||
|
|
15655
|
+
'').trim();
|
|
15656
|
+
const schemaMetaCandidates = [];
|
|
15657
|
+
if (schemaId) {
|
|
15658
|
+
schemaMetaCandidates.push(`${schemaScopeKey}:schema:${schemaId}`);
|
|
15659
|
+
}
|
|
15660
|
+
if (!schemaId) {
|
|
15661
|
+
const storedIds = await firstValueFrom(this.storage.loadConfig(`${schemaScopeKey}:index`)).catch(() => []);
|
|
15662
|
+
const ids = (Array.isArray(storedIds) ? storedIds : [])
|
|
15663
|
+
.map((item) => String(item || '').trim())
|
|
15664
|
+
.filter((item) => !!item);
|
|
15665
|
+
ids.forEach((id) => schemaMetaCandidates.push(`${schemaScopeKey}:schema:${id}`));
|
|
15666
|
+
}
|
|
15667
|
+
schemaMetaCandidates.push(schemaScopeKey); // legacy fallback
|
|
15668
|
+
let resolvedMeta;
|
|
15669
|
+
for (const candidate of Array.from(new Set(schemaMetaCandidates))) {
|
|
15670
|
+
const loaded = await firstValueFrom(this.storage.loadConfig(candidate)).catch(() => undefined);
|
|
15671
|
+
if (loaded && typeof loaded === 'object') {
|
|
15672
|
+
resolvedMeta = loaded;
|
|
15673
|
+
break;
|
|
15674
|
+
}
|
|
15675
|
+
}
|
|
15676
|
+
this.serverMeta = resolvedMeta || undefined;
|
|
15526
15677
|
}
|
|
15527
15678
|
catch { }
|
|
15528
15679
|
this.cdr.detectChanges();
|