Use modal as default fallback
This commit is contained in:
parent
a197b887fb
commit
b34a9880f7
@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { SidePanel } from '@ohif/ui';
|
||||
import { SidePanel, ErrorBoundary } from '@ohif/ui';
|
||||
import Header from './Header.jsx';
|
||||
import NestedMenu from './ToolbarButtonNestedMenu.jsx';
|
||||
|
||||
@ -93,27 +92,28 @@ function ViewerLayout({
|
||||
return (
|
||||
<div>
|
||||
<Header>
|
||||
<div className="relative flex justify-center">
|
||||
{toolbars.primary.map(toolDef => {
|
||||
const isNested = Array.isArray(toolDef);
|
||||
|
||||
if (!isNested) {
|
||||
const { id, Component, componentProps } = toolDef;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
} else {
|
||||
return (
|
||||
<NestedMenu isActive={activeTool.isActive} icon={activeTool.icon} label={activeTool.label}>
|
||||
<div className="flex">
|
||||
{toolDef.map(x => {
|
||||
const { id, Component, componentProps } = x;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
})}
|
||||
</div>
|
||||
</NestedMenu>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
<ErrorBoundary context="Primary Toolbar">
|
||||
<div className="relative flex justify-center">
|
||||
{toolbars.primary.map(toolDef => {
|
||||
const isNested = Array.isArray(toolDef);
|
||||
if (!isNested) {
|
||||
const { id, Component, componentProps } = toolDef;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
} else {
|
||||
return (
|
||||
<NestedMenu isActive={activeTool.isActive} icon={activeTool.icon} label={activeTool.label}>
|
||||
<div className="flex">
|
||||
{toolDef.map(x => {
|
||||
const { id, Component, componentProps } = x;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
})}
|
||||
</div>
|
||||
</NestedMenu>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
</Header>
|
||||
<div
|
||||
className="flex flex-row flex-no-wrap items-stretch w-full overflow-hidden"
|
||||
@ -121,36 +121,43 @@ function ViewerLayout({
|
||||
>
|
||||
{/* LEFT SIDEPANELS */}
|
||||
{leftPanelComponents.length && (
|
||||
<SidePanel
|
||||
side="left"
|
||||
defaultComponentOpen={leftPanelComponents[0].name}
|
||||
childComponents={leftPanelComponents}
|
||||
/>
|
||||
<ErrorBoundary context="Left Panel">
|
||||
<SidePanel
|
||||
side="left"
|
||||
defaultComponentOpen={leftPanelComponents[0].name}
|
||||
childComponents={leftPanelComponents}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
{/* TOOLBAR + GRID */}
|
||||
<div className="flex flex-col flex-1 h-full">
|
||||
<div className="flex h-12 border-b border-transparent flex-2 w-100">
|
||||
<div className="flex items-center w-full px-3 bg-primary-dark">
|
||||
{toolbars.secondary.map(toolDef => {
|
||||
const { id, Component, componentProps } = toolDef;
|
||||
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
})}
|
||||
</div>
|
||||
<ErrorBoundary context="Secondary Toolbar">
|
||||
<div className="flex items-center w-full px-3 bg-primary-dark">
|
||||
{toolbars.secondary.map(toolDef => {
|
||||
const { id, Component, componentProps } = toolDef;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
})}
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
<div className="flex items-center justify-center flex-1 h-full pt-1 pb-2 overflow-hidden bg-black">
|
||||
<ViewportGridComp
|
||||
servicesManager={servicesManager}
|
||||
viewportComponents={viewportComponents}
|
||||
/>
|
||||
<ErrorBoundary context="Grid">
|
||||
<ViewportGridComp
|
||||
servicesManager={servicesManager}
|
||||
viewportComponents={viewportComponents}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</div>
|
||||
{rightPanelComponents.length && (
|
||||
<SidePanel
|
||||
side="right"
|
||||
defaultComponentOpen={rightPanelComponents[0].name}
|
||||
childComponents={rightPanelComponents}
|
||||
/>
|
||||
<ErrorBoundary context="Right Panel">
|
||||
<SidePanel
|
||||
side="right"
|
||||
defaultComponentOpen={rightPanelComponents[0].name}
|
||||
childComponents={rightPanelComponents}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,46 +1,86 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary';
|
||||
import PropTypes from 'prop-types';
|
||||
import './ErrorFallback.css';
|
||||
import Modal from '../Modal';
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const ErrorFallback = ({ error, componentStack, resetErrorBoundary }) => {
|
||||
const DefaultFallback = ({ error, componentStack, context, resetErrorBoundary, fallbackRoute }) => {
|
||||
const title = `Something went wrong${!isProduction && ` in ${context}`}.`;
|
||||
const subtitle = `Sorry, something went wrong there. Try again.`;
|
||||
return (
|
||||
<div className="ErrorFallback" role="alert">
|
||||
<p>Something went wrong.</p>
|
||||
{isProduction && (
|
||||
<span>Sorry, something went wrong there. Try again.</span>
|
||||
<div className="ErrorFallback bg-primary-dark w-full h-full" role="alert">
|
||||
<p className="text-primary-light text-xl">{title}</p>
|
||||
<p className="text-primary-light text-base">{subtitle}</p>
|
||||
{!isProduction && (
|
||||
<div className="rounded-md bg-secondary-dark p-5 mt-5">
|
||||
<pre className="text-primary-light">Context: {context}</pre>
|
||||
<pre className="text-primary-light">Error Message: {error.message}</pre>
|
||||
<pre className="text-primary-light">Stack: {componentStack}</pre>
|
||||
</div>
|
||||
)}
|
||||
{!isProduction && <pre>{error.message}</pre>}
|
||||
{!isProduction && <pre>{componentStack}</pre>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ErrorFallback.propTypes = {
|
||||
resetErrorBoundary: PropTypes
|
||||
const noop = () => { };
|
||||
|
||||
DefaultFallback.propTypes = {
|
||||
error: PropTypes.object.isRequired,
|
||||
resetErrorBoundary: PropTypes.func,
|
||||
componentStack: PropTypes.string,
|
||||
};
|
||||
|
||||
DefaultFallback.defaultProps = {
|
||||
resetErrorBoundary: noop
|
||||
};
|
||||
|
||||
const ErrorBoundary = ({
|
||||
context = 'RCT',
|
||||
onReset = () => { },
|
||||
onError = () => { },
|
||||
fallbackComponent,
|
||||
children
|
||||
context,
|
||||
onReset,
|
||||
onError,
|
||||
fallbackComponent: FallbackComponent,
|
||||
children,
|
||||
fallbackRoute,
|
||||
isPage
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
|
||||
const onErrorHandler = (error, componentStack) => {
|
||||
console.error(`${context} Error Boundary`, error, componentStack);
|
||||
onError(error, componentStack);
|
||||
console.error(`${context} Error Boundary`, error, componentStack, context);
|
||||
onError(error, componentStack, context);
|
||||
};
|
||||
|
||||
const onResetHandler = () => {
|
||||
onReset();
|
||||
};
|
||||
const onResetHandler = (...args) => onReset(...args);
|
||||
|
||||
const withModal = (Component) => props => (
|
||||
<Modal
|
||||
closeButton
|
||||
shouldCloseOnEsc
|
||||
isOpen={isOpen}
|
||||
title={'Something went wrong'}
|
||||
onClose={() => {
|
||||
setIsOpen(false);
|
||||
if (fallbackRoute) {
|
||||
window.location = fallbackRoute;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Component {...props} />
|
||||
</Modal>
|
||||
);
|
||||
|
||||
const Fallback = isPage ? FallbackComponent : withModal(FallbackComponent);
|
||||
|
||||
return (
|
||||
<ReactErrorBoundary
|
||||
FallbackComponent={fallbackComponent || ErrorFallback}
|
||||
fallbackRender={props => (
|
||||
<Fallback
|
||||
{...props}
|
||||
context={context}
|
||||
fallbackRoute={fallbackRoute}
|
||||
/>
|
||||
)}
|
||||
onReset={onResetHandler}
|
||||
onError={onErrorHandler}
|
||||
>
|
||||
@ -49,4 +89,21 @@ const ErrorBoundary = ({
|
||||
);
|
||||
};
|
||||
|
||||
ErrorBoundary.propTypes = {
|
||||
context: PropTypes.string,
|
||||
onReset: PropTypes.func,
|
||||
onError: PropTypes.func,
|
||||
fallbackComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
||||
children: PropTypes.node.isRequired,
|
||||
fallbackRoute: PropTypes.string
|
||||
};
|
||||
|
||||
ErrorBoundary.defaultProps = {
|
||||
context: 'OHIF',
|
||||
onReset: noop,
|
||||
onError: noop,
|
||||
fallbackComponent: DefaultFallback,
|
||||
fallbackRoute: null
|
||||
};
|
||||
|
||||
export default ErrorBoundary;
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
.ErrorFallback {
|
||||
padding: 10px;
|
||||
|
||||
&,
|
||||
pre {
|
||||
color: #7cc5e9;
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: black;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
@ -136,7 +136,7 @@ const ViewportActionBar = ({
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex ml-4 mr-2 cursor-pointer" onClick={onPatientInfoClick}>
|
||||
<div className="flex ml-4 mr-2" onClick={onPatientInfoClick}>
|
||||
<PatientInfo
|
||||
isOpen={showPatientInfo}
|
||||
patientName={patientName}
|
||||
@ -245,7 +245,7 @@ function PatientInfo({
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
<div className="relative flex justify-end">
|
||||
<div className="relative flex justify-end cursor-pointer">
|
||||
<div className="relative">
|
||||
<Icon name="profile" className="w-5 text-white" />
|
||||
<Icon
|
||||
|
||||
@ -5,6 +5,7 @@ import DataSourceWrapper from './DataSourceWrapper';
|
||||
import WorkList from './WorkList';
|
||||
import NotFound from './NotFound';
|
||||
import buildModeRoutes from './buildModeRoutes';
|
||||
import { ErrorBoundary } from '@ohif/ui';
|
||||
|
||||
// TODO: Make these configurable
|
||||
// TODO: Include "routes" debug route if dev build
|
||||
@ -43,6 +44,7 @@ const createRoutes = (
|
||||
return (
|
||||
<Switch>
|
||||
{allRoutes.map((route, i) => {
|
||||
console.log(route);
|
||||
return (
|
||||
<Route
|
||||
key={i}
|
||||
@ -51,7 +53,9 @@ const createRoutes = (
|
||||
strict={route.strict}
|
||||
render={props => (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<route.component {...props} {...route.props} route={route} />
|
||||
<ErrorBoundary context={`Route ${route.path}`} fallbackRoute="/">
|
||||
<route.component {...props} {...route.props} route={route} />
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user