strapi-plugin-hubspot 0.13.0 → 0.14.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.
- package/CHANGELOG.md +36 -0
- package/README.md +59 -15
- package/dist/_chunks/{Forms-lrzuWzoB.js → Forms-Cch-7zei.js} +38 -3
- package/dist/_chunks/{Forms-CHB-sKem.mjs → Forms-ws6d8rdC.mjs} +38 -3
- package/dist/_chunks/{HubspotFormInput-YI09keTC.mjs → HubspotFormInput-18pWTITT.mjs} +1 -1
- package/dist/_chunks/{HubspotFormInput-Bb6it0nP.js → HubspotFormInput-M2l_8w_e.js} +1 -1
- package/dist/_chunks/{HubspotObjectInput-D3A6xzb3.js → HubspotObjectInput-BDO99qXs.js} +3 -3
- package/dist/_chunks/{HubspotObjectInput-CzLKT9oj.mjs → HubspotObjectInput-DshusXZP.mjs} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-DicskLcN.mjs → HubspotPropertyInput-C-kHDgwx.mjs} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-Dss3eUlL.js → HubspotPropertyInput-XGnH2tHn.js} +3 -3
- package/dist/_chunks/{Settings-4CbX3SPK.mjs → Settings-Bm7WkzK1.mjs} +2 -2
- package/dist/_chunks/{Settings-Ch8tPZAV.js → Settings-CRnsu6ob.js} +2 -2
- package/dist/_chunks/{en-PYFibnDc.js → en-BXMU5CjT.js} +4 -0
- package/dist/_chunks/{en-D8DJiSxd.mjs → en-DKV-8FWP.mjs} +4 -0
- package/dist/_chunks/{fr-yHk4sSEl.js → fr-Dx4XmZ4X.js} +4 -0
- package/dist/_chunks/{fr-BMjixfXn.mjs → fr-GB6T3ZyU.mjs} +4 -0
- package/dist/_chunks/{index-BAvedd2m.js → index-BlaG8oIq.js} +6 -6
- package/dist/_chunks/{index-BE2ribUL.mjs → index-CPVfElYB.mjs} +6 -6
- package/dist/_chunks/{objectLabels-DGJxYjKz.mjs → objectLabels-6OUnIDB5.mjs} +1 -1
- package/dist/_chunks/{objectLabels-CycoU0zY.js → objectLabels-CPc21Tdd.js} +1 -1
- package/dist/_chunks/{useHubspotSchema-DRfaI6mF.js → useHubspotSchema-0MvCM1AC.js} +1 -1
- package/dist/_chunks/{useHubspotSchema-e31UsYb2.mjs → useHubspotSchema-qCUs2gIX.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/builder/types.d.ts +2 -0
- package/dist/server/index.js +425 -189
- package/dist/server/index.mjs +425 -189
- package/dist/server/src/__tests__/hsforms.test.d.ts +1 -0
- package/dist/server/src/content-types.d.ts +8 -0
- package/dist/server/src/forms.d.ts +10 -6
- package/dist/server/src/hsforms.d.ts +75 -0
- package/dist/server/src/importHubspot.d.ts +1 -0
- package/dist/server/src/index.d.ts +12 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.14.0 — 2026-09-21
|
|
6
|
+
|
|
7
|
+
### Changed — native HubSpot form conversions
|
|
8
|
+
- Submissions of a built form now post to HubSpot's **Forms API**
|
|
9
|
+
(`/submissions/v3/integration/secure/submit/{portalId}/{formGuid}`) when a
|
|
10
|
+
marketing form GUID is set. That is what HubSpot counts as a conversion:
|
|
11
|
+
Original Source, workflows, lead-center notifications, reporting.
|
|
12
|
+
- The GUID is configuration, not code: pick it in the builder (or set
|
|
13
|
+
`forms.defaultFormId`), and swap `portalId` / `region` when moving from a
|
|
14
|
+
test portal to production.
|
|
15
|
+
- The visitor's `hubspotutk` (`meta.hutk`) is forwarded as `context.hutk` so
|
|
16
|
+
attribution sticks to the session.
|
|
17
|
+
- Extra fields not declared on the HubSpot form are dropped (they 400 the
|
|
18
|
+
whole submit). GDPR `legalConsentOptions` is sent when the HubSpot form
|
|
19
|
+
has a consent block.
|
|
20
|
+
- **CRM contact upsert is the fallback** when no GUID is configured. Timeline
|
|
21
|
+
notes remain available (`forms.timelineNote`, default `true`) on that
|
|
22
|
+
fallback only — they are not form conversions.
|
|
23
|
+
- Company find-or-create (SIRET / domain) still runs after a successful
|
|
24
|
+
submit, once the contact is looked up by email.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- Form attribute `hubspotFormId` and a picker in the builder.
|
|
28
|
+
- Plugin config `portalId`, `region` (`eu1` by default), `forms.defaultFormId`.
|
|
29
|
+
|
|
30
|
+
## 0.13.1 — 2026-09-21
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- **GDPR proof on submissions.** `meta.consent` / `meta.consentedAt` sent by
|
|
34
|
+
the frontend are stored on the submission row and written on the HubSpot
|
|
35
|
+
timeline note. They are not CRM properties — an unknown HubSpot key would
|
|
36
|
+
fail the whole upsert. Rebuild HubSpot's native legal-consent block as a
|
|
37
|
+
required checkbox named `consent` (see README).
|
|
38
|
+
|
|
3
39
|
## 0.13.0 — 2026-08-31
|
|
4
40
|
|
|
5
41
|
### Added
|
package/README.md
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
Build multi-step lead forms in a dedicated admin page: fields mapped to your
|
|
6
6
|
portal's *real* CRM properties through a searchable picker, conditional fields
|
|
7
7
|
and steps (AND/OR rules re-evaluated server-side), a public API your frontend
|
|
8
|
-
renders and posts to, and a submission pipeline that
|
|
9
|
-
finds-or-creates the Company
|
|
10
|
-
|
|
8
|
+
renders and posts to, and a submission pipeline that posts a **native HubSpot
|
|
9
|
+
form conversion** (Forms API + visitor `hutk`), finds-or-creates the Company
|
|
10
|
+
by corporate domain, and stores every submission in Strapi whatever the CRM's
|
|
11
|
+
mood.
|
|
11
12
|
|
|
12
13
|
Under it, the safety net this plugin has always been: property pickers as
|
|
13
14
|
custom fields for your own content types, save-time mapping validation, a
|
|
@@ -43,20 +44,28 @@ Permissions**):
|
|
|
43
44
|
| `GET` | `/api/hubspot/forms/:slug?locale=` | The published form — meta, steps, fields, conditions. The CRM mapping is stripped: the browser never learns your property names |
|
|
44
45
|
| `POST` | `/api/hubspot/forms/:slug/submit` | Validates (bounds, conditions, required), maps server-side, syncs HubSpot, stores the submission |
|
|
45
46
|
|
|
46
|
-
The submit pipeline, in order:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
The submit pipeline, in order: HubSpot **Forms API** (native conversion —
|
|
48
|
+
Original Source, workflows, lead-center notifications) when a marketing form
|
|
49
|
+
GUID is set on the builder form or via `forms.defaultFormId`; the visitor's
|
|
50
|
+
`hutk` is forwarded so attribution sticks. Then the contact is looked up by
|
|
51
|
+
email and, when the address is on a corporate domain, the company is
|
|
52
|
+
found-or-created and associated. A CRM contact upsert is the **fallback**
|
|
53
|
+
when no GUID is configured — it does not count as a form conversion.
|
|
54
|
+
Timeline notes are opt-in and only used on that fallback.
|
|
55
|
+
|
|
56
|
+
Portal id, region and form GUIDs are configuration. A test portal today,
|
|
57
|
+
production tomorrow: swap `portalId` / `region` / the GUID, no code change.
|
|
53
58
|
|
|
54
59
|
```ts
|
|
55
60
|
hubspot: {
|
|
56
61
|
config: {
|
|
62
|
+
apiKey: env("HUBSPOT_API_KEY"),
|
|
63
|
+
portalId: env("HUBSPOT_PORTAL_ID"), // test now, production later
|
|
64
|
+
region: env("HUBSPOT_REGION", "eu1"), // eu1 → api-eu1.hsforms.com
|
|
57
65
|
forms: {
|
|
58
66
|
companyFromDomain: true, // Company by corporate domain + association
|
|
59
|
-
timelineNote:
|
|
67
|
+
timelineNote: false, // recap note on the CRM-upsert fallback only
|
|
68
|
+
defaultFormId: env("HUBSPOT_DEFAULT_FORM_ID", ""),
|
|
60
69
|
},
|
|
61
70
|
},
|
|
62
71
|
}
|
|
@@ -66,6 +75,35 @@ Every submission is stored in **HubSpot form submissions** (Content Manager),
|
|
|
66
75
|
synced or not, with the CRM ids when the sync succeeded — the source of truth
|
|
67
76
|
lives in your database, not in HubSpot's availability.
|
|
68
77
|
|
|
78
|
+
### GDPR consent
|
|
79
|
+
|
|
80
|
+
HubSpot's native *legal consent* block is **not** a CRM field. Importing a
|
|
81
|
+
HubSpot form skips it (you'll see "rebuild it as a field"). The Forms API
|
|
82
|
+
submit sends `legalConsentOptions` when the HubSpot marketing form has a
|
|
83
|
+
GDPR block and the visitor ticked consent.
|
|
84
|
+
|
|
85
|
+
To connect consent so the CRM and Strapi both keep a proof:
|
|
86
|
+
|
|
87
|
+
1. **In HubSpot** (Settings → Properties → Contact), create a checkbox
|
|
88
|
+
property, e.g. `rgpd_consent`. Optionally a datetime `rgpd_consented_at`.
|
|
89
|
+
2. **In the form builder** (Admin → HubSpot Forms), last step: add a
|
|
90
|
+
**Checkbox**, name it `consent` (that name is what the site recognizes —
|
|
91
|
+
it will not inject a second box), mark it **required**.
|
|
92
|
+
3. **Map it**: Object = Contact, property = `rgpd_consent`. The visitor's tick
|
|
93
|
+
then lands on the contact (if that property is on the HubSpot form) and in
|
|
94
|
+
`legalConsentOptions`. Leave `consentedAt` unmapped; the frontend sends it
|
|
95
|
+
in `meta.consentedAt`, stored on the submission.
|
|
96
|
+
4. **Point the builder form at a HubSpot marketing form** (right-hand panel)
|
|
97
|
+
so the tick is a native conversion, not a CRM note.
|
|
98
|
+
5. **Publish** the form. The public submit pipeline already refuses a payload
|
|
99
|
+
without consent when the site is in front (Nuxt BFF). Direct calls to
|
|
100
|
+
`/api/hubspot/forms/:slug/submit` still accept a form that has no consent
|
|
101
|
+
field — add the checkbox so required-field validation covers them too.
|
|
102
|
+
|
|
103
|
+
The frontend should also send `meta.hutk` (the `hubspotutk` cookie set by
|
|
104
|
+
HubSpot's tracking script) and `meta.pageUrl` so Original Source is Organic
|
|
105
|
+
Search / Direct / etc. rather than *Offline sources*.
|
|
106
|
+
|
|
69
107
|
### Browsing submissions
|
|
70
108
|
|
|
71
109
|
The **Submissions** button on the forms list (also reachable from a form's
|
|
@@ -375,6 +413,8 @@ export default ({ env }) => ({
|
|
|
375
413
|
config: {
|
|
376
414
|
// Optional — the key can also be set from Settings → HubSpot.
|
|
377
415
|
apiKey: env("HUBSPOT_API_KEY", ""),
|
|
416
|
+
portalId: env("HUBSPOT_PORTAL_ID", ""),
|
|
417
|
+
region: env("HUBSPOT_REGION", "eu1"),
|
|
378
418
|
|
|
379
419
|
// Optional — objects whose properties are offered.
|
|
380
420
|
// Defaults to ["contact", "company"]. Standard names: contact, company,
|
|
@@ -421,6 +461,10 @@ Create a **private app** in HubSpot with a read scope per object you list:
|
|
|
421
461
|
- `crm.schemas.contacts.read`
|
|
422
462
|
- `crm.schemas.companies.read`
|
|
423
463
|
- `crm.schemas.deals.read`, `crm.schemas.custom.read`… as needed
|
|
464
|
+
- `crm.objects.contacts.read` / `write`, `crm.objects.companies.read` / `write`
|
|
465
|
+
- `forms` — list portal forms (import + builder picker) and **submit** them
|
|
466
|
+
via the Forms API (native conversions). Without this scope the pipeline
|
|
467
|
+
falls back to a CRM upsert, which HubSpot treats as an offline source.
|
|
424
468
|
|
|
425
469
|
An object the token can't read is **skipped, not fatal**: the picker keeps
|
|
426
470
|
working for the others and explains which one is missing a scope. `oauth` is
|
|
@@ -430,10 +474,10 @@ turn on the *view in HubSpot* links.
|
|
|
430
474
|
### Regions
|
|
431
475
|
|
|
432
476
|
The REST API is global: `api.hubapi.com` routes by token, whatever the portal's
|
|
433
|
-
hosting region. The **web app
|
|
434
|
-
`app-eu1.hubspot.com
|
|
435
|
-
|
|
436
|
-
|
|
477
|
+
hosting region. The **web app and the Forms API are not** — an EU-hosted portal
|
|
478
|
+
lives on `app-eu1.hubspot.com` and submits to `api-eu1.hsforms.com`. Set
|
|
479
|
+
`config.region` (`eu1`, `na1`, …) to match. Deep links are built from the
|
|
480
|
+
`uiDomain` HubSpot reports for your portal rather than a hardcoded host.
|
|
437
481
|
|
|
438
482
|
The key is resolved in this order, first match wins:
|
|
439
483
|
|
|
@@ -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-
|
|
10
|
+
const index$1 = require("./index-BlaG8oIq.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-
|
|
15
|
-
const useHubspotSchema = require("./useHubspotSchema-
|
|
14
|
+
const objectLabels = require("./objectLabels-CPc21Tdd.js");
|
|
15
|
+
const useHubspotSchema = require("./useHubspotSchema-0MvCM1AC.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" } });
|
|
@@ -657,6 +657,7 @@ const FormEditor = () => {
|
|
|
657
657
|
const [errors, setErrors] = React__namespace.useState([]);
|
|
658
658
|
const [problems, setProblems] = React__namespace.useState([]);
|
|
659
659
|
const [feedback, setFeedback] = React__namespace.useState(null);
|
|
660
|
+
const [hsForms, setHsForms] = React__namespace.useState([]);
|
|
660
661
|
const t = (id, defaultMessage, values) => formatMessage({ id: index$1.getTranslation(id), defaultMessage }, values);
|
|
661
662
|
const query = locale ? `?locale=${locale}` : "";
|
|
662
663
|
React__namespace.useEffect(() => {
|
|
@@ -670,6 +671,9 @@ const FormEditor = () => {
|
|
|
670
671
|
React__namespace.useEffect(() => {
|
|
671
672
|
get("/i18n/locales").then(({ data }) => Array.isArray(data) && setLocales(data)).catch(() => setLocales([]));
|
|
672
673
|
}, [get]);
|
|
674
|
+
React__namespace.useEffect(() => {
|
|
675
|
+
get(`/${index$1.PLUGIN_ID}/builder/import/hubspot`).then(({ data }) => setHsForms(Array.isArray(data.forms) ? data.forms : [])).catch(() => setHsForms([]));
|
|
676
|
+
}, [get]);
|
|
673
677
|
React__namespace.useEffect(() => {
|
|
674
678
|
let cancelled = false;
|
|
675
679
|
setEntry(null);
|
|
@@ -764,6 +768,7 @@ const FormEditor = () => {
|
|
|
764
768
|
submitLabel: entry.submitLabel,
|
|
765
769
|
successMessage: entry.successMessage,
|
|
766
770
|
class: entry.class,
|
|
771
|
+
hubspotFormId: entry.hubspotFormId ?? "",
|
|
767
772
|
definition
|
|
768
773
|
}
|
|
769
774
|
);
|
|
@@ -1195,6 +1200,36 @@ const FormEditor = () => {
|
|
|
1195
1200
|
}
|
|
1196
1201
|
)
|
|
1197
1202
|
] }),
|
|
1203
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
|
|
1204
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t("editor.hubspot-form", "HubSpot marketing form") }),
|
|
1205
|
+
hsForms.length ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1206
|
+
designSystem.SingleSelect,
|
|
1207
|
+
{
|
|
1208
|
+
value: entry.hubspotFormId ?? "",
|
|
1209
|
+
placeholder: t(
|
|
1210
|
+
"editor.hubspot-form-placeholder",
|
|
1211
|
+
"Pick a form of the connected portal"
|
|
1212
|
+
),
|
|
1213
|
+
onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
|
|
1214
|
+
children: [
|
|
1215
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: t("editor.hubspot-form-none", "None — CRM upsert only") }),
|
|
1216
|
+
entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
|
|
1217
|
+
hsForms.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: f.id, children: f.name }, f.id))
|
|
1218
|
+
]
|
|
1219
|
+
}
|
|
1220
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1221
|
+
designSystem.TextInput,
|
|
1222
|
+
{
|
|
1223
|
+
value: entry.hubspotFormId ?? "",
|
|
1224
|
+
placeholder: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
|
1225
|
+
onChange: (e) => patchEntry({ hubspotFormId: e.target.value.trim() || null })
|
|
1226
|
+
}
|
|
1227
|
+
),
|
|
1228
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
1229
|
+
"editor.hubspot-form-hint",
|
|
1230
|
+
"Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded."
|
|
1231
|
+
) })
|
|
1232
|
+
] }),
|
|
1198
1233
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
1199
1234
|
"editor.form-hint",
|
|
1200
1235
|
"Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
|
|
@@ -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-
|
|
8
|
+
import { g as getTranslation, P as PLUGIN_ID } from "./index-CPVfElYB.mjs";
|
|
9
9
|
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from "@dnd-kit/core";
|
|
10
10
|
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from "@dnd-kit/sortable";
|
|
11
11
|
import { CSS } from "@dnd-kit/utilities";
|
|
12
|
-
import { o as objectLabel } from "./objectLabels-
|
|
13
|
-
import { u as useHubspotSchema } from "./useHubspotSchema-
|
|
12
|
+
import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
|
|
13
|
+
import { u as useHubspotSchema } from "./useHubspotSchema-qCUs2gIX.mjs";
|
|
14
14
|
const OPERATORS = [
|
|
15
15
|
"eq",
|
|
16
16
|
"neq",
|
|
@@ -637,6 +637,7 @@ const FormEditor = () => {
|
|
|
637
637
|
const [errors, setErrors] = React.useState([]);
|
|
638
638
|
const [problems, setProblems] = React.useState([]);
|
|
639
639
|
const [feedback, setFeedback] = React.useState(null);
|
|
640
|
+
const [hsForms, setHsForms] = React.useState([]);
|
|
640
641
|
const t = (id, defaultMessage, values) => formatMessage({ id: getTranslation(id), defaultMessage }, values);
|
|
641
642
|
const query = locale ? `?locale=${locale}` : "";
|
|
642
643
|
React.useEffect(() => {
|
|
@@ -650,6 +651,9 @@ const FormEditor = () => {
|
|
|
650
651
|
React.useEffect(() => {
|
|
651
652
|
get("/i18n/locales").then(({ data }) => Array.isArray(data) && setLocales(data)).catch(() => setLocales([]));
|
|
652
653
|
}, [get]);
|
|
654
|
+
React.useEffect(() => {
|
|
655
|
+
get(`/${PLUGIN_ID}/builder/import/hubspot`).then(({ data }) => setHsForms(Array.isArray(data.forms) ? data.forms : [])).catch(() => setHsForms([]));
|
|
656
|
+
}, [get]);
|
|
653
657
|
React.useEffect(() => {
|
|
654
658
|
let cancelled = false;
|
|
655
659
|
setEntry(null);
|
|
@@ -744,6 +748,7 @@ const FormEditor = () => {
|
|
|
744
748
|
submitLabel: entry.submitLabel,
|
|
745
749
|
successMessage: entry.successMessage,
|
|
746
750
|
class: entry.class,
|
|
751
|
+
hubspotFormId: entry.hubspotFormId ?? "",
|
|
747
752
|
definition
|
|
748
753
|
}
|
|
749
754
|
);
|
|
@@ -1175,6 +1180,36 @@ const FormEditor = () => {
|
|
|
1175
1180
|
}
|
|
1176
1181
|
)
|
|
1177
1182
|
] }),
|
|
1183
|
+
/* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
1184
|
+
/* @__PURE__ */ jsx(Field.Label, { children: t("editor.hubspot-form", "HubSpot marketing form") }),
|
|
1185
|
+
hsForms.length ? /* @__PURE__ */ jsxs(
|
|
1186
|
+
SingleSelect,
|
|
1187
|
+
{
|
|
1188
|
+
value: entry.hubspotFormId ?? "",
|
|
1189
|
+
placeholder: t(
|
|
1190
|
+
"editor.hubspot-form-placeholder",
|
|
1191
|
+
"Pick a form of the connected portal"
|
|
1192
|
+
),
|
|
1193
|
+
onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
|
|
1194
|
+
children: [
|
|
1195
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: t("editor.hubspot-form-none", "None — CRM upsert only") }),
|
|
1196
|
+
entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsx(SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
|
|
1197
|
+
hsForms.map((f) => /* @__PURE__ */ jsx(SingleSelectOption, { value: f.id, children: f.name }, f.id))
|
|
1198
|
+
]
|
|
1199
|
+
}
|
|
1200
|
+
) : /* @__PURE__ */ jsx(
|
|
1201
|
+
TextInput,
|
|
1202
|
+
{
|
|
1203
|
+
value: entry.hubspotFormId ?? "",
|
|
1204
|
+
placeholder: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
|
1205
|
+
onChange: (e) => patchEntry({ hubspotFormId: e.target.value.trim() || null })
|
|
1206
|
+
}
|
|
1207
|
+
),
|
|
1208
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
1209
|
+
"editor.hubspot-form-hint",
|
|
1210
|
+
"Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded."
|
|
1211
|
+
) })
|
|
1212
|
+
] }),
|
|
1178
1213
|
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
1179
1214
|
"editor.form-hint",
|
|
1180
1215
|
"Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
|
|
@@ -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-
|
|
6
|
+
import { P as PLUGIN_ID, g as getTranslation } from "./index-CPVfElYB.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-
|
|
8
|
+
const index$1 = require("./index-BlaG8oIq.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" } });
|
|
@@ -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-
|
|
8
|
-
const objectLabels = require("./objectLabels-
|
|
9
|
-
const useHubspotSchema = require("./useHubspotSchema-
|
|
7
|
+
const index$1 = require("./index-BlaG8oIq.js");
|
|
8
|
+
const objectLabels = require("./objectLabels-CPc21Tdd.js");
|
|
9
|
+
const useHubspotSchema = require("./useHubspotSchema-0MvCM1AC.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-
|
|
6
|
-
import { o as objectLabel } from "./objectLabels-
|
|
7
|
-
import { u as useHubspotSchema } from "./useHubspotSchema-
|
|
5
|
+
import { g as getTranslation } from "./index-CPVfElYB.mjs";
|
|
6
|
+
import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
|
|
7
|
+
import { u as useHubspotSchema } from "./useHubspotSchema-qCUs2gIX.mjs";
|
|
8
8
|
const HubspotObjectInput = React.forwardRef(
|
|
9
9
|
({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
|
|
10
10
|
const intl = useIntl();
|
package/dist/_chunks/{HubspotPropertyInput-DicskLcN.mjs → HubspotPropertyInput-C-kHDgwx.mjs}
RENAMED
|
@@ -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-
|
|
8
|
-
import { o as objectLabel } from "./objectLabels-
|
|
9
|
-
import { u as useHubspotSchema } from "./useHubspotSchema-
|
|
7
|
+
import { g as getTranslation } from "./index-CPVfElYB.mjs";
|
|
8
|
+
import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
|
|
9
|
+
import { u as useHubspotSchema } from "./useHubspotSchema-qCUs2gIX.mjs";
|
|
10
10
|
const oneLine = {
|
|
11
11
|
display: "block",
|
|
12
12
|
whiteSpace: "nowrap",
|
|
@@ -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-
|
|
10
|
-
const objectLabels = require("./objectLabels-
|
|
11
|
-
const useHubspotSchema = require("./useHubspotSchema-
|
|
9
|
+
const index$1 = require("./index-BlaG8oIq.js");
|
|
10
|
+
const objectLabels = require("./objectLabels-CPc21Tdd.js");
|
|
11
|
+
const useHubspotSchema = require("./useHubspotSchema-0MvCM1AC.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" } });
|
|
@@ -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-
|
|
6
|
+
import { g as getTranslation, P as PLUGIN_ID } from "./index-CPVfElYB.mjs";
|
|
7
7
|
import { Link as Link$1 } from "react-router-dom";
|
|
8
|
-
import { o as objectLabel } from "./objectLabels-
|
|
8
|
+
import { o as objectLabel } from "./objectLabels-6OUnIDB5.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-
|
|
8
|
+
const index$1 = require("./index-BlaG8oIq.js");
|
|
9
9
|
const reactRouterDom = require("react-router-dom");
|
|
10
|
-
const objectLabels = require("./objectLabels-
|
|
10
|
+
const objectLabels = require("./objectLabels-CPc21Tdd.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" } });
|
|
@@ -141,6 +141,10 @@ const en = {
|
|
|
141
141
|
"editor.form-next": "Next label",
|
|
142
142
|
"editor.form-submit": "Submit label",
|
|
143
143
|
"editor.form-success": "Success message",
|
|
144
|
+
"editor.hubspot-form": "HubSpot marketing form",
|
|
145
|
+
"editor.hubspot-form-placeholder": "Pick a form of the connected portal",
|
|
146
|
+
"editor.hubspot-form-none": "None — CRM upsert only",
|
|
147
|
+
"editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded.",
|
|
144
148
|
"editor.form-hint": "Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
|
|
145
149
|
"panel.label": "Label",
|
|
146
150
|
"panel.name": "Payload key",
|
|
@@ -139,6 +139,10 @@ const en = {
|
|
|
139
139
|
"editor.form-next": "Next label",
|
|
140
140
|
"editor.form-submit": "Submit label",
|
|
141
141
|
"editor.form-success": "Success message",
|
|
142
|
+
"editor.hubspot-form": "HubSpot marketing form",
|
|
143
|
+
"editor.hubspot-form-placeholder": "Pick a form of the connected portal",
|
|
144
|
+
"editor.hubspot-form-none": "None — CRM upsert only",
|
|
145
|
+
"editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded.",
|
|
142
146
|
"editor.form-hint": "Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
|
|
143
147
|
"panel.label": "Label",
|
|
144
148
|
"panel.name": "Payload key",
|
|
@@ -141,6 +141,10 @@ const fr = {
|
|
|
141
141
|
"editor.form-next": "Libellé Suivant",
|
|
142
142
|
"editor.form-submit": "Libellé Envoyer",
|
|
143
143
|
"editor.form-success": "Message de succès",
|
|
144
|
+
"editor.hubspot-form": "Formulaire marketing HubSpot",
|
|
145
|
+
"editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
|
|
146
|
+
"editor.hubspot-form-none": "Aucun — upsert CRM uniquement",
|
|
147
|
+
"editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Changez de portail (test → prod) et sélectionnez le formulaire correspondant — rien n’est figé dans le code.",
|
|
144
148
|
"editor.form-hint": "Sélectionnez une étape ou un champ pour l'éditer. Le endpoint public sert ce formulaire sur /api/hubspot/forms/{slug}.",
|
|
145
149
|
"panel.label": "Libellé",
|
|
146
150
|
"panel.name": "Clé du payload",
|
|
@@ -139,6 +139,10 @@ const fr = {
|
|
|
139
139
|
"editor.form-next": "Libellé Suivant",
|
|
140
140
|
"editor.form-submit": "Libellé Envoyer",
|
|
141
141
|
"editor.form-success": "Message de succès",
|
|
142
|
+
"editor.hubspot-form": "Formulaire marketing HubSpot",
|
|
143
|
+
"editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
|
|
144
|
+
"editor.hubspot-form-none": "Aucun — upsert CRM uniquement",
|
|
145
|
+
"editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Changez de portail (test → prod) et sélectionnez le formulaire correspondant — rien n’est figé dans le code.",
|
|
142
146
|
"editor.form-hint": "Sélectionnez une étape ou un champ pour l'éditer. Le endpoint public sert ce formulaire sur /api/hubspot/forms/{slug}.",
|
|
143
147
|
"panel.label": "Libellé",
|
|
144
148
|
"panel.name": "Clé du payload",
|
|
@@ -26,7 +26,7 @@ const index = {
|
|
|
26
26
|
icon: icons.PaperPlane,
|
|
27
27
|
intlLabel: { id: `${PLUGIN_ID}.menu.label`, defaultMessage: "HubSpot Forms" },
|
|
28
28
|
permissions: [{ action: `plugin::${PLUGIN_ID}.forms`, subject: null }],
|
|
29
|
-
Component: async () => (await Promise.resolve().then(() => require("./Forms-
|
|
29
|
+
Component: async () => (await Promise.resolve().then(() => require("./Forms-Cch-7zei.js"))).default
|
|
30
30
|
});
|
|
31
31
|
app.customFields.register({
|
|
32
32
|
name: "property",
|
|
@@ -41,7 +41,7 @@ const index = {
|
|
|
41
41
|
defaultMessage: "Picked from the portal's real properties"
|
|
42
42
|
},
|
|
43
43
|
components: {
|
|
44
|
-
Input: async () => Promise.resolve().then(() => require("./HubspotPropertyInput-
|
|
44
|
+
Input: async () => Promise.resolve().then(() => require("./HubspotPropertyInput-XGnH2tHn.js"))
|
|
45
45
|
},
|
|
46
46
|
// Exposed in the Content-Type Builder. Without this, `objectField` could
|
|
47
47
|
// only be set by hand-editing schema.json — which is not how anyone
|
|
@@ -104,7 +104,7 @@ const index = {
|
|
|
104
104
|
defaultMessage: "Picked from the portal's configured objects"
|
|
105
105
|
},
|
|
106
106
|
components: {
|
|
107
|
-
Input: async () => Promise.resolve().then(() => require("./HubspotObjectInput-
|
|
107
|
+
Input: async () => Promise.resolve().then(() => require("./HubspotObjectInput-BDO99qXs.js"))
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
app.customFields.register({
|
|
@@ -120,7 +120,7 @@ const index = {
|
|
|
120
120
|
defaultMessage: "A form built in the HubSpot form builder, stored by slug"
|
|
121
121
|
},
|
|
122
122
|
components: {
|
|
123
|
-
Input: async () => Promise.resolve().then(() => require("./HubspotFormInput-
|
|
123
|
+
Input: async () => Promise.resolve().then(() => require("./HubspotFormInput-M2l_8w_e.js"))
|
|
124
124
|
}
|
|
125
125
|
});
|
|
126
126
|
app.createSettingSection(
|
|
@@ -136,7 +136,7 @@ const index = {
|
|
|
136
136
|
// Mirrors the RBAC action registered server-side: a role without it
|
|
137
137
|
// doesn't see the link at all — the routes refuse it anyway.
|
|
138
138
|
permissions: [{ action: `plugin::${PLUGIN_ID}.settings`, subject: null }],
|
|
139
|
-
Component: async () => (await Promise.resolve().then(() => require("./Settings-
|
|
139
|
+
Component: async () => (await Promise.resolve().then(() => require("./Settings-CRnsu6ob.js"))).default
|
|
140
140
|
}
|
|
141
141
|
]
|
|
142
142
|
);
|
|
@@ -146,7 +146,7 @@ const index = {
|
|
|
146
146
|
return Promise.all(
|
|
147
147
|
locales.map(async (locale) => {
|
|
148
148
|
try {
|
|
149
|
-
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-
|
|
149
|
+
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-BXMU5CjT.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-Dx4XmZ4X.js")) }), `./translations/${locale}.json`, 3);
|
|
150
150
|
return { data: prefixPluginTranslations(data), locale };
|
|
151
151
|
} catch {
|
|
152
152
|
return { data: {}, locale };
|
|
@@ -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-
|
|
28
|
+
Component: async () => (await import("./Forms-ws6d8rdC.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-
|
|
43
|
+
Input: async () => import("./HubspotPropertyInput-C-kHDgwx.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-
|
|
106
|
+
Input: async () => import("./HubspotObjectInput-DshusXZP.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-
|
|
122
|
+
Input: async () => import("./HubspotFormInput-18pWTITT.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-
|
|
138
|
+
Component: async () => (await import("./Settings-Bm7WkzK1.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-
|
|
148
|
+
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-DKV-8FWP.mjs"), "./translations/fr.json": () => import("./fr-GB6T3ZyU.mjs") }), `./translations/${locale}.json`, 3);
|
|
149
149
|
return { data: prefixPluginTranslations(data), locale };
|
|
150
150
|
} catch {
|
|
151
151
|
return { data: {}, locale };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const React = require("react");
|
|
3
3
|
const admin = require("@strapi/strapi/admin");
|
|
4
|
-
const index = require("./index-
|
|
4
|
+
const index = require("./index-BlaG8oIq.js");
|
|
5
5
|
function _interopNamespace(e) {
|
|
6
6
|
if (e && e.__esModule) return e;
|
|
7
7
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { useFetchClient } from "@strapi/strapi/admin";
|
|
3
|
-
import { P as PLUGIN_ID } from "./index-
|
|
3
|
+
import { P as PLUGIN_ID } from "./index-CPVfElYB.mjs";
|
|
4
4
|
let cached = null;
|
|
5
5
|
let inFlight = null;
|
|
6
6
|
const listeners = /* @__PURE__ */ new Set();
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED