feat(frontend-plugin-api): improve extension boundary
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
@@ -37,10 +38,11 @@
|
||||
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@backstage/version-bridge": "workspace:^",
|
||||
"@material-ui/core": "^4.12.4",
|
||||
"@types/react": "^16.13.1 || ^17.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"zod": "^3.21.4",
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Component, PropsWithChildren } from 'react';
|
||||
import { Button } from '@material-ui/core';
|
||||
import { BackstagePlugin } from '../wiring';
|
||||
import { ErrorPanel } from '@backstage/core-components';
|
||||
|
||||
type DefaultErrorBoundaryFallbackProps = PropsWithChildren<{
|
||||
plugin?: BackstagePlugin;
|
||||
error: Error;
|
||||
resetError: () => void;
|
||||
}>;
|
||||
|
||||
const DefaultErrorBoundaryFallback = ({
|
||||
plugin,
|
||||
error,
|
||||
resetError,
|
||||
}: DefaultErrorBoundaryFallbackProps) => {
|
||||
const title = `Error in ${plugin?.id}`;
|
||||
|
||||
return (
|
||||
<ErrorPanel title={title} error={error} defaultExpanded>
|
||||
<Button variant="outlined" onClick={resetError}>
|
||||
Retry
|
||||
</Button>
|
||||
</ErrorPanel>
|
||||
);
|
||||
};
|
||||
|
||||
type ErrorBoundaryProps = PropsWithChildren<{ plugin?: BackstagePlugin }>;
|
||||
type ErrorBoundaryState = { error?: Error };
|
||||
|
||||
/** @internal */
|
||||
export class ErrorBoundary extends Component<
|
||||
ErrorBoundaryProps,
|
||||
ErrorBoundaryState
|
||||
> {
|
||||
static getDerivedStateFromError(error: Error) {
|
||||
return { error };
|
||||
}
|
||||
|
||||
state: ErrorBoundaryState = { error: undefined };
|
||||
|
||||
handleErrorReset = () => {
|
||||
this.setState({ error: undefined });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { error } = this.state;
|
||||
const { plugin, children } = this.props;
|
||||
|
||||
if (error) {
|
||||
// TODO: use a configurable error boundary fallback
|
||||
return (
|
||||
<DefaultErrorBoundaryFallback
|
||||
plugin={plugin}
|
||||
error={error}
|
||||
resetError={this.handleErrorReset}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,35 @@
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { AnalyticsContext } from '@backstage/core-plugin-api';
|
||||
import { BackstagePlugin } from '../wiring';
|
||||
import { RouteRef } from '../routing';
|
||||
import { ErrorBoundary } from './ErrorBoundary';
|
||||
import { toInternalRouteRef } from '../routing/RouteRef';
|
||||
|
||||
/** @public */
|
||||
export interface ExtensionBoundaryProps {
|
||||
children: ReactNode;
|
||||
id: string;
|
||||
source?: BackstagePlugin;
|
||||
routeRef?: RouteRef;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function ExtensionBoundary(props: ExtensionBoundaryProps) {
|
||||
return <>{props.children}</>;
|
||||
const { id, source, routeRef, children } = props;
|
||||
|
||||
const attributes = {
|
||||
extension: id,
|
||||
pluginId: source?.id,
|
||||
routeRef: routeRef
|
||||
? toInternalRouteRef(routeRef).getDescription()
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<ErrorBoundary plugin={source}>
|
||||
<AnalyticsContext attributes={attributes}>{children}</AnalyticsContext>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user