mirror of
https://github.com/bitwarden/browser
synced 2026-02-24 16:43:27 +00:00
[PM-24560] - Add Archive UI Element to View and Edit Item Cards (#16954)
* finalize new UI elements for archive/unarchive * add tests * add missing service * add tests * updates to edit and view pages * use structureClone * fix lint * fix typo * clean up return types * fixes to archive UI * fix tests * use @if and userId$
This commit is contained in:
committed by
jaasen-livefront
parent
246a549f58
commit
348ed4b616
@@ -3,12 +3,14 @@ import { Observable } from "rxjs";
|
||||
import { CipherId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils";
|
||||
|
||||
import { CipherData } from "../models/data/cipher.data";
|
||||
|
||||
export abstract class CipherArchiveService {
|
||||
abstract hasArchiveFlagEnabled$: Observable<boolean>;
|
||||
abstract archivedCiphers$(userId: UserId): Observable<CipherViewLike[]>;
|
||||
abstract userCanArchive$(userId: UserId): Observable<boolean>;
|
||||
abstract userHasPremium$(userId: UserId): Observable<boolean>;
|
||||
abstract archiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<void>;
|
||||
abstract unarchiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<void>;
|
||||
abstract archiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<CipherData>;
|
||||
abstract unarchiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<CipherData>;
|
||||
abstract showSubscriptionEndedMessaging$(userId: UserId): Observable<boolean>;
|
||||
}
|
||||
|
||||
@@ -109,6 +109,10 @@ export class CipherView implements View, InitializerMetadata {
|
||||
return this.item?.subTitle;
|
||||
}
|
||||
|
||||
get canBeArchived(): boolean {
|
||||
return !this.isDeleted && !this.isArchived;
|
||||
}
|
||||
|
||||
get hasPasswordHistory(): boolean {
|
||||
return this.passwordHistory && this.passwordHistory.length > 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* include structuredClone in test environment.
|
||||
* @jest-environment ../../../../shared/test.environment.ts
|
||||
*/
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { of, firstValueFrom, BehaviorSubject } from "rxjs";
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from "@bitwarden/common/vault/utils/cipher-view-like-utils";
|
||||
|
||||
import { CipherArchiveService } from "../abstractions/cipher-archive.service";
|
||||
import { CipherData } from "../models/data/cipher.data";
|
||||
|
||||
export class DefaultCipherArchiveService implements CipherArchiveService {
|
||||
constructor(
|
||||
@@ -84,15 +85,17 @@ export class DefaultCipherArchiveService implements CipherArchiveService {
|
||||
);
|
||||
}
|
||||
|
||||
async archiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<void> {
|
||||
async archiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<CipherData> {
|
||||
const request = new CipherBulkArchiveRequest(Array.isArray(ids) ? ids : [ids]);
|
||||
const r = await this.apiService.send("PUT", "/ciphers/archive", request, true, true);
|
||||
const response = new ListResponse(r, CipherResponse);
|
||||
|
||||
const currentCiphers = await firstValueFrom(this.cipherService.ciphers$(userId));
|
||||
// prevent mutating ciphers$ state
|
||||
const localCiphers = structuredClone(currentCiphers);
|
||||
|
||||
for (const cipher of response.data) {
|
||||
const localCipher = currentCiphers[cipher.id as CipherId];
|
||||
const localCipher = localCiphers[cipher.id as CipherId];
|
||||
|
||||
if (localCipher == null) {
|
||||
continue;
|
||||
@@ -102,18 +105,21 @@ export class DefaultCipherArchiveService implements CipherArchiveService {
|
||||
localCipher.revisionDate = cipher.revisionDate;
|
||||
}
|
||||
|
||||
await this.cipherService.upsert(Object.values(currentCiphers), userId);
|
||||
await this.cipherService.upsert(Object.values(localCiphers), userId);
|
||||
return response.data[0];
|
||||
}
|
||||
|
||||
async unarchiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<void> {
|
||||
async unarchiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise<CipherData> {
|
||||
const request = new CipherBulkUnarchiveRequest(Array.isArray(ids) ? ids : [ids]);
|
||||
const r = await this.apiService.send("PUT", "/ciphers/unarchive", request, true, true);
|
||||
const response = new ListResponse(r, CipherResponse);
|
||||
|
||||
const currentCiphers = await firstValueFrom(this.cipherService.ciphers$(userId));
|
||||
// prevent mutating ciphers$ state
|
||||
const localCiphers = structuredClone(currentCiphers);
|
||||
|
||||
for (const cipher of response.data) {
|
||||
const localCipher = currentCiphers[cipher.id as CipherId];
|
||||
const localCipher = localCiphers[cipher.id as CipherId];
|
||||
|
||||
if (localCipher == null) {
|
||||
continue;
|
||||
@@ -123,6 +129,7 @@ export class DefaultCipherArchiveService implements CipherArchiveService {
|
||||
localCipher.revisionDate = cipher.revisionDate;
|
||||
}
|
||||
|
||||
await this.cipherService.upsert(Object.values(currentCiphers), userId);
|
||||
await this.cipherService.upsert(Object.values(localCiphers), userId);
|
||||
return response.data[0];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user