1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-29 07:43:28 +00:00

[PM-31264] Broken vault filters in milestone-1 (#18589) (#18599)

* Fix vault filters

Now uses the same `createFilterFunction` as web rather than the custom proxy like approach.

* Remove provide

(cherry picked from commit cf6d02fafa)
This commit is contained in:
Oscar Hinton
2026-01-27 20:01:06 +01:00
committed by GitHub
parent fefc8badfd
commit 6c880ea2ad

View File

@@ -4,6 +4,7 @@ import { CommonModule } from "@angular/common";
import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import {
combineLatest,
firstValueFrom,
Subject,
takeUntil,
@@ -70,6 +71,7 @@ import {
CipherFormModule,
CipherViewComponent,
CollectionAssignmentResult,
createFilterFunction,
DecryptionFailureDialogComponent,
DefaultChangeLoginPasswordService,
DefaultCipherFormConfigService,
@@ -79,6 +81,7 @@ import {
VaultFilter,
VaultFilterServiceAbstraction as VaultFilterService,
RoutedVaultFilterBridgeService,
RoutedVaultFilterService,
VaultItemsTransferService,
DefaultVaultItemsTransferService,
} from "@bitwarden/vault";
@@ -216,6 +219,7 @@ export class VaultComponent implements OnInit, OnDestroy, CopyClickListener {
private policyService: PolicyService,
private archiveCipherUtilitiesService: ArchiveCipherUtilitiesService,
private routedVaultFilterBridgeService: RoutedVaultFilterBridgeService,
private routedVaultFilterService: RoutedVaultFilterService,
private vaultFilterService: VaultFilterService,
private vaultItemTransferService: VaultItemsTransferService,
) {}
@@ -234,9 +238,16 @@ export class VaultComponent implements OnInit, OnDestroy, CopyClickListener {
});
// Subscribe to filter changes from router params via the bridge service
this.routedVaultFilterBridgeService.activeFilter$
// Use combineLatest to react to changes in both the filter and archive flag
combineLatest([
this.routedVaultFilterBridgeService.activeFilter$,
this.routedVaultFilterService.filter$,
this.cipherArchiveService.hasArchiveFlagEnabled$,
])
.pipe(
switchMap((vaultFilter: VaultFilter) => from(this.applyVaultFilter(vaultFilter))),
switchMap(([vaultFilter, routedFilter, archiveEnabled]) =>
from(this.applyVaultFilter(vaultFilter, routedFilter, archiveEnabled)),
),
takeUntil(this.componentIsDestroyed$),
)
.subscribe();
@@ -789,48 +800,19 @@ export class VaultComponent implements OnInit, OnDestroy, CopyClickListener {
await this.go().catch(() => {});
}
/**
* Wraps a filter function to handle CipherListView objects.
* CipherListView has a different type structure where type can be a string or object.
* This wrapper converts it to CipherView-compatible structure before filtering.
*/
private wrapFilterForCipherListView(
filterFn: (cipher: CipherView) => boolean,
): (cipher: CipherViewLike) => boolean {
return (cipher: CipherViewLike) => {
// For CipherListView, create a proxy object with the correct type property
if (CipherViewLikeUtils.isCipherListView(cipher)) {
const proxyCipher = {
...cipher,
type: CipherViewLikeUtils.getType(cipher),
// Normalize undefined organizationId to null for filter compatibility
organizationId: cipher.organizationId ?? null,
// Normalize empty string folderId to null for filter compatibility
folderId: cipher.folderId ? cipher.folderId : null,
// Explicitly include isDeleted and isArchived since they might be getters
isDeleted: CipherViewLikeUtils.isDeleted(cipher),
isArchived: CipherViewLikeUtils.isArchived(cipher),
};
return filterFn(proxyCipher as any);
}
return filterFn(cipher);
};
}
async applyVaultFilter(vaultFilter: VaultFilter) {
async applyVaultFilter(
vaultFilter: VaultFilter,
routedFilter: Parameters<typeof createFilterFunction>[0],
archiveEnabled: boolean,
) {
this.searchBarService.setPlaceholderText(
this.i18nService.t(this.calculateSearchBarLocalizationString(vaultFilter)),
);
this.activeFilter = vaultFilter;
const originalFilterFn = this.activeFilter.buildFilter();
const wrappedFilterFn = this.wrapFilterForCipherListView(originalFilterFn);
const filterFn = createFilterFunction(routedFilter, archiveEnabled);
await this.vaultItemsComponent?.reload(
wrappedFilterFn,
vaultFilter.isDeleted,
vaultFilter.isArchived,
);
await this.vaultItemsComponent?.reload(filterFn, vaultFilter.isDeleted, vaultFilter.isArchived);
}
private getAvailableCollections(cipher: CipherView): CollectionView[] {