@oondemand/create-central-oon 0.5.6 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -89
- package/bin/cli.js +4 -17
- package/docs/ADVANCED_UX_PATTERNS.md +3 -2
- package/docs/AGENTS.md +3 -4
- package/docs/BACKEND_API.md +2 -4
- package/docs/BACKEND_PATTERNS.md +1 -2
- package/docs/BACKEND_PROCESS_MANIFEST.md +6 -6
- package/docs/CAPABILITIES.md +2 -3
- package/docs/CHECKLIST_IMPLEMENTACAO.md +4 -4
- package/docs/FRONTEND_API.md +20 -23
- package/docs/FRONTEND_CODE_FIRST.md +35 -0
- package/docs/FRONTEND_PATTERNS.md +13 -15
- package/docs/METADATA_CRUD_UI.md +1 -1
- package/docs/PORTAL_COCKPIT_PATTERNS.md +10 -145
- package/docs/REACTIVE_DOMAIN_FORMULAS.md +2 -2
- package/package.json +1 -1
- package/schemas/central.app.schema.json +2 -16
- package/src/conformance.js +42 -106
- package/src/index.js +4 -28
- package/src/render.js +4 -30
- package/templates/_base/README.md +7 -6
- package/templates/_base/backend/package.json +1 -1
- package/templates/_base/central.app.json +4 -9
- package/templates/_base/frontend/package.json +1 -1
- package/templates/_base/frontend/src/app/app.tsx +25 -0
- package/templates/_base/frontend/src/app/navigation.ts +5 -0
- package/templates/_base/frontend/src/app/routes.tsx +6 -0
- package/templates/_base/frontend/src/app/theme.ts +8 -0
- package/templates/_base/frontend/src/components/gitkeep +1 -0
- package/templates/_base/frontend/src/features/gitkeep +1 -0
- package/templates/_base/frontend/src/layouts/gitkeep +1 -0
- package/templates/_base/frontend/src/main.tsx +3 -8
- package/templates/_base/frontend/src/pages/HomePage.tsx +25 -0
- package/templates/_base/frontend/tsconfig.json +1 -1
- package/templates/_base/package.json +1 -1
- package/docs/CONNECTORS_AND_INTEGRATIONS.md +0 -66
- package/docs/FRONTEND_MANIFEST_REFERENCE.md +0 -487
- package/templates/_base/backend/src/integrations/gitkeep +0 -0
- package/templates/_base/frontend/central.ui.json +0 -58
- package/templates/_base/frontend/src/collections/gitkeep +0 -0
- package/templates/_base/frontend/src/dashboards/gitkeep +0 -0
- package/templates/_base/frontend/src/documents/gitkeep +0 -0
- package/templates/_base/frontend/src/overrides/gitkeep +0 -0
- package/templates/_base/frontend/src/pipelines/gitkeep +0 -0
- package/templates/basic/backend/src/models/Pessoa.js +0 -21
- package/templates/basic/frontend/central.ui.json +0 -8
- package/templates/documentos-fiscais/backend/central.config.js +0 -32
- package/templates/documentos-fiscais/backend/src/models/DocumentoFiscal.js +0 -23
- package/templates/documentos-fiscais/frontend/central.ui.json +0 -16
- package/templates/multi-moedas/backend/central.config.js +0 -32
- package/templates/multi-moedas/backend/src/models/Cotacao.js +0 -23
- package/templates/multi-moedas/backend/src/models/Moeda.js +0 -15
- package/templates/multi-moedas/frontend/central.ui.json +0 -11
- package/templates/omie-sidecar/backend/central.config.js +0 -33
- package/templates/omie-sidecar/backend/src/mappings/pessoa-cliente.js +0 -20
- package/templates/omie-sidecar/backend/src/models/Pessoa.js +0 -24
- package/templates/omie-sidecar/backend/src/triggers/Pessoa.js +0 -14
- package/templates/omie-sidecar/frontend/central.ui.json +0 -8
- package/templates/pedidos-marketplace/backend/central.config.js +0 -32
- package/templates/pedidos-marketplace/backend/src/models/Pedido.js +0 -22
- package/templates/pedidos-marketplace/backend/src/models/Produto.js +0 -16
- package/templates/pedidos-marketplace/frontend/central.ui.json +0 -10
- package/templates/servicos-prestados/backend/central.config.js +0 -32
- package/templates/servicos-prestados/backend/src/models/Cliente.js +0 -15
- package/templates/servicos-prestados/backend/src/models/ServicoPrestado.js +0 -22
- package/templates/servicos-prestados/frontend/central.ui.json +0 -10
- package/templates/servicos-tomados/backend/central.config.js +0 -32
- package/templates/servicos-tomados/backend/src/models/Pessoa.js +0 -15
- package/templates/servicos-tomados/backend/src/models/Servico.js +0 -22
- package/templates/servicos-tomados/frontend/central.ui.json +0 -10
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineOonApp, type OonAppKind, type OonTenancyModel } from "@oondemand/oon-core-front";
|
|
2
|
+
import manifest from "../../../central.app.json";
|
|
3
|
+
import { navigation } from "./navigation";
|
|
4
|
+
import { routes } from "./routes";
|
|
5
|
+
import { theme } from "./theme";
|
|
6
|
+
|
|
7
|
+
export const app = defineOonApp({
|
|
8
|
+
app: {
|
|
9
|
+
id: manifest.id,
|
|
10
|
+
name: manifest.name,
|
|
11
|
+
title: manifest.name,
|
|
12
|
+
kind: manifest.appKind as OonAppKind,
|
|
13
|
+
tenancyModel: manifest.tenancyModel as OonTenancyModel,
|
|
14
|
+
capabilities: manifest.capabilities,
|
|
15
|
+
},
|
|
16
|
+
api: {
|
|
17
|
+
baseUrl: import.meta.env.VITE_API_URL ?? "/api",
|
|
18
|
+
meusAppsUrl: import.meta.env.DEV ? undefined : import.meta.env.VITE_MEUS_APPS_URL,
|
|
19
|
+
},
|
|
20
|
+
runtimeMode: import.meta.env.DEV ? "local" : "platform",
|
|
21
|
+
routes,
|
|
22
|
+
navigation,
|
|
23
|
+
theme,
|
|
24
|
+
shell: { shell: "default" },
|
|
25
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import app from "
|
|
3
|
-
import ui from "../central.ui.json";
|
|
1
|
+
import { startOonApp } from "@oondemand/oon-core-front";
|
|
2
|
+
import { app } from "./app/app";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
apiBaseUrl: import.meta.env.VITE_API_URL ?? "/api",
|
|
7
|
-
runtimeMode: import.meta.env.DEV ? "local" : "platform",
|
|
8
|
-
meusAppsUrl: import.meta.env.DEV ? undefined : import.meta.env.VITE_MEUS_APPS_URL,
|
|
9
|
-
});
|
|
4
|
+
startOonApp(app);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Stack, Text } from "@chakra-ui/react";
|
|
2
|
+
import { CorePage, CorePageHeader, CoreStatusPanel, CoreSummaryCards } from "@oondemand/oon-core-front/ui";
|
|
3
|
+
|
|
4
|
+
export function HomePage() {
|
|
5
|
+
return (
|
|
6
|
+
<CorePage>
|
|
7
|
+
<CorePageHeader
|
|
8
|
+
title="Boas-vindas ao __NAME__"
|
|
9
|
+
description="A fundação técnica está pronta para receber a experiência e o domínio do app."
|
|
10
|
+
/>
|
|
11
|
+
<Stack gap={6}>
|
|
12
|
+
<CoreSummaryCards items={[
|
|
13
|
+
{ id: "core", label: "OonCore", value: "Pronto", description: "Shell, autenticação, sessão, tenant e RBAC." },
|
|
14
|
+
{ id: "platform", label: "Plataforma Oon", value: "Governada", description: "Publicação, ambientes, acesso e proveniência." },
|
|
15
|
+
]} />
|
|
16
|
+
<CoreStatusPanel
|
|
17
|
+
title="Próximos passos"
|
|
18
|
+
status="Code-first"
|
|
19
|
+
description="Crie páginas em src/pages, componentes em src/components e organize o domínio em src/features."
|
|
20
|
+
/>
|
|
21
|
+
<Text color="text.muted">Menus, rotas, layouts e temas ficam em src/app e podem combinar componentes locais com blocos públicos do OonCore.</Text>
|
|
22
|
+
</Stack>
|
|
23
|
+
</CorePage>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Conectores e Integrações
|
|
2
|
-
|
|
3
|
-
Toda integração deve ser modelada como um processo rastreável, não como chamada solta dentro de controller.
|
|
4
|
-
|
|
5
|
-
## Objetivo
|
|
6
|
-
|
|
7
|
-
Transformar cada integração em:
|
|
8
|
-
|
|
9
|
-
```txt
|
|
10
|
-
configuração + mapping + execução + status + rastreabilidade
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Estrutura recomendada
|
|
14
|
-
|
|
15
|
-
```txt
|
|
16
|
-
backend/src/integrations/
|
|
17
|
-
├── <sistema>/
|
|
18
|
-
│ ├── client.js
|
|
19
|
-
│ ├── mappings/
|
|
20
|
-
│ ├── services/
|
|
21
|
-
│ └── README.md
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Client
|
|
25
|
-
|
|
26
|
-
O client deve concentrar:
|
|
27
|
-
|
|
28
|
-
- URL base;
|
|
29
|
-
- autenticação;
|
|
30
|
-
- headers;
|
|
31
|
-
- timeout;
|
|
32
|
-
- retry técnico;
|
|
33
|
-
- normalização de erro.
|
|
34
|
-
|
|
35
|
-
Não coloque regra de negócio no client.
|
|
36
|
-
|
|
37
|
-
## Mapping
|
|
38
|
-
|
|
39
|
-
Mappings devem transformar dados entre a Central e o sistema externo.
|
|
40
|
-
|
|
41
|
-
Regras:
|
|
42
|
-
|
|
43
|
-
- mapping deve ser explícito;
|
|
44
|
-
- campos obrigatórios devem ser validados antes do envio;
|
|
45
|
-
- resposta externa deve ser normalizada;
|
|
46
|
-
- erros devem ser compreensíveis para operação.
|
|
47
|
-
|
|
48
|
-
## Esteira de integração
|
|
49
|
-
|
|
50
|
-
Toda integração relevante deve gerar registro operacional com:
|
|
51
|
-
|
|
52
|
-
- origem;
|
|
53
|
-
- destino;
|
|
54
|
-
- payload resumido ou referência;
|
|
55
|
-
- status;
|
|
56
|
-
- tentativas;
|
|
57
|
-
- erro normalizado;
|
|
58
|
-
- data/hora;
|
|
59
|
-
- usuário ou processo responsável.
|
|
60
|
-
|
|
61
|
-
## Segurança
|
|
62
|
-
|
|
63
|
-
- Nunca versionar app key, secret, token ou credencial.
|
|
64
|
-
- Não logar payloads sensíveis sem necessidade.
|
|
65
|
-
- Não expor credenciais no frontend.
|
|
66
|
-
- Usar `.env` e configuração de ambiente.
|
|
@@ -1,487 +0,0 @@
|
|
|
1
|
-
# Referência do Manifesto Frontend OonCore
|
|
2
|
-
|
|
3
|
-
Este documento é a referência operacional para qualquer Agent criar ou alterar manifestos do frontend OonCore.
|
|
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 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`
|
|
11
|
-
|
|
12
|
-
## Arquivos envolvidos
|
|
13
|
-
|
|
14
|
-
```txt
|
|
15
|
-
frontend/central.ui.json # manifesto declarativo da Central
|
|
16
|
-
frontend/src/main.tsx # bootstrap do frontend
|
|
17
|
-
packages/oonCore-front/src/manifest.ts # conversão central.ui.json -> OonCoreFrontConfig
|
|
18
|
-
packages/oonCore-front/src/types.ts # tipos oficiais do contrato
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Regra principal
|
|
22
|
-
|
|
23
|
-
O manifesto JSON não deve carregar componentes React. Ele só pode declarar dados e chaves de renderer, como:
|
|
24
|
-
|
|
25
|
-
```txt
|
|
26
|
-
custom:MeusAppsHeader
|
|
27
|
-
fields.password
|
|
28
|
-
cells.statusBadge
|
|
29
|
-
cards.appLauncher
|
|
30
|
-
actions.ativarApp
|
|
31
|
-
menus.portal
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Os componentes reais devem ser registrados em código TypeScript/React pelo `registry`.
|
|
35
|
-
|
|
36
|
-
## Níveis de contrato
|
|
37
|
-
|
|
38
|
-
Existem três níveis importantes:
|
|
39
|
-
|
|
40
|
-
1. `central.ui.json`: entrada declarativa usada pelas Centrais geradas.
|
|
41
|
-
2. `CentralUiManifest`: contrato lido por `startFromManifest`.
|
|
42
|
-
3. `OonUiManifest` / `OonCoreFrontConfig`: contrato interno mais completo do Core Front.
|
|
43
|
-
|
|
44
|
-
Para Agents, a ordem recomendada é:
|
|
45
|
-
|
|
46
|
-
1. Começar pelo `central.ui.json`.
|
|
47
|
-
2. Usar `pages` e `blocks` quando precisar de UI v2.
|
|
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.
|
|
51
|
-
|
|
52
|
-
## CentralUiManifest
|
|
53
|
-
|
|
54
|
-
Contrato aceito por `startFromManifest(manifest, runtime)`.
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
interface CentralUiManifest {
|
|
58
|
-
name: string;
|
|
59
|
-
slug: string;
|
|
60
|
-
backend?: { metadataUrl?: string };
|
|
61
|
-
schemaVersion?: 1 | 2;
|
|
62
|
-
layout?: OonLayoutConfig;
|
|
63
|
-
registry?: OonComponentRegistry;
|
|
64
|
-
navigation?: OonNavigationConfig;
|
|
65
|
-
pages?: OonPageDef[];
|
|
66
|
-
collections?: OonCollectionManifestDef[];
|
|
67
|
-
pipelines?: Array<{
|
|
68
|
-
name?: string;
|
|
69
|
-
model?: string;
|
|
70
|
-
mode?: string;
|
|
71
|
-
stageField?: string;
|
|
72
|
-
path?: string;
|
|
73
|
-
label?: string;
|
|
74
|
-
section?: string;
|
|
75
|
-
}>;
|
|
76
|
-
documents?: Array<{
|
|
77
|
-
model: string;
|
|
78
|
-
mode?: string;
|
|
79
|
-
path?: string;
|
|
80
|
-
label?: string;
|
|
81
|
-
section?: string;
|
|
82
|
-
approval?: boolean;
|
|
83
|
-
attachments?: boolean;
|
|
84
|
-
}>;
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Opções de raiz
|
|
89
|
-
|
|
90
|
-
| Campo | Tipo | Uso |
|
|
91
|
-
| --- | --- | --- |
|
|
92
|
-
| `name` | `string` | Nome exibido da Central. |
|
|
93
|
-
| `slug` | `string` | Identificador da Central/app. |
|
|
94
|
-
| `backend.metadataUrl` | `string` | URL explícita de metadata, quando aplicável. |
|
|
95
|
-
| `schemaVersion` | `1 \| 2` | Sem valor = compatibilidade v1. Use `2` para UI v2. |
|
|
96
|
-
| `layout` | `OonLayoutConfig` | Shell, sidebar, topbar, header, footer e slots. |
|
|
97
|
-
| `navigation` | `OonNavigationConfig` | Modo do menu e itens manuais. |
|
|
98
|
-
| `pages` | `OonPageDef[]` | Páginas por blocos da UI v2. |
|
|
99
|
-
| `collections` | `Array` | Views de coleção, simples ou avançadas. |
|
|
100
|
-
| `pipelines` | `Array` | Atalho para gerar esteiras. |
|
|
101
|
-
| `documents` | `Array` | Atalho para gerar documentos. |
|
|
102
|
-
|
|
103
|
-
## Layout
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
type OonSlotConfig = "core" | "none" | `custom:${string}`;
|
|
107
|
-
|
|
108
|
-
interface OonLayoutConfig {
|
|
109
|
-
shell?: "default" | "portal" | "content-only" | `custom:${string}`;
|
|
110
|
-
sidebar?: OonSlotConfig;
|
|
111
|
-
topbar?: OonSlotConfig;
|
|
112
|
-
header?: "none" | `custom:${string}`;
|
|
113
|
-
footer?: "core" | "none" | `custom:${string}`;
|
|
114
|
-
assistant?: "core" | "none" | `custom:${string}`;
|
|
115
|
-
main?: "core";
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### Valores de `layout.shell`
|
|
120
|
-
|
|
121
|
-
| Valor | Comportamento |
|
|
122
|
-
| --- | --- |
|
|
123
|
-
| `default` | Shell operacional padrão com sidebar/topbar. |
|
|
124
|
-
| `portal` | Shell para portal, útil para Meus Apps ou home de cards. |
|
|
125
|
-
| `content-only` | Experiência focada em conteúdo. |
|
|
126
|
-
| `custom:<key>` | Shell registrado em `registry.layoutSlots`. |
|
|
127
|
-
|
|
128
|
-
## Navigation
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
type OonNavigationMode = "auto" | "manual" | "mixed";
|
|
132
|
-
|
|
133
|
-
interface OonNavigationConfig {
|
|
134
|
-
mode?: OonNavigationMode;
|
|
135
|
-
items?: OonMenuItem[];
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Collections no central.ui.json
|
|
140
|
-
|
|
141
|
-
Atalho para coleções simples ou avançadas.
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
interface OonCollectionManifestDef {
|
|
145
|
-
model: string;
|
|
146
|
-
mode?: "full" | "minimal" | "dynamic";
|
|
147
|
-
path?: string;
|
|
148
|
-
label?: string;
|
|
149
|
-
section?: string;
|
|
150
|
-
list?: OonCollectionListConfig;
|
|
151
|
-
relations?: Record<string, OonRelationDef>;
|
|
152
|
-
detailModal?: OonDetailModalConfig;
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Exemplo simples
|
|
157
|
-
|
|
158
|
-
```json
|
|
159
|
-
{
|
|
160
|
-
"collections": [
|
|
161
|
-
{
|
|
162
|
-
"model": "Cliente",
|
|
163
|
-
"mode": "dynamic",
|
|
164
|
-
"path": "/clientes",
|
|
165
|
-
"label": "Clientes",
|
|
166
|
-
"section": "Cadastros"
|
|
167
|
-
}
|
|
168
|
-
]
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Exemplo avançado
|
|
173
|
-
|
|
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
|
-
]
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## list
|
|
216
|
-
|
|
217
|
-
Configura filtros, colunas e ações do grid principal.
|
|
218
|
-
|
|
219
|
-
```ts
|
|
220
|
-
interface OonCollectionListConfig {
|
|
221
|
-
filters?: OonListFilterDef[];
|
|
222
|
-
columns?: Array<string | OonColumnDef>;
|
|
223
|
-
rowActions?: OonRowActionDef[];
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### list.filters
|
|
228
|
-
|
|
229
|
-
```json
|
|
230
|
-
{
|
|
231
|
-
"field": "tipoRegistro",
|
|
232
|
-
"label": "Tipo",
|
|
233
|
-
"type": "select",
|
|
234
|
-
"options": [
|
|
235
|
-
{ "label": "Todos", "value": "" },
|
|
236
|
-
{ "label": "Orçamento", "value": "Orçamento" }
|
|
237
|
-
]
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
Tipos previstos:
|
|
242
|
-
|
|
243
|
-
- `text`
|
|
244
|
-
- `select`
|
|
245
|
-
- `date`
|
|
246
|
-
- `dateRange`
|
|
247
|
-
- `numberRange`
|
|
248
|
-
- `boolean`
|
|
249
|
-
- `ref`
|
|
250
|
-
|
|
251
|
-
### list.rowActions
|
|
252
|
-
|
|
253
|
-
```json
|
|
254
|
-
{
|
|
255
|
-
"type": "openDetailModal",
|
|
256
|
-
"label": "Editar",
|
|
257
|
-
"icon": "edit",
|
|
258
|
-
"initialTab": "resumo"
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
## relations
|
|
263
|
-
|
|
264
|
-
Relações nomeadas entre model pai e models filhos.
|
|
265
|
-
|
|
266
|
-
```json
|
|
267
|
-
{
|
|
268
|
-
"relations": {
|
|
269
|
-
"itens": {
|
|
270
|
-
"model": "OrcamentoItem",
|
|
271
|
-
"foreignKey": "projetoId",
|
|
272
|
-
"parentKey": "_id"
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
## detailModal
|
|
279
|
-
|
|
280
|
-
Configura modal de detalhe/criação com abas.
|
|
281
|
-
|
|
282
|
-
```ts
|
|
283
|
-
interface OonDetailModalConfig {
|
|
284
|
-
enabled?: boolean;
|
|
285
|
-
titleField?: string;
|
|
286
|
-
size?: "md" | "lg" | "xl" | "full";
|
|
287
|
-
defaultTab?: string;
|
|
288
|
-
tabs: OonDetailTabDef[];
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Abas suportadas
|
|
293
|
-
|
|
294
|
-
- `summary`
|
|
295
|
-
- `form`
|
|
296
|
-
- `relatedGrid`
|
|
297
|
-
- `readonlyGrid`
|
|
298
|
-
- `customComponent`
|
|
299
|
-
|
|
300
|
-
### Aba summary
|
|
301
|
-
|
|
302
|
-
```json
|
|
303
|
-
{
|
|
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
|
-
]
|
|
311
|
-
}
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Aba form
|
|
315
|
-
|
|
316
|
-
```json
|
|
317
|
-
{
|
|
318
|
-
"id": "dados",
|
|
319
|
-
"label": "Dados Principais",
|
|
320
|
-
"type": "form",
|
|
321
|
-
"groups": [
|
|
322
|
-
{ "label": "Identificação", "fields": ["codigo", "nome", "status"] }
|
|
323
|
-
]
|
|
324
|
-
}
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Aba relatedGrid
|
|
328
|
-
|
|
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": []
|
|
343
|
-
}
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
### Aba readonlyGrid
|
|
347
|
-
|
|
348
|
-
```json
|
|
349
|
-
{
|
|
350
|
-
"id": "pagamentos",
|
|
351
|
-
"label": "Pagamentos",
|
|
352
|
-
"type": "readonlyGrid",
|
|
353
|
-
"relation": "pagamentos",
|
|
354
|
-
"columns": ["codigo", "descricao", "status", "valor"]
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## rowActions
|
|
359
|
-
|
|
360
|
-
Ações reutilizáveis em grid principal ou grids relacionados.
|
|
361
|
-
|
|
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[];
|
|
377
|
-
}
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### apiAction
|
|
381
|
-
|
|
382
|
-
```json
|
|
383
|
-
{
|
|
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"]
|
|
391
|
-
}
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
## CollectionViewDef completo
|
|
395
|
-
|
|
396
|
-
Contrato interno completo quando a coleção já está em `ui.views` ou em blocos.
|
|
397
|
-
|
|
398
|
-
```ts
|
|
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;
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
## Compatibilidade
|
|
422
|
-
|
|
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.
|
|
427
|
-
|
|
428
|
-
## UX avançada implementada
|
|
429
|
-
|
|
430
|
-
Campos aceitos em `collections[]`:
|
|
431
|
-
|
|
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`.
|
|
437
|
-
|
|
438
|
-
Tipos de aba:
|
|
439
|
-
|
|
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.
|
|
445
|
-
|
|
446
|
-
`apiAction.endpoint` aceita `:id`, `:parentId`, `:fieldName` e `:parent.fieldName`. `refresh` aceita `self`, `parent`, `all` ou ids de abas.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
## Opções remotas em campos de formulário
|
|
450
|
-
|
|
451
|
-
Campos `enum` podem carregar opções de um endpoint dependente do formulário atual ou do registro pai. O contrato funciona em formulários principais e em criação/edição de `relatedGrid`.
|
|
452
|
-
|
|
453
|
-
```ts
|
|
454
|
-
{
|
|
455
|
-
field: "roleCode",
|
|
456
|
-
label: "Perfil",
|
|
457
|
-
kind: "enum",
|
|
458
|
-
optionsEndpoint: "/control-plane/app-role-catalogs/:appId?tenantId=:parentId",
|
|
459
|
-
optionsResponsePath: "options",
|
|
460
|
-
optionsValueField: "value",
|
|
461
|
-
optionsLabelField: "label",
|
|
462
|
-
optionsDescriptionField: "description",
|
|
463
|
-
optionsEditablePath: "editable",
|
|
464
|
-
optionsDependsOn: ["appId", "tenantId"],
|
|
465
|
-
fallbackOptions: [{ value: "admin", label: "Administrador" }],
|
|
466
|
-
readonlyOnFallback: true,
|
|
467
|
-
optionsUnavailableMessage: "Catálogo indisponível; perfil admin aplicado."
|
|
468
|
-
}
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
| Campo | Uso |
|
|
472
|
-
| --- | --- |
|
|
473
|
-
| `optionsEndpoint` | Endpoint relativo. Aceita `:field`, `:parentId` e `:parent.field`; valores são codificados para URL. |
|
|
474
|
-
| `optionsResponsePath` | Caminho da lista na resposta. Sem valor, a própria resposta deve ser um array. |
|
|
475
|
-
| `optionsValueField` | Campo usado como valor da opção; padrão `value`. |
|
|
476
|
-
| `optionsLabelField` | Campo usado como rótulo; padrão `label`. |
|
|
477
|
-
| `optionsDescriptionField` | Campo opcional de descrição. |
|
|
478
|
-
| `optionsEditablePath` | Booleano remoto que permite ou bloqueia a edição. |
|
|
479
|
-
| `optionsDependsOn` | Campos que precisam estar preenchidos e cuja mudança invalida a seleção atual. |
|
|
480
|
-
| `fallbackOptions` | Opções seguras usadas quando o endpoint falha ou retorna lista vazia. |
|
|
481
|
-
| `readonlyOnFallback` | Bloqueia a seleção durante o fallback; padrão `true`. |
|
|
482
|
-
| `optionsUnavailableMessage` | Mensagem explicando o fallback ao usuário. |
|
|
483
|
-
| `readonly` | Bloqueia o campo em qualquer estado. |
|
|
484
|
-
|
|
485
|
-
Durante a edição, a interpolação também considera os valores iniciais completos do registro, inclusive campos somente leitura que não são renderizados no formulário. Valores alterados pelo usuário prevalecem sobre os valores iniciais.
|
|
486
|
-
|
|
487
|
-
O backend continua responsável por validar o valor selecionado. Opções remotas melhoram a experiência, mas não substituem autorização nem validação de domínio.
|
|
File without changes
|