Revision 9889fa14
Added by Ron Lavi almost 3 years ago
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
Fixes #33026, #30865 - Add React error boundary