strapi-plugin-hubspot 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +28 -13
- package/dist/_chunks/{Forms-ClyI4MJ1.js → Forms-D0QXkYAN.js} +216 -112
- package/dist/_chunks/{Forms-B7eIm0Fi.mjs → Forms-DEoZGrEt.mjs} +218 -114
- package/dist/_chunks/{HubspotFormInput-Do7F83V6.js → HubspotFormInput-4ZMYXWM_.js} +1 -1
- package/dist/_chunks/{HubspotFormInput-cZAiaAaq.mjs → HubspotFormInput-CPep55GL.mjs} +1 -1
- package/dist/_chunks/{HubspotObjectInput-DWqk2C26.js → HubspotObjectInput-BTqYXJIa.js} +3 -3
- package/dist/_chunks/{HubspotObjectInput-ZZk_7hWq.mjs → HubspotObjectInput-CQszIx1W.mjs} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-v9B3wb1a.js → HubspotPropertyInput-2MgIKlR_.js} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-5bkDGmGo.mjs → HubspotPropertyInput-ClNph0f1.mjs} +3 -3
- package/dist/_chunks/{Settings-QcFbm3s5.mjs → Settings-CZ-qQSKT.mjs} +78 -5
- package/dist/_chunks/{Settings-X3EHnTaO.js → Settings-DhiHQC6U.js} +77 -4
- package/dist/_chunks/{en-ZHvaZLi7.js → en-CSgFmKmM.js} +16 -3
- package/dist/_chunks/{en-DMJeF7EN.mjs → en-Dh3bMS6N.mjs} +16 -3
- package/dist/_chunks/{fr-Ds_2EAzZ.js → fr-D_EhZS0P.js} +16 -3
- package/dist/_chunks/{fr-CVAntLmc.mjs → fr-aWOIOlS9.mjs} +16 -3
- package/dist/_chunks/{index-BpcilDy1.js → index-ciliGv0E.js} +6 -6
- package/dist/_chunks/{index-BSJAhj8r.mjs → index-gKM4jVf8.mjs} +6 -6
- package/dist/_chunks/{objectLabels-CYXXFpNB.js → objectLabels-BjYfdhRB.js} +1 -1
- package/dist/_chunks/{objectLabels-CrYRzsqe.mjs → objectLabels-DQpSLUaJ.mjs} +1 -1
- package/dist/_chunks/{useHubspotSchema-CBF4GkmK.mjs → useHubspotSchema-CE7tJgOM.mjs} +1 -1
- package/dist/_chunks/{useHubspotSchema-Ba6xZUCL.js → useHubspotSchema-KKVppjC2.js} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/builder/Sortable.d.ts +25 -12
- package/dist/admin/src/builder/__tests__/relocateField.test.d.ts +1 -0
- package/dist/admin/src/builder/relocateField.d.ts +14 -0
- package/dist/server/index.js +216 -7
- package/dist/server/index.mjs +216 -7
- package/dist/server/src/__tests__/formSync.test.d.ts +1 -0
- package/dist/server/src/formSync.d.ts +37 -0
- package/dist/server/src/forms.d.ts +6 -8
- package/dist/server/src/hsforms.d.ts +8 -0
- package/dist/server/src/importHubspot.d.ts +4 -0
- package/dist/server/src/index.d.ts +6 -0
- package/dist/server/src/settings.d.ts +32 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.16.1 — 2026-09-22
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Fields in the builder can be dragged from one step to another (the grip
|
|
9
|
+
handle is no longer limited to reordering inside the current step). Arrow
|
|
10
|
+
buttons still move a field into the neighbouring step.
|
|
11
|
+
|
|
12
|
+
## 0.16.0 — 2026-09-22
|
|
13
|
+
|
|
14
|
+
### Added — submission policies
|
|
15
|
+
The plugin no longer assumes one HubSpot workflow. **Settings → HubSpot**
|
|
16
|
+
(and `forms.*` in `config/plugins.ts`) now expose three independent choices:
|
|
17
|
+
|
|
18
|
+
- **`submissionMode`** (`auto` / `forms` / `crm`): native marketing-form
|
|
19
|
+
conversions when a GUID is linked, CRM upsert only, or automatic.
|
|
20
|
+
- **`writeExtraProperties`** (default `true`): after a Forms API conversion,
|
|
21
|
+
leftover mapped contact fields still land on the contact via CRM upsert.
|
|
22
|
+
- **`syncFieldsOnPublish`** (default `false`): on publish, PATCH missing
|
|
23
|
+
mapped contact fields onto the linked HubSpot form. Off so HubSpot-first
|
|
24
|
+
installs aren't mutated. CRM properties are never created.
|
|
25
|
+
|
|
5
26
|
## 0.15.0 — 2026-09-21
|
|
6
27
|
|
|
7
28
|
### Added — account settings in the admin
|
package/README.md
CHANGED
|
@@ -44,14 +44,25 @@ Permissions**):
|
|
|
44
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 |
|
|
45
45
|
| `POST` | `/api/hubspot/forms/:slug/submit` | Validates (bounds, conditions, required), maps server-side, syncs HubSpot, stores the submission |
|
|
46
46
|
|
|
47
|
-
The submit pipeline
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
The submit pipeline is a **policy**, not a single path. Settings → HubSpot
|
|
48
|
+
(or `forms.*` in `config/plugins.ts`) pick how this install talks to HubSpot —
|
|
49
|
+
so a portal that wants native conversions and a portal that only wants CRM
|
|
50
|
+
upserts can share the same plugin:
|
|
51
|
+
|
|
52
|
+
| Setting | Default | What it does |
|
|
53
|
+
|---|---|---|
|
|
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
|
+
| `forms.writeExtraProperties` | `true` | After a conversion, CRM-write mapped contact fields the HubSpot form dropped (they 400 the Forms API) |
|
|
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
|
+
|
|
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.
|
|
62
|
+
|
|
63
|
+
CRM properties are **never created**. Map to properties that already exist in
|
|
64
|
+
the portal; opting into field sync only adds form fields that point at those
|
|
65
|
+
properties.
|
|
55
66
|
|
|
56
67
|
Portal id, region and form GUIDs are configuration. A test portal today,
|
|
57
68
|
production tomorrow: swap `portalId` / `region` / the GUID, no code change.
|
|
@@ -66,6 +77,9 @@ hubspot: {
|
|
|
66
77
|
companyFromDomain: true, // Company by corporate domain + association
|
|
67
78
|
timelineNote: false, // recap note on the CRM-upsert fallback only
|
|
68
79
|
defaultFormId: env("HUBSPOT_DEFAULT_FORM_ID", ""),
|
|
80
|
+
submissionMode: "auto", // auto | forms | crm
|
|
81
|
+
writeExtraProperties: true,
|
|
82
|
+
syncFieldsOnPublish: false,
|
|
69
83
|
},
|
|
70
84
|
},
|
|
71
85
|
}
|
|
@@ -365,11 +379,12 @@ its equivalent per object you send to).
|
|
|
365
379
|
|
|
366
380
|
### A settings screen
|
|
367
381
|
|
|
368
|
-
**Settings → HubSpot** holds the private app token
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
`config/plugins.ts` and env
|
|
372
|
-
|
|
382
|
+
**Settings → HubSpot** holds the private app token, the HubSpot account that
|
|
383
|
+
receives conversions (portal id, region, default marketing form), **and** the
|
|
384
|
+
submission policy: conversion vs CRM upsert, leftover contact writes, form
|
|
385
|
+
field sync on publish. Values saved here override `config/plugins.ts` and env
|
|
386
|
+
— switching test → production, or switching HubSpot-first ↔ Strapi-first, is
|
|
387
|
+
an admin change, not a deploy.
|
|
373
388
|
|
|
374
389
|
The token is stored server-side and never returned to the browser: the UI only
|
|
375
390
|
receives whether a key exists, where it comes from, and its last four
|
|
@@ -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-ciliGv0E.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-BjYfdhRB.js");
|
|
15
|
+
const useHubspotSchema = require("./useHubspotSchema-KKVppjC2.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" } });
|
|
@@ -173,32 +173,107 @@ const ConditionEditor = ({ condition, candidates, onChange }) => {
|
|
|
173
173
|
] })
|
|
174
174
|
] });
|
|
175
175
|
};
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
176
|
+
function relocateField(steps, fieldId, overId) {
|
|
177
|
+
const next = steps.map((step) => ({ ...step, fields: [...step.fields] }));
|
|
178
|
+
let fromStep = -1;
|
|
179
|
+
let fromIndex = -1;
|
|
180
|
+
for (let i = 0; i < next.length; i += 1) {
|
|
181
|
+
const index2 = next[i].fields.findIndex((field2) => field2.id === fieldId);
|
|
182
|
+
if (index2 !== -1) {
|
|
183
|
+
fromStep = i;
|
|
184
|
+
fromIndex = index2;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (fromStep === -1) return steps;
|
|
189
|
+
let toStep = -1;
|
|
190
|
+
let toIndex = -1;
|
|
191
|
+
const containerId = overId.startsWith("container:") ? overId.slice("container:".length) : "";
|
|
192
|
+
if (containerId) {
|
|
193
|
+
toStep = next.findIndex((step) => step.id === containerId);
|
|
194
|
+
toIndex = toStep === -1 ? -1 : next[toStep].fields.length;
|
|
195
|
+
} else {
|
|
196
|
+
for (let i = 0; i < next.length; i += 1) {
|
|
197
|
+
const index2 = next[i].fields.findIndex((field2) => field2.id === overId);
|
|
198
|
+
if (index2 !== -1) {
|
|
199
|
+
toStep = i;
|
|
200
|
+
toIndex = index2;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (toStep === -1) {
|
|
205
|
+
toStep = next.findIndex((step) => step.id === overId);
|
|
206
|
+
toIndex = toStep === -1 ? -1 : next[toStep].fields.length;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (toStep === -1 || toIndex === -1) return steps;
|
|
210
|
+
if (fromStep === toStep) {
|
|
211
|
+
if (fromIndex === toIndex) return steps;
|
|
212
|
+
next[fromStep].fields = sortable.arrayMove(next[fromStep].fields, fromIndex, toIndex);
|
|
213
|
+
return next;
|
|
214
|
+
}
|
|
215
|
+
const [field] = next[fromStep].fields.splice(fromIndex, 1);
|
|
216
|
+
if (!field) return steps;
|
|
217
|
+
next[toStep].fields.splice(toIndex, 0, field);
|
|
218
|
+
return next;
|
|
219
|
+
}
|
|
220
|
+
const collisionDetection = (args) => {
|
|
221
|
+
const type = args.active.data.current?.type;
|
|
222
|
+
const droppableContainers = args.droppableContainers.filter((container) => {
|
|
223
|
+
const other = container.data.current?.type;
|
|
224
|
+
if (type === "step") return other === "step";
|
|
225
|
+
if (type === "field") return other === "field" || other === "container";
|
|
226
|
+
return true;
|
|
227
|
+
});
|
|
228
|
+
return core.closestCorners({ ...args, droppableContainers });
|
|
229
|
+
};
|
|
230
|
+
function SortableBoard({
|
|
231
|
+
children,
|
|
232
|
+
onDragEnd
|
|
180
233
|
}) {
|
|
181
234
|
const sensors = core.useSensors(
|
|
182
235
|
// An 8px activation distance keeps clicks (selection!) from starting drags.
|
|
183
236
|
core.useSensor(core.PointerSensor, { activationConstraint: { distance: 8 } }),
|
|
184
237
|
core.useSensor(core.KeyboardSensor, { coordinateGetter: sortable.sortableKeyboardCoordinates })
|
|
185
238
|
);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
239
|
+
return /* @__PURE__ */ jsxRuntime.jsx(core.DndContext, { sensors, collisionDetection, onDragEnd, children });
|
|
240
|
+
}
|
|
241
|
+
function SortableGroup({
|
|
242
|
+
ids,
|
|
243
|
+
children
|
|
244
|
+
}) {
|
|
245
|
+
return /* @__PURE__ */ jsxRuntime.jsx(sortable.SortableContext, { items: ids, strategy: sortable.verticalListSortingStrategy, children });
|
|
246
|
+
}
|
|
247
|
+
function SortableContainer({
|
|
248
|
+
stepId,
|
|
249
|
+
children
|
|
250
|
+
}) {
|
|
251
|
+
const { setNodeRef, isOver } = core.useDroppable({
|
|
252
|
+
id: `container:${stepId}`,
|
|
253
|
+
data: { type: "container", stepId }
|
|
254
|
+
});
|
|
255
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
256
|
+
"div",
|
|
257
|
+
{
|
|
258
|
+
ref: setNodeRef,
|
|
259
|
+
style: {
|
|
260
|
+
minHeight: 8,
|
|
261
|
+
borderRadius: 4,
|
|
262
|
+
outline: isOver ? "2px dashed currentColor" : void 0,
|
|
263
|
+
outlineOffset: 4
|
|
264
|
+
},
|
|
265
|
+
children
|
|
266
|
+
}
|
|
267
|
+
);
|
|
195
268
|
}
|
|
196
269
|
function SortableItem({
|
|
197
270
|
id,
|
|
271
|
+
data,
|
|
198
272
|
children
|
|
199
273
|
}) {
|
|
200
274
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = sortable.useSortable({
|
|
201
|
-
id
|
|
275
|
+
id,
|
|
276
|
+
data
|
|
202
277
|
});
|
|
203
278
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
204
279
|
"div",
|
|
@@ -794,11 +869,32 @@ const FormEditor = () => {
|
|
|
794
869
|
setBusy(true);
|
|
795
870
|
setFeedback(null);
|
|
796
871
|
try {
|
|
797
|
-
await post(`/${index$1.PLUGIN_ID}/builder/forms/${documentId}/publish${query}`);
|
|
872
|
+
const { data } = await post(`/${index$1.PLUGIN_ID}/builder/forms/${documentId}/publish${query}`);
|
|
798
873
|
setPublished(true);
|
|
799
874
|
setErrors([]);
|
|
800
875
|
setProblems([]);
|
|
801
|
-
|
|
876
|
+
const added = Array.isArray(data?.addedFields) ? data.addedFields.length : 0;
|
|
877
|
+
if (data?.syncWarning) {
|
|
878
|
+
setFeedback({
|
|
879
|
+
tone: "success",
|
|
880
|
+
text: t(
|
|
881
|
+
"editor.published-sync-warn",
|
|
882
|
+
"Form published. HubSpot field sync failed: {error}",
|
|
883
|
+
{ error: data.syncWarning }
|
|
884
|
+
)
|
|
885
|
+
});
|
|
886
|
+
} else if (added) {
|
|
887
|
+
setFeedback({
|
|
888
|
+
tone: "success",
|
|
889
|
+
text: t(
|
|
890
|
+
"editor.published-synced",
|
|
891
|
+
"Form published. {count, plural, one {# field added} other {# fields added}} to the HubSpot form.",
|
|
892
|
+
{ count: added }
|
|
893
|
+
)
|
|
894
|
+
});
|
|
895
|
+
} else {
|
|
896
|
+
setFeedback({ tone: "success", text: t("editor.published", "Form published.") });
|
|
897
|
+
}
|
|
802
898
|
} catch (err) {
|
|
803
899
|
const data = err.response?.data;
|
|
804
900
|
setErrors(data?.errors ?? []);
|
|
@@ -868,14 +964,28 @@ const FormEditor = () => {
|
|
|
868
964
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 6, alignItems: "flex-start", children: [
|
|
869
965
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { flex: "1", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
870
966
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
871
|
-
|
|
967
|
+
SortableBoard,
|
|
872
968
|
{
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
969
|
+
onDragEnd: ({ active, over }) => {
|
|
970
|
+
if (!over || active.id === over.id) return;
|
|
971
|
+
const kind = active.data.current?.type;
|
|
972
|
+
if (kind === "step") {
|
|
973
|
+
const ids = definition.steps.map((s) => s.id);
|
|
974
|
+
const from = ids.indexOf(String(active.id));
|
|
975
|
+
const to = ids.indexOf(String(over.id));
|
|
976
|
+
if (from === -1 || to === -1) return;
|
|
977
|
+
patchDefinition((steps) => reorderByIds(steps, sortable.arrayMove(ids, from, to)));
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
if (kind === "field") {
|
|
981
|
+
patchDefinition((steps) => relocateField(steps, String(active.id), String(over.id)));
|
|
982
|
+
}
|
|
983
|
+
},
|
|
984
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SortableGroup, { ids: definition.steps.map((s) => s.id), children: definition.steps.map((step, stepIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
876
985
|
SortableItem,
|
|
877
986
|
{
|
|
878
987
|
id: step.id,
|
|
988
|
+
data: { type: "step" },
|
|
879
989
|
children: (stepHandle) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
880
990
|
designSystem.Box,
|
|
881
991
|
{
|
|
@@ -951,95 +1061,89 @@ const FormEditor = () => {
|
|
|
951
1061
|
] })
|
|
952
1062
|
] }),
|
|
953
1063
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
954
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1064
|
+
/* @__PURE__ */ jsxRuntime.jsx(SortableContainer, { stepId: step.id, children: /* @__PURE__ */ jsxRuntime.jsx(SortableGroup, { ids: step.fields.map((f) => f.id), children: step.fields.map((field, fieldIndex) => {
|
|
1065
|
+
const flags = fieldFlags(field.id);
|
|
1066
|
+
const isSelected = selection.kind === "field" && selection.fieldId === field.id;
|
|
1067
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1068
|
+
SortableItem,
|
|
1069
|
+
{
|
|
1070
|
+
id: field.id,
|
|
1071
|
+
data: { type: "field", stepId: step.id },
|
|
1072
|
+
children: (fieldHandle) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1073
|
+
designSystem.Box,
|
|
964
1074
|
{
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
),
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
),
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
{
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
},
|
|
1038
|
-
field.id
|
|
1039
|
-
);
|
|
1040
|
-
})
|
|
1041
|
-
}
|
|
1042
|
-
),
|
|
1075
|
+
background: isSelected ? "primary100" : "neutral100",
|
|
1076
|
+
hasRadius: true,
|
|
1077
|
+
padding: 3,
|
|
1078
|
+
onClick: (e) => {
|
|
1079
|
+
e.stopPropagation();
|
|
1080
|
+
setSelection({ kind: "field", fieldId: field.id });
|
|
1081
|
+
},
|
|
1082
|
+
style: { cursor: "pointer" },
|
|
1083
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1084
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
1085
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1086
|
+
"span",
|
|
1087
|
+
{
|
|
1088
|
+
...fieldHandle.attributes,
|
|
1089
|
+
...fieldHandle.listeners,
|
|
1090
|
+
onClick: (e) => e.stopPropagation(),
|
|
1091
|
+
style: { cursor: "grab", display: "inline-flex" },
|
|
1092
|
+
"aria-label": t("editor.drag-field", "Drag to move the field, including to another step"),
|
|
1093
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Drag, {})
|
|
1094
|
+
}
|
|
1095
|
+
),
|
|
1096
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", children: field.label || field.name || "—" }),
|
|
1097
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: field.type }),
|
|
1098
|
+
field.required && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "neutral150", textColor: "neutral600", children: t("editor.required", "required") }),
|
|
1099
|
+
field.hubspot?.property && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
1100
|
+
field.hubspot.object ?? "contact",
|
|
1101
|
+
".",
|
|
1102
|
+
field.hubspot.property
|
|
1103
|
+
] }),
|
|
1104
|
+
field.visibleIf?.rules?.length ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "alternative100", textColor: "alternative700", children: t("editor.conditional", "Conditional") }) : null,
|
|
1105
|
+
(flags.error || flags.problem) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "danger100", textColor: "danger700", children: flags.error?.code ?? flags.problem?.code })
|
|
1106
|
+
] }),
|
|
1107
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, onClick: (e) => e.stopPropagation(), children: [
|
|
1108
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1109
|
+
designSystem.IconButton,
|
|
1110
|
+
{
|
|
1111
|
+
label: t("editor.field-up", "Move up"),
|
|
1112
|
+
onClick: () => moveField(stepIndex, fieldIndex, -1),
|
|
1113
|
+
disabled: stepIndex === 0 && fieldIndex === 0,
|
|
1114
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUp, {})
|
|
1115
|
+
}
|
|
1116
|
+
),
|
|
1117
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1118
|
+
designSystem.IconButton,
|
|
1119
|
+
{
|
|
1120
|
+
label: t("editor.field-down", "Move down"),
|
|
1121
|
+
onClick: () => moveField(stepIndex, fieldIndex, 1),
|
|
1122
|
+
disabled: stepIndex === definition.steps.length - 1 && fieldIndex === step.fields.length - 1,
|
|
1123
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDown, {})
|
|
1124
|
+
}
|
|
1125
|
+
),
|
|
1126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1127
|
+
designSystem.IconButton,
|
|
1128
|
+
{
|
|
1129
|
+
label: t("editor.field-delete", "Delete the field"),
|
|
1130
|
+
onClick: () => {
|
|
1131
|
+
setSelection({ kind: "form" });
|
|
1132
|
+
patchStep(step.id, {
|
|
1133
|
+
fields: step.fields.filter((f) => f.id !== field.id)
|
|
1134
|
+
});
|
|
1135
|
+
},
|
|
1136
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
|
|
1137
|
+
}
|
|
1138
|
+
)
|
|
1139
|
+
] })
|
|
1140
|
+
] })
|
|
1141
|
+
}
|
|
1142
|
+
)
|
|
1143
|
+
},
|
|
1144
|
+
field.id
|
|
1145
|
+
);
|
|
1146
|
+
}) }) }),
|
|
1043
1147
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1044
1148
|
designSystem.Button,
|
|
1045
1149
|
{
|
|
@@ -1060,7 +1164,7 @@ const FormEditor = () => {
|
|
|
1060
1164
|
)
|
|
1061
1165
|
},
|
|
1062
1166
|
step.id
|
|
1063
|
-
))
|
|
1167
|
+
)) })
|
|
1064
1168
|
}
|
|
1065
1169
|
),
|
|
1066
1170
|
/* @__PURE__ */ jsxRuntime.jsx(
|