strapi-plugin-hubspot 0.16.2 → 0.16.5

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 (33) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +8 -5
  3. package/dist/_chunks/{Forms-BOQWely0.mjs → Forms-DyV6KyiO.mjs} +20 -6
  4. package/dist/_chunks/{Forms-mMNP7hc9.js → Forms-uUN4XjhW.js} +20 -6
  5. package/dist/_chunks/{HubspotFormInput-DI35Aqiu.js → HubspotFormInput-BkWat_wu.js} +1 -1
  6. package/dist/_chunks/{HubspotFormInput-DCkoavrN.mjs → HubspotFormInput-DEXPX-6j.mjs} +1 -1
  7. package/dist/_chunks/{HubspotObjectInput-Cq1TuL_l.js → HubspotObjectInput-CFDYW-TM.js} +3 -3
  8. package/dist/_chunks/{HubspotObjectInput-BbnvhdbD.mjs → HubspotObjectInput-DL8fYK2x.mjs} +3 -3
  9. package/dist/_chunks/{HubspotPropertyInput-BLZzsW08.js → HubspotPropertyInput-CFMkbQeT.js} +3 -3
  10. package/dist/_chunks/{HubspotPropertyInput-BHfpBD36.mjs → HubspotPropertyInput-WU5FMJj3.mjs} +3 -3
  11. package/dist/_chunks/{Settings-BAsx0LGv.js → Settings-B_hhdpHa.js} +21 -3
  12. package/dist/_chunks/{Settings-DqRpHtnT.mjs → Settings-CiXEps_C.mjs} +21 -3
  13. package/dist/_chunks/{en-Djd3TID0.mjs → en-BIUBYzHv.mjs} +5 -1
  14. package/dist/_chunks/{en-sfzopB5K.js → en-CFhEtgZJ.js} +5 -1
  15. package/dist/_chunks/{fr-C7t1elmR.mjs → fr-CMYcnFH0.mjs} +5 -1
  16. package/dist/_chunks/{fr-sF5Josfh.js → fr-zdUuuV0M.js} +5 -1
  17. package/dist/_chunks/{index-CLAy5dVN.mjs → index-BeBn7bJa.mjs} +6 -6
  18. package/dist/_chunks/{index-R3ReZXF1.js → index-CG_WQzSa.js} +6 -6
  19. package/dist/_chunks/{objectLabels-CW2iBOkD.js → objectLabels-BGq-Ypgn.js} +1 -1
  20. package/dist/_chunks/{objectLabels--zOmqsfm.mjs → objectLabels-CS_0QCNz.mjs} +1 -1
  21. package/dist/_chunks/{useHubspotSchema-BRzzvs9t.js → useHubspotSchema-BZP2qkAu.js} +1 -1
  22. package/dist/_chunks/{useHubspotSchema-Bz2o1BU-.mjs → useHubspotSchema-CP7LRdzO.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 +1 -1
  26. package/dist/server/index.js +108 -30
  27. package/dist/server/index.mjs +108 -30
  28. package/dist/server/src/forms.d.ts +3 -2
  29. package/dist/server/src/hsforms.d.ts +53 -7
  30. package/dist/server/src/importHubspot.d.ts +9 -0
  31. package/dist/server/src/index.d.ts +1 -0
  32. package/dist/server/src/settings.d.ts +6 -0
  33. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.16.5 — 2026-09-23
6
+
7
+ ### Fixed
8
+ - Admin TypeScript build failed on Submissions (`unknown` used as ReactNode).
9
+ Same conversion-fail behaviour as 0.16.4; this is the first npm publish of
10
+ that fix.
11
+
12
+ ## 0.16.4 — 2026-09-23
13
+
14
+ ### Fixed
15
+ - A linked HubSpot form that refused the Forms API (GDPR communications,
16
+ CAPTCHA, extra required fields) silently fell back to a CRM upsert + note,
17
+ so the contact looked updated with no native submission. The submit now
18
+ sends `objectTypeId`, the form's communication consents, skips the
19
+ email-only retry when HubSpot requires other fields, and refuses CAPTCHA
20
+ forms with a stored error. Strapi Submissions distinguish **Conversion**
21
+ vs **Contact only**.
22
+
23
+ ## 0.16.3 — 2026-09-22
24
+
25
+ ### Changed
26
+ - Timeline recap notes (`forms.timelineNote`, default `true`) now also write
27
+ after a native Forms API conversion: page URL and originating subject sit
28
+ on the contact next to the conversion. The Forms API already forwards
29
+ `context.pageUri` / `pageName`. Toggle lives in Settings → HubSpot.
30
+
5
31
  ## 0.16.2 — 2026-09-22
6
32
 
7
33
  ### Added
package/README.md CHANGED
@@ -54,11 +54,14 @@ upserts can share the same plugin:
54
54
  | `forms.submissionMode` | `auto` | `auto`: Forms API when a marketing GUID is linked, else CRM upsert. `forms`: always try the Forms API. `crm`: never count as a conversion |
55
55
  | `forms.writeExtraProperties` | `true` | After a conversion, CRM-write mapped contact fields the HubSpot form dropped (they 400 the Forms API) |
56
56
  | `forms.syncFieldsOnPublish` | `false` | On publish, PATCH missing mapped **contact** fields onto the HubSpot form. Off by default so HubSpot-first installs aren't mutated |
57
+ | `forms.timelineNote` | `true` | Recap note on the contact after a successful sync (page URL, subject, answers). Sits next to a native conversion; turn off if you only want the form submission |
57
58
 
58
- The visitor's `hutk` is forwarded so attribution sticks. Then the contact is
59
- looked up by email and, when the address is on a corporate domain, the company
60
- is found-or-created and associated. Timeline notes are opt-in and only used
61
- on the CRM-upsert path.
59
+ The visitor's `hutk` is forwarded so attribution sticks. The conversion carries
60
+ `context.pageUri` / `pageName` (the page the visitor submitted from). Then the
61
+ contact is looked up by email and, when the address is on a corporate domain,
62
+ the company is found-or-created and associated. Timeline notes (`forms.timelineNote`,
63
+ default `true`) add a recap of that page plus the originating subject on the
64
+ contact timeline — they don't replace the conversion.
62
65
 
63
66
  CRM properties are **never created**. Map to properties that already exist in
64
67
  the portal; opting into field sync only adds form fields that point at those
@@ -75,7 +78,7 @@ hubspot: {
75
78
  region: env("HUBSPOT_REGION", "eu1"), // eu1 → api-eu1.hsforms.com
76
79
  forms: {
77
80
  companyFromDomain: true, // Company by corporate domain + association
78
- timelineNote: false, // recap note on the CRM-upsert fallback only
81
+ timelineNote: true, // recap note (page + subject) next to the conversion
79
82
  defaultFormId: env("HUBSPOT_DEFAULT_FORM_ID", ""),
80
83
  submissionMode: "auto", // auto | forms | crm
81
84
  writeExtraProperties: true,
@@ -5,12 +5,12 @@ import { u as useIntl } from "./index-CEh8vkxY.mjs";
5
5
  import { Typography, Flex, Box, SingleSelect, SingleSelectOption, MultiSelect, MultiSelectOption, TextInput, IconButton, Button, Combobox, ComboboxOption, Field, Textarea, Checkbox, Divider, Loader, Badge, Table, Thead, Tr, Th, Tbody, Td, Modal } from "@strapi/design-system";
6
6
  import { Trash, Plus, ArrowClockwise, ArrowLeft, Drag, ArrowUp, ArrowDown, List, Duplicate, Download } from "@strapi/icons";
7
7
  import { useFetchClient } from "@strapi/strapi/admin";
8
- import { g as getTranslation, P as PLUGIN_ID } from "./index-CLAy5dVN.mjs";
8
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-BeBn7bJa.mjs";
9
9
  import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, useDroppable, closestCorners } from "@dnd-kit/core";
10
10
  import { arrayMove, sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from "@dnd-kit/sortable";
11
11
  import { CSS } from "@dnd-kit/utilities";
12
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
13
- import { u as useHubspotSchema } from "./useHubspotSchema-Bz2o1BU-.mjs";
12
+ import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
13
+ import { u as useHubspotSchema } from "./useHubspotSchema-CP7LRdzO.mjs";
14
14
  const OPERATORS = [
15
15
  "eq",
16
16
  "neq",
@@ -705,6 +705,7 @@ const FormEditor = () => {
705
705
  const locale = searchParams.get("locale") ?? void 0;
706
706
  const [entry, setEntry] = React.useState(null);
707
707
  const [published, setPublished] = React.useState(false);
708
+ const [publishedHubspotFormId, setPublishedHubspotFormId] = React.useState(null);
708
709
  const [locales, setLocales] = React.useState([]);
709
710
  const [selection, setSelection] = React.useState({ kind: "form" });
710
711
  const [dirty, setDirty] = React.useState(false);
@@ -741,6 +742,7 @@ const FormEditor = () => {
741
742
  if (cancelled) return;
742
743
  setEntry(data.form);
743
744
  setPublished(data.published);
745
+ setPublishedHubspotFormId(data.publishedHubspotFormId ?? null);
744
746
  setDirty(false);
745
747
  }).catch(async () => {
746
748
  if (cancelled || !locale) return;
@@ -851,6 +853,7 @@ const FormEditor = () => {
851
853
  try {
852
854
  const { data } = await post(`/${PLUGIN_ID}/builder/forms/${documentId}/publish${query}`);
853
855
  setPublished(true);
856
+ setPublishedHubspotFormId(entry.hubspotFormId ?? null);
854
857
  setErrors([]);
855
858
  setProblems([]);
856
859
  const added = Array.isArray(data?.addedFields) ? data.addedFields.length : 0;
@@ -1339,7 +1342,10 @@ const FormEditor = () => {
1339
1342
  ),
1340
1343
  onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
1341
1344
  children: [
1342
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: t("editor.hubspot-form-none", "None — CRM upsert only") }),
1345
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: t(
1346
+ "editor.hubspot-form-none",
1347
+ "Default marketing form (Settings) — contact only if none is set"
1348
+ ) }),
1343
1349
  entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsx(SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
1344
1350
  hsForms.map((f) => /* @__PURE__ */ jsx(SingleSelectOption, { value: f.id, children: f.name }, f.id))
1345
1351
  ]
@@ -1355,6 +1361,10 @@ const FormEditor = () => {
1355
1361
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
1356
1362
  "editor.hubspot-form-hint",
1357
1363
  "Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay."
1364
+ ) }),
1365
+ published && (entry.hubspotFormId || "") !== (publishedHubspotFormId || "") && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", children: t(
1366
+ "editor.hubspot-form-unpublished",
1367
+ "The live site still uses the previously published HubSpot form. Publish to apply this link."
1358
1368
  ) })
1359
1369
  ] }),
1360
1370
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
@@ -1764,7 +1774,7 @@ const Submissions = () => {
1764
1774
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { children: row.formTitle || row.form }) }),
1765
1775
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: row.email || "—" }) }),
1766
1776
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", ellipsis: true, children: preview(row.values) }) }),
1767
- /* @__PURE__ */ jsx(Td, { children: row.hubspotSynced ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: t("submissions.synced", "Synced") }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.not-synced", "Not synced") }) })
1777
+ /* @__PURE__ */ jsx(Td, { children: row.meta?.hubspotConversion === true || row.meta?.hubspotConversion === "true" ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: t("submissions.converted", "Conversion") }) : row.hubspotSynced ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.contact-only", "Contact only") }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.not-synced", "Not synced") }) })
1768
1778
  ]
1769
1779
  },
1770
1780
  row.documentId
@@ -1800,9 +1810,13 @@ const Submissions = () => {
1800
1810
  /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: key }),
1801
1811
  /* @__PURE__ */ jsx(Typography, { tag: "p", children: String(value) })
1802
1812
  ] }, key)),
1803
- selected.meta?.pagePath && /* @__PURE__ */ jsxs(Box, { children: [
1813
+ typeof selected.meta?.pagePath === "string" && selected.meta.pagePath && /* @__PURE__ */ jsxs(Box, { children: [
1804
1814
  /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: t("submissions.meta-page", "Submitted from") }),
1805
1815
  /* @__PURE__ */ jsx(Typography, { tag: "p", children: selected.meta.pagePath })
1816
+ ] }),
1817
+ typeof selected.meta?.hubspotError === "string" && selected.meta.hubspotError && /* @__PURE__ */ jsxs(Box, { children: [
1818
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "danger600", tag: "p", children: t("submissions.conversion-error", "Conversion failed") }),
1819
+ /* @__PURE__ */ jsx(Typography, { tag: "p", children: selected.meta.hubspotError })
1806
1820
  ] })
1807
1821
  ] }) })
1808
1822
  ] }) })
@@ -7,12 +7,12 @@ 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-R3ReZXF1.js");
10
+ const index$1 = require("./index-CG_WQzSa.js");
11
11
  const core = require("@dnd-kit/core");
12
12
  const sortable = require("@dnd-kit/sortable");
13
13
  const utilities = require("@dnd-kit/utilities");
14
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
15
- const useHubspotSchema = require("./useHubspotSchema-BRzzvs9t.js");
14
+ const objectLabels = require("./objectLabels-BGq-Ypgn.js");
15
+ const useHubspotSchema = require("./useHubspotSchema-BZP2qkAu.js");
16
16
  function _interopNamespace(e) {
17
17
  if (e && e.__esModule) return e;
18
18
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -725,6 +725,7 @@ const FormEditor = () => {
725
725
  const locale = searchParams.get("locale") ?? void 0;
726
726
  const [entry, setEntry] = React__namespace.useState(null);
727
727
  const [published, setPublished] = React__namespace.useState(false);
728
+ const [publishedHubspotFormId, setPublishedHubspotFormId] = React__namespace.useState(null);
728
729
  const [locales, setLocales] = React__namespace.useState([]);
729
730
  const [selection, setSelection] = React__namespace.useState({ kind: "form" });
730
731
  const [dirty, setDirty] = React__namespace.useState(false);
@@ -761,6 +762,7 @@ const FormEditor = () => {
761
762
  if (cancelled) return;
762
763
  setEntry(data.form);
763
764
  setPublished(data.published);
765
+ setPublishedHubspotFormId(data.publishedHubspotFormId ?? null);
764
766
  setDirty(false);
765
767
  }).catch(async () => {
766
768
  if (cancelled || !locale) return;
@@ -871,6 +873,7 @@ const FormEditor = () => {
871
873
  try {
872
874
  const { data } = await post(`/${index$1.PLUGIN_ID}/builder/forms/${documentId}/publish${query}`);
873
875
  setPublished(true);
876
+ setPublishedHubspotFormId(entry.hubspotFormId ?? null);
874
877
  setErrors([]);
875
878
  setProblems([]);
876
879
  const added = Array.isArray(data?.addedFields) ? data.addedFields.length : 0;
@@ -1359,7 +1362,10 @@ const FormEditor = () => {
1359
1362
  ),
1360
1363
  onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
1361
1364
  children: [
1362
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: t("editor.hubspot-form-none", "None — CRM upsert only") }),
1365
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: t(
1366
+ "editor.hubspot-form-none",
1367
+ "Default marketing form (Settings) — contact only if none is set"
1368
+ ) }),
1363
1369
  entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
1364
1370
  hsForms.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: f.id, children: f.name }, f.id))
1365
1371
  ]
@@ -1375,6 +1381,10 @@ const FormEditor = () => {
1375
1381
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
1376
1382
  "editor.hubspot-form-hint",
1377
1383
  "Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay."
1384
+ ) }),
1385
+ published && (entry.hubspotFormId || "") !== (publishedHubspotFormId || "") && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: t(
1386
+ "editor.hubspot-form-unpublished",
1387
+ "The live site still uses the previously published HubSpot form. Publish to apply this link."
1378
1388
  ) })
1379
1389
  ] }),
1380
1390
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
@@ -1784,7 +1794,7 @@ const Submissions = () => {
1784
1794
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.formTitle || row.form }) }),
1785
1795
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", children: row.email || "—" }) }),
1786
1796
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", ellipsis: true, children: preview(row.values) }) }),
1787
- /* @__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") }) })
1797
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: row.meta?.hubspotConversion === true || row.meta?.hubspotConversion === "true" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success700", children: t("submissions.converted", "Conversion") }) : row.hubspotSynced ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.contact-only", "Contact only") }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.not-synced", "Not synced") }) })
1788
1798
  ]
1789
1799
  },
1790
1800
  row.documentId
@@ -1820,9 +1830,13 @@ const Submissions = () => {
1820
1830
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: key }),
1821
1831
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: String(value) })
1822
1832
  ] }, key)),
1823
- selected.meta?.pagePath && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1833
+ typeof selected.meta?.pagePath === "string" && selected.meta.pagePath && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1824
1834
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: t("submissions.meta-page", "Submitted from") }),
1825
1835
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: selected.meta.pagePath })
1836
+ ] }),
1837
+ typeof selected.meta?.hubspotError === "string" && selected.meta.hubspotError && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
1838
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "danger600", tag: "p", children: t("submissions.conversion-error", "Conversion failed") }),
1839
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: selected.meta.hubspotError })
1826
1840
  ] })
1827
1841
  ] }) })
1828
1842
  ] }) })
@@ -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-R3ReZXF1.js");
8
+ const index$1 = require("./index-CG_WQzSa.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" } });
@@ -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-CLAy5dVN.mjs";
6
+ import { P as PLUGIN_ID, g as getTranslation } from "./index-BeBn7bJa.mjs";
7
7
  const HubspotFormInput = React.forwardRef(
8
8
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
9
9
  const { formatMessage } = 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-R3ReZXF1.js");
8
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
9
- const useHubspotSchema = require("./useHubspotSchema-BRzzvs9t.js");
7
+ const index$1 = require("./index-CG_WQzSa.js");
8
+ const objectLabels = require("./objectLabels-BGq-Ypgn.js");
9
+ const useHubspotSchema = require("./useHubspotSchema-BZP2qkAu.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" } });
@@ -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-CLAy5dVN.mjs";
6
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
7
- import { u as useHubspotSchema } from "./useHubspotSchema-Bz2o1BU-.mjs";
5
+ import { g as getTranslation } from "./index-BeBn7bJa.mjs";
6
+ import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
7
+ import { u as useHubspotSchema } from "./useHubspotSchema-CP7LRdzO.mjs";
8
8
  const HubspotObjectInput = React.forwardRef(
9
9
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
10
10
  const intl = useIntl();
@@ -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-R3ReZXF1.js");
10
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
11
- const useHubspotSchema = require("./useHubspotSchema-BRzzvs9t.js");
9
+ const index$1 = require("./index-CG_WQzSa.js");
10
+ const objectLabels = require("./objectLabels-BGq-Ypgn.js");
11
+ const useHubspotSchema = require("./useHubspotSchema-BZP2qkAu.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-CLAy5dVN.mjs";
8
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
9
- import { u as useHubspotSchema } from "./useHubspotSchema-Bz2o1BU-.mjs";
7
+ import { g as getTranslation } from "./index-BeBn7bJa.mjs";
8
+ import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
9
+ import { u as useHubspotSchema } from "./useHubspotSchema-CP7LRdzO.mjs";
10
10
  const oneLine = {
11
11
  display: "block",
12
12
  whiteSpace: "nowrap",
@@ -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-R3ReZXF1.js");
8
+ const index$1 = require("./index-CG_WQzSa.js");
9
9
  const reactRouterDom = require("react-router-dom");
10
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
10
+ const objectLabels = require("./objectLabels-BGq-Ypgn.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,6 +204,7 @@ const HubspotSettings = () => {
204
204
  const [submissionMode, setSubmissionMode] = React__namespace.useState("auto");
205
205
  const [writeExtraProperties, setWriteExtraProperties] = React__namespace.useState(true);
206
206
  const [syncFieldsOnPublish, setSyncFieldsOnPublish] = React__namespace.useState(false);
207
+ const [timelineNote, setTimelineNote] = React__namespace.useState(true);
207
208
  const [forms, setForms] = React__namespace.useState([]);
208
209
  const [busy, setBusy] = React__namespace.useState(false);
209
210
  const [feedback, setFeedback] = React__namespace.useState(
@@ -218,6 +219,7 @@ const HubspotSettings = () => {
218
219
  setSubmissionMode(data.submissionMode === "crm" || data.submissionMode === "forms" ? data.submissionMode : "auto");
219
220
  setWriteExtraProperties(data.writeExtraProperties !== false);
220
221
  setSyncFieldsOnPublish(data.syncFieldsOnPublish === true);
222
+ setTimelineNote(data.timelineNote !== false);
221
223
  setForms(Array.isArray(data.forms) ? data.forms : []);
222
224
  };
223
225
  const load = React__namespace.useCallback(async () => {
@@ -240,7 +242,8 @@ const HubspotSettings = () => {
240
242
  defaultFormId,
241
243
  submissionMode,
242
244
  writeExtraProperties,
243
- syncFieldsOnPublish
245
+ syncFieldsOnPublish,
246
+ timelineNote
244
247
  });
245
248
  setApiKey("");
246
249
  await load();
@@ -474,6 +477,21 @@ const HubspotSettings = () => {
474
477
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
475
478
  "settings.sync.hint",
476
479
  "Strapi-first installs: a field added here appears on the HubSpot form next publish. HubSpot-first installs should leave this off — importing a form already carries its fields. Properties themselves are never created; map to ones that exist in the portal."
480
+ ) }),
481
+ /* @__PURE__ */ jsxRuntime.jsx(
482
+ designSystem.Checkbox,
483
+ {
484
+ checked: timelineNote,
485
+ onCheckedChange: (checked) => setTimelineNote(checked === true),
486
+ children: t(
487
+ "settings.note.label",
488
+ "Also write a recap note on the contact (page, subject, answers)"
489
+ )
490
+ }
491
+ ),
492
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
493
+ "settings.note.hint",
494
+ "The conversion already carries the page URL (pageUri). The note puts that page plus the originating subject on the contact timeline, next to the native form submission."
477
495
  ) })
478
496
  ] }) }),
479
497
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
@@ -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, SingleSelect, SingleSelectOption, Checkbox } from "@strapi/design-system";
5
5
  import { useFetchClient } from "@strapi/strapi/admin";
6
- import { g as getTranslation, P as PLUGIN_ID } from "./index-CLAy5dVN.mjs";
6
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-BeBn7bJa.mjs";
7
7
  import { Link as Link$1 } from "react-router-dom";
8
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
8
+ import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
9
9
  const AuditSection = ({ configured }) => {
10
10
  const intl = useIntl();
11
11
  const { formatMessage } = intl;
@@ -184,6 +184,7 @@ const HubspotSettings = () => {
184
184
  const [submissionMode, setSubmissionMode] = React.useState("auto");
185
185
  const [writeExtraProperties, setWriteExtraProperties] = React.useState(true);
186
186
  const [syncFieldsOnPublish, setSyncFieldsOnPublish] = React.useState(false);
187
+ const [timelineNote, setTimelineNote] = React.useState(true);
187
188
  const [forms, setForms] = React.useState([]);
188
189
  const [busy, setBusy] = React.useState(false);
189
190
  const [feedback, setFeedback] = React.useState(
@@ -198,6 +199,7 @@ const HubspotSettings = () => {
198
199
  setSubmissionMode(data.submissionMode === "crm" || data.submissionMode === "forms" ? data.submissionMode : "auto");
199
200
  setWriteExtraProperties(data.writeExtraProperties !== false);
200
201
  setSyncFieldsOnPublish(data.syncFieldsOnPublish === true);
202
+ setTimelineNote(data.timelineNote !== false);
201
203
  setForms(Array.isArray(data.forms) ? data.forms : []);
202
204
  };
203
205
  const load = React.useCallback(async () => {
@@ -220,7 +222,8 @@ const HubspotSettings = () => {
220
222
  defaultFormId,
221
223
  submissionMode,
222
224
  writeExtraProperties,
223
- syncFieldsOnPublish
225
+ syncFieldsOnPublish,
226
+ timelineNote
224
227
  });
225
228
  setApiKey("");
226
229
  await load();
@@ -454,6 +457,21 @@ const HubspotSettings = () => {
454
457
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
455
458
  "settings.sync.hint",
456
459
  "Strapi-first installs: a field added here appears on the HubSpot form next publish. HubSpot-first installs should leave this off — importing a form already carries its fields. Properties themselves are never created; map to ones that exist in the portal."
460
+ ) }),
461
+ /* @__PURE__ */ jsx(
462
+ Checkbox,
463
+ {
464
+ checked: timelineNote,
465
+ onCheckedChange: (checked) => setTimelineNote(checked === true),
466
+ children: t(
467
+ "settings.note.label",
468
+ "Also write a recap note on the contact (page, subject, answers)"
469
+ )
470
+ }
471
+ ),
472
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
473
+ "settings.note.hint",
474
+ "The conversion already carries the page URL (pageUri). The note puts that page plus the originating subject on the contact timeline, next to the native form submission."
457
475
  ) })
458
476
  ] }) }),
459
477
  /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
@@ -163,8 +163,9 @@ const en = {
163
163
  "editor.form-success": "Success message",
164
164
  "editor.hubspot-form": "HubSpot marketing form",
165
165
  "editor.hubspot-form-placeholder": "Pick a form of the connected portal",
166
- "editor.hubspot-form-none": "None — CRM upsert only",
166
+ "editor.hubspot-form-none": "Default marketing form (Settings) — contact only if none is set",
167
167
  "editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay.",
168
+ "editor.hubspot-form-unpublished": "The live site still uses the previously published HubSpot form. Publish to apply this link.",
168
169
  "editor.resync": "Resync from HubSpot",
169
170
  "editor.resynced": "Resynced from HubSpot — {updated, plural, one {# field updated} other {# fields updated}}, {added, plural, one {# added} other {# added}}.",
170
171
  "editor.resynced-gaps": "Resynced from HubSpot — {updated, plural, one {# updated} other {# updated}}, {added, plural, one {# added} other {# added}}, {skipped, plural, one {# skipped} other {# skipped}}.",
@@ -269,6 +270,9 @@ const en = {
269
270
  "submissions.col-answers": "Answers",
270
271
  "submissions.col-crm": "CRM",
271
272
  "submissions.synced": "Synced",
273
+ "submissions.converted": "Conversion",
274
+ "submissions.contact-only": "Contact only",
275
+ "submissions.conversion-error": "Conversion failed",
272
276
  "submissions.not-synced": "Not synced",
273
277
  "submissions.count": "{total, plural, one {# submission} other {# submissions}}",
274
278
  "submissions.prev": "Previous",
@@ -165,8 +165,9 @@ const en = {
165
165
  "editor.form-success": "Success message",
166
166
  "editor.hubspot-form": "HubSpot marketing form",
167
167
  "editor.hubspot-form-placeholder": "Pick a form of the connected portal",
168
- "editor.hubspot-form-none": "None — CRM upsert only",
168
+ "editor.hubspot-form-none": "Default marketing form (Settings) — contact only if none is set",
169
169
  "editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay.",
170
+ "editor.hubspot-form-unpublished": "The live site still uses the previously published HubSpot form. Publish to apply this link.",
170
171
  "editor.resync": "Resync from HubSpot",
171
172
  "editor.resynced": "Resynced from HubSpot — {updated, plural, one {# field updated} other {# fields updated}}, {added, plural, one {# added} other {# added}}.",
172
173
  "editor.resynced-gaps": "Resynced from HubSpot — {updated, plural, one {# updated} other {# updated}}, {added, plural, one {# added} other {# added}}, {skipped, plural, one {# skipped} other {# skipped}}.",
@@ -271,6 +272,9 @@ const en = {
271
272
  "submissions.col-answers": "Answers",
272
273
  "submissions.col-crm": "CRM",
273
274
  "submissions.synced": "Synced",
275
+ "submissions.converted": "Conversion",
276
+ "submissions.contact-only": "Contact only",
277
+ "submissions.conversion-error": "Conversion failed",
274
278
  "submissions.not-synced": "Not synced",
275
279
  "submissions.count": "{total, plural, one {# submission} other {# submissions}}",
276
280
  "submissions.prev": "Previous",
@@ -163,8 +163,9 @@ const fr = {
163
163
  "editor.form-success": "Message de succès",
164
164
  "editor.hubspot-form": "Formulaire marketing HubSpot",
165
165
  "editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
166
- "editor.hubspot-form-none": "Aucun — upsert CRM uniquement",
166
+ "editor.hubspot-form-none": "Formulaire marketing par défaut (Réglages) — contact seul si aucun n'est défini",
167
167
  "editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Après une modification dans HubSpot, utilisez Resynchroniser — les champs mappés se mettent à jour sur place, les nouveaux s’ajoutent, vos étapes restent.",
168
+ "editor.hubspot-form-unpublished": "Le site live utilise encore le formulaire HubSpot précédemment publié. Publiez pour appliquer ce lien.",
168
169
  "editor.resync": "Resynchroniser depuis HubSpot",
169
170
  "editor.resynced": "Resynchronisé depuis HubSpot — {updated, plural, one {# champ mis à jour} other {# champs mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}.",
170
171
  "editor.resynced-gaps": "Resynchronisé depuis HubSpot — {updated, plural, one {# mis à jour} other {# mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}, {skipped, plural, one {# écarté} other {# écartés}}.",
@@ -269,6 +270,9 @@ const fr = {
269
270
  "submissions.col-answers": "Réponses",
270
271
  "submissions.col-crm": "CRM",
271
272
  "submissions.synced": "Synchronisée",
273
+ "submissions.converted": "Conversion",
274
+ "submissions.contact-only": "Contact seul",
275
+ "submissions.conversion-error": "Conversion échouée",
272
276
  "submissions.not-synced": "Non synchronisée",
273
277
  "submissions.count": "{total, plural, one {# soumission} other {# soumissions}}",
274
278
  "submissions.prev": "Précédent",
@@ -165,8 +165,9 @@ const fr = {
165
165
  "editor.form-success": "Message de succès",
166
166
  "editor.hubspot-form": "Formulaire marketing HubSpot",
167
167
  "editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
168
- "editor.hubspot-form-none": "Aucun — upsert CRM uniquement",
168
+ "editor.hubspot-form-none": "Formulaire marketing par défaut (Réglages) — contact seul si aucun n'est défini",
169
169
  "editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Après une modification dans HubSpot, utilisez Resynchroniser — les champs mappés se mettent à jour sur place, les nouveaux s’ajoutent, vos étapes restent.",
170
+ "editor.hubspot-form-unpublished": "Le site live utilise encore le formulaire HubSpot précédemment publié. Publiez pour appliquer ce lien.",
170
171
  "editor.resync": "Resynchroniser depuis HubSpot",
171
172
  "editor.resynced": "Resynchronisé depuis HubSpot — {updated, plural, one {# champ mis à jour} other {# champs mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}.",
172
173
  "editor.resynced-gaps": "Resynchronisé depuis HubSpot — {updated, plural, one {# mis à jour} other {# mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}, {skipped, plural, one {# écarté} other {# écartés}}.",
@@ -271,6 +272,9 @@ const fr = {
271
272
  "submissions.col-answers": "Réponses",
272
273
  "submissions.col-crm": "CRM",
273
274
  "submissions.synced": "Synchronisée",
275
+ "submissions.converted": "Conversion",
276
+ "submissions.contact-only": "Contact seul",
277
+ "submissions.conversion-error": "Conversion échouée",
274
278
  "submissions.not-synced": "Non synchronisée",
275
279
  "submissions.count": "{total, plural, one {# soumission} other {# soumissions}}",
276
280
  "submissions.prev": "Précédent",
@@ -25,7 +25,7 @@ const index = {
25
25
  icon: PaperPlane,
26
26
  intlLabel: { id: `${PLUGIN_ID}.menu.label`, defaultMessage: "HubSpot Forms" },
27
27
  permissions: [{ action: `plugin::${PLUGIN_ID}.forms`, subject: null }],
28
- Component: async () => (await import("./Forms-BOQWely0.mjs")).default
28
+ Component: async () => (await import("./Forms-DyV6KyiO.mjs")).default
29
29
  });
30
30
  app.customFields.register({
31
31
  name: "property",
@@ -40,7 +40,7 @@ const index = {
40
40
  defaultMessage: "Picked from the portal's real properties"
41
41
  },
42
42
  components: {
43
- Input: async () => import("./HubspotPropertyInput-BHfpBD36.mjs")
43
+ Input: async () => import("./HubspotPropertyInput-WU5FMJj3.mjs")
44
44
  },
45
45
  // Exposed in the Content-Type Builder. Without this, `objectField` could
46
46
  // only be set by hand-editing schema.json — which is not how anyone
@@ -103,7 +103,7 @@ const index = {
103
103
  defaultMessage: "Picked from the portal's configured objects"
104
104
  },
105
105
  components: {
106
- Input: async () => import("./HubspotObjectInput-BbnvhdbD.mjs")
106
+ Input: async () => import("./HubspotObjectInput-DL8fYK2x.mjs")
107
107
  }
108
108
  });
109
109
  app.customFields.register({
@@ -119,7 +119,7 @@ const index = {
119
119
  defaultMessage: "A form built in the HubSpot form builder, stored by slug"
120
120
  },
121
121
  components: {
122
- Input: async () => import("./HubspotFormInput-DCkoavrN.mjs")
122
+ Input: async () => import("./HubspotFormInput-DEXPX-6j.mjs")
123
123
  }
124
124
  });
125
125
  app.createSettingSection(
@@ -135,7 +135,7 @@ const index = {
135
135
  // Mirrors the RBAC action registered server-side: a role without it
136
136
  // doesn't see the link at all — the routes refuse it anyway.
137
137
  permissions: [{ action: `plugin::${PLUGIN_ID}.settings`, subject: null }],
138
- Component: async () => (await import("./Settings-DqRpHtnT.mjs")).default
138
+ Component: async () => (await import("./Settings-CiXEps_C.mjs")).default
139
139
  }
140
140
  ]
141
141
  );
@@ -145,7 +145,7 @@ const index = {
145
145
  return Promise.all(
146
146
  locales.map(async (locale) => {
147
147
  try {
148
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-Djd3TID0.mjs"), "./translations/fr.json": () => import("./fr-C7t1elmR.mjs") }), `./translations/${locale}.json`, 3);
148
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-BIUBYzHv.mjs"), "./translations/fr.json": () => import("./fr-CMYcnFH0.mjs") }), `./translations/${locale}.json`, 3);
149
149
  return { data: prefixPluginTranslations(data), locale };
150
150
  } catch {
151
151
  return { data: {}, locale };