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:
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 = {};
|
||||
Reference in New Issue
Block a user