Repository navigation
feat(drive): sync recordings and exports to Google Drive - #1541
Draft
Davidjayan wants to merge 3 commits into
Draft
Davidjayan wants to merge 3 commits into
Davidjayan wants to merge 3 commits into
Conversation
Connect a Google account from the new Google Drive dialog (app menu). While sync is on, each new recording is uploaded to an OpenScreen folder in the user's Drive, and each MP4 export of a project replaces that project's Drive file in place, so its link always opens the latest edit. Local files are never touched, and a failed upload never fails the recording or export. - Settings: OAuth client (or OPENSCREEN_GOOGLE_CLIENT_ID/_SECRET), connect, a Sync to Google Drive switch, disconnect. No client ID ships. - Load Project: a Drive icon on synced rows, and a row menu with Share drive link, Edit drive visibility and Unsync from drive. - Main process: loopback OAuth with PKCE and the drive.file scope, resumable streamed uploads, credentials in safeStorage. - Strings in all 15 locales, an architecture doc, manual checklist items, and the FAQ no longer says there is no cloud storage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Load Project list scrolls, and the Drive menu inside it showed only its first rows. It now opens in a portal with fixed positioning, above or below its button, and closes when the list scrolls. The browser shim keeps a Drive connection and project states in localStorage, so the dialog and the menu can be driven in browser mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
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. |
The first test's waitFor used the 1 s default for the panel's first render, which a loaded machine misses: the full suite failed here on main too, while the file alone passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Optional Google Drive sync. Connect your own Google account, and each new recording and each MP4 export is copied to an
OpenScreenfolder in your Drive. Local files are always kept, and a failed upload never fails the recording or the export.One Drive file per project, one link. The recording creates the Drive file. Each later MP4 export of the project replaces that file's content in place, so the file id and the link stay the same. A link shared after recording opens the latest edit.
Settings (app menu → Google Drive):
OPENSCREEN_GOOGLE_CLIENT_ID/OPENSCREEN_GOOGLE_CLIENT_SECRET.drive.file, so OpenScreen sees only the files it created.Load Project list:
Code:
electron/drive/:google-oauth.ts: sign-in, refresh, revoke.google-drive-api.ts: folder, resumable upload sent as one streamedPUT(takes run to GB), permissions. Plainfetch, nogoogleapisdependency.google-drive-store.ts: settings JSON, plussafeStoragefor the refresh token and client secret. The keychain is read lazily, never at startup.google-drive-service.ts: orchestration. Uploads for one project are queued, so an export finishing mid-upload lands on top of it instead of becoming a second file. Two edge cases:invalid_grant), the account is disconnected.drivebridge domain. Payloads are validated innativeBridge.ts.src/lib/driveSync.tsis the renderer's single, never-throwing call. It is used byimportPendingRecordingand byExportDialog(MP4 only; a GIF would change what a shared link shows).GoogleDriveSettings.tsx(newEditorDialogSection"drive") andProjectDriveMenu.tsx. The row menu opens in a portal, so the scrolling project list cannot clip it.localStorage, so this UI can be driven in browser mode.technical-documentation/architecture/google-drive-sync.md(+ README row).Related issue
No issue filed.
Type of change
Release impact
Desktop impact
Screenshots / video
Captured from the renderer in browser mode (
NO_ELECTRON=1 npm run dev,?windowType=editor), with the Drive shim seeded with a connected account. These show the UI only; no real Google sign-in or upload is in them.Row menu: Share drive link, Edit drive visibility, Unsync from drive
Settings: first setup → connect → connected, with the sync switch
Testing
Automated:
npx tsc --noEmitandnpx tsc -p tsconfig.test.json --noEmitpass.npm run lint: no new diagnostics (36 warnings, the same asmain).npm run i18n:checkpasses.New tests:
google-oauth.test.ts: PKCE, the consent URL and scope, and a real loopback sign-in round trip. Also a forgedstateis refused, refresh,invalid_grant, and the timeout.google-drive-api.test.ts: create vs replace-in-place, Drive errors, permissions, the folder. Also a streamed upload through Node's realfetchinto a local server, which checks every byte arrives.google-drive-service.test.ts: against an in-memory fake Drive. Covers env-over-settings client, sync on/off, the same file id across recording and exports, overlapping uploads queued, a Drive-deleted file re-created, a revoked token disconnecting, failed-upload state, visibility, and unsync.google-drive-store.test.ts: persistence, credentials kept out of the JSON, refusal without the keychain, defensive parsing.nativeBridge.drive.test.ts: payload validation, andUNAVAILABLEwithout a Drive service.driveSync.test.ts.GoogleDriveSettings.test.tsx.OpenProjectModal.drive.test.tsx: badge, the three menu items, copy, visibility, unsync, disabled items while uploading, and the menu not clipped by the list. Escape closes the menu, not the dialog.EditorTopBar.test.tsx: the new menu row.npm run test: all pass (394 files, 5470 tests, 1 skipped).LeftPanel.copyMessage.test.tsx. Its firstwaitForallowed 1 s for the panel's first render.main(runningsrc/components/ai-editionalone: 1 failed / 89 passed), while the file alone passed.testTimeoutinvitest.config.ts.Manual:
manual-e2e-checklist.mdlists those checks; they are still to do.🤖 Generated with Claude Code