@fluig-kit/ecm 1.0.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 +304 -0
- package/dist/fluig-kit-ecm.es.js +849 -0
- package/dist/fluig-kit-ecm.umd.js +31 -0
- package/dist/index.d.ts +166 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
|
|
2
|
+
## 🚀 Fluig Kit — Desenvolvimento ECM_WORKFLOW e WCM com React
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
O **Fluig Kit** é um conjunto moderno de ferramentas e bibliotecas criado para **substituir o desenvolvimento legado baseado em jQuery e FreeMarker** no TOTVS Fluig.
|
|
6
|
+
|
|
7
|
+
Ele permite a criação de **formulários ECM Workflow** e **Widgets WCM** utilizando tecnologias modernas como **React, Vite, TypeScript, React Hook Form e Zod**, oferecendo uma arquitetura **previsível, escalável e fácil de manter**.
|
|
8
|
+
|
|
9
|
+
Além disso, possibilita a integração com **qualquer biblioteca do ecossistema React**, ampliando a flexibilidade e o poder de personalização das soluções.
|
|
10
|
+
|
|
11
|
+
## 🎯 Objetivos do Fluig Kit
|
|
12
|
+
|
|
13
|
+
- Modernizar o desenvolvimento de formulários Fluig
|
|
14
|
+
- Eliminar dependência direta de jQuery e FreeMarker
|
|
15
|
+
- Facilitar validações, regras de negócio e controle de estado
|
|
16
|
+
- Melhorar a experiência de desenvolvimento (DX)
|
|
17
|
+
- Permitir desenvolvimento local com simulação fiel do Fluig
|
|
18
|
+
|
|
19
|
+
## 📦 Estrutura dos Pacotes (Monorepo)
|
|
20
|
+
|
|
21
|
+
O kit é organizado em múltiplos pacotes, cada um com uma responsabilidade clara:
|
|
22
|
+
|
|
23
|
+
#### `@fluig-kit/core`
|
|
24
|
+
Núcleo da aplicação.
|
|
25
|
+
Responsabilidades:
|
|
26
|
+
- Cliente HTTP (`apiClient`)
|
|
27
|
+
- Logger de debug (`DebugLogger`)
|
|
28
|
+
- Comunicação com o Fluig via `parentProxy`
|
|
29
|
+
- Em produção: `window.top`
|
|
30
|
+
- Em desenvolvimento: Proxy Local + Extensão
|
|
31
|
+
---
|
|
32
|
+
#### `@fluig-kit/ecm`
|
|
33
|
+
Camada específica para **ECM / Workflow**.
|
|
34
|
+
Inclui:
|
|
35
|
+
- `FluigWorkflowForm`
|
|
36
|
+
- Hooks (`useFluigApi`, `useSection`, etc.)
|
|
37
|
+
- Integração com React Hook Form
|
|
38
|
+
- Controle de ciclo de vida do Fluig
|
|
39
|
+
---
|
|
40
|
+
#### `@fluig-kit/cli`
|
|
41
|
+
Ferramenta de linha de comando para desenvolvimento local.
|
|
42
|
+
Funções:
|
|
43
|
+
- Sobe um **Proxy Local**
|
|
44
|
+
- Resolve problemas de **CORS**
|
|
45
|
+
- Assina requisições com **OAuth 1.0a**
|
|
46
|
+
- Simula chamadas para `window.parent` e `window.top`
|
|
47
|
+
---
|
|
48
|
+
#### `@fluig-kit/extension`
|
|
49
|
+
Extensão do Google Chrome.
|
|
50
|
+
Funções:
|
|
51
|
+
- Ponte de autenticação entre o **localhost** e o Fluig
|
|
52
|
+
- Executa chamadas no contexto real da aba do Fluig
|
|
53
|
+
- Comunicação via **WebSocket** com o Proxy Local
|
|
54
|
+
|
|
55
|
+
## 🛠️ Configuração do Ambiente
|
|
56
|
+
#### 1️⃣ Variáveis de Ambiente (`.env`)
|
|
57
|
+
|
|
58
|
+
Crie um arquivo `.env` na raiz do projeto React:
|
|
59
|
+
|
|
60
|
+
```env
|
|
61
|
+
# URL base do ambiente Fluig
|
|
62
|
+
VITE_FLUIG_BASE_URL=https://SEUDOMINIO.fluig.cloudtotvs.com.br
|
|
63
|
+
|
|
64
|
+
# Credenciais OAuth (Fluig > Painel de Controle > OAuth Application)
|
|
65
|
+
CONSUMER_KEY=SEU_CONSUMER_KEY
|
|
66
|
+
CONSUMER_SECRET=SEU_CONSUMER_SECRET
|
|
67
|
+
ACCESS_TOKEN=SEU_ACCESS_TOKEN
|
|
68
|
+
TOKEN_SECRET=SEU_TOKEN_SECRET
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Essas variáveis são usadas **exclusivamente pelo Proxy Local** para assinar as requisições.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
#### 2️⃣ Instalação da Extensão do Chrome
|
|
76
|
+
Passos:
|
|
77
|
+
1. Execute:
|
|
78
|
+
```
|
|
79
|
+
npm run dev
|
|
80
|
+
```
|
|
81
|
+
2. No Chrome, abra:
|
|
82
|
+
```
|
|
83
|
+
chrome://extensions
|
|
84
|
+
```
|
|
85
|
+
3. Ative **Modo do Desenvolvedor**
|
|
86
|
+
4. Clique em **Carregar sem compactação**
|
|
87
|
+
5. Selecione a pasta `.fluig-extension` gerada na **raiz** do projeto
|
|
88
|
+
|
|
89
|
+
>⚠️ A extensão injeta um script no Fluig para permitir comunicação segura com o localhost.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
## 💻 Desenvolvimento do Formulário
|
|
93
|
+
|
|
94
|
+
#### Inicialização da Aplicação (`App.jsx`)
|
|
95
|
+
O app deve ser envolvido pelos **Providers do Fluig Kit**:
|
|
96
|
+
```jsx
|
|
97
|
+
import React from "react";
|
|
98
|
+
import { createRoot } from "react-dom/client";
|
|
99
|
+
import {
|
|
100
|
+
FluigApiProvider,
|
|
101
|
+
FluigRuntimeProvider,
|
|
102
|
+
SchemaRegistryProvider,
|
|
103
|
+
FluigWorkflowForm
|
|
104
|
+
} from "@fluig-kit/ecm";
|
|
105
|
+
|
|
106
|
+
import { schemaBase } from "./form/schemas/schema";
|
|
107
|
+
import { WORKFLOW_STRUCTURE, SECTIONS_REGISTRY } from "./config/workflow";
|
|
108
|
+
|
|
109
|
+
const DEV_CONFIG = {
|
|
110
|
+
enabled: true,
|
|
111
|
+
activityId: 5,
|
|
112
|
+
showDebugLogs: true
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const CONFIG_API = {
|
|
116
|
+
baseURL: import.meta.env.VITE_FLUIG_BASE_URL,
|
|
117
|
+
localProxyURL: "http://localhost:4000/fluig-proxy-api"
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
createRoot(document.getElementById("root")).render(
|
|
121
|
+
<FluigRuntimeProvider devConfig={DEV_CONFIG}>
|
|
122
|
+
<FluigApiProvider config={CONFIG_API}>
|
|
123
|
+
<SchemaRegistryProvider baseSchema={schemaBase}>
|
|
124
|
+
<FluigWorkflowForm
|
|
125
|
+
workflowStructure={WORKFLOW_STRUCTURE}
|
|
126
|
+
sectionsRegistry={SECTIONS_REGISTRY}
|
|
127
|
+
/>
|
|
128
|
+
</SchemaRegistryProvider>
|
|
129
|
+
</FluigApiProvider>
|
|
130
|
+
</FluigRuntimeProvider>
|
|
131
|
+
);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 🧱 Seções do Formulário (`Section`)
|
|
135
|
+
|
|
136
|
+
Uma **Section** representa um bloco lógico do formulário e controla:
|
|
137
|
+
- Visibilidade
|
|
138
|
+
- ReadOnly
|
|
139
|
+
- Regras por atividade
|
|
140
|
+
|
|
141
|
+
```jsx
|
|
142
|
+
import { Section, useSection } from "@fluig-kit/ecm";
|
|
143
|
+
import { Input } from "@diefra/fluig-ui";
|
|
144
|
+
import { useWatch } from "react-hook-form";
|
|
145
|
+
|
|
146
|
+
function EngCargoContent() {
|
|
147
|
+
const { form } = useSection();
|
|
148
|
+
const salario = useWatch({ control: form.control, name: "SALARIO" });
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div className="row">
|
|
152
|
+
<div className="col-md-6">
|
|
153
|
+
<Input name="NOMECARGO" label="Nome do Cargo" />
|
|
154
|
+
</div>
|
|
155
|
+
<div className="col-md-6">
|
|
156
|
+
<Input name="SALARIO" label="Salário" type="monetary" />
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default function EngCargo(props) {
|
|
163
|
+
return (
|
|
164
|
+
<Section id="EngCargo" className="well" {...props}>
|
|
165
|
+
<EngCargoContent />
|
|
166
|
+
</Section>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## ⚙️ Configuração do Workflow (`workflow.ts`)
|
|
172
|
+
|
|
173
|
+
Define o comportamento do formulário por atividade.
|
|
174
|
+
|
|
175
|
+
#### Conceitos principais
|
|
176
|
+
|
|
177
|
+
- **Sections**: controlam blocos inteiros
|
|
178
|
+
- **Fields**: controlam campos individuais
|
|
179
|
+
- **Rules**: regras condicionais
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
export const WORKFLOW_STRUCTURE = {
|
|
183
|
+
0: {
|
|
184
|
+
sections: {
|
|
185
|
+
active: ["InfSolicitante", "EngCargo"],
|
|
186
|
+
hidden: ["AprovacaoRH"]
|
|
187
|
+
},
|
|
188
|
+
fields: {
|
|
189
|
+
active: ["NOMECARGO"]
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
5: {
|
|
194
|
+
sections: {
|
|
195
|
+
active: ["AprovacaoRH"],
|
|
196
|
+
readonly: ["InfSolicitante", "EngCargo"]
|
|
197
|
+
},
|
|
198
|
+
fields: {
|
|
199
|
+
active: ["PARECER_RH"],
|
|
200
|
+
rules: [
|
|
201
|
+
{
|
|
202
|
+
target: ["OBS_REPROVACAO"],
|
|
203
|
+
when: { field: "PARECER_RH", equals: "REPROVAR" },
|
|
204
|
+
type: "active"
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 📡 Consumo da API Fluig (`useFluigApi`)
|
|
213
|
+
|
|
214
|
+
```jsx
|
|
215
|
+
import { useFluigApi } from "@fluig-kit/ecm";
|
|
216
|
+
import { useEffect, useState } from "react";
|
|
217
|
+
|
|
218
|
+
export function useUsuarios() {
|
|
219
|
+
const api = useFluigApi();
|
|
220
|
+
const [users, setUsers] = useState([]);
|
|
221
|
+
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
async function fetchUsers() {
|
|
224
|
+
const res = await api.get("/api/public/2.0/users/list/ACTIVE");
|
|
225
|
+
setUsers(res.content);
|
|
226
|
+
}
|
|
227
|
+
fetchUsers();
|
|
228
|
+
}, [api]);
|
|
229
|
+
|
|
230
|
+
return users;
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
O hook decide automaticamente:
|
|
235
|
+
- **Localhost** → Proxy OAuth
|
|
236
|
+
- **Produção** → Cookie de sessão
|
|
237
|
+
|
|
238
|
+
## 🔄 Movimentação do Workflow
|
|
239
|
+
|
|
240
|
+
```jsx
|
|
241
|
+
import { useSection } from "@fluig-kit/ecm";
|
|
242
|
+
|
|
243
|
+
function MinhaAprovacao() {
|
|
244
|
+
const { next } = useSection();
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<button onClick={() => next(15)}>
|
|
248
|
+
Aprovar
|
|
249
|
+
</button>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
## 🏗️ Geração de HTML e Build (generateHtmlTemplate)
|
|
254
|
+
|
|
255
|
+
O Fluig não executa React nativamente no salvamento do formulário, ele busca campos HTML.
|
|
256
|
+
```html
|
|
257
|
+
<input name="NOME_DO_CAMPO">
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
A função generateHtmlTemplate gera um HTML estático com inputs ocultos (type="hidden") baseados nos seus Schemas Zod.
|
|
261
|
+
|
|
262
|
+
Script de Build (build.cjs)
|
|
263
|
+
Crie este script na raiz para gerar o form.html final:
|
|
264
|
+
|
|
265
|
+
```js
|
|
266
|
+
const fs = require("fs");
|
|
267
|
+
const path = require("path");
|
|
268
|
+
const { generateHtmlTemplate } = require("@fluig-kit/ecm");
|
|
269
|
+
|
|
270
|
+
// EXEMPLO SECTIONS_REGISTRY
|
|
271
|
+
// export const SECTIONS_REGISTRY = {
|
|
272
|
+
// InfSolicitante: { Component: InfSolicitante, schema: schemaSolicitante },
|
|
273
|
+
// EngCargo: { Component: EngCargo, schema: schemaEngCargo },
|
|
274
|
+
// InfVaga: { Component: InfVaga, schema: schemaInfVaga },
|
|
275
|
+
// ...
|
|
276
|
+
//}
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
// 1. Extrai schemas Zod
|
|
280
|
+
const schemas = Object.values(SECTIONS_REGISTRY).map((s) => s.schema).filter(Boolean);
|
|
281
|
+
|
|
282
|
+
// 2. Gera HTML com inputs hidden
|
|
283
|
+
const finalHtml = generateHtmlTemplate(schemas);
|
|
284
|
+
|
|
285
|
+
// 3. Salva o arquivo
|
|
286
|
+
const distPath = path.resolve(__dirname, "./dist/form.html");
|
|
287
|
+
fs.mkdirSync(path.dirname(distPath), { recursive: true });
|
|
288
|
+
fs.writeFileSync(distPath, finalHtml);
|
|
289
|
+
|
|
290
|
+
console.log("✅ form.html gerado com sucesso!");
|
|
291
|
+
} catch (error) {
|
|
292
|
+
console.error("❌ Erro:", error);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
Atualize o package.json:
|
|
297
|
+
|
|
298
|
+
```JSON
|
|
299
|
+
"scripts": {
|
|
300
|
+
"build": "vite build && node build.cjs"
|
|
301
|
+
}
|
|
302
|
+
````
|
|
303
|
+
---
|
|
304
|
+
Desenvolvido por © **[Ketson Kersen](https://github.com/ketsonkersen)**
|