Skip to content

Commit

Permalink
feat(app): add e-stop screen (#13010)
Browse files Browse the repository at this point in the history
add e-stop screen
  • Loading branch information
koji authored Jul 5, 2023
1 parent fc94a4f commit 8280fb0
Show file tree
Hide file tree
Showing 21 changed files with 176 additions and 30 deletions.
7 changes: 7 additions & 0 deletions app/src/App/OnDeviceDisplayApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { MaintenanceRunTakeover } from '../organisms/TakeoverModal'
import { ConnectViaEthernet } from '../pages/OnDeviceDisplay/ConnectViaEthernet'
import { ConnectViaUSB } from '../pages/OnDeviceDisplay/ConnectViaUSB'
import { ConnectViaWifi } from '../pages/OnDeviceDisplay/ConnectViaWifi'
import { EmergencyStop } from '../pages/EmergencyStop'
import { NameRobot } from '../pages/OnDeviceDisplay/NameRobot'
import { NetworkSetupMenu } from '../pages/OnDeviceDisplay/NetworkSetupMenu'
import { ProtocolSetup } from '../pages/OnDeviceDisplay/ProtocolSetup'
Expand Down Expand Up @@ -172,6 +173,12 @@ export const onDeviceDisplayRoutes: RouteProps[] = [
name: 'Update Robot',
path: '/robot-settings/update-robot',
},
{
Component: EmergencyStop,
exact: true,
name: 'Emergency Stop',
path: '/emergency-stop',
},
{
Component: () => (
<>
Expand Down
11 changes: 11 additions & 0 deletions app/src/App/__tests__/OnDeviceDisplayApp.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { RunSummary } from '../../pages/OnDeviceDisplay/RunSummary'
import { Welcome } from '../../pages/OnDeviceDisplay/Welcome'
import { NameRobot } from '../../pages/OnDeviceDisplay/NameRobot'
import { InitialLoadingScreen } from '../../pages/OnDeviceDisplay/InitialLoadingScreen'
import { EmergencyStop } from '../../pages/EmergencyStop'
import { getOnDeviceDisplaySettings } from '../../redux/config'
import { getIsShellReady } from '../../redux/shell'
import { useCurrentRunRoute, useProtocolReceiptToast } from '../hooks'
Expand All @@ -42,6 +43,7 @@ jest.mock('../../pages/OnDeviceDisplay/RunningProtocol')
jest.mock('../../pages/OnDeviceDisplay/RunSummary')
jest.mock('../../pages/OnDeviceDisplay/NameRobot')
jest.mock('../../pages/OnDeviceDisplay/InitialLoadingScreen')
jest.mock('../../pages/EmergencyStop')
jest.mock('../../redux/config')
jest.mock('../../redux/shell')
jest.mock('../hooks')
Expand Down Expand Up @@ -92,6 +94,9 @@ const mockRunningProtocol = RunningProtocol as jest.MockedFunction<
>
const mockRunSummary = RunSummary as jest.MockedFunction<typeof RunSummary>
const mockNameRobot = NameRobot as jest.MockedFunction<typeof NameRobot>
const mockEmergencyStop = EmergencyStop as jest.MockedFunction<
typeof EmergencyStop
>
const mockGetOnDeviceDisplaySettings = getOnDeviceDisplaySettings as jest.MockedFunction<
typeof getOnDeviceDisplaySettings
>
Expand Down Expand Up @@ -137,6 +142,7 @@ describe('OnDeviceDisplayApp', () => {
mockgetIsShellReady.mockReturnValue(false)
mockNameRobot.mockReturnValue(<div>Mock NameRobot</div>)
mockInitialLoadingScreen.mockReturnValue(<div>Mock Loading</div>)
mockEmergencyStop.mockReturnValue(<div>Mock EmergencyStop</div>)
mockUseCurrentRunRoute.mockReturnValue(null)
})
afterEach(() => {
Expand Down Expand Up @@ -214,6 +220,11 @@ describe('OnDeviceDisplayApp', () => {
mockgetIsShellReady.mockReturnValue(true)
getByText('Mock Loading')
})
it('renders EmergencyStop component from /emergency-stop', () => {
mockUseCurrentRunRoute.mockReturnValue('/emergency-stop')
const [{ getByText }] = render('/emergency-stop')
getByText('Mock EmergencyStop')
})
it('renders protocol receipt toasts', () => {
render('/')
expect(mockUseProtocolReceiptToasts).toHaveBeenCalled()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app/src/assets/localization/en/device_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@
"download": "Download",
"downloading_logs": "Downloading logs...",
"downloading_software": "Downloading software...",
"e_stop_connected": "E-stop successfully connected",
"e_stop_not_connected": "Connect the E-stop to an auxiliary port on the back of the robot.",
"enter_network_name": "Enter network name",
"enter_password": "Enter password",
"ethernet_connection_description": "Connect an Ethernet cable to the back of the robot and a network switch or hub.",
Expand All @@ -110,6 +112,7 @@
"health_check": "Check health",
"hide": "Hide",
"incorrect_password_for_ssid": "Oops! Incorrect password for {{ssid}}",
"install_e_stop": "Install the E-stop",
"installing_software": "Installing software...",
"ip_address": "IP Address",
"join_other_network_error_message": "Must be 2–32 characters long",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ConfirmRobotName({
}
return (
<>
<StepMeter totalSteps={5} currentStep={5} />
<StepMeter totalSteps={6} currentStep={6} />
<Flex
padding={`${SPACING.spacing32} ${SPACING.spacing40} ${SPACING.spacing40}`}
flexDirection={DIRECTION_COLUMN}
Expand Down
2 changes: 1 addition & 1 deletion app/src/organisms/UpdateRobotSoftware/CheckUpdates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function CheckUpdates(): JSX.Element {
height="32.5rem"
borderRadius={BORDERS.borderRadiusSize3}
>
<Icon name="ot-spinner" size="5rem" spin color={COLORS.darkGreyEnabled} />
<Icon name="ot-spinner" size="5rem" spin color={COLORS.darkBlack70} />
<StyledText as="h2" fontWeight={TYPOGRAPHY.fontWeightBold}>
{t('checking_for_updates')}
</StyledText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function ErrorUpdateSoftware({
flex="1"
buttonType="secondary"
buttonText={t('proceed_without_updating')}
onClick={() => history.push('/robot-settings/rename-robot')}
onClick={() => history.push('/emergency-stop')}
/>
<MediumButton
flex="1"
Expand Down
13 changes: 1 addition & 12 deletions app/src/organisms/UpdateRobotSoftware/NoUpdateFound.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { useDispatch } from 'react-redux'
import { useHistory } from 'react-router-dom'

import {
Expand All @@ -17,12 +16,10 @@ import {

import { StyledText } from '../../atoms/text'
import { MediumButton } from '../../atoms/buttons'
import { updateConfigValue } from '../../redux/config'

export function NoUpdateFound(): JSX.Element {
const { i18n, t } = useTranslation(['device_settings', 'shared'])
const history = useHistory()
const dispatch = useDispatch()
return (
<Flex
flexDirection={DIRECTION_COLUMN}
Expand Down Expand Up @@ -51,15 +48,7 @@ export function NoUpdateFound(): JSX.Element {
</Flex>
<MediumButton
buttonText={i18n.format(t('shared:continue'), 'capitalize')}
onClick={() => {
dispatch(
updateConfigValue(
'onDeviceDisplaySettings.unfinishedUnboxingFlowRoute',
'/robot-settings/rename-robot'
)
)
history.push('/robot-settings/rename-robot')
}}
onClick={() => history.push('/emergency-stop')}
/>
</Flex>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('ErrorUpdateSoftware', () => {
it('call mockPush when tapping Proceed without updating', () => {
const [{ getByText }] = render(props)
getByText('Proceed without updating').click()
expect(mockPush).toBeCalledWith('/robot-settings/rename-robot')
expect(mockPush).toBeCalledWith('/emergency-stop')
})

it('call mock function when tapping Try again', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ describe('NoUpdateFound', () => {
it('should call mock function when tapping next button', () => {
const [{ getByText }] = render()
getByText('Continue').click()
expect(mockPush).toBeCalledWith('/robot-settings/rename-robot')
expect(mockPush).toBeCalledWith('/emergency-stop')
})
})
39 changes: 39 additions & 0 deletions app/src/pages/EmergencyStop/__tests__/EmergencyStop.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as React from 'react'

import { renderWithProviders } from '@opentrons/components'

import { i18n } from '../../../i18n'
import { EmergencyStop } from '..'

// const ESTOP_IMAGE_NAME = 'install_e_stop.png'
const mockPush = jest.fn()
jest.mock('react-router-dom', () => {
const reactRouterDom = jest.requireActual('react-router-dom')
return {
...reactRouterDom,
useHistory: () => ({ push: mockPush } as any),
}
})

const render = () => {
return renderWithProviders(<EmergencyStop />, {
i18nInstance: i18n,
})
}

describe('EmergencyStop', () => {
// Note (kk:06/28/2023) commented test cases will be activated when added the function to check e-stop status

it.todo(
'should render text, image, and button when e-stop button is not connected'
)

it('should render text, icon, button when e-stop button is connected', () => {
const [{ getByText, getByTestId, getByRole }] = render()
getByTestId('EmergencyStop_connected_icon')
getByText('E-stop successfully connected')
expect(getByRole('button')).not.toBeDisabled()
})

it.todo('should call a mock function when tapping continue button')
})
99 changes: 99 additions & 0 deletions app/src/pages/EmergencyStop/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { useHistory } from 'react-router-dom'

import {
Icon,
Flex,
SPACING,
COLORS,
BORDERS,
DIRECTION_COLUMN,
JUSTIFY_CENTER,
ALIGN_CENTER,
TYPOGRAPHY,
} from '@opentrons/components'

import { StyledText } from '../../atoms/text'
import { MediumButton } from '../../atoms/buttons'
import { StepMeter } from '../../atoms/StepMeter'

import estopImg from '../../assets/images/on-device-display/install_e_stop.png'

export function EmergencyStop(): JSX.Element {
const { i18n, t } = useTranslation(['device_settings', 'shared'])
const history = useHistory()
// Note (kk:06/28/2023) this IF is for test and it will be removed when the e-stop status check function
// I will add the function soon
const isEstopConnected = true

return (
<>
<StepMeter totalSteps={6} currentStep={4} />
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing32}
paddingX={SPACING.spacing40}
>
<Flex
paddingY={SPACING.spacing32}
justifyContent={JUSTIFY_CENTER}
alignItems={ALIGN_CENTER}
>
<StyledText as="h2" fontWeight={TYPOGRAPHY.fontWeightBold}>
{t('install_e_stop')}
</StyledText>
</Flex>
<Flex
flexDirection={DIRECTION_COLUMN}
padding={`${SPACING.spacing40} ${SPACING.spacing80}`}
backgroundColor={
isEstopConnected ? COLORS.green3 : COLORS.darkBlack20
}
borderRadius={BORDERS.borderRadiusSize3}
alignItems={ALIGN_CENTER}
>
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={isEstopConnected ? SPACING.spacing32 : SPACING.spacing16}
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_CENTER}
height="13.5rem"
>
{isEstopConnected ? (
<>
<Icon
name="ot-check"
size="3rem"
color={COLORS.green2}
data-testid="EmergencyStop_connected_icon"
/>
<StyledText as="h3" fontWeight={TYPOGRAPHY.fontWeightSemiBold}>
{t('e_stop_connected')}
</StyledText>
</>
) : (
<>
<img src={estopImg} height="116px" alt="E-stop button" />
<StyledText
as="h3"
fontWeight={TYPOGRAPHY.fontWeightSemiBold}
color={COLORS.darkBlack70}
textAlign={TYPOGRAPHY.textAlignCenter}
>
{t('e_stop_not_connected')}
</StyledText>
</>
)}
</Flex>
</Flex>
<MediumButton
flex="1"
buttonText={i18n.format(t('shared:continue'), 'capitalize')}
disabled={!isEstopConnected}
onClick={() => history.push('/robot-settings/rename-robot')}
/>
</Flex>
</>
)
}
2 changes: 1 addition & 1 deletion app/src/pages/OnDeviceDisplay/ConnectViaEthernet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function ConnectViaEthernet(): JSX.Element {

return (
<>
<StepMeter totalSteps={5} currentStep={2} />
<StepMeter totalSteps={6} currentStep={2} />
<Flex
margin={`${SPACING.spacing32} ${SPACING.spacing40} ${SPACING.spacing40}`}
flexDirection={DIRECTION_COLUMN}
Expand Down
4 changes: 2 additions & 2 deletions app/src/pages/OnDeviceDisplay/ConnectViaUSB.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ConnectViaUSB(): JSX.Element {

return (
<>
<StepMeter totalSteps={5} currentStep={2} />
<StepMeter totalSteps={6} currentStep={2} />
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing32}
Expand Down Expand Up @@ -98,7 +98,7 @@ export function ConnectViaUSB(): JSX.Element {
</Flex>
<MediumButton
buttonText={i18n.format(t('shared:continue'), 'capitalize')}
onClick={() => history.push('/robot-settings/rename-robot')}
onClick={() => history.push('/emergency-stop')}
/>
</Flex>
) : (
Expand Down
2 changes: 1 addition & 1 deletion app/src/pages/OnDeviceDisplay/ConnectViaWifi/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export function ConnectViaWifi(): JSX.Element {

return (
<>
<StepMeter totalSteps={5} currentStep={2} />
<StepMeter totalSteps={6} currentStep={2} />
<Flex
flexDirection={DIRECTION_COLUMN}
// subtract height of StepMeter
Expand Down
2 changes: 1 addition & 1 deletion app/src/pages/OnDeviceDisplay/NameRobot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export function NameRobot(): JSX.Element {
<ConfirmRobotName robotName={newName} />
) : (
<>
{isInitialSetup ? <StepMeter totalSteps={5} currentStep={4} /> : null}
{isInitialSetup ? <StepMeter totalSteps={6} currentStep={5} /> : null}
<Flex
flexDirection={DIRECTION_COLUMN}
marginTop={SPACING.spacing32}
Expand Down
2 changes: 1 addition & 1 deletion app/src/pages/OnDeviceDisplay/NetworkSetupMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function NetworkSetupMenu(): JSX.Element {

return (
<>
<StepMeter totalSteps={5} currentStep={1} />
<StepMeter totalSteps={6} currentStep={1} />
<Flex
padding={`${SPACING.spacing32} ${SPACING.spacing60} ${SPACING.spacing60}`}
flexDirection={DIRECTION_COLUMN}
Expand Down
2 changes: 1 addition & 1 deletion app/src/pages/OnDeviceDisplay/RobotDashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function RobotDashboard(): JSX.Element {
getOnDeviceDisplaySettings
)
const [showWelcomeModal, setShowWelcomeModal] = React.useState<boolean>(
unfinishedUnboxingFlowRoute === '/robot-settings/rename-robot'
unfinishedUnboxingFlowRoute !== null
)

const recentRunsOfUniqueProtocols = allRuns
Expand Down
6 changes: 2 additions & 4 deletions app/src/pages/OnDeviceDisplay/UpdateRobot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function UpdateRobot(): JSX.Element {
dispatch(
updateConfigValue(
'onDeviceDisplaySettings.unfinishedUnboxingFlowRoute',
'/robot-settings/rename-robot'
'/emergency-stop'
)
)
}
Expand Down Expand Up @@ -113,9 +113,7 @@ export function UpdateRobot(): JSX.Element {
}, [robotUpdateType, dispatch, robotName, isDownloading])

return (
<Flex
padding={`${SPACING.spacing24} ${SPACING.spacing40} ${SPACING.spacing40}`}
>
<Flex padding={SPACING.spacing40}>
{isShowCheckingUpdates ? (
<CheckUpdates />
) : robotUpdateType !== 'upgrade' ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('ConnectViaWifi', () => {
const [{ getByTestId }] = render()
getByTestId('StepMeter_StepMeterContainer')
const bar = getByTestId('StepMeter_StepMeterBar')
expect(bar).toHaveStyle('width: 40%')
expect(bar).toHaveStyle('width: 33.33333333333333%')
})

it('should render Searching for networks', () => {
Expand Down
Loading

0 comments on commit 8280fb0

Please sign in to comment.