fix: preserve workspace when closing the last pane in a tab
This commit is contained in:
parent
a763406db2
commit
08eccb89d2
|
|
@ -1876,18 +1876,20 @@ impl App {
|
|||
.unwrap();
|
||||
};
|
||||
let workspace_id = self.state.workspaces[ws_idx].id.clone();
|
||||
let Some(ws) = self.state.workspaces.get_mut(ws_idx) else {
|
||||
return serde_json::to_string(&ErrorResponse {
|
||||
id: request.id,
|
||||
error: ErrorBody {
|
||||
code: "pane_not_found".into(),
|
||||
message: format!("pane {} not found", target.pane_id),
|
||||
},
|
||||
})
|
||||
.unwrap();
|
||||
let should_close_workspace = {
|
||||
let Some(ws) = self.state.workspaces.get_mut(ws_idx) else {
|
||||
return serde_json::to_string(&ErrorResponse {
|
||||
id: request.id,
|
||||
error: ErrorBody {
|
||||
code: "pane_not_found".into(),
|
||||
message: format!("pane {} not found", target.pane_id),
|
||||
},
|
||||
})
|
||||
.unwrap();
|
||||
};
|
||||
ws.close_pane(pane_id)
|
||||
};
|
||||
let pane_count = ws.layout.pane_count();
|
||||
if pane_count <= 1 {
|
||||
if should_close_workspace {
|
||||
self.state.selected = ws_idx;
|
||||
self.state.close_selected_workspace();
|
||||
self.emit_event(crate::api::schema::EventEnvelope {
|
||||
|
|
@ -1902,7 +1904,6 @@ impl App {
|
|||
data: crate::api::schema::EventData::WorkspaceClosed { workspace_id },
|
||||
});
|
||||
} else {
|
||||
ws.close_pane(pane_id);
|
||||
self.schedule_session_save();
|
||||
self.emit_event(crate::api::schema::EventEnvelope {
|
||||
event: crate::api::schema::EventKind::PaneClosed,
|
||||
|
|
@ -2794,6 +2795,56 @@ mod tests {
|
|||
assert_eq!(seed_cwd, std::path::PathBuf::from("/tmp/pion"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_close_request_closes_only_the_target_tab_when_other_tabs_exist() {
|
||||
let mut app = test_app();
|
||||
let mut workspace = Workspace::test_new("api-pane-close");
|
||||
let second_tab = workspace.test_add_tab(Some("logs"));
|
||||
workspace.switch_tab(second_tab);
|
||||
app.state.workspaces = vec![workspace];
|
||||
app.state.active = Some(0);
|
||||
app.state.selected = 0;
|
||||
|
||||
let target_pane = app.state.workspaces[0].tabs[second_tab].root_pane;
|
||||
let target_pane_id = app.pane_info(0, target_pane).unwrap().pane_id;
|
||||
|
||||
let response = app.handle_api_request(crate::api::schema::Request {
|
||||
id: "req_pane_close".into(),
|
||||
method: crate::api::schema::Method::PaneClose(crate::api::schema::PaneTarget {
|
||||
pane_id: target_pane_id,
|
||||
}),
|
||||
});
|
||||
let response: serde_json::Value = serde_json::from_str(&response).unwrap();
|
||||
|
||||
assert_eq!(response["result"]["type"], "ok");
|
||||
assert_eq!(app.state.workspaces.len(), 1);
|
||||
assert_eq!(app.state.workspaces[0].tabs.len(), 1);
|
||||
assert_eq!(app.state.workspaces[0].display_name(), "api-pane-close");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_close_request_closes_workspace_when_it_removes_the_last_pane() {
|
||||
let mut app = test_app();
|
||||
let workspace = Workspace::test_new("api-pane-close-last");
|
||||
app.state.workspaces = vec![workspace];
|
||||
app.state.active = Some(0);
|
||||
app.state.selected = 0;
|
||||
|
||||
let target_pane = app.state.workspaces[0].tabs[0].root_pane;
|
||||
let target_pane_id = app.pane_info(0, target_pane).unwrap().pane_id;
|
||||
|
||||
let response = app.handle_api_request(crate::api::schema::Request {
|
||||
id: "req_pane_close_last".into(),
|
||||
method: crate::api::schema::Method::PaneClose(crate::api::schema::PaneTarget {
|
||||
pane_id: target_pane_id,
|
||||
}),
|
||||
});
|
||||
let response: serde_json::Value = serde_json::from_str(&response).unwrap();
|
||||
|
||||
assert_eq!(response["result"]["type"], "ok");
|
||||
assert!(app.state.workspaces.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn session_dirty_flag_schedules_debounced_save() {
|
||||
let mut app = test_app();
|
||||
|
|
|
|||
|
|
@ -356,6 +356,91 @@ fn tab_management_commands_work() {
|
|||
cleanup_spawned_herdr(herdr, base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_close_only_removes_the_target_tab_when_other_tabs_exist() {
|
||||
let base = unique_test_dir();
|
||||
let config_home = base.join("config");
|
||||
let runtime_dir = base.join("runtime");
|
||||
let socket_path = runtime_dir.join("herdr.sock");
|
||||
|
||||
let herdr = spawn_herdr(&config_home, &runtime_dir, &socket_path);
|
||||
wait_for_socket(&socket_path, Duration::from_secs(5));
|
||||
|
||||
let created = run_cli(
|
||||
&socket_path,
|
||||
&["workspace", "create", "--cwd", base.to_str().unwrap()],
|
||||
);
|
||||
assert!(created.status.success());
|
||||
let created_json: serde_json::Value = serde_json::from_slice(&created.stdout).unwrap();
|
||||
let workspace_id = created_json["result"]["workspace"]["workspace_id"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let created_tab = run_cli(
|
||||
&socket_path,
|
||||
&["tab", "create", "--workspace", &workspace_id],
|
||||
);
|
||||
assert!(created_tab.status.success());
|
||||
let created_tab_json: serde_json::Value = serde_json::from_slice(&created_tab.stdout).unwrap();
|
||||
let second_root_pane_id = created_tab_json["result"]["root_pane"]["pane_id"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let closed = run_cli(&socket_path, &["pane", "close", &second_root_pane_id]);
|
||||
assert!(closed.status.success());
|
||||
let closed_json: serde_json::Value = serde_json::from_slice(&closed.stdout).unwrap();
|
||||
assert_eq!(closed_json["result"]["type"], "ok");
|
||||
|
||||
let workspaces = run_cli(&socket_path, &["workspace", "list"]);
|
||||
assert!(workspaces.status.success());
|
||||
let workspaces_json: serde_json::Value = serde_json::from_slice(&workspaces.stdout).unwrap();
|
||||
assert_eq!(workspaces_json["result"]["workspaces"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(workspaces_json["result"]["workspaces"][0]["workspace_id"], workspace_id);
|
||||
|
||||
let tabs = run_cli(&socket_path, &["tab", "list", "--workspace", &workspace_id]);
|
||||
assert!(tabs.status.success());
|
||||
let tabs_json: serde_json::Value = serde_json::from_slice(&tabs.stdout).unwrap();
|
||||
assert_eq!(tabs_json["result"]["tabs"].as_array().unwrap().len(), 1);
|
||||
|
||||
cleanup_spawned_herdr(herdr, base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_close_removes_the_workspace_when_it_closes_the_last_pane() {
|
||||
let base = unique_test_dir();
|
||||
let config_home = base.join("config");
|
||||
let runtime_dir = base.join("runtime");
|
||||
let socket_path = runtime_dir.join("herdr.sock");
|
||||
|
||||
let herdr = spawn_herdr(&config_home, &runtime_dir, &socket_path);
|
||||
wait_for_socket(&socket_path, Duration::from_secs(5));
|
||||
|
||||
let created = run_cli(
|
||||
&socket_path,
|
||||
&["workspace", "create", "--cwd", base.to_str().unwrap()],
|
||||
);
|
||||
assert!(created.status.success());
|
||||
let created_json: serde_json::Value = serde_json::from_slice(&created.stdout).unwrap();
|
||||
let root_pane_id = created_json["result"]["root_pane"]["pane_id"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
let closed = run_cli(&socket_path, &["pane", "close", &root_pane_id]);
|
||||
assert!(closed.status.success());
|
||||
let closed_json: serde_json::Value = serde_json::from_slice(&closed.stdout).unwrap();
|
||||
assert_eq!(closed_json["result"]["type"], "ok");
|
||||
|
||||
let workspaces = run_cli(&socket_path, &["workspace", "list"]);
|
||||
assert!(workspaces.status.success());
|
||||
let workspaces_json: serde_json::Value = serde_json::from_slice(&workspaces.stdout).unwrap();
|
||||
assert!(workspaces_json["result"]["workspaces"].as_array().unwrap().is_empty());
|
||||
|
||||
cleanup_spawned_herdr(herdr, base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_run_read_and_wait_commands_work() {
|
||||
let base = unique_test_dir();
|
||||
|
|
|
|||
Loading…
Reference in New Issue