feat: add file and folder duplicate/copy operation#152
Merged
Conversation
Add a "Duplicate" context menu option that copies files and folders within the same bucket, appending " (copy)" to the name while preserving all metadata. - New CopyObject backend endpoint (POST /api/buckets/:bucket/copy) - Frontend duplicate logic with progress tracking for folder duplication - Backend integration tests (6 tests) and E2E test for file duplication Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
r2-explorer-docs | 8b6656a | Commit Preview URL Branch Preview URL |
Mar 10 2026, 12:06 AM |
G4brym
commented
Mar 10, 2026
Owner
Author
G4brym
left a comment
There was a problem hiding this comment.
Automated Code Review — APPROVED ✅
Review Scores: 5/5 reviewers approved
CI Status: All checks passed ✅
Summary
Clean, well-implemented feature that adds file/folder duplication to R2-Explorer. The implementation closely follows established codebase patterns (mirrors MoveObject endpoint and folder delete iteration). Backend endpoint correctly implements copy semantics (get + put without delete), preserving all metadata. Frontend adds context menu integration with progress feedback for folder operations. Test coverage is solid with 6 backend integration tests and an E2E test.
Review Perspectives
- Correctness: ✅ Copy semantics correct (no source deletion), name generation handles files/folders/extensions properly, events wired correctly through component hierarchy
- Security: ✅ Follows existing auth/middleware patterns, POST blocked by readonly middleware, no injection surfaces, base64 encoding matches existing patterns
- Performance: ✅ Single-file copy streams via R2 get/put (no memory buffering), folder copy matches existing sequential pattern
- Code Quality: ✅ Mirrors existing codebase patterns closely, clean and readable, well-structured
- Testing: ✅ 6 backend integration tests covering happy path, metadata preservation, error cases, and source integrity; E2E test covers primary user flow
Minor Notes (non-blocking)
Number.parseInt((i * 100) / folderContents.length)works butMath.floor()would be semantically more appropriate for truncating a numbergenerateCopyNameuses arrow function syntax while sibling methods usefunction()— inconsistent but harmless since it doesn't referencethis- Silent overwrite if
filename (copy).extalready exists is a documented, acceptable trade-off for MVP
🤖 Automated review by prodboard
This was referenced Mar 10, 2026
Merged
This was referenced Mar 22, 2026
This was referenced Mar 30, 2026
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
CopyObjectbackend endpoint (POST /api/buckets/:bucket/copy) that gets the source object and puts it at the destination without deleting the originalRelated Issue
Prodboard issue: bcb8905b3911e595 — [I] [R2-Explorer] Add file and folder duplicate/copy operation
Changes
packages/worker/src/modules/buckets/copyObject.ts— CopyObject endpoint following MoveObject pattern (without delete)packages/worker/src/index.ts— Register/api/buckets/:bucket/copyroutepackages/dashboard/src/appUtils.js— AddcopyObjectAPI handler methodpackages/dashboard/src/pages/files/FileContextMenu.vue— Add "Duplicate" menu itempackages/dashboard/src/components/files/FileOptions.vue— AddduplicateObjectandgenerateCopyNamemethodspackages/dashboard/src/pages/files/FilesFolderPage.vue— Wire upduplicateObjecteventpackages/worker/tests/integration/copy.test.ts— 6 backend integration testspackages/dashboard/e2e/file-operations.spec.ts— E2E test for file duplication via context menuTest Plan
🤖 Generated with Claude Code