edit predictions: Onboarding funnel telemetry (#24237)
Release Notes: - N/A
This commit is contained in:
parent
0a89d1a479
commit
630d0add19
10 changed files with 82 additions and 15 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6388,6 +6388,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
"supermaven",
|
"supermaven",
|
||||||
|
"telemetry",
|
||||||
"theme",
|
"theme",
|
||||||
"ui",
|
"ui",
|
||||||
"workspace",
|
"workspace",
|
||||||
|
|
|
@ -3946,10 +3946,6 @@ impl Editor {
|
||||||
self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
|
self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_zed_predict_onboarding(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
window.dispatch_action(zed_actions::OpenZedPredictOnboarding.boxed_clone(), cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_completion(
|
fn do_completion(
|
||||||
&mut self,
|
&mut self,
|
||||||
item_ix: Option<usize>,
|
item_ix: Option<usize>,
|
||||||
|
@ -5445,7 +5441,11 @@ impl Editor {
|
||||||
.on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
|
.on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
|
||||||
.on_click(cx.listener(|this, _event, window, cx| {
|
.on_click(cx.listener(|this, _event, window, cx| {
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
this.toggle_zed_predict_onboarding(window, cx)
|
this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
|
||||||
|
window.dispatch_action(
|
||||||
|
zed_actions::OpenZedPredictOnboarding.boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
}))
|
}))
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
@ -14074,7 +14074,8 @@ impl Editor {
|
||||||
.get("vim_mode")
|
.get("vim_mode")
|
||||||
== Some(&serde_json::Value::Bool(true));
|
== Some(&serde_json::Value::Bool(true));
|
||||||
|
|
||||||
let copilot_enabled = all_language_settings(file, cx).inline_completions.provider
|
let edit_predictions_provider = all_language_settings(file, cx).inline_completions.provider;
|
||||||
|
let copilot_enabled = edit_predictions_provider
|
||||||
== language::language_settings::InlineCompletionProvider::Copilot;
|
== language::language_settings::InlineCompletionProvider::Copilot;
|
||||||
let copilot_enabled_for_language = self
|
let copilot_enabled_for_language = self
|
||||||
.buffer
|
.buffer
|
||||||
|
@ -14089,6 +14090,7 @@ impl Editor {
|
||||||
vim_mode,
|
vim_mode,
|
||||||
copilot_enabled,
|
copilot_enabled,
|
||||||
copilot_enabled_for_language,
|
copilot_enabled_for_language,
|
||||||
|
edit_predictions_provider,
|
||||||
is_via_ssh = project.is_via_ssh(),
|
is_via_ssh = project.is_via_ssh(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ workspace.workspace = true
|
||||||
zed_actions.workspace = true
|
zed_actions.workspace = true
|
||||||
zeta.workspace = true
|
zeta.workspace = true
|
||||||
client.workspace = true
|
client.workspace = true
|
||||||
|
telemetry.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
copilot = { workspace = true, features = ["test-support"] }
|
copilot = { workspace = true, features = ["test-support"] }
|
||||||
|
|
|
@ -256,6 +256,10 @@ impl Render for InlineCompletionButton {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.on_click(cx.listener(move |_, _, window, cx| {
|
.on_click(cx.listener(move |_, _, window, cx| {
|
||||||
|
telemetry::event!(
|
||||||
|
"Pending ToS Clicked",
|
||||||
|
source = "Edit Prediction Status Button"
|
||||||
|
);
|
||||||
window.dispatch_action(
|
window.dispatch_action(
|
||||||
zed_actions::OpenZedPredictOnboarding.boxed_clone(),
|
zed_actions::OpenZedPredictOnboarding.boxed_clone(),
|
||||||
cx,
|
cx,
|
||||||
|
@ -426,6 +430,8 @@ impl InlineCompletionButton {
|
||||||
|
|
||||||
if data_collection.is_supported() {
|
if data_collection.is_supported() {
|
||||||
let provider = provider.clone();
|
let provider = provider.clone();
|
||||||
|
let enabled = data_collection.is_enabled();
|
||||||
|
|
||||||
menu = menu
|
menu = menu
|
||||||
.separator()
|
.separator()
|
||||||
.header("Help Improve The Model")
|
.header("Help Improve The Model")
|
||||||
|
@ -434,9 +440,21 @@ impl InlineCompletionButton {
|
||||||
// TODO: We want to add something later that communicates whether
|
// TODO: We want to add something later that communicates whether
|
||||||
// the current project is open-source.
|
// the current project is open-source.
|
||||||
ContextMenuEntry::new("Share Training Data")
|
ContextMenuEntry::new("Share Training Data")
|
||||||
.toggleable(IconPosition::Start, data_collection.is_enabled())
|
.toggleable(IconPosition::Start, enabled)
|
||||||
.handler(move |_, cx| {
|
.handler(move |_, cx| {
|
||||||
provider.toggle_data_collection(cx);
|
provider.toggle_data_collection(cx);
|
||||||
|
|
||||||
|
if !enabled {
|
||||||
|
telemetry::event!(
|
||||||
|
"Data Collection Enabled",
|
||||||
|
source = "Edit Prediction Status Menu"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
telemetry::event!(
|
||||||
|
"Data Collection Disabled",
|
||||||
|
source = "Edit Prediction Status Menu"
|
||||||
|
);
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,20 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
||||||
let user_store = user_store.clone();
|
let user_store = user_store.clone();
|
||||||
move |cx| {
|
move |cx| {
|
||||||
let new_provider = all_language_settings(None, cx).inline_completions.provider;
|
let new_provider = all_language_settings(None, cx).inline_completions.provider;
|
||||||
|
|
||||||
if new_provider != provider {
|
if new_provider != provider {
|
||||||
|
let tos_accepted = user_store
|
||||||
|
.read(cx)
|
||||||
|
.current_user_has_accepted_terms()
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
telemetry::event!(
|
||||||
|
"Edit Prediction Provider Changed",
|
||||||
|
from = provider,
|
||||||
|
to = new_provider,
|
||||||
|
zed_ai_tos_accepted = tos_accepted,
|
||||||
|
);
|
||||||
|
|
||||||
provider = new_provider;
|
provider = new_provider;
|
||||||
assign_inline_completion_providers(
|
assign_inline_completion_providers(
|
||||||
&editors,
|
&editors,
|
||||||
|
@ -104,11 +117,7 @@ pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
if !user_store
|
if !tos_accepted {
|
||||||
.read(cx)
|
|
||||||
.current_user_has_accepted_terms()
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
match provider {
|
match provider {
|
||||||
InlineCompletionProvider::Zed => {
|
InlineCompletionProvider::Zed => {
|
||||||
let Some(window) = cx.active_window() else {
|
let Some(window) = cx.active_window() else {
|
||||||
|
|
|
@ -6,6 +6,8 @@ use settings::SettingsStore;
|
||||||
use ui::{prelude::*, ButtonLike, Tooltip};
|
use ui::{prelude::*, ButtonLike, Tooltip};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
|
use crate::onboarding_event;
|
||||||
|
|
||||||
/// Prompts the user to try Zed's Edit Prediction feature
|
/// Prompts the user to try Zed's Edit Prediction feature
|
||||||
pub struct ZedPredictBanner {
|
pub struct ZedPredictBanner {
|
||||||
dismissed: bool,
|
dismissed: bool,
|
||||||
|
@ -53,6 +55,7 @@ impl ZedPredictBanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dismiss(&mut self, cx: &mut Context<Self>) {
|
fn dismiss(&mut self, cx: &mut Context<Self>) {
|
||||||
|
onboarding_event!("Banner Dismissed");
|
||||||
persist_dismissed(cx);
|
persist_dismissed(cx);
|
||||||
self.dismissed = true;
|
self.dismissed = true;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -107,6 +110,7 @@ impl Render for ZedPredictBanner {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.on_click(|_, window, cx| {
|
.on_click(|_, window, cx| {
|
||||||
|
onboarding_event!("Banner Clicked");
|
||||||
window.dispatch_action(Box::new(zed_actions::OpenZedPredictOnboarding), cx)
|
window.dispatch_action(Box::new(zed_actions::OpenZedPredictOnboarding), cx)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
use crate::ZED_PREDICT_DATA_COLLECTION_CHOICE;
|
use crate::{onboarding_event, ZED_PREDICT_DATA_COLLECTION_CHOICE};
|
||||||
use client::{Client, UserStore};
|
use client::{Client, UserStore};
|
||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use feature_flags::FeatureFlagAppExt as _;
|
use feature_flags::FeatureFlagAppExt as _;
|
||||||
|
@ -61,16 +61,22 @@ impl ZedPredictModal {
|
||||||
fn view_terms(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
|
fn view_terms(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
cx.open_url("https://zed.dev/terms-of-service");
|
cx.open_url("https://zed.dev/terms-of-service");
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
||||||
|
onboarding_event!("ToS Link Clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_blog(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
|
fn view_blog(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
cx.open_url("https://zed.dev/blog/"); // TODO Add the link when live
|
cx.open_url("https://zed.dev/blog/"); // TODO Add the link when live
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
||||||
|
onboarding_event!("Blog Link clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inline_completions_doc(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
|
fn inline_completions_doc(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
cx.open_url("https://zed.dev/docs/configuring-zed#inline-completions");
|
cx.open_url("https://zed.dev/docs/configuring-zed#inline-completions");
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
||||||
|
onboarding_event!("Docs Link Clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_and_enable(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
|
fn accept_and_enable(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
@ -106,6 +112,11 @@ impl ZedPredictModal {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.detach_and_notify_err(window, cx);
|
.detach_and_notify_err(window, cx);
|
||||||
|
|
||||||
|
onboarding_event!(
|
||||||
|
"Enable Clicked",
|
||||||
|
data_collection_opted_in = self.data_collection_opted_in,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
|
fn sign_in(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
@ -122,12 +133,15 @@ impl ZedPredictModal {
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.sign_in_status = status;
|
this.sign_in_status = status;
|
||||||
|
onboarding_event!("Signed In");
|
||||||
cx.notify()
|
cx.notify()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
result
|
result
|
||||||
})
|
})
|
||||||
.detach_and_notify_err(window, cx);
|
.detach_and_notify_err(window, cx);
|
||||||
|
|
||||||
|
onboarding_event!("Sign In Clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
|
fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
@ -159,6 +173,7 @@ impl Render for ZedPredictModal {
|
||||||
.track_focus(&self.focus_handle(cx))
|
.track_focus(&self.focus_handle(cx))
|
||||||
.on_action(cx.listener(Self::cancel))
|
.on_action(cx.listener(Self::cancel))
|
||||||
.on_action(cx.listener(|_, _: &menu::Cancel, _window, cx| {
|
.on_action(cx.listener(|_, _: &menu::Cancel, _window, cx| {
|
||||||
|
onboarding_event!("Cancelled", trigger = "Action");
|
||||||
cx.emit(DismissEvent);
|
cx.emit(DismissEvent);
|
||||||
}))
|
}))
|
||||||
.on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
|
.on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
|
||||||
|
@ -241,6 +256,7 @@ impl Render for ZedPredictModal {
|
||||||
.child(h_flex().absolute().top_2().right_2().child(
|
.child(h_flex().absolute().top_2().right_2().child(
|
||||||
IconButton::new("cancel", IconName::X).on_click(cx.listener(
|
IconButton::new("cancel", IconName::X).on_click(cx.listener(
|
||||||
|_, _: &ClickEvent, _window, cx| {
|
|_, _: &ClickEvent, _window, cx| {
|
||||||
|
onboarding_event!("Cancelled", trigger = "X click");
|
||||||
cx.emit(DismissEvent);
|
cx.emit(DismissEvent);
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
|
@ -302,7 +318,7 @@ impl Render for ZedPredictModal {
|
||||||
.label("Read and accept the")
|
.label("Read and accept the")
|
||||||
.on_click(cx.listener(move |this, state, _window, cx| {
|
.on_click(cx.listener(move |this, state, _window, cx| {
|
||||||
this.terms_of_service = *state == ToggleState::Selected;
|
this.terms_of_service = *state == ToggleState::Selected;
|
||||||
cx.notify()
|
cx.notify();
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
@ -340,7 +356,11 @@ impl Render for ZedPredictModal {
|
||||||
.on_click(cx.listener(|this, _, _, cx| {
|
.on_click(cx.listener(|this, _, _, cx| {
|
||||||
this.data_collection_expanded =
|
this.data_collection_expanded =
|
||||||
!this.data_collection_expanded;
|
!this.data_collection_expanded;
|
||||||
cx.notify()
|
cx.notify();
|
||||||
|
|
||||||
|
if this.data_collection_expanded {
|
||||||
|
onboarding_event!("Data Collection Learn More Clicked");
|
||||||
|
}
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
9
crates/zeta/src/onboarding_telemetry.rs
Normal file
9
crates/zeta/src/onboarding_telemetry.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! onboarding_event {
|
||||||
|
($name:expr) => {
|
||||||
|
telemetry::event!($name, source = "Edit Prediction Onboarding");
|
||||||
|
};
|
||||||
|
($name:expr, $($key:ident $(= $value:expr)?),+ $(,)?) => {
|
||||||
|
telemetry::event!($name, source = "Edit Prediction Onboarding", $($key $(= $value)?),+);
|
||||||
|
};
|
||||||
|
}
|
|
@ -52,6 +52,8 @@ impl RateCompletionModal {
|
||||||
pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
|
pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
|
||||||
if let Some(zeta) = Zeta::global(cx) {
|
if let Some(zeta) = Zeta::global(cx) {
|
||||||
workspace.toggle_modal(window, cx, |_window, cx| RateCompletionModal::new(zeta, cx));
|
workspace.toggle_modal(window, cx, |_window, cx| RateCompletionModal::new(zeta, cx));
|
||||||
|
|
||||||
|
telemetry::event!("Rate Completion Modal Open", source = "Edit Prediction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ mod init;
|
||||||
mod license_detection;
|
mod license_detection;
|
||||||
mod onboarding_banner;
|
mod onboarding_banner;
|
||||||
mod onboarding_modal;
|
mod onboarding_modal;
|
||||||
|
mod onboarding_telemetry;
|
||||||
mod rate_completion_modal;
|
mod rate_completion_modal;
|
||||||
|
|
||||||
pub(crate) use completion_diff_element::*;
|
pub(crate) use completion_diff_element::*;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue