Files
grafana/public/app/features/plugins/extensions/ExtensionErrorBoundary.tsx
Levente Balogh 77f84e494d Plugin Extensions: Add error boundaries (#107515)
* feat(grafana-data): expose PluginContext

This is aimed to be used in the `PluginErrorBoundary` (which is a class component, and cannot use the hook.)

* feat(PluginErrorBoundary): add an error boundary for plugins

* feat(ExtensionsErrorBoundary): add an error boundary for extensions)

* feat(Extensions/Utils): wrap components with error boundaries

* feat(Plugins): wrap root plugin page with an error boundary

* fix: Fallback component should always be visible for onClick() modals

* review: use object arguments instead of positional ones for `renderWithPluginContext()`

* review: update `wrapWithPluginContext()` to receive args as an object

* refactor(AppChromeExtensionPoint): remove the error boundary

We have an error boundary on the extensions-framework level now

* refactor(ExtensionSidebar): remove the ErrorBoundary from the extensions

This is handled on the extensions-framework level now.

* test(ExtensionSidebar): add tests

* chore: translation extraction

* chore: prettier formatting

* fix(PluginErrorBoundary): remove unnecessary type casting
2025-07-07 14:51:04 +02:00

43 lines
1.1 KiB
TypeScript

import * as React from 'react';
import { PluginErrorBoundary } from '../components/PluginErrorBoundary';
import { ExtensionErrorAlert } from './ExtensionErrorAlert';
import { ExtensionsLog, log as baseLog } from './logs/log';
import { isGrafanaDevMode } from './utils';
export const ExtensionErrorBoundary = ({
children,
pluginId,
extensionTitle,
log = baseLog,
fallbackAlwaysVisible = false,
}: {
children: React.ReactNode;
pluginId: string;
extensionTitle: string;
log?: ExtensionsLog;
fallbackAlwaysVisible?: boolean;
}) => {
return (
<PluginErrorBoundary
onError={(error, errorInfo) => {
log.error(`Extension "${pluginId}/${extensionTitle}" failed to load.`, {
message: error.message,
componentStack: errorInfo.componentStack ?? '',
digest: errorInfo.digest ?? '',
});
}}
fallback={() => {
if (isGrafanaDevMode() || fallbackAlwaysVisible) {
return <ExtensionErrorAlert pluginId={pluginId} extensionTitle={extensionTitle} />;
}
return null;
}}
>
{children}
</PluginErrorBoundary>
);
};