@@ -193,55 +193,111 @@ impl OperationInProcessStats {
193193
194194impl std:: fmt:: Display for UpdateStats {
195195 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
196- let mut messages = Vec :: new ( ) ;
197- let num_errors = self . num_errors . get ( ) ;
198- if num_errors > 0 {
199- messages. push ( format ! ( "{num_errors} source rows FAILED" ) ) ;
200- }
201-
202- let num_skipped = self . num_no_change . get ( ) ;
203- if num_skipped > 0 {
204- messages. push ( format ! ( "{num_skipped} source rows NO CHANGE" ) ) ;
205- }
206-
196+ let mut segments = Vec :: new ( ) ;
207197 let num_insertions = self . num_insertions . get ( ) ;
208198 let num_deletions = self . num_deletions . get ( ) ;
209199 let num_updates = self . num_updates . get ( ) ;
210- let num_reprocesses = self . num_reprocesses . get ( ) ;
211- let num_source_rows = num_insertions + num_deletions + num_updates + num_reprocesses;
212- if num_source_rows > 0 {
213- let mut sub_messages = Vec :: new ( ) ;
200+ let num_no_change = self . num_no_change . get ( ) ;
201+ let num_errors = self . num_errors . get ( ) ;
202+ let num_in_process = self . processing . get_in_process ( ) ;
203+ let total = num_insertions + num_deletions + num_updates + num_no_change;
204+
205+ // Progress bar segments
206+ if total > 0 {
214207 if num_insertions > 0 {
215- sub_messages . push ( format ! ( "{num_insertions} ADDED" ) ) ;
208+ segments . push ( ( num_insertions , "+" , format ! ( "\x1B [90m(+{} added) \x1B [0m" , num_insertions ) ) ) ;
216209 }
217210 if num_deletions > 0 {
218- sub_messages. push ( format ! ( "{num_deletions} REMOVED" ) ) ;
219- }
220- if num_reprocesses > 0 {
221- sub_messages. push ( format ! (
222- "{num_reprocesses} REPROCESSED on flow/logic changes or reexport"
223- ) ) ;
211+ segments. push ( ( num_deletions, "-" , format ! ( "\x1B [90m(-{} removed)\x1B [0m" , num_deletions) ) ) ;
224212 }
225213 if num_updates > 0 {
226- sub_messages. push ( format ! ( "{num_updates} UPDATED in source content only" ) ) ;
214+ segments. push ( ( num_updates, "~" , format ! ( "\x1B [90m(~{} updated)\x1B [0m" , num_updates) ) ) ;
215+ }
216+ if num_no_change > 0 {
217+ segments. push ( ( num_no_change, " " , "" . to_string ( ) ) ) ;
227218 }
228- messages. push ( format ! (
229- "{num_source_rows} source rows processed ({})" ,
230- sub_messages. join( ", " ) ,
231- ) ) ;
232219 }
233220
234- let num_in_process = self . processing . get_in_process ( ) ;
235- if num_in_process > 0 {
236- messages. push ( format ! ( "{num_in_process} source rows IN PROCESS" ) ) ;
221+ // Error handling
222+ if num_errors > 0 {
223+ write ! ( f, "{} rows failed" , num_errors) ?;
224+ if !segments. is_empty ( ) {
225+ write ! ( f, "; " ) ?;
226+ }
237227 }
238228
239- if !messages. is_empty ( ) {
240- write ! ( f, "{}" , messages. join( "; " ) ) ?;
229+ // Progress bar
230+ if !segments. is_empty ( ) {
231+ let mut sorted_segments = segments. clone ( ) ;
232+ sorted_segments. sort_by_key ( |s| s. 0 ) ;
233+ sorted_segments. reverse ( ) ;
234+
235+ let bar_width = 40 ;
236+ let mut bar = String :: new ( ) ;
237+
238+ let percentage = ( ( total - num_in_process) as f64 / total as f64 * 100.0 ) as i64 ;
239+ let mut remaining_width = bar_width;
240+
241+ for ( count, segment_type, _) in sorted_segments. iter ( ) {
242+ let segment_width = ( * count * bar_width as i64 / total as i64 ) as usize ;
243+ let width = std:: cmp:: min ( segment_width, remaining_width) ;
244+ if width > 0 {
245+ // Calculate completed and remaining portions
246+ let completed_portion = ( width as f64 * ( total - num_in_process) as f64 / total as f64 ) as usize ;
247+ let remaining_portion = width - completed_portion;
248+
249+ // Add segment with appropriate characters based on type
250+ if completed_portion > 0 {
251+ let completed_char = match * segment_type {
252+ "+" => "█" ,
253+ "-" => "▓" ,
254+ "~" => "▒" ,
255+ _ => "░"
256+ } ;
257+ bar. push_str ( & completed_char. repeat ( completed_portion) ) ;
258+ }
259+
260+ if remaining_portion > 0 {
261+ let remaining_char = match * segment_type {
262+ "+" => "▒" ,
263+ "-" => "░" ,
264+ "~" => "░" ,
265+ _ => " "
266+ } ;
267+ bar. push_str ( & remaining_char. repeat ( remaining_portion) ) ;
268+ }
269+
270+ remaining_width = remaining_width. saturating_sub ( width) ;
271+ }
272+ }
273+ if remaining_width > 0 {
274+ bar. push_str ( & " " . repeat ( remaining_width) ) ;
275+ }
276+ write ! ( f, "[{}] {}/{} records " , bar, total - num_in_process, total) ?;
277+
278+ // Add segment labels
279+ let mut first = true ;
280+ for ( _, _, label) in segments. iter ( ) {
281+ if !label. is_empty ( ) {
282+ if !first {
283+ write ! ( f, " " ) ?;
284+ }
285+ write ! ( f, "{}" , label) ?;
286+ first = false ;
287+ }
288+ }
241289 } else {
242290 write ! ( f, "No changes" ) ?;
243291 }
244292
293+ // In-process info
294+ if num_in_process > 0 {
295+ if !segments. is_empty ( ) {
296+ write ! ( f, " " ) ?;
297+ }
298+ write ! ( f, "({} in process)" , num_in_process) ?;
299+ }
300+
245301 Ok ( ( ) )
246302 }
247303}
0 commit comments