diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-20 00:34:04 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-20 00:34:04 +0300 |
| commit | ff8e5a14abe445a61dc200fd30a70870c75d183c (patch) | |
| tree | 53934152b2b7993a67c4c05ce54a58548310a7d5 /src/app | |
| parent | fb93e3747544afc3288d7b5e831d5ca3dd5c3768 (diff) | |
fix: stop auto-opening release notes on startup
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/input/mod.rs | 1 | ||||
| -rw-r--r-- | src/app/input/modal.rs | 45 | ||||
| -rw-r--r-- | src/app/input/navigate.rs | 3 | ||||
| -rw-r--r-- | src/app/input/terminal.rs | 1 | ||||
| -rw-r--r-- | src/app/mod.rs | 105 | ||||
| -rw-r--r-- | src/app/runtime.rs | 2 |
6 files changed, 124 insertions, 33 deletions
diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs index ae8fb12b..ad68f9da 100644 --- a/src/app/input/mod.rs +++ b/src/app/input/mod.rs @@ -295,7 +295,6 @@ fn app_for_mouse_test() -> App { &crate::config::Config::default(), true, None, - None, api_rx, crate::api::EventHub::default(), ); diff --git a/src/app/input/modal.rs b/src/app/input/modal.rs index 954f97de..ff5e8582 100644 --- a/src/app/input/modal.rs +++ b/src/app/input/modal.rs @@ -627,6 +627,23 @@ mod tests { use super::super::{capture_snapshot, state_with_workspaces}; use super::*; + fn config_env_lock() -> &'static std::sync::Mutex<()> { + static LOCK: std::sync::OnceLock<std::sync::Mutex<()>> = std::sync::OnceLock::new(); + LOCK.get_or_init(|| std::sync::Mutex::new(())) + } + + fn temp_config_path(name: &str) -> std::path::PathBuf { + let unique = format!( + "herdr-modal-{name}-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos() + ); + std::env::temp_dir().join(unique).join("config.toml") + } + #[test] fn custom_resize_key_exits_resize_mode() { let mut state = state_with_workspaces(&["test"]); @@ -643,6 +660,34 @@ mod tests { } #[test] + fn global_menu_whats_new_opens_saved_release_notes() { + let _guard = config_env_lock().lock().unwrap(); + let path = temp_config_path("whats-new-saved-release-notes"); + std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path); + crate::release_notes::save_pending(env!("CARGO_PKG_VERSION"), "### Changed\n- Menu") + .unwrap(); + + let mut state = state_with_workspaces(&["test"]); + state.latest_release_notes_available = true; + + assert!(global_menu_actions(&state).contains(&GlobalMenuAction::WhatsNew)); + + apply_global_menu_action(&mut state, GlobalMenuAction::WhatsNew); + + assert_eq!(state.mode, Mode::ReleaseNotes); + assert_eq!( + state + .release_notes + .as_ref() + .map(|notes| notes.body.as_str()), + Some("### Changed\n- Menu") + ); + + std::env::remove_var(crate::config::CONFIG_PATH_ENV_VAR); + let _ = std::fs::remove_dir_all(path.parent().unwrap()); + } + + #[test] fn rename_modal_keyboard_and_mouse_share_actions() { let mut state = state_with_workspaces(&["test"]); state.mode = Mode::RenameWorkspace; diff --git a/src/app/input/navigate.rs b/src/app/input/navigate.rs index e2e0993e..34d0a342 100644 --- a/src/app/input/navigate.rs +++ b/src/app/input/navigate.rs @@ -1035,7 +1035,6 @@ mod tests { &Config::default(), true, None, - None, api_rx, crate::api::EventHub::default(), ); @@ -1084,7 +1083,6 @@ mod tests { &Config::default(), true, None, - None, api_rx, crate::api::EventHub::default(), ); @@ -1153,7 +1151,6 @@ mod tests { &Config::default(), true, None, - None, api_rx, crate::api::EventHub::default(), ); diff --git a/src/app/input/terminal.rs b/src/app/input/terminal.rs index b5ceda12..12fb67b2 100644 --- a/src/app/input/terminal.rs +++ b/src/app/input/terminal.rs @@ -461,7 +461,6 @@ mod tests { &Config::default(), true, None, - None, api_rx, crate::api::EventHub::default(), ); diff --git a/src/app/mod.rs b/src/app/mod.rs index 39cf0c13..3e8a8b83 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -198,7 +198,6 @@ impl App { config: &Config, no_session: bool, config_diagnostic: Option<String>, - startup_release_notes: Option<crate::release_notes::ReleaseNotes>, api_rx: tokio::sync::mpsc::UnboundedReceiver<crate::api::ApiRequestMessage>, event_hub: crate::api::EventHub, ) -> Self { @@ -321,8 +320,6 @@ impl App { let mode = if config.should_show_onboarding() { state::Mode::Onboarding - } else if startup_release_notes.is_some() { - state::Mode::ReleaseNotes } else if startup_product_announcement.is_some() { state::Mode::ProductAnnouncement } else if active.is_some() { @@ -353,12 +350,7 @@ impl App { request_complete_onboarding: false, name_input: String::new(), name_input_replace_on_type: false, - release_notes: startup_release_notes.map(|notes| state::ReleaseNotesState { - version: notes.version, - body: notes.body, - scroll: 0, - preview: notes.preview, - }), + release_notes: None, product_announcement: startup_product_announcement.map(|announcement| { state::ProductAnnouncementState { version: announcement.version, @@ -1131,7 +1123,6 @@ mod tests { &Config::default(), true, None, - None, api_rx, crate::api::EventHub::default(), ) @@ -1154,6 +1145,14 @@ mod tests { std::env::temp_dir().join(unique).join("config.toml") } + fn restore_xdg_state_home(original: Option<std::ffi::OsString>) { + if let Some(value) = original { + std::env::set_var("XDG_STATE_HOME", value); + } else { + std::env::remove_var("XDG_STATE_HOME"); + } + } + #[test] fn git_refresh_deadline_is_suppressed_while_in_flight() { let mut app = test_app(); @@ -1204,14 +1203,7 @@ mod tests { config.ui.agent_panel_scope = crate::config::AgentPanelScopeConfig::Current; let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); - let app = App::new( - &config, - true, - None, - None, - api_rx, - crate::api::EventHub::default(), - ); + let app = App::new(&config, true, None, api_rx, crate::api::EventHub::default()); assert_eq!( app.state.agent_panel_scope, @@ -1255,6 +1247,74 @@ mod tests { } #[test] + fn startup_keeps_pending_release_notes_available_without_auto_opening() { + let _guard = config_env_lock().lock().unwrap(); + let path = temp_config_path("startup-pending-release-notes-no-auto-open"); + std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path); + + crate::release_notes::save_pending(env!("CARGO_PKG_VERSION"), "### Changed\n- One") + .unwrap(); + let config = Config { + onboarding: Some(false), + ..Default::default() + }; + let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); + + let app = App::new(&config, true, None, api_rx, crate::api::EventHub::default()); + + assert_eq!(app.state.mode, Mode::Navigate); + assert!(app.state.release_notes.is_none()); + 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 startup_still_auto_opens_unseen_product_announcement() { + let _guard = config_env_lock().lock().unwrap(); + let path = temp_config_path("startup-product-announcement-auto-open"); + let state_home = path.parent().unwrap().join("state"); + let original_xdg_state_home = std::env::var_os("XDG_STATE_HOME"); + std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path); + std::env::set_var("XDG_STATE_HOME", &state_home); + + crate::release_notes::save_pending(env!("CARGO_PKG_VERSION"), "### Changed\n- One") + .unwrap(); + crate::product_announcements::save_manifest_announcement( + env!("CARGO_PKG_VERSION"), + Some(&crate::product_announcements::ManifestAnnouncement { + id: "startup-announcement".into(), + title: Some("Startup announcement".into()), + body: "### Announcement\n- One".into(), + }), + ) + .unwrap(); + + let config = Config { + onboarding: Some(false), + ..Default::default() + }; + let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); + + let app = App::new(&config, true, None, api_rx, crate::api::EventHub::default()); + + assert_eq!(app.state.mode, Mode::ProductAnnouncement); + assert_eq!( + app.state + .product_announcement + .as_ref() + .map(|announcement| announcement.id.as_str()), + Some("startup-announcement") + ); + assert!(app.state.release_notes.is_none()); + + std::env::remove_var(crate::config::CONFIG_PATH_ENV_VAR); + restore_xdg_state_home(original_xdg_state_home); + let _ = std::fs::remove_dir_all(path.parent().unwrap()); + } + + #[test] fn reload_config_updates_live_state() { let _guard = config_env_lock().lock().unwrap(); let path = temp_config_path("reload-config-success"); @@ -1382,14 +1442,7 @@ mod tests { config.ui.sidebar_max_width = 30; let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); - let app = App::new( - &config, - true, - None, - None, - api_rx, - crate::api::EventHub::default(), - ); + let app = App::new(&config, true, None, api_rx, crate::api::EventHub::default()); assert_eq!( app.state.sidebar_min_width, 18, diff --git a/src/app/runtime.rs b/src/app/runtime.rs index 739d3548..5671bf38 100644 --- a/src/app/runtime.rs +++ b/src/app/runtime.rs @@ -419,7 +419,6 @@ mod tests { &crate::config::Config::default(), true, None, - None, tokio::sync::mpsc::unbounded_channel().1, crate::api::EventHub::default(), ); @@ -528,7 +527,6 @@ mod tests { &crate::config::Config::default(), true, None, - None, tokio::sync::mpsc::unbounded_channel().1, crate::api::EventHub::default(), ); |
