feat: add nav store persistence and tmp file cleanup
Completes persistence story and crash recovery hardening. Nav store persistence: - Wraps nav store with zustand persist middleware - Persists activeView to localStorage under "mc-nav-store" - Remembers which view you were on across sessions Bridge tmp file cleanup (src-tauri/src/data/bridge.rs): - New cleanup_tmp_files() method removes orphaned .json.tmp files - Called on startup to clean up from crashes during save_map() - Logs cleaned files for debugging - Returns count of files removed The atomic write pattern (write to .tmp, then rename) can leave orphan files if the app crashes between write and rename. This cleanup ensures we don't accumulate stale tmp files over time. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -216,6 +216,33 @@ impl<L: LoreCli, B: BeadsCli> Bridge<L, B> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Clean up orphaned .tmp files from interrupted atomic writes.
|
||||
///
|
||||
/// Called on startup to remove any .json.tmp files left behind from
|
||||
/// crashes during save_map(). Returns the number of files cleaned up.
|
||||
pub fn cleanup_tmp_files(&self) -> Result<usize, BridgeError> {
|
||||
if !self.data_dir.exists() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let mut cleaned = 0;
|
||||
for entry in fs::read_dir(&self.data_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.extension().is_some_and(|e| e == "tmp") {
|
||||
tracing::info!("Cleaning up orphaned tmp file: {:?}", path);
|
||||
fs::remove_file(&path)?;
|
||||
cleaned += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if cleaned > 0 {
|
||||
tracing::info!("Cleaned up {} orphaned tmp file(s)", cleaned);
|
||||
}
|
||||
|
||||
Ok(cleaned)
|
||||
}
|
||||
|
||||
/// Save the mapping file atomically (write to .tmp, then rename)
|
||||
pub fn save_map(&self, map: &GitLabBeadMap) -> Result<(), BridgeError> {
|
||||
fs::create_dir_all(&self.data_dir)?;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
|
||||
export type ViewId = "focus" | "queue" | "inbox";
|
||||
|
||||
@@ -14,7 +15,14 @@ export interface NavState {
|
||||
setView: (view: ViewId) => void;
|
||||
}
|
||||
|
||||
export const useNavStore = create<NavState>((set) => ({
|
||||
activeView: "focus",
|
||||
setView: (view) => set({ activeView: view }),
|
||||
}));
|
||||
export const useNavStore = create<NavState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
activeView: "focus",
|
||||
setView: (view) => set({ activeView: view }),
|
||||
}),
|
||||
{
|
||||
name: "mc-nav-store",
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user