@praxisui/metadata-editor 8.0.0-beta.8 → 8.0.0-beta.9

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.
@@ -1054,6 +1054,61 @@ const inputProperties = [
1054
1054
  { name: 'defaultValue', label: 'Valor padrão', editorType: 'text', group: 'Geral' },
1055
1055
  ];
1056
1056
 
1057
+ const arrayProperties = [
1058
+ { name: 'label', label: 'Label', editorType: 'text', group: 'Geral' },
1059
+ { name: 'hint', label: 'Hint', editorType: 'text', group: 'Geral' },
1060
+ { name: 'defaultValue', label: 'Valor inicial (JSON array)', editorType: 'textarea', group: 'Geral' },
1061
+ {
1062
+ name: 'array.itemType',
1063
+ label: 'Tipo do item',
1064
+ editorType: 'select',
1065
+ group: 'Colecao',
1066
+ defaultValue: 'object',
1067
+ options: [
1068
+ { value: 'object', text: 'Objeto' },
1069
+ ],
1070
+ },
1071
+ {
1072
+ name: 'array.mode',
1073
+ label: 'Modo',
1074
+ editorType: 'select',
1075
+ group: 'Colecao',
1076
+ defaultValue: 'cards',
1077
+ options: [
1078
+ { value: 'cards', text: 'Cards' },
1079
+ ],
1080
+ },
1081
+ { name: 'array.itemSchemaRef', label: 'Schema do item ($ref)', editorType: 'text', group: 'Colecao' },
1082
+ { name: 'array.itemIdentityField', label: 'Campo de identidade', editorType: 'text', group: 'Colecao' },
1083
+ { name: 'array.addLabel', label: 'Texto do botao adicionar', editorType: 'text', group: 'Colecao' },
1084
+ { name: 'array.emptyState', label: 'Texto vazio', editorType: 'text', group: 'Colecao' },
1085
+ { name: 'array.itemTitleTemplate', label: 'Template do titulo do item', editorType: 'text', group: 'Colecao', hint: 'Ex.: {{nome}} - {{cargo}}' },
1086
+ { name: 'array.minItems', label: 'Minimo de itens', editorType: 'number', group: 'Validacao' },
1087
+ { name: 'array.maxItems', label: 'Maximo de itens', editorType: 'number', group: 'Validacao' },
1088
+ {
1089
+ name: 'array.deleteMode',
1090
+ label: 'Modo de exclusao',
1091
+ editorType: 'select',
1092
+ group: 'Operacoes',
1093
+ defaultValue: 'removeFromPayload',
1094
+ options: [
1095
+ { value: 'removeFromPayload', text: 'Remover do payload' },
1096
+ ],
1097
+ },
1098
+ { name: 'array.operations.add', label: 'Permitir adicionar', editorType: 'checkbox', group: 'Operacoes', defaultValue: true },
1099
+ { name: 'array.operations.edit', label: 'Permitir editar', editorType: 'checkbox', group: 'Operacoes', defaultValue: true },
1100
+ { name: 'array.operations.remove', label: 'Permitir remover', editorType: 'checkbox', group: 'Operacoes', defaultValue: true },
1101
+ { name: 'array.collectionValidation.uniqueBy', label: 'Unico por campos', editorType: 'textarea', group: 'Validacao', hint: 'JSON array ou uma linha por campo. Ex.: ["email"]' },
1102
+ { name: 'array.collectionValidation.exactlyOne.field', label: 'Exatamente um: campo', editorType: 'text', group: 'Validacao' },
1103
+ { name: 'array.collectionValidation.exactlyOne.value', label: 'Exatamente um: valor tipado', editorType: 'text', group: 'Validacao', hint: 'Use true/false, numero ou texto. Ex.: true, 1, PRINCIPAL.' },
1104
+ { name: 'array.collectionValidation.exactlyOne.message', label: 'Mensagem: exatamente um', editorType: 'text', group: 'Validacao' },
1105
+ { name: 'array.collectionValidation.atLeastOne.field', label: 'Pelo menos um: campo', editorType: 'text', group: 'Validacao' },
1106
+ { name: 'array.collectionValidation.atLeastOne.value', label: 'Pelo menos um: valor tipado', editorType: 'text', group: 'Validacao', hint: 'Use true/false, numero ou texto. Ex.: true, 1, ACTIVE.' },
1107
+ { name: 'array.collectionValidation.atLeastOne.message', label: 'Mensagem: pelo menos um', editorType: 'text', group: 'Validacao' },
1108
+ { name: 'array.itemSchema.fields', label: 'Subcampos (JSON)', editorType: 'textarea', group: 'Subcampos', hint: 'Lista FieldMetadata[] usada quando nao houver itemSchemaRef resolvido.' },
1109
+ { name: 'required', label: 'Obrigatorio', editorType: 'checkbox', group: 'Validacao' },
1110
+ ];
1111
+
1057
1112
  // Editor de metadados para componentes SELECT-like
1058
1113
  // Paridade com INPUT: grupos, linhas e propriedades canônicas
1059
1114
  const selectProperties = [
@@ -1215,6 +1270,302 @@ const selectProperties = [
1215
1270
  { name: 'dataAttributes', label: 'Data attributes (JSON)', editorType: 'textarea', group: 'Acessibilidade', hint: '{ "testId": "select-a" }' },
1216
1271
  ];
1217
1272
 
1273
+ function cloneProperty$7(prop) {
1274
+ return {
1275
+ ...prop,
1276
+ options: Array.isArray(prop.options)
1277
+ ? prop.options.map((opt) => typeof opt === 'object' && opt !== null ? { ...opt } : opt)
1278
+ : prop.options,
1279
+ };
1280
+ }
1281
+ const entityLookupProperties = [
1282
+ ...selectProperties.map((prop) => cloneProperty$7(prop)),
1283
+ {
1284
+ name: 'optionSource.key',
1285
+ label: 'Option source key',
1286
+ editorType: 'text',
1287
+ group: 'Fonte de entidade',
1288
+ required: true,
1289
+ hint: 'Chave publicada pelo backend para filtrar e reidratar a entidade.',
1290
+ },
1291
+ {
1292
+ name: 'optionSource.type',
1293
+ label: 'Tipo da fonte',
1294
+ editorType: 'select',
1295
+ group: 'Fonte de entidade',
1296
+ defaultValue: 'RESOURCE_ENTITY',
1297
+ options: [
1298
+ { value: 'RESOURCE_ENTITY', text: 'RESOURCE_ENTITY' },
1299
+ { value: 'LIGHT_LOOKUP', text: 'LIGHT_LOOKUP' },
1300
+ ],
1301
+ hint: 'Use RESOURCE_ENTITY para entidades reais de dominio.',
1302
+ },
1303
+ {
1304
+ name: 'optionSource.entityKey',
1305
+ label: 'Entity key',
1306
+ editorType: 'text',
1307
+ group: 'Fonte de entidade',
1308
+ hint: 'Identificador semantico da entidade, por exemplo supplier, customer ou contract.',
1309
+ },
1310
+ {
1311
+ name: 'optionSource.resourcePath',
1312
+ label: 'Resource path',
1313
+ editorType: 'text',
1314
+ group: 'Fonte de entidade',
1315
+ hint: 'Caminho base do recurso que publica option-sources e by-ids.',
1316
+ },
1317
+ {
1318
+ name: 'optionSource.filterField',
1319
+ label: 'Campo de filtro principal',
1320
+ editorType: 'text',
1321
+ group: 'Fonte de entidade',
1322
+ hint: 'Campo usado por fontes derivadas quando houver filtro simples no backend.',
1323
+ },
1324
+ {
1325
+ name: 'optionSource.propertyPath',
1326
+ label: 'Property path',
1327
+ editorType: 'text',
1328
+ group: 'Fonte de entidade',
1329
+ hint: 'Caminho de propriedade usado por fontes derivadas ou projeções leves.',
1330
+ },
1331
+ {
1332
+ name: 'optionSource.valuePropertyPath',
1333
+ label: 'Campo de valor',
1334
+ editorType: 'text',
1335
+ group: 'Fonte de entidade',
1336
+ defaultValue: 'id',
1337
+ hint: 'Campo canonico salvo no payload do formulario.',
1338
+ },
1339
+ {
1340
+ name: 'optionSource.labelPropertyPath',
1341
+ label: 'Campo de label',
1342
+ editorType: 'text',
1343
+ group: 'Fonte de entidade',
1344
+ defaultValue: 'label',
1345
+ hint: 'Campo principal exibido para o usuario.',
1346
+ },
1347
+ {
1348
+ name: 'optionSource.codePropertyPath',
1349
+ label: 'Campo de codigo',
1350
+ editorType: 'text',
1351
+ group: 'Exibicao de entidade',
1352
+ hint: 'Codigo curto exibido antes do label, por exemplo FOR-8742.',
1353
+ },
1354
+ {
1355
+ name: 'optionSource.descriptionPropertyPaths',
1356
+ label: 'Campos de descricao',
1357
+ editorType: 'textarea',
1358
+ group: 'Exibicao de entidade',
1359
+ hint: 'JSON array ou uma linha por campo. Ex.: ["documentNumber", "city", "state"].',
1360
+ },
1361
+ {
1362
+ name: 'optionSource.statusPropertyPath',
1363
+ label: 'Campo de status',
1364
+ editorType: 'text',
1365
+ group: 'Exibicao de entidade',
1366
+ hint: 'Campo que informa status operacional da entidade.',
1367
+ },
1368
+ {
1369
+ name: 'optionSource.disabledPropertyPath',
1370
+ label: 'Campo disabled',
1371
+ editorType: 'text',
1372
+ group: 'Exibicao de entidade',
1373
+ hint: 'Campo booleano que indica bloqueio visual ou operacional da entidade.',
1374
+ },
1375
+ {
1376
+ name: 'optionSource.disabledReasonPropertyPath',
1377
+ label: 'Campo de motivo bloqueado',
1378
+ editorType: 'text',
1379
+ group: 'Exibicao de entidade',
1380
+ hint: 'Campo opcional com mensagem de bloqueio quando selectable=false.',
1381
+ },
1382
+ {
1383
+ name: 'optionSource.searchPropertyPaths',
1384
+ label: 'Campos de busca',
1385
+ editorType: 'textarea',
1386
+ group: 'Busca',
1387
+ hint: 'JSON array ou uma linha por campo pesquisavel.',
1388
+ },
1389
+ {
1390
+ name: 'optionSource.searchMode',
1391
+ label: 'Modo de busca',
1392
+ editorType: 'select',
1393
+ group: 'Busca',
1394
+ options: [
1395
+ { value: 'contains', text: 'contains' },
1396
+ { value: 'startsWith', text: 'startsWith' },
1397
+ { value: 'exact', text: 'exact' },
1398
+ ],
1399
+ hint: 'Semantica de busca publicada pelo backend para esta fonte.',
1400
+ },
1401
+ {
1402
+ name: 'optionSource.pageSize',
1403
+ label: 'Tamanho da pagina',
1404
+ editorType: 'number',
1405
+ group: 'Busca',
1406
+ hint: 'Quantidade sugerida de resultados por pagina.',
1407
+ },
1408
+ {
1409
+ name: 'optionSource.includeIds',
1410
+ label: 'Incluir IDs selecionados',
1411
+ editorType: 'checkbox',
1412
+ group: 'Busca',
1413
+ defaultValue: true,
1414
+ hint: 'Mantem entidades ja selecionadas visiveis durante busca paginada.',
1415
+ },
1416
+ {
1417
+ name: 'optionSource.dependsOn',
1418
+ label: 'Dependencias',
1419
+ editorType: 'textarea',
1420
+ group: 'Dependencias',
1421
+ hint: 'JSON array ou uma linha por campo do formulario que filtra o lookup.',
1422
+ },
1423
+ {
1424
+ name: 'optionSource.dependencyFilterMap',
1425
+ label: 'Mapa de filtros',
1426
+ editorType: 'textarea',
1427
+ group: 'Dependencias',
1428
+ hint: 'JSON object. Ex.: { "empresaId": "companyId", "fornecedorId": "supplierId" }.',
1429
+ },
1430
+ {
1431
+ name: 'optionSource.selectionPolicy.statusPropertyPath',
1432
+ label: 'Politica: campo de status',
1433
+ editorType: 'text',
1434
+ group: 'Politica de selecao',
1435
+ hint: 'Campo usado para aplicar allowedStatuses ou blockedStatuses.',
1436
+ },
1437
+ {
1438
+ name: 'optionSource.selectionPolicy.selectablePropertyPath',
1439
+ label: 'Politica: campo selectable',
1440
+ editorType: 'text',
1441
+ group: 'Politica de selecao',
1442
+ hint: 'Campo booleano publicado pelo backend para indicar se a entidade pode ser selecionada.',
1443
+ },
1444
+ {
1445
+ name: 'optionSource.selectionPolicy.allowedStatuses',
1446
+ label: 'Status permitidos',
1447
+ editorType: 'textarea',
1448
+ group: 'Politica de selecao',
1449
+ hint: 'JSON array ou uma linha por status. Ex.: ACTIVE, SIGNED.',
1450
+ },
1451
+ {
1452
+ name: 'optionSource.selectionPolicy.blockedStatuses',
1453
+ label: 'Status bloqueados',
1454
+ editorType: 'textarea',
1455
+ group: 'Politica de selecao',
1456
+ hint: 'JSON array ou uma linha por status.',
1457
+ },
1458
+ {
1459
+ name: 'optionSource.selectionPolicy.disabledReasonTemplate',
1460
+ label: 'Template de motivo bloqueado',
1461
+ editorType: 'text',
1462
+ group: 'Politica de selecao',
1463
+ hint: 'Mensagem template exibida quando a entidade nao pode ser selecionada.',
1464
+ },
1465
+ {
1466
+ name: 'optionSource.selectionPolicy.validationMessageTemplate',
1467
+ label: 'Template de validacao',
1468
+ editorType: 'text',
1469
+ group: 'Politica de selecao',
1470
+ hint: 'Mensagem template usada em validacoes de selecao.',
1471
+ },
1472
+ {
1473
+ name: 'optionSource.selectionPolicy.allowRetainInvalidExistingValue',
1474
+ label: 'Manter valor invalido existente',
1475
+ editorType: 'checkbox',
1476
+ group: 'Politica de selecao',
1477
+ hint: 'Exibe entidade historica ja salva mesmo quando nao pode ser selecionada em novos registros.',
1478
+ },
1479
+ {
1480
+ name: 'optionSource.capabilities.filter',
1481
+ label: 'Capability: filter',
1482
+ editorType: 'checkbox',
1483
+ group: 'Capabilities',
1484
+ defaultValue: true,
1485
+ },
1486
+ {
1487
+ name: 'optionSource.capabilities.byIds',
1488
+ label: 'Capability: by-ids',
1489
+ editorType: 'checkbox',
1490
+ group: 'Capabilities',
1491
+ defaultValue: true,
1492
+ },
1493
+ {
1494
+ name: 'optionSource.capabilities.navigateToDetail',
1495
+ label: 'Capability: detalhe',
1496
+ editorType: 'checkbox',
1497
+ group: 'Capabilities',
1498
+ },
1499
+ {
1500
+ name: 'optionSource.capabilities.detail',
1501
+ label: 'Capability: endpoint de detalhe',
1502
+ editorType: 'checkbox',
1503
+ group: 'Capabilities',
1504
+ },
1505
+ {
1506
+ name: 'optionSource.capabilities.edit',
1507
+ label: 'Capability: editar',
1508
+ editorType: 'checkbox',
1509
+ group: 'Capabilities',
1510
+ },
1511
+ {
1512
+ name: 'optionSource.capabilities.create',
1513
+ label: 'Capability: criar',
1514
+ editorType: 'checkbox',
1515
+ group: 'Capabilities',
1516
+ },
1517
+ {
1518
+ name: 'optionSource.capabilities.multiSelect',
1519
+ label: 'Capability: multi-select',
1520
+ editorType: 'checkbox',
1521
+ group: 'Capabilities',
1522
+ },
1523
+ {
1524
+ name: 'optionSource.capabilities.recent',
1525
+ label: 'Capability: recentes',
1526
+ editorType: 'checkbox',
1527
+ group: 'Capabilities',
1528
+ },
1529
+ {
1530
+ name: 'optionSource.capabilities.favorites',
1531
+ label: 'Capability: favoritos',
1532
+ editorType: 'checkbox',
1533
+ group: 'Capabilities',
1534
+ },
1535
+ {
1536
+ name: 'optionSource.capabilities.auditSnapshot',
1537
+ label: 'Capability: snapshot de auditoria',
1538
+ editorType: 'checkbox',
1539
+ group: 'Capabilities',
1540
+ },
1541
+ {
1542
+ name: 'optionSource.detail.hrefTemplate',
1543
+ label: 'Template de detalhe',
1544
+ editorType: 'text',
1545
+ group: 'Navegacao',
1546
+ hint: 'Template de detalhe, por exemplo /contracts/{id}.',
1547
+ },
1548
+ {
1549
+ name: 'optionSource.detail.routeTemplate',
1550
+ label: 'Template de rota',
1551
+ editorType: 'text',
1552
+ group: 'Navegacao',
1553
+ hint: 'Template de rota de detalhe, por exemplo /contracts/:id.',
1554
+ },
1555
+ {
1556
+ name: 'optionSource.detail.openDetailMode',
1557
+ label: 'Modo de detalhe',
1558
+ editorType: 'select',
1559
+ group: 'Navegacao',
1560
+ options: [
1561
+ { value: 'route', text: 'Rota' },
1562
+ { value: 'drawer', text: 'Drawer' },
1563
+ { value: 'dialog', text: 'Dialog' },
1564
+ { value: 'external', text: 'Externo' },
1565
+ ],
1566
+ },
1567
+ ];
1568
+
1218
1569
  const transferListProperties = [
1219
1570
  // Geral
1220
1571
  { name: 'label', label: 'Label', editorType: 'text', group: 'Geral' },
@@ -5323,7 +5674,7 @@ const INLINE_FILTER_EDITOR_PROPERTIES_BY_CONTROL_TYPE = Object.freeze({
5323
5674
  [INLINE_FILTER_CONTROL_TYPES.SELECT]: selectProperties,
5324
5675
  [INLINE_FILTER_CONTROL_TYPES.SEARCHABLE_SELECT]: selectProperties,
5325
5676
  [INLINE_FILTER_CONTROL_TYPES.ASYNC_SELECT]: selectProperties,
5326
- [INLINE_FILTER_CONTROL_TYPES.ENTITY_LOOKUP]: selectProperties,
5677
+ [INLINE_FILTER_CONTROL_TYPES.ENTITY_LOOKUP]: entityLookupProperties,
5327
5678
  [INLINE_FILTER_CONTROL_TYPES.AUTOCOMPLETE]: selectProperties,
5328
5679
  [INLINE_FILTER_CONTROL_TYPES.MULTI_SELECT]: selectProperties,
5329
5680
  [INLINE_FILTER_CONTROL_TYPES.INPUT]: inputProperties,
@@ -5380,10 +5731,12 @@ class FieldMetadataEditorComponent {
5380
5731
  { value: FieldControlType.URL_INPUT, label: 'URL' },
5381
5732
  { value: FieldControlType.SEARCH_INPUT, label: 'Busca' },
5382
5733
  { value: FieldControlType.PHONE, label: 'Telefone' },
5734
+ { value: FieldControlType.ARRAY_INPUT, label: 'Colecao editavel' },
5383
5735
  { value: FieldControlType.SELECT, label: 'Seleção (Select)' },
5384
5736
  { value: FieldControlType.MULTI_SELECT, label: 'Seleção múltipla' },
5385
5737
  { value: FieldControlType.SEARCHABLE_SELECT, label: 'Seleção buscável' },
5386
5738
  { value: FieldControlType.ASYNC_SELECT, label: 'Seleção assíncrona' },
5739
+ { value: FieldControlType.ENTITY_LOOKUP, label: 'Entity Lookup' },
5387
5740
  { value: FieldControlType.AUTO_COMPLETE, label: 'Auto-completar' },
5388
5741
  { value: FieldControlType.SELECTION_LIST, label: 'Lista de seleção' },
5389
5742
  { value: FieldControlType.TREE_SELECT, label: 'Árvore (Tree Select)' },
@@ -5471,9 +5824,12 @@ class FieldMetadataEditorComponent {
5471
5824
  return inlineProps;
5472
5825
  if (controlType === FieldControlType.INPUT)
5473
5826
  return inputProperties;
5827
+ if (controlType === FieldControlType.ARRAY_INPUT)
5828
+ return arrayProperties;
5829
+ if (controlTypeToken === 'entitylookup')
5830
+ return entityLookupProperties;
5474
5831
  if (controlTypeToken === 'searchableselect' ||
5475
- controlTypeToken === 'asyncselect' ||
5476
- controlTypeToken === 'entitylookup')
5832
+ controlTypeToken === 'asyncselect')
5477
5833
  return selectProperties;
5478
5834
  if (controlType === FieldControlType.NUMERIC_TEXT_BOX)
5479
5835
  return numberProperties;
@@ -5518,6 +5874,8 @@ class FieldMetadataEditorComponent {
5518
5874
  controlType === FieldControlType.AUTO_COMPLETE ||
5519
5875
  controlType === FieldControlType.SELECTION_LIST)
5520
5876
  return selectProperties;
5877
+ if (controlType === FieldControlType.ENTITY_LOOKUP)
5878
+ return entityLookupProperties;
5521
5879
  if (controlType === FieldControlType.TEXTAREA)
5522
5880
  return textareaProperties;
5523
5881
  if (controlType === FieldControlType.TRANSFER_LIST)
@@ -5594,11 +5952,14 @@ class FieldMetadataEditorComponent {
5594
5952
  this.registry.register(this.controlType, inputProperties);
5595
5953
  props = inputProperties;
5596
5954
  }
5955
+ else if (controlTypeToken === 'entitylookup') {
5956
+ this.registry.register(this.controlType, entityLookupProperties);
5957
+ props = entityLookupProperties;
5958
+ }
5597
5959
  else if (
5598
5960
  // Aliases for select-like
5599
5961
  controlTypeToken === 'searchableselect' ||
5600
- controlTypeToken === 'asyncselect' ||
5601
- controlTypeToken === 'entitylookup') {
5962
+ controlTypeToken === 'asyncselect') {
5602
5963
  this.registry.register(this.controlType, selectProperties);
5603
5964
  props = selectProperties;
5604
5965
  }
@@ -5683,6 +6044,10 @@ class FieldMetadataEditorComponent {
5683
6044
  this.registry.register(this.controlType, selectProperties);
5684
6045
  props = selectProperties;
5685
6046
  }
6047
+ else if (this.controlType === FieldControlType.ENTITY_LOOKUP) {
6048
+ this.registry.register(this.controlType, entityLookupProperties);
6049
+ props = entityLookupProperties;
6050
+ }
5686
6051
  else if (this.controlType === FieldControlType.TEXTAREA) {
5687
6052
  this.registry.register(this.controlType, textareaProperties);
5688
6053
  props = textareaProperties;
@@ -5844,7 +6209,7 @@ class FieldMetadataEditorComponent {
5844
6209
  const name = p?.name;
5845
6210
  if (!name)
5846
6211
  continue;
5847
- const val = getByPath(this.seed, name);
6212
+ const val = this.toEditorControlValue(p, getByPath(this.seed, name));
5848
6213
  // Preserve false/0; skip only null/undefined
5849
6214
  if (val !== undefined && val !== null) {
5850
6215
  this.factory.setValueByPath(this.form, name, val);
@@ -6154,6 +6519,97 @@ class FieldMetadataEditorComponent {
6154
6519
  patch.links = parsedLinks;
6155
6520
  }
6156
6521
  }
6522
+ this.normalizeEntityLookupPatchValues(patch);
6523
+ this.normalizeArrayPatchValues(patch);
6524
+ }
6525
+ normalizeEntityLookupPatchValues(patch) {
6526
+ const optionSource = patch?.optionSource;
6527
+ if (!optionSource || typeof optionSource !== 'object') {
6528
+ return;
6529
+ }
6530
+ this.normalizeStringListProperty(optionSource, 'descriptionPropertyPaths');
6531
+ this.normalizeStringListProperty(optionSource, 'searchPropertyPaths');
6532
+ this.normalizeStringListProperty(optionSource, 'dependsOn');
6533
+ this.normalizeJsonObjectProperty(optionSource, 'dependencyFilterMap');
6534
+ const selectionPolicy = optionSource.selectionPolicy;
6535
+ if (selectionPolicy && typeof selectionPolicy === 'object') {
6536
+ this.normalizeStringListProperty(selectionPolicy, 'allowedStatuses');
6537
+ this.normalizeStringListProperty(selectionPolicy, 'blockedStatuses');
6538
+ }
6539
+ }
6540
+ normalizeStringListProperty(target, key) {
6541
+ if (!target || typeof target !== 'object' || typeof target[key] !== 'string') {
6542
+ return;
6543
+ }
6544
+ const parsed = this.parseStringListTextarea(target[key]);
6545
+ if (parsed) {
6546
+ target[key] = parsed;
6547
+ }
6548
+ }
6549
+ normalizeJsonObjectProperty(target, key) {
6550
+ if (!target || typeof target !== 'object' || typeof target[key] !== 'string') {
6551
+ return;
6552
+ }
6553
+ const parsed = this.tryParseJson(String(target[key]).trim());
6554
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
6555
+ target[key] = parsed;
6556
+ }
6557
+ }
6558
+ normalizeArrayPatchValues(patch) {
6559
+ const arrayPatch = patch?.array;
6560
+ if (!arrayPatch || typeof arrayPatch !== 'object') {
6561
+ return;
6562
+ }
6563
+ const collectionValidation = arrayPatch.collectionValidation;
6564
+ if (collectionValidation &&
6565
+ typeof collectionValidation === 'object' &&
6566
+ typeof collectionValidation.uniqueBy === 'string') {
6567
+ const parsedUniqueBy = this.parseStringListTextarea(collectionValidation.uniqueBy);
6568
+ if (parsedUniqueBy) {
6569
+ collectionValidation.uniqueBy = parsedUniqueBy;
6570
+ }
6571
+ }
6572
+ this.normalizeArrayCountRuleValue(collectionValidation?.exactlyOne);
6573
+ this.normalizeArrayCountRuleValue(collectionValidation?.atLeastOne);
6574
+ const itemSchema = arrayPatch.itemSchema;
6575
+ if (itemSchema &&
6576
+ typeof itemSchema === 'object' &&
6577
+ typeof itemSchema.fields === 'string') {
6578
+ const parsedFields = this.parseArrayTextarea(itemSchema.fields);
6579
+ if (parsedFields) {
6580
+ itemSchema.fields = parsedFields;
6581
+ }
6582
+ }
6583
+ if (typeof patch.defaultValue === 'string') {
6584
+ const parsedDefaultValue = this.parseArrayTextarea(patch.defaultValue);
6585
+ if (parsedDefaultValue) {
6586
+ patch.defaultValue = parsedDefaultValue;
6587
+ }
6588
+ }
6589
+ }
6590
+ normalizeArrayCountRuleValue(rule) {
6591
+ if (!rule || typeof rule !== 'object' || typeof rule.value !== 'string') {
6592
+ return;
6593
+ }
6594
+ const raw = rule.value.trim();
6595
+ if (!raw) {
6596
+ return;
6597
+ }
6598
+ try {
6599
+ rule.value = JSON.parse(raw);
6600
+ }
6601
+ catch {
6602
+ rule.value = raw;
6603
+ }
6604
+ }
6605
+ toEditorControlValue(prop, value) {
6606
+ if (prop?.editorType === 'textarea' &&
6607
+ value !== undefined &&
6608
+ value !== null &&
6609
+ typeof value !== 'string') {
6610
+ return JSON.stringify(value, null, 2);
6611
+ }
6612
+ return value;
6157
6613
  }
6158
6614
  /**
6159
6615
  * Interpreta textarea como lista simples de strings:
@@ -6267,15 +6723,19 @@ class CascadeRulesService {
6267
6723
  return map;
6268
6724
  }
6269
6725
  hydrateRule(field) {
6270
- const deps = field.dependencyFields;
6726
+ const deps = (field.dependencyFields ??
6727
+ field.optionSource?.dependsOn);
6271
6728
  if (!deps || deps.length === 0)
6272
6729
  return null;
6730
+ const dependencyFilterMap = field.dependencyFilterMap ??
6731
+ field.optionSource?.dependencyFilterMap ??
6732
+ null;
6273
6733
  const vm = {
6274
6734
  targetField: field.name,
6275
6735
  dependencyFields: [...deps],
6276
6736
  enableDependencyCascade: field.enableDependencyCascade === false ? false : true,
6277
6737
  resetOnDependentChange: !!field.resetOnDependentChange,
6278
- dependencyFilterMap: field.dependencyFilterMap || null,
6738
+ dependencyFilterMap,
6279
6739
  dependencyValuePath: field.dependencyValuePath || null,
6280
6740
  dependencyMergeStrategy: field.dependencyMergeStrategy || 'merge',
6281
6741
  dependencyDebounceMs: field.dependencyDebounceMs != null
package/index.d.ts CHANGED
@@ -153,6 +153,12 @@ declare class FieldMetadataEditorComponent implements OnInit {
153
153
  * Evita persistir strings cruas quando o componente espera arrays.
154
154
  */
155
155
  private normalizeKnownTextareaPatchValues;
156
+ private normalizeEntityLookupPatchValues;
157
+ private normalizeStringListProperty;
158
+ private normalizeJsonObjectProperty;
159
+ private normalizeArrayPatchValues;
160
+ private normalizeArrayCountRuleValue;
161
+ private toEditorControlValue;
156
162
  /**
157
163
  * Interpreta textarea como lista simples de strings:
158
164
  * - JSON array de strings
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/metadata-editor",
3
- "version": "8.0.0-beta.8",
3
+ "version": "8.0.0-beta.9",
4
4
  "description": "Metadata editor for Praxis UI fields and components with runtime integration.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^20.0.0",