1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00

[AC-1479][BEEEP] Refactor ConfigService to improve observable usage (#5602)

* refactor ConfigService to use observables

* make environmentService.urls a ReplaySubject

---------

Co-authored-by: Hinton <hinton@users.noreply.github.com>
This commit is contained in:
Thomas Rittson
2023-09-09 00:05:37 +10:00
committed by GitHub
parent fe354f9063
commit 61e1bc1a1c
29 changed files with 356 additions and 158 deletions

View File

@@ -89,7 +89,7 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
async updateEnvironmentInfo() {
this.selectedEnvironment = this.environmentService.selectedRegion;
this.euServerFlagEnabled = await this.configService.getFeatureFlagBool(
this.euServerFlagEnabled = await this.configService.getFeatureFlag<boolean>(
FeatureFlag.DisplayEuEnvironmentFlag
);
}

View File

@@ -331,7 +331,7 @@ describe("SsoComponent", () => {
describe("Trusted Device Encryption scenarios", () => {
beforeEach(() => {
mockConfigService.getFeatureFlagBool.mockResolvedValue(true); // TDE enabled
mockConfigService.getFeatureFlag.mockResolvedValue(true); // TDE enabled
});
describe("Given Trusted Device Encryption is enabled and user needs to set a master password", () => {

View File

@@ -242,7 +242,7 @@ export class SsoComponent {
private async isTrustedDeviceEncEnabled(
trustedDeviceOption: TrustedDeviceUserDecryptionOption
): Promise<boolean> {
const trustedDeviceEncryptionFeatureActive = await this.configService.getFeatureFlagBool(
const trustedDeviceEncryptionFeatureActive = await this.configService.getFeatureFlag<boolean>(
FeatureFlag.TrustedDeviceEncryption
);

View File

@@ -376,7 +376,7 @@ describe("TwoFactorComponent", () => {
describe("Trusted Device Encryption scenarios", () => {
beforeEach(() => {
mockConfigService.getFeatureFlagBool.mockResolvedValue(true);
mockConfigService.getFeatureFlag.mockResolvedValue(true);
});
describe("Given Trusted Device Encryption is enabled and user needs to set a master password", () => {

View File

@@ -257,7 +257,7 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
trustedDeviceOption: TrustedDeviceUserDecryptionOption
): Promise<boolean> {
const ssoTo2faFlowActive = this.route.snapshot.queryParamMap.get("sso") === "true";
const trustedDeviceEncryptionFeatureActive = await this.configService.getFeatureFlagBool(
const trustedDeviceEncryptionFeatureActive = await this.configService.getFeatureFlag<boolean>(
FeatureFlag.TrustedDeviceEncryption
);

View File

@@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { mock, MockProxy } from "jest-mock-extended";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { FeatureFlag, FeatureFlagValue } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -41,21 +41,12 @@ describe("IfFeatureDirective", () => {
let content: HTMLElement;
let mockConfigService: MockProxy<ConfigServiceAbstraction>;
const mockConfigFlagValue = (flag: FeatureFlag, flagValue: any) => {
if (typeof flagValue === "boolean") {
mockConfigService.getFeatureFlagBool.mockImplementation((f, defaultValue = false) =>
flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
} else if (typeof flagValue === "string") {
mockConfigService.getFeatureFlagString.mockImplementation((f, defaultValue = "") =>
flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
} else if (typeof flagValue === "number") {
mockConfigService.getFeatureFlagNumber.mockImplementation((f, defaultValue = 0) =>
flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
}
const mockConfigFlagValue = (flag: FeatureFlag, flagValue: FeatureFlagValue) => {
mockConfigService.getFeatureFlag.mockImplementation((f, defaultValue) =>
flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
};
const queryContent = (testId: string) =>
fixture.debugElement.query(By.css(`[data-testid="${testId}"]`))?.nativeElement;
@@ -126,7 +117,7 @@ describe("IfFeatureDirective", () => {
});
it("hides content when the directive throws an unexpected exception", async () => {
mockConfigService.getFeatureFlagBool.mockImplementation(() => Promise.reject("Some error"));
mockConfigService.getFeatureFlag.mockImplementation(() => Promise.reject("Some error"));
fixture.detectChanges();
await fixture.whenStable();

View File

@@ -1,12 +1,9 @@
import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from "@angular/core";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { FeatureFlag, FeatureFlagValue } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
// Replace this with a type safe lookup of the feature flag values in PM-2282
type FlagValue = boolean | number | string;
/**
* Directive that conditionally renders the element when the feature flag is enabled and/or
* matches the value specified by {@link appIfFeatureValue}.
@@ -26,7 +23,7 @@ export class IfFeatureDirective implements OnInit {
* Optional value to compare against the value of the feature flag in the config service.
* @default true
*/
@Input() appIfFeatureValue: FlagValue = true;
@Input() appIfFeatureValue: FeatureFlagValue = true;
private hasView = false;
@@ -39,15 +36,7 @@ export class IfFeatureDirective implements OnInit {
async ngOnInit() {
try {
let flagValue: FlagValue;
if (typeof this.appIfFeatureValue === "boolean") {
flagValue = await this.configService.getFeatureFlagBool(this.appIfFeature);
} else if (typeof this.appIfFeatureValue === "number") {
flagValue = await this.configService.getFeatureFlagNumber(this.appIfFeature);
} else if (typeof this.appIfFeatureValue === "string") {
flagValue = await this.configService.getFeatureFlagString(this.appIfFeature);
}
const flagValue = await this.configService.getFeatureFlag(this.appIfFeature);
if (this.appIfFeatureValue === flagValue) {
if (!this.hasView) {

View File

@@ -30,15 +30,15 @@ describe("canAccessFeature", () => {
// Mock the correct getter based on the type of flagValue; also mock default values if one is not provided
if (typeof flagValue === "boolean") {
mockConfigService.getFeatureFlagBool.mockImplementation((flag, defaultValue = false) =>
mockConfigService.getFeatureFlag.mockImplementation((flag, defaultValue = false) =>
flag == testFlag ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
} else if (typeof flagValue === "string") {
mockConfigService.getFeatureFlagString.mockImplementation((flag, defaultValue = "") =>
mockConfigService.getFeatureFlag.mockImplementation((flag, defaultValue = "") =>
flag == testFlag ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
} else if (typeof flagValue === "number") {
mockConfigService.getFeatureFlagNumber.mockImplementation((flag, defaultValue = 0) =>
mockConfigService.getFeatureFlag.mockImplementation((flag, defaultValue = 0) =>
flag == testFlag ? Promise.resolve(flagValue) : Promise.resolve(defaultValue)
);
}
@@ -143,7 +143,7 @@ describe("canAccessFeature", () => {
it("fails to navigate when the config service throws an unexpected exception", async () => {
const { router } = setup(canAccessFeature(testFlag), true);
mockConfigService.getFeatureFlagBool.mockImplementation(() => Promise.reject("Some error"));
mockConfigService.getFeatureFlag.mockImplementation(() => Promise.reject("Some error"));
await router.navigate([featureRoute]);

View File

@@ -29,16 +29,8 @@ export const canAccessFeature = (
const i18nService = inject(I18nService);
const logService = inject(LogService);
let flagValue: FlagValue;
try {
if (typeof requiredFlagValue === "boolean") {
flagValue = await configService.getFeatureFlagBool(featureFlag);
} else if (typeof requiredFlagValue === "number") {
flagValue = await configService.getFeatureFlagNumber(featureFlag);
} else if (typeof requiredFlagValue === "string") {
flagValue = await configService.getFeatureFlagString(featureFlag);
}
const flagValue = await configService.getFeatureFlag(featureFlag);
if (flagValue === requiredFlagValue) {
return true;

View File

@@ -640,7 +640,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
useClass: SyncNotifierService,
},
{
provide: ConfigServiceAbstraction,
provide: ConfigService,
useClass: ConfigService,
deps: [
StateServiceAbstraction,
@@ -649,6 +649,10 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
EnvironmentServiceAbstraction,
],
},
{
provide: ConfigServiceAbstraction,
useExisting: ConfigService,
},
{
provide: ConfigApiServiceAbstraction,
useClass: ConfigApiService,