Skip to content

[PB-6531]: match name collisions by name and type and batch their resolution - #2148

Merged
terrerox merged 19 commits into
refactor/extract-name-collision-upload-actionsfrom
fix/name-collision-matching-and-batching
Oct 7, 2026
Merged

terrerox merged 19 commits into
refactor/extract-name-collision-upload-actionsfrom
fix/name-collision-matching-and-batching

Conversation

@terrerox

Copy link
Copy Markdown
Contributor

Description

Stacked on refactor/extract-name-collision-upload-actions. Two fixes to how name collisions are resolved, split out of #2039 so that PR only adds the Skip option.

  • Duplicated items were matched to their existing counterpart by array index, which could make Replace trash the wrong file. They are now paired by name and type (name only for folders) via findExistingItemFor in nameCollision.utils.ts, and items without a match are left out of the replace.
  • Each resolution goes through the array-based primitives (moveItemsToTrash, moveItemsThunk, the upload managers) in one call instead of one call per item, so batching, concurrency limits and per-item error handling are inherited rather than reimplemented. Versioned replacements still run one at a time because that upload bypasses the queue. The destination folder is refreshed once per group instead of once per item.

Unit tests cover the matching rules and every resolution path.

Related Issues

Related Pull Requests

Checklist

  • Changes have been tested locally.
  • Unit tests have been written or updated as necessary.
  • The code adheres to the repository's coding standards.
  • Relevant documentation has been added or updated.
  • No new warnings or errors have been introduced.
  • SonarCloud issues have been reviewed and addressed.
  • QA Passed

Testing Process

yarn vitest run src/app/drive/components/NameCollisionDialog, plus the manual upload/move collision flows (keep both, replace, with and without versioning).

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Deploying drive-web with  Cloudflare Pages  Cloudflare Pages

Latest commit: afbfe83
Status:⚡️  Build in progress...

View logs

@terrerox terrerox self-assigned this Sep 11, 2026
@terrerox
terrerox added this pull request to stack #2149 September 11, 2026 04:06
@terrerox
terrerox removed this pull request from stack #2149 September 11, 2026 05:41
@terrerox
terrerox added this pull request to stack #2151 September 11, 2026 05:44
@terrerox
terrerox force-pushed the refactor/extract-name-collision-upload-actions branch from 34f9b46 to af37153 Compare September 15, 2026 03:33
@terrerox
terrerox force-pushed the fix/name-collision-matching-and-batching branch from 7091a30 to bce942f Compare September 15, 2026 03:33
* The duplicate checks return raw API items without isFolder, so existing items are tagged
* here to let consumers tell colliding files and folders apart.
*/
const asExistingItems = (items: (DriveFileData | DriveFolderData)[], isFolder: boolean): DriveItemData[] =>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: asExistingItems reads like a cast but it's actually adding isFolder field, maybe addIsFolderField or similar would be more honest about what it does

Comment on lines +63 to +71
const keepAndMoveItems = async (
items: DriveItemData[],
destinationUuid: string,
{ dispatch }: NameCollisionContext,
) => {
for (const item of items) {
const itemParsed = await getUniqueNameMovePayload(item, destinationUuid);
await dispatch(storageThunks.moveItemsThunk({ items: [itemParsed], destinationFolderId: destinationUuid }));
}
): Promise<void> => {
if (items.length === 0) return;

const itemsParsed = await Promise.all(items.map((item) => getUniqueNameMovePayload(item, destinationUuid)));
await dispatch(storageThunks.moveItemsThunk({ items: itemsParsed, destinationFolderId: destinationUuid }));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe would be fine to check if some items have same name+extension, because I think that from trash could go items with same name and extension to same folder and will produce errors

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I Fixed in #2159, with e2e in #2160 because this PR will exceed kloc limit.

CandelR
CandelR previously approved these changes Sep 22, 2026
@terrerox
terrerox force-pushed the fix/name-collision-matching-and-batching branch 2 times, most recently from 6ce2539 to 510b4d1 Compare September 30, 2026 02:25
@terrerox
terrerox force-pushed the fix/name-collision-matching-and-batching branch 2 times, most recently from 08a7437 to 16b1766 Compare October 7, 2026 01:03
Duplicated items were matched to their existing counterpart by array
index, which could make Replace trash the wrong file. They are now paired
by name and type (or name only for folders), and each resolution goes
through the array-based primitives (moveItemsToTrash, moveItemsThunk,
upload managers) so batching, concurrency limits and per-item error
handling are inherited instead of reimplemented per item.
…never cross-match

The duplicate checks return raw API items that carry no isFolder, so the
name matcher could never pair a moved folder with its existing folder and
could pair an uploaded folder with a file of the same name. Existing items
are now tagged when the collision groups are built, and the matcher only
pairs folders with folders and files with files.
Covers single and multiple duplicates, per-item and apply-to-all skipping,
non-conflicting files still uploading, and Replace trashing the matching
file, with auth, bootstrap and Drive endpoints mocked so the specs run
without a backend. Queued uploads are asserted through the task panel
because Playwright cannot intercept the bridge in Firefox.
Adds a Skip option to the name-collision dialog, next to Replace and Keep
both, for both upload and move collisions. Duplicates are resolved one at
a time, and a new "Apply this action to all duplicates" checkbox handles
them all at once, closing the dialog immediately and running the work in
the background.

The renameModal i18n block is renamed to alreadyExistsModal (the dialog
does not rename anything), the description text is operation-neutral and
the apply-to-all label toggles the checkbox.
Skipping a colliding folder upload now keeps the existing folder and uploads only
the files and subfolders that do not exist yet, merging colliding subfolders
recursively so the folder structure is preserved.
Covers keep both for files and folders, replacing a folder, merging a
skipped folder into the existing one, replace, keep both and skip for
moved files, and versioned replace. The Drive mock now tracks folders,
folder creation, moves and a versioning flag; moves are driven by
dispatching the HTML5 drag events on the row's drop zone.
@terrerox
terrerox force-pushed the fix/name-collision-matching-and-batching branch from 16b1766 to 5a3ca29 Compare October 7, 2026 13:25
@terrerox
terrerox removed this pull request from stack #2151 October 7, 2026 13:28
terrerox and others added 7 commits October 7, 2026 10:04
…restore-e2e

[PB-6531]: e2e coverage for same-name restore collisions
…atch

[PB-6531]: resolve same-name items within a move collision batch
…ge-on-skip

[PB-6531]: merge folder uploads into the existing folder on skip
[PB-6531]: e2e coverage for the skip option in name collisions
…collision

[PB-6531]feat/skip item option in name collision
@terrerox
terrerox merged commit bef2cfe into refactor/extract-name-collision-upload-actions Oct 7, 2026
1 of 3 checks passed
@terrerox
terrerox deleted the fix/name-collision-matching-and-batching branch October 7, 2026 14:43
@sonarqubecloud

sonarqubecloud Bot commented Oct 7, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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.

2 participants