onboarding: Add more telemetry (#36121)

1. Welcome Page Open
2. Welcome Nav clicked
3. Skip clicked
4. Font changed
5. Import settings clicked
6. Inlay Hints
7. Git Blame
8. Format on Save
9. Font Ligature
10. Ai Enabled
11. Ai Provider Modal open


Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
This commit is contained in:
Anthony Eid 2025-08-13 12:02:14 -04:00 committed by GitHub
parent 6c1f19571a
commit a7442d8880
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 111 additions and 19 deletions

1
Cargo.lock generated
View file

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

View file

@ -38,6 +38,7 @@ project.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true
settings.workspace = true settings.workspace = true
telemetry.workspace = true
theme.workspace = true theme.workspace = true
ui.workspace = true ui.workspace = true
util.workspace = true util.workspace = true

View file

@ -188,6 +188,11 @@ fn render_llm_provider_card(
workspace workspace
.update(cx, |workspace, cx| { .update(cx, |workspace, cx| {
workspace.toggle_modal(window, cx, |window, cx| { workspace.toggle_modal(window, cx, |window, cx| {
telemetry::event!(
"Welcome AI Modal Opened",
provider = provider.name().0,
);
let modal = AiConfigurationModal::new( let modal = AiConfigurationModal::new(
provider.clone(), provider.clone(),
window, window,
@ -245,16 +250,25 @@ pub(crate) fn render_ai_setup_page(
ToggleState::Selected ToggleState::Selected
}, },
|&toggle_state, _, cx| { |&toggle_state, _, cx| {
let enabled = match toggle_state {
ToggleState::Indeterminate => {
return;
}
ToggleState::Unselected => true,
ToggleState::Selected => false,
};
telemetry::event!(
"Welcome AI Enabled",
toggle = if enabled { "on" } else { "off" },
);
let fs = <dyn Fs>::global(cx); let fs = <dyn Fs>::global(cx);
update_settings_file::<DisableAiSettings>( update_settings_file::<DisableAiSettings>(
fs, fs,
cx, cx,
move |ai_settings: &mut Option<bool>, _| { move |ai_settings: &mut Option<bool>, _| {
*ai_settings = match toggle_state { *ai_settings = Some(enabled);
ToggleState::Indeterminate => None,
ToggleState::Unselected => Some(true),
ToggleState::Selected => Some(false),
};
}, },
); );
}, },

View file

@ -35,6 +35,11 @@ fn write_show_mini_map(show: ShowMinimap, cx: &mut App) {
EditorSettings::override_global(curr_settings, cx); EditorSettings::override_global(curr_settings, cx);
update_settings_file::<EditorSettings>(fs, cx, move |editor_settings, _| { update_settings_file::<EditorSettings>(fs, cx, move |editor_settings, _| {
telemetry::event!(
"Welcome Minimap Clicked",
from = editor_settings.minimap.unwrap_or_default(),
to = show
);
editor_settings.minimap.get_or_insert_default().show = Some(show); editor_settings.minimap.get_or_insert_default().show = Some(show);
}); });
} }
@ -71,7 +76,7 @@ fn read_git_blame(cx: &App) -> bool {
ProjectSettings::get_global(cx).git.inline_blame_enabled() ProjectSettings::get_global(cx).git.inline_blame_enabled()
} }
fn set_git_blame(enabled: bool, cx: &mut App) { fn write_git_blame(enabled: bool, cx: &mut App) {
let fs = <dyn Fs>::global(cx); let fs = <dyn Fs>::global(cx);
let mut curr_settings = ProjectSettings::get_global(cx).clone(); let mut curr_settings = ProjectSettings::get_global(cx).clone();
@ -95,6 +100,12 @@ fn write_ui_font_family(font: SharedString, cx: &mut App) {
let fs = <dyn Fs>::global(cx); let fs = <dyn Fs>::global(cx);
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| { update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
telemetry::event!(
"Welcome Font Changed",
type = "ui font",
old = theme_settings.ui_font_family,
new = font.clone()
);
theme_settings.ui_font_family = Some(FontFamilyName(font.into())); theme_settings.ui_font_family = Some(FontFamilyName(font.into()));
}); });
} }
@ -119,6 +130,13 @@ fn write_buffer_font_family(font_family: SharedString, cx: &mut App) {
let fs = <dyn Fs>::global(cx); let fs = <dyn Fs>::global(cx);
update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| { update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
telemetry::event!(
"Welcome Font Changed",
type = "editor font",
old = theme_settings.buffer_font_family,
new = font_family.clone()
);
theme_settings.buffer_font_family = Some(FontFamilyName(font_family.into())); theme_settings.buffer_font_family = Some(FontFamilyName(font_family.into()));
}); });
} }
@ -197,7 +215,7 @@ fn render_setting_import_button(
.color(Color::Muted) .color(Color::Muted)
.size(IconSize::XSmall), .size(IconSize::XSmall),
) )
.child(Label::new(label)), .child(Label::new(label.clone())),
) )
.when(imported, |this| { .when(imported, |this| {
this.child( this.child(
@ -212,7 +230,10 @@ fn render_setting_import_button(
) )
}), }),
) )
.on_click(move |_, window, cx| window.dispatch_action(action.boxed_clone(), cx)), .on_click(move |_, window, cx| {
telemetry::event!("Welcome Import Settings", import_source = label,);
window.dispatch_action(action.boxed_clone(), cx);
}),
) )
} }
@ -605,7 +626,13 @@ fn render_popular_settings_section(
ui::ToggleState::Unselected ui::ToggleState::Unselected
}, },
|toggle_state, _, cx| { |toggle_state, _, cx| {
write_font_ligatures(toggle_state == &ToggleState::Selected, cx); let enabled = toggle_state == &ToggleState::Selected;
telemetry::event!(
"Welcome Font Ligature",
options = if enabled { "on" } else { "off" },
);
write_font_ligatures(enabled, cx);
}, },
) )
.tab_index({ .tab_index({
@ -625,7 +652,13 @@ fn render_popular_settings_section(
ui::ToggleState::Unselected ui::ToggleState::Unselected
}, },
|toggle_state, _, cx| { |toggle_state, _, cx| {
write_format_on_save(toggle_state == &ToggleState::Selected, cx); let enabled = toggle_state == &ToggleState::Selected;
telemetry::event!(
"Welcome Format On Save Changed",
options = if enabled { "on" } else { "off" },
);
write_format_on_save(enabled, cx);
}, },
) )
.tab_index({ .tab_index({
@ -644,7 +677,13 @@ fn render_popular_settings_section(
ui::ToggleState::Unselected ui::ToggleState::Unselected
}, },
|toggle_state, _, cx| { |toggle_state, _, cx| {
write_inlay_hints(toggle_state == &ToggleState::Selected, cx); let enabled = toggle_state == &ToggleState::Selected;
telemetry::event!(
"Welcome Inlay Hints Changed",
options = if enabled { "on" } else { "off" },
);
write_inlay_hints(enabled, cx);
}, },
) )
.tab_index({ .tab_index({
@ -663,7 +702,13 @@ fn render_popular_settings_section(
ui::ToggleState::Unselected ui::ToggleState::Unselected
}, },
|toggle_state, _, cx| { |toggle_state, _, cx| {
set_git_blame(toggle_state == &ToggleState::Selected, cx); let enabled = toggle_state == &ToggleState::Selected;
telemetry::event!(
"Welcome Git Blame Changed",
options = if enabled { "on" } else { "off" },
);
write_git_blame(enabled, cx);
}, },
) )
.tab_index({ .tab_index({

View file

@ -214,6 +214,7 @@ pub fn init(cx: &mut App) {
} }
pub fn show_onboarding_view(app_state: Arc<AppState>, cx: &mut App) -> Task<anyhow::Result<()>> { pub fn show_onboarding_view(app_state: Arc<AppState>, cx: &mut App) -> Task<anyhow::Result<()>> {
telemetry::event!("Onboarding Page Opened");
open_new( open_new(
Default::default(), Default::default(),
app_state, app_state,
@ -242,6 +243,16 @@ enum SelectedPage {
AiSetup, AiSetup,
} }
impl SelectedPage {
fn name(&self) -> &'static str {
match self {
SelectedPage::Basics => "Basics",
SelectedPage::Editing => "Editing",
SelectedPage::AiSetup => "AI Setup",
}
}
}
struct Onboarding { struct Onboarding {
workspace: WeakEntity<Workspace>, workspace: WeakEntity<Workspace>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
@ -261,7 +272,21 @@ impl Onboarding {
}) })
} }
fn set_page(&mut self, page: SelectedPage, cx: &mut Context<Self>) { fn set_page(
&mut self,
page: SelectedPage,
clicked: Option<&'static str>,
cx: &mut Context<Self>,
) {
if let Some(click) = clicked {
telemetry::event!(
"Welcome Tab Clicked",
from = self.selected_page.name(),
to = page.name(),
clicked = click,
);
}
self.selected_page = page; self.selected_page = page;
cx.notify(); cx.notify();
cx.emit(ItemEvent::UpdateTab); cx.emit(ItemEvent::UpdateTab);
@ -325,8 +350,13 @@ impl Onboarding {
gpui::Empty.into_any_element(), gpui::Empty.into_any_element(),
IntoElement::into_any_element, IntoElement::into_any_element,
)) ))
.on_click(cx.listener(move |this, _, _, cx| { .on_click(cx.listener(move |this, click_event, _, cx| {
this.set_page(page, cx); let click = match click_event {
gpui::ClickEvent::Mouse(_) => "mouse",
gpui::ClickEvent::Keyboard(_) => "keyboard",
};
this.set_page(page, Some(click), cx);
})) }))
}) })
} }
@ -475,6 +505,7 @@ impl Onboarding {
} }
fn on_finish(_: &Finish, _: &mut Window, cx: &mut App) { fn on_finish(_: &Finish, _: &mut Window, cx: &mut App) {
telemetry::event!("Welcome Skip Clicked");
go_to_welcome_page(cx); go_to_welcome_page(cx);
} }
@ -532,13 +563,13 @@ impl Render for Onboarding {
.on_action(Self::handle_sign_in) .on_action(Self::handle_sign_in)
.on_action(Self::handle_open_account) .on_action(Self::handle_open_account)
.on_action(cx.listener(|this, _: &ActivateBasicsPage, _, cx| { .on_action(cx.listener(|this, _: &ActivateBasicsPage, _, cx| {
this.set_page(SelectedPage::Basics, cx); this.set_page(SelectedPage::Basics, Some("action"), cx);
})) }))
.on_action(cx.listener(|this, _: &ActivateEditingPage, _, cx| { .on_action(cx.listener(|this, _: &ActivateEditingPage, _, cx| {
this.set_page(SelectedPage::Editing, cx); this.set_page(SelectedPage::Editing, Some("action"), cx);
})) }))
.on_action(cx.listener(|this, _: &ActivateAISetupPage, _, cx| { .on_action(cx.listener(|this, _: &ActivateAISetupPage, _, cx| {
this.set_page(SelectedPage::AiSetup, cx); this.set_page(SelectedPage::AiSetup, Some("action"), cx);
})) }))
.on_action(cx.listener(|_, _: &menu::SelectNext, window, cx| { .on_action(cx.listener(|_, _: &menu::SelectNext, window, cx| {
window.focus_next(); window.focus_next();
@ -806,7 +837,7 @@ impl workspace::SerializableItem for Onboarding {
if let Some(page) = page { if let Some(page) = page {
zlog::info!("Onboarding page {page:?} loaded"); zlog::info!("Onboarding page {page:?} loaded");
onboarding_page.update(cx, |onboarding_page, cx| { onboarding_page.update(cx, |onboarding_page, cx| {
onboarding_page.set_page(page, cx); onboarding_page.set_page(page, None, cx);
}) })
} }
onboarding_page onboarding_page