aboutsummaryrefslogtreecommitdiff
path: root/src/app/actions.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-06-17 16:08:43 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-06-17 16:08:43 +0300
commit54490254f70469cd154ee630bc4bec84da178f0c (patch)
tree450bf0397398b28932f636d33e37f73c011dd19d /src/app/actions.rs
parentd998753efe506a04c80306795efc72bff60bb0ec (diff)
feat: sort agent panel by priority
refs #318
Diffstat (limited to 'src/app/actions.rs')
-rw-r--r--src/app/actions.rs95
1 files changed, 67 insertions, 28 deletions
diff --git a/src/app/actions.rs b/src/app/actions.rs
index 9df07af5..1e0f0f5e 100644
--- a/src/app/actions.rs
+++ b/src/app/actions.rs
@@ -951,12 +951,6 @@ impl AppState {
let workspace_id = self.workspaces[idx].id.clone();
crate::logging::workspace_focused(&workspace_id);
self.mark_session_dirty();
- if matches!(
- self.agent_panel_scope,
- crate::app::state::AgentPanelScope::CurrentWorkspace
- ) {
- self.agent_panel_scroll = 0;
- }
self.ensure_workspace_visible(idx);
if let Some(ws) = self.workspaces.get_mut(idx) {
let active_tab = ws.active_tab;
@@ -994,14 +988,6 @@ impl AppState {
crate::logging::workspace_focused(&workspace_id);
}
self.mark_session_dirty();
- if workspace_changed
- && matches!(
- self.agent_panel_scope,
- crate::app::state::AgentPanelScope::CurrentWorkspace
- )
- {
- self.agent_panel_scroll = 0;
- }
self.ensure_workspace_visible(ws_idx);
if let Some(ws) = self.workspaces.get_mut(ws_idx) {
ws.switch_tab(tab_idx);
@@ -2587,6 +2573,12 @@ impl AppState {
self.mark_session_dirty();
}
let change = mutation.effective_state_change?;
+ if change.previous_state != change.state {
+ self.next_agent_state_change_seq += 1;
+ if let Some(terminal) = self.terminals.get_mut(&terminal_id) {
+ terminal.last_agent_state_change_seq = Some(self.next_agent_state_change_seq);
+ }
+ }
let seen = self.apply_pane_state_change(ws_idx, pane_id, &change)?;
let update = PaneStateUpdate {
pane_id,
@@ -3542,6 +3534,16 @@ mod tests {
}
fn mark_agent(state: &mut AppState, ws_idx: usize, tab_idx: usize, pane_id: PaneId) {
+ set_agent_state(state, ws_idx, tab_idx, pane_id, AgentState::Idle);
+ }
+
+ fn set_agent_state(
+ state: &mut AppState,
+ ws_idx: usize,
+ tab_idx: usize,
+ pane_id: PaneId,
+ agent_state: AgentState,
+ ) {
state.ensure_test_terminals();
let terminal_id = state.workspaces[ws_idx].tabs[tab_idx]
.panes
@@ -3550,12 +3552,28 @@ mod tests {
.attached_terminal_id
.clone();
if let Some(terminal) = state.terminals.get_mut(&terminal_id) {
- terminal.set_detected_state(Some(Agent::Pi), AgentState::Idle);
+ terminal.set_detected_state(Some(Agent::Pi), agent_state);
}
}
+ fn transition_agent_state(state: &mut AppState, pane_id: PaneId, agent_state: AgentState) {
+ state
+ .update_terminal_state(pane_id, |terminal| {
+ Some(terminal.set_detected_state_with_screen_signals_at(
+ Some(Agent::Pi),
+ agent_state,
+ matches!(agent_state, AgentState::Blocked),
+ false,
+ false,
+ false,
+ std::time::Instant::now(),
+ ))
+ })
+ .expect("agent state transition should update pane state");
+ }
+
#[test]
- fn next_agent_cycles_agent_panel_entries_in_all_scope() {
+ fn next_agent_cycles_agent_panel_entries() {
let mut first = Workspace::test_new("one");
let first_root = first.tabs[0].root_pane;
let first_second = first.test_split(Direction::Horizontal);
@@ -3569,7 +3587,6 @@ mod tests {
state.active = Some(0);
state.selected = 0;
state.mode = Mode::Terminal;
- state.agent_panel_scope = crate::app::state::AgentPanelScope::AllWorkspaces;
mark_agent(&mut state, 0, 0, first_root);
mark_agent(&mut state, 0, 0, first_second);
mark_agent(&mut state, 1, 0, second_root);
@@ -3602,7 +3619,6 @@ mod tests {
state.active = Some(0);
state.selected = 0;
state.mode = Mode::Terminal;
- state.agent_panel_scope = crate::app::state::AgentPanelScope::AllWorkspaces;
mark_agent(&mut state, 0, 0, first_root);
mark_agent(&mut state, 0, 0, first_second);
mark_agent(&mut state, 1, 0, second_root);
@@ -3618,7 +3634,6 @@ mod tests {
fn focus_agent_entry_succeeds_for_already_focused_agent() {
let mut state = app_with_workspaces(&["one"]);
let root = state.workspaces[0].tabs[0].root_pane;
- state.agent_panel_scope = crate::app::state::AgentPanelScope::AllWorkspaces;
mark_agent(&mut state, 0, 0, root);
assert!(state.focus_agent_entry(0));
@@ -3628,11 +3643,11 @@ mod tests {
}
#[test]
- fn next_agent_cycles_only_current_scope_entries() {
+ fn next_agent_cycles_priority_sorted_agent_panel_entries() {
let mut first = Workspace::test_new("one");
let first_root = first.tabs[0].root_pane;
let first_second = first.test_split(Direction::Horizontal);
- first.tabs[0].layout.focus_pane(first_second);
+ first.tabs[0].layout.focus_pane(first_root);
let second = Workspace::test_new("two");
let second_root = second.tabs[0].root_pane;
@@ -3642,15 +3657,40 @@ mod tests {
state.active = Some(0);
state.selected = 0;
state.mode = Mode::Terminal;
- state.agent_panel_scope = crate::app::state::AgentPanelScope::CurrentWorkspace;
- mark_agent(&mut state, 0, 0, first_root);
- mark_agent(&mut state, 0, 0, first_second);
- mark_agent(&mut state, 1, 0, second_root);
+ state.agent_panel_sort = crate::app::state::AgentPanelSort::Priority;
+ set_agent_state(&mut state, 0, 0, first_root, AgentState::Idle);
+ set_agent_state(&mut state, 0, 0, first_second, AgentState::Working);
+ set_agent_state(&mut state, 1, 0, second_root, AgentState::Blocked);
state.next_agent();
- assert_eq!(state.active, Some(0));
- assert_eq!(state.workspaces[0].focused_pane_id(), Some(first_root));
+ assert_eq!(state.active, Some(1));
+ assert_eq!(state.workspaces[1].focused_pane_id(), Some(second_root));
+ state.assert_invariants_for_test();
+ }
+
+ #[test]
+ fn priority_sort_keeps_recently_changed_idle_agent_above_older_idle_agent() {
+ let mut workspace = Workspace::test_new("one");
+ let first = workspace.tabs[0].root_pane;
+ let second = workspace.test_split(Direction::Horizontal);
+ workspace.tabs[0].layout.focus_pane(first);
+
+ let mut state = AppState::test_new();
+ state.workspaces = vec![workspace];
+ state.ensure_test_terminals();
+ state.active = Some(0);
+ state.selected = 0;
+ state.mode = Mode::Terminal;
+ state.agent_panel_sort = crate::app::state::AgentPanelSort::Priority;
+
+ transition_agent_state(&mut state, first, AgentState::Idle);
+ transition_agent_state(&mut state, second, AgentState::Working);
+ assert_eq!(crate::ui::agent_panel_entries(&state)[0].pane_id, second);
+
+ transition_agent_state(&mut state, second, AgentState::Idle);
+
+ assert_eq!(crate::ui::agent_panel_entries(&state)[0].pane_id, second);
state.assert_invariants_for_test();
}
@@ -3668,7 +3708,6 @@ mod tests {
state.active = Some(0);
state.selected = 0;
state.mode = Mode::Terminal;
- state.agent_panel_scope = crate::app::state::AgentPanelScope::CurrentWorkspace;
for tab_idx in 0..state.workspaces[0].tabs.len() {
let pane_id = state.workspaces[0].tabs[tab_idx].root_pane;
mark_agent(&mut state, 0, tab_idx, pane_id);