@oondemand/create-central-oon 0.3.11 → 0.3.14
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/docs/ADVANCED_UX_PATTERNS.md +195 -0
- package/docs/CODEX.md +35 -2
- package/docs/DETAIL_MODAL_AND_RELATED_GRIDS.md +525 -0
- package/docs/FRONTEND_MANIFEST_REFERENCE.md +214 -459
- package/docs/FRONTEND_PATTERNS.md +79 -5
- package/package.json +1 -1
- package/templates/_base/backend/package.json +1 -1
- package/templates/_base/frontend/package.json +1 -1
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Este documento é a referência operacional para o Codex criar ou alterar manifestos do frontend OonCore.
|
|
4
4
|
|
|
5
|
-
Use este arquivo junto com `FRONTEND_PATTERNS.md`. O arquivo de padrões explica como pensar a UI; este arquivo lista as opções do contrato atual.
|
|
5
|
+
Use este arquivo junto com `FRONTEND_PATTERNS.md`. O arquivo de padrões explica como pensar a UI; este arquivo lista as opções do contrato atual e das extensões planejadas para UX avançada.
|
|
6
|
+
|
|
7
|
+
Para modal com abas, grids relacionados editáveis e ações por linha, leia também:
|
|
8
|
+
|
|
9
|
+
- `ADVANCED_UX_PATTERNS.md`
|
|
10
|
+
- `DETAIL_MODAL_AND_RELATED_GRIDS.md`
|
|
6
11
|
|
|
7
12
|
## Arquivos envolvidos
|
|
8
13
|
|
|
@@ -40,8 +45,9 @@ Para Codex, a ordem recomendada é:
|
|
|
40
45
|
|
|
41
46
|
1. Começar pelo `central.ui.json`.
|
|
42
47
|
2. Usar `pages` e `blocks` quando precisar de UI v2.
|
|
43
|
-
3. Usar
|
|
44
|
-
4.
|
|
48
|
+
3. Usar `collections[].list`, `collections[].detailModal`, `form.groups`, `relations` e `relatedGrid` para UX operacional avançada.
|
|
49
|
+
4. Usar registry/overrides em TypeScript quando precisar de componentes customizados.
|
|
50
|
+
5. Evitar recriar shell, rotas, menu, grid, cards ou formulários manualmente.
|
|
45
51
|
|
|
46
52
|
## CentralUiManifest
|
|
47
53
|
|
|
@@ -57,13 +63,7 @@ interface CentralUiManifest {
|
|
|
57
63
|
registry?: OonComponentRegistry;
|
|
58
64
|
navigation?: OonNavigationConfig;
|
|
59
65
|
pages?: OonPageDef[];
|
|
60
|
-
collections?:
|
|
61
|
-
model: string;
|
|
62
|
-
mode?: CollectionMode;
|
|
63
|
-
path?: string;
|
|
64
|
-
label?: string;
|
|
65
|
-
section?: string;
|
|
66
|
-
}>;
|
|
66
|
+
collections?: OonCollectionManifestDef[];
|
|
67
67
|
pipelines?: Array<{
|
|
68
68
|
name?: string;
|
|
69
69
|
model?: string;
|
|
@@ -85,7 +85,7 @@ interface CentralUiManifest {
|
|
|
85
85
|
}
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
## Opções de raiz
|
|
89
89
|
|
|
90
90
|
| Campo | Tipo | Uso |
|
|
91
91
|
| --- | --- | --- |
|
|
@@ -96,7 +96,7 @@ interface CentralUiManifest {
|
|
|
96
96
|
| `layout` | `OonLayoutConfig` | Shell, sidebar, topbar, header, footer e slots. |
|
|
97
97
|
| `navigation` | `OonNavigationConfig` | Modo do menu e itens manuais. |
|
|
98
98
|
| `pages` | `OonPageDef[]` | Páginas por blocos da UI v2. |
|
|
99
|
-
| `collections` | `Array` |
|
|
99
|
+
| `collections` | `Array` | Views de coleção, simples ou avançadas. |
|
|
100
100
|
| `pipelines` | `Array` | Atalho para gerar esteiras. |
|
|
101
101
|
| `documents` | `Array` | Atalho para gerar documentos. |
|
|
102
102
|
|
|
@@ -125,34 +125,6 @@ interface OonLayoutConfig {
|
|
|
125
125
|
| `content-only` | Experiência focada em conteúdo. |
|
|
126
126
|
| `custom:<key>` | Shell registrado em `registry.layoutSlots`. |
|
|
127
127
|
|
|
128
|
-
### Slots
|
|
129
|
-
|
|
130
|
-
| Campo | Valores | Uso |
|
|
131
|
-
| --- | --- | --- |
|
|
132
|
-
| `sidebar` | `core`, `none`, `custom:<key>` | Menu lateral. |
|
|
133
|
-
| `topbar` | `core`, `none`, `custom:<key>` | Barra superior. |
|
|
134
|
-
| `header` | `none`, `custom:<key>` | Header custom acima da página. |
|
|
135
|
-
| `footer` | `core`, `none`, `custom:<key>` | Rodapé. |
|
|
136
|
-
| `assistant` | `core`, `none`, `custom:<key>` | Assistente/copiloto, quando suportado. |
|
|
137
|
-
| `main` | `core` | Área principal do Core. |
|
|
138
|
-
|
|
139
|
-
### Exemplo
|
|
140
|
-
|
|
141
|
-
```json
|
|
142
|
-
{
|
|
143
|
-
"schemaVersion": 2,
|
|
144
|
-
"name": "Meus Apps",
|
|
145
|
-
"slug": "meus-apps",
|
|
146
|
-
"layout": {
|
|
147
|
-
"shell": "portal",
|
|
148
|
-
"sidebar": "none",
|
|
149
|
-
"topbar": "none",
|
|
150
|
-
"header": "custom:MeusAppsHeader",
|
|
151
|
-
"footer": "core"
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
128
|
## Navigation
|
|
157
129
|
|
|
158
130
|
```ts
|
|
@@ -164,52 +136,24 @@ interface OonNavigationConfig {
|
|
|
164
136
|
}
|
|
165
137
|
```
|
|
166
138
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
| Valor | Comportamento |
|
|
170
|
-
| --- | --- |
|
|
171
|
-
| `auto` | Core gera menu a partir de coleções, documentos, esteiras, dashboards e páginas. |
|
|
172
|
-
| `manual` | Usa apenas `navigation.items`. |
|
|
173
|
-
| `mixed` | Combina menu automático com itens manuais. |
|
|
139
|
+
## Collections no central.ui.json
|
|
174
140
|
|
|
175
|
-
|
|
141
|
+
Atalho para coleções simples ou avançadas.
|
|
176
142
|
|
|
177
143
|
```ts
|
|
178
|
-
interface
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
144
|
+
interface OonCollectionManifestDef {
|
|
145
|
+
model: string;
|
|
146
|
+
mode?: "full" | "minimal" | "dynamic";
|
|
147
|
+
path?: string;
|
|
148
|
+
label?: string;
|
|
182
149
|
section?: string;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
badge?: string | number;
|
|
187
|
-
external?: boolean;
|
|
188
|
-
hidden?: boolean;
|
|
189
|
-
action?: string;
|
|
190
|
-
renderer?: string;
|
|
150
|
+
list?: OonCollectionListConfig;
|
|
151
|
+
relations?: Record<string, OonRelationDef>;
|
|
152
|
+
detailModal?: OonDetailModalConfig;
|
|
191
153
|
}
|
|
192
154
|
```
|
|
193
155
|
|
|
194
|
-
###
|
|
195
|
-
|
|
196
|
-
| Campo | Uso |
|
|
197
|
-
| --- | --- |
|
|
198
|
-
| `label` | Texto do menu. |
|
|
199
|
-
| `href` | Rota interna ou URL. |
|
|
200
|
-
| `section` | Agrupamento visual. |
|
|
201
|
-
| `order` | Ordenação. |
|
|
202
|
-
| `permissions` | Permissões exigidas. |
|
|
203
|
-
| `children` | Subitens. |
|
|
204
|
-
| `badge` | Indicador simples. |
|
|
205
|
-
| `external` | Link externo. |
|
|
206
|
-
| `hidden` | Oculta item sem remover do manifesto. |
|
|
207
|
-
| `action` | Chave de ação. |
|
|
208
|
-
| `renderer` | Renderer customizado em `registry.menuRenderers`. |
|
|
209
|
-
|
|
210
|
-
## Collections no central.ui.json
|
|
211
|
-
|
|
212
|
-
Atalho simples para coleções.
|
|
156
|
+
### Exemplo simples
|
|
213
157
|
|
|
214
158
|
```json
|
|
215
159
|
{
|
|
@@ -225,467 +169,278 @@ Atalho simples para coleções.
|
|
|
225
169
|
}
|
|
226
170
|
```
|
|
227
171
|
|
|
228
|
-
###
|
|
229
|
-
|
|
230
|
-
| Campo | Tipo | Uso |
|
|
231
|
-
| --- | --- | --- |
|
|
232
|
-
| `model` | `string` | Model do backend. |
|
|
233
|
-
| `mode` | `full`, `minimal`, `dynamic` | Modo de renderização. |
|
|
234
|
-
| `path` | `string` | Rota. |
|
|
235
|
-
| `label` | `string` | Nome no menu/tela. |
|
|
236
|
-
| `section` | `string` | Grupo do menu. |
|
|
237
|
-
|
|
238
|
-
## CollectionViewDef completo
|
|
239
|
-
|
|
240
|
-
Contrato interno completo quando a coleção já está em `ui.views` ou em blocos.
|
|
172
|
+
### Exemplo avançado
|
|
241
173
|
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"collections": [
|
|
177
|
+
{
|
|
178
|
+
"model": "OrcamentoProjeto",
|
|
179
|
+
"mode": "dynamic",
|
|
180
|
+
"path": "/orcamentos-projetos",
|
|
181
|
+
"label": "Orçamentos/Projetos",
|
|
182
|
+
"section": "Operação",
|
|
183
|
+
"list": {
|
|
184
|
+
"filters": [
|
|
185
|
+
{
|
|
186
|
+
"field": "tipoRegistro",
|
|
187
|
+
"label": "Tipo",
|
|
188
|
+
"type": "select",
|
|
189
|
+
"options": [
|
|
190
|
+
{ "label": "Todos", "value": "" },
|
|
191
|
+
{ "label": "Orçamento", "value": "Orçamento" },
|
|
192
|
+
{ "label": "Projeto", "value": "Projeto" }
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
"rowActions": [
|
|
197
|
+
{ "type": "openDetailModal", "icon": "edit", "label": "Editar", "initialTab": "resumo" }
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"relations": {
|
|
201
|
+
"itens": { "model": "OrcamentoItem", "foreignKey": "projetoId", "parentKey": "_id" },
|
|
202
|
+
"pagamentos": { "model": "Pagamento", "foreignKey": "projetoId", "parentKey": "_id" }
|
|
203
|
+
},
|
|
204
|
+
"detailModal": {
|
|
205
|
+
"enabled": true,
|
|
206
|
+
"titleField": "nome",
|
|
207
|
+
"defaultTab": "resumo",
|
|
208
|
+
"tabs": []
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
]
|
|
273
212
|
}
|
|
274
213
|
```
|
|
275
214
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
```ts
|
|
279
|
-
interface OonFormFieldDef {
|
|
280
|
-
field: string;
|
|
281
|
-
label?: string;
|
|
282
|
-
kind?: FieldKind;
|
|
283
|
-
required?: boolean;
|
|
284
|
-
options?: string[];
|
|
285
|
-
ref?: string;
|
|
286
|
-
renderer?: string;
|
|
287
|
-
permissions?: string[];
|
|
288
|
-
}
|
|
289
|
-
```
|
|
215
|
+
## list
|
|
290
216
|
|
|
291
|
-
|
|
217
|
+
Configura filtros, colunas e ações do grid principal.
|
|
292
218
|
|
|
293
219
|
```ts
|
|
294
|
-
interface
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
permissions?: string[];
|
|
299
|
-
action?: string;
|
|
220
|
+
interface OonCollectionListConfig {
|
|
221
|
+
filters?: OonListFilterDef[];
|
|
222
|
+
columns?: Array<string | OonColumnDef>;
|
|
223
|
+
rowActions?: OonRowActionDef[];
|
|
300
224
|
}
|
|
301
225
|
```
|
|
302
226
|
|
|
303
|
-
|
|
227
|
+
### list.filters
|
|
304
228
|
|
|
305
229
|
```json
|
|
306
230
|
{
|
|
307
|
-
"
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"approval": true,
|
|
314
|
-
"attachments": true
|
|
315
|
-
}
|
|
231
|
+
"field": "tipoRegistro",
|
|
232
|
+
"label": "Tipo",
|
|
233
|
+
"type": "select",
|
|
234
|
+
"options": [
|
|
235
|
+
{ "label": "Todos", "value": "" },
|
|
236
|
+
{ "label": "Orçamento", "value": "Orçamento" }
|
|
316
237
|
]
|
|
317
238
|
}
|
|
318
239
|
```
|
|
319
240
|
|
|
320
|
-
|
|
241
|
+
Tipos previstos:
|
|
321
242
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
| `approval` | Habilita comportamento de aprovação. |
|
|
330
|
-
| `attachments` | Habilita anexos. |
|
|
243
|
+
- `text`
|
|
244
|
+
- `select`
|
|
245
|
+
- `date`
|
|
246
|
+
- `dateRange`
|
|
247
|
+
- `numberRange`
|
|
248
|
+
- `boolean`
|
|
249
|
+
- `ref`
|
|
331
250
|
|
|
332
|
-
|
|
251
|
+
### list.rowActions
|
|
333
252
|
|
|
334
253
|
```json
|
|
335
254
|
{
|
|
336
|
-
"
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
"path": "/pedidos/esteira",
|
|
341
|
-
"label": "Esteira de Pedidos",
|
|
342
|
-
"section": "Operação"
|
|
343
|
-
}
|
|
344
|
-
]
|
|
255
|
+
"type": "openDetailModal",
|
|
256
|
+
"label": "Editar",
|
|
257
|
+
"icon": "edit",
|
|
258
|
+
"initialTab": "resumo"
|
|
345
259
|
}
|
|
346
260
|
```
|
|
347
261
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
| Campo | Uso |
|
|
351
|
-
| --- | --- |
|
|
352
|
-
| `name` | Nome alternativo usado como model quando `model` não for informado. |
|
|
353
|
-
| `model` | Model dos cards/tickets. |
|
|
354
|
-
| `mode` | Modo futuro/reservado. |
|
|
355
|
-
| `stageField` | Campo que define a coluna/etapa. |
|
|
356
|
-
| `path` | Rota. |
|
|
357
|
-
| `label` | Nome exibido. |
|
|
358
|
-
| `section` | Grupo do menu. |
|
|
359
|
-
|
|
360
|
-
## PipelineViewDef completo
|
|
262
|
+
## relations
|
|
361
263
|
|
|
362
|
-
|
|
363
|
-
interface PipelineViewDef {
|
|
364
|
-
type: "pipeline";
|
|
365
|
-
id?: string;
|
|
366
|
-
model: string;
|
|
367
|
-
label?: string;
|
|
368
|
-
path?: string;
|
|
369
|
-
icon?: ReactNode;
|
|
370
|
-
section?: string;
|
|
371
|
-
stageField?: string;
|
|
372
|
-
stages?: Array<{ id: string; label: string }>;
|
|
373
|
-
permissions?: string[];
|
|
374
|
-
}
|
|
375
|
-
```
|
|
264
|
+
Relações nomeadas entre model pai e models filhos.
|
|
376
265
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
icon?: ReactNode;
|
|
387
|
-
section?: string;
|
|
388
|
-
approval?: boolean;
|
|
389
|
-
attachments?: boolean;
|
|
390
|
-
permissions?: string[];
|
|
391
|
-
}
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
## DashboardViewDef
|
|
395
|
-
|
|
396
|
-
```ts
|
|
397
|
-
interface DashboardViewDef {
|
|
398
|
-
type: "dashboard";
|
|
399
|
-
id?: string;
|
|
400
|
-
label?: string;
|
|
401
|
-
path?: string;
|
|
402
|
-
icon?: ReactNode;
|
|
403
|
-
section?: string;
|
|
404
|
-
widgets?: DashboardWidgetDef[];
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
interface DashboardWidgetDef {
|
|
408
|
-
id: string;
|
|
409
|
-
label: string;
|
|
410
|
-
model?: string;
|
|
411
|
-
kind?: "count" | "sum" | "custom";
|
|
412
|
-
field?: string;
|
|
413
|
-
render?: () => ReactNode;
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"relations": {
|
|
269
|
+
"itens": {
|
|
270
|
+
"model": "OrcamentoItem",
|
|
271
|
+
"foreignKey": "projetoId",
|
|
272
|
+
"parentKey": "_id"
|
|
273
|
+
}
|
|
274
|
+
}
|
|
414
275
|
}
|
|
415
276
|
```
|
|
416
277
|
|
|
417
|
-
|
|
278
|
+
## detailModal
|
|
418
279
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
Páginas permitem compor rotas por blocos.
|
|
280
|
+
Configura modal de detalhe/criação com abas.
|
|
422
281
|
|
|
423
282
|
```ts
|
|
424
|
-
interface
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
icon?: ReactNode;
|
|
431
|
-
layout?: "default" | "content-only" | "portal";
|
|
432
|
-
blocks?: OonBlockDef[];
|
|
433
|
-
component?: string;
|
|
434
|
-
permissions?: string[];
|
|
435
|
-
hidden?: boolean;
|
|
436
|
-
order?: number;
|
|
283
|
+
interface OonDetailModalConfig {
|
|
284
|
+
enabled?: boolean;
|
|
285
|
+
titleField?: string;
|
|
286
|
+
size?: "md" | "lg" | "xl" | "full";
|
|
287
|
+
defaultTab?: string;
|
|
288
|
+
tabs: OonDetailTabDef[];
|
|
437
289
|
}
|
|
438
290
|
```
|
|
439
291
|
|
|
440
|
-
###
|
|
292
|
+
### Abas suportadas
|
|
441
293
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
| `title` | Título da página. |
|
|
448
|
-
| `section` | Grupo do menu. |
|
|
449
|
-
| `layout` | Layout da página. |
|
|
450
|
-
| `blocks` | Blocos renderizados. |
|
|
451
|
-
| `component` | Componente custom em `registry.pageComponents`. |
|
|
452
|
-
| `permissions` | Permissões da página. |
|
|
453
|
-
| `hidden` | Oculta do menu. |
|
|
454
|
-
| `order` | Ordenação no menu. |
|
|
455
|
-
|
|
456
|
-
## Blocks UI v2
|
|
457
|
-
|
|
458
|
-
Tipos atuais:
|
|
459
|
-
|
|
460
|
-
```ts
|
|
461
|
-
type OonBlockDef =
|
|
462
|
-
| OonCustomBlockDef
|
|
463
|
-
| OonCollectionDataGridBlockDef
|
|
464
|
-
| OonCollectionCardsBlockDef
|
|
465
|
-
| OonSectionBlockDef
|
|
466
|
-
| OonMarkdownBlockDef
|
|
467
|
-
| OonGenericBlockDef;
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
### Campos comuns
|
|
471
|
-
|
|
472
|
-
```ts
|
|
473
|
-
interface OonBaseBlockDef {
|
|
474
|
-
id?: string;
|
|
475
|
-
title?: string;
|
|
476
|
-
permissions?: string[];
|
|
477
|
-
hidden?: boolean;
|
|
478
|
-
}
|
|
479
|
-
```
|
|
294
|
+
- `summary`
|
|
295
|
+
- `form`
|
|
296
|
+
- `relatedGrid`
|
|
297
|
+
- `readonlyGrid`
|
|
298
|
+
- `customComponent`
|
|
480
299
|
|
|
481
|
-
###
|
|
300
|
+
### Aba summary
|
|
482
301
|
|
|
483
302
|
```json
|
|
484
303
|
{
|
|
485
|
-
"
|
|
486
|
-
"
|
|
487
|
-
"
|
|
488
|
-
|
|
489
|
-
|
|
304
|
+
"id": "resumo",
|
|
305
|
+
"label": "Resumo",
|
|
306
|
+
"type": "summary",
|
|
307
|
+
"cards": [
|
|
308
|
+
{ "label": "Itens", "source": "relatedCount", "relation": "itens" },
|
|
309
|
+
{ "label": "Total", "field": "total", "format": "currency" }
|
|
310
|
+
]
|
|
490
311
|
}
|
|
491
312
|
```
|
|
492
313
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
### collection.datagrid
|
|
314
|
+
### Aba form
|
|
496
315
|
|
|
497
316
|
```json
|
|
498
317
|
{
|
|
499
|
-
"
|
|
500
|
-
"
|
|
501
|
-
"
|
|
502
|
-
"
|
|
318
|
+
"id": "dados",
|
|
319
|
+
"label": "Dados Principais",
|
|
320
|
+
"type": "form",
|
|
321
|
+
"groups": [
|
|
322
|
+
{ "label": "Identificação", "fields": ["codigo", "nome", "status"] }
|
|
323
|
+
]
|
|
503
324
|
}
|
|
504
325
|
```
|
|
505
326
|
|
|
506
|
-
|
|
327
|
+
### Aba relatedGrid
|
|
507
328
|
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"id": "itens",
|
|
332
|
+
"label": "Itens",
|
|
333
|
+
"type": "relatedGrid",
|
|
334
|
+
"relation": "itens",
|
|
335
|
+
"editable": true,
|
|
336
|
+
"editMode": "inline",
|
|
337
|
+
"columns": [
|
|
338
|
+
{ "field": "item", "editable": true },
|
|
339
|
+
{ "field": "status", "editable": true },
|
|
340
|
+
{ "field": "total", "editable": true, "format": "currency" }
|
|
341
|
+
],
|
|
342
|
+
"rowActions": []
|
|
516
343
|
}
|
|
517
344
|
```
|
|
518
345
|
|
|
519
|
-
###
|
|
346
|
+
### Aba readonlyGrid
|
|
520
347
|
|
|
521
348
|
```json
|
|
522
349
|
{
|
|
523
|
-
"
|
|
524
|
-
"
|
|
525
|
-
"
|
|
350
|
+
"id": "pagamentos",
|
|
351
|
+
"label": "Pagamentos",
|
|
352
|
+
"type": "readonlyGrid",
|
|
353
|
+
"relation": "pagamentos",
|
|
354
|
+
"columns": ["codigo", "descricao", "status", "valor"]
|
|
526
355
|
}
|
|
527
356
|
```
|
|
528
357
|
|
|
529
|
-
|
|
358
|
+
## rowActions
|
|
530
359
|
|
|
531
|
-
|
|
360
|
+
Ações reutilizáveis em grid principal ou grids relacionados.
|
|
532
361
|
|
|
533
|
-
```
|
|
534
|
-
{
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
"
|
|
539
|
-
|
|
540
|
-
|
|
362
|
+
```ts
|
|
363
|
+
interface OonRowActionDef {
|
|
364
|
+
id?: string;
|
|
365
|
+
label: string;
|
|
366
|
+
icon?: string;
|
|
367
|
+
type: "openDetailModal" | "navigate" | "apiAction" | "customAction";
|
|
368
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
369
|
+
endpoint?: string;
|
|
370
|
+
initialTab?: string;
|
|
371
|
+
confirm?: { title?: string; description?: string };
|
|
372
|
+
disabledWhen?: OonConditionDef;
|
|
373
|
+
hiddenWhen?: OonConditionDef;
|
|
374
|
+
refresh?: string[];
|
|
375
|
+
roles?: string[];
|
|
376
|
+
permissions?: string[];
|
|
541
377
|
}
|
|
542
378
|
```
|
|
543
379
|
|
|
544
|
-
###
|
|
380
|
+
### apiAction
|
|
545
381
|
|
|
546
382
|
```json
|
|
547
383
|
{
|
|
548
|
-
"
|
|
549
|
-
"
|
|
384
|
+
"id": "gerarPagamento",
|
|
385
|
+
"label": "Gerar pagamento",
|
|
386
|
+
"type": "apiAction",
|
|
387
|
+
"method": "POST",
|
|
388
|
+
"endpoint": "/api/ss-eventos/orcamentos-itens/:id/gerar-pagamento",
|
|
389
|
+
"disabledWhen": { "field": "pagamentoId", "exists": true },
|
|
390
|
+
"refresh": ["self", "pagamentos", "resumo", "parent"]
|
|
550
391
|
}
|
|
551
392
|
```
|
|
552
393
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
O contrato já reserva:
|
|
556
|
-
|
|
557
|
-
```txt
|
|
558
|
-
collection.form
|
|
559
|
-
pipeline.board
|
|
560
|
-
document.viewer
|
|
561
|
-
dashboard.kpi
|
|
562
|
-
tabs
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
Esses blocos podem ser usados como contrato futuro, mas confirme suporte visual antes de depender deles em produção.
|
|
394
|
+
## CollectionViewDef completo
|
|
566
395
|
|
|
567
|
-
|
|
396
|
+
Contrato interno completo quando a coleção já está em `ui.views` ou em blocos.
|
|
568
397
|
|
|
569
398
|
```ts
|
|
570
|
-
interface
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
| `actions.ativarApp` | `actionRenderers` |
|
|
590
|
-
| `menus.portal` | `menuRenderers` |
|
|
591
|
-
|
|
592
|
-
## Exemplo v1 simples
|
|
593
|
-
|
|
594
|
-
```json
|
|
595
|
-
{
|
|
596
|
-
"name": "Central SS Eventos",
|
|
597
|
-
"slug": "central-ss-eventos",
|
|
598
|
-
"navigation": { "mode": "auto" },
|
|
599
|
-
"collections": [
|
|
600
|
-
{ "model": "Orcamento", "label": "Orçamentos", "section": "Operação" },
|
|
601
|
-
{ "model": "Prestador", "label": "Prestadores", "section": "Cadastros" }
|
|
602
|
-
],
|
|
603
|
-
"pipelines": [
|
|
604
|
-
{ "model": "Pagamento", "stageField": "status", "label": "Esteira de Pagamentos" }
|
|
605
|
-
],
|
|
606
|
-
"documents": [
|
|
607
|
-
{ "model": "DocumentoFiscal", "label": "Documentos Fiscais", "approval": true, "attachments": true }
|
|
608
|
-
]
|
|
399
|
+
interface CollectionViewDef {
|
|
400
|
+
type: "collection";
|
|
401
|
+
id?: string;
|
|
402
|
+
model: string;
|
|
403
|
+
label?: string;
|
|
404
|
+
path?: string;
|
|
405
|
+
icon?: ReactNode;
|
|
406
|
+
section?: string;
|
|
407
|
+
mode?: "full" | "minimal" | "dynamic";
|
|
408
|
+
columns?: OonColumnDef[];
|
|
409
|
+
form?: OonFormFieldDef[];
|
|
410
|
+
importExport?: boolean;
|
|
411
|
+
renderer?: string;
|
|
412
|
+
cardRenderer?: string;
|
|
413
|
+
actions?: OonActionDef[];
|
|
414
|
+
permissions?: string[];
|
|
415
|
+
list?: OonCollectionListConfig;
|
|
416
|
+
relations?: Record<string, OonRelationDef>;
|
|
417
|
+
detailModal?: OonDetailModalConfig;
|
|
609
418
|
}
|
|
610
419
|
```
|
|
611
420
|
|
|
612
|
-
##
|
|
421
|
+
## Compatibilidade
|
|
613
422
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
"slug": "meus-apps",
|
|
619
|
-
"layout": {
|
|
620
|
-
"shell": "portal",
|
|
621
|
-
"sidebar": "none",
|
|
622
|
-
"topbar": "none",
|
|
623
|
-
"header": "custom:MeusAppsHeader",
|
|
624
|
-
"footer": "core"
|
|
625
|
-
},
|
|
626
|
-
"navigation": { "mode": "mixed" },
|
|
627
|
-
"pages": [
|
|
628
|
-
{
|
|
629
|
-
"path": "/",
|
|
630
|
-
"label": "Meus Apps",
|
|
631
|
-
"layout": "content-only",
|
|
632
|
-
"blocks": [
|
|
633
|
-
{ "type": "custom", "component": "MeusAppsHero" },
|
|
634
|
-
{ "type": "collection.cards", "model": "App", "renderer": "cards.appLauncher" }
|
|
635
|
-
]
|
|
636
|
-
},
|
|
637
|
-
{
|
|
638
|
-
"path": "/admin/apps",
|
|
639
|
-
"label": "Apps",
|
|
640
|
-
"section": "Administração",
|
|
641
|
-
"blocks": [
|
|
642
|
-
{ "type": "collection.datagrid", "model": "App", "mode": "dynamic" }
|
|
643
|
-
]
|
|
644
|
-
}
|
|
645
|
-
]
|
|
646
|
-
}
|
|
647
|
-
```
|
|
423
|
+
- Os campos `list`, `relations` e `detailModal` são opcionais.
|
|
424
|
+
- Manifestos existentes continuam funcionando.
|
|
425
|
+
- Sem `detailModal`, o Core mantém comportamento atual.
|
|
426
|
+
- Sem `form.groups`, o Core mantém formulário padrão.
|
|
648
427
|
|
|
649
|
-
##
|
|
650
|
-
|
|
651
|
-
```tsx
|
|
652
|
-
import manifest from "../central.ui.json";
|
|
653
|
-
import { manifestToConfig, start } from "@oondemand/oon-core-front";
|
|
654
|
-
import { MeusAppsHeader } from "./overrides/MeusAppsHeader";
|
|
655
|
-
import { AppLauncherCard } from "./overrides/AppLauncherCard";
|
|
656
|
-
|
|
657
|
-
const config = manifestToConfig(manifest, {
|
|
658
|
-
apiBaseUrl: import.meta.env.VITE_API_URL,
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
start({
|
|
662
|
-
...config,
|
|
663
|
-
registry: {
|
|
664
|
-
layoutSlots: {
|
|
665
|
-
MeusAppsHeader,
|
|
666
|
-
},
|
|
667
|
-
cardRenderers: {
|
|
668
|
-
"cards.appLauncher": AppLauncherCard,
|
|
669
|
-
appLauncher: AppLauncherCard,
|
|
670
|
-
},
|
|
671
|
-
},
|
|
672
|
-
});
|
|
673
|
-
```
|
|
428
|
+
## UX avançada implementada
|
|
674
429
|
|
|
675
|
-
|
|
430
|
+
Campos aceitos em `collections[]`:
|
|
676
431
|
|
|
677
|
-
-
|
|
678
|
-
-
|
|
679
|
-
- `
|
|
680
|
-
-
|
|
432
|
+
- `list.filters`: filtros acima do grid principal.
|
|
433
|
+
- `list.columns`: colunas declarativas opcionais.
|
|
434
|
+
- `list.rowActions`: ações por linha (`openDetailModal`, `navigate`, `apiAction`, `customAction`).
|
|
435
|
+
- `relations`: mapa de relações `{ model, foreignKey, parentKey }`.
|
|
436
|
+
- `detailModal`: modal genérica com `titleField`, `defaultTab`, `size` e `tabs`.
|
|
681
437
|
|
|
682
|
-
|
|
438
|
+
Tipos de aba:
|
|
683
439
|
|
|
684
|
-
|
|
440
|
+
- `summary`: cards com `field`, `relatedCount`, `relatedSum`, `relatedAvg` ou `customMetric`.
|
|
441
|
+
- `form`: campos ou `groups` do registro principal.
|
|
442
|
+
- `relatedGrid`: registros filhos, opcionalmente editáveis inline.
|
|
443
|
+
- `readonlyGrid`: registros filhos sem edição.
|
|
444
|
+
- `customComponent`: chave de componente registrado.
|
|
685
445
|
|
|
686
|
-
|
|
687
|
-
- O requisito cabe em `pages` + `blocks`?
|
|
688
|
-
- O requisito cabe em renderer registrado por chave?
|
|
689
|
-
- A permissão está declarada em página, bloco, menu ou backend?
|
|
690
|
-
- Não há componente React serializado no JSON?
|
|
691
|
-
- A Central continua funcionando com atualização do pacote Core?
|
|
446
|
+
`apiAction.endpoint` aceita `:id`, `:parentId`, `:fieldName` e `:parent.fieldName`. `refresh` aceita `self`, `parent`, `all` ou ids de abas.
|