From a060f82cc155ab2dccad1350050eb7fbb50235ee Mon Sep 17 00:00:00 2001 From: Randy Lutcavich Date: Sun, 12 Apr 2026 20:42:03 -0500 Subject: [PATCH] feat: add undo/redo toolbar buttons and fix temporal partialize Add visible Undo/Redo buttons to the toolbar with proper disabled state, wired to the zundo temporal store. Fix the temporal middleware's partialize config to only snapshot editing state (words, deletedRanges, segments, language). Previously, all state including playhead position, hover state, and selection was captured, causing spurious undo steps when the user simply moved the playhead. --- frontend/src/App.tsx | 26 +++++++++++++++++++++++++- frontend/src/store/editorStore.ts | 10 +++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8542392..0bd4079 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState, useRef } from 'react'; +import { useCallback, useEffect, useState, useRef } from 'react'; +import { useStore } from 'zustand'; import { useEditorStore } from './store/editorStore'; import VideoPlayer from './components/VideoPlayer'; import TranscriptEditor from './components/TranscriptEditor'; @@ -16,6 +17,8 @@ import { Loader2, FolderSearch, FileInput, + Undo2, + Redo2, } from 'lucide-react'; const IS_ELECTRON = !!window.electronAPI; @@ -35,6 +38,15 @@ export default function App() { backendUrl, } = useEditorStore(); + const { pastStates, futureStates } = useStore(useEditorStore.temporal, (s) => ({ + pastStates: s.pastStates, + futureStates: s.futureStates, + })); + const canUndo = pastStates.length > 0; + const canRedo = futureStates.length > 0; + const handleUndo = useCallback(() => useEditorStore.temporal.getState().undo(), []); + const handleRedo = useCallback(() => useEditorStore.temporal.getState().redo(), []); + const [activePanel, setActivePanel] = useState(null); const [manualPath, setManualPath] = useState(''); const [whisperModel, setWhisperModel] = useState('base'); @@ -208,6 +220,18 @@ export default function App() { label="Open" onClick={IS_ELECTRON ? handleOpenFile : () => useEditorStore.getState().reset()} /> + } + label="Undo" + onClick={handleUndo} + disabled={!canUndo} + /> + } + label="Redo" + onClick={handleRedo} + disabled={!canRedo} + /> } label="AI" diff --git a/frontend/src/store/editorStore.ts b/frontend/src/store/editorStore.ts index ec9448d..e1cb456 100644 --- a/frontend/src/store/editorStore.ts +++ b/frontend/src/store/editorStore.ts @@ -227,6 +227,14 @@ export const useEditorStore = create()( reset: () => set(initialState), }), - { limit: 100 }, + { + limit: 100, + partialize: (state) => ({ + words: state.words, + deletedRanges: state.deletedRanges, + segments: state.segments, + language: state.language, + }), + }, ), );