@prenta/admin 1.17.1 → 1.17.2
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 +10 -0
- package/dist/__tests__/views/ai-settings.render.test.js +67 -1
- package/dist/__tests__/views/ai-settings.render.test.js.map +1 -1
- package/dist/components/CoauthorResultPopover.d.ts.map +1 -1
- package/dist/components/CoauthorResultPopover.js +4 -1
- package/dist/components/CoauthorResultPopover.js.map +1 -1
- package/dist/components/CommentSidePanel.d.ts +0 -7
- package/dist/components/CommentSidePanel.d.ts.map +1 -1
- package/dist/components/CommentSidePanel.js +0 -2
- package/dist/components/CommentSidePanel.js.map +1 -1
- package/dist/components/EditorRail.d.ts +2 -1
- package/dist/components/EditorRail.d.ts.map +1 -1
- package/dist/components/MediaPickerModal.d.ts +2 -1
- package/dist/components/MediaPickerModal.d.ts.map +1 -1
- package/dist/components/TipTapEditor.d.ts +3 -2
- package/dist/components/TipTapEditor.d.ts.map +1 -1
- package/dist/components/forms/EntriesTable.d.ts +0 -1
- package/dist/components/forms/EntriesTable.d.ts.map +1 -1
- package/dist/components/forms/EntriesTable.js +1 -1
- package/dist/components/forms/EntriesTable.js.map +1 -1
- package/dist/components/pages/tag-badges.d.ts +2 -2
- package/dist/components/pages/tag-badges.d.ts.map +1 -1
- package/dist/components/pages/tag-badges.js.map +1 -1
- package/dist/components/seo/FaqProposalPreview.d.ts +2 -3
- package/dist/components/seo/FaqProposalPreview.d.ts.map +1 -1
- package/dist/components/seo/FaqProposalPreview.js +1 -1
- package/dist/components/seo/FaqProposalPreview.js.map +1 -1
- package/dist/components/seo/SeoCopilotDrawer.js +1 -1
- package/dist/components/seo/SeoCopilotDrawer.js.map +1 -1
- package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
- package/dist/components/seo/SeoEditorPane.js +4 -1
- package/dist/components/seo/SeoEditorPane.js.map +1 -1
- package/dist/components/ui/Badge.d.ts +3 -9
- package/dist/components/ui/Badge.d.ts.map +1 -1
- package/dist/components/ui/Badge.js +2 -3
- package/dist/components/ui/Badge.js.map +1 -1
- 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 +0 -1
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +2 -3
- package/dist/components/ui/Card.d.ts.map +1 -1
- package/dist/components/ui/Card.js +0 -4
- package/dist/components/ui/Card.js.map +1 -1
- package/dist/components/ui/Input.d.ts +6 -8
- package/dist/components/ui/Input.d.ts.map +1 -1
- package/dist/components/ui/Input.js +6 -6
- package/dist/components/ui/Input.js.map +1 -1
- package/dist/components/ui/Modal.d.ts +1 -1
- package/dist/components/ui/Modal.d.ts.map +1 -1
- package/dist/components/ui/ResizableAside.d.ts +0 -13
- package/dist/components/ui/ResizableAside.d.ts.map +1 -1
- package/dist/components/ui/ResizableAside.js +5 -5
- package/dist/components/ui/ResizableAside.js.map +1 -1
- package/dist/components/ui/StatusBadge.d.ts +2 -2
- package/dist/components/ui/StatusBadge.d.ts.map +1 -1
- package/dist/components/ui/StatusBadge.js +0 -1
- package/dist/components/ui/StatusBadge.js.map +1 -1
- package/dist/components/ui/Toggle.d.ts +2 -8
- package/dist/components/ui/Toggle.d.ts.map +1 -1
- package/dist/components/ui/Toggle.js +0 -1
- package/dist/components/ui/Toggle.js.map +1 -1
- package/dist/fields/FieldRenderer.d.ts +2 -1
- package/dist/fields/FieldRenderer.d.ts.map +1 -1
- package/dist/fields/index.d.ts +0 -17
- package/dist/fields/index.d.ts.map +1 -1
- package/dist/fields/index.js +0 -15
- package/dist/fields/index.js.map +1 -1
- package/dist/layout/primitives/tokens.d.ts +0 -2
- package/dist/layout/primitives/tokens.d.ts.map +1 -1
- package/dist/layout/primitives/tokens.js +0 -6
- package/dist/layout/primitives/tokens.js.map +1 -1
- package/dist/lib/brand-voice-client.d.ts +14 -1
- package/dist/lib/brand-voice-client.d.ts.map +1 -1
- package/dist/lib/brand-voice-client.js +7 -0
- package/dist/lib/brand-voice-client.js.map +1 -1
- package/dist/lib/coauthor-client.d.ts +2 -1
- package/dist/lib/coauthor-client.d.ts.map +1 -1
- package/dist/lib/collection-schema.d.ts +0 -9
- package/dist/lib/collection-schema.d.ts.map +1 -1
- package/dist/lib/collection-schema.js +2 -2
- package/dist/lib/collection-schema.js.map +1 -1
- package/dist/lib/editor-seo-content.d.ts +0 -10
- package/dist/lib/editor-seo-content.d.ts.map +1 -1
- package/dist/lib/editor-seo-content.js +0 -13
- package/dist/lib/editor-seo-content.js.map +1 -1
- package/dist/lib/forms-service.d.ts +3 -21
- package/dist/lib/forms-service.d.ts.map +1 -1
- package/dist/lib/forms-service.js +0 -25
- package/dist/lib/forms-service.js.map +1 -1
- package/dist/lib/notifications-client.d.ts +4 -3
- package/dist/lib/notifications-client.d.ts.map +1 -1
- package/dist/lib/page-audit-input.d.ts +0 -10
- package/dist/lib/page-audit-input.d.ts.map +1 -1
- package/dist/lib/page-audit-input.js +1 -1
- package/dist/lib/page-audit-input.js.map +1 -1
- package/dist/lib/page-editor-service.d.ts +2 -4
- package/dist/lib/page-editor-service.d.ts.map +1 -1
- package/dist/lib/page-editor-service.js +3 -3
- package/dist/lib/page-editor-service.js.map +1 -1
- package/dist/lib/pages-service.d.ts +2 -13
- package/dist/lib/pages-service.d.ts.map +1 -1
- package/dist/lib/pages-service.js +3 -24
- package/dist/lib/pages-service.js.map +1 -1
- package/dist/lib/plan.d.ts +2 -1
- package/dist/lib/plan.d.ts.map +1 -1
- package/dist/lib/post-editor-service.d.ts +3 -13
- package/dist/lib/post-editor-service.d.ts.map +1 -1
- package/dist/lib/post-editor-service.js +5 -6
- package/dist/lib/post-editor-service.js.map +1 -1
- package/dist/lib/post-types-service.d.ts +2 -3
- package/dist/lib/post-types-service.d.ts.map +1 -1
- package/dist/lib/post-types-service.js +1 -1
- package/dist/lib/post-types-service.js.map +1 -1
- package/dist/lib/posts-service.d.ts +2 -1
- package/dist/lib/posts-service.d.ts.map +1 -1
- package/dist/lib/preview-link.d.ts +0 -9
- package/dist/lib/preview-link.d.ts.map +1 -1
- package/dist/lib/preview-link.js +0 -15
- package/dist/lib/preview-link.js.map +1 -1
- package/dist/lib/rail-width.d.ts +0 -1
- package/dist/lib/rail-width.d.ts.map +1 -1
- package/dist/lib/rail-width.js +1 -1
- package/dist/lib/rail-width.js.map +1 -1
- package/dist/lib/reflow-probe.d.ts +0 -67
- package/dist/lib/reflow-probe.d.ts.map +1 -1
- package/dist/lib/reflow-probe.js +4 -4
- package/dist/lib/reflow-probe.js.map +1 -1
- package/dist/lib/seo-service.d.ts +14 -32
- package/dist/lib/seo-service.d.ts.map +1 -1
- package/dist/lib/seo-service.js +7 -26
- package/dist/lib/seo-service.js.map +1 -1
- package/dist/lib/theme-chrome.d.ts +0 -1
- package/dist/lib/theme-chrome.d.ts.map +1 -1
- package/dist/lib/theme-chrome.js +1 -1
- package/dist/lib/theme-chrome.js.map +1 -1
- package/dist/lib/version-history.d.ts +2 -2
- package/dist/lib/version-history.d.ts.map +1 -1
- package/dist/lib/workflow-chrome.d.ts +0 -3
- package/dist/lib/workflow-chrome.d.ts.map +1 -1
- package/dist/lib/workflow-chrome.js +3 -3
- package/dist/lib/workflow-chrome.js.map +1 -1
- package/dist/views/Login.d.ts +2 -1
- package/dist/views/Login.d.ts.map +1 -1
- package/dist/views/MediaBrowser.d.ts.map +1 -1
- package/dist/views/MediaBrowser.js +3 -2
- package/dist/views/MediaBrowser.js.map +1 -1
- package/dist/views/PageEditor.d.ts +2 -1
- package/dist/views/PageEditor.d.ts.map +1 -1
- package/dist/views/Pages/PagesListView.d.ts +0 -1
- package/dist/views/Pages/PagesListView.d.ts.map +1 -1
- package/dist/views/Pages/PagesListView.js +1 -1
- package/dist/views/Pages/PagesListView.js.map +1 -1
- package/dist/views/Pages.d.ts +2 -1
- package/dist/views/Pages.d.ts.map +1 -1
- package/dist/views/Redirects.d.ts +2 -1
- package/dist/views/Redirects.d.ts.map +1 -1
- package/dist/views/page-editor/section-types.d.ts +2 -2
- package/dist/views/page-editor/section-types.d.ts.map +1 -1
- package/dist/views/page-editor/section-types.js +1 -1
- package/dist/views/page-editor/section-types.js.map +1 -1
- package/dist/views/page-editor/sections/admin-renderers.d.ts +2 -1
- package/dist/views/page-editor/sections/admin-renderers.d.ts.map +1 -1
- package/dist/views/page-editor/theme-chrome/index.d.ts +1 -6
- package/dist/views/page-editor/theme-chrome/index.d.ts.map +1 -1
- package/dist/views/page-editor/theme-chrome/index.js +1 -3
- package/dist/views/page-editor/theme-chrome/index.js.map +1 -1
- package/dist/views/page-editor/viewports.d.ts +1 -1
- package/dist/views/page-editor/viewports.d.ts.map +1 -1
- package/dist/views/page-editor/viewports.js +1 -1
- package/dist/views/page-editor/viewports.js.map +1 -1
- package/dist/views/settings/AISettingsTab.d.ts.map +1 -1
- package/dist/views/settings/AISettingsTab.js +13 -3
- package/dist/views/settings/AISettingsTab.js.map +1 -1
- package/dist/views/settings/BrandVoiceCard.d.ts +3 -0
- package/dist/views/settings/BrandVoiceCard.d.ts.map +1 -1
- package/dist/views/settings/BrandVoiceCard.js +2 -2
- package/dist/views/settings/BrandVoiceCard.js.map +1 -1
- package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.d.ts.map +1 -1
- package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.js +4 -1
- package/dist/views/settings/brand-voice/BrandVoiceAlignmentPanel.js.map +1 -1
- package/dist/views/settings/featureModel.d.ts +0 -3
- package/dist/views/settings/featureModel.d.ts.map +1 -1
- package/dist/views/settings/featureModel.js +2 -2
- package/dist/views/settings/featureModel.js.map +1 -1
- package/dist/views/settings/useAiSettings.d.ts +2 -2
- package/dist/views/settings/useAiSettings.d.ts.map +1 -1
- package/dist/views/settings/useAiSettings.js +6 -2
- package/dist/views/settings/useAiSettings.js.map +1 -1
- package/dist/views/settings/useAppearanceSettings.d.ts +5 -6
- package/dist/views/settings/useAppearanceSettings.d.ts.map +1 -1
- package/dist/views/settings/useAppearanceSettings.js +1 -1
- package/dist/views/settings/useAppearanceSettings.js.map +1 -1
- package/dist/views/settings/useEmailSettings.d.ts +3 -2
- package/dist/views/settings/useEmailSettings.d.ts.map +1 -1
- package/dist/views/settings/useGeneralSettings.d.ts +2 -11
- package/dist/views/settings/useGeneralSettings.d.ts.map +1 -1
- package/dist/views/settings/useGeneralSettings.js +3 -3
- package/dist/views/settings/useGeneralSettings.js.map +1 -1
- package/dist/views/settings/useSeoSettings.d.ts +1 -1
- package/dist/views/settings/useSeoSettings.d.ts.map +1 -1
- package/dist/views/settings/useUpdates.d.ts +1 -3
- package/dist/views/settings/useUpdates.d.ts.map +1 -1
- package/dist/views/settings/useUpdates.js +1 -1
- package/dist/views/settings/useUpdates.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/views/ai-settings.render.test.tsx +86 -2
- package/src/components/CoauthorResultPopover.tsx +3 -1
- package/src/components/CommentSidePanel.tsx +0 -1
- package/src/components/EditorRail.tsx +1 -1
- package/src/components/MediaPickerModal.tsx +1 -1
- package/src/components/TipTapEditor.tsx +2 -2
- package/src/components/forms/EntriesTable.tsx +1 -1
- package/src/components/pages/tag-badges.tsx +1 -1
- package/src/components/seo/FaqProposalPreview.tsx +2 -2
- package/src/components/seo/SeoCopilotDrawer.tsx +1 -1
- package/src/components/seo/SeoEditorPane.tsx +3 -1
- package/src/components/ui/Badge.tsx +4 -6
- package/src/components/ui/Button.tsx +1 -3
- package/src/components/ui/Card.tsx +1 -14
- package/src/components/ui/Input.tsx +7 -15
- package/src/components/ui/Modal.tsx +1 -1
- package/src/components/ui/ResizableAside.tsx +5 -5
- package/src/components/ui/StatusBadge.tsx +1 -3
- package/src/components/ui/Toggle.tsx +1 -3
- package/src/fields/FieldRenderer.tsx +1 -1
- package/src/fields/index.ts +0 -17
- package/src/layout/primitives/tokens.ts +0 -7
- package/src/lib/brand-voice-client.ts +18 -1
- package/src/lib/coauthor-client.ts +1 -1
- package/src/lib/collection-schema.ts +2 -2
- package/src/lib/editor-seo-content.ts +0 -22
- package/src/lib/forms-service.ts +2 -42
- package/src/lib/notifications-client.ts +3 -3
- package/src/lib/page-audit-input.ts +1 -1
- package/src/lib/page-editor-service.ts +1 -3
- package/src/lib/pages-service.ts +4 -29
- package/src/lib/plan.ts +1 -1
- package/src/lib/post-editor-service.ts +4 -10
- package/src/lib/post-types-service.ts +2 -2
- package/src/lib/posts-service.ts +1 -1
- package/src/lib/preview-link.ts +0 -14
- package/src/lib/rail-width.ts +1 -1
- package/src/lib/reflow-probe.ts +4 -4
- package/src/lib/seo-service.ts +20 -60
- package/src/lib/theme-chrome.ts +1 -1
- package/src/lib/version-history.ts +2 -2
- package/src/lib/workflow-chrome.ts +3 -3
- package/src/views/Login.tsx +1 -1
- package/src/views/MediaBrowser.tsx +3 -2
- package/src/views/PageEditor.tsx +1 -1
- package/src/views/Pages/PagesListView.tsx +1 -1
- package/src/views/Pages.tsx +1 -1
- package/src/views/Redirects.tsx +1 -1
- package/src/views/page-editor/section-types.ts +0 -9
- package/src/views/page-editor/sections/admin-renderers.tsx +1 -1
- package/src/views/page-editor/theme-chrome/index.ts +2 -10
- package/src/views/page-editor/viewports.ts +0 -3
- package/src/views/settings/AISettingsTab.tsx +15 -3
- package/src/views/settings/BrandVoiceCard.tsx +11 -1
- package/src/views/settings/brand-voice/BrandVoiceAlignmentPanel.tsx +3 -1
- package/src/views/settings/featureModel.ts +2 -2
- package/src/views/settings/useAiSettings.ts +8 -3
- package/src/views/settings/useAppearanceSettings.ts +4 -6
- package/src/views/settings/useEmailSettings.ts +2 -2
- package/src/views/settings/useGeneralSettings.ts +5 -10
- package/src/views/settings/useSeoSettings.ts +1 -1
- package/src/views/settings/useUpdates.ts +2 -2
package/src/views/Pages.tsx
CHANGED
|
@@ -24,7 +24,7 @@ import { FolderTree, type FolderSelection } from '../components/FolderTree.js'
|
|
|
24
24
|
|
|
25
25
|
type PageSortKey = 'title' | 'author' | 'template' | 'status' | 'date'
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
interface PagesProps {
|
|
28
28
|
onNavigate?: (path: string) => void
|
|
29
29
|
}
|
|
30
30
|
|
package/src/views/Redirects.tsx
CHANGED
|
@@ -10,27 +10,18 @@ export {
|
|
|
10
10
|
SECTION_TYPES,
|
|
11
11
|
SECTION_TYPE_LIST,
|
|
12
12
|
getSectionType,
|
|
13
|
-
getSectionTypesForScope,
|
|
14
13
|
getAddableSectionTypesForScope,
|
|
15
|
-
isSectionTypeAddable,
|
|
16
14
|
isSectionTypeHideable,
|
|
17
15
|
isSectionEffectivelyVisible,
|
|
18
|
-
sectionTypeLabel,
|
|
19
|
-
isKnownSectionType,
|
|
20
16
|
resolveRepeaterField,
|
|
21
|
-
isRepeaterField,
|
|
22
17
|
blankRepeaterRow,
|
|
23
18
|
} from '@prenta/core/page-sections'
|
|
24
19
|
|
|
25
20
|
export type {
|
|
26
21
|
SectionTypeId,
|
|
27
22
|
SectionScope,
|
|
28
|
-
SectionFieldType,
|
|
29
23
|
SectionFieldDef,
|
|
30
24
|
SectionSettings,
|
|
31
|
-
SectionTypeDef,
|
|
32
25
|
ResolvedRepeater,
|
|
33
|
-
RepeaterRow,
|
|
34
26
|
PostHeaderConfig,
|
|
35
|
-
PostTemplate,
|
|
36
27
|
} from '@prenta/core/page-sections'
|
|
@@ -62,7 +62,7 @@ export interface AdminSectionPostContext {
|
|
|
62
62
|
* Paint budget to protect, but sections-react renderers call `claim()` during
|
|
63
63
|
* render, so the shape must exist or a real renderer throws on its first image.
|
|
64
64
|
*/
|
|
65
|
-
|
|
65
|
+
interface AdminLcpController {
|
|
66
66
|
claim(): boolean
|
|
67
67
|
readonly claimed: boolean
|
|
68
68
|
}
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
ThemeChromeProvider,
|
|
3
|
-
useThemeChromeSpec,
|
|
4
|
-
useThemeChromeContext,
|
|
5
|
-
} from './ThemeChromeProvider.js'
|
|
1
|
+
export { ThemeChromeProvider, useThemeChromeContext } from './ThemeChromeProvider.js'
|
|
6
2
|
export { ThemeChromeFrame } from './ThemeChromeFrame.js'
|
|
7
|
-
|
|
3
|
+
|
|
8
4
|
export { ThemeChromeHealth } from './ThemeChromeHealth.js'
|
|
9
|
-
export type { ThemeChromeHealthProps } from './ThemeChromeHealth.js'
|
|
10
|
-
export { ThemeChromeModeToggle } from './ThemeChromeModeToggle.js'
|
|
11
|
-
export type { ThemeChromeModeToggleProps } from './ThemeChromeModeToggle.js'
|
|
12
|
-
export { useThemeChromeMode } from './useThemeChromeMode.js'
|
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
* mid-migration; import from `../../lib/breakpoints.js` in new code.
|
|
6
6
|
*/
|
|
7
7
|
export {
|
|
8
|
-
BREAKPOINTS as VIEWPORTS,
|
|
9
8
|
DEFAULT_BREAKPOINT as DEFAULT_VIEWPORT,
|
|
10
|
-
getBreakpoint as getViewport,
|
|
11
|
-
type Breakpoint as Viewport,
|
|
12
9
|
type BreakpointId as ViewportId,
|
|
13
10
|
} from '../../lib/breakpoints.js'
|
|
@@ -54,7 +54,14 @@ export function AISettingsTab({ role, config }: AISettingsTabProps) {
|
|
|
54
54
|
'Connect an AI provider under Provider connections before generating a brand voice profile.',
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
// The runtime resolves the provider's curated default when no default
|
|
58
|
+
// model is set. Only built-in providers have a curated catalog — a
|
|
59
|
+
// `custom` endpoint cannot supply that default, so a custom-only site (or
|
|
60
|
+
// one with no keyed built-in connection) still needs an explicit model.
|
|
61
|
+
const hasKeyedProvider = ai.providers.some(
|
|
62
|
+
(p) => p.enabled && p.hasKey && p.provider !== 'custom',
|
|
63
|
+
)
|
|
64
|
+
if (!ai.form.defaultModelId && !hasKeyedProvider) {
|
|
58
65
|
return {
|
|
59
66
|
ready: false,
|
|
60
67
|
message:
|
|
@@ -67,8 +74,13 @@ export function AISettingsTab({ role, config }: AISettingsTabProps) {
|
|
|
67
74
|
message: 'Save your AI settings before generating a brand voice profile.',
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
|
-
return {
|
|
71
|
-
|
|
77
|
+
return {
|
|
78
|
+
ready: true,
|
|
79
|
+
...(ai.form.defaultModelId
|
|
80
|
+
? {}
|
|
81
|
+
: { note: 'No default model selected — using the provider’s recommended default.' }),
|
|
82
|
+
}
|
|
83
|
+
}, [ai.dirty, ai.form.defaultModelId, ai.form.features, ai.providers])
|
|
72
84
|
|
|
73
85
|
if (ai.loading) {
|
|
74
86
|
return (
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type BrandAlignmentScoreResult,
|
|
10
10
|
type BrandVoiceStructuredProfile,
|
|
11
11
|
} from '@prenta/core/brand-voice'
|
|
12
|
-
import { AlertTriangle, Download, FileUp, Link2, Loader2, Sparkles } from 'lucide-react'
|
|
12
|
+
import { AlertTriangle, Download, FileUp, Info, Link2, Loader2, Sparkles } from 'lucide-react'
|
|
13
13
|
import { useCallback, useId, useMemo, useRef, useState } from 'react'
|
|
14
14
|
import { toast } from 'sonner'
|
|
15
15
|
import { BrandVoiceAlignmentPanel } from './brand-voice/BrandVoiceAlignmentPanel.js'
|
|
@@ -95,7 +95,10 @@ function downloadTextFile(filename: string, contents: string) {
|
|
|
95
95
|
*/
|
|
96
96
|
export interface BrandVoiceAiReadiness {
|
|
97
97
|
ready: boolean
|
|
98
|
+
/** Why AI generation is blocked (rendered as a warning when `ready` is false). */
|
|
98
99
|
message?: string
|
|
100
|
+
/** Informational context when ready — e.g. running on the provider's default model. */
|
|
101
|
+
note?: string
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
export function BrandVoiceCard({
|
|
@@ -348,6 +351,13 @@ export function BrandVoiceCard({
|
|
|
348
351
|
</div>
|
|
349
352
|
)}
|
|
350
353
|
|
|
354
|
+
{aiReadiness?.ready && aiReadiness.note && (
|
|
355
|
+
<p className="text-muted-foreground flex items-start gap-2 text-sm">
|
|
356
|
+
<Info size={16} className="mt-0.5 shrink-0" aria-hidden="true" />
|
|
357
|
+
<span>{aiReadiness.note}</span>
|
|
358
|
+
</p>
|
|
359
|
+
)}
|
|
360
|
+
|
|
351
361
|
<div className="flex flex-wrap items-center gap-2">
|
|
352
362
|
<button
|
|
353
363
|
type="button"
|
|
@@ -5,7 +5,7 @@ import { BRAND_VOICE_CHANNEL_PRESETS } from '@prenta/core/brand-voice'
|
|
|
5
5
|
import { Loader2, Wand2 } from 'lucide-react'
|
|
6
6
|
import { useId, useState } from 'react'
|
|
7
7
|
import { toast } from 'sonner'
|
|
8
|
-
import { fixBrandVoiceContent } from '../../../lib/brand-voice-client.js'
|
|
8
|
+
import { brandVoiceFixAiNotice, fixBrandVoiceContent } from '../../../lib/brand-voice-client.js'
|
|
9
9
|
|
|
10
10
|
const INPUT_CLASS =
|
|
11
11
|
'w-full rounded-md border border-border bg-input-background px-3 py-2 text-base text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-60'
|
|
@@ -78,6 +78,8 @@ export function BrandVoiceAlignmentPanel({
|
|
|
78
78
|
? 'Copy revised to match brand voice.'
|
|
79
79
|
: 'Applied brand voice rule fixes.',
|
|
80
80
|
)
|
|
81
|
+
const notice = brandVoiceFixAiNotice(res.result)
|
|
82
|
+
if (notice) toast.info(notice)
|
|
81
83
|
} finally {
|
|
82
84
|
setFixing(false)
|
|
83
85
|
}
|
|
@@ -21,13 +21,13 @@ const CAPABILITY_LABELS: Record<string, string> = {
|
|
|
21
21
|
longContext: 'long context',
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
function findModel(models: AiModelView[], id: string | undefined): AiModelView | undefined {
|
|
25
25
|
if (!id) return undefined
|
|
26
26
|
return models.find((m) => m.id === id || m.providerModelId === id)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/** Required capabilities a model is missing. Unknown capability strings are ignored. */
|
|
30
|
-
|
|
30
|
+
function missingCapabilities(model: AiModelView | undefined, required: string[]): string[] {
|
|
31
31
|
const wanted = required.filter((c) => c in CAPABILITY_LABELS)
|
|
32
32
|
if (!model) return wanted
|
|
33
33
|
return wanted.filter((c) => !model.capabilities?.[c])
|
|
@@ -31,7 +31,7 @@ export type AiConnectionStatus =
|
|
|
31
31
|
| 'provider_down'
|
|
32
32
|
| 'needs_setup'
|
|
33
33
|
| 'unknown'
|
|
34
|
-
|
|
34
|
+
type AiModelStatus = 'available' | 'unavailable' | 'deprecated' | 'unknown'
|
|
35
35
|
|
|
36
36
|
export interface AiModelView {
|
|
37
37
|
id: string
|
|
@@ -147,7 +147,7 @@ const EMPTY_BRAND_VOICE: BrandVoiceForm = {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
/** The buffered (Save-bar) portion of AI settings. */
|
|
150
|
-
|
|
150
|
+
interface AiSettingsForm {
|
|
151
151
|
defaultProviderId: string
|
|
152
152
|
defaultModelId: string
|
|
153
153
|
features: AiFeatureView[]
|
|
@@ -453,7 +453,12 @@ export function useAiSettings(canEdit: boolean): UseAiSettings {
|
|
|
453
453
|
method: 'POST',
|
|
454
454
|
body: JSON.stringify(input),
|
|
455
455
|
})
|
|
456
|
-
if (res.error)
|
|
456
|
+
if (res.error) {
|
|
457
|
+
// 503 "not configured" bodies carry the runtime's setup `hint`
|
|
458
|
+
// separately from `error` (same contract as every other AI route).
|
|
459
|
+
const hint = (res.errorBody as { hint?: unknown } | undefined)?.hint
|
|
460
|
+
return { ok: false, error: typeof hint === 'string' ? `${res.error} ${hint}` : res.error }
|
|
461
|
+
}
|
|
457
462
|
if (!res.data?.draft) return { ok: false, error: 'No draft profile was returned.' }
|
|
458
463
|
const structured = res.data.draft.document?.trim()
|
|
459
464
|
? parseStructuredProfile(res.data.draft.document)
|
|
@@ -30,10 +30,10 @@ import { cmsApi } from '../../lib/api.js'
|
|
|
30
30
|
import { BRAND_UPDATED_EVENT } from '../../lib/favicon.js'
|
|
31
31
|
import type { SettingsSourceMetadata, ValidationIssue } from './useGeneralSettings.js'
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
type SaveState = 'idle' | 'saving' | 'success' | 'error'
|
|
34
34
|
|
|
35
35
|
/** Theme + typography + motion form (the `appearance` settings blob). */
|
|
36
|
-
|
|
36
|
+
interface AppearanceForm {
|
|
37
37
|
colorMode: ColorMode
|
|
38
38
|
accent: string
|
|
39
39
|
density: SidebarDensity
|
|
@@ -42,7 +42,7 @@ export interface AppearanceForm {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/** Brand asset references + admin branding mode (the `brand` settings blob). */
|
|
45
|
-
|
|
45
|
+
interface BrandForm {
|
|
46
46
|
mode: AdminBrandingMode
|
|
47
47
|
publicPrimaryLogoAssetId?: string
|
|
48
48
|
publicLogoMarkAssetId?: string
|
|
@@ -64,7 +64,7 @@ export type BrandAssetField =
|
|
|
64
64
|
| 'adminDarkLogoAssetId'
|
|
65
65
|
| 'faviconSourceAssetId'
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
const FIELD_ROLE: Record<BrandAssetField, BrandAssetRole> = {
|
|
68
68
|
publicPrimaryLogoAssetId: 'publicPrimaryLogo',
|
|
69
69
|
publicLogoMarkAssetId: 'publicLogoMark',
|
|
70
70
|
publicDarkLogoAssetId: 'publicDarkLogo',
|
|
@@ -74,8 +74,6 @@ export const FIELD_ROLE: Record<BrandAssetField, BrandAssetRole> = {
|
|
|
74
74
|
faviconSourceAssetId: 'faviconSource',
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
export type { AssetPreview } from '../../lib/appearance-api.js'
|
|
78
|
-
|
|
79
77
|
/** An existing media-library asset chosen for a brand field via the picker. */
|
|
80
78
|
export interface SelectedBrandAsset {
|
|
81
79
|
id: string
|
|
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
|
5
5
|
import { cmsApi } from '../../lib/api.js'
|
|
6
6
|
|
|
7
7
|
export type EmailProviderKey = 'resend' | 'smtpcom' | 'ses' | 'smtp'
|
|
8
|
-
|
|
8
|
+
type SaveState = 'idle' | 'saving' | 'success' | 'error'
|
|
9
9
|
|
|
10
10
|
export const EMAIL_PROVIDER_OPTIONS: Array<{ value: EmailProviderKey; label: string }> = [
|
|
11
11
|
{ value: 'resend', label: 'Resend' },
|
|
@@ -15,7 +15,7 @@ export const EMAIL_PROVIDER_OPTIONS: Array<{ value: EmailProviderKey; label: str
|
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
/** Form state. Secrets are write-only: inputs start empty and never echo stored values. */
|
|
18
|
-
|
|
18
|
+
interface EmailSettingsForm {
|
|
19
19
|
/** Empty string = email delivery not configured here. */
|
|
20
20
|
provider: EmailProviderKey | ''
|
|
21
21
|
from: string
|
|
@@ -16,7 +16,7 @@ export interface GeneralSettingsForm {
|
|
|
16
16
|
noIndexNonProduction: boolean
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
type SettingsSource = 'config' | 'environment' | 'database' | 'plugin' | 'computed'
|
|
20
20
|
|
|
21
21
|
export interface SettingsSourceMetadata {
|
|
22
22
|
source: SettingsSource
|
|
@@ -24,12 +24,7 @@ export interface SettingsSourceMetadata {
|
|
|
24
24
|
reason?: string
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
| 'indexable'
|
|
29
|
-
| 'protected'
|
|
30
|
-
| 'blocked'
|
|
31
|
-
| 'partially_blocked'
|
|
32
|
-
| 'unknown'
|
|
27
|
+
type IndexStatusLevel = 'indexable' | 'protected' | 'blocked' | 'partially_blocked' | 'unknown'
|
|
33
28
|
|
|
34
29
|
export interface SiteIndexStatus {
|
|
35
30
|
status: IndexStatusLevel
|
|
@@ -69,7 +64,7 @@ const EMPTY_FORM: GeneralSettingsForm = {
|
|
|
69
64
|
}
|
|
70
65
|
|
|
71
66
|
/** Validate a site URL: absolute http(s), no trailing slash, parseable. */
|
|
72
|
-
|
|
67
|
+
function validateSiteUrl(value: string): { valid: boolean; error?: string } {
|
|
73
68
|
const trimmed = value.trim()
|
|
74
69
|
if (!trimmed) return { valid: true }
|
|
75
70
|
let url: URL
|
|
@@ -88,7 +83,7 @@ export function validateSiteUrl(value: string): { valid: boolean; error?: string
|
|
|
88
83
|
}
|
|
89
84
|
|
|
90
85
|
/** Best-effort IANA timezone check using the Intl API. */
|
|
91
|
-
|
|
86
|
+
function isValidTimeZone(tz: string): boolean {
|
|
92
87
|
if (!tz) return false
|
|
93
88
|
try {
|
|
94
89
|
new Intl.DateTimeFormat('en-US', { timeZone: tz })
|
|
@@ -99,7 +94,7 @@ export function isValidTimeZone(tz: string): boolean {
|
|
|
99
94
|
}
|
|
100
95
|
|
|
101
96
|
/** Best-effort BCP 47 locale check. */
|
|
102
|
-
|
|
97
|
+
function isValidLocale(locale: string): boolean {
|
|
103
98
|
if (!locale) return false
|
|
104
99
|
try {
|
|
105
100
|
// Throws RangeError on structurally invalid tags.
|
|
@@ -20,7 +20,7 @@ export interface UpdateChangelogItem {
|
|
|
20
20
|
type?: UpdateChangeType
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
interface UpdatePluginCompatibility {
|
|
24
24
|
name: string
|
|
25
25
|
compatible: boolean
|
|
26
26
|
minVersion?: string
|
|
@@ -52,7 +52,7 @@ interface GithubForm {
|
|
|
52
52
|
const REPO_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/
|
|
53
53
|
|
|
54
54
|
/** Admin/Owner may manage updates (matches the server's `requireAdminScope`). */
|
|
55
|
-
|
|
55
|
+
function canManageUpdates(role: string | null | undefined): boolean {
|
|
56
56
|
const r = (role ?? '').toUpperCase()
|
|
57
57
|
return r === 'ADMIN' || r === 'OWNER'
|
|
58
58
|
}
|