@fayz-ai/plugin-forms 0.9.0-next.1 → 0.9.1

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 (59) hide show
  1. package/README.md +3 -3
  2. package/dist/{FormBuilder-7SWZQKFN.js → FormBuilder-JCNHXQXT.js} +4 -4
  3. package/dist/{FormBuilder-7SWZQKFN.js.map → FormBuilder-JCNHXQXT.js.map} +1 -1
  4. package/dist/{chunk-W2ZNJGQC.js → chunk-JCAWSDX6.js} +3 -3
  5. package/dist/chunk-JCAWSDX6.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/{CustomFormsContext.d.ts → context.d.ts} +1 -1
  9. package/dist/context.d.ts.map +1 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -4
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/agent-tools.d.ts.map +1 -0
  15. package/dist/lib/document-types.d.ts.map +1 -0
  16. package/package.json +5 -7
  17. package/dist/CustomFormsContext.d.ts.map +0 -1
  18. package/dist/agent-tools.d.ts.map +0 -1
  19. package/dist/chunk-W2ZNJGQC.js.map +0 -1
  20. package/dist/document-types.d.ts.map +0 -1
  21. package/src/CustomFormsContext.tsx +0 -28
  22. package/src/agent-tools.ts +0 -73
  23. package/src/components/AddDocumentDropdown.tsx +0 -92
  24. package/src/components/BuilderCanvas.tsx +0 -87
  25. package/src/components/BuilderField.tsx +0 -81
  26. package/src/components/DocumentFormDialog.tsx +0 -155
  27. package/src/components/DocumentList.tsx +0 -254
  28. package/src/components/FieldConfigDialog.tsx +0 -243
  29. package/src/components/FieldPalette.tsx +0 -81
  30. package/src/components/FormBuilder.tsx +0 -427
  31. package/src/components/FormRenderer.tsx +0 -256
  32. package/src/components/FormViewer.tsx +0 -94
  33. package/src/components/PersonDocumentsWidget.tsx +0 -229
  34. package/src/components/TemplateSelector.tsx +0 -91
  35. package/src/config.ts +0 -43
  36. package/src/data/index.ts +0 -3
  37. package/src/data/mock.ts +0 -193
  38. package/src/data/supabase.ts +0 -408
  39. package/src/data/tables.ts +0 -7
  40. package/src/data/types.ts +0 -33
  41. package/src/document-types.ts +0 -51
  42. package/src/index.ts +0 -234
  43. package/src/lib/person-fields.ts +0 -67
  44. package/src/lib/print.ts +0 -207
  45. package/src/lib/tenant.ts +0 -9
  46. package/src/locales/en.ts +0 -95
  47. package/src/locales/index.ts +0 -7
  48. package/src/locales/pt-BR.ts +0 -95
  49. package/src/migrations/000_plg_rename.sql +0 -21
  50. package/src/migrations/001_frm_base.sql +0 -174
  51. package/src/migrations/002_document_archetype.sql +0 -223
  52. package/src/migrations/003_agent_rpcs.sql +0 -174
  53. package/src/migrations/index.ts +0 -610
  54. package/src/store.ts +0 -167
  55. package/src/types.ts +0 -217
  56. package/src/views/CustomFormsSettingsTab.tsx +0 -105
  57. package/src/views/TemplateListView.tsx +0 -174
  58. /package/dist/{agent-tools.d.ts → lib/agent-tools.d.ts} +0 -0
  59. /package/dist/{document-types.d.ts → lib/document-types.d.ts} +0 -0
package/src/config.ts DELETED
@@ -1,43 +0,0 @@
1
- import type { PluginRegistryDef, PluginScope, VerticalId } from '@fayz-ai/core'
2
- import type { CustomFormsDataProvider } from './data/types'
3
-
4
- export interface CustomFormsPluginOptions {
5
- scope?: PluginScope
6
- verticalId?: VerticalId
7
- dataProvider?: CustomFormsDataProvider
8
- navSection?: 'main' | 'secondary' | 'settings'
9
- navPosition?: number
10
- labels?: Partial<CustomFormsLabels>
11
- /** App-owned registries shown inside Forms & Documents settings. */
12
- settingsRegistries?: PluginRegistryDef[]
13
- }
14
-
15
- export interface CustomFormsLabels {
16
- pageTitle: string
17
- settingsLabel: string
18
- settingsSubtitle: string
19
- templates: string
20
- documents: string
21
- newTemplate: string
22
- addDocument: string
23
- }
24
-
25
- export interface CustomFormsConfig {
26
- labels: CustomFormsLabels
27
- }
28
-
29
- const DEFAULT_LABELS: CustomFormsLabels = {
30
- pageTitle: 'Custom Forms',
31
- settingsLabel: 'Forms & Documents',
32
- settingsSubtitle: 'Create and manage custom forms for your business',
33
- templates: 'Templates',
34
- documents: 'Documents',
35
- newTemplate: 'New Template',
36
- addDocument: 'Add Document',
37
- }
38
-
39
- export function resolveConfig(options?: CustomFormsPluginOptions): CustomFormsConfig {
40
- return {
41
- labels: { ...DEFAULT_LABELS, ...options?.labels },
42
- }
43
- }
package/src/data/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export type { CustomFormsDataProvider } from './types'
2
- export { createMockFormsProvider } from './mock'
3
- export { createSupabaseFormsProvider } from './supabase'
package/src/data/mock.ts DELETED
@@ -1,193 +0,0 @@
1
- import type { CustomFormsDataProvider } from './types'
2
- import type {
3
- FormTemplate,
4
- FormDocument,
5
- DocumentFile,
6
- TemplateQuery,
7
- DocumentQuery,
8
- PaginatedResult,
9
- CreateTemplateInput,
10
- UpdateTemplateInput,
11
- CreateDocumentInput,
12
- UpdateDocumentInput,
13
- } from '../types'
14
-
15
- function uuid() {
16
- return crypto.randomUUID()
17
- }
18
-
19
- function now() {
20
- return new Date().toISOString()
21
- }
22
-
23
- export function createMockFormsProvider(): CustomFormsDataProvider {
24
- const templates: FormTemplate[] = []
25
- const documents: FormDocument[] = []
26
- const files: DocumentFile[] = []
27
-
28
- return {
29
- // ── Templates ──────────────────────────────────────────
30
- async getTemplates(query: TemplateQuery): Promise<PaginatedResult<FormTemplate>> {
31
- let filtered = templates.filter((t) => !t.isDeleted && t.isCurrent)
32
- if (query.category) {
33
- filtered = filtered.filter((t) => t.category === query.category)
34
- }
35
- if (query.search) {
36
- const s = query.search.toLowerCase()
37
- filtered = filtered.filter((t) => t.name.toLowerCase().includes(s))
38
- }
39
- const page = query.page ?? 1
40
- const pageSize = query.pageSize ?? 25
41
- const start = (page - 1) * pageSize
42
- return { data: filtered.slice(start, start + pageSize), total: filtered.length }
43
- },
44
-
45
- async getTemplateById(id: string): Promise<FormTemplate | null> {
46
- return templates.find((t) => t.id === id && !t.isDeleted) ?? null
47
- },
48
-
49
- async createTemplate(input: CreateTemplateInput): Promise<FormTemplate> {
50
- const template: FormTemplate = {
51
- id: uuid(),
52
- tenantId: 'mock-tenant',
53
- name: input.name,
54
- description: input.description,
55
- category: input.category,
56
- version: 1,
57
- isCurrent: true,
58
- schema: input.schema,
59
- specialty: input.specialty,
60
- tags: input.tags ?? [],
61
- metadata: input.metadata ?? {},
62
- isActive: true,
63
- isDeleted: false,
64
- createdAt: now(),
65
- updatedAt: now(),
66
- }
67
- templates.push(template)
68
- return template
69
- },
70
-
71
- async updateTemplate(id: string, input: UpdateTemplateInput): Promise<FormTemplate> {
72
- const idx = templates.findIndex((t) => t.id === id)
73
- if (idx === -1) throw new Error('Template not found')
74
- const existing = templates[idx]
75
- const updated: FormTemplate = {
76
- ...existing,
77
- ...input,
78
- tags: input.tags ?? existing.tags,
79
- metadata: input.metadata ?? existing.metadata,
80
- schema: input.schema ?? existing.schema,
81
- updatedAt: now(),
82
- }
83
- templates[idx] = updated
84
- return updated
85
- },
86
-
87
- async deleteTemplate(id: string): Promise<void> {
88
- const idx = templates.findIndex((t) => t.id === id)
89
- if (idx !== -1) templates[idx] = { ...templates[idx], isDeleted: true }
90
- },
91
-
92
- // ── Documents ──────────────────────────────────────────
93
- async getDocuments(query: DocumentQuery): Promise<PaginatedResult<FormDocument>> {
94
- let filtered = documents.filter((d) => !d.isDeleted)
95
- if (query.personId) {
96
- filtered = filtered.filter((d) => d.personId === query.personId)
97
- }
98
- if (query.templateId) {
99
- filtered = filtered.filter((d) => d.templateId === query.templateId)
100
- }
101
- if (query.status) {
102
- const statuses = Array.isArray(query.status) ? query.status : [query.status]
103
- filtered = filtered.filter((d) => statuses.includes(d.status))
104
- }
105
- if (query.search) {
106
- const s = query.search.toLowerCase()
107
- filtered = filtered.filter(
108
- (d) =>
109
- d.title?.toLowerCase().includes(s) ||
110
- d.templateName?.toLowerCase().includes(s),
111
- )
112
- }
113
- filtered.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
114
- const page = query.page ?? 1
115
- const pageSize = query.pageSize ?? 25
116
- const start = (page - 1) * pageSize
117
- return { data: filtered.slice(start, start + pageSize), total: filtered.length }
118
- },
119
-
120
- async getDocumentById(id: string): Promise<FormDocument | null> {
121
- return documents.find((d) => d.id === id && !d.isDeleted) ?? null
122
- },
123
-
124
- async createDocument(input: CreateDocumentInput): Promise<FormDocument> {
125
- const template = templates.find((t) => t.id === input.templateId)
126
- const doc: FormDocument = {
127
- id: uuid(),
128
- tenantId: 'mock-tenant',
129
- templateId: input.templateId ?? '',
130
- templateName: template?.name,
131
- templateCategory: template?.category,
132
- personId: input.personId,
133
- title: input.title,
134
- data: input.data ?? {},
135
- kind: input.kind ?? (input.templateId ? 'form' : 'attachment'),
136
- status: input.status ?? 'draft',
137
- metadata: {},
138
- isDeleted: false,
139
- createdAt: now(),
140
- updatedAt: now(),
141
- }
142
- documents.push(doc)
143
- return doc
144
- },
145
-
146
- async updateDocument(id: string, input: UpdateDocumentInput): Promise<FormDocument> {
147
- const idx = documents.findIndex((d) => d.id === id)
148
- if (idx === -1) throw new Error('Document not found')
149
- const existing = documents[idx]
150
- const updated: FormDocument = {
151
- ...existing,
152
- ...input,
153
- data: input.data ?? existing.data,
154
- updatedAt: now(),
155
- }
156
- documents[idx] = updated
157
- return updated
158
- },
159
-
160
- async deleteDocument(id: string): Promise<void> {
161
- const idx = documents.findIndex((d) => d.id === id)
162
- if (idx !== -1) documents[idx] = { ...documents[idx], isDeleted: true }
163
- },
164
-
165
- // ── Files ──────────────────────────────────────────────
166
- async getDocumentFiles(documentId: string): Promise<DocumentFile[]> {
167
- return files.filter((f) => f.documentId === documentId)
168
- },
169
-
170
- async uploadFile(documentId: string, fieldKey: string, file: File): Promise<DocumentFile> {
171
- const docFile: DocumentFile = {
172
- id: uuid(),
173
- tenantId: 'mock-tenant',
174
- documentId,
175
- fieldKey,
176
- fileUrl: URL.createObjectURL(file),
177
- fileName: file.name,
178
- fileSize: file.size,
179
- mimeType: file.type,
180
- sortOrder: files.filter((f) => f.documentId === documentId && f.fieldKey === fieldKey).length,
181
- metadata: {},
182
- createdAt: now(),
183
- }
184
- files.push(docFile)
185
- return docFile
186
- },
187
-
188
- async deleteFile(fileId: string): Promise<void> {
189
- const idx = files.findIndex((f) => f.id === fileId)
190
- if (idx !== -1) files.splice(idx, 1)
191
- },
192
- }
193
- }
@@ -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
- }