@actuate-media/cms-admin 0.66.0 → 0.68.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.
Files changed (244) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/AdminRoot.d.ts.map +1 -1
  3. package/dist/AdminRoot.js +36 -9
  4. package/dist/AdminRoot.js.map +1 -1
  5. package/dist/__tests__/components/inspector-pane.test.d.ts +2 -0
  6. package/dist/__tests__/components/inspector-pane.test.d.ts.map +1 -0
  7. package/dist/__tests__/components/inspector-pane.test.js +31 -0
  8. package/dist/__tests__/components/inspector-pane.test.js.map +1 -0
  9. package/dist/__tests__/hooks/useIdleLogout.test.d.ts +2 -0
  10. package/dist/__tests__/hooks/useIdleLogout.test.d.ts.map +1 -0
  11. package/dist/__tests__/hooks/useIdleLogout.test.js +64 -0
  12. package/dist/__tests__/hooks/useIdleLogout.test.js.map +1 -0
  13. package/dist/__tests__/lib/pages-tree.test.d.ts +2 -0
  14. package/dist/__tests__/lib/pages-tree.test.d.ts.map +1 -0
  15. package/dist/__tests__/lib/pages-tree.test.js +173 -0
  16. package/dist/__tests__/lib/pages-tree.test.js.map +1 -0
  17. package/dist/__tests__/lib/post-types-service.test.d.ts +2 -0
  18. package/dist/__tests__/lib/post-types-service.test.d.ts.map +1 -0
  19. package/dist/__tests__/lib/post-types-service.test.js +88 -0
  20. package/dist/__tests__/lib/post-types-service.test.js.map +1 -0
  21. package/dist/__tests__/views/collection-list-nav.render.test.js +43 -5
  22. package/dist/__tests__/views/collection-list-nav.render.test.js.map +1 -1
  23. package/dist/__tests__/views/dashboard.test.js +7 -3
  24. package/dist/__tests__/views/dashboard.test.js.map +1 -1
  25. package/dist/__tests__/views/forms-list.render.test.js +25 -6
  26. package/dist/__tests__/views/forms-list.render.test.js.map +1 -1
  27. package/dist/__tests__/views/media-seo-audit.render.test.d.ts +2 -0
  28. package/dist/__tests__/views/media-seo-audit.render.test.d.ts.map +1 -0
  29. package/dist/__tests__/views/media-seo-audit.render.test.js +102 -0
  30. package/dist/__tests__/views/media-seo-audit.render.test.js.map +1 -0
  31. package/dist/__tests__/views/onboarding-block.render.test.d.ts +2 -0
  32. package/dist/__tests__/views/onboarding-block.render.test.d.ts.map +1 -0
  33. package/dist/__tests__/views/onboarding-block.render.test.js +146 -0
  34. package/dist/__tests__/views/onboarding-block.render.test.js.map +1 -0
  35. package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts +2 -0
  36. package/dist/__tests__/views/page-builder-sections-panel.render.test.d.ts.map +1 -0
  37. package/dist/__tests__/views/page-builder-sections-panel.render.test.js +121 -0
  38. package/dist/__tests__/views/page-builder-sections-panel.render.test.js.map +1 -0
  39. package/dist/__tests__/views/page-templates.render.test.d.ts +2 -0
  40. package/dist/__tests__/views/page-templates.render.test.d.ts.map +1 -0
  41. package/dist/__tests__/views/page-templates.render.test.js +105 -0
  42. package/dist/__tests__/views/page-templates.render.test.js.map +1 -0
  43. package/dist/__tests__/views/pages-list-view.test.js +77 -1
  44. package/dist/__tests__/views/pages-list-view.test.js.map +1 -1
  45. package/dist/__tests__/views/post-type-editor.render.test.d.ts +2 -0
  46. package/dist/__tests__/views/post-type-editor.render.test.d.ts.map +1 -0
  47. package/dist/__tests__/views/post-type-editor.render.test.js +102 -0
  48. package/dist/__tests__/views/post-type-editor.render.test.js.map +1 -0
  49. package/dist/__tests__/views/security-settings.render.test.js +85 -4
  50. package/dist/__tests__/views/security-settings.render.test.js.map +1 -1
  51. package/dist/__tests__/views/seo-content-pane.render.test.d.ts +2 -0
  52. package/dist/__tests__/views/seo-content-pane.render.test.d.ts.map +1 -0
  53. package/dist/__tests__/views/seo-content-pane.render.test.js +117 -0
  54. package/dist/__tests__/views/seo-content-pane.render.test.js.map +1 -0
  55. package/dist/actuate-admin.css +1 -1
  56. package/dist/components/collections/EntryDetailPane.d.ts +10 -0
  57. package/dist/components/collections/EntryDetailPane.d.ts.map +1 -0
  58. package/dist/components/collections/EntryDetailPane.js +92 -0
  59. package/dist/components/collections/EntryDetailPane.js.map +1 -0
  60. package/dist/components/forms/FieldsPanel.js +1 -1
  61. package/dist/components/forms/FieldsPanel.js.map +1 -1
  62. package/dist/components/forms/FormSchemaPane.d.ts +8 -0
  63. package/dist/components/forms/FormSchemaPane.d.ts.map +1 -0
  64. package/dist/components/forms/FormSchemaPane.js +95 -0
  65. package/dist/components/forms/FormSchemaPane.js.map +1 -0
  66. package/dist/components/script-tags/ScriptTagEditorPane.d.ts +26 -0
  67. package/dist/components/script-tags/ScriptTagEditorPane.d.ts.map +1 -0
  68. package/dist/components/script-tags/ScriptTagEditorPane.js +160 -0
  69. package/dist/components/script-tags/ScriptTagEditorPane.js.map +1 -0
  70. package/dist/components/seo/SeoEditorPane.d.ts +9 -0
  71. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -0
  72. package/dist/components/seo/SeoEditorPane.js +175 -0
  73. package/dist/components/seo/SeoEditorPane.js.map +1 -0
  74. package/dist/components/ui/Badge.d.ts +1 -1
  75. package/dist/components/ui/Button.d.ts +1 -1
  76. package/dist/components/ui/InspectorPane.d.ts +51 -0
  77. package/dist/components/ui/InspectorPane.d.ts.map +1 -0
  78. package/dist/components/ui/InspectorPane.js +42 -0
  79. package/dist/components/ui/InspectorPane.js.map +1 -0
  80. package/dist/components/ui/StatusBadge.d.ts +1 -1
  81. package/dist/components/ui/index.d.ts +2 -0
  82. package/dist/components/ui/index.d.ts.map +1 -1
  83. package/dist/components/ui/index.js +1 -0
  84. package/dist/components/ui/index.js.map +1 -1
  85. package/dist/hooks/useIdleLogout.d.ts +18 -0
  86. package/dist/hooks/useIdleLogout.d.ts.map +1 -0
  87. package/dist/hooks/useIdleLogout.js +66 -0
  88. package/dist/hooks/useIdleLogout.js.map +1 -0
  89. package/dist/lib/api.d.ts +1 -0
  90. package/dist/lib/api.d.ts.map +1 -1
  91. package/dist/lib/api.js +7 -1
  92. package/dist/lib/api.js.map +1 -1
  93. package/dist/lib/page-editor-service.d.ts +11 -2
  94. package/dist/lib/page-editor-service.d.ts.map +1 -1
  95. package/dist/lib/page-editor-service.js +8 -2
  96. package/dist/lib/page-editor-service.js.map +1 -1
  97. package/dist/lib/pages-tree.d.ts +44 -0
  98. package/dist/lib/pages-tree.d.ts.map +1 -0
  99. package/dist/lib/pages-tree.js +106 -0
  100. package/dist/lib/pages-tree.js.map +1 -0
  101. package/dist/lib/post-types-service.d.ts +44 -0
  102. package/dist/lib/post-types-service.d.ts.map +1 -0
  103. package/dist/lib/post-types-service.js +83 -0
  104. package/dist/lib/post-types-service.js.map +1 -0
  105. package/dist/views/CollectionList.d.ts.map +1 -1
  106. package/dist/views/CollectionList.js +23 -4
  107. package/dist/views/CollectionList.js.map +1 -1
  108. package/dist/views/Dashboard.d.ts.map +1 -1
  109. package/dist/views/Dashboard.js +31 -2
  110. package/dist/views/Dashboard.js.map +1 -1
  111. package/dist/views/Forms.d.ts.map +1 -1
  112. package/dist/views/Forms.js +25 -21
  113. package/dist/views/Forms.js.map +1 -1
  114. package/dist/views/MediaBrowser.d.ts.map +1 -1
  115. package/dist/views/MediaBrowser.js +28 -2
  116. package/dist/views/MediaBrowser.js.map +1 -1
  117. package/dist/views/MediaSeoAudit.d.ts +25 -0
  118. package/dist/views/MediaSeoAudit.d.ts.map +1 -0
  119. package/dist/views/MediaSeoAudit.js +97 -0
  120. package/dist/views/MediaSeoAudit.js.map +1 -0
  121. package/dist/views/Pages/PagesListView.d.ts.map +1 -1
  122. package/dist/views/Pages/PagesListView.js +90 -10
  123. package/dist/views/Pages/PagesListView.js.map +1 -1
  124. package/dist/views/Pages/PagesTreeTable.d.ts +35 -0
  125. package/dist/views/Pages/PagesTreeTable.d.ts.map +1 -0
  126. package/dist/views/Pages/PagesTreeTable.js +28 -0
  127. package/dist/views/Pages/PagesTreeTable.js.map +1 -0
  128. package/dist/views/Posts/PostTypeEditor.d.ts +16 -0
  129. package/dist/views/Posts/PostTypeEditor.d.ts.map +1 -0
  130. package/dist/views/Posts/PostTypeEditor.js +159 -0
  131. package/dist/views/Posts/PostTypeEditor.js.map +1 -0
  132. package/dist/views/Posts/PostTypesView.d.ts +3 -2
  133. package/dist/views/Posts/PostTypesView.d.ts.map +1 -1
  134. package/dist/views/Posts/PostTypesView.js +1 -1
  135. package/dist/views/Posts/PostTypesView.js.map +1 -1
  136. package/dist/views/ScriptTags.d.ts +5 -1
  137. package/dist/views/ScriptTags.d.ts.map +1 -1
  138. package/dist/views/ScriptTags.js +32 -7
  139. package/dist/views/ScriptTags.js.map +1 -1
  140. package/dist/views/dashboard/OnboardingBlock.d.ts +29 -0
  141. package/dist/views/dashboard/OnboardingBlock.d.ts.map +1 -0
  142. package/dist/views/dashboard/OnboardingBlock.js +71 -0
  143. package/dist/views/dashboard/OnboardingBlock.js.map +1 -0
  144. package/dist/views/page-builder/BuilderSectionsPanel.d.ts +20 -0
  145. package/dist/views/page-builder/BuilderSectionsPanel.d.ts.map +1 -0
  146. package/dist/views/page-builder/BuilderSectionsPanel.js +105 -0
  147. package/dist/views/page-builder/BuilderSectionsPanel.js.map +1 -0
  148. package/dist/views/page-builder/PageBuilder.d.ts.map +1 -1
  149. package/dist/views/page-builder/PageBuilder.js +51 -2
  150. package/dist/views/page-builder/PageBuilder.js.map +1 -1
  151. package/dist/views/page-builder/PageTemplates.d.ts.map +1 -1
  152. package/dist/views/page-builder/PageTemplates.js +113 -6
  153. package/dist/views/page-builder/PageTemplates.js.map +1 -1
  154. package/dist/views/page-editor/PageSectionEditor.d.ts +7 -1
  155. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  156. package/dist/views/page-editor/PageSectionEditor.js +3 -3
  157. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  158. package/dist/views/page-editor/PageSettingsModal.d.ts +1 -1
  159. package/dist/views/page-editor/PageSettingsModal.d.ts.map +1 -1
  160. package/dist/views/page-editor/PageSettingsModal.js +42 -3
  161. package/dist/views/page-editor/PageSettingsModal.js.map +1 -1
  162. package/dist/views/seo/ContentTab.d.ts.map +1 -1
  163. package/dist/views/seo/ContentTab.js +22 -6
  164. package/dist/views/seo/ContentTab.js.map +1 -1
  165. package/dist/views/settings/AccessProtectionCard.d.ts +5 -1
  166. package/dist/views/settings/AccessProtectionCard.d.ts.map +1 -1
  167. package/dist/views/settings/AccessProtectionCard.js +13 -10
  168. package/dist/views/settings/AccessProtectionCard.js.map +1 -1
  169. package/dist/views/settings/SecurityTab.d.ts.map +1 -1
  170. package/dist/views/settings/SecurityTab.js +3 -3
  171. package/dist/views/settings/SecurityTab.js.map +1 -1
  172. package/dist/views/settings/SessionPolicyCard.d.ts +1 -2
  173. package/dist/views/settings/SessionPolicyCard.d.ts.map +1 -1
  174. package/dist/views/settings/SessionPolicyCard.js +12 -5
  175. package/dist/views/settings/SessionPolicyCard.js.map +1 -1
  176. package/dist/views/settings/useSecuritySettings.d.ts +13 -1
  177. package/dist/views/settings/useSecuritySettings.d.ts.map +1 -1
  178. package/dist/views/settings/useSecuritySettings.js +47 -4
  179. package/dist/views/settings/useSecuritySettings.js.map +1 -1
  180. package/package.json +2 -2
  181. package/src/AdminRoot.tsx +43 -10
  182. package/src/__tests__/components/inspector-pane.test.tsx +64 -0
  183. package/src/__tests__/hooks/useIdleLogout.test.tsx +86 -0
  184. package/src/__tests__/lib/pages-tree.test.ts +197 -0
  185. package/src/__tests__/lib/post-types-service.test.ts +112 -0
  186. package/src/__tests__/views/collection-list-nav.render.test.tsx +51 -5
  187. package/src/__tests__/views/dashboard.test.tsx +7 -3
  188. package/src/__tests__/views/forms-list.render.test.tsx +34 -6
  189. package/src/__tests__/views/media-seo-audit.render.test.tsx +117 -0
  190. package/src/__tests__/views/onboarding-block.render.test.tsx +193 -0
  191. package/src/__tests__/views/page-builder-sections-panel.render.test.tsx +138 -0
  192. package/src/__tests__/views/page-templates.render.test.tsx +142 -0
  193. package/src/__tests__/views/pages-list-view.test.tsx +93 -1
  194. package/src/__tests__/views/post-type-editor.render.test.tsx +116 -0
  195. package/src/__tests__/views/security-settings.render.test.tsx +111 -4
  196. package/src/__tests__/views/seo-content-pane.render.test.tsx +142 -0
  197. package/src/components/collections/EntryDetailPane.tsx +182 -0
  198. package/src/components/forms/FieldsPanel.tsx +3 -1
  199. package/src/components/forms/FormSchemaPane.tsx +192 -0
  200. package/src/components/script-tags/ScriptTagEditorPane.tsx +474 -0
  201. package/src/components/seo/SeoEditorPane.tsx +533 -0
  202. package/src/components/ui/InspectorPane.tsx +129 -0
  203. package/src/components/ui/index.ts +10 -0
  204. package/src/hooks/useIdleLogout.ts +77 -0
  205. package/src/lib/api.ts +8 -2
  206. package/src/lib/page-editor-service.ts +16 -2
  207. package/src/lib/pages-tree.ts +145 -0
  208. package/src/lib/post-types-service.ts +129 -0
  209. package/src/views/CollectionList.tsx +158 -110
  210. package/src/views/Dashboard.tsx +238 -196
  211. package/src/views/Forms.tsx +154 -126
  212. package/src/views/MediaBrowser.tsx +641 -511
  213. package/src/views/MediaSeoAudit.tsx +320 -0
  214. package/src/views/Pages/PagesListView.tsx +352 -183
  215. package/src/views/Pages/PagesTreeTable.tsx +339 -0
  216. package/src/views/Posts/PostTypeEditor.tsx +568 -0
  217. package/src/views/Posts/PostTypesView.tsx +5 -4
  218. package/src/views/ScriptTags.tsx +204 -129
  219. package/src/views/dashboard/OnboardingBlock.tsx +233 -0
  220. package/src/views/page-builder/BuilderSectionsPanel.tsx +304 -0
  221. package/src/views/page-builder/PageBuilder.tsx +69 -2
  222. package/src/views/page-builder/PageTemplates.tsx +340 -57
  223. package/src/views/page-editor/PageSectionEditor.tsx +9 -2
  224. package/src/views/page-editor/PageSettingsModal.tsx +75 -2
  225. package/src/views/seo/ContentTab.tsx +113 -80
  226. package/src/views/settings/AccessProtectionCard.tsx +83 -53
  227. package/src/views/settings/SecurityTab.tsx +23 -2
  228. package/src/views/settings/SessionPolicyCard.tsx +45 -9
  229. package/src/views/settings/useSecuritySettings.ts +78 -22
  230. package/dist/components/forms/FormSchemaDrawer.d.ts +0 -9
  231. package/dist/components/forms/FormSchemaDrawer.d.ts.map +0 -1
  232. package/dist/components/forms/FormSchemaDrawer.js +0 -99
  233. package/dist/components/forms/FormSchemaDrawer.js.map +0 -1
  234. package/dist/components/seo/SeoEditorDrawer.d.ts +0 -8
  235. package/dist/components/seo/SeoEditorDrawer.d.ts.map +0 -1
  236. package/dist/components/seo/SeoEditorDrawer.js +0 -172
  237. package/dist/components/seo/SeoEditorDrawer.js.map +0 -1
  238. package/dist/views/ScriptTagEditor.d.ts +0 -6
  239. package/dist/views/ScriptTagEditor.d.ts.map +0 -1
  240. package/dist/views/ScriptTagEditor.js +0 -111
  241. package/dist/views/ScriptTagEditor.js.map +0 -1
  242. package/src/components/forms/FormSchemaDrawer.tsx +0 -192
  243. package/src/components/seo/SeoEditorDrawer.tsx +0 -529
  244. package/src/views/ScriptTagEditor.tsx +0 -353
@@ -6,7 +6,7 @@ interface PageSettingsModalProps {
6
6
  onClose: () => void;
7
7
  onSave: (patch: Partial<EditorPage>) => void;
8
8
  }
9
- /** Edits page-level fields: title, slug, path, and SEO. */
9
+ /** Edits page-level fields: title, slug, path, parent page, and SEO. */
10
10
  export declare function PageSettingsModal({ open, page, canEdit, onClose, onSave, }: PageSettingsModalProps): import("react/jsx-runtime").JSX.Element;
11
11
  export {};
12
12
  //# sourceMappingURL=PageSettingsModal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageSettingsModal.d.ts","sourceRoot":"","sources":["../../../src/views/page-editor/PageSettingsModal.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAOlE,UAAU,sBAAsB;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;CAC7C;AAQD,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,OAAO,EACP,MAAM,GACP,EAAE,sBAAsB,2CAyIxB"}
1
+ {"version":3,"file":"PageSettingsModal.d.ts","sourceRoot":"","sources":["../../../src/views/page-editor/PageSettingsModal.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAOlE,UAAU,sBAAsB;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;CAC7C;AAaD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,OAAO,EACP,MAAM,GACP,EAAE,sBAAsB,2CA4MxB"}
@@ -5,6 +5,7 @@ import { normalizeSlug, validateSlug } from '@actuate-media/cms-core/client';
5
5
  import { Modal } from '../../components/ui/Modal.js';
6
6
  import { Button } from '../../components/ui/Button.js';
7
7
  import { SeoCharCount } from '../../components/seo/SeoCharCount.js';
8
+ import { cmsApi } from '../../lib/api.js';
8
9
  const SEO_TITLE_MIN = 30;
9
10
  const SEO_TITLE_MAX = 60;
10
11
  const SEO_DESC_MIN = 120;
@@ -12,25 +13,56 @@ const SEO_DESC_MAX = 160;
12
13
  const LABEL = 'text-foreground mb-1 block text-xs font-medium';
13
14
  const INPUT = 'border-input bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none';
14
15
  const slugify = normalizeSlug;
15
- /** Edits page-level fields: title, slug, path, and SEO. */
16
+ /** Edits page-level fields: title, slug, path, parent page, and SEO. */
16
17
  export function PageSettingsModal({ open, page, canEdit, onClose, onSave, }) {
17
18
  const [title, setTitle] = useState(page.title);
18
19
  const [slug, setSlug] = useState(page.slug);
19
20
  const [path, setPath] = useState(page.path);
21
+ const [parentPageId, setParentPageId] = useState(page.parentPageId ?? '');
20
22
  const [seoTitle, setSeoTitle] = useState(page.seoTitle);
21
23
  const [seoDescription, setSeoDescription] = useState(page.seoDescription);
22
24
  // Auto-derive slug/path from title until the user edits slug manually.
23
25
  const [slugTouched, setSlugTouched] = useState(Boolean(page.slug));
26
+ const [parentOptions, setParentOptions] = useState(null);
24
27
  useEffect(() => {
25
28
  if (!open)
26
29
  return;
27
30
  setTitle(page.title);
28
31
  setSlug(page.slug);
29
32
  setPath(page.path);
33
+ setParentPageId(page.parentPageId ?? '');
30
34
  setSeoTitle(page.seoTitle);
31
35
  setSeoDescription(page.seoDescription);
32
36
  setSlugTouched(Boolean(page.slug));
33
37
  }, [open, page]);
38
+ // Load the parent-page choices lazily the first time the modal opens.
39
+ // The page itself is excluded (a page can't be its own parent); deeper
40
+ // cycle protection lives in the tree builder, which breaks bad chains.
41
+ useEffect(() => {
42
+ if (!open || parentOptions !== null)
43
+ return;
44
+ let cancelled = false;
45
+ cmsApi('/collections/pages?pageSize=500&sort=updatedAt&order=desc')
46
+ .then((res) => {
47
+ if (cancelled)
48
+ return;
49
+ const docs = res.data?.docs ?? [];
50
+ const options = docs
51
+ .filter((d) => d.id !== page.id)
52
+ .map((d) => ({ id: d.id, title: d.title ?? '(untitled)' }))
53
+ .sort((a, b) => a.title.localeCompare(b.title));
54
+ setParentOptions(options);
55
+ })
56
+ .catch(() => {
57
+ // Leave the picker in its loading state note; the rest of the
58
+ // settings form stays fully usable.
59
+ if (!cancelled)
60
+ setParentOptions([]);
61
+ });
62
+ return () => {
63
+ cancelled = true;
64
+ };
65
+ }, [open, parentOptions, page.id]);
34
66
  function handleTitle(next) {
35
67
  setTitle(next);
36
68
  if (!slugTouched) {
@@ -44,12 +76,19 @@ export function PageSettingsModal({ open, page, canEdit, onClose, onSave, }) {
44
76
  function handleSave() {
45
77
  if (slugError)
46
78
  return;
47
- onSave({ title, slug, path: path || (slug ? `/${slug}` : '/'), seoTitle, seoDescription });
79
+ onSave({
80
+ title,
81
+ slug,
82
+ path: path || (slug ? `/${slug}` : '/'),
83
+ parentPageId: parentPageId || null,
84
+ seoTitle,
85
+ seoDescription,
86
+ });
48
87
  onClose();
49
88
  }
50
89
  return (_jsx(Modal, { open: open, onClose: onClose, title: "Page settings", actions: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", onClick: onClose, children: "Cancel" }), _jsx(Button, { variant: "primary", onClick: handleSave, disabled: !canEdit || Boolean(slugError), children: "Done" })] }), children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: "ps-title", children: ["Title ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: "ps-title", className: INPUT, value: title, disabled: !canEdit, onChange: (e) => handleTitle(e.target.value) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: "ps-slug", children: "Slug" }), _jsx("input", { id: "ps-slug", className: INPUT, value: slug, disabled: !canEdit, "aria-invalid": Boolean(slugError), "aria-describedby": slugError ? 'ps-slug-error' : undefined, onChange: (e) => {
51
90
  setSlugTouched(true);
52
91
  setSlug(slugify(e.target.value));
53
- } }), slugError && (_jsx("p", { id: "ps-slug-error", className: "text-destructive mt-1 text-xs", children: slugError }))] }), _jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: "ps-path", children: ["Path ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: "ps-path", className: INPUT, value: path, disabled: !canEdit, placeholder: "/about/story", onChange: (e) => setPath(e.target.value) })] })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: `${LABEL} mb-0`, htmlFor: "ps-seo-title", children: "SEO title" }), _jsx(SeoCharCount, { value: seoTitle, min: SEO_TITLE_MIN, max: SEO_TITLE_MAX })] }), _jsx("input", { id: "ps-seo-title", className: INPUT, value: seoTitle, disabled: !canEdit, placeholder: title || 'Defaults to the page title', onChange: (e) => setSeoTitle(e.target.value) })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: `${LABEL} mb-0`, htmlFor: "ps-seo-desc", children: "SEO description" }), _jsx(SeoCharCount, { value: seoDescription, min: SEO_DESC_MIN, max: SEO_DESC_MAX })] }), _jsx("textarea", { id: "ps-seo-desc", className: `${INPUT} min-h-[64px] resize-y`, value: seoDescription, disabled: !canEdit, placeholder: "Summarize the page for search results (120\u2013160 characters)", onChange: (e) => setSeoDescription(e.target.value) })] })] }) }));
92
+ } }), slugError && (_jsx("p", { id: "ps-slug-error", className: "text-destructive mt-1 text-xs", children: slugError }))] }), _jsxs("div", { children: [_jsxs("label", { className: LABEL, htmlFor: "ps-path", children: ["Path ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx("input", { id: "ps-path", className: INPUT, value: path, disabled: !canEdit, placeholder: "/about/story", onChange: (e) => setPath(e.target.value) })] })] }), _jsxs("div", { children: [_jsx("label", { className: LABEL, htmlFor: "ps-parent", children: "Parent page" }), _jsxs("select", { id: "ps-parent", className: INPUT, value: parentPageId, disabled: !canEdit || parentOptions === null, onChange: (e) => setParentPageId(e.target.value), children: [_jsx("option", { value: "", children: "None \u2014 top level" }), parentPageId && !(parentOptions ?? []).some((p) => p.id === parentPageId) && (_jsx("option", { value: parentPageId, children: parentOptions === null ? 'Loading…' : 'Current parent' })), (parentOptions ?? []).map((p) => (_jsx("option", { value: p.id, children: p.title }, p.id)))] }), _jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: "Nests this page under a parent in the Pages tree view." })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: `${LABEL} mb-0`, htmlFor: "ps-seo-title", children: "SEO title" }), _jsx(SeoCharCount, { value: seoTitle, min: SEO_TITLE_MIN, max: SEO_TITLE_MAX })] }), _jsx("input", { id: "ps-seo-title", className: INPUT, value: seoTitle, disabled: !canEdit, placeholder: title || 'Defaults to the page title', onChange: (e) => setSeoTitle(e.target.value) })] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: `${LABEL} mb-0`, htmlFor: "ps-seo-desc", children: "SEO description" }), _jsx(SeoCharCount, { value: seoDescription, min: SEO_DESC_MIN, max: SEO_DESC_MAX })] }), _jsx("textarea", { id: "ps-seo-desc", className: `${INPUT} min-h-[64px] resize-y`, value: seoDescription, disabled: !canEdit, placeholder: "Summarize the page for search results (120\u2013160 characters)", onChange: (e) => setSeoDescription(e.target.value) })] })] }) }));
54
93
  }
55
94
  //# sourceMappingURL=PageSettingsModal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageSettingsModal.js","sourceRoot":"","sources":["../../../src/views/page-editor/PageSettingsModal.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PageSettingsModal.js","sourceRoot":"","sources":["../../../src/views/page-editor/PageSettingsModal.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ContentTab.d.ts","sourceRoot":"","sources":["../../../src/views/seo/ContentTab.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,UAAU,CAAC,EACzB,iBAAiB,EACjB,eAAe,GAChB,EAAE;IACD,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC,2CAgIA"}
1
+ {"version":3,"file":"ContentTab.d.ts","sourceRoot":"","sources":["../../../src/views/seo/ContentTab.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,UAAU,CAAC,EACzB,iBAAiB,EACjB,eAAe,GAChB,EAAE;IACD,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC,2CAwJA"}
@@ -1,10 +1,17 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Content SEO tab — pages/posts list with per-item SEO editing in an inline
5
+ * 380px inspector pane (design split-pane pattern; previously an overlay
6
+ * drawer). Row click toggles the pane; deep links
7
+ * (`?tab=content&entityType=…&entityId=…`) open it on mount.
8
+ */
3
9
  import { useMemo, useState } from 'react';
4
- import { Search, FileText, Pencil } from 'lucide-react';
10
+ import { Search, FileText } from 'lucide-react';
5
11
  import { fetchSeoContentRecords, applyContentSeoQuery, } from '../../lib/seo-service.js';
6
12
  import { SectionCard, SeoLoading, SeoEmptyState, SeoErrorState, ScorePill, SeoStatusBadge, } from '../../components/seo/primitives.js';
7
- import { SeoEditorDrawer } from '../../components/seo/SeoEditorDrawer.js';
13
+ import { InspectorPane, SplitPaneLayout, SplitPaneList } from '../../components/ui/InspectorPane.js';
14
+ import { SeoEditorPane } from '../../components/seo/SeoEditorPane.js';
8
15
  import { useSeoResource } from './useSeoResource.js';
9
16
  const FILTERS = [
10
17
  { id: 'all', label: 'All' },
@@ -16,12 +23,21 @@ export function ContentTab({ initialEntityType, initialEntityId, }) {
16
23
  const { data, loading, error, refetch } = useSeoResource(fetchSeoContentRecords, []);
17
24
  const [search, setSearch] = useState('');
18
25
  const [filter, setFilter] = useState('all');
19
- const [editor, setEditor] = useState(initialEntityType && initialEntityId ? { type: initialEntityType, id: initialEntityId } : null);
26
+ const [selection, setSelection] = useState(initialEntityType && initialEntityId ? { type: initialEntityType, id: initialEntityId } : null);
20
27
  const rows = useMemo(() => applyContentSeoQuery(data ?? [], { search, filter }), [data, search, filter]);
28
+ const toggleRow = (type, id) => {
29
+ setSelection((prev) => (prev?.type === type && prev.id === id ? null : { type, id }));
30
+ };
21
31
  return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { className: "relative max-w-sm flex-1", children: [_jsx(Search, { className: "text-muted-foreground pointer-events-none absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2", "aria-hidden": true }), _jsx("input", { className: inputCls, placeholder: "Search content\u2026", value: search, onChange: (e) => setSearch(e.target.value), "aria-label": "Search content" })] }), _jsx("div", { className: "flex gap-1", role: "group", "aria-label": "Content type filter", children: FILTERS.map((f) => (_jsx("button", { type: "button", "aria-pressed": filter === f.id, onClick: () => setFilter(f.id), className: `focus-visible:ring-ring rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none ${filter === f.id
22
32
  ? 'bg-primary text-primary-foreground'
23
- : 'text-muted-foreground hover:bg-accent hover:text-foreground'}`, children: f.label }, f.id))) })] }), _jsx(SectionCard, { children: loading ? (_jsx(SeoLoading, { label: "Loading content\u2026" })) : error ? (_jsx(SeoErrorState, { message: error, onRetry: refetch })) : rows.length === 0 ? (_jsx(SeoEmptyState, { icon: _jsx(FileText, { size: 24 }), title: search || filter !== 'all' ? 'No matching content' : 'No content yet', description: search || filter !== 'all'
24
- ? 'Try adjusting your search or filter.'
25
- : 'Publish pages or posts to manage their SEO here.' })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", "aria-label": "Content SEO", 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: "Title" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Type" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Meta" }), _jsx("th", { className: "py-2 pr-4 text-right font-medium", children: "Score" }), _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: rows.map((r) => (_jsxs("tr", { className: "hover:bg-accent/40", children: [_jsxs("td", { className: "py-2.5 pr-4", children: [_jsx("span", { className: "text-foreground block font-medium", children: r.title }), _jsx("span", { className: "text-muted-foreground block truncate", children: r.url })] }), _jsx("td", { className: "py-2.5 pr-4 capitalize", children: _jsx("span", { className: "text-muted-foreground", children: r.entityType }) }), _jsx("td", { className: "py-2.5 pr-4", children: _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(SeoStatusBadge, { label: r.metaTitle ? 'Title' : 'No title', tone: r.metaTitle ? 'good' : 'critical' }), _jsx(SeoStatusBadge, { label: r.metaDescription ? 'Desc' : 'No desc', tone: r.metaDescription ? 'good' : 'critical' }), r.noindex && _jsx(SeoStatusBadge, { label: "No-index", tone: "fair" })] }) }), _jsx("td", { className: "py-2.5 pr-4 text-right", children: _jsx(ScorePill, { score: r.seoScore }) }), _jsx("td", { className: "py-2.5 text-right", children: _jsxs("button", { onClick: () => setEditor({ type: r.entityType, id: r.entityId }), className: "text-primary hover:bg-accent focus-visible:ring-ring inline-flex items-center gap-1 rounded-md px-2 py-1 text-sm focus-visible:ring-2 focus-visible:outline-none", children: [_jsx(Pencil, { className: "h-3.5 w-3.5", "aria-hidden": true }), " Edit"] }) })] }, `${r.entityType}-${r.entityId}`))) })] }) })) }), _jsx(SeoEditorDrawer, { open: editor !== null, onOpenChange: (o) => !o && setEditor(null), entityType: editor?.type ?? null, entityId: editor?.id ?? null, onSaved: refetch })] }));
33
+ : 'text-muted-foreground hover:bg-accent hover:text-foreground'}`, children: f.label }, f.id))) })] }), _jsxs(SplitPaneLayout, { className: "h-[calc(100vh-280px)] min-h-[440px]", children: [_jsx(SplitPaneList, { children: _jsx(SectionCard, { children: loading ? (_jsx(SeoLoading, { label: "Loading content\u2026" })) : error ? (_jsx(SeoErrorState, { message: error, onRetry: refetch })) : rows.length === 0 ? (_jsx(SeoEmptyState, { icon: _jsx(FileText, { size: 24 }), title: search || filter !== 'all' ? 'No matching content' : 'No content yet', description: search || filter !== 'all'
34
+ ? 'Try adjusting your search or filter.'
35
+ : 'Publish pages or posts to manage their SEO here.' })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", "aria-label": "Content SEO", 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: "Title" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Type" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Meta" }), _jsx("th", { className: "py-2 text-right font-medium", children: "Score" })] }) }), _jsx("tbody", { className: "divide-border divide-y", children: rows.map((r) => {
36
+ const isSelected = selection?.type === r.entityType && selection.id === r.entityId;
37
+ return (_jsxs("tr", { className: `cursor-pointer transition-colors ${isSelected ? 'bg-[var(--acc-l)]' : 'hover:bg-accent/40'}`, onClick: () => toggleRow(r.entityType, r.entityId), children: [_jsx("td", { className: "py-2.5 pr-4", children: _jsxs("button", { type: "button", onClick: (e) => {
38
+ e.stopPropagation();
39
+ toggleRow(r.entityType, r.entityId);
40
+ }, "aria-expanded": isSelected, className: "text-left", children: [_jsx("span", { className: "text-foreground block font-medium", children: r.title }), _jsx("span", { className: "text-muted-foreground block truncate", children: r.url })] }) }), _jsx("td", { className: "py-2.5 pr-4 capitalize", children: _jsx("span", { className: "text-muted-foreground", children: r.entityType }) }), _jsx("td", { className: "py-2.5 pr-4", children: _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(SeoStatusBadge, { label: r.metaTitle ? 'Title' : 'No title', tone: r.metaTitle ? 'good' : 'critical' }), _jsx(SeoStatusBadge, { label: r.metaDescription ? 'Desc' : 'No desc', tone: r.metaDescription ? 'good' : 'critical' }), r.noindex && _jsx(SeoStatusBadge, { label: "No-index", tone: "fair" })] }) }), _jsx("td", { className: "py-2.5 text-right", children: _jsx(ScorePill, { score: r.seoScore }) })] }, `${r.entityType}-${r.entityId}`));
41
+ }) })] }) })) }) }), _jsx(InspectorPane, { open: selection !== null, width: 380, "aria-label": "SEO editor", children: selection && (_jsx(SeoEditorPane, { entityType: selection.type, entityId: selection.id, onClose: () => setSelection(null), onSaved: refetch }, `${selection.type}-${selection.id}`)) })] })] }));
26
42
  }
27
43
  //# sourceMappingURL=ContentTab.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContentTab.js","sourceRoot":"","sources":["../../../src/views/seo/ContentTab.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ContentTab.js","sourceRoot":"","sources":["../../../src/views/seo/ContentTab.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,9 @@
1
1
  import { type IpAllowlistStatus, type SecretsStatus, type SecuritySourceMetadata } from '@actuate-media/cms-core/security-center';
2
- export declare function AccessProtectionCard({ ipAllowlist, secrets, csrfEnabled, uploadValidation, sources, onNavigate, }: {
2
+ import { type SecurityForm } from './useSecuritySettings.js';
3
+ export declare function AccessProtectionCard({ form, setField, canEdit, ipAllowlist, secrets, csrfEnabled, uploadValidation, sources, onNavigate, }: {
4
+ form: SecurityForm;
5
+ setField: <K extends keyof SecurityForm>(key: K, value: SecurityForm[K]) => void;
6
+ canEdit: boolean;
3
7
  ipAllowlist: IpAllowlistStatus;
4
8
  secrets: SecretsStatus;
5
9
  csrfEnabled: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"AccessProtectionCard.d.ts","sourceRoot":"","sources":["../../../src/views/settings/AccessProtectionCard.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC5B,MAAM,yCAAyC,CAAA;AAIhD,wBAAgB,oBAAoB,CAAC,EACnC,WAAW,EACX,OAAO,EACP,WAAW,EACX,gBAAgB,EAChB,OAAO,EACP,UAAU,GACX,EAAE;IACD,WAAW,EAAE,iBAAiB,CAAA;IAC9B,OAAO,EAAE,aAAa,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;IAC/C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,2CAmHA"}
1
+ {"version":3,"file":"AccessProtectionCard.d.ts","sourceRoot":"","sources":["../../../src/views/settings/AccessProtectionCard.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC5B,MAAM,yCAAyC,CAAA;AAGhD,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEhF,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,WAAW,EACX,OAAO,EACP,WAAW,EACX,gBAAgB,EAChB,OAAO,EACP,UAAU,GACX,EAAE;IACD,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAChF,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,iBAAiB,CAAA;IAC9B,OAAO,EAAE,aAAa,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;IAC/C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,2CA0IA"}
@@ -1,20 +1,23 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useId, useState } from 'react';
4
- import { Check, X } from 'lucide-react';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useId } from 'react';
4
+ import { AlertTriangle } from 'lucide-react';
5
5
  import { validateIpRange, } from '@actuate-media/cms-core/security-center';
6
- import { SettingsSourceBadge } from './components.js';
6
+ import { SettingsSourceBadge, SettingsToggleRow } from './components.js';
7
7
  import { SecurityCard, StatusRow } from './securityPrimitives.js';
8
- export function AccessProtectionCard({ ipAllowlist, secrets, csrfEnabled, uploadValidation, sources, onNavigate, }) {
8
+ import { parseAllowlistText } from './useSecuritySettings.js';
9
+ export function AccessProtectionCard({ form, setField, canEdit, ipAllowlist, secrets, csrfEnabled, uploadValidation, sources, onNavigate, }) {
9
10
  const headingId = useId();
10
- const ipTestId = useId();
11
- const [ipTest, setIpTest] = useState('');
12
- const ipTestValid = ipTest.trim() === '' ? null : validateIpRange(ipTest);
11
+ const allowlistId = useId();
12
+ const allowlistHintId = useId();
13
+ const entries = parseAllowlistText(form.ipAllowlistText);
14
+ const invalidEntries = entries.filter((entry) => !validateIpRange(entry));
15
+ const configRanges = ipAllowlist.configRanges ?? [];
13
16
  const distributed = secrets.rateLimitBackend === 'distributed';
14
- return (_jsxs(SecurityCard, { headingId: headingId, title: "Access & Request Protection", description: "Network-level access restrictions and request-level protections. These are enforced by the platform; edit network rules in config.", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-foreground text-sm font-medium", children: "Admin IP allowlist" }), _jsx(SettingsSourceBadge, { meta: sources.ipAllowlist })] }), _jsx(StatusRow, { status: ipAllowlist.enabled ? 'pass' : 'unknown', label: "Status", value: ipAllowlist.enabled ? `${ipAllowlist.ranges.length} range(s)` : 'Not configured' }), ipAllowlist.currentIp && (_jsx(StatusRow, { status: ipAllowlist.currentIpAllowed === null
17
+ return (_jsxs(SecurityCard, { headingId: headingId, title: "Access Control", description: "Restrict where the admin and CMS API can be reached from, and control the audit trail.", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("label", { htmlFor: allowlistId, className: "text-foreground text-base font-medium", children: "Allowed IP addresses" }), _jsx(SettingsSourceBadge, { meta: sources.ipAllowlist })] }), _jsx("textarea", { id: allowlistId, rows: 3, value: form.ipAllowlistText, disabled: !canEdit, onChange: (e) => setField('ipAllowlistText', e.target.value), placeholder: '203.0.113.0/24\n198.51.100.42', "aria-describedby": allowlistHintId, "aria-invalid": invalidEntries.length > 0 || undefined, className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full resize-y rounded-md border px-3 py-2 font-mono text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50" }), _jsx("p", { id: allowlistHintId, className: "text-muted-foreground text-sm", children: "Restrict admin access to these ranges. One IP or CIDR range per line; leave empty to allow all addresses." }), invalidEntries.length > 0 && (_jsxs("p", { className: "text-destructive text-sm", role: "alert", children: ["Invalid entries: ", invalidEntries.join(', ')] })), entries.length > 0 && (_jsxs("div", { className: "border-warning/30 bg-warning/10 text-warning flex items-start gap-2 rounded-md border p-2.5 text-sm", children: [_jsx(AlertTriangle, { size: 15, className: "mt-0.5 shrink-0", "aria-hidden": "true" }), _jsxs("span", { children: ["Make sure your own IP", ipAllowlist.currentIp ? (_jsxs(_Fragment, { children: [' ', "(", _jsx("span", { className: "font-mono", children: ipAllowlist.currentIp }), ")"] })) : null, ' ', "is covered \u2014 saving a list that excludes it will lock you out of the admin."] })] })), configRanges.length > 0 && (_jsxs("div", { className: "pt-1", children: [_jsxs("p", { className: "text-muted-foreground text-sm", children: ["Always enforced from ", _jsx("code", { className: "font-mono", children: "admin.ipAllowlist" }), " in actuate.config.ts:"] }), _jsx("div", { className: "text-muted-foreground mt-1 flex flex-wrap gap-1.5", children: configRanges.map((r) => (_jsx("code", { className: "bg-muted rounded px-1.5 py-0.5 font-mono text-xs", children: r }, r))) })] })), ipAllowlist.currentIp && ipAllowlist.enabled && (_jsx(StatusRow, { status: ipAllowlist.currentIpAllowed === null
15
18
  ? 'unknown'
16
19
  : ipAllowlist.currentIpAllowed
17
20
  ? 'pass'
18
- : 'fail', label: "Your current IP", value: _jsxs("span", { className: "font-mono text-xs", children: [ipAllowlist.currentIp, ipAllowlist.currentIpAllowed === false && ' (blocked)'] }) })), ipAllowlist.enabled && (_jsx("div", { className: "text-muted-foreground flex flex-wrap gap-1.5 pt-1", children: ipAllowlist.ranges.map((r) => (_jsx("code", { className: "bg-muted rounded px-1.5 py-0.5 font-mono text-xs", children: r }, r))) })), _jsxs("div", { className: "pt-1", children: [_jsx("label", { htmlFor: ipTestId, className: "text-muted-foreground mb-1 block text-sm", children: "Validate an IP or CIDR range" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { id: ipTestId, type: "text", value: ipTest, onChange: (e) => setIpTest(e.target.value), placeholder: "e.g. 203.0.113.0/24", className: "border-border bg-input-background text-foreground focus-visible:ring-ring w-full max-w-xs rounded-md border px-3 py-1.5 font-mono text-sm focus-visible:ring-2 focus-visible:outline-none" }), ipTestValid === true && (_jsxs("span", { className: "text-success flex items-center gap-1 text-sm", children: [_jsx(Check, { size: 15, "aria-hidden": "true" }), " Valid"] })), ipTestValid === false && (_jsxs("span", { className: "text-destructive flex items-center gap-1 text-sm", children: [_jsx(X, { size: 15, "aria-hidden": "true" }), " Invalid"] }))] }), _jsxs("p", { className: "text-muted-foreground mt-1 text-xs", children: ["Add validated ranges to ", _jsx("code", { className: "font-mono", children: "admin.ipAllowlist" }), " in actuate.config.ts; the middleware enforces them."] })] })] }), _jsxs("div", { className: "border-border mt-4 space-y-2 border-t pt-4", children: [_jsx(StatusRow, { status: csrfEnabled ? 'pass' : 'fail', label: "CSRF protection", value: csrfEnabled ? 'Enabled' : 'Disabled', badge: _jsx(SettingsSourceBadge, { meta: sources.csrf }) }), _jsx(StatusRow, { status: distributed ? 'pass' : 'warning', label: "Rate limiting", value: distributed ? 'Distributed (Upstash)' : 'In-memory', badge: _jsx(SettingsSourceBadge, { meta: sources.rateLimiting }) }), _jsx(StatusRow, { status: uploadValidation ? 'pass' : 'warning', label: "Upload validation", value: "MIME + magic bytes + SVG sanitization", badge: _jsx(SettingsSourceBadge, { meta: sources.uploadValidation }) }), onNavigate && (_jsx("button", { type: "button", onClick: () => onNavigate('/media'), className: "text-brand mt-1 text-sm hover:underline", children: "Manage upload rules in Media \u2192" }))] })] }));
21
+ : 'fail', label: "Your current IP", value: _jsxs("span", { className: "font-mono text-xs", children: [ipAllowlist.currentIp, ipAllowlist.currentIpAllowed === false && ' (blocked)'] }) }))] }), _jsx("div", { className: "border-border mt-4 border-t pt-4", children: _jsx(SettingsToggleRow, { label: "Audit logging", description: "Record every content change, login and settings update. Security-critical events (failed logins, MFA and security policy changes) are always recorded.", checked: form.auditLoggingEnabled, disabled: !canEdit, onChange: (value) => setField('auditLoggingEnabled', value) }) }), _jsxs("div", { className: "border-border mt-4 space-y-2 border-t pt-4", children: [_jsx(StatusRow, { status: csrfEnabled ? 'pass' : 'fail', label: "CSRF protection", value: csrfEnabled ? 'Enabled' : 'Disabled', badge: _jsx(SettingsSourceBadge, { meta: sources.csrf }) }), _jsx(StatusRow, { status: distributed ? 'pass' : 'warning', label: "Rate limiting", value: distributed ? 'Distributed (Upstash)' : 'In-memory', badge: _jsx(SettingsSourceBadge, { meta: sources.rateLimiting }) }), _jsx(StatusRow, { status: uploadValidation ? 'pass' : 'warning', label: "Upload validation", value: "MIME + magic bytes + SVG sanitization", badge: _jsx(SettingsSourceBadge, { meta: sources.uploadValidation }) }), onNavigate && (_jsx("button", { type: "button", onClick: () => onNavigate('/media'), className: "text-brand mt-1 text-sm hover:underline", children: "Manage upload rules in Media \u2192" }))] })] }));
19
22
  }
20
23
  //# sourceMappingURL=AccessProtectionCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccessProtectionCard.js","sourceRoot":"","sources":["../../../src/views/settings/AccessProtectionCard.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AccessProtectionCard.js","sourceRoot":"","sources":["../../../src/views/settings/AccessProtectionCard.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityTab.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SecurityTab.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,UAAU,GACX,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,2CAmIA"}
1
+ {"version":3,"file":"SecurityTab.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SecurityTab.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,UAAU,GACX,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,2CAoJA"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect } from 'react';
4
4
  import { ShieldAlert } from 'lucide-react';
5
- import { SettingsSaveBar, SettingsValidationSummary } from './components.js';
5
+ import { ConfirmDangerousSettingDialog, SettingsSaveBar, SettingsValidationSummary, } from './components.js';
6
6
  import { AccessProtectionCard } from './AccessProtectionCard.js';
7
7
  import { AuthMfaCard } from './AuthMfaCard.js';
8
8
  import { SecretsAuditCard } from './SecretsAuditCard.js';
@@ -14,7 +14,7 @@ function CardSkeleton() {
14
14
  }
15
15
  export function SecurityTab({ role, onNavigate, }) {
16
16
  const canEdit = role === 'ADMIN';
17
- const { loading, loadError, data, form, setField, dirty, issues, hasErrors, saveState, save, reset, revokeState, revokeAllOtherSessions, } = useSecuritySettings(canEdit);
17
+ const { loading, loadError, data, form, setField, dirty, issues, hasErrors, saveState, save, reset, lockoutPrompt, dismissLockoutPrompt, revokeState, revokeAllOtherSessions, } = useSecuritySettings(canEdit);
18
18
  // Deep-link support: /settings?tab=security&section=sessions|ip-allowlist|audit
19
19
  useEffect(() => {
20
20
  if (loading || typeof window === 'undefined')
@@ -36,6 +36,6 @@ export function SecurityTab({ role, onNavigate, }) {
36
36
  ? 'Ask an administrator to review the Security tab.'
37
37
  : (loadError ?? 'The security service could not be reached. Try again shortly.') })] })] }));
38
38
  }
39
- return (_jsxs("div", { className: "space-y-4 pb-4", children: [_jsx(SecurityStatusCard, { status: data.status, onNavigate: onNavigate }), issues.length > 0 && _jsx(SettingsValidationSummary, { issues: issues }), !canEdit && (_jsx("p", { className: "text-muted-foreground text-sm", children: "You have read-only access. Only administrators can change security settings." })), _jsx(AuthMfaCard, { form: form, setField: setField, canEdit: canEdit, viewerHasMfa: data.viewerHasMfa, withMfa: data.users.withMfa, totalAdmins: data.users.totalAdmins, onNavigate: onNavigate }), _jsx("div", { id: "security-sessions", children: _jsx(SessionPolicyCard, { form: form, setField: setField, canEdit: canEdit, sessionMaxAgeHours: data.sessionMaxAgeHours, activeSessions: data.activeSessions, revokeState: revokeState, onRevokeAll: () => void revokeAllOtherSessions() }) }), _jsx("div", { id: "security-ip-allowlist", children: _jsx(AccessProtectionCard, { ipAllowlist: data.ipAllowlist, secrets: data.secrets, csrfEnabled: data.csrfEnabled, uploadValidation: data.uploadValidation, sources: data.sources, onNavigate: onNavigate }) }), _jsx("div", { id: "security-audit", children: _jsx(SecretsAuditCard, { secrets: data.secrets, auditEnabled: data.auditEnabled, failedLogins24h: data.failedLogins24h, users: data.users, apiKeys: data.apiKeys, sources: data.sources, onNavigate: onNavigate }) }), saveState === 'error' && (_jsx("p", { className: "text-destructive text-sm", role: "alert", children: "Failed to save security settings. Please try again." })), _jsx(SettingsSaveBar, { dirty: dirty, canEdit: canEdit, hasErrors: hasErrors, saveState: saveState, onSave: () => void save(), onReset: reset })] }));
39
+ return (_jsxs("div", { className: "space-y-4 pb-4", children: [_jsx(SecurityStatusCard, { status: data.status, onNavigate: onNavigate }), issues.length > 0 && _jsx(SettingsValidationSummary, { issues: issues }), !canEdit && (_jsx("p", { className: "text-muted-foreground text-sm", children: "You have read-only access. Only administrators can change security settings." })), _jsx(AuthMfaCard, { form: form, setField: setField, canEdit: canEdit, viewerHasMfa: data.viewerHasMfa, withMfa: data.users.withMfa, totalAdmins: data.users.totalAdmins, onNavigate: onNavigate }), _jsx("div", { id: "security-sessions", children: _jsx(SessionPolicyCard, { form: form, setField: setField, canEdit: canEdit, activeSessions: data.activeSessions, revokeState: revokeState, onRevokeAll: () => void revokeAllOtherSessions() }) }), _jsx("div", { id: "security-ip-allowlist", children: _jsx(AccessProtectionCard, { form: form, setField: setField, canEdit: canEdit, ipAllowlist: data.ipAllowlist, secrets: data.secrets, csrfEnabled: data.csrfEnabled, uploadValidation: data.uploadValidation, sources: data.sources, onNavigate: onNavigate }) }), _jsx("div", { id: "security-audit", children: _jsx(SecretsAuditCard, { secrets: data.secrets, auditEnabled: data.auditEnabled, failedLogins24h: data.failedLogins24h, users: data.users, apiKeys: data.apiKeys, sources: data.sources, onNavigate: onNavigate }) }), saveState === 'error' && (_jsx("p", { className: "text-destructive text-sm", role: "alert", children: "Failed to save security settings. Please try again." })), _jsx(ConfirmDangerousSettingDialog, { open: lockoutPrompt !== null, title: "This allowlist may lock you out", description: lockoutPrompt ?? 'Your current IP is not covered by the allowlist you are about to save.', confirmLabel: "Save anyway", onConfirm: () => void save({ confirmLockout: true }), onCancel: dismissLockoutPrompt }), _jsx(SettingsSaveBar, { dirty: dirty, canEdit: canEdit, hasErrors: hasErrors, saveState: saveState, onSave: () => void save(), onReset: reset })] }));
40
40
  }
41
41
  //# sourceMappingURL=SecurityTab.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityTab.js","sourceRoot":"","sources":["../../../src/views/settings/SecurityTab.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SecurityTab.js","sourceRoot":"","sources":["../../../src/views/settings/SecurityTab.tsx"],"names":[],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  import type { SecurityForm } from './useSecuritySettings.js';
2
- export declare function SessionPolicyCard({ form, setField, canEdit, sessionMaxAgeHours, activeSessions, revokeState, onRevokeAll, }: {
2
+ export declare function SessionPolicyCard({ form, setField, canEdit, activeSessions, revokeState, onRevokeAll, }: {
3
3
  form: SecurityForm;
4
4
  setField: <K extends keyof SecurityForm>(key: K, value: SecurityForm[K]) => void;
5
5
  canEdit: boolean;
6
- sessionMaxAgeHours: number;
7
6
  activeSessions: number;
8
7
  revokeState: 'idle' | 'working' | 'done' | 'error';
9
8
  onRevokeAll: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"SessionPolicyCard.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SessionPolicyCard.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAM5D,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAChF,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;IAClD,WAAW,EAAE,MAAM,IAAI,CAAA;CACxB,2CA6FA"}
1
+ {"version":3,"file":"SessionPolicyCard.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SessionPolicyCard.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAY5D,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,cAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAChF,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;IAClD,WAAW,EAAE,MAAM,IAAI,CAAA;CACxB,2CA0HA"}
@@ -2,18 +2,25 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useId, useState } from 'react';
4
4
  import { Loader2 } from 'lucide-react';
5
- import { MAX_CONCURRENT_SESSION_OPTIONS } from '@actuate-media/cms-core/security-center';
6
- import { ConfirmDangerousSettingDialog } from './components.js';
5
+ import { MAX_CONCURRENT_SESSION_OPTIONS, SESSION_TIMEOUT_HOURS_OPTIONS, } from '@actuate-media/cms-core/security-center';
6
+ import { ConfirmDangerousSettingDialog, SettingsToggleRow } from './components.js';
7
7
  import { SecurityCard, StatusRow } from './securityPrimitives.js';
8
8
  function sessionsLabel(n) {
9
9
  return n === 0 ? 'Unlimited' : String(n);
10
10
  }
11
- export function SessionPolicyCard({ form, setField, canEdit, sessionMaxAgeHours, activeSessions, revokeState, onRevokeAll, }) {
11
+ function timeoutLabel(hours) {
12
+ if (hours === 1)
13
+ return '1 hour';
14
+ if (hours === 168)
15
+ return '7 days';
16
+ return `${hours} hours`;
17
+ }
18
+ export function SessionPolicyCard({ form, setField, canEdit, activeSessions, revokeState, onRevokeAll, }) {
12
19
  const headingId = useId();
13
20
  const maxId = useId();
21
+ const timeoutId = useId();
14
22
  const [confirmRevoke, setConfirmRevoke] = useState(false);
15
- const maxAgeDays = Math.round(sessionMaxAgeHours / 24);
16
- return (_jsxs(SecurityCard, { headingId: headingId, title: "Session Policy", description: "Control how many sessions an account can hold and revoke active sessions.", children: [_jsx("div", { className: "space-y-4", children: _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("label", { htmlFor: maxId, className: "flex-1", children: [_jsx("span", { className: "text-foreground text-base font-medium", children: "Maximum concurrent sessions" }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-sm", children: "Oldest sessions are signed out when a user exceeds this. Choose Unlimited to disable the cap." })] }), _jsx("select", { id: maxId, value: form.maxConcurrentSessions, disabled: !canEdit, onChange: (e) => setField('maxConcurrentSessions', Number(e.target.value)), className: "border-border bg-input-background text-foreground focus-visible:ring-ring rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", children: MAX_CONCURRENT_SESSION_OPTIONS.map((n) => (_jsx("option", { value: n, children: sessionsLabel(n) }, n))) })] }) }), _jsxs("div", { className: "border-border mt-4 space-y-2 border-t pt-4", children: [_jsx(StatusRow, { status: "pass", label: "Active admin sessions", value: String(activeSessions) }), _jsx(StatusRow, { status: "pass", label: "Maximum session age", value: `${maxAgeDays} day${maxAgeDays === 1 ? '' : 's'}` }), _jsx(StatusRow, { status: "pass", label: "Revoke sessions on password change", value: "Enabled" })] }), _jsxs("div", { className: "border-border mt-4 flex items-center justify-between gap-3 border-t pt-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: "Revoke other sessions" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Sign out every session except this one. Useful after a suspected compromise." }), revokeState === 'done' && (_jsx("p", { className: "text-success mt-1 text-sm", "aria-live": "polite", children: "Other sessions revoked." })), revokeState === 'error' && (_jsx("p", { className: "text-destructive mt-1 text-sm", "aria-live": "polite", children: "Could not revoke sessions. Try again." }))] }), _jsxs("button", { type: "button", disabled: !canEdit || revokeState === 'working', onClick: () => setConfirmRevoke(true), className: "border-border text-foreground hover:bg-accent inline-flex shrink-0 items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50", children: [revokeState === 'working' && (_jsx(Loader2, { size: 15, className: "animate-spin", "aria-hidden": "true" })), "Revoke other sessions"] })] }), _jsx(ConfirmDangerousSettingDialog, { open: confirmRevoke, title: "Revoke all other sessions?", description: "Every active session except your current one will be signed out immediately. Those users (and your other devices) will need to sign in again.", confirmLabel: "Revoke sessions", onConfirm: () => {
23
+ return (_jsxs(SecurityCard, { headingId: headingId, title: "Sessions", description: "Control session lifetime, idle sign-out, and how many sessions an account can hold.", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("label", { htmlFor: timeoutId, className: "flex-1", children: [_jsx("span", { className: "text-foreground text-base font-medium", children: "Session timeout" }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-sm", children: "Members are signed out automatically after this period of inactivity." })] }), _jsx("select", { id: timeoutId, value: form.timeoutHours, disabled: !canEdit, onChange: (e) => setField('timeoutHours', Number(e.target.value)), className: "border-border bg-input-background text-foreground focus-visible:ring-ring rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", children: SESSION_TIMEOUT_HOURS_OPTIONS.map((h) => (_jsx("option", { value: h, children: timeoutLabel(h) }, h))) })] }), _jsx(SettingsToggleRow, { label: "Idle auto-logout", description: "End the session after the timeout above when the tab is inactive.", checked: form.idleLogoutEnabled, disabled: !canEdit, onChange: (value) => setField('idleLogoutEnabled', value) }), _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("label", { htmlFor: maxId, className: "flex-1", children: [_jsx("span", { className: "text-foreground text-base font-medium", children: "Maximum concurrent sessions" }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-sm", children: "Oldest sessions are signed out when a user exceeds this. Choose Unlimited to disable the cap." })] }), _jsx("select", { id: maxId, value: form.maxConcurrentSessions, disabled: !canEdit, onChange: (e) => setField('maxConcurrentSessions', Number(e.target.value)), className: "border-border bg-input-background text-foreground focus-visible:ring-ring rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", children: MAX_CONCURRENT_SESSION_OPTIONS.map((n) => (_jsx("option", { value: n, children: sessionsLabel(n) }, n))) })] })] }), _jsxs("div", { className: "border-border mt-4 space-y-2 border-t pt-4", children: [_jsx(StatusRow, { status: "pass", label: "Active admin sessions", value: String(activeSessions) }), _jsx(StatusRow, { status: "pass", label: "Maximum session age", value: timeoutLabel(form.timeoutHours) }), _jsx(StatusRow, { status: "pass", label: "Revoke sessions on password change", value: "Enabled" })] }), _jsxs("div", { className: "border-border mt-4 flex items-center justify-between gap-3 border-t pt-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: "Revoke other sessions" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Sign out every session except this one. Useful after a suspected compromise." }), revokeState === 'done' && (_jsx("p", { className: "text-success mt-1 text-sm", "aria-live": "polite", children: "Other sessions revoked." })), revokeState === 'error' && (_jsx("p", { className: "text-destructive mt-1 text-sm", "aria-live": "polite", children: "Could not revoke sessions. Try again." }))] }), _jsxs("button", { type: "button", disabled: !canEdit || revokeState === 'working', onClick: () => setConfirmRevoke(true), className: "border-border text-foreground hover:bg-accent inline-flex shrink-0 items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50", children: [revokeState === 'working' && (_jsx(Loader2, { size: 15, className: "animate-spin", "aria-hidden": "true" })), "Revoke other sessions"] })] }), _jsx(ConfirmDangerousSettingDialog, { open: confirmRevoke, title: "Revoke all other sessions?", description: "Every active session except your current one will be signed out immediately. Those users (and your other devices) will need to sign in again.", confirmLabel: "Revoke sessions", onConfirm: () => {
17
24
  setConfirmRevoke(false);
18
25
  onRevokeAll();
19
26
  }, onCancel: () => setConfirmRevoke(false) })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"SessionPolicyCard.js","sourceRoot":"","sources":["../../../src/views/settings/SessionPolicyCard.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionPolicyCard.js","sourceRoot":"","sources":["../../../src/views/settings/SessionPolicyCard.tsx"],"names":[],"mappings":"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"}
@@ -5,8 +5,15 @@ export interface SecurityForm {
5
5
  mfaRequired: boolean;
6
6
  mfaGracePeriodDays: number;
7
7
  maxConcurrentSessions: number;
8
+ timeoutHours: number;
9
+ idleLogoutEnabled: boolean;
10
+ /** Raw textarea contents — one IP/CIDR entry per line. */
11
+ ipAllowlistText: string;
12
+ auditLoggingEnabled: boolean;
8
13
  }
9
14
  type SaveState = 'idle' | 'saving' | 'success' | 'error';
15
+ /** Split the textarea into trimmed, de-duplicated entries (one per line). */
16
+ export declare function parseAllowlistText(text: string): string[];
10
17
  export interface UseSecuritySettings {
11
18
  loading: boolean;
12
19
  loadError: string | null;
@@ -19,9 +26,14 @@ export interface UseSecuritySettings {
19
26
  canEdit: boolean;
20
27
  saveState: SaveState;
21
28
  saveError: string | null;
22
- save: () => Promise<void>;
29
+ save: (options?: {
30
+ confirmLockout?: boolean;
31
+ }) => Promise<void>;
23
32
  reset: () => void;
24
33
  refetch: () => void;
34
+ /** Server rejected the save with IP_LOCKOUT_RISK — message to confirm. */
35
+ lockoutPrompt: string | null;
36
+ dismissLockoutPrompt: () => void;
25
37
  revokeState: 'idle' | 'working' | 'done' | 'error';
26
38
  revokeAllOtherSessions: () => Promise<number | null>;
27
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useSecuritySettings.d.ts","sourceRoot":"","sources":["../../../src/views/settings/useSecuritySettings.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,yCAAyC,CAAA;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAE9D,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,OAAO,CAAA;IACpB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,MAAM,CAAA;CAC9B;AAED,KAAK,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;AAuBxD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC/B,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAChF,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;IAClD,sBAAsB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CACrD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAiIzE"}
1
+ {"version":3,"file":"useSecuritySettings.d.ts","sourceRoot":"","sources":["../../../src/views/settings/useSecuritySettings.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,yCAAyC,CAAA;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAE9D,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,OAAO,CAAA;IACpB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,OAAO,CAAA;CAC7B;AAED,KAAK,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;AAYxD,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOzD;AA6BD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC/B,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAChF,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,eAAe,EAAE,CAAA;IACzB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,0EAA0E;IAC1E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,oBAAoB,EAAE,MAAM,IAAI,CAAA;IAChC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;IAClD,sBAAsB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CACrD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAuJzE"}