diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-06 02:27:06 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-06 02:27:06 +0300 |
| commit | 9e9bc8a144667a6b7debfd4f0c7a31ff0e11493a (patch) | |
| tree | 03f1259f91fd9edeacfd4b904f2e84d4acf25232 /src/client/shell/endpoint_agents.rs | |
| parent | 35b0dff96579f099e0436290085024424ffb289c (diff) | |
feat: manage multiple ssh machines from one client (#3670)
Diffstat (limited to 'src/client/shell/endpoint_agents.rs')
| -rw-r--r-- | src/client/shell/endpoint_agents.rs | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/client/shell/endpoint_agents.rs b/src/client/shell/endpoint_agents.rs new file mode 100644 index 00000000..a49fccf9 --- /dev/null +++ b/src/client/shell/endpoint_agents.rs @@ -0,0 +1,129 @@ +use super::render::put_text; +use super::*; + +pub(super) fn render_collapsed( + buffer: &mut Buffer, + area: Rect, + endpoints: &[ClientShellEndpoint], + active_endpoint_id: &ClientEndpointId, + config: &ClientShellConfig, + hits: &mut ShellHitMap, +) { + let rows = agent_rows(endpoints, active_endpoint_id, config); + for (index, row) in rows.into_iter().take(area.height as usize).enumerate() { + let rect = Rect::new(area.x, area.y + index as u16, area.width, 1); + if row.agent.focused { + buffer.set_style(rect, Style::default().bg(config.palette.active_row_bg)); + } + let initial = row.machine_label.chars().next().unwrap_or('?'); + put_text( + buffer, + rect.x, + rect.y, + rect.width, + &format!( + "{initial}{}", + status_icon(row.agent.status, config.status_indicators) + ), + Style::default() + .fg(if row.stale { + config.palette.overlay0 + } else { + status_color(row.agent.status, &config.palette) + }) + .add_modifier(if row.stale { + Modifier::DIM + } else { + Modifier::empty() + }), + ); + hits.endpoint_agents + .push((rect, row.endpoint_id, row.agent.pane_id)); + } +} + +pub(super) fn render_expanded( + buffer: &mut Buffer, + area: Rect, + agent_view_label: Option<&str>, + endpoints: &[ClientShellEndpoint], + active_endpoint_id: &ClientEndpointId, + config: &ClientShellConfig, + agent_scroll: &mut usize, + hits: &mut ShellHitMap, +) { + if !super::agent_sidebar::render_agent_panel_header( + buffer, + area, + agent_view_label, + config, + hits, + ) { + return; + } + let rows = agent_rows(endpoints, active_endpoint_id, config); + super::agent_sidebar::render_agent_list( + buffer, + area, + &rows, + agent_view_label.map(|_| " no matching agents"), + config, + agent_scroll, + hits, + |row| row.agent.rows.len(), + |buffer, rect, row, hits| { + super::agent_sidebar::render_agent_row(buffer, rect, &row.agent, config); + if row.stale { + buffer.set_style( + rect, + Style::default() + .fg(config.palette.overlay0) + .add_modifier(Modifier::DIM), + ); + } + hits.endpoint_agents + .push((rect, row.endpoint_id.clone(), row.agent.pane_id.clone())); + }, + ); +} + +struct EndpointAgentRow { + endpoint_id: ClientEndpointId, + machine_label: String, + stale: bool, + agent: super::agent_sidebar::AgentRow, +} + +fn agent_rows( + endpoints: &[ClientShellEndpoint], + active_endpoint_id: &ClientEndpointId, + config: &ClientShellConfig, +) -> Vec<EndpointAgentRow> { + let mut rendered_rows = endpoints + .iter() + .filter_map(|endpoint| { + endpoint.snapshot.as_deref().map(|snapshot| { + super::agent_sidebar::agent_rows(snapshot, config, Some(&endpoint.label)) + .into_iter() + .map(|agent| ((endpoint.endpoint_id.clone(), agent.pane_id.clone()), agent)) + .collect::<Vec<_>>() + }) + }) + .flatten() + .collect::<HashMap<_, _>>(); + + super::aggregate_navigation::aggregate_agent_rows(endpoints, config.agent_panel_sort) + .into_iter() + .filter_map(|row| { + let key = (row.endpoint.endpoint_id.clone(), row.agent.pane_id.clone()); + let mut agent = rendered_rows.remove(&key)?; + agent.focused &= row.endpoint.endpoint_id == active_endpoint_id; + Some(EndpointAgentRow { + endpoint_id: row.endpoint.endpoint_id.clone(), + machine_label: row.endpoint.label.to_owned(), + stale: row.endpoint.stale(), + agent, + }) + }) + .collect() +} |
