@praxisui/table 3.0.0-beta.9 → 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
|
|
@@ -62,6 +64,37 @@ last_updated: "2026-03-07"
|
|
|
62
64
|
- Governar configuracao de colunas, toolbar e comportamento em runtime
|
|
63
65
|
- Integrar tabelas a fluxos CRUD, IA e editores visuais do ecossistema Praxis UI
|
|
64
66
|
|
|
67
|
+
## `x-ui.analytics` como fallback tabular canônico
|
|
68
|
+
|
|
69
|
+
O `@praxisui/table` materializa a familia `analytic-table` quando o `@praxisui/core`
|
|
70
|
+
resolve que uma projection de `x-ui.analytics` continua valida, mas nao e um chart
|
|
71
|
+
inequivoco.
|
|
72
|
+
|
|
73
|
+
Regras:
|
|
74
|
+
|
|
75
|
+
- a decisao da familia continua no `@praxisui/core`
|
|
76
|
+
- o `@praxisui/table` nao decide `chart` vs `analytic-table`
|
|
77
|
+
- a tabela apenas materializa a decision/projection recebida
|
|
78
|
+
- a materializacao preserva `dimension`, `metrics`, `sort`, `limit` e agregacao sem
|
|
79
|
+
inventar defaults semanticos no host
|
|
80
|
+
- `primaryMetrics` e `secondaryMetrics` entram na mesma trilha canonica de execucao
|
|
81
|
+
- projections `timeseries` preservam o valor temporal bruto para manter ordenacao
|
|
82
|
+
cronologica consistente no fallback tabular
|
|
83
|
+
|
|
84
|
+
Superficies publicas:
|
|
85
|
+
|
|
86
|
+
- `AnalyticsTableConfigAdapterService`: converte projection em `TableConfig` local
|
|
87
|
+
- `AnalyticsTableStatsApiService`: executa `praxis.stats` e devolve linhas tabulares
|
|
88
|
+
- `AnalyticsTableContractService`: fachada publica para hosts que querem resolver
|
|
89
|
+
contrato + dados de tabela analitica sem reimplementar leitura de `x-ui.analytics`
|
|
90
|
+
|
|
91
|
+
Filtro runtime:
|
|
92
|
+
|
|
93
|
+
- a projection continua sendo a fonte canonica da semantica analitica
|
|
94
|
+
- o host pode passar `queryContext.filters` em `loadTableViews(..., { queryContexts })`
|
|
95
|
+
- somente `filters` entram no request remoto nesta fase
|
|
96
|
+
- `sort`, `limit` e agregacao continuam vindo da projection publicada
|
|
97
|
+
|
|
65
98
|
> Componente de tabela empresarial avançado com arquitetura unificada
|
|
66
99
|
|
|
67
100
|
## Customization Mode Contract
|
|
@@ -115,6 +148,24 @@ Nota: a classe de tema é decisão do host (`.dark-theme` ou `.theme-dark`/`.the
|
|
|
115
148
|
- **Acessibilidade**: WCAG 2.1 AA compliant
|
|
116
149
|
- **Verificação de Schema**: ETag/If-None-Match com notificações (somente em customização)
|
|
117
150
|
|
|
151
|
+
## Expansion Hypermedia
|
|
152
|
+
|
|
153
|
+
O primeiro corte de `behavior.expansion.detail.source.mode = "hypermedia"` é
|
|
154
|
+
`capabilities-first`:
|
|
155
|
+
|
|
156
|
+
- a row expandida começa em `_links.capabilities`
|
|
157
|
+
- `surfaces`, `actions` e operações canônicas vêm do snapshot agregado retornado
|
|
158
|
+
pelo backend
|
|
159
|
+
- o detail renderiza um resumo contextual somente leitura, com foco em UX de
|
|
160
|
+
negócio e affordances disponíveis naquele registro
|
|
161
|
+
- este corte não executa `surface.open` inline nem dispara workflow inline
|
|
162
|
+
- quando o item não expõe `rel="capabilities"`, o runtime aplica fail-closed
|
|
163
|
+
|
|
164
|
+
Observação de escala:
|
|
165
|
+
- o prefetch por linha continua ativo quando `actions.row.enabled=true`
|
|
166
|
+
- quando apenas o expansion `hypermedia` está ligado, o discovery contextual é
|
|
167
|
+
resolvido sob demanda ao expandir a linha
|
|
168
|
+
|
|
118
169
|
### 📄 Contrato Inline do Filtro
|
|
119
170
|
|
|
120
171
|
- Referencia canonica: `projects/praxis-dynamic-fields/docs/dynamic-fields-inline-components-guide.md` (slug publicado: `dynamic-fields-inline-components-guide`)
|
|
@@ -143,17 +194,17 @@ O novo editor é "column-first" e usa uma tipagem compartilhada com o Editor de
|
|
|
143
194
|
- Editores de valor dinâmicos: inputs numéricos, listas (CSV/múltipla seleção), datepickers.
|
|
144
195
|
- Grupos lógicos: construa condições com AND/OR/NOT e reordene via arrastar-e-soltar (CDK DragDrop).
|
|
145
196
|
- Preview: execute “Testar” para ver quantas linhas seriam afetadas pelas regras ativas.
|
|
146
|
-
- Import/Export: exporta JSON sem o campo `enabled`; importa com validação de
|
|
197
|
+
- Import/Export: exporta JSON sem o campo `enabled`; importa com validação estrutural de JSON Logic e sanitização de estilos (allowlist).
|
|
147
198
|
|
|
148
|
-
Exemplos de
|
|
199
|
+
Exemplos de JSON Logic:
|
|
149
200
|
|
|
150
|
-
```
|
|
151
|
-
contains
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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] }
|
|
157
208
|
```
|
|
158
209
|
|
|
159
210
|
Notas sobre enum/CSV:
|
|
@@ -294,41 +345,15 @@ Notas
|
|
|
294
345
|
|
|
295
346
|
Onde é consumido (preview e runtime)
|
|
296
347
|
|
|
297
|
-
- Preview/validação no Editor de Regras
|
|
298
|
-
-
|
|
299
|
-
- 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`
|
|
300
350
|
- Runtime na Tabela (aplica `rowConditionalStyles`/`conditionalStyles`):
|
|
301
|
-
-
|
|
351
|
+
- JSON Logic canônico + compatibilidade transitória de leitura DSL: `projects/praxis-table/src/lib/praxis-table.ts`
|
|
302
352
|
|
|
303
353
|
Observação
|
|
304
|
-
-
|
|
305
|
-
-
|
|
306
|
-
|
|
307
|
-
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.
|
|
308
356
|
|
|
309
|
-
```ts
|
|
310
|
-
import { Injectable } from '@angular/core';
|
|
311
|
-
import { FunctionRegistry } from '@praxisui/specification';
|
|
312
|
-
|
|
313
|
-
@Injectable({ providedIn: 'root' })
|
|
314
|
-
export class TableDslRegistryFactory {
|
|
315
|
-
private readonly registry = FunctionRegistry.getInstance<any>('orders-table-rules');
|
|
316
|
-
|
|
317
|
-
constructor() {
|
|
318
|
-
this.registry.clear();
|
|
319
|
-
this.registry.register('isStatus', (_row: any, value: any, expected: any) =>
|
|
320
|
-
String(value ?? '').toLowerCase() === String(expected ?? '').toLowerCase(),
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
get(): FunctionRegistry<any> {
|
|
325
|
-
return this.registry;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Uso no host:
|
|
330
|
-
// <praxis-table [dslFunctionRegistry]="tableDslRegistryFactory.get()" ... />
|
|
331
|
-
```
|
|
332
357
|
|
|
333
358
|
### ⚙️ Painel de Configurações
|
|
334
359
|
|
|
@@ -722,7 +747,6 @@ sequenceDiagram
|
|
|
722
747
|
- `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'`
|
|
723
748
|
- `snoozeMs: number = 86400000`
|
|
724
749
|
- `autoOpenSettingsOnOutdated: boolean = false`
|
|
725
|
-
- `dslFunctionRegistry: FunctionRegistry<any> | null = null`
|
|
726
750
|
- Outputs:
|
|
727
751
|
- `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; trigger?: string; tableId?: string }`
|
|
728
752
|
- Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via `loadSchema()`).
|
|
@@ -1494,7 +1518,6 @@ Veja também: `docs/host-crud-integration.md` (guia operacional host) e `project
|
|
|
1494
1518
|
- `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'` — seleciona como o runtime publica avisos de drift quando a política operacional estiver habilitada.
|
|
1495
1519
|
- `snoozeMs: number = 86400000` — tempo de soneca para avisos (ms).
|
|
1496
1520
|
- `autoOpenSettingsOnOutdated: boolean = false` — abre Configurações ao detectar schema desatualizado.
|
|
1497
|
-
- `dslFunctionRegistry: FunctionRegistry<any> | null = null` — adiciona funções DSL custom sem substituir o registry nativo.
|
|
1498
1521
|
- Output:
|
|
1499
1522
|
- `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; tableId?: string }` — emitido após verificação leve (304/200).
|
|
1500
1523
|
|
|
@@ -1637,3 +1660,4 @@ Apache-2.0 — consulte `LICENSE` na raiz do workspace para detalhes.
|
|
|
1637
1660
|
**Parte do Praxis UI Workspace**
|
|
1638
1661
|
**Versão**: 2.0.0 (Unified Architecture)
|
|
1639
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
|
|
625
|
-
warnings.push(`Computed expression
|
|
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
|
-
|
|
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
|
-
|
|
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
|