@actuate-media/cms-admin 0.69.0 → 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 +19 -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/form-entries.render.test.js +14 -4
- package/dist/__tests__/views/form-entries.render.test.js.map +1 -1
- package/dist/__tests__/views/form-submissions.render.test.js +14 -4
- package/dist/__tests__/views/form-submissions.render.test.js.map +1 -1
- package/dist/__tests__/views/media-seo-audit.render.test.js +26 -0
- package/dist/__tests__/views/media-seo-audit.render.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/__tests__/views/redirects-pane.render.test.d.ts +2 -0
- package/dist/__tests__/views/redirects-pane.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/redirects-pane.render.test.js +121 -0
- package/dist/__tests__/views/redirects-pane.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/components/SEOPanel.js +3 -3
- package/dist/components/SEOPanel.js.map +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/components/collections/EntryDetailPane.js +1 -1
- package/dist/components/collections/EntryDetailPane.js.map +1 -1
- package/dist/components/forms/EntriesTable.d.ts +3 -1
- package/dist/components/forms/EntriesTable.d.ts.map +1 -1
- package/dist/components/forms/EntriesTable.js +5 -2
- package/dist/components/forms/EntriesTable.js.map +1 -1
- package/dist/components/forms/FormEntryDetailPane.d.ts +10 -0
- package/dist/components/forms/FormEntryDetailPane.d.ts.map +1 -0
- package/dist/components/forms/FormEntryDetailPane.js +137 -0
- package/dist/components/forms/FormEntryDetailPane.js.map +1 -0
- package/dist/components/forms/FormSchemaPane.js +1 -1
- package/dist/components/forms/FormSchemaPane.js.map +1 -1
- package/dist/components/script-tags/ScriptTagEditorPane.js +1 -1
- package/dist/components/script-tags/ScriptTagEditorPane.js.map +1 -1
- package/dist/components/seo/RedirectEditorPane.d.ts +12 -0
- package/dist/components/seo/RedirectEditorPane.d.ts.map +1 -0
- package/dist/components/seo/RedirectEditorPane.js +89 -0
- package/dist/components/seo/RedirectEditorPane.js.map +1 -0
- package/dist/components/seo/SeoEditorPane.js +1 -1
- package/dist/components/seo/SeoEditorPane.js.map +1 -1
- package/dist/components/ui/DataTable.js +2 -2
- package/dist/components/ui/DataTable.js.map +1 -1
- package/dist/components/ui/Skeleton.js +3 -3
- package/dist/components/ui/Skeleton.js.map +1 -1
- package/dist/components/ui/Toggle.js +1 -1
- package/dist/components/ui/Toggle.js.map +1 -1
- package/dist/fields/BlockBuilderField.js +1 -1
- package/dist/fields/BlockBuilderField.js.map +1 -1
- package/dist/fields/MediaField.js +1 -1
- package/dist/fields/MediaField.js.map +1 -1
- package/dist/fields/PropInput.js +1 -1
- package/dist/fields/PropInput.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/layout/Header.js +1 -1
- package/dist/layout/Header.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/DocumentEdit.js +1 -1
- package/dist/views/DocumentEdit.js.map +1 -1
- package/dist/views/FormEditor.js +5 -7
- package/dist/views/FormEditor.js.map +1 -1
- package/dist/views/FormEntries.d.ts.map +1 -1
- package/dist/views/FormEntries.js +18 -14
- package/dist/views/FormEntries.js.map +1 -1
- package/dist/views/FormSubmissions.d.ts.map +1 -1
- package/dist/views/FormSubmissions.js +18 -15
- package/dist/views/FormSubmissions.js.map +1 -1
- package/dist/views/Forms.js +5 -5
- package/dist/views/Forms.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 +3 -2
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/MediaSeoAudit.d.ts +4 -1
- package/dist/views/MediaSeoAudit.d.ts.map +1 -1
- package/dist/views/MediaSeoAudit.js +12 -2
- package/dist/views/MediaSeoAudit.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 +52 -17
- 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 +4 -3
- 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/dist/views/seo/ContentTab.js +6 -6
- package/dist/views/seo/ContentTab.js.map +1 -1
- package/dist/views/seo/RedirectsTab.d.ts.map +1 -1
- package/dist/views/seo/RedirectsTab.js +23 -8
- package/dist/views/seo/RedirectsTab.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/form-entries.render.test.tsx +16 -4
- package/src/__tests__/views/form-submissions.render.test.tsx +16 -4
- package/src/__tests__/views/media-seo-audit.render.test.tsx +34 -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/__tests__/views/redirects-pane.render.test.tsx +156 -0
- package/src/components/SEOPanel.tsx +9 -9
- package/src/components/TipTapEditor.tsx +11 -9
- package/src/components/collections/EntryDetailPane.tsx +1 -1
- package/src/components/forms/EntriesTable.tsx +12 -3
- package/src/components/forms/{EntryDetailDrawer.tsx → FormEntryDetailPane.tsx} +112 -102
- package/src/components/forms/FormSchemaPane.tsx +1 -1
- package/src/components/script-tags/ScriptTagEditorPane.tsx +1 -1
- package/src/components/seo/RedirectEditorPane.tsx +271 -0
- package/src/components/seo/SeoEditorPane.tsx +1 -1
- package/src/components/ui/DataTable.tsx +3 -3
- package/src/components/ui/Skeleton.tsx +8 -8
- package/src/components/ui/Toggle.tsx +1 -1
- package/src/fields/BlockBuilderField.tsx +1 -1
- package/src/fields/MediaField.tsx +1 -1
- package/src/fields/PropInput.tsx +1 -1
- package/src/index.ts +3 -0
- package/src/layout/Header.tsx +2 -2
- package/src/lib/pages-service.ts +15 -0
- package/src/lib/pages-tree.ts +54 -0
- package/src/styles/actuate-tokens.css +4 -0
- package/src/styles/theme.css +9 -3
- package/src/views/DocumentEdit.tsx +4 -4
- package/src/views/FormEditor.tsx +10 -10
- package/src/views/FormEntries.tsx +81 -66
- package/src/views/FormSubmissions.tsx +78 -64
- package/src/views/Forms.tsx +16 -16
- package/src/views/HiddenLoginNotFound.tsx +6 -0
- package/src/views/MediaBrowser.tsx +14 -10
- package/src/views/MediaSeoAudit.tsx +39 -2
- package/src/views/PageEditor.tsx +4 -0
- package/src/views/Pages/PagesListView.tsx +99 -54
- package/src/views/Pages/PagesTreeTable.tsx +204 -109
- package/src/views/Pages.tsx +4 -0
- package/src/views/Redirects.tsx +4 -0
- package/src/views/ScriptTags.tsx +36 -42
- package/src/views/page-builder/PageBuilder.tsx +30 -2
- package/src/views/page-builder/PageTemplates.tsx +56 -15
- package/src/views/seo/ContentTab.tsx +10 -10
- package/src/views/seo/RedirectsTab.tsx +145 -109
- package/dist/components/forms/EntryDetailDrawer.d.ts +0 -11
- package/dist/components/forms/EntryDetailDrawer.d.ts.map +0 -1
- package/dist/components/forms/EntryDetailDrawer.js +0 -145
- package/dist/components/forms/EntryDetailDrawer.js.map +0 -1
- package/dist/components/seo/RedirectEditorDrawer.d.ts +0 -9
- package/dist/components/seo/RedirectEditorDrawer.d.ts.map +0 -1
- package/dist/components/seo/RedirectEditorDrawer.js +0 -95
- package/dist/components/seo/RedirectEditorDrawer.js.map +0 -1
- package/src/components/seo/RedirectEditorDrawer.tsx +0 -231
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useRef, useState } from 'react';
|
|
4
|
-
import { Plus,
|
|
4
|
+
import { Plus, Trash2, Upload, Download, Sparkles, ArrowRight, GitBranch, Check, X, Link2, } from 'lucide-react';
|
|
5
5
|
import { toast } from 'sonner';
|
|
6
6
|
import { fetchRedirectOverview, fetchRedirectRules, fetchRedirectChains, fetchRedirectSuggestions, deleteRedirectRule, flattenRedirectChain, generate404RecoverySuggestions, acceptRedirectSuggestion, dismissRedirectSuggestion, exportRedirectsCsv, importRedirectsCsv, } from '../../lib/seo-service.js';
|
|
7
7
|
import { SectionCard, SeoLoading, SeoEmptyState, SeoErrorState, SeoStatusBadge, btnPrimary, btnSecondary, btnGhostIcon, } from '../../components/seo/primitives.js';
|
|
8
|
-
import {
|
|
8
|
+
import { RedirectEditorPane } from '../../components/seo/RedirectEditorPane.js';
|
|
9
|
+
import { InspectorPane, SplitPaneLayout, SplitPaneList } from '../../components/ui/InspectorPane.js';
|
|
9
10
|
import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js';
|
|
10
11
|
import { useSeoResource } from './useSeoResource.js';
|
|
11
12
|
function OverviewCards({ onRefetchKey }) {
|
|
@@ -83,11 +84,13 @@ export function RedirectsTab() {
|
|
|
83
84
|
refetch();
|
|
84
85
|
bump();
|
|
85
86
|
};
|
|
87
|
+
const toggleRow = (rule) => setEditor((prev) => (prev?.rule?.id === rule.id ? null : { rule }));
|
|
86
88
|
async function handleDelete(rule) {
|
|
87
89
|
const res = await deleteRedirectRule(rule.id);
|
|
88
90
|
if (res.error)
|
|
89
91
|
return toast.error(res.error);
|
|
90
92
|
toast.success('Redirect deleted.');
|
|
93
|
+
setEditor((cur) => (cur?.rule?.id === rule.id ? null : cur));
|
|
91
94
|
refetchAll();
|
|
92
95
|
}
|
|
93
96
|
async function handleExport() {
|
|
@@ -120,11 +123,23 @@ export function RedirectsTab() {
|
|
|
120
123
|
}
|
|
121
124
|
refetchAll();
|
|
122
125
|
}
|
|
123
|
-
return (_jsxs("div", { className: "space-y-4", children: [_jsx(OverviewCards, { onRefetchKey: refetchKey }), _jsxs("div", { className: "grid grid-cols-1 gap-4 xl:grid-cols-2", children: [_jsx(Ai404RecoveryCard, { onApplied: refetchAll }), _jsx(ChainMapCard, { onFlattened: refetchAll })] }), _jsx(SectionCard, { title: "Redirect Rules", action: _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx("input", { ref: fileRef, type: "file", accept: ".csv,text/csv", className: "sr-only", "aria-hidden": true, tabIndex: -1, onChange: (e) => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(OverviewCards, { onRefetchKey: refetchKey }), _jsxs("div", { className: "grid grid-cols-1 gap-4 xl:grid-cols-2", children: [_jsx(Ai404RecoveryCard, { onApplied: refetchAll }), _jsx(ChainMapCard, { onFlattened: refetchAll })] }), _jsxs(SplitPaneLayout, { className: "h-[calc(100vh-280px)] min-h-[440px]", children: [_jsx(SplitPaneList, { children: _jsx(SectionCard, { title: "Redirect Rules", action: _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx("input", { ref: fileRef, type: "file", accept: ".csv,text/csv", className: "sr-only", "aria-hidden": true, tabIndex: -1, onChange: (e) => {
|
|
127
|
+
const f = e.target.files?.[0];
|
|
128
|
+
if (f)
|
|
129
|
+
handleImportFile(f);
|
|
130
|
+
e.target.value = '';
|
|
131
|
+
} }), _jsxs("button", { className: btnSecondary, onClick: () => fileRef.current?.click(), children: [_jsx(Upload, { className: "h-4 w-4", "aria-hidden": true }), " Import"] }), _jsxs("button", { className: btnSecondary, onClick: handleExport, children: [_jsx(Download, { className: "h-4 w-4", "aria-hidden": true }), " Export"] }), _jsxs("button", { className: btnPrimary, onClick: () => setEditor({ rule: null }), children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), " New redirect"] })] }), children: loading ? (_jsx(SeoLoading, { label: "Loading redirects\u2026" })) : error ? (_jsx(SeoErrorState, { message: error, onRetry: refetch })) : (data ?? []).length === 0 ? (_jsx(SeoEmptyState, { icon: _jsx(Link2, { size: 24 }), title: "No redirects yet", description: "Create a redirect or import a CSV to get started.", action: _jsxs("button", { className: btnPrimary, onClick: () => setEditor({ rule: null }), children: [_jsx(Plus, { className: "h-4 w-4", "aria-hidden": true }), " New redirect"] }) })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", "aria-label": "Redirect rules", children: [_jsx("thead", { children: _jsxs("tr", { className: "text-muted-foreground border-border border-b text-left", children: [_jsx("th", { className: "py-2 pr-4 font-medium", children: "Source" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Destination" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Type" }), _jsx("th", { className: "py-2 pr-4 text-right font-medium", children: "Hits" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Status" }), _jsx("th", { className: "py-2 text-right font-medium", children: _jsx("span", { className: "sr-only", children: "Actions" }) })] }) }), _jsx("tbody", { className: "divide-border divide-y", children: data.map((r) => {
|
|
132
|
+
const isSelected = editor?.rule?.id === r.id;
|
|
133
|
+
return (_jsxs("tr", { className: `cursor-pointer transition-colors ${isSelected ? 'bg-[var(--acc-l)]' : 'hover:bg-accent/40'}`, onClick: () => toggleRow(r), children: [_jsx("td", { className: "py-2.5 pr-4", children: _jsx("button", { type: "button", onClick: (e) => {
|
|
134
|
+
e.stopPropagation();
|
|
135
|
+
toggleRow(r);
|
|
136
|
+
}, "aria-expanded": isSelected, className: "text-foreground focus-visible:ring-ring rounded text-left font-mono hover:underline focus-visible:ring-2 focus-visible:outline-none", children: r.fromPath }) }), _jsx("td", { className: "text-muted-foreground py-2.5 pr-4 font-mono", children: r.type === 410 ? _jsx("span", { className: "italic", children: "\u2014 (gone)" }) : r.toPath }), _jsx("td", { className: "text-foreground py-2.5 pr-4 tabular-nums", children: r.type }), _jsx("td", { className: "text-foreground py-2.5 pr-4 text-right tabular-nums", children: r.hits }), _jsx("td", { className: "py-2.5 pr-4", children: _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(SeoStatusBadge, { label: r.enabled ? 'Enabled' : 'Disabled', tone: r.enabled ? 'good' : 'neutral' }), r.stale && _jsx(SeoStatusBadge, { label: "Stale", tone: "fair" })] }) }), _jsx("td", { className: "py-2.5 text-right", children: _jsx("div", { className: "flex justify-end gap-1", children: _jsx("button", { className: btnGhostIcon, onClick: (e) => {
|
|
137
|
+
e.stopPropagation();
|
|
138
|
+
setConfirmDelete(r);
|
|
139
|
+
}, "aria-label": `Delete redirect ${r.fromPath}`, children: _jsx(Trash2, { className: "h-4 w-4", "aria-hidden": true }) }) }) })] }, r.id));
|
|
140
|
+
}) })] }) })) }) }), _jsx(InspectorPane, { open: editor !== null, width: 420, "aria-label": "Redirect editor", children: editor && (_jsx(RedirectEditorPane, { rule: editor.rule, onClose: () => setEditor(null), onSaved: () => {
|
|
141
|
+
setEditor(null);
|
|
142
|
+
refetchAll();
|
|
143
|
+
}, onDelete: (rule) => setConfirmDelete(rule) }, editor.rule?.id ?? 'new')) })] }), _jsx(ConfirmDialog, { open: confirmDelete !== null, onClose: () => setConfirmDelete(null), onConfirm: () => confirmDelete && handleDelete(confirmDelete), title: "Delete redirect", description: `Delete the redirect from "${confirmDelete?.fromPath}"? This cannot be undone.`, confirmLabel: "Delete", destructive: true })] }));
|
|
129
144
|
}
|
|
130
145
|
//# sourceMappingURL=RedirectsTab.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedirectsTab.js","sourceRoot":"","sources":["../../../src/views/seo/RedirectsTab.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RedirectsTab.js","sourceRoot":"","sources":["../../../src/views/seo/RedirectsTab.tsx"],"names":[],"mappings":"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"}
|
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
|
+
})
|
|
@@ -4,7 +4,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
|
4
4
|
|
|
5
5
|
// Drive the global All Entries inbox through a mocked forms-service so the test
|
|
6
6
|
// owns the data and can assert the cross-form table (Form column + form
|
|
7
|
-
// filter), status-pill refetches, and opening the detail
|
|
7
|
+
// filter), status-pill refetches, and opening the inline detail pane.
|
|
8
8
|
function makeEntry(over: Record<string, unknown> = {}) {
|
|
9
9
|
return {
|
|
10
10
|
id: 'e1',
|
|
@@ -122,12 +122,24 @@ describe('FormEntries (All Entries)', () => {
|
|
|
122
122
|
)
|
|
123
123
|
})
|
|
124
124
|
|
|
125
|
-
it('opens the detail
|
|
125
|
+
it('opens the detail pane inline when a row is clicked', async () => {
|
|
126
126
|
render(<FormEntries onNavigate={() => {}} />)
|
|
127
|
-
const
|
|
127
|
+
const rowButton = await screen.findByRole('button', { name: 'Jordan Avery' })
|
|
128
|
+
expect(rowButton.getAttribute('aria-expanded')).toBe('false')
|
|
128
129
|
|
|
129
|
-
fireEvent.click(
|
|
130
|
+
fireEvent.click(rowButton)
|
|
130
131
|
|
|
132
|
+
expect(screen.getByRole('region', { name: 'Entry details' })).toBeTruthy()
|
|
133
|
+
expect(rowButton.getAttribute('aria-expanded')).toBe('true')
|
|
131
134
|
await waitFor(() => expect(fetchEntry).toHaveBeenCalledWith('e1'))
|
|
132
135
|
})
|
|
136
|
+
|
|
137
|
+
it('collapses the pane via its close button', async () => {
|
|
138
|
+
render(<FormEntries onNavigate={() => {}} />)
|
|
139
|
+
fireEvent.click(await screen.findByRole('button', { name: 'Jordan Avery' }))
|
|
140
|
+
expect(screen.getByRole('region', { name: 'Entry details' })).toBeTruthy()
|
|
141
|
+
|
|
142
|
+
fireEvent.click(screen.getByRole('button', { name: 'Close entry details' }))
|
|
143
|
+
expect(screen.queryByRole('region', { name: 'Entry details' })).toBeNull()
|
|
144
|
+
})
|
|
133
145
|
})
|
|
@@ -4,7 +4,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
|
4
4
|
|
|
5
5
|
// Drive the per-form submissions table through a mocked forms-service so the
|
|
6
6
|
// test owns the data and can assert rendering, status-pill refetches, bulk
|
|
7
|
-
// selection, and opening the detail
|
|
7
|
+
// selection, and opening the inline detail pane without a real backend.
|
|
8
8
|
function makeEntry(over: Record<string, unknown> = {}) {
|
|
9
9
|
return {
|
|
10
10
|
id: 'e1',
|
|
@@ -118,12 +118,24 @@ describe('FormSubmissions table', () => {
|
|
|
118
118
|
expect(screen.getByRole('button', { name: 'Mark read' })).toBeTruthy()
|
|
119
119
|
})
|
|
120
120
|
|
|
121
|
-
it('opens the detail
|
|
121
|
+
it('opens the detail pane inline when a row is clicked', async () => {
|
|
122
122
|
render(<FormSubmissions formId="f1" onNavigate={() => {}} />)
|
|
123
|
-
const
|
|
123
|
+
const rowButton = await screen.findByRole('button', { name: 'Jordan Avery' })
|
|
124
|
+
expect(rowButton.getAttribute('aria-expanded')).toBe('false')
|
|
124
125
|
|
|
125
|
-
fireEvent.click(
|
|
126
|
+
fireEvent.click(rowButton)
|
|
126
127
|
|
|
128
|
+
expect(screen.getByRole('region', { name: 'Entry details' })).toBeTruthy()
|
|
129
|
+
expect(rowButton.getAttribute('aria-expanded')).toBe('true')
|
|
127
130
|
await waitFor(() => expect(fetchEntry).toHaveBeenCalledWith('e1'))
|
|
128
131
|
})
|
|
132
|
+
|
|
133
|
+
it('collapses the pane via its close button', async () => {
|
|
134
|
+
render(<FormSubmissions formId="f1" onNavigate={() => {}} />)
|
|
135
|
+
fireEvent.click(await screen.findByRole('button', { name: 'Jordan Avery' }))
|
|
136
|
+
expect(screen.getByRole('region', { name: 'Entry details' })).toBeTruthy()
|
|
137
|
+
|
|
138
|
+
fireEvent.click(screen.getByRole('button', { name: 'Close entry details' }))
|
|
139
|
+
expect(screen.queryByRole('region', { name: 'Entry details' })).toBeNull()
|
|
140
|
+
})
|
|
129
141
|
})
|
|
@@ -114,4 +114,38 @@ describe('MediaSeoAudit', () => {
|
|
|
114
114
|
fireEvent.click(screen.getByRole('button', { name: 'Missing Alt' }))
|
|
115
115
|
expect(screen.getByText('No items match this filter')).toBeTruthy()
|
|
116
116
|
})
|
|
117
|
+
|
|
118
|
+
it('renders a retryable error state instead of an empty audit when the fetch failed', () => {
|
|
119
|
+
const onRetry = vi.fn()
|
|
120
|
+
render(<MediaSeoAudit items={[]} onEdit={vi.fn()} error="Network error" onRetry={onRetry} />)
|
|
121
|
+
|
|
122
|
+
expect(screen.getByRole('alert')).toBeTruthy()
|
|
123
|
+
expect(screen.getByText("Couldn't load media")).toBeTruthy()
|
|
124
|
+
expect(screen.getByText('Network error')).toBeTruthy()
|
|
125
|
+
expect(screen.queryByText('No media to audit')).toBeNull()
|
|
126
|
+
|
|
127
|
+
fireEvent.click(screen.getByRole('button', { name: 'Retry' }))
|
|
128
|
+
expect(onRetry).toHaveBeenCalledTimes(1)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('still renders loaded items when an error arrives after data (stale-but-usable)', () => {
|
|
132
|
+
render(<MediaSeoAudit items={ITEMS} onEdit={vi.fn()} error="Refresh failed" />)
|
|
133
|
+
expect(screen.getByRole('table', { name: 'Media SEO audit' })).toBeTruthy()
|
|
134
|
+
expect(screen.queryByRole('alert')).toBeNull()
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('activates a row with the keyboard (Enter and Space)', () => {
|
|
138
|
+
const onEdit = vi.fn()
|
|
139
|
+
render(<MediaSeoAudit items={ITEMS} onEdit={onEdit} />)
|
|
140
|
+
|
|
141
|
+
const row = screen.getByRole('row', { name: 'Edit SEO metadata for hero-banner.jpg' })
|
|
142
|
+
expect(row.getAttribute('tabindex')).toBe('0')
|
|
143
|
+
|
|
144
|
+
fireEvent.keyDown(row, { key: 'Enter' })
|
|
145
|
+
expect(onEdit).toHaveBeenCalledTimes(1)
|
|
146
|
+
expect(onEdit.mock.calls[0]![0].id).toBe('no-alt')
|
|
147
|
+
|
|
148
|
+
fireEvent.keyDown(row, { key: ' ' })
|
|
149
|
+
expect(onEdit).toHaveBeenCalledTimes(2)
|
|
150
|
+
})
|
|
117
151
|
})
|
|
@@ -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')
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Redirects tab with the inline editor pane (design split-pane pattern —
|
|
7
|
+
* previously the `RedirectEditorDrawer` overlay). Pins: row click toggles the
|
|
8
|
+
* 420px pane, "New redirect" opens it in create mode, and save flows through
|
|
9
|
+
* the same `createRedirectRule` / `updateRedirectRule` service calls.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function makeRule(over: Record<string, unknown> = {}) {
|
|
13
|
+
return {
|
|
14
|
+
id: 'r1',
|
|
15
|
+
type: 301 as const,
|
|
16
|
+
fromPath: '/old-path',
|
|
17
|
+
toPath: '/new-path',
|
|
18
|
+
enabled: true,
|
|
19
|
+
priority: 0,
|
|
20
|
+
preserveQuery: false,
|
|
21
|
+
hits: 3,
|
|
22
|
+
lastHitAt: null,
|
|
23
|
+
stale: false,
|
|
24
|
+
source: 'manual',
|
|
25
|
+
notes: null,
|
|
26
|
+
createdAt: '2026-06-01T00:00:00Z',
|
|
27
|
+
updatedAt: '2026-06-01T00:00:00Z',
|
|
28
|
+
...over,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const RULES = [makeRule(), makeRule({ id: 'r2', fromPath: '/other', toPath: '/elsewhere' })]
|
|
33
|
+
|
|
34
|
+
const fetchRedirectRules = vi.fn(async () => RULES)
|
|
35
|
+
const createRedirectRule = vi.fn(async (_p: unknown) => ({}))
|
|
36
|
+
const updateRedirectRule = vi.fn(async (_id: string, _p: unknown) => ({}))
|
|
37
|
+
const deleteRedirectRule = vi.fn(async (_id: string) => ({}))
|
|
38
|
+
|
|
39
|
+
vi.mock('../../lib/seo-service.js', () => ({
|
|
40
|
+
fetchRedirectOverview: vi.fn(async () => ({
|
|
41
|
+
activeRedirects: 2,
|
|
42
|
+
staleRedirects: 0,
|
|
43
|
+
notFoundCount: 0,
|
|
44
|
+
chainsAndLoops: 0,
|
|
45
|
+
})),
|
|
46
|
+
fetchRedirectRules: () => fetchRedirectRules(),
|
|
47
|
+
fetchRedirectChains: vi.fn(async () => []),
|
|
48
|
+
fetchRedirectSuggestions: vi.fn(async () => []),
|
|
49
|
+
createRedirectRule: (p: unknown) => createRedirectRule(p),
|
|
50
|
+
updateRedirectRule: (id: string, p: unknown) => updateRedirectRule(id, p),
|
|
51
|
+
deleteRedirectRule: (id: string) => deleteRedirectRule(id),
|
|
52
|
+
flattenRedirectChain: vi.fn(async () => ({})),
|
|
53
|
+
generate404RecoverySuggestions: vi.fn(async () => ({})),
|
|
54
|
+
acceptRedirectSuggestion: vi.fn(async () => ({})),
|
|
55
|
+
dismissRedirectSuggestion: vi.fn(async () => ({})),
|
|
56
|
+
exportRedirectsCsv: vi.fn(async () => ({ csv: '' })),
|
|
57
|
+
importRedirectsCsv: vi.fn(async () => ({ imported: 0 })),
|
|
58
|
+
}))
|
|
59
|
+
|
|
60
|
+
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() } }))
|
|
61
|
+
|
|
62
|
+
const { RedirectsTab } = await import('../../views/seo/RedirectsTab.js')
|
|
63
|
+
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
fetchRedirectRules.mockClear()
|
|
66
|
+
createRedirectRule.mockClear()
|
|
67
|
+
updateRedirectRule.mockClear()
|
|
68
|
+
deleteRedirectRule.mockClear()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe('Redirects inline editor pane', () => {
|
|
72
|
+
it('opens the pane on row click with the rule loaded', async () => {
|
|
73
|
+
render(<RedirectsTab />)
|
|
74
|
+
const rowButton = await screen.findByRole('button', { name: '/old-path' })
|
|
75
|
+
expect(rowButton.getAttribute('aria-expanded')).toBe('false')
|
|
76
|
+
|
|
77
|
+
fireEvent.click(rowButton)
|
|
78
|
+
|
|
79
|
+
expect(screen.getByRole('region', { name: 'Redirect editor' })).toBeTruthy()
|
|
80
|
+
expect(rowButton.getAttribute('aria-expanded')).toBe('true')
|
|
81
|
+
// The form is prefilled from the selected rule.
|
|
82
|
+
expect(screen.getByLabelText('Source path')).toHaveProperty('value', '/old-path')
|
|
83
|
+
expect(screen.getByLabelText('Destination')).toHaveProperty('value', '/new-path')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('toggles the pane closed when the same row is clicked again', async () => {
|
|
87
|
+
render(<RedirectsTab />)
|
|
88
|
+
const rowButton = await screen.findByRole('button', { name: '/old-path' })
|
|
89
|
+
|
|
90
|
+
fireEvent.click(rowButton)
|
|
91
|
+
expect(screen.getByRole('region', { name: 'Redirect editor' })).toBeTruthy()
|
|
92
|
+
|
|
93
|
+
fireEvent.click(rowButton)
|
|
94
|
+
expect(screen.queryByRole('region', { name: 'Redirect editor' })).toBeNull()
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('collapses the pane via the close button', async () => {
|
|
98
|
+
render(<RedirectsTab />)
|
|
99
|
+
fireEvent.click(await screen.findByRole('button', { name: '/old-path' }))
|
|
100
|
+
expect(screen.getByRole('region', { name: 'Redirect editor' })).toBeTruthy()
|
|
101
|
+
|
|
102
|
+
fireEvent.click(screen.getByRole('button', { name: 'Close redirect editor' }))
|
|
103
|
+
expect(screen.queryByRole('region', { name: 'Redirect editor' })).toBeNull()
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('saves an edited rule through updateRedirectRule and refetches', async () => {
|
|
107
|
+
render(<RedirectsTab />)
|
|
108
|
+
fireEvent.click(await screen.findByRole('button', { name: '/old-path' }))
|
|
109
|
+
const before = fetchRedirectRules.mock.calls.length
|
|
110
|
+
|
|
111
|
+
fireEvent.change(screen.getByLabelText('Destination'), { target: { value: '/moved' } })
|
|
112
|
+
fireEvent.click(screen.getByRole('button', { name: 'Save changes' }))
|
|
113
|
+
|
|
114
|
+
await waitFor(() =>
|
|
115
|
+
expect(updateRedirectRule).toHaveBeenCalledWith(
|
|
116
|
+
'r1',
|
|
117
|
+
expect.objectContaining({ fromPath: '/old-path', toPath: '/moved', type: 301 }),
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
// Saving closes the pane and refetches the list.
|
|
121
|
+
await waitFor(() =>
|
|
122
|
+
expect(screen.queryByRole('region', { name: 'Redirect editor' })).toBeNull(),
|
|
123
|
+
)
|
|
124
|
+
await waitFor(() => expect(fetchRedirectRules.mock.calls.length).toBeGreaterThan(before))
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('creates a rule from the New redirect pane', async () => {
|
|
128
|
+
render(<RedirectsTab />)
|
|
129
|
+
await screen.findByRole('button', { name: '/old-path' })
|
|
130
|
+
|
|
131
|
+
fireEvent.click(screen.getByRole('button', { name: /New redirect/ }))
|
|
132
|
+
expect(screen.getByRole('region', { name: 'Redirect editor' })).toBeTruthy()
|
|
133
|
+
|
|
134
|
+
fireEvent.change(screen.getByLabelText('Source path'), { target: { value: 'legacy' } })
|
|
135
|
+
fireEvent.change(screen.getByLabelText('Destination'), { target: { value: '/fresh' } })
|
|
136
|
+
fireEvent.click(screen.getByRole('button', { name: 'Create redirect' }))
|
|
137
|
+
|
|
138
|
+
// Paths are normalized to a leading slash before saving.
|
|
139
|
+
await waitFor(() =>
|
|
140
|
+
expect(createRedirectRule).toHaveBeenCalledWith(
|
|
141
|
+
expect.objectContaining({ fromPath: '/legacy', toPath: '/fresh', type: 301 }),
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('shows a validation error instead of saving when the source is missing', async () => {
|
|
147
|
+
render(<RedirectsTab />)
|
|
148
|
+
await screen.findByRole('button', { name: '/old-path' })
|
|
149
|
+
|
|
150
|
+
fireEvent.click(screen.getByRole('button', { name: /New redirect/ }))
|
|
151
|
+
fireEvent.click(screen.getByRole('button', { name: 'Create redirect' }))
|
|
152
|
+
|
|
153
|
+
expect(await screen.findByRole('alert')).toBeTruthy()
|
|
154
|
+
expect(createRedirectRule).not.toHaveBeenCalled()
|
|
155
|
+
})
|
|
156
|
+
})
|