@actuate-media/cms-admin 0.42.1 → 0.42.4
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 +1508 -0
- package/README.md +35 -0
- package/dist/__tests__/lib/post-editor-service.test.js +120 -1
- package/dist/__tests__/lib/post-editor-service.test.js.map +1 -1
- package/dist/__tests__/views/post-section-editor.test.d.ts +2 -0
- package/dist/__tests__/views/post-section-editor.test.d.ts.map +1 -0
- package/dist/__tests__/views/post-section-editor.test.js +96 -0
- package/dist/__tests__/views/post-section-editor.test.js.map +1 -0
- package/dist/lib/collection-schema.d.ts +29 -0
- package/dist/lib/collection-schema.d.ts.map +1 -0
- package/dist/lib/collection-schema.js +54 -0
- package/dist/lib/collection-schema.js.map +1 -0
- package/dist/lib/page-editor-service.d.ts.map +1 -1
- package/dist/lib/page-editor-service.js +2 -32
- package/dist/lib/page-editor-service.js.map +1 -1
- package/dist/lib/post-editor-service.d.ts +1 -0
- package/dist/lib/post-editor-service.d.ts.map +1 -1
- package/dist/lib/post-editor-service.js +50 -9
- package/dist/lib/post-editor-service.js.map +1 -1
- package/dist/lib/posts-service.d.ts.map +1 -1
- package/dist/lib/posts-service.js +3 -1
- package/dist/lib/posts-service.js.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.js +5 -2
- package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.js +27 -4
- package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
- package/package.json +5 -4
- package/src/__tests__/lib/post-editor-service.test.ts +136 -0
- package/src/__tests__/views/post-section-editor.test.tsx +147 -0
- package/src/lib/collection-schema.ts +62 -0
- package/src/lib/page-editor-service.ts +3 -35
- package/src/lib/post-editor-service.ts +54 -8
- package/src/lib/posts-service.ts +4 -1
- package/src/views/page-editor/PageSectionEditor.tsx +5 -2
- package/src/views/post-editor/PostSectionEditor.tsx +49 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
4
|
-
import { AlertTriangle, Loader2 } from 'lucide-react'
|
|
4
|
+
import { AlertTriangle, Loader2, Lock } from 'lucide-react'
|
|
5
5
|
import { toast } from 'sonner'
|
|
6
6
|
import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js'
|
|
7
7
|
import { ErrorBoundary } from '../../components/ErrorBoundary.js'
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
emptyPostFromTemplate,
|
|
14
14
|
fetchPostForEditor,
|
|
15
15
|
fetchTemplateForEditor,
|
|
16
|
+
missingPostFields,
|
|
16
17
|
moveSection,
|
|
17
18
|
publishPost,
|
|
18
19
|
removeSection,
|
|
@@ -123,12 +124,35 @@ export function PostSectionEditor({
|
|
|
123
124
|
return col?.labels?.singular ?? postType
|
|
124
125
|
}, [config, postType])
|
|
125
126
|
|
|
127
|
+
// A misconfigured post-type collection (missing the fields the editor
|
|
128
|
+
// writes) would silently drop content on save — detect it up front.
|
|
129
|
+
// Memoized to a string/null so the load effect can depend on it without
|
|
130
|
+
// re-running when `config`'s object identity changes between renders.
|
|
131
|
+
const schemaError = useMemo(() => {
|
|
132
|
+
const missing = missingPostFields(config, postType)
|
|
133
|
+
if (missing.length === 0) return null
|
|
134
|
+
const plural = missing.length > 1
|
|
135
|
+
return (
|
|
136
|
+
`The "${postType}" collection is missing required field${plural ? 's' : ''}: ` +
|
|
137
|
+
`${missing.join(', ')}. Declare ${plural ? 'them' : 'it'} in your CMS config ` +
|
|
138
|
+
`so the post editor can save without losing content.`
|
|
139
|
+
)
|
|
140
|
+
}, [config, postType])
|
|
141
|
+
|
|
126
142
|
// ─── Load ──────────────────────────────────────────────────────────
|
|
127
143
|
useEffect(() => {
|
|
128
144
|
let cancelled = false
|
|
129
145
|
setLoading(true)
|
|
130
146
|
setLoadError(null)
|
|
131
147
|
|
|
148
|
+
// Fail loud on a misconfigured post-type collection rather than letting
|
|
149
|
+
// the user build a post whose content would be silently dropped on save.
|
|
150
|
+
if (schemaError) {
|
|
151
|
+
setLoadError(schemaError)
|
|
152
|
+
setLoading(false)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
132
156
|
// Always load the type template header (the post editor renders it but
|
|
133
157
|
// never edits it — header design lives at the type level).
|
|
134
158
|
fetchTemplateForEditor(postType)
|
|
@@ -160,7 +184,7 @@ export function PostSectionEditor({
|
|
|
160
184
|
return () => {
|
|
161
185
|
cancelled = true
|
|
162
186
|
}
|
|
163
|
-
}, [postType, documentId])
|
|
187
|
+
}, [postType, documentId, schemaError])
|
|
164
188
|
|
|
165
189
|
// ─── Unsaved-changes guard ───────────────────────────────────────────
|
|
166
190
|
useEffect(() => {
|
|
@@ -424,6 +448,12 @@ export function PostSectionEditor({
|
|
|
424
448
|
|
|
425
449
|
const selected = post.sections.find((s) => s.id === selectedId) ?? null
|
|
426
450
|
|
|
451
|
+
// Sections whose type has no registered definition (seed/code-owned, e.g.
|
|
452
|
+
// `opal-*`). They are preserved verbatim on save but can't be edited here.
|
|
453
|
+
const unmanagedTypes = Array.from(
|
|
454
|
+
new Set(post.sections.filter((s) => s.unmanaged).map((s) => s.sectionType)),
|
|
455
|
+
)
|
|
456
|
+
|
|
427
457
|
// Section types the canvas renders as placeholders — no built-in body
|
|
428
458
|
// component and no consumer-registered admin renderer. When present the
|
|
429
459
|
// editor surfaces "structure view" messaging and promotes "View on site"
|
|
@@ -460,6 +490,23 @@ export function PostSectionEditor({
|
|
|
460
490
|
structuralTypes={structuralTypes}
|
|
461
491
|
/>
|
|
462
492
|
|
|
493
|
+
{unmanagedTypes.length > 0 && (
|
|
494
|
+
<div
|
|
495
|
+
role="status"
|
|
496
|
+
className="border-border bg-muted/50 flex items-start gap-3 border-b px-4 py-2.5"
|
|
497
|
+
>
|
|
498
|
+
<Lock className="text-muted-foreground mt-0.5 shrink-0" size={16} aria-hidden />
|
|
499
|
+
<p className="text-muted-foreground flex-1 text-sm">
|
|
500
|
+
This post has{' '}
|
|
501
|
+
<span className="text-foreground font-medium">
|
|
502
|
+
{unmanagedTypes.length} section type{unmanagedTypes.length > 1 ? 's' : ''}
|
|
503
|
+
</span>{' '}
|
|
504
|
+
managed outside the editor ({unmanagedTypes.join(', ')}). They are preserved on save
|
|
505
|
+
but edited in your seed script or code, not here.
|
|
506
|
+
</p>
|
|
507
|
+
</div>
|
|
508
|
+
)}
|
|
509
|
+
|
|
463
510
|
{validation && (
|
|
464
511
|
<ValidationSummary
|
|
465
512
|
errors={validation.errors}
|