@prenta/admin 2.6.0 → 2.7.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 +104 -0
- package/design-system/tokens.css +179 -85
- package/design-system/tokens.json +276 -85
- package/design-system/tokens.scss +148 -44
- package/design-system/tokens.tailwind.cjs +50 -1
- package/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +42 -20
- package/dist/AdminRoot.js.map +1 -1
- package/dist/LoginRoot.d.ts.map +1 -1
- package/dist/LoginRoot.js +2 -1
- package/dist/LoginRoot.js.map +1 -1
- package/dist/__tests__/components/author-avatar.test.js +3 -17
- package/dist/__tests__/components/author-avatar.test.js.map +1 -1
- package/dist/__tests__/components/notification-bell.test.js +86 -15
- package/dist/__tests__/components/notification-bell.test.js.map +1 -1
- package/dist/__tests__/components/responsive-tiers.render.test.d.ts +2 -0
- package/dist/__tests__/components/responsive-tiers.render.test.d.ts.map +1 -0
- package/dist/__tests__/components/responsive-tiers.render.test.js +313 -0
- package/dist/__tests__/components/responsive-tiers.render.test.js.map +1 -0
- package/dist/__tests__/components/serp-preview.render.test.js +6 -3
- package/dist/__tests__/components/serp-preview.render.test.js.map +1 -1
- package/dist/__tests__/components/shell-primitives.render.test.d.ts +2 -0
- package/dist/__tests__/components/shell-primitives.render.test.d.ts.map +1 -0
- package/dist/__tests__/components/shell-primitives.render.test.js +716 -0
- package/dist/__tests__/components/shell-primitives.render.test.js.map +1 -0
- package/dist/__tests__/components/theme-provider-accent.test.js +49 -7
- package/dist/__tests__/components/theme-provider-accent.test.js.map +1 -1
- package/dist/__tests__/components/toggle.test.js +10 -3
- package/dist/__tests__/components/toggle.test.js.map +1 -1
- package/dist/__tests__/components/ui-primitives.test.js +3 -7
- package/dist/__tests__/components/ui-primitives.test.js.map +1 -1
- package/dist/__tests__/layout/build-nav-items.test.js +1 -1
- package/dist/__tests__/layout/build-nav-items.test.js.map +1 -1
- package/dist/__tests__/layout/shell-nav.render.test.d.ts +2 -0
- package/dist/__tests__/layout/shell-nav.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/shell-nav.render.test.js +736 -0
- package/dist/__tests__/layout/shell-nav.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-forms-submenu.render.test.js +8 -4
- package/dist/__tests__/layout/sidebar-forms-submenu.render.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-groups.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-groups.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-groups.render.test.js +56 -0
- package/dist/__tests__/layout/sidebar-groups.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.d.ts +2 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.js +82 -0
- package/dist/__tests__/layout/sidebar-menus.render.test.js.map +1 -0
- package/dist/__tests__/layout/sidebar-plugin-nav.test.js +1 -1
- package/dist/__tests__/layout/sidebar-plugin-nav.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-posts.test.js +48 -38
- package/dist/__tests__/layout/sidebar-posts.test.js.map +1 -1
- package/dist/__tests__/layout/sidebar-submenu.render.test.js +26 -10
- package/dist/__tests__/layout/sidebar-submenu.render.test.js.map +1 -1
- package/dist/__tests__/layout/topbar.render.test.d.ts +2 -0
- package/dist/__tests__/layout/topbar.render.test.d.ts.map +1 -0
- package/dist/__tests__/layout/topbar.render.test.js +406 -0
- package/dist/__tests__/layout/topbar.render.test.js.map +1 -0
- package/dist/__tests__/lib/api.test.js +2 -0
- package/dist/__tests__/lib/api.test.js.map +1 -1
- package/dist/__tests__/lib/job-drawer.test.d.ts +2 -0
- package/dist/__tests__/lib/job-drawer.test.d.ts.map +1 -0
- package/dist/__tests__/lib/job-drawer.test.js +393 -0
- package/dist/__tests__/lib/job-drawer.test.js.map +1 -0
- package/dist/__tests__/lib/job-view.test.d.ts +2 -0
- package/dist/__tests__/lib/job-view.test.d.ts.map +1 -0
- package/dist/__tests__/lib/job-view.test.js +387 -0
- package/dist/__tests__/lib/job-view.test.js.map +1 -0
- package/dist/__tests__/lib/jobs-service.test.d.ts +2 -0
- package/dist/__tests__/lib/jobs-service.test.d.ts.map +1 -0
- package/dist/__tests__/lib/jobs-service.test.js +88 -0
- package/dist/__tests__/lib/jobs-service.test.js.map +1 -0
- package/dist/__tests__/router/admin-route-order.test.d.ts +2 -0
- package/dist/__tests__/router/admin-route-order.test.d.ts.map +1 -0
- package/dist/__tests__/router/admin-route-order.test.js +36 -0
- package/dist/__tests__/router/admin-route-order.test.js.map +1 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.d.ts +2 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.d.ts.map +1 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.js +110 -0
- package/dist/__tests__/styles/ai-gradient-contrast.test.js.map +1 -0
- package/dist/__tests__/styles/breakpoint-order.test.d.ts +2 -0
- package/dist/__tests__/styles/breakpoint-order.test.d.ts.map +1 -0
- package/dist/__tests__/styles/breakpoint-order.test.js +52 -0
- package/dist/__tests__/styles/breakpoint-order.test.js.map +1 -0
- package/dist/__tests__/styles/responsive-layer.test.js +303 -12
- package/dist/__tests__/styles/responsive-layer.test.js.map +1 -1
- package/dist/__tests__/styles/tailwind-preset.test.d.ts +2 -0
- package/dist/__tests__/styles/tailwind-preset.test.d.ts.map +1 -0
- package/dist/__tests__/styles/tailwind-preset.test.js +147 -0
- package/dist/__tests__/styles/tailwind-preset.test.js.map +1 -0
- package/dist/__tests__/styles/theme-token-scope.test.js +9 -3
- package/dist/__tests__/styles/theme-token-scope.test.js.map +1 -1
- package/dist/__tests__/styles/tiers.test.d.ts +2 -0
- package/dist/__tests__/styles/tiers.test.d.ts.map +1 -0
- package/dist/__tests__/styles/tiers.test.js +121 -0
- package/dist/__tests__/styles/tiers.test.js.map +1 -0
- package/dist/__tests__/styles/tokens-drift.test.js +57 -6
- package/dist/__tests__/styles/tokens-drift.test.js.map +1 -1
- package/dist/__tests__/views/admin-lazy-route.render.test.js +27 -1
- package/dist/__tests__/views/admin-lazy-route.render.test.js.map +1 -1
- package/dist/__tests__/views/ai-settings.render.test.js +4 -4
- package/dist/__tests__/views/appearance-menus-route.render.test.d.ts +2 -0
- package/dist/__tests__/views/appearance-menus-route.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/appearance-menus-route.render.test.js +50 -0
- package/dist/__tests__/views/appearance-menus-route.render.test.js.map +1 -0
- package/dist/__tests__/views/appearance-settings.render.test.js +8 -6
- package/dist/__tests__/views/appearance-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/appearance-theme-provider.render.test.d.ts +2 -0
- package/dist/__tests__/views/appearance-theme-provider.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/appearance-theme-provider.render.test.js +286 -0
- package/dist/__tests__/views/appearance-theme-provider.render.test.js.map +1 -0
- package/dist/__tests__/views/dashboard.test.js +37 -0
- package/dist/__tests__/views/dashboard.test.js.map +1 -1
- package/dist/__tests__/views/document-edit-navigation.render.test.d.ts +2 -0
- package/dist/__tests__/views/document-edit-navigation.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/document-edit-navigation.render.test.js +101 -0
- package/dist/__tests__/views/document-edit-navigation.render.test.js.map +1 -0
- package/dist/__tests__/views/document-edit-routes.render.test.d.ts +2 -0
- package/dist/__tests__/views/document-edit-routes.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/document-edit-routes.render.test.js +113 -0
- package/dist/__tests__/views/document-edit-routes.render.test.js.map +1 -0
- package/dist/__tests__/views/email-settings.render.test.js +2 -2
- package/dist/__tests__/views/form-entries.render.test.js +15 -0
- package/dist/__tests__/views/form-entries.render.test.js.map +1 -1
- package/dist/__tests__/views/form-submissions.render.test.js +18 -0
- package/dist/__tests__/views/form-submissions.render.test.js.map +1 -1
- package/dist/__tests__/views/forms-list.render.test.js +12 -0
- package/dist/__tests__/views/forms-list.render.test.js.map +1 -1
- package/dist/__tests__/views/general-settings.render.test.js +26 -10
- package/dist/__tests__/views/general-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/jobs-drawer.render.test.d.ts +2 -0
- package/dist/__tests__/views/jobs-drawer.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/jobs-drawer.render.test.js +908 -0
- package/dist/__tests__/views/jobs-drawer.render.test.js.map +1 -0
- package/dist/__tests__/views/jobs-list.render.test.d.ts +2 -0
- package/dist/__tests__/views/jobs-list.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/jobs-list.render.test.js +695 -0
- package/dist/__tests__/views/jobs-list.render.test.js.map +1 -0
- package/dist/__tests__/views/kpi-grid.test.d.ts +2 -0
- package/dist/__tests__/views/kpi-grid.test.d.ts.map +1 -0
- package/dist/__tests__/views/kpi-grid.test.js +26 -0
- package/dist/__tests__/views/kpi-grid.test.js.map +1 -0
- package/dist/__tests__/views/mcp-connect.render.test.js +1 -0
- package/dist/__tests__/views/mcp-connect.render.test.js.map +1 -1
- package/dist/__tests__/views/post-section-editor.test.js +3 -1
- package/dist/__tests__/views/post-section-editor.test.js.map +1 -1
- package/dist/__tests__/views/script-tags.render.test.js +25 -0
- package/dist/__tests__/views/script-tags.render.test.js.map +1 -1
- package/dist/__tests__/views/security-settings.render.test.js +9 -8
- package/dist/__tests__/views/security-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/seo-settings.render.test.js +7 -7
- package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
- package/dist/__tests__/views/settings-save-bar.render.test.d.ts +2 -0
- package/dist/__tests__/views/settings-save-bar.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/settings-save-bar.render.test.js +68 -0
- package/dist/__tests__/views/settings-save-bar.render.test.js.map +1 -0
- package/dist/__tests__/views/settings-save-footer.render.test.js +23 -15
- package/dist/__tests__/views/settings-save-footer.render.test.js.map +1 -1
- package/dist/__tests__/views/settings-tabs.render.test.d.ts +2 -0
- package/dist/__tests__/views/settings-tabs.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/settings-tabs.render.test.js +319 -0
- package/dist/__tests__/views/settings-tabs.render.test.js.map +1 -0
- package/dist/__tests__/views/updates-tab.render.test.js +4 -3
- package/dist/__tests__/views/updates-tab.render.test.js.map +1 -1
- package/dist/components/Breadcrumbs.d.ts +8 -1
- package/dist/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/Breadcrumbs.js +6 -0
- package/dist/components/Breadcrumbs.js.map +1 -1
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +40 -4
- package/dist/components/CommandPalette.js.map +1 -1
- package/dist/components/LocaleSwitcher.d.ts.map +1 -1
- package/dist/components/LocaleSwitcher.js +1 -1
- package/dist/components/LocaleSwitcher.js.map +1 -1
- package/dist/components/NotificationBell.d.ts.map +1 -1
- package/dist/components/NotificationBell.js +44 -3
- package/dist/components/NotificationBell.js.map +1 -1
- package/dist/components/OfflineStatus.js +1 -1
- package/dist/components/OfflineStatus.js.map +1 -1
- package/dist/components/PresenceIndicator.d.ts.map +1 -1
- package/dist/components/PresenceIndicator.js +2 -1
- package/dist/components/PresenceIndicator.js.map +1 -1
- package/dist/components/ReflowMeter.js +2 -2
- package/dist/components/ReflowMeter.js.map +1 -1
- package/dist/components/SEOPanel.js +2 -2
- package/dist/components/SEOPanel.js.map +1 -1
- package/dist/components/ThemeProvider.d.ts +24 -4
- package/dist/components/ThemeProvider.d.ts.map +1 -1
- package/dist/components/ThemeProvider.js +80 -22
- package/dist/components/ThemeProvider.js.map +1 -1
- package/dist/components/TipTapEditor.d.ts.map +1 -1
- package/dist/components/TipTapEditor.js +3 -4
- package/dist/components/TipTapEditor.js.map +1 -1
- package/dist/components/forms/EmbedPanel.js +1 -1
- package/dist/components/forms/EmbedPanel.js.map +1 -1
- package/dist/components/forms/FormEntryDetailPane.js +6 -1
- package/dist/components/forms/FormEntryDetailPane.js.map +1 -1
- package/dist/components/forms/ShortcodeGlossary.d.ts.map +1 -1
- package/dist/components/forms/ShortcodeGlossary.js +6 -1
- package/dist/components/forms/ShortcodeGlossary.js.map +1 -1
- package/dist/components/forms/primitives.d.ts +15 -5
- package/dist/components/forms/primitives.d.ts.map +1 -1
- package/dist/components/forms/primitives.js +11 -11
- package/dist/components/forms/primitives.js.map +1 -1
- package/dist/components/pages/tag-badges.d.ts +2 -1
- package/dist/components/pages/tag-badges.d.ts.map +1 -1
- package/dist/components/pages/tag-badges.js +4 -3
- package/dist/components/pages/tag-badges.js.map +1 -1
- package/dist/components/seo/PageAuditPanel.js +2 -2
- package/dist/components/seo/PageAuditPanel.js.map +1 -1
- package/dist/components/seo/SerpPreview.d.ts +4 -4
- package/dist/components/seo/SerpPreview.js +1 -1
- package/dist/components/seo/SerpPreview.js.map +1 -1
- package/dist/components/seo/primitives.js +2 -2
- package/dist/components/seo/primitives.js.map +1 -1
- package/dist/components/ui/AuthorAvatar.d.ts +4 -4
- package/dist/components/ui/AuthorAvatar.d.ts.map +1 -1
- package/dist/components/ui/AuthorAvatar.js +11 -10
- package/dist/components/ui/AuthorAvatar.js.map +1 -1
- package/dist/components/ui/Badge.d.ts +1 -1
- package/dist/components/ui/Badge.js +1 -1
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Breadcrumb.d.ts +27 -0
- package/dist/components/ui/Breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/Breadcrumb.js +41 -0
- package/dist/components/ui/Breadcrumb.js.map +1 -0
- package/dist/components/ui/Button.d.ts +2 -2
- package/dist/components/ui/Button.d.ts.map +1 -1
- package/dist/components/ui/Button.js +31 -16
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +8 -4
- package/dist/components/ui/Card.d.ts.map +1 -1
- package/dist/components/ui/Card.js +21 -13
- package/dist/components/ui/Card.js.map +1 -1
- package/dist/components/ui/CardListControls.d.ts +34 -0
- package/dist/components/ui/CardListControls.d.ts.map +1 -0
- package/dist/components/ui/CardListControls.js +25 -0
- package/dist/components/ui/CardListControls.js.map +1 -0
- package/dist/components/ui/CountChip.d.ts +20 -0
- package/dist/components/ui/CountChip.d.ts.map +1 -0
- package/dist/components/ui/CountChip.js +48 -0
- package/dist/components/ui/CountChip.js.map +1 -0
- package/dist/components/ui/FilterPill.d.ts +2 -1
- package/dist/components/ui/FilterPill.d.ts.map +1 -1
- package/dist/components/ui/FilterPill.js +3 -2
- package/dist/components/ui/FilterPill.js.map +1 -1
- package/dist/components/ui/Input.d.ts +1 -1
- package/dist/components/ui/InspectorPane.d.ts +1 -1
- package/dist/components/ui/InspectorPane.d.ts.map +1 -1
- package/dist/components/ui/InspectorPane.js +15 -4
- package/dist/components/ui/InspectorPane.js.map +1 -1
- package/dist/components/ui/Modal.d.ts.map +1 -1
- package/dist/components/ui/Modal.js +10 -2
- package/dist/components/ui/Modal.js.map +1 -1
- package/dist/components/ui/PageHeader.d.ts +28 -0
- package/dist/components/ui/PageHeader.d.ts.map +1 -0
- package/dist/components/ui/PageHeader.js +18 -0
- package/dist/components/ui/PageHeader.js.map +1 -0
- package/dist/components/ui/RowActions.d.ts +5 -0
- package/dist/components/ui/RowActions.d.ts.map +1 -1
- package/dist/components/ui/RowActions.js +7 -2
- package/dist/components/ui/RowActions.js.map +1 -1
- package/dist/components/ui/Segmented.d.ts +21 -0
- package/dist/components/ui/Segmented.d.ts.map +1 -0
- package/dist/components/ui/Segmented.js +41 -0
- package/dist/components/ui/Segmented.js.map +1 -0
- package/dist/components/ui/Toaster.d.ts +12 -0
- package/dist/components/ui/Toaster.d.ts.map +1 -0
- package/dist/components/ui/Toaster.js +103 -0
- package/dist/components/ui/Toaster.js.map +1 -0
- package/dist/components/ui/Toggle.d.ts +4 -3
- package/dist/components/ui/Toggle.d.ts.map +1 -1
- package/dist/components/ui/Toggle.js +16 -12
- package/dist/components/ui/Toggle.js.map +1 -1
- package/dist/components/ui/UnderlineTabs.d.ts +56 -0
- package/dist/components/ui/UnderlineTabs.d.ts.map +1 -0
- package/dist/components/ui/UnderlineTabs.js +205 -0
- package/dist/components/ui/UnderlineTabs.js.map +1 -0
- package/dist/components/ui/UnsavedBar.d.ts +25 -0
- package/dist/components/ui/UnsavedBar.d.ts.map +1 -0
- package/dist/components/ui/UnsavedBar.js +22 -0
- package/dist/components/ui/UnsavedBar.js.map +1 -0
- package/dist/components/ui/admin-links.d.ts +11 -0
- package/dist/components/ui/admin-links.d.ts.map +1 -0
- package/dist/components/ui/admin-links.js +10 -0
- package/dist/components/ui/admin-links.js.map +1 -0
- package/dist/components/ui/card-table.d.ts +43 -0
- package/dist/components/ui/card-table.d.ts.map +1 -0
- package/dist/components/ui/card-table.js +31 -0
- package/dist/components/ui/card-table.js.map +1 -0
- package/dist/components/virtual-window.d.ts +7 -0
- package/dist/components/virtual-window.d.ts.map +1 -1
- package/dist/components/virtual-window.js +5 -2
- package/dist/components/virtual-window.js.map +1 -1
- package/dist/fields/RelationshipField.js +1 -1
- package/dist/fields/RelationshipField.js.map +1 -1
- package/dist/files/dm-mono-latin-400-normal.woff +0 -0
- package/dist/files/dm-mono-latin-400-normal.woff2 +0 -0
- package/dist/files/dm-mono-latin-500-normal.woff +0 -0
- package/dist/files/dm-mono-latin-500-normal.woff2 +0 -0
- package/dist/files/dm-mono-latin-ext-400-normal.woff +0 -0
- package/dist/files/dm-mono-latin-ext-400-normal.woff2 +0 -0
- package/dist/files/dm-mono-latin-ext-500-normal.woff +0 -0
- package/dist/files/dm-mono-latin-ext-500-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-400-normal.woff +0 -0
- package/dist/files/dm-sans-latin-400-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-500-normal.woff +0 -0
- package/dist/files/dm-sans-latin-500-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-600-normal.woff +0 -0
- package/dist/files/dm-sans-latin-600-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-700-normal.woff +0 -0
- package/dist/files/dm-sans-latin-700-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-400-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-400-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-500-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-500-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-600-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-600-normal.woff2 +0 -0
- package/dist/files/dm-sans-latin-ext-700-normal.woff +0 -0
- package/dist/files/dm-sans-latin-ext-700-normal.woff2 +0 -0
- package/dist/hooks/useAppearanceBootstrap.d.ts.map +1 -1
- package/dist/hooks/useAppearanceBootstrap.js +9 -3
- package/dist/hooks/useAppearanceBootstrap.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/Header.d.ts +14 -5
- package/dist/layout/Header.d.ts.map +1 -1
- package/dist/layout/Header.js +78 -13
- package/dist/layout/Header.js.map +1 -1
- package/dist/layout/Layout.d.ts +5 -3
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js +45 -54
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/MobileTabBar.d.ts +20 -0
- package/dist/layout/MobileTabBar.d.ts.map +1 -0
- package/dist/layout/MobileTabBar.js +29 -0
- package/dist/layout/MobileTabBar.js.map +1 -0
- package/dist/layout/Sidebar.d.ts +8 -26
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +309 -345
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/layout/nav-config.d.ts +101 -0
- package/dist/layout/nav-config.d.ts.map +1 -0
- package/dist/layout/nav-config.js +297 -0
- package/dist/layout/nav-config.js.map +1 -0
- package/dist/layout/primitives/AdminShell.d.ts +10 -2
- package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
- package/dist/layout/primitives/AdminShell.js +114 -6
- package/dist/layout/primitives/AdminShell.js.map +1 -1
- package/dist/layout/topbar-classes.d.ts +8 -0
- package/dist/layout/topbar-classes.d.ts.map +1 -0
- package/dist/layout/topbar-classes.js +8 -0
- package/dist/layout/topbar-classes.js.map +1 -0
- package/dist/layout/use-nav-items.d.ts +10 -0
- package/dist/layout/use-nav-items.d.ts.map +1 -0
- package/dist/layout/use-nav-items.js +39 -0
- package/dist/layout/use-nav-items.js.map +1 -0
- package/dist/lib/api.d.ts +6 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +1 -1
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/appearance-api.d.ts +3 -1
- package/dist/lib/appearance-api.d.ts.map +1 -1
- package/dist/lib/appearance-api.js +1 -0
- package/dist/lib/appearance-api.js.map +1 -1
- package/dist/lib/job-drawer.d.ts +128 -0
- package/dist/lib/job-drawer.d.ts.map +1 -0
- package/dist/lib/job-drawer.js +351 -0
- package/dist/lib/job-drawer.js.map +1 -0
- package/dist/lib/job-view.d.ts +187 -0
- package/dist/lib/job-view.d.ts.map +1 -0
- package/dist/lib/job-view.js +363 -0
- package/dist/lib/job-view.js.map +1 -0
- package/dist/lib/jobs-service.d.ts +134 -0
- package/dist/lib/jobs-service.d.ts.map +1 -0
- package/dist/lib/jobs-service.js +179 -0
- package/dist/lib/jobs-service.js.map +1 -0
- package/dist/lib/sheet-focus.d.ts +24 -0
- package/dist/lib/sheet-focus.d.ts.map +1 -0
- package/dist/lib/sheet-focus.js +61 -0
- package/dist/lib/sheet-focus.js.map +1 -0
- package/dist/lib/tiers.d.ts +30 -0
- package/dist/lib/tiers.d.ts.map +1 -0
- package/dist/lib/tiers.js +43 -0
- package/dist/lib/tiers.js.map +1 -0
- package/dist/prenta-admin.css +1 -1
- package/dist/router/admin-routes.d.ts.map +1 -1
- package/dist/router/admin-routes.js +8 -0
- package/dist/router/admin-routes.js.map +1 -1
- package/dist/router/index.d.ts +5 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +7 -0
- package/dist/router/index.js.map +1 -1
- package/dist/views/ApiKeys.js +2 -2
- package/dist/views/ApiKeys.js.map +1 -1
- package/dist/views/AppearanceChrome.d.ts +6 -0
- package/dist/views/AppearanceChrome.d.ts.map +1 -0
- package/dist/views/AppearanceChrome.js +25 -0
- package/dist/views/AppearanceChrome.js.map +1 -0
- package/dist/views/CollectionList.d.ts.map +1 -1
- package/dist/views/CollectionList.js +73 -53
- package/dist/views/CollectionList.js.map +1 -1
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +14 -8
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.d.ts +6 -1
- package/dist/views/DocumentEdit.d.ts.map +1 -1
- package/dist/views/DocumentEdit.js +44 -8
- package/dist/views/DocumentEdit.js.map +1 -1
- package/dist/views/FormDeliveries.d.ts.map +1 -1
- package/dist/views/FormDeliveries.js +7 -1
- package/dist/views/FormDeliveries.js.map +1 -1
- package/dist/views/FormEntries.d.ts.map +1 -1
- package/dist/views/FormEntries.js +11 -2
- package/dist/views/FormEntries.js.map +1 -1
- package/dist/views/FormSubmissions.d.ts +1 -1
- package/dist/views/FormSubmissions.d.ts.map +1 -1
- package/dist/views/FormSubmissions.js +15 -4
- package/dist/views/FormSubmissions.js.map +1 -1
- package/dist/views/Forms.d.ts.map +1 -1
- package/dist/views/Forms.js +6 -4
- package/dist/views/Forms.js.map +1 -1
- package/dist/views/FormsSettings.d.ts +2 -0
- package/dist/views/FormsSettings.d.ts.map +1 -0
- package/dist/views/FormsSettings.js +37 -0
- package/dist/views/FormsSettings.js.map +1 -0
- package/dist/views/Jobs/BusyButton.d.ts +15 -0
- package/dist/views/Jobs/BusyButton.d.ts.map +1 -0
- package/dist/views/Jobs/BusyButton.js +26 -0
- package/dist/views/Jobs/BusyButton.js.map +1 -0
- package/dist/views/Jobs/CancelJobDialog.d.ts +21 -0
- package/dist/views/Jobs/CancelJobDialog.d.ts.map +1 -0
- package/dist/views/Jobs/CancelJobDialog.js +66 -0
- package/dist/views/Jobs/CancelJobDialog.js.map +1 -0
- package/dist/views/Jobs/DrawerActivity.d.ts +16 -0
- package/dist/views/Jobs/DrawerActivity.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerActivity.js +59 -0
- package/dist/views/Jobs/DrawerActivity.js.map +1 -0
- package/dist/views/Jobs/DrawerOverview.d.ts +28 -0
- package/dist/views/Jobs/DrawerOverview.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerOverview.js +32 -0
- package/dist/views/Jobs/DrawerOverview.js.map +1 -0
- package/dist/views/Jobs/DrawerResults.d.ts +25 -0
- package/dist/views/Jobs/DrawerResults.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerResults.js +50 -0
- package/dist/views/Jobs/DrawerResults.js.map +1 -0
- package/dist/views/Jobs/DrawerReview.d.ts +44 -0
- package/dist/views/Jobs/DrawerReview.d.ts.map +1 -0
- package/dist/views/Jobs/DrawerReview.js +110 -0
- package/dist/views/Jobs/DrawerReview.js.map +1 -0
- package/dist/views/Jobs/JobDrawer.d.ts +31 -0
- package/dist/views/Jobs/JobDrawer.d.ts.map +1 -0
- package/dist/views/Jobs/JobDrawer.js +353 -0
- package/dist/views/Jobs/JobDrawer.js.map +1 -0
- package/dist/views/Jobs/JobsTable.d.ts +19 -0
- package/dist/views/Jobs/JobsTable.d.ts.map +1 -0
- package/dist/views/Jobs/JobsTable.js +80 -0
- package/dist/views/Jobs/JobsTable.js.map +1 -0
- package/dist/views/Jobs/WorkerStrip.d.ts +22 -0
- package/dist/views/Jobs/WorkerStrip.d.ts.map +1 -0
- package/dist/views/Jobs/WorkerStrip.js +63 -0
- package/dist/views/Jobs/WorkerStrip.js.map +1 -0
- package/dist/views/Jobs/atoms.d.ts +19 -0
- package/dist/views/Jobs/atoms.d.ts.map +1 -0
- package/dist/views/Jobs/atoms.js +52 -0
- package/dist/views/Jobs/atoms.js.map +1 -0
- package/dist/views/Jobs/focus.d.ts +23 -0
- package/dist/views/Jobs/focus.d.ts.map +1 -0
- package/dist/views/Jobs/focus.js +54 -0
- package/dist/views/Jobs/focus.js.map +1 -0
- package/dist/views/Jobs/icons.d.ts +22 -0
- package/dist/views/Jobs/icons.d.ts.map +1 -0
- package/dist/views/Jobs/icons.js +23 -0
- package/dist/views/Jobs/icons.js.map +1 -0
- package/dist/views/Jobs/placeholders.d.ts +6 -0
- package/dist/views/Jobs/placeholders.d.ts.map +1 -0
- package/dist/views/Jobs/placeholders.js +20 -0
- package/dist/views/Jobs/placeholders.js.map +1 -0
- package/dist/views/Jobs/useJobDetail.d.ts +21 -0
- package/dist/views/Jobs/useJobDetail.d.ts.map +1 -0
- package/dist/views/Jobs/useJobDetail.js +39 -0
- package/dist/views/Jobs/useJobDetail.js.map +1 -0
- package/dist/views/Jobs/useJobsFeed.d.ts +35 -0
- package/dist/views/Jobs/useJobsFeed.d.ts.map +1 -0
- package/dist/views/Jobs/useJobsFeed.js +231 -0
- package/dist/views/Jobs/useJobsFeed.js.map +1 -0
- package/dist/views/Jobs/useReviewItems.d.ts +39 -0
- package/dist/views/Jobs/useReviewItems.d.ts.map +1 -0
- package/dist/views/Jobs/useReviewItems.js +140 -0
- package/dist/views/Jobs/useReviewItems.js.map +1 -0
- package/dist/views/Jobs.d.ts +10 -1
- package/dist/views/Jobs.d.ts.map +1 -1
- package/dist/views/Jobs.js +126 -35
- package/dist/views/Jobs.js.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +37 -9
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/Pages/PagesListView.d.ts +1 -1
- package/dist/views/Pages/PagesListView.d.ts.map +1 -1
- package/dist/views/Pages/PagesListView.js +34 -5
- package/dist/views/Pages/PagesListView.js.map +1 -1
- package/dist/views/Posts/NewPostTypeInstructions.d.ts.map +1 -1
- package/dist/views/Posts/NewPostTypeInstructions.js +12 -2
- package/dist/views/Posts/NewPostTypeInstructions.js.map +1 -1
- package/dist/views/Posts/PostTypesView.d.ts.map +1 -1
- package/dist/views/Posts/PostTypesView.js +10 -1
- package/dist/views/Posts/PostTypesView.js.map +1 -1
- package/dist/views/Posts/PostsListView.d.ts +1 -2
- package/dist/views/Posts/PostsListView.d.ts.map +1 -1
- package/dist/views/Posts/PostsListView.js +31 -3
- package/dist/views/Posts/PostsListView.js.map +1 -1
- package/dist/views/SEO.d.ts.map +1 -1
- package/dist/views/SEO.js +3 -3
- package/dist/views/SEO.js.map +1 -1
- package/dist/views/ScriptTags.d.ts.map +1 -1
- package/dist/views/ScriptTags.js +20 -15
- package/dist/views/ScriptTags.js.map +1 -1
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +115 -51
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SpamFolder.d.ts +2 -0
- package/dist/views/SpamFolder.d.ts.map +1 -0
- package/dist/views/SpamFolder.js +14 -0
- package/dist/views/SpamFolder.js.map +1 -0
- package/dist/views/Trash.d.ts +6 -1
- package/dist/views/Trash.d.ts.map +1 -1
- package/dist/views/Trash.js +7 -2
- package/dist/views/Trash.js.map +1 -1
- package/dist/views/Users.js +2 -2
- package/dist/views/Users.js.map +1 -1
- package/dist/views/WidgetsPlaceholder.d.ts +2 -0
- package/dist/views/WidgetsPlaceholder.d.ts.map +1 -0
- package/dist/views/WidgetsPlaceholder.js +15 -0
- package/dist/views/WidgetsPlaceholder.js.map +1 -0
- package/dist/views/dashboard/kpi-grid.d.ts +18 -0
- package/dist/views/dashboard/kpi-grid.d.ts.map +1 -0
- package/dist/views/dashboard/kpi-grid.js +36 -0
- package/dist/views/dashboard/kpi-grid.js.map +1 -0
- package/dist/views/lazy-views.d.ts +4 -0
- package/dist/views/lazy-views.d.ts.map +1 -1
- package/dist/views/lazy-views.js +4 -0
- package/dist/views/lazy-views.js.map +1 -1
- package/dist/views/page-editor/PageTab.js +1 -1
- package/dist/views/page-editor/PageTab.js.map +1 -1
- package/dist/views/page-editor/ReviewBar.js +1 -1
- package/dist/views/page-editor/ReviewBar.js.map +1 -1
- package/dist/views/page-editor/VersionHistoryPanel.js +1 -1
- package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -1
- package/dist/views/seo/AuditTab.js +1 -1
- package/dist/views/seo/AuditTab.js.map +1 -1
- package/dist/views/seo/OverviewTab.d.ts.map +1 -1
- package/dist/views/seo/OverviewTab.js +2 -2
- package/dist/views/seo/OverviewTab.js.map +1 -1
- package/dist/views/seo/ProposalsTab.js +1 -1
- package/dist/views/seo/ProposalsTab.js.map +1 -1
- package/dist/views/settings/AISettingsTab.d.ts.map +1 -1
- package/dist/views/settings/AISettingsTab.js +4 -2
- package/dist/views/settings/AISettingsTab.js.map +1 -1
- package/dist/views/settings/AccessProtectionCard.js +1 -1
- package/dist/views/settings/AccessProtectionCard.js.map +1 -1
- package/dist/views/settings/AdminThemeCard.d.ts.map +1 -1
- package/dist/views/settings/AdminThemeCard.js +63 -15
- package/dist/views/settings/AdminThemeCard.js.map +1 -1
- package/dist/views/settings/AppearanceTab.d.ts.map +1 -1
- package/dist/views/settings/AppearanceTab.js +4 -2
- package/dist/views/settings/AppearanceTab.js.map +1 -1
- package/dist/views/settings/BrandPreviewCard.js +1 -1
- package/dist/views/settings/BrandPreviewCard.js.map +1 -1
- package/dist/views/settings/BrandVoiceCard.js +1 -1
- package/dist/views/settings/BrandVoiceCard.js.map +1 -1
- package/dist/views/settings/EmailSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/EmailSettingsTab.js +5 -3
- package/dist/views/settings/EmailSettingsTab.js.map +1 -1
- package/dist/views/settings/GeneralSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/GeneralSettingsTab.js +4 -2
- package/dist/views/settings/GeneralSettingsTab.js.map +1 -1
- package/dist/views/settings/McpConnectTab.d.ts.map +1 -1
- package/dist/views/settings/McpConnectTab.js +1 -1
- package/dist/views/settings/McpConnectTab.js.map +1 -1
- package/dist/views/settings/ProviderConnectionCard.js +1 -1
- package/dist/views/settings/ProviderConnectionCard.js.map +1 -1
- package/dist/views/settings/SearchDataCard.js +1 -1
- package/dist/views/settings/SearchDataCard.js.map +1 -1
- package/dist/views/settings/SecurityStatusCard.js +2 -2
- package/dist/views/settings/SecurityStatusCard.js.map +1 -1
- package/dist/views/settings/SecurityTab.d.ts.map +1 -1
- package/dist/views/settings/SecurityTab.js +4 -2
- package/dist/views/settings/SecurityTab.js.map +1 -1
- package/dist/views/settings/SeoAutopilotCard.js +2 -2
- package/dist/views/settings/SeoAutopilotCard.js.map +1 -1
- package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/SeoSettingsTab.js +5 -3
- package/dist/views/settings/SeoSettingsTab.js.map +1 -1
- package/dist/views/settings/SiteIndexStatusCard.js +1 -1
- package/dist/views/settings/SiteIndexStatusCard.js.map +1 -1
- package/dist/views/settings/SiteThemeCard.js +1 -1
- package/dist/views/settings/UpdatesTab.d.ts.map +1 -1
- package/dist/views/settings/UpdatesTab.js +6 -5
- package/dist/views/settings/UpdatesTab.js.map +1 -1
- package/dist/views/settings/components.d.ts +7 -11
- package/dist/views/settings/components.d.ts.map +1 -1
- package/dist/views/settings/components.js +18 -12
- package/dist/views/settings/components.js.map +1 -1
- package/dist/views/settings/useAppearanceSettings.d.ts +7 -1
- package/dist/views/settings/useAppearanceSettings.d.ts.map +1 -1
- package/dist/views/settings/useAppearanceSettings.js +89 -22
- package/dist/views/settings/useAppearanceSettings.js.map +1 -1
- package/dist/views/users/UserDetailDrawer.js +1 -1
- package/dist/views/users/UserDetailDrawer.js.map +1 -1
- package/package.json +11 -9
- package/src/AdminRoot.tsx +88 -30
- package/src/LoginRoot.tsx +2 -1
- package/src/__tests__/components/author-avatar.test.tsx +3 -20
- package/src/__tests__/components/notification-bell.test.tsx +146 -14
- package/src/__tests__/components/responsive-tiers.render.test.tsx +461 -0
- package/src/__tests__/components/serp-preview.render.test.tsx +6 -3
- package/src/__tests__/components/shell-primitives.render.test.tsx +951 -0
- package/src/__tests__/components/theme-provider-accent.test.tsx +83 -8
- package/src/__tests__/components/toggle.test.tsx +11 -3
- package/src/__tests__/components/ui-primitives.test.tsx +5 -8
- package/src/__tests__/layout/build-nav-items.test.ts +1 -1
- package/src/__tests__/layout/shell-nav.render.test.tsx +983 -0
- package/src/__tests__/layout/sidebar-forms-submenu.render.test.tsx +8 -4
- package/src/__tests__/layout/sidebar-groups.render.test.tsx +116 -0
- package/src/__tests__/layout/sidebar-menus.render.test.tsx +116 -0
- package/src/__tests__/layout/sidebar-plugin-nav.test.ts +1 -1
- package/src/__tests__/layout/sidebar-posts.test.ts +48 -40
- package/src/__tests__/layout/sidebar-submenu.render.test.tsx +35 -10
- package/src/__tests__/layout/topbar.render.test.tsx +464 -0
- package/src/__tests__/lib/api.test.ts +2 -0
- package/src/__tests__/lib/job-drawer.test.ts +493 -0
- package/src/__tests__/lib/job-view.test.ts +437 -0
- package/src/__tests__/lib/jobs-service.test.ts +98 -0
- package/src/__tests__/router/admin-route-order.test.ts +39 -0
- package/src/__tests__/styles/ai-gradient-contrast.test.ts +135 -0
- package/src/__tests__/styles/breakpoint-order.test.ts +68 -0
- package/src/__tests__/styles/responsive-layer.test.ts +367 -12
- package/src/__tests__/styles/tailwind-preset.test.ts +154 -0
- package/src/__tests__/styles/theme-token-scope.test.ts +10 -3
- package/src/__tests__/styles/tiers.test.ts +136 -0
- package/src/__tests__/styles/tokens-drift.test.ts +67 -6
- package/src/__tests__/views/admin-lazy-route.render.test.tsx +41 -1
- package/src/__tests__/views/ai-settings.render.test.tsx +4 -4
- package/src/__tests__/views/appearance-menus-route.render.test.tsx +58 -0
- package/src/__tests__/views/appearance-settings.render.test.tsx +10 -8
- package/src/__tests__/views/appearance-theme-provider.render.test.tsx +347 -0
- package/src/__tests__/views/dashboard.test.tsx +48 -0
- package/src/__tests__/views/document-edit-navigation.render.test.tsx +130 -0
- package/src/__tests__/views/document-edit-routes.render.test.tsx +130 -0
- package/src/__tests__/views/email-settings.render.test.tsx +2 -2
- package/src/__tests__/views/form-entries.render.test.tsx +22 -0
- package/src/__tests__/views/form-submissions.render.test.tsx +22 -0
- package/src/__tests__/views/forms-list.render.test.tsx +13 -0
- package/src/__tests__/views/general-settings.render.test.tsx +38 -11
- package/src/__tests__/views/jobs-drawer.render.test.tsx +1047 -0
- package/src/__tests__/views/jobs-list.render.test.tsx +850 -0
- package/src/__tests__/views/kpi-grid.test.ts +29 -0
- package/src/__tests__/views/mcp-connect.render.test.tsx +1 -0
- package/src/__tests__/views/post-section-editor.test.tsx +5 -1
- package/src/__tests__/views/script-tags.render.test.tsx +29 -0
- package/src/__tests__/views/security-settings.render.test.tsx +9 -10
- package/src/__tests__/views/seo-settings.render.test.tsx +7 -9
- package/src/__tests__/views/settings-save-bar.render.test.tsx +91 -0
- package/src/__tests__/views/settings-save-footer.render.test.tsx +25 -15
- package/src/__tests__/views/settings-tabs.render.test.tsx +371 -0
- package/src/__tests__/views/updates-tab.render.test.tsx +4 -3
- package/src/components/Breadcrumbs.tsx +7 -1
- package/src/components/CommandPalette.tsx +51 -3
- package/src/components/LocaleSwitcher.tsx +5 -6
- package/src/components/NotificationBell.tsx +74 -18
- package/src/components/OfflineStatus.tsx +1 -1
- package/src/components/PresenceIndicator.tsx +2 -1
- package/src/components/ReflowMeter.tsx +3 -3
- package/src/components/SEOPanel.tsx +2 -2
- package/src/components/ThemeProvider.tsx +122 -42
- package/src/components/TipTapEditor.tsx +3 -4
- package/src/components/forms/EmbedPanel.tsx +1 -1
- package/src/components/forms/FormEntryDetailPane.tsx +7 -1
- package/src/components/forms/ShortcodeGlossary.tsx +7 -1
- package/src/components/forms/primitives.tsx +37 -21
- package/src/components/pages/tag-badges.tsx +4 -3
- package/src/components/seo/PageAuditPanel.tsx +2 -2
- package/src/components/seo/SerpPreview.tsx +5 -5
- package/src/components/seo/primitives.tsx +2 -2
- package/src/components/ui/AuthorAvatar.tsx +11 -10
- package/src/components/ui/Badge.tsx +1 -1
- package/src/components/ui/Breadcrumb.tsx +109 -0
- package/src/components/ui/Button.tsx +40 -15
- package/src/components/ui/Card.tsx +35 -32
- package/src/components/ui/CardListControls.tsx +90 -0
- package/src/components/ui/CountChip.tsx +90 -0
- package/src/components/ui/FilterPill.tsx +5 -3
- package/src/components/ui/InspectorPane.tsx +21 -7
- package/src/components/ui/Modal.tsx +20 -6
- package/src/components/ui/PageHeader.tsx +63 -0
- package/src/components/ui/RowActions.tsx +7 -2
- package/src/components/ui/Segmented.tsx +97 -0
- package/src/components/ui/Toaster.tsx +139 -0
- package/src/components/ui/Toggle.tsx +18 -14
- package/src/components/ui/UnderlineTabs.tsx +373 -0
- package/src/components/ui/UnsavedBar.tsx +119 -0
- package/src/components/ui/admin-links.tsx +20 -0
- package/src/components/ui/card-table.ts +34 -0
- package/src/components/virtual-window.tsx +13 -2
- package/src/fields/RelationshipField.tsx +1 -1
- package/src/hooks/useAppearanceBootstrap.ts +9 -3
- package/src/index.ts +19 -0
- package/src/layout/Header.tsx +210 -135
- package/src/layout/Layout.tsx +61 -108
- package/src/layout/MobileTabBar.tsx +92 -0
- package/src/layout/Sidebar.tsx +555 -593
- package/src/layout/nav-config.tsx +425 -0
- package/src/layout/primitives/AdminShell.tsx +154 -6
- package/src/layout/topbar-classes.ts +8 -0
- package/src/layout/use-nav-items.ts +40 -0
- package/src/lib/api.ts +7 -1
- package/src/lib/appearance-api.ts +4 -0
- package/src/lib/job-drawer.ts +424 -0
- package/src/lib/job-view.ts +456 -0
- package/src/lib/jobs-service.ts +290 -0
- package/src/lib/sheet-focus.ts +71 -0
- package/src/lib/tiers.ts +43 -0
- package/src/router/admin-routes.ts +8 -0
- package/src/router/index.ts +9 -1
- package/src/styles/prenta-tokens.css +263 -82
- package/src/styles/responsive.css +460 -22
- package/src/styles/theme.css +177 -28
- package/src/views/ApiKeys.tsx +2 -2
- package/src/views/AppearanceChrome.tsx +74 -0
- package/src/views/CollectionList.tsx +264 -205
- package/src/views/Dashboard.tsx +26 -13
- package/src/views/DocumentEdit.tsx +111 -56
- package/src/views/FormDeliveries.tsx +30 -17
- package/src/views/FormEntries.tsx +28 -20
- package/src/views/FormSubmissions.tsx +32 -34
- package/src/views/Forms.tsx +55 -34
- package/src/views/FormsSettings.tsx +94 -0
- package/src/views/Jobs/BusyButton.tsx +56 -0
- package/src/views/Jobs/CancelJobDialog.tsx +127 -0
- package/src/views/Jobs/DrawerActivity.tsx +142 -0
- package/src/views/Jobs/DrawerOverview.tsx +139 -0
- package/src/views/Jobs/DrawerResults.tsx +155 -0
- package/src/views/Jobs/DrawerReview.tsx +464 -0
- package/src/views/Jobs/JobDrawer.tsx +556 -0
- package/src/views/Jobs/JobsTable.tsx +260 -0
- package/src/views/Jobs/WorkerStrip.tsx +144 -0
- package/src/views/Jobs/atoms.tsx +93 -0
- package/src/views/Jobs/focus.ts +56 -0
- package/src/views/Jobs/icons.tsx +111 -0
- package/src/views/Jobs/placeholders.tsx +66 -0
- package/src/views/Jobs/useJobDetail.ts +64 -0
- package/src/views/Jobs/useJobsFeed.ts +249 -0
- package/src/views/Jobs/useReviewItems.ts +187 -0
- package/src/views/Jobs.tsx +282 -105
- package/src/views/MediaBrowser.tsx +71 -21
- package/src/views/Pages/PagesListView.tsx +115 -39
- package/src/views/Posts/NewPostTypeInstructions.tsx +15 -10
- package/src/views/Posts/PostTypesView.tsx +28 -6
- package/src/views/Posts/PostsListView.tsx +130 -40
- package/src/views/SEO.tsx +23 -8
- package/src/views/ScriptTags.tsx +233 -153
- package/src/views/Settings.tsx +215 -256
- package/src/views/SpamFolder.tsx +32 -0
- package/src/views/Trash.tsx +12 -1
- package/src/views/Users.tsx +2 -2
- package/src/views/WidgetsPlaceholder.tsx +33 -0
- package/src/views/dashboard/kpi-grid.ts +38 -0
- package/src/views/lazy-views.tsx +12 -0
- package/src/views/page-editor/PageTab.tsx +2 -2
- package/src/views/page-editor/ReviewBar.tsx +1 -1
- package/src/views/page-editor/VersionHistoryPanel.tsx +1 -1
- package/src/views/seo/AuditTab.tsx +1 -1
- package/src/views/seo/OverviewTab.tsx +6 -5
- package/src/views/seo/ProposalsTab.tsx +1 -1
- package/src/views/settings/AISettingsTab.tsx +10 -6
- package/src/views/settings/AccessProtectionCard.tsx +1 -1
- package/src/views/settings/AdminThemeCard.tsx +228 -35
- package/src/views/settings/AppearanceTab.tsx +10 -6
- package/src/views/settings/BrandPreviewCard.tsx +1 -1
- package/src/views/settings/BrandVoiceCard.tsx +1 -1
- package/src/views/settings/EmailSettingsTab.tsx +11 -7
- package/src/views/settings/GeneralSettingsTab.tsx +10 -6
- package/src/views/settings/McpConnectTab.tsx +2 -1
- package/src/views/settings/ProviderConnectionCard.tsx +1 -1
- package/src/views/settings/SearchDataCard.tsx +1 -1
- package/src/views/settings/SecurityStatusCard.tsx +2 -2
- package/src/views/settings/SecurityTab.tsx +10 -6
- package/src/views/settings/SeoAutopilotCard.tsx +2 -2
- package/src/views/settings/SeoSettingsTab.tsx +13 -9
- package/src/views/settings/SiteIndexStatusCard.tsx +1 -1
- package/src/views/settings/SiteThemeCard.tsx +1 -1
- package/src/views/settings/UpdatesTab.tsx +107 -101
- package/src/views/settings/components.tsx +26 -62
- package/src/views/settings/useAppearanceSettings.ts +116 -25
- package/src/views/users/UserDetailDrawer.tsx +1 -1
- package/dist/components/ui/StatPill.d.ts +0 -18
- package/dist/components/ui/StatPill.d.ts.map +0 -1
- package/dist/components/ui/StatPill.js +0 -5
- package/dist/components/ui/StatPill.js.map +0 -1
- package/src/components/ui/StatPill.tsx +0 -37
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
4
|
+
import { fetchFormsSidebarCounts, type FormsSidebarCount } from '../lib/forms-service.js'
|
|
5
|
+
import { onFormsChanged } from '../lib/forms-events.js'
|
|
6
|
+
import { applyFormsNav, buildNavItems, type NavItem } from './nav-config.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The nav tree with live Forms counts. Counts refresh on mount and whenever a
|
|
10
|
+
* forms/entries mutation fires the shared event (mark read, archive, notify
|
|
11
|
+
* toggle, …). Best-effort: a failed fetch keeps the last known value rather
|
|
12
|
+
* than surfacing an error in nav. Pass `enabled: false` to skip the fetch when
|
|
13
|
+
* the caller already has the items.
|
|
14
|
+
*/
|
|
15
|
+
export function useNavItems(config: any, enabled = true): NavItem[] {
|
|
16
|
+
const [forms, setForms] = useState<FormsSidebarCount[]>([])
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!enabled) return
|
|
20
|
+
let active = true
|
|
21
|
+
const load = () => {
|
|
22
|
+
fetchFormsSidebarCounts()
|
|
23
|
+
.then((counts) => {
|
|
24
|
+
// A malformed response must not break the nav.
|
|
25
|
+
if (active && Array.isArray(counts)) setForms(counts)
|
|
26
|
+
})
|
|
27
|
+
.catch(() => {
|
|
28
|
+
/* keep the last known value; nav must never break on a fetch error */
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
load()
|
|
32
|
+
const off = onFormsChanged(load)
|
|
33
|
+
return () => {
|
|
34
|
+
active = false
|
|
35
|
+
off()
|
|
36
|
+
}
|
|
37
|
+
}, [enabled])
|
|
38
|
+
|
|
39
|
+
return useMemo(() => applyFormsNav(buildNavItems(config), forms), [config, forms])
|
|
40
|
+
}
|
package/src/lib/api.ts
CHANGED
|
@@ -76,6 +76,12 @@ export interface CmsApiResult<T> {
|
|
|
76
76
|
* `/seo/autopilot/applied/:id/revert`). Callers must narrow it themselves.
|
|
77
77
|
*/
|
|
78
78
|
errorBody?: unknown
|
|
79
|
+
/**
|
|
80
|
+
* The parsed 2xx body, for the few endpoints that send fields beside `data`
|
|
81
|
+
* (e.g. a job review decision's `documentStatus` and `notice`). Callers must
|
|
82
|
+
* narrow it themselves.
|
|
83
|
+
*/
|
|
84
|
+
body?: unknown
|
|
79
85
|
status: number
|
|
80
86
|
}
|
|
81
87
|
|
|
@@ -121,7 +127,7 @@ export async function cmsApi<T = unknown>(
|
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
129
|
|
|
124
|
-
return { data: json.data ?? json, status: res.status }
|
|
130
|
+
return { data: json.data ?? json, body: json, status: res.status }
|
|
125
131
|
} catch (err) {
|
|
126
132
|
return { error: err instanceof Error ? err.message : 'Network error', status: 0 }
|
|
127
133
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type BrandAssetLike,
|
|
5
5
|
type BrandSettings,
|
|
6
6
|
type ColorMode,
|
|
7
|
+
type LightBase,
|
|
7
8
|
type LogoShape,
|
|
8
9
|
type SidebarDensity,
|
|
9
10
|
} from '@prenta/core/appearance'
|
|
@@ -14,6 +15,8 @@ import type { AdminBrandCache, AppearanceSnapshot } from '../components/ThemePro
|
|
|
14
15
|
export interface AppearanceApiResponse {
|
|
15
16
|
appearance: {
|
|
16
17
|
adminColorModeDefault: ColorMode
|
|
18
|
+
/** Absent on servers that predate the Linen base; treat as Porcelain. */
|
|
19
|
+
adminLightBase?: LightBase
|
|
17
20
|
adminAccentColor: string
|
|
18
21
|
sidebarDensity: SidebarDensity
|
|
19
22
|
contentFont: string
|
|
@@ -83,6 +86,7 @@ export function appearanceApiToSnapshot(data: AppearanceApiResponse): Appearance
|
|
|
83
86
|
const assets = parseAppearanceAssets(data.assets)
|
|
84
87
|
return {
|
|
85
88
|
theme: data.appearance.adminColorModeDefault,
|
|
89
|
+
lightBase: data.appearance.adminLightBase === 'linen' ? 'linen' : 'porcelain',
|
|
86
90
|
accent: data.appearance.adminAccentColor,
|
|
87
91
|
density: data.appearance.sidebarDensity,
|
|
88
92
|
font: data.appearance.contentFont,
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import type { Job, JobEvent, JobReviewItem } from '@prenta/core'
|
|
2
|
+
import { JOB_OPS, formatCreated, formatLater, jobType, view, type JobRow } from './job-view.js'
|
|
3
|
+
import type { ApproveAllOutcome, OnApprove } from './jobs-service.js'
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* The job drawer's copy and mappings, ported from the kit's jobs-drawer.jsx
|
|
7
|
+
* (`OVERVIEW`, the tabs, the facts grid, the activity list and the raw row).
|
|
8
|
+
* They read the list's `JobRow` for the state the screen shows, and the API's
|
|
9
|
+
* `Job` for what only the detail has.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type DrawerTab = 'overview' | 'review' | 'results' | 'activity' | 'details'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* jobs-drawer.jsx `tabs`: Review for batch AI, Results for scans. Review is
|
|
16
|
+
* left out for someone who can't read the suggested changes (a 403), and a
|
|
17
|
+
* job type the kit doesn't know has neither.
|
|
18
|
+
*/
|
|
19
|
+
export function drawerTabs(
|
|
20
|
+
type: string,
|
|
21
|
+
canReview: boolean,
|
|
22
|
+
): Array<{ id: DrawerTab; label: string }> {
|
|
23
|
+
const second: { id: DrawerTab; label: string } | null =
|
|
24
|
+
type === 'batch-ai'
|
|
25
|
+
? canReview
|
|
26
|
+
? { id: 'review', label: 'Review' }
|
|
27
|
+
: null
|
|
28
|
+
: type === 'seo-scan' || type === 'content-health'
|
|
29
|
+
? { id: 'results', label: 'Results' }
|
|
30
|
+
: null
|
|
31
|
+
return [
|
|
32
|
+
{ id: 'overview', label: 'Overview' },
|
|
33
|
+
...(second ? [second] : []),
|
|
34
|
+
{ id: 'activity', label: 'Activity' },
|
|
35
|
+
{ id: 'details', label: 'Details' },
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A queued job whose next run is further off than this waits out a usage limit. */
|
|
40
|
+
const CAP_WAIT_MS = 2 * 60_000
|
|
41
|
+
|
|
42
|
+
export interface CapWait {
|
|
43
|
+
message: string
|
|
44
|
+
until: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A job waiting out an AI usage cap (CONFLICTS.md §4, "Cap refusals"). It
|
|
49
|
+
* yielded with the cap's message in `progress.message` and `runAt` at the
|
|
50
|
+
* reset, and with no error, because the slice didn't fail.
|
|
51
|
+
*/
|
|
52
|
+
export function capWait(job: Job, row: JobRow, now: number): CapWait | null {
|
|
53
|
+
if (row.state !== 'queued' || row.error || row.cancelling) return null
|
|
54
|
+
const message = job.progress.message?.trim()
|
|
55
|
+
const until = Date.parse(job.runAt)
|
|
56
|
+
if (!message || !(until - now > CAP_WAIT_MS)) return null
|
|
57
|
+
return { message, until }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function sentence(text: string): string {
|
|
61
|
+
return /[.!?…]$/.test(text) ? text : `${text}.`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function lowerFirst(text: string): string {
|
|
65
|
+
return text.charAt(0).toLowerCase() + text.slice(1)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* jobs-drawer.jsx `OVERVIEW`: the plain-language status sentence. Edits:
|
|
70
|
+
* attempts read the job's `maxAttempts`; the slice copy keeps its own
|
|
71
|
+
* capitals ("the SEO digest"); "Finished in … across n slices" counts slices
|
|
72
|
+
* from the type's slice size; and a job waiting out a usage cap, or a cancel
|
|
73
|
+
* whose worker stopped, says so.
|
|
74
|
+
*/
|
|
75
|
+
export function overviewSentence(row: JobRow, job: Job, now: number): string {
|
|
76
|
+
const type = jobType(row.type)
|
|
77
|
+
const unit = type.unit
|
|
78
|
+
const wait = capWait(job, row, now)
|
|
79
|
+
if (wait) {
|
|
80
|
+
const done = row.done > 0 ? `${row.done} of ${row.total} ${unit} done. ` : ''
|
|
81
|
+
return `${done}Paused for a usage limit. ${sentence(wait.message)} It continues ${formatLater(wait.until, now)}.`
|
|
82
|
+
}
|
|
83
|
+
const v = view(row)
|
|
84
|
+
switch (v.k) {
|
|
85
|
+
case 'running': {
|
|
86
|
+
const slice = type.slice ? ` Each slice ${lowerFirst(type.slice)}` : ''
|
|
87
|
+
return `Running slice ${row.done + 1} of ${row.total} now.${slice} When the worker’s 20 seconds are up, the job yields and continues on the next run. Yielding isn’t a failure and doesn’t use a retry.`
|
|
88
|
+
}
|
|
89
|
+
case 'between':
|
|
90
|
+
return `${row.done} of ${row.total} ${unit} done. It’s waiting for the next worker run, about once a minute.`
|
|
91
|
+
case 'queued':
|
|
92
|
+
return `Waiting for the worker. ${
|
|
93
|
+
row.queuePos
|
|
94
|
+
? `${row.queuePos} job${row.queuePos > 1 ? 's are' : ' is'} ahead of it.`
|
|
95
|
+
: 'It starts on the next run.'
|
|
96
|
+
}`
|
|
97
|
+
case 'retry':
|
|
98
|
+
return `The last slice threw an error, so the job will try again in ${row.retryIn} seconds. Retries wait 30 seconds, then double each time, up to 15 minutes. After ${row.maxAttempts} attempts it’s marked failed.`
|
|
99
|
+
case 'dead':
|
|
100
|
+
return `Stopped after ${row.maxAttempts} attempts at ${unit === 'pages' ? 'page' : 'document'} ${row.done + 1}. The last error is kept below. Retrying resets the attempt count and continues from where it stopped.`
|
|
101
|
+
case 'cancelled':
|
|
102
|
+
return `Cancelled${row.cancelledBy ? ` by ${row.cancelledBy}` : ''} after ${row.done} of ${row.total} ${unit}. Work already done was kept.`
|
|
103
|
+
case 'cancelling':
|
|
104
|
+
// A running job whose lock went stale ends on the next tick (CancelJobDialog).
|
|
105
|
+
return row.status === 'running' && row.state !== 'running'
|
|
106
|
+
? 'Its last slice stopped without finishing. It stops on the next worker run, within a minute.'
|
|
107
|
+
: 'Stopping when the current slice finishes, usually within 20 seconds.'
|
|
108
|
+
case 'review':
|
|
109
|
+
return `Finished. ${row.pending} AI change${row.pending > 1 ? 's are' : ' is'} waiting for approval. Nothing is applied until someone approves it.`
|
|
110
|
+
default: {
|
|
111
|
+
const took = row.took ?? '—'
|
|
112
|
+
const slices = type.perSlice ? Math.max(1, Math.ceil(row.total / type.perSlice)) : 0
|
|
113
|
+
return slices
|
|
114
|
+
? `Finished in ${took} across ${slices} slice${slices === 1 ? '' : 's'}.`
|
|
115
|
+
: `Finished in ${took}.`
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The facts grid's "Attempts". The API counts failures, so a healthy job has
|
|
122
|
+
* 0; the kit shows the attempt a job is on or finished with ("1 of 3"), and
|
|
123
|
+
* for one waiting to retry, or failed, the attempts used.
|
|
124
|
+
*/
|
|
125
|
+
export function shownAttempts(row: JobRow): number {
|
|
126
|
+
const k = view(row).k
|
|
127
|
+
if (k === 'retry' || k === 'dead' || k === 'queued') return row.attempts
|
|
128
|
+
return Math.min(row.attempts + 1, row.maxAttempts)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The operation's label ("Rewrite meta descriptions"), or null when the kit doesn't know it. */
|
|
132
|
+
export function operationLabel(operation: unknown): string | null {
|
|
133
|
+
return JOB_OPS.find((op) => op.id === operation)?.label ?? null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** "now", "6s ago", "19m ago", then the list's "Yesterday 16:41". */
|
|
137
|
+
export function formatEventTime(iso: string, now: number): string {
|
|
138
|
+
const ms = now - Date.parse(iso)
|
|
139
|
+
if (!(ms >= 5_000)) return 'now'
|
|
140
|
+
if (ms < 60_000) return `${Math.floor(ms / 1000)}s ago`
|
|
141
|
+
if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m ago`
|
|
142
|
+
return formatCreated(iso, now)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export type TimelineTone = 'ok' | 'err' | 'warn' | 'run' | 'none'
|
|
146
|
+
|
|
147
|
+
export interface TimelineEntry {
|
|
148
|
+
key: string
|
|
149
|
+
/** ISO time; null on the two rows made up for a job with no events. */
|
|
150
|
+
at: string | null
|
|
151
|
+
title: string
|
|
152
|
+
detail: string
|
|
153
|
+
tone: TimelineTone
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** A fold has no key of its own: `foldIds` gives it one that lasts. */
|
|
157
|
+
export type TimelineRow =
|
|
158
|
+
| { kind: 'entry'; entry: TimelineEntry }
|
|
159
|
+
| { kind: 'group'; entries: TimelineEntry[] }
|
|
160
|
+
|
|
161
|
+
/** Finished slices shown before the rest collapse into "{n} earlier slices". */
|
|
162
|
+
const SLICES_SHOWN = 2
|
|
163
|
+
|
|
164
|
+
function eventTone(event: JobEvent, newest: boolean, running: boolean): TimelineTone {
|
|
165
|
+
switch (event.kind) {
|
|
166
|
+
case 'finished':
|
|
167
|
+
case 'slice_ok':
|
|
168
|
+
return 'ok'
|
|
169
|
+
case 'yielded':
|
|
170
|
+
return /usage limit/i.test(event.message) ? 'warn' : 'ok'
|
|
171
|
+
case 'slice_failed':
|
|
172
|
+
case 'dead':
|
|
173
|
+
return 'err'
|
|
174
|
+
case 'retry_scheduled':
|
|
175
|
+
case 'stale_lock':
|
|
176
|
+
case 'cancel_requested':
|
|
177
|
+
return 'warn'
|
|
178
|
+
case 'claimed':
|
|
179
|
+
return newest && running ? 'run' : 'none'
|
|
180
|
+
default:
|
|
181
|
+
return 'none'
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function eventDetail(event: JobEvent, by: string): string {
|
|
186
|
+
const parts: string[] = []
|
|
187
|
+
const detail = event.detail?.trim()
|
|
188
|
+
if (detail) parts.push(detail)
|
|
189
|
+
else if (event.kind === 'queued' && event.message === 'Queued') parts.push(`${by} started it`)
|
|
190
|
+
if (typeof event.durationMs === 'number') parts.push(`${(event.durationMs / 1000).toFixed(1)}s`)
|
|
191
|
+
if (event.tokens) parts.push(`${event.tokens.toLocaleString()} tokens`)
|
|
192
|
+
if (event.kind === 'yielded' && !/usage limit/i.test(event.message)) parts.push('yielded')
|
|
193
|
+
return parts.join(' · ')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* The Activity tab (jobs-drawer.jsx `act`), newest first, from the job's
|
|
198
|
+
* events. Each slice writes "Slice started" and then how it ended; the start
|
|
199
|
+
* is shown only while it runs, when it names a later attempt, and for the
|
|
200
|
+
* oldest one, so the list reads like the kit's. Past the newest two finished
|
|
201
|
+
* slices, runs of finished slices collapse into one "{n} earlier slices" row.
|
|
202
|
+
* A job with no events (from before the log existed) gets the kit's two rows.
|
|
203
|
+
*/
|
|
204
|
+
export function timeline(events: JobEvent[], job: Job, row: JobRow): TimelineRow[] {
|
|
205
|
+
if (events.length === 0) {
|
|
206
|
+
const succeeded = row.state === 'succeeded'
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
kind: 'entry',
|
|
210
|
+
entry: {
|
|
211
|
+
key: 'updated',
|
|
212
|
+
at: job.updatedAt,
|
|
213
|
+
title: succeeded ? 'Finished' : 'Updated',
|
|
214
|
+
detail: row.took ? `Took ${row.took}` : '',
|
|
215
|
+
tone: succeeded ? 'ok' : 'none',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
kind: 'entry',
|
|
220
|
+
entry: { key: 'queued', at: job.createdAt, title: 'Queued', detail: row.by, tone: 'none' },
|
|
221
|
+
},
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
const sorted = events
|
|
225
|
+
.map((event, index) => ({ event, index }))
|
|
226
|
+
.sort((a, b) => Date.parse(b.event.at) - Date.parse(a.event.at) || a.index - b.index)
|
|
227
|
+
.map(({ event }) => event)
|
|
228
|
+
let oldestClaim = -1
|
|
229
|
+
sorted.forEach((event, index) => {
|
|
230
|
+
if (event.kind === 'claimed') oldestClaim = index
|
|
231
|
+
})
|
|
232
|
+
// Keys are counted from the oldest end, so a new event doesn't change the
|
|
233
|
+
// keys of the ones already shown (and an open group stays open).
|
|
234
|
+
const keys: string[] = []
|
|
235
|
+
const seen = new Map<string, number>()
|
|
236
|
+
for (let index = sorted.length - 1; index >= 0; index--) {
|
|
237
|
+
const event = sorted[index]!
|
|
238
|
+
const base = `${event.at}|${event.kind}|${event.message}`
|
|
239
|
+
const repeats = seen.get(base) ?? 0
|
|
240
|
+
seen.set(base, repeats + 1)
|
|
241
|
+
keys[index] = repeats ? `${base}|${repeats}` : base
|
|
242
|
+
}
|
|
243
|
+
const running = row.state === 'running'
|
|
244
|
+
const rows: TimelineRow[] = []
|
|
245
|
+
let shownSlices = 0
|
|
246
|
+
let group: TimelineEntry[] = []
|
|
247
|
+
const flush = () => {
|
|
248
|
+
const [first] = group
|
|
249
|
+
if (group.length === 1 && first) rows.push({ kind: 'entry', entry: first })
|
|
250
|
+
else if (first) rows.push({ kind: 'group', entries: group })
|
|
251
|
+
group = []
|
|
252
|
+
}
|
|
253
|
+
sorted.forEach((event, index) => {
|
|
254
|
+
const tone = eventTone(event, index === 0, running)
|
|
255
|
+
if (event.kind === 'claimed' && tone !== 'run' && !event.detail && index !== oldestClaim) return
|
|
256
|
+
const entry: TimelineEntry = {
|
|
257
|
+
key: keys[index]!,
|
|
258
|
+
at: event.at,
|
|
259
|
+
title: event.message,
|
|
260
|
+
detail: eventDetail(event, row.by),
|
|
261
|
+
tone,
|
|
262
|
+
}
|
|
263
|
+
const slice = (event.kind === 'yielded' || event.kind === 'slice_ok') && tone === 'ok'
|
|
264
|
+
if (slice && shownSlices >= SLICES_SHOWN) {
|
|
265
|
+
group.push(entry)
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
if (slice) shownSlices++
|
|
269
|
+
flush()
|
|
270
|
+
rows.push({ kind: 'entry', entry })
|
|
271
|
+
})
|
|
272
|
+
flush()
|
|
273
|
+
return rows
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** What `foldIds` remembers from one refresh to the next. */
|
|
277
|
+
export interface FoldMemory {
|
|
278
|
+
/** Entry key → the id of the fold it was in. */
|
|
279
|
+
entries: Map<string, string>
|
|
280
|
+
next: number
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* An id for each fold in `rows`, in order, that lasts while any of its
|
|
285
|
+
* slices is still in it. A fold's edges all move: newer slices join it, the
|
|
286
|
+
* newest-50 window drops its oldest, and older folds shrink away, so no
|
|
287
|
+
* position or edge entry names it for long. `memory` maps each folded entry
|
|
288
|
+
* to its fold's id and is updated. When folds merge, an id in `prefer` (the
|
|
289
|
+
* open ones) wins, so an open fold stays open, and a fold made of entries
|
|
290
|
+
* never folded before gets a new id, so it never takes an open fold's state.
|
|
291
|
+
*/
|
|
292
|
+
export function foldIds(
|
|
293
|
+
rows: TimelineRow[],
|
|
294
|
+
memory: FoldMemory,
|
|
295
|
+
prefer: ReadonlySet<string> = new Set(),
|
|
296
|
+
): string[] {
|
|
297
|
+
const used = new Set<string>()
|
|
298
|
+
const seen = new Map<string, string>()
|
|
299
|
+
const ids: string[] = []
|
|
300
|
+
for (const row of rows) {
|
|
301
|
+
if (row.kind !== 'group') continue
|
|
302
|
+
const known: string[] = []
|
|
303
|
+
for (const entry of row.entries) {
|
|
304
|
+
const id = memory.entries.get(entry.key)
|
|
305
|
+
if (id && !used.has(id) && !known.includes(id)) known.push(id)
|
|
306
|
+
}
|
|
307
|
+
const id =
|
|
308
|
+
known.find((candidate) => prefer.has(candidate)) ?? known[0] ?? `fold-${memory.next++}`
|
|
309
|
+
used.add(id)
|
|
310
|
+
for (const entry of row.entries) seen.set(entry.key, id)
|
|
311
|
+
ids.push(id)
|
|
312
|
+
}
|
|
313
|
+
// Entries no longer folded have left the window (or never come back).
|
|
314
|
+
memory.entries = seen
|
|
315
|
+
return ids
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The Details tab's raw row. Like the kit, the frozen document ids read as
|
|
320
|
+
* "[42 ids]" rather than up to 1,000 of them.
|
|
321
|
+
*/
|
|
322
|
+
export function detailsJson(job: Job): string {
|
|
323
|
+
const payload = job.payload as Record<string, unknown>
|
|
324
|
+
const ids = payload.documentIds
|
|
325
|
+
return JSON.stringify(
|
|
326
|
+
Array.isArray(ids)
|
|
327
|
+
? { ...job, payload: { ...payload, documentIds: `[${ids.length} ids]` } }
|
|
328
|
+
: job,
|
|
329
|
+
null,
|
|
330
|
+
2,
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** The link a link suggestion's `after` holds (cms-core `ai/batch-links.ts`, `LINK_IN_AFTER`). */
|
|
335
|
+
const LINK_IN_AFTER = /<a href="(\/(?!\/)[^"<>\s\\]*)">([^<>]+)<\/a>/
|
|
336
|
+
|
|
337
|
+
export interface LinkParts {
|
|
338
|
+
before: string
|
|
339
|
+
anchor: string
|
|
340
|
+
href: string
|
|
341
|
+
after: string
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* A link suggestion's line split around its link, so the drawer shows the
|
|
346
|
+
* words as text and never renders the markup. Null when `after` holds no link
|
|
347
|
+
* in the form the server writes.
|
|
348
|
+
*/
|
|
349
|
+
export function linkParts(after: string): LinkParts | null {
|
|
350
|
+
const match = LINK_IN_AFTER.exec(after)
|
|
351
|
+
if (!match) return null
|
|
352
|
+
return {
|
|
353
|
+
before: after.slice(0, match.index),
|
|
354
|
+
href: match[1] ?? '',
|
|
355
|
+
anchor: match[2] ?? '',
|
|
356
|
+
after: after.slice(match.index + match[0].length),
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** The suggested text's limit, past which its count turns red (JOBS.md: meta descriptions). */
|
|
361
|
+
export function charLimit(field: string): number | null {
|
|
362
|
+
return field === 'metaDescription' ? 155 : null
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* A fresh read of the loaded changes, in the order suggested. A change decided
|
|
367
|
+
* here after that read started keeps the copy the decision returned, so a slow
|
|
368
|
+
* refresh can't put it back to pending.
|
|
369
|
+
*/
|
|
370
|
+
export function mergeReviewItems(
|
|
371
|
+
fresh: JobReviewItem[],
|
|
372
|
+
loaded: JobReviewItem[],
|
|
373
|
+
keep: ReadonlySet<string>,
|
|
374
|
+
): JobReviewItem[] {
|
|
375
|
+
const local = new Map(loaded.map((item) => [item.id, item]))
|
|
376
|
+
return fresh.map((item) => (keep.has(item.id) ? (local.get(item.id) ?? item) : item))
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** A page appended to the loaded changes, without repeating any. */
|
|
380
|
+
export function appendReviewItems(loaded: JobReviewItem[], page: JobReviewItem[]): JobReviewItem[] {
|
|
381
|
+
const seen = new Set(loaded.map((item) => item.id))
|
|
382
|
+
return [...loaded, ...page.filter((item) => !seen.has(item.id))]
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* "Approve all" toast (jobs-drawer.jsx `approveAll`), plus what stayed in
|
|
387
|
+
* review: approve-all skips changes to published documents when they'd be
|
|
388
|
+
* saved as drafts, changes the reviewer can't write, and saves that fail.
|
|
389
|
+
*/
|
|
390
|
+
export function approveAllMessage(
|
|
391
|
+
outcome: Pick<ApproveAllOutcome, 'approved' | 'remaining'>,
|
|
392
|
+
onApprove: OnApprove,
|
|
393
|
+
): { title: string; description?: string } {
|
|
394
|
+
const { approved, remaining } = outcome
|
|
395
|
+
const title =
|
|
396
|
+
approved > 0
|
|
397
|
+
? `${approved} change${approved === 1 ? '' : 's'} approved · ${onApprove === 'publish' ? 'published' : 'saved as drafts'}`
|
|
398
|
+
: 'No changes were approved'
|
|
399
|
+
if (remaining <= 0) return { title }
|
|
400
|
+
const left = `${remaining} ${remaining === 1 ? 'change' : 'changes'} stayed in review.`
|
|
401
|
+
return {
|
|
402
|
+
title,
|
|
403
|
+
description:
|
|
404
|
+
onApprove === 'publish'
|
|
405
|
+
? `${left} They couldn’t be applied.`
|
|
406
|
+
: `${left} Changes to published documents need Publish, so approve those one at a time.`,
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* "Approve all" stopped because an edit couldn't be approved: nothing else
|
|
412
|
+
* was approved, so the AI's text can't replace that edit.
|
|
413
|
+
*/
|
|
414
|
+
export function approveAllStoppedMessage(
|
|
415
|
+
approvedEdits: number,
|
|
416
|
+
refusedEdits: number,
|
|
417
|
+
): { title: string; description: string } {
|
|
418
|
+
const plural = (count: number) => `${count} edited change${count === 1 ? '' : 's'}`
|
|
419
|
+
const done = approvedEdits > 0 ? `${plural(approvedEdits)} approved. ` : ''
|
|
420
|
+
return {
|
|
421
|
+
title: 'Approve all stopped',
|
|
422
|
+
description: `${done}${plural(refusedEdits)} couldn’t be approved, so nothing else was, and the AI’s text doesn’t replace an edit. Each change says why.`,
|
|
423
|
+
}
|
|
424
|
+
}
|