mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 22:02:36 +08:00

* 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
50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import * as React from 'react';
|
|
|
|
import { PluginContext } from '@grafana/data';
|
|
|
|
interface PluginErrorBoundaryProps {
|
|
children: React.ReactNode;
|
|
fallback?: React.ComponentType<{ error: Error | null; errorInfo: React.ErrorInfo | null }>;
|
|
onError?: (error: Error, info: React.ErrorInfo) => void;
|
|
}
|
|
|
|
interface PluginErrorBoundaryState {
|
|
hasError: boolean;
|
|
error: Error | null;
|
|
errorInfo: React.ErrorInfo | null;
|
|
}
|
|
|
|
export class PluginErrorBoundary extends React.Component<PluginErrorBoundaryProps, PluginErrorBoundaryState> {
|
|
static contextType = PluginContext;
|
|
|
|
declare context: React.ContextType<typeof PluginContext>;
|
|
|
|
constructor(props: PluginErrorBoundaryProps) {
|
|
super(props);
|
|
this.state = { hasError: false, error: null, errorInfo: null };
|
|
}
|
|
|
|
static getDerivedStateFromError(error: Error): PluginErrorBoundaryState {
|
|
return { hasError: true, error: error, errorInfo: null };
|
|
}
|
|
|
|
componentDidCatch(error: Error, info: React.ErrorInfo) {
|
|
if (this.props.onError) {
|
|
this.props.onError(error, info);
|
|
} else {
|
|
console.error(`Plugin "${this.context?.meta.id}" failed to load:`, error, info);
|
|
}
|
|
|
|
this.setState({ error, errorInfo: info });
|
|
}
|
|
|
|
render() {
|
|
const Fallback = this.props.fallback;
|
|
if (this.state.hasError) {
|
|
return Fallback ? <Fallback error={this.state.error} errorInfo={this.state.errorInfo} /> : null;
|
|
}
|
|
|
|
return this.props.children;
|
|
}
|
|
}
|