From ac789e8d5664896bf2dee8ad2f8ad320fb4b5533 Mon Sep 17 00:00:00 2001 From: Tristan Michael Date: Sun, 5 Apr 2026 14:29:30 -0700 Subject: [PATCH] Handle deleted/moved workspace folders (missing state) Detect when the current workspace folder cannot be opened and show a dedicated "missing" screen that explains the workspace was not found. Catch failures from get_lists during loadConfig, set a missingWorkspace state and switch to the missing screen, and provide forgetMissingWorkspace() to remove the missing workspace from the config and either switch to the next available workspace or fall back to the setup screen. Add UI in App.svelte to present the workspace name, explanation, and a Continue button that invokes forgetting the missing workspace. --- apps/tauri/src/App.svelte | 20 ++++++++++++- apps/tauri/src/lib/stores/app.svelte.ts | 37 ++++++++++++++++++++++++- apps/tauri/src/lib/types.ts | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/apps/tauri/src/App.svelte b/apps/tauri/src/App.svelte index 80d38ec..9154f58 100644 --- a/apps/tauri/src/App.svelte +++ b/apps/tauri/src/App.svelte @@ -29,7 +29,25 @@ {/if} - {#if app.screen === "setup"} + {#if app.screen === "missing"} +
+
+

Workspace Not Found

+

+ The workspace {app.missingWorkspace} could not be opened. Its folder may have been moved or deleted. +

+

+ It will be removed from your workspace list. You can re-add it if the folder becomes available again. +

+ +
+
+ {:else if app.screen === "setup"} {:else} diff --git a/apps/tauri/src/lib/stores/app.svelte.ts b/apps/tauri/src/lib/stores/app.svelte.ts index e6250c2..c69d472 100644 --- a/apps/tauri/src/lib/stores/app.svelte.ts +++ b/apps/tauri/src/lib/stores/app.svelte.ts @@ -25,6 +25,7 @@ let syncing = $state(false); let syncMode = $state<"full" | "push" | "pull">("full"); let lastSyncResult = $state(null); let error = $state(null); +let missingWorkspace = $state(null); // ── Derived ────────────────────────────────────────────────────────── @@ -70,8 +71,18 @@ async function loadConfig() { try { config = await invoke("get_config"); if (hasWorkspace) { + // Try loading lists — if the workspace path is gone, get_lists will fail + lists = []; + try { + lists = await invoke("get_lists"); + } catch { + missingWorkspace = config!.current_workspace; + screen = "missing"; + return; + } + if (lists.length > 0 && !activeListId) activeListId = lists[0].id; + if (activeListId) await loadTasks(); screen = "tasks"; - await loadLists(); } else { screen = "setup"; } @@ -343,6 +354,26 @@ async function addWebdavWorkspace(name: string, webdavUrl: string, webdavPath: s } } +async function forgetMissingWorkspace() { + if (!missingWorkspace) return; + await removeWorkspace(missingWorkspace); + missingWorkspace = null; + config = await invoke("get_config"); + if (hasWorkspace) { + // Switch to the next available workspace + const nextName = Object.keys(config!.workspaces)[0]; + if (nextName) { + await switchWorkspace(nextName); + screen = "tasks"; + return; + } + } + screen = "setup"; + lists = []; + tasks = []; + activeListId = null; +} + function setScreen(s: Screen) { screen = s; } @@ -399,6 +430,9 @@ export const app = { get hasWorkspace() { return hasWorkspace; }, + get missingWorkspace() { + return missingWorkspace; + }, getSubtasks, loadConfig, addWorkspace, @@ -422,6 +456,7 @@ export const app = { setSyncMode, setTheme, addWebdavWorkspace, + forgetMissingWorkspace, setScreen, clearError, }; diff --git a/apps/tauri/src/lib/types.ts b/apps/tauri/src/lib/types.ts index f8d0433..0bb1cab 100644 --- a/apps/tauri/src/lib/types.ts +++ b/apps/tauri/src/lib/types.ts @@ -44,4 +44,4 @@ export interface SyncResult { errors: string[]; } -export type Screen = "setup" | "tasks" | "settings"; +export type Screen = "setup" | "tasks" | "settings" | "missing";