From ba1c74b9052a79806e1f159547f4e5cc442227e7 Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Tue, 16 Dec 2025 18:04:54 -0500 Subject: [PATCH] [PM-29286] clear selected items when filter is changed (#17929) * check filter inside vault-items and clear on change --- .../vault-items/vault-items.component.spec.ts | 31 ++++++++++++++++++- .../vault-items/vault-items.component.ts | 28 ++++++++++++++++- .../vault-items/vault-items.stories.ts | 12 +++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts b/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts index 1eccb4c49ce..c1c25c625da 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts @@ -1,6 +1,6 @@ import { ScrollingModule } from "@angular/cdk/scrolling"; import { TestBed } from "@angular/core/testing"; -import { of } from "rxjs"; +import { of, Subject } from "rxjs"; import { CollectionView } from "@bitwarden/admin-console/common"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -11,12 +11,15 @@ import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/res import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils"; import { MenuModule, TableModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; +import { RoutedVaultFilterService } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service"; +import { RoutedVaultFilterModel } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model"; import { VaultItem } from "./vault-item"; import { VaultItemsComponent } from "./vault-items.component"; describe("VaultItemsComponent", () => { let component: VaultItemsComponent; + let filterSelect: Subject; const cipher1: Partial = { id: "cipher-1", @@ -31,6 +34,8 @@ describe("VaultItemsComponent", () => { }; beforeEach(async () => { + filterSelect = new Subject(); + await TestBed.configureTestingModule({ declarations: [VaultItemsComponent], imports: [ScrollingModule, TableModule, I18nPipe, MenuModule], @@ -61,6 +66,12 @@ describe("VaultItemsComponent", () => { hasArchiveFlagEnabled$: of(true), }, }, + { + provide: RoutedVaultFilterService, + useValue: { + filter$: filterSelect, + }, + }, ], }); @@ -143,4 +154,22 @@ describe("VaultItemsComponent", () => { expect(component.bulkUnarchiveAllowed).toBe(false); }); }); + + describe("filter change handling", () => { + it("clears selection when routed filter changes", () => { + const items: VaultItem[] = [ + { cipher: cipher1 as CipherView }, + { cipher: cipher2 as CipherView }, + ]; + + component["selection"].select(...items); + expect(component["selection"].selected.length).toBeGreaterThan(0); + + filterSelect.next({ + folderId: "folderId", + }); + + expect(component["selection"].selected.length).toBe(0); + }); + }); }); diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.ts b/apps/web/src/app/vault/components/vault-items/vault-items.component.ts index a935314eb3a..a51009a1e5b 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.ts @@ -3,7 +3,15 @@ import { SelectionModel } from "@angular/cdk/collections"; import { Component, EventEmitter, Input, Output } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { Observable, combineLatest, map, of, startWith, switchMap } from "rxjs"; +import { + Observable, + combineLatest, + distinctUntilChanged, + map, + of, + startWith, + switchMap, +} from "rxjs"; import { CollectionView, Unassigned, CollectionAdminView } from "@bitwarden/admin-console/common"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; @@ -19,6 +27,7 @@ import { } from "@bitwarden/common/vault/utils/cipher-view-like-utils"; import { SortDirection, TableDataSource } from "@bitwarden/components"; import { OrganizationId } from "@bitwarden/sdk-internal"; +import { RoutedVaultFilterService } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service"; import { GroupView } from "../../../admin-console/organizations/core"; @@ -152,6 +161,7 @@ export class VaultItemsComponent { protected cipherAuthorizationService: CipherAuthorizationService, protected restrictedItemTypesService: RestrictedItemTypesService, protected cipherArchiveService: CipherArchiveService, + protected routedVaultFilterService: RoutedVaultFilterService, ) { this.canDeleteSelected$ = this.selection.changed.pipe( startWith(null), @@ -219,6 +229,22 @@ export class VaultItemsComponent { ); }), ); + + this.routedVaultFilterService.filter$ + .pipe( + distinctUntilChanged( + (prev, curr) => + prev.organizationId === curr.organizationId && + prev.collectionId === curr.collectionId && + prev.folderId === curr.folderId && + prev.type === curr.type && + prev.organizationIdParamType === curr.organizationIdParamType, + ), + takeUntilDestroyed(), + ) + .subscribe(() => { + this.clearSelection(); + }); } clearSelection() { diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts index d973fbcbbc7..a71427cf475 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts @@ -40,6 +40,7 @@ import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cip import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils"; import { LayoutComponent } from "@bitwarden/components"; +import { RoutedVaultFilterService } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service"; import { GroupView } from "../../../admin-console/organizations/core"; import { PreloadedEnglishI18nModule } from "../../../core/tests"; @@ -150,6 +151,17 @@ export default { hasArchiveFlagEnabled$: of(true), }, }, + { + provide: RoutedVaultFilterService, + useValue: { + filter$: of({ + organizationId: null, + collectionId: null, + folderId: null, + type: null, + }), + }, + }, ], }), applicationConfig({