Skip to content

feat: undo/redo and project recovery with versioned project files - #1822

Merged
magic-peach merged 1 commit into
mainfrom
feat/undo-recovery
Oct 29, 2026
Merged

magic-peach merged 1 commit into
mainfrom
feat/undo-recovery

Conversation

@magic-peach

Copy link
Copy Markdown
Collaborator
  • One immutable EditState (recipe minus the sound preference, plus image overlay settings) in a bounded history: 100 steps, no duplicates, slider drags and typing coalesced into one step.
  • Undo/redo buttons and Cmd/Ctrl+Z, Shift+Cmd+Z, Ctrl+Y; left to the browser inside text fields; disabled during export.
  • Project record (edits + source description, no media) saved locally and flushed on pagehide; missing-source recovery that resumes when the same file is chosen again.
  • Save/open .reframe.json with strict validation and a migration table.
  • "Delete saved data" removes everything the editor stored.
  • Reset settings is now undoable and no longer deletes saved data.
  • Fix two pre-existing test failures on main (duplicate imports in exportEstimate.test.ts, URL state leaking between hook tests).

Description

Related Issue

Type of Contribution

  • Bug fix
  • New feature
  • Documentation update
  • Refactor
  • GSSoC contribution

Participant Info

  • GitHub username:
  • Contribution level (Beginner/Intermediate/Advanced):

Screen Recording

How to record: run bun run dev → open http://localhost:3000 → demonstrate the full working flow of your change, including any edge cases.

  • macOS: Cmd + Shift + 5 → Record Selected Portion, or use QuickTime Player
  • Windows: Win + G → Xbox Game Bar → Capture
  • Linux: OBS Studio, GNOME Screenshot tool, or kazam
  • Any OS: Loom (free screen recorder, great for sharing)

Recording / Loom link: ## Checklist

  • I have read the contribution guidelines
  • My changes follow the project structure
  • I have tested my changes in Chrome, Firefox, and Safari
  • bun run lint passes (no ESLint errors)
  • bunx tsc --noEmit passes (no TypeScript errors)
  • New interactive elements have aria-label / accessible names
  • No console.log statements left in
  • This PR is related to a valid issue
  • Screen recording attached above (required for UI/feature/design changes)

- One immutable EditState (recipe minus the sound preference, plus image
  overlay settings) in a bounded history: 100 steps, no duplicates,
  slider drags and typing coalesced into one step.
- Undo/redo buttons and Cmd/Ctrl+Z, Shift+Cmd+Z, Ctrl+Y; left to the
  browser inside text fields; disabled during export.
- Project record (edits + source description, no media) saved locally
  and flushed on pagehide; missing-source recovery that resumes when the
  same file is chosen again.
- Save/open .reframe.json with strict validation and a migration table.
- "Delete saved data" removes everything the editor stored.
- Reset settings is now undoable and no longer deletes saved data.
- Fix two pre-existing test failures on main (duplicate imports in
  exportEstimate.test.ts, URL state leaking between hook tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for reframe-os ready!

Name Link
🔨 Latest commit cd413fd
🔍 Latest deploy log https://app.netlify.com/projects/reframe-os/deploys/6ada3a1fd54024e7a0fff308
😎 Deploy Preview https://deploy-preview-1822--reframe-os.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added level:advanced Advanced level - 55 pts type:bug Bug fix labels Oct 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ PR Format Issues — @magic-peach

Please fix the following before your PR can be reviewed:

  • ⚠️ No linked issue found. Add Closes #<issue-number> to your PR description.

Push new commits after fixing — this comment will update automatically.

📖 CONTRIBUTING.md

@github-actions

Copy link
Copy Markdown
Contributor

👋 Thanks for your PR, @magic-peach!

Welcome to Reframe — a browser-based video editor built for everyone 🎬

🟠 GSSoC'26 PR detected — thanks for contributing under GirlScript Summer of Code 2026!

What happens next

  1. 🤖 Automated checks — build & TypeScript typecheck will run automatically
  2. ✅ Vercel preview — a preview deployment will be created (requires maintainer authorization for fork PRs)
  3. 👀 Code review — a maintainer will review your changes
  4. 🚀 Merge — once approved, your PR will be merged!

Quick checklist

  • PR title follows Conventional Commits (e.g. feat: add dark mode)
  • Linked the issue this PR closes (e.g. Closes #123)
  • Tested the changes locally (bun run dev)
  • Build passes (bun run build)

Useful links

Happy coding! 🎉

@github-actions github-actions Bot added type:design UI/UX design type:docs Documentation type:feature New feature type:refactor Code refactor type:testing Testing gssoc'26 GirlScript Summer of Code 2026 labels Oct 22, 2026
@reframe-oss reframe-oss deleted a comment from github-actions Bot Oct 22, 2026
@magic-peach
magic-peach marked this pull request as draft October 22, 2026 16:37
@chiragjangiir

Copy link
Copy Markdown

Code Review: Undo/Redo & Project Recovery Architecture

Thanks for this comprehensive PR! The architecture in docs/PROJECTS.md is well-structured, especially the bounded immutable history snapshots (HISTORY_LIMIT = 100), continuous slider coalescing (COALESCE_WINDOW_MS = 600), and respecting isTextEntryTarget so native browser input undo isn't hijacked.

I noticed a minor validation gap between src/hooks/useVideoEditor.ts and src/lib/project.ts:

  • Location: src/hooks/useVideoEditor.ts (isValidValue) vs. src/lib/project.ts (parseRecipe)
  • Problem: isValidValue defines switch cases for brightness, contrast, saturation, but omits volume, sharpness, stabilization, denoise, keepAudio, and normalizeAudio, letting them fall through to default: return true.
  • Evidence: parseRecipe in src/lib/project.ts strictly enforces:
    volume: num(raw, "volume", 0, 200),
    sharpness: num(raw, "sharpness", 0, 3),
    keepAudio: bool(raw, "keepAudio"),
    normalizeAudio: bool(raw, "normalizeAudio"),
    stabilization: bool(raw, "stabilization"),
    denoise: bool(raw, "denoise"),
  • Impact: If unconstrained values enter via URL parameters (e.g., ?volume=-10 or ?sharpness=50), isValidValue allows them into EditState and localStorage. When reloaded or imported via parseProject, num(raw, "volume", 0, 200) throws a ProjectError, failing project recovery.
  • Suggested direction: Add matching bounds checks in isValidValue:
    case "volume":
      return typeof val === "number" && !isNaN(val) && val >= 0 && val <= 200;
    case "sharpness":
      return typeof val === "number" && !isNaN(val) && val >= 0 && val <= 3;
    case "keepAudio":
    case "normalizeAudio":
    case "stabilization":
    case "denoise":
      return typeof val === "boolean";

Aside from this, the test coverage and documentation are thorough!

@magic-peach
magic-peach marked this pull request as ready for review October 29, 2026 07:10
@magic-peach
magic-peach merged commit ae6a107 into main Oct 29, 2026
19 of 24 checks passed
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

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

Labels

gssoc'26 GirlScript Summer of Code 2026 level:advanced Advanced level - 55 pts type:bug Bug fix type:design UI/UX design type:docs Documentation type:feature New feature type:refactor Code refactor type:testing Testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants