fix(frontend): auto-select newly created project#3
fix(frontend): auto-select newly created project#3nikzdevz wants to merge 1 commit intodevin/frontend-project-isolationfrom
Conversation
…effect) Co-Authored-By: thesyperdev@gmail.com <thesyperdev@gmail.com>
| if (currentId == null) { | ||
| setCurrent(list[0].id); | ||
| } |
There was a problem hiding this comment.
🔴 Removed guard allows stale project ID to persist after project deletion
The old code reset the current project when the stored ID was not found in the fetched project list: if (!currentId || !list.some((p) => p.id === currentId)). The new code only checks if (currentId == null), removing the !list.some(...) guard. If a project is deleted (via API, CLI tool, or database reset) while its ID is stored in localStorage, the currentProjectId remains a non-null stale string, so currentId == null is false and the auto-selection never fires. This causes the ProjectSelector to show "Select project" (frontend/src/components/ProjectSelector.tsx:15 finds no match), all page queries (Dashboard, Tasks, Sessions, etc.) to filter by a non-existent project ID returning empty results, and SSE events to be silently dropped at frontend/src/events/EventBus.ts:153-158 because the event's project_id won't match the stale ID.
| if (currentId == null) { | |
| setCurrent(list[0].id); | |
| } | |
| if (currentId == null || !list.some((p) => p.id === currentId)) { | |
| setCurrent(list[0].id); | |
| } |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Smoke-test follow-up to PR #2. Manual end-to-end testing (and Devin Review, independently — see #2 (comment)) surfaced one wiring bug: creating a new project via the sidebar modal did not auto-switch to it. The sidebar kept showing the previously selected project even though the new project was persisted and visible in the dropdown list.
Root cause — race between
CreateProjectModal.onSuccessanduseProjectsfallback effectUser fills the modal for "Bravo" and clicks Create.
POST /api/projectssucceeds andonSuccessfires:qc.invalidateQueries({ queryKey: ['projects'] })— triggers an async refetch of the projects list.setCurrent(project.id)— setscurrentProjectId = <Bravo id>synchronously.React re-renders.
useProjectsstill has the stale cached list[Alpha]inquery.data(the refetch hasn't landed yet).Its effect runs with the new
currentId = <Bravo id>butlist = [Alpha]:The "not-in-list" branch fires and overwrites the Bravo selection with Alpha's id.
The refetch finally lands with
[Alpha, Bravo], butcurrentIdis now Alpha again — the effect's guard passes and the bug is locked in.Fix
Two small defensive changes; either alone would close the race:
useProjects.ts— the fallback effect now only defaults when there is no selection at all (currentId == null). It no longer reacts to a stale list by clobbering a valid selection. If the user's selected project is later deleted,ProjectSelectoralready falls back to the "Select project" label.CreateProjectModal.tsx— on successful create, synchronously seed the projects query cache viaqc.setQueryDatabefore callingsetCurrent, then invalidate. This eliminates the stale-list window entirely.Evidence from the smoke test
Recorded flow: create Alpha, add
task-in-alpha, create Bravo from the modal. Expected: sidebar flips to "Bravo". Actual ondevin/frontend-project-isolation: sidebar stays on "Alpha", and Bravo only appears in the dropdown list:Full recording with on-screen annotations: https://app.devin.ai/attachments/aa8ea7d1-5481-43e7-a1b5-945815741bb7/rec-89d9e14b-b59c-404f-a19b-306835613a2c-edited.mp4
Everything else PR #2 claimed tested green during the smoke test:
/api/statscounts flip on project switch.localStorage(obsmcp:project) across reload./api/knowledge-graph?project_id=…filters correctly (tested by seeding one knowledge node under Alpha viasqlite3; Alpha returns it, Bravo returns empty)./api/statsno longer leaks a_scopedebug field.Base branch
This PR targets
devin/frontend-project-isolation(PR #2's branch) so the diff is only the fix. Merge PR #2 first, then this; or rebase this ontomainif PR #2 is squashed.Review & Testing Checklist for Human
projectsthat reassigns only when the current id is genuinely missing after a successful refetch.POST /api/projectsstill fires and the response body is used — the newsetQueryDataoptimistic-append relies onproject.idfrom the server.Notes
Frontend-only changes; no backend touched, no schema changes, no CI (repo has no GitHub Actions by design). PR #2's inline Devin Review comment flagging the same race is at #2 (comment).