strapi-plugin-hubspot 0.8.0 → 0.10.0

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 (38) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +28 -0
  3. package/dist/_chunks/{Forms-77Mornxt.mjs → Forms-BGdNbq-k.mjs} +348 -33
  4. package/dist/_chunks/{Forms-B8kkPY0c.js → Forms-BVkE1C46.js} +345 -30
  5. package/dist/_chunks/{HubspotFormInput-BVknnlmR.mjs → HubspotFormInput-QJldybwT.mjs} +1 -1
  6. package/dist/_chunks/{HubspotFormInput-kx3LlQYF.js → HubspotFormInput-ddrrD-GJ.js} +1 -1
  7. package/dist/_chunks/{HubspotObjectInput-B-Y1PZ6c.mjs → HubspotObjectInput-B_W9dpvD.mjs} +3 -3
  8. package/dist/_chunks/{HubspotObjectInput-BOO1PvOj.js → HubspotObjectInput-DZ4H-vju.js} +3 -3
  9. package/dist/_chunks/{HubspotPropertyInput-awfD1opH.js → HubspotPropertyInput-BJHUy5Zr.js} +3 -3
  10. package/dist/_chunks/{HubspotPropertyInput-Drxn_Ddt.mjs → HubspotPropertyInput-CiVxcnEt.mjs} +3 -3
  11. package/dist/_chunks/{Settings-DrujhMxS.mjs → Settings-B0NyQtsh.mjs} +2 -2
  12. package/dist/_chunks/{Settings-BT1NhvxO.js → Settings-DaFRUzjG.js} +2 -2
  13. package/dist/_chunks/{en-BYKKi1LK.mjs → en-D1sHFQdN.mjs} +48 -1
  14. package/dist/_chunks/{en-B8adhJhO.js → en-zJv-SuNb.js} +48 -1
  15. package/dist/_chunks/{fr-DzgArgi3.mjs → fr-E3zTW7pq.mjs} +48 -1
  16. package/dist/_chunks/{fr-DnKtGXaB.js → fr-fh0uH6Rp.js} +48 -1
  17. package/dist/_chunks/{index-LrCSAHoH.mjs → index-BpapRdHX.mjs} +6 -6
  18. package/dist/_chunks/{index-P7p8ASb6.js → index-rgjWxSn4.js} +6 -6
  19. package/dist/_chunks/{objectLabels-yNrnTOBo.mjs → objectLabels-DQYwGDr3.mjs} +1 -1
  20. package/dist/_chunks/{objectLabels-Dn-zriuZ.js → objectLabels-mBjwR5EE.js} +1 -1
  21. package/dist/_chunks/{useHubspotSchema-BottzdRR.js → useHubspotSchema-CJEiHbjz.js} +1 -1
  22. package/dist/_chunks/{useHubspotSchema-DccG2KbZ.mjs → useHubspotSchema-DX4JTPFt.mjs} +1 -1
  23. package/dist/admin/index.js +1 -1
  24. package/dist/admin/index.mjs +1 -1
  25. package/dist/admin/src/builder/types.d.ts +28 -1
  26. package/dist/admin/src/pages/Forms.d.ts +5 -1
  27. package/dist/admin/src/pages/Submissions.d.ts +8 -0
  28. package/dist/server/index.js +353 -14
  29. package/dist/server/index.mjs +353 -14
  30. package/dist/server/src/__tests__/importHubspot.test.d.ts +1 -0
  31. package/dist/server/src/__tests__/submissions.test.d.ts +1 -0
  32. package/dist/server/src/conditions.d.ts +3 -1
  33. package/dist/server/src/formsAdmin.d.ts +13 -0
  34. package/dist/server/src/importHubspot.d.ts +85 -0
  35. package/dist/server/src/index.d.ts +28 -1
  36. package/dist/server/src/submissions.d.ts +28 -0
  37. package/dist/shared/types.d.ts +15 -1
  38. package/package.json +1 -1
@@ -7,9 +7,9 @@ const index = require("./index-DkTxsEqL.js");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const icons = require("@strapi/icons");
9
9
  const admin = require("@strapi/strapi/admin");
10
- const index$1 = require("./index-P7p8ASb6.js");
11
- const objectLabels = require("./objectLabels-Dn-zriuZ.js");
12
- const useHubspotSchema = require("./useHubspotSchema-BottzdRR.js");
10
+ const index$1 = require("./index-rgjWxSn4.js");
11
+ const objectLabels = require("./objectLabels-mBjwR5EE.js");
12
+ const useHubspotSchema = require("./useHubspotSchema-CJEiHbjz.js");
13
13
  function _interopNamespace(e) {
14
14
  if (e && e.__esModule) return e;
15
15
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -28,8 +28,31 @@ function _interopNamespace(e) {
28
28
  return Object.freeze(n);
29
29
  }
30
30
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
31
- const OPERATORS = ["eq", "neq", "contains", "empty", "notEmpty", "gt", "lt"];
32
- const NEEDS_VALUE = /* @__PURE__ */ new Set(["eq", "neq", "contains", "gt", "lt"]);
31
+ const OPERATORS = [
32
+ "eq",
33
+ "neq",
34
+ "in",
35
+ "notIn",
36
+ "contains",
37
+ "notContains",
38
+ "startsWith",
39
+ "endsWith",
40
+ "empty",
41
+ "notEmpty",
42
+ "gt",
43
+ "lt"
44
+ ];
45
+ const NEEDS_VALUE = /* @__PURE__ */ new Set([
46
+ "eq",
47
+ "neq",
48
+ "contains",
49
+ "notContains",
50
+ "startsWith",
51
+ "endsWith",
52
+ "gt",
53
+ "lt"
54
+ ]);
55
+ const NEEDS_VALUES = /* @__PURE__ */ new Set(["in", "notIn"]);
33
56
  const ConditionEditor = ({ condition, candidates, onChange }) => {
34
57
  const { formatMessage } = index.useIntl();
35
58
  const t = (id, defaultMessage) => formatMessage({ id: index$1.getTranslation(id), defaultMessage });
@@ -40,7 +63,12 @@ const ConditionEditor = ({ condition, candidates, onChange }) => {
40
63
  empty: t("condition.op.empty", "is empty"),
41
64
  notEmpty: t("condition.op.notEmpty", "is filled"),
42
65
  gt: t("condition.op.gt", "is greater than"),
43
- lt: t("condition.op.lt", "is less than")
66
+ lt: t("condition.op.lt", "is less than"),
67
+ in: t("condition.op.in", "is any of"),
68
+ notIn: t("condition.op.notIn", "is none of"),
69
+ notContains: t("condition.op.notContains", "doesn't contain"),
70
+ startsWith: t("condition.op.startsWith", "starts with"),
71
+ endsWith: t("condition.op.endsWith", "ends with")
44
72
  };
45
73
  const rules = condition?.rules ?? [];
46
74
  const logic = condition?.logic ?? "and";
@@ -74,10 +102,31 @@ const ConditionEditor = ({ condition, candidates, onChange }) => {
74
102
  {
75
103
  "aria-label": t("condition.operator", "Operator"),
76
104
  value: rule.operator,
77
- onChange: (v) => updateRule(index2, { operator: v }),
105
+ onChange: (v) => updateRule(index2, { operator: v, value: "", values: [] }),
78
106
  children: OPERATORS.map((op) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: op, children: opLabel[op] }, op))
79
107
  }
80
108
  ) }),
109
+ NEEDS_VALUES.has(rule.operator) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { flex: "1", minWidth: "140px", children: targetOptions.length ? /* @__PURE__ */ jsxRuntime.jsx(
110
+ designSystem.MultiSelect,
111
+ {
112
+ "aria-label": t("condition.values", "Values"),
113
+ value: rule.values ?? [],
114
+ withTags: true,
115
+ onChange: (values) => updateRule(index2, { values }),
116
+ children: targetOptions.map((o) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.MultiSelectOption, { value: o.value, children: o.label || o.value }, o.value))
117
+ }
118
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
119
+ designSystem.TextInput,
120
+ {
121
+ "aria-label": t("condition.values", "Values"),
122
+ placeholder: t("condition.values-placeholder", "value1, value2…"),
123
+ defaultValue: (rule.values ?? []).join(", "),
124
+ onBlur: (e) => updateRule(index2, {
125
+ values: e.target.value.split(",").map((v) => v.trim()).filter(Boolean)
126
+ })
127
+ },
128
+ `${index2}-${rule.operator}`
129
+ ) }),
81
130
  NEEDS_VALUE.has(rule.operator) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { flex: "1", minWidth: "110px", children: targetOptions.length ? /* @__PURE__ */ jsxRuntime.jsx(
82
131
  designSystem.SingleSelect,
83
132
  {
@@ -930,6 +979,12 @@ const FormsList = () => {
930
979
  const [error, setError] = React__namespace.useState(null);
931
980
  const [sources, setSources] = React__namespace.useState([]);
932
981
  const [sourceId, setSourceId] = React__namespace.useState("");
982
+ const [hsForms, setHsForms] = React__namespace.useState([]);
983
+ const [hsFormId, setHsFormId] = React__namespace.useState("");
984
+ const [hsError, setHsError] = React__namespace.useState(null);
985
+ const [report, setReport] = React__namespace.useState(
986
+ null
987
+ );
933
988
  const t = (id, defaultMessage, values) => formatMessage({ id: index$1.getTranslation(id), defaultMessage }, values);
934
989
  const load = React__namespace.useCallback(async () => {
935
990
  const { data } = await get(`/${index$1.PLUGIN_ID}/builder/forms`);
@@ -940,6 +995,17 @@ const FormsList = () => {
940
995
  get(
941
996
  `/${index$1.PLUGIN_ID}/builder/import/sources`
942
997
  ).then(({ data }) => setSources(data.sources ?? [])).catch(() => setSources([]));
998
+ get(`/${index$1.PLUGIN_ID}/builder/import/hubspot`).then(({ data }) => setHsForms(data.configured ? data.forms ?? [] : [])).catch(
999
+ () => (
1000
+ // Reachable settings but no portal list: almost always the missing scope.
1001
+ setHsError(
1002
+ t(
1003
+ "forms.hubspot-list-error",
1004
+ "Could not list the portal's forms — the token needs the `forms` read scope."
1005
+ )
1006
+ )
1007
+ )
1008
+ );
943
1009
  }, [load]);
944
1010
  const runImport = async () => {
945
1011
  if (!sourceId) return;
@@ -955,6 +1021,48 @@ const FormsList = () => {
955
1021
  setBusy(false);
956
1022
  }
957
1023
  };
1024
+ const runHubspotImport = async () => {
1025
+ if (!hsFormId) return;
1026
+ setBusy(true);
1027
+ setError(null);
1028
+ setReport(null);
1029
+ try {
1030
+ const { data } = await post(
1031
+ `/${index$1.PLUGIN_ID}/builder/import/hubspot`,
1032
+ { formId: hsFormId }
1033
+ );
1034
+ if (data.skipped.length) {
1035
+ setReport(data);
1036
+ setBusy(false);
1037
+ await load();
1038
+ } else {
1039
+ navigate(data.documentId);
1040
+ }
1041
+ } catch {
1042
+ setError(t("forms.import-error", "Could not import the form."));
1043
+ setBusy(false);
1044
+ }
1045
+ };
1046
+ const skippedLine = (item) => {
1047
+ const label = item.label ?? "";
1048
+ const detail = item.detail ?? "";
1049
+ switch (item.code) {
1050
+ case "field-type":
1051
+ return t("forms.skipped-field-type", '"{label}" skipped — unsupported type ({detail})', { label, detail });
1052
+ case "hidden-field":
1053
+ return t("forms.skipped-hidden", '"{label}" skipped — hidden fields are not supported yet', { label });
1054
+ case "object":
1055
+ return t("forms.skipped-object", '"{label}" skipped — unmapped object ({detail})', { label, detail });
1056
+ case "duplicate":
1057
+ return t("forms.skipped-duplicate", '"{label}" skipped — the name "{detail}" is already used', { label, detail });
1058
+ case "condition":
1059
+ return t("forms.skipped-condition", 'Condition on "{label}" dropped — no equivalent operator ({detail})', { label, detail });
1060
+ case "rich-text":
1061
+ return t("forms.skipped-rich-text", "A content block was skipped — the builder has no rich-text element");
1062
+ case "legal-consent":
1063
+ return t("forms.skipped-consent", "The GDPR consent block was skipped — rebuild it as a field if needed");
1064
+ }
1065
+ };
958
1066
  const create = async () => {
959
1067
  if (!name.trim()) return;
960
1068
  setBusy(true);
@@ -1007,6 +1115,7 @@ const FormsList = () => {
1007
1115
  ) })
1008
1116
  ] }),
1009
1117
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1118
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.List, {}), onClick: () => navigate("submissions"), children: t("forms.submissions", "Submissions") }),
1010
1119
  /* @__PURE__ */ jsxRuntime.jsx(
1011
1120
  designSystem.TextInput,
1012
1121
  {
@@ -1021,38 +1130,74 @@ const FormsList = () => {
1021
1130
  ] })
1022
1131
  ] }),
1023
1132
  error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", children: error }) }),
1024
- sources.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", hasRadius: true, shadow: "tableShadow", padding: 4, marginBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "flex-end", justifyContent: "space-between", children: [
1133
+ (sources.length > 0 || hsForms.length > 0 || hsError) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", hasRadius: true, shadow: "tableShadow", padding: 4, marginBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1134
+ hsForms.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "flex-end", justifyContent: "space-between", children: [
1135
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1136
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: t("forms.import-hubspot-title", "Import from your HubSpot portal") }),
1137
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", tag: "p", children: t(
1138
+ "forms.import-hubspot-hint",
1139
+ "Translates a form built in HubSpot into a draft here, CRM mapping included. What the builder can't express is skipped and reported. Re-importing overwrites the draft."
1140
+ ) })
1141
+ ] }),
1142
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1143
+ /* @__PURE__ */ jsxRuntime.jsx(
1144
+ designSystem.SingleSelect,
1145
+ {
1146
+ "aria-label": t("forms.import-hubspot-source", "HubSpot form to import"),
1147
+ placeholder: t("forms.import-hubspot-source", "HubSpot form to import"),
1148
+ value: hsFormId,
1149
+ onChange: (v) => setHsFormId(String(v)),
1150
+ children: hsForms.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: f.id, children: f.name }, f.id))
1151
+ }
1152
+ ),
1153
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: runHubspotImport, disabled: busy || !hsFormId, children: t("forms.import", "Import") })
1154
+ ] })
1155
+ ] }),
1156
+ hsError && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "warning700", children: hsError }),
1157
+ sources.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "flex-end", justifyContent: "space-between", children: [
1158
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1159
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: t("forms.import-title", "Import an existing form") }),
1160
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", tag: "p", children: t(
1161
+ "forms.import-hint",
1162
+ "Converts a legacy content-type form (all locales) into a draft here — same slug, source untouched. Re-importing overwrites the draft."
1163
+ ) })
1164
+ ] }),
1165
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1166
+ /* @__PURE__ */ jsxRuntime.jsx(
1167
+ designSystem.SingleSelect,
1168
+ {
1169
+ "aria-label": t("forms.import-source", "Form to import"),
1170
+ placeholder: t("forms.import-source", "Form to import"),
1171
+ value: sourceId,
1172
+ onChange: (v) => setSourceId(String(v)),
1173
+ children: sources.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: s.documentId, children: [
1174
+ s.name,
1175
+ " ",
1176
+ s.slug ? `(${s.slug})` : ""
1177
+ ] }, s.documentId))
1178
+ }
1179
+ ),
1180
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: runImport, disabled: busy || !sourceId, children: t("forms.import", "Import") })
1181
+ ] })
1182
+ ] })
1183
+ ] }) }),
1184
+ report && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "warning100", hasRadius: true, padding: 4, marginBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "flex-start", gap: 4, children: [
1025
1185
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1026
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: t("forms.import-title", "Import an existing form") }),
1027
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", tag: "p", children: t(
1028
- "forms.import-hint",
1029
- "Converts a legacy content-type form (all locales) into a draft here — same slug, source untouched. Re-importing overwrites the draft."
1030
- ) })
1186
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", textColor: "warning700", children: t("forms.report-title", "Imported with gaps") }),
1187
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { tag: "ul", paddingTop: 2, style: { listStyle: "disc", paddingLeft: 16 }, children: report.skipped.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "warning700", children: skippedLine(item) }) }, i)) })
1031
1188
  ] }),
1032
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1033
- /* @__PURE__ */ jsxRuntime.jsx(
1034
- designSystem.SingleSelect,
1035
- {
1036
- "aria-label": t("forms.import-source", "Form to import"),
1037
- placeholder: t("forms.import-source", "Form to import"),
1038
- value: sourceId,
1039
- onChange: (v) => setSourceId(String(v)),
1040
- children: sources.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: s.documentId, children: [
1041
- s.name,
1042
- " ",
1043
- s.slug ? `(${s.slug})` : ""
1044
- ] }, s.documentId))
1045
- }
1046
- ),
1047
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: runImport, disabled: busy || !sourceId, children: t("forms.import", "Import") })
1189
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, shrink: 0, children: [
1190
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", onClick: () => setReport(null), children: t("forms.report-dismiss", "Dismiss") }),
1191
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => navigate(report.documentId), children: t("forms.report-open", "Open the form") })
1048
1192
  ] })
1049
1193
  ] }) }),
1050
- !rows ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: t("forms.loading", "Loading…") }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", hasRadius: true, shadow: "tableShadow", padding: 8, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: t("forms.empty", "No form yet — name one above to open the builder.") }) }) : /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 6, rowCount: rows.length, children: [
1194
+ !rows ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: t("forms.loading", "Loading…") }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", hasRadius: true, shadow: "tableShadow", padding: 8, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: t("forms.empty", "No form yet — name one above to open the builder.") }) }) : /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 7, rowCount: rows.length, children: [
1051
1195
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1052
1196
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-name", "Name") }) }),
1053
1197
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-slug", "Slug") }) }),
1054
1198
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-structure", "Structure") }) }),
1055
1199
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-status", "Status") }) }),
1200
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-submissions", "Submissions") }) }),
1056
1201
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-updated", "Updated") }) }),
1057
1202
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("forms.col-actions", "Actions") }) })
1058
1203
  ] }) }),
@@ -1069,6 +1214,15 @@ const FormsList = () => {
1069
1214
  fields: row.fields
1070
1215
  }) }) }),
1071
1216
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: row.published ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success700", children: t("forms.published", "Published") }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: t("forms.draft", "Draft") }) }),
1217
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { onClick: (e) => e.stopPropagation(), children: row.submissions > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
1218
+ designSystem.Button,
1219
+ {
1220
+ variant: "ghost",
1221
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.List, {}),
1222
+ onClick: () => navigate(`submissions?form=${encodeURIComponent(row.slug)}`),
1223
+ children: row.submissions
1224
+ }
1225
+ ) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: "—" }) }),
1072
1226
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: row.updatedAt ? new Date(row.updatedAt).toLocaleString() : "—" }) }),
1073
1227
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, children: [
1074
1228
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1097,8 +1251,169 @@ const FormsList = () => {
1097
1251
  ] })
1098
1252
  ] });
1099
1253
  };
1254
+ const PAGE_SIZE = 20;
1255
+ const preview = (values, max = 3) => {
1256
+ const parts = Object.entries(values ?? {}).slice(0, max).map(([k, v]) => `${k}: ${String(v)}`);
1257
+ const more = Object.keys(values ?? {}).length - max;
1258
+ return parts.join(" · ") + (more > 0 ? ` · +${more}` : "");
1259
+ };
1260
+ const Submissions = () => {
1261
+ const { formatMessage } = index.useIntl();
1262
+ const { get } = admin.useFetchClient();
1263
+ const navigate = reactRouterDom.useNavigate();
1264
+ const [searchParams, setSearchParams] = reactRouterDom.useSearchParams();
1265
+ const form = searchParams.get("form") ?? "";
1266
+ const [forms, setForms] = React__namespace.useState([]);
1267
+ const [rows, setRows] = React__namespace.useState(null);
1268
+ const [total, setTotal] = React__namespace.useState(0);
1269
+ const [page, setPage] = React__namespace.useState(1);
1270
+ const [selected, setSelected] = React__namespace.useState(null);
1271
+ const [error, setError] = React__namespace.useState(null);
1272
+ const [exporting, setExporting] = React__namespace.useState(false);
1273
+ const t = (id, defaultMessage, values) => formatMessage({ id: index$1.getTranslation(id), defaultMessage }, values);
1274
+ React__namespace.useEffect(() => {
1275
+ get(`/${index$1.PLUGIN_ID}/builder/forms`).then(({ data }) => setForms(data.forms)).catch(() => setForms([]));
1276
+ }, [get]);
1277
+ React__namespace.useEffect(() => {
1278
+ setRows(null);
1279
+ const query = new URLSearchParams({ page: String(page), pageSize: String(PAGE_SIZE) });
1280
+ if (form) query.set("form", form);
1281
+ get(
1282
+ `/${index$1.PLUGIN_ID}/builder/submissions?${query}`
1283
+ ).then(({ data }) => {
1284
+ setRows(data.submissions);
1285
+ setTotal(data.total);
1286
+ }).catch(() => setError(t("submissions.load-error", "Could not load the submissions.")));
1287
+ }, [get, form, page]);
1288
+ const changeForm = (slug) => {
1289
+ setPage(1);
1290
+ setSearchParams(slug ? { form: slug } : {});
1291
+ };
1292
+ const exportCsv = async () => {
1293
+ if (!form) return;
1294
+ setExporting(true);
1295
+ setError(null);
1296
+ try {
1297
+ const { data } = await get(
1298
+ `/${index$1.PLUGIN_ID}/builder/submissions/export?form=${encodeURIComponent(form)}`
1299
+ );
1300
+ const url = URL.createObjectURL(new Blob([data.csv], { type: "text/csv;charset=utf-8" }));
1301
+ const link = document.createElement("a");
1302
+ link.href = url;
1303
+ link.download = data.filename;
1304
+ link.click();
1305
+ URL.revokeObjectURL(url);
1306
+ } catch {
1307
+ setError(t("submissions.export-error", "Could not export the submissions."));
1308
+ } finally {
1309
+ setExporting(false);
1310
+ }
1311
+ };
1312
+ const pages = Math.max(1, Math.ceil(total / PAGE_SIZE));
1313
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 8, children: [
1314
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "flex-end", paddingBottom: 6, children: [
1315
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1316
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
1317
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { label: t("submissions.back", "Back to the forms"), onClick: () => navigate(".."), children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}) }),
1318
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: t("submissions.title", "Submissions") })
1319
+ ] }),
1320
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "epsilon", textColor: "neutral600", tag: "p", children: t(
1321
+ "submissions.subtitle",
1322
+ "Every answer received by the built forms — stored whatever the CRM's mood."
1323
+ ) })
1324
+ ] }),
1325
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1326
+ /* @__PURE__ */ jsxRuntime.jsx(
1327
+ designSystem.SingleSelect,
1328
+ {
1329
+ "aria-label": t("submissions.filter", "Filter by form"),
1330
+ placeholder: t("submissions.all-forms", "All forms"),
1331
+ value: form,
1332
+ onChange: (v) => changeForm(String(v)),
1333
+ onClear: () => changeForm(""),
1334
+ children: forms.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: f.slug, children: f.name }, f.slug))
1335
+ }
1336
+ ),
1337
+ /* @__PURE__ */ jsxRuntime.jsx(
1338
+ designSystem.Button,
1339
+ {
1340
+ variant: "secondary",
1341
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
1342
+ onClick: exportCsv,
1343
+ disabled: !form || exporting,
1344
+ title: form ? void 0 : t("submissions.export-pick", "Pick a form to export"),
1345
+ children: t("submissions.export", "Export CSV")
1346
+ }
1347
+ )
1348
+ ] })
1349
+ ] }),
1350
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger600", children: error }) }),
1351
+ !rows ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: t("submissions.loading", "Loading…") }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { background: "neutral0", hasRadius: true, shadow: "tableShadow", padding: 8, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: form ? t("submissions.empty-form", "No submission for this form yet.") : t("submissions.empty", "No submission yet.") }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1352
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 5, rowCount: rows.length, children: [
1353
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1354
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("submissions.col-date", "Date") }) }),
1355
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("submissions.col-form", "Form") }) }),
1356
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("submissions.col-email", "Email") }) }),
1357
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("submissions.col-answers", "Answers") }) }),
1358
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: t("submissions.col-crm", "CRM") }) })
1359
+ ] }) }),
1360
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: rows.map((row) => /* @__PURE__ */ jsxRuntime.jsxs(
1361
+ designSystem.Tr,
1362
+ {
1363
+ onClick: () => setSelected(row),
1364
+ style: { cursor: "pointer" },
1365
+ children: [
1366
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: row.createdAt ? new Date(row.createdAt).toLocaleString() : "—" }) }),
1367
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.formTitle || row.form }) }),
1368
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", children: row.email || "—" }) }),
1369
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", ellipsis: true, children: preview(row.values) }) }),
1370
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: row.hubspotSynced ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success700", children: t("submissions.synced", "Synced") }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.not-synced", "Not synced") }) })
1371
+ ]
1372
+ },
1373
+ row.documentId
1374
+ )) })
1375
+ ] }),
1376
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", paddingTop: 4, children: [
1377
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: t("submissions.count", "{total, plural, one {# submission} other {# submissions}}", {
1378
+ total
1379
+ }) }),
1380
+ pages > 1 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1381
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", disabled: page <= 1, onClick: () => setPage(page - 1), children: t("submissions.prev", "Previous") }),
1382
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: t("submissions.page", "{page} / {pages}", { page, pages }) }),
1383
+ /* @__PURE__ */ jsxRuntime.jsx(
1384
+ designSystem.Button,
1385
+ {
1386
+ variant: "tertiary",
1387
+ disabled: page >= pages,
1388
+ onClick: () => setPage(page + 1),
1389
+ children: t("submissions.next", "Next")
1390
+ }
1391
+ )
1392
+ ] })
1393
+ ] })
1394
+ ] }),
1395
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: Boolean(selected), onOpenChange: (open) => !open && setSelected(null), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1396
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Title, { children: [
1397
+ selected?.formTitle || selected?.form,
1398
+ " ",
1399
+ selected?.createdAt ? `— ${new Date(selected.createdAt).toLocaleString()}` : ""
1400
+ ] }) }),
1401
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: selected && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1402
+ Object.entries(selected.values ?? {}).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1403
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: key }),
1404
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: String(value) })
1405
+ ] }, key)),
1406
+ selected.meta?.pagePath && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1407
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: t("submissions.meta-page", "Submitted from") }),
1408
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: selected.meta.pagePath })
1409
+ ] })
1410
+ ] }) })
1411
+ ] }) })
1412
+ ] });
1413
+ };
1100
1414
  const Forms = () => /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [
1101
1415
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: /* @__PURE__ */ jsxRuntime.jsx(FormsList, {}) }),
1416
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "submissions", element: /* @__PURE__ */ jsxRuntime.jsx(Submissions, {}) }),
1102
1417
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: ":documentId", element: /* @__PURE__ */ jsxRuntime.jsx(FormEditor, {}) })
1103
1418
  ] });
1104
1419
  exports.default = Forms;
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Field, Flex, Loader, Combobox, ComboboxOption } from "@strapi/design-system";
5
5
  import { useFetchClient } from "@strapi/strapi/admin";
6
- import { P as PLUGIN_ID, g as getTranslation } from "./index-LrCSAHoH.mjs";
6
+ import { P as PLUGIN_ID, g as getTranslation } from "./index-BpapRdHX.mjs";
7
7
  const HubspotFormInput = React.forwardRef(
8
8
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
9
9
  const { formatMessage } = useIntl();
@@ -5,7 +5,7 @@ const React = require("react");
5
5
  const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const admin = require("@strapi/strapi/admin");
8
- const index$1 = require("./index-P7p8ASb6.js");
8
+ const index$1 = require("./index-rgjWxSn4.js");
9
9
  function _interopNamespace(e) {
10
10
  if (e && e.__esModule) return e;
11
11
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -2,9 +2,9 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Field, Flex, Loader, SingleSelect, SingleSelectOption } from "@strapi/design-system";
5
- import { g as getTranslation } from "./index-LrCSAHoH.mjs";
6
- import { o as objectLabel } from "./objectLabels-yNrnTOBo.mjs";
7
- import { u as useHubspotSchema } from "./useHubspotSchema-DccG2KbZ.mjs";
5
+ import { g as getTranslation } from "./index-BpapRdHX.mjs";
6
+ import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
7
+ import { u as useHubspotSchema } from "./useHubspotSchema-DX4JTPFt.mjs";
8
8
  const HubspotObjectInput = React.forwardRef(
9
9
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
10
10
  const intl = useIntl();
@@ -4,9 +4,9 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
- const index$1 = require("./index-P7p8ASb6.js");
8
- const objectLabels = require("./objectLabels-Dn-zriuZ.js");
9
- const useHubspotSchema = require("./useHubspotSchema-BottzdRR.js");
7
+ const index$1 = require("./index-rgjWxSn4.js");
8
+ const objectLabels = require("./objectLabels-mBjwR5EE.js");
9
+ const useHubspotSchema = require("./useHubspotSchema-CJEiHbjz.js");
10
10
  function _interopNamespace(e) {
11
11
  if (e && e.__esModule) return e;
12
12
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -6,9 +6,9 @@ const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const icons = require("@strapi/icons");
8
8
  const admin = require("@strapi/strapi/admin");
9
- const index$1 = require("./index-P7p8ASb6.js");
10
- const objectLabels = require("./objectLabels-Dn-zriuZ.js");
11
- const useHubspotSchema = require("./useHubspotSchema-BottzdRR.js");
9
+ const index$1 = require("./index-rgjWxSn4.js");
10
+ const objectLabels = require("./objectLabels-mBjwR5EE.js");
11
+ const useHubspotSchema = require("./useHubspotSchema-CJEiHbjz.js");
12
12
  function _interopNamespace(e) {
13
13
  if (e && e.__esModule) return e;
14
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -4,9 +4,9 @@ import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Field, Flex, Loader, Combobox, ComboboxOption, IconButton, Button, Typography, Link } from "@strapi/design-system";
5
5
  import { ArrowClockwise } from "@strapi/icons";
6
6
  import { useField } from "@strapi/strapi/admin";
7
- import { g as getTranslation } from "./index-LrCSAHoH.mjs";
8
- import { o as objectLabel } from "./objectLabels-yNrnTOBo.mjs";
9
- import { u as useHubspotSchema } from "./useHubspotSchema-DccG2KbZ.mjs";
7
+ import { g as getTranslation } from "./index-BpapRdHX.mjs";
8
+ import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
9
+ import { u as useHubspotSchema } from "./useHubspotSchema-DX4JTPFt.mjs";
10
10
  const oneLine = {
11
11
  display: "block",
12
12
  whiteSpace: "nowrap",
@@ -3,9 +3,9 @@ import * as React from "react";
3
3
  import { u as useIntl } from "./index-CEh8vkxY.mjs";
4
4
  import { Flex, Divider, Typography, Button, Box, Link, Badge, Loader, Field } from "@strapi/design-system";
5
5
  import { useFetchClient } from "@strapi/strapi/admin";
6
- import { g as getTranslation, P as PLUGIN_ID } from "./index-LrCSAHoH.mjs";
6
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-BpapRdHX.mjs";
7
7
  import { Link as Link$1 } from "react-router-dom";
8
- import { o as objectLabel } from "./objectLabels-yNrnTOBo.mjs";
8
+ import { o as objectLabel } from "./objectLabels-DQYwGDr3.mjs";
9
9
  const AuditSection = ({ configured }) => {
10
10
  const intl = useIntl();
11
11
  const { formatMessage } = intl;
@@ -5,9 +5,9 @@ const React = require("react");
5
5
  const index = require("./index-DkTxsEqL.js");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const admin = require("@strapi/strapi/admin");
8
- const index$1 = require("./index-P7p8ASb6.js");
8
+ const index$1 = require("./index-rgjWxSn4.js");
9
9
  const reactRouterDom = require("react-router-dom");
10
- const objectLabels = require("./objectLabels-Dn-zriuZ.js");
10
+ const objectLabels = require("./objectLabels-mBjwR5EE.js");
11
11
  function _interopNamespace(e) {
12
12
  if (e && e.__esModule) return e;
13
13
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -204,7 +204,54 @@ const en = {
204
204
  "panel.persist": "Answer memory",
205
205
  "panel.persist-session": "This visit only",
206
206
  "panel.persist-days30": "30 days (non-identifying fields only)",
207
- "panel.class": "CSS classes"
207
+ "panel.class": "CSS classes",
208
+ "forms.col-submissions": "Submissions",
209
+ "forms.submissions": "Submissions",
210
+ "forms.import-hubspot-title": "Import from your HubSpot portal",
211
+ "forms.import-hubspot-hint": "Translates a form built in HubSpot into a draft here, CRM mapping included. What the builder can't express is skipped and reported. Re-importing overwrites the draft.",
212
+ "forms.import-hubspot-source": "HubSpot form to import",
213
+ "forms.hubspot-list-error": "Could not list the portal's forms — the token needs the `forms` read scope.",
214
+ "forms.report-title": "Imported with gaps",
215
+ "forms.report-dismiss": "Dismiss",
216
+ "forms.report-open": "Open the form",
217
+ "forms.skipped-field-type": '"{label}" skipped — unsupported type ({detail})',
218
+ "forms.skipped-hidden": '"{label}" skipped — hidden fields are not supported yet',
219
+ "forms.skipped-object": '"{label}" skipped — unmapped object ({detail})',
220
+ "forms.skipped-duplicate": '"{label}" skipped — the name "{detail}" is already used',
221
+ "forms.skipped-condition": 'Condition on "{label}" dropped — no equivalent operator ({detail})',
222
+ "forms.skipped-rich-text": "A content block was skipped — the builder has no rich-text element",
223
+ "forms.skipped-consent": "The GDPR consent block was skipped — rebuild it as a field if needed",
224
+ "submissions.title": "Submissions",
225
+ "submissions.subtitle": "Every answer received by the built forms — stored whatever the CRM's mood.",
226
+ "submissions.back": "Back to the forms",
227
+ "submissions.filter": "Filter by form",
228
+ "submissions.all-forms": "All forms",
229
+ "submissions.export": "Export CSV",
230
+ "submissions.export-pick": "Pick a form to export",
231
+ "submissions.export-error": "Could not export the submissions.",
232
+ "submissions.load-error": "Could not load the submissions.",
233
+ "submissions.loading": "Loading…",
234
+ "submissions.empty": "No submission yet.",
235
+ "submissions.empty-form": "No submission for this form yet.",
236
+ "submissions.col-date": "Date",
237
+ "submissions.col-form": "Form",
238
+ "submissions.col-email": "Email",
239
+ "submissions.col-answers": "Answers",
240
+ "submissions.col-crm": "CRM",
241
+ "submissions.synced": "Synced",
242
+ "submissions.not-synced": "Not synced",
243
+ "submissions.count": "{total, plural, one {# submission} other {# submissions}}",
244
+ "submissions.prev": "Previous",
245
+ "submissions.next": "Next",
246
+ "submissions.page": "{page} / {pages}",
247
+ "submissions.meta-page": "Submitted from",
248
+ "condition.op.in": "is any of",
249
+ "condition.op.notIn": "is none of",
250
+ "condition.op.notContains": "doesn't contain",
251
+ "condition.op.startsWith": "starts with",
252
+ "condition.op.endsWith": "ends with",
253
+ "condition.values": "Values",
254
+ "condition.values-placeholder": "value1, value2…"
208
255
  };
209
256
  export {
210
257
  en as default