@actuate-media/cms-admin 0.69.1 → 0.70.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 +13 -0
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +4 -1
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/lib/pages-tree.test.js +40 -1
- package/dist/__tests__/lib/pages-tree.test.js.map +1 -1
- package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts +2 -0
- package/dist/__tests__/views/page-builder-template-seed.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/page-builder-template-seed.render.test.js +48 -0
- package/dist/__tests__/views/page-builder-template-seed.render.test.js.map +1 -0
- package/dist/__tests__/views/page-templates.render.test.js +21 -0
- package/dist/__tests__/views/page-templates.render.test.js.map +1 -1
- package/dist/actuate-admin.css +1 -1
- package/dist/components/TipTapEditor.d.ts.map +1 -1
- package/dist/components/TipTapEditor.js +11 -9
- package/dist/components/TipTapEditor.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/pages-service.d.ts +7 -0
- package/dist/lib/pages-service.d.ts.map +1 -1
- package/dist/lib/pages-service.js +11 -0
- package/dist/lib/pages-service.js.map +1 -1
- package/dist/lib/pages-tree.d.ts +14 -0
- package/dist/lib/pages-tree.d.ts.map +1 -1
- package/dist/lib/pages-tree.js +51 -0
- package/dist/lib/pages-tree.js.map +1 -1
- package/dist/views/FormEditor.js +5 -7
- package/dist/views/FormEditor.js.map +1 -1
- package/dist/views/HiddenLoginNotFound.d.ts +6 -0
- package/dist/views/HiddenLoginNotFound.d.ts.map +1 -1
- package/dist/views/HiddenLoginNotFound.js +6 -0
- package/dist/views/HiddenLoginNotFound.js.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +2 -1
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/PageEditor.d.ts +4 -0
- package/dist/views/PageEditor.d.ts.map +1 -1
- package/dist/views/PageEditor.js +4 -0
- package/dist/views/PageEditor.js.map +1 -1
- package/dist/views/Pages/PagesListView.d.ts.map +1 -1
- package/dist/views/Pages/PagesListView.js +40 -5
- package/dist/views/Pages/PagesListView.js.map +1 -1
- package/dist/views/Pages/PagesTreeTable.d.ts +11 -1
- package/dist/views/Pages/PagesTreeTable.d.ts.map +1 -1
- package/dist/views/Pages/PagesTreeTable.js +40 -9
- package/dist/views/Pages/PagesTreeTable.js.map +1 -1
- package/dist/views/Pages.d.ts +4 -0
- package/dist/views/Pages.d.ts.map +1 -1
- package/dist/views/Pages.js +4 -0
- package/dist/views/Pages.js.map +1 -1
- package/dist/views/Redirects.d.ts +4 -0
- package/dist/views/Redirects.d.ts.map +1 -1
- package/dist/views/Redirects.js +4 -0
- package/dist/views/Redirects.js.map +1 -1
- package/dist/views/ScriptTags.d.ts.map +1 -1
- package/dist/views/ScriptTags.js +2 -1
- package/dist/views/ScriptTags.js.map +1 -1
- package/dist/views/page-builder/PageBuilder.d.ts +3 -1
- package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
- package/dist/views/page-builder/PageBuilder.js +24 -2
- package/dist/views/page-builder/PageBuilder.js.map +1 -1
- package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
- package/dist/views/page-builder/PageTemplates.js +30 -4
- package/dist/views/page-builder/PageTemplates.js.map +1 -1
- package/package.json +1 -1
- package/src/AdminRoot.tsx +11 -1
- package/src/__tests__/lib/pages-tree.test.ts +49 -0
- package/src/__tests__/views/page-builder-template-seed.render.test.tsx +59 -0
- package/src/__tests__/views/page-templates.render.test.tsx +40 -0
- package/src/components/TipTapEditor.tsx +11 -9
- package/src/index.ts +3 -0
- package/src/lib/pages-service.ts +15 -0
- package/src/lib/pages-tree.ts +54 -0
- package/src/views/FormEditor.tsx +10 -10
- package/src/views/HiddenLoginNotFound.tsx +6 -0
- package/src/views/MediaBrowser.tsx +8 -9
- package/src/views/PageEditor.tsx +4 -0
- package/src/views/Pages/PagesListView.tsx +54 -9
- package/src/views/Pages/PagesTreeTable.tsx +203 -111
- package/src/views/Pages.tsx +4 -0
- package/src/views/Redirects.tsx +4 -0
- package/src/views/ScriptTags.tsx +12 -8
- package/src/views/page-builder/PageBuilder.tsx +30 -2
- package/src/views/page-builder/PageTemplates.tsx +56 -15
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
|
-
import { AlertTriangle, Layers, Pencil, RefreshCw, Trash2 } from 'lucide-react';
|
|
4
|
+
import { AlertTriangle, Copy, FilePlus, Layers, Pencil, RefreshCw, Trash2 } from 'lucide-react';
|
|
5
5
|
import { toast } from 'sonner';
|
|
6
6
|
import { cmsApi } from '../../lib/api.js';
|
|
7
7
|
import { useApiData } from '../../lib/useApiData.js';
|
|
@@ -56,17 +56,43 @@ export function PageTemplates({ onNavigate }) {
|
|
|
56
56
|
refetch();
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
async function duplicateTemplate(template) {
|
|
60
|
+
// The list payload carries the full tree, so no extra fetch is needed.
|
|
61
|
+
// Duplicating a built-in is the supported way to customize one (built-ins
|
|
62
|
+
// themselves are locked against edits).
|
|
63
|
+
if (!template.tree) {
|
|
64
|
+
toast.error('Template has no layout to duplicate');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const res = await cmsApi('/page-templates', {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
body: JSON.stringify({
|
|
70
|
+
name: `${template.name ?? 'Untitled template'} (copy)`,
|
|
71
|
+
description: template.description ?? null,
|
|
72
|
+
category: categoryOf(template),
|
|
73
|
+
tree: template.tree,
|
|
74
|
+
thumbnail: template.thumbnail ?? null,
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
if (res.error) {
|
|
78
|
+
toast.error(res.error);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
toast.success('Template duplicated');
|
|
82
|
+
refetch();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return (_jsxs("div", { className: "p-4 pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-[var(--r)] border border-[var(--bdr)] bg-[var(--card)] p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-[var(--muted)]", "aria-hidden": true }), _jsx("span", { className: "flex-1 text-sm text-[var(--txt)]", children: error }), _jsx("button", { type: "button", onClick: refetch, className: "rounded-md border border-[var(--bdr)] px-3 py-1 text-sm text-[var(--txt)] hover:bg-[var(--acc-l)]", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground mb-1", children: "Page Templates" }), _jsxs("p", { className: "text-sm text-[var(--sub)]", children: [templates.length, " saved template", templates.length === 1 ? '' : 's'] })] }), _jsx(Button, { type: "button", variant: "outline", size: "md", onClick: refetch, leftIcon: _jsx(RefreshCw, { size: 16, "aria-hidden": true }), children: "Refresh" })] }), !loading && templates.length > 0 && (_jsxs("div", { className: "mb-4 flex flex-wrap items-center gap-2", children: [_jsx("div", { className: "max-w-xs min-w-52 flex-1", children: _jsx(SearchInput, { value: search, onChange: setSearch, placeholder: "Search templates\u2026" }) }), _jsxs("div", { className: "flex gap-1.5", role: "group", "aria-label": "Filter templates by category", children: [_jsx(FilterPill, { active: category === 'all', onClick: () => setCategory('all'), children: "All" }), Object.keys(CATEGORIES).map((cat) => (_jsx(FilterPill, { active: category === cat, onClick: () => setCategory(cat), children: CATEGORIES[cat].label }, cat)))] }), _jsxs("span", { className: "ml-auto text-[12.5px] whitespace-nowrap text-[var(--muted)]", children: [filtered.length, " of ", templates.length] })] })), loading ? (_jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3", role: "status", "aria-live": "polite", "aria-label": "Loading page templates", children: Array.from({ length: 6 }, (_, i) => (_jsx(Skeleton, { variant: "card" }, i))) })) : templates.length === 0 ? (_jsx(EmptyState, { icon: _jsx(Layers, { size: 24, "aria-hidden": true }), title: "No page templates yet", description: "Built-in templates are seeded by the CMS when the templates API is available.", actionLabel: "View Saved Sections", onAction: () => onNavigate?.('/saved-sections') })) : filtered.length === 0 ? (_jsx("p", { className: "py-12 text-center text-sm text-[var(--muted)]", children: "No templates match your search." })) : (_jsx("ul", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3", "aria-label": "Page templates", children: filtered.map((template) => (_jsx(TemplateCard, { template: template, onUse: () => onNavigate?.(`/page-builder/new?template=${template.id}`), onDuplicate: () => void duplicateTemplate(template), onEdit: () => setEditTarget(template), onDelete: () => setDeleteTarget(template) }, template.id))) })), _jsx(TemplateEditModal, { template: editTarget, onClose: () => setEditTarget(null), onSaved: () => {
|
|
60
86
|
setEditTarget(null);
|
|
61
87
|
refetch();
|
|
62
88
|
} }), _jsx(ConfirmDialog, { open: deleteTarget !== null, onClose: () => setDeleteTarget(null), onConfirm: () => void confirmDelete(), title: "Delete template?", description: `"${deleteTarget?.name ?? 'This template'}" will be permanently removed. Pages already created from it are not affected.`, confirmLabel: "Delete", destructive: true })] }));
|
|
63
89
|
}
|
|
64
|
-
function TemplateCard({ template, onEdit, onDelete, }) {
|
|
90
|
+
function TemplateCard({ template, onUse, onDuplicate, onEdit, onDelete, }) {
|
|
65
91
|
const cat = CATEGORIES[categoryOf(template)];
|
|
66
92
|
const sections = sectionCountOf(template);
|
|
67
93
|
const name = template.name ?? 'Untitled template';
|
|
68
94
|
const updated = template.updatedAt ? new Date(template.updatedAt).toLocaleDateString() : null;
|
|
69
|
-
return (_jsxs("li", { className: "group relative flex flex-col overflow-hidden rounded-[var(--r)] border border-[var(--bdr)] bg-[var(--card)] shadow-[var(--shd)] transition-[border-color,box-shadow,transform] duration-[var(--motion-fast)] focus-within:border-[var(--acc-m)] focus-within:shadow-[var(--shd2)] hover:-translate-y-0.5 hover:border-[var(--acc-m)] hover:shadow-[var(--shd2)] motion-reduce:hover:translate-y-0", children: [_jsx(TemplatePreview, { template: template, sections: sections }), _jsxs("div", { className: "flex flex-1 flex-col p-4 pb-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsx("h2", { className: "text-[15px] leading-snug font-medium text-[var(--txt)]", children: name }), template.builtIn && (_jsx("span", { className: "shrink-0 rounded-full border border-[var(--bdr)] bg-[var(--bg)] px-2 py-0.5 text-[10.5px] font-medium whitespace-nowrap text-[var(--sub)]", children: "Built-in" }))] }), _jsx("p", { className: "mt-2 min-h-10 text-[12.5px] leading-relaxed text-[var(--sub)]", children: template.description ?? 'No description provided.' }), _jsxs("div", { className: "relative mt-3 flex h-[46px] items-center justify-between border-t border-[var(--bdr)] py-2.5", children: [_jsxs("span", { className: `inline-flex items-center gap-1.5 text-[11.5px] font-medium ${cat.text}`, children: [_jsx("span", { "aria-hidden": true, className: `h-[7px] w-[7px] shrink-0 rounded-full ${cat.dot}` }), cat.label] }), _jsxs("span", { className: "text-[11.5px] text-[var(--muted)] transition-opacity duration-[var(--motion-fast)] group-focus-within:opacity-0 group-hover:opacity-0", children: [sections, " section", sections === 1 ? '' : 's', updated ? ` · ${updated}` : ''] }),
|
|
95
|
+
return (_jsxs("li", { className: "group relative flex flex-col overflow-hidden rounded-[var(--r)] border border-[var(--bdr)] bg-[var(--card)] shadow-[var(--shd)] transition-[border-color,box-shadow,transform] duration-[var(--motion-fast)] focus-within:border-[var(--acc-m)] focus-within:shadow-[var(--shd2)] hover:-translate-y-0.5 hover:border-[var(--acc-m)] hover:shadow-[var(--shd2)] motion-reduce:hover:translate-y-0", children: [_jsx(TemplatePreview, { template: template, sections: sections }), _jsxs("div", { className: "flex flex-1 flex-col p-4 pb-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsx("h2", { className: "text-[15px] leading-snug font-medium text-[var(--txt)]", children: name }), template.builtIn && (_jsx("span", { className: "shrink-0 rounded-full border border-[var(--bdr)] bg-[var(--bg)] px-2 py-0.5 text-[10.5px] font-medium whitespace-nowrap text-[var(--sub)]", children: "Built-in" }))] }), _jsx("p", { className: "mt-2 min-h-10 text-[12.5px] leading-relaxed text-[var(--sub)]", children: template.description ?? 'No description provided.' }), _jsxs("div", { className: "relative mt-3 flex h-[46px] items-center justify-between border-t border-[var(--bdr)] py-2.5", children: [_jsxs("span", { className: `inline-flex items-center gap-1.5 text-[11.5px] font-medium ${cat.text}`, children: [_jsx("span", { "aria-hidden": true, className: `h-[7px] w-[7px] shrink-0 rounded-full ${cat.dot}` }), cat.label] }), _jsxs("span", { className: "text-[11.5px] text-[var(--muted)] transition-opacity duration-[var(--motion-fast)] group-focus-within:opacity-0 group-hover:opacity-0", children: [sections, " section", sections === 1 ? '' : 's', updated ? ` · ${updated}` : ''] }), _jsxs(RowActions, { className: "absolute top-1/2 right-0 -translate-y-1/2", children: [_jsx(RowActionButton, { "aria-label": `Create page from ${name}`, onClick: onUse, children: _jsx(FilePlus, { size: 14, "aria-hidden": true }) }), _jsx(RowActionButton, { "aria-label": `Duplicate ${name}`, onClick: onDuplicate, children: _jsx(Copy, { size: 14, "aria-hidden": true }) }), !template.builtIn && (_jsxs(_Fragment, { children: [_jsx(RowActionButton, { "aria-label": `Edit ${name}`, onClick: onEdit, children: _jsx(Pencil, { size: 14, "aria-hidden": true }) }), _jsx(RowActionButton, { "aria-label": `Delete ${name}`, danger: true, onClick: onDelete, children: _jsx(Trash2, { size: 14, "aria-hidden": true }) })] }))] })] })] })] }));
|
|
70
96
|
}
|
|
71
97
|
/**
|
|
72
98
|
* Card preview area. Uses the stored thumbnail when one exists; otherwise
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageTemplates.js","sourceRoot":"","sources":["../../../src/views/page-builder/PageTemplates.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PageTemplates.js","sourceRoot":"","sources":["../../../src/views/page-builder/PageTemplates.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC/F,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAA;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAe1D,MAAM,UAAU,GAAqE;IACnF,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,mBAAmB,EAAE;IAChF,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,mBAAmB,EAAE;IAChF,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,oBAAoB,EAAE;CACnF,CAAA;AAED,SAAS,UAAU,CAAC,QAAsB;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAA;IAC7B,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AACjE,CAAC;AAED,SAAS,cAAc,CAAC,QAAsB;IAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;AACnF,CAAC;AAMD,MAAM,UAAU,aAAa,CAAC,EAAE,UAAU,EAAsB;IAC9D,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,UAAU,CAAiB,iBAAiB,CAAC,CAAA;IACvF,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEnD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACxC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAqB,KAAK,CAAC,CAAA;IACnE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAA;IACvE,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAA;IAE3E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE;QAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACrC,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YAC5B,MAAM,YAAY,GAChB,CAAC,CAAC;gBACF,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACxC,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACjD,MAAM,eAAe,GAAG,QAAQ,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAA;YACxE,OAAO,YAAY,IAAI,eAAe,CAAA;QACxC,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEjC,KAAK,UAAU,aAAa;QAC1B,IAAI,CAAC,YAAY;YAAE,OAAM;QACzB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,mBAAmB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACpF,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;YACjC,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,UAAU,iBAAiB,CAAC,QAAsB;QACrD,uEAAuE;QACvE,0EAA0E;QAC1E,wCAAwC;QACxC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAA;YAClD,OAAM;QACR,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,GAAG,QAAQ,CAAC,IAAI,IAAI,mBAAmB,SAAS;gBACtD,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,IAAI;gBACzC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC;gBAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,IAAI;aACtC,CAAC;SACH,CAAC,CAAA;QACF,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;YACpC,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,UAAU,aACtB,KAAK,IAAI,CACR,eAAK,SAAS,EAAC,iGAAiG,aAC9G,KAAC,aAAa,IAAC,SAAS,EAAC,sCAAsC,wBAAe,EAC9E,eAAM,SAAS,EAAC,kCAAkC,YAAE,KAAK,GAAQ,EACjE,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,mGAAmG,sBAGtG,IACL,CACP,EAED,eAAK,SAAS,EAAC,8CAA8C,aAC3D,0BACE,aAAI,SAAS,EAAC,sBAAsB,+BAAoB,EACxD,aAAG,SAAS,EAAC,2BAA2B,aACrC,SAAS,CAAC,MAAM,qBAAiB,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IACjE,IACA,EACN,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,wBAAgB,wBAGtC,IACL,EAEL,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CACnC,eAAK,SAAS,EAAC,wCAAwC,aACrD,cAAK,SAAS,EAAC,0BAA0B,YACvC,KAAC,WAAW,IAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAC,wBAAmB,GAAG,GAC/E,EACN,eAAK,SAAS,EAAC,cAAc,EAAC,IAAI,EAAC,OAAO,gBAAY,8BAA8B,aAClF,KAAC,UAAU,IAAC,MAAM,EAAE,QAAQ,KAAK,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,oBAE5D,EACX,MAAM,CAAC,IAAI,CAAC,UAAU,CAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACtD,KAAC,UAAU,IAAW,MAAM,EAAE,QAAQ,KAAK,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,YAC5E,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,IADP,GAAG,CAEP,CACd,CAAC,IACE,EACN,gBAAM,SAAS,EAAC,6DAA6D,aAC1E,QAAQ,CAAC,MAAM,UAAM,SAAS,CAAC,MAAM,IACjC,IACH,CACP,EAEA,OAAO,CAAC,CAAC,CAAC,CACT,cACE,SAAS,EAAC,sDAAsD,EAChE,IAAI,EAAC,QAAQ,eACH,QAAQ,gBACP,wBAAwB,YAElC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACnC,KAAC,QAAQ,IAAS,OAAO,EAAC,MAAM,IAAjB,CAAC,CAAmB,CACpC,CAAC,GACE,CACP,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC3B,KAAC,UAAU,IACT,IAAI,EAAE,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,wBAAgB,EACtC,KAAK,EAAC,uBAAuB,EAC7B,WAAW,EAAC,+EAA+E,EAC3F,WAAW,EAAC,qBAAqB,EACjC,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,iBAAiB,CAAC,GAC/C,CACH,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1B,YAAG,SAAS,EAAC,+CAA+C,gDAExD,CACL,CAAC,CAAC,CAAC,CACF,aACE,SAAS,EAAC,sDAAsD,gBACrD,gBAAgB,YAE1B,QAAQ,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAC1B,KAAC,YAAY,IAEX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,8BAA8B,QAAQ,CAAC,EAAE,EAAE,CAAC,EACtE,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,iBAAiB,CAAC,QAAQ,CAAC,EACnD,MAAM,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,EACrC,QAAQ,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,IALpC,QAAQ,CAAC,EAAE,CAMhB,CACH,CAAC,GACC,CACN,EAED,KAAC,iBAAiB,IAChB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAClC,OAAO,EAAE,GAAG,EAAE;oBACZ,aAAa,CAAC,IAAI,CAAC,CAAA;oBACnB,OAAO,EAAE,CAAA;gBACX,CAAC,GACD,EAEF,KAAC,aAAa,IACZ,IAAI,EAAE,YAAY,KAAK,IAAI,EAC3B,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,EACpC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,aAAa,EAAE,EACrC,KAAK,EAAC,kBAAkB,EACxB,WAAW,EAAE,IAAI,YAAY,EAAE,IAAI,IAAI,eAAe,gFAAgF,EACtI,YAAY,EAAC,QAAQ,EACrB,WAAW,SACX,IACE,CACP,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,QAAQ,EACR,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAQ,GAOT;IACC,MAAM,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,mBAAmB,CAAA;IACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAE7F,OAAO,CACL,cAAI,SAAS,EAAC,mYAAmY,aAC/Y,KAAC,eAAe,IAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAI,EAE3D,eAAK,SAAS,EAAC,+BAA+B,aAC5C,eAAK,SAAS,EAAC,wCAAwC,aACrD,aAAI,SAAS,EAAC,wDAAwD,YAAE,IAAI,GAAM,EACjF,QAAQ,CAAC,OAAO,IAAI,CACnB,eAAM,SAAS,EAAC,2IAA2I,yBAEpJ,CACR,IACG,EACN,YAAG,SAAS,EAAC,+DAA+D,YACzE,QAAQ,CAAC,WAAW,IAAI,0BAA0B,GACjD,EAEJ,eAAK,SAAS,EAAC,8FAA8F,aAC3G,gBACE,SAAS,EAAE,8DAA8D,GAAG,CAAC,IAAI,EAAE,aAEnF,oCAAkB,SAAS,EAAE,yCAAyC,GAAG,CAAC,GAAG,EAAE,GAAI,EAClF,GAAG,CAAC,KAAK,IACL,EACP,gBAAM,SAAS,EAAC,uIAAuI,aACpJ,QAAQ,cAAU,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAC3C,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAC1B,EACP,MAAC,UAAU,IAAC,SAAS,EAAC,2CAA2C,aAC/D,KAAC,eAAe,kBAAa,oBAAoB,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,YACrE,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,wBAAgB,GAClB,EAClB,KAAC,eAAe,kBAAa,aAAa,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,YACpE,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,wBAAgB,GACd,EACjB,CAAC,QAAQ,CAAC,OAAO,IAAI,CACpB,8BACE,KAAC,eAAe,kBAAa,QAAQ,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,YAC1D,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,wBAAgB,GAChB,EAClB,KAAC,eAAe,kBAAa,UAAU,IAAI,EAAE,EAAE,MAAM,QAAC,OAAO,EAAE,QAAQ,YACrE,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,wBAAgB,GAChB,IACjB,CACJ,IACU,IACT,IACF,IACH,CACN,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAgD;IAC3F,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACvB,OAAO,CACL,cAAK,SAAS,EAAC,2EAA2E,YACxF,cACE,GAAG,EAAE,QAAQ,CAAC,SAAS,EACvB,GAAG,EAAE,cAAc,QAAQ,CAAC,IAAI,IAAI,UAAU,EAAE,EAChD,SAAS,EAAC,4BAA4B,GACtC,GACE,CACP,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACnD,OAAO,CACL,oCAEE,SAAS,EAAC,qFAAqF,aAE/F,cAAK,SAAS,EAAC,qCAAqC,GAAG,EACtD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACtC,cAEE,SAAS,EAAC,qCAAqC,EAC/C,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,IAF9B,CAAC,CAGN,CACH,CAAC,IACE,CACP,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,EACzB,QAAQ,EACR,OAAO,EACP,OAAO,GAKR;IACC,0EAA0E;IAC1E,uDAAuD;IACvD,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IAC1B,OAAO,CACL,KAAC,gBAAgB,IAAmB,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAnE,QAAQ,CAAC,EAAE,CAA4D,CAC/F,CAAA;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,QAAQ,EACR,OAAO,EACP,OAAO,GAKR;IACC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IACrD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAA;IAC1E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAa,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC1E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,KAAK,UAAU,UAAU;QACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,mBAAmB,QAAQ,CAAC,EAAE,EAAE,EAAE;YACzD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;gBACjB,WAAW,EAAE,WAAW,CAAC,IAAI,EAAE,IAAI,IAAI;gBACvC,QAAQ;aACT,CAAC;SACH,CAAC,CAAA;QACF,SAAS,CAAC,KAAK,CAAC,CAAA;QAChB,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;YACjC,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED,OAAO,CACL,KAAC,KAAK,IACJ,IAAI,QACJ,OAAO,EAAE,OAAO,EAChB,KAAK,EAAC,eAAe,EACrB,OAAO,EACL,8BACE,KAAC,MAAM,IAAC,OAAO,EAAC,OAAO,EAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAEjD,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,6BAElE,IACR,YAGL,eAAK,SAAS,EAAC,qBAAqB,aAClC,iBAAO,SAAS,EAAC,uBAAuB,aACtC,eAAM,SAAS,EAAC,uCAAuC,qBAAY,EACnE,KAAC,KAAK,IACJ,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACxC,WAAW,EAAC,eAAe,GAC3B,IACI,EACR,iBAAO,SAAS,EAAC,uBAAuB,aACtC,eAAM,SAAS,EAAC,uCAAuC,4BAAmB,EAC1E,mBACE,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC/C,IAAI,EAAE,CAAC,EACP,WAAW,EAAC,iCAA4B,EACxC,SAAS,EAAC,yPAAyP,GACnQ,IACI,EACR,iBAAO,SAAS,EAAC,uBAAuB,aACtC,eAAM,SAAS,EAAC,uCAAuC,yBAAgB,EACvE,KAAC,MAAM,IAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,KAAmB,CAAC,YAC/E,MAAM,CAAC,IAAI,CAAC,UAAU,CAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACtD,iBAAkB,KAAK,EAAE,GAAG,YACzB,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,IADX,GAAG,CAEP,CACV,CAAC,GACK,IACH,IACJ,GACA,CACT,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
package/src/AdminRoot.tsx
CHANGED
|
@@ -627,7 +627,17 @@ function AdminShell({
|
|
|
627
627
|
// declared as `type: 'page'` through the Page Builder by default.
|
|
628
628
|
const pageBuilderNew = matchRoute('/page-builder/new')
|
|
629
629
|
if (pageBuilderNew) {
|
|
630
|
-
|
|
630
|
+
// "Use template" on the Templates grid seeds the new page from a
|
|
631
|
+
// saved template (`/page-builder/new?template=<id>`).
|
|
632
|
+
const builderQuery = parseRouteQuery(currentPath)
|
|
633
|
+
return (
|
|
634
|
+
<PageBuilder
|
|
635
|
+
templateId={builderQuery.get('template') ?? undefined}
|
|
636
|
+
collectionSlug="pages"
|
|
637
|
+
config={config}
|
|
638
|
+
onNavigate={navigate}
|
|
639
|
+
/>
|
|
640
|
+
)
|
|
631
641
|
}
|
|
632
642
|
|
|
633
643
|
const pageBuilderEdit = matchRoute('/page-builder/:id')
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import {
|
|
3
3
|
buildPageTree,
|
|
4
|
+
checkReparent,
|
|
5
|
+
collectDescendantIds,
|
|
4
6
|
defaultExpandedIds,
|
|
5
7
|
flattenPageTree,
|
|
6
8
|
type PageTreeNode,
|
|
@@ -195,3 +197,50 @@ describe('defaultExpandedIds', () => {
|
|
|
195
197
|
expect([...defaultExpandedIds(roots)]).toEqual(['about'])
|
|
196
198
|
})
|
|
197
199
|
})
|
|
200
|
+
|
|
201
|
+
describe('collectDescendantIds', () => {
|
|
202
|
+
it('returns every id in the subtree, excluding the page itself', () => {
|
|
203
|
+
const roots = buildPageTree([
|
|
204
|
+
page({ id: 'about', title: 'About Us', path: '/about' }),
|
|
205
|
+
page({ id: 'team', title: 'Our Team', path: '/about/team' }),
|
|
206
|
+
page({ id: 'deep', title: 'Deep', path: '/about/team/deep' }),
|
|
207
|
+
page({ id: 'blog', title: 'Blog', path: '/blog' }),
|
|
208
|
+
])
|
|
209
|
+
expect([...collectDescendantIds(roots, 'about')].sort()).toEqual(['deep', 'team'])
|
|
210
|
+
expect([...collectDescendantIds(roots, 'blog')]).toEqual([])
|
|
211
|
+
expect([...collectDescendantIds(roots, 'missing')]).toEqual([])
|
|
212
|
+
})
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
describe('checkReparent', () => {
|
|
216
|
+
const roots = () =>
|
|
217
|
+
buildPageTree([
|
|
218
|
+
page({ id: 'about', title: 'About Us', path: '/about' }),
|
|
219
|
+
page({ id: 'team', title: 'Our Team', path: '/about/team' }),
|
|
220
|
+
page({ id: 'deep', title: 'Deep', path: '/about/team/deep' }),
|
|
221
|
+
page({ id: 'blog', title: 'Blog', path: '/blog' }),
|
|
222
|
+
])
|
|
223
|
+
|
|
224
|
+
it('allows moving a page under an unrelated page', () => {
|
|
225
|
+
expect(checkReparent(roots(), 'blog', 'team')).toEqual({ ok: true })
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
it('allows moving a subtree up to an ancestor that is not its parent', () => {
|
|
229
|
+
// deep currently sits under team; moving it directly under about is legal.
|
|
230
|
+
expect(checkReparent(roots(), 'deep', 'about')).toEqual({ ok: true })
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('rejects self-drops', () => {
|
|
234
|
+
expect(checkReparent(roots(), 'about', 'about').ok).toBe(false)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('rejects drops into the page own subtree (cycle)', () => {
|
|
238
|
+
expect(checkReparent(roots(), 'about', 'team').ok).toBe(false)
|
|
239
|
+
expect(checkReparent(roots(), 'about', 'deep').ok).toBe(false)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
it('rejects no-op moves onto the current parent', () => {
|
|
243
|
+
expect(checkReparent(roots(), 'team', 'about').ok).toBe(false)
|
|
244
|
+
expect(checkReparent(roots(), 'deep', 'team').ok).toBe(false)
|
|
245
|
+
})
|
|
246
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest'
|
|
3
|
+
import { cleanup, render, screen, waitFor } from '@testing-library/react'
|
|
4
|
+
|
|
5
|
+
const cmsApi = vi.fn()
|
|
6
|
+
vi.mock('../../lib/api.js', () => ({ cmsApi: (...args: unknown[]) => cmsApi(...args) }))
|
|
7
|
+
vi.mock('sonner', () => ({
|
|
8
|
+
toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() },
|
|
9
|
+
Toaster: () => null,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
const { PageBuilder } = await import('../../views/page-builder/PageBuilder.js')
|
|
13
|
+
|
|
14
|
+
const TEMPLATE_TREE = {
|
|
15
|
+
id: 'tpl-page',
|
|
16
|
+
type: 'page',
|
|
17
|
+
children: [
|
|
18
|
+
{
|
|
19
|
+
id: 'sec1',
|
|
20
|
+
type: 'section',
|
|
21
|
+
settings: { label: 'Hero From Template' },
|
|
22
|
+
children: [],
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
cmsApi.mockReset()
|
|
29
|
+
cmsApi.mockImplementation(async (endpoint: string) => {
|
|
30
|
+
if (endpoint === '/page-templates/tpl-1') {
|
|
31
|
+
return { data: { id: 'tpl-1', name: 'Landing', tree: TEMPLATE_TREE }, status: 200 }
|
|
32
|
+
}
|
|
33
|
+
return { data: {}, status: 200 }
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterEach(cleanup)
|
|
38
|
+
|
|
39
|
+
describe('PageBuilder template seeding (/page-builder/new?template=)', () => {
|
|
40
|
+
it('fetches the template and seeds the canvas tree for a new page', async () => {
|
|
41
|
+
render(
|
|
42
|
+
<PageBuilder templateId="tpl-1" collectionSlug="pages" config={{}} onNavigate={() => {}} />,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/page-templates/tpl-1'))
|
|
46
|
+
// replaceTree marks the builder dirty — the unsaved-changes dot is the
|
|
47
|
+
// observable proof the template tree was seeded into the canvas state.
|
|
48
|
+
expect(await screen.findByTitle('Unsaved changes')).toBeTruthy()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('starts from a blank, clean tree when no template id is given', async () => {
|
|
52
|
+
render(<PageBuilder collectionSlug="pages" config={{}} onNavigate={() => {}} />)
|
|
53
|
+
|
|
54
|
+
await waitFor(() =>
|
|
55
|
+
expect(cmsApi).not.toHaveBeenCalledWith(expect.stringContaining('/page-templates/')),
|
|
56
|
+
)
|
|
57
|
+
expect(screen.queryByTitle('Unsaved changes')).toBeNull()
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -119,6 +119,46 @@ describe('PageTemplates card grid', () => {
|
|
|
119
119
|
})
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
+
it('routes "Use template" into the builder with the template id', async () => {
|
|
123
|
+
const onNavigate = vi.fn()
|
|
124
|
+
render(<PageTemplates onNavigate={onNavigate} />)
|
|
125
|
+
await screen.findByText('Landing Page')
|
|
126
|
+
|
|
127
|
+
fireEvent.click(screen.getByRole('button', { name: 'Create page from Landing Page' }))
|
|
128
|
+
|
|
129
|
+
expect(onNavigate).toHaveBeenCalledWith('/page-builder/new?template=builtin-landing')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('duplicates a template (built-ins included) via POST with a "(copy)" name', async () => {
|
|
133
|
+
render(<PageTemplates onNavigate={() => {}} />)
|
|
134
|
+
await screen.findByText('Landing Page')
|
|
135
|
+
|
|
136
|
+
fireEvent.click(screen.getByRole('button', { name: 'Duplicate Landing Page' }))
|
|
137
|
+
|
|
138
|
+
await waitFor(() =>
|
|
139
|
+
expect(cmsApi).toHaveBeenCalledWith(
|
|
140
|
+
'/page-templates',
|
|
141
|
+
expect.objectContaining({ method: 'POST' }),
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
const postCall = cmsApi.mock.calls.find(
|
|
145
|
+
(c) => (c[1] as RequestInit | undefined)?.method === 'POST',
|
|
146
|
+
)!
|
|
147
|
+
expect(JSON.parse((postCall[1] as RequestInit).body as string)).toMatchObject({
|
|
148
|
+
name: 'Landing Page (copy)',
|
|
149
|
+
category: 'landing',
|
|
150
|
+
tree: TEMPLATES[0]!.tree,
|
|
151
|
+
})
|
|
152
|
+
// The grid refetches so the copy appears.
|
|
153
|
+
await waitFor(() =>
|
|
154
|
+
expect(
|
|
155
|
+
cmsApi.mock.calls.filter(
|
|
156
|
+
(c) => c[0] === '/page-templates' && !(c[1] as RequestInit | undefined)?.method,
|
|
157
|
+
).length,
|
|
158
|
+
).toBeGreaterThanOrEqual(2),
|
|
159
|
+
)
|
|
160
|
+
})
|
|
161
|
+
|
|
122
162
|
it('filters cards by search text', async () => {
|
|
123
163
|
render(<PageTemplates onNavigate={() => {}} />)
|
|
124
164
|
await screen.findByText('Team Member')
|
|
@@ -155,13 +155,13 @@ const editorStyles = `
|
|
|
155
155
|
}
|
|
156
156
|
.ProseMirror th,
|
|
157
157
|
.ProseMirror td {
|
|
158
|
-
border: 1px solid
|
|
158
|
+
border: 1px solid var(--bdr);
|
|
159
159
|
padding: 0.5rem;
|
|
160
160
|
text-align: left;
|
|
161
161
|
min-width: 80px;
|
|
162
162
|
}
|
|
163
163
|
.ProseMirror th {
|
|
164
|
-
background-color:
|
|
164
|
+
background-color: var(--surface-muted);
|
|
165
165
|
font-weight: 600;
|
|
166
166
|
}
|
|
167
167
|
.ProseMirror img {
|
|
@@ -170,11 +170,13 @@ const editorStyles = `
|
|
|
170
170
|
border-radius: 0.375rem;
|
|
171
171
|
}
|
|
172
172
|
.ProseMirror blockquote {
|
|
173
|
-
border-left: 3px solid
|
|
173
|
+
border-left: 3px solid var(--acc);
|
|
174
174
|
padding-left: 1rem;
|
|
175
175
|
margin: 1rem 0;
|
|
176
|
-
color:
|
|
176
|
+
color: var(--sub);
|
|
177
177
|
}
|
|
178
|
+
/* Code blocks use a fixed dark slate theme in both light and dark modes
|
|
179
|
+
(standard "dark editor chrome" convention; no theme token maps to it). */
|
|
178
180
|
.ProseMirror pre {
|
|
179
181
|
background: #1e293b;
|
|
180
182
|
color: #e2e8f0;
|
|
@@ -184,7 +186,7 @@ const editorStyles = `
|
|
|
184
186
|
margin: 0.75rem 0;
|
|
185
187
|
}
|
|
186
188
|
.ProseMirror code {
|
|
187
|
-
background:
|
|
189
|
+
background: var(--surface-muted);
|
|
188
190
|
padding: 0.125rem 0.375rem;
|
|
189
191
|
border-radius: 0.25rem;
|
|
190
192
|
font-size: 0.875em;
|
|
@@ -197,18 +199,18 @@ const editorStyles = `
|
|
|
197
199
|
}
|
|
198
200
|
.ProseMirror hr {
|
|
199
201
|
border: none;
|
|
200
|
-
border-top: 2px solid
|
|
202
|
+
border-top: 2px solid var(--bdr);
|
|
201
203
|
margin: 1.5rem 0;
|
|
202
204
|
}
|
|
203
205
|
.ProseMirror p.is-editor-empty:first-child::before {
|
|
204
206
|
content: attr(data-placeholder);
|
|
205
207
|
float: left;
|
|
206
|
-
color:
|
|
208
|
+
color: var(--muted);
|
|
207
209
|
pointer-events: none;
|
|
208
210
|
height: 0;
|
|
209
211
|
}
|
|
210
212
|
.ProseMirror .selectedCell {
|
|
211
|
-
background-color:
|
|
213
|
+
background-color: var(--acc-l);
|
|
212
214
|
}
|
|
213
215
|
`
|
|
214
216
|
|
|
@@ -659,7 +661,7 @@ export function TipTapEditor({
|
|
|
659
661
|
className={`border-border bg-card flex-1 overflow-hidden rounded-lg border ${className ?? ''}`}
|
|
660
662
|
>
|
|
661
663
|
{collaboration && awareness && (
|
|
662
|
-
<div className="bg-card flex items-center justify-between gap-2 border-b
|
|
664
|
+
<div className="bg-card border-border flex items-center justify-between gap-2 border-b px-2 py-1.5">
|
|
663
665
|
<PresenceChips awareness={awareness} status={collabStatus} />
|
|
664
666
|
<OfflineStatus connection={collabStatus} offline={offlineStatus} />
|
|
665
667
|
</div>
|
package/src/index.ts
CHANGED
|
@@ -50,13 +50,16 @@ export type {
|
|
|
50
50
|
} from './layout/primitives/index.js'
|
|
51
51
|
|
|
52
52
|
export { Dashboard } from './views/Dashboard.js'
|
|
53
|
+
/** @deprecated Superseded by `PagesListView` routing in `AdminRoot`; will be removed in the next major. */
|
|
53
54
|
export { Pages } from './views/Pages.js'
|
|
55
|
+
/** @deprecated Superseded by the visual page builder (`PageBuilder`); will be removed in the next major. */
|
|
54
56
|
export { PageEditor } from './views/PageEditor.js'
|
|
55
57
|
export { MediaBrowser } from './views/MediaBrowser.js'
|
|
56
58
|
export { Forms } from './views/Forms.js'
|
|
57
59
|
export { FormEditor } from './views/FormEditor.js'
|
|
58
60
|
export type { FormEditorProps } from './views/FormEditor.js'
|
|
59
61
|
export { FormSubmissions } from './views/FormSubmissions.js'
|
|
62
|
+
/** @deprecated Superseded by the Redirects tab inside the `SEO` view; will be removed in the next major. */
|
|
60
63
|
export { Redirects } from './views/Redirects.js'
|
|
61
64
|
export { Users } from './views/Users.js'
|
|
62
65
|
export { Settings } from './views/Settings.js'
|
package/src/lib/pages-service.ts
CHANGED
|
@@ -520,6 +520,21 @@ export async function duplicatePage(id: string): Promise<{ id?: string; error?:
|
|
|
520
520
|
return { id: res.data?.id }
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Reparent a page in the tree. `parentPageId: null` makes it top-level.
|
|
525
|
+
* Document updates merge `data`, so only the parent link changes.
|
|
526
|
+
*/
|
|
527
|
+
export async function movePage(
|
|
528
|
+
id: string,
|
|
529
|
+
parentPageId: string | null,
|
|
530
|
+
): Promise<{ error?: string }> {
|
|
531
|
+
const res = await cmsApi(`/collections/${PAGES_COLLECTION}/${encodeURIComponent(id)}`, {
|
|
532
|
+
method: 'PUT',
|
|
533
|
+
body: JSON.stringify({ data: { parentPageId } }),
|
|
534
|
+
})
|
|
535
|
+
return res.error ? { error: res.error } : {}
|
|
536
|
+
}
|
|
537
|
+
|
|
523
538
|
/** Soft-delete a single page. */
|
|
524
539
|
export async function deletePage(id: string): Promise<{ error?: string }> {
|
|
525
540
|
const res = await cmsApi(`/collections/${PAGES_COLLECTION}/${encodeURIComponent(id)}`, {
|
package/src/lib/pages-tree.ts
CHANGED
|
@@ -143,3 +143,57 @@ export function flattenPageTree(nodes: PageTreeNode[], expanded: Set<string>): P
|
|
|
143
143
|
export function defaultExpandedIds(roots: PageTreeNode[]): Set<string> {
|
|
144
144
|
return new Set(roots.filter((n) => n.children.length > 0).map((n) => n.page.id))
|
|
145
145
|
}
|
|
146
|
+
|
|
147
|
+
/** Ids of every page in `id`'s subtree (excluding `id` itself). */
|
|
148
|
+
export function collectDescendantIds(roots: PageTreeNode[], id: string): Set<string> {
|
|
149
|
+
const out = new Set<string>()
|
|
150
|
+
const collect = (node: PageTreeNode) => {
|
|
151
|
+
for (const child of node.children) {
|
|
152
|
+
out.add(child.page.id)
|
|
153
|
+
collect(child)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const find = (nodes: PageTreeNode[]): PageTreeNode | undefined => {
|
|
157
|
+
for (const n of nodes) {
|
|
158
|
+
if (n.page.id === id) return n
|
|
159
|
+
const hit = find(n.children)
|
|
160
|
+
if (hit) return hit
|
|
161
|
+
}
|
|
162
|
+
return undefined
|
|
163
|
+
}
|
|
164
|
+
const node = find(roots)
|
|
165
|
+
if (node) collect(node)
|
|
166
|
+
return out
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export type ReparentCheck = { ok: true } | { ok: false; reason: string }
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Validate a drag-reparent: `sourceId` becomes a child of `targetId`
|
|
173
|
+
* (or a root when `targetId` is null). Rejects self-drops, drops into the
|
|
174
|
+
* page's own subtree (would create a cycle), and no-op moves.
|
|
175
|
+
*/
|
|
176
|
+
export function checkReparent(
|
|
177
|
+
roots: PageTreeNode[],
|
|
178
|
+
sourceId: string,
|
|
179
|
+
targetId: string | null,
|
|
180
|
+
): ReparentCheck {
|
|
181
|
+
if (targetId === sourceId) {
|
|
182
|
+
return { ok: false, reason: 'A page cannot be its own parent' }
|
|
183
|
+
}
|
|
184
|
+
if (targetId !== null && collectDescendantIds(roots, sourceId).has(targetId)) {
|
|
185
|
+
return { ok: false, reason: 'Cannot move a page into its own sub-pages' }
|
|
186
|
+
}
|
|
187
|
+
const parentOf = (nodes: PageTreeNode[], parent: string | null): string | null | undefined => {
|
|
188
|
+
for (const n of nodes) {
|
|
189
|
+
if (n.page.id === sourceId) return parent
|
|
190
|
+
const hit = parentOf(n.children, n.page.id)
|
|
191
|
+
if (hit !== undefined) return hit
|
|
192
|
+
}
|
|
193
|
+
return undefined
|
|
194
|
+
}
|
|
195
|
+
if ((parentOf(roots, null) ?? null) === targetId) {
|
|
196
|
+
return { ok: false, reason: 'Page is already there' }
|
|
197
|
+
}
|
|
198
|
+
return { ok: true }
|
|
199
|
+
}
|
package/src/views/FormEditor.tsx
CHANGED
|
@@ -351,11 +351,11 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
351
351
|
</label>
|
|
352
352
|
<div className="flex gap-3">
|
|
353
353
|
<label
|
|
354
|
-
className=
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}}
|
|
354
|
+
className={`flex cursor-pointer items-center gap-2 rounded-lg border px-4 py-2 transition-colors ${
|
|
355
|
+
confirmation.type === 'message'
|
|
356
|
+
? 'border-primary bg-accent'
|
|
357
|
+
: 'border-border hover:bg-muted bg-transparent'
|
|
358
|
+
}`}
|
|
359
359
|
>
|
|
360
360
|
<input
|
|
361
361
|
type="radio"
|
|
@@ -369,11 +369,11 @@ export function FormEditor({ formId, onNavigate }: FormEditorProps) {
|
|
|
369
369
|
<span className="text-sm">Show Message</span>
|
|
370
370
|
</label>
|
|
371
371
|
<label
|
|
372
|
-
className=
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}}
|
|
372
|
+
className={`flex cursor-pointer items-center gap-2 rounded-lg border px-4 py-2 transition-colors ${
|
|
373
|
+
confirmation.type === 'redirect'
|
|
374
|
+
? 'border-primary bg-accent'
|
|
375
|
+
: 'border-border hover:bg-muted bg-transparent'
|
|
376
|
+
}`}
|
|
377
377
|
>
|
|
378
378
|
<input
|
|
379
379
|
type="radio"
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
* (`config.admin.loginPath` set). Mimics the framework's default 404 page so
|
|
6
6
|
* hitting `/admin` reveals nothing — no login form, no admin branding, and no
|
|
7
7
|
* redirect that would leak the real login location.
|
|
8
|
+
*
|
|
9
|
+
* INTENTIONAL raw colors: although this mounts inside `.actuate-admin` (so the
|
|
10
|
+
* theme CSS vars are technically available), it must NOT use them. Painting
|
|
11
|
+
* this screen with the admin palette (or its dark-mode variant) would make it
|
|
12
|
+
* visibly differ from the framework's stock 404 and fingerprint the hidden
|
|
13
|
+
* admin to anyone probing `/admin`. Plain #fff/#000 matches the default 404.
|
|
8
14
|
*/
|
|
9
15
|
export function HiddenLoginNotFound() {
|
|
10
16
|
return (
|
|
@@ -31,6 +31,7 @@ import { sortByRelevance, type SortConfig, toggleSort } from '../lib/search.js'
|
|
|
31
31
|
import { useApiData } from '../lib/useApiData.js'
|
|
32
32
|
import { cmsApi } from '../lib/api.js'
|
|
33
33
|
import { FolderTree, type FolderSelection } from '../components/FolderTree.js'
|
|
34
|
+
import { Button } from '../components/ui/Button.js'
|
|
34
35
|
import { StatusBadge } from '../components/ui/StatusBadge.js'
|
|
35
36
|
import { StatPill } from '../components/ui/StatPill.js'
|
|
36
37
|
import { MediaSeoAudit, type MediaSeoAuditItem } from './MediaSeoAudit.js'
|
|
@@ -508,18 +509,16 @@ export function MediaBrowser({ onNavigate, currentPath }: MediaBrowserProps) {
|
|
|
508
509
|
className="hidden"
|
|
509
510
|
onChange={(e) => handleUploadFiles(e.target.files)}
|
|
510
511
|
/>
|
|
511
|
-
<
|
|
512
|
+
<Button
|
|
513
|
+
type="button"
|
|
514
|
+
variant="primary"
|
|
515
|
+
size="md"
|
|
512
516
|
onClick={() => fileInputRef.current?.click()}
|
|
513
|
-
|
|
514
|
-
|
|
517
|
+
loading={uploading}
|
|
518
|
+
leftIcon={<Upload size={16} aria-hidden />}
|
|
515
519
|
>
|
|
516
|
-
{uploading ? (
|
|
517
|
-
<Loader2 className="h-4 w-4 animate-spin" />
|
|
518
|
-
) : (
|
|
519
|
-
<Upload className="h-4 w-4" />
|
|
520
|
-
)}
|
|
521
520
|
{uploading ? 'Uploading...' : 'Upload Files'}
|
|
522
|
-
</
|
|
521
|
+
</Button>
|
|
523
522
|
</div>
|
|
524
523
|
</div>
|
|
525
524
|
|
package/src/views/PageEditor.tsx
CHANGED
|
@@ -12,6 +12,10 @@ export interface PageEditorProps {
|
|
|
12
12
|
onNavigate?: (path: string) => void
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Superseded by the visual page builder (`PageBuilder` and the
|
|
17
|
+
* `views/page-editor/` section editor); will be removed in the next major.
|
|
18
|
+
*/
|
|
15
19
|
export function PageEditor({ id, onNavigate }: PageEditorProps) {
|
|
16
20
|
const isNew = !id
|
|
17
21
|
const { data, loading, error } = useApiData<any>(isNew ? '' : `/collections/pages/${id}`)
|