This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch chore/consolidate-error-boundary in repository https://gitbox.apache.org/repos/asf/superset.git
commit 92d4e16de6134a02e32563c29385dc5b35c26f9b Author: Evan Rusackas <[email protected]> AuthorDate: Fri Feb 6 13:50:30 2026 -0800 chore: consolidate ErrorBoundary to @superset-ui/core This change: - Creates a new ErrorBoundary in @superset-ui/core based on react-error-boundary API - Removes the react-error-boundary npm dependency - Updates all usages to import from @superset-ui/core - Deletes the old src/components/ErrorBoundary directory The new ErrorBoundary supports: - FallbackComponent prop for custom error UI - fallbackRender prop for render function fallback - onError callback for error reporting - resetErrorBoundary for error recovery When no fallback is provided, errors are caught silently (returns null). Co-Authored-By: Claude Opus 4.5 <[email protected]> --- superset-frontend/package-lock.json | 10 --- .../packages/superset-ui-core/package.json | 1 - .../src/chart/components/ErrorBoundary.tsx | 89 ++++++++++++++++++++++ .../src/chart/components/SuperChart.tsx | 2 +- .../packages/superset-ui-core/src/chart/index.ts | 5 ++ .../test/chart/components/SuperChart.test.tsx | 2 +- superset-frontend/src/components/Chart/Chart.tsx | 7 +- .../ErrorBoundary/ErrorBoundary.test.tsx | 63 --------------- .../src/components/ErrorBoundary/index.tsx | 63 --------------- .../src/components/ErrorBoundary/types.ts | 31 -------- superset-frontend/src/components/index.ts | 1 - .../DashboardBuilder/DashboardBuilder.tsx | 3 +- .../nativeFilters/ConfigModal/BaseConfigModal.tsx | 2 +- .../FiltersConfigModal/FiltersConfigModal.tsx | 2 +- superset-frontend/src/embedded/index.tsx | 2 +- .../src/explore/components/Control.tsx | 2 +- .../FilterControl/AdhocFilterEditPopover/index.tsx | 2 +- .../src/extensions/ExtensionsContext.tsx | 2 +- superset-frontend/src/features/home/ChartTable.tsx | 2 +- superset-frontend/src/views/App.tsx | 8 +- 20 files changed, 109 insertions(+), 190 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 1a97f933ab2..d8d810d8c9b 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -49999,15 +49999,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-error-boundary": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-6.1.0.tgz", - "integrity": "sha512-02k9WQ/mUhdbXir0tC1NiMesGzRPaCsJEWU/4bcFrbY1YMZOtHShtZP6zw0SJrBWA/31H0KT9/FgdL8+sPKgHA==", - "license": "MIT", - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0" - } - }, "node_modules/react-google-recaptcha": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", @@ -63712,7 +63703,6 @@ "re-resizable": "^6.11.2", "react-ace": "^14.0.1", "react-draggable": "^4.5.0", - "react-error-boundary": "^6.1.0", "react-js-cron": "^5.2.0", "react-markdown": "^8.0.7", "react-resize-detector": "^7.1.2", diff --git a/superset-frontend/packages/superset-ui-core/package.json b/superset-frontend/packages/superset-ui-core/package.json index c8bc4627b1d..f02d4cbc2e9 100644 --- a/superset-frontend/packages/superset-ui-core/package.json +++ b/superset-frontend/packages/superset-ui-core/package.json @@ -55,7 +55,6 @@ "react-resize-detector": "^7.1.2", "react-syntax-highlighter": "^16.1.0", "react-ultimate-pagination": "^1.3.2", - "react-error-boundary": "^6.1.0", "react-markdown": "^8.0.7", "regenerator-runtime": "^0.14.1", "rehype-raw": "^7.0.0", diff --git a/superset-frontend/packages/superset-ui-core/src/chart/components/ErrorBoundary.tsx b/superset-frontend/packages/superset-ui-core/src/chart/components/ErrorBoundary.tsx new file mode 100644 index 00000000000..a1698eb97dc --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/chart/components/ErrorBoundary.tsx @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 { Component, ComponentType, ErrorInfo, ReactNode } from 'react'; + +export interface FallbackProps { + error: Error; + resetErrorBoundary: () => void; +} + +export interface ErrorBoundaryProps { + children: ReactNode; + FallbackComponent?: ComponentType<FallbackProps>; + fallbackRender?: (props: FallbackProps) => ReactNode; + onError?: (error: Error, info: ErrorInfo) => void; +} + +interface ErrorBoundaryState { + error: Error | null; +} + +/** + * ErrorBoundary component for catching and handling errors in child components. + * Provides FallbackComponent support similar to react-error-boundary. + */ +export class ErrorBoundary extends Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { error: null }; + } + + static getDerivedStateFromError(error: Error): ErrorBoundaryState { + return { error }; + } + + componentDidCatch(error: Error, info: ErrorInfo): void { + this.props.onError?.(error, info); + } + + resetErrorBoundary = (): void => { + this.setState({ error: null }); + }; + + render() { + const { error } = this.state; + const { children, FallbackComponent, fallbackRender } = this.props; + + if (error) { + const fallbackProps: FallbackProps = { + error, + resetErrorBoundary: this.resetErrorBoundary, + }; + + if (fallbackRender) { + return fallbackRender(fallbackProps); + } + + if (FallbackComponent) { + return <FallbackComponent {...fallbackProps} />; + } + + // Default fallback if no FallbackComponent provided + return null; + } + + return children; + } +} + +export default ErrorBoundary; diff --git a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx index 553a98f568a..be0561eea26 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx +++ b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx @@ -29,7 +29,7 @@ import { ErrorBoundary, ErrorBoundaryProps, FallbackProps, -} from 'react-error-boundary'; +} from './ErrorBoundary'; import { ParentSize } from '@visx/responsive'; import { createSelector } from 'reselect'; import { withTheme } from '@emotion/react'; diff --git a/superset-frontend/packages/superset-ui-core/src/chart/index.ts b/superset-frontend/packages/superset-ui-core/src/chart/index.ts index 69081f9740d..edfd1e57f39 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/chart/index.ts @@ -26,6 +26,11 @@ export { ChartProps }; export type { ChartPropsConfig }; export { default as createLoadableRenderer } from './components/createLoadableRenderer'; +export { + ErrorBoundary, + type ErrorBoundaryProps, + type FallbackProps, +} from './components/ErrorBoundary'; export { default as reactify } from './components/reactify'; export { default as SuperChart } from './components/SuperChart'; diff --git a/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChart.test.tsx b/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChart.test.tsx index a739748d2ee..9f647320588 100644 --- a/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChart.test.tsx +++ b/superset-frontend/packages/superset-ui-core/test/chart/components/SuperChart.test.tsx @@ -21,7 +21,7 @@ import '@testing-library/jest-dom'; import { render, screen } from '@superset-ui/core/spec'; import mockConsole, { RestoreConsole } from 'jest-mock-console'; import { triggerResizeObserver } from 'resize-observer-polyfill'; -import { ErrorBoundary } from 'react-error-boundary'; +import { ErrorBoundary } from '../../../src/chart/components/ErrorBoundary'; import { promiseTimeout, SuperChart } from '@superset-ui/core'; import { WrapperProps } from '../../../src/chart/components/SuperChart'; diff --git a/superset-frontend/src/components/Chart/Chart.tsx b/superset-frontend/src/components/Chart/Chart.tsx index 9a05bb270fb..ad2062e2590 100644 --- a/superset-frontend/src/components/Chart/Chart.tsx +++ b/superset-frontend/src/components/Chart/Chart.tsx @@ -33,7 +33,7 @@ import { styled } from '@apache-superset/core/ui'; import type { ChartState, Datasource, ChartStatus } from 'src/explore/types'; import { PLACEHOLDER_DATASOURCE } from 'src/dashboard/constants'; import { EmptyState, Loading } from '@superset-ui/core/components'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; @@ -396,10 +396,7 @@ class Chart extends PureComponent<ChartProps, {}> { } return ( - <ErrorBoundary - onError={this.handleRenderContainerFailure} - showMessage={false} - > + <ErrorBoundary onError={this.handleRenderContainerFailure}> <Styles data-ui-anchor="chart" className="chart-container" diff --git a/superset-frontend/src/components/ErrorBoundary/ErrorBoundary.test.tsx b/superset-frontend/src/components/ErrorBoundary/ErrorBoundary.test.tsx deleted file mode 100644 index 1b167667a94..00000000000 --- a/superset-frontend/src/components/ErrorBoundary/ErrorBoundary.test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 { ReactElement } from 'react'; -import { render, screen } from 'spec/helpers/testing-library'; -import type { ErrorBoundaryProps } from './types'; -import { ErrorBoundary } from '.'; - -const mockedProps: Partial<ErrorBoundaryProps> = { - children: <span>Error children</span>, - onError: jest.fn(), - showMessage: false, -}; - -const Child = (): ReactElement => { - throw new Error('Thrown error'); -}; - -test('should render', () => { - const { container } = render( - <ErrorBoundary {...mockedProps}> - <Child /> - </ErrorBoundary>, - ); - expect(container).toBeInTheDocument(); -}); - -test('should not render an error message', () => { - render( - <ErrorBoundary {...mockedProps}> - <Child /> - </ErrorBoundary>, - ); - expect(screen.queryByText('Unexpected error')).not.toBeInTheDocument(); -}); - -test('should render an error message', () => { - const messageProps = { - ...mockedProps, - showMessage: true, - }; - render( - <ErrorBoundary {...messageProps}> - <Child /> - </ErrorBoundary>, - ); - expect(screen.getByText('Unexpected error')).toBeInTheDocument(); -}); diff --git a/superset-frontend/src/components/ErrorBoundary/index.tsx b/superset-frontend/src/components/ErrorBoundary/index.tsx deleted file mode 100644 index 8dcef63b406..00000000000 --- a/superset-frontend/src/components/ErrorBoundary/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 { Component, ErrorInfo } from 'react'; -import { t } from '@apache-superset/core'; -import { ErrorAlert } from '../ErrorMessage'; -import type { ErrorBoundaryProps, ErrorBoundaryState } from './types'; - -export class ErrorBoundary extends Component< - ErrorBoundaryProps, - ErrorBoundaryState -> { - static defaultProps: Partial<ErrorBoundaryProps> = { - showMessage: true, - }; - - constructor(props: ErrorBoundaryProps) { - super(props); - this.state = { error: null, info: null }; - } - - componentDidCatch(error: Error, info: ErrorInfo): void { - this.props.onError?.(error, info); - this.setState({ error, info }); - } - - render() { - const { error, info } = this.state; - const { showMessage, className } = this.props; - if (error) { - const firstLine = error.toString().split('\n')[0]; - if (showMessage) { - return ( - <ErrorAlert - errorType={t('Unexpected error')} - message={firstLine} - descriptionDetails={info?.componentStack} - className={className} - /> - ); - } - return null; - } - return this.props.children; - } -} - -export type { ErrorBoundaryProps }; diff --git a/superset-frontend/src/components/ErrorBoundary/types.ts b/superset-frontend/src/components/ErrorBoundary/types.ts deleted file mode 100644 index 48b32124999..00000000000 --- a/superset-frontend/src/components/ErrorBoundary/types.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 type { ErrorInfo, ReactNode } from 'react'; - -export interface ErrorBoundaryProps { - children: ReactNode; - onError?: (error: Error, info: ErrorInfo) => void; - showMessage?: boolean; - className?: string; -} - -export interface ErrorBoundaryState { - error: Error | null; - info: ErrorInfo | null; -} diff --git a/superset-frontend/src/components/index.ts b/superset-frontend/src/components/index.ts index 558f080261f..5aa513020bd 100644 --- a/superset-frontend/src/components/index.ts +++ b/superset-frontend/src/components/index.ts @@ -36,7 +36,6 @@ export { DatabaseSelector, type DatabaseObject } from './DatabaseSelector'; export * from './Datasource'; export * from './ErrorMessage'; export { ImportModal, type ImportModelsModalProps } from './ImportModal'; -export { ErrorBoundary, type ErrorBoundaryProps } from './ErrorBoundary'; export * from './GenericLink'; export { GridTable, type TableProps } from './GridTable'; export * from './Tag'; diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx index e9a04342264..d5c9eb66fd7 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx @@ -24,7 +24,8 @@ import { addAlpha, JsonObject, useElementOnScreen } from '@superset-ui/core'; import { css, styled, useTheme } from '@apache-superset/core/ui'; import { useDispatch, useSelector } from 'react-redux'; import { EmptyState, Loading } from '@superset-ui/core/components'; -import { ErrorBoundary, BasicErrorAlert } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; +import { BasicErrorAlert } from 'src/components'; import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane'; import DashboardHeader from 'src/dashboard/components/Header'; import { Icons } from '@superset-ui/core/components/Icons'; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/ConfigModal/BaseConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/ConfigModal/BaseConfigModal.tsx index e2b915ea1e0..72cf16de09a 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/ConfigModal/BaseConfigModal.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/ConfigModal/BaseConfigModal.tsx @@ -18,7 +18,7 @@ */ import { ReactNode, useState, useCallback } from 'react'; import type { FormInstance } from '@superset-ui/core/components'; -import { ErrorBoundary } from 'src/components/ErrorBoundary'; +import { ErrorBoundary } from '@superset-ui/core'; import { BaseModalBody, BaseForm, BaseModalWrapper } from './SharedStyles'; import { ModalFooter } from './ModalFooter'; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx index 659f0154c87..bb3e813eb72 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx @@ -22,7 +22,7 @@ import { t } from '@apache-superset/core'; import { ChartCustomizationType, NativeFilterType } from '@superset-ui/core'; import { styled, css, useTheme } from '@apache-superset/core/ui'; import { Constants, Form, Icons, Flex } from '@superset-ui/core/components'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { testWithId } from 'src/utils/testUtils'; import useEffectEvent from 'src/hooks/useEffectEvent'; import { diff --git a/superset-frontend/src/embedded/index.tsx b/superset-frontend/src/embedded/index.tsx index 305b254e314..86cf89346e3 100644 --- a/superset-frontend/src/embedded/index.tsx +++ b/superset-frontend/src/embedded/index.tsx @@ -32,7 +32,7 @@ import setupPlugins from 'src/setup/setupPlugins'; import { useUiConfig } from 'src/components/UiConfigContext'; import { store, USER_LOADED } from 'src/views/store'; import { Loading } from '@superset-ui/core/components'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { addDangerToast } from 'src/components/MessageToasts/actions'; import ToastContainer from 'src/components/MessageToasts/ToastContainer'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; diff --git a/superset-frontend/src/explore/components/Control.tsx b/superset-frontend/src/explore/components/Control.tsx index f6eed7623f4..bbec4c1e686 100644 --- a/superset-frontend/src/explore/components/Control.tsx +++ b/superset-frontend/src/explore/components/Control.tsx @@ -24,7 +24,7 @@ import { } from '@superset-ui/chart-controls'; import { JsonValue, QueryFormData, usePrevious } from '@superset-ui/core'; import { styled } from '@apache-superset/core/ui'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { ExploreActions } from 'src/explore/actions/exploreActions'; import controlMap from './controls'; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.tsx index 1456543505e..8d03b3b1e1d 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.tsx @@ -20,7 +20,7 @@ import type React from 'react'; import { createRef, Component, type RefObject } from 'react'; import type { SupersetTheme } from '@apache-superset/core/ui'; import { Button, Icons, Select } from '@superset-ui/core/components'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { SupersetClient } from '@superset-ui/core'; import { t } from '@apache-superset/core'; import { styled } from '@apache-superset/core/ui'; diff --git a/superset-frontend/src/extensions/ExtensionsContext.tsx b/superset-frontend/src/extensions/ExtensionsContext.tsx index dadea48fe23..a7c645c896c 100644 --- a/superset-frontend/src/extensions/ExtensionsContext.tsx +++ b/superset-frontend/src/extensions/ExtensionsContext.tsx @@ -24,7 +24,7 @@ import { useEffect, useMemo, } from 'react'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { setExtensionsContextValue } from './ExtensionsContextUtils'; import ExtensionPlaceholder from './ExtensionPlaceholder'; diff --git a/superset-frontend/src/features/home/ChartTable.tsx b/superset-frontend/src/features/home/ChartTable.tsx index 9da1e91962a..c4435075ab2 100644 --- a/superset-frontend/src/features/home/ChartTable.tsx +++ b/superset-frontend/src/features/home/ChartTable.tsx @@ -43,7 +43,7 @@ import ChartCard from 'src/features/charts/ChartCard'; import Chart from 'src/types/Chart'; import handleResourceExport from 'src/utils/export'; import { Loading } from '@superset-ui/core/components'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import { Icons } from '@superset-ui/core/components/Icons'; import { navigateTo } from 'src/utils/navigationUtils'; import EmptyState from './EmptyState'; diff --git a/superset-frontend/src/views/App.tsx b/superset-frontend/src/views/App.tsx index 87df93f8b28..d5732d7cdab 100644 --- a/superset-frontend/src/views/App.tsx +++ b/superset-frontend/src/views/App.tsx @@ -27,7 +27,7 @@ import { bindActionCreators } from 'redux'; import { css } from '@apache-superset/core/ui'; import { Layout, Loading } from '@superset-ui/core/components'; import { setupAGGridModules } from '@superset-ui/core/components/ThemedAgGridReact'; -import { ErrorBoundary } from 'src/components'; +import { ErrorBoundary } from '@superset-ui/core'; import Menu from 'src/features/home/Menu'; import getBootstrapData, { applicationRoot } from 'src/utils/getBootstrapData'; import ToastContainer from 'src/components/MessageToasts/ToastContainer'; @@ -91,11 +91,7 @@ const App = () => ( flex-direction: column; `} > - <ErrorBoundary - css={css` - margin: 16px; - `} - > + <ErrorBoundary> <Component user={bootstrapData.user} {...props} /> </ErrorBoundary> </Layout.Content>
