mirror of
https://github.com/bitwarden/browser
synced 2026-02-07 12:13:45 +00:00
Merge remote-tracking branch 'origin' into auth/pm-18720/change-password-component-non-dialog-v3
This commit is contained in:
@@ -11,7 +11,6 @@ import { ButtonModule } from "@bitwarden/components";
|
||||
*/
|
||||
@Component({
|
||||
selector: "app-authentication-timeout",
|
||||
standalone: true,
|
||||
imports: [CommonModule, JslibModule, ButtonModule, RouterModule],
|
||||
template: `
|
||||
<p class="tw-text-center">
|
||||
|
||||
@@ -85,11 +85,11 @@ import { IconComponent } from "./vault/components/icon.component";
|
||||
TextDragDirective,
|
||||
CopyClickDirective,
|
||||
A11yTitleDirective,
|
||||
AutofocusDirective,
|
||||
],
|
||||
declarations: [
|
||||
A11yInvalidDirective,
|
||||
ApiActionDirective,
|
||||
AutofocusDirective,
|
||||
BoxRowDirective,
|
||||
DeprecatedCalloutComponent,
|
||||
CopyTextDirective,
|
||||
|
||||
36
libs/angular/src/platform/i18n/document-lang.setter.spec.ts
Normal file
36
libs/angular/src/platform/i18n/document-lang.setter.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { DocumentLangSetter } from "./document-lang.setter";
|
||||
|
||||
describe("DocumentLangSetter", () => {
|
||||
const document = mock<Document>();
|
||||
const i18nService = mock<I18nService>();
|
||||
|
||||
const sut = new DocumentLangSetter(document, i18nService);
|
||||
|
||||
describe("start", () => {
|
||||
it("reacts to locale changes while start called with a non-closed subscription", async () => {
|
||||
const localeSubject = new Subject<string>();
|
||||
i18nService.locale$ = localeSubject;
|
||||
|
||||
localeSubject.next("en");
|
||||
|
||||
expect(document.documentElement.lang).toBeFalsy();
|
||||
|
||||
const sub = sut.start();
|
||||
|
||||
localeSubject.next("es");
|
||||
|
||||
expect(document.documentElement.lang).toBe("es");
|
||||
|
||||
sub.unsubscribe();
|
||||
|
||||
localeSubject.next("ar");
|
||||
|
||||
expect(document.documentElement.lang).toBe("es");
|
||||
});
|
||||
});
|
||||
});
|
||||
26
libs/angular/src/platform/i18n/document-lang.setter.ts
Normal file
26
libs/angular/src/platform/i18n/document-lang.setter.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Subscription } from "rxjs";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
/**
|
||||
* A service for managing the setting of the `lang="<locale>" attribute on the
|
||||
* main document for the application.
|
||||
*/
|
||||
export class DocumentLangSetter {
|
||||
constructor(
|
||||
private readonly document: Document,
|
||||
private readonly i18nService: I18nService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Starts listening to an upstream source for the best locale for the user
|
||||
* and applies it to the application document.
|
||||
* @returns A subscription that can be unsubscribed if you wish to stop
|
||||
* applying lang attribute updates to the application document.
|
||||
*/
|
||||
start(): Subscription {
|
||||
return this.i18nService.locale$.subscribe((locale) => {
|
||||
this.document.documentElement.lang = locale;
|
||||
});
|
||||
}
|
||||
}
|
||||
1
libs/angular/src/platform/i18n/index.ts
Normal file
1
libs/angular/src/platform/i18n/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { DocumentLangSetter } from "./document-lang.setter";
|
||||
@@ -21,6 +21,7 @@ import { SafeInjectionToken } from "@bitwarden/ui-common";
|
||||
export { SafeInjectionToken } from "@bitwarden/ui-common";
|
||||
|
||||
export const WINDOW = new SafeInjectionToken<Window>("WINDOW");
|
||||
export const DOCUMENT = new SafeInjectionToken<Document>("DOCUMENT");
|
||||
export const OBSERVABLE_MEMORY_STORAGE = new SafeInjectionToken<
|
||||
AbstractStorageService & ObservableStorageService
|
||||
>("OBSERVABLE_MEMORY_STORAGE");
|
||||
|
||||
@@ -337,6 +337,7 @@ import {
|
||||
import { DeviceTrustToastService as DeviceTrustToastServiceAbstraction } from "../auth/services/device-trust-toast.service.abstraction";
|
||||
import { DeviceTrustToastService } from "../auth/services/device-trust-toast.service.implementation";
|
||||
import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "../platform/abstractions/form-validation-errors.service";
|
||||
import { DocumentLangSetter } from "../platform/i18n";
|
||||
import { FormValidationErrorsService } from "../platform/services/form-validation-errors.service";
|
||||
import { LoggingErrorHandler } from "../platform/services/logging-error-handler";
|
||||
import { AngularThemingService } from "../platform/services/theming/angular-theming.service";
|
||||
@@ -349,6 +350,7 @@ import { NoopViewCacheService } from "../platform/view-cache/internal";
|
||||
import {
|
||||
CLIENT_TYPE,
|
||||
DEFAULT_VAULT_TIMEOUT,
|
||||
DOCUMENT,
|
||||
ENV_ADDITIONAL_REGIONS,
|
||||
HTTP_OPERATIONS,
|
||||
INTRAPROCESS_MESSAGING_SUBJECT,
|
||||
@@ -378,6 +380,7 @@ const safeProviders: SafeProvider[] = [
|
||||
safeProvider(ModalService),
|
||||
safeProvider(PasswordRepromptService),
|
||||
safeProvider({ provide: WINDOW, useValue: window }),
|
||||
safeProvider({ provide: DOCUMENT, useValue: document }),
|
||||
safeProvider({
|
||||
provide: LOCALE_ID as SafeInjectionToken<string>,
|
||||
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
|
||||
@@ -1460,12 +1463,7 @@ const safeProviders: SafeProvider[] = [
|
||||
safeProvider({
|
||||
provide: CipherAuthorizationService,
|
||||
useClass: DefaultCipherAuthorizationService,
|
||||
deps: [
|
||||
CollectionService,
|
||||
OrganizationServiceAbstraction,
|
||||
AccountServiceAbstraction,
|
||||
ConfigService,
|
||||
],
|
||||
deps: [CollectionService, OrganizationServiceAbstraction, AccountServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: AuthRequestApiService,
|
||||
@@ -1512,7 +1510,6 @@ const safeProviders: SafeProvider[] = [
|
||||
StateProvider,
|
||||
ApiServiceAbstraction,
|
||||
OrganizationServiceAbstraction,
|
||||
ConfigService,
|
||||
AuthServiceAbstraction,
|
||||
NotificationsService,
|
||||
MessageListener,
|
||||
@@ -1544,6 +1541,11 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: MasterPasswordApiService,
|
||||
deps: [ApiServiceAbstraction, LogService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: DocumentLangSetter,
|
||||
useClass: DocumentLangSetter,
|
||||
deps: [DOCUMENT, I18nServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: CipherEncryptionService,
|
||||
useClass: DefaultCipherEncryptionService,
|
||||
|
||||
@@ -25,7 +25,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CollectionId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
CipherService,
|
||||
EncryptionContext,
|
||||
@@ -348,7 +348,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(
|
||||
this.cipher,
|
||||
[this.collectionId as CollectionId],
|
||||
this.isAdminConsoleAction,
|
||||
);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { CipherId, CollectionId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
@@ -521,9 +521,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
);
|
||||
this.showPremiumRequiredTotp =
|
||||
this.cipher.login.totp && !this.canAccessPremium && !this.cipher.organizationUseTotp;
|
||||
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(this.cipher, [
|
||||
this.collectionId as CollectionId,
|
||||
]);
|
||||
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(this.cipher);
|
||||
this.canRestoreCipher$ = this.cipherAuthorizationService.canRestoreCipher$(this.cipher);
|
||||
|
||||
if (this.cipher.folderId) {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { Injectable, inject } from "@angular/core";
|
||||
import { Observable, combineLatest, from, of } from "rxjs";
|
||||
import { catchError, map } from "rxjs/operators";
|
||||
|
||||
import { VaultProfileService } from "@bitwarden/angular/vault/services/vault-profile.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||
|
||||
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class DownloadBitwardenNudgeService extends DefaultSingleNudgeService {
|
||||
private vaultProfileService = inject(VaultProfileService);
|
||||
private logService = inject(LogService);
|
||||
|
||||
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
||||
catchError(() => {
|
||||
this.logService.error("Failed to load profile date:");
|
||||
// Default to today to ensure the nudge is shown
|
||||
return of(new Date());
|
||||
}),
|
||||
);
|
||||
|
||||
return combineLatest([
|
||||
profileDate$,
|
||||
this.getNudgeStatus$(nudgeType, userId),
|
||||
of(Date.now() - THIRTY_DAYS_MS),
|
||||
]).pipe(
|
||||
map(([profileCreationDate, status, profileCutoff]) => {
|
||||
const profileOlderThanCutoff = profileCreationDate.getTime() < profileCutoff;
|
||||
return {
|
||||
hasBadgeDismissed: status.hasBadgeDismissed || profileOlderThanCutoff,
|
||||
hasSpotlightDismissed: status.hasSpotlightDismissed || profileOlderThanCutoff,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -30,10 +30,7 @@ export class EmptyVaultNudgeService extends DefaultSingleNudgeService {
|
||||
this.collectionService.decryptedCollections$,
|
||||
]).pipe(
|
||||
switchMap(([nudgeStatus, ciphers, orgs, collections]) => {
|
||||
const filteredCiphers = ciphers?.filter((cipher) => {
|
||||
return cipher.deletedDate == null;
|
||||
});
|
||||
const vaultHasContents = !(filteredCiphers == null || filteredCiphers.length === 0);
|
||||
const vaultHasContents = !(ciphers == null || ciphers.length === 0);
|
||||
if (orgs == null || orgs.length === 0) {
|
||||
return nudgeStatus.hasBadgeDismissed || nudgeStatus.hasSpotlightDismissed
|
||||
? of(nudgeStatus)
|
||||
@@ -47,18 +44,22 @@ export class EmptyVaultNudgeService extends DefaultSingleNudgeService {
|
||||
const hasManageCollections = collections.some(
|
||||
(c) => c.manage && orgIds.has(c.organizationId),
|
||||
);
|
||||
// Do not show nudge when
|
||||
// user has previously dismissed nudge
|
||||
// OR
|
||||
// user belongs to an organization and cannot create collections || manage collections
|
||||
if (
|
||||
nudgeStatus.hasBadgeDismissed ||
|
||||
nudgeStatus.hasSpotlightDismissed ||
|
||||
hasManageCollections ||
|
||||
canCreateCollections
|
||||
) {
|
||||
|
||||
// When the user has dismissed the nudge or spotlight, return the nudge status directly
|
||||
if (nudgeStatus.hasBadgeDismissed || nudgeStatus.hasSpotlightDismissed) {
|
||||
return of(nudgeStatus);
|
||||
}
|
||||
|
||||
// When the user belongs to an organization and cannot create collections or manage collections,
|
||||
// hide the nudge and spotlight
|
||||
if (!hasManageCollections && !canCreateCollections) {
|
||||
return of({
|
||||
hasSpotlightDismissed: true,
|
||||
hasBadgeDismissed: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise, return the nudge status based on the vault contents
|
||||
return of({
|
||||
hasSpotlightDismissed: vaultHasContents,
|
||||
hasBadgeDismissed: vaultHasContents,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * from "./autofill-nudge.service";
|
||||
export * from "./account-security-nudge.service";
|
||||
export * from "./has-items-nudge.service";
|
||||
export * from "./download-bitwarden-nudge.service";
|
||||
export * from "./empty-vault-nudge.service";
|
||||
export * from "./vault-settings-import-nudge.service";
|
||||
export * from "./new-item-nudge.service";
|
||||
export * from "./new-account-nudge.service";
|
||||
|
||||
@@ -12,16 +12,16 @@ import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* Custom Nudge Service to use for the Autofill Nudge in the Vault
|
||||
* Custom Nudge Service to check if account is older than 30 days
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
export class AutofillNudgeService extends DefaultSingleNudgeService {
|
||||
export class NewAccountNudgeService extends DefaultSingleNudgeService {
|
||||
vaultProfileService = inject(VaultProfileService);
|
||||
logService = inject(LogService);
|
||||
|
||||
nudgeStatus$(_: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||
const profileDate$ = from(this.vaultProfileService.getProfileCreationDate(userId)).pipe(
|
||||
catchError(() => {
|
||||
this.logService.error("Error getting profile creation date");
|
||||
@@ -32,7 +32,7 @@ export class AutofillNudgeService extends DefaultSingleNudgeService {
|
||||
|
||||
return combineLatest([
|
||||
profileDate$,
|
||||
this.getNudgeStatus$(NudgeType.AutofillNudge, userId),
|
||||
this.getNudgeStatus$(nudgeType, userId),
|
||||
of(Date.now() - THIRTY_DAYS_MS),
|
||||
]).pipe(
|
||||
map(([profileCreationDate, status, profileCutoff]) => {
|
||||
@@ -0,0 +1,74 @@
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
import { combineLatest, Observable, of, switchMap } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
|
||||
import { DefaultSingleNudgeService } from "../default-single-nudge.service";
|
||||
import { NudgeStatus, NudgeType } from "../nudges.service";
|
||||
|
||||
/**
|
||||
* Custom Nudge Service for the vault settings import badge.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
export class VaultSettingsImportNudgeService extends DefaultSingleNudgeService {
|
||||
cipherService = inject(CipherService);
|
||||
organizationService = inject(OrganizationService);
|
||||
collectionService = inject(CollectionService);
|
||||
|
||||
nudgeStatus$(nudgeType: NudgeType, userId: UserId): Observable<NudgeStatus> {
|
||||
return combineLatest([
|
||||
this.getNudgeStatus$(nudgeType, userId),
|
||||
this.cipherService.cipherViews$(userId),
|
||||
this.organizationService.organizations$(userId),
|
||||
this.collectionService.decryptedCollections$,
|
||||
]).pipe(
|
||||
switchMap(([nudgeStatus, ciphers, orgs, collections]) => {
|
||||
const vaultHasMoreThanOneItem = (ciphers?.length ?? 0) > 1;
|
||||
const { hasBadgeDismissed, hasSpotlightDismissed } = nudgeStatus;
|
||||
|
||||
// When the user has no organizations, return the nudge status directly
|
||||
if ((orgs?.length ?? 0) === 0) {
|
||||
return hasBadgeDismissed || hasSpotlightDismissed
|
||||
? of(nudgeStatus)
|
||||
: of({
|
||||
hasSpotlightDismissed: vaultHasMoreThanOneItem,
|
||||
hasBadgeDismissed: vaultHasMoreThanOneItem,
|
||||
});
|
||||
}
|
||||
|
||||
const orgIds = new Set(orgs.map((org) => org.id));
|
||||
const canCreateCollections = orgs.some((org) => org.canCreateNewCollections);
|
||||
const hasManageCollections = collections.some(
|
||||
(c) => c.manage && orgIds.has(c.organizationId),
|
||||
);
|
||||
|
||||
// When the user has dismissed the nudge or spotlight, return the nudge status directly
|
||||
if (hasBadgeDismissed || hasSpotlightDismissed) {
|
||||
return of(nudgeStatus);
|
||||
}
|
||||
|
||||
// When the user belongs to an organization and cannot create collections or manage collections,
|
||||
// hide the nudge and spotlight
|
||||
if (!hasManageCollections && !canCreateCollections) {
|
||||
return of({
|
||||
hasSpotlightDismissed: true,
|
||||
hasBadgeDismissed: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise, return the nudge status based on the vault contents
|
||||
return of({
|
||||
hasSpotlightDismissed: vaultHasMoreThanOneItem,
|
||||
hasBadgeDismissed: vaultHasMoreThanOneItem,
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,8 @@ import { FakeStateProvider, mockAccountServiceWith } from "../../../../../libs/c
|
||||
import {
|
||||
HasItemsNudgeService,
|
||||
EmptyVaultNudgeService,
|
||||
DownloadBitwardenNudgeService,
|
||||
NewAccountNudgeService,
|
||||
VaultSettingsImportNudgeService,
|
||||
} from "./custom-nudges-services";
|
||||
import { DefaultSingleNudgeService } from "./default-single-nudge.service";
|
||||
import { NudgesService, NudgeType } from "./nudges.service";
|
||||
@@ -33,7 +34,7 @@ describe("Vault Nudges Service", () => {
|
||||
getFeatureFlag: jest.fn().mockReturnValue(true),
|
||||
};
|
||||
|
||||
const nudgeServices = [EmptyVaultNudgeService, DownloadBitwardenNudgeService];
|
||||
const nudgeServices = [EmptyVaultNudgeService, NewAccountNudgeService];
|
||||
|
||||
beforeEach(async () => {
|
||||
fakeStateProvider = new FakeStateProvider(mockAccountServiceWith("user-id" as UserId));
|
||||
@@ -57,13 +58,17 @@ describe("Vault Nudges Service", () => {
|
||||
useValue: mock<HasItemsNudgeService>(),
|
||||
},
|
||||
{
|
||||
provide: DownloadBitwardenNudgeService,
|
||||
useValue: mock<DownloadBitwardenNudgeService>(),
|
||||
provide: NewAccountNudgeService,
|
||||
useValue: mock<NewAccountNudgeService>(),
|
||||
},
|
||||
{
|
||||
provide: EmptyVaultNudgeService,
|
||||
useValue: mock<EmptyVaultNudgeService>(),
|
||||
},
|
||||
{
|
||||
provide: VaultSettingsImportNudgeService,
|
||||
useValue: mock<VaultSettingsImportNudgeService>(),
|
||||
},
|
||||
{
|
||||
provide: ApiService,
|
||||
useValue: mock<ApiService>(),
|
||||
|
||||
@@ -5,14 +5,15 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { UserKeyDefinition, NUDGES_DISK } from "@bitwarden/common/platform/state";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values";
|
||||
|
||||
import {
|
||||
NewAccountNudgeService,
|
||||
HasItemsNudgeService,
|
||||
EmptyVaultNudgeService,
|
||||
AutofillNudgeService,
|
||||
DownloadBitwardenNudgeService,
|
||||
NewItemNudgeService,
|
||||
AccountSecurityNudgeService,
|
||||
VaultSettingsImportNudgeService,
|
||||
} from "./custom-nudges-services";
|
||||
import { DefaultSingleNudgeService, SingleNudgeService } from "./default-single-nudge.service";
|
||||
|
||||
@@ -24,24 +25,23 @@ export type NudgeStatus = {
|
||||
/**
|
||||
* Enum to list the various nudge types, to be used by components/badges to show/hide the nudge
|
||||
*/
|
||||
// FIXME: update to use a const object instead of a typescript enum
|
||||
// eslint-disable-next-line @bitwarden/platform/no-enums
|
||||
export enum NudgeType {
|
||||
/** Nudge to show when user has no items in their vault
|
||||
* Add future nudges here
|
||||
*/
|
||||
EmptyVaultNudge = "empty-vault-nudge",
|
||||
HasVaultItems = "has-vault-items",
|
||||
AutofillNudge = "autofill-nudge",
|
||||
AccountSecurity = "account-security",
|
||||
DownloadBitwarden = "download-bitwarden",
|
||||
NewLoginItemStatus = "new-login-item-status",
|
||||
NewCardItemStatus = "new-card-item-status",
|
||||
NewIdentityItemStatus = "new-identity-item-status",
|
||||
NewNoteItemStatus = "new-note-item-status",
|
||||
NewSshItemStatus = "new-ssh-item-status",
|
||||
GeneratorNudgeStatus = "generator-nudge-status",
|
||||
}
|
||||
export const NudgeType = {
|
||||
/** Nudge to show when user has no items in their vault */
|
||||
EmptyVaultNudge: "empty-vault-nudge",
|
||||
VaultSettingsImportNudge: "vault-settings-import-nudge",
|
||||
HasVaultItems: "has-vault-items",
|
||||
AutofillNudge: "autofill-nudge",
|
||||
AccountSecurity: "account-security",
|
||||
DownloadBitwarden: "download-bitwarden",
|
||||
NewLoginItemStatus: "new-login-item-status",
|
||||
NewCardItemStatus: "new-card-item-status",
|
||||
NewIdentityItemStatus: "new-identity-item-status",
|
||||
NewNoteItemStatus: "new-note-item-status",
|
||||
NewSshItemStatus: "new-ssh-item-status",
|
||||
GeneratorNudgeStatus: "generator-nudge-status",
|
||||
} as const;
|
||||
|
||||
export type NudgeType = UnionOfValues<typeof NudgeType>;
|
||||
|
||||
export const NUDGE_DISMISSED_DISK_KEY = new UserKeyDefinition<
|
||||
Partial<Record<NudgeType, NudgeStatus>>
|
||||
@@ -55,6 +55,7 @@ export const NUDGE_DISMISSED_DISK_KEY = new UserKeyDefinition<
|
||||
})
|
||||
export class NudgesService {
|
||||
private newItemNudgeService = inject(NewItemNudgeService);
|
||||
private newAcctNudgeService = inject(NewAccountNudgeService);
|
||||
|
||||
/**
|
||||
* Custom nudge services to use for specific nudge types
|
||||
@@ -64,9 +65,11 @@ export class NudgesService {
|
||||
private customNudgeServices: Partial<Record<NudgeType, SingleNudgeService>> = {
|
||||
[NudgeType.HasVaultItems]: inject(HasItemsNudgeService),
|
||||
[NudgeType.EmptyVaultNudge]: inject(EmptyVaultNudgeService),
|
||||
[NudgeType.VaultSettingsImportNudge]: inject(VaultSettingsImportNudgeService),
|
||||
[NudgeType.AccountSecurity]: inject(AccountSecurityNudgeService),
|
||||
[NudgeType.AutofillNudge]: inject(AutofillNudgeService),
|
||||
[NudgeType.DownloadBitwarden]: inject(DownloadBitwardenNudgeService),
|
||||
[NudgeType.AutofillNudge]: this.newAcctNudgeService,
|
||||
[NudgeType.DownloadBitwarden]: this.newAcctNudgeService,
|
||||
[NudgeType.GeneratorNudgeStatus]: this.newAcctNudgeService,
|
||||
[NudgeType.NewLoginItemStatus]: this.newItemNudgeService,
|
||||
[NudgeType.NewCardItemStatus]: this.newItemNudgeService,
|
||||
[NudgeType.NewIdentityItemStatus]: this.newItemNudgeService,
|
||||
|
||||
Reference in New Issue
Block a user