@actuate-media/cms-admin 0.76.7 → 0.77.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 +14 -0
- package/dist/__tests__/views/form-editor.render.test.d.ts +2 -0
- package/dist/__tests__/views/form-editor.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/form-editor.render.test.js +146 -0
- package/dist/__tests__/views/form-editor.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/lib/forms-service.d.ts +15 -3
- package/dist/lib/forms-service.d.ts.map +1 -1
- package/dist/lib/forms-service.js.map +1 -1
- package/dist/views/FormEditor.d.ts.map +1 -1
- package/dist/views/FormEditor.js +211 -116
- package/dist/views/FormEditor.js.map +1 -1
- package/package.json +9 -9
- package/src/__tests__/views/form-editor.render.test.tsx +186 -0
- package/src/lib/forms-service.ts +16 -1
- package/src/views/FormEditor.tsx +655 -510
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @actuate-media/cms-admin
|
|
2
2
|
|
|
3
|
+
## 0.77.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 21aa417: Consolidate the two form-editing surfaces onto the typed Forms API and make GA4 form analytics work end-to-end.
|
|
8
|
+
|
|
9
|
+
**cms-admin** — The Edit Form page is rebuilt as the canonical full-page form editor, backed by the same typed Forms API as the Forms list's inline Schema pane (no more legacy `/collections/forms` writes that bypassed schema versioning). It now covers everything in one place: Details (name/description/status + post-submit confirmation), Fields (versioned schema editor), **Notifications** (previously only reachable from the Schema pane), Analytics (GA4), Embed, and Integrations (webhooks). Confirmation settings now persist to `successMessage` / `redirectUrl` — the fields the public submission pipeline actually reads (the old editor wrote a `confirmation` object the runtime ignored). New forms are created through `POST /forms`, gaining slug generation, an initial schema version, and notification defaults, then route into the full editor.
|
|
10
|
+
|
|
11
|
+
**cms-core** — `FormDefinition` gains a sanitized `analytics` (GA4) config, persisted via the forms service (`createForm` / `updateForm` / `duplicateForm`) and exposed on the public form schema only when tracking is enabled. New `normalizeAnalyticsConfig` export and a client-safe `@actuate-media/cms-core/forms/analytics` subpath export.
|
|
12
|
+
|
|
13
|
+
**sections-react** — `<ActuateForm>` now fires GA4 `form_start` / `form_submit` / `form_error` events (with optional conversion value) when the form has analytics enabled. Also fixes the success state to read the submit endpoint's `confirmation` _object_ (`{ type, message, redirectUrl }`) — previously it was treated as a string, which broke the success message and ignored server-driven redirects. New `resolveSubmitOutcome` helper with regression coverage.
|
|
14
|
+
|
|
15
|
+
**plugin-forms** — The `forms` collection field map now declares every key the typed forms service persists (`description`, `notificationSettings`, `embedSettings`, `spamSettings`, `successMessage`, `redirectUrl`, `analytics`, `activeSchemaVersionId`, …). The data layer strips undeclared keys on write, so consumer apps registering this plugin would previously drop notification/embed/spam settings silently. Status options now match the typed `FormStatus` (`active` / `draft` / `archived`).
|
|
16
|
+
|
|
3
17
|
## 0.76.7
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-editor.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/form-editor.render.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @vitest-environment happy-dom
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
5
|
+
// Drive the editor through a mocked forms-service so the test owns the data
|
|
6
|
+
// and can assert that every tab persists through the typed Forms API (the
|
|
7
|
+
// same backend as the Forms list's Schema pane — no more legacy
|
|
8
|
+
// /collections/forms writes).
|
|
9
|
+
const FORM = {
|
|
10
|
+
id: 'f1',
|
|
11
|
+
name: 'Contact Us',
|
|
12
|
+
slug: 'contact-us',
|
|
13
|
+
description: 'General contact',
|
|
14
|
+
status: 'active',
|
|
15
|
+
fields: [
|
|
16
|
+
{ id: 'c1', label: 'Full Name', key: 'name', type: 'text', required: true, sortOrder: 0 },
|
|
17
|
+
{ id: 'c2', label: 'Email', key: 'email', type: 'email', required: true, sortOrder: 1 },
|
|
18
|
+
],
|
|
19
|
+
successMessage: 'Thanks for reaching out!',
|
|
20
|
+
redirectUrl: '',
|
|
21
|
+
analytics: { enabled: false },
|
|
22
|
+
totalEntries: 3,
|
|
23
|
+
notifyEnabled: true,
|
|
24
|
+
};
|
|
25
|
+
const fetchFormById = vi.fn(async (_id) => ({ ...FORM }));
|
|
26
|
+
const fetchFormSchema = vi.fn(async (_id) => ({
|
|
27
|
+
fields: FORM.fields,
|
|
28
|
+
activeVersionId: 'v1',
|
|
29
|
+
versions: [],
|
|
30
|
+
}));
|
|
31
|
+
const updateForm = vi.fn(async (_id, patch) => ({
|
|
32
|
+
data: { ...FORM, ...patch },
|
|
33
|
+
}));
|
|
34
|
+
const saveFormSchema = vi.fn(async (_id, _fields) => ({ data: {} }));
|
|
35
|
+
const createForm = vi.fn(async (payload) => ({
|
|
36
|
+
data: { ...FORM, id: 'new-form-id', ...payload },
|
|
37
|
+
}));
|
|
38
|
+
const fetchNotificationSettings = vi.fn(async (_id) => ({
|
|
39
|
+
enabled: true,
|
|
40
|
+
recipients: ['team@example.com'],
|
|
41
|
+
}));
|
|
42
|
+
const updateNotificationSettings = vi.fn(async () => ({ data: {} }));
|
|
43
|
+
const fetchEmbedSettings = vi.fn(async () => ({}));
|
|
44
|
+
const fetchFormWebhooks = vi.fn(async () => []);
|
|
45
|
+
vi.mock('../../lib/forms-service.js', () => ({
|
|
46
|
+
fetchFormById: (id) => fetchFormById(id),
|
|
47
|
+
fetchFormSchema: (id) => fetchFormSchema(id),
|
|
48
|
+
updateForm: (id, patch) => updateForm(id, patch),
|
|
49
|
+
saveFormSchema: (id, fields) => saveFormSchema(id, fields),
|
|
50
|
+
createForm: (payload) => createForm(payload),
|
|
51
|
+
fetchNotificationSettings: (id) => fetchNotificationSettings(id),
|
|
52
|
+
updateNotificationSettings: () => updateNotificationSettings(),
|
|
53
|
+
fetchEmbedSettings: () => fetchEmbedSettings(),
|
|
54
|
+
updateEmbedSettings: vi.fn(async () => ({ data: {} })),
|
|
55
|
+
fetchFormWebhooks: () => fetchFormWebhooks(),
|
|
56
|
+
createFormWebhook: vi.fn(async () => ({ data: {} })),
|
|
57
|
+
updateFormWebhook: vi.fn(async () => ({ data: {} })),
|
|
58
|
+
deleteFormWebhook: vi.fn(async () => ({})),
|
|
59
|
+
testFormWebhook: vi.fn(async () => ({ data: { ok: true } })),
|
|
60
|
+
}));
|
|
61
|
+
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() } }));
|
|
62
|
+
const { FormEditor } = await import('../../views/FormEditor.js');
|
|
63
|
+
// Radix Tabs activates on mousedown (button 0), not a bare click.
|
|
64
|
+
function selectTab(name) {
|
|
65
|
+
const tab = screen.getByRole('tab', { name });
|
|
66
|
+
fireEvent.mouseDown(tab, { button: 0 });
|
|
67
|
+
fireEvent.click(tab);
|
|
68
|
+
}
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
fetchFormById.mockClear();
|
|
71
|
+
fetchFormSchema.mockClear();
|
|
72
|
+
updateForm.mockClear();
|
|
73
|
+
saveFormSchema.mockClear();
|
|
74
|
+
createForm.mockClear();
|
|
75
|
+
fetchNotificationSettings.mockClear();
|
|
76
|
+
});
|
|
77
|
+
describe('FormEditor (existing form)', () => {
|
|
78
|
+
it('loads through the typed Forms API and renders every settings tab', async () => {
|
|
79
|
+
render(_jsx(FormEditor, { formId: "f1", onNavigate: () => { } }));
|
|
80
|
+
expect(await screen.findByRole('heading', { name: 'Contact Us' })).toBeTruthy();
|
|
81
|
+
expect(fetchFormById).toHaveBeenCalledWith('f1');
|
|
82
|
+
expect(fetchFormSchema).toHaveBeenCalledWith('f1');
|
|
83
|
+
const tabs = screen.getAllByRole('tab').map((t) => t.textContent);
|
|
84
|
+
expect(tabs).toEqual([
|
|
85
|
+
'Details',
|
|
86
|
+
'Fields',
|
|
87
|
+
'Notifications',
|
|
88
|
+
'Analytics',
|
|
89
|
+
'Embed',
|
|
90
|
+
'Integrations',
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
it('saves details (message confirmation clears the redirect URL)', async () => {
|
|
94
|
+
render(_jsx(FormEditor, { formId: "f1", onNavigate: () => { } }));
|
|
95
|
+
await screen.findByRole('heading', { name: 'Contact Us' });
|
|
96
|
+
fireEvent.change(screen.getByLabelText(/Form Name/), { target: { value: 'Contact' } });
|
|
97
|
+
fireEvent.click(screen.getByRole('button', { name: /Save Details/ }));
|
|
98
|
+
await waitFor(() => expect(updateForm).toHaveBeenCalledWith('f1', expect.objectContaining({
|
|
99
|
+
name: 'Contact',
|
|
100
|
+
status: 'active',
|
|
101
|
+
successMessage: 'Thanks for reaching out!',
|
|
102
|
+
redirectUrl: '',
|
|
103
|
+
})));
|
|
104
|
+
});
|
|
105
|
+
it('exposes notification settings from the editor (the old editor had none)', async () => {
|
|
106
|
+
render(_jsx(FormEditor, { formId: "f1", onNavigate: () => { } }));
|
|
107
|
+
await screen.findByRole('heading', { name: 'Contact Us' });
|
|
108
|
+
selectTab('Notifications');
|
|
109
|
+
await waitFor(() => expect(fetchNotificationSettings).toHaveBeenCalledWith('f1'));
|
|
110
|
+
expect(await screen.findByText('Enable notifications')).toBeTruthy();
|
|
111
|
+
});
|
|
112
|
+
it('persists GA4 analytics through the typed update endpoint', async () => {
|
|
113
|
+
render(_jsx(FormEditor, { formId: "f1", onNavigate: () => { } }));
|
|
114
|
+
await screen.findByRole('heading', { name: 'Contact Us' });
|
|
115
|
+
selectTab('Analytics');
|
|
116
|
+
fireEvent.click(await screen.findByRole('switch', { name: /Google Analytics 4/ }));
|
|
117
|
+
fireEvent.click(screen.getByRole('button', { name: /Save Analytics/ }));
|
|
118
|
+
await waitFor(() => expect(updateForm).toHaveBeenCalledWith('f1', {
|
|
119
|
+
analytics: expect.objectContaining({ enabled: true }),
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
it('saves the field schema through the versioned schema endpoint', async () => {
|
|
123
|
+
render(_jsx(FormEditor, { formId: "f1", onNavigate: () => { } }));
|
|
124
|
+
await screen.findByRole('heading', { name: 'Contact Us' });
|
|
125
|
+
selectTab('Fields');
|
|
126
|
+
fireEvent.click(await screen.findByRole('button', { name: 'Add Field' }));
|
|
127
|
+
fireEvent.click(screen.getByRole('button', { name: /Save Schema/ }));
|
|
128
|
+
await waitFor(() => expect(saveFormSchema).toHaveBeenCalledWith('f1', expect.arrayContaining([expect.objectContaining({ key: 'name' })])));
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('FormEditor (new form)', () => {
|
|
132
|
+
it('creates through the typed API and routes into the full editor', async () => {
|
|
133
|
+
const onNavigate = vi.fn();
|
|
134
|
+
render(_jsx(FormEditor, { onNavigate: onNavigate }));
|
|
135
|
+
fireEvent.change(screen.getByLabelText(/Form Name/), { target: { value: 'Newsletter' } });
|
|
136
|
+
fireEvent.click(screen.getByRole('button', { name: /Create Form/ }));
|
|
137
|
+
await waitFor(() => expect(createForm).toHaveBeenCalledWith(expect.objectContaining({ name: 'Newsletter', status: 'active' })));
|
|
138
|
+
await waitFor(() => expect(onNavigate).toHaveBeenCalledWith('/forms/new-form-id/edit'));
|
|
139
|
+
});
|
|
140
|
+
it('disables Create until a name is entered', () => {
|
|
141
|
+
render(_jsx(FormEditor, { onNavigate: () => { } }));
|
|
142
|
+
const create = screen.getByRole('button', { name: /Create Form/ });
|
|
143
|
+
expect(create.disabled).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=form-editor.render.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-editor.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/form-editor.render.test.tsx"],"names":[],"mappings":"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"}
|