forlogic-core 1.5.2 → 1.5.3
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 +455 -20
- package/dist/README.md +394 -171
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/docs/AI_RULES.md +0 -213
- package/dist/docs/README.md +0 -102
- package/dist/docs/TROUBLESHOOTING.md +0 -473
- package/dist/docs/architecture/TOKENS_ARCHITECTURE.md +0 -712
- package/dist/docs/templates/app-layout.tsx +0 -192
- package/dist/docs/templates/basic-crud-page.tsx +0 -97
- package/dist/docs/templates/basic-crud-working.tsx +0 -182
- package/dist/docs/templates/complete-crud-example.tsx +0 -307
- package/dist/docs/templates/custom-form.tsx +0 -99
- package/dist/docs/templates/custom-service.tsx +0 -194
- package/dist/docs/templates/permission-check-hook.tsx +0 -275
- package/dist/docs/templates/qualiex-config.ts +0 -137
- package/dist/docs/templates/qualiex-integration-example.tsx +0 -430
- package/dist/docs/templates/quick-start-example.tsx +0 -96
- package/dist/docs/templates/rls-policies.sql +0 -80
- package/dist/docs/templates/sidebar-config.tsx +0 -145
package/dist/README.md
CHANGED
|
@@ -1,248 +1,471 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🧱 Projeto atual
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
**Schema padrão:** `central`
|
|
4
|
+
|
|
5
|
+
> **Nota sobre schemas:** O schema padrão é `central`, mas módulos podem usar schemas diferentes quando necessário para organização ou isolamento de dados. Por exemplo, o módulo de treinamentos usa o schema `trainings`. Você pode especificar o schema no service usando `schemaName: 'nome_do_schema'`.
|
|
5
6
|
|
|
6
7
|
---
|
|
7
8
|
|
|
8
|
-
##
|
|
9
|
+
## 🤖 REGRAS CRÍTICAS
|
|
10
|
+
|
|
11
|
+
### ⚠️ TOP 3 ERROS
|
|
12
|
+
|
|
13
|
+
1. **ESQUECER SCHEMA**
|
|
14
|
+
```typescript
|
|
15
|
+
// ❌ ERRADO
|
|
16
|
+
.from('table')
|
|
9
17
|
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
// ✅ CORRETO
|
|
19
|
+
.schema('schema').from('table')
|
|
12
20
|
```
|
|
13
21
|
|
|
14
|
-
|
|
22
|
+
2. **RLS COM `id` (sem alias)**
|
|
23
|
+
```sql
|
|
24
|
+
-- ❌ ERRADO
|
|
25
|
+
CREATE POLICY "Users view own" ON schema.table
|
|
26
|
+
FOR SELECT USING (id_user = auth.uid());
|
|
15
27
|
|
|
16
|
-
|
|
28
|
+
-- ✅ CORRETO
|
|
29
|
+
CREATE POLICY "Users view own" ON schema.table
|
|
30
|
+
FOR SELECT USING (alias = auth.uid());
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. **NÃO CRIAR ÍNDICES AUTOMATICAMENTE**
|
|
34
|
+
```sql
|
|
35
|
+
-- ❌ PROIBIDO criar índices sem aprovação
|
|
36
|
+
CREATE INDEX idx_table_user ON schema.table(id_user);
|
|
17
37
|
|
|
18
|
-
|
|
19
|
-
npm install react react-dom react-router-dom @tanstack/react-query
|
|
38
|
+
-- ✅ Apenas quando solicitado explicitamente
|
|
20
39
|
```
|
|
21
40
|
|
|
22
41
|
---
|
|
23
42
|
|
|
24
|
-
|
|
43
|
+
### ✅ CHECKLIST (antes de implementar)
|
|
44
|
+
|
|
45
|
+
- [ ] Schema `schema` especificado em queries e service?
|
|
46
|
+
- [ ] RLS usando `alias` (nunca `id_user`)?
|
|
47
|
+
- [ ] Preservar `item.id` no update?
|
|
48
|
+
- [ ] Config gerado com `useMemo()`?
|
|
49
|
+
- [ ] `<Outlet />` no componente pai?
|
|
50
|
+
- [ ] Qualiex header `un-alias` configurado?
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 🚀 QUICK START - Criar CRUD Completo
|
|
25
55
|
|
|
26
|
-
### 1
|
|
56
|
+
### **1️⃣ Type**
|
|
57
|
+
```typescript
|
|
58
|
+
// src/processes/process.ts
|
|
59
|
+
export interface Process {
|
|
60
|
+
id: string;
|
|
61
|
+
id_user: string | null;
|
|
62
|
+
title: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
status: 'draft' | 'active' | 'completed';
|
|
65
|
+
created_at?: string;
|
|
66
|
+
updated_at?: string;
|
|
67
|
+
deleted?: boolean;
|
|
68
|
+
}
|
|
27
69
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
import 'forlogic-core/index.css';
|
|
70
|
+
export type ProcessInsert = Omit<Process, 'id' | 'created_at' | 'updated_at'>;
|
|
71
|
+
export type ProcessUpdate = Partial<ProcessInsert>;
|
|
72
|
+
```
|
|
32
73
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
74
|
+
### **2️⃣ Service**
|
|
75
|
+
```typescript
|
|
76
|
+
// src/processes/processService.ts
|
|
77
|
+
import { createSimpleService } from 'forlogic-core';
|
|
78
|
+
import { Process, ProcessInsert, ProcessUpdate } from './process';
|
|
79
|
+
|
|
80
|
+
export const { service: processService, useCrudHook: useProcesses } =
|
|
81
|
+
createSimpleService<Process, ProcessInsert, ProcessUpdate>({
|
|
82
|
+
tableName: 'processes',
|
|
83
|
+
entityName: 'processo',
|
|
84
|
+
schemaName: 'central', // ⚠️ OBRIGATÓRIO
|
|
85
|
+
searchFields: ['title', 'description'],
|
|
86
|
+
enableQualiexEnrichment: true
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### **3️⃣ Save Handler**
|
|
91
|
+
```typescript
|
|
92
|
+
// src/processes/ProcessesPage.tsx
|
|
93
|
+
import { createSimpleSaveHandler } from 'forlogic-core';
|
|
94
|
+
import { processService } from './processService';
|
|
95
|
+
|
|
96
|
+
const handleSave = createSimpleSaveHandler({
|
|
97
|
+
service: processService,
|
|
98
|
+
entityName: 'processo'
|
|
36
99
|
});
|
|
100
|
+
|
|
101
|
+
// ⚠️ CRÍTICO: Preservar ID no update
|
|
102
|
+
const handleUpdate = async (item: Process) => {
|
|
103
|
+
await handleSave({
|
|
104
|
+
...item,
|
|
105
|
+
id: item.id // ⚠️ OBRIGATÓRIO para update
|
|
106
|
+
});
|
|
107
|
+
};
|
|
37
108
|
```
|
|
38
109
|
|
|
39
|
-
###
|
|
110
|
+
### **4️⃣ Config (com useMemo)**
|
|
111
|
+
```typescript
|
|
112
|
+
// src/processes/ProcessesPage.tsx
|
|
113
|
+
import { useMemo } from 'react';
|
|
114
|
+
import { generateCrudConfig } from 'forlogic-core';
|
|
115
|
+
|
|
116
|
+
export default function ProcessesPage() {
|
|
117
|
+
const crud = useProcesses();
|
|
118
|
+
|
|
119
|
+
// ⚠️ OBRIGATÓRIO useMemo para evitar re-renders
|
|
120
|
+
const config = useMemo(() =>
|
|
121
|
+
generateCrudConfig<Process>({
|
|
122
|
+
entity: 'processo',
|
|
123
|
+
columns: [
|
|
124
|
+
{ key: 'title', label: 'Título', type: 'text', required: true },
|
|
125
|
+
{ key: 'status', label: 'Status', type: 'select',
|
|
126
|
+
options: [
|
|
127
|
+
{ value: 'draft', label: 'Rascunho' },
|
|
128
|
+
{ value: 'active', label: 'Ativo' },
|
|
129
|
+
{ value: 'completed', label: 'Concluído' }
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
{ key: 'description', label: 'Descrição', type: 'textarea' }
|
|
133
|
+
]
|
|
134
|
+
}),
|
|
135
|
+
[]);
|
|
136
|
+
|
|
137
|
+
return createCrudPage({
|
|
138
|
+
config,
|
|
139
|
+
crud,
|
|
140
|
+
saveHandler: handleSave
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
```
|
|
40
144
|
|
|
41
|
-
|
|
145
|
+
### **5️⃣ Page + Outlet (preservar estado)**
|
|
146
|
+
```typescript
|
|
42
147
|
// src/App.tsx
|
|
43
|
-
import {
|
|
44
|
-
import { BrowserRouter } from 'react-router-dom';
|
|
148
|
+
import { Outlet } from 'react-router-dom';
|
|
45
149
|
|
|
46
150
|
function App() {
|
|
47
151
|
return (
|
|
48
|
-
<
|
|
49
|
-
<
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
</QueryClientProvider>
|
|
56
|
-
</ErrorBoundary>
|
|
152
|
+
<Routes>
|
|
153
|
+
<Route path="/processes" element={<ProcessLayout />}>
|
|
154
|
+
<Route index element={<ProcessesPage />} />
|
|
155
|
+
<Route path="new" element={<ProcessesPage />} />
|
|
156
|
+
<Route path=":id/edit" element={<ProcessesPage />} />
|
|
157
|
+
</Route>
|
|
158
|
+
</Routes>
|
|
57
159
|
);
|
|
58
160
|
}
|
|
161
|
+
|
|
162
|
+
// ⚠️ OBRIGATÓRIO: Outlet preserva estado
|
|
163
|
+
function ProcessLayout() {
|
|
164
|
+
return <Outlet />; // Evita reload do componente
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### 🔗 Integração Qualiex (opcional)
|
|
171
|
+
|
|
172
|
+
**Auto-enrichment** (já configurado no BaseService):
|
|
173
|
+
```typescript
|
|
174
|
+
// ✅ Automático - dados enriquecidos com nome do usuário
|
|
175
|
+
const processes = await processService.getAll();
|
|
176
|
+
// processes[0].usuario_nome = "João Silva" (se enableQualiexEnrichment: true)
|
|
59
177
|
```
|
|
60
178
|
|
|
61
|
-
|
|
179
|
+
**Componentes prontos:**
|
|
180
|
+
```typescript
|
|
181
|
+
import { QualiexUserField, QualiexResponsibleSelectField } from 'forlogic-core';
|
|
62
182
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
183
|
+
// Select de usuários Qualiex
|
|
184
|
+
<QualiexResponsibleSelectField
|
|
185
|
+
value={form.watch('id_user')}
|
|
186
|
+
onChange={(userId) => form.setValue('id_user', userId)}
|
|
187
|
+
/>
|
|
188
|
+
```
|
|
66
189
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
190
|
+
**Componentes em formulários CRUD:**
|
|
191
|
+
```typescript
|
|
192
|
+
// Para seleção de usuário
|
|
193
|
+
{
|
|
194
|
+
name: 'responsible_id',
|
|
195
|
+
label: 'Responsável',
|
|
196
|
+
type: 'simple-qualiex-user-field' as const,
|
|
197
|
+
required: true
|
|
73
198
|
}
|
|
74
199
|
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
200
|
+
// Para seleção de responsável
|
|
201
|
+
{
|
|
202
|
+
name: 'responsible_id',
|
|
203
|
+
label: 'Responsável',
|
|
204
|
+
type: 'single-responsible-select' as const,
|
|
205
|
+
required: true
|
|
206
|
+
}
|
|
207
|
+
```
|
|
79
208
|
|
|
80
|
-
|
|
81
|
-
const useEmployeesCrud = () => useCrud({
|
|
82
|
-
service,
|
|
83
|
-
queryKey: 'employees'
|
|
84
|
-
});
|
|
209
|
+
**Componentes customizados:**
|
|
85
210
|
|
|
86
|
-
|
|
87
|
-
const columns = [
|
|
88
|
-
{ key: 'name', label: 'Nome' },
|
|
89
|
-
{ key: 'email', label: 'Email' },
|
|
90
|
-
{ key: 'role', label: 'Cargo' }
|
|
91
|
-
];
|
|
211
|
+
Você pode criar e usar componentes customizados nos formulários para necessidades específicas:
|
|
92
212
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
];
|
|
213
|
+
```typescript
|
|
214
|
+
// Exemplo de campo customizado
|
|
215
|
+
{
|
|
216
|
+
name: 'custom_field',
|
|
217
|
+
label: 'Campo Customizado',
|
|
218
|
+
type: 'my-custom-component' as const,
|
|
219
|
+
required: true
|
|
220
|
+
}
|
|
221
|
+
```
|
|
103
222
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
});
|
|
223
|
+
> **Nota:** Componentes customizados devem ser registrados no `BaseForm.tsx` para funcionarem corretamente nos formulários CRUD.
|
|
224
|
+
|
|
225
|
+
**⚠️ CRÍTICO:** Requests Qualiex exigem header `un-alias`:
|
|
226
|
+
```typescript
|
|
227
|
+
// ✅ Já configurado no BaseService automaticamente
|
|
228
|
+
headers: { 'un-alias': 'true' }
|
|
111
229
|
```
|
|
112
230
|
|
|
113
231
|
---
|
|
114
232
|
|
|
115
|
-
##
|
|
233
|
+
## 🗃️ MIGRATIONS + RLS
|
|
234
|
+
|
|
235
|
+
### Template SQL Completo
|
|
236
|
+
```sql
|
|
237
|
+
-- 1️⃣ Criar tabela
|
|
238
|
+
CREATE TABLE central.processes (
|
|
239
|
+
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
240
|
+
id_user UUID, -- ⚠️ NUNCA foreign key para auth.users
|
|
241
|
+
title TEXT NOT NULL,
|
|
242
|
+
description TEXT,
|
|
243
|
+
status TEXT DEFAULT 'draft',
|
|
244
|
+
created_at TIMESTAMPTZ DEFAULT now(),
|
|
245
|
+
updated_at TIMESTAMPTZ DEFAULT now(),
|
|
246
|
+
deleted BOOLEAN DEFAULT false
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
-- 2️⃣ Habilitar RLS
|
|
250
|
+
ALTER TABLE central.processes ENABLE ROW LEVEL SECURITY;
|
|
251
|
+
|
|
252
|
+
-- 3️⃣ Políticas RLS (usar 'alias', nunca 'id_user')
|
|
253
|
+
CREATE POLICY "Users view own processes"
|
|
254
|
+
ON central.processes FOR SELECT
|
|
255
|
+
USING (alias = auth.uid()); -- ⚠️ 'alias', não 'id_user'
|
|
256
|
+
|
|
257
|
+
CREATE POLICY "Users insert own processes"
|
|
258
|
+
ON central.processes FOR INSERT
|
|
259
|
+
WITH CHECK (alias = auth.uid());
|
|
260
|
+
|
|
261
|
+
CREATE POLICY "Users update own processes"
|
|
262
|
+
ON central.processes FOR UPDATE
|
|
263
|
+
USING (alias = auth.uid());
|
|
264
|
+
|
|
265
|
+
-- 4️⃣ Trigger updated_at
|
|
266
|
+
CREATE TRIGGER set_updated_at
|
|
267
|
+
BEFORE UPDATE ON central.processes
|
|
268
|
+
FOR EACH ROW
|
|
269
|
+
EXECUTE FUNCTION public.set_updated_at();
|
|
270
|
+
|
|
271
|
+
-- 5️⃣ Índices (apenas se necessário)
|
|
272
|
+
-- ⚠️ NÃO criar automaticamente - solicitar aprovação
|
|
273
|
+
-- CREATE INDEX idx_processes_user ON central.processes(id_user);
|
|
274
|
+
```
|
|
116
275
|
|
|
117
|
-
|
|
276
|
+
### ❌ Sintaxes Proibidas RLS
|
|
277
|
+
```sql
|
|
278
|
+
-- NUNCA usar 'id' ou 'id_user' direto
|
|
279
|
+
id_user = auth.uid() -- ❌ ERRADO
|
|
280
|
+
id = auth.uid() -- ❌ ERRADO
|
|
118
281
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- **[Navegação da Docs](dist/docs/README.md)** - Hub central da documentação
|
|
282
|
+
-- SEMPRE usar 'alias'
|
|
283
|
+
alias = auth.uid() -- ✅ CORRETO
|
|
284
|
+
```
|
|
123
285
|
|
|
124
286
|
---
|
|
125
287
|
|
|
126
|
-
##
|
|
288
|
+
## 🐛 TROUBLESHOOTING
|
|
127
289
|
|
|
128
|
-
###
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- Ações em lote (deletar múltiplos)
|
|
290
|
+
### 1️⃣ "relation does not exist"
|
|
291
|
+
```typescript
|
|
292
|
+
// Causa: Schema ausente
|
|
293
|
+
.from('processes') // ❌
|
|
133
294
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- Integração com Supabase Auth
|
|
138
|
-
- Gerenciamento de tokens
|
|
295
|
+
// Solução:
|
|
296
|
+
.from('processes', { schema: 'central' }) // ✅
|
|
297
|
+
```
|
|
139
298
|
|
|
140
|
-
###
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- Totalmente customizável
|
|
299
|
+
### 2️⃣ RLS retorna vazio
|
|
300
|
+
```sql
|
|
301
|
+
-- Causa: Sintaxe incorreta
|
|
302
|
+
USING (id_user = auth.uid()) -- ❌
|
|
145
303
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
- **React Query**: Cache e sincronização de dados
|
|
304
|
+
-- Solução:
|
|
305
|
+
USING (alias = auth.uid()) -- ✅
|
|
306
|
+
```
|
|
150
307
|
|
|
151
|
-
|
|
308
|
+
### 3️⃣ Duplicação de registros
|
|
309
|
+
```typescript
|
|
310
|
+
// Causa: ID ausente no update
|
|
311
|
+
await service.save({ title: 'Novo' }); // ❌ Cria duplicado
|
|
152
312
|
|
|
153
|
-
|
|
313
|
+
// Solução: Preservar ID
|
|
314
|
+
await service.save({ id: item.id, title: 'Novo' }); // ✅
|
|
315
|
+
```
|
|
154
316
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
useCrud,
|
|
160
|
-
QualiexUserField
|
|
161
|
-
} from 'forlogic-core';
|
|
317
|
+
### 4️⃣ Página recarrega ao editar
|
|
318
|
+
```typescript
|
|
319
|
+
// Causa: Config sem useMemo
|
|
320
|
+
const config = generateCrudConfig(...); // ❌ Re-render infinito
|
|
162
321
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
description: string;
|
|
167
|
-
responsible_id: string;
|
|
168
|
-
status: 'pending' | 'in_progress' | 'done';
|
|
169
|
-
}
|
|
322
|
+
// Solução:
|
|
323
|
+
const config = useMemo(() => generateCrudConfig(...), []); // ✅
|
|
324
|
+
```
|
|
170
325
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
326
|
+
### 5️⃣ Estado reseta ao navegar
|
|
327
|
+
```typescript
|
|
328
|
+
// Causa: Outlet ausente
|
|
329
|
+
<Route path="/processes" element={<ProcessesPage />} /> // ❌
|
|
174
330
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
name: 'responsible_id',
|
|
191
|
-
label: 'Responsável',
|
|
192
|
-
type: 'custom',
|
|
193
|
-
component: QualiexUserField
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
name: 'status',
|
|
197
|
-
label: 'Status',
|
|
198
|
-
type: 'select',
|
|
199
|
-
options: [
|
|
200
|
-
{ value: 'pending', label: 'Pendente' },
|
|
201
|
-
{ value: 'in_progress', label: 'Em Progresso' },
|
|
202
|
-
{ value: 'done', label: 'Concluído' }
|
|
203
|
-
]
|
|
204
|
-
}
|
|
205
|
-
]
|
|
206
|
-
}
|
|
207
|
-
],
|
|
208
|
-
title: 'Tarefas'
|
|
209
|
-
});
|
|
331
|
+
// Solução: Layout com Outlet
|
|
332
|
+
<Route path="/processes" element={<ProcessLayout />}>
|
|
333
|
+
<Route index element={<ProcessesPage />} />
|
|
334
|
+
</Route>
|
|
335
|
+
// ProcessLayout: return <Outlet />; // ✅
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### 6️⃣ Qualiex retorna 401
|
|
339
|
+
```typescript
|
|
340
|
+
// Causa: Header ausente
|
|
341
|
+
fetch(url); // ❌
|
|
342
|
+
|
|
343
|
+
// Solução: Adicionar header
|
|
344
|
+
fetch(url, { headers: { 'un-alias': 'true' } }); // ✅
|
|
345
|
+
// (BaseService já faz automaticamente)
|
|
210
346
|
```
|
|
211
347
|
|
|
212
348
|
---
|
|
213
349
|
|
|
214
|
-
##
|
|
350
|
+
## 📐 CONTROLE DE LARGURA DAS COLUNAS
|
|
215
351
|
|
|
216
|
-
|
|
352
|
+
O `forlogic-core` oferece três formas de definir larguras de colunas nas tabelas CRUD:
|
|
217
353
|
|
|
218
|
-
|
|
354
|
+
### **1️⃣ Via `className` (Recomendado)**
|
|
355
|
+
Use classes do Tailwind para larguras fixas ou responsivas:
|
|
356
|
+
```typescript
|
|
357
|
+
const columns = [
|
|
358
|
+
{
|
|
359
|
+
key: 'status',
|
|
360
|
+
header: 'Status',
|
|
361
|
+
className: 'w-24 text-center', // Largura fixa: 96px
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
key: 'updated_at',
|
|
365
|
+
header: 'Atualizado em',
|
|
366
|
+
className: 'w-40 text-center whitespace-nowrap', // 160px, sem quebra
|
|
367
|
+
},
|
|
368
|
+
];
|
|
369
|
+
```
|
|
219
370
|
|
|
220
|
-
|
|
221
|
-
|
|
371
|
+
### **2️⃣ Via `width` (Fixo em pixels)**
|
|
372
|
+
Especifique largura fixa diretamente:
|
|
373
|
+
```typescript
|
|
374
|
+
{
|
|
375
|
+
key: 'order',
|
|
376
|
+
header: 'Ordem',
|
|
377
|
+
width: 60, // Largura fixa: 60px
|
|
378
|
+
className: 'text-center',
|
|
379
|
+
}
|
|
222
380
|
```
|
|
223
381
|
|
|
224
|
-
###
|
|
382
|
+
### **3️⃣ Via `minWidth` + `weight` (Flexível)**
|
|
383
|
+
Para colunas que crescem proporcionalmente:
|
|
384
|
+
```typescript
|
|
385
|
+
{
|
|
386
|
+
key: 'description',
|
|
387
|
+
header: 'Descrição',
|
|
388
|
+
minWidth: 200, // Mínimo: 200px
|
|
389
|
+
weight: 2, // 2x mais espaço que colunas padrão (weight: 1)
|
|
390
|
+
}
|
|
391
|
+
```
|
|
225
392
|
|
|
226
|
-
|
|
393
|
+
### **⚠️ Importante**
|
|
394
|
+
- A tabela usa `table-auto` para respeitar essas configurações
|
|
395
|
+
- Para truncar textos longos, use: `className: "max-w-[200px] truncate"`
|
|
396
|
+
- Combine `whitespace-nowrap` com largura fixa para evitar quebras
|
|
227
397
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
398
|
+
### **📋 Exemplo Completo**
|
|
399
|
+
```typescript
|
|
400
|
+
const columns: CrudColumn<MyEntity>[] = [
|
|
401
|
+
{
|
|
402
|
+
key: 'order',
|
|
403
|
+
header: 'Ordem',
|
|
404
|
+
width: 60, // Fixo: 60px
|
|
405
|
+
className: 'text-center',
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
key: 'title',
|
|
409
|
+
header: 'Título',
|
|
410
|
+
minWidth: 200, // Mínimo: 200px, cresce conforme espaço disponível
|
|
411
|
+
weight: 3, // 3x mais espaço que colunas padrão
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
key: 'status',
|
|
415
|
+
header: 'Status',
|
|
416
|
+
className: 'w-24 text-center', // Tailwind: 96px
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
key: 'progress',
|
|
420
|
+
header: 'Nível & Progresso',
|
|
421
|
+
className: 'w-40 text-center', // Tailwind: 160px
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
key: 'updated_at',
|
|
425
|
+
header: 'Atualizado em',
|
|
426
|
+
className: 'w-40 text-center whitespace-nowrap', // 160px, sem quebra
|
|
427
|
+
render: (item) => formatDate(item.updated_at)
|
|
428
|
+
},
|
|
429
|
+
];
|
|
234
430
|
```
|
|
235
431
|
|
|
236
432
|
---
|
|
237
433
|
|
|
238
|
-
##
|
|
434
|
+
## 📚 REFERÊNCIA RÁPIDA
|
|
435
|
+
|
|
436
|
+
### Imports Essenciais
|
|
437
|
+
```typescript
|
|
438
|
+
// CRUD
|
|
439
|
+
import {
|
|
440
|
+
createSimpleService,
|
|
441
|
+
createCrudPage,
|
|
442
|
+
generateCrudConfig,
|
|
443
|
+
createSimpleSaveHandler
|
|
444
|
+
} from 'forlogic-core';
|
|
445
|
+
|
|
446
|
+
// UI
|
|
447
|
+
import { Button, Input, Card, toast } from 'forlogic-core/ui';
|
|
239
448
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
449
|
+
// Auth
|
|
450
|
+
import { useAuth, ProtectedRoute } from 'forlogic-core';
|
|
451
|
+
|
|
452
|
+
// Qualiex
|
|
453
|
+
import { QualiexUserField, useQualiexUsers } from 'forlogic-core';
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Estrutura de Arquivos
|
|
457
|
+
```
|
|
458
|
+
src/
|
|
459
|
+
├── processes/
|
|
460
|
+
│ ├── process.ts # Types
|
|
461
|
+
│ ├── processService.ts # Service + Hook
|
|
462
|
+
│ └── ProcessesPage.tsx # Page + Config
|
|
463
|
+
```
|
|
243
464
|
|
|
244
465
|
---
|
|
245
466
|
|
|
246
467
|
## 📝 Licença
|
|
247
468
|
|
|
248
469
|
MIT License - ForLogic © 2025
|
|
470
|
+
|
|
471
|
+
**Última atualização:** 2025-10-05
|