mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 17:23:37 +00:00
[PM-5979] Refactor EnvironmentService (#8040)
Refactor environment service to emit a single observable. This required significant changes to how the environment service behaves and tackles much of the tech debt planned for it.
This commit is contained in:
@@ -2386,12 +2386,6 @@
|
||||
"message": "EU",
|
||||
"description": "European Union"
|
||||
},
|
||||
"usDomain": {
|
||||
"message": "bitwarden.com"
|
||||
},
|
||||
"euDomain": {
|
||||
"message": "bitwarden.eu"
|
||||
},
|
||||
"accessDenied": {
|
||||
"message": "Access denied. You do not have permission to view this page."
|
||||
},
|
||||
|
||||
@@ -65,7 +65,7 @@ export class AccountSwitcherService {
|
||||
name: account.name ?? account.email,
|
||||
email: account.email,
|
||||
id: id,
|
||||
server: await this.environmentService.getHost(id),
|
||||
server: (await this.environmentService.getEnvironment(id))?.getHostname(),
|
||||
status: account.status,
|
||||
isActive: id === activeAccount?.id,
|
||||
avatarColor: await firstValueFrom(
|
||||
|
||||
@@ -94,10 +94,6 @@ export class HomeComponent implements OnInit, OnDestroy {
|
||||
this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
|
||||
}
|
||||
|
||||
get selfHostedDomain() {
|
||||
return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null;
|
||||
}
|
||||
|
||||
setFormValues() {
|
||||
this.loginService.setEmail(this.formGroup.value.email);
|
||||
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, NgZone } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service";
|
||||
@@ -114,7 +115,8 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
await this.ssoLoginService.setCodeVerifier(codeVerifier);
|
||||
await this.ssoLoginService.setSsoState(state);
|
||||
|
||||
let url = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
let url = env.getWebVaultUrl();
|
||||
if (url == null) {
|
||||
url = "https://vault.bitwarden.com";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component";
|
||||
@@ -64,9 +65,9 @@ export class SsoComponent extends BaseSsoComponent {
|
||||
configService,
|
||||
);
|
||||
|
||||
const url = this.environmentService.getWebVaultUrl();
|
||||
|
||||
this.redirectUri = url + "/sso-connector.html";
|
||||
environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => {
|
||||
this.redirectUri = env.getWebVaultUrl() + "/sso-connector.html";
|
||||
});
|
||||
this.clientId = "browser";
|
||||
|
||||
super.onSuccessfulLogin = async () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Subject, Subscription } from "rxjs";
|
||||
import { Subject, Subscription, firstValueFrom } from "rxjs";
|
||||
import { filter, first, takeUntil } from "rxjs/operators";
|
||||
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
|
||||
@@ -225,7 +225,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
}
|
||||
}
|
||||
|
||||
override launchDuoFrameless() {
|
||||
override async launchDuoFrameless() {
|
||||
const duoHandOffMessage = {
|
||||
title: this.i18nService.t("youSuccessfullyLoggedIn"),
|
||||
message: this.i18nService.t("youMayCloseThisWindow"),
|
||||
@@ -234,8 +234,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
|
||||
// we're using the connector here as a way to set a cookie with translations
|
||||
// before continuing to the duo frameless url
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const launchUrl =
|
||||
this.environmentService.getWebVaultUrl() +
|
||||
env.getWebVaultUrl() +
|
||||
"/duo-redirect-connector.html" +
|
||||
"?duoFramelessUrl=" +
|
||||
encodeURIComponent(this.duoFramelessUrl) +
|
||||
|
||||
@@ -113,7 +113,7 @@ type NotificationBackgroundExtensionMessageHandlers = {
|
||||
bgGetEnableChangedPasswordPrompt: () => Promise<boolean>;
|
||||
bgGetEnableAddedLoginPrompt: () => Promise<boolean>;
|
||||
bgGetExcludedDomains: () => Promise<NeverDomains>;
|
||||
getWebVaultUrlForNotification: () => string;
|
||||
getWebVaultUrlForNotification: () => Promise<string>;
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
@@ -1348,16 +1349,21 @@ describe("NotificationBackground", () => {
|
||||
const message: NotificationBackgroundExtensionMessage = {
|
||||
command: "getWebVaultUrlForNotification",
|
||||
};
|
||||
const webVaultUrl = "https://example.com";
|
||||
const env = new SelfHostedEnvironment({ webVault: "https://example.com" });
|
||||
|
||||
Object.defineProperty(environmentService, "environment$", {
|
||||
configurable: true,
|
||||
get: () => null,
|
||||
});
|
||||
|
||||
const environmentServiceSpy = jest
|
||||
.spyOn(environmentService, "getWebVaultUrl")
|
||||
.mockReturnValueOnce(webVaultUrl);
|
||||
.spyOn(environmentService as any, "environment$", "get")
|
||||
.mockReturnValue(new BehaviorSubject(env).asObservable());
|
||||
|
||||
sendExtensionRuntimeMessage(message);
|
||||
await flushPromises();
|
||||
|
||||
expect(environmentServiceSpy).toHaveBeenCalled();
|
||||
expect(environmentServiceSpy).toHaveReturnedWith(webVaultUrl);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -165,6 +165,7 @@ export default class NotificationBackground {
|
||||
notificationQueueMessage: NotificationQueueMessageItem,
|
||||
) {
|
||||
const notificationType = notificationQueueMessage.type;
|
||||
|
||||
const typeData: Record<string, any> = {
|
||||
isVaultLocked: notificationQueueMessage.wasVaultLocked,
|
||||
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
||||
@@ -655,8 +656,9 @@ export default class NotificationBackground {
|
||||
return await firstValueFrom(this.folderService.folderViews$);
|
||||
}
|
||||
|
||||
private getWebVaultUrl(): string {
|
||||
return this.environmentService.getWebVaultUrl();
|
||||
private async getWebVaultUrl(): Promise<string> {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
return env.getWebVaultUrl();
|
||||
}
|
||||
|
||||
private async removeIndividualVault(): Promise<boolean> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { mock, mockReset } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
@@ -12,9 +12,13 @@ import {
|
||||
DefaultDomainSettingsService,
|
||||
DomainSettingsService,
|
||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import {
|
||||
EnvironmentService,
|
||||
Region,
|
||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { CloudEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/services/i18n.service";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import {
|
||||
@@ -48,8 +52,6 @@ import {
|
||||
|
||||
import OverlayBackground from "./overlay.background";
|
||||
|
||||
const iconServerUrl = "https://icons.bitwarden.com/";
|
||||
|
||||
describe("OverlayBackground", () => {
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
||||
@@ -61,9 +63,15 @@ describe("OverlayBackground", () => {
|
||||
const cipherService = mock<CipherService>();
|
||||
const autofillService = mock<AutofillService>();
|
||||
const authService = mock<AuthService>();
|
||||
const environmentService = mock<EnvironmentService>({
|
||||
getIconsUrl: () => iconServerUrl,
|
||||
});
|
||||
|
||||
const environmentService = mock<EnvironmentService>();
|
||||
environmentService.environment$ = new BehaviorSubject(
|
||||
new CloudEnvironment({
|
||||
key: Region.US,
|
||||
domain: "bitwarden.com",
|
||||
urls: { icons: "https://icons.bitwarden.com/" },
|
||||
}),
|
||||
);
|
||||
const stateService = mock<BrowserStateService>();
|
||||
const autofillSettingsService = mock<AutofillSettingsService>();
|
||||
const i18nService = mock<I18nService>();
|
||||
|
||||
@@ -53,7 +53,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
private overlayListPort: chrome.runtime.Port;
|
||||
private focusedFieldData: FocusedFieldData;
|
||||
private overlayPageTranslations: Record<string, string>;
|
||||
private readonly iconsServerUrl: string;
|
||||
private iconsServerUrl: string;
|
||||
private readonly extensionMessageHandlers: OverlayBackgroundExtensionMessageHandlers = {
|
||||
openAutofillOverlay: () => this.openOverlay(false),
|
||||
autofillOverlayElementClosed: ({ message }) => this.overlayElementClosed(message),
|
||||
@@ -98,9 +98,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private themeStateService: ThemeStateService,
|
||||
) {
|
||||
this.iconsServerUrl = this.environmentService.getIconsUrl();
|
||||
}
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Removes cached page details for a tab
|
||||
@@ -118,6 +116,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
*/
|
||||
async init() {
|
||||
this.setupExtensionMessageListeners();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
this.iconsServerUrl = env.getIconsUrl();
|
||||
await this.getOverlayVisibility();
|
||||
await this.getAuthStatus();
|
||||
}
|
||||
|
||||
@@ -613,6 +613,7 @@ export default class MainBackground {
|
||||
this.authService,
|
||||
this.environmentService,
|
||||
this.logService,
|
||||
this.stateProvider,
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -1032,10 +1033,6 @@ export default class MainBackground {
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(async () => {
|
||||
await this.environmentService.setUrlsFromStorage();
|
||||
// Workaround to ignore stateService.activeAccount until URLs are set
|
||||
// TODO: Remove this when implementing ticket PM-2637
|
||||
this.environmentService.initialized = true;
|
||||
if (!this.isPrivateMode) {
|
||||
await this.refreshBadge();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
@@ -220,7 +222,8 @@ export default class RuntimeBackground {
|
||||
}
|
||||
break;
|
||||
case "authResult": {
|
||||
const vaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const vaultUrl = env.getWebVaultUrl();
|
||||
|
||||
if (msg.referrer == null || Utils.getHostname(vaultUrl) !== msg.referrer) {
|
||||
return;
|
||||
@@ -241,7 +244,8 @@ export default class RuntimeBackground {
|
||||
break;
|
||||
}
|
||||
case "webAuthnResult": {
|
||||
const vaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const vaultUrl = env.getWebVaultUrl();
|
||||
|
||||
if (msg.referrer == null || Utils.getHostname(vaultUrl) !== msg.referrer) {
|
||||
return;
|
||||
@@ -364,7 +368,8 @@ export default class RuntimeBackground {
|
||||
|
||||
async sendBwInstalledMessageToVault() {
|
||||
try {
|
||||
const vaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const vaultUrl = env.getWebVaultUrl();
|
||||
const urlObj = new URL(vaultUrl);
|
||||
|
||||
const tabs = await BrowserApi.tabsQuery({ url: `${urlObj.href}*` });
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from "./environment-service.factory";
|
||||
import { FactoryOptions, CachedServices, factory } from "./factory-options";
|
||||
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||
import { stateProviderFactory } from "./state-provider.factory";
|
||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||
|
||||
type ConfigServiceFactoryOptions = FactoryOptions & {
|
||||
@@ -43,6 +44,7 @@ export function configServiceFactory(
|
||||
await authServiceFactory(cache, opts),
|
||||
await environmentServiceFactory(cache, opts),
|
||||
await logServiceFactory(cache, opts),
|
||||
await stateProviderFactory(cache, opts),
|
||||
opts.configServiceOptions?.subscribe ?? true,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/services/config/config.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
|
||||
|
||||
@@ -21,8 +22,17 @@ export class BrowserConfigService extends ConfigService {
|
||||
authService: AuthService,
|
||||
environmentService: EnvironmentService,
|
||||
logService: LogService,
|
||||
stateProvider: StateProvider,
|
||||
subscribe = false,
|
||||
) {
|
||||
super(stateService, configApiService, authService, environmentService, logService, subscribe);
|
||||
super(
|
||||
stateService,
|
||||
configApiService,
|
||||
authService,
|
||||
environmentService,
|
||||
logService,
|
||||
stateProvider,
|
||||
subscribe,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { Region } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
|
||||
import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
import { GroupPolicyEnvironment } from "../../admin-console/types/group-policy-environment";
|
||||
import { devFlagEnabled, devFlagValue } from "../flags";
|
||||
|
||||
export class BrowserEnvironmentService extends EnvironmentService {
|
||||
export class BrowserEnvironmentService extends DefaultEnvironmentService {
|
||||
constructor(
|
||||
private logService: LogService,
|
||||
stateProvider: StateProvider,
|
||||
@@ -29,16 +32,18 @@ export class BrowserEnvironmentService extends EnvironmentService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const env = await this.getManagedEnvironment();
|
||||
const managedEnv = await this.getManagedEnvironment();
|
||||
const env = await firstValueFrom(this.environment$);
|
||||
const urls = env.getUrls();
|
||||
|
||||
return (
|
||||
env.base != this.baseUrl ||
|
||||
env.webVault != this.webVaultUrl ||
|
||||
env.api != this.webVaultUrl ||
|
||||
env.identity != this.identityUrl ||
|
||||
env.icons != this.iconsUrl ||
|
||||
env.notifications != this.notificationsUrl ||
|
||||
env.events != this.eventsUrl
|
||||
managedEnv.base != urls.base ||
|
||||
managedEnv.webVault != urls.webVault ||
|
||||
managedEnv.api != urls.api ||
|
||||
managedEnv.identity != urls.identity ||
|
||||
managedEnv.icons != urls.icons ||
|
||||
managedEnv.notifications != urls.notifications ||
|
||||
managedEnv.events != urls.events
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +67,7 @@ export class BrowserEnvironmentService extends EnvironmentService {
|
||||
|
||||
async setUrlsToManagedEnvironment() {
|
||||
const env = await this.getManagedEnvironment();
|
||||
await this.setUrls({
|
||||
await this.setEnvironment(Region.SelfHosted, {
|
||||
base: env.base,
|
||||
webVault: env.webVault,
|
||||
api: env.api,
|
||||
|
||||
@@ -222,12 +222,12 @@ function getBgService<T>(service: keyof MainBackground) {
|
||||
},
|
||||
{
|
||||
provide: BrowserEnvironmentService,
|
||||
useExisting: EnvironmentService,
|
||||
useClass: BrowserEnvironmentService,
|
||||
deps: [LogService, StateProvider, AccountServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useFactory: getBgService<EnvironmentService>("environmentService"),
|
||||
deps: [],
|
||||
useExisting: BrowserEnvironmentService,
|
||||
},
|
||||
{ provide: TotpService, useFactory: getBgService<TotpService>("totpService"), deps: [] },
|
||||
{
|
||||
@@ -480,6 +480,7 @@ function getBgService<T>(service: keyof MainBackground) {
|
||||
ConfigApiServiceAbstraction,
|
||||
AuthServiceAbstraction,
|
||||
EnvironmentService,
|
||||
StateProvider,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
|
||||
@@ -6,33 +6,33 @@
|
||||
<div bitDialogContent>
|
||||
<p>© Bitwarden Inc. 2015-{{ year }}</p>
|
||||
<p>{{ "version" | i18n }}: {{ version }}</p>
|
||||
<ng-container *ngIf="serverConfig$ | async as serverConfig">
|
||||
<p *ngIf="isCloud">
|
||||
{{ "serverVersion" | i18n }}: {{ this.serverConfig?.version }}
|
||||
<span *ngIf="!serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})
|
||||
<ng-container *ngIf="data$ | async as data">
|
||||
<p *ngIf="data.isCloud">
|
||||
{{ "serverVersion" | i18n }}: {{ data.serverConfig?.version }}
|
||||
<span *ngIf="!data.serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (data.serverConfig.utcDate | date: "mediumDate") }})
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<ng-container *ngIf="!isCloud">
|
||||
<ng-container *ngIf="serverConfig.server">
|
||||
<ng-container *ngIf="!data.isCloud">
|
||||
<ng-container *ngIf="data.serverConfig.server">
|
||||
<p>
|
||||
{{ "serverVersion" | i18n }} <small>({{ "thirdParty" | i18n }})</small>:
|
||||
{{ this.serverConfig?.version }}
|
||||
<span *ngIf="!serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})
|
||||
{{ data.serverConfig?.version }}
|
||||
<span *ngIf="!data.serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (data.serverConfig.utcDate | date: "mediumDate") }})
|
||||
</span>
|
||||
</p>
|
||||
<div>
|
||||
<small>{{ "thirdPartyServerMessage" | i18n: serverConfig.server?.name }}</small>
|
||||
<small>{{ "thirdPartyServerMessage" | i18n: data.serverConfig.server?.name }}</small>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<p *ngIf="!serverConfig.server">
|
||||
<p *ngIf="!data.serverConfig.server">
|
||||
{{ "serverVersion" | i18n }} <small>({{ "selfHostedServer" | i18n }})</small>:
|
||||
{{ this.serverConfig?.version }}
|
||||
<span *ngIf="!serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})
|
||||
{{ data.serverConfig?.version }}
|
||||
<span *ngIf="!data.serverConfig.isValid()">
|
||||
({{ "lastSeenOn" | i18n: (data.serverConfig.utcDate | date: "mediumDate") }})
|
||||
</span>
|
||||
</p>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
import { combineLatest, map } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { ButtonModule, DialogModule } from "@bitwarden/components";
|
||||
|
||||
@@ -16,11 +15,13 @@ import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
imports: [CommonModule, JslibModule, DialogModule, ButtonModule],
|
||||
})
|
||||
export class AboutComponent {
|
||||
protected serverConfig$: Observable<ServerConfig> = this.configService.serverConfig$;
|
||||
|
||||
protected year = new Date().getFullYear();
|
||||
protected version = BrowserApi.getApplicationVersion();
|
||||
protected isCloud = this.environmentService.isCloud();
|
||||
|
||||
protected data$ = combineLatest([
|
||||
this.configService.serverConfig$,
|
||||
this.environmentService.environment$.pipe(map((env) => env.isCloud())),
|
||||
]).pipe(map(([serverConfig, isCloud]) => ({ serverConfig, isCloud })));
|
||||
|
||||
constructor(
|
||||
private configService: ConfigServiceAbstraction,
|
||||
|
||||
@@ -446,9 +446,8 @@ export class SettingsComponent implements OnInit {
|
||||
type: "info",
|
||||
});
|
||||
if (confirmed) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab(this.environmentService.getWebVaultUrl());
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
await BrowserApi.createNewTab(env.getWebVaultUrl());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,10 +478,9 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async webVault() {
|
||||
const url = this.environmentService.getWebVaultUrl();
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
BrowserApi.createNewTab(url);
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const url = env.getWebVaultUrl();
|
||||
await BrowserApi.createNewTab(url);
|
||||
}
|
||||
|
||||
async import() {
|
||||
|
||||
Reference in New Issue
Block a user