From 51c038053f156936e558a27bcec9705594dd2e9a Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 15 Feb 2024 09:56:45 +0100 Subject: [PATCH 1/4] Clear all blueprints in RAM and on disk when clicking "Reset Viewer" --- crates/re_ui/src/command.rs | 2 +- crates/re_viewer/src/app.rs | 11 +++++++--- crates/re_viewer/src/lib.rs | 35 +++++++++++++++++++++++++++++++ crates/re_viewer/src/store_hub.rs | 9 +++++++- crates/rerun/src/run.rs | 33 +---------------------------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/crates/re_ui/src/command.rs b/crates/re_ui/src/command.rs index fb8424f5fc43..22fe42c951c0 100644 --- a/crates/re_ui/src/command.rs +++ b/crates/re_ui/src/command.rs @@ -119,7 +119,7 @@ impl UICommand { Self::ResetViewer => ( "Reset Viewer", - "Reset the Viewer to how it looked the first time you ran it", + "Reset the Viewer to how it looked the first time you ran it, forgetting all stored blueprints and UI state", ), #[cfg(not(target_arch = "wasm32"))] diff --git a/crates/re_viewer/src/app.rs b/crates/re_viewer/src/app.rs index 303f1794190b..117b74a34285 100644 --- a/crates/re_viewer/src/app.rs +++ b/crates/re_viewer/src/app.rs @@ -374,7 +374,7 @@ impl App { // By clearing the blueprint it will be re-populated with the defaults // at the beginning of the next frame. re_log::debug!("Reset blueprint"); - store_hub.clear_blueprint(); + store_hub.clear_current_blueprint(); } SystemCommand::UpdateBlueprint(blueprint_id, updates) => { // We only want to update the blueprint if the "inspect blueprint timeline" mode is @@ -1048,12 +1048,17 @@ impl App { /// Reset the viewer to how it looked the first time you ran it. fn reset(&mut self, store_hub: &mut StoreHub, egui_ctx: &egui::Context) { self.state = Default::default(); - store_hub.clear_blueprint(); - // Keep the style: + store_hub.clear_all_blueprints(); + + // Reset egui, but keep the style: let style = egui_ctx.style(); egui_ctx.memory_mut(|mem| *mem = Default::default()); egui_ctx.set_style((*style).clone()); + + if let Err(err) = crate::reset_viewer_persistence() { + re_log::warn!("Failed to reset viewer: {err}"); + } } pub fn recording_db(&self) -> Option<&EntityDb> { diff --git a/crates/re_viewer/src/lib.rs b/crates/re_viewer/src/lib.rs index dd325eba9612..f5eec351ee1e 100644 --- a/crates/re_viewer/src/lib.rs +++ b/crates/re_viewer/src/lib.rs @@ -234,3 +234,38 @@ pub fn wake_up_ui_thread_on_each_msg( .unwrap(); new_rx } + +/// Reset the viewer state as stored on disk, keeping only the analytics state. +pub fn reset_viewer_persistence() -> anyhow::Result<()> { + // TODO(#2579): implement web-storage for blueprints as well, and clear it here + + #[cfg(not(target_arch = "wasm32"))] + { + let Some(data_dir) = eframe::storage_dir(native::APP_ID) else { + anyhow::bail!("Failed to figure out where Rerun stores its data.") + }; + + // Note: `remove_dir_all` fails if the directory doesn't exist. + if data_dir.exists() { + // Keep analytics, because it is used to uniquely identify users over time. + let analytics_file_path = data_dir.join("analytics.json"); + let analytics = std::fs::read(&analytics_file_path); + + if let Err(err) = std::fs::remove_dir_all(&data_dir) { + anyhow::bail!("Failed to remove {data_dir:?}: {err}"); + } else { + re_log::info!("Cleared {data_dir:?}."); + } + + if let Ok(analytics) = analytics { + // Restore analytics.json: + std::fs::create_dir(&data_dir).ok(); + std::fs::write(&analytics_file_path, analytics).ok(); + } + } else { + re_log::info!("Rerun state was already cleared."); + } + } + + Ok(()) +} diff --git a/crates/re_viewer/src/store_hub.rs b/crates/re_viewer/src/store_hub.rs index 2fc9710a87e6..5cb6ff9c6f8b 100644 --- a/crates/re_viewer/src/store_hub.rs +++ b/crates/re_viewer/src/store_hub.rs @@ -186,7 +186,7 @@ impl StoreHub { } /// Clear the current blueprint - pub fn clear_blueprint(&mut self) { + pub fn clear_current_blueprint(&mut self) { if let Some(app_id) = &self.selected_application_id { if let Some(blueprint_id) = self.blueprint_by_app_id.remove(app_id) { self.store_bundle.remove(&blueprint_id); @@ -194,6 +194,13 @@ impl StoreHub { } } + /// Forgets all blueprints + pub fn clear_all_blueprints(&mut self) { + for (_app_id, blueprint_id) in self.blueprint_by_app_id.drain() { + self.store_bundle.remove(&blueprint_id); + } + } + /// Insert a new recording into the [`StoreHub`]. /// /// Note that the recording is not automatically made active. Use [`StoreHub::set_recording_id`] diff --git a/crates/rerun/src/run.rs b/crates/rerun/src/run.rs index 8274093477db..c571bd2b4b1c 100644 --- a/crates/rerun/src/run.rs +++ b/crates/rerun/src/run.rs @@ -381,7 +381,7 @@ where Command::Print(print_command) => print_command.run(), #[cfg(feature = "native_viewer")] - Command::Reset => reset_viewer(), + Command::Reset => re_viewer::reset_viewer_persistence(), } } else { run_impl(build_info, call_source, args).await @@ -880,34 +880,3 @@ fn parse_max_latency(max_latency: Option<&String>) -> f32 { .unwrap_or_else(|err| panic!("Failed to parse max_latency ({max_latency:?}): {err}")) }) } - -#[cfg(feature = "native_viewer")] -fn reset_viewer() -> anyhow::Result<()> { - let Some(data_dir) = re_viewer::external::eframe::storage_dir(re_viewer::native::APP_ID) else { - anyhow::bail!("Failed to figure out where Rerun stores its data.") - }; - - // Note: `remove_dir_all` fails if the directory doesn't exist. - if data_dir.exists() { - // Keep analytics, because it is used to uniquely identify users over time. - let analytics_file_path = data_dir.join("analytics.json"); - let analytics = std::fs::read(&analytics_file_path); - - if let Err(err) = std::fs::remove_dir_all(&data_dir) { - anyhow::bail!("Failed to remove {data_dir:?}: {err}"); - } else { - eprintln!("Cleared {data_dir:?}."); - } - - if let Ok(analytics) = analytics { - // Restore analytics.json: - std::fs::create_dir(&data_dir).ok(); - std::fs::write(&analytics_file_path, analytics).ok(); - } - - Ok(()) - } else { - eprintln!("Rerun state was already cleared."); - Ok(()) - } -} From 3233c41d4d4001f566f954f13bf8c4ffb7bd039e Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 15 Feb 2024 10:05:39 +0100 Subject: [PATCH 2/4] Clear egui and app state in web local storage --- crates/re_viewer/src/lib.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/crates/re_viewer/src/lib.rs b/crates/re_viewer/src/lib.rs index f5eec351ee1e..eeac6c6c1dda 100644 --- a/crates/re_viewer/src/lib.rs +++ b/crates/re_viewer/src/lib.rs @@ -235,10 +235,10 @@ pub fn wake_up_ui_thread_on_each_msg( new_rx } -/// Reset the viewer state as stored on disk, keeping only the analytics state. +/// Reset the viewer state as stored on disk and local storage, +/// keeping only the analytics state. +#[allow(clippy::unnecessary_wraps)] // wasm only pub fn reset_viewer_persistence() -> anyhow::Result<()> { - // TODO(#2579): implement web-storage for blueprints as well, and clear it here - #[cfg(not(target_arch = "wasm32"))] { let Some(data_dir) = eframe::storage_dir(native::APP_ID) else { @@ -266,6 +266,19 @@ pub fn reset_viewer_persistence() -> anyhow::Result<()> { re_log::info!("Rerun state was already cleared."); } } + #[cfg(target_arch = "wasm32")] + { + // TODO(emilk): eframe should have an API for this. + if let Some(storage) = web_sys::window() + .and_then(|w| w.local_storage().ok()) + .flatten() + { + storage.delete("egui").ok(); + storage.delete(eframe::APP_KEY).ok(); + } + + // TODO(#2579): implement web-storage for blueprints as well, and clear it here + } Ok(()) } From 1df2d6f03b32c2ba6b7e8e29a1d1fc949568faf6 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 15 Feb 2024 10:08:35 +0100 Subject: [PATCH 3/4] Add missing web_sys feature flag --- crates/re_viewer/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/re_viewer/Cargo.toml b/crates/re_viewer/Cargo.toml index 749db3cd6c08..5eb8fb025b16 100644 --- a/crates/re_viewer/Cargo.toml +++ b/crates/re_viewer/Cargo.toml @@ -113,6 +113,7 @@ web-sys = { workspace = true, features = [ 'Url', 'UrlSearchParams', 'Window', + "Storage", ] } From 6693fc4968ffb24bd89e262b25ef06ac9d171576 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 15 Feb 2024 10:43:17 +0100 Subject: [PATCH 4/4] Fix local storage key --- crates/re_viewer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/re_viewer/src/lib.rs b/crates/re_viewer/src/lib.rs index eeac6c6c1dda..d7f194780a73 100644 --- a/crates/re_viewer/src/lib.rs +++ b/crates/re_viewer/src/lib.rs @@ -273,7 +273,7 @@ pub fn reset_viewer_persistence() -> anyhow::Result<()> { .and_then(|w| w.local_storage().ok()) .flatten() { - storage.delete("egui").ok(); + storage.delete("egui_memory_ron").ok(); storage.delete(eframe::APP_KEY).ok(); }