Allow telemetry::event! with no properties (#22190)

Conrad Irwin created

CC @josephTLyons

Release Notes:

- N/A

Change summary

Cargo.lock                                            |   1 
crates/extensions_ui/Cargo.toml                       |   1 
crates/extensions_ui/src/components/feature_upsell.rs |  16 -
crates/extensions_ui/src/extensions_ui.rs             | 107 ++++--------
crates/telemetry/src/telemetry.rs                     |   7 
5 files changed, 54 insertions(+), 78 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -4412,6 +4412,7 @@ dependencies = [
  "serde",
  "settings",
  "smallvec",
+ "telemetry",
  "theme",
  "ui",
  "util",

crates/extensions_ui/Cargo.toml 🔗

@@ -30,6 +30,7 @@ semantic_version.workspace = true
 serde.workspace = true
 settings.workspace = true
 smallvec.workspace = true
+telemetry.workspace = true
 theme.workspace = true
 ui.workspace = true
 util.workspace = true

crates/extensions_ui/src/components/feature_upsell.rs 🔗

@@ -1,6 +1,3 @@
-use std::sync::Arc;
-
-use client::telemetry::Telemetry;
 use gpui::{AnyElement, Div, StyleRefinement};
 use smallvec::SmallVec;
 use ui::{prelude::*, ButtonLike};
@@ -8,17 +5,15 @@ use ui::{prelude::*, ButtonLike};
 #[derive(IntoElement)]
 pub struct FeatureUpsell {
     base: Div,
-    telemetry: Arc<Telemetry>,
     text: SharedString,
     docs_url: Option<SharedString>,
     children: SmallVec<[AnyElement; 2]>,
 }
 
 impl FeatureUpsell {
-    pub fn new(telemetry: Arc<Telemetry>, text: impl Into<SharedString>) -> Self {
+    pub fn new(text: impl Into<SharedString>) -> Self {
         Self {
             base: h_flex(),
-            telemetry,
             text: text.into(),
             docs_url: None,
             children: SmallVec::new(),
@@ -67,12 +62,13 @@ impl RenderOnce for FeatureUpsell {
                                     .child(Icon::new(IconName::ArrowUpRight)),
                             )
                             .on_click({
-                                let telemetry = self.telemetry.clone();
                                 let docs_url = docs_url.clone();
                                 move |_event, cx| {
-                                    telemetry.report_app_event(format!(
-                                        "feature upsell: viewed docs ({docs_url})"
-                                    ));
+                                    telemetry::event!(
+                                        "Documentation Viewed",
+                                        source = "Feature Upsell",
+                                        url = docs_url,
+                                    );
                                     cx.open_url(&docs_url)
                                 }
                             }),

crates/extensions_ui/src/extensions_ui.rs 🔗

@@ -7,7 +7,6 @@ use std::sync::OnceLock;
 use std::time::Duration;
 use std::{ops::Range, sync::Arc};
 
-use client::telemetry::Telemetry;
 use client::ExtensionMetadata;
 use collections::{BTreeMap, BTreeSet};
 use editor::{Editor, EditorElement, EditorStyle};
@@ -182,7 +181,6 @@ fn keywords_by_feature() -> &'static BTreeMap<Feature, Vec<&'static str>> {
 pub struct ExtensionsPage {
     workspace: WeakView<Workspace>,
     list: UniformListScrollHandle,
-    telemetry: Arc<Telemetry>,
     is_fetching_extensions: bool,
     filter: ExtensionFilter,
     remote_extension_entries: Vec<ExtensionMetadata>,
@@ -221,7 +219,6 @@ impl ExtensionsPage {
             let mut this = Self {
                 workspace: workspace.weak_handle(),
                 list: UniformListScrollHandle::new(),
-                telemetry: workspace.client().telemetry().clone(),
                 is_fetching_extensions: false,
                 filter: ExtensionFilter::All,
                 dev_extension_entries: Vec::new(),
@@ -704,18 +701,15 @@ impl ExtensionsPage {
 
         match status.clone() {
             ExtensionStatus::NotInstalled => (
-                Button::new(SharedString::from(extension.id.clone()), "Install").on_click(
-                    cx.listener({
-                        let extension_id = extension.id.clone();
-                        move |this, _, cx| {
-                            this.telemetry
-                                .report_app_event("extensions: install extension".to_string());
-                            ExtensionStore::global(cx).update(cx, |store, cx| {
-                                store.install_latest_extension(extension_id.clone(), cx)
-                            });
-                        }
-                    }),
-                ),
+                Button::new(SharedString::from(extension.id.clone()), "Install").on_click({
+                    let extension_id = extension.id.clone();
+                    move |_, cx| {
+                        telemetry::event!("Extension Installed");
+                        ExtensionStore::global(cx).update(cx, |store, cx| {
+                            store.install_latest_extension(extension_id.clone(), cx)
+                        });
+                    }
+                }),
                 None,
             ),
             ExtensionStatus::Installing => (
@@ -729,18 +723,15 @@ impl ExtensionsPage {
                 ),
             ),
             ExtensionStatus::Installed(installed_version) => (
-                Button::new(SharedString::from(extension.id.clone()), "Uninstall").on_click(
-                    cx.listener({
-                        let extension_id = extension.id.clone();
-                        move |this, _, cx| {
-                            this.telemetry
-                                .report_app_event("extensions: uninstall extension".to_string());
-                            ExtensionStore::global(cx).update(cx, |store, cx| {
-                                store.uninstall_extension(extension_id.clone(), cx)
-                            });
-                        }
-                    }),
-                ),
+                Button::new(SharedString::from(extension.id.clone()), "Uninstall").on_click({
+                    let extension_id = extension.id.clone();
+                    move |_, cx| {
+                        telemetry::event!("Extension Uninstalled", extension_id);
+                        ExtensionStore::global(cx).update(cx, |store, cx| {
+                            store.uninstall_extension(extension_id.clone(), cx)
+                        });
+                    }
+                }),
                 if installed_version == extension.manifest.version {
                     None
                 } else {
@@ -760,13 +751,11 @@ impl ExtensionsPage {
                                 })
                             })
                             .disabled(!is_compatible)
-                            .on_click(cx.listener({
+                            .on_click({
                                 let extension_id = extension.id.clone();
                                 let version = extension.manifest.version.clone();
-                                move |this, _, cx| {
-                                    this.telemetry.report_app_event(
-                                        "extensions: install extension".to_string(),
-                                    );
+                                move |_, cx| {
+                                    telemetry::event!("Extension Installed", extension_id, version);
                                     ExtensionStore::global(cx).update(cx, |store, cx| {
                                         store
                                             .upgrade_extension(
@@ -777,7 +766,7 @@ impl ExtensionsPage {
                                             .detach_and_log_err(cx)
                                     });
                                 }
-                            })),
+                            }),
                     )
                 },
             ),
@@ -972,19 +961,16 @@ impl ExtensionsPage {
         let upsells_count = self.upsells.len();
 
         v_flex().children(self.upsells.iter().enumerate().map(|(ix, feature)| {
-            let telemetry = self.telemetry.clone();
             let upsell = match feature {
                 Feature::Git => FeatureUpsell::new(
-                    telemetry,
                     "Zed comes with basic Git support. More Git features are coming in the future.",
                 )
                 .docs_url("https://zed.dev/docs/git"),
                 Feature::OpenIn => FeatureUpsell::new(
-                    telemetry,
                     "Zed supports linking to a source line on GitHub and others.",
                 )
                 .docs_url("https://zed.dev/docs/git#git-integrations"),
-                Feature::Vim => FeatureUpsell::new(telemetry, "Vim support is built-in to Zed!")
+                Feature::Vim => FeatureUpsell::new("Vim support is built-in to Zed!")
                     .docs_url("https://zed.dev/docs/vim")
                     .child(CheckboxWithLabel::new(
                         "enable-vim",
@@ -995,8 +981,7 @@ impl ExtensionsPage {
                             ui::ToggleState::Unselected
                         },
                         cx.listener(move |this, selection, cx| {
-                            this.telemetry
-                                .report_app_event("feature upsell: toggle vim".to_string());
+                            telemetry::event!("Vim Mode Toggled", source = "Feature Upsell");
                             this.update_settings::<VimModeSetting>(
                                 selection,
                                 cx,
@@ -1004,36 +989,22 @@ impl ExtensionsPage {
                             );
                         }),
                     )),
-                Feature::LanguageBash => {
-                    FeatureUpsell::new(telemetry, "Shell support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/bash")
-                }
-                Feature::LanguageC => {
-                    FeatureUpsell::new(telemetry, "C support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/c")
-                }
-                Feature::LanguageCpp => {
-                    FeatureUpsell::new(telemetry, "C++ support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/cpp")
-                }
-                Feature::LanguageGo => {
-                    FeatureUpsell::new(telemetry, "Go support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/go")
-                }
-                Feature::LanguagePython => {
-                    FeatureUpsell::new(telemetry, "Python support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/python")
-                }
-                Feature::LanguageReact => {
-                    FeatureUpsell::new(telemetry, "React support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/typescript")
-                }
-                Feature::LanguageRust => {
-                    FeatureUpsell::new(telemetry, "Rust support is built-in to Zed!")
-                        .docs_url("https://zed.dev/docs/languages/rust")
-                }
+                Feature::LanguageBash => FeatureUpsell::new("Shell support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/bash"),
+                Feature::LanguageC => FeatureUpsell::new("C support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/c"),
+                Feature::LanguageCpp => FeatureUpsell::new("C++ support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/cpp"),
+                Feature::LanguageGo => FeatureUpsell::new("Go support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/go"),
+                Feature::LanguagePython => FeatureUpsell::new("Python support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/python"),
+                Feature::LanguageReact => FeatureUpsell::new("React support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/typescript"),
+                Feature::LanguageRust => FeatureUpsell::new("Rust support is built-in to Zed!")
+                    .docs_url("https://zed.dev/docs/languages/rust"),
                 Feature::LanguageTypescript => {
-                    FeatureUpsell::new(telemetry, "Typescript support is built-in to Zed!")
+                    FeatureUpsell::new("Typescript support is built-in to Zed!")
                         .docs_url("https://zed.dev/docs/languages/typescript")
                 }
             };

crates/telemetry/src/telemetry.rs 🔗

@@ -17,6 +17,13 @@ pub use telemetry_events::FlexibleEvent as Event;
 /// ```
 #[macro_export]
 macro_rules! event {
+    ($name:expr) => {{
+        let event = $crate::Event {
+            event_type: $name.to_string(),
+            event_properties: std::collections::HashMap::new(),
+        };
+        $crate::send_event(event);
+    }};
     ($name:expr, $($key:ident $(= $value:expr)?),+ $(,)?) => {{
         let event = $crate::Event {
             event_type: $name.to_string(),