Skip to content

[PM-40318] Introduce Web's VaultNextComponet for VFO1 - #22425

Draft
shane-melton wants to merge 2 commits into
mainfrom
vault/pm-40318/web-filter-integration
Draft

[PM-40318] Introduce Web's VaultNextComponet for VFO1#22425
shane-melton wants to merge 2 commits into
mainfrom
vault/pm-40318/web-filter-integration

Conversation

@shane-melton

@shane-melton shane-melton commented Aug 14, 2026

Copy link
Copy Markdown
Member

🎟️ Tracking

PM-40318

📔 Objective

Introduce the VaultNextComponent that uses the new, shared VaultItemsTableComponent for VFO1.

Router query parameter mapping and legacy query param handling coming in a followup PR.

📸 Screenshots

Screenshot 2026-08-13 at 5 13 46 PM

@shane-melton

Copy link
Copy Markdown
Member Author

@nick-livefront Tagging you since you've just done similar work in Desktop. I have a few minor things to clean up still, but should be ready for an initial review.

@shane-melton shane-melton added ai-review Request a Claude code review t:feature Change Type - Feature Development labels Aug 14, 2026
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the new VaultNextComponent and WebVaultItemActionsService for web's individual vault, the featureFlaggedRoute swap behind VFO1Foundation, and the shared CipherActionService / CipherRowMenuService changes in libs/vault. The web component mirrors the desktop VaultListTableComponent pattern landed in #22383 (signals + inject(), OnPush, safeProvider, row handlers delegated to CipherRowMenuService), and the dialog flows in WebVaultItemActionsService match the legacy vault.component.ts behavior for password reprompt, edit vs partial-edit config, unknown-cipher toasting, passkey clone warning, and attachment entitlement checks. The permanentlyDeleteItem key resolves in all three client locale files, and the new reprompt gates on restore and viewAttachments close real gaps in the shared service. New page is behind a feature flag with trash/archive intentionally excluded and documented.

Code Review Details
  • ❓ : Writable-collection gate for "Add to shared folder" is global rather than scoped to the cipher's own organization
    • libs/vault/src/services/cipher-row-menu.service.ts:199

return false;
}

return this.organizations().length > 0 && collections.some((c) => !c.readOnly);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

QUESTION: Should the writable-collection check be scoped to the cipher's own organization?

Details

The gate is global: any org membership plus any writable collection anywhere. For a cipher that already belongs to org A, the destination is fixed — WebVaultItemActionsService.assignToCollections narrows availableCollections to c.organizationId === cipher.organizationId, and AssignCollectionsComponent.handleOrganizationCiphers narrows further with canEditItems(org).

So a user in org A (read-only collections only) and org B (writable) sees "Add to shared folder" on an org A item and lands in a dialog with an empty picker.

A per-org scope for org ciphers would keep the global check for personal items, where the dialog does let the user choose the org:

const assignable = cipher.organizationId
  ? collections.filter((c) => c.organizationId === cipher.organizationId && !c.readOnly)
  : collections.filter((c) => !c.readOnly);

return this.organizations().length > 0 && assignable.length > 0;

Not a regression — the previous gate (!!cipher.organizationId && canAssignToCollections) had the same dead end — so happy to leave it if the multi-org case is out of scope for VFO1.

@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.13924% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.92%. Comparing base (25d5c69) to head (902b201).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...c/app/vault/services/vault-item-actions.service.ts 86.30% 6 Missing and 4 partials ⚠️
...app/vault/individual-vault/vault-routing.module.ts 0.00% 3 Missing ⚠️
...web/src/app/vault/individual-vault/vault.module.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #22425      +/-   ##
==========================================
- Coverage   53.93%   53.92%   -0.01%     
==========================================
  Files        4297     4299       +2     
  Lines      136500   136639     +139     
  Branches    21569    21590      +21     
==========================================
+ Hits        73616    73685      +69     
- Misses      57518    57584      +66     
- Partials     5366     5370       +4     

☔ View full report in Codecov by Harness.
📢 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.

@nick-livefront nick-livefront left a comment

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.

Nothing major to me, looks great!

Comment on lines +59 to +60
this.accountService.activeAccount$.pipe(
getUserId,

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.

⛏️ (non-blocking) This is the second usage of activeAccount$ -> getUserId. Should we make a single reference to active account. Minor benefit of one emission rather than two, Angular might optimize that already 🤷

const isDeleted = CipherViewLikeUtils.isDeleted(cipher);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "deleteItem" },
title: { key: isDeleted ? "permanentlyDeleteItem" : "deleteItem" },

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.

👏 Nice catch!

* The web individual vault's cipher actions that open a web-specific dialog.
*/
@Injectable()
export class WebVaultItemActionsService {

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.

👏 A separate service rather than keeping these in the vault, 10/10

Comment on lines +35 to +38
* Not yet wired: the typed filter adapter that syncs the
* table's chips to the URL, the redirect that rewrites legacy filter query params, and the
* `?itemId=&action=` deep link that opens an item on load. Until the chips are wired there is no
* route to trash or the archive from this page, so both are excluded from the list.

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.

FYI: I should have a utility method up for review this morning that handles this.

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 t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants