1
0
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:
Will Martin
2023-08-16 08:26:56 -04:00
committed by GitHub
parent c304b59c3b
commit a4fcd62c99
147 changed files with 448 additions and 758 deletions

View File

@@ -0,0 +1,26 @@
<form [formGroup]="formGroup" [bitSubmit]="accept">
<bit-simple-dialog>
<i bitDialogIcon class="bwi tw-text-3xl" [class]="iconClasses" aria-hidden="true"></i>
<span bitDialogTitle>{{ title }}</span>
<div bitDialogContent>{{ content }}</div>
<ng-container bitDialogFooter>
<button type="submit" bitButton bitFormButton buttonType="primary">
{{ acceptButtonText }}
</button>
<button
*ngIf="showCancelButton"
type="button"
bitButton
bitFormButton
buttonType="secondary"
(click)="dialogRef.close(false)"
>
{{ cancelButtonText }}
</button>
</ng-container>
</bit-simple-dialog>
</form>

View File

@@ -0,0 +1,83 @@
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { FormGroup } from "@angular/forms";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { SimpleDialogOptions, SimpleDialogType, Translation } from "../..";
const DEFAULT_ICON: Record<SimpleDialogType, string> = {
primary: "bwi-business",
success: "bwi-star",
info: "bwi-info-circle",
warning: "bwi-exclamation-triangle",
danger: "bwi-error",
};
const DEFAULT_COLOR: Record<SimpleDialogType, string> = {
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 {
get iconClasses() {
return [
this.simpleDialogOpts.icon ?? DEFAULT_ICON[this.simpleDialogOpts.type],
DEFAULT_COLOR[this.simpleDialogOpts.type],
];
}
protected title: string;
protected content: string;
protected acceptButtonText: string;
protected cancelButtonText: string;
protected formGroup = new FormGroup({});
protected showCancelButton = this.simpleDialogOpts.cancelButtonText !== null;
constructor(
public dialogRef: DialogRef,
private i18nService: I18nService,
@Inject(DIALOG_DATA) public simpleDialogOpts?: SimpleDialogOptions
) {
this.localizeText();
}
protected accept = async () => {
if (this.simpleDialogOpts.acceptAction) {
await this.simpleDialogOpts.acceptAction();
}
this.dialogRef.close(true);
};
private localizeText() {
this.title = this.translate(this.simpleDialogOpts.title);
this.content = this.translate(this.simpleDialogOpts.content);
this.acceptButtonText = this.translate(this.simpleDialogOpts.acceptButtonText, "yes");
if (this.showCancelButton) {
// If accept text is overridden, use cancel, otherwise no
this.cancelButtonText = this.translate(
this.simpleDialogOpts.cancelButtonText,
this.simpleDialogOpts.acceptButtonText !== undefined ? "cancel" : "no"
);
}
}
private translate(translation: string | Translation, defaultKey?: string): string {
// Translation interface use implies we must localize.
if (typeof translation === "object") {
return this.i18nService.t(translation.key, ...(translation.placeholders ?? []));
}
// Use string that is already translated or use default key post translate
return translation ?? this.i18nService.t(defaultKey);
}
}

View File

@@ -0,0 +1,181 @@
import { Component } from "@angular/core";
import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
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: `
<div *ngFor="let group of dialogs">
<h2>{{ group.title }}</h2>
<div class="tw-mb-4 tw-flex tw-flex-row tw-gap-2">
<button
*ngFor="let dialog of group.dialogs"
bitButton
(click)="openSimpleConfigurableDialog(dialog)"
>
{{ dialog.title }}
</button>
</div>
</div>
<bit-callout *ngIf="showCallout" [type]="calloutType" title="Dialog Close Result">
{{ dialogCloseResult }}
</bit-callout>
`,
})
class StoryDialogComponent {
protected dialogs: { title: string; dialogs: SimpleDialogOptions[] }[] = [
{
title: "Regular",
dialogs: [
{
title: this.i18nService.t("primaryTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "primary",
},
{
title: this.i18nService.t("successTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "success",
},
{
title: this.i18nService.t("infoTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "info",
},
{
title: this.i18nService.t("warningTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "warning",
},
{
title: this.i18nService.t("dangerTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "danger",
},
],
},
{
title: "Custom",
dialogs: [
{
title: this.i18nService.t("primaryTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "primary",
acceptButtonText: "Ok",
cancelButtonText: null,
},
{
title: this.i18nService.t("primaryTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "primary",
acceptButtonText: this.i18nService.t("accept"),
cancelButtonText: this.i18nService.t("decline"),
},
{
title: this.i18nService.t("primaryTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "primary",
acceptButtonText: "Ok",
},
],
},
{
title: "Icon",
dialogs: [
{
title: this.i18nService.t("primaryTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "primary",
icon: "bwi-family",
},
],
},
{
title: "Additional",
dialogs: [
{
title: this.i18nService.t("primaryTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
type: "primary",
disableClose: true,
},
{
title: this.i18nService.t("asyncTypeSimpleDialog"),
content: this.i18nService.t("dialogContent"),
acceptAction: () => {
return new Promise((resolve) => setTimeout(resolve, 10000));
},
type: "primary",
},
],
},
];
showCallout = false;
calloutType = "info";
dialogCloseResult: boolean;
constructor(public dialogService: DialogService, private i18nService: I18nService) {}
async openSimpleConfigurableDialog(opts: SimpleDialogOptions) {
this.dialogCloseResult = await this.dialogService.openSimpleDialog(opts);
this.showCallout = true;
if (this.dialogCloseResult) {
this.calloutType = "success";
} else {
this.calloutType = "info";
}
}
}
export default {
title: "Component Library/Dialogs/Service/SimpleConfigurable",
component: StoryDialogComponent,
decorators: [
moduleMetadata({
imports: [ButtonModule, DialogModule, CalloutModule],
}),
applicationConfig({
providers: [
{
provide: I18nService,
useFactory: () => {
return new I18nMockService({
primaryTypeSimpleDialog: "Primary Type Simple Dialog",
successTypeSimpleDialog: "Success Type Simple Dialog",
infoTypeSimpleDialog: "Info Type Simple Dialog",
warningTypeSimpleDialog: "Warning Type Simple Dialog",
dangerTypeSimpleDialog: "Danger Type Simple Dialog",
asyncTypeSimpleDialog: "Async",
dialogContent: "Dialog content goes here",
yes: "Yes",
no: "No",
ok: "Ok",
cancel: "Cancel",
accept: "Accept",
decline: "Decline",
});
},
},
],
}),
],
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library",
},
},
} as Meta;
type Story = StoryObj<StoryDialogComponent>;
export const Default: Story = {};