@fayz-ai/plugin-forms 0.10.0 → 0.10.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.
- package/dist/analytics/cards.d.ts +3 -0
- package/dist/analytics/cards.d.ts.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +150 -63
- package/dist/index.js.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/views/TemplateListView.d.ts.map +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../../src/analytics/cards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AA2BrD,wBAAgB,wBAAwB,IAAI,gBAAgB,EAAE,CA2E7D"}
|
package/dist/config.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ export interface CustomFormsPluginOptions {
|
|
|
9
9
|
labels?: Partial<CustomFormsLabels>;
|
|
10
10
|
/** App-owned registries shown inside Forms & Documents settings. */
|
|
11
11
|
settingsRegistries?: PluginRegistryDef[];
|
|
12
|
+
/**
|
|
13
|
+
* Pass `false` to leave form submissions out of /analytics. Contributed by
|
|
14
|
+
* default — a filled form has no other place in the product where it can be
|
|
15
|
+
* read in bulk.
|
|
16
|
+
*/
|
|
17
|
+
analyticsCards?: false;
|
|
12
18
|
}
|
|
13
19
|
export interface CustomFormsLabels {
|
|
14
20
|
pageTitle: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAE3D,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,uBAAuB,CAAA;IACtC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACnC,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAE3D,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,uBAAuB,CAAA;IACtC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACnC,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,CAAA;IACxC;;;;OAIG;IACH,cAAc,CAAC,EAAE,KAAK,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAYD,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,iBAAiB,CAInF"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAUnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAUnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AA4CxD,YAAY,EAAE,wBAAwB,EAAE,CAAA;AACxC,OAAO,EAAE,4BAA4B,EAAE,KAAK,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAEvH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,cAAc,CAwL1F"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createOrUpdateFormTool, prefillFromPerson, FormRenderer, printDocument } from './chunk-RBLXIKWB.js';
|
|
2
2
|
import React2, { useState, useCallback, useRef, useMemo, useEffect } from 'react';
|
|
3
|
-
import { registerTranslations, createSafeDataProvider, getSupabaseClientOptional, useTranslation, getActiveTenantId, emitDomainEvent, useDataVersion } from '@fayz-ai/core';
|
|
4
|
-
import { PluginSettingsPanel, registerTimelineSource, useLimitGuard, invalidateLimit, askAI, PermissionGate,
|
|
3
|
+
import { tl, registerTranslations, createSafeDataProvider, getSupabaseClientOptional, useTranslation, getActiveTenantId, emitDomainEvent, useDataVersion } from '@fayz-ai/core';
|
|
4
|
+
import { PluginSettingsPanel, registerTimelineSource, useLimitGuard, invalidateLimit, askAI, PermissionGate, PageActions } from '@fayz-ai/admin';
|
|
5
5
|
import { create } from 'zustand';
|
|
6
|
-
import { FileText, Image, Paperclip, Pencil, Archive,
|
|
7
|
-
import { Badge, Button, PageHeaderActions, Card, DataTable, useSaveBar, Dropdown, DropdownTrigger, DropdownContent, DropdownSeparator, DropdownLabel } from '@fayz-ai/ui';
|
|
6
|
+
import { FileText, Image, Paperclip, Plus, WandSparkles, Pencil, Archive, Search, ArrowLeft, Printer, ChevronDown, Upload, Eye } from 'lucide-react';
|
|
7
|
+
import { Badge, RowActions, Button, PageHeaderActions, Card, DataTable, useSaveBar, Dropdown, DropdownTrigger, DropdownContent, DropdownSeparator, DropdownLabel } from '@fayz-ai/ui';
|
|
8
8
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
9
9
|
|
|
10
10
|
// src/data/tables.ts
|
|
@@ -881,32 +881,40 @@ function TemplateListView({ store, config, onEdit, onNew }) {
|
|
|
881
881
|
const loading = store((s) => s.templatesLoading);
|
|
882
882
|
const usage = store((s) => s.templateUsage);
|
|
883
883
|
const orgId = getFormsTenantId();
|
|
884
|
-
const createActions = useMemo(() =>
|
|
885
|
-
{
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
884
|
+
const createActions = useMemo(() => {
|
|
885
|
+
const permission = { feature: "custom_forms", action: "create" };
|
|
886
|
+
return [
|
|
887
|
+
{
|
|
888
|
+
id: "new",
|
|
889
|
+
label: t("customForms.newTemplate"),
|
|
890
|
+
description: t("customForms.newByHandHint"),
|
|
891
|
+
icon: Plus,
|
|
892
|
+
intent: "primary",
|
|
893
|
+
creates: true,
|
|
894
|
+
onSelect: onNew,
|
|
895
|
+
permission
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
id: "ai",
|
|
899
|
+
label: t("assistant.askAI"),
|
|
900
|
+
description: t("customForms.newWithAIHint"),
|
|
901
|
+
icon: WandSparkles,
|
|
902
|
+
intent: "secondary",
|
|
903
|
+
creates: true,
|
|
904
|
+
onSelect: () => askAI({
|
|
905
|
+
hint: t("customForms.askPlaceholder"),
|
|
906
|
+
intro: {
|
|
907
|
+
role: "setup",
|
|
908
|
+
persona: t("customForms.askPersona"),
|
|
909
|
+
pitch: t("customForms.askPitch"),
|
|
910
|
+
description: t("customForms.askDescription"),
|
|
911
|
+
suggestions: [0, 1, 2].map((i) => ({ label: t(`customForms.askSuggestion.${i}`) }))
|
|
912
|
+
}
|
|
913
|
+
}),
|
|
914
|
+
permission
|
|
915
|
+
}
|
|
916
|
+
];
|
|
917
|
+
}, [t, onNew]);
|
|
910
918
|
const version = useDataVersion(`${FORM_TEMPLATE_EVENT}*`);
|
|
911
919
|
useEffect(() => {
|
|
912
920
|
if (!orgId) return;
|
|
@@ -969,32 +977,31 @@ function TemplateListView({ store, config, onEdit, onNew }) {
|
|
|
969
977
|
{
|
|
970
978
|
id: "actions",
|
|
971
979
|
header: "",
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
),
|
|
985
|
-
/* @__PURE__ */ jsx(
|
|
986
|
-
"button",
|
|
987
|
-
{
|
|
988
|
-
onClick: (e) => {
|
|
989
|
-
e.stopPropagation();
|
|
990
|
-
void handleArchive(row.original);
|
|
980
|
+
// RowActions is the one renderer for what can be done to a single row —
|
|
981
|
+
// it owns the sizing, the accessible name and the rule that keeps a
|
|
982
|
+
// destructive action off the row itself.
|
|
983
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(
|
|
984
|
+
RowActions,
|
|
985
|
+
{
|
|
986
|
+
actions: [
|
|
987
|
+
{
|
|
988
|
+
id: "edit",
|
|
989
|
+
label: t("common.edit"),
|
|
990
|
+
icon: Pencil,
|
|
991
|
+
onSelect: () => onEdit(row.original)
|
|
991
992
|
},
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
993
|
+
{
|
|
994
|
+
id: "archive",
|
|
995
|
+
label: t("customForms.archive"),
|
|
996
|
+
icon: Archive,
|
|
997
|
+
intent: "danger",
|
|
998
|
+
onSelect: () => {
|
|
999
|
+
void handleArchive(row.original);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
]
|
|
1003
|
+
}
|
|
1004
|
+
)
|
|
998
1005
|
}
|
|
999
1006
|
], [t, usage, onEdit, handleArchive]);
|
|
1000
1007
|
const emptyState = /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-6 text-center", children: [
|
|
@@ -1007,14 +1014,7 @@ function TemplateListView({ store, config, onEdit, onNew }) {
|
|
|
1007
1014
|
] }) })
|
|
1008
1015
|
] });
|
|
1009
1016
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1010
|
-
/* @__PURE__ */ jsx(
|
|
1011
|
-
QuickActionsButton,
|
|
1012
|
-
{
|
|
1013
|
-
label: t("customForms.newTemplate"),
|
|
1014
|
-
variant: "default",
|
|
1015
|
-
actions: createActions
|
|
1016
|
-
}
|
|
1017
|
-
) }) }),
|
|
1017
|
+
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(PageActions, { actions: createActions }) }),
|
|
1018
1018
|
/* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
1019
1019
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "relative min-w-[10rem] flex-1", children: [
|
|
1020
1020
|
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
|
|
@@ -1841,6 +1841,89 @@ function registerFormsTimelineSource() {
|
|
|
1841
1841
|
}
|
|
1842
1842
|
});
|
|
1843
1843
|
}
|
|
1844
|
+
var SUBMISSIONS = "plg_forms_rep_submissions";
|
|
1845
|
+
var CAT = tl("Forms", "Formul\xE1rios");
|
|
1846
|
+
var STATUS_LABELS = {
|
|
1847
|
+
draft: tl("Draft", "Rascunho"),
|
|
1848
|
+
completed: tl("Completed", "Conclu\xEDdo"),
|
|
1849
|
+
signed: tl("Signed", "Assinado"),
|
|
1850
|
+
archived: tl("Archived", "Arquivado")
|
|
1851
|
+
};
|
|
1852
|
+
function buildFormsAnalyticsCards() {
|
|
1853
|
+
const base = { domain: "custom_forms", compare: true, canonicalOwner: "public.documents" };
|
|
1854
|
+
return [
|
|
1855
|
+
{
|
|
1856
|
+
...base,
|
|
1857
|
+
id: "forms.submissions",
|
|
1858
|
+
name: tl("Form submissions", "Formul\xE1rios preenchidos"),
|
|
1859
|
+
description: tl(
|
|
1860
|
+
"Forms filled in during the period, whoever filled them.",
|
|
1861
|
+
"Formul\xE1rios preenchidos no per\xEDodo, por quem quer que seja."
|
|
1862
|
+
),
|
|
1863
|
+
icon: "FileText",
|
|
1864
|
+
category: CAT,
|
|
1865
|
+
grain: "submission",
|
|
1866
|
+
query: {
|
|
1867
|
+
source: { kind: "view", name: SUBMISSIONS },
|
|
1868
|
+
dimensions: [{ key: "created_at", label: tl("Date", "Data"), grain: "auto" }],
|
|
1869
|
+
measures: [{ key: "submissions", label: tl("Submissions", "Preenchimentos"), agg: "count", format: "number" }]
|
|
1870
|
+
},
|
|
1871
|
+
viz: { type: "kpi", spark: true },
|
|
1872
|
+
dashboard: { span: 1, order: 30 }
|
|
1873
|
+
},
|
|
1874
|
+
{
|
|
1875
|
+
...base,
|
|
1876
|
+
id: "forms.by-template",
|
|
1877
|
+
name: tl("Submissions by form", "Preenchimentos por formul\xE1rio"),
|
|
1878
|
+
description: tl(
|
|
1879
|
+
"Which templates are actually being used \u2014 and which one nobody answers.",
|
|
1880
|
+
"Quais modelos est\xE3o realmente em uso \u2014 e qual ningu\xE9m responde."
|
|
1881
|
+
),
|
|
1882
|
+
icon: "ClipboardList",
|
|
1883
|
+
category: CAT,
|
|
1884
|
+
grain: "submission",
|
|
1885
|
+
query: {
|
|
1886
|
+
source: { kind: "view", name: SUBMISSIONS },
|
|
1887
|
+
dimensions: [{ key: "template_name", label: tl("Form", "Formul\xE1rio") }],
|
|
1888
|
+
measures: [{ key: "submissions", label: tl("Submissions", "Preenchimentos"), agg: "count", format: "number" }],
|
|
1889
|
+
defaultSort: "submissions",
|
|
1890
|
+
defaultSortDir: "desc"
|
|
1891
|
+
},
|
|
1892
|
+
viz: { type: "breakdown", limit: 8 }
|
|
1893
|
+
},
|
|
1894
|
+
{
|
|
1895
|
+
// The list the product never had: one row per filled form, with the
|
|
1896
|
+
// person behind it. No measures, so it is a plain select — the rows ARE
|
|
1897
|
+
// the report, and the viewer's export button turns them into a file.
|
|
1898
|
+
...base,
|
|
1899
|
+
id: "forms.submissions-list",
|
|
1900
|
+
name: tl("Submission list", "Lista de preenchimentos"),
|
|
1901
|
+
description: tl(
|
|
1902
|
+
"Every form filled in the period, with who filled it \u2014 ready to export.",
|
|
1903
|
+
"Todo formul\xE1rio preenchido no per\xEDodo, com quem preencheu \u2014 pronto para exportar."
|
|
1904
|
+
),
|
|
1905
|
+
icon: "Table",
|
|
1906
|
+
category: CAT,
|
|
1907
|
+
grain: "submission",
|
|
1908
|
+
query: {
|
|
1909
|
+
source: { kind: "view", name: SUBMISSIONS },
|
|
1910
|
+
defaultSort: "created_at",
|
|
1911
|
+
defaultSortDir: "desc"
|
|
1912
|
+
},
|
|
1913
|
+
columns: [
|
|
1914
|
+
{ key: "created_at", label: tl("Filled", "Preenchido em"), type: "date", sortable: true },
|
|
1915
|
+
{ key: "template_name", label: tl("Form", "Formul\xE1rio"), type: "text" },
|
|
1916
|
+
{ key: "person_name", label: tl("Person", "Pessoa"), type: "person", idKey: "person_id" },
|
|
1917
|
+
{ key: "person_email", label: tl("E-mail", "E-mail"), type: "email" },
|
|
1918
|
+
{ key: "person_phone", label: tl("Phone", "Telefone"), type: "text" },
|
|
1919
|
+
{ key: "status", label: tl("Status", "Situa\xE7\xE3o"), type: "text", valueMap: STATUS_LABELS },
|
|
1920
|
+
{ key: "template_category", label: tl("Category", "Categoria"), type: "text", visible: false },
|
|
1921
|
+
{ key: "signed_at", label: tl("Signed at", "Assinado em"), type: "date", visible: false }
|
|
1922
|
+
],
|
|
1923
|
+
viz: { type: "table" }
|
|
1924
|
+
}
|
|
1925
|
+
];
|
|
1926
|
+
}
|
|
1844
1927
|
function registerBuiltInProviders(formsProvider) {
|
|
1845
1928
|
registerDocumentTypeProvider({
|
|
1846
1929
|
id: "custom_forms:templates",
|
|
@@ -1949,6 +2032,10 @@ function createCustomFormsPlugin(options) {
|
|
|
1949
2032
|
{ key: "form_templates", label: "Form templates", table: "plg_forms_templates" },
|
|
1950
2033
|
{ key: "documents_month", label: "Documents / month", table: "documents", period: "month" }
|
|
1951
2034
|
],
|
|
2035
|
+
// O formulário preenchido vira número e vira LISTA em /analytics — até aqui
|
|
2036
|
+
// ele só existia dentro da ficha de uma pessoa, um de cada vez. Read model
|
|
2037
|
+
// na migration 006.
|
|
2038
|
+
analyticsCards: options?.analyticsCards === false ? [] : buildFormsAnalyticsCards(),
|
|
1952
2039
|
navigation: [],
|
|
1953
2040
|
routes: [],
|
|
1954
2041
|
settings: [
|