@praxisui/table 9.0.0-beta.9 → 9.0.0-beta.90
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 +102 -1
- package/ai/component-registry.json +29486 -0
- package/docs/column-resize-reorder-implementation-plan.md +42 -34
- package/docs/local-data-support-implementation-plan.md +17 -17
- package/docs/local-data-support-pr-package.md +12 -12
- package/docs/release-notes-p1-hardening.md +1 -3
- package/docs/resource-events.md +36 -0
- package/fesm2022/{praxisui-table-filter-form-dialog-host.component-DbwGIMjF.mjs → praxisui-table-filter-form-dialog-host.component-CMUCxwyL.mjs} +10 -13
- package/fesm2022/{praxisui-table-praxisui-table-B-goiuDf.mjs → praxisui-table-praxisui-table-CWBFPs1H.mjs} +5954 -2059
- package/fesm2022/{praxisui-table-table-agentic-authoring-turn-flow-DL9l0XF7.mjs → praxisui-table-table-agentic-authoring-turn-flow-BLNUMwu5.mjs} +243 -19
- package/fesm2022/{praxisui-table-table-ai.adapter-9uRovA63.mjs → praxisui-table-table-ai.adapter-CeH1iTVt.mjs} +113 -13
- package/fesm2022/praxisui-table.mjs +1 -1
- package/package.json +16 -11
- package/src/lib/praxis-table.json-api.md +63 -22
- package/types/praxisui-table.d.ts +365 -44
|
@@ -7,7 +7,7 @@ Allow users to resize and move columns in `praxis-table` without conflicting wit
|
|
|
7
7
|
## Guiding Principles
|
|
8
8
|
|
|
9
9
|
- `sort` belongs to a dedicated sortable label/container, not to the entire `th`
|
|
10
|
-
- `reorder` belongs to a
|
|
10
|
+
- `reorder` belongs to the draggable header cell, without a permanent move icon
|
|
11
11
|
- `resize` belongs to a dedicated handle on the right edge of the header cell
|
|
12
12
|
- runtime mutations should reuse the existing persistence pipeline through a shared column-mutation coordinator
|
|
13
13
|
- width persistence should normalize to `px`
|
|
@@ -33,15 +33,17 @@ This is the main reason resize must not be introduced as another gesture on the
|
|
|
33
33
|
|
|
34
34
|
Additional constraints from the current implementation:
|
|
35
35
|
|
|
36
|
-
- reorder keyboard parity is attached to the
|
|
37
|
-
- reorder
|
|
36
|
+
- reorder keyboard parity is attached to the dedicated header sort trigger through Ctrl/Alt + arrows
|
|
37
|
+
- runtime reorder does not render a visible move icon/handle, matching SAP Fiori and MUI Data Grid patterns
|
|
38
38
|
- persistence currently saves the full `config` snapshot for each runtime mutation
|
|
39
39
|
- width styling may already come from `column.width`, `headerStyle`, or `style`
|
|
40
40
|
|
|
41
41
|
Current reorder affordance note:
|
|
42
42
|
|
|
43
|
-
-
|
|
44
|
-
-
|
|
43
|
+
- reorder is implicit on the draggable header cell, matching enterprise grids such as SAP Fiori and MUI Data Grid
|
|
44
|
+
- the current `cdkDrag` root remains on the `th` so preview, placeholder sizing, and index semantics stay stable
|
|
45
|
+
- `mat-sort-header` is mounted on `.praxis-header-sort-trigger`, not on the full `th`, so sort remains a focused label interaction while header drag remains available
|
|
46
|
+
- keyboard reorder belongs to the focused header sort trigger via Ctrl/Alt + arrow keys
|
|
45
47
|
|
|
46
48
|
The plan must explicitly unwind those couplings instead of treating them as incidental details.
|
|
47
49
|
|
|
@@ -52,37 +54,32 @@ The plan must explicitly unwind those couplings instead of treating them as inci
|
|
|
52
54
|
Refactor the header so each interaction has an explicit zone:
|
|
53
55
|
|
|
54
56
|
- sortable label container: sort
|
|
55
|
-
-
|
|
57
|
+
- draggable header cell: reorder, with no permanent move icon
|
|
56
58
|
- right-edge handle: resize
|
|
57
59
|
|
|
58
60
|
Changes in `praxis-table.html`:
|
|
59
61
|
|
|
60
62
|
- keep `.praxis-header-label-text`
|
|
61
|
-
-
|
|
62
|
-
- add a sortable wrapper such as `.praxis-header-sort-trigger`
|
|
63
|
-
- keep `.praxis-column-drag-handle`
|
|
64
|
-
- add `.praxis-column-resize-handle`
|
|
63
|
+
- add a sortable wrapper `.praxis-header-sort-trigger`
|
|
65
64
|
- keep `cdkDrag` on the `th`
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
65
|
+
- do not render a visible reorder icon/handle in the runtime header
|
|
66
|
+
- add `.praxis-column-resize-handle`
|
|
67
|
+
- keep keyboard reorder on the header sort trigger without blocking sort Enter/Space behavior
|
|
68
|
+
- ensure the resize handle stops `click`, `pointerdown`, and keyboard bubbling into the sort trigger
|
|
69
69
|
|
|
70
70
|
Changes in `praxis-table.scss`:
|
|
71
71
|
|
|
72
72
|
- make the sortable label container the only area that shows sort cursor/hover treatment
|
|
73
|
-
- keep drag handle aligned next to the label text
|
|
74
73
|
- add resize handle positioned at the far right edge
|
|
75
|
-
- use `cursor: grab` for reorder
|
|
76
74
|
- use `cursor: col-resize` for resize
|
|
77
75
|
- use a hit area around `8px` to `12px` for resize
|
|
78
|
-
- remove `pointer-events: none` from the drag handle and make it a real interactive control
|
|
79
76
|
|
|
80
77
|
Sorting strategy:
|
|
81
78
|
|
|
82
79
|
- do not keep the full `th` as the primary sort interaction target
|
|
83
80
|
- move the sort trigger to the label/container inside the header cell
|
|
84
81
|
- preserve keyboard sort semantics on that dedicated sort target
|
|
85
|
-
- treat suppression of `click` on
|
|
82
|
+
- treat suppression of `click` on resize handles as a hard requirement, not a best-effort safeguard
|
|
86
83
|
|
|
87
84
|
### Phase 2: Add Runtime Resize State
|
|
88
85
|
|
|
@@ -125,7 +122,7 @@ On resize start:
|
|
|
125
122
|
|
|
126
123
|
Behavioral rule:
|
|
127
124
|
|
|
128
|
-
- dragging
|
|
125
|
+
- dragging starts from the header cell, except the resize handle and sortable label interactions
|
|
129
126
|
- sorting only starts from the dedicated sortable label/container
|
|
130
127
|
- resizing only starts from the right-edge resize handle
|
|
131
128
|
|
|
@@ -151,6 +148,12 @@ Width rules:
|
|
|
151
148
|
- if `column.width` is already in `px`, use it directly
|
|
152
149
|
- if width is `%`, `auto`, or empty, measure the current header width at first resize and convert to `px`
|
|
153
150
|
- persist resized widths as `px`
|
|
151
|
+
- resizing changes the internal table content width, not the host/card/viewport width
|
|
152
|
+
- when the summed column widths exceed the viewport, the scroll container owns horizontal overflow
|
|
153
|
+
- when the summed column widths are smaller than the viewport, empty space may remain after the last column instead of redistributing widths implicitly
|
|
154
|
+
- do not resize neighboring columns in `px` mode; the resized column changes and following columns move accordingly
|
|
155
|
+
- when resize is enabled, persisted `px` widths below the effective readable minimum are normalized back into `config.columns[]`, not only corrected during rendering
|
|
156
|
+
- the effective readable minimum includes the column header text, the resize separator gutter, and the sort gutter only when that concrete column is sortable
|
|
154
157
|
- explicitly define precedence when `headerStyle` or `style` also carry width declarations
|
|
155
158
|
- document that first user resize converts responsive width intent into fixed runtime width intent
|
|
156
159
|
- validate width behavior under sticky start/end columns and horizontal scroll mode
|
|
@@ -186,9 +189,10 @@ Resize persistence policy:
|
|
|
186
189
|
|
|
187
190
|
- persist on commit only, not continuously during pointer move
|
|
188
191
|
- commit point is `pointerup` for pointer interactions
|
|
189
|
-
- keyboard resize
|
|
190
|
-
-
|
|
192
|
+
- keyboard resize commits stepwise on each handled key event
|
|
193
|
+
- keyboard resize uses `ArrowLeft`, `ArrowRight`, `Shift + Arrow`, `Home`, and `End`
|
|
191
194
|
- define stale-callback protection for resize and reorder through the same shared coordinator
|
|
195
|
+
- derived table width used during/after resize must be cleared when the visible column contract changes externally
|
|
192
196
|
- do not add undo in the first slice unless a concrete UX requirement appears, but keep the runtime contract compatible with future undo support
|
|
193
197
|
|
|
194
198
|
Emit a resize event after persistence:
|
|
@@ -240,16 +244,18 @@ Resize handle:
|
|
|
240
244
|
|
|
241
245
|
Keyboard behavior for resize handle:
|
|
242
246
|
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
247
|
+
- `ArrowLeft` and `ArrowRight` resize by the default step
|
|
248
|
+
- `Shift + ArrowLeft` and `Shift + ArrowRight` resize by the larger step
|
|
249
|
+
- `Home` applies the configured minimum width
|
|
250
|
+
- `End` applies the configured maximum width when one is configured
|
|
251
|
+
- `Escape` cancels an active pointer resize before commit
|
|
252
|
+
- keyboard resize commits stepwise on each handled key event
|
|
246
253
|
|
|
247
|
-
Reorder
|
|
254
|
+
Reorder accessibility:
|
|
248
255
|
|
|
249
|
-
-
|
|
250
|
-
- move
|
|
251
|
-
-
|
|
252
|
-
- preserve visible focus styling and screen-reader parity after removing those affordances from the `th`
|
|
256
|
+
- keep keyboard reorder on the focused header sort trigger with Alt/Ctrl + arrow keys
|
|
257
|
+
- do not add a permanent focusable move icon unless a future accessibility review proves the header-trigger model insufficient
|
|
258
|
+
- preserve visible focus styling and screen-reader parity on the header label/sort trigger
|
|
253
259
|
|
|
254
260
|
### Phase 8: Testing
|
|
255
261
|
|
|
@@ -260,7 +266,7 @@ Add focused tests for interaction conflicts:
|
|
|
260
266
|
- resize handle click does not bubble into sort click
|
|
261
267
|
- reorder does not alter width
|
|
262
268
|
- clicking the sortable label still sorts
|
|
263
|
-
- reorder still works through the
|
|
269
|
+
- reorder still works through the draggable header cell
|
|
264
270
|
- keyboard reorder still works after moving intent to the handle
|
|
265
271
|
- sort keyboard interaction still works after sort leaves the `th`
|
|
266
272
|
|
|
@@ -300,18 +306,18 @@ Add visual/e2e coverage later:
|
|
|
300
306
|
## Recommended Delivery Sequence
|
|
301
307
|
|
|
302
308
|
1. Refactor header structure so sort is isolated to a dedicated sortable label/container
|
|
303
|
-
2.
|
|
304
|
-
3. Add resize handle with
|
|
305
|
-
4. Validate sticky and horizontal-scroll behavior in
|
|
309
|
+
2. Keep reorder implicit on the header and remove stale move-icon guidance from docs/editor copy
|
|
310
|
+
3. Add resize handle with pointer support, keyboard support, and explicit cancel paths
|
|
311
|
+
4. Validate sticky and horizontal-scroll behavior in a follow-up hardening slice
|
|
306
312
|
5. Introduce shared column runtime mutation coordination for reorder + resize persistence
|
|
307
313
|
6. Persist column width on commit only
|
|
308
314
|
7. Add focused conflict and persistence tests
|
|
309
|
-
8. Add
|
|
315
|
+
8. Add broader sticky, horizontal-scroll, and non-data-column E2E coverage
|
|
310
316
|
9. Enable only through config/feature flag
|
|
311
317
|
|
|
312
318
|
## Definition of Done
|
|
313
319
|
|
|
314
|
-
- users can reorder
|
|
320
|
+
- users can reorder from the header without a permanent move icon
|
|
315
321
|
- users can resize only from the right-edge handle
|
|
316
322
|
- clicking the sortable label still sorts
|
|
317
323
|
- reorder, resize, and sort do not interfere with each other
|
|
@@ -326,6 +332,8 @@ Add visual/e2e coverage later:
|
|
|
326
332
|
- first resize may intentionally convert responsive width behavior into fixed pixel width behavior
|
|
327
333
|
- sticky start/end columns and horizontal scroll are immediate implementation concerns
|
|
328
334
|
- resize and reorder mutations need a shared commit/stale-callback policy, not parallel ad hoc logic
|
|
335
|
+
- table-level width is runtime-derived state; it must not outlive the column contract that produced it
|
|
336
|
+
- the canonical enterprise default follows the SAP/MUI model for fixed-width columns: resize the column and the internal content width, keep the outer viewport stable, and use horizontal overflow when needed
|
|
329
337
|
|
|
330
338
|
## Suggested Follow-Up
|
|
331
339
|
|
|
@@ -466,24 +466,24 @@ Todos os itens abaixo devem estar `true`:
|
|
|
466
466
|
14. Revalidacao complementar do wrapper CRUD apos o hardening:
|
|
467
467
|
- `ng test praxis-crud --watch=false --browsers=ChromeHeadless --polyfills=zone.js --polyfills=zone.js/testing`;
|
|
468
468
|
- `TOTAL: 30 SUCCESS`.
|
|
469
|
-
15. Validacao da lane dedicada
|
|
469
|
+
15. Validacao da lane dedicada:
|
|
470
470
|
- `bash ./scripts/test-table-preimpl-lane.sh`: bloqueada por infraestrutura (`No usable Chromium binary found for headless capture`).
|
|
471
471
|
- fallback operacional via Windows Chrome com os mesmos includes da lane:
|
|
472
472
|
`ng test praxis-table --watch=false --browsers=ChromeHeadless --polyfills=zone.js --polyfills=zone.js/testing --include ...`;
|
|
473
473
|
- resultado do fallback: `TOTAL: 48 SUCCESS`.
|
|
474
|
-
16. Mitigacao operacional
|
|
474
|
+
16. Mitigacao operacional validada sem alterar o script da lane:
|
|
475
475
|
- wrapper: `tools/karma/chromium-bin-wrapper.sh` (contorna apenas probe `--dump-dom`);
|
|
476
476
|
- execucao:
|
|
477
477
|
`CHROMIUM_REAL_BIN=<puppeteer-executablePath> CHROMIUM_BIN=tools/karma/chromium-bin-wrapper.sh CHROME_BIN=tools/karma/chromium-bin-wrapper.sh bash ./scripts/test-table-preimpl-lane.sh`;
|
|
478
478
|
- resultado: `TOTAL: 48 SUCCESS`.
|
|
479
|
-
17. Revalidacao integrada do gate seguro apos mitigacao
|
|
480
|
-
- `
|
|
479
|
+
17. Revalidacao integrada do gate seguro apos mitigacao:
|
|
480
|
+
- gate legado removido; usar `npm run test:table` e, quando aplicavel, `bash tools/karma/run-table-dsl-compat-gate.sh`;
|
|
481
481
|
- `praxis-table lane`: `PASS` (`TOTAL: 48 SUCCESS`);
|
|
482
482
|
- `praxis-crud full`: `PASS` (`TOTAL: 30 SUCCESS`).
|
|
483
|
-
18. Automacao do gate seguro
|
|
484
|
-
- `tools/karma/
|
|
483
|
+
18. Automacao do gate seguro concluida:
|
|
484
|
+
- runner legado removido; `tools/karma/karma.headless.conf.cjs` agora centraliza a configuracao headless;
|
|
485
485
|
- revalidacao sem env manual:
|
|
486
|
-
|
|
486
|
+
`npm run test:table`;
|
|
487
487
|
- resultado: `praxis-table lane PASS (48 SUCCESS)` e `praxis-crud full PASS (30 SUCCESS)`.
|
|
488
488
|
19. Cobertura adicional no wrapper `praxis-crud` para precedencia remoto > local concluida:
|
|
489
489
|
- novo teste para `metadata.table.resourcePath` prevalecer sobre `metadata.data`;
|
|
@@ -492,9 +492,9 @@ Todos os itens abaixo devem estar `true`:
|
|
|
492
492
|
- validacao dirigida executada com tsconfig temporario isolado (evitando erro externo de compilacao em `praxis-dynamic-fields`):
|
|
493
493
|
`ng test praxis-crud --watch=false --browsers=ChromeHeadless --polyfills=zone.js --polyfills=zone.js/testing --ts-config .tmp-preimpl-lane/tsconfig.crud-isolated.json --include projects/praxis-crud/src/lib/praxis-crud.component.spec.ts`;
|
|
494
494
|
- resultado: `TOTAL: 11 SUCCESS`.
|
|
495
|
-
20. Revalidacao do
|
|
496
|
-
- comando: `
|
|
497
|
-
- tentativa
|
|
495
|
+
20. Revalidacao do gate apos ampliar cobertura do CRUD:
|
|
496
|
+
- comando atual: `npm run test:table`;
|
|
497
|
+
- tentativa legada da lane `praxis-table` permaneceu bloqueada por deteccao de Chromium (`No usable Chromium binary found for headless capture`);
|
|
498
498
|
- fallback automatico via `cmd.exe + ChromeHeadless` executou com sucesso;
|
|
499
499
|
- resultado final:
|
|
500
500
|
- `praxis-table lane`: `PASS` (`TOTAL: 48 SUCCESS`);
|
|
@@ -502,23 +502,23 @@ Todos os itens abaixo devem estar `true`:
|
|
|
502
502
|
21. Revalidacao full da `praxis-table` apos a ampliacao de cobertura no CRUD:
|
|
503
503
|
- comando: `ng test praxis-table --watch=false --browsers=ChromeHeadless --polyfills=zone.js --polyfills=zone.js/testing`;
|
|
504
504
|
- resultado: `TOTAL: 372 SUCCESS`.
|
|
505
|
-
22. Hardening da lane
|
|
506
|
-
- `scripts/test-table-preimpl-lane.sh` agora aplica automaticamente `tools/karma/chromium-bin-wrapper.sh` quando o probe direto de Chromium falha
|
|
505
|
+
22. Hardening da lane no script dedicado concluido:
|
|
506
|
+
- `scripts/test-table-preimpl-lane.sh` agora aplica automaticamente `tools/karma/chromium-bin-wrapper.sh` quando o probe direto de Chromium falha;
|
|
507
507
|
- revalidacao direta da lane, sem env manual:
|
|
508
508
|
`bash ./scripts/test-table-preimpl-lane.sh`;
|
|
509
509
|
- resultado: `TOTAL: 48 SUCCESS`.
|
|
510
510
|
- revalidacao adicional com ambiente limpo de browser vars:
|
|
511
511
|
`env -u CHROMIUM_BIN -u CHROME_BIN -u CHROMIUM_REAL_BIN bash ./scripts/test-table-preimpl-lane.sh`;
|
|
512
512
|
- resultado: `TOTAL: 48 SUCCESS`.
|
|
513
|
-
23. Revalidacao do gate seguro apos hardening da lane
|
|
514
|
-
- comando: `
|
|
513
|
+
23. Revalidacao do gate seguro apos hardening da lane:
|
|
514
|
+
- comando atual: `npm run test:table`;
|
|
515
515
|
- resultado final: `praxis-table lane PASS (48 SUCCESS)` e `praxis-crud full PASS (32 SUCCESS)`;
|
|
516
|
-
- nesta execucao, a lane
|
|
516
|
+
- nesta execucao, a lane concluiu na trilha primaria.
|
|
517
517
|
24. Revalidacao completa do gate seguro em modo estrito + full suite:
|
|
518
518
|
- comando:
|
|
519
|
-
|
|
519
|
+
`npm run test:table`;
|
|
520
520
|
- resultado final:
|
|
521
521
|
- `praxis-table lane`: `PASS` (`TOTAL: 48 SUCCESS`);
|
|
522
|
-
|
|
522
|
+
- `praxis-table lane path`: `headless`;
|
|
523
523
|
- `praxis-crud full`: `PASS` (`TOTAL: 32 SUCCESS`);
|
|
524
524
|
- `praxis-table full`: `PASS` (`TOTAL: 372 SUCCESS`).
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Pacote de PR - Local Data Support + Gate Karma
|
|
2
2
|
|
|
3
3
|
## Objetivo do pacote
|
|
4
|
-
Consolidar o estado pronto para PR da trilha de suporte local/remote da `praxis-table`, com evidencias de validacao e operacao de testes
|
|
4
|
+
Consolidar o estado pronto para PR da trilha de suporte local/remote da `praxis-table`, com evidencias de validacao e operacao de testes locais.
|
|
5
5
|
|
|
6
6
|
## Escopo consolidado
|
|
7
7
|
1. `praxis-crud` com suporte a `metadata.data` sem `resource.path`, preservando precedencia remoto > local.
|
|
8
|
-
2. Hardening da lane isolada da `praxis-table
|
|
9
|
-
3. Runner de gate seguro
|
|
10
|
-
4. Revalidacao final do gate com
|
|
8
|
+
2. Hardening da lane isolada da `praxis-table`.
|
|
9
|
+
3. Runner de gate seguro legado substituido pelos comandos canônicos atuais.
|
|
10
|
+
4. Revalidacao final do gate com suites completas verdes.
|
|
11
11
|
|
|
12
12
|
## Commits da etapa
|
|
13
13
|
1. `7855fb9` feat(praxis-crud): suportar modo local via metadata.data sem resource.path
|
|
@@ -19,24 +19,24 @@ Consolidar o estado pronto para PR da trilha de suporte local/remote da `praxis-
|
|
|
19
19
|
7. `0086e4c` test(praxis-table): estabiliza specs pendentes e fecha suíte
|
|
20
20
|
8. `4e95076` test(praxis-table): expand shared TestBed provider coverage
|
|
21
21
|
9. `e545355` docs(praxis-table): atualizar status de validacao pos-hardening
|
|
22
|
-
10. `186e367` chore(karma): add
|
|
22
|
+
10. `186e367` chore(karma): add chromium probe wrapper for preimpl lane
|
|
23
23
|
11. `3951fab` docs(praxis-table): registrar revalidacao do safe gate
|
|
24
|
-
12. `73e7160` chore(karma): auto-configure
|
|
24
|
+
12. `73e7160` chore(karma): auto-configure chromium wrapper in safe gate
|
|
25
25
|
13. `7a8e0d4` test(praxis-crud): cobrir precedencia de resourcePath fallback
|
|
26
26
|
14. `d84c49d` docs(praxis-table): registrar safe-gate com crud 32 success
|
|
27
27
|
15. `5d0a335` docs(praxis-table): registrar full suite 372 success apos safe-gate
|
|
28
28
|
16. `0c0f55a` chore(karma): auto-fallback to chromium wrapper in preimpl lane
|
|
29
29
|
17. `f7fe073` chore(karma): log resolved real chromium in preimpl lane
|
|
30
30
|
18. `1857a87` docs(praxis-table): registrar gate estrito com full suite verde
|
|
31
|
-
19. `b7d6782` docs(karma): document strict
|
|
31
|
+
19. `b7d6782` docs(karma): document strict safe-gate modes
|
|
32
32
|
|
|
33
33
|
## Validacoes executadas (gate operacional)
|
|
34
34
|
1. `bash ./scripts/test-table-preimpl-lane.sh`
|
|
35
35
|
- Resultado: `TOTAL: 48 SUCCESS`.
|
|
36
|
-
2. `
|
|
37
|
-
-
|
|
38
|
-
3.
|
|
39
|
-
-
|
|
36
|
+
2. Gate canônico atual: `npm run test:table`
|
|
37
|
+
- Substitui o runner legado removido.
|
|
38
|
+
3. Gate ordenado de compatibilidade DSL quando a mudanca tocar contratos da tabela: `bash tools/karma/run-table-dsl-compat-gate.sh`
|
|
39
|
+
- Usar junto com build/test focal conforme o `AGENTS.md` da subarea.
|
|
40
40
|
|
|
41
41
|
## Cobertura critica confirmada
|
|
42
42
|
1. Preservacao de `pageSize` local (override do usuario)
|
|
@@ -57,7 +57,7 @@ Consolidar o estado pronto para PR da trilha de suporte local/remote da `praxis-
|
|
|
57
57
|
- manter validacao focada e reproduzivel via `ng test` com `--include` por suite/arquivo;
|
|
58
58
|
- preferir setup de testes centralizado e reutilizavel (consolidacao de providers compartilhados no hardening dos integration tests);
|
|
59
59
|
- manter contratos e comportamento com regressao protegida por specs dedicadas (precedencia `resourcePath > data`, transicoes local/remote/empty);
|
|
60
|
-
- executar gate com comandos explicitos e deterministicos
|
|
60
|
+
- executar gate com comandos explicitos e deterministicos.
|
|
61
61
|
3. Referencias oficiais retornadas por `search_documentation`:
|
|
62
62
|
- https://angular.dev/cli/test#options
|
|
63
63
|
- https://angular.dev/guide/testing/utility-apis
|
|
@@ -11,9 +11,7 @@ Nota historica: esta baseline e anterior a canonicalizacao de Json Logic. As ref
|
|
|
11
11
|
- Helpers anteriores mantidos (`jsonGet/jsonEq/jsonIn`, `isBlank`, `today/now`, `len*`, etc.).
|
|
12
12
|
- Normalização legada preservada para expressões antigas.
|
|
13
13
|
- Limitação documentada: parser atual não suporta comparação direta de retorno de função (`fn(...) == valor`).
|
|
14
|
-
- `toolbar.actions.visibleWhen`
|
|
15
|
-
- `prod/qa`: fail-closed.
|
|
16
|
-
- `dev/hml`: fail-open para diagnostico.
|
|
14
|
+
- `toolbar.actions.visibleWhen` hoje falha fechado em todos os ambientes quando a condicao nao e Json Logic valida. A baseline historica de `2026-02-26` registrava comportamento diagnostico legado, mas esse comportamento foi removido na canonicalizacao.
|
|
17
15
|
- `shortcutScope` canonico com validacao (`toolbar|global`) e fallback seguro.
|
|
18
16
|
- Guards schema-only para:
|
|
19
17
|
- `behavior.sorting.multiSort`
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Praxis Table Resource Events
|
|
2
|
+
|
|
3
|
+
`PraxisTable` emits `resourceEvent` in parallel with its existing public outputs. The envelope is intended for enterprise hosts that need one governed stream for audit, analytics, shell orchestration, and related-resource surfaces.
|
|
4
|
+
|
|
5
|
+
## Event Mapping
|
|
6
|
+
|
|
7
|
+
| Table interaction | `kind` | `sourceOutput` | `phase` |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| Row click | `row-click` | `rowClick` | `notification` |
|
|
10
|
+
| Row double click | `row-double-click` | `rowDoubleClick` | `notification` |
|
|
11
|
+
| Selection change | `selection-change` | `selectionChange` | `notification` |
|
|
12
|
+
| Row action | `row-action` | `rowAction` | `notification` |
|
|
13
|
+
| Toolbar action | `toolbar-action` | `toolbarAction` | `notification` |
|
|
14
|
+
| Bulk action | `bulk-action` | `bulkAction` | `notification` |
|
|
15
|
+
| Export action | `export-action` | `exportAction` | `success` or `error` |
|
|
16
|
+
| Dynamic record surface fallback | `surface-open` | `recordSurfaceOpen` | `request` |
|
|
17
|
+
| Catalog-backed record surface | `surface-open` | `recordSurfaceOpen` | `request`, then `success` or `error` |
|
|
18
|
+
| Catalog-backed collection surface | `surface-open` | `toolbarAction` | `request`, then `success` or `error` |
|
|
19
|
+
|
|
20
|
+
`notification` events preserve the old output semantics and should not be interpreted as business completion. Host-mediated operations such as `surface.open` emit `request` before invoking `GlobalActionService` and then emit `success` or `error` after the result is known.
|
|
21
|
+
|
|
22
|
+
`selectionChange` can also be emitted with `trigger: "data-reconcile"` when a data update removes identities from the effective selection. Rehydrating the same selected identities does not emit a new selection event. With `persistSelection`, identities may remain selected outside the current page; `persistOnDataUpdate` only reconciles selection against the current visible dataset.
|
|
23
|
+
|
|
24
|
+
Record-oriented events may carry `resourceIdentity`. Resolution prefers a valid
|
|
25
|
+
explicit `x-ui.resource.identity`, then a key-only fallback from a valid
|
|
26
|
+
`x-ui.resource.idField`, then the effective host `idField` when that field is
|
|
27
|
+
present in the filtered response schema. Fallback identities expose `source`
|
|
28
|
+
and structured `diagnostics`; they never infer a title from property names. If
|
|
29
|
+
the configured field has no displayable row value, the event carries
|
|
30
|
+
`resourceIdentity: null` and the runtime emits a deduplicated diagnostic.
|
|
31
|
+
|
|
32
|
+
## Surface Rules
|
|
33
|
+
|
|
34
|
+
For catalog-backed surfaces, `resourceEvent.surface` carries the canonical `ResourceSurfaceCatalogItem`, including `relatedResource` when the backend publishes it. For fallback dynamic-page requests, the payload still carries the requested surface context, but `surface` may be `null` because no full catalog item is available.
|
|
35
|
+
|
|
36
|
+
Consumers must keep legacy outputs wired where they already depend on them. `resourceEvent` is the canonical cross-component event stream, not a breaking replacement for existing outputs.
|
|
@@ -4,13 +4,14 @@ import * as i1 from '@angular/material/dialog';
|
|
|
4
4
|
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
5
5
|
import * as i3 from '@angular/material/button';
|
|
6
6
|
import { MatButtonModule } from '@angular/material/button';
|
|
7
|
-
import * as
|
|
7
|
+
import * as i13 from '@angular/material/progress-bar';
|
|
8
8
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
9
|
-
import * as
|
|
9
|
+
import * as i7 from '@angular/material/icon';
|
|
10
10
|
import { MatIconModule } from '@angular/material/icon';
|
|
11
|
-
import * as
|
|
11
|
+
import * as i14 from '@angular/material/tooltip';
|
|
12
12
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
13
13
|
import { PraxisFilterForm } from '@praxisui/dynamic-form';
|
|
14
|
+
import { PraxisIconButtonComponent } from '@praxisui/core';
|
|
14
15
|
|
|
15
16
|
class FilterFormDialogHostComponent {
|
|
16
17
|
data;
|
|
@@ -109,10 +110,8 @@ class FilterFormDialogHostComponent {
|
|
|
109
110
|
<mat-icon>tune</mat-icon>
|
|
110
111
|
<span>{{ data.title || 'Filtro avançado' }}</span>
|
|
111
112
|
</div>
|
|
112
|
-
<button
|
|
113
|
-
[attr.aria-label]="data.i18n?.cancel || 'Fechar'">
|
|
114
|
-
<mat-icon>close</mat-icon>
|
|
115
|
-
</button>
|
|
113
|
+
<button praxisIconButton="close" size="compact" type="button" class="pfx-dialog-close" (click)="close()"
|
|
114
|
+
[attr.aria-label]="data.i18n?.cancel || 'Fechar'"></button>
|
|
116
115
|
</div>
|
|
117
116
|
<mat-dialog-content class="pfx-filter-dialog-content" aria-labelledby="filterDialogTitle">
|
|
118
117
|
@if (data?.schemaLoading) {
|
|
@@ -161,20 +160,18 @@ class FilterFormDialogHostComponent {
|
|
|
161
160
|
{{ data.i18n?.apply || 'Aplicar' }}
|
|
162
161
|
</button>
|
|
163
162
|
</mat-dialog-actions>
|
|
164
|
-
`, isInline: true, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--mdc-dialog-subhead-color, var(--md-sys-color-on-surface))}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant))}.pfx-dialog-loading{display:flex;flex-direction:column;gap:10px;min-height:128px;justify-content:center;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant));font-size:.875rem}.pfx-form-pending{height:0;overflow:hidden;visibility:hidden;pointer-events:none}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}.pfx-save-shortcut-button{margin-right:auto}.pfx-save-shortcut-button mat-icon{margin-right:6px;width:18px;height:18px;font-size:18px}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "
|
|
163
|
+
`, isInline: true, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--mdc-dialog-subhead-color, var(--md-sys-color-on-surface))}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant))}.pfx-dialog-loading{display:flex;flex-direction:column;gap:10px;min-height:128px;justify-content:center;color:var(--mdc-dialog-supporting-text-color, var(--md-sys-color-on-surface-variant));font-size:.875rem}.pfx-form-pending{height:0;overflow:hidden;visibility:hidden;pointer-events:none}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}.pfx-save-shortcut-button{margin-right:auto}.pfx-save-shortcut-button mat-icon{margin-right:6px;width:18px;height:18px;font-size:18px}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i13.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i14.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "requestSearch", "validityChange"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }] });
|
|
165
164
|
}
|
|
166
165
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: FilterFormDialogHostComponent, decorators: [{
|
|
167
166
|
type: Component,
|
|
168
|
-
args: [{ selector: 'praxis-filter-form-dialog-host', standalone: true, imports: [MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, MatTooltipModule, PraxisFilterForm], template: `
|
|
167
|
+
args: [{ selector: 'praxis-filter-form-dialog-host', standalone: true, imports: [MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, MatTooltipModule, PraxisFilterForm, PraxisIconButtonComponent], template: `
|
|
169
168
|
<div mat-dialog-title class="pfx-dialog-title" id="filterDialogTitle">
|
|
170
169
|
<div class="pfx-dialog-title-text">
|
|
171
170
|
<mat-icon>tune</mat-icon>
|
|
172
171
|
<span>{{ data.title || 'Filtro avançado' }}</span>
|
|
173
172
|
</div>
|
|
174
|
-
<button
|
|
175
|
-
[attr.aria-label]="data.i18n?.cancel || 'Fechar'">
|
|
176
|
-
<mat-icon>close</mat-icon>
|
|
177
|
-
</button>
|
|
173
|
+
<button praxisIconButton="close" size="compact" type="button" class="pfx-dialog-close" (click)="close()"
|
|
174
|
+
[attr.aria-label]="data.i18n?.cancel || 'Fechar'"></button>
|
|
178
175
|
</div>
|
|
179
176
|
<mat-dialog-content class="pfx-filter-dialog-content" aria-labelledby="filterDialogTitle">
|
|
180
177
|
@if (data?.schemaLoading) {
|