Skip to content

Commit

Permalink
feat(app): add a few components for deck configuration on ODD (#13688)
Browse files Browse the repository at this point in the history
* feat(app): add a few components for deck configuration on ODD
  • Loading branch information
koji authored Oct 3, 2023
1 parent 8cca3a0 commit 8579809
Show file tree
Hide file tree
Showing 15 changed files with 481 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions app/src/assets/localization/en/device_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"about_module": "About {{name}}",
"about_pipette_name": "About {{name}} Pipette",
"about_pipette": "About pipette",
"add_to_slot_description": "Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.",
"add_to_slot": "Add to slot {{slotName}}",
"add": "Add",
"an_error_occurred_while_updating_module": "An error occurred while updating your {{moduleName}}. Please try again.",
"an_error_occurred_while_updating_please_try_again": "An error occurred while updating your pipette's settings. Please try again.",
Expand All @@ -18,20 +20,27 @@
"calibrate_pipette": "Calibrate pipette",
"calibration_needed": "Calibration needed. <calLink>Calibrate now</calLink>",
"canceled": "canceled",
"changes_will_be_lost_description": "Are you sure you want to exit without saving your deck configuration?",
"changes_will_be_lost": "Changes will be lost",
"choose_protocol_to_run": "Choose protocol to Run on {{name}}",
"close_lid": "Close lid",
"completed": "completed",
"confirm": "Confirm",
"continue_editing": "Continue editing",
"controls": "Controls",
"current_speed": "Current: {{speed}} rpm",
"current_temp": "Current: {{temp}} °C",
"current_version": "Current Version",
"deck_cal_missing": "Pipette Offset calibration missing. Calibrate deck first.",
"deck_configuration": "deck configuration",
"deck_fixture_setup_instructions": "Deck fixture setup instructions",
"deck_fixture_setup_modal_bottom_description": "For detailed instructions for different types of fixtures, scan the QR code or go to the link below.",
"deck_fixture_setup_modal_top_description": "First, unscrew and remove the deck slot where you'll install a fixture. Then put the fixture in place and attach it as needed.",
"deck_slot": "deck slot {{slot}}",
"delete_run": "Delete protocol run record",
"detach_gripper": "Detach gripper",
"detach_pipette": "Detach pipette",
"discard_changes": "Discard changes",
"disengaged": "Disengaged",
"download_run_log": "Download protocol run log",
"empty": "Empty",
Expand Down Expand Up @@ -138,6 +147,7 @@
"set_temperature": "Set temperature",
"shake_speed": "shake speed",
"shaker": "Shaker",
"staging_area_slot": "Staging area slot",
"status": "Status",
"target_speed": "Target: {{speed}} rpm",
"target_temp": "Target: {{temp}} °C",
Expand All @@ -152,6 +162,7 @@
"this_robot_will_restart_with_update": "<block>This robot has to restart to update its software. Restarting will immediately stop the current run or calibration.</block><block>Do you want to update now anyway?</block>",
"tip_pickup_drop": "Tip Pickup / Drop",
"to_run_protocol_go_to_protocols_page": "To run a protocol on this robot, import a protocol on the <navlink>Protocols page</navlink>",
"trash": "Trash",
"update_now": "Update now",
"updating_firmware": "Updating firmware...",
"usb_port_not_connected": "usb not connected",
Expand All @@ -160,6 +171,7 @@
"view_pipette_setting": "Pipette Settings",
"view_run_record": "View protocol run record",
"view": "View",
"waste_chute": "Waste chute",
"welcome_modal_description": "A place to run protocols, manage your instruments, and view robot status.",
"welcome_to_your_dashboard": "Welcome to your dashboard!",
"yes_update_now": "Yes, update now"
Expand Down
1 change: 1 addition & 0 deletions app/src/assets/localization/en/devices_landing.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"connect_to_network": "Connect to network",
"connection_troubleshooting_intro": "If you’re having trouble with the robot’s connection, try these troubleshooting tasks. First, double check that the robot is powered on.",
"contact_support_for_connection_help": "If none of these work, contact Opentrons Support for help (via the question mark link in this app, or by emailing {{support_email}}.)",
"deck_configuration": "Deck configuration",
"devices": "Devices",
"disconnect_from_network": "Disconnect from network",
"empty": "Empty",
Expand Down
2 changes: 1 addition & 1 deletion app/src/atoms/MenuList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const MenuList = (props: MenuListProps): JSX.Element | null => {
return isOnDevice && onClick != null ? (
<LegacyModalShell
borderRadius={BORDERS.borderRadiusSize4}
width="19.625rem"
width="21.875rem"
onOutsideClick={onClick}
>
<Flex
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react'
import { touchScreenViewport } from '../../DesignTokens/constants'
import { AddDeckConfigurationModal } from './AddDeckConfigurationModal'
import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Organisms/AddDeckConfigurationModal',
argTypes: {
modalSize: {
options: ['small', 'medium', 'large'],
control: { type: 'radio' },
},
onOutsideClick: { action: 'clicked' },
},
parameters: touchScreenViewport,
} as Meta

const Template: Story<
React.ComponentProps<typeof AddDeckConfigurationModal>
> = args => <AddDeckConfigurationModal {...args} />
export const Default = Template.bind({})
Default.args = {
slotName: 'D3',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { css } from 'styled-components'
import {
ALIGN_CENTER,
BORDERS,
Btn,
COLORS,
DIRECTION_COLUMN,
DIRECTION_ROW,
Flex,
JUSTIFY_SPACE_BETWEEN,
SPACING,
TYPOGRAPHY,
} from '@opentrons/components'

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

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

interface AddDeckConfigurationModalProps {
slotName: string
}

// ToDo (kk:09/29/2023)
// update this component when Deck configuration component is ready
// Need to use getFixtureDisplayName
export function AddDeckConfigurationModal({
slotName,
}: AddDeckConfigurationModalProps): JSX.Element {
const { t } = useTranslation('device_details')

const modalHeader: ModalHeaderBaseProps = {
title: t('add_to_slot', { slotName: slotName }),
hasExitIcon: true,
}

return (
<Modal header={modalHeader}>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing32}>
<StyledText as="p">{t('add_to_slot_description')}</StyledText>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing8}>
<AddFixtureButton fixtureLoadName={t('staging_area_slot')} />
<AddFixtureButton fixtureLoadName={t('trash')} />
<AddFixtureButton fixtureLoadName={t('waste_chute')} />
</Flex>
</Flex>
</Modal>
)
}

interface AddFixtureButtonProps {
fixtureLoadName: string
}
function AddFixtureButton({
fixtureLoadName,
}: AddFixtureButtonProps): JSX.Element {
const { t } = useTranslation('device_details')

// ToDo (kk:10/02/2023)
// Need to update a function for onClick
return (
<Btn
onClick={() => {}}
display="flex"
justifyContent={JUSTIFY_SPACE_BETWEEN}
flexDirection={DIRECTION_ROW}
alignItems={ALIGN_CENTER}
padding={`${SPACING.spacing16} ${SPACING.spacing24}`}
css={FIXTIRE_BUTTON_STYLE}
>
<StyledText as="p" fontWeight={TYPOGRAPHY.fontWeightSemiBold}>
{fixtureLoadName}
</StyledText>
<StyledText as="p">{t('add')}</StyledText>
</Btn>
)
}

const FIXTIRE_BUTTON_STYLE = css`
background-color: ${COLORS.light1};
cursor: default;
border-radius: ${BORDERS.borderRadiusSize3};
box-shadow: none;
&:focus {
background-color: ${COLORS.light1Pressed};
box-shadow: none;
}
&:hover {
border: none;
box-shadow: none;
background-color: ${COLORS.light1};
}
&:focus-visible {
box-shadow: ${ODD_FOCUS_VISIBLE};
background-color: ${COLORS.light1};
}
&:active {
background-color: ${COLORS.light1Pressed};
}
&:disabled {
background-color: ${COLORS.light1};
color: ${COLORS.darkBlack60};
}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react'
import { touchScreenViewport } from '../../DesignTokens/constants'
import { DeckConfigurationDiscardChangesModal } from './DeckConfigurationDiscardChangesModal'
import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Organisms/DeckConfigurationDiscardChangesModalProps',
argTypes: {
modalSize: {
options: ['small', 'medium', 'large'],
control: { type: 'radio' },
},
onOutsideClick: { action: 'clicked' },
},
parameters: touchScreenViewport,
} as Meta

const Template: Story<
React.ComponentProps<typeof DeckConfigurationDiscardChangesModal>
> = args => <DeckConfigurationDiscardChangesModal {...args} />
export const Default = Template.bind({})
Default.args = {
setShowConfirmationModal: () => {},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import {
DIRECTION_COLUMN,
DIRECTION_ROW,
Flex,
SPACING,
} from '@opentrons/components'

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

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

interface DeckConfigurationDiscardChangesModalProps {
setShowConfirmationModal: (showConfirmationModal: boolean) => void
}

export function DeckConfigurationDiscardChangesModal({
setShowConfirmationModal,
}: DeckConfigurationDiscardChangesModalProps): JSX.Element {
const { t } = useTranslation('device_details')
const modalHeader: ModalHeaderBaseProps = {
title: t('changes_will_be_lost'),
}

const handleDiscard = (): void => {
// ToDo (kk: 09/29/2023) discard deck configuration changes
setShowConfirmationModal(false)
// close the modal and then back the previous screen
}

return (
<Modal header={modalHeader}>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing32}>
<StyledText as="p">{t('changes_will_be_lost_description')}</StyledText>
<Flex
width="100%"
flexDirection={DIRECTION_ROW}
gridGap={SPACING.spacing8}
>
<SmallButton
width="100%"
buttonType="alert"
buttonText={t('discard_changes')}
onClick={handleDiscard}
/>
<SmallButton
width="100%"
buttonText={t('continue_editing')}
onClick={() => setShowConfirmationModal(false)}
/>
</Flex>
</Flex>
</Modal>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react'
import { touchScreenViewport } from '../../DesignTokens/constants'
import { DeckFixtureSetupInstructionModal } from './DeckFixtureSetupInstructionModal'
import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Organisms/DeckFixtureSetupInstructionModal',
argTypes: {
modalSize: {
options: ['small', 'medium', 'large'],
control: { type: 'radio' },
},
onOutsideClick: { action: 'clicked' },
},
parameters: touchScreenViewport,
} as Meta

const Template: Story<
React.ComponentProps<typeof DeckFixtureSetupInstructionModal>
> = args => <DeckFixtureSetupInstructionModal {...args} />
export const Default = Template.bind({})
Default.args = {
setShowSetupInstructionsModal: () => {},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import {
BORDERS,
COLORS,
DIRECTION_COLUMN,
DIRECTION_ROW,
Flex,
SPACING,
TYPOGRAPHY,
} from '@opentrons/components'
import { StyledText } from '../../atoms/text'
import { Modal } from '../../molecules/Modal'

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

import imgSrc from '../../assets/images/on-device-display/deck_fixture_setup.png'

const SETUP_INSTRUCTION_URL = 'www.opentrons.com/support/fixtures'
const IMG_ALT = 'QRCode for Deck fixture setup instructions page'

interface DeckFixtureSetupInstructionModalProps {
setShowSetupInstructionsModal: (showSetupInstructionsModal: boolean) => void
}

export function DeckFixtureSetupInstructionModal({
setShowSetupInstructionsModal,
}: DeckFixtureSetupInstructionModalProps): JSX.Element {
const { t } = useTranslation('device_details')
const modalHeader: ModalHeaderBaseProps = {
title: t('deck_fixture_setup_instructions'),
iconName: 'information',
iconColor: COLORS.darkBlack100,
hasExitIcon: true,
}

return (
<Modal
header={modalHeader}
onOutsideClick={() => setShowSetupInstructionsModal(false)}
>
<Flex flexDirection={DIRECTION_ROW} gridGap={SPACING.spacing40}>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing24}>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing12}>
<StyledText as="p">
{t('deck_fixture_setup_modal_top_description')}
</StyledText>
<StyledText as="p">
{t('deck_fixture_setup_modal_bottom_description')}
</StyledText>
</Flex>
<Flex
padding={`${SPACING.spacing16} ${SPACING.spacing24}`}
backgroundColor={COLORS.light1}
borderRadius={BORDERS.borderRadiusSize3}
>
<StyledText as="p" fontWeight={TYPOGRAPHY.fontWeightSemiBold}>
{SETUP_INSTRUCTION_URL}
</StyledText>
</Flex>
</Flex>
<Flex>
<img src={imgSrc} alt={IMG_ALT} width="178px" height="178px" />
</Flex>
</Flex>
</Modal>
)
}
Loading

0 comments on commit 8579809

Please sign in to comment.