Currently, whenever Zed has a new version available for download, the update button shows up in the status bar. Problem is: that status bar slot can also display other buttons/information, such as problems with your language server or general errors. In case the two things exist (a problem and a new version), just one of them would be displayed, which is not great; you should be able to see both. Additionally, given we ship new versions pretty often, I've frequently saw feedback about wanting to hide away the new version button... at least temporarily while there's no immediate interest in upgrading. So, this PR tackles all of that. The button to update a new version is moved up to the title bar, nearby your avatar, and you have the ability to dismiss, which effectively just moves the button from the title bar to inside your user menu. https://github.com/user-attachments/assets/e3f1d76d-9b85-4bee-a70f-e22dd5e7fdb3 Release Notes: - Moved the update Zed button to the title bar and allowed it to be dismissed. --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
149 lines
5.4 KiB
Rust
149 lines
5.4 KiB
Rust
use std::sync::Arc;
|
|
|
|
use anyhow::anyhow;
|
|
use auto_update::{AutoUpdateStatus, AutoUpdater, UpdateCheckType, VersionCheckType};
|
|
use gpui::{Empty, Render};
|
|
use semver::Version;
|
|
use ui::{UpdateButton, prelude::*};
|
|
|
|
pub struct UpdateVersion {
|
|
status: AutoUpdateStatus,
|
|
update_check_type: UpdateCheckType,
|
|
dismissed: bool,
|
|
}
|
|
|
|
impl UpdateVersion {
|
|
pub fn new(cx: &mut Context<Self>) -> Self {
|
|
if let Some(auto_updater) = AutoUpdater::get(cx) {
|
|
cx.observe(&auto_updater, |this, auto_update, cx| {
|
|
this.status = auto_update.read(cx).status();
|
|
this.update_check_type = auto_update.read(cx).update_check_type();
|
|
if this.status.is_updated() {
|
|
this.dismissed = false;
|
|
}
|
|
})
|
|
.detach();
|
|
Self {
|
|
status: auto_updater.read(cx).status(),
|
|
update_check_type: UpdateCheckType::Automatic,
|
|
dismissed: false,
|
|
}
|
|
} else {
|
|
Self {
|
|
status: AutoUpdateStatus::Idle,
|
|
update_check_type: UpdateCheckType::Automatic,
|
|
dismissed: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn update_simulation(&mut self, cx: &mut Context<Self>) {
|
|
let next_state = match self.status {
|
|
AutoUpdateStatus::Idle => AutoUpdateStatus::Checking,
|
|
AutoUpdateStatus::Checking => AutoUpdateStatus::Downloading {
|
|
version: VersionCheckType::Semantic(Version::new(1, 99, 0)),
|
|
},
|
|
AutoUpdateStatus::Downloading { .. } => AutoUpdateStatus::Installing {
|
|
version: VersionCheckType::Semantic(Version::new(1, 99, 0)),
|
|
},
|
|
AutoUpdateStatus::Installing { .. } => AutoUpdateStatus::Updated {
|
|
version: VersionCheckType::Semantic(Version::new(1, 99, 0)),
|
|
},
|
|
AutoUpdateStatus::Updated { .. } => AutoUpdateStatus::Errored {
|
|
error: Arc::new(anyhow!("Network timeout")),
|
|
},
|
|
AutoUpdateStatus::Errored { .. } => AutoUpdateStatus::Idle,
|
|
};
|
|
|
|
self.status = next_state;
|
|
self.update_check_type = UpdateCheckType::Manual;
|
|
self.dismissed = false;
|
|
cx.notify()
|
|
}
|
|
|
|
pub fn show_update_in_menu_bar(&self) -> bool {
|
|
self.dismissed && self.status.is_updated()
|
|
}
|
|
|
|
fn version_tooltip_message(version: &VersionCheckType) -> String {
|
|
format!("Version: {}", {
|
|
match version {
|
|
VersionCheckType::Sha(sha) => format!("{}…", sha.short()),
|
|
VersionCheckType::Semantic(semantic_version) => semantic_version.to_string(),
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Render for UpdateVersion {
|
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
if self.dismissed {
|
|
return Empty.into_any_element();
|
|
}
|
|
match &self.status {
|
|
AutoUpdateStatus::Checking if self.update_check_type.is_manual() => {
|
|
UpdateButton::checking().into_any_element()
|
|
}
|
|
AutoUpdateStatus::Downloading { version } if self.update_check_type.is_manual() => {
|
|
let tooltip = Self::version_tooltip_message(&version);
|
|
UpdateButton::downloading(tooltip).into_any_element()
|
|
}
|
|
AutoUpdateStatus::Installing { version } if self.update_check_type.is_manual() => {
|
|
let tooltip = Self::version_tooltip_message(&version);
|
|
UpdateButton::installing(tooltip).into_any_element()
|
|
}
|
|
AutoUpdateStatus::Updated { version } => {
|
|
let tooltip = Self::version_tooltip_message(&version);
|
|
UpdateButton::updated(tooltip)
|
|
.on_click(|_, _, cx| {
|
|
workspace::reload(cx);
|
|
})
|
|
.on_dismiss(cx.listener(|this, _, _window, cx| {
|
|
this.dismissed = true;
|
|
cx.notify()
|
|
}))
|
|
.into_any_element()
|
|
}
|
|
AutoUpdateStatus::Errored { error } => {
|
|
let error_str = error.to_string();
|
|
UpdateButton::errored(error_str)
|
|
.on_click(|_, window, cx| {
|
|
window.dispatch_action(Box::new(workspace::OpenLog), cx);
|
|
})
|
|
.on_dismiss(cx.listener(|this, _, _window, cx| {
|
|
this.dismissed = true;
|
|
cx.notify()
|
|
}))
|
|
.into_any_element()
|
|
}
|
|
AutoUpdateStatus::Idle
|
|
| AutoUpdateStatus::Checking { .. }
|
|
| AutoUpdateStatus::Downloading { .. }
|
|
| AutoUpdateStatus::Installing { .. } => Empty.into_any_element(),
|
|
}
|
|
}
|
|
}
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use auto_update::VersionCheckType;
|
|
use release_channel::AppCommitSha;
|
|
use semver::Version;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_version_tooltip_message() {
|
|
let message = UpdateVersion::version_tooltip_message(&VersionCheckType::Semantic(
|
|
Version::new(1, 0, 0),
|
|
));
|
|
|
|
assert_eq!(message, "Version: 1.0.0");
|
|
|
|
let message = UpdateVersion::version_tooltip_message(&VersionCheckType::Sha(
|
|
AppCommitSha::new("14d9a4189f058d8736339b06ff2340101eaea5af".to_string()),
|
|
));
|
|
|
|
assert_eq!(message, "Version: 14d9a41…");
|
|
}
|
|
}
|