Skip to content

refactor(editor): extract history state model#544

Merged
meiiie merged 1 commit into
mainfrom
refactor/editor-history-model-slice
May 20, 2026
Merged

refactor(editor): extract history state model#544
meiiie merged 1 commit into
mainfrom
refactor/editor-history-model-slice

Conversation

@meiiie
Copy link
Copy Markdown
Collaborator

@meiiie meiiie commented May 20, 2026

Description

Extracts the editor undo/redo history stack out of VideoEditor.tsx into a pure state-transition module with focused unit coverage.

Motivation

This is the next small editor architecture slice. Before introducing any external state library, this PR separates the editor history model from React rendering/orchestration so the state boundary is explicit, tested, and reviewable.

Type of Change

  • Refactor
  • Tests

Related Issue(s)

None.

Changes Made

  • Added src/components/video-editor/editorHistory.ts with the editor history snapshot type, stack creation/reset, record, undo, and redo transitions.
  • Added src/components/video-editor/editorHistory.test.ts covering initialization, unchanged snapshots, record/redo clearing, undo/redo movement, applying-history updates, max-depth trimming, reset, and cloning behavior.
  • Updated VideoEditor.tsx to delegate history stack mutations to the extracted model while keeping UI state application local to the component.

Scope Note

No UI behavior, timeline behavior, export behavior, keyboard shortcut mapping, persistence format, or native/runtime path is intentionally changed. This PR does not introduce Zustand, Redux, or another state dependency; it first carves out a tested pure state boundary.

Testing Guide

Review the new history model and verify that VideoEditor.tsx still owns applying snapshots to React state, while editorHistory.ts owns only stack transitions.

Checklist

  • One focused architecture slice
  • Behavior-preserving refactor
  • Unit coverage added for moved state logic
  • Typecheck passed
  • Scoped Biome completed
  • Branch diff excludes unrelated generated/local files

Local Checks

  • npm test -- src/components/video-editor/editorHistory.test.ts (8 tests passed)
  • npm test -- src/components/video-editor/editorHistory.test.ts src/components/video-editor/types.test.ts (25 tests passed)
  • npx tsc --noEmit --pretty false (passed)
  • npx biome check --formatter-enabled=false --assist-enabled=false src/components/video-editor/VideoEditor.tsx src/components/video-editor/editorHistory.ts src/components/video-editor/editorHistory.test.ts (exit 0; existing unrelated VideoEditor.tsx exhaustive-deps warning remains)
  • git diff --check main...HEAD (passed)

Runtime/Repro Evidence

Not run. This PR moves pure editor history stack transitions into a tested module; no Electron, preview rendering, export, or native runtime path changed.

Summary by CodeRabbit

  • Tests
    • Added comprehensive test coverage for editor history and undo/redo functionality.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR introduces a centralized editor history stack module (editorHistory.ts) that manages undo/redo state, then refactors VideoEditor.tsx to replace its local history refs with this unified system. Comprehensive tests validate the new history behavior.

Changes

Centralized Undo/Redo History

Layer / File(s) Summary
History Stack Types and Core Operations
src/components/video-editor/editorHistory.ts
EditorHistorySnapshot and EditorHistoryStack types define the state shape. Core functions create, reset, clone snapshots, and perform deep equality checking. recordEditorHistorySnapshot moves prior state into past, detects unchanged snapshots, and bounds history length via maxEntries. undoEditorHistoryStack and redoEditorHistoryStack transition snapshots between past, current, and future stacks.
History Stack Test Suite
src/components/video-editor/editorHistory.test.ts
Tests cover initialization without undo history, unchanged snapshot detection, record/undo/redo transitions, applying-history mode suppression, maxEntries truncation, full stack reset, and snapshot immutability via cloning.
VideoEditor History Integration
src/components/video-editor/VideoEditor.tsx
Replaces local past/future/current refs with a single editorHistoryRef initialized from createEditorHistoryStack(). Undo/redo button availability now derives from editorHistoryRef.current.past and .future. handleUndo and handleRedo call the new stack operations and apply returned snapshots. History snapshot recording uses recordEditorHistorySnapshot() with applyingHistory flag. Snapshot cloning switches to cloneStructured, and project load resets history via resetEditorHistoryStack().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

Checked

Poem

🐰 A history stack, neat and clean,
Undo, redo, and in between,
Snapshots cloned with utmost care,
VideoEditor's burden we share!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor(editor): extract history state model' clearly and concisely summarizes the main change: extracting editor history logic into a separate module.
Description check ✅ Passed The PR description comprehensively covers all required template sections with specific details about changes, motivation, testing, and scope.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/editor-history-model-slice

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@meiiie meiiie marked this pull request as ready for review May 20, 2026 16:38
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/components/video-editor/editorHistory.test.ts (1)

119-127: ⚡ Quick win

Add a direct stack-immutability regression test.

This currently verifies the clone helper, but not that recordEditorHistorySnapshot stores an isolated copy in stack.current/past.

🧪 Proposed test addition
+	it("stores cloned snapshots in history stack entries", () => {
+		const stack = createEditorHistoryStack();
+		const snapshot = createSnapshot("first");
+
+		recordEditorHistorySnapshot(stack, snapshot);
+		snapshot.selectedZoomId = "mutated";
+
+		expect(stack.current?.selectedZoomId).toBe("first");
+	});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/video-editor/editorHistory.test.ts` around lines 119 - 127,
Add a regression test that ensures recordEditorHistorySnapshot stores an
isolated (cloned) copy into the history stack (stack.current and/or past) rather
than a reference: call createSnapshot to build an initial snapshot, call
recordEditorHistorySnapshot(snapshot) (or whichever API pushes into the history
stack), mutate the original snapshot afterwards (e.g., change selectedZoomId),
then assert that the snapshot stored in stack.current and/or past remains
unchanged and deep-equals the original unmutated snapshot; use
cloneEditorHistorySnapshot and areEditorHistorySnapshotsEqual to help locate and
compare the stored copy.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/video-editor/editorHistory.test.ts`:
- Around line 119-127: Add a regression test that ensures
recordEditorHistorySnapshot stores an isolated (cloned) copy into the history
stack (stack.current and/or past) rather than a reference: call createSnapshot
to build an initial snapshot, call recordEditorHistorySnapshot(snapshot) (or
whichever API pushes into the history stack), mutate the original snapshot
afterwards (e.g., change selectedZoomId), then assert that the snapshot stored
in stack.current and/or past remains unchanged and deep-equals the original
unmutated snapshot; use cloneEditorHistorySnapshot and
areEditorHistorySnapshotsEqual to help locate and compare the stored copy.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e2980627-1827-4a51-811e-14854619d322

📥 Commits

Reviewing files that changed from the base of the PR and between 4f729b7 and b97149c.

📒 Files selected for processing (3)
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/editorHistory.test.ts
  • src/components/video-editor/editorHistory.ts

@meiiie meiiie merged commit 170d66c into main May 20, 2026
3 checks passed
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.

1 participant