Skip to content

Commit

Permalink
[EuiProviders] Warn Developer if EuiProvider is missing (#184608)
Browse files Browse the repository at this point in the history
## Summary

Addresses elastic/kibana-team#805

## Rollout plan

These steps will graduate toward a consistency of Dark Mode theming (and
I18n, and Analytics for Error Boundaries) by ensuring that EUI
components are always rendered with `KibanaRenderContextProvider`
wrapping the root of the rendering tree.

**The final behavior:** in Dev mode when KibanaRenderContextProvider is
missing, developers will see a console.error and a toast Error message.
In CI environments, the error scenario will cause the EUI components to
fail with an error and developers will have to address the issue with a
fix by viewing the test logs.

1. **[Done]** Initial error behavior: throw error if EUI Provider is
missing in a Draft PR. In CI of that Draft PR, EUI components will fail
to render and show an error.
1. SharedUX team (@tsullivan) implements the fixes using separate PRs
2. **[In this PR]** Soften the error behavior and take effect only in
Dev mode
    1. Use console.error to give an error message and a stack trace
    2. Show an Error toast to convey the error message to Developers
3. **[Not Started]** ~~After running in a mode of step 2 for a length of
time, we add restrictions to CI environments with the final error
behavior.~~ Update the navigation methods of the common page objects for
functional tests, to detect when the toast message appears during
functional testing, and throw a helpful error.

## Notification for developers
Developers would see this error toast with a message telling them they
need to use EuiProvider, plus a link for "more details." They can also
check the JS console to see the error details.

<img width="1798" alt="image"
src="https://github.com/elastic/kibana/assets/908371/061fcec8-4a66-45fd-a77a-c6a2226f7871">

## How this helps
Surfacing these kinds of errors automates the discovery of finding where
dark mode issues exist. Here is an example of a hard-to-find dark mode
issue that was easily caught by the kinds of testing enabled in this PR:

<img width="1436" alt="connection details - before"
src="https://github.com/elastic/kibana/assets/908371/ec6c19b0-5697-41bd-a8eb-935e8388983d">

The way to problems in this nature is to wrap the React context in
`<KibanaRenderContextProvider>`, and setting the required CoreStart
service dependencies of `analytics`, `i18n` and `theme`.
  • Loading branch information
tsullivan authored Jul 23, 2024
1 parent b098522 commit f43b5d5
Showing 1 changed file with 35 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { BehaviorSubject, combineLatest, merge, type Observable, of, ReplaySubject } from 'rxjs';
import { mergeMap, map, takeUntil, filter } from 'rxjs';
import { parse } from 'url';
import { setEuiDevProviderWarning } from '@elastic/eui';
import useObservable from 'react-use/lib/useObservable';

import type { CoreContext } from '@kbn/core-base-browser-internal';
Expand Down Expand Up @@ -173,6 +174,39 @@ export class ChromeService {
this.mutationObserver.observe(body, { attributes: true });
};

// Ensure developers are notified if working in a context that lacks the EUI Provider.
private handleEuiDevProviderWarning = (notifications: NotificationsStart) => {
const isDev = this.params.coreContext.env.mode.name === 'development';
if (isDev) {
setEuiDevProviderWarning((providerError) => {
const errorObject = new Error(providerError.toString());
// show a stack trace in the console
// eslint-disable-next-line no-console
console.error(errorObject);

notifications.toasts.addDanger({
title: '`EuiProvider` is missing',
text: mountReactNode(
<p data-test-sub="core-chrome-euiDevProviderWarning-toast">
<FormattedMessage
id="core.chrome.euiDevProviderWarning"
defaultMessage="Kibana components must be wrapped in a React Context provider for full functionality and proper theming support. See {link}."
values={{
link: (
<a href="https://docs.elastic.dev/kibana-dev-docs/react-context">
https://docs.elastic.dev/kibana-dev-docs/react-context
</a>
),
}}
/>
</p>
),
toastLifeTimeMs: 60 * 60 * 1000, // keep message visible for up to an hour
});
});
}
};

public setup({ analytics }: SetupDeps) {
const docTitle = this.docTitle.setup({ document: window.document });
registerAnalyticsContextProvider(analytics, docTitle.title$);
Expand All @@ -188,6 +222,7 @@ export class ChromeService {
}: StartDeps): Promise<InternalChromeStart> {
this.initVisibility(application);
this.handleEuiFullScreenChanges();
this.handleEuiDevProviderWarning(notifications);

const globalHelpExtensionMenuLinks$ = new BehaviorSubject<ChromeGlobalHelpExtensionMenuLink[]>(
[]
Expand Down

0 comments on commit f43b5d5

Please sign in to comment.