@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/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { createOrUpdateFormTool, prefillFromPerson, FormRenderer, printDocument } from './chunk-
|
|
1
|
+
import { createOrUpdateFormTool, prefillFromPerson, FormRenderer, printDocument } from './chunk-RBLXIKWB.js';
|
|
2
2
|
import React2, { useState, useCallback, useRef, useEffect } from 'react';
|
|
3
|
-
import { registerTranslations, createSafeDataProvider,
|
|
4
|
-
import { PluginSettingsPanel, useLimitGuard, invalidateLimit, PermissionGate } from '@fayz-ai/
|
|
3
|
+
import { registerTranslations, createSafeDataProvider, getSupabaseClientOptional, useTranslation, getActiveTenantId } from '@fayz-ai/core';
|
|
4
|
+
import { PluginSettingsPanel, registerTimelineSource, useLimitGuard, invalidateLimit, PermissionGate } from '@fayz-ai/admin';
|
|
5
5
|
import { create } from 'zustand';
|
|
6
6
|
import { FileText, Image, Paperclip, Search, Plus, Pencil, Archive, ArrowLeft, Printer, ChevronDown, Upload, Eye } from 'lucide-react';
|
|
7
7
|
import { Input, Button, Card, CardContent, Badge, useSaveBar, Dropdown, DropdownTrigger, DropdownContent, DropdownSeparator, DropdownLabel, DropdownItem } from '@fayz-ai/ui';
|
|
8
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
9
9
|
|
|
10
10
|
// src/data/tables.ts
|
|
11
11
|
var T = {
|
|
@@ -85,6 +85,19 @@ function createMockFormsProvider() {
|
|
|
85
85
|
const idx = templates.findIndex((t) => t.id === id);
|
|
86
86
|
if (idx !== -1) templates[idx] = { ...templates[idx], isDeleted: true };
|
|
87
87
|
},
|
|
88
|
+
async getTemplateUsage() {
|
|
89
|
+
const usage = {};
|
|
90
|
+
for (const doc of documents) {
|
|
91
|
+
if (doc.isDeleted || !doc.templateId) continue;
|
|
92
|
+
const current = usage[doc.templateId] ?? { documentCount: 0, lastDocumentAt: null };
|
|
93
|
+
current.documentCount += 1;
|
|
94
|
+
if (!current.lastDocumentAt || doc.createdAt > current.lastDocumentAt) {
|
|
95
|
+
current.lastDocumentAt = doc.createdAt;
|
|
96
|
+
}
|
|
97
|
+
usage[doc.templateId] = current;
|
|
98
|
+
}
|
|
99
|
+
return usage;
|
|
100
|
+
},
|
|
88
101
|
// ── Documents ──────────────────────────────────────────
|
|
89
102
|
async getDocuments(query) {
|
|
90
103
|
let filtered = documents.filter((d) => !d.isDeleted);
|
|
@@ -189,6 +202,26 @@ function getClient() {
|
|
|
189
202
|
if (!supabase) throw new Error("Supabase not initialized");
|
|
190
203
|
return supabase;
|
|
191
204
|
}
|
|
205
|
+
var USAGE_FALLBACK_LIMIT = 5e3;
|
|
206
|
+
async function countTemplateUsageClientSide(db, tenantId) {
|
|
207
|
+
try {
|
|
208
|
+
const { data, error, count } = await db.from("v_documents").select("template_id, created_at", { count: "exact" }).eq("tenant_id", tenantId).eq("is_active", true).not("template_id", "is", null).limit(USAGE_FALLBACK_LIMIT);
|
|
209
|
+
if (error) return {};
|
|
210
|
+
if (typeof count === "number" && count > USAGE_FALLBACK_LIMIT) return {};
|
|
211
|
+
const usage = {};
|
|
212
|
+
for (const row of data ?? []) {
|
|
213
|
+
const current = usage[row.template_id] ?? { documentCount: 0, lastDocumentAt: null };
|
|
214
|
+
current.documentCount += 1;
|
|
215
|
+
if (!current.lastDocumentAt || row.created_at > current.lastDocumentAt) {
|
|
216
|
+
current.lastDocumentAt = row.created_at;
|
|
217
|
+
}
|
|
218
|
+
usage[row.template_id] = current;
|
|
219
|
+
}
|
|
220
|
+
return usage;
|
|
221
|
+
} catch {
|
|
222
|
+
return {};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
192
225
|
function mapTemplate(r) {
|
|
193
226
|
return {
|
|
194
227
|
id: r.id,
|
|
@@ -336,6 +369,31 @@ function createSupabaseFormsProvider() {
|
|
|
336
369
|
const { error } = await db.from(T.templates).update({ is_deleted: true, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", id);
|
|
337
370
|
if (error) throw new Error(error.message);
|
|
338
371
|
},
|
|
372
|
+
// Uso por modelo. Caminho principal: `v_forms_template_usage`, que agrega no
|
|
373
|
+
// banco (004_template_usage.sql) e devolve uma linha por modelo.
|
|
374
|
+
//
|
|
375
|
+
// O fallback existe porque um pool provisionado antes daquela migração não
|
|
376
|
+
// tem a view, e a tela não pode ficar sem o número por causa disso: ele
|
|
377
|
+
// relê as colunas mínimas dos documentos e agrega aqui. É limitado de
|
|
378
|
+
// propósito — acima do teto o número seria mentira, e mentir sobre uma
|
|
379
|
+
// contagem é pior do que omiti-la, então ele desiste em silêncio.
|
|
380
|
+
async getTemplateUsage() {
|
|
381
|
+
const db = getClient();
|
|
382
|
+
const tenantId = getTenantId();
|
|
383
|
+
if (!tenantId) return {};
|
|
384
|
+
const { data, error } = await db.from("v_forms_template_usage").select("template_id, document_count, last_document_at").eq("tenant_id", tenantId);
|
|
385
|
+
if (!error) {
|
|
386
|
+
const usage = {};
|
|
387
|
+
for (const row of data ?? []) {
|
|
388
|
+
usage[row.template_id] = {
|
|
389
|
+
documentCount: Number(row.document_count ?? 0),
|
|
390
|
+
lastDocumentAt: row.last_document_at ?? null
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
return usage;
|
|
394
|
+
}
|
|
395
|
+
return countTemplateUsageClientSide(db, tenantId);
|
|
396
|
+
},
|
|
339
397
|
// ── Documents (public.documents + plg_forms_documents extension) ──
|
|
340
398
|
async getDocuments(query) {
|
|
341
399
|
const db = getClient();
|
|
@@ -451,6 +509,7 @@ function createCustomFormsStore(provider) {
|
|
|
451
509
|
templatesTotal: 0,
|
|
452
510
|
templatesLoading: false,
|
|
453
511
|
templatesError: null,
|
|
512
|
+
templateUsage: {},
|
|
454
513
|
documents: [],
|
|
455
514
|
documentsTotal: 0,
|
|
456
515
|
documentsLoading: false,
|
|
@@ -470,6 +529,18 @@ function createCustomFormsStore(provider) {
|
|
|
470
529
|
set({ templatesLoading: false });
|
|
471
530
|
}
|
|
472
531
|
},
|
|
532
|
+
// Separado de `fetchTemplates` porque é outra pergunta e outro custo: a
|
|
533
|
+
// lista precisa dos modelos para desenhar, e o uso é um enfeite que chega
|
|
534
|
+
// depois. Junto, a tela inteira esperaria a agregação; e uma falha na
|
|
535
|
+
// contagem levaria embora a lista, que não tem nada a ver com isso — daí
|
|
536
|
+
// ele engolir o erro em vez de escrevê-lo em `templatesError`.
|
|
537
|
+
async fetchTemplateUsage() {
|
|
538
|
+
try {
|
|
539
|
+
set({ templateUsage: await provider.getTemplateUsage() });
|
|
540
|
+
} catch {
|
|
541
|
+
set({ templateUsage: {} });
|
|
542
|
+
}
|
|
543
|
+
},
|
|
473
544
|
async fetchTemplateById(id) {
|
|
474
545
|
set({ activeTemplateLoading: true });
|
|
475
546
|
try {
|
|
@@ -629,6 +700,8 @@ var en = {
|
|
|
629
700
|
"customForms.archive": "Archive",
|
|
630
701
|
"customForms.archiveDocumentConfirm": "Archive this document? It leaves the active list but is kept on file.",
|
|
631
702
|
"customForms.printPdf": "Print / PDF",
|
|
703
|
+
"customForms.usageCount": "{{count}} filled in",
|
|
704
|
+
"customForms.usageLast": "last on {{date}}",
|
|
632
705
|
// Registry
|
|
633
706
|
"registry.form-categories": "Categories",
|
|
634
707
|
"registry.form-categories.description": "Categories for organizing form templates",
|
|
@@ -718,6 +791,8 @@ var ptBR = {
|
|
|
718
791
|
"customForms.archive": "Arquivar",
|
|
719
792
|
"customForms.archiveDocumentConfirm": "Arquivar este documento? Ele sai da lista ativa mas fica guardado.",
|
|
720
793
|
"customForms.printPdf": "Imprimir / PDF",
|
|
794
|
+
"customForms.usageCount": "{{count}} preenchidos",
|
|
795
|
+
"customForms.usageLast": "\xFAltimo em {{date}}",
|
|
721
796
|
// Registry
|
|
722
797
|
"registry.form-categories": "Categorias",
|
|
723
798
|
"registry.form-categories.description": "Categorias para organizar modelos de formul\xE1rios",
|
|
@@ -761,6 +836,7 @@ function TemplateListView({ store, config, onEdit, onNew }) {
|
|
|
761
836
|
const [search, setSearch] = useState("");
|
|
762
837
|
const templates = store((s) => s.templates);
|
|
763
838
|
const loading = store((s) => s.templatesLoading);
|
|
839
|
+
const usage = store((s) => s.templateUsage);
|
|
764
840
|
const orgId = getFormsTenantId();
|
|
765
841
|
useEffect(() => {
|
|
766
842
|
if (!orgId) return;
|
|
@@ -769,6 +845,10 @@ function TemplateListView({ store, config, onEdit, onNew }) {
|
|
|
769
845
|
}, 50);
|
|
770
846
|
return () => clearTimeout(timer);
|
|
771
847
|
}, [orgId, search]);
|
|
848
|
+
useEffect(() => {
|
|
849
|
+
if (!orgId) return;
|
|
850
|
+
void store.getState().fetchTemplateUsage();
|
|
851
|
+
}, [orgId]);
|
|
772
852
|
const handleArchive = useCallback(async (template) => {
|
|
773
853
|
if (!window.confirm(t("customForms.archiveTemplateConfirm"))) return;
|
|
774
854
|
await store.getState().updateTemplate(template.id, { isActive: false });
|
|
@@ -851,6 +931,17 @@ function TemplateListView({ store, config, onEdit, onNew }) {
|
|
|
851
931
|
"v",
|
|
852
932
|
template.version
|
|
853
933
|
] })
|
|
934
|
+
] }),
|
|
935
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-2 text-[10px] text-muted-foreground", children: [
|
|
936
|
+
t("customForms.usageCount", {
|
|
937
|
+
count: String(usage[template.id]?.documentCount ?? 0)
|
|
938
|
+
}),
|
|
939
|
+
usage[template.id]?.lastDocumentAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
940
|
+
/* @__PURE__ */ jsx("span", { className: "px-1", children: "\xB7" }),
|
|
941
|
+
t("customForms.usageLast", {
|
|
942
|
+
date: new Date(usage[template.id].lastDocumentAt).toLocaleDateString()
|
|
943
|
+
})
|
|
944
|
+
] })
|
|
854
945
|
] })
|
|
855
946
|
] })
|
|
856
947
|
},
|
|
@@ -917,7 +1008,7 @@ function BuilderWrapper({
|
|
|
917
1008
|
onBack
|
|
918
1009
|
}) {
|
|
919
1010
|
const FormBuilderLazy = React2.lazy(
|
|
920
|
-
() => import('./FormBuilder-
|
|
1011
|
+
() => import('./FormBuilder-YHJHF6HZ.js').then((m) => ({ default: m.FormBuilder }))
|
|
921
1012
|
);
|
|
922
1013
|
return /* @__PURE__ */ jsx(
|
|
923
1014
|
React2.Suspense,
|
|
@@ -1114,6 +1205,21 @@ function DocumentList({ personId, provider, store, onView, onFileDrop }) {
|
|
|
1114
1205
|
}
|
|
1115
1206
|
);
|
|
1116
1207
|
}
|
|
1208
|
+
function DocumentBodySkeleton({ rows = 5 }) {
|
|
1209
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-4 rounded-xl border p-4", "aria-hidden": true, children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
1210
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-28 animate-pulse rounded bg-muted" }),
|
|
1211
|
+
/* @__PURE__ */ jsx("div", { className: "h-9 w-full animate-pulse rounded-md bg-muted" })
|
|
1212
|
+
] }, i)) });
|
|
1213
|
+
}
|
|
1214
|
+
function DocumentHeaderSkeleton() {
|
|
1215
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", "aria-hidden": true, children: [
|
|
1216
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-3.5 shrink-0 animate-pulse rounded bg-muted" }),
|
|
1217
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
|
|
1218
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-48 max-w-full animate-pulse rounded bg-muted" }),
|
|
1219
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-24 animate-pulse rounded bg-muted" })
|
|
1220
|
+
] })
|
|
1221
|
+
] });
|
|
1222
|
+
}
|
|
1117
1223
|
function generateTitle(templateName, personName) {
|
|
1118
1224
|
const date = (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
1119
1225
|
return personName ? `${templateName} \u2014 ${personName} \u2014 ${date}` : `${templateName} \u2014 ${date}`;
|
|
@@ -1190,7 +1296,28 @@ function DocumentFormDialog({
|
|
|
1190
1296
|
saveLabel: t("customForms.saveAndComplete")
|
|
1191
1297
|
});
|
|
1192
1298
|
if (!template) {
|
|
1193
|
-
return /* @__PURE__ */
|
|
1299
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1300
|
+
existingDocument?.title ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1301
|
+
/* @__PURE__ */ jsx(
|
|
1302
|
+
"button",
|
|
1303
|
+
{
|
|
1304
|
+
onClick: onBack,
|
|
1305
|
+
className: "flex items-center gap-1 text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
1306
|
+
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-3.5 w-3.5" })
|
|
1307
|
+
}
|
|
1308
|
+
),
|
|
1309
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1310
|
+
/* @__PURE__ */ jsx("h3", { className: "truncate text-sm font-semibold", children: existingDocument.title }),
|
|
1311
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: new Date(existingDocument.createdAt).toLocaleDateString() })
|
|
1312
|
+
] })
|
|
1313
|
+
] }) : /* @__PURE__ */ jsx(DocumentHeaderSkeleton, {}),
|
|
1314
|
+
/* @__PURE__ */ jsx(
|
|
1315
|
+
DocumentBodySkeleton,
|
|
1316
|
+
{
|
|
1317
|
+
rows: Math.min(Math.max(Object.keys(existingDocument?.data ?? {}).length, 3), 8)
|
|
1318
|
+
}
|
|
1319
|
+
)
|
|
1320
|
+
] });
|
|
1194
1321
|
}
|
|
1195
1322
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1196
1323
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
@@ -1239,9 +1366,6 @@ function FormViewer({ document: doc, provider, onBack, onEdit }) {
|
|
|
1239
1366
|
}, 50);
|
|
1240
1367
|
return () => clearTimeout(timer);
|
|
1241
1368
|
}, [doc.templateId, provider]);
|
|
1242
|
-
if (!template) {
|
|
1243
|
-
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx("div", { className: "h-5 w-5 border-2 border-primary border-t-transparent animate-spin rounded-full" }) });
|
|
1244
|
-
}
|
|
1245
1369
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1246
1370
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1247
1371
|
/* @__PURE__ */ jsx(
|
|
@@ -1253,7 +1377,7 @@ function FormViewer({ document: doc, provider, onBack, onEdit }) {
|
|
|
1253
1377
|
}
|
|
1254
1378
|
),
|
|
1255
1379
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1256
|
-
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-sm truncate", children: doc.title ?? template
|
|
1380
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-sm truncate", children: doc.title ?? template?.name ?? "" }),
|
|
1257
1381
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: new Date(doc.createdAt).toLocaleDateString() })
|
|
1258
1382
|
] }),
|
|
1259
1383
|
/* @__PURE__ */ jsx(Badge, { variant: "secondary", className: `text-[10px] ${STATUS_COLORS2[doc.status] ?? ""}`, children: t(`customForms.status.${doc.status}`) }),
|
|
@@ -1263,7 +1387,8 @@ function FormViewer({ document: doc, provider, onBack, onEdit }) {
|
|
|
1263
1387
|
variant: "outline",
|
|
1264
1388
|
size: "sm",
|
|
1265
1389
|
className: "h-8",
|
|
1266
|
-
|
|
1390
|
+
disabled: !template,
|
|
1391
|
+
onClick: () => template && printDocument(template, doc),
|
|
1267
1392
|
children: [
|
|
1268
1393
|
/* @__PURE__ */ jsx(Printer, { className: "h-3 w-3 mr-1" }),
|
|
1269
1394
|
t("customForms.printPdf")
|
|
@@ -1275,7 +1400,7 @@ function FormViewer({ document: doc, provider, onBack, onEdit }) {
|
|
|
1275
1400
|
t("common.edit")
|
|
1276
1401
|
] })
|
|
1277
1402
|
] }),
|
|
1278
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-xl border p-4", children: /* @__PURE__ */ jsx(
|
|
1403
|
+
template ? /* @__PURE__ */ jsx("div", { className: "rounded-xl border p-4", children: /* @__PURE__ */ jsx(
|
|
1279
1404
|
FormRenderer,
|
|
1280
1405
|
{
|
|
1281
1406
|
schema: template.schema,
|
|
@@ -1284,11 +1409,15 @@ function FormViewer({ document: doc, provider, onBack, onEdit }) {
|
|
|
1284
1409
|
},
|
|
1285
1410
|
readOnly: true
|
|
1286
1411
|
}
|
|
1287
|
-
) })
|
|
1412
|
+
) }) : (
|
|
1413
|
+
// O documento já diz quantos campos tem: o esqueleto sai da altura certa
|
|
1414
|
+
// em vez de chutar, e a chegada do conteúdo não mexe no scroll.
|
|
1415
|
+
/* @__PURE__ */ jsx(DocumentBodySkeleton, { rows: Math.min(Math.max(Object.keys(doc.data ?? {}).length, 3), 8) })
|
|
1416
|
+
)
|
|
1288
1417
|
] });
|
|
1289
1418
|
}
|
|
1290
1419
|
|
|
1291
|
-
// src/document-types.ts
|
|
1420
|
+
// src/lib/document-types.ts
|
|
1292
1421
|
var providers = [];
|
|
1293
1422
|
function registerDocumentTypeProvider(provider) {
|
|
1294
1423
|
if (providers.find((p) => p.id === provider.id)) return;
|
|
@@ -1514,6 +1643,34 @@ function FileDocumentViewer({ document: doc, onBack }) {
|
|
|
1514
1643
|
] }) })
|
|
1515
1644
|
] });
|
|
1516
1645
|
}
|
|
1646
|
+
function registerFormsTimelineSource() {
|
|
1647
|
+
registerTimelineSource({
|
|
1648
|
+
id: "documents",
|
|
1649
|
+
label: "Documentos",
|
|
1650
|
+
icon: "FileText",
|
|
1651
|
+
tone: "primary",
|
|
1652
|
+
async fetch(args) {
|
|
1653
|
+
const db = getSupabaseClientOptional();
|
|
1654
|
+
if (!db) return [];
|
|
1655
|
+
let query = db.from("v_documents").select("id, title, kind, status, template_name, created_at").eq("tenant_id", args.tenantId).eq("person_id", args.personId).eq("is_active", true).order("created_at", { ascending: false }).limit(args.limit);
|
|
1656
|
+
if (args.before) query = query.lt("created_at", args.before);
|
|
1657
|
+
const { data, error } = await query;
|
|
1658
|
+
if (error) return [];
|
|
1659
|
+
return (data ?? []).map((row) => ({
|
|
1660
|
+
id: `document:${row.id}`,
|
|
1661
|
+
sourceId: "documents",
|
|
1662
|
+
occurredAt: row.created_at,
|
|
1663
|
+
title: row.title ?? row.template_name ?? "Documento",
|
|
1664
|
+
// O modelo só entra como descrição quando o título não veio dele —
|
|
1665
|
+
// senão a linha diria a mesma coisa duas vezes.
|
|
1666
|
+
description: row.template_name && row.template_name !== row.title ? row.template_name : void 0,
|
|
1667
|
+
badge: row.status ?? void 0,
|
|
1668
|
+
icon: row.kind === "image" ? "Image" : row.kind === "attachment" ? "Paperclip" : "FileText",
|
|
1669
|
+
targetTab: "documents"
|
|
1670
|
+
}));
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1517
1674
|
function registerBuiltInProviders(formsProvider) {
|
|
1518
1675
|
registerDocumentTypeProvider({
|
|
1519
1676
|
id: "custom_forms:templates",
|
|
@@ -1554,6 +1711,7 @@ function createCustomFormsPlugin(options) {
|
|
|
1554
1711
|
);
|
|
1555
1712
|
const store = createCustomFormsStore(provider);
|
|
1556
1713
|
registerBuiltInProviders(provider);
|
|
1714
|
+
registerFormsTimelineSource();
|
|
1557
1715
|
const formRegistries = [
|
|
1558
1716
|
{
|
|
1559
1717
|
id: "form-categories",
|
|
@@ -1590,9 +1748,6 @@ function createCustomFormsPlugin(options) {
|
|
|
1590
1748
|
const SettingsComponent = () => React2.createElement(PluginSettingsPanel, {
|
|
1591
1749
|
title: config.labels.settingsLabel,
|
|
1592
1750
|
subtitle: config.labels.settingsSubtitle,
|
|
1593
|
-
// The settings shell already renders the section label as the page H1;
|
|
1594
|
-
// hide the panel's own duplicate title (keeps the subtitle).
|
|
1595
|
-
hideTitle: true,
|
|
1596
1751
|
customTabs: [
|
|
1597
1752
|
{
|
|
1598
1753
|
id: "forms",
|
|
@@ -1701,6 +1856,8 @@ function createCustomFormsPlugin(options) {
|
|
|
1701
1856
|
audits: true
|
|
1702
1857
|
}
|
|
1703
1858
|
],
|
|
1859
|
+
// Where a submitted form is supposed to land.
|
|
1860
|
+
integrations: ["mailchimp", "rd-station", "zapier"],
|
|
1704
1861
|
locales: customFormsLocales
|
|
1705
1862
|
};
|
|
1706
1863
|
}
|