From 697e71d91b350c8a5413793b371a58a191dfa553 Mon Sep 17 00:00:00 2001 From: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> Date: Thu, 26 Feb 2026 00:01:59 +0100 Subject: [PATCH] multiworkspace: Disable sidebar if disable_ai is enabled (#50137) We don't want to show the sidebar to users if they have `disable_ai` enabled because it's an AI focused feature. In the future if we add non AI functionality to the sidebar we'll reenable it. Before you mark this PR as ready for review, make sure that you have: - [x] Added a solid test coverage and/or screenshots from doing manual testing - [x] Done a self-review taking into account security and performance aspects - [x] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - N/A --- Cargo.lock | 1 + crates/platform_title_bar/Cargo.toml | 1 + .../src/platform_title_bar.rs | 4 +- crates/title_bar/src/title_bar.rs | 6 +- crates/workspace/src/multi_workspace.rs | 128 ++++++++++++++++-- 5 files changed, 124 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a995f9c5c15ee1f5f2bfcdce20c144c2eb6a2fa8..a9aa6e2303ce4bf15ffe35b0a1a1948e0950d06a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12475,6 +12475,7 @@ version = "0.1.0" dependencies = [ "feature_flags", "gpui", + "project", "settings", "smallvec", "theme", diff --git a/crates/platform_title_bar/Cargo.toml b/crates/platform_title_bar/Cargo.toml index 2f1f6d2cd9297136077780aafdc75d22ecf6b845..43ad6166929bc463edbea878941ba19ffe2ea3a9 100644 --- a/crates/platform_title_bar/Cargo.toml +++ b/crates/platform_title_bar/Cargo.toml @@ -15,6 +15,7 @@ doctest = false [dependencies] feature_flags.workspace = true gpui.workspace = true +project.workspace = true settings.workspace = true smallvec.workspace = true theme.workspace = true diff --git a/crates/platform_title_bar/src/platform_title_bar.rs b/crates/platform_title_bar/src/platform_title_bar.rs index 6f89a5c39137896ee4b1a6cd3b81770fc3382284..7053fe89e7fdc6ece9ad50fdd8facaf31dba3086 100644 --- a/crates/platform_title_bar/src/platform_title_bar.rs +++ b/crates/platform_title_bar/src/platform_title_bar.rs @@ -7,6 +7,8 @@ use gpui::{ MouseButton, ParentElement, StatefulInteractiveElement, Styled, Window, WindowControlArea, div, px, }; +use project::DisableAiSettings; +use settings::Settings; use smallvec::SmallVec; use std::mem; use ui::{ @@ -95,7 +97,7 @@ impl PlatformTitleBar { } pub fn is_multi_workspace_enabled(cx: &App) -> bool { - cx.has_flag::() + cx.has_flag::() && !DisableAiSettings::get_global(cx).disable_ai } } diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index b52bde3fdb0b0230c271cc99210fdd13e7eac7cc..f00a71a305e306ba9201e5a4976382012ae0059e 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -31,7 +31,9 @@ use gpui::{ StatefulInteractiveElement, Styled, Subscription, WeakEntity, Window, actions, div, }; use onboarding_banner::OnboardingBanner; -use project::{Project, git_store::GitStoreEvent, trusted_worktrees::TrustedWorktrees}; +use project::{ + DisableAiSettings, Project, git_store::GitStoreEvent, trusted_worktrees::TrustedWorktrees, +}; use remote::RemoteConnectionOptions; use settings::Settings; use settings::WorktreeId; @@ -686,7 +688,7 @@ impl TitleBar { _window: &mut Window, cx: &mut Context, ) -> Option { - if !cx.has_flag::() { + if !cx.has_flag::() || DisableAiSettings::get_global(cx).disable_ai { return None; } diff --git a/crates/workspace/src/multi_workspace.rs b/crates/workspace/src/multi_workspace.rs index e5d529556be690298b57fbb864a7010729e8c170..b8651c38b1c6ce54455e0d134acd3777ad285ee4 100644 --- a/crates/workspace/src/multi_workspace.rs +++ b/crates/workspace/src/multi_workspace.rs @@ -5,7 +5,8 @@ use gpui::{ ManagedView, MouseButton, Pixels, Render, Subscription, Task, Tiling, Window, WindowId, actions, deferred, px, }; -use project::Project; +use project::{DisableAiSettings, Project}; +use settings::Settings; use std::future::Future; use std::path::PathBuf; use ui::prelude::*; @@ -122,6 +123,12 @@ impl MultiWorkspace { } }); let quit_subscription = cx.on_app_quit(Self::app_will_quit); + let settings_subscription = + cx.observe_global_in::(window, |this, window, cx| { + if DisableAiSettings::get_global(cx).disable_ai && this.sidebar_open { + this.close_sidebar(window, cx); + } + }); Self::subscribe_to_workspace(&workspace, cx); Self { window_id: window.window_handle().window_id(), @@ -133,7 +140,11 @@ impl MultiWorkspace { pending_removal_tasks: Vec::new(), _serialize_task: None, _create_task: None, - _subscriptions: vec![release_subscription, quit_subscription], + _subscriptions: vec![ + release_subscription, + quit_subscription, + settings_subscription, + ], } } @@ -169,7 +180,7 @@ impl MultiWorkspace { } pub fn multi_workspace_enabled(&self, cx: &App) -> bool { - cx.has_flag::() + cx.has_flag::() && !DisableAiSettings::get_global(cx).disable_ai } pub fn toggle_sidebar(&mut self, window: &mut Window, cx: &mut Context) { @@ -732,16 +743,18 @@ impl Render for MultiWorkspace { this.activate_previous_workspace(window, cx); }, )) - .on_action(cx.listener( - |this: &mut Self, _: &ToggleWorkspaceSidebar, window, cx| { - this.toggle_sidebar(window, cx); - }, - )) - .on_action( - cx.listener(|this: &mut Self, _: &FocusWorkspaceSidebar, window, cx| { - this.focus_sidebar(window, cx); - }), - ) + .when(self.multi_workspace_enabled(cx), |this| { + this.on_action(cx.listener( + |this: &mut Self, _: &ToggleWorkspaceSidebar, window, cx| { + this.toggle_sidebar(window, cx); + }, + )) + .on_action(cx.listener( + |this: &mut Self, _: &FocusWorkspaceSidebar, window, cx| { + this.focus_sidebar(window, cx); + }, + )) + }) .when( self.sidebar_open() && self.multi_workspace_enabled(cx), |this| { @@ -774,3 +787,92 @@ impl Render for MultiWorkspace { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use fs::FakeFs; + use gpui::TestAppContext; + use settings::SettingsStore; + + fn init_test(cx: &mut TestAppContext) { + cx.update(|cx| { + let settings_store = SettingsStore::test(cx); + cx.set_global(settings_store); + theme::init(theme::LoadThemes::JustBase, cx); + DisableAiSettings::register(cx); + cx.update_flags(false, vec!["agent-v2".into()]); + }); + } + + #[gpui::test] + async fn test_sidebar_disabled_when_disable_ai_is_enabled(cx: &mut TestAppContext) { + init_test(cx); + let fs = FakeFs::new(cx.executor()); + let project = Project::test(fs, [], cx).await; + + let (multi_workspace, cx) = + cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx)); + + multi_workspace.read_with(cx, |mw, cx| { + assert!(mw.multi_workspace_enabled(cx)); + }); + + multi_workspace.update_in(cx, |mw, _window, cx| { + mw.open_sidebar(cx); + assert!(mw.is_sidebar_open()); + }); + + cx.update(|_window, cx| { + DisableAiSettings::override_global(DisableAiSettings { disable_ai: true }, cx); + }); + cx.run_until_parked(); + + multi_workspace.read_with(cx, |mw, cx| { + assert!( + !mw.is_sidebar_open(), + "Sidebar should be closed when disable_ai is true" + ); + assert!( + !mw.multi_workspace_enabled(cx), + "Multi-workspace should be disabled when disable_ai is true" + ); + }); + + multi_workspace.update_in(cx, |mw, window, cx| { + mw.toggle_sidebar(window, cx); + }); + multi_workspace.read_with(cx, |mw, _cx| { + assert!( + !mw.is_sidebar_open(), + "Sidebar should remain closed when toggled with disable_ai true" + ); + }); + + cx.update(|_window, cx| { + DisableAiSettings::override_global(DisableAiSettings { disable_ai: false }, cx); + }); + cx.run_until_parked(); + + multi_workspace.read_with(cx, |mw, cx| { + assert!( + mw.multi_workspace_enabled(cx), + "Multi-workspace should be enabled after re-enabling AI" + ); + assert!( + !mw.is_sidebar_open(), + "Sidebar should still be closed after re-enabling AI (not auto-opened)" + ); + }); + + multi_workspace.update_in(cx, |mw, window, cx| { + mw.toggle_sidebar(window, cx); + }); + multi_workspace.read_with(cx, |mw, _cx| { + assert!( + mw.is_sidebar_open(), + "Sidebar should open when toggled after re-enabling AI" + ); + }); + } +}