From dcaa1f10483a055be609538fca2657b1422d02c7 Mon Sep 17 00:00:00 2001 From: Sopaco Date: Sat, 28 Mar 2026 14:39:49 +0800 Subject: [PATCH] Await project load and fetch iterations on select Make project_loaded and project_initialized handlers async and await loadProject so the view switches after data is loaded. Fetch the full iteration via API in handleSelectIteration (now async) and show an error message on failure. Add iterationsLoaded flag and setIterationsLoaded setter to the project store to track iteration load state. --- crates/cowork-gui/src/hooks/useAppEvents.ts | 8 +++--- .../src/hooks/useIterationActions.ts | 28 ++++++++++--------- crates/cowork-gui/src/stores/projectStore.ts | 15 ++++++++-- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/crates/cowork-gui/src/hooks/useAppEvents.ts b/crates/cowork-gui/src/hooks/useAppEvents.ts index 0aaf9a3..94d99ed 100644 --- a/crates/cowork-gui/src/hooks/useAppEvents.ts +++ b/crates/cowork-gui/src/hooks/useAppEvents.ts @@ -377,25 +377,25 @@ export function useAppEvents(userInput: string, setUserInput: (input: string) => }), // Project events - listen('project_loaded', () => { + listen('project_loaded', async () => { setProcessing(false); setCurrentAgent(null); setInputRequest(null); clearMessages(); setCurrentIteration(null); + await loadProject(); setActiveView('iterations'); - loadProject(); message.success('Project loaded'); }), - listen('project_initialized', () => { + listen('project_initialized', async () => { setProcessing(false); setCurrentAgent(null); setInputRequest(null); clearMessages(); setCurrentIteration(null); + await loadProject(); setActiveView('iterations'); - loadProject(); message.success('Project initialized'); }), diff --git a/crates/cowork-gui/src/hooks/useIterationActions.ts b/crates/cowork-gui/src/hooks/useIterationActions.ts index f71191d..5c8cd4a 100644 --- a/crates/cowork-gui/src/hooks/useIterationActions.ts +++ b/crates/cowork-gui/src/hooks/useIterationActions.ts @@ -2,7 +2,6 @@ import { useCallback } from 'react'; import { App as AntApp } from 'antd'; import { useProjectStore, useAgentStore, useUIStore } from '../stores'; import API from '../api'; -import type { Iteration } from '../stores'; /** * Hook for handling iteration-related actions @@ -12,7 +11,7 @@ export function useIterationActions() { const { message } = AntApp.useApp(); // Project store - const { iterations, currentIteration, setCurrentIteration, setIsExecuting } = useProjectStore(); + const { currentIteration, setCurrentIteration, setIsExecuting } = useProjectStore(); // Agent store const { setProcessing } = useAgentStore(); @@ -22,23 +21,26 @@ export function useIterationActions() { /** * Handle selecting an iteration + * Directly fetches iteration data via API without depending on local iterations array */ const handleSelectIteration = useCallback( - (iterationId: string) => { - const iteration = iterations.find((i: Iteration) => i.id === iterationId); - if (iteration) { + async (iterationId: string) => { + try { const { currentIteration, isExecuting } = useProjectStore.getState(); - API.iteration.get(iterationId).then((full) => { - if (isExecuting && currentIteration?.id === iterationId) { - setCurrentIteration({ ...full, status: currentIteration.status }); - } else { - setCurrentIteration(full); - } - }); + const fullIteration = await API.iteration.get(iterationId); + + if (isExecuting && currentIteration?.id === iterationId) { + setCurrentIteration({ ...fullIteration, status: currentIteration.status }); + } else { + setCurrentIteration(fullIteration); + } setActiveView('chat'); + } catch (error) { + console.error('Failed to load iteration:', error); + message.error('Failed to load iteration: ' + error); } }, - [iterations, setCurrentIteration, setActiveView] + [setCurrentIteration, setActiveView, message] ); /** diff --git a/crates/cowork-gui/src/stores/projectStore.ts b/crates/cowork-gui/src/stores/projectStore.ts index cc6320b..ea5ae49 100644 --- a/crates/cowork-gui/src/stores/projectStore.ts +++ b/crates/cowork-gui/src/stores/projectStore.ts @@ -41,12 +41,14 @@ interface ProjectState { currentIteration: Iteration | null; loading: boolean; isExecuting: boolean; + iterationsLoaded: boolean; loadProject: () => Promise; loadIterations: () => Promise; setCurrentIteration: (iteration: Iteration | null) => void; updateCurrentIterationStatus: (status: string) => void; setIsExecuting: (executing: boolean) => void; + setIterationsLoaded: (loaded: boolean) => void; clearProject: () => void; } @@ -56,6 +58,7 @@ export const useProjectStore = create((set, get) => ({ currentIteration: null, loading: false, isExecuting: false, + iterationsLoaded: false, loadProject: async () => { try { @@ -65,7 +68,7 @@ export const useProjectStore = create((set, get) => ({ if (project) { const iterations = await API.iteration.list(); - set({ iterations: iterations || [] }); + set({ iterations: iterations || [], iterationsLoaded: true }); const { currentIteration, isExecuting } = get(); if (currentIteration) { @@ -88,16 +91,17 @@ export const useProjectStore = create((set, get) => ({ } } catch (error) { console.error('Failed to load project:', error); - set({ loading: false }); + set({ loading: false, iterationsLoaded: false }); } }, loadIterations: async () => { try { const iterations = await API.iteration.list(); - set({ iterations: iterations || [] }); + set({ iterations: iterations || [], iterationsLoaded: true }); } catch (error) { console.error('Failed to load iterations:', error); + set({ iterationsLoaded: false }); } }, @@ -116,12 +120,17 @@ export const useProjectStore = create((set, get) => ({ set({ isExecuting: executing }); }, + setIterationsLoaded: (loaded) => { + set({ iterationsLoaded: loaded }); + }, + clearProject: () => { set({ project: null, iterations: [], currentIteration: null, isExecuting: false, + iterationsLoaded: false, }); }, }));