diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-16 01:09:25 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-16 01:09:25 +0300 |
| commit | ef1c6b1497fd0ad26e9d32f301ffb801cb96aa40 (patch) | |
| tree | f80cbb5fc67eb2796c932a9fdd5315ce3d21d18e /src/app | |
| parent | d76a5b8cec72b420b340a13ea186ea169b39b69e (diff) | |
fix: switch updates to manual preview flow
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/actions.rs | 22 | ||||
| -rw-r--r-- | src/app/input.rs | 33 | ||||
| -rw-r--r-- | src/app/mod.rs | 26 |
3 files changed, 65 insertions, 16 deletions
diff --git a/src/app/actions.rs b/src/app/actions.rs index fcdeff92..ffb41ba1 100644 --- a/src/app/actions.rs +++ b/src/app/actions.rs @@ -481,8 +481,8 @@ impl AppState { self.update_dismissed = true; self.toast = Some(ToastNotification { kind: ToastKind::UpdateInstalled, - title: format!("updated to v{version}"), - context: "restart to use it".to_string(), + title: format!("v{version} available"), + context: "run `herdr update`".to_string(), }); Vec::new() } @@ -1009,6 +1009,24 @@ mod tests { } #[test] + fn update_ready_sets_manual_update_toast() { + let mut state = AppState::test_new(); + + let updates = state.handle_app_event(AppEvent::UpdateReady { + version: "0.5.0".into(), + }); + + assert!(updates.is_empty()); + assert_eq!(state.update_available.as_deref(), Some("0.5.0")); + assert!(state.latest_release_notes_available); + assert!(state.update_dismissed); + let toast = state.toast.as_ref().expect("update toast"); + assert_eq!(toast.kind, ToastKind::UpdateInstalled); + assert_eq!(toast.title, "v0.5.0 available"); + assert_eq!(toast.context, "run `herdr update`"); + } + + #[test] fn toggle_fullscreen_works() { let mut state = app_with_workspaces(&["test"]); state.workspaces[0].test_split(Direction::Horizontal); diff --git a/src/app/input.rs b/src/app/input.rs index 347d8e41..dbc2547d 100644 --- a/src/app/input.rs +++ b/src/app/input.rs @@ -1446,7 +1446,10 @@ impl AppState { } fn release_notes_modal_inner(&self) -> Option<ratatui::layout::Rect> { - self.onboarding_modal_inner(76, 20) + self.onboarding_modal_inner( + crate::ui::RELEASE_NOTES_MODAL_SIZE.0, + crate::ui::RELEASE_NOTES_MODAL_SIZE.1, + ) } fn release_notes_close_button_at(&self, col: u16, row: u16) -> bool { @@ -1473,7 +1476,12 @@ impl AppState { if inner.height < 8 || inner.width < 4 { return None; } - Some(crate::ui::modal_stack_areas(inner, 2, 1, 0, 1).content) + let body = crate::ui::modal_stack_areas(inner, 2, 1, 0, 1).content; + let preview = self + .release_notes + .as_ref() + .is_some_and(|notes| notes.preview); + Some(crate::ui::release_notes_sections(body, preview).notes_body) } fn release_notes_scroll_metrics(&self) -> Option<crate::pane::ScrollMetrics> { @@ -1774,14 +1782,12 @@ impl AppState { pub(crate) fn global_menu_labels(&self) -> Vec<&'static str> { let mut labels = vec!["settings", "keybinds", "reload keybinds"]; - if self.latest_release_notes_available || self.update_available.is_some() { + if self.update_available.is_some() { + labels.push("update available"); + } else if self.latest_release_notes_available { labels.push("what's new"); } - labels.push(if self.update_available.is_some() { - "quit to apply update" - } else { - "quit" - }); + labels.push("quit"); labels } @@ -1791,7 +1797,10 @@ impl AppState { let labels = self.global_menu_labels(); let content_width = labels .iter() - .map(|label| label.chars().count() as u16) + .map(|label| { + let extra = if *label == "update available" { 2 } else { 0 }; + label.chars().count() as u16 + extra + }) .max() .unwrap_or(8) .saturating_add(2); @@ -4269,7 +4278,7 @@ mod tests { } #[test] - fn update_pending_menu_surfaces_quit_to_apply_update_action() { + fn update_available_menu_surfaces_update_status_without_apply_action() { let mut app = app_for_mouse_test(); app.state.update_available = Some("0.3.2".into()); app.state.latest_release_notes_available = true; @@ -4287,8 +4296,8 @@ mod tests { "settings", "keybinds", "reload keybinds", - "what's new", - "quit to apply update" + "update available", + "quit" ] ); diff --git a/src/app/mod.rs b/src/app/mod.rs index 165a6ff3..36b00033 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -205,7 +205,12 @@ impl App { "using pane scrollback configuration" ); - let latest_release_notes_available = crate::release_notes::load_latest().is_some(); + let latest_release_notes = crate::release_notes::load_latest(); + let update_available = latest_release_notes + .as_ref() + .filter(|notes| notes.preview) + .map(|notes| notes.version.clone()); + let latest_release_notes_available = latest_release_notes.is_some(); let mode = if config.should_show_onboarding() { state::Mode::Onboarding @@ -261,7 +266,7 @@ impl App { tab_press: None, selection: None, context_menu: None, - update_available: None, + update_available, latest_release_notes_available, update_dismissed: false, config_diagnostic, @@ -1362,6 +1367,23 @@ mod tests { } #[test] + fn startup_restores_preview_update_available_from_saved_notes() { + let _guard = config_env_lock().lock().unwrap(); + let path = temp_config_path("startup-preview-update-available"); + std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path); + + crate::release_notes::save_pending("0.5.0", "### Changed\n- One").unwrap(); + + let app = test_app(); + + assert_eq!(app.state.update_available.as_deref(), Some("0.5.0")); + assert!(app.state.latest_release_notes_available); + + std::env::remove_var(crate::config::CONFIG_PATH_ENV_VAR); + let _ = std::fs::remove_dir_all(path.parent().unwrap()); + } + + #[test] fn reload_keybinds_updates_live_state() { let _guard = config_env_lock().lock().unwrap(); let path = temp_config_path("reload-keybinds-success"); |
