mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 23:03:32 +00:00
[CL-106] use CL's DialogService in Desktop & Browser (#5875)
* remove libs/angular dialog service; move simple dialog types to CL * update DialogServiceAbstraction imports to CL * update imports in libs/angular to use CL * colocate simple dialog types * move SimpleConfigurableDialog files under SimpleDialog * remove CL import alias from CL src * update imports * run prettier * convert SimpleDialog enums to types * replace DialogServiceAbstraction with DialogService * restrict libs/angular imports in CL * add deprecation note to ModalService * Delete BrowserDialogService * Remove ElectronDialogService * update browser and desktop services.module * remove os.EOL in simple dialog * change SimpleDialogCloseType to boolean * remove close type
This commit is contained in:
@@ -2,8 +2,6 @@ import { DialogModule as CdkDialogModule } from "@angular/cdk/dialog";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
|
||||
import { AsyncActionsModule } from "../async-actions";
|
||||
import { ButtonModule } from "../button";
|
||||
import { IconButtonModule } from "../icon-button";
|
||||
@@ -13,7 +11,7 @@ import { DialogComponent } from "./dialog/dialog.component";
|
||||
import { DialogService } from "./dialog.service";
|
||||
import { DialogCloseDirective } from "./directives/dialog-close.directive";
|
||||
import { DialogTitleContainerDirective } from "./directives/dialog-title-container.directive";
|
||||
import { SimpleConfigurableDialogComponent } from "./simple-configurable-dialog/simple-configurable-dialog.component";
|
||||
import { SimpleConfigurableDialogComponent } from "./simple-dialog/simple-configurable-dialog/simple-configurable-dialog.component";
|
||||
import { IconDirective, SimpleDialogComponent } from "./simple-dialog/simple-dialog.component";
|
||||
|
||||
@NgModule({
|
||||
@@ -40,11 +38,6 @@ import { IconDirective, SimpleDialogComponent } from "./simple-dialog/simple-dia
|
||||
DialogCloseDirective,
|
||||
IconDirective,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: DialogServiceAbstraction,
|
||||
useClass: DialogService,
|
||||
},
|
||||
],
|
||||
providers: [DialogService],
|
||||
})
|
||||
export class DialogModule {}
|
||||
|
||||
@@ -18,19 +18,15 @@ import {
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
import { filter, firstValueFrom, Subject, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import {
|
||||
DialogServiceAbstraction,
|
||||
SimpleDialogCloseType,
|
||||
} from "@bitwarden/angular/services/dialog";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { SimpleDialogOptions } from "../../../angular/src/services/dialog/simple-dialog-options";
|
||||
|
||||
import { SimpleConfigurableDialogComponent } from "./simple-configurable-dialog/simple-configurable-dialog.component";
|
||||
import { SimpleConfigurableDialogComponent } from "./simple-dialog/simple-configurable-dialog/simple-configurable-dialog.component";
|
||||
import { SimpleDialogOptions, Translation } from "./simple-dialog/types";
|
||||
|
||||
@Injectable()
|
||||
export class DialogService extends Dialog implements OnDestroy, DialogServiceAbstraction {
|
||||
export class DialogService extends Dialog implements OnDestroy {
|
||||
private _destroy$ = new Subject<void>();
|
||||
|
||||
private backDropClasses = ["tw-fixed", "tw-bg-black", "tw-bg-opacity-30", "tw-inset-0"];
|
||||
@@ -46,7 +42,9 @@ export class DialogService extends Dialog implements OnDestroy, DialogServiceAbs
|
||||
|
||||
/** Not in parent class */
|
||||
@Optional() router: Router,
|
||||
@Optional() authService: AuthService
|
||||
@Optional() authService: AuthService,
|
||||
|
||||
protected i18nService: I18nService
|
||||
) {
|
||||
super(_overlay, _injector, _defaultOptions, _parentDialog, _overlayContainer, scrollStrategy);
|
||||
|
||||
@@ -88,12 +86,12 @@ export class DialogService extends Dialog implements OnDestroy, DialogServiceAbs
|
||||
* @returns `boolean` - True if the user accepted the dialog, false otherwise.
|
||||
*/
|
||||
async openSimpleDialog(simpleDialogOptions: SimpleDialogOptions): Promise<boolean> {
|
||||
const dialogRef = this.open(SimpleConfigurableDialogComponent, {
|
||||
const dialogRef = this.open<boolean>(SimpleConfigurableDialogComponent, {
|
||||
data: simpleDialogOptions,
|
||||
disableClose: simpleDialogOptions.disableClose,
|
||||
});
|
||||
|
||||
return (await firstValueFrom(dialogRef.closed)) == SimpleDialogCloseType.ACCEPT;
|
||||
return firstValueFrom(dialogRef.closed);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +103,7 @@ export class DialogService extends Dialog implements OnDestroy, DialogServiceAbs
|
||||
* @param {SimpleDialogOptions} simpleDialogOptions - An object containing options for the dialog.
|
||||
* @returns `DialogRef` - The reference to the opened dialog.
|
||||
* Contains a closed observable which can be subscribed to for determining which button
|
||||
* a user pressed (see `SimpleDialogCloseType`)
|
||||
* a user pressed
|
||||
*/
|
||||
openSimpleDialogRef(simpleDialogOptions: SimpleDialogOptions): DialogRef {
|
||||
return this.open(SimpleConfigurableDialogComponent, {
|
||||
@@ -113,4 +111,21 @@ export class DialogService extends Dialog implements OnDestroy, DialogServiceAbs
|
||||
disableClose: simpleDialogOptions.disableClose,
|
||||
});
|
||||
}
|
||||
|
||||
protected translate(translation: string | Translation, defaultKey?: string): string {
|
||||
if (translation == null && defaultKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (translation == null) {
|
||||
return this.i18nService.t(defaultKey);
|
||||
}
|
||||
|
||||
// Translation interface use implies we must localize.
|
||||
if (typeof translation === "object") {
|
||||
return this.i18nService.t(translation.key, ...(translation.placeholders ?? []));
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from "./dialog.module";
|
||||
export * from "./simple-dialog/types";
|
||||
export * from "./dialog.service";
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
bitButton
|
||||
bitFormButton
|
||||
buttonType="secondary"
|
||||
(click)="dialogRef.close(SimpleDialogCloseType.CANCEL)"
|
||||
(click)="dialogRef.close(false)"
|
||||
>
|
||||
{{ cancelButtonText }}
|
||||
</button>
|
||||
@@ -2,37 +2,30 @@ import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { FormGroup } from "@angular/forms";
|
||||
|
||||
import {
|
||||
SimpleDialogType,
|
||||
SimpleDialogCloseType,
|
||||
Translation,
|
||||
} from "@bitwarden/angular/services/dialog";
|
||||
import { SimpleDialogOptions } from "@bitwarden/angular/services/dialog/simple-dialog-options";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { SimpleDialogOptions, SimpleDialogType, Translation } from "../..";
|
||||
|
||||
const DEFAULT_ICON: Record<SimpleDialogType, string> = {
|
||||
[SimpleDialogType.PRIMARY]: "bwi-business",
|
||||
[SimpleDialogType.SUCCESS]: "bwi-star",
|
||||
[SimpleDialogType.INFO]: "bwi-info-circle",
|
||||
[SimpleDialogType.WARNING]: "bwi-exclamation-triangle",
|
||||
[SimpleDialogType.DANGER]: "bwi-error",
|
||||
primary: "bwi-business",
|
||||
success: "bwi-star",
|
||||
info: "bwi-info-circle",
|
||||
warning: "bwi-exclamation-triangle",
|
||||
danger: "bwi-error",
|
||||
};
|
||||
|
||||
const DEFAULT_COLOR: Record<SimpleDialogType, string> = {
|
||||
[SimpleDialogType.PRIMARY]: "tw-text-primary-500",
|
||||
[SimpleDialogType.SUCCESS]: "tw-text-success",
|
||||
[SimpleDialogType.INFO]: "tw-text-info",
|
||||
[SimpleDialogType.WARNING]: "tw-text-warning",
|
||||
[SimpleDialogType.DANGER]: "tw-text-danger",
|
||||
primary: "tw-text-primary-500",
|
||||
success: "tw-text-success",
|
||||
info: "tw-text-info",
|
||||
warning: "tw-text-warning",
|
||||
danger: "tw-text-danger",
|
||||
};
|
||||
|
||||
@Component({
|
||||
templateUrl: "./simple-configurable-dialog.component.html",
|
||||
})
|
||||
export class SimpleConfigurableDialogComponent {
|
||||
protected SimpleDialogType = SimpleDialogType;
|
||||
protected SimpleDialogCloseType = SimpleDialogCloseType;
|
||||
|
||||
get iconClasses() {
|
||||
return [
|
||||
this.simpleDialogOpts.icon ?? DEFAULT_ICON[this.simpleDialogOpts.type],
|
||||
@@ -61,7 +54,7 @@ export class SimpleConfigurableDialogComponent {
|
||||
await this.simpleDialogOpts.acceptAction();
|
||||
}
|
||||
|
||||
this.dialogRef.close(SimpleDialogCloseType.ACCEPT);
|
||||
this.dialogRef.close(true);
|
||||
};
|
||||
|
||||
private localizeText() {
|
||||
@@ -1,17 +1,13 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular";
|
||||
|
||||
import {
|
||||
SimpleDialogType,
|
||||
SimpleDialogOptions,
|
||||
DialogServiceAbstraction,
|
||||
} from "@bitwarden/angular/services/dialog";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { ButtonModule } from "../../button";
|
||||
import { CalloutModule } from "../../callout";
|
||||
import { I18nMockService } from "../../utils/i18n-mock.service";
|
||||
import { DialogModule } from "../dialog.module";
|
||||
import { SimpleDialogOptions, DialogService } from "../..";
|
||||
import { ButtonModule } from "../../../button";
|
||||
import { CalloutModule } from "../../../callout";
|
||||
import { I18nMockService } from "../../../utils/i18n-mock.service";
|
||||
import { DialogModule } from "../../dialog.module";
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
@@ -41,27 +37,27 @@ class StoryDialogComponent {
|
||||
{
|
||||
title: this.i18nService.t("primaryTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
},
|
||||
{
|
||||
title: this.i18nService.t("successTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.SUCCESS,
|
||||
type: "success",
|
||||
},
|
||||
{
|
||||
title: this.i18nService.t("infoTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.INFO,
|
||||
type: "info",
|
||||
},
|
||||
{
|
||||
title: this.i18nService.t("warningTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.WARNING,
|
||||
type: "warning",
|
||||
},
|
||||
{
|
||||
title: this.i18nService.t("dangerTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.DANGER,
|
||||
type: "danger",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -71,21 +67,21 @@ class StoryDialogComponent {
|
||||
{
|
||||
title: this.i18nService.t("primaryTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
acceptButtonText: "Ok",
|
||||
cancelButtonText: null,
|
||||
},
|
||||
{
|
||||
title: this.i18nService.t("primaryTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
acceptButtonText: this.i18nService.t("accept"),
|
||||
cancelButtonText: this.i18nService.t("decline"),
|
||||
},
|
||||
{
|
||||
title: this.i18nService.t("primaryTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
acceptButtonText: "Ok",
|
||||
},
|
||||
],
|
||||
@@ -96,7 +92,7 @@ class StoryDialogComponent {
|
||||
{
|
||||
title: this.i18nService.t("primaryTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
icon: "bwi-family",
|
||||
},
|
||||
],
|
||||
@@ -107,7 +103,7 @@ class StoryDialogComponent {
|
||||
{
|
||||
title: this.i18nService.t("primaryTypeSimpleDialog"),
|
||||
content: this.i18nService.t("dialogContent"),
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
disableClose: true,
|
||||
},
|
||||
{
|
||||
@@ -116,7 +112,7 @@ class StoryDialogComponent {
|
||||
acceptAction: () => {
|
||||
return new Promise((resolve) => setTimeout(resolve, 10000));
|
||||
},
|
||||
type: SimpleDialogType.PRIMARY,
|
||||
type: "primary",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -126,7 +122,7 @@ class StoryDialogComponent {
|
||||
calloutType = "info";
|
||||
dialogCloseResult: boolean;
|
||||
|
||||
constructor(public dialogService: DialogServiceAbstraction, private i18nService: I18nService) {}
|
||||
constructor(public dialogService: DialogService, private i18nService: I18nService) {}
|
||||
|
||||
async openSimpleConfigurableDialog(opts: SimpleDialogOptions) {
|
||||
this.dialogCloseResult = await this.dialogService.openSimpleDialog(opts);
|
||||
@@ -4,15 +4,15 @@ import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
import { ButtonModule } from "../button";
|
||||
import { IconButtonModule } from "../icon-button";
|
||||
import { SharedModule } from "../shared/shared.module";
|
||||
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||
import { ButtonModule } from "../../button";
|
||||
import { IconButtonModule } from "../../icon-button";
|
||||
import { SharedModule } from "../../shared/shared.module";
|
||||
import { I18nMockService } from "../../utils/i18n-mock.service";
|
||||
import { DialogService } from "../dialog.service";
|
||||
import { DialogCloseDirective } from "../directives/dialog-close.directive";
|
||||
import { DialogTitleContainerDirective } from "../directives/dialog-title-container.directive";
|
||||
|
||||
import { DialogService } from "./dialog.service";
|
||||
import { DialogCloseDirective } from "./directives/dialog-close.directive";
|
||||
import { DialogTitleContainerDirective } from "./directives/dialog-title-container.directive";
|
||||
import { SimpleDialogComponent } from "./simple-dialog/simple-dialog.component";
|
||||
import { SimpleDialogComponent } from "./simple-dialog.component";
|
||||
|
||||
interface Animal {
|
||||
animal: string;
|
||||
61
libs/components/src/dialog/simple-dialog/types.ts
Normal file
61
libs/components/src/dialog/simple-dialog/types.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export interface Translation {
|
||||
key: string;
|
||||
placeholders?: Array<string | number>;
|
||||
}
|
||||
|
||||
// Using type lets devs skip optional params w/out having to pass undefined.
|
||||
/**
|
||||
*
|
||||
* @typedef {Object} SimpleDialogOptions - A configuration type for the Simple Dialog component
|
||||
*/
|
||||
export type SimpleDialogOptions = {
|
||||
/**
|
||||
* Dialog title.
|
||||
*
|
||||
* If not localized, pass in a `Translation`. */
|
||||
title: string | Translation;
|
||||
|
||||
/** Dialog content.
|
||||
*
|
||||
* If not localized, pass in a `Translation`. */
|
||||
content: string | Translation;
|
||||
|
||||
/** Dialog type. It controls default icons and icon colors. */
|
||||
type: SimpleDialogType;
|
||||
|
||||
/** Dialog custom icon class.
|
||||
*
|
||||
* If not provided, a standard icon will be inferred from type.
|
||||
* Note: icon color is enforced based on dialog type. */
|
||||
icon?: string;
|
||||
|
||||
/** Dialog custom accept button text.
|
||||
*
|
||||
* If not provided, ("yes" | i18n) will be used.
|
||||
*
|
||||
* If not localized, pass in a `Translation` */
|
||||
acceptButtonText?: string | Translation;
|
||||
|
||||
/**
|
||||
* Dialog custom cancel button text.
|
||||
*
|
||||
* If not provided, ("no" | i18n) will be used.
|
||||
*
|
||||
* If custom acceptButtonText is passed in, ("cancel" | i18n) will be used.
|
||||
*
|
||||
* If null is provided, the cancel button will be removed.
|
||||
*
|
||||
* If not localized, pass in a `Translation` */
|
||||
cancelButtonText?: string | Translation;
|
||||
|
||||
/** Whether or not the user can use escape or clicking the backdrop to close the dialog */
|
||||
disableClose?: boolean;
|
||||
|
||||
/**
|
||||
* Custom accept action. Runs when the user clicks the accept button and shows a loading spinner until the promise
|
||||
* is resolved.
|
||||
*/
|
||||
acceptAction?: () => Promise<void>;
|
||||
};
|
||||
|
||||
export type SimpleDialogType = "primary" | "success" | "info" | "warning" | "danger";
|
||||
Reference in New Issue
Block a user