[PM-8115] Desktop, Extension UI Refresh: Self-hosted Setup Dialog (#11597)

* Reimplement RegistrationSelfHostedEnvConfigDialogComponent

* Update EnvironmentSelectorComponent text based on feature flag.

* Initialize RegistrationSelfHostedEnvConfigDialog with existing values if self hosted

* Cleanup debug

* Add comment

* Remove changes to home and login components

* Remove changes to desktop login component

* Remove changes to browser home component

* Simplify accessing string.

* Add environment selector service.

* Cleanup unused imports in environment-selector

* Launch new env selector dialog from desktop

* Fix lint errors

* Address PR feedback: move dialog component, remove EnvironmentSelectorService, remove unused translation string

* Remove changes to AnonLayout

* PM-8115 - Export Re-usable component from Libs/auth for clean import elsewhere in clients.

* Remove unused accessingString variable

* Add success toast

---------

Co-authored-by: Jared Snider <jsnider@bitwarden.com>
This commit is contained in:
Alec Rippberger 2024-10-28 16:12:57 -05:00 committed by GitHub
parent 95e8e0c9bf
commit 9da80a6cba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 67 additions and 21 deletions

View File

@ -3234,9 +3234,6 @@
} }
} }
}, },
"loggingInOn": {
"message": "Logging in on"
},
"opensInANewWindow": { "opensInANewWindow": {
"message": "Opens in a new window" "message": "Opens in a new window"
}, },

View File

@ -2804,9 +2804,6 @@
"message": "EU", "message": "EU",
"description": "European Union" "description": "European Union"
}, },
"loggingInOn": {
"message": "Logging in on"
},
"selfHostedServer": { "selfHostedServer": {
"message": "self-hosted" "message": "self-hosted"
}, },

View File

@ -4,7 +4,7 @@
} as data" } as data"
> >
<div class="environment-selector-btn"> <div class="environment-selector-btn">
{{ "loggingInOn" | i18n }}: {{ "accessing" | i18n }}:
<button <button
type="button" type="button"
(click)="toggle(null)" (click)="toggle(null)"

View File

@ -1,14 +1,19 @@
import { animate, state, style, transition, trigger } from "@angular/animations"; import { animate, state, style, transition, trigger } from "@angular/animations";
import { ConnectedPosition } from "@angular/cdk/overlay"; import { ConnectedPosition } from "@angular/cdk/overlay";
import { Component, EventEmitter, Output, Input, OnInit, OnDestroy } from "@angular/core"; import { Component, EventEmitter, Output, Input, OnInit, OnDestroy } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import { Observable, map, Subject, takeUntil } from "rxjs"; import { Observable, map, Subject, takeUntil } from "rxjs";
import { SelfHostedEnvConfigDialogComponent } from "@bitwarden/auth/angular";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { import {
EnvironmentService, EnvironmentService,
Region, Region,
RegionConfig, RegionConfig,
} from "@bitwarden/common/platform/abstractions/environment.service"; } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService, ToastService } from "@bitwarden/components";
export const ExtensionDefaultOverlayPosition: ConnectedPosition[] = [ export const ExtensionDefaultOverlayPosition: ConnectedPosition[] = [
{ {
@ -56,7 +61,7 @@ export interface EnvironmentSelectorRouteData {
], ],
}) })
export class EnvironmentSelectorComponent implements OnInit, OnDestroy { export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
@Output() onOpenSelfHostedSettings = new EventEmitter(); @Output() onOpenSelfHostedSettings = new EventEmitter<void>();
@Input() overlayPosition: ConnectedPosition[] = [ @Input() overlayPosition: ConnectedPosition[] = [
{ {
originX: "start", originX: "start",
@ -79,8 +84,11 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
constructor( constructor(
protected environmentService: EnvironmentService, protected environmentService: EnvironmentService,
protected router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private dialogService: DialogService,
private configService: ConfigService,
private toastService: ToastService,
private i18nService: I18nService,
) {} ) {}
ngOnInit() { ngOnInit() {
@ -102,8 +110,25 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
return; return;
} }
/**
* Opens the self-hosted settings dialog.
*
* If the `UnauthenticatedExtensionUIRefresh` feature flag is enabled,
* the self-hosted settings dialog is opened directly. Otherwise, the
* `onOpenSelfHostedSettings` event is emitted.
*/
if (option === Region.SelfHosted) { if (option === Region.SelfHosted) {
this.onOpenSelfHostedSettings.emit(); if (await this.configService.getFeatureFlag(FeatureFlag.UnauthenticatedExtensionUIRefresh)) {
if (await SelfHostedEnvConfigDialogComponent.open(this.dialogService)) {
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("environmentSaved"),
});
}
} else {
this.onOpenSelfHostedSettings.emit();
}
return; return;
} }

View File

@ -55,3 +55,6 @@ export * from "./lock/lock-component.service";
// vault timeout // vault timeout
export * from "./vault-timeout-input/vault-timeout-input.component"; export * from "./vault-timeout-input/vault-timeout-input.component";
// self hosted environment configuration dialog
export * from "./self-hosted-env-config-dialog/self-hosted-env-config-dialog.component";

View File

@ -15,7 +15,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService, FormFieldModule, SelectModule, ToastService } from "@bitwarden/components"; import { DialogService, FormFieldModule, SelectModule, ToastService } from "@bitwarden/components";
import { RegistrationSelfHostedEnvConfigDialogComponent } from "./registration-self-hosted-env-config-dialog.component"; import { SelfHostedEnvConfigDialogComponent } from "../../self-hosted-env-config-dialog/self-hosted-env-config-dialog.component";
/** /**
* Component for selecting the environment to register with in the email verification registration flow. * Component for selecting the environment to register with in the email verification registration flow.
@ -125,9 +125,7 @@ export class RegistrationEnvSelectorComponent implements OnInit, OnDestroy {
} }
if (selectedRegion === Region.SelfHosted) { if (selectedRegion === Region.SelfHosted) {
return from( return from(SelfHostedEnvConfigDialogComponent.open(this.dialogService)).pipe(
RegistrationSelfHostedEnvConfigDialogComponent.open(this.dialogService),
).pipe(
tap((result: boolean | undefined) => tap((result: boolean | undefined) =>
this.handleSelfHostedEnvConfigDialogResult(result, prevSelectedRegion), this.handleSelfHostedEnvConfigDialogResult(result, prevSelectedRegion),
), ),

View File

@ -10,7 +10,7 @@ import {
ValidationErrors, ValidationErrors,
ValidatorFn, ValidatorFn,
} from "@angular/forms"; } from "@angular/forms";
import { Subject, firstValueFrom } from "rxjs"; import { Subject, firstValueFrom, take, filter, takeUntil } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { import {
@ -54,8 +54,8 @@ function selfHostedEnvSettingsFormValidator(): ValidatorFn {
*/ */
@Component({ @Component({
standalone: true, standalone: true,
selector: "auth-registration-self-hosted-env-config-dialog", selector: "self-hosted-env-config-dialog",
templateUrl: "registration-self-hosted-env-config-dialog.component.html", templateUrl: "self-hosted-env-config-dialog.component.html",
imports: [ imports: [
CommonModule, CommonModule,
JslibModule, JslibModule,
@ -68,14 +68,14 @@ function selfHostedEnvSettingsFormValidator(): ValidatorFn {
AsyncActionsModule, AsyncActionsModule,
], ],
}) })
export class RegistrationSelfHostedEnvConfigDialogComponent implements OnInit, OnDestroy { export class SelfHostedEnvConfigDialogComponent implements OnInit, OnDestroy {
/** /**
* Opens the dialog. * Opens the dialog.
* @param dialogService - Dialog service. * @param dialogService - Dialog service.
* @returns Promise that resolves to true if the dialog was closed with a successful result, false otherwise. * @returns Promise that resolves to true if the dialog was closed with a successful result, false otherwise.
*/ */
static async open(dialogService: DialogService): Promise<boolean> { static async open(dialogService: DialogService): Promise<boolean> {
const dialogRef = dialogService.open<boolean>(RegistrationSelfHostedEnvConfigDialogComponent, { const dialogRef = dialogService.open<boolean>(SelfHostedEnvConfigDialogComponent, {
disableClose: false, disableClose: false,
}); });
@ -131,7 +131,33 @@ export class RegistrationSelfHostedEnvConfigDialogComponent implements OnInit, O
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
) {} ) {}
ngOnInit() {} ngOnInit() {
/**
* Populate the form with the current self-hosted environment settings.
*/
this.environmentService.environment$
.pipe(
take(1),
filter((env) => {
const region = env.getRegion();
return region === Region.SelfHosted;
}),
takeUntil(this.destroy$),
)
.subscribe({
next: (env) => {
const urls = env.getUrls();
this.formGroup.patchValue({
baseUrl: urls.base || "",
webVaultUrl: urls.webVault || "",
apiUrl: urls.api || "",
identityUrl: urls.identity || "",
iconsUrl: urls.icons || "",
notificationsUrl: urls.notifications || "",
});
},
});
}
submit = async () => { submit = async () => {
this.showErrorSummary = false; this.showErrorSummary = false;