1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-09 21:20:27 +00:00

PM-23733 - Integrate feature flags component into desktop - WIP as self hosted check doesn't work as written.

This commit is contained in:
Jared Snider
2025-07-25 17:32:11 -04:00
parent fe9e473f21
commit a283195847
7 changed files with 65 additions and 10 deletions

View File

@@ -17,6 +17,7 @@ import {
import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password";
import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component";
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
import { preventProdAccessGuard } from "@bitwarden/angular/platform/guard/prevent-prod-access.guard";
import {
LoginComponent,
LoginSecondaryContentComponent,
@@ -141,6 +142,19 @@ const routes: Routes = [
path: "",
component: AnonLayoutWrapperComponent,
children: [
{
path: "feature-flags",
canMatch: [preventProdAccessGuard], //preventSelfHostedAccessGuard
data: {
pageTitle: {
key: "featureFlags",
},
maxWidth: "3xl",
hideIcon: true,
} satisfies RouteDataProperties & AnonLayoutWrapperData,
loadComponent: () =>
import("@bitwarden/angular/platform/feature-flags").then((m) => m.FeatureFlagsComponent),
},
{
path: "signup",
canActivate: [unauthGuardFn()],

View File

@@ -308,6 +308,9 @@ export class AppComponent implements OnInit, OnDestroy {
case "openPasswordHistory":
await this.openGeneratorHistory();
break;
case "viewFeatureFlags":
await this.viewFeatureFlags();
break;
case "showToast":
this.toastService._showToast(message);
break;
@@ -520,6 +523,10 @@ export class AppComponent implements OnInit, OnDestroy {
return;
}
async viewFeatureFlags() {
await this.router.navigate(["/feature-flags"]);
}
private async updateAppMenu() {
let updateRequest: MenuUpdateRequest;
const stateAccounts = await firstValueFrom(this.accountService.accounts$);

View File

@@ -1548,6 +1548,21 @@
"toggleDevTools": {
"message": "Toggle developer tools"
},
"featureFlags": {
"message": "Feature flags"
},
"flagName": {
"message": "Flag name"
},
"flagValue": {
"message": "Flag value"
},
"copyData": {
"message": "Copy data"
},
"refresh": {
"message": "Refresh"
},
"minimize": {
"message": "Minimize",
"description": "Minimize window"

View File

@@ -47,6 +47,7 @@ export class MenuMain {
app.getVersion(),
await firstValueFrom(this.desktopSettingsService.hardwareAcceleration$),
this.versionMain,
await this.isProdOrSelfHost(),
updateRequest,
).menu,
);
@@ -57,6 +58,11 @@ export class MenuMain {
return env.getWebVaultUrl() ?? cloudWebVaultUrl;
}
private async isProdOrSelfHost(): Promise<boolean> {
const env = await firstValueFrom(this.environmentService.environment$);
return env.isProduction() || env.isSelfHosted();
}
private initContextMenu() {
if (this.windowMain.win == null) {
return;

View File

@@ -36,17 +36,29 @@ export class ViewMenu implements IMenubarMenu {
items.push(this.toggleDevTools);
}
// Desktop is considered self hosted argh.
// if (this._isProdOrSelfHost) {
items.push(this.featureFlags);
// }
return items;
}
private readonly _i18nService: I18nService;
private readonly _messagingService: MessagingService;
private readonly _isLocked: boolean;
private readonly _isProdOrSelfHost: boolean;
constructor(i18nService: I18nService, messagingService: MessagingService, isLocked: boolean) {
constructor(
i18nService: I18nService,
messagingService: MessagingService,
isLocked: boolean,
isProdOrSelfHost: boolean,
) {
this._i18nService = i18nService;
this._messagingService = messagingService;
this._isLocked = isLocked;
this._isProdOrSelfHost = isProdOrSelfHost;
}
private get searchVault(): MenuItemConstructorOptions {
@@ -134,13 +146,13 @@ export class ViewMenu implements IMenubarMenu {
};
}
// private get viewFeatureFlags(): MenuItemConstructorOptions {
// return {
// id: "viewFeatureFlags",
// label: this.localize("viewFeatureFlags"),
// role: "viewFeatureFlags",
// };
// }
private get featureFlags(): MenuItemConstructorOptions {
return {
id: "featureFlags",
label: this.localize("featureFlags"),
click: () => this.sendMessage("viewFeatureFlags"),
};
}
private localize(s: string) {
return this._i18nService.t(s);

View File

@@ -58,6 +58,7 @@ export class Menubar {
appVersion: string,
hardwareAccelerationEnabled: boolean,
versionMain: VersionMain,
isProdOrSelfHost: boolean,
updateRequest?: MenuUpdateRequest,
) {
let isLocked = true;
@@ -85,7 +86,7 @@ export class Menubar {
isLockable,
),
new EditMenu(i18nService, messagingService, isLocked),
new ViewMenu(i18nService, messagingService, isLocked),
new ViewMenu(i18nService, messagingService, isLocked, isProdOrSelfHost),
new AccountMenu(
i18nService,
messagingService,

View File

@@ -186,7 +186,7 @@ const routes: Routes = [
key: "featureFlags",
},
maxWidth: "3xl",
hideIcon: true, // TODO: log bug with UIF or offer a PR to fix where this isn't reset to false upon navigation
hideIcon: true,
} satisfies RouteDataProperties & AnonLayoutWrapperData,
loadComponent: () =>
import("@bitwarden/angular/platform/feature-flags").then((m) => m.FeatureFlagsComponent),