Project

General

Profile

« Previous | Next » 

Revision 9889fa14

Added by Ron Lavi almost 3 years ago

Fixes #33026, #30865 - Add React error boundary

View differences:

webpack/assets/javascripts/react_app/Root/ReactApp.js
import apolloClient from './apollo';
import ToastsList from '../components/ToastsList';
import ErrorBoundary from '../components/common/ErrorBoundary';
const ReactApp = ({ layout, metadata, toasts }) => {
const contextData = { metadata };
......
<ApolloProvider client={apolloClient}>
<ConnectedRouter history={history}>
<Layout data={layout}>
<ToastsList railsMessages={toasts} />
<AppSwitcher />
<ErrorBoundary history={history}>
<ToastsList railsMessages={toasts} />
<AppSwitcher />
</ErrorBoundary>
</Layout>
</ConnectedRouter>
</ApolloProvider>
webpack/assets/javascripts/react_app/components/common/EmptyState/EmptyStatePattern.js
);
};
const EmptyStateIcon = () =>
React.isValidElement(icon) ? (
icon
) : (
<Icon name={icon} type={iconType} size="2x" />
);
return (
<EmptyState variant={EmptyStateVariant.xl}>
<span className="empty-state-icon">
{/* TODO: Add pf4 icons, Redmine issue: #30865 */}
<Icon name={icon} type={iconType} size="2x" />
<EmptyStateIcon />
</span>
<Title headingLevel="h5" size="4xl">
{header}
webpack/assets/javascripts/react_app/components/common/EmptyState/EmptyStatePropTypes.js
};
export const emptyStatePatternPropTypes = {
icon: PropTypes.string,
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
iconType: PropTypes.string,
header: PropTypes.string.isRequired,
documentation: PropTypes.oneOfType([
webpack/assets/javascripts/react_app/components/common/EmptyState/__snapshots__/EmptyState.test.js.snap
<span
className="empty-state-icon"
>
<Icon
name="printer"
size="2x"
type="pf"
/>
<EmptyStateIcon />
</span>
<Title
headingLevel="h5"
webpack/assets/javascripts/react_app/components/common/ErrorBoundary/index.js
import React from 'react';
import PropTypes from 'prop-types';
import { ExclamationCircleIcon } from '@patternfly/react-icons';
import {
ClipboardCopy,
ClipboardCopyVariant,
Grid,
GridItem,
} from '@patternfly/react-core';
import { translate as __ } from '../../../common/I18n';
import EmptyState from '../EmptyState';
import { foremanUrl } from '../../../common/helpers';
import './index.scss';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
props.history.listen(() => {
if (this.state.hasError) {
this.setState({
hasError: false,
});
}
});
}
componentDidCatch(error, info) {
this.setState({ hasError: true, error, info });
}
render() {
const { history, children } = this.props;
const { hasError, error, info } = this.state;
if (!hasError) return children;
const description = (
<>
<p>
{__('There was a problem processing the request. Please try again.')}
</p>
<p
dangerouslySetInnerHTML={{
__html: __(
`To report an issue <a target="_blank" rel="noopener noreferrer" href=${foremanUrl(
'/links/issues'
)}>click here</a>`
),
}}
/>
</>
);
const action = {
title: __('Return to last page'),
onClick: history.goBack,
};
return (
<Grid className="error-boundary-foreman-app">
<GridItem sm={12}>
<EmptyState
icon={<ExclamationCircleIcon />}
header={__('Something went wrong')}
description={description}
action={action}
/>
</GridItem>
<GridItem sm={8} smOffset={2}>
<ClipboardCopy isReadOnly variant={ClipboardCopyVariant.expansion}>
{error.toString()}
{info.componentStack}
</ClipboardCopy>
</GridItem>
</Grid>
);
}
}
ErrorBoundary.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
history: PropTypes.object.isRequired,
};
export default ErrorBoundary;
webpack/assets/javascripts/react_app/components/common/ErrorBoundary/index.scss
.error-boundary-foreman-app {
.empty-state-icon {
color: var(--pf-global--palette--red-200);
}
.pf-c-clipboard-copy__expandable-content {
white-space: pre-wrap;
}
}

Also available in: Unified diff