From 0148c1379b76c5c0a9d05588c07dcb06ec32f93f Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Fri, 22 May 2026 02:21:12 +0300 Subject: feat: add git worktree workspace management refs #137 --- src/app/api/panes.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/app/api/workspaces.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) (limited to 'src/app/api') diff --git a/src/app/api/panes.rs b/src/app/api/panes.rs index b09ecb2a..2b1741d9 100644 --- a/src/app/api/panes.rs +++ b/src/app/api/panes.rs @@ -351,3 +351,48 @@ fn pane_not_found(id: String, pane_id: &str) -> String { fn invalid_agent(id: String) -> String { encode_error(id, "invalid_agent", "agent label must not be empty") } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{api::schema::SuccessResponse, config::Config, workspace::Workspace}; + + fn app_with_linked_worktree() -> App { + let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); + let mut app = App::new( + &Config::default(), + true, + None, + api_rx, + crate::api::EventHub::default(), + ); + app.state.workspaces = vec![Workspace::test_new("issue")]; + app.state.workspaces[0].worktree_space = Some(crate::workspace::WorktreeSpaceMembership { + key: "repo-key".into(), + label: "herdr".into(), + repo_root: "/repo/herdr".into(), + checkout_path: "/repo/herdr-issue".into(), + is_linked_worktree: true, + }); + app + } + + #[test] + fn api_pane_close_closes_linked_worktree_workspace_only() { + let mut app = app_with_linked_worktree(); + let pane_id = app.state.workspaces[0].tabs[0].root_pane; + let public_pane_id = app.public_pane_id(0, pane_id).unwrap(); + + let response = app.handle_pane_close( + "req".into(), + PaneTarget { + pane_id: public_pane_id, + }, + ); + + let success: SuccessResponse = serde_json::from_str(&response).unwrap(); + assert_eq!(success.id, "req"); + assert_eq!(app.state.request_remove_linked_worktree, None); + assert!(app.state.workspaces.is_empty()); + } +} diff --git a/src/app/api/workspaces.rs b/src/app/api/workspaces.rs index 2f8c1a28..f5e9a563 100644 --- a/src/app/api/workspaces.rs +++ b/src/app/api/workspaces.rs @@ -166,3 +166,46 @@ fn workspace_not_found(id: String, workspace_id: &str) -> String { format!("workspace {workspace_id} not found"), ) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{api::schema::SuccessResponse, config::Config, workspace::Workspace}; + + fn app_with_linked_worktree() -> App { + let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); + let mut app = App::new( + &Config::default(), + true, + None, + api_rx, + crate::api::EventHub::default(), + ); + app.state.workspaces = vec![Workspace::test_new("issue")]; + app.state.workspaces[0].worktree_space = Some(crate::workspace::WorktreeSpaceMembership { + key: "repo-key".into(), + label: "herdr".into(), + repo_root: "/repo/herdr".into(), + checkout_path: "/repo/herdr-issue".into(), + is_linked_worktree: true, + }); + app + } + + #[test] + fn api_workspace_close_closes_linked_worktree_workspace_only() { + let mut app = app_with_linked_worktree(); + + let response = app.handle_workspace_close( + "req".into(), + WorkspaceTarget { + workspace_id: app.state.workspaces[0].id.clone(), + }, + ); + + let success: SuccessResponse = serde_json::from_str(&response).unwrap(); + assert_eq!(success.id, "req"); + assert_eq!(app.state.request_remove_linked_worktree, None); + assert!(app.state.workspaces.is_empty()); + } +} -- cgit v1.2.3