copilot: Fix missing sign-out button when Zed is the edit prediction provider (#26340)

Closes #25884

Added a sign-out button for Copilot in Assistant settings, allowing
sign-out even when copilot is disabled.

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/43fc97ad-f73c-49e1-a7b6-a3910434d661"
/>



Release Notes:

- Added a sign-out button for Copilot in Assistant settings.
This commit is contained in:
Smit Barmase 2025-03-09 16:09:14 +00:00 committed by GitHub
parent e298301b40
commit 5aae3bdc69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 15 deletions

View file

@ -623,16 +623,21 @@ impl Copilot {
pub fn sign_out(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> { pub fn sign_out(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx); self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
if let CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) = &self.server { match &self.server {
let server = server.clone(); CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) => {
cx.background_spawn(async move { let server = server.clone();
server cx.background_spawn(async move {
.request::<request::SignOut>(request::SignOutParams {}) server
.await?; .request::<request::SignOut>(request::SignOutParams {})
.await?;
anyhow::Ok(())
})
}
CopilotServer::Disabled => cx.background_spawn(async move {
clear_copilot_config_dir().await;
anyhow::Ok(()) anyhow::Ok(())
}) }),
} else { _ => Task::ready(Err(anyhow!("copilot hasn't started yet"))),
Task::ready(Err(anyhow!("copilot hasn't started yet")))
} }
} }
@ -1016,6 +1021,10 @@ async fn clear_copilot_dir() {
remove_matching(paths::copilot_dir(), |_| true).await remove_matching(paths::copilot_dir(), |_| true).await
} }
async fn clear_copilot_config_dir() {
remove_matching(copilot_chat::copilot_chat_config_dir(), |_| true).await
}
async fn get_copilot_lsp(http: Arc<dyn HttpClient>) -> anyhow::Result<PathBuf> { async fn get_copilot_lsp(http: Arc<dyn HttpClient>) -> anyhow::Result<PathBuf> {
const SERVER_PATH: &str = "dist/language-server.js"; const SERVER_PATH: &str = "dist/language-server.js";

View file

@ -213,7 +213,7 @@ pub fn init(fs: Arc<dyn Fs>, client: Arc<dyn HttpClient>, cx: &mut App) {
cx.set_global(GlobalCopilotChat(copilot_chat)); cx.set_global(GlobalCopilotChat(copilot_chat));
} }
fn copilot_chat_config_dir() -> &'static PathBuf { pub fn copilot_chat_config_dir() -> &'static PathBuf {
static COPILOT_CHAT_CONFIG_DIR: OnceLock<PathBuf> = OnceLock::new(); static COPILOT_CHAT_CONFIG_DIR: OnceLock<PathBuf> = OnceLock::new();
COPILOT_CHAT_CONFIG_DIR.get_or_init(|| { COPILOT_CHAT_CONFIG_DIR.get_or_init(|| {

View file

@ -11,8 +11,8 @@ use futures::future::BoxFuture;
use futures::stream::BoxStream; use futures::stream::BoxStream;
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use gpui::{ use gpui::{
percentage, svg, Animation, AnimationExt, AnyView, App, AsyncApp, Entity, Render, Subscription, percentage, svg, Action, Animation, AnimationExt, AnyView, App, AsyncApp, Entity, Render,
Task, Transformation, Subscription, Task, Transformation,
}; };
use language_model::{ use language_model::{
AuthenticateError, LanguageModel, LanguageModelCompletionEvent, LanguageModelId, AuthenticateError, LanguageModel, LanguageModelCompletionEvent, LanguageModelId,
@ -337,9 +337,20 @@ impl Render for ConfigurationView {
if self.state.read(cx).is_authenticated(cx) { if self.state.read(cx).is_authenticated(cx) {
const LABEL: &str = "Authorized."; const LABEL: &str = "Authorized.";
h_flex() h_flex()
.gap_1() .justify_between()
.child(Icon::new(IconName::Check).color(Color::Success)) .child(
.child(Label::new(LABEL)) h_flex()
.gap_1()
.child(Icon::new(IconName::Check).color(Color::Success))
.child(Label::new(LABEL)),
)
.child(
Button::new("sign_out", "Sign Out")
.style(ui::ButtonStyle::Filled)
.on_click(|_, window, cx| {
window.dispatch_action(copilot::SignOut.boxed_clone(), cx);
}),
)
} else { } else {
let loading_icon = svg() let loading_icon = svg()
.size_8() .size_8()