diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json
index 9cc3355ec3..528d86e0d1 100644
--- a/packages/frontend-plugin-api/package.json
+++ b/packages/frontend-plugin-api/package.json
@@ -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",
diff --git a/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx b/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx
new file mode 100644
index 0000000000..f9ce9c9809
--- /dev/null
+++ b/packages/frontend-plugin-api/src/components/ErrorBoundary.tsx
@@ -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 (
+
+
+
+ );
+};
+
+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 (
+
+ );
+ }
+
+ return children;
+ }
+}
diff --git a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx
index c6a218c15f..796908c619 100644
--- a/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx
+++ b/packages/frontend-plugin-api/src/components/ExtensionBoundary.tsx
@@ -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 (
+
+ {children}
+
+ );
}
diff --git a/yarn.lock b/yarn.lock
index 1e2f6fdb5d..8999966568 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4246,11 +4246,13 @@ __metadata:
resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api"
dependencies:
"@backstage/cli": "workspace:^"
+ "@backstage/core-components": "workspace:^"
"@backstage/core-plugin-api": "workspace:^"
"@backstage/frontend-app-api": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/types": "workspace:^"
"@backstage/version-bridge": "workspace:^"
+ "@material-ui/core": ^4.12.4
"@testing-library/jest-dom": ^6.0.0
"@testing-library/react": ^14.0.0
"@types/react": ^16.13.1 || ^17.0.0