@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.
Files changed (82) hide show
  1. package/README.md +3 -3
  2. package/dist/{FormBuilder-7SWZQKFN.js → FormBuilder-YHJHF6HZ.js} +4 -4
  3. package/dist/{FormBuilder-7SWZQKFN.js.map → FormBuilder-YHJHF6HZ.js.map} +1 -1
  4. package/dist/{chunk-W2ZNJGQC.js → chunk-RBLXIKWB.js} +221 -8
  5. package/dist/chunk-RBLXIKWB.js.map +1 -0
  6. package/dist/components/AddDocumentDropdown.d.ts +1 -1
  7. package/dist/components/AddDocumentDropdown.d.ts.map +1 -1
  8. package/dist/components/DocumentFormDialog.d.ts.map +1 -1
  9. package/dist/components/DocumentSkeleton.d.ts +21 -0
  10. package/dist/components/DocumentSkeleton.d.ts.map +1 -0
  11. package/dist/components/FormRenderer.d.ts.map +1 -1
  12. package/dist/components/FormViewer.d.ts.map +1 -1
  13. package/dist/{CustomFormsContext.d.ts → context.d.ts} +1 -1
  14. package/dist/context.d.ts.map +1 -0
  15. package/dist/data/mock.d.ts.map +1 -1
  16. package/dist/data/supabase.d.ts.map +1 -1
  17. package/dist/data/types.d.ts +4 -1
  18. package/dist/data/types.d.ts.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +174 -17
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/agent-tools.d.ts.map +1 -0
  24. package/dist/lib/document-types.d.ts.map +1 -0
  25. package/dist/lib/html-text.d.ts +21 -0
  26. package/dist/lib/html-text.d.ts.map +1 -0
  27. package/dist/lib/print.d.ts.map +1 -1
  28. package/dist/lib/timeline-source.d.ts +10 -0
  29. package/dist/lib/timeline-source.d.ts.map +1 -0
  30. package/dist/locales/en.d.ts.map +1 -1
  31. package/dist/locales/pt-BR.d.ts.map +1 -1
  32. package/dist/migrations/index.d.ts +1 -0
  33. package/dist/migrations/index.d.ts.map +1 -1
  34. package/dist/store.d.ts +5 -1
  35. package/dist/store.d.ts.map +1 -1
  36. package/dist/types.d.ts +13 -0
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/views/TemplateListView.d.ts.map +1 -1
  39. package/package.json +5 -7
  40. package/dist/CustomFormsContext.d.ts.map +0 -1
  41. package/dist/agent-tools.d.ts.map +0 -1
  42. package/dist/chunk-W2ZNJGQC.js.map +0 -1
  43. package/dist/document-types.d.ts.map +0 -1
  44. package/src/CustomFormsContext.tsx +0 -28
  45. package/src/agent-tools.ts +0 -73
  46. package/src/components/AddDocumentDropdown.tsx +0 -92
  47. package/src/components/BuilderCanvas.tsx +0 -87
  48. package/src/components/BuilderField.tsx +0 -81
  49. package/src/components/DocumentFormDialog.tsx +0 -155
  50. package/src/components/DocumentList.tsx +0 -254
  51. package/src/components/FieldConfigDialog.tsx +0 -243
  52. package/src/components/FieldPalette.tsx +0 -81
  53. package/src/components/FormBuilder.tsx +0 -427
  54. package/src/components/FormRenderer.tsx +0 -256
  55. package/src/components/FormViewer.tsx +0 -94
  56. package/src/components/PersonDocumentsWidget.tsx +0 -229
  57. package/src/components/TemplateSelector.tsx +0 -91
  58. package/src/config.ts +0 -43
  59. package/src/data/index.ts +0 -3
  60. package/src/data/mock.ts +0 -193
  61. package/src/data/supabase.ts +0 -408
  62. package/src/data/tables.ts +0 -7
  63. package/src/data/types.ts +0 -33
  64. package/src/document-types.ts +0 -51
  65. package/src/index.ts +0 -234
  66. package/src/lib/person-fields.ts +0 -67
  67. package/src/lib/print.ts +0 -207
  68. package/src/lib/tenant.ts +0 -9
  69. package/src/locales/en.ts +0 -95
  70. package/src/locales/index.ts +0 -7
  71. package/src/locales/pt-BR.ts +0 -95
  72. package/src/migrations/000_plg_rename.sql +0 -21
  73. package/src/migrations/001_frm_base.sql +0 -174
  74. package/src/migrations/002_document_archetype.sql +0 -223
  75. package/src/migrations/003_agent_rpcs.sql +0 -174
  76. package/src/migrations/index.ts +0 -610
  77. package/src/store.ts +0 -167
  78. package/src/types.ts +0 -217
  79. package/src/views/CustomFormsSettingsTab.tsx +0 -105
  80. package/src/views/TemplateListView.tsx +0 -174
  81. /package/dist/{agent-tools.d.ts → lib/agent-tools.d.ts} +0 -0
  82. /package/dist/{document-types.d.ts → lib/document-types.d.ts} +0 -0
@@ -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
- }
@@ -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
- }
@@ -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
- }