Workspace has no undo history panel — user can press Cmd+Z to step back one entry at a time, no way to see the full history and pick a specific snapshot to revert to (Figma/Illustrator-style history panel) #255

Closed
opened 2026-10-04 03:36:29 +00:00 by Mark · 1 comment
Owner

Finding

src/components/workspace/useWorkspace.ts:201 defines MAX_HISTORY = 50. The history is tracked in state.history: HistoryState[] (per the type definition). The user can step through with Cmd+Z and Cmd+Shift+Z, but there's no UI to see the history list or click on a specific entry.

grep -n 'history.*panel\|HistoryList' src/components/workspace/ returns 0.

A user who:

  • Auto-digitizes
  • Tweaks the density
  • Re-does
  • Tweaks the color
  • Tries Cmd+Z a few times
  • Realizes they want the "first auto-digitize" version back
  • Can't — Cmd+Z only steps back one at a time, no way to "go to 5 steps back"

Figma, Illustrator, Sketch all have a "History" panel that lists every action with timestamps. The user clicks an entry to revert to that state.

Where

  • History state: src/components/workspace/useWorkspace.ts:201-214 (MAX_HISTORY = 50)
  • No panel: grep -n 'HistoryList' src/ returns 0
  • Cmd+Z: src/components/workspace/useWorkspace.ts (handleUndo / handleRedo)

Suggested fix shape

Add a "History" panel toggle to the right side of the workspace's top bar:

<button
  onClick={() => setShowHistoryPanel((v) => !v)}
  data-testid="toggle-history"
  title="Show history"
>
  <History size={14} />
</button>

The panel slides in from the right with a list of history entries:

{showHistoryPanel && (
  <div className="fixed right-0 top-0 bottom-0 w-80 bg-white border-l">
    <h3>History</h3>
    <ul>
      {state.history.map((entry, i) => (
        <li
          key={i}
          onClick={() => jumpToHistoryEntry(i)}
          className={i === state.historyIndex ? 'active' : ''}
        >
          <span>{describeSnapshot(entry)}</span>
          <span>{i === state.historyIndex ? 'current' : ''}</span>
        </li>
      ))}
    </ul>
  </div>
)}

describeSnapshot(entry) returns a human-readable summary:

  • "Auto-digitize: 12,438 stitches"
  • "Update image: rotate 90°"
  • "Move stitch object: 'red region' → (45, 67)"
  • "Save to gallery"

This requires the history to store not just snapshots but also an "action label" string. Add action: string to the HistoryState.

jumpToHistoryEntry(i) sets historyIndex = i and dispatches the new state.

Severity

Low. The user can step through with Cmd+Z. Power users with many edits notice.

Discovered by

Gap analysis (2026-10-02) of workspace history affordances.

  • The editor's #206 (open) is the editor's version of the same gap.
  • The history persistence (currently session-local) is a separate concern.
  • Most modern editors have this panel; it's a standard affordance.
## Finding `src/components/workspace/useWorkspace.ts:201` defines `MAX_HISTORY = 50`. The history is tracked in `state.history: HistoryState[]` (per the type definition). The user can step through with Cmd+Z and Cmd+Shift+Z, but there's no UI to see the history list or click on a specific entry. `grep -n 'history.*panel\|HistoryList' src/components/workspace/` returns 0. A user who: - Auto-digitizes - Tweaks the density - Re-does - Tweaks the color - Tries Cmd+Z a few times - Realizes they want the "first auto-digitize" version back - Can't — Cmd+Z only steps back one at a time, no way to "go to 5 steps back" Figma, Illustrator, Sketch all have a "History" panel that lists every action with timestamps. The user clicks an entry to revert to that state. ## Where - History state: `src/components/workspace/useWorkspace.ts:201-214` (MAX_HISTORY = 50) - No panel: `grep -n 'HistoryList' src/` returns 0 - Cmd+Z: `src/components/workspace/useWorkspace.ts` (handleUndo / handleRedo) ## Suggested fix shape Add a "History" panel toggle to the right side of the workspace's top bar: ```tsx <button onClick={() => setShowHistoryPanel((v) => !v)} data-testid="toggle-history" title="Show history" > <History size={14} /> </button> ``` The panel slides in from the right with a list of history entries: ```tsx {showHistoryPanel && ( <div className="fixed right-0 top-0 bottom-0 w-80 bg-white border-l"> <h3>History</h3> <ul> {state.history.map((entry, i) => ( <li key={i} onClick={() => jumpToHistoryEntry(i)} className={i === state.historyIndex ? 'active' : ''} > <span>{describeSnapshot(entry)}</span> <span>{i === state.historyIndex ? 'current' : ''}</span> </li> ))} </ul> </div> )} ``` `describeSnapshot(entry)` returns a human-readable summary: - "Auto-digitize: 12,438 stitches" - "Update image: rotate 90°" - "Move stitch object: 'red region' → (45, 67)" - "Save to gallery" This requires the history to store not just snapshots but also an "action label" string. Add `action: string` to the HistoryState. `jumpToHistoryEntry(i)` sets `historyIndex = i` and dispatches the new state. ## Severity Low. The user can step through with Cmd+Z. Power users with many edits notice. ## Discovered by Gap analysis (2026-10-02) of workspace history affordances. ## Related - The editor's #206 (open) is the editor's version of the same gap. - The history persistence (currently session-local) is a separate concern. - Most modern editors have this panel; it's a standard affordance.
Author
Owner

Shipped in c7e3c88 (push 06b0603 → c7e3c88).

Figma/Illustrator-style history panel landed:

  • HistoryState gained an action: string label so each snapshot carries a human-readable description ("Auto-digitize: 12,438 stitches", "Update image: rotation", "Delete selected", "Reorder objects", "Load design", …).
  • New HistoryPanel overlay (right-side, fixed) lists every snapshot in reverse-chronological order, current entry highlighted, forward (redo) entries dimmed. Click an entry to jump to that snapshot.
  • New JUMP_TO_HISTORY reducer action restores state from a chosen index. Same deep-clone contract as UNDO/REDO.
  • History icon button in the AppHeader (between Fit-to-view and Settings). Disabled until the stack has at least one entry.
  • applyHistorySnapshot shared helper for UNDO/REDO/JUMP — fixes a latent inconsistency where UNDO at historyIndex===0 had historyIndex: -1 while still restoring history[0]. historyIndex now consistently points at the restored snapshot.

Tests: 510/510 across 51 workspace test files. New HistoryPanel.test.tsx and issue-255-history.test.tsx. Existing issue-174.test.tsx updated for the new historyIndex invariant.

Shipped in c7e3c88 (push 06b0603 → c7e3c88). Figma/Illustrator-style history panel landed: - `HistoryState` gained an `action: string` label so each snapshot carries a human-readable description ("Auto-digitize: 12,438 stitches", "Update image: rotation", "Delete selected", "Reorder objects", "Load design", …). - New `HistoryPanel` overlay (right-side, fixed) lists every snapshot in reverse-chronological order, current entry highlighted, forward (redo) entries dimmed. Click an entry to jump to that snapshot. - New `JUMP_TO_HISTORY` reducer action restores state from a chosen index. Same deep-clone contract as UNDO/REDO. - `History` icon button in the AppHeader (between Fit-to-view and Settings). Disabled until the stack has at least one entry. - `applyHistorySnapshot` shared helper for UNDO/REDO/JUMP — fixes a latent inconsistency where UNDO at historyIndex===0 had `historyIndex: -1` while still restoring history[0]. historyIndex now consistently points at the restored snapshot. Tests: 510/510 across 51 workspace test files. New HistoryPanel.test.tsx and issue-255-history.test.tsx. Existing issue-174.test.tsx updated for the new historyIndex invariant.
Mark closed this issue 2026-10-04 10:30:37 +00:00
Sign in to join this conversation.
No description provided.