Skip to content

Add editor autosave recovery#538

Open
yusufm wants to merge 2 commits intosiddharthvaddem:mainfrom
yusufm:codex/editor-autosave-recovery
Open

Add editor autosave recovery#538
yusufm wants to merge 2 commits intosiddharthvaddem:mainfrom
yusufm:codex/editor-autosave-recovery

Conversation

@yusufm
Copy link
Copy Markdown
Contributor

@yusufm yusufm commented May 3, 2026

Summary

  • autosave unsaved editor project state to local recovery storage
  • offer restore/discard when a recovery draft exists on editor startup
  • preserve the previous saved baseline when restoring recovered edits
  • fix the linted hook dependency used by CI

Testing

  • npm run lint
  • npm run build-vite

Summary by CodeRabbit

  • New Features

    • Unsaved editor changes are now automatically persisted as a recovery draft and can be restored on next startup. A controlled "Restore unsaved edits?" dialog appears when a recovery draft is found, letting you restore or discard recovered edits; the dialog requires an explicit choice (cannot be dismissed by Escape or clicking outside).
  • Refactor

    • Internal improvements to the screen recorder logic for more reliable cleanup and overlay handling.

@yusufm yusufm requested a review from siddharthvaddem as a code owner May 3, 2026 21:35
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0c88fdc0-6ad7-4af8-b3e1-ef9ccc0c1898

📥 Commits

Reviewing files that changed from the base of the PR and between 0084ca1 and b35b649.

📒 Files selected for processing (1)
  • src/components/video-editor/VideoEditor.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/video-editor/VideoEditor.tsx

📝 Walkthrough

Walkthrough

Adds local autosave/recovery to VideoEditor (localStorage draft read/validate/write, restore/discard dialog, passes saved snapshot into applyLoadedProject) and refactors useScreenRecorder to memoize safeHideCountdownOverlay and include it in effect dependencies.

Changes

VideoEditor Recovery Draft

Layer / File(s) Summary
Data Shape & Storage Helpers
src/components/video-editor/VideoEditor.tsx
Adds AUTOSAVE_STORAGE_KEY, AUTOSAVE_DELAY_MS, RecoveryDraft type, readRecoveryDraft() and clearRecoveryDraft() for validation and cleanup in localStorage.
State Initialization
src/components/video-editor/VideoEditor.tsx
Introduces recoveryDraft React state to hold a pending recovery draft.
Project Loading & Snapshot Handling
src/components/video-editor/VideoEditor.tsx
Extends applyLoadedProject to accept options?.lastSavedSnapshot and sets lastSavedSnapshot from the option or a freshly computed snapshot.
Autosave Effect & Initial Recovery
src/components/video-editor/VideoEditor.tsx
Adds an effect that schedules delayed writes of RecoveryDraft when there are unsaved changes, clears storage when no unsaved changes or project path changes, and reads/validates stored draft on init.
Recovery UI & Handlers
src/components/video-editor/VideoEditor.tsx
Adds controlled "Restore unsaved edits?" dialog (Escape/outside-pointer disabled) and handlers: handleRestoreRecoveryDraft (calls applyLoadedProject with draft snapshot) and handleDiscardRecoveryDraft.

useScreenRecorder Countdown Overlay Refactor

Layer / File(s) Summary
Memoized Helper
src/hooks/useScreenRecorder.ts
Replaces inline helper with useCallback safeHideCountdownOverlay(runId) that calls window.electronAPI.hideCountdownOverlay(runId) and warns on errors.
Effect Cleanup & Deps
src/hooks/useScreenRecorder.ts
Cleanup effect now calls memoized helper and includes safeHideCountdownOverlay in dependency array; removes old inline definition.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • siddharthvaddem

autosave hums in quiet nights,
drafts hide like little lights,
press restore — chaos soothed away,
or toss the ghost and carry on your day. ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Description check ❓ Inconclusive The PR description covers key points but is missing several template sections including Motivation, Type of Change, Related Issue, and Screenshots/Video details. Add the missing sections from the template: explain the motivation/problem solved, specify the type of change, link related issues, and include any applicable screenshots or videos.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add editor autosave recovery' clearly summarizes the main feature being added across both modified files.
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.


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
Review rate limit: 4/8 reviews remaining, refill in 30 minutes.

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0084ca1113

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +390 to +392
if (!currentProjectMedia || !currentProjectSnapshot || !hasUnsavedChanges) {
clearRecoveryDraft();
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep recovery draft until user makes restore decision

This effect deletes the persisted recovery payload whenever the currently loaded project has no unsaved changes, which happens immediately on startup for a normal saved project. Because pendingRecoveryDraft is only kept in memory after load, a restart/crash before the user clicks Restore will permanently drop the recoverable edits from localStorage. The clear path should be gated so existing recovery data is retained until explicit restore/discard.

Useful? React with 👍 / 👎.

/>
<Dialog
open={Boolean(recoveryDraft)}
onOpenChange={(open) => !open && handleDiscardRecoveryDraft()}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid destructive discard on generic dialog close

The dialog’s onOpenChange treats any close action as a hard discard, and this DialogContent includes the default close affordances (escape, outside click, and the top-right close button). That means a user can lose the only recovery draft by accidentally dismissing the modal instead of intentionally pressing the Discard action. Closing should not delete recovery data unless the user explicitly confirms discard.

Useful? React with 👍 / 👎.

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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/video-editor/VideoEditor.tsx`:
- Around line 388-463: Autosave and the unsaved-changes flag miss updates to
webcamSizePreset and cursorHighlight because hasUnsavedChanges is derived from
currentProjectSnapshot which doesn't include those fields; update the snapshot /
hashing logic (where currentProjectSnapshot or lastSavedSnapshot is
created—e.g., the createProjectData or snapshot serialization/hash function) to
include webcamSizePreset and cursorHighlight so changes to those controls update
currentProjectSnapshot, flip hasUnsavedChanges, and trigger the
autosave/editorState behavior shown in the VideoEditor useEffect.
- Around line 388-463: The effect currently calls clearRecoveryDraft() whenever
hasUnsavedChanges is false which deletes the persisted draft while the restore
dialog may still be open; update the condition so we no longer clear the
localStorage draft merely because the live editor is "clean" — instead only
clear when there is truly no project context (e.g. !currentProjectMedia ||
!currentProjectSnapshot) or when the draft belongs to a different project
(compare draft.projectPath to currentProjectPath) or when the user explicitly
dismisses the restore dialog; modify the useEffect in VideoEditor (the block
referencing hasUnsavedChanges and clearRecoveryDraft) to remove
hasUnsavedChanges as the sole trigger and add a guard for an explicit
restore/discard state (or a projectPath mismatch) before calling
clearRecoveryDraft.
- Around line 2241-2265: The recovery Dialog is currently rendered after an
early `if (error)` return so it never appears when startup errors occur; to fix,
render the <Dialog> (controlled by `Boolean(recoveryDraft)`) alongside or above
the error UI so it mounts even when `error` is set — move the Dialog block out
of the post-error return (or include it inside the error rendering branch) and
keep its handlers `handleDiscardRecoveryDraft` and `handleRestoreRecoveryDraft`
and props (`open`, `onOpenChange`) intact so users can restore/discard drafts
while on the error screen.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 19238c15-c0fe-4eaa-b572-3c6a6f4b2ea4

📥 Commits

Reviewing files that changed from the base of the PR and between 7e00cdb and 0084ca1.

📒 Files selected for processing (2)
  • src/components/video-editor/VideoEditor.tsx
  • src/hooks/useScreenRecorder.ts

Comment thread src/components/video-editor/VideoEditor.tsx
Comment on lines +2241 to +2265
<Dialog
open={Boolean(recoveryDraft)}
onOpenChange={(open) => !open && handleDiscardRecoveryDraft()}
>
<DialogContent>
<DialogHeader>
<DialogTitle>Restore unsaved edits?</DialogTitle>
<DialogDescription>
OpenScreen recovered unsaved editor changes from{" "}
{recoveryDraft
? new Date(recoveryDraft.savedAt).toLocaleString()
: "a previous session"}
.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button type="button" variant="secondary" onClick={handleDiscardRecoveryDraft}>
Discard
</Button>
<Button type="button" onClick={handleRestoreRecoveryDraft}>
Restore
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the recovery dialog reachable on startup failures.

This modal is mounted after the existing if (error) early return above, so any startup path that sets an error will skip the restore/discard prompt entirely. That’s the worst time to hide it — users can’t recover the draft if they’re stuck on the error screen.

♻️ Possible shape
-	if (error) {
+	if (error && !recoveryDraft) {
 		return (
 			<div className="flex items-center justify-center h-screen bg-background">
 				<div className="text-destructive">{error}</div>
 			</div>
 		);
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/VideoEditor.tsx` around lines 2241 - 2265, The
recovery Dialog is currently rendered after an early `if (error)` return so it
never appears when startup errors occur; to fix, render the <Dialog> (controlled
by `Boolean(recoveryDraft)`) alongside or above the error UI so it mounts even
when `error` is set — move the Dialog block out of the post-error return (or
include it inside the error rendering branch) and keep its handlers
`handleDiscardRecoveryDraft` and `handleRestoreRecoveryDraft` and props (`open`,
`onOpenChange`) intact so users can restore/discard drafts while on the error
screen.

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