@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
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { createOrUpdateFormTool, prefillFromPerson, FormRenderer, printDocument } from './chunk-W2ZNJGQC.js';
1
+ import { createOrUpdateFormTool, prefillFromPerson, FormRenderer, printDocument } from './chunk-RBLXIKWB.js';
2
2
  import React2, { useState, useCallback, useRef, useEffect } from 'react';
3
- import { registerTranslations, createSafeDataProvider, useTranslation, getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core';
4
- import { PluginSettingsPanel, useLimitGuard, invalidateLimit, PermissionGate } from '@fayz-ai/saas';
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-7SWZQKFN.js').then((m) => ({ default: m.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__ */ 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" }) });
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.name }),
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
- onClick: () => printDocument(template, doc),
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
  }