From e1d5ee30534f928651e46e39345c23cb8a8ac5d8 Mon Sep 17 00:00:00 2001 From: wuyangfan <1102042793@qq.com> Date: Wed, 27 May 2026 00:54:28 +0800 Subject: [PATCH 1/2] fix(web): clear pendingPrompt when navigating back to Home (#2878) Leaving a project via the back affordance now clears any persisted pendingPrompt on that project so a later Home session does not inherit stale composer seed text from the previous visit. --- apps/web/src/App.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 3c648a87a..a7b88e0c1 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1088,8 +1088,17 @@ export function App() { }, []); const handleBack = useCallback(() => { + const projectId = route.kind === 'project' ? route.projectId : null; + if (projectId) { + setProjects((curr) => + curr.map((p) => + p.id === projectId ? { ...p, pendingPrompt: undefined } : p, + ), + ); + void patchProject(projectId, { pendingPrompt: null }); + } navigate({ kind: 'home', view: 'home' }); - }, []); + }, [route]); const handleClearPendingPrompt = useCallback(() => { const projectId = route.kind === 'project' ? route.projectId : null; From 483f247c2768c9a1a773a3bd2014171841926f8c Mon Sep 17 00:00:00 2001 From: wuyangfan <1102042793@qq.com> Date: Wed, 27 May 2026 21:59:54 +0800 Subject: [PATCH 2/2] test(web): cover pendingPrompt clearing helper for Home back (#2878) Extract projectsWithClearedPendingPrompt for handleBack and handleClearPendingPrompt, with unit tests. --- apps/web/src/App.tsx | 22 ++++++++++++---------- apps/web/tests/App.test.ts | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index a7b88e0c1..d98ed4dca 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -170,6 +170,16 @@ export function resolveSettingsCloseConfig( return base.onboardingCompleted ? base : { ...base, onboardingCompleted: true }; } +export function projectsWithClearedPendingPrompt( + projects: Project[], + projectId: string | null | undefined, +): Project[] { + if (!projectId) return projects; + return projects.map((p) => + p.id === projectId ? { ...p, pendingPrompt: undefined } : p, + ); +} + export function App() { const { t } = useI18n(); const clientType = useMemo(() => detectClientType(), []); @@ -1090,11 +1100,7 @@ export function App() { const handleBack = useCallback(() => { const projectId = route.kind === 'project' ? route.projectId : null; if (projectId) { - setProjects((curr) => - curr.map((p) => - p.id === projectId ? { ...p, pendingPrompt: undefined } : p, - ), - ); + setProjects((curr) => projectsWithClearedPendingPrompt(curr, projectId)); void patchProject(projectId, { pendingPrompt: null }); } navigate({ kind: 'home', view: 'home' }); @@ -1103,11 +1109,7 @@ export function App() { const handleClearPendingPrompt = useCallback(() => { const projectId = route.kind === 'project' ? route.projectId : null; if (!projectId) return; - setProjects((curr) => - curr.map((p) => - p.id === projectId ? { ...p, pendingPrompt: undefined } : p, - ), - ); + setProjects((curr) => projectsWithClearedPendingPrompt(curr, projectId)); void patchProject(projectId, { pendingPrompt: null }); }, [route]); diff --git a/apps/web/tests/App.test.ts b/apps/web/tests/App.test.ts index 79404d5cf..1a4789320 100644 --- a/apps/web/tests/App.test.ts +++ b/apps/web/tests/App.test.ts @@ -4,10 +4,11 @@ import { buildPersistedConfig, isAutosaveDraftOnlyChange, persistComposioConfigChange, + projectsWithClearedPendingPrompt, resolveSettingsCloseConfig, shouldSyncMediaProvidersOnSave, } from '../src/App'; -import type { AppConfig } from '../src/types'; +import type { AppConfig, Project } from '../src/types'; const baseConfig: AppConfig = { mode: 'api', @@ -123,3 +124,20 @@ describe('resolveSettingsCloseConfig', () => { }); }); }); + +describe('projectsWithClearedPendingPrompt', () => { + const projects: Project[] = [ + { id: 'a', name: 'A', pendingPrompt: 'keep me' } as Project, + { id: 'b', name: 'B', pendingPrompt: 'stale seed' } as Project, + ]; + + it('clears pendingPrompt for the target project (#2878)', () => { + const next = projectsWithClearedPendingPrompt(projects, 'b'); + expect(next.find((p) => p.id === 'b')?.pendingPrompt).toBeUndefined(); + expect(next.find((p) => p.id === 'a')?.pendingPrompt).toBe('keep me'); + }); + + it('returns the original list when projectId is missing', () => { + expect(projectsWithClearedPendingPrompt(projects, null)).toBe(projects); + }); +});