mirror of
https://github.com/herdrdev/herdr.git
synced 2026-09-22 00:01:06 +00:00
fix: reveal selected agent when cycling the sidebar
This commit is contained in:
@@ -87,6 +87,36 @@ pub(super) fn render_expanded(
|
||||
);
|
||||
}
|
||||
|
||||
impl ClientShellState {
|
||||
pub(super) fn reveal_endpoint_agent(&mut self, endpoint_id: &ClientEndpointId, pane_id: &str) {
|
||||
if self.hits.agent_body.is_empty() {
|
||||
return;
|
||||
}
|
||||
let rows = agent_rows(&self.endpoints, &self.active_endpoint_id, &self.config);
|
||||
let Some(target) = rows
|
||||
.iter()
|
||||
.position(|row| &row.endpoint_id == endpoint_id && row.agent.pane_id == pane_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let heights = rows
|
||||
.iter()
|
||||
.map(|row| row.agent.rows.len().max(1).min(u16::MAX as usize) as u16)
|
||||
.collect::<Vec<_>>();
|
||||
let mut gaps = vec![self.config.agents.row_gap; rows.len()];
|
||||
if let Some(last) = gaps.last_mut() {
|
||||
*last = 0;
|
||||
}
|
||||
self.agent_scroll = super::scroll::list_scroll_start_to_reveal(
|
||||
&heights,
|
||||
&gaps,
|
||||
self.hits.agent_body.height,
|
||||
self.agent_scroll,
|
||||
target,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct EndpointAgentRow {
|
||||
endpoint_id: ClientEndpointId,
|
||||
machine_label: String,
|
||||
|
||||
@@ -203,6 +203,7 @@ impl ClientShellState {
|
||||
_ => unreachable!("endpoint agent navigation"),
|
||||
};
|
||||
let target = &agents[next];
|
||||
self.reveal_endpoint_agent(&target.endpoint_id, &target.pane_id);
|
||||
self.focus_or_activate(
|
||||
target.endpoint_id.clone(),
|
||||
ClientEndpointFocusTarget::Pane(target.pane_id.clone()),
|
||||
|
||||
@@ -109,6 +109,72 @@ fn state_with_scrollable_agents() -> (ClientShellState, ClientEndpointId) {
|
||||
(state, remote)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_navigation_reveals_offscreen_targets() {
|
||||
use crate::input::KeybindAction;
|
||||
|
||||
for action in [
|
||||
KeybindAction::NextAgent,
|
||||
KeybindAction::PreviousAgent,
|
||||
KeybindAction::FocusAgent(0),
|
||||
] {
|
||||
let (mut state, remote) = state_with_scrollable_agents();
|
||||
let (endpoint_id, pane_id) = match action {
|
||||
KeybindAction::NextAgent => (ClientEndpointId::Local, "pane_2"),
|
||||
KeybindAction::PreviousAgent => (remote, "pane_8"),
|
||||
_ => (ClientEndpointId::Local, "pane_1"),
|
||||
};
|
||||
state.agent_scroll = if action == KeybindAction::PreviousAgent {
|
||||
0
|
||||
} else {
|
||||
state.hits.agent_max_scroll
|
||||
};
|
||||
state.compose(100, 28).unwrap();
|
||||
assert!(!state
|
||||
.hits
|
||||
.endpoint_agents
|
||||
.iter()
|
||||
.any(|(_, endpoint, pane)| { endpoint == &endpoint_id && pane == pane_id }));
|
||||
|
||||
let mut outcome = ClientShellInput::default();
|
||||
assert!(state.handle_endpoint_navigation(action, &mut outcome));
|
||||
if endpoint_id != state.active_endpoint_id {
|
||||
assert!(state.activate_endpoint_projection(&endpoint_id));
|
||||
}
|
||||
state.compose(100, 28).unwrap();
|
||||
assert!(
|
||||
state
|
||||
.hits
|
||||
.endpoint_agents
|
||||
.iter()
|
||||
.any(|(_, endpoint, pane)| { endpoint == &endpoint_id && pane == pane_id }),
|
||||
"{action:?} must reveal the selected agent"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_navigation_keeps_scroll_when_target_is_visible() {
|
||||
let (mut state, _) = state_with_scrollable_agents();
|
||||
let (_, endpoint_id, pane_id) = state.hits.endpoint_agents[1].clone();
|
||||
let targets = super::super::aggregate_navigation::online_agent_targets(
|
||||
&state.endpoints,
|
||||
&state.active_endpoint_id,
|
||||
state.config.agent_panel_sort,
|
||||
);
|
||||
let index = targets
|
||||
.iter()
|
||||
.position(|target| target.endpoint_id == endpoint_id && target.pane_id == pane_id)
|
||||
.unwrap();
|
||||
let scroll = state.agent_scroll;
|
||||
assert!(state.handle_endpoint_navigation(
|
||||
crate::input::KeybindAction::FocusAgent(index),
|
||||
&mut ClientShellInput::default(),
|
||||
));
|
||||
state.compose(100, 28).unwrap();
|
||||
assert_eq!(state.agent_scroll, scroll);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn switching_machines_preserves_aggregate_agent_scroll_and_visible_rows() {
|
||||
let (mut state, remote) = state_with_scrollable_agents();
|
||||
|
||||
Reference in New Issue
Block a user