Skip to content

feat(editor): add undo/redo buttons to viewer toolbar - #648

Open
rkolpakov-sudo wants to merge 2 commits into
pascalorg:mainfrom
rkolpakov-sudo:feat/undo-redo-toolbar
Open

feat(editor): add undo/redo buttons to viewer toolbar#648
rkolpakov-sudo wants to merge 2 commits into
pascalorg:mainfrom
rkolpakov-sudo:feat/undo-redo-toolbar

Conversation

@rkolpakov-sudo

@rkolpakov-sudo rkolpakov-sudo commented Aug 14, 2026

Copy link
Copy Markdown

What does this PR do?

Adds Undo/Redo buttons to the viewer toolbar (top-left, next to the collapse and view-mode controls). The buttons subscribe to the history store via subscribeHistoryCommandState and dispatch through runUndo/runRedo, which respect the collaborative history delegate and fall back to standalone Zundo when no controller is installed. Buttons disable when nothing can be undone/redone.

Keyboard shortcuts were already wired (Ctrl/Cmd+Z undo, Ctrl/Cmd+Shift+Z redo) and command palette entries already existed; this PR adds the visible toolbar affordance and the CHANGELOG entry.

How to test

  1. Run bun dev and open the editor at http://localhost:3002
  2. Create or move a node in the 3D view
  3. Click the Undo button — the action is reverted; click Redo — it is reapplied
  4. With an empty history, both buttons are disabled
  5. Press Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z to confirm the keyboard shortcuts still work alongside the buttons

Screenshots / screen recording

N/A — visual change; a screen recording will be added if requested.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

Note

Low Risk
UI-only addition that reuses existing history APIs; no changes to undo/redo or scene mutation logic.

Overview
Adds Undo and Redo controls to the top-left community viewer toolbar (between sidebar collapse and 3D/2D/split view mode).

A new HistoryControls block subscribes to subscribeHistoryCommandState, reads canUndo / canRedo via getHistoryCommandState, and invokes runUndo / runRedo so behavior matches the command palette and keyboard shortcuts (including collaborative history when a delegate is set). Buttons use the same toolbar styling as other controls and are visually disabled when history is empty. CHANGELOG documents the feature under Unreleased → Features.

Reviewed by Cursor Bugbot for commit 55a63b6. Bugbot is set up for automated code reviews on this repo. Configure here.

@Aymericr Aymericr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, and apologies for the slow response. The feature is one we want, and you found the right seam — routing through runUndo/runRedo rather than reaching into the history store directly is exactly right, and it means the buttons honor the collaborative delegate for free.

One structural change before it lands. apps/editor is our standalone app; the hosted editor has its own toolbar, so as written this ships to one surface and the hosted one still has no undo button. Could you move HistoryControls into packages/editor — it belongs next to src/lib/history.ts, alongside the command-palette entries that already call the same API — and export it from the barrel? Then both toolbars can use one implementation. You'll need to either lift TOOLBAR_CONTAINER/TOOLBAR_BTN alongside it or take them as props; either is fine by me.

Two smaller things while you're in there:

  • Please use useSyncExternalStore instead of useState + useEffect. It's the pattern we use everywhere else for this (use-plugin-panels.tsx, plugins-panel.tsx, site-panel/index.tsx), and it closes the gap where an update between first render and effect commit gets dropped.
  • Use real disabled rather than aria-disabled plus a guard in the handler — the guard works, but the button stays focusable and clickable, and disabled is simpler.

For the CHANGELOG, our entries end with the PR link and your attribution, and stay at the user-facing level — no need to name subscribeHistoryCommandState. Have a look at the neighbouring entries for the shape.

Last thing: right now it sits between the sidebar collapse and the view-mode switcher, which puts history in the middle of the view controls. I'd rather it were its own group — let me know if you want a suggestion on placement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants