Skip to content

Commit

Permalink
feat(app): add protocol analysis failed modal for RTP (#14705)
Browse files Browse the repository at this point in the history
* feat(app): add protocol analysis failed modal for RTP
  • Loading branch information
koji authored Mar 23, 2024
1 parent 2857419 commit 7b40984
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 1 deletion.
5 changes: 4 additions & 1 deletion app/src/assets/localization/en/protocol_setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@
"reset_setup": "Restart setup to edit",
"reset_values": "Reset values",
"resolve": "Resolve",
"restart_setup_and_try": "Restart setup and try using different parameter values.",
"restart_setup": "Restart setup",
"restore_default": "Restore default values",
"robot_cal_description": "Robot calibration establishes how the robot knows where it is in relation to the deck. Accurate Robot calibration is essential to run protocols successfully. Robot calibration has 3 parts: Deck calibration, Tip Length calibration and Pipette Offset calibration.",
"robot_cal_help_title": "How Robot Calibration Works",
Expand Down Expand Up @@ -265,5 +267,6 @@
"view_setup_instructions": "View setup instructions",
"volume": "Volume",
"what_labware_offset_is": "A Labware Offset is a type of positional adjustment that accounts for small, real-world variances in the overall position of the labware on a robot’s deck. Labware Offset data is unique to a specific combination of labware definition, deck slot, and robot.",
"why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration."
"why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration.",
"with_the_chosen_value": "With the chosen values, the following error occurred:"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react'

import { touchScreenViewport } from '../../DesignTokens/constants'
import { AnalysisFailedModal } from './AnalysisFailedModal'

import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Organisms/AnalysisFailedModal',
component: AnalysisFailedModal,
parameters: touchScreenViewport,
} as Meta

const Template: Story<
React.ComponentProps<typeof AnalysisFailedModal>
> = args => <AnalysisFailedModal {...args} />

export const AnalysisFailed = Template.bind({})
AnalysisFailed.args = {
errors: [
'analysis failed reason message 1',
'analysis failed reason message 2',
],
protocolId: 'mockProtocolId',
setShowAnalysisFailedModal: () => {},
}
77 changes: 77 additions & 0 deletions app/src/organisms/ProtocolSetupParameters/AnalysisFailedModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { useHistory } from 'react-router-dom'
import {
BORDERS,
COLORS,
DIRECTION_COLUMN,
Flex,
SPACING,
} from '@opentrons/components'

import { StyledText } from '../../atoms/text'
import { SmallButton } from '../../atoms/buttons'
import { Modal } from '../../molecules/Modal'

import type { ModalHeaderBaseProps } from '../../molecules/Modal/types'

interface AnalysisFailedModalProps {
errors: string[]
protocolId: string
setShowAnalysisFailedModal: (showAnalysisFailedModal: boolean) => void
}

export function AnalysisFailedModal({
errors,
protocolId,
setShowAnalysisFailedModal,
}: AnalysisFailedModalProps): JSX.Element {
const { t } = useTranslation('protocol_setup')
const history = useHistory()
const modalHeader: ModalHeaderBaseProps = {
title: t('protocol_analysis_failed'),
iconName: 'information',
iconColor: COLORS.black90,
hasExitIcon: true,
}

const handleRestartSetup = (): void => {
history.push(`/protocols/${protocolId}`)
}

return (
<Modal
header={modalHeader}
onOutsideClick={() => setShowAnalysisFailedModal(false)}
>
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing32}
width="100%"
>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing16}>
<StyledText as="p">{t('with_the_chosen_value')}</StyledText>
<Flex
flexDirection={DIRECTION_COLUMN}
borderRadius={BORDERS.borderRadius8}
backgroundColor={COLORS.grey35}
padding={`${SPACING.spacing16} ${SPACING.spacing20}`}
overflowY="auto"
>
{errors.map((error, index) => (
<StyledText key={index} as="p">
{error}
</StyledText>
))}
</Flex>
<StyledText as="p">{t('restart_setup_and_try')}</StyledText>
</Flex>
<SmallButton
onClick={handleRestartSetup}
buttonText={t('restart_setup')}
buttonType="alert"
/>
</Flex>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react'
import { describe, it, vi, beforeEach, expect } from 'vitest'
import { fireEvent, screen } from '@testing-library/react'

import { renderWithProviders } from '../../../__testing-utils__'
import { i18n } from '../../../i18n'
import { AnalysisFailedModal } from '../AnalysisFailedModal'
import type * as ReactRouterDom from 'react-router-dom'

const mockPush = vi.fn()
const PROTOCOL_ID = 'mockId'
const mockSetShowAnalysisFailedModal = vi.fn()

vi.mock('react-router-dom', async importOriginal => {
const reactRouterDom = await importOriginal<typeof ReactRouterDom>()
return {
...reactRouterDom,
useHistory: () => ({ push: mockPush } as any),
}
})

const render = (props: React.ComponentProps<typeof AnalysisFailedModal>) => {
return renderWithProviders(<AnalysisFailedModal {...props} />, {
i18nInstance: i18n,
})
}

describe('AnalysisFailedModal', () => {
let props: React.ComponentProps<typeof AnalysisFailedModal>

beforeEach(() => {
props = {
errors: [
'analysis failed reason message 1',
'analysis failed reason message 2',
],
protocolId: PROTOCOL_ID,
setShowAnalysisFailedModal: mockSetShowAnalysisFailedModal,
}
})

it('should render text and button', () => {
render(props)
screen.getByText('Protocol analysis failed')
screen.getByText('With the chosen values, the following error occurred:')
screen.getByText('analysis failed reason message 1')
screen.getByText('analysis failed reason message 2')
screen.getByText('Restart setup and try using different parameter values.')
screen.getByText('Restart setup')
})

it('should call a mock function when tapping close button', () => {
render(props)
fireEvent.click(screen.getByLabelText('closeIcon'))
expect(mockSetShowAnalysisFailedModal).toHaveBeenCalled()
})

it('should call a mock function when tapping restart setup button', () => {
render(props)
fireEvent.click(screen.getByText('Restart setup'))
expect(mockPush).toHaveBeenCalledWith(`/protocols/${PROTOCOL_ID}`)
})
})

0 comments on commit 7b40984

Please sign in to comment.