@actuate-media/cms-admin 0.21.0 → 0.22.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/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +24 -0
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.js +30 -0
- package/dist/__tests__/layout/sidebar-forms-badge.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-submenu.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-submenu.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-submenu.render.test.js +66 -0
- package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -0
- package/dist/__tests__/views/forms-list.render.test.d.ts +2 -0
- package/dist/__tests__/views/forms-list.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/forms-list.render.test.js +122 -0
- package/dist/__tests__/views/forms-list.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/components/ErrorBoundary.d.ts +1 -1
- package/dist/components/forms/Drawer.d.ts +13 -0
- package/dist/components/forms/Drawer.d.ts.map +1 -0
- package/dist/components/forms/Drawer.js +13 -0
- package/dist/components/forms/Drawer.js.map +1 -0
- package/dist/components/forms/EmbedPanel.d.ts +7 -0
- package/dist/components/forms/EmbedPanel.d.ts.map +1 -0
- package/dist/components/forms/EmbedPanel.js +91 -0
- package/dist/components/forms/EmbedPanel.js.map +1 -0
- package/dist/components/forms/FieldsPanel.d.ts +8 -0
- package/dist/components/forms/FieldsPanel.d.ts.map +1 -0
- package/dist/components/forms/FieldsPanel.js +123 -0
- package/dist/components/forms/FieldsPanel.js.map +1 -0
- package/dist/components/forms/FormSchemaDrawer.d.ts +9 -0
- package/dist/components/forms/FormSchemaDrawer.d.ts.map +1 -0
- package/dist/components/forms/FormSchemaDrawer.js +96 -0
- package/dist/components/forms/FormSchemaDrawer.js.map +1 -0
- package/dist/components/forms/NotificationsPanel.d.ts +6 -0
- package/dist/components/forms/NotificationsPanel.d.ts.map +1 -0
- package/dist/components/forms/NotificationsPanel.js +80 -0
- package/dist/components/forms/NotificationsPanel.js.map +1 -0
- package/dist/components/forms/primitives.d.ts +42 -0
- package/dist/components/forms/primitives.d.ts.map +1 -0
- package/dist/components/forms/primitives.js +96 -0
- package/dist/components/forms/primitives.js.map +1 -0
- package/dist/layout/Sidebar.d.ts +5 -0
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +143 -10
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/lib/forms-events.d.ts +17 -0
- package/dist/lib/forms-events.d.ts.map +1 -0
- package/dist/lib/forms-events.js +20 -0
- package/dist/lib/forms-events.js.map +1 -0
- package/dist/lib/forms-service.d.ts +80 -0
- package/dist/lib/forms-service.d.ts.map +1 -0
- package/dist/lib/forms-service.js +144 -0
- package/dist/lib/forms-service.js.map +1 -0
- package/dist/views/Forms.d.ts.map +1 -1
- package/dist/views/Forms.js +119 -16
- package/dist/views/Forms.js.map +1 -1
- package/package.json +2 -2
- package/src/AdminRoot.tsx +22 -0
- package/src/__tests__/layout/sidebar-forms-badge.render.test.tsx +50 -0
- package/src/__tests__/layout/sidebar-submenu.render.test.tsx +93 -0
- package/src/__tests__/views/forms-list.render.test.tsx +141 -0
- package/src/components/forms/Drawer.tsx +70 -0
- package/src/components/forms/EmbedPanel.tsx +173 -0
- package/src/components/forms/FieldsPanel.tsx +385 -0
- package/src/components/forms/FormSchemaDrawer.tsx +185 -0
- package/src/components/forms/NotificationsPanel.tsx +240 -0
- package/src/components/forms/primitives.tsx +200 -0
- package/src/layout/Sidebar.tsx +295 -14
- package/src/lib/forms-events.ts +32 -0
- package/src/lib/forms-service.ts +244 -0
- package/src/views/Forms.tsx +343 -104
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forms service — typed client over the cms-core Forms REST endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Every Forms admin component reads/writes through this module (never raw
|
|
5
|
+
* `cmsApi` / `fetch`), so the network contract lives in one place. Read
|
|
6
|
+
* fetchers re-surface `cmsApi`'s `{ error }` as a thrown error (so the
|
|
7
|
+
* resource hook can show error/retry UI); mutations return `{ error? }`.
|
|
8
|
+
*
|
|
9
|
+
* The endpoint paths here are the contract implemented by cms-core
|
|
10
|
+
* `packages/cms-core/src/api/handlers.ts` (PR 2). Domain types are re-used
|
|
11
|
+
* from `@actuate-media/cms-core` so the admin can never drift from the server.
|
|
12
|
+
*/
|
|
13
|
+
import { cmsApi } from './api.js';
|
|
14
|
+
/**
|
|
15
|
+
* `cmsApi` never throws — it returns `{ error, status }` on a network/HTTP
|
|
16
|
+
* failure. Read (GET) fetchers must re-surface that as a thrown error so the
|
|
17
|
+
* resource hook can distinguish "request failed" from "empty result".
|
|
18
|
+
*/
|
|
19
|
+
function throwIfError(res) {
|
|
20
|
+
if (res.error)
|
|
21
|
+
throw new Error(res.error);
|
|
22
|
+
}
|
|
23
|
+
// ─── Forms list / stats / sidebar ────────────────────────────────────────
|
|
24
|
+
function buildFormsQuery(params) {
|
|
25
|
+
const qs = new URLSearchParams();
|
|
26
|
+
if (params.search)
|
|
27
|
+
qs.set('search', params.search);
|
|
28
|
+
if (params.status)
|
|
29
|
+
qs.set('status', params.status);
|
|
30
|
+
if (typeof params.notifyEnabled === 'boolean') {
|
|
31
|
+
qs.set('notifyEnabled', String(params.notifyEnabled));
|
|
32
|
+
}
|
|
33
|
+
if (params.sortBy)
|
|
34
|
+
qs.set('sortBy', params.sortBy);
|
|
35
|
+
if (params.sortDirection)
|
|
36
|
+
qs.set('sortDirection', params.sortDirection);
|
|
37
|
+
if (params.page)
|
|
38
|
+
qs.set('page', String(params.page));
|
|
39
|
+
if (params.pageSize)
|
|
40
|
+
qs.set('pageSize', String(params.pageSize));
|
|
41
|
+
const str = qs.toString();
|
|
42
|
+
return str ? `?${str}` : '';
|
|
43
|
+
}
|
|
44
|
+
export async function fetchForms(params = {}) {
|
|
45
|
+
const res = await cmsApi(`/forms${buildFormsQuery(params)}`);
|
|
46
|
+
throwIfError(res);
|
|
47
|
+
return res.data ?? [];
|
|
48
|
+
}
|
|
49
|
+
export async function fetchFormById(id) {
|
|
50
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}`);
|
|
51
|
+
throwIfError(res);
|
|
52
|
+
return res.data ?? null;
|
|
53
|
+
}
|
|
54
|
+
const EMPTY_STATS = {
|
|
55
|
+
totalForms: 0,
|
|
56
|
+
activeForms: 0,
|
|
57
|
+
totalEntries: 0,
|
|
58
|
+
unreadEntries: 0,
|
|
59
|
+
};
|
|
60
|
+
export async function fetchFormStats() {
|
|
61
|
+
const res = await cmsApi('/forms/stats');
|
|
62
|
+
throwIfError(res);
|
|
63
|
+
return res.data ?? EMPTY_STATS;
|
|
64
|
+
}
|
|
65
|
+
export async function fetchFormsSidebarCounts() {
|
|
66
|
+
const res = await cmsApi('/forms/sidebar-counts');
|
|
67
|
+
throwIfError(res);
|
|
68
|
+
return res.data ?? [];
|
|
69
|
+
}
|
|
70
|
+
export async function createForm(payload) {
|
|
71
|
+
const res = await cmsApi('/forms', {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
body: JSON.stringify(payload),
|
|
74
|
+
});
|
|
75
|
+
return { data: res.data, error: res.error };
|
|
76
|
+
}
|
|
77
|
+
export async function updateForm(id, payload) {
|
|
78
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}`, {
|
|
79
|
+
method: 'PATCH',
|
|
80
|
+
body: JSON.stringify(payload),
|
|
81
|
+
});
|
|
82
|
+
return { data: res.data, error: res.error };
|
|
83
|
+
}
|
|
84
|
+
export async function duplicateForm(id) {
|
|
85
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/duplicate`, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
});
|
|
88
|
+
return { data: res.data, error: res.error };
|
|
89
|
+
}
|
|
90
|
+
/** Move a form to the archived state (hidden from embed pickers, no new submissions). */
|
|
91
|
+
export async function archiveForm(id) {
|
|
92
|
+
return updateForm(id, { status: 'archived' });
|
|
93
|
+
}
|
|
94
|
+
/** Restore an archived form back to draft. */
|
|
95
|
+
export async function restoreForm(id) {
|
|
96
|
+
return updateForm(id, { status: 'draft' });
|
|
97
|
+
}
|
|
98
|
+
export async function deleteForm(id, opts = {}) {
|
|
99
|
+
const qs = opts.force ? '?force=true' : '';
|
|
100
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}${qs}`, { method: 'DELETE' });
|
|
101
|
+
return { error: res.error };
|
|
102
|
+
}
|
|
103
|
+
// ─── Schema ──────────────────────────────────────────────────────────────
|
|
104
|
+
export async function fetchFormSchema(id) {
|
|
105
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/schema`);
|
|
106
|
+
throwIfError(res);
|
|
107
|
+
return res.data ?? { fields: [], activeVersionId: null, versions: [] };
|
|
108
|
+
}
|
|
109
|
+
export async function saveFormSchema(id, fields, notes) {
|
|
110
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/schema`, { method: 'PUT', body: JSON.stringify({ fields, notes }) });
|
|
111
|
+
return { data: res.data, error: res.error };
|
|
112
|
+
}
|
|
113
|
+
// ─── Notifications ─────────────────────────────────────────────────────────
|
|
114
|
+
export async function fetchNotificationSettings(id) {
|
|
115
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/notifications`);
|
|
116
|
+
throwIfError(res);
|
|
117
|
+
return res.data ?? { enabled: false, recipients: [] };
|
|
118
|
+
}
|
|
119
|
+
export async function updateNotificationSettings(id, payload) {
|
|
120
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/notifications`, { method: 'PUT', body: JSON.stringify(payload) });
|
|
121
|
+
return { data: res.data, error: res.error };
|
|
122
|
+
}
|
|
123
|
+
/** Lightweight notify on/off toggle used by the forms-list switch. */
|
|
124
|
+
export async function setNotifyEnabled(id, enabled) {
|
|
125
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/notify`, {
|
|
126
|
+
method: 'PUT',
|
|
127
|
+
body: JSON.stringify({ enabled }),
|
|
128
|
+
});
|
|
129
|
+
return { data: res.data, error: res.error };
|
|
130
|
+
}
|
|
131
|
+
// ─── Embed ───────────────────────────────────────────────────────────────
|
|
132
|
+
export async function fetchEmbedSettings(id) {
|
|
133
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/embed`);
|
|
134
|
+
throwIfError(res);
|
|
135
|
+
return res.data ?? {};
|
|
136
|
+
}
|
|
137
|
+
export async function updateEmbedSettings(id, payload) {
|
|
138
|
+
const res = await cmsApi(`/forms/${encodeURIComponent(id)}/embed`, {
|
|
139
|
+
method: 'PUT',
|
|
140
|
+
body: JSON.stringify(payload),
|
|
141
|
+
});
|
|
142
|
+
return { data: res.data, error: res.error };
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=forms-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms-service.js","sourceRoot":"","sources":["../../src/lib/forms-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Forms.d.ts","sourceRoot":"","sources":["../../src/views/Forms.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Forms.d.ts","sourceRoot":"","sources":["../../src/views/Forms.tsx"],"names":[],"mappings":"AAmCA,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC;AA8BD,wBAAgB,KAAK,CAAC,EAAE,UAAU,EAAE,EAAE,UAAU,2CA0L/C"}
|
package/dist/views/Forms.js
CHANGED
|
@@ -1,24 +1,127 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Forms list — manage forms and view high-level submission status. Matches the
|
|
5
|
+
* Forms list screenshot: summary chips, search + status filter pills, and a
|
|
6
|
+
* compact table (Form / Fields / Status / Entries / Last Entry / Notify /
|
|
7
|
+
* Schema). All data flows through `lib/forms-service.ts`; the Schema action
|
|
8
|
+
* opens the right-side `FormSchemaDrawer`.
|
|
9
|
+
*/
|
|
10
|
+
import { ChevronRight, ClipboardList, Plus, Search, Settings2 } from 'lucide-react';
|
|
11
|
+
import * as Switch from '@radix-ui/react-switch';
|
|
12
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import { toast } from 'sonner';
|
|
5
14
|
import { sortByRelevance } from '../lib/search.js';
|
|
6
|
-
import {
|
|
15
|
+
import { fetchForms, fetchFormStats, setNotifyEnabled, } from '../lib/forms-service.js';
|
|
16
|
+
import { emitFormsChanged, onFormsChanged } from '../lib/forms-events.js';
|
|
17
|
+
import { FormSchemaDrawer } from '../components/forms/FormSchemaDrawer.js';
|
|
18
|
+
import { FieldTypeBadge, FormStatusBadge, FormsEmptyState, FormsErrorState, FormsLoading, SummaryChip, UnreadBadge, btnPrimary, } from '../components/forms/primitives.js';
|
|
19
|
+
const FILTERS = [
|
|
20
|
+
{ id: 'all', label: 'All' },
|
|
21
|
+
{ id: 'active', label: 'Active' },
|
|
22
|
+
{ id: 'draft', label: 'Draft' },
|
|
23
|
+
{ id: 'archived', label: 'Archived' },
|
|
24
|
+
];
|
|
25
|
+
function formatRelative(iso) {
|
|
26
|
+
if (!iso)
|
|
27
|
+
return '—';
|
|
28
|
+
const then = new Date(iso).getTime();
|
|
29
|
+
if (Number.isNaN(then))
|
|
30
|
+
return '—';
|
|
31
|
+
const diff = Date.now() - then;
|
|
32
|
+
const mins = Math.round(diff / 60000);
|
|
33
|
+
if (mins < 1)
|
|
34
|
+
return 'just now';
|
|
35
|
+
if (mins < 60)
|
|
36
|
+
return `${mins} min ago`;
|
|
37
|
+
const hrs = Math.round(mins / 60);
|
|
38
|
+
if (hrs < 24)
|
|
39
|
+
return `${hrs} hour${hrs === 1 ? '' : 's'} ago`;
|
|
40
|
+
const days = Math.round(hrs / 24);
|
|
41
|
+
if (days < 7)
|
|
42
|
+
return `${days} day${days === 1 ? '' : 's'} ago`;
|
|
43
|
+
return new Date(iso).toLocaleDateString(undefined, {
|
|
44
|
+
month: 'short',
|
|
45
|
+
day: 'numeric',
|
|
46
|
+
year: 'numeric',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
7
49
|
export function Forms({ onNavigate }) {
|
|
8
|
-
const
|
|
9
|
-
const [
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
50
|
+
const [forms, setForms] = useState([]);
|
|
51
|
+
const [stats, setStats] = useState(null);
|
|
52
|
+
const [loading, setLoading] = useState(true);
|
|
53
|
+
const [error, setError] = useState(null);
|
|
54
|
+
const [search, setSearch] = useState('');
|
|
55
|
+
const [filter, setFilter] = useState('all');
|
|
56
|
+
const [schemaForm, setSchemaForm] = useState(null);
|
|
57
|
+
const [schemaOpen, setSchemaOpen] = useState(false);
|
|
58
|
+
const load = useCallback(async () => {
|
|
59
|
+
setLoading(true);
|
|
60
|
+
setError(null);
|
|
61
|
+
try {
|
|
62
|
+
const [formsData, statsData] = await Promise.all([fetchForms(), fetchFormStats()]);
|
|
63
|
+
setForms(formsData);
|
|
64
|
+
setStats(statsData);
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
setError(e instanceof Error ? e.message : 'Failed to load forms');
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
setLoading(false);
|
|
71
|
+
}
|
|
72
|
+
}, []);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
void load();
|
|
75
|
+
}, [load]);
|
|
76
|
+
// Refresh when another surface signals a forms/submission change.
|
|
77
|
+
useEffect(() => onFormsChanged(() => void load()), [load]);
|
|
78
|
+
const filtered = useMemo(() => {
|
|
79
|
+
let results = forms;
|
|
80
|
+
if (filter !== 'all')
|
|
81
|
+
results = results.filter((f) => f.status === filter);
|
|
82
|
+
const q = search.trim().toLowerCase();
|
|
83
|
+
if (q) {
|
|
84
|
+
results = results.filter((f) => f.name.toLowerCase().includes(q) ||
|
|
85
|
+
f.slug.toLowerCase().includes(q) ||
|
|
86
|
+
(f.description ?? '').toLowerCase().includes(q) ||
|
|
87
|
+
f.fields.some((field) => field.label.toLowerCase().includes(q) || field.type.toLowerCase().includes(q)));
|
|
88
|
+
results = sortByRelevance(results, search, (f) => [
|
|
89
|
+
f.name,
|
|
90
|
+
f.slug,
|
|
91
|
+
f.description ?? '',
|
|
92
|
+
...f.fields.map((field) => field.label),
|
|
93
|
+
]);
|
|
16
94
|
}
|
|
17
95
|
return results;
|
|
18
|
-
}, [forms,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
96
|
+
}, [forms, filter, search]);
|
|
97
|
+
const openSchema = useCallback((form) => {
|
|
98
|
+
setSchemaForm(form);
|
|
99
|
+
setSchemaOpen(true);
|
|
100
|
+
}, []);
|
|
101
|
+
const handleNotifyToggle = useCallback(async (form, next) => {
|
|
102
|
+
// Optimistic update; roll back on error.
|
|
103
|
+
setForms((cur) => cur.map((f) => (f.id === form.id ? { ...f, notifyEnabled: next } : f)));
|
|
104
|
+
const res = await setNotifyEnabled(form.id, next);
|
|
105
|
+
if (res.error) {
|
|
106
|
+
setForms((cur) => cur.map((f) => (f.id === form.id ? { ...f, notifyEnabled: !next } : f)));
|
|
107
|
+
toast.error(res.error);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
emitFormsChanged();
|
|
111
|
+
}, []);
|
|
112
|
+
return (_jsxs("div", { className: "space-y-5 p-6", children: [_jsxs("header", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground text-2xl font-medium", children: "Forms" }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: "Manage forms and view incoming submissions" })] }), _jsxs("button", { className: btnPrimary, onClick: () => onNavigate?.('/forms/new'), children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), "New Form"] })] }), stats && (_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(SummaryChip, { value: stats.totalForms, label: stats.totalForms === 1 ? 'form' : 'forms' }), _jsx(SummaryChip, { value: stats.activeForms, label: "active", tone: "success" }), _jsx(SummaryChip, { value: stats.totalEntries, label: "total entries" }), _jsx(SummaryChip, { value: stats.unreadEntries, label: "unread", tone: stats.unreadEntries > 0 ? 'destructive' : 'neutral' })] })), _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { className: "relative w-full sm:max-w-xs", children: [_jsx(Search, { className: "text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2", "aria-hidden": true }), _jsx("input", { type: "search", placeholder: "Search forms\u2026", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search forms", className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full rounded-lg border py-2 pr-3 pl-9 text-sm focus-visible:ring-2 focus-visible:outline-none" })] }), _jsx("div", { className: "flex gap-1", role: "group", "aria-label": "Filter by status", children: FILTERS.map((f) => (_jsx("button", { type: "button", onClick: () => setFilter(f.id), "aria-pressed": filter === f.id, className: `rounded-full px-3 py-1.5 text-sm font-medium transition-colors ${filter === f.id
|
|
113
|
+
? 'bg-primary text-primary-foreground'
|
|
114
|
+
: 'text-muted-foreground hover:bg-accent hover:text-foreground'}`, children: f.label }, f.id))) })] }), error ? (_jsx(FormsErrorState, { message: error, onRetry: load })) : loading ? (_jsx(FormsLoading, { label: "Loading forms\u2026" })) : forms.length === 0 ? (_jsx(FormsEmptyState, { icon: _jsx(ClipboardList, { className: "h-6 w-6", "aria-hidden": true }), title: "No forms yet", description: "Create your first form to start collecting submissions.", action: _jsxs("button", { className: btnPrimary, onClick: () => onNavigate?.('/forms/new'), children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), "Create New Form"] }) })) : filtered.length === 0 ? (_jsx(FormsEmptyState, { title: "No forms match your filters", description: "Try a different search term or status filter.", action: _jsx("button", { type: "button", onClick: () => {
|
|
115
|
+
setSearch('');
|
|
116
|
+
setFilter('all');
|
|
117
|
+
}, className: "text-primary text-sm font-medium hover:underline", children: "Clear filters" }) })) : (_jsx(FormsTable, { forms: filtered, onOpenForm: (id) => onNavigate?.(`/forms/${id}/edit`), onOpenEntries: (id) => onNavigate?.(`/forms/${id}/submissions`), onOpenSchema: openSchema, onNotifyToggle: handleNotifyToggle })), _jsx(FormSchemaDrawer, { form: schemaForm, open: schemaOpen, onOpenChange: setSchemaOpen, onSaved: load })] }));
|
|
118
|
+
}
|
|
119
|
+
function FormsTable({ forms, onOpenForm, onOpenEntries, onOpenSchema, onNotifyToggle, }) {
|
|
120
|
+
return (_jsx("div", { className: "border-border bg-card overflow-x-auto rounded-lg border", children: _jsxs("table", { className: "w-full min-w-[760px] text-sm", "aria-label": "Forms", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-border text-muted-foreground border-b text-left text-xs", children: [_jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Form" }), _jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Fields" }), _jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Status" }), _jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Entries" }), _jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Last Entry" }), _jsx("th", { scope: "col", className: "px-4 py-2.5 text-center font-medium", children: "Notify" }), _jsx("th", { scope: "col", className: "px-4 py-2.5 text-right font-medium", children: _jsx("span", { className: "sr-only", children: "Schema" }) })] }) }), _jsx("tbody", { children: forms.map((form) => {
|
|
121
|
+
const fieldCount = form.fieldCount ?? form.fields.length;
|
|
122
|
+
const unread = form.unreadEntries ?? 0;
|
|
123
|
+
const muted = form.status === 'archived';
|
|
124
|
+
return (_jsxs("tr", { className: `border-border hover:bg-accent/40 border-b transition-colors last:border-b-0 ${muted ? 'opacity-60' : ''}`, children: [_jsx("td", { className: "px-4 py-3", children: _jsxs("button", { type: "button", onClick: () => onOpenForm(form.id), className: "block max-w-xs text-left", children: [_jsx("span", { className: "text-foreground block truncate font-medium hover:underline", children: form.name }), _jsxs("span", { className: "text-muted-foreground block truncate text-xs", children: ["/", form.slug, form.description ? ` · ${form.description}` : ''] })] }) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [form.fields.slice(0, 4).map((field) => (_jsx(FieldTypeBadge, { type: field.type }, field.id))), _jsxs("span", { className: "text-muted-foreground text-xs", children: [fieldCount, " fields"] })] }) }), _jsx("td", { className: "px-4 py-3", children: _jsx(FormStatusBadge, { status: form.status }) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("button", { type: "button", onClick: () => onOpenEntries(form.id), className: "text-foreground hover:text-primary focus-visible:ring-ring inline-flex items-center gap-1.5 rounded font-medium tabular-nums focus-visible:ring-2 focus-visible:outline-none", "aria-label": `View ${form.totalEntries ?? 0} entries for ${form.name}`, children: [form.totalEntries ?? 0, _jsx(UnreadBadge, { count: unread }), _jsx(ChevronRight, { className: "text-muted-foreground h-3.5 w-3.5", "aria-hidden": true })] }) }), _jsx("td", { className: "text-muted-foreground px-4 py-3 whitespace-nowrap", children: formatRelative(form.lastEntryAt) }), _jsx("td", { className: "px-4 py-3 text-center", children: _jsx(Switch.Root, { checked: form.notifyEnabled ?? false, onCheckedChange: (v) => onNotifyToggle(form, v), "aria-label": `Notifications for ${form.name}`, className: "bg-input-background data-[state=checked]:bg-primary focus-visible:ring-ring relative inline-flex h-[18px] w-8 shrink-0 rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none", children: _jsx(Switch.Thumb, { className: "bg-background block h-3.5 w-3.5 translate-x-0.5 rounded-full shadow-sm transition-transform data-[state=checked]:translate-x-[14px]" }) }) }), _jsx("td", { className: "px-4 py-3 text-right", children: _jsxs("button", { type: "button", onClick: () => onOpenSchema(form), className: "border-border text-foreground hover:bg-accent focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none", children: [_jsx(Settings2, { className: "h-3.5 w-3.5", "aria-hidden": true }), "Schema"] }) })] }, form.id));
|
|
125
|
+
}) })] }) }));
|
|
23
126
|
}
|
|
24
127
|
//# sourceMappingURL=Forms.js.map
|
package/dist/views/Forms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Forms.js","sourceRoot":"","sources":["../../src/views/Forms.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Forms.js","sourceRoot":"","sources":["../../src/views/Forms.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuate-media/cms-admin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/actuate-media/actuatecms.git",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"tailwindcss": "^4.0.0",
|
|
88
88
|
"typescript": "^5.7.0",
|
|
89
89
|
"vitest": "^3.0.0",
|
|
90
|
-
"@actuate-media/cms-core": "0.
|
|
90
|
+
"@actuate-media/cms-core": "0.31.0",
|
|
91
91
|
"@actuate-media/component-blocks": "0.2.0"
|
|
92
92
|
},
|
|
93
93
|
"scripts": {
|
package/src/AdminRoot.tsx
CHANGED
|
@@ -702,6 +702,28 @@ const ISOLATION_STYLE: React.CSSProperties = {
|
|
|
702
702
|
export function AdminRoot(props: AdminRootProps) {
|
|
703
703
|
const defaultDarkMode = props.config?.admin?.branding?.darkMode
|
|
704
704
|
|
|
705
|
+
// The admin is private application UI and must never be indexed. Ensure a
|
|
706
|
+
// `noindex, nofollow` robots meta tag is present while the admin is mounted,
|
|
707
|
+
// as defense-in-depth alongside the server `robots.txt` Disallow rule. This
|
|
708
|
+
// covers every consumer install (the admin page is typically a client
|
|
709
|
+
// component that can't export Next.js route metadata).
|
|
710
|
+
useEffect(() => {
|
|
711
|
+
if (typeof document === 'undefined') return
|
|
712
|
+
const PREV = document.querySelector<HTMLMetaElement>('meta[name="robots"]')
|
|
713
|
+
const prevContent = PREV?.getAttribute('content') ?? null
|
|
714
|
+
const meta = PREV ?? document.createElement('meta')
|
|
715
|
+
meta.setAttribute('name', 'robots')
|
|
716
|
+
meta.setAttribute('content', 'noindex, nofollow')
|
|
717
|
+
if (!PREV) document.head.appendChild(meta)
|
|
718
|
+
return () => {
|
|
719
|
+
if (prevContent === null) {
|
|
720
|
+
meta.remove()
|
|
721
|
+
} else {
|
|
722
|
+
meta.setAttribute('content', prevContent)
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}, [])
|
|
726
|
+
|
|
705
727
|
return (
|
|
706
728
|
<div style={ISOLATION_STYLE} className="actuate-admin">
|
|
707
729
|
<ThemeProvider defaultDarkMode={defaultDarkMode}>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { render, screen, waitFor } from '@testing-library/react'
|
|
4
|
+
|
|
5
|
+
// The Forms nav item shows a live unread total summed across active forms.
|
|
6
|
+
// Mock the sidebar-counts fetcher so the badge math is deterministic.
|
|
7
|
+
const fetchFormsSidebarCounts = vi.fn(async () => [
|
|
8
|
+
{ formId: 'f1', name: 'Contact Us', slug: 'contact-us', status: 'active', unread: 8 },
|
|
9
|
+
{ formId: 'f2', name: 'Project Inquiry', slug: 'project-inquiry', status: 'active', unread: 3 },
|
|
10
|
+
])
|
|
11
|
+
|
|
12
|
+
vi.mock('../../lib/forms-service.js', () => ({
|
|
13
|
+
fetchFormsSidebarCounts: () => fetchFormsSidebarCounts(),
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
const { Sidebar } = await import('../../layout/Sidebar.js')
|
|
17
|
+
|
|
18
|
+
describe('Sidebar forms unread badge', () => {
|
|
19
|
+
it('sums unread across active forms onto the Forms item', async () => {
|
|
20
|
+
render(
|
|
21
|
+
<Sidebar
|
|
22
|
+
collapsed={false}
|
|
23
|
+
onToggleCollapse={() => {}}
|
|
24
|
+
currentPath="/"
|
|
25
|
+
onNavigate={() => {}}
|
|
26
|
+
/>,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
// 8 + 3 = 11 unread surfaced as the Forms badge.
|
|
30
|
+
await waitFor(() => expect(screen.getByLabelText('11 unread')).toBeTruthy())
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('renders no badge when there are no unread submissions', async () => {
|
|
34
|
+
fetchFormsSidebarCounts.mockResolvedValueOnce([
|
|
35
|
+
{ formId: 'f1', name: 'Newsletter', slug: 'newsletter', status: 'active', unread: 0 },
|
|
36
|
+
])
|
|
37
|
+
|
|
38
|
+
render(
|
|
39
|
+
<Sidebar
|
|
40
|
+
collapsed={false}
|
|
41
|
+
onToggleCollapse={() => {}}
|
|
42
|
+
currentPath="/"
|
|
43
|
+
onNavigate={() => {}}
|
|
44
|
+
/>,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
await screen.findByText('Forms')
|
|
48
|
+
expect(screen.queryByLabelText(/unread$/)).toBeNull()
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
4
|
+
|
|
5
|
+
// The sidebar fetches forms unread counts on mount for the Forms badge. Stub
|
|
6
|
+
// it so these submenu tests stay offline and deterministic (no real fetch /
|
|
7
|
+
// teardown-abort noise).
|
|
8
|
+
vi.mock('../../lib/forms-service.js', () => ({
|
|
9
|
+
fetchFormsSidebarCounts: vi.fn(async () => []),
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
const { Sidebar } = await import('../../layout/Sidebar.js')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Submenu rendering behaviour:
|
|
16
|
+
* - Expanded: parent children (e.g. Posts -> All Posts / Post Types) render
|
|
17
|
+
* inline beneath the parent.
|
|
18
|
+
* - Collapsed: children are hidden inline and instead revealed in a
|
|
19
|
+
* hover/focus flyout, so the 80px rail stays clean but sub-pages remain
|
|
20
|
+
* reachable.
|
|
21
|
+
*/
|
|
22
|
+
function renderSidebar(collapsed: boolean) {
|
|
23
|
+
return render(
|
|
24
|
+
<Sidebar
|
|
25
|
+
collapsed={collapsed}
|
|
26
|
+
onToggleCollapse={() => {}}
|
|
27
|
+
currentPath="/"
|
|
28
|
+
onNavigate={() => {}}
|
|
29
|
+
/>,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('Sidebar submenus', () => {
|
|
34
|
+
it('renders children inline when expanded', () => {
|
|
35
|
+
renderSidebar(false)
|
|
36
|
+
expect(screen.getByText('All Posts')).toBeTruthy()
|
|
37
|
+
expect(screen.getByText('Post Types')).toBeTruthy()
|
|
38
|
+
expect(screen.getByText('Saved Sections')).toBeTruthy()
|
|
39
|
+
expect(screen.getByText('Widgets')).toBeTruthy()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('collapses and re-expands a parent submenu via the chevron toggle', () => {
|
|
43
|
+
renderSidebar(false)
|
|
44
|
+
|
|
45
|
+
// Children visible by default.
|
|
46
|
+
expect(screen.getByText('All Posts')).toBeTruthy()
|
|
47
|
+
|
|
48
|
+
// Collapse the Posts section.
|
|
49
|
+
fireEvent.click(screen.getByRole('button', { name: 'Collapse Posts' }))
|
|
50
|
+
expect(screen.queryByText('All Posts')).toBeNull()
|
|
51
|
+
|
|
52
|
+
// Re-expand it.
|
|
53
|
+
fireEvent.click(screen.getByRole('button', { name: 'Expand Posts' }))
|
|
54
|
+
expect(screen.getByText('All Posts')).toBeTruthy()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('keeps the active section expanded even when toggled closed', () => {
|
|
58
|
+
render(
|
|
59
|
+
<Sidebar
|
|
60
|
+
collapsed={false}
|
|
61
|
+
onToggleCollapse={() => {}}
|
|
62
|
+
currentPath="/posts"
|
|
63
|
+
onNavigate={() => {}}
|
|
64
|
+
/>,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
// Active section forces the submenu open; the chevron reports it as
|
|
68
|
+
// expanded and offers to collapse.
|
|
69
|
+
expect(screen.getByText('All Posts')).toBeTruthy()
|
|
70
|
+
fireEvent.click(screen.getByRole('button', { name: 'Collapse Posts' }))
|
|
71
|
+
// Still visible because the section is the active route.
|
|
72
|
+
expect(screen.getByText('All Posts')).toBeTruthy()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('hides children inline when collapsed and exposes them in a hover flyout', async () => {
|
|
76
|
+
renderSidebar(true)
|
|
77
|
+
|
|
78
|
+
// Inline children are not rendered in the collapsed rail.
|
|
79
|
+
expect(screen.queryByText('All Posts')).toBeNull()
|
|
80
|
+
expect(screen.queryByText('Post Types')).toBeNull()
|
|
81
|
+
|
|
82
|
+
// The parent is still reachable as an icon button labelled for AT.
|
|
83
|
+
const trigger = screen.getByRole('button', { name: 'Posts' })
|
|
84
|
+
|
|
85
|
+
// Hovering the parent opens the flyout (onMouseEnter lives on the wrapper).
|
|
86
|
+
fireEvent.mouseEnter(trigger.parentElement as HTMLElement)
|
|
87
|
+
|
|
88
|
+
await waitFor(() => {
|
|
89
|
+
expect(screen.getByText('All Posts')).toBeTruthy()
|
|
90
|
+
expect(screen.getByText('Post Types')).toBeTruthy()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
})
|