@praxisui/table 8.0.0-beta.20 → 8.0.0-beta.22
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 +69 -0
- package/docs/dynamic-filter-host-integration-guide.md +49 -0
- package/docs/dynamic-filter-range-filters-guide.md +7 -0
- package/docs/dynamic-filter-troubleshooting-guide.md +37 -0
- package/fesm2022/{praxisui-table-table-agentic-authoring-turn-flow-tu7jtTwV.mjs → praxisui-table-table-agentic-authoring-turn-flow-DRuE55Mi.mjs} +100 -0
- package/fesm2022/praxisui-table.mjs +1677 -363
- package/index.d.ts +218 -62
- package/package.json +10 -10
- package/src/lib/praxis-table.json-api.md +11 -1
package/README.md
CHANGED
|
@@ -163,6 +163,15 @@ Filtro runtime:
|
|
|
163
163
|
- The default is `false`; hosts opt in when they want settings, authoring affordances and schema-drift UX.
|
|
164
164
|
- Customization mode does not change the table data mode. It only gates configuration/editorial surfaces.
|
|
165
165
|
|
|
166
|
+
## Praxis Semantic Assistant
|
|
167
|
+
|
|
168
|
+
- The table assistant is part of the global Praxis semantic copilot experience, not a standalone table patch bot.
|
|
169
|
+
- In customization mode, opening the assistant registers a `PraxisAssistantContextSnapshot` through `PraxisAssistantSessionRegistryService`.
|
|
170
|
+
- The table session identity follows `table:{routeKey}:{componentInstanceId || tableId}` so multiple tables on the same page can preserve separate assistant sessions.
|
|
171
|
+
- Minimizing the table shell keeps a global minimized session that the App Shell can reopen; the App Shell does not interpret or execute table semantics.
|
|
172
|
+
- The table snapshot stores only safe context: table identity, target, context chips, manifest reference, resource path, schema field names, data/runtime digests, capability refs and governance hints.
|
|
173
|
+
- Prompts that indicate shared business decisions, such as rules, policies, compliance, LGPD, approval, eligibility or access control, must be routed to governed `domain-rules` handoff instead of local table config patches.
|
|
174
|
+
|
|
166
175
|
## Migration Note
|
|
167
176
|
|
|
168
177
|
- This release treats `enableCustomization=false` as the canonical default.
|
|
@@ -274,6 +283,25 @@ rowConditionalStyles: [
|
|
|
274
283
|
]
|
|
275
284
|
```
|
|
276
285
|
|
|
286
|
+
O editor especializado tambem persiste `effects: RuleEffectDefinition[]` em
|
|
287
|
+
`rowConditionalStyles` e `columns[].conditionalStyles`. O runtime consome esses
|
|
288
|
+
efeitos diretamente e ainda preserva `cssClass`/`style` como fallback de
|
|
289
|
+
compatibilidade, mantendo o ciclo abrir -> aplicar/salvar -> reabrir sem exigir
|
|
290
|
+
que consumidores recompilem manualmente os efeitos visuais.
|
|
291
|
+
|
|
292
|
+
Para renderizacao condicional, `columns[].conditionalRenderers` tambem aceita
|
|
293
|
+
`effects: RuleEffectDefinition[]` como fonte canonica para renderer, tooltip e
|
|
294
|
+
animacao. `rowConditionalRenderers` fica tipado no contrato publico para tooltip
|
|
295
|
+
e animacao de linha, preservando os campos planos `tooltip`/`animation` como
|
|
296
|
+
fallback.
|
|
297
|
+
|
|
298
|
+
Colunas calculadas usam `columns[].computed.expression` como AST JSON Logic
|
|
299
|
+
canonico. Regras, estilos e renderers condicionais podem referenciar esses
|
|
300
|
+
valores via `computed.<field>`. Quando uma coluna calculada depende de outra
|
|
301
|
+
coluna calculada, o runtime resolve a ordem de avaliacao por dependencias
|
|
302
|
+
declaradas ou referencias `var: "computed.<field>"`, evitando que o resultado
|
|
303
|
+
dependa da ordem fisica de `columns[]`.
|
|
304
|
+
|
|
277
305
|
```scss
|
|
278
306
|
.app-table .mat-mdc-row.app-row--priority-high {
|
|
279
307
|
background: linear-gradient(
|
|
@@ -471,6 +499,12 @@ por `PraxisAssistantTurnOrchestratorService`; a semantica especifica da tabela c
|
|
|
471
499
|
|
|
472
500
|
## Agentic Authoring & Manifest
|
|
473
501
|
|
|
502
|
+
Para acoes globais de `toolbar`, `row` e `bulk`, o authoring agentic aceita somente `GlobalActionRef` governado:
|
|
503
|
+
`actionId`, `payload`, `payloadExpr` e `meta`. O schema bloqueia propriedades arbitrarias e mantem `payloadExpr`
|
|
504
|
+
como escape avancado explicito, nao como objeto livre. Configuracoes novas devem persistir a acao em
|
|
505
|
+
`effects[].kind = "global-action"` com `effects[].globalAction`; `globalAction` plano permanece apenas como fallback
|
|
506
|
+
de compatibilidade para documentos existentes.
|
|
507
|
+
|
|
474
508
|
O `@praxisui/table` declara authoring agentic através de um `ComponentAuthoringManifest` canônico. O manifesto é a fonte versionada para descoberta de alvos, operações e validações de configuração da tabela.
|
|
475
509
|
|
|
476
510
|
- **Component ID:** `praxis-table`
|
|
@@ -1814,6 +1848,20 @@ actions: {
|
|
|
1814
1848
|
id: 'open-detail',
|
|
1815
1849
|
label: 'Abrir detalhe',
|
|
1816
1850
|
action: 'navigation.openRoute',
|
|
1851
|
+
effects: [
|
|
1852
|
+
{
|
|
1853
|
+
kind: 'global-action',
|
|
1854
|
+
globalAction: {
|
|
1855
|
+
actionId: 'navigation.openRoute',
|
|
1856
|
+
payload: {
|
|
1857
|
+
path: '/clientes/detalhe',
|
|
1858
|
+
query: {
|
|
1859
|
+
id: '${row.id}',
|
|
1860
|
+
},
|
|
1861
|
+
},
|
|
1862
|
+
},
|
|
1863
|
+
},
|
|
1864
|
+
],
|
|
1817
1865
|
globalAction: {
|
|
1818
1866
|
actionId: 'navigation.openRoute',
|
|
1819
1867
|
payload: {
|
|
@@ -1831,3 +1879,24 @@ actions: {
|
|
|
1831
1879
|
|
|
1832
1880
|
O runtime da tabela resolve templates como `${row.id}` antes de executar a
|
|
1833
1881
|
global action, o que permite reutilizar o mesmo contrato em `list` e `table`.
|
|
1882
|
+
Para configuracoes novas, `effects[].kind = 'global-action'` e o envelope
|
|
1883
|
+
canonico alinhado a `PraxisRuntimeGlobalActionEffect`; `globalAction` plano
|
|
1884
|
+
continua aceito como fallback de compatibilidade.
|
|
1885
|
+
O editor de acoes usa o mesmo adapter interno para toolbar, row e bulk actions:
|
|
1886
|
+
ao escolher novamente a mesma global action, ele preserva `payload` estruturado
|
|
1887
|
+
ou `payloadExpr` existente; ao trocar o `actionId`, ele descarta o payload antigo
|
|
1888
|
+
para evitar executar parametros de outra acao.
|
|
1889
|
+
|
|
1890
|
+
As acoes por linha tambem usam Json Logic canonico para `visibleWhen` e
|
|
1891
|
+
`disabledWhen`. O editor de acoes preserva esses objetos no fluxo
|
|
1892
|
+
abrir -> aplicar/salvar -> reabrir, por exemplo:
|
|
1893
|
+
|
|
1894
|
+
```ts
|
|
1895
|
+
{
|
|
1896
|
+
id: 'edit-active',
|
|
1897
|
+
label: 'Editar',
|
|
1898
|
+
action: 'edit',
|
|
1899
|
+
visibleWhen: { '===': [{ var: 'status' }, 'Ativo'] },
|
|
1900
|
+
disabledWhen: { '===': [{ var: 'status' }, 'Bloqueado'] },
|
|
1901
|
+
}
|
|
1902
|
+
```
|
|
@@ -118,6 +118,55 @@ Essas chaves são as mais importantes na prática:
|
|
|
118
118
|
- `allowSaveTags`: habilita tags persistidas/visíveis;
|
|
119
119
|
- `changeDebounceMs`: regula a cadência de emissão de `change` e `submit`.
|
|
120
120
|
|
|
121
|
+
#### Padronizar `materialDesign` dos campos de filtro
|
|
122
|
+
|
|
123
|
+
O `praxis-filter` normaliza a metadata efetiva de filtros com uma politica
|
|
124
|
+
visual consistente para toolbar compacta e formulario avancado. Quando o host
|
|
125
|
+
fornece metadata propria ou overrides em `alwaysVisibleFieldMetadataOverrides`,
|
|
126
|
+
ele deve preservar essa politica para campos com icones, prefixos, sufixos,
|
|
127
|
+
datepicker toggle, simbolo de moeda, seletor de cor ou clear button.
|
|
128
|
+
|
|
129
|
+
Configuracao recomendada:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const filterFieldMaterialDesign = {
|
|
133
|
+
floatLabel: 'always',
|
|
134
|
+
subscriptSizing: 'dynamic',
|
|
135
|
+
} as const;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Exemplo de override:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
advancedFilters: {
|
|
142
|
+
settings: {
|
|
143
|
+
alwaysVisibleFieldMetadataOverrides: {
|
|
144
|
+
cpf: {
|
|
145
|
+
prefixIcon: 'fingerprint',
|
|
146
|
+
materialDesign: filterFieldMaterialDesign,
|
|
147
|
+
},
|
|
148
|
+
dataNascimento: {
|
|
149
|
+
materialDesign: filterFieldMaterialDesign,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Nao trate isso como ajuste cosmetico local. O Angular Material recomenda
|
|
157
|
+
`floatLabel="always"` para campos `fill`/`outline` com prefixos/sufixos porque o
|
|
158
|
+
label em repouso nao compartilha o mesmo alinhamento do valor do input. A regra
|
|
159
|
+
de plataforma e aplicar essa politica na metadata efetiva de filtro antes de
|
|
160
|
+
recorrer a CSS; o runtime ja faz essa normalizacao para a barra compacta e para
|
|
161
|
+
o formulario avancado.
|
|
162
|
+
|
|
163
|
+
Campos compostos de faixa (`priceRange`, `dateRange`, `dateTimeRange` e
|
|
164
|
+
`timeRange`) devem ocupar uma linha completa no formulario avancado. Eles
|
|
165
|
+
materializam mais de um controle interno e, quando competem lado a lado com um
|
|
166
|
+
campo simples, perdem alinhamento vertical e tornam o hint ambíguo. O
|
|
167
|
+
`praxis-filter` aplica essa classe de layout automaticamente ao montar o
|
|
168
|
+
`FormConfig` avancado.
|
|
169
|
+
|
|
121
170
|
### 3. Definir política do painel avançado
|
|
122
171
|
|
|
123
172
|
Os principais knobs são:
|
|
@@ -103,6 +103,13 @@ O `PraxisFilter` converte `controlType` genérico em variante inline por padrão
|
|
|
103
103
|
|
|
104
104
|
Para monetário, `priceRange` já aponta para a experiência compacta específica do filtro.
|
|
105
105
|
|
|
106
|
+
### Formulario avancado
|
|
107
|
+
|
|
108
|
+
No formulario avancado, ranges compostos devem ocupar a linha completa. A regra
|
|
109
|
+
evita comparar verticalmente um controle com duas entradas internas contra um
|
|
110
|
+
campo simples, preserva leitura de label/hint e mantem espaco suficiente para
|
|
111
|
+
`Min`/`Max`, icones e sufixos.
|
|
112
|
+
|
|
106
113
|
### Filter settings
|
|
107
114
|
|
|
108
115
|
`filter-settings.component.ts` participa da história porque ele controla:
|
|
@@ -118,6 +118,43 @@ O shape enviado não respeita o contrato ou foi interpretado de maneira diferent
|
|
|
118
118
|
|
|
119
119
|
Compare o payload com o guia de ranges antes de tentar “corrigir no controller”.
|
|
120
120
|
|
|
121
|
+
## Sintoma: label conflita com icone, prefixo ou sufixo
|
|
122
|
+
|
|
123
|
+
### Causa provável
|
|
124
|
+
|
|
125
|
+
Campos Material `fill`/`outline` com `prefixIcon`, `suffixIcon`, `clearButton`,
|
|
126
|
+
datepicker toggle, simbolo de moeda, seletor de cor ou outros
|
|
127
|
+
`matPrefix`/`matSuffix` podem exibir o label em repouso sobreposto ou desalinhado.
|
|
128
|
+
|
|
129
|
+
Esse comportamento vem da propria geometria do `mat-form-field`: em `fill` e
|
|
130
|
+
`outline`, o label em repouso e o valor do input nao usam o mesmo alinhamento. O
|
|
131
|
+
Angular Material recomenda `floatLabel="always"` nesses casos.
|
|
132
|
+
|
|
133
|
+
### Onde olhar
|
|
134
|
+
|
|
135
|
+
- metadata efetiva do campo no filtro avancado;
|
|
136
|
+
- `alwaysVisibleFieldMetadataOverrides`;
|
|
137
|
+
- politica global aplicada pelo `praxis-filter` para materializar campos de filtro;
|
|
138
|
+
- `metadata.materialDesign.floatLabel`;
|
|
139
|
+
- `metadata.materialDesign.subscriptSizing`.
|
|
140
|
+
|
|
141
|
+
### Ação
|
|
142
|
+
|
|
143
|
+
Configure a metadata do campo ou a politica global do filtro:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"materialDesign": {
|
|
148
|
+
"floatLabel": "always",
|
|
149
|
+
"subscriptSizing": "dynamic"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Nao corrija deslocando label, prefixo, sufixo ou notch por CSS local. Esse tipo
|
|
155
|
+
de patch acopla o host a detalhes internos do Angular Material e tende a quebrar
|
|
156
|
+
em upgrades.
|
|
157
|
+
|
|
121
158
|
## Sintoma: campo inline não aparece na barra compacta
|
|
122
159
|
|
|
123
160
|
### Causa provável
|
|
@@ -26,6 +26,9 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
26
26
|
?.map((field) => this.toAiJsonObject(field))
|
|
27
27
|
.filter((field) => Object.keys(field).length > 0);
|
|
28
28
|
const contextHints = this.optionalJsonObject(this.adapter.getAuthoringContext?.());
|
|
29
|
+
if (this.shouldRouteToGovernedDecision(prompt, contextHints)) {
|
|
30
|
+
return this.toGovernedDecisionHandoff(prompt, request);
|
|
31
|
+
}
|
|
29
32
|
const response = await firstValueFrom(this.aiApi.getPatch({
|
|
30
33
|
componentId,
|
|
31
34
|
componentType,
|
|
@@ -173,9 +176,26 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
173
176
|
}
|
|
174
177
|
compileAdapterResponse(response) {
|
|
175
178
|
const compiled = this.adapter.compileAiResponse?.(response);
|
|
179
|
+
if (!compiled && response.patch && Object.keys(response.patch).length > 0) {
|
|
180
|
+
return {
|
|
181
|
+
type: 'error',
|
|
182
|
+
message: 'A tabela exige componentEditPlan validado pelo manifesto antes de gerar patch local.',
|
|
183
|
+
warnings: [
|
|
184
|
+
'free-table-patch-rejected',
|
|
185
|
+
'Use componentEditPlan validado contra PRAXIS_TABLE_AUTHORING_MANIFEST.',
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
176
189
|
if (!compiled) {
|
|
177
190
|
return response;
|
|
178
191
|
}
|
|
192
|
+
if (compiled.type === 'error') {
|
|
193
|
+
return {
|
|
194
|
+
type: 'error',
|
|
195
|
+
message: compiled.message || 'O componentEditPlan da tabela nao passou na validacao de capacidades.',
|
|
196
|
+
warnings: compiled.warnings,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
179
199
|
const warnings = [
|
|
180
200
|
...(response.warnings ?? []),
|
|
181
201
|
...(compiled.warnings ?? []),
|
|
@@ -183,6 +203,7 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
183
203
|
return {
|
|
184
204
|
...response,
|
|
185
205
|
...compiled,
|
|
206
|
+
patch: compiled.patch,
|
|
186
207
|
warnings: warnings.length ? warnings : undefined,
|
|
187
208
|
};
|
|
188
209
|
}
|
|
@@ -251,6 +272,85 @@ class TableAgenticAuthoringTurnFlow {
|
|
|
251
272
|
...(rowCount !== undefined ? { rowCount } : {}),
|
|
252
273
|
};
|
|
253
274
|
}
|
|
275
|
+
shouldRouteToGovernedDecision(prompt, contextHints) {
|
|
276
|
+
const normalized = prompt.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
|
|
277
|
+
const recommendedFlow = this.toRecord(contextHints?.['domainCatalog'])?.['recommendedAuthoringFlow'];
|
|
278
|
+
if (recommendedFlow === 'shared_rule_authoring')
|
|
279
|
+
return true;
|
|
280
|
+
return [
|
|
281
|
+
'regra',
|
|
282
|
+
'politica',
|
|
283
|
+
'policy',
|
|
284
|
+
'compliance',
|
|
285
|
+
'lgpd',
|
|
286
|
+
'privacidade',
|
|
287
|
+
'aprovacao',
|
|
288
|
+
'aprovar',
|
|
289
|
+
'publicar',
|
|
290
|
+
'materializar',
|
|
291
|
+
'enforcement',
|
|
292
|
+
'validacao de negocio',
|
|
293
|
+
'validar negocio',
|
|
294
|
+
'elegibilidade',
|
|
295
|
+
'permissao',
|
|
296
|
+
'acesso',
|
|
297
|
+
].some((term) => normalized.includes(term));
|
|
298
|
+
}
|
|
299
|
+
toGovernedDecisionHandoff(prompt, request) {
|
|
300
|
+
const message = 'Esse pedido parece alterar uma decisao de negocio compartilhada. A tabela pode ajudar a descrever o alvo, mas a regra deve seguir pelo fluxo governado de domain-rules antes de qualquer materializacao runtime.';
|
|
301
|
+
return {
|
|
302
|
+
state: 'clarification',
|
|
303
|
+
phase: 'clarify',
|
|
304
|
+
sessionId: request.sessionId,
|
|
305
|
+
assistantMessage: message,
|
|
306
|
+
statusText: 'Handoff governado necessario.',
|
|
307
|
+
canApply: false,
|
|
308
|
+
quickReplies: [
|
|
309
|
+
{
|
|
310
|
+
id: 'shared-rule-handoff',
|
|
311
|
+
label: 'Continuar como regra governada',
|
|
312
|
+
prompt,
|
|
313
|
+
kind: 'shared-rule-handoff',
|
|
314
|
+
description: 'Criar intake de domain-rules em vez de aplicar patch local na tabela.',
|
|
315
|
+
icon: 'rule',
|
|
316
|
+
tone: 'warning',
|
|
317
|
+
contextHints: {
|
|
318
|
+
flowId: 'shared_rule_authoring',
|
|
319
|
+
source: 'praxis-table',
|
|
320
|
+
recommendedAction: 'domain-rules/intake',
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
],
|
|
324
|
+
clarificationQuestions: [
|
|
325
|
+
{
|
|
326
|
+
id: 'table-governed-rule-confirmation',
|
|
327
|
+
type: 'confirm',
|
|
328
|
+
label: 'Deseja continuar pelo fluxo governado de regras compartilhadas?',
|
|
329
|
+
description: 'Esse caminho permite intake, simulacao, aprovacao/publicacao, materializacao e validacao de enforcement.',
|
|
330
|
+
required: true,
|
|
331
|
+
options: [
|
|
332
|
+
{
|
|
333
|
+
id: 'shared-rule-handoff',
|
|
334
|
+
label: 'Sim, continuar governado',
|
|
335
|
+
value: prompt,
|
|
336
|
+
description: 'Nao aplicar como patch local da tabela.',
|
|
337
|
+
contextHints: {
|
|
338
|
+
flowId: 'shared_rule_authoring',
|
|
339
|
+
source: 'praxis-table',
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
diagnostics: {
|
|
346
|
+
governedDecisionHandoff: {
|
|
347
|
+
flowId: 'shared_rule_authoring',
|
|
348
|
+
sourcePrompt: prompt,
|
|
349
|
+
sourceComponent: 'praxis-table',
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
254
354
|
optionalJsonObject(value) {
|
|
255
355
|
if (value === undefined || value === null) {
|
|
256
356
|
return undefined;
|