|
|
|
|
@ -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[] {
|
|
|
|
|
|