Skip to content

[PM-32743] Convert collections to folders when importing into My Items#20453

Open
mcamirault wants to merge 3 commits intomainfrom
tools/pm-32743/import-collections-to-my-items-as-folders
Open

[PM-32743] Convert collections to folders when importing into My Items#20453
mcamirault wants to merge 3 commits intomainfrom
tools/pm-32743/import-collections-to-my-items-as-folders

Conversation

@mcamirault
Copy link
Copy Markdown
Contributor

@mcamirault mcamirault commented Apr 30, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-32743

📔 Objective

This PR changes what happens to collections when importing into My Items. Previously other collections a cipher might be part of were ignored because My Items does not support nesting; with this change the other collections will be recreated as folders with the same names, with any collection hierarchy recreated as a folder hierarchy and with the cipher in the folder created from its collection. Since a cipher can only have one folder but be part of multiple collections, we now throw an error if you try to import into My Items with any ciphers that are part of multiple collections. Importing into the base of the org or into any other collection besides My Items is unchanged.

📸 Screenshots

For the following demos we are importing from an org export with three collections and two ciphers:
Default Collection: One cipher called "Default Collection Credential"
Developers: No ciphers, one sub-collection called "Tools Developers"
Tools Developers: One cipher called "Tools Dev Credentials"

Importing into the base of an empty organization. This is will also happen if importing into any collection besides My Items, though the collection structure will be under the target collection

Screen.Recording.2026-04-30.at.11.54.54.mov

This results in the following collection structure:

  • Default Collection: One cipher
  • Developers: No ciphers, one sub-collection
    • Tools Developers: One cipher

and no folders are created

Importing into My Items

Screen.Recording.2026-04-30.at.11.55.46.mov

This results in the following collection structure:

  • My Items: Two ciphers

and the following folder structure:

  • Default collection: One cipher
  • Developers: No ciphers, one sub-folder
    • Tools Developers: One cipher

@mcamirault mcamirault requested a review from a team as a code owner April 30, 2026 16:39
@mcamirault mcamirault added the ai-review Request a Claude code review label Apr 30, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 30, 2026

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Re-review after the fix-up commits (d51705e3f9 and a51fdeaec8). The previously flagged critical issue — the multi-collection guard checking cipher.collectionIds, which Bitwarden importers explicitly null out — has been addressed. The guard now inspects importResult.collectionRelationships (import.service.ts:529-536), which is the field the Bitwarden JSON and encrypted-JSON importers actually populate, so the throw fires for the real-world input source. New unit tests at import.service.spec.ts:285 and :300 exercise both the multi-collection rejection and the collections-to-folders mapping, covering the gap noted in the prior review. The addFolders extraction and the new folders/folderRelationships fields on ImportOrganizationCiphersRequest look correct and consistent.

Code Review Details

No findings.

Comment thread libs/importer/src/services/import.service.ts Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

❌ Patch coverage is 68.18182% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.13%. Comparing base (ee3d946) to head (a51fdea).
⚠️ Report is 35 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
libs/importer/src/services/import.service.ts 75.00% 3 Missing and 2 partials ⚠️
...els/request/import-organization-ciphers.request.ts 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #20453      +/-   ##
==========================================
+ Coverage   47.11%   47.13%   +0.01%     
==========================================
  Files        3943     3947       +4     
  Lines      119797   119862      +65     
  Branches    18388    18396       +8     
==========================================
+ Hits        56442    56492      +50     
- Misses      59081    59091      +10     
- Partials     4274     4279       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

harr1424
harr1424 previously approved these changes Apr 30, 2026
Copy link
Copy Markdown
Contributor

@harr1424 harr1424 left a comment

Choose a reason for hiding this comment

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

Barring the ❌ CRITICAL finding reported during the Claude review, this looks good to me! Happy to re-review if it's not a false positive.

@sonarqubecloud
Copy link
Copy Markdown

❌ The last analysis has failed.

See analysis details on SonarQube Cloud

@harr1424 harr1424 self-requested a review April 30, 2026 22:56
@mcamirault
Copy link
Copy Markdown
Contributor Author

@claude Review this again

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 1, 2026

Claude finished @mcamirault's task in 2m 10s —— View job


Re-review: APPROVE

The previously flagged CRITICAL issue is resolved. The multi-collection guard at libs/importer/src/services/import.service.ts:529-536 now inspects importResult.collectionRelationships — the field actually populated by the Bitwarden JSON importer (bitwarden-json-importer.ts:65-72 pushes onto collectionRelationships after nulling cipher.collectionIds at line 52). The throw will fire for the real-world input source.

What was verified this pass:

  • addFolders extraction (import.service.ts:431-447) is a clean refactor; identical behavior to the previous inline blocks, now reused by handleOrganizationalImport so My Items imports actually carry folder data through.
  • New folders/folderRelationships on ImportOrganizationCiphersRequest are needed for the org-import path to send folder data to the server.
  • setImportTarget for DefaultUserCollection correctly: (1) bails on multi-collection ciphers, (2) maps each collection to a like-named FolderView (slash-delimited names will yield nested folders, matching the screenshot), (3) reuses the existing collectionRelationships tuples as folderRelationships, then collapses collections to [importTarget] and re-points all ciphers at index 0.
  • New tests at import.service.spec.ts:285 and :300 exercise both the rejection path and the collections-to-folders mapping. The gap noted previously is closed.

Non-blocking observations:

  • The membership check is O(n·m): for each cipher index, it filters the full relationships array. A single pass building Map<cipherIdx, count> would be O(n+m). Not worth blocking — typical imports are small — but a Map keyed only on cipherIdx would also drop the unused _c parameter on the outer some.
  • The new request fields rely on server-side support for folders during org import; that's outside this repo's surface area, so flagging only as awareness.

No new findings. Approving.
| Branch

@mcamirault mcamirault added the needs-qa Marks a PR as requiring QA approval label May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review needs-qa Marks a PR as requiring QA approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants