@@ -3085,27 +3085,65 @@ impl<A: API + 'static, F: Fn() -> A + Send + Sync> UI<A, F> {
30853085 async fn on_workspace_info ( & mut self , path : std:: path:: PathBuf ) -> anyhow:: Result < ( ) > {
30863086 self . spinner . start ( Some ( "Fetching workspace info..." ) ) ?;
30873087
3088- match self . api . get_workspace_info ( path) . await {
3089- Ok ( Some ( workspace) ) => {
3090- self . spinner . stop ( None ) ?;
3088+ // Fetch workspace info and status in parallel
3089+ let ( workspace_result, status_result) = tokio:: join!(
3090+ self . api. get_workspace_info( path. clone( ) ) ,
3091+ self . api. get_workspace_status( path)
3092+ ) ;
3093+
3094+ self . spinner . stop ( None ) ?;
30913095
3096+ match workspace_result {
3097+ Ok ( Some ( workspace) ) => {
30923098 // When viewing a specific workspace's info, it's implicitly the active one
3093- let info = Self :: format_workspace_info ( & workspace, true ) ;
3099+ let mut info = Self :: format_workspace_info ( & workspace, true ) ;
3100+
3101+ // Add sync status summary if available
3102+ if let Ok ( statuses) = status_result {
3103+ use forge_domain:: SyncStatus ;
3104+
3105+ let in_sync = statuses
3106+ . iter ( )
3107+ . filter ( |s| s. status == SyncStatus :: InSync )
3108+ . count ( ) ;
3109+ let modified = statuses
3110+ . iter ( )
3111+ . filter ( |s| s. status == SyncStatus :: Modified )
3112+ . count ( ) ;
3113+ let added = statuses
3114+ . iter ( )
3115+ . filter ( |s| s. status == SyncStatus :: New )
3116+ . count ( ) ;
3117+ let deleted = statuses
3118+ . iter ( )
3119+ . filter ( |s| s. status == SyncStatus :: Deleted )
3120+ . count ( ) ;
3121+
3122+ // Add sync status section
3123+ info = info. add_title ( "Sync Status" ) ;
3124+ info = info. add_key_value ( "Total Files" , statuses. len ( ) . to_string ( ) ) ;
3125+ if in_sync > 0 {
3126+ info = info. add_key_value ( "In Sync" , in_sync. to_string ( ) ) ;
3127+ }
3128+ if modified > 0 {
3129+ info = info. add_key_value ( "Modified" , modified. to_string ( ) ) ;
3130+ }
3131+ if added > 0 {
3132+ info = info. add_key_value ( "Added" , added. to_string ( ) ) ;
3133+ }
3134+ if deleted > 0 {
3135+ info = info. add_key_value ( "Deleted" , deleted. to_string ( ) ) ;
3136+ }
3137+ }
30943138
30953139 self . writeln ( info)
30963140 }
3097- Ok ( None ) => {
3098- self . spinner . stop ( None ) ?;
3099- self . writeln_to_stderr (
3100- TitleFormat :: error ( "No workspace found" )
3101- . display ( )
3102- . to_string ( ) ,
3103- )
3104- }
3105- Err ( e) => {
3106- self . spinner . stop ( None ) ?;
3107- Err ( e)
3108- }
3141+ Ok ( None ) => self . writeln_to_stderr (
3142+ TitleFormat :: error ( "No workspace found" )
3143+ . display ( )
3144+ . to_string ( ) ,
3145+ ) ,
3146+ Err ( e) => Err ( e) ,
31093147 }
31103148 }
31113149
@@ -3146,39 +3184,42 @@ impl<A: API + 'static, F: Fn() -> A + Send + Sync> UI<A, F> {
31463184
31473185 let mut statuses = self . api . get_workspace_status ( path. clone ( ) ) . await ?;
31483186 statuses. sort_by ( |a, b| a. status . cmp ( & b. status ) ) ;
3149- let workspace_info = self . api . get_workspace_info ( path) . await ?;
31503187
31513188 if !porcelain {
31523189 self . spinner . stop ( None ) ?;
31533190 }
31543191
3155- // Get workspace ID if available
3156- let workspace_id = workspace_info
3157- . as_ref ( )
3158- . map ( |info| info. workspace_id . to_string ( ) )
3159- . unwrap_or_else ( || "Unknown" . to_string ( ) ) ;
3160-
3161- // Calculate counts
3162- let in_sync = statuses
3192+ // Calculate out of sync count
3193+ let out_of_sync = statuses
31633194 . iter ( )
3164- . filter ( |s| s. status == SyncStatus :: InSync )
3165- . count ( ) ;
3166- let modified = statuses
3167- . iter ( )
3168- . filter ( |s| s. status == SyncStatus :: Modified )
3169- . count ( ) ;
3170- let added = statuses
3171- . iter ( )
3172- . filter ( |s| s. status == SyncStatus :: New )
3173- . count ( ) ;
3174- let deleted = statuses
3175- . iter ( )
3176- . filter ( |s| s. status == SyncStatus :: Deleted )
3195+ . filter ( |s| {
3196+ s. status == SyncStatus :: Modified
3197+ || s. status == SyncStatus :: New
3198+ || s. status == SyncStatus :: Deleted
3199+ } )
31773200 . count ( ) ;
31783201
3179- let out_of_sync = modified + added + deleted;
3202+ // When all files are in sync, show a simple log message
3203+ if out_of_sync == 0 {
3204+ if porcelain {
3205+ // In porcelain mode, output empty result
3206+ self . writeln (
3207+ Porcelain :: from ( Info :: new ( ) )
3208+ . into_long ( )
3209+ . set_headers ( [ "STATUS" , "FILE" ] )
3210+ . uppercase_headers ( ) ,
3211+ ) ?;
3212+ } else {
3213+ // Show log info message when all files are in sync
3214+ self . writeln_title ( TitleFormat :: info ( format ! (
3215+ "All {} files are in sync" ,
3216+ statuses. len( )
3217+ ) ) ) ?;
3218+ }
3219+ return Ok ( ( ) ) ;
3220+ }
31803221
3181- // Build file list info
3222+ // Build file list info only when there are files out of sync
31823223 let mut info = Info :: new ( ) . add_title ( format ! ( "File Status [{} out of sync]" , out_of_sync) ) ;
31833224
31843225 // Add file list (skip in-sync files)
@@ -3204,25 +3245,6 @@ impl<A: API + 'static, F: Fn() -> A + Send + Sync> UI<A, F> {
32043245 ) ?;
32053246 } else {
32063247 self . writeln ( info) ?;
3207-
3208- // Build summary info
3209- let mut summary =
3210- Info :: new ( ) . add_title ( format ! ( "Workspace Status [{} files]" , statuses. len( ) ) ) ;
3211- summary = summary. add_key_value ( "ID" , workspace_id) ;
3212- if in_sync > 0 {
3213- summary = summary. add_key_value ( "In Sync" , in_sync. to_string ( ) ) ;
3214- }
3215- if modified > 0 {
3216- summary = summary. add_key_value ( "Modified" , modified. to_string ( ) ) ;
3217- }
3218- if added > 0 {
3219- summary = summary. add_key_value ( "Added" , added. to_string ( ) ) ;
3220- }
3221- if deleted > 0 {
3222- summary = summary. add_key_value ( "Deleted" , deleted. to_string ( ) ) ;
3223- }
3224-
3225- self . writeln ( summary) ?;
32263248 }
32273249
32283250 Ok ( ( ) )
0 commit comments