Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion app/src/workspace/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5987,7 +5987,7 @@ impl Workspace {
/// Builds the unified new-session menu items
/// tab bar chevron and the vertical tab bar `+` button.
///
/// Order: Agent → Terminal (sidecar) → Cloud Oz → [tab configs] → separator → New worktree config (sidecar) → New tab config.
/// Order: Agent → Terminal (sidecar) → Cloud Oz → [tab configs] → separator → New worktree config (sidecar) → New tab config → separator → Reopen closed session.
fn unified_new_session_menu_items(
&self,
ctx: &mut ViewContext<Self>,
Expand All @@ -5999,6 +5999,8 @@ impl Workspace {
let effective_default = ai_settings.default_session_mode(ctx);
let default_tab_config_path = ai_settings.default_tab_config_path().to_string();
let shortcut_label = keybinding_name_to_display_string(NEW_TAB_BINDING_NAME, ctx);
let reopen_closed_session_shortcut_label =
keybinding_name_to_display_string("app:reopen_closed_session", ctx);

// 1. Agent (if AI enabled)
if is_any_ai_enabled {
Expand Down Expand Up @@ -6159,6 +6161,15 @@ impl Workspace {
);
}

menu_items.push(MenuItem::Separator);
menu_items.push(
MenuItemFields::new("Reopen closed session")
.with_on_select_action(WorkspaceAction::ReopenClosedSession)
.with_key_shortcut_label(reopen_closed_session_shortcut_label)
.with_disabled(UndoCloseStack::handle(ctx).as_ref(ctx).is_empty())
.into_item(),
);

menu_items
}

Expand Down
40 changes: 40 additions & 0 deletions app/src/workspace/view_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,15 @@ fn new_session_menu_label(item: &MenuItem<WorkspaceAction>) -> String {
}
}

fn reopen_closed_session_menu_item(
menu_items: &[MenuItem<WorkspaceAction>],
) -> &MenuItemFields<WorkspaceAction> {
match menu_items.last() {
Some(MenuItem::Item(fields)) if fields.label() == "Reopen closed session" => fields,
_ => panic!("expected Reopen closed session to be the last new-session menu item"),
}
}

#[test]
fn test_reward_modal_no_overlap() {
App::test((), |mut app| async move {
Expand Down Expand Up @@ -2575,6 +2584,37 @@ fn test_unified_new_session_menu_uses_new_worktree_config_label_and_order() {
});
}

#[test]
fn test_unified_new_session_menu_includes_reopen_closed_session() {
App::test((), |mut app| async move {
initialize_app(&mut app);

let workspace = mock_workspace(&mut app);

workspace.update(&mut app, |workspace, ctx| {
let menu_items = workspace.unified_new_session_menu_items(ctx);
assert!(matches!(
menu_items.get(menu_items.len() - 2),
Some(MenuItem::Separator)
));

let reopen_item = reopen_closed_session_menu_item(&menu_items);
assert!(reopen_item.is_disabled());
assert!(matches!(
reopen_item.on_select_action(),
Some(action) if matches!(action, WorkspaceAction::ReopenClosedSession)
));

workspace.add_terminal_tab(false, ctx);
workspace.remove_tab(workspace.active_tab_index(), true, true, ctx);

let menu_items = workspace.unified_new_session_menu_items(ctx);
let reopen_item = reopen_closed_session_menu_item(&menu_items);
assert!(!reopen_item.is_disabled());
});
});
}

#[cfg(feature = "local_fs")]
#[test]
fn test_worktree_sidecar_search_editor_proxies_navigation_and_escape() {
Expand Down
Loading