diff --git a/components/src/atoms/ListItem/ListItemChildren/ListItemCustomize.tsx b/components/src/atoms/ListItem/ListItemChildren/ListItemCustomize.tsx
index 9a2482d3f00..b329b2fdc78 100644
--- a/components/src/atoms/ListItem/ListItemChildren/ListItemCustomize.tsx
+++ b/components/src/atoms/ListItem/ListItemChildren/ListItemCustomize.tsx
@@ -1,4 +1,5 @@
import * as React from 'react'
+import { css } from 'styled-components'
import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../../styles'
import { COLORS } from '../../../helix-design-system'
import { Flex, Link } from '../../../primitives'
@@ -53,13 +54,20 @@ export function ListItemCustomize(props: ListItemCustomizeProps): JSX.Element {
{tag != null ? : null}
{onClick != null && linkText != null ? (
-
-
-
- {linkText}
-
-
-
+
+ {linkText}
+
) : null}
)
diff --git a/protocol-designer/src/NavigationBar.tsx b/protocol-designer/src/NavigationBar.tsx
index 9ce09424a54..cecddf6d0c1 100644
--- a/protocol-designer/src/NavigationBar.tsx
+++ b/protocol-designer/src/NavigationBar.tsx
@@ -1,11 +1,12 @@
import * as React from 'react'
-import { NavLink, useLocation } from 'react-router-dom'
+import { useLocation, useNavigate } from 'react-router-dom'
import styled from 'styled-components'
-import { useDispatch } from 'react-redux'
+import { useDispatch, useSelector } from 'react-redux'
import { useTranslation } from 'react-i18next'
import {
ALIGN_CENTER,
+ Btn,
COLORS,
DIRECTION_COLUMN,
Flex,
@@ -13,17 +14,33 @@ import {
SPACING,
StyledText,
} from '@opentrons/components'
+import { toggleNewProtocolModal } from './navigation/actions'
import { actions as loadFileActions } from './load-file'
+import { BUTTON_LINK_STYLE } from './atoms'
+import { getHasUnsavedChanges } from './load-file/selectors'
import type { ThunkDispatch } from './types'
export function NavigationBar(): JSX.Element | null {
- const { t } = useTranslation('shared')
+ const { t } = useTranslation(['shared', 'alert'])
const location = useLocation()
+ const navigate = useNavigate()
const dispatch: ThunkDispatch = useDispatch()
const loadFile = (
fileChangeEvent: React.ChangeEvent
): void => {
dispatch(loadFileActions.loadProtocolFile(fileChangeEvent))
+ dispatch(toggleNewProtocolModal(false))
+ }
+ const hasUnsavedChanges = useSelector(getHasUnsavedChanges)
+
+ const handleCreateNew = (): void => {
+ if (
+ !hasUnsavedChanges ||
+ window.confirm(t('alert:confirm_create_new') as string)
+ ) {
+ dispatch(toggleNewProtocolModal(true))
+ navigate('/createNew')
+ }
}
return location.pathname === '/designer' ||
@@ -46,16 +63,18 @@ export function NavigationBar(): JSX.Element | null {
{location.pathname === '/createNew' ? null : (
-
+
- {t('create_new_protocol')}
+ {t('create_new')}
-
+
)}
-
- {t('import')}
-
+
+
+ {t('import')}
+
+
@@ -64,15 +83,6 @@ export function NavigationBar(): JSX.Element | null {
)
}
-const NavbarLink = styled(NavLink)`
- color: ${COLORS.black90};
- text-decoration: none;
- align-self: ${ALIGN_CENTER};
- &:hover {
- color: ${COLORS.black70};
- }
-`
-
const StyledLabel = styled.label`
height: 20px;
cursor: pointer;
diff --git a/protocol-designer/src/__tests__/NavigationBar.test.tsx b/protocol-designer/src/__tests__/NavigationBar.test.tsx
index 86bbe715623..1bd852474e8 100644
--- a/protocol-designer/src/__tests__/NavigationBar.test.tsx
+++ b/protocol-designer/src/__tests__/NavigationBar.test.tsx
@@ -1,14 +1,17 @@
import * as React from 'react'
-import { describe, it, vi } from 'vitest'
-import { screen } from '@testing-library/react'
+import { describe, it, vi, beforeEach, expect } from 'vitest'
+import { fireEvent, screen } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'
import { i18n } from '../assets/localization'
import { renderWithProviders } from '../__testing-utils__'
import { NavigationBar } from '../NavigationBar'
+import { getHasUnsavedChanges } from '../load-file/selectors'
+import { toggleNewProtocolModal } from '../navigation/actions'
+vi.mock('../navigation/actions')
vi.mock('../file-data/selectors')
-
+vi.mock('../load-file/selectors')
const render = () => {
return renderWithProviders(
@@ -19,19 +22,23 @@ const render = () => {
}
describe('NavigationBar', () => {
+ beforeEach(() => {
+ vi.mocked(getHasUnsavedChanges).mockReturnValue(false)
+ })
it('should render text and link button', () => {
render()
screen.getByText('Opentrons')
screen.getByText('Protocol Designer')
screen.getByText('Version # fake_PD_version')
- screen.getByText('Create new protocol')
+ screen.getByText('Create new')
screen.getByText('Import')
})
- it.todo(
- 'when clicking Create new protocol, mock function should be called',
- () => {}
- )
+ it('when clicking Create new, should call the toggle action', () => {
+ render()
+ fireEvent.click(screen.getByText('Create new'))
+ expect(vi.mocked(toggleNewProtocolModal)).toHaveBeenCalled()
+ })
it.todo('when clicking Import, mock function should be called', () => {})
})
diff --git a/protocol-designer/src/assets/localization/en/shared.json b/protocol-designer/src/assets/localization/en/shared.json
index c96a789d594..77be26bec0f 100644
--- a/protocol-designer/src/assets/localization/en/shared.json
+++ b/protocol-designer/src/assets/localization/en/shared.json
@@ -8,7 +8,7 @@
"confirm_reorder": "Are you sure you want to reorder these steps, it may cause errors?",
"confirm": "Confirm",
"create_a_protocol": "Create a protocol",
- "create_new_protocol": "Create new protocol",
+ "create_new": "Create new",
"done": "Done",
"edit_existing": "Edit existing protocol",
"edit": "edit",
diff --git a/protocol-designer/src/atoms/constants.ts b/protocol-designer/src/atoms/constants.ts
new file mode 100644
index 00000000000..e5c73333cd8
--- /dev/null
+++ b/protocol-designer/src/atoms/constants.ts
@@ -0,0 +1,9 @@
+import { css } from 'styled-components'
+import { COLORS } from '@opentrons/components'
+
+export const BUTTON_LINK_STYLE = css`
+ color: ${COLORS.grey60};
+ &:hover {
+ color: ${COLORS.grey40};
+ }
+`
diff --git a/protocol-designer/src/atoms/index.ts b/protocol-designer/src/atoms/index.ts
index f8f44e7744b..f87cf0102a1 100644
--- a/protocol-designer/src/atoms/index.ts
+++ b/protocol-designer/src/atoms/index.ts
@@ -1 +1 @@
-console.log('atoms for new components')
+export * from './constants'
diff --git a/protocol-designer/src/organisms/PipetteInfoItem/index.tsx b/protocol-designer/src/organisms/PipetteInfoItem/index.tsx
index c376f0f7777..4628fc7481b 100644
--- a/protocol-designer/src/organisms/PipetteInfoItem/index.tsx
+++ b/protocol-designer/src/organisms/PipetteInfoItem/index.tsx
@@ -13,6 +13,7 @@ import {
TYPOGRAPHY,
} from '@opentrons/components'
import { getPipetteSpecsV2 } from '@opentrons/shared-data'
+import { BUTTON_LINK_STYLE } from '../../atoms'
import { getLabwareDefsByURI } from '../../labware-defs/selectors'
import type { PipetteMount, PipetteName } from '@opentrons/shared-data'
import type { FormPipettesByMount, PipetteOnDeck } from '../../step-forms'
@@ -79,6 +80,7 @@ export function PipetteInfoItem(props: PipetteInfoItemProps): JSX.Element {
{t('edit')}
@@ -92,6 +94,7 @@ export function PipetteInfoItem(props: PipetteInfoItemProps): JSX.Element {
cleanForm()
}}
textDecoration={TYPOGRAPHY.textDecorationUnderline}
+ css={BUTTON_LINK_STYLE}
>
{t('remove')}
diff --git a/protocol-designer/src/organisms/SlotInformation/index.tsx b/protocol-designer/src/organisms/SlotInformation/index.tsx
index b2e785b0af1..c01c1266cc5 100644
--- a/protocol-designer/src/organisms/SlotInformation/index.tsx
+++ b/protocol-designer/src/organisms/SlotInformation/index.tsx
@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
import { useLocation } from 'react-router-dom'
import {
ALIGN_CENTER,
- Box,
DeckInfoLabel,
DIRECTION_COLUMN,
Flex,
@@ -83,7 +82,11 @@ interface StackInfoListProps {
function StackInfoList({ title, items }: StackInfoListProps): JSX.Element {
const pathLocation = useLocation()
return (
-
+
{items.length > 0 ? (
items.map((item, index) => (
)}
-
+
)
}
diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx
index fa3a7f1dc10..5ed48732bc0 100644
--- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx
+++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx
@@ -30,8 +30,8 @@ import { getLabwareDefsByURI } from '../../labware-defs/selectors'
import { setFeatureFlags } from '../../feature-flags/actions'
import { createCustomTiprackDef } from '../../labware-defs/actions'
import { useKitchen } from '../../organisms/Kitchen/hooks'
-import { IncompatibleTipsModal } from '../../organisms'
-import { PipetteInfoItem } from '../../organisms/'
+import { IncompatibleTipsModal, PipetteInfoItem } from '../../organisms'
+import { BUTTON_LINK_STYLE } from '../../atoms'
import { WizardBody } from './WizardBody'
import { PIPETTE_GENS, PIPETTE_TYPES, PIPETTE_VOLUMES } from './constants'
import { getTiprackOptions } from './utils'
@@ -373,6 +373,7 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null {
{has96Channel ? null : (
{
const leftPipetteName = pipettesByMount.left.pipetteName
const rightPipetteName = pipettesByMount.right.pipetteName
diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx
index acfdbfcd992..498a9392685 100644
--- a/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx
+++ b/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx
@@ -15,6 +15,7 @@ import {
JUSTIFY_SPACE_BETWEEN,
} from '@opentrons/components'
import temporaryImg from '../../assets/images/placeholder_image_delete.png'
+import { BUTTON_LINK_STYLE } from '../../atoms'
interface WizardBodyProps {
stepNumber: number
@@ -83,11 +84,8 @@ export function WizardBody(props: WizardBodyProps): JSX.Element {
justifyContent={JUSTIFY_SPACE_BETWEEN}
>
{goBack != null ? (
-
-
+
+
{t('go_back')}
diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/CreateNewProtocol.test.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/CreateNewProtocol.test.tsx
deleted file mode 100644
index 8ca87d9d825..00000000000
--- a/protocol-designer/src/pages/CreateNewProtocolWizard/__tests__/CreateNewProtocol.test.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-import { it } from 'vitest'
-
-it.todo('write test for CreateNewProtocol')
diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/index.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/index.tsx
index 8b2e28bdada..753965c6300 100644
--- a/protocol-designer/src/pages/CreateNewProtocolWizard/index.tsx
+++ b/protocol-designer/src/pages/CreateNewProtocolWizard/index.tsx
@@ -6,7 +6,6 @@ import uniq from 'lodash/uniq'
import mapValues from 'lodash/mapValues'
import { yupResolver } from '@hookform/resolvers/yup'
import { useDispatch, useSelector } from 'react-redux'
-import { useTranslation } from 'react-i18next'
import { useForm } from 'react-hook-form'
import { useNavigate } from 'react-router-dom'
import {
@@ -22,10 +21,7 @@ import {
getAreSlotsAdjacent,
} from '@opentrons/shared-data'
import { Box, COLORS } from '@opentrons/components'
-import {
- actions as fileActions,
- selectors as loadFileSelectors,
-} from '../../load-file'
+import { actions as fileActions } from '../../load-file'
import { uuid } from '../../utils'
import * as labwareDefSelectors from '../../labware-defs/selectors'
import * as labwareDefActions from '../../labware-defs/actions'
@@ -38,6 +34,7 @@ import {
createDeckFixture,
toggleIsGripperRequired,
} from '../../step-forms/actions/additionalItems'
+import { getNewProtocolModal } from '../../navigation/selectors'
import { SelectRobot } from './SelectRobot'
import { SelectPipettes } from './SelectPipettes'
import { SelectGripper } from './SelectGripper'
@@ -153,12 +150,11 @@ const validationSchema: any = Yup.object().shape({
})
export function CreateNewProtocolWizard(): JSX.Element | null {
- const { t } = useTranslation(['modal', 'alert'])
- const hasUnsavedChanges = useSelector(loadFileSelectors.getHasUnsavedChanges)
+ const navigate = useNavigate()
+ const showWizard = useSelector(getNewProtocolModal)
const customLabware = useSelector(
labwareDefSelectors.getCustomLabwareDefsByURI
)
- const navigate = useNavigate()
const [currentStepIndex, setCurrentStepIndex] = React.useState(0)
const [wizardSteps, setWizardSteps] = React.useState(
WIZARD_STEPS
@@ -166,6 +162,12 @@ export function CreateNewProtocolWizard(): JSX.Element | null {
const dispatch = useDispatch>()
+ React.useEffect(() => {
+ if (!showWizard) {
+ navigate('/overview')
+ }
+ }, [showWizard])
+
const createProtocolFile = (values: WizardFormState): void => {
navigate('/overview')
@@ -217,144 +219,140 @@ export function CreateNewProtocolWizard(): JSX.Element | null {
}
const newProtocolFields = values.fields
- if (
- !hasUnsavedChanges ||
- window.confirm(t('alert:confirm_create_new') as string)
- ) {
- dispatch(fileActions.createNewProtocol(newProtocolFields))
- const pipettesById: Record = pipettes.reduce(
- (acc, pipette) => ({ ...acc, [uuid()]: pipette }),
- {}
+ dispatch(fileActions.createNewProtocol(newProtocolFields))
+ const pipettesById: Record = pipettes.reduce(
+ (acc, pipette) => ({ ...acc, [uuid()]: pipette }),
+ {}
+ )
+ // create custom labware
+ mapValues(customLabware, labwareDef =>
+ dispatch(
+ labwareDefActions.createCustomLabwareDefAction({
+ def: labwareDef,
+ })
)
- // create custom labware
- mapValues(customLabware, labwareDef =>
- dispatch(
- labwareDefActions.createCustomLabwareDefAction({
- def: labwareDef,
+ )
+ // create new pipette entities
+ dispatch(
+ stepFormActions.createPipettes(
+ mapValues(
+ pipettesById,
+ (p: PipetteOnDeck, id: string): NormalizedPipette => ({
+ // @ts-expect-error(sa, 2021-6-22): id will always get overwritten
+ id,
+ ...omit(p, 'mount'),
})
)
)
- // create new pipette entities
- dispatch(
- stepFormActions.createPipettes(
- mapValues(
+ )
+ // update pipette locations in initial deck setup step
+ dispatch(
+ steplistActions.changeSavedStepForm({
+ stepId: INITIAL_DECK_SETUP_STEP_ID,
+ update: {
+ pipetteLocationUpdate: mapValues(
pipettesById,
- (p: PipetteOnDeck, id: string): NormalizedPipette => ({
- // @ts-expect-error(sa, 2021-6-22): id will always get overwritten
- id,
- ...omit(p, 'mount'),
- })
- )
- )
- )
- // update pipette locations in initial deck setup step
+ (p: typeof pipettesById[keyof typeof pipettesById]) => p.mount
+ ),
+ },
+ })
+ )
+
+ // add trash
+ if (values.additionalEquipment.includes('trashBin')) {
+ // defaulting trash to appropriate locations
dispatch(
- steplistActions.changeSavedStepForm({
- stepId: INITIAL_DECK_SETUP_STEP_ID,
- update: {
- pipetteLocationUpdate: mapValues(
- pipettesById,
- (p: typeof pipettesById[keyof typeof pipettesById]) => p.mount
- ),
- },
- })
+ createDeckFixture(
+ 'trashBin',
+ values.fields.robotType === FLEX_ROBOT_TYPE
+ ? getTrashSlot(values)
+ : 'cutout12'
+ )
)
+ }
- // add trash
- if (values.additionalEquipment.includes('trashBin')) {
- // defaulting trash to appropriate locations
- dispatch(
- createDeckFixture(
- 'trashBin',
- values.fields.robotType === FLEX_ROBOT_TYPE
- ? getTrashSlot(values)
- : 'cutout12'
- )
+ // add waste chute
+ if (values.additionalEquipment.includes('wasteChute')) {
+ dispatch(createDeckFixture('wasteChute', WASTE_CHUTE_CUTOUT))
+ }
+ // add staging areas
+ const stagingAreas = values.additionalEquipment.filter(
+ equipment => equipment === 'stagingArea'
+ )
+ if (stagingAreas.length > 0) {
+ stagingAreas.forEach((_, index) => {
+ return dispatch(
+ createDeckFixture('stagingArea', STAGING_AREA_CUTOUTS[index])
)
- }
+ })
+ }
- // add waste chute
- if (values.additionalEquipment.includes('wasteChute')) {
- dispatch(createDeckFixture('wasteChute', WASTE_CHUTE_CUTOUT))
+ // create modules
+ // sort so modules with slot are created first
+ // then modules without a slot are generated in remaining available slots
+ modules.sort((a, b) => {
+ if (a.slot == null && b.slot != null) {
+ return 1
}
- // add staging areas
- const stagingAreas = values.additionalEquipment.filter(
- equipment => equipment === 'stagingArea'
- )
- if (stagingAreas.length > 0) {
- stagingAreas.forEach((_, index) => {
- return dispatch(
- createDeckFixture('stagingArea', STAGING_AREA_CUTOUTS[index])
- )
- })
+ if (b.slot == null && a.slot != null) {
+ return -1
}
+ return 0
+ })
- // create modules
- // sort so modules with slot are created first
- // then modules without a slot are generated in remaining available slots
- modules.sort((a, b) => {
- if (a.slot == null && b.slot != null) {
- return 1
- }
- if (b.slot == null && a.slot != null) {
- return -1
- }
- return 0
- })
-
- modules.forEach(moduleArgs => {
- return moduleArgs.slot != null
- ? dispatch(stepFormActions.createModule(moduleArgs))
- : dispatch(
- createModuleWithNoSlot({
- model: moduleArgs.model,
- type: moduleArgs.type,
- isMagneticBlock: moduleArgs.type === MAGNETIC_BLOCK_TYPE,
- })
- )
- })
+ modules.forEach(moduleArgs => {
+ return moduleArgs.slot != null
+ ? dispatch(stepFormActions.createModule(moduleArgs))
+ : dispatch(
+ createModuleWithNoSlot({
+ model: moduleArgs.model,
+ type: moduleArgs.type,
+ isMagneticBlock: moduleArgs.type === MAGNETIC_BLOCK_TYPE,
+ })
+ )
+ })
- // add gripper
- if (values.additionalEquipment.includes('gripper')) {
- dispatch(toggleIsGripperRequired())
- }
+ // add gripper
+ if (values.additionalEquipment.includes('gripper')) {
+ dispatch(toggleIsGripperRequired())
+ }
- // auto-generate assigned tipracks for pipettes
- const newTiprackModels: string[] = uniq(
- pipettes.flatMap(pipette => pipette.tiprackDefURI)
- )
- const hasMagneticBlock = modules.some(
- module => module.type === MAGNETIC_BLOCK_TYPE
- )
- const FLEX_MIDDLE_SLOTS = hasMagneticBlock ? [] : ['C2', 'B2', 'A2']
- const hasOt2TC = modules.find(
- module => module.type === THERMOCYCLER_MODULE_TYPE
- )
- const heaterShakerSlot = modules.find(
- module => module.type === HEATERSHAKER_MODULE_TYPE
- )?.slot
- const OT2_MIDDLE_SLOTS = hasOt2TC ? ['2', '5'] : ['2', '5', '8', '11']
- const modifiedOt2Slots = OT2_MIDDLE_SLOTS.filter(slot =>
- heaterShakerSlot != null
- ? !getAreSlotsAdjacent(heaterShakerSlot, slot)
- : slot
+ // auto-generate assigned tipracks for pipettes
+ const newTiprackModels: string[] = uniq(
+ pipettes.flatMap(pipette => pipette.tiprackDefURI)
+ )
+ const hasMagneticBlock = modules.some(
+ module => module.type === MAGNETIC_BLOCK_TYPE
+ )
+ const FLEX_MIDDLE_SLOTS = hasMagneticBlock ? [] : ['C2', 'B2', 'A2']
+ const hasOt2TC = modules.find(
+ module => module.type === THERMOCYCLER_MODULE_TYPE
+ )
+ const heaterShakerSlot = modules.find(
+ module => module.type === HEATERSHAKER_MODULE_TYPE
+ )?.slot
+ const OT2_MIDDLE_SLOTS = hasOt2TC ? ['2', '5'] : ['2', '5', '8', '11']
+ const modifiedOt2Slots = OT2_MIDDLE_SLOTS.filter(slot =>
+ heaterShakerSlot != null
+ ? !getAreSlotsAdjacent(heaterShakerSlot, slot)
+ : slot
+ )
+ newTiprackModels.forEach((tiprackDefURI, index) => {
+ dispatch(
+ labwareIngredActions.createContainer({
+ slot:
+ values.fields.robotType === FLEX_ROBOT_TYPE
+ ? FLEX_MIDDLE_SLOTS[index]
+ : modifiedOt2Slots[index],
+ labwareDefURI: tiprackDefURI,
+ adapterUnderLabwareDefURI:
+ values.pipettesByMount.left.pipetteName === 'p1000_96'
+ ? adapter96ChannelDefUri
+ : undefined,
+ })
)
- newTiprackModels.forEach((tiprackDefURI, index) => {
- dispatch(
- labwareIngredActions.createContainer({
- slot:
- values.fields.robotType === FLEX_ROBOT_TYPE
- ? FLEX_MIDDLE_SLOTS[index]
- : modifiedOt2Slots[index],
- labwareDefURI: tiprackDefURI,
- adapterUnderLabwareDefURI:
- values.pipettesByMount.left.pipetteName === 'p1000_96'
- ? adapter96ChannelDefUri
- : undefined,
- })
- )
- })
- }
+ })
+
dispatch(labwareIngredActions.generateNewProtocol({ isNewProtocol: true }))
}
@@ -370,7 +368,7 @@ export function CreateNewProtocolWizard(): JSX.Element | null {
}
}
- return (
+ return showWizard ? (
- )
+ ) : null
}
interface CreateFileFormProps {
diff --git a/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx b/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx
index 4bf071027fd..b340fc6d471 100644
--- a/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx
+++ b/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx
@@ -1,16 +1,18 @@
import * as React from 'react'
-import { describe, it, vi, beforeEach } from 'vitest'
+import { describe, it, vi, beforeEach, expect } from 'vitest'
import { MemoryRouter } from 'react-router-dom'
-import { screen } from '@testing-library/react'
+import { screen, fireEvent } from '@testing-library/react'
import { i18n } from '../../../assets/localization'
import { renderWithProviders } from '../../../__testing-utils__'
import { loadProtocolFile } from '../../../load-file/actions'
import { getFileMetadata } from '../../../file-data/selectors'
+import { toggleNewProtocolModal } from '../../../navigation/actions'
import { Landing } from '../index'
vi.mock('../../../load-file/actions')
vi.mock('../../../file-data/selectors')
+vi.mock('../../../navigation/actions')
const render = () => {
return renderWithProviders(
@@ -25,7 +27,7 @@ const render = () => {
describe('Landing', () => {
beforeEach(() => {
- vi.mocked(getFileMetadata).mockReturnValue({ created: 123 })
+ vi.mocked(getFileMetadata).mockReturnValue({})
vi.mocked(loadProtocolFile).mockReturnValue(vi.fn())
})
it('renders the landing page image and text', () => {
@@ -35,7 +37,8 @@ describe('Landing', () => {
screen.getByText(
'The easiest way to automate liquid handling on your Opentrons robot. No code required.'
)
- screen.getByRole('button', { name: 'Create a protocol' })
+ fireEvent.click(screen.getByRole('button', { name: 'Create a protocol' }))
+ expect(vi.mocked(toggleNewProtocolModal)).toHaveBeenCalled()
screen.getByText('Edit existing protocol')
screen.getByRole('img', { name: 'welcome image' })
})
diff --git a/protocol-designer/src/pages/Landing/index.tsx b/protocol-designer/src/pages/Landing/index.tsx
index 61c590462ed..47674bddda3 100644
--- a/protocol-designer/src/pages/Landing/index.tsx
+++ b/protocol-designer/src/pages/Landing/index.tsx
@@ -13,8 +13,10 @@ import {
StyledText,
TYPOGRAPHY,
} from '@opentrons/components'
+import { BUTTON_LINK_STYLE } from '../../atoms'
import { actions as loadFileActions } from '../../load-file'
import { getFileMetadata } from '../../file-data/selectors'
+import { toggleNewProtocolModal } from '../../navigation/actions'
import welcomeImage from '../../assets/images/welcome_page.png'
import type { ThunkDispatch } from '../../types'
@@ -64,6 +66,9 @@ export function Landing(): JSX.Element {
{t('no-code-required')}
{
+ dispatch(toggleNewProtocolModal(true))
+ }}
marginY={SPACING.spacing32}
buttonText={
@@ -75,9 +80,11 @@ export function Landing(): JSX.Element {
/>
-
- {t('edit_existing')}
-
+
+
+ {t('edit_existing')}
+
+
diff --git a/protocol-designer/src/pages/ProtocolOverview/DeckThumbnail.tsx b/protocol-designer/src/pages/ProtocolOverview/DeckThumbnail.tsx
index 3036d1fe5de..b37fa5897fe 100644
--- a/protocol-designer/src/pages/ProtocolOverview/DeckThumbnail.tsx
+++ b/protocol-designer/src/pages/ProtocolOverview/DeckThumbnail.tsx
@@ -44,7 +44,6 @@ const OT2_STANDARD_DECK_VIEW_LAYER_BLOCK_LIST: string[] = [
]
const lightFill = COLORS.grey35
-const darkFill = COLORS.grey60
interface DeckThumbnailProps {
hoverSlot: DeckSlotId | null
@@ -135,7 +134,6 @@ export function DeckThumbnail(props: DeckThumbnailProps): JSX.Element {
deckDefinition={deckDef}
showExpansion={cutoutId === 'cutoutA1'}
fixtureBaseColor={lightFill}
- slotClipColor={darkFill}
/>
) : null
})}
@@ -144,7 +142,6 @@ export function DeckThumbnail(props: DeckThumbnailProps): JSX.Element {
key={fixture.id}
cutoutId={fixture.location as StagingAreaLocation}
deckDefinition={deckDef}
- slotClipColor={darkFill}
fixtureBaseColor={lightFill}
/>
))}
@@ -181,7 +178,6 @@ export function DeckThumbnail(props: DeckThumbnailProps): JSX.Element {
key={fixture.id}
cutoutId={fixture.location as typeof WASTE_CHUTE_CUTOUT}
deckDefinition={deckDef}
- slotClipColor={darkFill}
fixtureBaseColor={lightFill}
/>
))}
diff --git a/protocol-designer/src/pages/ProtocolOverview/index.tsx b/protocol-designer/src/pages/ProtocolOverview/index.tsx
index 3f0b17be10c..2be14aa9b56 100644
--- a/protocol-designer/src/pages/ProtocolOverview/index.tsx
+++ b/protocol-designer/src/pages/ProtocolOverview/index.tsx
@@ -8,7 +8,6 @@ import { css } from 'styled-components'
import {
ALIGN_CENTER,
Btn,
- COLORS,
DIRECTION_COLUMN,
Flex,
InfoScreen,
@@ -45,6 +44,7 @@ import { resetScrollElements } from '../../ui/steps/utils'
import { useBlockingHint } from '../../components/Hints/useBlockingHint'
import { v8WarningContent } from '../../components/FileSidebar/FileSidebar'
import { MaterialsListModal } from '../../organisms/MaterialsListModal'
+import { BUTTON_LINK_STYLE } from '../../atoms'
import {
EditProtocolMetadataModal,
EditInstrumentsModal,
@@ -322,6 +322,7 @@ export function ProtocolOverview(): JSX.Element {
onClick={() => {
setShowEditMetadataModal(true)
}}
+ css={BUTTON_LINK_STYLE}
data-testid="ProtocolOverview_MetadataEditButton"
>
@@ -358,6 +359,7 @@ export function ProtocolOverview(): JSX.Element {
onClick={() => {
setShowEditInstrumentsModal(true)
}}
+ css={BUTTON_LINK_STYLE}
>
{t('edit')}
@@ -438,16 +440,13 @@ export function ProtocolOverview(): JSX.Element {
}
- content={liquid.description ?? t('n/a')}
+ content={liquid.description ?? t('na')}
/>
)
)
) : (
-
+
)}
@@ -459,10 +458,7 @@ export function ProtocolOverview(): JSX.Element {
{Object.keys(savedStepForms).length <= 1 ? (
-
+
) : (
{
setShowMaterialsListModal(true)
}}
+ css={BUTTON_LINK_STYLE}
>
{t('materials_list')}