aboutsummaryrefslogtreecommitdiff
path: root/src/client/shell/endpoint_agents.rs
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-06 02:27:06 +0300
committerGitHub <noreply@github.com>2026-09-06 02:27:06 +0300
commit9e9bc8a144667a6b7debfd4f0c7a31ff0e11493a (patch)
tree03f1259f91fd9edeacfd4b904f2e84d4acf25232 /src/client/shell/endpoint_agents.rs
parent35b0dff96579f099e0436290085024424ffb289c (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.rs129
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()
+}