feat: persist generation sources in post editor state and API

This commit is contained in:
Ender 2025-10-25 13:36:30 +02:00
parent 4d1f8298de
commit 4fd46f4d24
4 changed files with 22 additions and 6 deletions

View File

@ -31,6 +31,7 @@ export default function EditorShell({ onLogout: _onLogout, initialPostId, onBack
genImageKeys,
generatedDraft,
imagePlaceholders,
generationSources,
// setters
setDraft,
setMeta,
@ -40,6 +41,7 @@ export default function EditorShell({ onLogout: _onLogout, initialPostId, onBack
setActiveStep,
setGeneratedDraft,
setImagePlaceholders,
setGenerationSources,
// actions
savePost,
deletePost,
@ -151,6 +153,7 @@ export default function EditorShell({ onLogout: _onLogout, initialPostId, onBack
onChangePrompt={setPromptText}
generatedDraft={generatedDraft}
imagePlaceholders={imagePlaceholders}
generationSources={generationSources}
onGeneratedDraft={(content) => {
setGeneratedDraft(content);
void savePost({ generatedDraft: content });
@ -159,6 +162,10 @@ export default function EditorShell({ onLogout: _onLogout, initialPostId, onBack
setImagePlaceholders(placeholders);
void savePost({ imagePlaceholders: placeholders });
}}
onGenerationSources={(sources) => {
setGenerationSources(sources);
void savePost({ generationSources: sources });
}}
/>
</StepContainer>
)}

View File

@ -14,8 +14,10 @@ export default function StepGenerate({
onChangePrompt,
generatedDraft,
imagePlaceholders,
generationSources,
onGeneratedDraft,
onImagePlaceholders,
onGenerationSources,
}: {
postClips: Clip[];
genImageKeys: string[];
@ -24,13 +26,14 @@ export default function StepGenerate({
onChangePrompt: (v: string) => void;
generatedDraft: string;
imagePlaceholders: string[];
generationSources: Array<{ title: string; url: string }>;
onGeneratedDraft: (content: string) => void;
onImagePlaceholders: (placeholders: string[]) => void;
onGenerationSources: (sources: Array<{ title: string; url: string }>) => void;
}) {
const [generating, setGenerating] = useState(false);
const [error, setError] = useState<string>('');
const [useWebSearch, setUseWebSearch] = useState(false);
const [sources, setSources] = useState<Array<{ title: string; url: string }>>([]);
return (
<Box sx={{ display: 'grid', gap: 2 }}>
<StepHeader
@ -121,7 +124,7 @@ export default function StepGenerate({
onGeneratedDraft(result.content);
onImagePlaceholders(result.imagePlaceholders);
setSources(result.sources || []);
onGenerationSources(result.sources || []);
} catch (err: any) {
setError(err?.message || 'Generation failed');
} finally {
@ -149,11 +152,11 @@ export default function StepGenerate({
{generatedDraft && (
<CollapsibleSection title="Generated Draft">
<Stack spacing={2}>
{sources.length > 0 && (
{generationSources.length > 0 && (
<Alert severity="success">
<Typography variant="body2" sx={{ fontWeight: 'bold', mb: 0.5 }}>Sources ({sources.length}):</Typography>
<Typography variant="body2" sx={{ fontWeight: 'bold', mb: 0.5 }}>Sources ({generationSources.length}):</Typography>
<Stack spacing={0.5}>
{sources.map((source, idx) => (
{generationSources.map((source: { title: string; url: string }, idx: number) => (
<Typography key={idx} variant="caption" component="div">
{idx + 1}. <Link href={source.url} target="_blank" rel="noopener noreferrer">{source.title}</Link>
</Typography>

View File

@ -18,6 +18,7 @@ export function usePostEditor(initialPostId?: string | null) {
const [genImageKeys, setGenImageKeys] = useState<string[]>([]);
const [generatedDraft, setGeneratedDraft] = useState<string>('');
const [imagePlaceholders, setImagePlaceholders] = useState<string[]>([]);
const [generationSources, setGenerationSources] = useState<Array<{ title: string; url: string }>>([]);
const autoSaveTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
@ -45,6 +46,7 @@ export function usePostEditor(initialPostId?: string | null) {
if (Array.isArray(data.selectedImageKeys)) setGenImageKeys(data.selectedImageKeys);
if (data.generatedDraft) setGeneratedDraft(data.generatedDraft);
if (Array.isArray(data.imagePlaceholders)) setImagePlaceholders(data.imagePlaceholders);
if (Array.isArray(data.generationSources)) setGenerationSources(data.generationSources);
} catch {}
})();
}
@ -64,6 +66,7 @@ export function usePostEditor(initialPostId?: string | null) {
selectedImageKeys: genImageKeys.length > 0 ? genImageKeys : undefined,
generatedDraft: generatedDraft || undefined,
imagePlaceholders: imagePlaceholders.length > 0 ? imagePlaceholders : undefined,
generationSources: generationSources.length > 0 ? generationSources : undefined,
...(overrides || {}),
};
const data = await savePostApi(payload);
@ -75,7 +78,7 @@ export function usePostEditor(initialPostId?: string | null) {
setToast({ open: true, message: 'Post saved', severity: 'success' });
}
return data;
}, [postId, draft, meta, postStatus, promptText, genImageKeys, generatedDraft, imagePlaceholders]);
}, [postId, draft, meta, postStatus, promptText, genImageKeys, generatedDraft, imagePlaceholders, generationSources]);
const deletePost = async () => {
if (!postId) return;
@ -176,6 +179,7 @@ export function usePostEditor(initialPostId?: string | null) {
genImageKeys,
generatedDraft,
imagePlaceholders,
generationSources,
// setters
setDraft,
setMeta,
@ -186,6 +190,7 @@ export function usePostEditor(initialPostId?: string | null) {
setActiveStep,
setGeneratedDraft,
setImagePlaceholders,
setGenerationSources,
// actions
savePost,
deletePost,

View File

@ -10,6 +10,7 @@ export type SavePostPayload = {
selectedImageKeys?: string[];
generatedDraft?: string;
imagePlaceholders?: string[];
generationSources?: Array<{ title: string; url: string }>;
};
export async function getPost(id: string) {