@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.
Files changed (37) hide show
  1. package/CHANGELOG.md +1508 -0
  2. package/README.md +35 -0
  3. package/dist/__tests__/lib/post-editor-service.test.js +120 -1
  4. package/dist/__tests__/lib/post-editor-service.test.js.map +1 -1
  5. package/dist/__tests__/views/post-section-editor.test.d.ts +2 -0
  6. package/dist/__tests__/views/post-section-editor.test.d.ts.map +1 -0
  7. package/dist/__tests__/views/post-section-editor.test.js +96 -0
  8. package/dist/__tests__/views/post-section-editor.test.js.map +1 -0
  9. package/dist/lib/collection-schema.d.ts +29 -0
  10. package/dist/lib/collection-schema.d.ts.map +1 -0
  11. package/dist/lib/collection-schema.js +54 -0
  12. package/dist/lib/collection-schema.js.map +1 -0
  13. package/dist/lib/page-editor-service.d.ts.map +1 -1
  14. package/dist/lib/page-editor-service.js +2 -32
  15. package/dist/lib/page-editor-service.js.map +1 -1
  16. package/dist/lib/post-editor-service.d.ts +1 -0
  17. package/dist/lib/post-editor-service.d.ts.map +1 -1
  18. package/dist/lib/post-editor-service.js +50 -9
  19. package/dist/lib/post-editor-service.js.map +1 -1
  20. package/dist/lib/posts-service.d.ts.map +1 -1
  21. package/dist/lib/posts-service.js +3 -1
  22. package/dist/lib/posts-service.js.map +1 -1
  23. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  24. package/dist/views/page-editor/PageSectionEditor.js +5 -2
  25. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  26. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  27. package/dist/views/post-editor/PostSectionEditor.js +27 -4
  28. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  29. package/package.json +5 -4
  30. package/src/__tests__/lib/post-editor-service.test.ts +136 -0
  31. package/src/__tests__/views/post-section-editor.test.tsx +147 -0
  32. package/src/lib/collection-schema.ts +62 -0
  33. package/src/lib/page-editor-service.ts +3 -35
  34. package/src/lib/post-editor-service.ts +54 -8
  35. package/src/lib/posts-service.ts +4 -1
  36. package/src/views/page-editor/PageSectionEditor.tsx +5 -2
  37. 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}