fix: align collapsed sidebar agent rows (#1182)
refs #1168 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
This commit is contained in:
parent
77f0339c3c
commit
552aa8ca22
|
|
@ -1,6 +1,6 @@
|
|||
use ratatui::layout::Rect;
|
||||
|
||||
use crate::app::state::{AppState, Mode, ViewLayout};
|
||||
use crate::app::state::{AppState, ViewLayout};
|
||||
|
||||
use super::ScrollbarClickTarget;
|
||||
|
||||
|
|
@ -330,24 +330,6 @@ impl AppState {
|
|||
(idx < self.workspaces.len()).then_some(idx)
|
||||
}
|
||||
|
||||
fn collapsed_detail_workspace_idx(&self) -> Option<usize> {
|
||||
if matches!(
|
||||
self.mode,
|
||||
Mode::Navigate
|
||||
| Mode::RenameWorkspace
|
||||
| Mode::Resize
|
||||
| Mode::ConfirmClose
|
||||
| Mode::ContextMenu
|
||||
| Mode::Settings
|
||||
| Mode::GlobalMenu
|
||||
| Mode::KeybindHelp
|
||||
) {
|
||||
Some(self.selected)
|
||||
} else {
|
||||
self.active
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn collapsed_agent_detail_target_at(
|
||||
&self,
|
||||
row: u16,
|
||||
|
|
@ -370,12 +352,10 @@ impl AppState {
|
|||
return None;
|
||||
}
|
||||
|
||||
let ws_idx = self.collapsed_detail_workspace_idx()?;
|
||||
let ws = self.workspaces.get(ws_idx)?;
|
||||
let detail_idx = (row - detail_content_area.y) as usize;
|
||||
let details = ws.pane_details(&self.terminals);
|
||||
let details = crate::ui::agent_panel_entries(self);
|
||||
let detail = details.get(detail_idx)?;
|
||||
Some((ws_idx, detail.tab_idx, detail.pane_id))
|
||||
Some((detail.ws_idx, detail.tab_idx, detail.pane_id))
|
||||
}
|
||||
|
||||
pub(super) fn workspace_drop_index_at_row(&self, row: u16) -> Option<usize> {
|
||||
|
|
@ -498,7 +478,7 @@ mod tests {
|
|||
use crate::{
|
||||
app::state::{AgentPanelSort, DragTarget, Mode},
|
||||
config::SidebarCollapsedModeConfig,
|
||||
detect::Agent,
|
||||
detect::{Agent, AgentState},
|
||||
workspace::Workspace,
|
||||
};
|
||||
|
||||
|
|
@ -952,6 +932,51 @@ mod tests {
|
|||
assert_eq!(app.state.mode, Mode::Terminal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clicking_collapsed_priority_agent_row_switches_to_matching_workspace() {
|
||||
let mut app = app_for_mouse_test();
|
||||
let first = Workspace::test_new("one");
|
||||
let first_pane = first.tabs[0].root_pane;
|
||||
let second = Workspace::test_new("two");
|
||||
let second_pane = second.tabs[0].root_pane;
|
||||
|
||||
app.state.workspaces = vec![first, second];
|
||||
app.state.ensure_test_terminals();
|
||||
app.state.active = Some(0);
|
||||
app.state.selected = 0;
|
||||
app.state.mode = Mode::Terminal;
|
||||
app.state.sidebar_collapsed = true;
|
||||
app.state.agent_panel_sort = AgentPanelSort::Priority;
|
||||
app.state.view.sidebar_rect = Rect::new(0, 0, 4, 20);
|
||||
app.state.view.terminal_area = Rect::new(4, 0, 80, 20);
|
||||
|
||||
let set_state = |app: &mut crate::app::App, ws_idx: usize, pane_id, state| {
|
||||
let terminal_id = app.state.workspaces[ws_idx].tabs[0].panes[&pane_id]
|
||||
.attached_terminal_id
|
||||
.clone();
|
||||
let terminal = app.state.terminals.get_mut(&terminal_id).unwrap();
|
||||
terminal.detected_agent = Some(Agent::Claude);
|
||||
terminal.state = state;
|
||||
};
|
||||
set_state(&mut app, 0, first_pane, AgentState::Working);
|
||||
set_state(&mut app, 1, second_pane, AgentState::Blocked);
|
||||
|
||||
let (_, _, detail_area) =
|
||||
crate::ui::collapsed_sidebar_sections(app.state.view.sidebar_rect);
|
||||
app.handle_mouse(mouse(
|
||||
MouseEventKind::Down(MouseButton::Left),
|
||||
detail_area.x,
|
||||
detail_area.y,
|
||||
));
|
||||
|
||||
assert_eq!(app.state.active, Some(1));
|
||||
assert_eq!(app.state.selected, 1);
|
||||
assert_eq!(
|
||||
app.state.workspaces[1].tabs[0].layout.focused(),
|
||||
second_pane
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clicking_collapsed_sidebar_toggle_expands_sidebar() {
|
||||
let mut app = app_for_mouse_test();
|
||||
|
|
|
|||
|
|
@ -710,11 +710,6 @@ pub(super) fn render_sidebar_collapsed(app: &AppState, frame: &mut Frame, area:
|
|||
}
|
||||
}
|
||||
|
||||
let detail_ws_idx = if is_navigating {
|
||||
Some(app.selected)
|
||||
} else {
|
||||
app.active
|
||||
};
|
||||
let detail_content_area = Rect::new(
|
||||
detail_area.x,
|
||||
detail_area.y,
|
||||
|
|
@ -722,29 +717,26 @@ pub(super) fn render_sidebar_collapsed(app: &AppState, frame: &mut Frame, area:
|
|||
detail_area.height.saturating_sub(1),
|
||||
);
|
||||
if detail_content_area != Rect::default() {
|
||||
if let Some(ws_idx) = detail_ws_idx {
|
||||
if let Some(ws) = app.workspaces.get(ws_idx) {
|
||||
for (detail_idx, detail) in ws.pane_details(&app.terminals).iter().enumerate() {
|
||||
let y = detail_content_area.y + detail_idx as u16;
|
||||
if y >= detail_content_area.y + detail_content_area.height {
|
||||
break;
|
||||
}
|
||||
let pane_num = ws
|
||||
.public_pane_number(detail.pane_id)
|
||||
.unwrap_or(detail_idx + 1);
|
||||
let pane_style = Style::default().fg(p.overlay0);
|
||||
let (icon, icon_style) =
|
||||
agent_icon(detail.state, detail.seen, app.spinner_tick, p);
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
Span::styled(format!("{pane_num}"), pane_style),
|
||||
Span::styled(" ", pane_style),
|
||||
Span::styled(icon, icon_style),
|
||||
])),
|
||||
Rect::new(detail_content_area.x, y, detail_content_area.width, 1),
|
||||
);
|
||||
}
|
||||
for (detail_idx, detail) in agent_panel_entries(app).iter().enumerate() {
|
||||
let y = detail_content_area.y + detail_idx as u16;
|
||||
if y >= detail_content_area.y + detail_content_area.height {
|
||||
break;
|
||||
}
|
||||
let pane_num = app
|
||||
.workspaces
|
||||
.get(detail.ws_idx)
|
||||
.and_then(|ws| ws.public_pane_number(detail.pane_id))
|
||||
.unwrap_or(detail_idx + 1);
|
||||
let pane_style = Style::default().fg(p.overlay0);
|
||||
let (icon, icon_style) = agent_icon(detail.state, detail.seen, app.spinner_tick, p);
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
Span::styled(format!("{pane_num}"), pane_style),
|
||||
Span::styled(" ", pane_style),
|
||||
Span::styled(icon, icon_style),
|
||||
])),
|
||||
Rect::new(detail_content_area.x, y, detail_content_area.width, 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1297,6 +1289,45 @@ mod tests {
|
|||
assert_eq!(labels, ["four", "two", "one", "three"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collapsed_sidebar_uses_all_workspaces_agent_panel_order() {
|
||||
let mut app = crate::app::state::AppState::test_new();
|
||||
app.workspaces = vec![Workspace::test_new("one"), Workspace::test_new("two")];
|
||||
app.ensure_test_terminals();
|
||||
app.active = Some(0);
|
||||
app.selected = 0;
|
||||
app.agent_panel_sort = crate::app::state::AgentPanelSort::Priority;
|
||||
|
||||
let set_state = |app: &mut crate::app::state::AppState, ws_idx: usize, state| {
|
||||
let pane = app.workspaces[ws_idx].tabs[0].root_pane;
|
||||
let terminal_id = app.workspaces[ws_idx].tabs[0].panes[&pane]
|
||||
.attached_terminal_id
|
||||
.clone();
|
||||
let terminal = app.terminals.get_mut(&terminal_id).unwrap();
|
||||
terminal.detected_agent = Some(Agent::Claude);
|
||||
terminal.state = state;
|
||||
};
|
||||
set_state(&mut app, 0, AgentState::Working);
|
||||
set_state(&mut app, 1, AgentState::Blocked);
|
||||
|
||||
let area = Rect::new(0, 0, 5, 12);
|
||||
let (_, _, detail_area) = collapsed_sidebar_sections(area);
|
||||
let first_detail_y = detail_area.y;
|
||||
let mut terminal = Terminal::new(TestBackend::new(area.width, area.height))
|
||||
.expect("test terminal should initialize");
|
||||
|
||||
terminal
|
||||
.draw(|frame| render_sidebar_collapsed(&app, frame, area))
|
||||
.expect("collapsed sidebar should render");
|
||||
|
||||
let buffer = terminal.backend().buffer();
|
||||
assert_eq!(buffer[(detail_area.x + 2, first_detail_y)].symbol(), "◉");
|
||||
assert_eq!(
|
||||
buffer[(detail_area.x + 2, first_detail_y)].style().fg,
|
||||
Some(app.palette.red)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn all_workspaces_agent_panel_entries_use_live_root_runtime_cwd_for_workspace_label() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue