diff --git a/Cargo.lock b/Cargo.lock index abe5705761..727622397a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4412,6 +4412,7 @@ dependencies = [ "serde", "settings", "smallvec", + "telemetry", "theme", "ui", "util", diff --git a/crates/extensions_ui/Cargo.toml b/crates/extensions_ui/Cargo.toml index cc6e78d6f3..be263b286e 100644 --- a/crates/extensions_ui/Cargo.toml +++ b/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 diff --git a/crates/extensions_ui/src/components/feature_upsell.rs b/crates/extensions_ui/src/components/feature_upsell.rs index 883174db41..6eed0439df 100644 --- a/crates/extensions_ui/src/components/feature_upsell.rs +++ b/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, text: SharedString, docs_url: Option, children: SmallVec<[AnyElement; 2]>, } impl FeatureUpsell { - pub fn new(telemetry: Arc, text: impl Into) -> Self { + pub fn new(text: impl Into) -> 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) } }), diff --git a/crates/extensions_ui/src/extensions_ui.rs b/crates/extensions_ui/src/extensions_ui.rs index edbe188ee6..ac9efa1a64 100644 --- a/crates/extensions_ui/src/extensions_ui.rs +++ b/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> { pub struct ExtensionsPage { workspace: WeakView, list: UniformListScrollHandle, - telemetry: Arc, is_fetching_extensions: bool, filter: ExtensionFilter, remote_extension_entries: Vec, @@ -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::( 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") } }; diff --git a/crates/telemetry/src/telemetry.rs b/crates/telemetry/src/telemetry.rs index 64e36f4c3d..9fb05543a9 100644 --- a/crates/telemetry/src/telemetry.rs +++ b/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(),