forlogic-core 1.5.0 → 1.5.2
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 +21 -1116
- package/dist/README.md +248 -0
- package/dist/docs/AI_RULES.md +213 -0
- package/dist/docs/README.md +102 -0
- package/dist/docs/TROUBLESHOOTING.md +473 -0
- package/dist/docs/architecture/TOKENS_ARCHITECTURE.md +712 -0
- package/dist/docs/templates/app-layout.tsx +192 -0
- package/dist/docs/templates/basic-crud-page.tsx +97 -0
- package/dist/docs/templates/basic-crud-working.tsx +182 -0
- package/dist/docs/templates/complete-crud-example.tsx +307 -0
- package/dist/docs/templates/custom-form.tsx +99 -0
- package/dist/docs/templates/custom-service.tsx +194 -0
- package/dist/docs/templates/permission-check-hook.tsx +275 -0
- package/dist/docs/templates/qualiex-config.ts +137 -0
- package/dist/docs/templates/qualiex-integration-example.tsx +430 -0
- package/dist/docs/templates/quick-start-example.tsx +96 -0
- package/dist/docs/templates/rls-policies.sql +80 -0
- package/dist/docs/templates/sidebar-config.tsx +145 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -1
- package/dist/assets/index-C_ZLBeXY.css +0 -1
- package/dist/assets/index-wEAMQwsw.js +0 -7898
- package/dist/index.html +0 -19
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TEMPLATE: App Layout
|
|
3
|
+
* ⚠️ ORDEM DOS PROVIDERS É CRÍTICA: Consulte docs/AI_REFERENCE.md
|
|
4
|
+
*/
|
|
5
|
+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
|
|
6
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
7
|
+
import {
|
|
8
|
+
AuthProvider,
|
|
9
|
+
AppLayout,
|
|
10
|
+
ProtectedRoute,
|
|
11
|
+
SidebarConfig,
|
|
12
|
+
Toaster
|
|
13
|
+
} from 'forlogic-core'
|
|
14
|
+
import { Home, Users, Settings, BarChart3 } from 'lucide-react'
|
|
15
|
+
|
|
16
|
+
// Importar suas páginas
|
|
17
|
+
import { HomePage } from './pages/HomePage'
|
|
18
|
+
import { UsersPage } from './pages/UsersPage'
|
|
19
|
+
import { SettingsPage } from './pages/SettingsPage'
|
|
20
|
+
import { LoginPage } from './pages/LoginPage'
|
|
21
|
+
|
|
22
|
+
// Configurar React Query
|
|
23
|
+
const queryClient = new QueryClient({
|
|
24
|
+
defaultOptions: {
|
|
25
|
+
queries: {
|
|
26
|
+
staleTime: 5 * 60 * 1000, // 5 minutos
|
|
27
|
+
retry: 1
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Configuração da sidebar
|
|
33
|
+
const sidebarConfig: SidebarConfig = {
|
|
34
|
+
appName: 'APP_NAME',
|
|
35
|
+
navigation: [
|
|
36
|
+
{
|
|
37
|
+
label: 'Dashboard',
|
|
38
|
+
path: '/',
|
|
39
|
+
icon: BarChart3,
|
|
40
|
+
complementaryText: 'Visão geral do sistema'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'Usuários',
|
|
44
|
+
path: '/users',
|
|
45
|
+
icon: Users,
|
|
46
|
+
complementaryText: 'Gestão de usuários'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'Configurações',
|
|
50
|
+
path: '/settings',
|
|
51
|
+
icon: Settings,
|
|
52
|
+
complementaryText: 'Configurações do sistema'
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function App() {
|
|
58
|
+
return (
|
|
59
|
+
<QueryClientProvider client={queryClient}>
|
|
60
|
+
<AuthProvider>
|
|
61
|
+
<Router>
|
|
62
|
+
<Routes>
|
|
63
|
+
{/* Rota pública de login */}
|
|
64
|
+
<Route path="/login" element={<LoginPage />} />
|
|
65
|
+
|
|
66
|
+
{/* Rotas protegidas com layout */}
|
|
67
|
+
<Route path="/*" element={
|
|
68
|
+
<ProtectedRoute>
|
|
69
|
+
<AppLayout sidebarConfig={sidebarConfig}>
|
|
70
|
+
<Routes>
|
|
71
|
+
<Route path="/" element={<HomePage />} />
|
|
72
|
+
<Route path="/users" element={<UsersPage />} />
|
|
73
|
+
<Route path="/settings" element={<SettingsPage />} />
|
|
74
|
+
</Routes>
|
|
75
|
+
</AppLayout>
|
|
76
|
+
</ProtectedRoute>
|
|
77
|
+
} />
|
|
78
|
+
</Routes>
|
|
79
|
+
</Router>
|
|
80
|
+
<Toaster />
|
|
81
|
+
</AuthProvider>
|
|
82
|
+
</QueryClientProvider>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default App
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
ESTRUTURA ALTERNATIVA - Layout por Página:
|
|
90
|
+
|
|
91
|
+
Se preferir controlar o layout por página:
|
|
92
|
+
|
|
93
|
+
function App() {
|
|
94
|
+
return (
|
|
95
|
+
<QueryClientProvider client={queryClient}>
|
|
96
|
+
<AuthProvider>
|
|
97
|
+
<Router>
|
|
98
|
+
<Routes>
|
|
99
|
+
{/* Páginas sem layout */}
|
|
100
|
+
<Route path="/login" element={<LoginPage />} />
|
|
101
|
+
|
|
102
|
+
{/* Páginas com layout */}
|
|
103
|
+
<Route path="/" element={
|
|
104
|
+
<ProtectedRoute>
|
|
105
|
+
<AppLayout sidebarConfig={sidebarConfig}>
|
|
106
|
+
<HomePage />
|
|
107
|
+
</AppLayout>
|
|
108
|
+
</ProtectedRoute>
|
|
109
|
+
} />
|
|
110
|
+
|
|
111
|
+
<Route path="/users" element={
|
|
112
|
+
<ProtectedRoute>
|
|
113
|
+
<AppLayout sidebarConfig={sidebarConfig}>
|
|
114
|
+
<UsersPage />
|
|
115
|
+
</AppLayout>
|
|
116
|
+
</ProtectedRoute>
|
|
117
|
+
} />
|
|
118
|
+
</Routes>
|
|
119
|
+
</Router>
|
|
120
|
+
<Toaster />
|
|
121
|
+
</AuthProvider>
|
|
122
|
+
</QueryClientProvider>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
EXEMPLO DE PÁGINA DE LOGIN:
|
|
127
|
+
|
|
128
|
+
import { useState } from 'react'
|
|
129
|
+
import { Navigate } from 'react-router-dom'
|
|
130
|
+
import { useAuth, Button, Input, Card, CardContent, CardHeader, CardTitle } from 'forlogic-core'
|
|
131
|
+
|
|
132
|
+
export function LoginPage() {
|
|
133
|
+
const { user, login } = useAuth()
|
|
134
|
+
const [email, setEmail] = useState('')
|
|
135
|
+
const [password, setPassword] = useState('')
|
|
136
|
+
const [loading, setLoading] = useState(false)
|
|
137
|
+
|
|
138
|
+
if (user) {
|
|
139
|
+
return <Navigate to="/" replace />
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const handleLogin = async (e) => {
|
|
143
|
+
e.preventDefault()
|
|
144
|
+
setLoading(true)
|
|
145
|
+
try {
|
|
146
|
+
await login(email, password)
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('Erro no login:', error)
|
|
149
|
+
} finally {
|
|
150
|
+
setLoading(false)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
156
|
+
<Card className="w-full max-w-md">
|
|
157
|
+
<CardHeader>
|
|
158
|
+
<CardTitle>Entrar no Sistema</CardTitle>
|
|
159
|
+
</CardHeader>
|
|
160
|
+
<CardContent>
|
|
161
|
+
<form onSubmit={handleLogin} className="space-y-4">
|
|
162
|
+
<Input
|
|
163
|
+
type="email"
|
|
164
|
+
placeholder="Email"
|
|
165
|
+
value={email}
|
|
166
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
167
|
+
required
|
|
168
|
+
/>
|
|
169
|
+
<Input
|
|
170
|
+
type="password"
|
|
171
|
+
placeholder="Senha"
|
|
172
|
+
value={password}
|
|
173
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
174
|
+
required
|
|
175
|
+
/>
|
|
176
|
+
<Button type="submit" className="w-full" disabled={loading}>
|
|
177
|
+
{loading ? 'Entrando...' : 'Entrar'}
|
|
178
|
+
</Button>
|
|
179
|
+
</form>
|
|
180
|
+
</CardContent>
|
|
181
|
+
</Card>
|
|
182
|
+
</div>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
CONFIGURAÇÃO DE AMBIENTE:
|
|
187
|
+
|
|
188
|
+
Certifique-se de ter as variáveis de ambiente configuradas:
|
|
189
|
+
|
|
190
|
+
REACT_APP_SUPABASE_URL=your_supabase_url
|
|
191
|
+
REACT_APP_SUPABASE_ANON_KEY=your_supabase_anon_key
|
|
192
|
+
*/
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TEMPLATE: CRUD Básico
|
|
3
|
+
* ⚠️ REGRAS: Consulte docs/AI_REFERENCE.md
|
|
4
|
+
*/
|
|
5
|
+
import { createSimpleService, createCrudPage, createSimpleSaveHandler } from 'forlogic-core';
|
|
6
|
+
|
|
7
|
+
// 1. Definir interfaces
|
|
8
|
+
interface ENTITY_INTERFACE {
|
|
9
|
+
id: string;
|
|
10
|
+
FIELD_NAME: FIELD_TYPE;
|
|
11
|
+
created_at?: Date;
|
|
12
|
+
updated_at?: Date;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CreateENTITY_INTERFACEPayload {
|
|
16
|
+
FIELD_NAME: FIELD_TYPE;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface UpdateENTITY_INTERFACEPayload {
|
|
20
|
+
FIELD_NAME: FIELD_TYPE;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 2. Criar service
|
|
24
|
+
const { service: SERVICE_NAME, useCrudHook: useENTITY_NAMECrud } =
|
|
25
|
+
createSimpleService<ENTITY_INTERFACE, CreateENTITY_INTERFACEPayload, UpdateENTITY_INTERFACEPayload>({
|
|
26
|
+
tableName: 'TABLE_NAME',
|
|
27
|
+
entityName: 'ENTITY_NAME_SINGULAR',
|
|
28
|
+
searchFields: ['FIELD_NAME'],
|
|
29
|
+
schemaName: 'YOUR_SCHEMA' // Use o schema do seu projeto (ex: 'central', 'trainings', 'public')
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 3. Criar página
|
|
33
|
+
export const ENTITY_NAMEPage = () => {
|
|
34
|
+
const manager = useENTITY_NAMECrud();
|
|
35
|
+
|
|
36
|
+
const handleSave = createSimpleSaveHandler<ENTITY_INTERFACE, CreateENTITY_INTERFACEPayload, UpdateENTITY_INTERFACEPayload>(
|
|
37
|
+
manager,
|
|
38
|
+
(data) => ({ FIELD_NAME: data.FIELD_NAME }),
|
|
39
|
+
(data) => ({ FIELD_NAME: data.FIELD_NAME })
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const CrudPageComponent = createCrudPage({
|
|
43
|
+
manager,
|
|
44
|
+
config: {
|
|
45
|
+
entityName: 'ENTITY_NAME_SINGULAR',
|
|
46
|
+
entityNamePlural: 'ENTITY_PLURAL',
|
|
47
|
+
columns: [
|
|
48
|
+
{ key: 'FIELD_NAME', label: 'FIELD_LABEL', type: 'FIELD_TYPE' as const }
|
|
49
|
+
],
|
|
50
|
+
formSections: [
|
|
51
|
+
{
|
|
52
|
+
id: 'basic',
|
|
53
|
+
title: 'Informações',
|
|
54
|
+
fields: [
|
|
55
|
+
{ name: 'FIELD_NAME', label: 'FIELD_LABEL', type: 'FIELD_TYPE', required: true }
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
onSave: handleSave
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return <CrudPageComponent />;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
INSTRUÇÕES DE USO:
|
|
68
|
+
|
|
69
|
+
1. Substitua os placeholders:
|
|
70
|
+
- ENTITY_NAME: Nome do componente (ex: Products)
|
|
71
|
+
- ENTITY_INTERFACE: Interface TypeScript (ex: Product)
|
|
72
|
+
- ENTITY_NAME_SINGULAR: Nome singular em português (ex: produto)
|
|
73
|
+
- ENTITY_PLURAL: Nome plural em português (ex: Produtos)
|
|
74
|
+
- TABLE_NAME: Nome da tabela no Supabase (ex: products)
|
|
75
|
+
- FIELD_NAME: Nome do campo (ex: name)
|
|
76
|
+
- FIELD_LABEL: Label do campo (ex: Nome)
|
|
77
|
+
- FIELD_TYPE: Tipo TypeScript (ex: string, number, boolean)
|
|
78
|
+
|
|
79
|
+
2. Adicione ao router:
|
|
80
|
+
<Route path="/ROUTE_PATH" element={<ENTITY_NAMEPage />} />
|
|
81
|
+
|
|
82
|
+
3. Adicione à sidebar se necessário:
|
|
83
|
+
{ label: 'LABEL', path: '/ROUTE_PATH', icon: ICON_NAME }
|
|
84
|
+
|
|
85
|
+
4. Este padrão garante:
|
|
86
|
+
✅ Interface CRUD completa
|
|
87
|
+
✅ Formulário com validação
|
|
88
|
+
✅ Tabela com ações
|
|
89
|
+
✅ Estados de loading
|
|
90
|
+
✅ UPDATE que funciona corretamente (preserva ID)
|
|
91
|
+
✅ Tratamento de erros
|
|
92
|
+
|
|
93
|
+
IMPORTANTE:
|
|
94
|
+
- SEMPRE use useCrudHook() dentro do componente
|
|
95
|
+
- SEMPRE use createSimpleSaveHandler para garantir UPDATE correto
|
|
96
|
+
- NUNCA passe service diretamente para createCrudPage (causa erro "isLoading is undefined")
|
|
97
|
+
*/
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TEMPLATE: CRUD 100% Funcional
|
|
3
|
+
* ⚠️ REGRAS: Consulte docs/AI_REFERENCE.md
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createSimpleService, createCrudPage, createSimpleSaveHandler } from 'forlogic-core';
|
|
7
|
+
|
|
8
|
+
// ============= PASSO 1: DEFINIR TIPOS =============
|
|
9
|
+
|
|
10
|
+
interface MyEntity {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
active: boolean;
|
|
15
|
+
created_at?: Date;
|
|
16
|
+
updated_at?: Date;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface CreateMyEntityPayload {
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
active: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface UpdateMyEntityPayload {
|
|
26
|
+
title: string;
|
|
27
|
+
description: string;
|
|
28
|
+
active: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ============= PASSO 2: CRIAR SERVICE =============
|
|
32
|
+
|
|
33
|
+
const { service, useCrudHook } = createSimpleService<MyEntity, CreateMyEntityPayload, UpdateMyEntityPayload>({
|
|
34
|
+
tableName: 'my_entities', // Nome da tabela no Supabase
|
|
35
|
+
entityName: 'minha entidade', // Nome singular (para mensagens)
|
|
36
|
+
searchFields: ['title', 'description'], // Campos pesquisáveis
|
|
37
|
+
schemaName: 'YOUR_SCHEMA', // Use o schema do seu projeto (ex: 'central', 'trainings', 'public')
|
|
38
|
+
enableQualiexEnrichment: true // Enriquecimento automático com dados do Qualiex
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ============= PASSO 3: CRIAR COMPONENTE DA PÁGINA =============
|
|
42
|
+
|
|
43
|
+
export const MyEntitiesPage = () => {
|
|
44
|
+
// Hook que retorna o manager com todos os métodos CRUD
|
|
45
|
+
const manager = useCrudHook();
|
|
46
|
+
|
|
47
|
+
// Handler que garante que UPDATE preserva o ID
|
|
48
|
+
const handleSave = createSimpleSaveHandler<MyEntity, CreateMyEntityPayload, UpdateMyEntityPayload>(
|
|
49
|
+
manager,
|
|
50
|
+
// Transform CREATE - define campos do payload de criação
|
|
51
|
+
(data) => ({
|
|
52
|
+
title: data.title,
|
|
53
|
+
description: data.description || '',
|
|
54
|
+
active: data.active ?? true
|
|
55
|
+
}),
|
|
56
|
+
// Transform UPDATE - define campos do payload de atualização
|
|
57
|
+
(data) => ({
|
|
58
|
+
title: data.title,
|
|
59
|
+
description: data.description || '',
|
|
60
|
+
active: data.active
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Cria o componente da página CRUD
|
|
65
|
+
const CrudPageComponent = createCrudPage({
|
|
66
|
+
manager, // SEMPRE passe manager aqui, NUNCA service
|
|
67
|
+
config: {
|
|
68
|
+
entityName: 'Minha Entidade',
|
|
69
|
+
entityNamePlural: 'Minhas Entidades',
|
|
70
|
+
|
|
71
|
+
// Colunas da tabela
|
|
72
|
+
columns: [
|
|
73
|
+
{
|
|
74
|
+
key: 'title',
|
|
75
|
+
label: 'Título',
|
|
76
|
+
type: 'text' as const,
|
|
77
|
+
required: true,
|
|
78
|
+
searchable: true
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
key: 'description',
|
|
82
|
+
label: 'Descrição',
|
|
83
|
+
type: 'text' as const
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: 'active',
|
|
87
|
+
label: 'Ativo',
|
|
88
|
+
type: 'boolean' as const
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
|
|
92
|
+
// Seções do formulário
|
|
93
|
+
formSections: [
|
|
94
|
+
{
|
|
95
|
+
id: 'basic-info',
|
|
96
|
+
title: 'Informações Básicas',
|
|
97
|
+
fields: [
|
|
98
|
+
{
|
|
99
|
+
name: 'title',
|
|
100
|
+
label: 'Título',
|
|
101
|
+
type: 'text',
|
|
102
|
+
required: true,
|
|
103
|
+
placeholder: 'Digite o título'
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'description',
|
|
107
|
+
label: 'Descrição',
|
|
108
|
+
type: 'textarea',
|
|
109
|
+
placeholder: 'Digite a descrição (opcional)'
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'active',
|
|
113
|
+
label: 'Ativo',
|
|
114
|
+
type: 'boolean'
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
onSave: handleSave // Handler que garante UPDATE correto
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return <CrudPageComponent />;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// ============= CHECKLIST DE USO =============
|
|
127
|
+
/*
|
|
128
|
+
✅ Definir interface da entidade (MyEntity)
|
|
129
|
+
✅ Definir interfaces de payload (CreateMyEntityPayload, UpdateMyEntityPayload)
|
|
130
|
+
✅ Criar service com createSimpleService
|
|
131
|
+
✅ Usar useCrudHook() dentro do componente
|
|
132
|
+
✅ Criar handleSave com createSimpleSaveHandler
|
|
133
|
+
✅ Passar manager (não service) para createCrudPage
|
|
134
|
+
✅ Configurar columns e formSections
|
|
135
|
+
✅ Adicionar rota no router
|
|
136
|
+
✅ Adicionar item na sidebar se necessário
|
|
137
|
+
|
|
138
|
+
❌ ERROS COMUNS A EVITAR:
|
|
139
|
+
- Passar service para createCrudPage (causa "isLoading is undefined")
|
|
140
|
+
- Não usar createSimpleSaveHandler (causa UPDATE criar novo registro)
|
|
141
|
+
- Esquecer de chamar useCrudHook() (sem manager, componente quebra)
|
|
142
|
+
- Usar interface errada para payloads (validação falha)
|
|
143
|
+
*/
|
|
144
|
+
|
|
145
|
+
// ============= EXEMPLOS DE CAMPOS ESPECIAIS =============
|
|
146
|
+
/*
|
|
147
|
+
// Campo select com opções fixas:
|
|
148
|
+
{
|
|
149
|
+
name: 'category',
|
|
150
|
+
label: 'Categoria',
|
|
151
|
+
type: 'select',
|
|
152
|
+
options: [
|
|
153
|
+
{ label: 'Opção 1', value: 'opt1' },
|
|
154
|
+
{ label: 'Opção 2', value: 'opt2' }
|
|
155
|
+
],
|
|
156
|
+
required: true
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Campo de usuário do Qualiex:
|
|
160
|
+
{
|
|
161
|
+
name: 'id_user',
|
|
162
|
+
label: 'Responsável',
|
|
163
|
+
type: 'simple-qualiex-user-field',
|
|
164
|
+
required: true
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Campo de data:
|
|
168
|
+
{
|
|
169
|
+
name: 'due_date',
|
|
170
|
+
label: 'Data de Vencimento',
|
|
171
|
+
type: 'date'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Campo numérico:
|
|
175
|
+
{
|
|
176
|
+
name: 'quantity',
|
|
177
|
+
label: 'Quantidade',
|
|
178
|
+
type: 'number',
|
|
179
|
+
min: 0,
|
|
180
|
+
step: 1
|
|
181
|
+
}
|
|
182
|
+
*/
|