@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
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
# DETAIL_MODAL_AND_RELATED_GRIDS.md — Modal com Abas e Grids Relacionados
|
|
2
|
+
|
|
3
|
+
Este documento define o contrato desejado para evoluir o `@oondemand/oon-core-front` com modal de detalhe, abas, grids relacionados, edição inline e ações por linha.
|
|
4
|
+
|
|
5
|
+
Status: **especificação para implementação**.
|
|
6
|
+
|
|
7
|
+
## 1. Motivação
|
|
8
|
+
|
|
9
|
+
Centrais operacionais frequentemente têm uma entidade principal com filhos operacionais.
|
|
10
|
+
|
|
11
|
+
Exemplos:
|
|
12
|
+
|
|
13
|
+
- Projeto -> Itens -> Pagamentos
|
|
14
|
+
- Pedido -> Produtos -> Expedições
|
|
15
|
+
- Contrato -> Parcelas -> Documentos
|
|
16
|
+
- Cliente -> Atividades -> Histórico
|
|
17
|
+
- Migração -> Registros -> Exceções
|
|
18
|
+
|
|
19
|
+
Hoje, esses casos tendem a virar páginas customizadas. O objetivo é abstrair o padrão no Core.
|
|
20
|
+
|
|
21
|
+
## 2. Resultado esperado
|
|
22
|
+
|
|
23
|
+
O manifesto deve ser capaz de declarar:
|
|
24
|
+
|
|
25
|
+
```txt
|
|
26
|
+
Grid principal da coleção
|
|
27
|
+
└── ação editar
|
|
28
|
+
└── modal com abas
|
|
29
|
+
├── Resumo
|
|
30
|
+
├── Dados Principais
|
|
31
|
+
├── Itens relacionados editáveis inline
|
|
32
|
+
└── Pagamentos/Histórico somente leitura
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 3. Extensão proposta do manifesto
|
|
36
|
+
|
|
37
|
+
### 3.1. Collections com list e detailModal
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"model": "OrcamentoProjeto",
|
|
42
|
+
"mode": "dynamic",
|
|
43
|
+
"path": "/orcamentos-projetos",
|
|
44
|
+
"label": "Orçamentos/Projetos",
|
|
45
|
+
"section": "Operação",
|
|
46
|
+
"list": {
|
|
47
|
+
"filters": [],
|
|
48
|
+
"columns": [],
|
|
49
|
+
"rowActions": []
|
|
50
|
+
},
|
|
51
|
+
"relations": {},
|
|
52
|
+
"detailModal": {
|
|
53
|
+
"enabled": true,
|
|
54
|
+
"titleField": "nome",
|
|
55
|
+
"size": "xl",
|
|
56
|
+
"defaultTab": "resumo",
|
|
57
|
+
"tabs": []
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3.2. list.filters
|
|
63
|
+
|
|
64
|
+
Filtros declarativos renderizados acima do grid.
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"field": "tipoRegistro",
|
|
69
|
+
"label": "Tipo",
|
|
70
|
+
"type": "select",
|
|
71
|
+
"options": [
|
|
72
|
+
{ "label": "Orçamentos e projetos", "value": "" },
|
|
73
|
+
{ "label": "Só orçamentos", "value": "Orçamento" },
|
|
74
|
+
{ "label": "Só projetos", "value": "Projeto" }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Tipos iniciais:
|
|
80
|
+
|
|
81
|
+
- `text`
|
|
82
|
+
- `select`
|
|
83
|
+
- `date`
|
|
84
|
+
- `dateRange`
|
|
85
|
+
- `numberRange`
|
|
86
|
+
- `boolean`
|
|
87
|
+
- `ref`
|
|
88
|
+
|
|
89
|
+
### 3.3. list.rowActions
|
|
90
|
+
|
|
91
|
+
Ações no grid principal.
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"type": "openDetailModal",
|
|
96
|
+
"label": "Editar",
|
|
97
|
+
"icon": "edit",
|
|
98
|
+
"initialTab": "resumo"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Tipos iniciais:
|
|
103
|
+
|
|
104
|
+
- `openDetailModal`
|
|
105
|
+
- `navigate`
|
|
106
|
+
- `apiAction`
|
|
107
|
+
- `customAction`
|
|
108
|
+
|
|
109
|
+
### 3.4. relations
|
|
110
|
+
|
|
111
|
+
Relações nomeadas reutilizáveis por abas, filtros e ações.
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"relations": {
|
|
116
|
+
"itens": {
|
|
117
|
+
"model": "OrcamentoItem",
|
|
118
|
+
"foreignKey": "projetoId",
|
|
119
|
+
"parentKey": "_id"
|
|
120
|
+
},
|
|
121
|
+
"pagamentos": {
|
|
122
|
+
"model": "Pagamento",
|
|
123
|
+
"foreignKey": "projetoId",
|
|
124
|
+
"parentKey": "_id"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 4. Abas suportadas
|
|
131
|
+
|
|
132
|
+
### 4.1. summary
|
|
133
|
+
|
|
134
|
+
Cards de resumo.
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"id": "resumo",
|
|
139
|
+
"label": "Resumo",
|
|
140
|
+
"type": "summary",
|
|
141
|
+
"cards": [
|
|
142
|
+
{ "label": "Itens", "source": "relatedCount", "relation": "itens" },
|
|
143
|
+
{ "label": "Total PARA", "field": "totalParaComImpostos", "format": "currency" }
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Fontes:
|
|
149
|
+
|
|
150
|
+
- `field`
|
|
151
|
+
- `relatedCount`
|
|
152
|
+
- `relatedSum`
|
|
153
|
+
- `relatedAvg`
|
|
154
|
+
- `customMetric`
|
|
155
|
+
|
|
156
|
+
Formatos:
|
|
157
|
+
|
|
158
|
+
- `text`
|
|
159
|
+
- `number`
|
|
160
|
+
- `currency`
|
|
161
|
+
- `percent`
|
|
162
|
+
- `date`
|
|
163
|
+
- `badge`
|
|
164
|
+
|
|
165
|
+
### 4.2. form
|
|
166
|
+
|
|
167
|
+
Formulário do registro principal.
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"id": "dados",
|
|
172
|
+
"label": "Dados Principais",
|
|
173
|
+
"type": "form",
|
|
174
|
+
"groups": [
|
|
175
|
+
{
|
|
176
|
+
"label": "Identificação",
|
|
177
|
+
"fields": ["tipoRegistro", "codigo", "nome", "status"]
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 4.3. relatedGrid
|
|
184
|
+
|
|
185
|
+
Grid de filhos editável ou não.
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"id": "itens",
|
|
190
|
+
"label": "Itens",
|
|
191
|
+
"type": "relatedGrid",
|
|
192
|
+
"relation": "itens",
|
|
193
|
+
"editable": true,
|
|
194
|
+
"editMode": "inline",
|
|
195
|
+
"columns": [],
|
|
196
|
+
"rowActions": []
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 4.4. readonlyGrid
|
|
201
|
+
|
|
202
|
+
Grid relacionado somente leitura.
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"id": "pagamentos",
|
|
207
|
+
"label": "Pagamentos",
|
|
208
|
+
"type": "readonlyGrid",
|
|
209
|
+
"relation": "pagamentos",
|
|
210
|
+
"columns": ["codigo", "descricao", "statusEsteira", "valorFechamento"]
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 4.5. customComponent
|
|
215
|
+
|
|
216
|
+
Aba com componente customizado registrado por chave.
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"id": "analise",
|
|
221
|
+
"label": "Análise",
|
|
222
|
+
"type": "customComponent",
|
|
223
|
+
"component": "custom:AnaliseProjeto"
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 5. Colunas de relatedGrid
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"field": "totalParaComImpostos",
|
|
232
|
+
"label": "Total PARA",
|
|
233
|
+
"editable": true,
|
|
234
|
+
"format": "currency",
|
|
235
|
+
"width": 140
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Propriedades:
|
|
240
|
+
|
|
241
|
+
- `field`
|
|
242
|
+
- `label`
|
|
243
|
+
- `editable`
|
|
244
|
+
- `readonly`
|
|
245
|
+
- `format`
|
|
246
|
+
- `renderer`
|
|
247
|
+
- `editor`
|
|
248
|
+
- `width`
|
|
249
|
+
- `hidden`
|
|
250
|
+
- `roles`
|
|
251
|
+
- `required`
|
|
252
|
+
|
|
253
|
+
## 6. Edição inline
|
|
254
|
+
|
|
255
|
+
O grid editável deve manter alterações em estado local por linha.
|
|
256
|
+
|
|
257
|
+
Requisitos:
|
|
258
|
+
|
|
259
|
+
- célula editável conforme metadata do campo;
|
|
260
|
+
- linha marcada como alterada;
|
|
261
|
+
- botão `Salvar` por linha;
|
|
262
|
+
- botão `Cancelar` por linha;
|
|
263
|
+
- `PUT /:modelPath/:id` usando CRUD genérico;
|
|
264
|
+
- loading por linha;
|
|
265
|
+
- erro por linha;
|
|
266
|
+
- refresh pós-salvamento configurável.
|
|
267
|
+
|
|
268
|
+
## 7. Row actions
|
|
269
|
+
|
|
270
|
+
### 7.1. apiAction
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"id": "gerarPagamento",
|
|
275
|
+
"label": "Gerar pagamento",
|
|
276
|
+
"type": "apiAction",
|
|
277
|
+
"method": "POST",
|
|
278
|
+
"endpoint": "/api/ss-eventos/orcamentos-itens/:id/gerar-pagamento",
|
|
279
|
+
"confirm": {
|
|
280
|
+
"title": "Gerar pagamento?",
|
|
281
|
+
"description": "Será criado um ticket financeiro vinculado a este item."
|
|
282
|
+
},
|
|
283
|
+
"disabledWhen": {
|
|
284
|
+
"field": "pagamentoId",
|
|
285
|
+
"exists": true
|
|
286
|
+
},
|
|
287
|
+
"refresh": ["self", "pagamentos", "resumo", "parent"]
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### 7.2. Interpolação de endpoint
|
|
292
|
+
|
|
293
|
+
Suportar:
|
|
294
|
+
|
|
295
|
+
- `:id` -> `_id` da linha;
|
|
296
|
+
- `:parentId` -> `_id` do registro pai;
|
|
297
|
+
- `:fieldName` -> valor do campo na linha;
|
|
298
|
+
- `:parent.fieldName` -> valor do campo no pai.
|
|
299
|
+
|
|
300
|
+
### 7.3. disabledWhen
|
|
301
|
+
|
|
302
|
+
Operadores mínimos:
|
|
303
|
+
|
|
304
|
+
```json
|
|
305
|
+
{ "field": "pagamentoId", "exists": true }
|
|
306
|
+
{ "field": "status", "equals": "Cancelado" }
|
|
307
|
+
{ "field": "valor", "gt": 0 }
|
|
308
|
+
{ "field": "tipo", "in": ["A", "B"] }
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 7.4. refresh
|
|
312
|
+
|
|
313
|
+
Alvos:
|
|
314
|
+
|
|
315
|
+
- `self`: grid/aba atual;
|
|
316
|
+
- `parent`: registro principal;
|
|
317
|
+
- nome de aba: `pagamentos`, `resumo` etc.;
|
|
318
|
+
- `all`: todas as queries da modal.
|
|
319
|
+
|
|
320
|
+
## 8. RBAC
|
|
321
|
+
|
|
322
|
+
Cada nível pode ter `roles` ou `permissions`.
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"id": "gerarPagamento",
|
|
327
|
+
"roles": ["admin", "financeiro"]
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
A UI deve ocultar/desabilitar conforme permissão, mas a autoridade final continua no backend.
|
|
332
|
+
|
|
333
|
+
## 9. Componentes Core necessários
|
|
334
|
+
|
|
335
|
+
### CoreDetailModal
|
|
336
|
+
|
|
337
|
+
Responsável por:
|
|
338
|
+
|
|
339
|
+
- abrir detalhe/criação;
|
|
340
|
+
- buscar registro principal;
|
|
341
|
+
- controlar abas;
|
|
342
|
+
- salvar dados principais;
|
|
343
|
+
- orquestrar refresh;
|
|
344
|
+
- validar RBAC visual;
|
|
345
|
+
- renderizar erros.
|
|
346
|
+
|
|
347
|
+
### CoreTabbedDetail
|
|
348
|
+
|
|
349
|
+
Renderiza abas configuradas no manifesto.
|
|
350
|
+
|
|
351
|
+
### CoreRelatedGrid
|
|
352
|
+
|
|
353
|
+
Renderiza grid relacionado pelo `relation`.
|
|
354
|
+
|
|
355
|
+
### CoreInlineEditableCell
|
|
356
|
+
|
|
357
|
+
Renderiza o editor apropriado por tipo de campo.
|
|
358
|
+
|
|
359
|
+
### CoreRowAction
|
|
360
|
+
|
|
361
|
+
Executa ações declaradas por linha.
|
|
362
|
+
|
|
363
|
+
### CoreSummaryCards
|
|
364
|
+
|
|
365
|
+
Renderiza cards de resumo por fields e agregações relacionadas.
|
|
366
|
+
|
|
367
|
+
## 10. Compatibilidade
|
|
368
|
+
|
|
369
|
+
A implementação deve ser compatível com manifestos existentes.
|
|
370
|
+
|
|
371
|
+
- `collections[]` atual continua funcionando.
|
|
372
|
+
- `detailModal` é opcional.
|
|
373
|
+
- `list` é opcional.
|
|
374
|
+
- Sem `rowActions`, mantém ação padrão do Core.
|
|
375
|
+
- Sem `form.groups`, mantém formulário atual.
|
|
376
|
+
|
|
377
|
+
## 11. Critérios de aceite
|
|
378
|
+
|
|
379
|
+
- O manifesto consegue declarar a tela de Orçamentos/Projetos da SS Eventos sem página React customizada.
|
|
380
|
+
- A tela principal renderiza filtros, busca, grid e ação editar.
|
|
381
|
+
- A ação editar abre modal com abas.
|
|
382
|
+
- A aba Dados Principais salva o registro pai.
|
|
383
|
+
- A aba Itens carrega apenas filhos do pai selecionado.
|
|
384
|
+
- A aba Itens permite edição inline por linha.
|
|
385
|
+
- A aba Itens executa ação `Gerar pagamento` por linha.
|
|
386
|
+
- Após gerar pagamento, o item mostra badge de pagamento gerado.
|
|
387
|
+
- A aba Pagamentos recarrega automaticamente.
|
|
388
|
+
- A aba Resumo atualiza contadores/totais.
|
|
389
|
+
- RBAC visual respeita roles/permissions declaradas.
|
|
390
|
+
- Sem regressão em coleções simples.
|
|
391
|
+
|
|
392
|
+
## 12. Exemplo completo SS Eventos
|
|
393
|
+
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"model": "OrcamentoProjeto",
|
|
397
|
+
"mode": "dynamic",
|
|
398
|
+
"path": "/orcamentos-projetos",
|
|
399
|
+
"label": "Orçamentos/Projetos",
|
|
400
|
+
"section": "Operação",
|
|
401
|
+
"list": {
|
|
402
|
+
"filters": [
|
|
403
|
+
{
|
|
404
|
+
"field": "tipoRegistro",
|
|
405
|
+
"label": "Tipo",
|
|
406
|
+
"type": "select",
|
|
407
|
+
"options": [
|
|
408
|
+
{ "label": "Orçamentos e projetos", "value": "" },
|
|
409
|
+
{ "label": "Só orçamentos", "value": "Orçamento" },
|
|
410
|
+
{ "label": "Só projetos", "value": "Projeto" }
|
|
411
|
+
]
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"columns": ["tipoRegistro", "codigo", "nome", "cliente", "status", "totalItens", "totalParaComImpostos", "lucroTotalEvento"],
|
|
415
|
+
"rowActions": [
|
|
416
|
+
{ "type": "openDetailModal", "label": "Editar", "icon": "edit", "initialTab": "resumo" }
|
|
417
|
+
]
|
|
418
|
+
},
|
|
419
|
+
"relations": {
|
|
420
|
+
"itens": { "model": "OrcamentoItem", "foreignKey": "projetoId", "parentKey": "_id" },
|
|
421
|
+
"pagamentos": { "model": "Pagamento", "foreignKey": "projetoId", "parentKey": "_id" }
|
|
422
|
+
},
|
|
423
|
+
"detailModal": {
|
|
424
|
+
"enabled": true,
|
|
425
|
+
"titleField": "nome",
|
|
426
|
+
"defaultTab": "resumo",
|
|
427
|
+
"tabs": [
|
|
428
|
+
{
|
|
429
|
+
"id": "resumo",
|
|
430
|
+
"label": "Resumo",
|
|
431
|
+
"type": "summary",
|
|
432
|
+
"cards": [
|
|
433
|
+
{ "label": "Itens", "source": "relatedCount", "relation": "itens" },
|
|
434
|
+
{ "label": "Pagamentos", "source": "relatedCount", "relation": "pagamentos" },
|
|
435
|
+
{ "label": "Total PARA", "field": "totalParaComImpostos", "format": "currency" },
|
|
436
|
+
{ "label": "Lucro", "field": "lucroTotalEvento", "format": "currency" }
|
|
437
|
+
]
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"id": "dados",
|
|
441
|
+
"label": "Dados Principais",
|
|
442
|
+
"type": "form",
|
|
443
|
+
"groups": [
|
|
444
|
+
{ "label": "Identificação", "fields": ["tipoRegistro", "codigo", "nome", "status", "cliente"] },
|
|
445
|
+
{ "label": "Evento", "fields": ["dataEvento", "localEvento", "contato"] },
|
|
446
|
+
{ "label": "Totais", "fields": ["totalItens", "totalParaComImpostos", "lucroTotalEvento"] }
|
|
447
|
+
]
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"id": "itens",
|
|
451
|
+
"label": "Itens",
|
|
452
|
+
"type": "relatedGrid",
|
|
453
|
+
"relation": "itens",
|
|
454
|
+
"editable": true,
|
|
455
|
+
"editMode": "inline",
|
|
456
|
+
"columns": [
|
|
457
|
+
{ "field": "linhaPlanilha", "readonly": true },
|
|
458
|
+
{ "field": "categoria", "editable": true },
|
|
459
|
+
{ "field": "item", "editable": true },
|
|
460
|
+
{ "field": "fornecedorRazaoSocial", "editable": true },
|
|
461
|
+
{ "field": "status", "editable": true },
|
|
462
|
+
{ "field": "totalParaComImpostos", "editable": true, "format": "currency" },
|
|
463
|
+
{ "field": "formaPagamento", "editable": true },
|
|
464
|
+
{ "field": "pagamentoId", "label": "Pagamento", "readonly": true, "display": "badgeExists" }
|
|
465
|
+
],
|
|
466
|
+
"rowActions": [
|
|
467
|
+
{
|
|
468
|
+
"id": "gerarPagamento",
|
|
469
|
+
"label": "Gerar pagamento",
|
|
470
|
+
"type": "apiAction",
|
|
471
|
+
"method": "POST",
|
|
472
|
+
"endpoint": "/api/ss-eventos/orcamentos-itens/:id/gerar-pagamento",
|
|
473
|
+
"disabledWhen": { "field": "pagamentoId", "exists": true },
|
|
474
|
+
"refresh": ["self", "pagamentos", "resumo", "parent"]
|
|
475
|
+
}
|
|
476
|
+
]
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"id": "pagamentos",
|
|
480
|
+
"label": "Pagamentos",
|
|
481
|
+
"type": "readonlyGrid",
|
|
482
|
+
"relation": "pagamentos",
|
|
483
|
+
"columns": ["codigo", "descricao", "fornecedorRazaoSocial", "statusEsteira", "valorFechamento", "formaPagamento", "dataPagamento"]
|
|
484
|
+
}
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## 11. Status implementado no Core
|
|
491
|
+
|
|
492
|
+
O `@oondemand/oon-core-front` implementa o contrato acima de forma genérica nos componentes `CoreDetailModal`, `CoreTabbedDetail`, `CoreSummaryCards`, `CoreRelatedGrid`, `CoreInlineEditableCell` e `CoreRowAction`.
|
|
493
|
+
|
|
494
|
+
Exemplo completo:
|
|
495
|
+
|
|
496
|
+
```json
|
|
497
|
+
{
|
|
498
|
+
"model": "OrcamentoProjeto",
|
|
499
|
+
"mode": "dynamic",
|
|
500
|
+
"path": "/orcamentos-projetos",
|
|
501
|
+
"label": "Orçamentos/Projetos",
|
|
502
|
+
"section": "Operação",
|
|
503
|
+
"list": {
|
|
504
|
+
"filters": [{ "field": "tipoRegistro", "label": "Tipo", "type": "select", "options": [{ "label": "Todos", "value": "" }] }],
|
|
505
|
+
"rowActions": [{ "type": "openDetailModal", "label": "Editar", "initialTab": "resumo" }]
|
|
506
|
+
},
|
|
507
|
+
"relations": {
|
|
508
|
+
"itens": { "model": "OrcamentoItem", "foreignKey": "projetoId", "parentKey": "_id" },
|
|
509
|
+
"pagamentos": { "model": "Pagamento", "foreignKey": "projetoId", "parentKey": "_id" }
|
|
510
|
+
},
|
|
511
|
+
"detailModal": {
|
|
512
|
+
"enabled": true,
|
|
513
|
+
"titleField": "nome",
|
|
514
|
+
"defaultTab": "resumo",
|
|
515
|
+
"tabs": [
|
|
516
|
+
{ "id": "resumo", "label": "Resumo", "type": "summary", "cards": [{ "label": "Itens", "source": "relatedCount", "relation": "itens" }] },
|
|
517
|
+
{ "id": "dados", "label": "Dados Principais", "type": "form", "groups": [{ "label": "Identificação", "fields": ["codigo", "nome", "status"] }] },
|
|
518
|
+
{ "id": "itens", "label": "Itens", "type": "relatedGrid", "relation": "itens", "editable": true, "editMode": "inline", "columns": ["item", "status"] },
|
|
519
|
+
{ "id": "pagamentos", "label": "Pagamentos", "type": "readonlyGrid", "relation": "pagamentos", "columns": ["codigo", "valorFechamento"] }
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
`rowActions` do tipo `apiAction` suportam interpolação de `:id`, `:parentId`, `:fieldName` e `:parent.fieldName`, além de `confirm`, `disabledWhen`, `hiddenWhen` e `refresh` com `self`, `parent`, `all` ou o id de uma aba.
|