Repository navigation
Conversation
A host may drop the armed tool when the rail panel changes (the community does, with any placement in flight). B and F armed first, so pressed from any other panel they opened Build or Items in select mode. Now that the rail reopens on the panel left open, that is the first thing a reload offers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e, and a tab saves only what changed A blob that failed to parse left `persist.hasHydrated()` false for the session, so the gate never opened: nothing was saved again, and the bad blob was never replaced. It now counts as none, hydration finishes on the defaults, and the next save replaces it. `persist` saves the whole state on every set, so a second tab replaced the panel picked in the first on its next update, even one that changed no preference. A save of the blob the tab already holds is now skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed sidebar opens onto the one picked While the rail lacks the panel picked in a workspace (a plugin panel joins once the scene's plugins load, or the plugin is gone), the layout showed its first panel but the store kept the missing id, so host readers (the getting started guide, the navbar, the agent's view of the editor) disagreed with the screen. The store now follows what shows; the pick stays in `sidebarPanels` and comes back once the rail has it. Reopening a collapsed sidebar expanded it before switching panels, so the panel left open opened for a moment, and a host that arms a panel's tool as it opens (Paint) armed it on the way to another one. `showSidebarPanel(id)` picks first, then expands; the rail click and `openSidebarPanel` use it, and hosts get it for their own entry points. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Follow-up to #1036 (the rail panel and preferences survive a reload). It fixes what the review of that work found.
activeSidebarPanelis the panel on screen. When the rail lacks the panel picked in a workspace, the layout shows its first panel. Two cases: a plugin panel joins only once the scene's plugins load, or the plugin is gone. Until now the store kept the missing id, so host code that reads it disagreed with the screen. Examples in Community: the getting-started guide could keep asking for the Build panel while Build was open, and on mobile the navbar hid Share for an Item builder the screen no longer showed.useShownSidebarPanel(lib/sidebar-panel.ts) now writes the panel it shows intoactiveSidebarPaneland leaves the pick insidebarPanels, so the pick still comes back once the rail has it. This removes the old "adopt the shown tab" effect, and with it the stale-closure path from the Bugbot thread on editor: the rail panel and preferences survive a reload #1036.openSidebarPanelexpanded first and switched panels second. For a moment, the panel left open was the open one. Community arms the paint brush when Paint opens, so reopening a sidebar collapsed on Paint onto Chat armed Paint on the way: that cleared the selection, replaced the paint material and left the Site phase. The newshowSidebarPanel(id)picks first, then expands at a usable width. The rail click andopenSidebarPaneluse it, and it is exported for hosts' own entry points.hooks/use-keyboard.ts). A host may drop the armed tool when the panel changes (Community does), so B or F pressed from any other panel opened Build or Items in select mode. Since the rail now reopens on the panel left open, that is the first thing a reload offers.lib/hydration-gated-storage.ts):hasHydrated()stayed false for the session, so nothing was saved again and the bad blob was never replaced.persistwrites the whole state on everyset, so a second tab's next update, even one that changed no preference, replaced the panel picked in the first.wiki/architecture/plugin-authoring.md:activeSidebarPanelis the panel on screen,showSidebarPanel, and a tab saves its preferences only when they change.Why
From the owner's feedback (plan row D1, verbatim):
#1036 made the panel survive a reload. The review of it (Claude and GPT-6 Astra) found these defects, each of them reachable after a reload.
How to test
In the Community app (hosted PR pascalorg/private-editor#896):
localStorage['pascal-editor-ui-preferences']and reload. The editor opens on its defaults, and the next change saves a valid blob.Automated, run from the private-editor worktree root against this branch:
bun test editor/packages/editor/src/store/opens-in-select-mode.test.ts editor/packages/editor/src/hooks/use-keyboard.test.ts: 35 pass. Each of the four new tests fails without its fix:bun test editor/packages/editor/src: 2061 pass, 19 fail. All 19 failures are inlib/history.test.tsand fail the same way onmainwhen run from the private-editor root: its child process prints aTHREE_CJS_DEPRECATEDwarning to stderr, which the test reads as a failure.bunx turbo run check-types --filter='./editor/packages/*': 9/9.biome checkon the changed files with this repo's config: clean.Screenshots / screen recording
Not added here. The behaviour was checked in the running Community app; the hosted PR lists what was checked.
Deployment notes
feedback/sidebar-review-pin(f88b020): the same three commits on editor: the rail panel and preferences survive a reload #1036's content, on the base the hostedmainpins (80d7a2f). Editormainafter Interior views in view_scene, paint and search_materials with native scene materials #1034 adds thepaintandsearch_materialscontracts, which the hosted chat does not register yet, so the hosted parity test fails on any SHA that includes it. The landing step re-bumps the hosted gitlink to this PR's merge commit once the hosted side of Interior views in view_scene, paint and search_materials with native scene materials #1034 is in.Supersedes
Nothing. It follows #1036.
Review
Fixed:
Rejected:
selectMaterialcalls the model'ssetActivePaintMaterial, which is bound toarmMaterialPaint(lib/material-paint-panel-model.ts). Checked in the app, and pinned by the hosted e2e.createJSONStorage.mainbefore editor: the rail panel and preferences survive a reload #1036 (the tab does not change and the panel stays mounted), and D1 does not ask for it.Checklist
bun dev(tested through the Community dev server, not this repo'sbun dev)bun checkto verify) (biome checkon the changed files)mainbranch🤖 Generated with Claude Code
Note
Medium Risk
Touches editor UI state, keyboard shortcuts, and localStorage persistence across tabs; behavior changes are user-visible but covered by new tests and follow-on to sidebar persistence work.
Overview
Aligns sidebar state with what users actually see and fixes ordering bugs when reopening panels or using keyboard shortcuts.
activeSidebarPanelnow matches the panel on screen.useShownSidebarPanelwrites the displayed tab intoactiveSidebarPanelwhen the rail is missing a remembered pick (e.g. plugin tabs not loaded yet), whilesidebarPanelskeeps the preference so it restores once the tab appears.showSidebarPanel(id)(exported) sets the panel before expanding a collapsed sidebar; rail clicks andopenSidebarPaneluse it so hosts do not briefly mount the wrong panel (e.g. Paint arming on the way to Chat).B and F open Build/Items before arming wall/item tools so hosts that reset tools on panel change still end in the right mode.
Persisted UI storage (
hydration-gated-storage): corruptlocalStorageno longer blocks hydration forever; writes are skipped when the serialized blob is unchanged so another tab’s stale in-memory state does not overwrite a newer saved panel.Reviewed by Cursor Bugbot for commit 3450f45. Bugbot is set up for automated code reviews on this repo. Configure here.