@praxisui/table 4.0.0-beta.0 → 5.0.0-beta.0

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/README.md CHANGED
@@ -50,6 +50,8 @@ last_updated: "2026-03-07"
50
50
 
51
51
  # @praxisui/table
52
52
 
53
+ > Estado canônico do workspace Angular: JSON Logic é o único contrato ativo de regras. Menções a DSL neste documento existem apenas como contexto histórico de migração ou referência para payloads legados.
54
+
53
55
  ## Documentation
54
56
 
55
57
  - Documentação oficial: https://praxisui.dev
@@ -192,17 +194,17 @@ O novo editor é "column-first" e usa uma tipagem compartilhada com o Editor de
192
194
  - Editores de valor dinâmicos: inputs numéricos, listas (CSV/múltipla seleção), datepickers.
193
195
  - Grupos lógicos: construa condições com AND/OR/NOT e reordene via arrastar-e-soltar (CDK DragDrop).
194
196
  - Preview: execute “Testar” para ver quantas linhas seriam afetadas pelas regras ativas.
195
- - Import/Export: exporta JSON sem o campo `enabled`; importa com validação de DSL e sanitização de estilos (allowlist).
197
+ - Import/Export: exporta JSON sem o campo `enabled`; importa com validação estrutural de JSON Logic e sanitização de estilos (allowlist).
196
198
 
197
- Exemplos de DSL:
199
+ Exemplos de JSON Logic:
198
200
 
199
- ```text
200
- contains(status, 'Ativo')
201
- not (status in ['A', 'I'])
202
- (price >= 10 and price <= 20)
203
- (createdAt >= '2024-10-01' and createdAt <= '2024-10-31')
204
- (name == null or name == '')
205
- active == true
201
+ ```json
202
+ { "contains": [{ "var": "status" }, "Ativo"] }
203
+ { "!": [{ "in": [{ "var": "status" }, ["A", "I"]] }] }
204
+ { "and": [{ ">=": [{ "var": "price" }, 10] }, { "<=": [{ "var": "price" }, 20] }] }
205
+ { "and": [{ ">=": [{ "var": "createdAt" }, "2024-10-01"] }, { "<=": [{ "var": "createdAt" }, "2024-10-31"] }] }
206
+ { "or": [{ "==": [{ "var": "name" }, null] }, { "==": [{ "var": "name" }, ""] }] }
207
+ { "==": [{ "var": "active" }, true] }
206
208
  ```
207
209
 
208
210
  Notas sobre enum/CSV:
@@ -343,41 +345,15 @@ Notas
343
345
 
344
346
  Onde é consumido (preview e runtime)
345
347
 
346
- - Preview/validação no Editor de Regras (usa `DslParser` interno):
347
- - Validação da expressão (parse): projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts:536
348
- - Preview “Testar” (parse + evaluate): projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts:909
348
+ - Preview/validação no Editor de Regras:
349
+ - Authoring canônico manual e visual em JSON Logic: `projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts`
349
350
  - Runtime na Tabela (aplica `rowConditionalStyles`/`conditionalStyles`):
350
- - Parser interno do componente: projects/praxis-table/src/lib/praxis-table.ts:282
351
+ - JSON Logic canônico + compatibilidade transitória de leitura DSL: `projects/praxis-table/src/lib/praxis-table.ts`
351
352
 
352
353
  Observação
353
- - O runtime da tabela injeta o registry DSL padrão para validação/parse/execução.
354
- - Para funções realmente custom, injete via input `[dslFunctionRegistry]` no componente.
355
-
356
- Exemplo de Provider (recomendado)
354
+ - JSON Logic é o contrato canônico para novas regras e para o editor de regras da tabela.
355
+ - O runtime ainda mantém compatibilidade transitória para regras DSL antigas.
357
356
 
358
- ```ts
359
- import { Injectable } from '@angular/core';
360
- import { FunctionRegistry } from '@praxisui/specification';
361
-
362
- @Injectable({ providedIn: 'root' })
363
- export class TableDslRegistryFactory {
364
- private readonly registry = FunctionRegistry.getInstance<any>('orders-table-rules');
365
-
366
- constructor() {
367
- this.registry.clear();
368
- this.registry.register('isStatus', (_row: any, value: any, expected: any) =>
369
- String(value ?? '').toLowerCase() === String(expected ?? '').toLowerCase(),
370
- );
371
- }
372
-
373
- get(): FunctionRegistry<any> {
374
- return this.registry;
375
- }
376
- }
377
-
378
- // Uso no host:
379
- // <praxis-table [dslFunctionRegistry]="tableDslRegistryFactory.get()" ... />
380
- ```
381
357
 
382
358
  ### ⚙️ Painel de Configurações
383
359
 
@@ -771,7 +747,6 @@ sequenceDiagram
771
747
  - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'`
772
748
  - `snoozeMs: number = 86400000`
773
749
  - `autoOpenSettingsOnOutdated: boolean = false`
774
- - `dslFunctionRegistry: FunctionRegistry<any> | null = null`
775
750
  - Outputs:
776
751
  - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; trigger?: string; tableId?: string }`
777
752
  - Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via `loadSchema()`).
@@ -1543,7 +1518,6 @@ Veja também: `docs/host-crud-integration.md` (guia operacional host) e `project
1543
1518
  - `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'` — seleciona como o runtime publica avisos de drift quando a política operacional estiver habilitada.
1544
1519
  - `snoozeMs: number = 86400000` — tempo de soneca para avisos (ms).
1545
1520
  - `autoOpenSettingsOnOutdated: boolean = false` — abre Configurações ao detectar schema desatualizado.
1546
- - `dslFunctionRegistry: FunctionRegistry<any> | null = null` — adiciona funções DSL custom sem substituir o registry nativo.
1547
1521
  - Output:
1548
1522
  - `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; tableId?: string }` — emitido após verificação leve (304/200).
1549
1523
 
@@ -1686,3 +1660,4 @@ Apache-2.0 — consulte `LICENSE` na raiz do workspace para detalhes.
1686
1660
  **Parte do Praxis UI Workspace**
1687
1661
  **Versão**: 2.0.0 (Unified Architecture)
1688
1662
  **Compatibilidade**: Angular 18+
1663
+
@@ -591,6 +591,20 @@ Columns Analysis:
591
591
  'behavior.expansion.detail.source.inlineSchema',
592
592
  'behavior.expansion.detail.source.resourcePath.paramsMap',
593
593
  ]);
594
+ const jsonLogicObjectPaths = new Set([
595
+ 'columns[].computed.expression',
596
+ 'columns[].conditionalStyles[].condition',
597
+ 'columns[].conditionalRenderers[].condition',
598
+ 'rowConditionalStyles[].condition',
599
+ 'toolbar.actions[].visibleWhen',
600
+ 'toolbar.actions[].children[].visibleWhen',
601
+ 'actions.row.actions[].visibleWhen',
602
+ 'actions.row.actions[].disabledWhen',
603
+ 'columns[].renderer.button.disabledCondition',
604
+ 'columns[].renderer.toggle.disabledCondition',
605
+ 'columns[].conditionalRenderers[].renderer.button.disabledCondition',
606
+ 'columns[].conditionalRenderers[].renderer.toggle.disabledCondition',
607
+ ]);
594
608
  const recurse = (obj, currentPath) => {
595
609
  if (typeof obj !== 'object' || obj === null)
596
610
  return obj;
@@ -613,30 +627,26 @@ Columns Analysis:
613
627
  const prefixMatch = Array.from(allowedPaths).some(p => p.startsWith(newPath + '.') || p.startsWith(newPath + '['));
614
628
  if (exactMatch || prefixMatch) {
615
629
  if (exactMatch
616
- && passthroughObjectPaths.has(newPath)
630
+ && (passthroughObjectPaths.has(newPath) || jsonLogicObjectPaths.has(newPath))
617
631
  && typeof obj[key] === 'object'
618
- && obj[key] !== null) {
632
+ && obj[key] !== null
633
+ && !Array.isArray(obj[key])) {
619
634
  cleanObj[key] = obj[key];
620
635
  continue;
621
636
  }
622
- const val = recurse(obj[key], newPath);
623
637
  if (newPath === 'columns[].computed.expression') {
624
- if (typeof val !== 'string') {
625
- warnings.push(`Computed expression inválida: ${newPath} (não é string)`);
638
+ if (!obj[key] || typeof obj[key] !== 'object' || Array.isArray(obj[key])) {
639
+ warnings.push(`Computed expression inválida: ${newPath} (deve ser Json Logic)`);
626
640
  continue;
627
641
  }
628
- const trimmed = val.trim();
629
- if (!trimmed) {
642
+ if (Object.keys(obj[key]).length === 0) {
630
643
  warnings.push(`Computed expression vazia: ${newPath}`);
631
644
  continue;
632
645
  }
633
- if (trimmed.length > 200) {
634
- warnings.push(`Computed expression muito longa: ${newPath}`);
635
- continue;
636
- }
637
- cleanObj[key] = trimmed;
646
+ cleanObj[key] = obj[key];
638
647
  continue;
639
648
  }
649
+ const val = recurse(obj[key], newPath);
640
650
  // Se for objeto vazio após limpeza, não inclui (salvo se for intenção explicita de limpar config, mas patch geralmente é aditivo)
641
651
  if (typeof val === 'object' && val !== null && !Array.isArray(val) && Object.keys(val).length === 0) {
642
652
  // ignora