1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 13:23:34 +00:00

remove PM8851_BrowserOnboardingNudge feature flag (#15956)

This commit is contained in:
Nick Krantz
2025-08-15 08:55:37 -05:00
committed by GitHub
parent 6ed1e8d83c
commit 7f841a4f06
11 changed files with 22 additions and 110 deletions

View File

@@ -1,11 +1,9 @@
import { Component } from "@angular/core";
import { combineLatest, map, Observable, startWith, switchMap } from "rxjs";
import { map, Observable, startWith, switchMap } from "rxjs";
import { NudgesService } from "@bitwarden/angular/vault";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { Icons } from "@bitwarden/components";
import { NavButton } from "../platform/popup/layout/popup-tab-navigation.component";
@@ -19,12 +17,9 @@ export class TabsV2Component {
private hasActiveBadges$ = this.accountService.activeAccount$
.pipe(getUserId)
.pipe(switchMap((userId) => this.nudgesService.hasActiveBadges$(userId)));
protected navButtons$: Observable<NavButton[]> = combineLatest([
this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge),
this.hasActiveBadges$,
]).pipe(
startWith([false, false]),
map(([onboardingFeatureEnabled, hasBadges]) => {
protected navButtons$: Observable<NavButton[]> = this.hasActiveBadges$.pipe(
startWith(false),
map((hasBadges) => {
return [
{
label: "vault",
@@ -49,7 +44,7 @@ export class TabsV2Component {
page: "/tabs/settings",
icon: Icons.SettingsInactive,
iconActive: Icons.SettingsActive,
showBerry: onboardingFeatureEnabled && hasBadges,
showBerry: hasBadges,
},
];
}),
@@ -57,6 +52,5 @@ export class TabsV2Component {
constructor(
private nudgesService: NudgesService,
private accountService: AccountService,
private readonly configService: ConfigService,
) {}
}

View File

@@ -23,12 +23,6 @@
<i slot="end" class="bwi bwi-external-link" aria-hidden="true"></i>
</button>
</bit-item>
<bit-item *ngIf="!(isNudgeFeatureEnabled$ | async)">
<a bit-item-content routerLink="/more-from-bitwarden">
{{ "moreFromBitwarden" | i18n }}
<i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i>
</a>
</bit-item>
<bit-item>
<button type="button" bit-item-content (click)="rate()">
{{ "rateExtension" | i18n }}

View File

@@ -5,8 +5,6 @@ import { firstValueFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { DeviceType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService, ItemModule } from "@bitwarden/components";
@@ -48,17 +46,12 @@ export class AboutPageV2Component {
private dialogService: DialogService,
private environmentService: EnvironmentService,
private platformUtilsService: PlatformUtilsService,
private configService: ConfigService,
) {}
about() {
this.dialogService.open(AboutDialogComponent);
}
protected isNudgeFeatureEnabled$ = this.configService.getFeatureFlag$(
FeatureFlag.PM8851_BrowserOnboardingNudge,
);
async launchHelp() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "continueToHelpCenter" },

View File

@@ -76,7 +76,7 @@
<i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i>
</a>
</bit-item>
<bit-item *ngIf="isNudgeFeatureEnabled$ | async">
<bit-item>
<a bit-item-content routerLink="/download-bitwarden">
<i slot="start" class="bwi bwi-mobile" aria-hidden="true"></i>
<div class="tw-flex tw-items-center tw-justify-center">
@@ -92,7 +92,7 @@
<i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i>
</a>
</bit-item>
<bit-item *ngIf="isNudgeFeatureEnabled$ | async">
<bit-item>
<a bit-item-content routerLink="/more-from-bitwarden">
<i slot="start" class="bwi bwi-filter" aria-hidden="true"></i>
{{ "moreFromBitwarden" | i18n }}

View File

@@ -14,8 +14,6 @@ import {
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { NudgesService, NudgeType } from "@bitwarden/angular/vault";
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { UserId } from "@bitwarden/common/types/guid";
import { BadgeComponent, ItemModule } from "@bitwarden/components";
@@ -75,15 +73,10 @@ export class SettingsV2Component implements OnInit {
),
);
protected isNudgeFeatureEnabled$ = this.configService.getFeatureFlag$(
FeatureFlag.PM8851_BrowserOnboardingNudge,
);
constructor(
private readonly nudgesService: NudgesService,
private readonly accountService: AccountService,
private readonly autofillBrowserSettingsService: AutofillBrowserSettingsService,
private readonly configService: ConfigService,
) {}
async ngOnInit() {

View File

@@ -1,29 +1,23 @@
import { TestBed } from "@angular/core/testing";
import { Router } from "@angular/router";
import { mock, MockProxy } from "jest-mock-extended";
import { of } from "rxjs";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { IntroCarouselService } from "../services/intro-carousel.service";
import { IntroCarouselGuard } from "./intro-carousel.guard";
describe("IntroCarouselGuard", () => {
let mockConfigService: MockProxy<ConfigService>;
const mockIntroCarouselService = {
introCarouselState$: of(true),
};
const createUrlTree = jest.fn();
beforeEach(() => {
mockConfigService = mock<ConfigService>();
createUrlTree.mockClear();
TestBed.configureTestingModule({
providers: [
{ provide: Router, useValue: { createUrlTree } },
{ provide: ConfigService, useValue: mockConfigService },
{
provide: IntroCarouselService,
useValue: mockIntroCarouselService,
@@ -32,22 +26,16 @@ describe("IntroCarouselGuard", () => {
});
});
it("should return true if the feature flag is off", async () => {
mockConfigService.getFeatureFlag.mockResolvedValue(false);
const result = await TestBed.runInInjectionContext(async () => await IntroCarouselGuard());
expect(result).toBe(true);
});
it("should navigate to intro-carousel route if feature flag is true and dismissed is true", async () => {
mockConfigService.getFeatureFlag.mockResolvedValue(true);
it("should return true when dismissed is true", async () => {
const result = await TestBed.runInInjectionContext(async () => await IntroCarouselGuard());
expect(result).toBe(true);
});
it("should navigate to intro-carousel route if feature flag is true and dismissed is false", async () => {
it("should navigate to intro-carousel route when dismissed is false", async () => {
TestBed.overrideProvider(IntroCarouselService, {
useValue: { introCarouselState$: of(false) },
});
mockConfigService.getFeatureFlag.mockResolvedValue(true);
await TestBed.runInInjectionContext(async () => await IntroCarouselGuard());
expect(createUrlTree).toHaveBeenCalledWith(["/intro-carousel"]);
});

View File

@@ -2,23 +2,15 @@ import { inject } from "@angular/core";
import { Router } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { IntroCarouselService } from "../services/intro-carousel.service";
export const IntroCarouselGuard = async () => {
const router = inject(Router);
const configService = inject(ConfigService);
const introCarouselService = inject(IntroCarouselService);
const hasOnboardingNudgesFlag = await configService.getFeatureFlag(
FeatureFlag.PM8851_BrowserOnboardingNudge,
);
const hasIntroCarouselDismissed = await firstValueFrom(introCarouselService.introCarouselState$);
if (!hasOnboardingNudgesFlag || hasIntroCarouselDismissed) {
if (hasIntroCarouselDismissed) {
return true;
}

View File

@@ -1,8 +1,6 @@
import { Injectable } from "@angular/core";
import { firstValueFrom, map, Observable } from "rxjs";
import { map, Observable } from "rxjs";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import {
GlobalState,
KeyDefinition,
@@ -28,17 +26,9 @@ export class IntroCarouselService {
map((x) => x ?? false),
);
constructor(
private stateProvider: StateProvider,
private configService: ConfigService,
) {}
constructor(private stateProvider: StateProvider) {}
async setIntroCarouselDismissed(): Promise<void> {
const hasVaultNudgeFlag = await firstValueFrom(
this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge),
);
if (hasVaultNudgeFlag) {
await this.introCarouselState.update(() => true);
}
await this.introCarouselState.update(() => true);
}
}

View File

@@ -8,7 +8,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { StateProvider } from "@bitwarden/common/platform/state";
import { UserId } from "@bitwarden/common/types/guid";
@@ -31,10 +30,6 @@ describe("Vault Nudges Service", () => {
let fakeStateProvider: FakeStateProvider;
let testBed: TestBed;
const mockConfigService = {
getFeatureFlag$: jest.fn().mockReturnValue(of(true)),
getFeatureFlag: jest.fn().mockReturnValue(true),
};
const nudgeServices = [
EmptyVaultNudgeService,
@@ -58,7 +53,6 @@ describe("Vault Nudges Service", () => {
provide: StateProvider,
useValue: fakeStateProvider,
},
{ provide: ConfigService, useValue: mockConfigService },
{
provide: HasItemsNudgeService,
useValue: mock<HasItemsNudgeService>(),

View File

@@ -1,8 +1,6 @@
import { inject, Injectable } from "@angular/core";
import { combineLatest, map, Observable, of, shareReplay, switchMap } from "rxjs";
import { combineLatest, map, Observable, shareReplay } from "rxjs";
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";
@@ -83,7 +81,6 @@ export class NudgesService {
* @private
*/
private defaultNudgeService = inject(DefaultSingleNudgeService);
private configService = inject(ConfigService);
private getNudgeService(nudge: NudgeType): SingleNudgeService {
return this.customNudgeServices[nudge] ?? this.defaultNudgeService;
@@ -95,16 +92,9 @@ export class NudgesService {
* @param userId
*/
showNudgeSpotlight$(nudge: NudgeType, userId: UserId): Observable<boolean> {
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
switchMap((hasVaultNudgeFlag) => {
if (!hasVaultNudgeFlag) {
return of(false);
}
return this.getNudgeService(nudge)
.nudgeStatus$(nudge, userId)
.pipe(map((nudgeStatus) => !nudgeStatus.hasSpotlightDismissed));
}),
);
return this.getNudgeService(nudge)
.nudgeStatus$(nudge, userId)
.pipe(map((nudgeStatus) => !nudgeStatus.hasSpotlightDismissed));
}
/**
@@ -113,16 +103,9 @@ export class NudgesService {
* @param userId
*/
showNudgeBadge$(nudge: NudgeType, userId: UserId): Observable<boolean> {
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
switchMap((hasVaultNudgeFlag) => {
if (!hasVaultNudgeFlag) {
return of(false);
}
return this.getNudgeService(nudge)
.nudgeStatus$(nudge, userId)
.pipe(map((nudgeStatus) => !nudgeStatus.hasBadgeDismissed));
}),
);
return this.getNudgeService(nudge)
.nudgeStatus$(nudge, userId)
.pipe(map((nudgeStatus) => !nudgeStatus.hasBadgeDismissed));
}
/**
@@ -131,14 +114,7 @@ export class NudgesService {
* @param userId
*/
showNudgeStatus$(nudge: NudgeType, userId: UserId) {
return this.configService.getFeatureFlag$(FeatureFlag.PM8851_BrowserOnboardingNudge).pipe(
switchMap((hasVaultNudgeFlag) => {
if (!hasVaultNudgeFlag) {
return of({ hasBadgeDismissed: true, hasSpotlightDismissed: true } as NudgeStatus);
}
return this.getNudgeService(nudge).nudgeStatus$(nudge, userId);
}),
);
return this.getNudgeService(nudge).nudgeStatus$(nudge, userId);
}
/**

View File

@@ -47,7 +47,6 @@ export enum FeatureFlag {
EventBasedOrganizationIntegrations = "event-based-organization-integrations",
/* Vault */
PM8851_BrowserOnboardingNudge = "pm-8851-browser-onboarding-nudge",
PM19941MigrateCipherDomainToSdk = "pm-19941-migrate-cipher-domain-to-sdk",
PM22134SdkCipherListView = "pm-22134-sdk-cipher-list-view",
PM22136_SdkCipherEncryption = "pm-22136-sdk-cipher-encryption",
@@ -92,7 +91,6 @@ export const DefaultFeatureFlagValue = {
[FeatureFlag.EventBasedOrganizationIntegrations]: FALSE,
/* Vault */
[FeatureFlag.PM8851_BrowserOnboardingNudge]: FALSE,
[FeatureFlag.CipherKeyEncryption]: FALSE,
[FeatureFlag.PM19941MigrateCipherDomainToSdk]: FALSE,
[FeatureFlag.RemoveCardItemTypePolicy]: FALSE,