From eb76db4050b411829276ddaf52a886c466457d3c Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 10 Apr 2026 13:27:04 -0400 Subject: [PATCH] edit_prediction: Disable training data collection based on organization configuration (#53639) This PR makes it so we disable training data collection for Edit Prediction based on the organization's configuration. Closes CLO-641. Release Notes: - N/A --- .../src/zed_edit_prediction_delegate.rs | 42 +++++++++++++++++++ .../src/edit_prediction_types.rs | 9 ++++ .../src/edit_prediction_button.rs | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/crates/edit_prediction/src/zed_edit_prediction_delegate.rs b/crates/edit_prediction/src/zed_edit_prediction_delegate.rs index 1a574e9389715ce888f8b8c5ec8be921ceab4a38..f0fa37c4d6f1a97aa4b1b96b3a6885ed60cc801a 100644 --- a/crates/edit_prediction/src/zed_edit_prediction_delegate.rs +++ b/crates/edit_prediction/src/zed_edit_prediction_delegate.rs @@ -6,6 +6,7 @@ use edit_prediction_types::{ DataCollectionState, EditPredictionDelegate, EditPredictionDiscardReason, EditPredictionIconSet, SuggestionDisplayType, }; +use feature_flags::FeatureFlagAppExt; use gpui::{App, Entity, prelude::*}; use language::{Buffer, ToPoint as _}; use project::Project; @@ -73,6 +74,24 @@ impl EditPredictionDelegate for ZedEditPredictionDelegate { self.store .read(cx) .is_file_open_source(&self.project, file, cx); + + if let Some(organization_configuration) = self + .store + .read(cx) + .user_store + .read(cx) + .current_organization_configuration() + { + if !organization_configuration + .edit_prediction + .is_feedback_enabled + { + return DataCollectionState::Disabled { + is_project_open_source, + }; + } + } + if self.store.read(cx).data_collection_choice.is_enabled(cx) { DataCollectionState::Enabled { is_project_open_source, @@ -89,6 +108,29 @@ impl EditPredictionDelegate for ZedEditPredictionDelegate { } } + fn can_toggle_data_collection(&self, cx: &App) -> bool { + if cx.is_staff() { + return false; + } + + if let Some(organization_configuration) = self + .store + .read(cx) + .user_store + .read(cx) + .current_organization_configuration() + { + if !organization_configuration + .edit_prediction + .is_feedback_enabled + { + return false; + } + } + + true + } + fn toggle_data_collection(&mut self, cx: &mut App) { self.store.update(cx, |store, cx| { store.toggle_data_collection_choice(cx); diff --git a/crates/edit_prediction_types/src/edit_prediction_types.rs b/crates/edit_prediction_types/src/edit_prediction_types.rs index eb4b7b2292e907dc5d630873dbb4d1abb9edbeb5..31caf628544ade8709553e4255dc6d5f2e6a8f00 100644 --- a/crates/edit_prediction_types/src/edit_prediction_types.rs +++ b/crates/edit_prediction_types/src/edit_prediction_types.rs @@ -168,6 +168,10 @@ pub trait EditPredictionDelegate: 'static + Sized { None } + fn can_toggle_data_collection(&self, _cx: &App) -> bool { + true + } + fn toggle_data_collection(&mut self, _cx: &mut App) {} fn is_enabled( &self, @@ -209,6 +213,7 @@ pub trait EditPredictionDelegateHandle { fn icons(&self, cx: &App) -> EditPredictionIconSet; fn data_collection_state(&self, cx: &App) -> DataCollectionState; fn usage(&self, cx: &App) -> Option; + fn can_toggle_data_collection(&self, cx: &App) -> bool; fn toggle_data_collection(&self, cx: &mut App); fn is_refreshing(&self, cx: &App) -> bool; fn refresh( @@ -265,6 +270,10 @@ where self.read(cx).usage(cx) } + fn can_toggle_data_collection(&self, cx: &App) -> bool { + self.read(cx).can_toggle_data_collection(cx) + } + fn toggle_data_collection(&self, cx: &mut App) { self.update(cx, |this, cx| this.toggle_data_collection(cx)) } diff --git a/crates/edit_prediction_ui/src/edit_prediction_button.rs b/crates/edit_prediction_ui/src/edit_prediction_button.rs index e7aff1271f0505d9c87899cc8b555e377ca3fbd0..bf915409480f1ab56ef7b2c002c467c02c1095d3 100644 --- a/crates/edit_prediction_ui/src/edit_prediction_button.rs +++ b/crates/edit_prediction_ui/src/edit_prediction_button.rs @@ -790,7 +790,7 @@ impl EditPredictionButton { .toggleable(IconPosition::Start, data_collection.is_enabled()) .icon(icon_name) .icon_color(icon_color) - .disabled(cx.is_staff()) + .disabled(!provider.can_toggle_data_collection(cx)) .documentation_aside(DocumentationSide::Left, move |cx| { let (msg, label_color, icon_name, icon_color) = match (is_open_source, is_collecting) { (true, true) => (