}
diff --git a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx
index 1dbeeca8c6..f8adb81a2a 100644
--- a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx
+++ b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.test.tsx
@@ -17,7 +17,13 @@
import React from 'react';
import { ErrorBoundary } from './ErrorBoundary';
-import { renderInTestApp, withLogCollector } from '@backstage/test-utils';
+import {
+ MockErrorApi,
+ renderInTestApp,
+ withLogCollector,
+} from '@backstage/test-utils';
+import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
+import { errorApiRef } from '@backstage/core-plugin-api';
type BombProps = {
shouldThrow?: boolean;
@@ -35,28 +41,33 @@ const Bomb = ({ shouldThrow }: BombProps) => {
describe('', () => {
it('should render error boundary with and without error', async () => {
const { error } = await withLogCollector(['error'], async () => {
+ const apis = ApiRegistry.with(errorApiRef, new MockErrorApi());
const {
rerender,
queryByRole,
getByRole,
getByText,
} = await renderInTestApp(
-
-
- ,
+
+
+
+
+ ,
);
expect(queryByRole('alert')).not.toBeInTheDocument();
expect(getByText(/working component/i)).toBeInTheDocument();
rerender(
-
-
- ,
+
+
+
+
+ ,
);
expect(getByRole('alert')).toBeInTheDocument();
- expect(getByText(/something went wrong here/i)).toBeInTheDocument();
+ expect(getByText(/something went wrong/i)).toBeInTheDocument();
});
expect(error).toEqual([
diff --git a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx
index 4134808311..b8dfd7ff3a 100644
--- a/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx
+++ b/packages/core-components/src/layout/ErrorBoundary/ErrorBoundary.tsx
@@ -15,9 +15,16 @@
*/
import React, { ComponentClass, Component, ErrorInfo } from 'react';
+import { Button } from '../../components/Button';
+import { ErrorPanel } from '../../components/ErrorPanel';
-type Props = {
- slackChannel?: string;
+type SlackChannel = {
+ name: string;
+ href?: string;
+};
+
+export type ErrorBoundaryProps = {
+ slackChannel?: string | SlackChannel;
onError?: (error: Error, errorInfo: string) => null;
};
@@ -26,28 +33,30 @@ type State = {
errorInfo?: ErrorInfo;
};
-type EProps = {
- error?: Error;
- slackChannel?: string;
- children?: React.ReactNode;
-};
+const SlackLink = (props: { slackChannel?: string | SlackChannel }) => {
+ const { slackChannel } = props;
+
+ if (!slackChannel) {
+ return null;
+ } else if (typeof slackChannel === 'string') {
+ return <>Please contact {slackChannel} for help.>;
+ } else if (!slackChannel.href) {
+ return <>Please contact {slackChannel.name} for help.>;
+ }
-const Error = ({ slackChannel }: EProps) => {
return (
-
- Something went wrong here.{' '}
- {slackChannel && <>Please contact {slackChannel} for help.>}
-
+
);
};
export const ErrorBoundary: ComponentClass<
- Props,
+ ErrorBoundaryProps,
State
-> = class ErrorBoundary extends Component {
- constructor(props: Props) {
+> = class ErrorBoundary extends Component {
+ constructor(props: ErrorBoundaryProps) {
super(props);
-
this.state = {
error: undefined,
errorInfo: undefined,
@@ -61,13 +70,17 @@ export const ErrorBoundary: ComponentClass<
}
render() {
- const { slackChannel } = this.props;
- const { error, errorInfo } = this.state;
+ const { slackChannel, children } = this.props;
+ const { error } = this.state;
- if (!errorInfo) {
- return this.props.children;
+ if (!error) {
+ return children;
}
- return ;
+ return (
+
+
+
+ );
}
};
diff --git a/packages/core-components/src/layout/ErrorBoundary/index.ts b/packages/core-components/src/layout/ErrorBoundary/index.ts
index 47c1b2bace..a0640bd5ef 100644
--- a/packages/core-components/src/layout/ErrorBoundary/index.ts
+++ b/packages/core-components/src/layout/ErrorBoundary/index.ts
@@ -14,4 +14,5 @@
* limitations under the License.
*/
+export type { ErrorBoundaryProps } from './ErrorBoundary';
export { ErrorBoundary } from './ErrorBoundary';
diff --git a/packages/core-components/src/layout/InfoCard/InfoCard.tsx b/packages/core-components/src/layout/InfoCard/InfoCard.tsx
index 9a64bfa6f3..763038388b 100644
--- a/packages/core-components/src/layout/InfoCard/InfoCard.tsx
+++ b/packages/core-components/src/layout/InfoCard/InfoCard.tsx
@@ -26,7 +26,7 @@ import {
makeStyles,
} from '@material-ui/core';
import classNames from 'classnames';
-import { ErrorBoundary } from '../ErrorBoundary';
+import { ErrorBoundary, ErrorBoundaryProps } from '../ErrorBoundary';
import { BottomLink, BottomLinkProps } from '../BottomLink';
const useStyles = makeStyles(theme => ({
@@ -95,8 +95,8 @@ export type InfoCardVariants = 'flex' | 'fullHeight' | 'gridItem';
* You can custom style an InfoCard with the 'style' (outer container) and 'cardStyle' (inner container)
* styles.
*
- * The InfoCard serves as an error boundary. As a result, if you provide a 'slackChannel' property this
- * specifies the channel to display in the error component that is displayed if an error occurs
+ * The InfoCard serves as an error boundary. As a result, if you provide an 'errorBoundaryProps' property this
+ * specifies the extra information to display in the error component that is displayed if an error occurs
* in any descendent components.
*
* By default the InfoCard has no custom layout of its children, but is treated as a block element. A
@@ -112,7 +112,9 @@ type Props = {
subheader?: ReactNode;
divider?: boolean;
deepLink?: BottomLinkProps;
+ /** @deprecated Use errorBoundaryProps instead */
slackChannel?: string;
+ errorBoundaryProps?: ErrorBoundaryProps;
variant?: InfoCardVariants;
style?: object;
cardStyle?: object;
@@ -133,7 +135,8 @@ export const InfoCard = ({
subheader,
divider = true,
deepLink,
- slackChannel = '#backstage',
+ slackChannel,
+ errorBoundaryProps,
variant,
children,
headerStyle,
@@ -169,9 +172,12 @@ export const InfoCard = ({
});
}
+ const errProps: ErrorBoundaryProps =
+ errorBoundaryProps || (slackChannel ? { slackChannel } : {});
+
return (
-
+
{title && (
({
root: {
@@ -52,7 +52,9 @@ const BoldHeader = withStyles(theme => ({
}))(CardHeader);
type Props = {
+ /** @deprecated Use errorBoundaryProps instead */
slackChannel?: string;
+ errorBoundaryProps?: ErrorBoundaryProps;
children?: ReactElement[];
onChange?: (event: React.ChangeEvent<{}>, value: number | string) => void;
title?: string;
@@ -61,7 +63,8 @@ type Props = {
};
const TabbedCard = ({
- slackChannel = '#backstage',
+ slackChannel,
+ errorBoundaryProps,
children,
title,
deepLink,
@@ -87,9 +90,12 @@ const TabbedCard = ({
});
}
+ const errProps: ErrorBoundaryProps =
+ errorBoundaryProps || (slackChannel ? { slackChannel } : {});
+
return (
-
+
{title && }