Convert copilot popup to modal

This commit is contained in:
Piotr Osiewicz 2024-01-05 16:27:52 +01:00
parent 3e8e1c6404
commit 0ce94fc791
3 changed files with 39 additions and 87 deletions

View file

@ -13,6 +13,7 @@ use language::{
File, Language, File, Language,
}; };
use settings::{update_settings_file, Settings, SettingsStore}; use settings::{update_settings_file, Settings, SettingsStore};
use sign_in::CopilotCodeVerification;
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use util::{paths, ResultExt}; use util::{paths, ResultExt};
use workspace::{ use workspace::{
@ -27,10 +28,6 @@ const COPILOT_SETTINGS_URL: &str = "https://github.com/settings/copilot";
const COPILOT_STARTING_TOAST_ID: usize = 1337; const COPILOT_STARTING_TOAST_ID: usize = 1337;
const COPILOT_ERROR_TOAST_ID: usize = 1338; const COPILOT_ERROR_TOAST_ID: usize = 1338;
pub fn init(cx: &mut AppContext) {
sign_in::init(cx);
}
pub struct CopilotButton { pub struct CopilotButton {
editor_subscription: Option<(Subscription, usize)>, editor_subscription: Option<(Subscription, usize)>,
editor_enabled: Option<bool>, editor_enabled: Option<bool>,
@ -337,7 +334,9 @@ fn initiate_sign_in(cx: &mut WindowContext) {
return; return;
}; };
let status = copilot.read(cx).status(); let status = copilot.read(cx).status();
let Some(workspace) = cx.window_handle().downcast::<Workspace>() else {
return;
};
match status { match status {
Status::Starting { task } => { Status::Starting { task } => {
let Some(workspace) = cx.window_handle().downcast::<Workspace>() else { let Some(workspace) = cx.window_handle().downcast::<Workspace>() else {
@ -376,9 +375,10 @@ fn initiate_sign_in(cx: &mut WindowContext) {
.detach(); .detach();
} }
_ => { _ => {
copilot copilot.update(cx, |this, cx| this.sign_in(cx)).detach();
.update(cx, |copilot, cx| copilot.sign_in(cx)) workspace.update(cx, |this, cx| {
.detach_and_log_err(cx); this.toggle_modal(cx, |cx| CopilotCodeVerification::new(&copilot, cx));
});
} }
} }
} }

View file

@ -1,91 +1,49 @@
use copilot::{request::PromptUserDeviceFlow, Copilot, Status}; use copilot::{request::PromptUserDeviceFlow, Copilot, Status};
use gpui::{ use gpui::{
div, size, svg, AppContext, Bounds, ClipboardItem, Element, GlobalPixels, InteractiveElement, div, size, svg, AppContext, Bounds, ClipboardItem, DismissEvent, Element, EventEmitter,
IntoElement, ParentElement, Point, Render, Styled, ViewContext, VisualContext, WindowBounds, FocusHandle, FocusableView, GlobalPixels, InteractiveElement, IntoElement, Model,
ParentElement, Point, Render, Styled, Subscription, ViewContext, VisualContext, WindowBounds,
WindowHandle, WindowKind, WindowOptions, WindowHandle, WindowKind, WindowOptions,
}; };
use ui::{prelude::*, Button, Icon, Label}; use ui::{prelude::*, Button, Icon, Label};
use workspace::ModalView;
const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot"; const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot";
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {}
if let Some(copilot) = Copilot::global(cx) {
let mut verification_window: Option<WindowHandle<CopilotCodeVerification>> = None;
cx.observe(&copilot, move |copilot, cx| {
let status = copilot.read(cx).status();
match &status {
crate::Status::SigningIn { prompt } => {
if let Some(window) = verification_window.as_mut() {
let updated = window
.update(cx, |verification, cx| {
verification.set_status(status.clone(), cx);
cx.activate_window();
})
.is_ok();
if !updated {
verification_window = Some(create_copilot_auth_window(cx, &status));
}
} else if let Some(_prompt) = prompt {
verification_window = Some(create_copilot_auth_window(cx, &status));
}
}
Status::Authorized | Status::Unauthorized => {
if let Some(window) = verification_window.as_ref() {
window
.update(cx, |verification, cx| {
verification.set_status(status, cx);
cx.activate(true);
cx.activate_window();
})
.ok();
}
}
_ => {
if let Some(code_verification) = verification_window.take() {
code_verification
.update(cx, |_, cx| cx.remove_window())
.ok();
}
}
}
})
.detach();
}
}
fn create_copilot_auth_window(
cx: &mut AppContext,
status: &Status,
) -> WindowHandle<CopilotCodeVerification> {
let window_size = size(GlobalPixels::from(400.), GlobalPixels::from(480.));
let window_options = WindowOptions {
bounds: WindowBounds::Fixed(Bounds::new(Point::default(), window_size)),
titlebar: None,
center: true,
focus: true,
show: true,
kind: WindowKind::PopUp,
is_movable: true,
display_id: None,
};
let window = cx.open_window(window_options, |cx| {
cx.new_view(|_| CopilotCodeVerification::new(status.clone()))
});
window
}
pub struct CopilotCodeVerification { pub struct CopilotCodeVerification {
status: Status, status: Status,
connect_clicked: bool, connect_clicked: bool,
focus_handle: FocusHandle,
_subscription: Subscription,
} }
//impl ModalView for CopilotCodeVerification {} impl FocusableView for CopilotCodeVerification {
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
self.focus_handle.clone()
}
}
impl EventEmitter<DismissEvent> for CopilotCodeVerification {}
impl ModalView for CopilotCodeVerification {}
impl CopilotCodeVerification { impl CopilotCodeVerification {
pub fn new(status: Status) -> Self { pub(crate) fn new(copilot: &Model<Copilot>, cx: &mut ViewContext<Self>) -> Self {
let status = copilot.read(cx).status();
Self { Self {
status, status,
connect_clicked: false, connect_clicked: false,
focus_handle: cx.focus_handle(),
_subscription: cx.observe(copilot, |this, copilot, cx| {
let status = copilot.read(cx).status();
match status {
Status::Authorized | Status::Unauthorized | Status::SigningIn { .. } => {
this.set_status(status, cx)
}
_ => cx.emit(DismissEvent),
}
}),
} }
} }
@ -159,10 +117,7 @@ impl CopilotCodeVerification {
.child(Label::new( .child(Label::new(
"You can update your settings or sign out from the Copilot menu in the status bar.", "You can update your settings or sign out from the Copilot menu in the status bar.",
)) ))
.child( .child(Button::new("copilot-enabled-done-button", "Done").on_click(|_, cx| {}))
Button::new("copilot-enabled-done-button", "Done")
.on_click(|_, cx| cx.remove_window()),
)
} }
fn render_unauthorized_modal() -> impl Element { fn render_unauthorized_modal() -> impl Element {
@ -175,10 +130,8 @@ impl CopilotCodeVerification {
.color(Color::Warning), .color(Color::Warning),
) )
.child( .child(
Button::new("copilot-subscribe-button", "Subscibe on Github").on_click(|_, cx| { Button::new("copilot-subscribe-button", "Subscibe on Github")
cx.remove_window(); .on_click(|_, cx| cx.open_url(COPILOT_SIGN_UP_URL)),
cx.open_url(COPILOT_SIGN_UP_URL)
}),
) )
} }
} }

View file

@ -158,7 +158,6 @@ fn main() {
node_runtime.clone(), node_runtime.clone(),
cx, cx,
); );
copilot_button::init(cx);
assistant::init(cx); assistant::init(cx);
cx.spawn(|_| watch_languages(fs.clone(), languages.clone())) cx.spawn(|_| watch_languages(fs.clone(), languages.clone()))