Skip to content

Commit

Permalink
fix(app): correct visuals for LPC errors (#16091)
Browse files Browse the repository at this point in the history
For reasons I don't understand, the LPC fatal error screen is its own
modal, which maybe used to be good but now looks extremely weird on the
ODD and maybe the app. Maybe because we changed the modal background or
something? I don't know why we didn't see this before.

Anyway, it's gross that it works that way, so just split it into a
contents component and an actual modal component. When we get a fatal
error that's not bad enough to break the JS, we render it as the active
component, and when we hit the (unique?) error boundary, we render it as
a modal.

Closes RQA-2987
  • Loading branch information
sfoster1 authored Aug 22, 2024
1 parent 4267278 commit 411c88a
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 61 deletions.
116 changes: 69 additions & 47 deletions app/src/organisms/LabwarePositionCheck/FatalErrorModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,69 +25,91 @@ import { WizardHeader } from '../../molecules/WizardHeader'
import { i18n } from '../../i18n'

const SUPPORT_EMAIL = '[email protected]'

interface FatalErrorModalProps {
interface FatalErrorProps {
errorMessage: string
shouldUseMetalProbe: boolean
onClose: () => void
}

interface FatalErrorModalProps extends FatalErrorProps {
isOnDevice: boolean
}

export function FatalErrorModal(props: FatalErrorModalProps): JSX.Element {
const { errorMessage, shouldUseMetalProbe, onClose } = props
const { t } = useTranslation(['labware_position_check', 'shared', 'branded'])
const { onClose, isOnDevice } = props
return createPortal(
<LegacyModalShell
width="47rem"
header={
isOnDevice ? (
<LegacyModalShell fullPage>
<WizardHeader
title={t('labware_position_check_title')}
onExit={onClose}
/>
}
>
<Flex
padding={SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_SPACE_BETWEEN}
gridGap={SPACING.spacing16}
<FatalError {...props} />
</LegacyModalShell>
) : (
<LegacyModalShell
width="47rem"
header={
<WizardHeader
title={t('labware_position_check_title')}
onExit={onClose}
/>
}
>
<Icon
name="ot-alert"
size="2.5rem"
color={COLORS.red50}
aria-label="alert"
/>
<ErrorHeader>
{i18n.format(t('shared:something_went_wrong'), 'sentenceCase')}
</ErrorHeader>
{shouldUseMetalProbe ? (
<LegacyStyledText
as="p"
fontWeight={TYPOGRAPHY.fontWeightSemiBold}
textAlign={TEXT_ALIGN_CENTER}
>
{t('remove_probe_before_exit')}
</LegacyStyledText>
) : null}
<LegacyStyledText as="p" textAlign={TEXT_ALIGN_CENTER}>
{t('branded:help_us_improve_send_error_report', {
support_email: SUPPORT_EMAIL,
})}
</LegacyStyledText>
<ErrorTextArea readOnly value={errorMessage ?? ''} spellCheck={false} />
<PrimaryButton
textTransform={TEXT_TRANSFORM_CAPITALIZE}
alignSelf={ALIGN_FLEX_END}
onClick={onClose}
>
{t('shared:exit')}
</PrimaryButton>
</Flex>
</LegacyModalShell>,
<FatalError {...props} />
</LegacyModalShell>
),
getTopPortalEl()
)
}

export function FatalError(props: FatalErrorProps): JSX.Element {
const { errorMessage, shouldUseMetalProbe, onClose } = props
const { t } = useTranslation(['labware_position_check', 'shared', 'branded'])
return (
<Flex
padding={SPACING.spacing32}
flexDirection={DIRECTION_COLUMN}
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_SPACE_BETWEEN}
gridGap={SPACING.spacing16}
>
<Icon
name="ot-alert"
size="2.5rem"
color={COLORS.red50}
aria-label="alert"
/>
<ErrorHeader>
{i18n.format(t('shared:something_went_wrong'), 'sentenceCase')}
</ErrorHeader>
{shouldUseMetalProbe ? (
<LegacyStyledText
as="p"
fontWeight={TYPOGRAPHY.fontWeightSemiBold}
textAlign={TEXT_ALIGN_CENTER}
>
{t('remove_probe_before_exit')}
</LegacyStyledText>
) : null}
<LegacyStyledText as="p" textAlign={TEXT_ALIGN_CENTER}>
{t('branded:help_us_improve_send_error_report', {
support_email: SUPPORT_EMAIL,
})}
</LegacyStyledText>
<ErrorTextArea readOnly value={errorMessage ?? ''} spellCheck={false} />
<PrimaryButton
textTransform={TEXT_TRANSFORM_CAPITALIZE}
alignSelf={ALIGN_FLEX_END}
onClick={onClose}
>
{t('shared:exit')}
</PrimaryButton>
</Flex>
)
}

const ErrorHeader = styled.h1`
text-align: ${TEXT_ALIGN_CENTER};
${TYPOGRAPHY.h1Default}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { PickUpTip } from './PickUpTip'
import { ReturnTip } from './ReturnTip'
import { ResultsSummary } from './ResultsSummary'
import { useChainMaintenanceCommands } from '../../resources/runs'
import { FatalErrorModal } from './FatalErrorModal'
import { FatalError } from './FatalErrorModal'
import { RobotMotionLoader } from './RobotMotionLoader'
import { useNotifyCurrentMaintenanceRun } from '../../resources/maintenance_runs'
import { getLabwarePositionCheckSteps } from './getLabwarePositionCheckSteps'
Expand Down Expand Up @@ -334,10 +334,10 @@ export const LabwarePositionCheckComponent = (
)
} else if (fatalError != null) {
modalContent = (
<FatalErrorModal
<FatalError
errorMessage={fatalError}
shouldUseMetalProbe={shouldUseMetalProbe}
onClose={handleCleanUpAndClose}
onClose={onCloseClick}
/>
)
} else if (showConfirmation) {
Expand Down Expand Up @@ -414,18 +414,12 @@ export const LabwarePositionCheckComponent = (
const wizardHeader = (
<WizardHeader
title={t('labware_position_check_title')}
currentStep={currentStepIndex}
totalSteps={totalStepCount}
currentStep={fatalError != null ? undefined : currentStepIndex}
totalSteps={fatalError != null ? undefined : totalStepCount}
onExit={
showConfirmation || isExiting
showConfirmation || isExiting || fatalError != null
? undefined
: () => {
if (fatalError != null) {
handleCleanUpAndClose()
} else {
confirmExitLPC()
}
}
: confirmExitLPC
}
/>
)
Expand Down
14 changes: 13 additions & 1 deletion app/src/organisms/LabwarePositionCheck/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as React from 'react'
import { useLogger } from '../../logger'
import { LabwarePositionCheckComponent } from './LabwarePositionCheckComponent'
import { FatalErrorModal } from './FatalErrorModal'
import { getIsOnDevice } from '../../redux/config'
import { useSelector } from 'react-redux'

import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data'
import type {
Expand Down Expand Up @@ -31,12 +33,14 @@ export const LabwarePositionCheck = (
props: LabwarePositionCheckModalProps
): JSX.Element => {
const logger = useLogger(new URL('', import.meta.url).pathname)
const isOnDevice = useSelector(getIsOnDevice)
return (
<ErrorBoundary
logger={logger}
ErrorComponent={FatalErrorModal}
shouldUseMetalProbe={props.robotType === FLEX_ROBOT_TYPE}
onClose={props.onCloseClick}
isOnDevice={isOnDevice}
>
<LabwarePositionCheckComponent {...props} />
</ErrorBoundary>
Expand All @@ -52,7 +56,9 @@ interface ErrorBoundaryProps {
errorMessage: string
shouldUseMetalProbe: boolean
onClose: () => void
isOnDevice: boolean
}) => JSX.Element
isOnDevice: boolean
}
class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
Expand All @@ -74,14 +80,20 @@ class ErrorBoundary extends React.Component<
}

render(): ErrorBoundaryProps['children'] | JSX.Element {
const { ErrorComponent, children, shouldUseMetalProbe } = this.props
const {
ErrorComponent,
children,
shouldUseMetalProbe,
isOnDevice,
} = this.props
const { error } = this.state
if (error != null)
return (
<ErrorComponent
errorMessage={error.message}
shouldUseMetalProbe={shouldUseMetalProbe}
onClose={this.props.onClose}
isOnDevice={isOnDevice}
/>
)
// Normally, just render children
Expand Down

0 comments on commit 411c88a

Please sign in to comment.