From c88cf6146b5af44e294d15c8867bd9ab0ebb038f Mon Sep 17 00:00:00 2001 From: 134 Date: Tue, 16 Jun 2026 22:30:05 +0800 Subject: [PATCH] fix: persist agent workflow selections immediately --- .../[id]/CanvasEditorLegacyPageClient.tsx | 72 +++++++++++++++++-- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx index 596a030f2..5e00877b0 100644 --- a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx +++ b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx @@ -3530,7 +3530,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { workflowMaterials, sanitizedWorkflowSelections, ]); - const persistedAgentProjectStateRef = useRef( + const persistedAgentProjectStateRef = useRef( buildPersistedAgentProjectState() ); @@ -3538,6 +3538,53 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { persistedAgentProjectStateRef.current = buildPersistedAgentProjectState(); }, [buildPersistedAgentProjectState]); + const writeAgentProjectDraftSnapshot = useCallback( + (projectState: AgentGenerationProjectPersistedState) => { + if (!isAgentMode || !agentProjectId || typeof window === "undefined") { + return; + } + + try { + const draftSnapshot: AgentProjectDraftSnapshot = { + savedAt: Date.now(), + title: agentProjectTitle, + thumbnail: agentProjectThumbnail, + projectState, + }; + window.localStorage.setItem( + getAgentProjectDraftStorageKey(agentProjectId), + JSON.stringify(draftSnapshot) + ); + } catch (error) { + console.warn("[Agent Project] Failed to persist immediate draft:", error); + } + }, + [agentProjectId, agentProjectThumbnail, agentProjectTitle, isAgentMode] + ); + + const patchPersistedAgentWorkflowState = useCallback( + (patch: Partial) => { + const currentProjectState = + persistedAgentProjectStateRef.current || + createEmptyAgentGenerationProjectPersistedState(); + const currentWorkflowState = + currentProjectState.workflowState || createEmptyAgentWorkflowPersistedState(); + const nextProjectState: AgentGenerationProjectPersistedState = { + ...currentProjectState, + workflowState: { + ...currentWorkflowState, + ...patch, + inputs: patch.inputs || currentWorkflowState.inputs, + selections: patch.selections || currentWorkflowState.selections, + }, + }; + + persistedAgentProjectStateRef.current = nextProjectState; + writeAgentProjectDraftSnapshot(nextProjectState); + }, + [writeAgentProjectDraftSnapshot] + ); + const hydrateAgentProjectSnapshot = useCallback( (params: { projectId: string; @@ -8782,9 +8829,10 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { const handleWorkflowInputsChange = useCallback( (next: AgentWorkflowInputs) => { workflowInputsRef.current = next; + patchPersistedAgentWorkflowState({ inputs: next }); setWorkflowInputs(next); }, - [] + [patchPersistedAgentWorkflowState] ); const handleWorkflowMaterialsChange = useCallback( (next: AgentWorkflowMaterialSelections) => { @@ -8792,9 +8840,10 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { ? next : clearAppearanceSummaryFromMaterials(next); workflowMaterialsRef.current = nextMaterials; + patchPersistedAgentWorkflowState({ materials: nextMaterials }); setWorkflowMaterials(nextMaterials); }, - [] + [patchPersistedAgentWorkflowState] ); const handleAppearanceRecognitionEnabledChange = useCallback( (next: boolean) => { @@ -8806,10 +8855,19 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { workflowMaterialsRef.current ); workflowMaterialsRef.current = clearedMaterials; + patchPersistedAgentWorkflowState({ + appearanceRecognitionEnabled: next, + materials: clearedMaterials, + }); setWorkflowMaterials(clearedMaterials); + } else { + patchPersistedAgentWorkflowState({ + appearanceRecognitionEnabled: next, + materials: workflowMaterialsRef.current, + }); } }, - [] + [patchPersistedAgentWorkflowState] ); const handleWorkflowSelectionsChange = useCallback( (next: Partial>) => { @@ -8857,18 +8915,20 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { }); workflowSelectionsRef.current = clearedSelections; + patchPersistedAgentWorkflowState({ selections: clearedSelections }); startTransition(() => { setWorkflowSelections(clearedSelections); }); }, - [resolvedWorkflowUiConfig] + [patchPersistedAgentWorkflowState, resolvedWorkflowUiConfig] ); const handleSelectedBrandModelChange = useCallback( (next: AgentWorkflowSelectedBrandModel | null) => { selectedBrandModelRef.current = next; + patchPersistedAgentWorkflowState({ selectedBrandModel: next }); setSelectedBrandModel(next); }, - [] + [patchPersistedAgentWorkflowState] ); const getLatestWorkflowContext = useCallback(() => { return buildAgentWorkflowComposerContext({