feat(files): export workspace files to Google Drive#4938
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Backend: New shared UI: Download becomes an Export submenu (Download / Google Drive) in the bulk bar, row context menu, and file detail actions. Reviewed by Cursor Bugbot for commit 5c9b2d8. Configure here. |
|
@greptile |
|
@cursor review |
Greptile SummaryThis PR adds a Export to Google Drive action to the workspace Files module, reusing the existing OAuth credentials from the Google Drive workflow block. The upload logic is extracted into a shared
Confidence Score: 5/5This PR is safe to merge. The new export route, shared upload helper, and modal flow are well-structured and the issues raised in earlier review rounds have all been addressed. The export route correctly checks auth, workspace membership, and token ownership before touching any Drive API. The shared upload helper properly guards both the multipart upload and the final metadata fetch against non-2xx responses, throwing a typed error in each case. The sessionStorage pending-export mechanism is structurally validated on consume. Test coverage is thorough across the route (8 cases) and the upload helper (3 cases). No logic gaps or security gaps were identified in the changed code. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
actor User
participant FilesUI as Files Page
participant ExportModal as ExportToDriveModal
participant OAuthModal as ConnectOAuthModal
participant SessionStorage
participant API as /api/workspaces/[id]/files/export-to-drive
participant DriveHelper as uploadBufferToDrive
participant GDrive as Google Drive API
User->>FilesUI: Select files → Export to Drive
FilesUI->>ExportModal: open(fileIds, fileNames)
ExportModal->>ExportModal: Load OAuth credentials (useOAuthCredentials)
alt No account / Connect new
ExportModal->>SessionStorage: writePendingDriveExport(fileIds, fileNames, priorCredentialIds)
ExportModal->>OAuthModal: "open ConnectOAuthModal (origin='files')"
OAuthModal-->>User: Google OAuth redirect (full page)
User-->>FilesUI: Return from OAuth
FilesUI->>SessionStorage: consumePendingDriveExport()
FilesUI->>ExportModal: re-open with priorCredentialIds (auto-selects new account)
end
User->>ExportModal: Click Export
ExportModal->>API: "POST { fileIds, credentialId }"
API->>API: getSession() + verifyWorkspaceMembership()
API->>API: refreshAccessTokenIfNeeded(credentialId, userId)
API->>API: listWorkspaceFiles(workspaceId)
loop For each file
API->>API: fetchWorkspaceFileBuffer(file)
API->>DriveHelper: "uploadBufferToDrive({ accessToken, name, mimeType, buffer })"
DriveHelper->>GDrive: POST multipart upload
GDrive-->>DriveHelper: "{ id }"
opt MIME conversion
DriveHelper->>GDrive: PATCH re-apply filename
end
DriveHelper->>GDrive: GET file metadata
GDrive-->>DriveHelper: DriveUploadedFile
DriveHelper-->>API: DriveUploadedFile
end
API-->>ExportModal: "{ success, exported[], failed[] }"
ExportModal->>User: toast.success (with Open link) / toast.error
ExportModal->>FilesUI: onOpenChange(false) → clearPendingDriveExport()
Reviews (5): Last reviewed commit: "feat(files): export workspace files to G..." | Re-trigger Greptile |
Greptile SummaryAdds Google Drive export to the workspace Files module, reusing existing OAuth credentials and introducing a shared
Confidence Score: 4/5The feature is well-structured and auth/permission checks are solid, but the shared upload helper can produce duplicate Drive files or return incorrect metadata when the final metadata fetch fails transiently. The upload helper does not check finalResponse.ok before parsing the metadata response. A transient Drive API error at that step causes the function to throw after the file is already in Drive; the export route then marks it as failed, and a user retry produces a duplicate. The fix is a two-line guard but the bug affects both the new export path and the existing Drive tool upload path. apps/sim/lib/google-drive/upload-to-drive.ts — the final metadata fetch and the post-conversion PATCH both need error handling. Important Files Changed
Sequence DiagramsequenceDiagram
participant UI as Files UI
participant Modal as ExportToDriveModal
participant API as POST /files/export-to-drive
participant Drive as Google Drive API
participant OAuth as OAuth (refreshAccessTokenIfNeeded)
UI->>Modal: openExportToDrive(fileIds, fileNames)
Modal->>API: "POST {fileIds, credentialId}"
API->>OAuth: refreshAccessTokenIfNeeded(credentialId, userId)
OAuth-->>API: accessToken
API->>API: listWorkspaceFiles filter by fileIds
loop per file
API->>API: fetchWorkspaceFileBuffer(file)
API->>Drive: POST multipart upload
Drive-->>API: "{id}"
API->>Drive: "GET files/{id}?fields=..."
Drive-->>API: DriveUploadedFile
end
API-->>Modal: "{success, exported[], failed[]}"
Modal->>UI: toast.success / toast.error
Reviews (2): Last reviewed commit: "feat(files): export workspace files to G..." | Re-trigger Greptile |
13fbcb3 to
6d9c0d1
Compare
6d9c0d1 to
7804a50
Compare
|
@greptile |
|
@cursor review |
Add an Export action to the Files module that pushes selected workspace files straight to a user's Google Drive, reusing the same OAuth credentials the Google Drive block uses. The existing Download action becomes a dropdown (Download / Google Drive) in the row context menu, bulk action bar, and file-viewer menu. - Shared uploadBufferToDrive() helper; refactor the Drive tool upload route to use it (single upload path) - Contract-bound POST /api/workspaces/[id]/files/export-to-drive with per-file error reporting; tokens via refreshAccessTokenIfNeeded - ExportToDriveModal: account picker + inline connect via a dedicated 'files' OAuth return origin - Route tests cover auth, validation, token, no-files, success, partial
7804a50 to
5c9b2d8
Compare
|
@greptile review |
1 similar comment
|
@greptile review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5c9b2d8. Configure here.
Summary
uploadBufferToDrive()helper and refactor the Drive tool upload route to use it, so the multipart upload path lives in one placePOST /api/workspaces/[id]/files/export-to-driveresolves a token viarefreshAccessTokenIfNeeded, reads each file's bytes, uploads to My Drive root, and reports per-file success/failure (a partial failure never aborts the batch)ExportToDriveModalwith an account picker + inline connect via a dedicatedfilesOAuth return origin, so connecting from Files returns to Files (not Integrations)Type of Change
Testing
check:api-validationall clean; workspace-files (26) and oauth-credentials (4) suites passingscope='active'); credential picker is user-scoped; token resolution path is identical to the Drive blockChecklist