diff --git a/crates/turborepo-ui/src/tui/app.rs b/crates/turborepo-ui/src/tui/app.rs index 99fc06c0d8c39..632cc5ccb1266 100644 --- a/crates/turborepo-ui/src/tui/app.rs +++ b/crates/turborepo-ui/src/tui/app.rs @@ -49,6 +49,7 @@ pub struct App { scroll: TableState, selected_task_index: usize, has_user_scrolled: bool, + has_sidebar: bool, done: bool, } @@ -92,6 +93,7 @@ impl App { tasks_by_status, scroll: TableState::default().with_selected(selected_task_index), selected_task_index, + has_sidebar: true, has_user_scrolled: has_user_interacted, } } @@ -771,6 +773,9 @@ fn update( app.has_user_scrolled = true; app.interact()?; } + Event::ToggleSidebar => { + app.has_sidebar = !app.has_sidebar; + } Event::Input { bytes } => { app.forward_input(&bytes)?; } @@ -822,13 +827,18 @@ fn update( fn view(app: &mut App, f: &mut Frame) { let cols = app.size.pane_cols(); - let horizontal = Layout::horizontal([Constraint::Fill(1), Constraint::Length(cols)]); + let horizontal = if app.has_sidebar { + Layout::horizontal([Constraint::Fill(1), Constraint::Length(cols)]) + } else { + Layout::horizontal([Constraint::Max(0), Constraint::Length(cols)]) + }; let [table, pane] = horizontal.areas(f.size()); let active_task = app.active_task().unwrap().to_string(); let output_logs = app.tasks.get(&active_task).unwrap(); - let pane_to_render: TerminalPane = TerminalPane::new(output_logs, &active_task, &app.focus); + let pane_to_render: TerminalPane = + TerminalPane::new(output_logs, &active_task, &app.focus, app.has_sidebar); let table_to_render = TaskTable::new(&app.tasks_by_status); diff --git a/crates/turborepo-ui/src/tui/event.rs b/crates/turborepo-ui/src/tui/event.rs index 4f609f9a59028..446f110d8f176 100644 --- a/crates/turborepo-ui/src/tui/event.rs +++ b/crates/turborepo-ui/src/tui/event.rs @@ -50,6 +50,7 @@ pub enum Event { rows: u16, cols: u16, }, + ToggleSidebar, SearchEnter, SearchExit { restore_scroll: bool, diff --git a/crates/turborepo-ui/src/tui/input.rs b/crates/turborepo-ui/src/tui/input.rs index 7ae9fb55dbb88..fb17dc5b19b8d 100644 --- a/crates/turborepo-ui/src/tui/input.rs +++ b/crates/turborepo-ui/src/tui/input.rs @@ -85,6 +85,7 @@ fn translate_key_event(options: InputOptions, key_event: KeyEvent) -> Option Some(Event::ToggleSidebar), KeyCode::Enter if matches!(options.focus, LayoutSections::Search { .. }) => { Some(Event::SearchExit { restore_scroll: false, diff --git a/crates/turborepo-ui/src/tui/pane.rs b/crates/turborepo-ui/src/tui/pane.rs index a1c5e584477b2..361743c7f4567 100644 --- a/crates/turborepo-ui/src/tui/pane.rs +++ b/crates/turborepo-ui/src/tui/pane.rs @@ -1,7 +1,7 @@ use ratatui::{ style::Style, text::Line, - widgets::{Block, Borders, Widget}, + widgets::{Block, Widget}, }; use tui_term::widget::PseudoTerminal; @@ -10,11 +10,13 @@ use super::{app::LayoutSections, TerminalOutput}; const FOOTER_TEXT_ACTIVE: &str = "Press`Ctrl-Z` to stop interacting."; const FOOTER_TEXT_INACTIVE: &str = "Press `Enter` to interact."; const HAS_SELECTION: &str = "Press `c` to copy selection"; +const TASK_LIST_HIDDEN: &str = "Press `h` to show task list."; pub struct TerminalPane<'a, W> { terminal_output: &'a TerminalOutput, task_name: &'a str, section: &'a LayoutSections, + has_sidebar: bool, } impl<'a, W> TerminalPane<'a, W> { @@ -22,11 +24,13 @@ impl<'a, W> TerminalPane<'a, W> { terminal_output: &'a TerminalOutput, task_name: &'a str, section: &'a LayoutSections, + has_sidebar: bool, ) -> Self { Self { terminal_output, section, task_name, + has_sidebar, } } @@ -35,15 +39,25 @@ impl<'a, W> TerminalPane<'a, W> { } fn footer(&self) -> Line { + let task_list_message = if !self.has_sidebar { + TASK_LIST_HIDDEN + } else { + "" + }; + match self.section { - LayoutSections::Pane if self.terminal_output.has_selection() => { - Line::from(format!("{FOOTER_TEXT_ACTIVE} {HAS_SELECTION}")).centered() - } + LayoutSections::Pane if self.terminal_output.has_selection() => Line::from(format!( + "{FOOTER_TEXT_ACTIVE} {task_list_message} {HAS_SELECTION}" + )) + .centered(), LayoutSections::Pane => Line::from(FOOTER_TEXT_ACTIVE.to_owned()).centered(), - LayoutSections::TaskList if self.terminal_output.has_selection() => { - Line::from(format!("{FOOTER_TEXT_INACTIVE} {HAS_SELECTION}")).centered() + LayoutSections::TaskList if self.terminal_output.has_selection() => Line::from( + format!("{FOOTER_TEXT_INACTIVE} {task_list_message} {HAS_SELECTION}"), + ) + .centered(), + LayoutSections::TaskList => { + Line::from(format!("{FOOTER_TEXT_INACTIVE} {task_list_message}")).centered() } - LayoutSections::TaskList => Line::from(FOOTER_TEXT_INACTIVE.to_owned()).centered(), LayoutSections::Search { results, .. } => { Line::from(format!("/ {}", results.query())).left_aligned() } @@ -58,7 +72,6 @@ impl<'a, W> Widget for &TerminalPane<'a, W> { { let screen = self.terminal_output.parser.screen(); let block = Block::default() - .borders(Borders::LEFT) .title(self.terminal_output.title(self.task_name)) .title_bottom(self.footer()) .style(if self.highlight() { diff --git a/crates/turborepo-ui/src/tui/table.rs b/crates/turborepo-ui/src/tui/table.rs index ddeb5cb34f14f..c0524235579c7 100644 --- a/crates/turborepo-ui/src/tui/table.rs +++ b/crates/turborepo-ui/src/tui/table.rs @@ -2,7 +2,7 @@ use ratatui::{ layout::{Constraint, Rect}, style::{Color, Style, Stylize}, text::Text, - widgets::{Cell, Row, StatefulWidget, Table, TableState}, + widgets::{Block, Borders, Cell, Row, StatefulWidget, Table, TableState}, }; use super::{event::TaskResult, spinner::SpinnerState, task::TasksByStatus}; @@ -17,6 +17,7 @@ pub struct TaskTable<'b> { } const TASK_NAVIGATE_INSTRUCTIONS: &str = "ā†‘ ā†“ to navigate"; +const HIDE_INSTRUCTIONS: &str = "h to hide"; impl<'b> TaskTable<'b> { /// Construct a new table with all of the planned tasks @@ -105,6 +106,7 @@ impl<'a> StatefulWidget for &'a TaskTable<'a> { ) .highlight_style(Style::default().fg(Color::Yellow)) .column_spacing(0) + .block(Block::new().borders(Borders::RIGHT)) .header( vec![format!("Tasks\n{bar}"), " \nā”€".to_owned()] .into_iter() @@ -114,13 +116,13 @@ impl<'a> StatefulWidget for &'a TaskTable<'a> { ) .footer( vec![ - format!("{bar}\n{TASK_NAVIGATE_INSTRUCTIONS}"), + format!("{bar}\n{TASK_NAVIGATE_INSTRUCTIONS}\n{HIDE_INSTRUCTIONS}"), format!("ā”€\n "), ] .into_iter() .map(Cell::from) .collect::() - .height(2), + .height(3), ); StatefulWidget::render(table, area, buf, state); }