settings_ui: Show migration banner (#41112)

Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...

---------

Co-authored-by: Danilo <danilo@zed.dev>
This commit is contained in:
Ben Kunkle
2025-10-27 10:13:26 -04:00
committed by GitHub
co-authored by Danilo
parent 5d359ea2f2
commit 2f7045f724
14 changed files with 373 additions and 144 deletions
+67 -31
View File
@@ -1139,6 +1139,7 @@ impl SettingsUiFile {
settings::SettingsFile::Project(location) => SettingsUiFile::Project(location),
settings::SettingsFile::Server => SettingsUiFile::Server("todo: server name"),
settings::SettingsFile::Default => return None,
settings::SettingsFile::Global => return None,
})
}
@@ -1730,7 +1731,10 @@ impl SettingsWindow {
let prev_files = self.files.clone();
let settings_store = cx.global::<SettingsStore>();
let mut ui_files = vec![];
let all_files = settings_store.get_all_files();
let mut all_files = settings_store.get_all_files();
if !all_files.contains(&settings::SettingsFile::User) {
all_files.push(settings::SettingsFile::User);
}
for file in all_files {
let Some(settings_ui_file) = SettingsUiFile::from_settings(file) else {
continue;
@@ -2685,40 +2689,72 @@ impl SettingsWindow {
if let Some(error) =
SettingsStore::global(cx).error_for_file(self.current_file.to_settings())
{
if self.shown_errors.insert(error.clone()) {
telemetry::event!("Settings Error Shown", error = &error);
}
warning_banner = v_flex()
.pb_4()
.child(
Banner::new()
.severity(Severity::Warning)
.child(
v_flex()
.my_0p5()
.gap_0p5()
.child(Label::new("Your settings file is in an invalid state."))
.child(
Label::new(error).size(LabelSize::Small).color(Color::Muted),
),
)
.action_slot(
div().pr_1().child(
Button::new("fix-in-json", "Fix in settings.json")
.tab_index(0_isize)
.style(ButtonStyle::Tinted(ui::TintColor::Warning))
.on_click(cx.listener(|this, _, _, cx| {
this.open_current_settings_file(cx);
})),
),
fn banner(
label: &'static str,
error: String,
shown_errors: &mut HashSet<String>,
cx: &mut Context<SettingsWindow>,
) -> impl IntoElement {
if shown_errors.insert(error.clone()) {
telemetry::event!("Settings Error Shown", label = label, error = &error);
}
Banner::new()
.severity(Severity::Warning)
.child(
v_flex()
.my_0p5()
.gap_0p5()
.child(Label::new(label))
.child(Label::new(error).size(LabelSize::Small).color(Color::Muted)),
)
.action_slot(
div().pr_1().child(
Button::new("fix-in-json", "Fix in settings.json")
.tab_index(0_isize)
.style(ButtonStyle::Tinted(ui::TintColor::Warning))
.on_click(cx.listener(|this, _, _, cx| {
this.open_current_settings_file(cx);
})),
),
)
)
}
let parse_error = error.parse_error();
let parse_failed = parse_error.is_some();
warning_banner = v_flex()
.gap_2()
.pb_4()
.when_some(parse_error, |this, err| {
this.child(banner(
"Failed to load your settings. Some values may be incorrect and changes may be lost.",
err,
&mut self.shown_errors,
cx,
))
})
.map(|this| match &error.migration_status {
settings::MigrationStatus::Succeeded => this.child(banner(
"Your settings are out of date, and need to be updated.",
match &self.current_file {
SettingsUiFile::User => "They can be automatically migrated to the latest version.",
SettingsUiFile::Server(_) | SettingsUiFile::Project(_) => "They must be manually migrated to the latest version."
}.to_string(),
&mut self.shown_errors,
cx,
)),
settings::MigrationStatus::Failed { error: err } if !parse_failed => this
.child(banner(
"Your settings file is out of date, automatic migration failed",
err.clone(),
&mut self.shown_errors,
cx,
)),
_ => this,
})
.into_any_element()
}
return v_flex()
.id("Settings-ui-page")
.id("settings-ui-page")
.on_action(cx.listener(|this, _: &menu::SelectNext, window, cx| {
if !sub_page_stack().is_empty() {
window.focus_next();
@@ -2789,8 +2825,8 @@ impl SettingsWindow {
.pt_6()
.px_8()
.bg(cx.theme().colors().editor_background)
.child(warning_banner)
.child(page_header)
.child(warning_banner)
.child(
div()
.size_full()