Fix theming for error toasts (#160219)

## Summary

Fixes https://github.com/elastic/kibana/issues/159153.

Applies the current theme (dark/light) to error toasts.

Before:


![image](b0a05412-3e07-4980-b3e8-8dcdb602119f)

After:


![image](96bbaf58-25a6-47a3-b9ba-b3caf7a90cd9)
This commit is contained in:
Lukas Olson 2023-06-28 07:58:33 -07:00 committed by GitHub
parent 1a21965403
commit 1223c3f55f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 40 deletions

View file

@ -75,7 +75,8 @@ export class NotificationsService {
title,
error,
openModal: overlays.openModal,
i18nContext: () => i18nDep.Context,
i18n: i18nDep,
theme,
}),
};
}

View file

@ -11,6 +11,8 @@ import React from 'react';
import { mountWithIntl } from '@kbn/test-jest-helpers';
import { ErrorToast } from './error_toast';
import { themeServiceMock } from '@kbn/core-theme-browser-mocks';
import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks';
interface ErrorToastProps {
error?: Error;
@ -19,6 +21,8 @@ interface ErrorToastProps {
}
let openModal: jest.Mock;
const mockTheme = themeServiceMock.createStartContract();
const mockI18n = i18nServiceMock.createStartContract();
beforeEach(() => (openModal = jest.fn()));
@ -29,9 +33,8 @@ function render(props: ErrorToastProps = {}) {
error={props.error || new Error('error message')}
title={props.title || 'An error occured'}
toastMessage={props.toastMessage || 'This is the toast message'}
i18nContext={() =>
({ children }) =>
<React.Fragment>{children}</React.Fragment>}
i18n={mockI18n}
theme={mockTheme}
/>
);
}

View file

@ -22,13 +22,16 @@ import { EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import type { I18nStart } from '@kbn/core-i18n-browser';
import type { OverlayStart } from '@kbn/core-overlays-browser';
import { ThemeServiceStart } from '@kbn/core-theme-browser';
import { CoreContextProvider } from '@kbn/core-theme-browser-internal';
interface ErrorToastProps {
title: string;
error: Error;
toastMessage: string;
openModal: OverlayStart['openModal'];
i18nContext: () => I18nStart['Context'];
i18n: I18nStart;
theme: ThemeServiceStart;
}
interface RequestError extends Error {
@ -52,9 +55,9 @@ export function showErrorDialog({
title,
error,
openModal,
i18nContext,
}: Pick<ErrorToastProps, 'error' | 'title' | 'openModal' | 'i18nContext'>) {
const I18nContext = i18nContext();
i18n,
theme,
}: Pick<ErrorToastProps, 'error' | 'title' | 'openModal' | 'i18n' | 'theme'>) {
let text = '';
if (isRequestError(error)) {
@ -68,32 +71,30 @@ export function showErrorDialog({
const modal = openModal(
mount(
<React.Fragment>
<I18nContext>
<EuiModalHeader>
<EuiModalHeaderTitle>{title}</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody data-test-subj="errorModalBody">
<EuiCallOut size="s" color="danger" iconType="error" title={error.message} />
{text && (
<React.Fragment>
<EuiSpacer size="s" />
<EuiCodeBlock isCopyable={true} paddingSize="s">
{text}
</EuiCodeBlock>
</React.Fragment>
)}
</EuiModalBody>
<EuiModalFooter>
<EuiButton onClick={() => modal.close()} fill>
<FormattedMessage
id="core.notifications.errorToast.closeModal"
defaultMessage="Close"
/>
</EuiButton>
</EuiModalFooter>
</I18nContext>
</React.Fragment>
<CoreContextProvider i18n={i18n} theme={theme}>
<EuiModalHeader>
<EuiModalHeaderTitle>{title}</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody data-test-subj="errorModalBody">
<EuiCallOut size="s" color="danger" iconType="error" title={error.message} />
{text && (
<React.Fragment>
<EuiSpacer size="s" />
<EuiCodeBlock isCopyable={true} paddingSize="s">
{text}
</EuiCodeBlock>
</React.Fragment>
)}
</EuiModalBody>
<EuiModalFooter>
<EuiButton onClick={() => modal.close()} fill>
<FormattedMessage
id="core.notifications.errorToast.closeModal"
defaultMessage="Close"
/>
</EuiButton>
</EuiModalFooter>
</CoreContextProvider>
)
);
}
@ -103,7 +104,8 @@ export function ErrorToast({
error,
toastMessage,
openModal,
i18nContext,
i18n,
theme,
}: ErrorToastProps) {
return (
<React.Fragment>
@ -113,7 +115,7 @@ export function ErrorToast({
size="s"
color="danger"
data-test-subj="errorToastBtn"
onClick={() => showErrorDialog({ title, error, openModal, i18nContext })}
onClick={() => showErrorDialog({ title, error, openModal, i18n, theme })}
>
<FormattedMessage
id="core.toasts.errorToast.seeFullError"

View file

@ -12,6 +12,7 @@ import { ToastsApi } from './toasts_api';
import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks';
import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks';
import { themeServiceMock } from '@kbn/core-theme-browser-mocks';
async function getCurrentToasts(toasts: ToastsApi) {
return await firstValueFrom(toasts.get$());
@ -41,7 +42,11 @@ function toastDeps() {
}
function startDeps() {
return { overlays: {} as any, i18n: i18nServiceMock.createStartContract() };
return {
overlays: {} as any,
i18n: i18nServiceMock.createStartContract(),
theme: themeServiceMock.createStartContract(),
};
}
describe('#get$()', () => {

View file

@ -22,6 +22,7 @@ import type {
ToastInputFields,
ToastOptions,
} from '@kbn/core-notifications-browser';
import { ThemeServiceStart } from '@kbn/core-theme-browser';
import { ErrorToast } from './error_toast';
const normalizeToast = (toastOrTitle: ToastInput): ToastInputFields => {
@ -44,15 +45,25 @@ export class ToastsApi implements IToasts {
private overlays?: OverlayStart;
private i18n?: I18nStart;
private theme?: ThemeServiceStart;
constructor(deps: { uiSettings: IUiSettingsClient }) {
this.uiSettings = deps.uiSettings;
}
/** @internal */
public start({ overlays, i18n }: { overlays: OverlayStart; i18n: I18nStart }) {
public start({
overlays,
i18n,
theme,
}: {
overlays: OverlayStart;
i18n: I18nStart;
theme: ThemeServiceStart;
}) {
this.overlays = overlays;
this.i18n = i18n;
this.theme = theme;
}
/** Observable of the toast messages to show to the user. */
@ -176,7 +187,8 @@ export class ToastsApi implements IToasts {
error={error}
title={options.title}
toastMessage={message}
i18nContext={() => this.i18n!.Context}
i18n={this.i18n!}
theme={this.theme!}
/>
),
...options,

View file

@ -38,7 +38,7 @@ export class ToastsService {
}
public start({ i18n, overlays, theme, targetDomElement }: StartDeps) {
this.api!.start({ overlays, i18n });
this.api!.start({ overlays, i18n, theme });
this.targetDomElement = targetDomElement;
render(