mirror of
https://github.com/zed-industries/zed.git
synced 2026-10-19 11:04:06 +00:00
Add disable_ai check for "Agent Panel" MenuItem (#63580)
# Objective - Removes Agent Panel menu item when AI disabled toggle is on. - Fixes #63497 ## Solution - Use the global DisableAiSettings - disable_ai check in `app_menus.rs`. To keep the order the same I 1. Check the disable AI setting 2. If true push to the `view_items` vec![] 3. Extend the vec![] with the remaining Menu Items and Separators. ## Testing This can be tested visually: 1. Open Zed with AI settings enabled 2. Click View when Zed is focused 3. Noting where Agent Panel is on the list and to make sure clicking it opens up the Agent Panel. 4. Open settings 5. Navigate to AI settings 6. Toggle disable AI on 7. Click View Expected: Agent Panel is gone from the menu. The opposite is also expected. - This was tested on macOS 26.6.2 (25G83). ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [] Tests cover the new/changed behavior To keep this PR simple, I did not add any testing to this, as there were no tests in this file already. - [x] Performance impact has been considered and is acceptable ## Showcase <details> <summary>Click to view showcase</summary> https://github.com/user-attachments/assets/50db44ac-6c11-4101-a064-fd4e3b285620 </details> --- Release Notes: - Fixed Agent Panel appearing in the "View" menu when disable AI settings is on. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
parent
c91e24a971
commit
c8c07aea5c
6 changed files with 414 additions and 19 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -18587,6 +18587,7 @@ dependencies = [
|
|||
"smallvec",
|
||||
"telemetry",
|
||||
"theme",
|
||||
"theme_settings",
|
||||
"ui",
|
||||
"util",
|
||||
"workspace",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::NoopTextSystem;
|
|||
use crate::PathPromptOptions;
|
||||
use crate::{
|
||||
AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DevicePixels,
|
||||
DummyKeyboardMapper, ForegroundExecutor, Keymap, Platform, PlatformDisplay,
|
||||
DummyKeyboardMapper, ForegroundExecutor, Keymap, OwnedMenu, Platform, PlatformDisplay,
|
||||
PlatformHeadlessRenderer, PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem,
|
||||
PromptButton, ScreenCaptureFrame, ScreenCaptureSource, ScreenCaptureStream, SharedString,
|
||||
SourceMetadata, SystemNotification, SystemNotificationResponse, Task, TestDisplay, TestWindow,
|
||||
|
|
@ -45,6 +45,7 @@ pub(crate) struct TestPlatform {
|
|||
RefCell<Option<oneshot::Sender<(Option<PathBuf>, Vec<std::ffi::OsString>)>>>,
|
||||
headless_renderer_factory: Option<Box<dyn Fn() -> Option<Box<dyn PlatformHeadlessRenderer>>>>,
|
||||
weak: Weak<Self>,
|
||||
menus: RefCell<Vec<OwnedMenu>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -159,6 +160,7 @@ impl TestPlatform {
|
|||
system_notifications: Default::default(),
|
||||
text_system,
|
||||
headless_renderer_factory,
|
||||
menus: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -573,7 +575,14 @@ impl Platform for TestPlatform {
|
|||
self.system_notifications.borrow_mut().response_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn set_menus(&self, _menus: Vec<crate::Menu>, _keymap: &Keymap) {}
|
||||
fn set_menus(&self, menus: Vec<crate::Menu>, _keymap: &Keymap) {
|
||||
*self.menus.borrow_mut() = menus.into_iter().map(|menu| menu.owned()).collect()
|
||||
}
|
||||
|
||||
fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
|
||||
Some(self.menus.borrow().clone())
|
||||
}
|
||||
|
||||
fn set_dock_menu(&self, _menu: Vec<crate::MenuItem>, _keymap: &Keymap) {}
|
||||
|
||||
fn add_recent_document(&self, _paths: &Path) {}
|
||||
|
|
|
|||
|
|
@ -74,5 +74,6 @@ remote = { workspace = true, features = ["test-support"] }
|
|||
rpc = { workspace = true, features = ["test-support"] }
|
||||
semver.workspace = true
|
||||
settings = { workspace = true, features = ["test-support"] }
|
||||
theme_settings.workspace = true
|
||||
util = { workspace = true, features = ["test-support"] }
|
||||
workspace = { workspace = true, features = ["test-support"] }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use gpui::{Action, Entity, OwnedMenu, OwnedMenuItem, Subscription, actions};
|
||||
use project::DisableAiSettings;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use workspace::AccessibleMode;
|
||||
|
||||
|
|
@ -52,22 +53,42 @@ pub struct ApplicationMenu {
|
|||
impl ApplicationMenu {
|
||||
pub fn new(_: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let menus = cx.get_menus().unwrap_or_default();
|
||||
// Re-render when settings change so toggling "accessible mode" expands or
|
||||
// collapses the menu bar (see `all_menus_shown`).
|
||||
let settings_subscription = cx.observe_global::<SettingsStore>(|_, cx| cx.notify());
|
||||
|
||||
let entries = Self::build_entries(menus);
|
||||
let mut disable_ai = DisableAiSettings::get_global(cx).disable_ai;
|
||||
let settings_subscription =
|
||||
cx.observe_global::<SettingsStore>(move |application_menu, cx| {
|
||||
let new_disable_ai = DisableAiSettings::get_global(cx).disable_ai;
|
||||
if new_disable_ai != disable_ai {
|
||||
disable_ai = new_disable_ai;
|
||||
for entry in &application_menu.entries {
|
||||
if entry.handle.is_deployed() {
|
||||
entry.handle.hide(cx);
|
||||
}
|
||||
}
|
||||
let menus = cx.get_menus().unwrap_or_default();
|
||||
application_menu.entries = Self::build_entries(menus);
|
||||
}
|
||||
cx.notify();
|
||||
});
|
||||
|
||||
Self {
|
||||
entries: menus
|
||||
.into_iter()
|
||||
.map(|menu| MenuEntry {
|
||||
menu,
|
||||
handle: PopoverMenuHandle::default(),
|
||||
})
|
||||
.collect(),
|
||||
entries,
|
||||
pending_menu_open: None,
|
||||
_settings_subscription: settings_subscription,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_entries(menus: Vec<OwnedMenu>) -> SmallVec<[MenuEntry; 8]> {
|
||||
menus
|
||||
.into_iter()
|
||||
.map(|menu| MenuEntry {
|
||||
menu,
|
||||
handle: PopoverMenuHandle::default(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn sanitize_menu_items(items: Vec<OwnedMenuItem>) -> Vec<OwnedMenuItem> {
|
||||
let mut cleaned = Vec::new();
|
||||
let mut last_was_separator = false;
|
||||
|
|
@ -343,3 +364,200 @@ impl Render for ApplicationMenu {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{Action, Menu, MenuItem, OwnedMenu, OwnedMenuItem, TestAppContext, UpdateGlobal};
|
||||
use project::DisableAiSettings;
|
||||
use settings::{Settings, SettingsStore};
|
||||
|
||||
use crate::application_menu::{ApplicationMenu, MenuEntry, OpenApplicationMenu};
|
||||
|
||||
fn init_test(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
DisableAiSettings::register(cx);
|
||||
theme_settings::init(theme::LoadThemes::JustBase, cx);
|
||||
});
|
||||
}
|
||||
|
||||
fn owned_menu(name: &str, item_name: &str) -> OwnedMenu {
|
||||
OwnedMenu {
|
||||
name: name.into(),
|
||||
disabled: false,
|
||||
items: vec![OwnedMenuItem::Action {
|
||||
name: item_name.to_string(),
|
||||
action: OpenApplicationMenu(String::new()).boxed_clone(),
|
||||
os_action: None,
|
||||
checked: false,
|
||||
disabled: false,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
fn has_item(entries: &[MenuEntry], menu_name: &str, item_name: &str) -> bool {
|
||||
entries.iter().any(|entry| {
|
||||
entry.menu.name == menu_name
|
||||
&& entry.menu.items.iter().any(
|
||||
|item| matches!(item, OwnedMenuItem::Action { name, .. } if name == item_name),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn menu_entry<'a>(entries: &'a [MenuEntry], menu_name: &str) -> &'a MenuEntry {
|
||||
entries
|
||||
.iter()
|
||||
.find(|entry| entry.menu.name == menu_name)
|
||||
.expect("expected menu")
|
||||
}
|
||||
|
||||
fn view_menu(include_agent_panel: bool) -> Menu {
|
||||
let mut items = Vec::new();
|
||||
if include_agent_panel {
|
||||
items.push(MenuItem::action(
|
||||
"Agent Panel",
|
||||
OpenApplicationMenu(String::new()),
|
||||
));
|
||||
}
|
||||
items.push(MenuItem::action(
|
||||
"Diagnostics",
|
||||
OpenApplicationMenu(String::new()),
|
||||
));
|
||||
|
||||
Menu {
|
||||
name: "View".into(),
|
||||
items,
|
||||
disabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_entries_reflects_current_menu_data() {
|
||||
let with_agent_panel =
|
||||
ApplicationMenu::build_entries(vec![owned_menu("View", "Agent Panel")]);
|
||||
assert!(has_item(&with_agent_panel, "View", "Agent Panel"));
|
||||
|
||||
let without_agent_panel =
|
||||
ApplicationMenu::build_entries(vec![owned_menu("View", "Diagnostics")]);
|
||||
assert!(!has_item(&without_agent_panel, "View", "Agent Panel"));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_entries_refresh_on_settings_change(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.set_menus(vec![view_menu(true)]);
|
||||
});
|
||||
|
||||
let (app_menu, cx) = cx.add_window_view(|window, cx| ApplicationMenu::new(window, cx));
|
||||
let view_handle = cx.update(|window, cx| {
|
||||
let view_handle = app_menu.read_with(cx, |app_menu, _| {
|
||||
menu_entry(&app_menu.entries, "View").handle.clone()
|
||||
});
|
||||
view_handle.show(window, cx);
|
||||
view_handle
|
||||
});
|
||||
assert!(view_handle.is_deployed());
|
||||
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| has_item(
|
||||
&app_menu.entries,
|
||||
"View",
|
||||
"Agent Panel"
|
||||
)));
|
||||
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| has_item(
|
||||
&app_menu.entries,
|
||||
"View",
|
||||
"Diagnostics"
|
||||
)));
|
||||
|
||||
cx.update(|_, cx| {
|
||||
cx.set_menus(vec![view_menu(false)]);
|
||||
DisableAiSettings::override_global(DisableAiSettings { disable_ai: true }, cx);
|
||||
});
|
||||
|
||||
assert!(!view_handle.is_deployed());
|
||||
assert!(
|
||||
!app_menu.read_with(cx, |app_menu, _| has_item(
|
||||
&app_menu.entries,
|
||||
"View",
|
||||
"Agent Panel"
|
||||
)),
|
||||
"expected Agent Panel is not in the View menu"
|
||||
);
|
||||
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| has_item(
|
||||
&app_menu.entries,
|
||||
"View",
|
||||
"Diagnostics"
|
||||
)));
|
||||
|
||||
cx.update(|_, cx| {
|
||||
cx.set_menus(vec![view_menu(true)]);
|
||||
DisableAiSettings::override_global(DisableAiSettings { disable_ai: false }, cx);
|
||||
});
|
||||
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| has_item(
|
||||
&app_menu.entries,
|
||||
"View",
|
||||
"Agent Panel"
|
||||
)));
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| has_item(
|
||||
&app_menu.entries,
|
||||
"View",
|
||||
"Diagnostics"
|
||||
)));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_entries_preserve_deployed_menu_on_unrelated_settings_change(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.set_menus(vec![
|
||||
Menu::new("Zed").items([MenuItem::action(
|
||||
"Settings",
|
||||
OpenApplicationMenu(String::new()),
|
||||
)]),
|
||||
view_menu(true),
|
||||
]);
|
||||
});
|
||||
|
||||
let (app_menu, cx) = cx.add_window_view(|window, cx| ApplicationMenu::new(window, cx));
|
||||
|
||||
let zed_handle = cx.update(|window, cx| {
|
||||
let zed_handle = app_menu.read_with(cx, |app_menu, _| {
|
||||
menu_entry(&app_menu.entries, "Zed").handle.clone()
|
||||
});
|
||||
zed_handle.show(window, cx);
|
||||
zed_handle
|
||||
});
|
||||
cx.run_until_parked();
|
||||
assert!(zed_handle.is_deployed());
|
||||
|
||||
cx.update(|window, cx| {
|
||||
let view_handle = app_menu.read_with(cx, |app_menu, _| {
|
||||
menu_entry(&app_menu.entries, "View").handle.clone()
|
||||
});
|
||||
zed_handle.hide(cx);
|
||||
view_handle.show(window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
assert!(!zed_handle.is_deployed());
|
||||
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| {
|
||||
menu_entry(&app_menu.entries, "View").handle.is_deployed()
|
||||
}));
|
||||
|
||||
cx.update(|_, cx| {
|
||||
SettingsStore::update_global(cx, |_, _| {});
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
assert!(app_menu.read_with(cx, |app_menu, _| {
|
||||
menu_entry(&app_menu.entries, "View").handle.is_deployed()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2143,6 +2143,10 @@ pub fn handle_keymap_file_changes(
|
|||
let new_helix_enabled = vim_mode_setting::HelixModeSetting::get_global(cx).0;
|
||||
let new_disable_ai = DisableAiSettings::get_global(cx).disable_ai;
|
||||
|
||||
if new_disable_ai != old_disable_ai {
|
||||
reload_menus(cx);
|
||||
}
|
||||
|
||||
if new_base_keymap != old_base_keymap
|
||||
|| new_vim_enabled != old_vim_enabled
|
||||
|| new_helix_enabled != old_helix_enabled
|
||||
|
|
@ -2313,6 +2317,11 @@ fn show_markdown_app_notification<F>(
|
|||
})
|
||||
}
|
||||
|
||||
fn reload_menus(cx: &mut App) {
|
||||
let menus = app_menus(cx);
|
||||
cx.set_menus(menus);
|
||||
}
|
||||
|
||||
fn reload_keymaps(cx: &mut App, mut user_key_bindings: Vec<KeyBinding>) {
|
||||
cx.clear_key_bindings();
|
||||
load_default_keymap(cx);
|
||||
|
|
@ -2321,9 +2330,7 @@ fn reload_keymaps(cx: &mut App, mut user_key_bindings: Vec<KeyBinding>) {
|
|||
key_binding.set_meta(KeybindSource::User.meta());
|
||||
}
|
||||
cx.bind_keys(filter_disabled_ai_bindings(user_key_bindings, cx));
|
||||
|
||||
let menus = app_menus(cx);
|
||||
cx.set_menus(menus);
|
||||
reload_menus(cx);
|
||||
// On Windows, this is set in the `update_jump_list` method of the `HistoryManager`.
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
cx.set_dock_menu(vec![gpui::MenuItem::action(
|
||||
|
|
@ -2865,8 +2872,8 @@ mod tests {
|
|||
use extension::ExtensionHostProxy;
|
||||
use fs::FakeFs;
|
||||
use gpui::{
|
||||
Action, AnyWindowHandle, App, AssetSource, BorrowAppContext, Modifiers, TestAppContext,
|
||||
UpdateGlobal, VisualTestContext, WindowHandle, actions, point, px,
|
||||
Action, AnyWindowHandle, App, AssetSource, BorrowAppContext, Modifiers, OwnedMenuItem,
|
||||
TestAppContext, UpdateGlobal, VisualTestContext, WindowHandle, actions, point, px,
|
||||
};
|
||||
use http_client::BlockedHttpClient;
|
||||
use language::LanguageRegistry;
|
||||
|
|
@ -8146,4 +8153,155 @@ mod tests {
|
|||
|
||||
window
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_reload_keymaps_rebuilds_menus(cx: &mut TestAppContext) {
|
||||
init_keymap_test(cx);
|
||||
|
||||
cx.update(|cx| reload_keymaps(cx, Vec::new()));
|
||||
cx.update(|cx| {
|
||||
assert!(
|
||||
has_view_item(cx, "Agent Panel"),
|
||||
"expected Agent Panel in the View menu when AI is enabled"
|
||||
);
|
||||
assert!(
|
||||
has_view_item(cx, "Diagnostics"),
|
||||
"expected Diagnostics to be in View menu"
|
||||
);
|
||||
});
|
||||
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |settings_store, cx| {
|
||||
settings_store.update_user_settings(cx, |settings| {
|
||||
settings.project.disable_ai = Some(SaturatingBool(true))
|
||||
});
|
||||
})
|
||||
});
|
||||
cx.update(|cx| {
|
||||
reload_keymaps(cx, Vec::new());
|
||||
});
|
||||
cx.update(|cx| {
|
||||
assert!(
|
||||
!has_view_item(cx, "Agent Panel"),
|
||||
"expected Agent Panel to be removed from the View menu after disabling AI"
|
||||
);
|
||||
assert!(
|
||||
has_view_item(cx, "Diagnostics"),
|
||||
"expected Diagnostics to remain in the View menu"
|
||||
);
|
||||
});
|
||||
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |settings_store, cx| {
|
||||
settings_store.update_user_settings(cx, |settings| {
|
||||
settings.project.disable_ai = Some(SaturatingBool(false));
|
||||
});
|
||||
});
|
||||
});
|
||||
cx.update(|cx| reload_keymaps(cx, Vec::new()));
|
||||
cx.update(|cx| {
|
||||
assert!(
|
||||
has_view_item(cx, "Agent Panel"),
|
||||
"expected Agent Panel back in the View menu after re-enabling AI"
|
||||
);
|
||||
assert!(
|
||||
has_view_item(cx, "Diagnostics"),
|
||||
"expected Diagnostics to remain in the View menu"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_disable_ai_menu_update_with_malformed_keymap(cx: &mut TestAppContext) {
|
||||
let executor = cx.executor();
|
||||
let app_state = init_keymap_test(cx);
|
||||
cx.update(|cx| reload_keymaps(cx, Vec::new()));
|
||||
cx.update(|cx| {
|
||||
assert!(
|
||||
has_view_item(cx, "Agent Panel"),
|
||||
"expected Agent Panel before disabling AI"
|
||||
);
|
||||
assert!(
|
||||
has_view_item(cx, "Diagnostics"),
|
||||
"expected Diagnostics in the View menu"
|
||||
);
|
||||
});
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.save(
|
||||
"/keymap.json".as_ref(),
|
||||
&r#"!@!@this is not valid json"#.into(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.expect("failed to save malformed keymap.json to the fake fs");
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update(|cx| {
|
||||
let (keymap_rx, keymap_watcher) = watch_config_file(
|
||||
&executor,
|
||||
app_state.fs.clone(),
|
||||
PathBuf::from("/keymap.json"),
|
||||
);
|
||||
watch_settings_files(app_state.fs.clone(), cx);
|
||||
handle_keymap_file_changes(keymap_rx, keymap_watcher, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.save(
|
||||
paths::settings_file(),
|
||||
&r#"{"disable_ai": true}"#.into(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.expect("failed to save disable_ai=true to the fake settings file");
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update(|cx| {
|
||||
assert!(
|
||||
!has_view_item(cx, "Agent Panel"),
|
||||
"expected Agent Panel removed even though the keymap file is malformed"
|
||||
);
|
||||
assert!(
|
||||
has_view_item(cx, "Diagnostics"),
|
||||
"expected Diagnostics to remain in the View menu"
|
||||
);
|
||||
});
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.save(
|
||||
paths::settings_file(),
|
||||
&r#"{"disable_ai": false}"#.into(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.expect("failed to save disable_ai=false to the fake settings file");
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update(|cx| {
|
||||
assert!(
|
||||
has_view_item(cx, "Agent Panel"),
|
||||
"expected Agent Panel added back even though the keymap file is malformed"
|
||||
);
|
||||
assert!(
|
||||
has_view_item(cx, "Diagnostics"),
|
||||
"expected Diagnostics to remain in the View menu"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn has_view_item(cx: &mut App, item_name: &str) -> bool {
|
||||
cx.get_menus()
|
||||
.expect("reload_keymaps should populate the menu bar")
|
||||
.iter()
|
||||
.find(|menu| menu.name == "View")
|
||||
.expect("expected a View menu")
|
||||
.items
|
||||
.iter()
|
||||
.any(|item| matches!(item, OwnedMenuItem::Action { name, .. } if name == item_name))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use collab_ui::collab_panel;
|
||||
use gpui::{App, Menu, MenuItem, OsAction};
|
||||
use project::DisableAiSettings;
|
||||
use release_channel::ReleaseChannel;
|
||||
use settings::Settings;
|
||||
use terminal_view::terminal_panel;
|
||||
use zed_actions::{Quit, assistant, debug_panel, dev, git_panel, project_panel};
|
||||
|
||||
|
|
@ -43,12 +45,18 @@ pub fn app_menus(cx: &mut App) -> Vec<Menu> {
|
|||
MenuItem::action("Collab Panel", collab_panel::ToggleFocus),
|
||||
MenuItem::action("Terminal Panel", terminal_panel::Toggle),
|
||||
MenuItem::action("Debugger Panel", debug_panel::ToggleFocus),
|
||||
MenuItem::action("Agent Panel", assistant::ToggleFocus),
|
||||
];
|
||||
|
||||
if !DisableAiSettings::get_global(cx).disable_ai {
|
||||
view_items.push(MenuItem::action("Agent Panel", assistant::ToggleFocus));
|
||||
}
|
||||
|
||||
view_items.extend([
|
||||
MenuItem::action("Git Panel", git_panel::ToggleFocus),
|
||||
MenuItem::separator(),
|
||||
MenuItem::action("Diagnostics", diagnostics::Deploy),
|
||||
MenuItem::separator(),
|
||||
];
|
||||
]);
|
||||
|
||||
if ReleaseChannel::try_global(cx) == Some(ReleaseChannel::Dev) {
|
||||
view_items.push(MenuItem::action(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue