Skip to repository content151 lines · 5.5 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T05:16:36.997Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
onboarding_modal.rs
1use std::sync::Arc;
2
3use crate::{EditPredictionStore, ZedPredictUpsell};
4use ai_onboarding::EditPredictionOnboarding;
5use db::kvp::Dismissable;
6use fs::Fs;
7use gpui::{
8 ClickEvent, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, MouseDownEvent, Render,
9 linear_color_stop, linear_gradient,
10};
11use language::language_settings::EditPredictionProvider;
12use settings::update_settings_file;
13use ui::prelude::*;
14use workspace::{ModalView, Workspace};
15
16#[macro_export]
17macro_rules! onboarding_event {
18 ($name:expr) => {
19 telemetry::event!($name, source = "Edit Prediction Onboarding");
20 };
21 ($name:expr, $($key:ident $(= $value:expr)?),+ $(,)?) => {
22 telemetry::event!($name, source = "Edit Prediction Onboarding", $($key $(= $value)?),+);
23 };
24}
25
26/// Introduces user to Zed's Edit Prediction feature
27pub struct ZedPredictModal {
28 onboarding: Entity<EditPredictionOnboarding>,
29 focus_handle: FocusHandle,
30}
31
32pub(crate) fn set_edit_prediction_provider(provider: EditPredictionProvider, cx: &mut App) {
33 let fs = <dyn Fs>::global(cx);
34 update_settings_file(fs, cx, move |settings, _| {
35 settings
36 .project
37 .all_languages
38 .edit_predictions
39 .get_or_insert(Default::default())
40 .provider = Some(provider);
41 });
42}
43
44impl ZedPredictModal {
45 pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
46 let project = workspace.project().clone();
47 workspace.toggle_modal(window, cx, |_window, cx| {
48 let weak_entity = cx.weak_entity();
49 let copilot = EditPredictionStore::try_global(cx)
50 .and_then(|store| store.read(cx).copilot_for_project(&project));
51 Self {
52 onboarding: cx.new(|cx| {
53 EditPredictionOnboarding::new(
54 copilot
55 .as_ref()
56 .is_some_and(|copilot| copilot.read(cx).status().is_configured()),
57 Arc::new({
58 let this = weak_entity.clone();
59 move |window, cx| {
60 ZedPredictUpsell::set_dismissed(true, cx);
61 set_edit_prediction_provider(EditPredictionProvider::Copilot, cx);
62 this.update(cx, |_, cx| cx.emit(DismissEvent)).ok();
63 if let Some(copilot) = copilot.clone() {
64 copilot_ui::initiate_sign_in(copilot, window, cx);
65 }
66 }
67 }),
68 cx,
69 )
70 }),
71 focus_handle: cx.focus_handle(),
72 }
73 });
74 }
75
76 fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
77 ZedPredictUpsell::set_dismissed(true, cx);
78 cx.emit(DismissEvent);
79 }
80}
81
82impl EventEmitter<DismissEvent> for ZedPredictModal {}
83
84impl Focusable for ZedPredictModal {
85 fn focus_handle(&self, _cx: &App) -> FocusHandle {
86 self.focus_handle.clone()
87 }
88}
89
90impl ModalView for ZedPredictModal {
91 fn on_before_dismiss(
92 &mut self,
93 _window: &mut Window,
94 cx: &mut Context<Self>,
95 ) -> workspace::DismissDecision {
96 ZedPredictUpsell::set_dismissed(true, cx);
97 workspace::DismissDecision::Dismiss(true)
98 }
99}
100
101impl Render for ZedPredictModal {
102 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
103 let window_height = window.viewport_size().height;
104 let max_height = window_height - px(200.);
105 let color = cx.theme().colors();
106
107 v_flex()
108 .id("edit-prediction-onboarding")
109 .key_context("ZedPredictModal")
110 .relative()
111 .w(px(550.))
112 .h_full()
113 .max_h(max_height)
114 .p_1()
115 .gap_2()
116 .elevation_3(cx)
117 .track_focus(&self.focus_handle(cx))
118 .overflow_hidden()
119 .on_action(cx.listener(Self::cancel))
120 .on_action(cx.listener(|_, _: &menu::Cancel, _window, cx| {
121 onboarding_event!("Cancelled", trigger = "Action");
122 cx.emit(DismissEvent);
123 }))
124 .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, cx| {
125 this.focus_handle.focus(window, cx);
126 }))
127 .child(
128 div()
129 .p_3()
130 .size_full()
131 .border_1()
132 .border_color(cx.theme().colors().border)
133 .rounded(px(5.))
134 .bg(linear_gradient(
135 360.,
136 linear_color_stop(color.panel_background, 1.0),
137 linear_color_stop(color.editor_background, 0.45),
138 ))
139 .child(self.onboarding.clone()),
140 )
141 .child(h_flex().absolute().top_3().right_3().child(
142 IconButton::new("cancel", IconName::Close).on_click(cx.listener(
143 |_, _: &ClickEvent, _window, cx| {
144 onboarding_event!("Cancelled", trigger = "X click");
145 cx.emit(DismissEvent);
146 },
147 )),
148 ))
149 }
150}
151