@@ -3,63 +3,41 @@ import App from "../App";
33import { LoadingScreen } from "./LoadingScreen" ;
44import { useWorkspaceStoreRaw } from "../stores/WorkspaceStore" ;
55import { useGitStatusStoreRaw } from "../stores/GitStatusStore" ;
6- import { usePersistedState } from "../hooks/usePersistedState" ;
7- import type { WorkspaceSelection } from "./ProjectSidebar" ;
86import { AppProvider } from "../contexts/AppContext" ;
97import { ProjectProvider , useProjectContext } from "../contexts/ProjectContext" ;
108import { WorkspaceProvider , useWorkspaceContext } from "../contexts/WorkspaceContext" ;
119
1210/**
1311 * AppLoader handles all initialization before rendering the main App:
14- * 1. Load workspace metadata and projects
12+ * 1. Load workspace metadata and projects (via contexts)
1513 * 2. Sync stores with loaded data
16- * 3. Restore workspace selection from URL hash (if present)
17- * 4. Only render App when everything is ready
14+ * 3. Only render App when everything is ready
1815 *
16+ * WorkspaceContext handles workspace selection restoration (localStorage, URL hash, launch project).
1917 * This ensures App.tsx can assume stores are always synced and removes
2018 * the need for conditional guards in effects.
2119 */
2220export function AppLoader ( ) {
23- return (
24- < ProjectProvider >
25- < AppLoaderMiddle />
26- </ ProjectProvider >
27- ) ;
28- }
29-
30- function AppLoaderMiddle ( ) {
31- // Workspace selection - restored from localStorage immediately
32- const [ selectedWorkspace , setSelectedWorkspace ] = usePersistedState < WorkspaceSelection | null > (
33- "selectedWorkspace" ,
34- null
35- ) ;
36-
3721 const { refreshProjects } = useProjectContext ( ) ;
3822
39- // Render App with WorkspaceProvider wrapping it
4023 return (
41- < WorkspaceProvider
42- selectedWorkspace = { selectedWorkspace }
43- onSelectedWorkspaceUpdate = { setSelectedWorkspace }
44- onProjectsUpdate = { ( ) => {
45- void refreshProjects ( ) ;
46- } }
47- >
48- < AppLoaderInner
49- selectedWorkspace = { selectedWorkspace }
50- setSelectedWorkspace = { setSelectedWorkspace }
51- />
52- </ WorkspaceProvider >
24+ < ProjectProvider >
25+ < WorkspaceProvider
26+ onProjectsUpdate = { ( ) => {
27+ void refreshProjects ( ) ;
28+ } }
29+ >
30+ < AppLoaderInner />
31+ </ WorkspaceProvider >
32+ </ ProjectProvider >
5333 ) ;
5434}
5535
5636/**
57- * Inner component that has access to WorkspaceContext
37+ * Inner component that has access to both ProjectContext and WorkspaceContext.
38+ * Syncs stores and shows loading screen until ready.
5839 */
59- function AppLoaderInner ( props : {
60- selectedWorkspace : WorkspaceSelection | null ;
61- setSelectedWorkspace : ( workspace : WorkspaceSelection | null ) => void ;
62- } ) {
40+ function AppLoaderInner ( ) {
6341 const workspaceContext = useWorkspaceContext ( ) ;
6442
6543 // Get store instances
@@ -85,78 +63,6 @@ function AppLoaderInner(props: {
8563 gitStatusStore ,
8664 ] ) ;
8765
88- // Restore workspace from URL hash (runs once when stores are synced)
89- const [ hasRestoredFromHash , setHasRestoredFromHash ] = useState ( false ) ;
90-
91- useEffect ( ( ) => {
92- const { setSelectedWorkspace } = props ;
93- // Wait until stores are synced before attempting restoration
94- if ( ! storesSynced ) return ;
95-
96- // Only run once
97- if ( hasRestoredFromHash ) return ;
98-
99- const hash = window . location . hash ;
100- if ( hash . startsWith ( "#workspace=" ) ) {
101- const workspaceId = decodeURIComponent ( hash . substring ( "#workspace=" . length ) ) ;
102-
103- // Find workspace in metadata
104- const metadata = workspaceContext . workspaceMetadata . get ( workspaceId ) ;
105-
106- if ( metadata ) {
107- // Restore from hash (overrides localStorage)
108- setSelectedWorkspace ( {
109- workspaceId : metadata . id ,
110- projectPath : metadata . projectPath ,
111- projectName : metadata . projectName ,
112- namedWorkspacePath : metadata . namedWorkspacePath ,
113- } ) ;
114- }
115- }
116-
117- setHasRestoredFromHash ( true ) ;
118- } , [ storesSynced , workspaceContext . workspaceMetadata , hasRestoredFromHash , props ] ) ;
119-
120- // Check for launch project from server (for --add-project flag)
121- // This only applies in server mode
122- useEffect ( ( ) => {
123- const { selectedWorkspace, setSelectedWorkspace } = props ;
124- // Wait until stores are synced and hash restoration is complete
125- if ( ! storesSynced || ! hasRestoredFromHash ) return ;
126-
127- // Skip if we already have a selected workspace (from localStorage or URL hash)
128- if ( selectedWorkspace ) return ;
129-
130- // Only check once
131- const checkLaunchProject = async ( ) => {
132- // Only available in server mode
133- if ( ! window . api . server ?. getLaunchProject ) return ;
134-
135- const launchProjectPath = await window . api . server . getLaunchProject ( ) ;
136- if ( ! launchProjectPath ) return ;
137-
138- // Find first workspace in this project
139- const projectWorkspaces = Array . from ( workspaceContext . workspaceMetadata . values ( ) ) . filter (
140- ( meta ) => meta . projectPath === launchProjectPath
141- ) ;
142-
143- if ( projectWorkspaces . length > 0 ) {
144- // Select the first workspace in the project
145- const metadata = projectWorkspaces [ 0 ] ;
146- setSelectedWorkspace ( {
147- workspaceId : metadata . id ,
148- projectPath : metadata . projectPath ,
149- projectName : metadata . projectName ,
150- namedWorkspacePath : metadata . namedWorkspacePath ,
151- } ) ;
152- }
153- // If no workspaces exist yet, just leave the project in the sidebar
154- // The user will need to create a workspace
155- } ;
156-
157- void checkLaunchProject ( ) ;
158- } , [ storesSynced , hasRestoredFromHash , workspaceContext . workspaceMetadata , props ] ) ;
159-
16066 // Show loading screen until stores are synced
16167 if ( workspaceContext . loading || ! storesSynced ) {
16268 return < LoadingScreen /> ;
@@ -170,8 +76,8 @@ function AppLoaderInner(props: {
17076 createWorkspace = { workspaceContext . createWorkspace }
17177 removeWorkspace = { workspaceContext . removeWorkspace }
17278 renameWorkspace = { workspaceContext . renameWorkspace }
173- selectedWorkspace = { props . selectedWorkspace }
174- setSelectedWorkspace = { props . setSelectedWorkspace }
79+ selectedWorkspace = { workspaceContext . selectedWorkspace }
80+ setSelectedWorkspace = { workspaceContext . setSelectedWorkspace }
17581 >
17682 < App />
17783 </ AppProvider >
0 commit comments