diff --git a/src/alerts.ts b/src/alerts.ts new file mode 100644 index 00000000..f05a8134 --- /dev/null +++ b/src/alerts.ts @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2022 The Pybricks Authors + +import { IToastProps } from '@blueprintjs/core'; +import alerts from './alerts/alerts'; +import explorer from './explorer/alerts'; +import { CreateToast } from './i18nToaster'; + +/** This collects alerts from all of the subsystems of the app */ +const alertDomains = { + alerts, + explorer, +}; + +/** Gets the type of available alert domains. */ +export type AlertDomain = keyof typeof alertDomains; + +/** + * Gets the type of available specific alerts for a domain. + * @template D The domain. + */ +export type AlertSpecific = keyof typeof alertDomains[D]; + +/** + * Gets the instance type of the object in the lookup table. + * @template D The domain. + * @template S The specific instance name in the domain. + */ +type AlertInstance< + D extends AlertDomain, + S extends AlertSpecific, +> = typeof alertDomains[D][S] extends CreateToast + ? CreateToast + : never; + +/** + * Gets the type of the `onAlert` callback for a specific instance in the lookup table. + * @template D The domain. + * @template S The specific instance name in the domain. + */ +export type AlertCallback< + D extends AlertDomain, + S extends AlertSpecific, +> = Parameters>[0]; + +/** + * Gets the type of available actions for a specific instance in the lookup table. + * @template D The domain. + * @template S The specific instance name in the domain. + */ +export type AlertActions> = + | Parameters>[0]>[0]; + +/** + * Gets the type of the properties for a specific instance in the lookup table. + * @template D The domain. + * @template S The specific instance name in the domain. + */ +export type AlertProps> = Parameters< + AlertInstance +>[1]; + +/** + * Gets the alert creation function from the lookup table and uses it to create + * a new alert (toast). + * + * @param domain The alert domain (app subsystem). + * @param specific The specific alert for the domain. + * @param onAlert The callback that will be called when the alert is dismissed. + * @param props Any additional properties required by this specific alert. + * @returns The newly created alert properties. + */ +export function getAlertProps>( + domain: D, + specific: S, + onAlert: AlertCallback, + props: AlertProps, +): IToastProps { + const create = alertDomains[domain][specific] as unknown as CreateToast< + Record | never, + string + >; + return create(onAlert, props); +} diff --git a/src/notifications/UnexpectedErrorNotification.scss b/src/alerts/UnexpectedErrorAlert.scss similarity index 86% rename from src/notifications/UnexpectedErrorNotification.scss rename to src/alerts/UnexpectedErrorAlert.scss index 286a790d..b7302997 100644 --- a/src/notifications/UnexpectedErrorNotification.scss +++ b/src/alerts/UnexpectedErrorAlert.scss @@ -3,7 +3,7 @@ @use '@blueprintjs/core/lib/scss/variables' as bp; -pre.pb-notification-stack-trace { +pre.pb-alerts-stack-trace { max-width: bp.$pt-grid-size * 50; max-height: bp.$pt-grid-size * 50; overflow: auto; diff --git a/src/notifications/UnexpectedErrorNotification.tsx b/src/alerts/UnexpectedErrorAlert.tsx similarity index 68% rename from src/notifications/UnexpectedErrorNotification.tsx rename to src/alerts/UnexpectedErrorAlert.tsx index 7880d929..f1938484 100644 --- a/src/notifications/UnexpectedErrorNotification.tsx +++ b/src/alerts/UnexpectedErrorAlert.tsx @@ -1,23 +1,21 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2021-2022 The Pybricks Authors +// Copyright (c) 2022 The Pybricks Authors -// Provides special notification contents for unexpected errors. - -import './UnexpectedErrorNotification.scss'; +import './UnexpectedErrorAlert.scss'; import { AnchorButton, Button, ButtonGroup, Collapse, Intent } from '@blueprintjs/core'; import { useI18n } from '@shopify/react-i18n'; import React, { useState } from 'react'; import { useId } from 'react-aria'; +import { CreateToast } from '../i18nToaster'; import { I18nId } from './i18n'; -type UnexpectedErrorNotificationProps = { - messageId: I18nId; - err: Error; +type UnexpectedErrorAlertProps = { + error: Error; }; -const UnexpectedErrorNotification: React.VoidFunctionComponent< - UnexpectedErrorNotificationProps -> = ({ messageId, err }) => { +const UnexpectedErrorAlert: React.VoidFunctionComponent = ({ + error, +}) => { // istanbul ignore next: babel-loader rewrites this line const [i18n] = useI18n(); const [isExpanded, setIsExpanded] = useState(false); @@ -25,7 +23,7 @@ const UnexpectedErrorNotification: React.VoidFunctionComponent< return ( <> -

{i18n.translate(messageId, { errorMessage: err.message })}

+

{i18n.translate(I18nId.Message, { errorMessage: error.message })}