@@ -397,44 +397,42 @@ impl RootView {
397397
398398 for snap in & snapshots {
399399 let conn_id = & snap. config . id ;
400- let folder_id = format ! ( "remote-folder:{}" , conn_id) ;
401400
402401 if let Some ( ref state) = snap. state {
403- // Build folder_project_ids using server's order when available
404- let folder_project_ids: Vec < String > = if !state. project_order . is_empty ( ) {
405- // New server: walk project_order, expand folder entries via state.folders
406- let server_folder_map: std:: collections:: HashMap < & str , & okena_core:: api:: ApiFolder > =
407- state. folders . iter ( ) . map ( |f| ( f. id . as_str ( ) , f) ) . collect ( ) ;
408- let mut ordered = Vec :: new ( ) ;
409- let mut seen_ids: std:: collections:: HashSet < String > = std:: collections:: HashSet :: new ( ) ;
402+ // Build the server folder lookup
403+ let server_folder_map: std:: collections:: HashMap < & str , & okena_core:: api:: ApiFolder > =
404+ state. folders . iter ( ) . map ( |f| ( f. id . as_str ( ) , f) ) . collect ( ) ;
405+
406+ // Build prefixed project_order and folder entries that mirror the server structure
407+ let mut remote_order: Vec < String > = Vec :: new ( ) ;
408+ let mut remote_folders: Vec < FolderData > = Vec :: new ( ) ;
409+
410+ if !state. project_order . is_empty ( ) {
410411 for order_id in & state. project_order {
411412 if let Some ( sf) = server_folder_map. get ( order_id. as_str ( ) ) {
412- for pid in & sf. project_ids {
413- let prefixed = format ! ( "remote:{}:{}" , conn_id, pid) ;
414- if seen_ids. insert ( prefixed. clone ( ) ) {
415- ordered. push ( prefixed) ;
416- }
417- }
413+ // This is a folder — create a prefixed FolderData
414+ let prefixed_folder_id = format ! ( "remote:{}:{}" , conn_id, sf. id) ;
415+ let prefixed_project_ids: Vec < String > = sf. project_ids . iter ( )
416+ . map ( |pid| format ! ( "remote:{}:{}" , conn_id, pid) )
417+ . collect ( ) ;
418+ remote_folders. push ( FolderData {
419+ id : prefixed_folder_id. clone ( ) ,
420+ name : sf. name . clone ( ) ,
421+ project_ids : prefixed_project_ids,
422+ collapsed : false ,
423+ folder_color : sf. folder_color ,
424+ } ) ;
425+ remote_order. push ( prefixed_folder_id) ;
418426 } else {
419- let prefixed = format ! ( "remote:{}:{}" , conn_id, order_id) ;
420- if seen_ids. insert ( prefixed. clone ( ) ) {
421- ordered. push ( prefixed) ;
422- }
427+ // This is a top-level project
428+ remote_order. push ( format ! ( "remote:{}:{}" , conn_id, order_id) ) ;
423429 }
424430 }
425- // Append orphans not in order
431+ } else {
432+ // Old server without project_order: put all projects as top-level
426433 for api_project in & state. projects {
427- let prefixed = format ! ( "remote:{}:{}" , conn_id, api_project. id) ;
428- if seen_ids. insert ( prefixed. clone ( ) ) {
429- ordered. push ( prefixed) ;
430- }
434+ remote_order. push ( format ! ( "remote:{}:{}" , conn_id, api_project. id) ) ;
431435 }
432- ordered
433- } else {
434- // Old server: fall back to state.projects Vec order
435- state. projects . iter ( )
436- . map ( |p| format ! ( "remote:{}:{}" , conn_id, p. id) )
437- . collect ( )
438436 } ;
439437
440438 for api_project in & state. projects {
@@ -478,9 +476,33 @@ impl RootView {
478476 existing. remote_services = remote_services;
479477 existing. remote_host = remote_host;
480478 existing. remote_git_status = api_project. git_status . clone ( ) ;
479+ existing. worktree_info = api_project. worktree_info . as_ref ( ) . map ( |wt| {
480+ crate :: workspace:: state:: WorktreeMetadata {
481+ parent_project_id : format ! ( "remote:{}:{}" , conn_id, wt. parent_project_id) ,
482+ color_override : wt. color_override ,
483+ main_repo_path : String :: new ( ) ,
484+ worktree_path : String :: new ( ) ,
485+ branch_name : String :: new ( ) ,
486+ }
487+ } ) ;
488+ existing. worktree_ids = api_project. worktree_ids . iter ( )
489+ . map ( |id| format ! ( "remote:{}:{}" , conn_id, id) )
490+ . collect ( ) ;
481491 // Don't overwrite show_in_overview — it's client-side state
482492 // (the user may have toggled visibility locally).
483493 } else {
494+ let worktree_info = api_project. worktree_info . as_ref ( ) . map ( |wt| {
495+ crate :: workspace:: state:: WorktreeMetadata {
496+ parent_project_id : format ! ( "remote:{}:{}" , conn_id, wt. parent_project_id) ,
497+ color_override : wt. color_override ,
498+ main_repo_path : String :: new ( ) ,
499+ worktree_path : String :: new ( ) ,
500+ branch_name : String :: new ( ) ,
501+ }
502+ } ) ;
503+ let worktree_ids: Vec < String > = api_project. worktree_ids . iter ( )
504+ . map ( |id| format ! ( "remote:{}:{}" , conn_id, id) )
505+ . collect ( ) ;
484506 ws. data . projects . push ( ProjectData {
485507 id : prefixed_id. clone ( ) ,
486508 name : api_project. name . clone ( ) ,
@@ -489,8 +511,8 @@ impl RootView {
489511 layout,
490512 terminal_names,
491513 hidden_terminals : std:: collections:: HashMap :: new ( ) ,
492- worktree_info : None ,
493- worktree_ids : Vec :: new ( ) ,
514+ worktree_info,
515+ worktree_ids,
494516 folder_color : project_color,
495517 hooks : HooksConfig :: default ( ) ,
496518 is_remote : true ,
@@ -506,32 +528,30 @@ impl RootView {
506528 } ) ;
507529 }
508530
509- let folder_name = snap. config . name . clone ( ) ;
531+ // Sync remote folders and project_order into workspace
532+ let remote_prefix = format ! ( "remote:{}:" , conn_id) ;
510533 workspace. update ( cx, |ws, _cx| {
511- if let Some ( folder) = ws. data . folders . iter_mut ( ) . find ( |f| f. id == folder_id) {
512- folder. name = folder_name;
513- folder. project_ids = folder_project_ids;
514- } else {
515- ws. data . folders . push ( FolderData {
516- id : folder_id. clone ( ) ,
517- name : folder_name,
518- project_ids : folder_project_ids,
519- collapsed : false ,
520- folder_color : FolderColor :: default ( ) ,
521- } ) ;
522- }
523- if !ws. data . project_order . contains ( & folder_id) {
524- ws. data . project_order . push ( folder_id. clone ( ) ) ;
534+ // Remove old remote folders for this connection
535+ ws. data . folders . retain ( |f| !f. id . starts_with ( & remote_prefix) ) ;
536+ // Remove old remote entries from project_order for this connection
537+ ws. data . project_order . retain ( |id| !id. starts_with ( & remote_prefix) ) ;
538+
539+ // Add new remote folders
540+ for rf in remote_folders {
541+ // Preserve collapsed state from previous sync
542+ ws. data . folders . push ( rf) ;
525543 }
544+
545+ // Add new remote project_order entries
546+ ws. data . project_order . extend ( remote_order) ;
526547 } ) ;
527548 } else {
528- // No state (disconnected/connecting) — remove materialized projects
549+ // No state (disconnected/connecting) — remove materialized projects and folders
529550 let prefix = format ! ( "remote:{}:" , conn_id) ;
530551 workspace. update ( cx, |ws, _cx| {
531552 ws. data . projects . retain ( |p| !p. id . starts_with ( & prefix) ) ;
532- if let Some ( folder) = ws. data . folders . iter_mut ( ) . find ( |f| f. id == folder_id) {
533- folder. project_ids . clear ( ) ;
534- }
553+ ws. data . folders . retain ( |f| !f. id . starts_with ( & prefix) ) ;
554+ ws. data . project_order . retain ( |id| !id. starts_with ( & prefix) ) ;
535555 } ) ;
536556 }
537557 }
@@ -546,8 +566,11 @@ impl RootView {
546566 }
547567 } ) ;
548568 ws. data . folders . retain ( |f| {
549- if f. id . starts_with ( "remote-folder:" ) {
550- let conn_id = f. id . strip_prefix ( "remote-folder:" ) . unwrap_or ( "" ) ;
569+ if f. id . starts_with ( "remote:" ) {
570+ // Remote folder IDs are "remote:{conn_id}:{folder_id}"
571+ // Extract conn_id (second segment)
572+ let rest = f. id . strip_prefix ( "remote:" ) . unwrap_or ( "" ) ;
573+ let conn_id = rest. split ( ':' ) . next ( ) . unwrap_or ( "" ) ;
551574 active_conn_ids. contains ( conn_id)
552575 } else {
553576 true
0 commit comments