mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-23197] update cipherService to return decCiphers (#15433)
* update cipherService to return decCiphers, update input to use signal, refactor observable, update spec
This commit is contained in:
@@ -383,7 +383,7 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
const decCiphers = await this.getDecryptedCiphers(userId);
|
||||
if (decCiphers != null && decCiphers.length !== 0) {
|
||||
await this.reindexCiphers(userId);
|
||||
return await this.getDecryptedCiphers(userId);
|
||||
return decCiphers;
|
||||
}
|
||||
|
||||
const decrypted = await this.decryptCiphers(await this.getAll(userId), userId);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<ng-container *ngIf="showNewItemSpotlight">
|
||||
<ng-container *ngIf="showNewItemSpotlight$ | async">
|
||||
<bit-spotlight
|
||||
[title]="nudgeTitle"
|
||||
[subtitle]="nudgeBody"
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ComponentRef } from "@angular/core";
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { NudgesService, NudgeType } from "@bitwarden/angular/vault";
|
||||
import { AccountService, Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherType } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { FakeAccountService, mockAccountServiceWith } from "../../../../../common/spec";
|
||||
|
||||
import { NewItemNudgeComponent } from "./new-item-nudge.component";
|
||||
|
||||
describe("NewItemNudgeComponent", () => {
|
||||
let component: NewItemNudgeComponent;
|
||||
let componentRef: ComponentRef<NewItemNudgeComponent>;
|
||||
let fixture: ComponentFixture<NewItemNudgeComponent>;
|
||||
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
let accountService: MockProxy<AccountService>;
|
||||
let nudgesService: MockProxy<NudgesService>;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith("test-user-id" as UserId);
|
||||
|
||||
beforeEach(async () => {
|
||||
i18nService = mock<I18nService>({ t: (key: string) => key });
|
||||
accountService = mock<AccountService>();
|
||||
nudgesService = mock<NudgesService>();
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
@@ -37,7 +40,8 @@ describe("NewItemNudgeComponent", () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NewItemNudgeComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.configType = null; // Set to null for initial state
|
||||
componentRef = fixture.componentRef;
|
||||
componentRef.setInput("configType", null); // Set a default type for testing
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
@@ -46,13 +50,11 @@ describe("NewItemNudgeComponent", () => {
|
||||
});
|
||||
|
||||
it("should set nudge title and body for CipherType.Login type", async () => {
|
||||
component.configType = CipherType.Login;
|
||||
accountService.activeAccount$ = of({ id: "test-user-id" as UserId } as Account);
|
||||
jest.spyOn(component, "checkHasSpotlightDismissed").mockResolvedValue(true);
|
||||
|
||||
await component.ngOnInit();
|
||||
|
||||
expect(component.showNewItemSpotlight).toBe(true);
|
||||
componentRef.setInput("configType", CipherType.Login);
|
||||
fixture.detectChanges();
|
||||
component.showNewItemSpotlight$.subscribe((value) => {
|
||||
expect(value).toEqual(true);
|
||||
});
|
||||
expect(component.nudgeTitle).toBe("newLoginNudgeTitle");
|
||||
expect(component.nudgeBody).toBe(
|
||||
"newLoginNudgeBodyOne <strong>newLoginNudgeBodyBold</strong> newLoginNudgeBodyTwo",
|
||||
@@ -61,39 +63,38 @@ describe("NewItemNudgeComponent", () => {
|
||||
});
|
||||
|
||||
it("should set nudge title and body for CipherType.Card type", async () => {
|
||||
component.configType = CipherType.Card;
|
||||
accountService.activeAccount$ = of({ id: "test-user-id" as UserId } as Account);
|
||||
jest.spyOn(component, "checkHasSpotlightDismissed").mockResolvedValue(true);
|
||||
|
||||
await component.ngOnInit();
|
||||
|
||||
expect(component.showNewItemSpotlight).toBe(true);
|
||||
componentRef.setInput("configType", CipherType.Card);
|
||||
fixture.detectChanges();
|
||||
component.showNewItemSpotlight$.subscribe((value) => {
|
||||
expect(value).toEqual(true);
|
||||
});
|
||||
expect(component.nudgeTitle).toBe("newCardNudgeTitle");
|
||||
expect(component.nudgeBody).toBe("newCardNudgeBody");
|
||||
expect(component.dismissalNudgeType).toBe(NudgeType.NewCardItemStatus);
|
||||
});
|
||||
|
||||
it("should not show anything if spotlight has been dismissed", async () => {
|
||||
component.configType = CipherType.Identity;
|
||||
accountService.activeAccount$ = of({ id: "test-user-id" as UserId } as Account);
|
||||
jest.spyOn(component, "checkHasSpotlightDismissed").mockResolvedValue(false);
|
||||
|
||||
await component.ngOnInit();
|
||||
|
||||
expect(component.showNewItemSpotlight).toBe(false);
|
||||
componentRef.setInput("configType", CipherType.Identity);
|
||||
fixture.detectChanges();
|
||||
component.showNewItemSpotlight$.subscribe((value) => {
|
||||
expect(value).toEqual(false);
|
||||
});
|
||||
expect(component.dismissalNudgeType).toBe(NudgeType.NewIdentityItemStatus);
|
||||
});
|
||||
|
||||
it("should set showNewItemSpotlight to false when user dismisses spotlight", async () => {
|
||||
component.showNewItemSpotlight = true;
|
||||
component.showNewItemSpotlight$ = of(true);
|
||||
component.dismissalNudgeType = NudgeType.NewLoginItemStatus;
|
||||
component.activeUserId = "test-user-id" as UserId;
|
||||
const activeUserId = "test-user-id" as UserId;
|
||||
component.activeUserId$ = of(activeUserId);
|
||||
|
||||
const dismissSpy = jest.spyOn(nudgesService, "dismissNudge").mockResolvedValue();
|
||||
|
||||
await component.dismissNewItemSpotlight();
|
||||
|
||||
expect(component.showNewItemSpotlight).toBe(false);
|
||||
expect(dismissSpy).toHaveBeenCalledWith(NudgeType.NewLoginItemStatus, component.activeUserId);
|
||||
component.showNewItemSpotlight$.subscribe((value) => {
|
||||
expect(value).toEqual(false);
|
||||
});
|
||||
expect(dismissSpy).toHaveBeenCalledWith(NudgeType.NewLoginItemStatus, activeUserId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { NgIf } from "@angular/common";
|
||||
import { Component, Input, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { AsyncPipe, NgIf } from "@angular/common";
|
||||
import { Component, input } from "@angular/core";
|
||||
import { toObservable } from "@angular/core/rxjs-interop";
|
||||
import { combineLatest, firstValueFrom, map, of, switchMap } from "rxjs";
|
||||
|
||||
import { NudgesService, NudgeType } from "@bitwarden/angular/vault";
|
||||
import { SpotlightComponent } from "@bitwarden/angular/vault/components/spotlight/spotlight.component";
|
||||
@@ -13,12 +14,17 @@ import { CipherType } from "@bitwarden/sdk-internal";
|
||||
@Component({
|
||||
selector: "vault-new-item-nudge",
|
||||
templateUrl: "./new-item-nudge.component.html",
|
||||
imports: [NgIf, SpotlightComponent],
|
||||
imports: [NgIf, SpotlightComponent, AsyncPipe],
|
||||
})
|
||||
export class NewItemNudgeComponent implements OnInit {
|
||||
@Input({ required: true }) configType: CipherType | null = null;
|
||||
activeUserId: UserId | null = null;
|
||||
showNewItemSpotlight: boolean = false;
|
||||
export class NewItemNudgeComponent {
|
||||
configType = input.required<CipherType | null>();
|
||||
activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
|
||||
showNewItemSpotlight$ = combineLatest([
|
||||
this.activeUserId$,
|
||||
toObservable(this.configType).pipe(map((cipherType) => this.mapToNudgeType(cipherType))),
|
||||
]).pipe(
|
||||
switchMap(([userId, nudgeType]) => this.nudgesService.showNudgeSpotlight$(nudgeType, userId)),
|
||||
);
|
||||
nudgeTitle: string = "";
|
||||
nudgeBody: string = "";
|
||||
dismissalNudgeType: NudgeType | null = null;
|
||||
@@ -29,10 +35,8 @@ export class NewItemNudgeComponent implements OnInit {
|
||||
private nudgesService: NudgesService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
switch (this.configType) {
|
||||
mapToNudgeType(cipherType: CipherType | null): NudgeType {
|
||||
switch (cipherType) {
|
||||
case CipherType.Login: {
|
||||
const nudgeBodyOne = this.i18nService.t("newLoginNudgeBodyOne");
|
||||
const nudgeBodyBold = this.i18nService.t("newLoginNudgeBodyBold");
|
||||
@@ -40,25 +44,25 @@ export class NewItemNudgeComponent implements OnInit {
|
||||
this.dismissalNudgeType = NudgeType.NewLoginItemStatus;
|
||||
this.nudgeTitle = this.i18nService.t("newLoginNudgeTitle");
|
||||
this.nudgeBody = `${nudgeBodyOne} <strong>${nudgeBodyBold}</strong> ${nudgeBodyTwo}`;
|
||||
break;
|
||||
return NudgeType.NewLoginItemStatus;
|
||||
}
|
||||
case CipherType.Card:
|
||||
this.dismissalNudgeType = NudgeType.NewCardItemStatus;
|
||||
this.nudgeTitle = this.i18nService.t("newCardNudgeTitle");
|
||||
this.nudgeBody = this.i18nService.t("newCardNudgeBody");
|
||||
break;
|
||||
return NudgeType.NewCardItemStatus;
|
||||
|
||||
case CipherType.Identity:
|
||||
this.dismissalNudgeType = NudgeType.NewIdentityItemStatus;
|
||||
this.nudgeTitle = this.i18nService.t("newIdentityNudgeTitle");
|
||||
this.nudgeBody = this.i18nService.t("newIdentityNudgeBody");
|
||||
break;
|
||||
return NudgeType.NewIdentityItemStatus;
|
||||
|
||||
case CipherType.SecureNote:
|
||||
this.dismissalNudgeType = NudgeType.NewNoteItemStatus;
|
||||
this.nudgeTitle = this.i18nService.t("newNoteNudgeTitle");
|
||||
this.nudgeBody = this.i18nService.t("newNoteNudgeBody");
|
||||
break;
|
||||
return NudgeType.NewNoteItemStatus;
|
||||
|
||||
case CipherType.SshKey: {
|
||||
const sshPartOne = this.i18nService.t("newSshNudgeBodyOne");
|
||||
@@ -67,25 +71,18 @@ export class NewItemNudgeComponent implements OnInit {
|
||||
this.dismissalNudgeType = NudgeType.NewSshItemStatus;
|
||||
this.nudgeTitle = this.i18nService.t("newSshNudgeTitle");
|
||||
this.nudgeBody = `${sshPartOne} <a href="https://bitwarden.com/help/ssh-agent" class="tw-text-primary-600 tw-font-bold" target="_blank">${sshPartTwo}</a>`;
|
||||
break;
|
||||
return NudgeType.NewSshItemStatus;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unsupported cipher type");
|
||||
}
|
||||
this.showNewItemSpotlight = await this.checkHasSpotlightDismissed(
|
||||
this.dismissalNudgeType as NudgeType,
|
||||
this.activeUserId,
|
||||
);
|
||||
}
|
||||
|
||||
async dismissNewItemSpotlight() {
|
||||
if (this.dismissalNudgeType && this.activeUserId) {
|
||||
await this.nudgesService.dismissNudge(this.dismissalNudgeType, this.activeUserId as UserId);
|
||||
this.showNewItemSpotlight = false;
|
||||
const activeUserId = await firstValueFrom(this.activeUserId$);
|
||||
if (this.dismissalNudgeType && activeUserId) {
|
||||
await this.nudgesService.dismissNudge(this.dismissalNudgeType, activeUserId as UserId);
|
||||
this.showNewItemSpotlight$ = of(false);
|
||||
}
|
||||
}
|
||||
|
||||
async checkHasSpotlightDismissed(nudgeType: NudgeType, userId: UserId): Promise<boolean> {
|
||||
return await firstValueFrom(this.nudgesService.showNudgeSpotlight$(nudgeType, userId));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user