Persist the workbench session across the editor/processor switch - #7654
Persist the workbench session across the editor/processor switch#7654EthanHealy01 wants to merge 4 commits into
Conversation
Mirror the open files, selection, active document and current view into per-tab sessionStorage, and refill an empty workbench from that record on the next mount, so switching to the processor (or reloading) no longer costs the user their workbench. The processor sidebar's switch back lands on the editor tool the user left, and the app switch now routes through the unsaved-changes guard. Restored files re-enter through the same FileContext entry point My Files uses, resolved to their current leaf version, so policy auto-run's persisted dispatch record keeps upload policies (and their billing) from firing a second time. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
🌐 TOML Translation Verification Summary🔄 Reference Branch:
|
📦 Tauri Desktop Builds Ready!The desktop applications have been built and are ready for testing. Download Artifacts:🍎 macOS Universal: Download Stirling-PDF-macos-universal (.dmg) - 340.4 MB Built from commit 6af209f |
Two fallout fixes from the workbench session restore: - reopenView wrote the recorded view once and then re-asserted it after the files hydrated, which also overwrote a view picked in between. Holding the restore guard is what keeps HomePage's defaults off it, so drop the second write. - engine-capabilities reopened the file from the library after a reload, but the restore now leaves it already open, and that button toggles an open file back out. The viewer already shows it, so assert the tile directly. The round-trip spec asserted the editor's file list emptied on the switch; the processor shell does not mount in the default build, so assert the URL and the recorded session instead, then load the editor cold for the return. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Some edge cases AI picked up on: Sign-out doesn't clear the record, so the next user in that tab gets the previous user's workbench (Med). Nothing removes stirling.workbench.session anywhere, and fileStorage.clearAll() exists but isn't called on sign-out either. User A works, signs out, user B signs in in the same tab, and B's editor opens with A's documents loaded. Those files were already reachable via My Files since IndexedDB is per-origin — so it's not a new data path, but it goes from "B could go looking" to "B's workbench opens with them in it", which is a different conversation with a customer. One line to clear the key. A failed write leaves a stale record rather than none (Low). setItem is atomic, so on quota exhaustion nothing is written and the previous record survives — the next restore rebuilds an older file set. Silently wrong rather than absent. A removeItem in the catch makes the failure mode "no restore" instead of "wrong restore". The 5-second settle timeout is a guess, and losing it loses the view, not the files (Low). Past SETTLE_TIMEOUT_MS the guard releases and HomePage's default-view heuristic can overwrite the recorded view. On a slow device with large PDFs you get your files back on the wrong screen, which reads as half-broken. Plus two nits: no schema version (a future shape change would silently restore zero files rather than being discarded), and the "Restored 0 of 5 files. The rest are no longer stored" toast is reachable in the total-loss case, where "the rest" is all of them. One piece of context that raises the stakes on the first item: WORKBENCH_SESSION_RESTORE is true in both core and proprietary, so this ships enabled rather than dark. The sign-out case is live on day one. CONNOR COMMENTS:
|
Review feedback on the session persistence PR. A tab outlives a session, so the record needed an owner and a way to disappear: - Records carry the signed-in user, and a restore refuses (and clears) one left by someone else - a 401 bounce or an expiry drops the next person on /login in the same tab, which clearing on the logout button alone misses. - Sign-out is detected from the identity going away rather than from any particular button, because SaaS signs out straight from the settings modal and several other paths never reach accountLogout. It suspends recording as well as clearing: signing out unmounts the editor, and that teardown flush would otherwise write the workbench straight back. - The editor's providers also mount on /login, so this records and restores nothing there instead of rebuilding the workbench behind the login form. - A failed write clears rather than leaving an older record to be restored. - The record is versioned, so a shape this build no longer trusts is discarded instead of half-read. - Total loss gets its own message rather than 'Restored 0 of N ... the rest'. - The view guard is held per hydrated file rather than one flat deadline, so a slow device does not get its files back on the wrong screen.
🚀 V2 Auto-Deployment Complete!🔗 Direct Test URL (non-SSL) http://54.175.155.236:7654 🧩 Admin portal included - try it at http://54.175.155.236:7654/portal. This deployment will be automatically cleaned up when the PR is closed. 🔄 Auto-deployed for approved V2 contributors. |
jbrunton96
left a comment
There was a problem hiding this comment.
Code looks good to me. Did an AI review of it and it brought up a couple of things which I've commented on the files
| useNavigationState, | ||
| useNavigationActions, | ||
| } from "@app/contexts/NavigationContext"; | ||
| import { isApplyingRestoredView } from "@app/services/workbenchSession"; |
There was a problem hiding this comment.
AI review:
HomePage.tsx:153 — the new leftFiles gate drops a guard unrelated to this feature, leaving the workbench stuck on the My Files grid at /editor after any HomePage remount (login bounce, share link).
| @@ -0,0 +1,284 @@ | |||
| // The editor/processor shell switch unmounts every editor provider, and a reload starts from nothing: | |||
| // this mirrors the workbench into sessionStorage and refills an empty one from that record on mount. | |||
| import { useCallback, useContext, useEffect, useRef, useState } from "react"; | |||
There was a problem hiding this comment.
AI review:
WorkbenchSessionPersistence.tsx:181 — a failed refreshSession() (SaaS team switch, password change) looks like a sign-out: the record is wiped and writes stay suspended for the rest of the page, since nothing resumes them when the identity returns.
|
A blip on the /auth/me check gets treated the same as a sign out, so the |
What
Switching editor -> processor (or reloading) unmounts every editor provider, which emptied the workbench. This PR mirrors the workbench into per-tab sessionStorage and refills an empty one from that record on the next mount:
useOtherAppSwitch(proprietary + saas) now routes throughrequestNavigation, so the same warning guards it as any other navigation.WorkbenchSessionPersistencewith a stub (OS-launched files own boot there).How to test
I've run through each of these manually: