@@ -42,9 +42,38 @@ fn focused_block(title: &str, focused: bool) -> Block<'static> {
4242fn key_hints ( completed : bool ) -> Line < ' static > {
4343 let base = "Up/Down move Tab focus PgUp/PgDn scroll g/G jump ? help" ;
4444 if completed {
45- Line :: from ( format ! ( "{base} q close" ) )
45+ Line :: from ( format ! ( "Press q to close {base} " ) )
4646 } else {
47- Line :: from ( format ! ( "{base} Ctrl-C interrupt" ) )
47+ Line :: from ( format ! ( "{base} q closes when finished Ctrl-C interrupt" ) )
48+ }
49+ }
50+
51+ fn completion_hint_line ( completed : bool ) -> Line < ' static > {
52+ if completed {
53+ Line :: from ( vec ! [
54+ Span :: styled(
55+ "READY TO CLOSE " ,
56+ Style :: default ( )
57+ . fg( Color :: Green )
58+ . add_modifier( Modifier :: BOLD ) ,
59+ ) ,
60+ Span :: styled(
61+ "Press q to close this dashboard." ,
62+ Style :: default ( )
63+ . fg( Color :: White )
64+ . add_modifier( Modifier :: BOLD ) ,
65+ ) ,
66+ ] )
67+ } else {
68+ Line :: from ( vec ! [
69+ Span :: styled(
70+ "RUNNING " ,
71+ Style :: default ( )
72+ . fg( Color :: Yellow )
73+ . add_modifier( Modifier :: BOLD ) ,
74+ ) ,
75+ Span :: raw( "The dashboard stays open until completion." ) ,
76+ ] )
4877 }
4978}
5079
@@ -55,7 +84,7 @@ pub fn render_dashboard(frame: &mut Frame<'_>, state: &DashboardState, show_help
5584 . constraints ( [
5685 Constraint :: Length ( 7 ) ,
5786 Constraint :: Min ( 12 ) ,
58- Constraint :: Length ( 3 ) ,
87+ Constraint :: Length ( 5 ) ,
5988 ] )
6089 . split ( area) ;
6190
@@ -247,6 +276,7 @@ fn render_footer(frame: &mut Frame<'_>, area: Rect, state: &DashboardState) {
247276 . join ( " " ) ,
248277 ) ) ;
249278 }
279+ lines. push ( completion_hint_line ( state. completed ) ) ;
250280 lines. push ( key_hints ( state. completed ) ) ;
251281 frame. render_widget (
252282 Paragraph :: new ( lines) . block ( Block :: default ( ) . borders ( Borders :: ALL ) . title ( "Summary" ) ) ,
@@ -260,7 +290,7 @@ fn render_help(frame: &mut Frame<'_>, area: Rect, completed: bool) {
260290 let quit_line = if completed {
261291 "q: close the dashboard"
262292 } else {
263- "q: ignored while the run is still active "
293+ "q: available after the run finishes "
264294 } ;
265295 let lines = vec ! [
266296 Line :: from( "Up/Down: move selected item" ) ,
@@ -307,7 +337,7 @@ mod tests {
307337 DashboardState , SummaryRow ,
308338 } ;
309339
310- use super :: render_dashboard;
340+ use super :: { completion_hint_line , key_hints , render_dashboard} ;
311341
312342 fn render_to_string ( state : & DashboardState ) -> String {
313343 let backend = TestBackend :: new ( 100 , 40 ) ;
@@ -365,6 +395,43 @@ mod tests {
365395 let rendered = render_to_string ( & state) ;
366396 assert ! ( rendered. contains( "failed=1" ) ) ;
367397 assert ! ( rendered. contains( "network error" ) ) ;
398+ assert ! ( rendered. contains( "READY TO CLOSE" ) ) ;
399+ assert ! ( rendered. contains( "Press q to close this dashboard" ) ) ;
400+ }
401+
402+ #[ test]
403+ fn key_hints_explain_when_q_is_available ( ) {
404+ let running = key_hints ( false ) ;
405+ let completed = key_hints ( true ) ;
406+ assert ! (
407+ running
408+ . spans
409+ . iter( )
410+ . any( |span| span. content. contains( "q closes when finished" ) )
411+ ) ;
412+ assert ! (
413+ completed
414+ . spans
415+ . iter( )
416+ . any( |span| span. content. contains( "Press q to close" ) )
417+ ) ;
418+ }
419+
420+ #[ test]
421+ fn completion_hint_is_explicit_when_finished ( ) {
422+ let completed = completion_hint_line ( true ) ;
423+ assert ! (
424+ completed
425+ . spans
426+ . iter( )
427+ . any( |span| span. content. contains( "READY TO CLOSE" ) )
428+ ) ;
429+ assert ! (
430+ completed
431+ . spans
432+ . iter( )
433+ . any( |span| span. content. contains( "Press q to close this dashboard" ) )
434+ ) ;
368435 }
369436
370437 #[ test]
0 commit comments