mirror of
https://github.com/herdrdev/herdr.git
synced 2026-09-22 08:01:06 +00:00
fix: keep spaces sidebar stable during resize (#3862)
refs #3817 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
This commit is contained in:
@@ -40,35 +40,55 @@ impl ClientShellState {
|
||||
.navigate_workspace_id
|
||||
.as_ref()
|
||||
.is_some_and(|target| self.navigation_target_valid(target));
|
||||
super::endpoint_sidebar::render_expanded(
|
||||
&mut buffer,
|
||||
sidebar,
|
||||
self.snapshot.as_deref(),
|
||||
&self.config,
|
||||
&mut render::ShellRenderState {
|
||||
endpoints: &self.endpoints,
|
||||
active_endpoint_id: &self.active_endpoint_id,
|
||||
collapsed_endpoints: &self.collapsed_endpoints,
|
||||
collapsed_groups: &self.collapsed_groups,
|
||||
remote_collapsed_groups: &self.remote_collapsed_groups,
|
||||
workspace_scroll: &mut self.workspace_scroll,
|
||||
agent_scroll: &mut self.agent_scroll,
|
||||
tab_scroll: &mut self.tab_scroll,
|
||||
reveal_focused_workspace: &mut self.reveal_focused_workspace,
|
||||
reveal_focused_tab: &mut self.reveal_focused_tab,
|
||||
sidebar_collapsed: false,
|
||||
sidebar_section_split: self.sidebar_section_split,
|
||||
tab_drag_insert_index: None,
|
||||
selected_workspace_id: self
|
||||
.navigate_workspace_id
|
||||
.as_ref()
|
||||
.filter(|_| valid_navigation_target),
|
||||
reveal_navigation_workspace: &mut self.reveal_navigation_workspace,
|
||||
dragged_workspace_id: None,
|
||||
workspace_drop_indicator_row: None,
|
||||
},
|
||||
&mut self.hits,
|
||||
);
|
||||
// A resize invalidates pane geometry, not the healthy Local workspace chrome.
|
||||
let local_snapshot = self.snapshot.as_deref().filter(|_| {
|
||||
self.endpoints.len() == 1
|
||||
&& !self.sidebar_collapsed
|
||||
&& layout.sidebar.width > 0
|
||||
&& self.endpoint_status(&self.active_endpoint_id)
|
||||
== Some(ClientEndpointStatus::Online)
|
||||
});
|
||||
let mut render_state = render::ShellRenderState {
|
||||
endpoints: &self.endpoints,
|
||||
active_endpoint_id: &self.active_endpoint_id,
|
||||
collapsed_endpoints: &self.collapsed_endpoints,
|
||||
collapsed_groups: &self.collapsed_groups,
|
||||
remote_collapsed_groups: &self.remote_collapsed_groups,
|
||||
workspace_scroll: &mut self.workspace_scroll,
|
||||
agent_scroll: &mut self.agent_scroll,
|
||||
tab_scroll: &mut self.tab_scroll,
|
||||
reveal_focused_workspace: &mut self.reveal_focused_workspace,
|
||||
reveal_focused_tab: &mut self.reveal_focused_tab,
|
||||
sidebar_collapsed: false,
|
||||
sidebar_section_split: self.sidebar_section_split,
|
||||
tab_drag_insert_index: None,
|
||||
selected_workspace_id: self
|
||||
.navigate_workspace_id
|
||||
.as_ref()
|
||||
.filter(|_| valid_navigation_target),
|
||||
reveal_navigation_workspace: &mut self.reveal_navigation_workspace,
|
||||
dragged_workspace_id: None,
|
||||
workspace_drop_indicator_row: None,
|
||||
};
|
||||
if let Some(snapshot) = local_snapshot {
|
||||
render::render_sidebar(
|
||||
&mut buffer,
|
||||
sidebar,
|
||||
snapshot,
|
||||
&self.config,
|
||||
&mut render_state,
|
||||
&mut self.hits,
|
||||
);
|
||||
} else {
|
||||
super::endpoint_sidebar::render_expanded(
|
||||
&mut buffer,
|
||||
sidebar,
|
||||
self.snapshot.as_deref(),
|
||||
&self.config,
|
||||
&mut render_state,
|
||||
&mut self.hits,
|
||||
);
|
||||
}
|
||||
if !self.config.mouse_capture {
|
||||
self.hits = ShellHitMap::default();
|
||||
}
|
||||
@@ -87,14 +107,16 @@ impl ClientShellState {
|
||||
} else {
|
||||
Rect::new(0, 0, cols, 1)
|
||||
};
|
||||
render::put_text(
|
||||
&mut buffer,
|
||||
message_area.x,
|
||||
message_area.y,
|
||||
message_area.width,
|
||||
&message,
|
||||
Style::default().fg(self.config.palette.overlay0),
|
||||
);
|
||||
if local_snapshot.is_none() || self.endpoint_error.is_some() {
|
||||
render::put_text(
|
||||
&mut buffer,
|
||||
message_area.x,
|
||||
message_area.y,
|
||||
message_area.width,
|
||||
&message,
|
||||
Style::default().fg(self.config.palette.overlay0),
|
||||
);
|
||||
}
|
||||
render::render_mode_bar(
|
||||
&mut buffer,
|
||||
Rect::new(0, 0, cols, rows),
|
||||
|
||||
@@ -99,6 +99,7 @@ fn client_owned_sidebar_dividers_resize_live() {
|
||||
state.set_snapshot(Box::new(snapshot()));
|
||||
state.set_pane_surface(surface());
|
||||
state.compose(106, 30).expect("expanded sidebar");
|
||||
assert!(state.hits.machines.is_empty());
|
||||
let workspace_body = state.hits.workspace_body;
|
||||
let needless_scroll =
|
||||
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
|
||||
@@ -128,15 +129,55 @@ fn client_owned_sidebar_dividers_resize_live() {
|
||||
assert!(state.sidebar_width_manual);
|
||||
assert!(resize.repaint);
|
||||
assert!(resize.resize);
|
||||
let waiting_frame = state.compose(106, 30).expect("waiting for resized surface");
|
||||
let waiting_text: String = waiting_frame
|
||||
.cells
|
||||
.iter()
|
||||
.map(|cell| cell.symbol.as_str())
|
||||
.collect();
|
||||
assert!(
|
||||
waiting_text.contains(" spaces"),
|
||||
"local sidebar must keep spaces while resizing: {waiting_text}"
|
||||
);
|
||||
assert!(!waiting_text.contains(" machines"));
|
||||
assert!(!waiting_text.contains("Select a connected machine"));
|
||||
assert!(!waiting_text.contains("LIVE"));
|
||||
assert!(waiting_frame.cursor.is_none());
|
||||
assert!(state.pane_surface.is_none());
|
||||
assert!(state.hits.panes.is_empty());
|
||||
assert!(state.hits.pane_splits.is_empty());
|
||||
assert!(state.hits.machines.is_empty());
|
||||
assert_eq!(state.hits.sidebar_divider.x, 31);
|
||||
assert_eq!(state.hits.workspaces[0].workspace_id, "ws_1");
|
||||
|
||||
let next_resize =
|
||||
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
|
||||
kind: MouseEventKind::Drag(MouseButton::Left),
|
||||
column: 32,
|
||||
row: width_divider.y + 2,
|
||||
modifiers: KeyModifiers::empty(),
|
||||
})]);
|
||||
assert!(next_resize.resize);
|
||||
state.compose(106, 30).expect("continued resize");
|
||||
assert_eq!(state.hits.sidebar_divider.x, 32);
|
||||
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
|
||||
kind: MouseEventKind::Up(MouseButton::Left),
|
||||
column: 31,
|
||||
column: 32,
|
||||
row: width_divider.y + 2,
|
||||
modifiers: KeyModifiers::empty(),
|
||||
})]);
|
||||
assert!(state.chrome_drag.is_none());
|
||||
|
||||
state.set_pane_surface(surface());
|
||||
state.compose(106, 30).expect("resized sidebar");
|
||||
let recovered_frame = state.compose(106, 30).expect("resized sidebar");
|
||||
let recovered_text: String = recovered_frame
|
||||
.cells
|
||||
.iter()
|
||||
.map(|cell| cell.symbol.as_str())
|
||||
.collect();
|
||||
assert!(recovered_text.contains(" spaces"));
|
||||
assert!(recovered_text.contains("LIVE"));
|
||||
assert!(!state.hits.panes.is_empty());
|
||||
let section_divider = state.hits.sidebar_section_divider;
|
||||
state.handle_raw_events(vec![RawInputEvent::Mouse(crossterm::event::MouseEvent {
|
||||
kind: MouseEventKind::Down(MouseButton::Left),
|
||||
|
||||
Reference in New Issue
Block a user