feat: use clientLoader + localStorage for resizable panel persistence#3387
feat: use clientLoader + localStorage for resizable panel persistence#3387devin-ai-integration[bot] wants to merge 3 commits intomainfrom
Conversation
Replace server-side cookie reading (getResizableSnapshot) with client-side localStorage for persisting resizable panel sizes. Cookies were hitting the ~4KB size limit; localStorage supports 5-10MB. - Run detail route: uses Remix clientLoader with hydrate=true to read panel snapshots from localStorage before first render - Prompts route: returns undefined for snapshots, letting the react-window-splitter library read from localStorage natively via autosaveStrategy="localStorage" Co-Authored-By: Eric Allam <eallam@icloud.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
Testing Results — clientLoader + localStorage Panel PersistenceRan the webapp locally against a fresh database with a completed task run. Tested the panel resize → localStorage persistence → reload restoration flow on the run detail route. Test Results
EvidenceAfter resizing tree panel (arrow keys moved divider left)localStorage values confirmed via DevTools consoleAfter page reload — panels restored to same positionHydration Warning (expected)This is inherent to the clientLoader pattern: the server has no access to localStorage, so it renders panels at default sizes. The clientLoader provides the saved sizes, causing React to detect a brief prop difference during hydration. The library self-corrects immediately and the UI displays correctly. Not Tested
|
…ize handles Co-Authored-By: Eric Allam <eallam@icloud.com>
Co-Authored-By: Eric Allam <eallam@icloud.com>
Summary
Replaces server-side cookie reading (
getResizableSnapshot) with client-side localStorage for persisting resizable panel sizes on two routes. Cookies were hitting the ~4KB size limit; localStorage supports 5–10MB.Two routes modified, two approaches used:
Run detail route (
runs.$runParam/route.tsx): Adds a RemixclientLoaderwithhydrate = truethat reads panel snapshots from localStorage before first render via agetLocalStorageSnapshothelper that validates the stored JSON shape.Prompts route (
prompts.$promptSlug/route.tsx): Simply removes the server-side cookie reads and returnsundefinedfor snapshots. Thereact-window-splitterlibrary already defaults toautosaveStrategy="localStorage"and reads from it when nosnapshotprop is provided. AclientLoaderwas not used here because this route usesremix-typedjson(typedjson/useTypedLoaderData), which doesn't compose cleanly withclientLoader.In both cases the library continues to automatically write to localStorage on resize (via
autosaveId), so no save-side changes were needed. TheresizablePanel.servermodule is left intact as it may be used by other routes.Review & Testing Checklist for Human
clientLoaderhere, the library's built-in localStorage read is doing the work — confirm it actually kicks in whensnapshotisundefined(keys:prompt-detail,prompt-vertical,prompt-generations)panel-run-parent-v2,panel-run-tree)clientLoader.hydrate = truepattern on the run detail route is the highest-risk area for hydration mismatchesNotes
getLocalStorageSnapshothelper checks for a"status"property to validate the stored shape. If the library ever changes its serialization format, this silently falls back to default panel sizes rather than crashing.remix-typedjsonconstraint but could be unified later ifremix-typedjsonis removed from the prompts route.Link to Devin session: https://app.devin.ai/sessions/2e69f1933945442e9daba486837a6f5b
Requested by: @ericallam