edit predictions: Show user if current project is open source (#24587)

Danilo Leal and João Marcos created

Release Notes:

- N/A

---------

Co-authored-by: João Marcos <marcospb19@hotmail.com>

Change summary

crates/inline_completion/src/inline_completion.rs               | 20 
crates/inline_completion_button/src/inline_completion_button.rs | 55 ++
crates/ui/src/components/context_menu.rs                        |  6 
crates/zeta/src/zeta.rs                                         | 36 +
4 files changed, 86 insertions(+), 31 deletions(-)

Detailed changes

crates/inline_completion/src/inline_completion.rs 🔗

@@ -25,18 +25,30 @@ pub enum DataCollectionState {
     /// The provider doesn't support data collection.
     Unsupported,
     /// Data collection is enabled.
-    Enabled,
+    Enabled { is_project_open_source: bool },
     /// Data collection is disabled or unanswered.
-    Disabled,
+    Disabled { is_project_open_source: bool },
 }
 
 impl DataCollectionState {
     pub fn is_supported(&self) -> bool {
-        !matches!(self, DataCollectionState::Unsupported)
+        !matches!(self, DataCollectionState::Unsupported { .. })
     }
 
     pub fn is_enabled(&self) -> bool {
-        matches!(self, DataCollectionState::Enabled)
+        matches!(self, DataCollectionState::Enabled { .. })
+    }
+
+    pub fn is_project_open_source(&self) -> bool {
+        match self {
+            Self::Enabled {
+                is_project_open_source,
+            }
+            | Self::Disabled {
+                is_project_open_source,
+            } => *is_project_open_source,
+            _ => false,
+        }
     }
 }
 

crates/inline_completion_button/src/inline_completion_button.rs 🔗

@@ -456,17 +456,56 @@ impl InlineCompletionButton {
             if data_collection.is_supported() {
                 let provider = provider.clone();
                 let enabled = data_collection.is_enabled();
+                let is_open_source = data_collection.is_project_open_source();
+                let is_collecting = data_collection.is_enabled();
 
                 menu = menu.item(
-                    // TODO: We want to add something later that communicates whether
-                    // the current project is open-source.
                     ContextMenuEntry::new("Share Training Data")
                         .toggleable(IconPosition::Start, data_collection.is_enabled())
-                        .documentation_aside(|_| {
-                            Label::new(indoc!{"
-                                Help us improve our open model by sharing data from open source repositories. \
-                                Zed must detect a license file in your repo for this setting to take effect.\
-                            "}).into_any_element()
+                        .icon_color(if is_open_source && is_collecting {
+                            Color::Success
+                        } else {
+                            Color::Accent
+                        })
+                        .documentation_aside(move |cx| {
+                            let (msg, label_color, icon_name, icon_color) = match (is_open_source, is_collecting) {
+                                (true, true) => (
+                                    "Project identified as open-source, and you're sharing data.",
+                                    Color::Default,
+                                    IconName::Check,
+                                    Color::Success,
+                                ),
+                                (true, false) => (
+                                    "Project identified as open-source, but you're not sharing data.",
+                                    Color::Muted,
+                                    IconName::XCircle,
+                                    Color::Muted,
+                                ),
+                                (false, _) => (
+                                    "Project not identified as open-source. No data captured.",
+                                    Color::Muted,
+                                    IconName::XCircle,
+                                    Color::Muted,
+                                ),
+                            };
+                            v_flex()
+                                .gap_2()
+                                .child(
+                                    Label::new(indoc!{
+                                        "Help us improve our open model by sharing data from open source repositories. \
+                                        Zed must detect a license file in your repo for this setting to take effect."
+                                    })
+                                )
+                                .child(
+                                    h_flex()
+                                        .pt_2()
+                                        .gap_1p5()
+                                        .border_t_1()
+                                        .border_color(cx.theme().colors().border_variant)
+                                        .child(Icon::new(icon_name).size(IconSize::XSmall).color(icon_color))
+                                        .child(div().child(Label::new(msg).size(LabelSize::Small).color(label_color)))
+                                )
+                                .into_any_element()
                         })
                         .handler(move |_, cx| {
                             provider.toggle_data_collection(cx);
@@ -483,7 +522,7 @@ impl InlineCompletionButton {
                                 );
                             }
                         })
-                )
+                );
             }
         }
 

crates/ui/src/components/context_menu.rs 🔗

@@ -524,7 +524,7 @@ impl Render for ContextMenu {
                         .occlude()
                         .elevation_2(cx)
                         .p_2()
-                        .max_w_80()
+                        .max_w_96()
                         .child(aside(cx)),
                 )
             })
@@ -600,6 +600,8 @@ impl Render for ContextMenu {
                                             let menu = cx.entity().downgrade();
                                             let icon_color = if *disabled {
                                                 Color::Muted
+                                            } else if toggle.is_some() {
+                                                icon_color.unwrap_or(Color::Accent)
                                             } else {
                                                 icon_color.unwrap_or(Color::Default)
                                             };
@@ -674,7 +676,7 @@ impl Render for ContextMenu {
                                                                 let contents =
                                                                     div().flex_none().child(
                                                                         Icon::new(IconName::Check)
-                                                                            .color(Color::Accent)
+                                                                            .color(icon_color)
                                                                             .size(*icon_size)
                                                                     )
                                                                     .when(!toggled, |contents|

crates/zeta/src/zeta.rs 🔗

@@ -1024,7 +1024,7 @@ impl LicenseDetectionWatcher {
     }
 
     /// Answers false until we find out it's open source
-    pub fn is_open_source(&self) -> bool {
+    pub fn is_project_open_source(&self) -> bool {
         *self.is_open_source_rx.borrow()
     }
 }
@@ -1227,7 +1227,6 @@ impl ProviderDataCollection {
             let zeta = zeta.read(cx);
             let choice = zeta.data_collection_choice.clone();
 
-            // Unwrap safety: there should be a watcher for each worktree
             let license_detection_watcher = zeta
                 .license_detection_watchers
                 .get(&file.worktree_id(cx))
@@ -1249,20 +1248,20 @@ impl ProviderDataCollection {
         }
     }
 
-    pub fn user_data_collection_choice(&self, cx: &App) -> bool {
-        self.choice
-            .as_ref()
-            .map_or(false, |choice| choice.read(cx).is_enabled())
+    pub fn can_collect_data(&self, cx: &App) -> bool {
+        self.is_data_collection_enabled(cx) && self.is_project_open_source()
     }
 
-    pub fn can_collect_data(&self, cx: &App) -> bool {
+    pub fn is_data_collection_enabled(&self, cx: &App) -> bool {
         self.choice
             .as_ref()
             .is_some_and(|choice| choice.read(cx).is_enabled())
-            && self
-                .license_detection_watcher
-                .as_ref()
-                .is_some_and(|watcher| watcher.is_open_source())
+    }
+
+    fn is_project_open_source(&self) -> bool {
+        self.license_detection_watcher
+            .as_ref()
+            .is_some_and(|watcher| watcher.is_project_open_source())
     }
 
     pub fn toggle(&mut self, cx: &mut App) {
@@ -1326,13 +1325,16 @@ impl inline_completion::EditPredictionProvider for ZetaInlineCompletionProvider
     }
 
     fn data_collection_state(&self, cx: &App) -> DataCollectionState {
-        if self
-            .provider_data_collection
-            .user_data_collection_choice(cx)
-        {
-            DataCollectionState::Enabled
+        let is_project_open_source = self.provider_data_collection.is_project_open_source();
+
+        if self.provider_data_collection.is_data_collection_enabled(cx) {
+            DataCollectionState::Enabled {
+                is_project_open_source,
+            }
         } else {
-            DataCollectionState::Disabled
+            DataCollectionState::Disabled {
+                is_project_open_source,
+            }
         }
     }