mirror of
https://github.com/bitwarden/browser
synced 2025-12-14 07:13:32 +00:00
[PM-22134] Migrate list views to CipherListView from the SDK (#15174)
* add `CipherViewLike` and utilities to handle `CipherView` and `CipherViewLike` * migrate libs needed for web vault to support `CipherViewLike` * migrate web vault components to support * add for CipherView. will have to be later * fetch full CipherView for copying a password * have only the cipher service utilize SDK migration flag - This keeps feature flag logic away from the component - Also cuts down on what is needed for other platforms * strongly type CipherView for AC vault - Probably temporary before migration of the AC vault to `CipherListView` SDK * fix build icon tests by being more gracious with the uri structure * migrate desktop components to CipherListViews$ * consume card from sdk * add browser implementation for `CipherListView` * update copy message for single copiable items * refactor `getCipherViewLikeLogin` to `getLogin` * refactor `getCipherViewLikeCard` to `getCard` * add `hasFido2Credentials` helper * add decryption failure to cipher like utils * add todo with ticket * fix decryption failure typing * fix copy card messages * fix addition of organizations and collections for `PopupCipherViewLike` - accessors were being lost * refactor to getters to fix re-rendering bug * fix decryption failure helper * fix sorting functions for `CipherViewLike` * formatting * add `CipherViewLikeUtils` tests * refactor "copiable" to "copyable" to match SDK * use `hasOldAttachments` from cipherlistview * fix typing * update SDK version * add feature flag for cipher list view work * use `CipherViewLikeUtils` for copyable values rather than referring to the cipher directly * update restricted item type to support CipherViewLike * add cipher support to `CipherViewLikeUtils` * update `isCipherListView` check * refactor CipherLike to a separate type * refactor `getFullCipherView` into the cipher service * add optional chaining for `uriChecksum` * set empty array for decrypted CipherListView * migrate nudge service to use `cipherListViews` * update web vault to not depend on `cipherViews$` * update popup list filters to use `CipherListView` * fix storybook * fix tests * accept undefined as a MY VAULT filter value for cipher list views * use `LoginUriView` for uri logic (#15530) * filter out null ciphers from the `_allDecryptedCiphers$` (#15539) * use `launchUri` to avoid any unexpected behavior in URIs - this appends `http://` when missing
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { buildCipherIcon, CipherIconDetails } from "@bitwarden/common/vault/icon/build-cipher-icon";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils";
|
||||
|
||||
@Component({
|
||||
selector: "app-vault-icon",
|
||||
@@ -25,7 +25,7 @@ export class IconComponent {
|
||||
/**
|
||||
* The cipher to display the icon for.
|
||||
*/
|
||||
cipher = input.required<CipherView>();
|
||||
cipher = input.required<CipherViewLike>();
|
||||
|
||||
imageLoaded = signal(false);
|
||||
|
||||
|
||||
@@ -21,20 +21,23 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SearchService } from "@bitwarden/common/vault/abstractions/search.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||
import { CIPHER_MENU_ITEMS } from "@bitwarden/common/vault/types/cipher-menu-items";
|
||||
import {
|
||||
CipherViewLike,
|
||||
CipherViewLikeUtils,
|
||||
} from "@bitwarden/common/vault/utils/cipher-view-like-utils";
|
||||
|
||||
@Directive()
|
||||
export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
export class VaultItemsComponent<C extends CipherViewLike> implements OnInit, OnDestroy {
|
||||
@Input() activeCipherId: string = null;
|
||||
@Output() onCipherClicked = new EventEmitter<CipherView>();
|
||||
@Output() onCipherRightClicked = new EventEmitter<CipherView>();
|
||||
@Output() onCipherClicked = new EventEmitter<C>();
|
||||
@Output() onCipherRightClicked = new EventEmitter<C>();
|
||||
@Output() onAddCipher = new EventEmitter<CipherType | undefined>();
|
||||
@Output() onAddCipherOptions = new EventEmitter();
|
||||
|
||||
loaded = false;
|
||||
ciphers: CipherView[] = [];
|
||||
ciphers: C[] = [];
|
||||
deleted = false;
|
||||
organization: Organization;
|
||||
CipherType = CipherType;
|
||||
@@ -55,7 +58,7 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
protected searchPending = false;
|
||||
|
||||
/** Construct filters as an observable so it can be appended to the cipher stream. */
|
||||
private _filter$ = new BehaviorSubject<(cipher: CipherView) => boolean | null>(null);
|
||||
private _filter$ = new BehaviorSubject<(cipher: C) => boolean | null>(null);
|
||||
private destroy$ = new Subject<void>();
|
||||
private isSearchable: boolean = false;
|
||||
private _searchText$ = new BehaviorSubject<string>("");
|
||||
@@ -71,7 +74,7 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
return this._filter$.value;
|
||||
}
|
||||
|
||||
set filter(value: (cipher: CipherView) => boolean | null) {
|
||||
set filter(value: (cipher: C) => boolean | null) {
|
||||
this._filter$.next(value);
|
||||
}
|
||||
|
||||
@@ -102,13 +105,13 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
async load(filter: (cipher: CipherView) => boolean = null, deleted = false) {
|
||||
async load(filter: (cipher: C) => boolean = null, deleted = false) {
|
||||
this.deleted = deleted ?? false;
|
||||
await this.applyFilter(filter);
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
async reload(filter: (cipher: CipherView) => boolean = null, deleted = false) {
|
||||
async reload(filter: (cipher: C) => boolean = null, deleted = false) {
|
||||
this.loaded = false;
|
||||
await this.load(filter, deleted);
|
||||
}
|
||||
@@ -117,15 +120,15 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
await this.reload(this.filter, this.deleted);
|
||||
}
|
||||
|
||||
async applyFilter(filter: (cipher: CipherView) => boolean = null) {
|
||||
async applyFilter(filter: (cipher: C) => boolean = null) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
selectCipher(cipher: CipherView) {
|
||||
selectCipher(cipher: C) {
|
||||
this.onCipherClicked.emit(cipher);
|
||||
}
|
||||
|
||||
rightClickCipher(cipher: CipherView) {
|
||||
rightClickCipher(cipher: C) {
|
||||
this.onCipherRightClicked.emit(cipher);
|
||||
}
|
||||
|
||||
@@ -141,7 +144,8 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
return !this.searchPending && this.isSearchable;
|
||||
}
|
||||
|
||||
protected deletedFilter: (cipher: CipherView) => boolean = (c) => c.isDeleted === this.deleted;
|
||||
protected deletedFilter: (cipher: C) => boolean = (c) =>
|
||||
CipherViewLikeUtils.isDeleted(c) === this.deleted;
|
||||
|
||||
/**
|
||||
* Creates stream of dependencies that results in the list of ciphers to display
|
||||
@@ -156,7 +160,7 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
.pipe(
|
||||
switchMap((userId) =>
|
||||
combineLatest([
|
||||
this.cipherService.cipherViews$(userId).pipe(filter((ciphers) => ciphers != null)),
|
||||
this.cipherService.cipherListViews$(userId).pipe(filter((ciphers) => ciphers != null)),
|
||||
this.cipherService.failedToDecryptCiphers$(userId),
|
||||
this._searchText$,
|
||||
this._filter$,
|
||||
@@ -165,12 +169,12 @@ export class VaultItemsComponent implements OnInit, OnDestroy {
|
||||
]),
|
||||
),
|
||||
switchMap(([indexedCiphers, failedCiphers, searchText, filter, userId, restricted]) => {
|
||||
let allCiphers = indexedCiphers ?? [];
|
||||
let allCiphers = (indexedCiphers ?? []) as C[];
|
||||
const _failedCiphers = failedCiphers ?? [];
|
||||
|
||||
allCiphers = [..._failedCiphers, ...allCiphers];
|
||||
allCiphers = [..._failedCiphers, ...allCiphers] as C[];
|
||||
|
||||
const restrictedTypeFilter = (cipher: CipherView) =>
|
||||
const restrictedTypeFilter = (cipher: CipherViewLike) =>
|
||||
!this.restrictedItemTypesService.isCipherRestricted(cipher, restricted);
|
||||
|
||||
return this.searchService.searchCiphers(
|
||||
|
||||
@@ -25,7 +25,7 @@ export class EmptyVaultNudgeService extends DefaultSingleNudgeService {
|
||||
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||
return combineLatest([
|
||||
this.getNudgeStatus$(nudgeType, userId),
|
||||
this.cipherService.cipherViews$(userId),
|
||||
this.cipherService.cipherListViews$(userId),
|
||||
this.organizationService.organizations$(userId),
|
||||
this.collectionService.decryptedCollections$,
|
||||
]).pipe(
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import {
|
||||
CipherViewLike,
|
||||
CipherViewLikeUtils,
|
||||
} from "@bitwarden/common/vault/utils/cipher-view-like-utils";
|
||||
|
||||
import { CipherStatus } from "./cipher-status.model";
|
||||
|
||||
export type VaultFilterFunction = (cipher: CipherView) => boolean;
|
||||
export type VaultFilterFunction = (cipher: CipherViewLike) => boolean;
|
||||
|
||||
export class VaultFilter {
|
||||
cipherType?: CipherType;
|
||||
@@ -44,10 +47,10 @@ export class VaultFilter {
|
||||
cipherPassesFilter = cipher.favorite;
|
||||
}
|
||||
if (this.status === "trash" && cipherPassesFilter) {
|
||||
cipherPassesFilter = cipher.isDeleted;
|
||||
cipherPassesFilter = CipherViewLikeUtils.isDeleted(cipher);
|
||||
}
|
||||
if (this.cipherType != null && cipherPassesFilter) {
|
||||
cipherPassesFilter = cipher.type === this.cipherType;
|
||||
cipherPassesFilter = CipherViewLikeUtils.getType(cipher) === this.cipherType;
|
||||
}
|
||||
if (this.selectedFolder && this.selectedFolderId == null && cipherPassesFilter) {
|
||||
cipherPassesFilter = cipher.folderId == null;
|
||||
@@ -68,7 +71,7 @@ export class VaultFilter {
|
||||
cipherPassesFilter = cipher.organizationId === this.selectedOrganizationId;
|
||||
}
|
||||
if (this.myVaultOnly && cipherPassesFilter) {
|
||||
cipherPassesFilter = cipher.organizationId === null;
|
||||
cipherPassesFilter = cipher.organizationId == null;
|
||||
}
|
||||
return cipherPassesFilter;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user