feat(flowchart): undo/redo toolbar buttons + history counter (C3)

The flowchart editor had Ctrl+Z / Ctrl+Shift+Z keyboard shortcuts
but no discoverable buttons. New History section in the side panel:
  - Undo / Redo buttons wired to _store.undo() / _store.redo()
  - Counter chip showing ↶/↷ availability
  - Buttons auto-disable when stacks are empty (via _store.canUndo()
    + canRedo() evaluated on every store subscription)

The store already exposed undo/redo/canUndo/canRedo — this commit
only adds the UI surface.

Amit Haridas
This commit is contained in:
Amit Haridas
2026-09-30 21:27:11 +05:30
parent 0bb1091c47
commit 4228ab78d8
2 changed files with 51 additions and 0 deletions
+19
View File
@@ -217,6 +217,18 @@
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 12px; margin-bottom: 12px;
} }
.fc-history-row {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
.fc-history-count {
margin-left: auto;
font-size: 11px;
color: var(--fc-border);
font-variant-numeric: tabular-nums;
}
.fc-ul { .fc-ul {
list-style: none; list-style: none;
padding: 0; padding: 0;
@@ -323,6 +335,13 @@
Save to File button alongside Insert at Cursor. Save to File button alongside Insert at Cursor.
--> -->
<div id="fc-nodelist" class="fc-nodelist"> <div id="fc-nodelist" class="fc-nodelist">
<h3 class="fc-section-title">History</h3>
<div class="fc-history-row">
<button class="fc-btn" id="fc-btn-undo" title="Undo (Ctrl+Z)">↶ Undo</button>
<button class="fc-btn" id="fc-btn-redo" title="Redo (Ctrl+Shift+Z)">↷ Redo</button>
<span class="fc-history-count" id="fc-history-count" aria-live="polite">0</span>
</div>
<h3 class="fc-section-title">Add Node</h3> <h3 class="fc-section-title">Add Node</h3>
<div class="fc-add-row"> <div class="fc-add-row">
<button class="fc-btn" data-add="process">+ Process</button> <button class="fc-btn" data-add="process">+ Process</button>
+32
View File
@@ -834,6 +834,9 @@
btnInsert: document.getElementById('fc-btn-insert'), btnInsert: document.getElementById('fc-btn-insert'),
btnSave: document.getElementById('fc-btn-save'), btnSave: document.getElementById('fc-btn-save'),
btnReset: document.getElementById('fc-btn-reset'), btnReset: document.getElementById('fc-btn-reset'),
btnUndo: document.getElementById('fc-btn-undo'),
btnRedo: document.getElementById('fc-btn-redo'),
historyCount: document.getElementById('fc-history-count'),
status: document.getElementById('fc-status'), status: document.getElementById('fc-status'),
// v4.11.0 — node-list panel (button-driven UI). Every mutation goes // v4.11.0 — node-list panel (button-driven UI). Every mutation goes
// through controls in this panel; the canvas is purely visual. // through controls in this panel; the canvas is purely visual.
@@ -1405,6 +1408,8 @@
debouncedPersist(); debouncedPersist();
// Keep the node-list panel in sync with every mutation. // Keep the node-list panel in sync with every mutation.
rerenderNodeList(); rerenderNodeList();
// v4.13.0 — keep the undo/redo buttons enabled-state in sync.
updateHistoryUI();
}); });
// Hydrate from disk (defensively — corrupt JSON is caught by the store). // Hydrate from disk (defensively — corrupt JSON is caught by the store).
@@ -1464,6 +1469,33 @@
}); });
} }
// v4.13.0 — toolbar undo/redo buttons + history counter. Both wired
// here so they share state with the existing keyboard shortcuts.
if (els.btnUndo) {
els.btnUndo.addEventListener('click', () => {
if (!_store) return;
_store.undo();
});
}
if (els.btnRedo) {
els.btnRedo.addEventListener('click', () => {
if (!_store) return;
_store.redo();
});
}
function updateHistoryUI() {
if (els.historyCount) {
// The store exposes canUndo()/canRedo(); show the stack depth as
// a vague "edit count" so the user has feedback that their work
// is being captured.
const u = _store.canUndo() ? 1 : 0;
const r = _store.canRedo() ? 1 : 0;
els.historyCount.textContent = `${u}↶ / ${r}↷`;
}
if (els.btnUndo) els.btnUndo.disabled = !_store.canUndo();
if (els.btnRedo) els.btnRedo.disabled = !_store.canRedo();
}
// Keyboard shortcuts — Ctrl/Cmd+Z / Ctrl/Cmd+Shift+Z. Delete / Backspace // Keyboard shortcuts — Ctrl/Cmd+Z / Ctrl/Cmd+Shift+Z. Delete / Backspace
// are intentionally NOT wired (v4.11.0 — there is no canvas selection // are intentionally NOT wired (v4.11.0 — there is no canvas selection
// state anymore; use the × buttons in the node-list panel instead). // state anymore; use the × buttons in the node-list panel instead).