@fayz-ai/plugin-forms 0.9.0 → 0.9.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 +3 -3
- package/dist/{FormBuilder-7SWZQKFN.js → FormBuilder-YHJHF6HZ.js} +4 -4
- package/dist/{FormBuilder-7SWZQKFN.js.map → FormBuilder-YHJHF6HZ.js.map} +1 -1
- package/dist/{chunk-W2ZNJGQC.js → chunk-RBLXIKWB.js} +221 -8
- package/dist/chunk-RBLXIKWB.js.map +1 -0
- package/dist/components/AddDocumentDropdown.d.ts +1 -1
- package/dist/components/AddDocumentDropdown.d.ts.map +1 -1
- package/dist/components/DocumentFormDialog.d.ts.map +1 -1
- package/dist/components/DocumentSkeleton.d.ts +21 -0
- package/dist/components/DocumentSkeleton.d.ts.map +1 -0
- package/dist/components/FormRenderer.d.ts.map +1 -1
- package/dist/components/FormViewer.d.ts.map +1 -1
- package/dist/{CustomFormsContext.d.ts → context.d.ts} +1 -1
- package/dist/context.d.ts.map +1 -0
- package/dist/data/mock.d.ts.map +1 -1
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/types.d.ts +4 -1
- package/dist/data/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +174 -17
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-tools.d.ts.map +1 -0
- package/dist/lib/document-types.d.ts.map +1 -0
- package/dist/lib/html-text.d.ts +21 -0
- package/dist/lib/html-text.d.ts.map +1 -0
- package/dist/lib/print.d.ts.map +1 -1
- package/dist/lib/timeline-source.d.ts +10 -0
- package/dist/lib/timeline-source.d.ts.map +1 -0
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/store.d.ts +5 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/views/TemplateListView.d.ts.map +1 -1
- package/package.json +5 -7
- package/dist/CustomFormsContext.d.ts.map +0 -1
- package/dist/agent-tools.d.ts.map +0 -1
- package/dist/chunk-W2ZNJGQC.js.map +0 -1
- package/dist/document-types.d.ts.map +0 -1
- package/src/CustomFormsContext.tsx +0 -28
- package/src/agent-tools.ts +0 -73
- package/src/components/AddDocumentDropdown.tsx +0 -92
- package/src/components/BuilderCanvas.tsx +0 -87
- package/src/components/BuilderField.tsx +0 -81
- package/src/components/DocumentFormDialog.tsx +0 -155
- package/src/components/DocumentList.tsx +0 -254
- package/src/components/FieldConfigDialog.tsx +0 -243
- package/src/components/FieldPalette.tsx +0 -81
- package/src/components/FormBuilder.tsx +0 -427
- package/src/components/FormRenderer.tsx +0 -256
- package/src/components/FormViewer.tsx +0 -94
- package/src/components/PersonDocumentsWidget.tsx +0 -229
- package/src/components/TemplateSelector.tsx +0 -91
- package/src/config.ts +0 -43
- package/src/data/index.ts +0 -3
- package/src/data/mock.ts +0 -193
- package/src/data/supabase.ts +0 -408
- package/src/data/tables.ts +0 -7
- package/src/data/types.ts +0 -33
- package/src/document-types.ts +0 -51
- package/src/index.ts +0 -234
- package/src/lib/person-fields.ts +0 -67
- package/src/lib/print.ts +0 -207
- package/src/lib/tenant.ts +0 -9
- package/src/locales/en.ts +0 -95
- package/src/locales/index.ts +0 -7
- package/src/locales/pt-BR.ts +0 -95
- package/src/migrations/000_plg_rename.sql +0 -21
- package/src/migrations/001_frm_base.sql +0 -174
- package/src/migrations/002_document_archetype.sql +0 -223
- package/src/migrations/003_agent_rpcs.sql +0 -174
- package/src/migrations/index.ts +0 -610
- package/src/store.ts +0 -167
- package/src/types.ts +0 -217
- package/src/views/CustomFormsSettingsTab.tsx +0 -105
- package/src/views/TemplateListView.tsx +0 -174
- /package/dist/{agent-tools.d.ts → lib/agent-tools.d.ts} +0 -0
- /package/dist/{document-types.d.ts → lib/document-types.d.ts} +0 -0
package/src/data/supabase.ts
DELETED
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
import { getFormsTenantId } from '../lib/tenant'
|
|
2
|
-
import type { CustomFormsDataProvider } from './types'
|
|
3
|
-
import type {
|
|
4
|
-
FormTemplate,
|
|
5
|
-
FormDocument,
|
|
6
|
-
DocumentFile,
|
|
7
|
-
TemplateQuery,
|
|
8
|
-
DocumentQuery,
|
|
9
|
-
PaginatedResult,
|
|
10
|
-
CreateTemplateInput,
|
|
11
|
-
UpdateTemplateInput,
|
|
12
|
-
CreateDocumentInput,
|
|
13
|
-
UpdateDocumentInput,
|
|
14
|
-
} from '../types'
|
|
15
|
-
import { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'
|
|
16
|
-
import { T } from './tables'
|
|
17
|
-
|
|
18
|
-
function getTenantId(): string {
|
|
19
|
-
// Local override wins; else use the app's active tenant so writes pass RLS.
|
|
20
|
-
return getFormsTenantId() ?? getActiveTenantId() ?? ''
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function getClient() {
|
|
24
|
-
const supabase = getSupabaseClientOptional() as any
|
|
25
|
-
if (!supabase) throw new Error('Supabase not initialized')
|
|
26
|
-
return supabase
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
function mapTemplate(r: any): FormTemplate {
|
|
31
|
-
return {
|
|
32
|
-
id: r.id,
|
|
33
|
-
tenantId: r.tenant_id,
|
|
34
|
-
name: r.name,
|
|
35
|
-
description: r.description,
|
|
36
|
-
category: r.category,
|
|
37
|
-
version: r.version,
|
|
38
|
-
isCurrent: r.is_current,
|
|
39
|
-
parentId: r.parent_id,
|
|
40
|
-
schema: r.schema,
|
|
41
|
-
specialty: r.specialty,
|
|
42
|
-
tags: r.tags ?? [],
|
|
43
|
-
metadata: r.metadata ?? {},
|
|
44
|
-
isActive: r.is_active,
|
|
45
|
-
isDeleted: r.is_deleted,
|
|
46
|
-
createdBy: r.created_by,
|
|
47
|
-
updatedBy: r.updated_by,
|
|
48
|
-
createdAt: r.created_at,
|
|
49
|
-
updatedAt: r.updated_at,
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function mapDocument(r: any): FormDocument {
|
|
54
|
-
return {
|
|
55
|
-
id: r.id,
|
|
56
|
-
tenantId: r.tenant_id,
|
|
57
|
-
templateId: r.template_id ?? '',
|
|
58
|
-
templateName: r.template_name,
|
|
59
|
-
templateCategory: r.template_category,
|
|
60
|
-
personId: r.person_id,
|
|
61
|
-
personName: r.person_name,
|
|
62
|
-
title: r.title,
|
|
63
|
-
data: r.form_data ?? {},
|
|
64
|
-
status: r.status,
|
|
65
|
-
signedAt: r.signed_at,
|
|
66
|
-
signedBy: r.signed_by,
|
|
67
|
-
notes: r.notes,
|
|
68
|
-
metadata: r.metadata ?? {},
|
|
69
|
-
isDeleted: false,
|
|
70
|
-
createdBy: r.created_by,
|
|
71
|
-
updatedBy: r.updated_by,
|
|
72
|
-
createdAt: r.created_at,
|
|
73
|
-
updatedAt: r.updated_at,
|
|
74
|
-
// Extra fields from core document
|
|
75
|
-
kind: r.kind,
|
|
76
|
-
fileUrl: r.file_url,
|
|
77
|
-
fileName: r.file_name,
|
|
78
|
-
fileSize: r.file_size,
|
|
79
|
-
mimeType: r.mime_type,
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function mapFile(r: any): DocumentFile {
|
|
84
|
-
return {
|
|
85
|
-
id: r.id,
|
|
86
|
-
tenantId: r.tenant_id,
|
|
87
|
-
documentId: r.document_id,
|
|
88
|
-
fieldKey: r.field_key,
|
|
89
|
-
fileUrl: r.file_url,
|
|
90
|
-
fileName: r.file_name,
|
|
91
|
-
fileSize: r.file_size,
|
|
92
|
-
mimeType: r.mime_type,
|
|
93
|
-
sortOrder: r.sort_order,
|
|
94
|
-
metadata: r.metadata ?? {},
|
|
95
|
-
createdAt: r.created_at,
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function createSupabaseFormsProvider(): CustomFormsDataProvider {
|
|
100
|
-
return {
|
|
101
|
-
// ── Templates ──────────────────────────────────────────
|
|
102
|
-
|
|
103
|
-
async getTemplates(query: TemplateQuery): Promise<PaginatedResult<FormTemplate>> {
|
|
104
|
-
const db = getClient()
|
|
105
|
-
let qb = db
|
|
106
|
-
.from(T.templates)
|
|
107
|
-
.select('*', { count: 'exact' })
|
|
108
|
-
.eq('tenant_id', getTenantId())
|
|
109
|
-
.eq('is_current', true)
|
|
110
|
-
.eq('is_deleted', false)
|
|
111
|
-
// Archived templates (isActive=false) leave the list and the picker.
|
|
112
|
-
.eq('is_active', true)
|
|
113
|
-
|
|
114
|
-
if (query.category) qb = qb.eq('category', query.category)
|
|
115
|
-
if (query.search) qb = qb.ilike('name', `%${query.search}%`)
|
|
116
|
-
|
|
117
|
-
const page = query.page ?? 1
|
|
118
|
-
const pageSize = query.pageSize ?? 25
|
|
119
|
-
qb = qb
|
|
120
|
-
.order('updated_at', { ascending: false })
|
|
121
|
-
.range((page - 1) * pageSize, page * pageSize - 1)
|
|
122
|
-
|
|
123
|
-
const { data, count, error } = await qb
|
|
124
|
-
if (error) throw new Error(error.message)
|
|
125
|
-
return { data: (data ?? []).map(mapTemplate), total: count ?? 0 }
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
async getTemplateById(id: string): Promise<FormTemplate | null> {
|
|
129
|
-
const db = getClient()
|
|
130
|
-
const { data, error } = await db
|
|
131
|
-
.from(T.templates)
|
|
132
|
-
.select('*')
|
|
133
|
-
.eq('id', id)
|
|
134
|
-
.eq('is_deleted', false)
|
|
135
|
-
.single()
|
|
136
|
-
if (error || !data) return null
|
|
137
|
-
return mapTemplate(data)
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
async createTemplate(input: CreateTemplateInput): Promise<FormTemplate> {
|
|
141
|
-
const db = getClient()
|
|
142
|
-
const tenantId = getTenantId()
|
|
143
|
-
const { data, error } = await db
|
|
144
|
-
.from(T.templates)
|
|
145
|
-
.insert({
|
|
146
|
-
tenant_id: tenantId,
|
|
147
|
-
name: input.name,
|
|
148
|
-
description: input.description,
|
|
149
|
-
category: input.category,
|
|
150
|
-
schema: input.schema,
|
|
151
|
-
specialty: input.specialty,
|
|
152
|
-
tags: input.tags ?? [],
|
|
153
|
-
metadata: input.metadata ?? {},
|
|
154
|
-
})
|
|
155
|
-
.select()
|
|
156
|
-
.single()
|
|
157
|
-
if (error) throw new Error(error.message)
|
|
158
|
-
return mapTemplate(data)
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
async updateTemplate(id: string, input: UpdateTemplateInput): Promise<FormTemplate> {
|
|
162
|
-
const db = getClient()
|
|
163
|
-
const tenantId = getTenantId()
|
|
164
|
-
|
|
165
|
-
const { count } = await db
|
|
166
|
-
.from(T.documents)
|
|
167
|
-
.select('document_id', { count: 'exact', head: true })
|
|
168
|
-
.eq('template_id', id)
|
|
169
|
-
|
|
170
|
-
const hasDocuments = (count ?? 0) > 0
|
|
171
|
-
|
|
172
|
-
if (hasDocuments && input.schema) {
|
|
173
|
-
const existing = await this.getTemplateById(id)
|
|
174
|
-
if (!existing) throw new Error('Template not found')
|
|
175
|
-
|
|
176
|
-
const { data: newRow, error: insertError } = await db
|
|
177
|
-
.from(T.templates)
|
|
178
|
-
.insert({
|
|
179
|
-
tenant_id: tenantId,
|
|
180
|
-
name: input.name ?? existing.name,
|
|
181
|
-
description: input.description ?? existing.description,
|
|
182
|
-
category: input.category ?? existing.category,
|
|
183
|
-
schema: input.schema,
|
|
184
|
-
specialty: input.specialty ?? existing.specialty,
|
|
185
|
-
tags: input.tags ?? existing.tags,
|
|
186
|
-
metadata: input.metadata ?? existing.metadata,
|
|
187
|
-
is_active: input.isActive ?? existing.isActive,
|
|
188
|
-
version: existing.version + 1,
|
|
189
|
-
is_current: true,
|
|
190
|
-
parent_id: existing.parentId ?? existing.id,
|
|
191
|
-
})
|
|
192
|
-
.select()
|
|
193
|
-
.single()
|
|
194
|
-
if (insertError) throw new Error(insertError.message)
|
|
195
|
-
|
|
196
|
-
await db
|
|
197
|
-
.from(T.templates)
|
|
198
|
-
.update({ is_current: false, updated_at: new Date().toISOString() })
|
|
199
|
-
.eq('id', id)
|
|
200
|
-
|
|
201
|
-
return mapTemplate(newRow)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const updates: Record<string, unknown> = { updated_at: new Date().toISOString() }
|
|
205
|
-
if (input.name !== undefined) updates.name = input.name
|
|
206
|
-
if (input.description !== undefined) updates.description = input.description
|
|
207
|
-
if (input.category !== undefined) updates.category = input.category
|
|
208
|
-
if (input.schema !== undefined) updates.schema = input.schema
|
|
209
|
-
if (input.specialty !== undefined) updates.specialty = input.specialty
|
|
210
|
-
if (input.tags !== undefined) updates.tags = input.tags
|
|
211
|
-
if (input.metadata !== undefined) updates.metadata = input.metadata
|
|
212
|
-
if (input.isActive !== undefined) updates.is_active = input.isActive
|
|
213
|
-
|
|
214
|
-
const { data, error } = await db
|
|
215
|
-
.from(T.templates)
|
|
216
|
-
.update(updates)
|
|
217
|
-
.eq('id', id)
|
|
218
|
-
.select()
|
|
219
|
-
.single()
|
|
220
|
-
if (error) throw new Error(error.message)
|
|
221
|
-
return mapTemplate(data)
|
|
222
|
-
},
|
|
223
|
-
|
|
224
|
-
async deleteTemplate(id: string): Promise<void> {
|
|
225
|
-
const db = getClient()
|
|
226
|
-
const { error } = await db
|
|
227
|
-
.from(T.templates)
|
|
228
|
-
.update({ is_deleted: true, updated_at: new Date().toISOString() })
|
|
229
|
-
.eq('id', id)
|
|
230
|
-
if (error) throw new Error(error.message)
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
// ── Documents (public.documents + plg_forms_documents extension) ──
|
|
234
|
-
|
|
235
|
-
async getDocuments(query: DocumentQuery): Promise<PaginatedResult<FormDocument>> {
|
|
236
|
-
const db = getClient()
|
|
237
|
-
// Query through the v_documents view (joins core + form extension)
|
|
238
|
-
let qb = db
|
|
239
|
-
.from('v_documents')
|
|
240
|
-
.select('*', { count: 'exact' })
|
|
241
|
-
.eq('tenant_id', getTenantId())
|
|
242
|
-
.eq('is_active', true)
|
|
243
|
-
|
|
244
|
-
if (query.personId) qb = qb.eq('person_id', query.personId)
|
|
245
|
-
if (query.templateId) qb = qb.eq('template_id', query.templateId)
|
|
246
|
-
if (query.status) {
|
|
247
|
-
const statuses = Array.isArray(query.status) ? query.status : [query.status]
|
|
248
|
-
qb = qb.in('status', statuses)
|
|
249
|
-
}
|
|
250
|
-
if (query.search) qb = qb.or(`title.ilike.%${query.search}%,template_name.ilike.%${query.search}%`)
|
|
251
|
-
|
|
252
|
-
const page = query.page ?? 1
|
|
253
|
-
const pageSize = query.pageSize ?? 50
|
|
254
|
-
qb = qb
|
|
255
|
-
.order('created_at', { ascending: false })
|
|
256
|
-
.range((page - 1) * pageSize, page * pageSize - 1)
|
|
257
|
-
|
|
258
|
-
const { data, count, error } = await qb
|
|
259
|
-
if (error) throw new Error(error.message)
|
|
260
|
-
return { data: (data ?? []).map(mapDocument), total: count ?? 0 }
|
|
261
|
-
},
|
|
262
|
-
|
|
263
|
-
async getDocumentById(id: string): Promise<FormDocument | null> {
|
|
264
|
-
const db = getClient()
|
|
265
|
-
const { data, error } = await db
|
|
266
|
-
.from('v_documents')
|
|
267
|
-
.select('*')
|
|
268
|
-
.eq('id', id)
|
|
269
|
-
.single()
|
|
270
|
-
if (error || !data) return null
|
|
271
|
-
return mapDocument(data)
|
|
272
|
-
},
|
|
273
|
-
|
|
274
|
-
async createDocument(input: CreateDocumentInput): Promise<FormDocument> {
|
|
275
|
-
const tenantId = getTenantId()
|
|
276
|
-
const isForm = !!input.templateId
|
|
277
|
-
|
|
278
|
-
// Step 1: Insert into public.documents
|
|
279
|
-
const { data: coreDoc, error: coreError } = await getClient()
|
|
280
|
-
.from('documents')
|
|
281
|
-
.insert({
|
|
282
|
-
tenant_id: tenantId,
|
|
283
|
-
kind: input.kind ?? (isForm ? 'form' : 'attachment'),
|
|
284
|
-
person_id: input.personId,
|
|
285
|
-
title: input.title,
|
|
286
|
-
status: input.status ?? 'draft',
|
|
287
|
-
file_url: input.fileUrl,
|
|
288
|
-
file_name: input.fileName,
|
|
289
|
-
file_size: input.fileSize,
|
|
290
|
-
mime_type: input.mimeType,
|
|
291
|
-
metadata: {},
|
|
292
|
-
})
|
|
293
|
-
.select()
|
|
294
|
-
.single()
|
|
295
|
-
if (coreError) throw new Error(coreError.message)
|
|
296
|
-
|
|
297
|
-
// Step 2: For form documents, insert extension row
|
|
298
|
-
if (isForm && input.templateId) {
|
|
299
|
-
const db = getClient()
|
|
300
|
-
const { error: extError } = await db
|
|
301
|
-
.from(T.documents)
|
|
302
|
-
.insert({
|
|
303
|
-
document_id: coreDoc.id,
|
|
304
|
-
tenant_id: tenantId,
|
|
305
|
-
template_id: input.templateId,
|
|
306
|
-
data: input.data ?? {},
|
|
307
|
-
})
|
|
308
|
-
if (extError) {
|
|
309
|
-
// Rollback core insert
|
|
310
|
-
await getClient().from('documents').delete().eq('id', coreDoc.id)
|
|
311
|
-
throw new Error(extError.message)
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Fetch via view to get joined data
|
|
316
|
-
const doc = await this.getDocumentById(coreDoc.id)
|
|
317
|
-
return doc!
|
|
318
|
-
},
|
|
319
|
-
|
|
320
|
-
async updateDocument(id: string, input: UpdateDocumentInput): Promise<FormDocument> {
|
|
321
|
-
const now = new Date().toISOString()
|
|
322
|
-
|
|
323
|
-
// Update core document fields
|
|
324
|
-
const coreUpdates: Record<string, unknown> = { updated_at: now }
|
|
325
|
-
if (input.status !== undefined) coreUpdates.status = input.status
|
|
326
|
-
if (input.title !== undefined) coreUpdates.title = input.title
|
|
327
|
-
if (input.notes !== undefined) coreUpdates.notes = input.notes
|
|
328
|
-
|
|
329
|
-
const { error: coreError } = await getClient()
|
|
330
|
-
.from('documents')
|
|
331
|
-
.update(coreUpdates)
|
|
332
|
-
.eq('id', id)
|
|
333
|
-
if (coreError) throw new Error(coreError.message)
|
|
334
|
-
|
|
335
|
-
// Update form extension if data is provided
|
|
336
|
-
if (input.data !== undefined) {
|
|
337
|
-
const db = getClient()
|
|
338
|
-
await db
|
|
339
|
-
.from(T.documents)
|
|
340
|
-
.update({ data: input.data, updated_at: now })
|
|
341
|
-
.eq('document_id', id)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const doc = await this.getDocumentById(id)
|
|
345
|
-
return doc!
|
|
346
|
-
},
|
|
347
|
-
|
|
348
|
-
async deleteDocument(id: string): Promise<void> {
|
|
349
|
-
const { error } = await getClient()
|
|
350
|
-
.from('documents')
|
|
351
|
-
.update({ is_active: false, updated_at: new Date().toISOString() })
|
|
352
|
-
.eq('id', id)
|
|
353
|
-
if (error) throw new Error(error.message)
|
|
354
|
-
},
|
|
355
|
-
|
|
356
|
-
// ── Files ──────────────────────────────────────────────
|
|
357
|
-
|
|
358
|
-
async getDocumentFiles(documentId: string): Promise<DocumentFile[]> {
|
|
359
|
-
const db = getClient()
|
|
360
|
-
const { data, error } = await db
|
|
361
|
-
.from(T.documentFiles)
|
|
362
|
-
.select('*')
|
|
363
|
-
.eq('document_id', documentId)
|
|
364
|
-
.order('sort_order')
|
|
365
|
-
if (error) throw new Error(error.message)
|
|
366
|
-
return (data ?? []).map(mapFile)
|
|
367
|
-
},
|
|
368
|
-
|
|
369
|
-
async uploadFile(documentId: string, fieldKey: string, file: File): Promise<DocumentFile> {
|
|
370
|
-
const db = getClient()
|
|
371
|
-
const tenantId = getTenantId()
|
|
372
|
-
const ext = file.name.split('.').pop() ?? 'bin'
|
|
373
|
-
const storagePath = `${tenantId}/forms/${documentId}/${fieldKey}/${crypto.randomUUID()}.${ext}`
|
|
374
|
-
|
|
375
|
-
const { error: uploadError } = await db.storage
|
|
376
|
-
.from('documents')
|
|
377
|
-
.upload(storagePath, file, { contentType: file.type })
|
|
378
|
-
if (uploadError) throw new Error(uploadError.message)
|
|
379
|
-
|
|
380
|
-
const { data: urlData } = db.storage.from('documents').getPublicUrl(storagePath)
|
|
381
|
-
|
|
382
|
-
const { data, error } = await db
|
|
383
|
-
.from(T.documentFiles)
|
|
384
|
-
.insert({
|
|
385
|
-
tenant_id: tenantId,
|
|
386
|
-
document_id: documentId,
|
|
387
|
-
field_key: fieldKey,
|
|
388
|
-
file_url: urlData.publicUrl,
|
|
389
|
-
file_name: file.name,
|
|
390
|
-
file_size: file.size,
|
|
391
|
-
mime_type: file.type,
|
|
392
|
-
})
|
|
393
|
-
.select()
|
|
394
|
-
.single()
|
|
395
|
-
if (error) throw new Error(error.message)
|
|
396
|
-
return mapFile(data)
|
|
397
|
-
},
|
|
398
|
-
|
|
399
|
-
async deleteFile(fileId: string): Promise<void> {
|
|
400
|
-
const db = getClient()
|
|
401
|
-
const { error } = await db
|
|
402
|
-
.from(T.documentFiles)
|
|
403
|
-
.delete()
|
|
404
|
-
.eq('id', fileId)
|
|
405
|
-
if (error) throw new Error(error.message)
|
|
406
|
-
},
|
|
407
|
-
}
|
|
408
|
-
}
|
package/src/data/tables.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Central physical-table-name registry for plugin-forms. `documents` stays core.
|
|
2
|
-
export const T = {
|
|
3
|
-
documents: 'plg_forms_documents',
|
|
4
|
-
templates: 'plg_forms_templates',
|
|
5
|
-
documentFiles: 'plg_forms_document_files',
|
|
6
|
-
categories: 'plg_forms_categories',
|
|
7
|
-
} as const
|
package/src/data/types.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
FormTemplate,
|
|
3
|
-
FormDocument,
|
|
4
|
-
DocumentFile,
|
|
5
|
-
TemplateQuery,
|
|
6
|
-
DocumentQuery,
|
|
7
|
-
PaginatedResult,
|
|
8
|
-
CreateTemplateInput,
|
|
9
|
-
UpdateTemplateInput,
|
|
10
|
-
CreateDocumentInput,
|
|
11
|
-
UpdateDocumentInput,
|
|
12
|
-
} from '../types'
|
|
13
|
-
|
|
14
|
-
export interface CustomFormsDataProvider {
|
|
15
|
-
// Templates
|
|
16
|
-
getTemplates(query: TemplateQuery): Promise<PaginatedResult<FormTemplate>>
|
|
17
|
-
getTemplateById(id: string): Promise<FormTemplate | null>
|
|
18
|
-
createTemplate(input: CreateTemplateInput): Promise<FormTemplate>
|
|
19
|
-
updateTemplate(id: string, input: UpdateTemplateInput): Promise<FormTemplate>
|
|
20
|
-
deleteTemplate(id: string): Promise<void>
|
|
21
|
-
|
|
22
|
-
// Documents
|
|
23
|
-
getDocuments(query: DocumentQuery): Promise<PaginatedResult<FormDocument>>
|
|
24
|
-
getDocumentById(id: string): Promise<FormDocument | null>
|
|
25
|
-
createDocument(input: CreateDocumentInput): Promise<FormDocument>
|
|
26
|
-
updateDocument(id: string, input: UpdateDocumentInput): Promise<FormDocument>
|
|
27
|
-
deleteDocument(id: string): Promise<void>
|
|
28
|
-
|
|
29
|
-
// Files
|
|
30
|
-
getDocumentFiles(documentId: string): Promise<DocumentFile[]>
|
|
31
|
-
uploadFile(documentId: string, fieldKey: string, file: File): Promise<DocumentFile>
|
|
32
|
-
deleteFile(fileId: string): Promise<void>
|
|
33
|
-
}
|
package/src/document-types.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type React from 'react'
|
|
2
|
-
|
|
3
|
-
// ============================================================
|
|
4
|
-
// Document Type Registry — extensible pattern for plugins
|
|
5
|
-
// to contribute document types to the "Add Document" dropdown
|
|
6
|
-
// ============================================================
|
|
7
|
-
|
|
8
|
-
export interface DocumentTypeOption {
|
|
9
|
-
/** Unique id, e.g. 'custom_forms:template:abc123' or 'core:image' */
|
|
10
|
-
id: string
|
|
11
|
-
label: string
|
|
12
|
-
icon: React.ElementType
|
|
13
|
-
/** Group label for dropdown sections (e.g. 'Formulários', 'Arquivos') */
|
|
14
|
-
group: string
|
|
15
|
-
/** Group sort order — lower groups appear first */
|
|
16
|
-
groupOrder?: number
|
|
17
|
-
/** Sort order within group */
|
|
18
|
-
order?: number
|
|
19
|
-
/** Description shown below label */
|
|
20
|
-
description?: string
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface DocumentTypeProvider {
|
|
24
|
-
/** Unique provider id, e.g. 'custom_forms', 'core_files' */
|
|
25
|
-
id: string
|
|
26
|
-
/** Returns available document types for a given person */
|
|
27
|
-
getTypes(personId: string): DocumentTypeOption[] | Promise<DocumentTypeOption[]>
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ── Global registry ────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
const providers: DocumentTypeProvider[] = []
|
|
33
|
-
|
|
34
|
-
export function registerDocumentTypeProvider(provider: DocumentTypeProvider) {
|
|
35
|
-
if (providers.find((p) => p.id === provider.id)) return
|
|
36
|
-
providers.push(provider)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getDocumentTypeProviders(): DocumentTypeProvider[] {
|
|
40
|
-
return providers
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export async function getAllDocumentTypes(personId: string): Promise<DocumentTypeOption[]> {
|
|
44
|
-
const results = await Promise.all(
|
|
45
|
-
providers.map((p) => Promise.resolve(p.getTypes(personId))),
|
|
46
|
-
)
|
|
47
|
-
const all = results.flat()
|
|
48
|
-
// Sort by groupOrder then order within group
|
|
49
|
-
all.sort((a, b) => (a.groupOrder ?? 50) - (b.groupOrder ?? 50) || (a.order ?? 0) - (b.order ?? 0))
|
|
50
|
-
return all
|
|
51
|
-
}
|