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