Merge pull request #9942 from strapi/chore/fix-error-plugins

Improve CM error management
This commit is contained in:
cyril lopez 2021-04-06 09:50:30 +02:00 committed by GitHub
commit 54b51d9d51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 104 additions and 112 deletions

View File

@ -1,49 +0,0 @@
/**
*
* ErrorBoundary
*
*/
import React from 'react';
import PropTypes from 'prop-types';
class ErrorBoundary extends React.Component {
// eslint-disable-line react/prefer-stateless-function
state = { error: null, errorInfo: null };
componentDidCatch(error, errorInfo) {
this.setState({
error,
errorInfo,
});
}
render() {
const { error, errorInfo } = this.state;
if (errorInfo) {
return (
<div style={{ background: '#ffff' }}>
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{error && error.toString()}
<br />
{errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
ErrorBoundary.defaultProps = {
children: null,
};
ErrorBoundary.propTypes = {
children: PropTypes.node,
};
export default ErrorBoundary;

View File

@ -1,22 +0,0 @@
import React from 'react';
import { shallow } from 'enzyme';
import ErrorBoundary from '../index';
describe('<ErrorBoundary />', () => {
it('should not crash', () => {
shallow(<ErrorBoundary />);
});
it('should render its child', () => {
const Child = () => <div>test</div>;
const wrapper = shallow(
<ErrorBoundary>
<Child />
</ErrorBoundary>,
);
expect(wrapper.find(Child)).toHaveLength(1);
});
});

View File

@ -8,12 +8,10 @@ import React, { memo } from 'react';
import PropTypes from 'prop-types';
import { Redirect } from 'react-router-dom';
import { get } from 'lodash';
import { BlockerComponent } from 'strapi-helper-plugin';
import { ErrorBoundary } from 'react-error-boundary';
import { BlockerComponent, ErrorFallback } from 'strapi-helper-plugin';
import PageTitle from '../../components/PageTitle';
import { LOGIN_LOGO } from '../../config';
import ErrorBoundary from '../ErrorBoundary';
export function PluginDispatcher(props) {
const {
@ -46,7 +44,7 @@ export function PluginDispatcher(props) {
return (
<div>
<PageTitle title={`Strapi - ${name}`} />
<ErrorBoundary>
<ErrorBoundary FallbackComponent={ErrorFallback}>
<PluginEntryComponent
{...props}
{...blockerComponentProps}

View File

@ -79,6 +79,7 @@
"react-dnd": "^10.0.2",
"react-dnd-html5-backend": "^10.0.2",
"react-dom": "^16.9.0",
"react-error-boundary": "3.1.1",
"react-fast-compare": "^3.2.0",
"react-helmet": "^6.1.0",
"react-intl": "4.5.0",

View File

@ -27,6 +27,7 @@ const alias = [
'react-dnd',
'react-dnd-html5-backend',
'react-dom',
'react-error-boundary',
'react-fast-compare',
'react-helmet',
'react-is',

View File

@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';
// https://github.com/bvaughn/react-error-boundary#usage
function ErrorFallback({ error }) {
return (
<div style={{ background: '#ffff' }}>
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{error.message}
<br />
{error.stack}
</details>
</div>
);
}
ErrorFallback.defaultProps = {
error: { message: null },
};
ErrorFallback.propTypes = {
error: PropTypes.shape({ message: PropTypes.string }),
};
export default ErrorFallback;

View File

@ -17,6 +17,7 @@ export { default as CircleButton } from './components/CircleButton';
export { default as ContainerFluid } from './components/ContainerFluid';
export { default as ErrorBoundary } from './components/ErrorBoundary';
export { default as ExtendComponent } from './components/ExtendComponent';
export { default as ErrorFallback } from './components/ErrorFallback';
export { default as FilterButton } from './components/FilterButton';
export { default as GlobalPagination } from './components/GlobalPagination';
export { default as HeaderNav } from './components/HeaderNav';

View File

@ -13,6 +13,7 @@ import PropTypes from 'prop-types';
import isEqual from 'react-fast-compare';
import { createDefaultForm, getTrad, removePasswordFieldsFromData } from '../../utils';
import pluginId from '../../pluginId';
import { useFindRedirectionLink } from '../../hooks';
import {
getData,
getDataSucceeded,
@ -23,8 +24,8 @@ import {
submitSucceeded,
} from '../../sharedReducers/crudReducer/actions';
import selectCrudReducer from '../../sharedReducers/crudReducer/selectors';
import { getRedirectionLink, getRequestUrl } from './utils';
import selectMenuLinks from './selectors';
import { getRequestUrl } from './utils';
// This container is used to handle the CRUD
const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }) => {
const { emitEvent } = useGlobalContext();
@ -38,8 +39,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
isLoading,
status,
} = useSelector(selectCrudReducer);
const collectionTypesMenuLinks = useSelector(selectMenuLinks);
const redirectionLink = getRedirectionLink(collectionTypesMenuLinks, slug, rawQuery);
const redirectionLink = useFindRedirectionLink(slug);
const isMounted = useRef(true);
const emitEventRef = useRef(emitEvent);

View File

@ -1,2 +1,2 @@
export { default as getRedirectionLink } from './getRedirectionLink';
// eslint-disable-next-line import/prefer-default-export
export { default as getRequestUrl } from './getRequestUrl';

View File

@ -1,8 +1,9 @@
import React, { memo, useMemo } from 'react';
import { Switch, Route } from 'react-router-dom';
import { ErrorBoundary } from 'react-error-boundary';
import { get } from 'lodash';
import PropTypes from 'prop-types';
import { LoadingIndicatorPage, CheckPagePermissions } from 'strapi-helper-plugin';
import { ErrorFallback, LoadingIndicatorPage, CheckPagePermissions } from 'strapi-helper-plugin';
import pluginPermissions from '../../permissions';
import { ContentTypeLayoutContext } from '../../contexts';
import { useFetchContentTypeLayout } from '../../hooks';
@ -82,31 +83,33 @@ const CollectionTypeRecursivePath = ({
));
return (
<ContentTypeLayoutContext.Provider value={layout}>
<Switch>
<Route path={`${url}/configurations/list`}>
<CheckPagePermissions permissions={pluginPermissions.collectionTypesConfigurations}>
<ListSettingsView
layout={rawContentTypeLayout}
slug={slug}
updateLayout={updateLayout}
/>
</CheckPagePermissions>
</Route>
<Route path={`${url}/configurations/edit`}>
<CheckPagePermissions permissions={pluginPermissions.collectionTypesConfigurations}>
<EditSettingsView
components={rawComponentsLayouts}
isContentTypeView
mainLayout={rawContentTypeLayout}
slug={slug}
updateLayout={updateLayout}
/>
</CheckPagePermissions>
</Route>
{routes}
</Switch>
</ContentTypeLayoutContext.Provider>
<ErrorBoundary FallbackComponent={ErrorFallback}>
<ContentTypeLayoutContext.Provider value={layout}>
<Switch>
<Route path={`${url}/configurations/list`}>
<CheckPagePermissions permissions={pluginPermissions.collectionTypesConfigurations}>
<ListSettingsView
layout={rawContentTypeLayout}
slug={slug}
updateLayout={updateLayout}
/>
</CheckPagePermissions>
</Route>
<Route path={`${url}/configurations/edit`}>
<CheckPagePermissions permissions={pluginPermissions.collectionTypesConfigurations}>
<EditSettingsView
components={rawComponentsLayouts}
isContentTypeView
mainLayout={rawContentTypeLayout}
slug={slug}
updateLayout={updateLayout}
/>
</CheckPagePermissions>
</Route>
{routes}
</Switch>
</ContentTypeLayoutContext.Provider>
</ErrorBoundary>
);
};

View File

@ -10,14 +10,14 @@ import { Flex, Padded } from '@buffetjs/core';
import isEqual from 'react-fast-compare';
import { stringify } from 'qs';
import {
PopUpWarning,
request,
CheckPermissions,
useGlobalContext,
InjectionZone,
InjectionZoneList,
PopUpWarning,
useGlobalContext,
useQueryParams,
useUser,
request,
} from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
import pluginPermissions from '../../permissions';

View File

@ -1,15 +1,25 @@
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom';
import { useQueryParams } from 'strapi-helper-plugin';
import { useFindRedirectionLink } from '../../hooks';
import { resetProps, setLayout } from '../ListView/actions';
import useSyncRbac from '../RBACManager/useSyncRbac';
import Permissions from './Permissions';
const ListViewLayout = ({ layout, ...props }) => {
const dispatch = useDispatch();
const [{ query }] = useQueryParams();
const { replace } = useHistory();
const [{ query, rawQuery }] = useQueryParams();
const permissions = useSyncRbac(query, props.slug, 'listView');
const redirectionLink = useFindRedirectionLink(props.slug);
useEffect(() => {
if (!rawQuery) {
replace(redirectionLink);
}
}, [rawQuery, replace, redirectionLink]);
useEffect(() => {
dispatch(setLayout(layout.contentType));

View File

@ -1,5 +1,6 @@
export { default as useContentTypeLayout } from './useContentTypeLayout';
export { default as useFetchContentTypeLayout } from './useFetchContentTypeLayout';
export { default as useFindRedirectionLink } from './useFindRedirectionLink';
export { default as useLayoutDnd } from './useLayoutDnd';
export { default as useListView } from './useListView';
export { default as useWysiwyg } from './useWysiwyg';

View File

@ -0,0 +1,14 @@
import { useSelector } from 'react-redux';
import { useQueryParams } from 'strapi-helper-plugin';
import selectMenuLinks from './selectors';
import getRedirectionLink from './utils/getRedirectionLink';
const useFindRedirectionLink = slug => {
const [{ rawQuery }] = useQueryParams();
const collectionTypesMenuLinks = useSelector(selectMenuLinks);
const redirectionLink = getRedirectionLink(collectionTypesMenuLinks, slug, rawQuery);
return redirectionLink;
};
export default useFindRedirectionLink;

View File

@ -15,7 +15,7 @@ const VALID_REST_OPERATORS = [
'null',
];
// from strapi-utims/convert-rest-query-params
// from strapi-utils/convert-rest-query-params
const findAppliedFilter = whereClause => {
// Useful to remove the mainField of relation fields.
const formattedWhereClause = whereClause.split('.')[0];

View File

@ -16285,6 +16285,13 @@ react-dom@^16.9.0:
prop-types "^15.6.2"
scheduler "^0.19.1"
react-error-boundary@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.1.tgz#932c5ca5cbab8ec4fe37fd7b415aa5c3a47597e7"
integrity sha512-W3xCd9zXnanqrTUeViceufD3mIW8Ut29BUD+S2f0eO2XCOU8b6UrJfY46RDGe5lxCJzfe4j0yvIfh0RbTZhKJw==
dependencies:
"@babel/runtime" "^7.12.5"
react-fast-compare@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"