mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
[PM-1019] Environment selection clients (#5480)
* [PM-169][PM-142][PM-191] Add Environments to Web and Desktop (#5294) * [PM-1351] Add property to server-config.response. Change config to be able to fetch without being authed. * [PM-1351] fetch every hour. * [PM-1351] fetch on vault sync. * [PM-1351] browser desktop fetch configs on sync complete. * [PM-1351] Add methods to retrieve feature flags * [PM-1351] Add enum to use as key to get values feature flag values * [PM-1351] Remove debug code * [PM-1351] Get flags when unauthed. Add enums as params. Hourly always fetch. * [PM-1351] add check for authed user using auth service * [PM-169] Web: add drop down to select environment * [PM-169] Fix pop up menu margins. Add DisplayEuEnvironmentFlag. * [PM-169] Change menu name. * [PM-169] Add environment selector ts and html. Add declaration and import on login.module * [PM-169] Add environment selector to desktop. * [PM-169] Ignore lint error. * [PM-169] add takeUntil to subscribes * [PM-191] PR Fixes, code format * [PM-168] Add Environments to extension login/registration (#5434)
This commit is contained in:
parent
6383d6ff8a
commit
b9fe78796a
@ -2221,7 +2221,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"message": "Region"
|
||||
},
|
||||
"opensInANewWindow": {
|
||||
"message": "Opens in a new window"
|
||||
},
|
||||
"eu": {
|
||||
"message": "EU",
|
||||
"description": "European Union"
|
||||
},
|
||||
"us": {
|
||||
"message": "US",
|
||||
"description": "United States"
|
||||
}
|
||||
}
|
||||
|
@ -2221,6 +2221,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"message": "Region"
|
||||
},
|
||||
"opensInANewWindow": {
|
||||
"message": "Opens in a new window"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { EnvironmentComponent as BaseEnvironmentComponent } from "@bitwarden/angular/components/environment.component";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
|
||||
@ -18,9 +19,10 @@ export class EnvironmentComponent extends BaseEnvironmentComponent implements On
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
public environmentService: BrowserEnvironmentService,
|
||||
i18nService: I18nService,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
modalService: ModalService
|
||||
) {
|
||||
super(platformUtilsService, environmentService, i18nService);
|
||||
super(platformUtilsService, environmentService, i18nService, modalService);
|
||||
this.showCustom = true;
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,7 @@
|
||||
<label for="email">{{ "emailAddress" | i18n }}</label>
|
||||
<input id="email" type="email" formControlName="email" appInputVerbatim="false" />
|
||||
</div>
|
||||
<div class="box-footer no-margin" *ngIf="selfHostedDomain">
|
||||
{{ "loggingInTo" | i18n : selfHostedDomain }}
|
||||
</div>
|
||||
<environment-selector class="environment-selector-padding"></environment-selector>
|
||||
<div class="remember-email-check">
|
||||
<input
|
||||
id="rememberEmail"
|
||||
@ -35,6 +33,3 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" routerLink="/environment" class="settings-icon" (click)="setFormValues()">
|
||||
<i class="bwi bwi-cog-f bwi-lg" aria-hidden="true"></i><span> {{ "settings" | i18n }}</span>
|
||||
</button>
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
@ -12,9 +14,12 @@ import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"
|
||||
selector: "app-home",
|
||||
templateUrl: "home.component.html",
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
loginInitiated = false;
|
||||
export class HomeComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(EnvironmentSelectorComponent, { static: true })
|
||||
environmentSelector!: EnvironmentSelectorComponent;
|
||||
private destroyed$: Subject<void> = new Subject();
|
||||
|
||||
loginInitiated = false;
|
||||
formGroup = this.formBuilder.group({
|
||||
email: ["", [Validators.required, Validators.email]],
|
||||
rememberEmail: [false],
|
||||
@ -27,9 +32,9 @@ export class HomeComponent implements OnInit {
|
||||
private router: Router,
|
||||
private i18nService: I18nService,
|
||||
private environmentService: EnvironmentService,
|
||||
private route: ActivatedRoute,
|
||||
private loginService: LoginService
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
let savedEmail = this.loginService.getEmail();
|
||||
const rememberEmail = this.loginService.getRememberEmail();
|
||||
@ -48,6 +53,18 @@ export class HomeComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.environmentSelector.onOpenSelfHostedSettings
|
||||
.pipe(takeUntil(this.destroyed$))
|
||||
.subscribe(() => {
|
||||
this.setFormValues();
|
||||
this.router.navigate(["environment"]);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroyed$.next();
|
||||
this.destroyed$.complete();
|
||||
}
|
||||
|
||||
submit() {
|
||||
|
@ -10,6 +10,7 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { BrowserModule } from "@angular/platform-browser";
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
|
||||
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
||||
import { BitwardenToastModule } from "@bitwarden/angular/components/toastr.component";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
||||
@ -153,6 +154,7 @@ import "./locales";
|
||||
AboutComponent,
|
||||
HelpAndFeedbackComponent,
|
||||
AutofillComponent,
|
||||
EnvironmentSelectorComponent,
|
||||
],
|
||||
providers: [CurrencyPipe, DatePipe],
|
||||
bootstrap: [AppComponent],
|
||||
|
BIN
apps/browser/src/popup/images/eu-flag.png
Normal file
BIN
apps/browser/src/popup/images/eu-flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
apps/browser/src/popup/images/us-flag.png
Normal file
BIN
apps/browser/src/popup/images/us-flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
@ -45,3 +45,67 @@ html.browser_safari {
|
||||
border-color: #2e3440;
|
||||
}
|
||||
}
|
||||
|
||||
.environment-selector-btn {
|
||||
font-size: $font-size-small;
|
||||
color: $text-muted;
|
||||
line-height: 25px;
|
||||
font-weight: 400;
|
||||
padding-left: 5px;
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a,
|
||||
a label:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.environment-selector-dialog {
|
||||
@include themify($themes) {
|
||||
background-color: themed("boxBackgroundColor");
|
||||
}
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.environment-selector-dialog-item {
|
||||
@include themify($themes) {
|
||||
color: themed("textColor") !important;
|
||||
}
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 0px 15px 0px 5px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
@include themify($themes) {
|
||||
background-color: themed("listItemBackgroundHoverColor") !important;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
margin-bottom: -2px;
|
||||
width: 22px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.img-us {
|
||||
content: url("../images/us-flag.png");
|
||||
}
|
||||
|
||||
.img-eu {
|
||||
content: url("../images/eu-flag.png");
|
||||
}
|
||||
}
|
||||
|
||||
.environment-selector-padding {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ body.body-full {
|
||||
}
|
||||
|
||||
.remember-email-check {
|
||||
padding-top: 8px;
|
||||
padding-top: 18px;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 18px;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { EnvironmentComponent as BaseEnvironmentComponent } from "@bitwarden/angular/components/environment.component";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
@ -13,8 +14,9 @@ export class EnvironmentComponent extends BaseEnvironmentComponent {
|
||||
constructor(
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
environmentService: EnvironmentService,
|
||||
i18nService: I18nService
|
||||
i18nService: I18nService,
|
||||
modalService: ModalService
|
||||
) {
|
||||
super(platformUtilsService, environmentService, i18nService);
|
||||
super(platformUtilsService, environmentService, i18nService, modalService);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,4 @@
|
||||
<div id="login-page">
|
||||
<div class="login-header">
|
||||
<button
|
||||
type="button"
|
||||
appStopClick
|
||||
(click)="settings()"
|
||||
class="environment-urls-settings-icon"
|
||||
attr.aria-label="{{ 'settings' | i18n }}"
|
||||
>
|
||||
<i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i>
|
||||
{{ "settings" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
<div id="login-page" class="page-top-padding">
|
||||
<form
|
||||
id="login-page"
|
||||
#form
|
||||
@ -19,7 +7,7 @@
|
||||
[formGroup]="formGroup"
|
||||
attr.aria-hidden="{{ showingModal }}"
|
||||
>
|
||||
<div id="content" class="content">
|
||||
<div id="content" class="content" style="padding-top: 50px">
|
||||
<img class="logo-image" alt="Bitwarden" />
|
||||
<p class="lead">{{ "loginOrCreateNewAccount" | i18n }}</p>
|
||||
<!-- start email -->
|
||||
@ -37,9 +25,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer" *ngIf="selfHostedDomain">
|
||||
{{ "loggingInTo" | i18n : selfHostedDomain }}
|
||||
</div>
|
||||
<environment-selector></environment-selector>
|
||||
</div>
|
||||
<div class="checkbox remember-email">
|
||||
<label for="rememberEmail">
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Component, NgZone, OnDestroy, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@ -31,7 +33,10 @@ const BroadcasterSubscriptionId = "LoginComponent";
|
||||
export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
@ViewChild("environment", { read: ViewContainerRef, static: true })
|
||||
environmentModal: ViewContainerRef;
|
||||
@ViewChild(EnvironmentSelectorComponent)
|
||||
environmentSelector!: EnvironmentSelectorComponent;
|
||||
|
||||
protected componentDestroyed$: Subject<void> = new Subject();
|
||||
webVaultHostname = "";
|
||||
|
||||
showingModal = false;
|
||||
@ -116,10 +121,17 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
});
|
||||
});
|
||||
this.messagingService.send("getWindowIsFocused");
|
||||
this.environmentSelector.onOpenSelfHostedSettings
|
||||
.pipe(takeUntil(this.componentDestroyed$))
|
||||
.subscribe(() => {
|
||||
this.settings();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
||||
this.componentDestroyed$.next();
|
||||
this.componentDestroyed$.complete();
|
||||
}
|
||||
|
||||
async settings() {
|
||||
@ -128,17 +140,16 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
this.environmentModal
|
||||
);
|
||||
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
modal.onShown.subscribe(() => {
|
||||
modal.onShown.pipe(takeUntil(this.componentDestroyed$)).subscribe(() => {
|
||||
this.showingModal = true;
|
||||
});
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
modal.onClosed.subscribe(() => {
|
||||
|
||||
modal.onClosed.pipe(takeUntil(this.componentDestroyed$)).subscribe(() => {
|
||||
this.showingModal = false;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
childComponent.onSaved.subscribe(async () => {
|
||||
// eslint-disable-next-line rxjs/no-async-subscribe
|
||||
childComponent.onSaved.pipe(takeUntil(this.componentDestroyed$)).subscribe(async () => {
|
||||
modal.close();
|
||||
await this.checkSelfHosted();
|
||||
});
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
|
||||
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
||||
|
||||
import { SharedModule } from "../../app/shared/shared.module";
|
||||
|
||||
import { LoginWithDeviceComponent } from "./login-with-device.component";
|
||||
@ -8,7 +10,7 @@ import { LoginComponent } from "./login.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, RouterModule],
|
||||
declarations: [LoginComponent, LoginWithDeviceComponent],
|
||||
declarations: [LoginComponent, LoginWithDeviceComponent, EnvironmentSelectorComponent],
|
||||
exports: [LoginComponent, LoginWithDeviceComponent],
|
||||
})
|
||||
export class LoginModule {}
|
||||
|
BIN
apps/desktop/src/images/eu-flag.png
Normal file
BIN
apps/desktop/src/images/eu-flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
apps/desktop/src/images/us-flag.png
Normal file
BIN
apps/desktop/src/images/us-flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
@ -2251,5 +2251,19 @@
|
||||
},
|
||||
"windowsBiometricUpdateWarningTitle": {
|
||||
"message": "Recommended Settings Update"
|
||||
},
|
||||
"region": {
|
||||
"message": "Region"
|
||||
},
|
||||
"eu": {
|
||||
"message": "EU",
|
||||
"description": "European Union"
|
||||
},
|
||||
"us": {
|
||||
"message": "US",
|
||||
"description": "United States"
|
||||
},
|
||||
"selfHosted": {
|
||||
"message": "Self-hosted"
|
||||
}
|
||||
}
|
||||
|
@ -38,3 +38,63 @@
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.environment-selector-btn {
|
||||
font-size: $font-size-small;
|
||||
color: $text-muted;
|
||||
line-height: 25px;
|
||||
font-weight: 400;
|
||||
padding-left: 5px;
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a,
|
||||
a label:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.environment-selector-dialog {
|
||||
@include themify($themes) {
|
||||
background-color: themed("boxBackgroundColor");
|
||||
}
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.environment-selector-dialog-item {
|
||||
@include themify($themes) {
|
||||
color: themed("textColor") !important;
|
||||
}
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 0px 15px 0px 5px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
@include themify($themes) {
|
||||
background-color: themed("listItemBackgroundHoverColor") !important;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
margin-bottom: -2px;
|
||||
width: 22px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.img-us {
|
||||
content: url("../images/us-flag.png");
|
||||
}
|
||||
|
||||
.img-eu {
|
||||
content: url("../images/eu-flag.png");
|
||||
}
|
||||
}
|
||||
|
@ -421,6 +421,10 @@ app-root > #loading,
|
||||
}
|
||||
}
|
||||
|
||||
.page-top-padding {
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.logo-image {
|
||||
@include themify($themes) {
|
||||
content: url("../images/logo-" + themed("logoSuffix") + "@2x.png");
|
||||
|
@ -1,5 +1,34 @@
|
||||
<router-outlet></router-outlet>
|
||||
<div class="container my-5 text-muted text-center">
|
||||
<div class="tw-mb-1">
|
||||
<bit-menu #environmentOptions>
|
||||
<a bitMenuItem href="https://vault.bitwarden.com" class="pr-4">
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check pb-1"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="isEuServer ? 'hidden' : 'visible'"
|
||||
></i>
|
||||
<img src="../../images/us_flag.png" alt="" class="pb-1 mr-1" />
|
||||
{{ "us" | i18n }}
|
||||
</a>
|
||||
<a bitMenuItem href="https://vault.bitwarden.eu" class="pr-4" *ngIf="euServerFlagEnabled">
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check pb-1"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="isEuServer ? 'visible' : 'hidden'"
|
||||
></i>
|
||||
<img src="../../images/eu_flag.png" alt="" class="pb-1 mr-1" />
|
||||
{{ "eu" | i18n }}
|
||||
</a>
|
||||
</bit-menu>
|
||||
{{ "region" | i18n }}:
|
||||
<a [routerLink]="[]" [bitMenuTriggerFor]="environmentOptions">
|
||||
<b>{{ isEuServer ? ("eu" | i18n) : ("us" | i18n) }}</b
|
||||
><i class="bwi bwi-fw bwi-sm bwi-angle-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
© {{ year }} Bitwarden Inc. <br />
|
||||
{{ "versionNumber" | i18n : version }}
|
||||
</div>
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
|
||||
@Component({
|
||||
selector: "app-frontend-layout",
|
||||
@ -9,12 +12,22 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
|
||||
export class FrontendLayoutComponent implements OnInit, OnDestroy {
|
||||
version: string;
|
||||
year = "2015";
|
||||
isEuServer = true;
|
||||
euServerFlagEnabled: boolean;
|
||||
|
||||
constructor(private platformUtilsService: PlatformUtilsService) {}
|
||||
constructor(
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private configService: ConfigServiceAbstraction
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.year = new Date().getFullYear().toString();
|
||||
this.version = await this.platformUtilsService.getApplicationVersion();
|
||||
this.euServerFlagEnabled = await this.configService.getFeatureFlagBool(
|
||||
FeatureFlag.DisplayEuEnvironmentFlag
|
||||
);
|
||||
this.isEuServer = Utils.getDomain(window.location.href).includes(".eu");
|
||||
|
||||
document.body.classList.add("layout_frontend");
|
||||
}
|
||||
|
||||
|
BIN
apps/web/src/images/eu_flag.png
Normal file
BIN
apps/web/src/images/eu_flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
apps/web/src/images/us_flag.png
Normal file
BIN
apps/web/src/images/us_flag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
@ -6789,6 +6789,17 @@
|
||||
"enforceOnLoginDesc": {
|
||||
"message": "Require existing members to change their passwords"
|
||||
},
|
||||
"region": {
|
||||
"message": "Region"
|
||||
},
|
||||
"eu": {
|
||||
"message": "EU",
|
||||
"description": "European Union"
|
||||
},
|
||||
"us": {
|
||||
"message": "US",
|
||||
"description": "United States"
|
||||
},
|
||||
"smProjectDeleteAccessRestricted": {
|
||||
"message": "You don't have permissions to delete this project",
|
||||
"description": "The individual description shown to the user when the user doesn't have access to delete a project."
|
||||
|
@ -0,0 +1,86 @@
|
||||
<label class="environment-selector-btn">
|
||||
{{ "region" | i18n }}:
|
||||
<a
|
||||
(click)="toggle(null)"
|
||||
cdkOverlayOrigin
|
||||
#trigger="cdkOverlayOrigin"
|
||||
aria-haspopup="menu"
|
||||
aria-controls="cdk-overlay-container"
|
||||
[ngSwitch]="selectedEnvironment"
|
||||
>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.US" class="text-primary">{{ "us" | i18n }}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.EU" class="text-primary">{{ "eu" | i18n }}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.SelfHosted" class="text-primary">{{
|
||||
"selfHosted" | i18n
|
||||
}}</label>
|
||||
<i class="bwi bwi-fw bwi-sm bwi-angle-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
</label>
|
||||
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
(backdropClick)="close()"
|
||||
(detach)="close()"
|
||||
[cdkConnectedOverlayOpen]="isOpen"
|
||||
[cdkConnectedOverlayPositions]="overlayPostition"
|
||||
>
|
||||
<div class="box-content">
|
||||
<div class="environment-selector-dialog" [@transformPanel]="'open'" role="dialog">
|
||||
<button
|
||||
type="button"
|
||||
class="environment-selector-dialog-item"
|
||||
(click)="toggle(ServerEnvironmentType.US)"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check"
|
||||
style="padding-bottom: 1px"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="
|
||||
selectedEnvironment === ServerEnvironmentType.US ? 'visible' : 'hidden'
|
||||
"
|
||||
></i>
|
||||
<img class="img-us" alt="" />
|
||||
<span>{{ "us" | i18n }}</span>
|
||||
</button>
|
||||
<br />
|
||||
<button
|
||||
type="button"
|
||||
class="environment-selector-dialog-item"
|
||||
(click)="toggle(ServerEnvironmentType.EU)"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check"
|
||||
style="padding-bottom: 1px"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="
|
||||
selectedEnvironment === ServerEnvironmentType.EU ? 'visible' : 'hidden'
|
||||
"
|
||||
></i>
|
||||
<img class="img-eu" alt="" />
|
||||
<span>{{ "eu" | i18n }}</span>
|
||||
</button>
|
||||
<br />
|
||||
<button
|
||||
type="button"
|
||||
class="environment-selector-dialog-item"
|
||||
(click)="toggle(ServerEnvironmentType.SelfHosted)"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check"
|
||||
style="padding-bottom: 1px"
|
||||
aria-hidden="true"
|
||||
[style.visibility]="
|
||||
selectedEnvironment === ServerEnvironmentType.SelfHosted ? 'visible' : 'hidden'
|
||||
"
|
||||
></i>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-pencil-square"
|
||||
style="padding-bottom: 1px"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span>{{ "selfHosted" | i18n }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
@ -0,0 +1,103 @@
|
||||
import { animate, state, style, transition, trigger } from "@angular/animations";
|
||||
import { ConnectedPosition } from "@angular/cdk/overlay";
|
||||
import { Component, EventEmitter, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
|
||||
@Component({
|
||||
selector: "environment-selector",
|
||||
templateUrl: "environment-selector.component.html",
|
||||
animations: [
|
||||
trigger("transformPanel", [
|
||||
state(
|
||||
"void",
|
||||
style({
|
||||
opacity: 0,
|
||||
})
|
||||
),
|
||||
transition(
|
||||
"void => open",
|
||||
animate(
|
||||
"100ms linear",
|
||||
style({
|
||||
opacity: 1,
|
||||
})
|
||||
)
|
||||
),
|
||||
transition("* => void", animate("100ms linear", style({ opacity: 0 }))),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
|
||||
@Output() onOpenSelfHostedSettings = new EventEmitter();
|
||||
isOpen = false;
|
||||
showingModal = false;
|
||||
selectedEnvironment: ServerEnvironment;
|
||||
ServerEnvironmentType = ServerEnvironment;
|
||||
euServerFlagEnabled: boolean;
|
||||
overlayPostition: ConnectedPosition[] = [
|
||||
{
|
||||
originX: "start",
|
||||
originY: "bottom",
|
||||
overlayX: "start",
|
||||
overlayY: "top",
|
||||
},
|
||||
];
|
||||
protected componentDestroyed$: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
protected environmentService: EnvironmentService,
|
||||
protected configService: ConfigServiceAbstraction,
|
||||
protected router: Router
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.euServerFlagEnabled = await this.configService.getFeatureFlagBool(
|
||||
FeatureFlag.DisplayEuEnvironmentFlag
|
||||
);
|
||||
this.updateEnvironmentInfo();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.componentDestroyed$.next();
|
||||
this.componentDestroyed$.complete();
|
||||
}
|
||||
|
||||
async toggle(option: ServerEnvironment) {
|
||||
this.isOpen = !this.isOpen;
|
||||
if (option === ServerEnvironment.EU) {
|
||||
await this.environmentService.setUrls({ base: "https://vault.bitwarden.eu" });
|
||||
} else if (option === ServerEnvironment.US) {
|
||||
await this.environmentService.setUrls({ base: "https://vault.bitwarden.com" });
|
||||
} else if (option === ServerEnvironment.SelfHosted) {
|
||||
this.onOpenSelfHostedSettings.emit();
|
||||
}
|
||||
this.updateEnvironmentInfo();
|
||||
}
|
||||
|
||||
updateEnvironmentInfo() {
|
||||
const webvaultUrl = this.environmentService.getWebVaultUrl();
|
||||
if (this.environmentService.isSelfHosted()) {
|
||||
this.selectedEnvironment = ServerEnvironment.SelfHosted;
|
||||
} else if (webvaultUrl != null && webvaultUrl.includes("bitwarden.eu")) {
|
||||
this.selectedEnvironment = ServerEnvironment.EU;
|
||||
} else {
|
||||
this.selectedEnvironment = ServerEnvironment.US;
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this.isOpen = false;
|
||||
this.updateEnvironmentInfo();
|
||||
}
|
||||
}
|
||||
|
||||
enum ServerEnvironment {
|
||||
US = "US",
|
||||
EU = "EU",
|
||||
SelfHosted = "Self-hosted",
|
||||
}
|
@ -4,6 +4,8 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
|
||||
import { ModalService } from "../services/modal.service";
|
||||
|
||||
@Directive()
|
||||
export class EnvironmentComponent {
|
||||
@Output() onSaved = new EventEmitter();
|
||||
@ -19,7 +21,8 @@ export class EnvironmentComponent {
|
||||
constructor(
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected environmentService: EnvironmentService,
|
||||
protected i18nService: I18nService
|
||||
protected i18nService: I18nService,
|
||||
private modalService: ModalService
|
||||
) {
|
||||
const urls = this.environmentService.getUrls();
|
||||
|
||||
@ -59,5 +62,6 @@ export class EnvironmentComponent {
|
||||
|
||||
protected saved() {
|
||||
this.onSaved.emit();
|
||||
this.modalService.closeAll();
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +218,8 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
return ![
|
||||
"http://vault.bitwarden.com",
|
||||
"https://vault.bitwarden.com",
|
||||
"http://vault.bitwarden.eu",
|
||||
"https://vault.bitwarden.eu",
|
||||
"http://vault.qa.bitwarden.pw",
|
||||
"https://vault.qa.bitwarden.pw",
|
||||
].includes(this.getWebVaultUrl());
|
||||
|
Loading…
Reference in New Issue
Block a user