diff --git a/components/src/atoms/ListItem/index.tsx b/components/src/atoms/ListItem/index.tsx index 39367f935c1..cb61f0a4d3c 100644 --- a/components/src/atoms/ListItem/index.tsx +++ b/components/src/atoms/ListItem/index.tsx @@ -56,7 +56,6 @@ export function ListItem(props: ListItemProps): JSX.Element { background-color: ${listItemProps.backgroundColor}; width: 100%; height: ${FLEX_MAX_CONTENT}; - padding: 0; border-radius: ${BORDERS.borderRadius4}; @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { diff --git a/components/src/organisms/Toolbox/index.tsx b/components/src/organisms/Toolbox/index.tsx index 4346806b861..e73de42e06b 100644 --- a/components/src/organisms/Toolbox/index.tsx +++ b/components/src/organisms/Toolbox/index.tsx @@ -87,7 +87,7 @@ export function Toolbox(props: ToolboxProps): JSX.Element { height={height} {...positionStyles} borderRadius={BORDERS.borderRadius8} - minWidth="19.5rem" + width={width} flex="0" > Set block temperature tofor", "thermocycler_profile": { "end_hold": { "block": "End at thermocycler block", diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx index 5078ff4c0e5..73b13636f4f 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx @@ -145,7 +145,8 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { const isPipetteStep = savedStepFormData.stepType === 'moveLiquid' || savedStepFormData.stepType === 'mix' - const isThermocyclerStep = savedStepFormData.stepType === 'thermocycler' + const isThermocyclerProfile = + savedStepFormData.thermocyclerFormType === 'thermocyclerProfile' return ( <> @@ -183,7 +184,7 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { )} {t('edit_step')} )} - {isPipetteStep || isThermocyclerStep ? ( + {isPipetteStep || isThermocyclerProfile ? ( { + setStepOverflowMenu(false) dispatch(hoverOnStep(stepId)) dispatch(toggleViewSubstep(stepId)) }} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx index b6340bd97ac..d5534efebae 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx @@ -47,8 +47,6 @@ export function SubstepsToolbox( return null } - const uiStepType = t(`application:stepType.${formData.stepType}`) - return ('commandCreatorFnName' in substeps && (substeps.commandCreatorFnName === 'transfer' || substeps.commandCreatorFnName === 'consolidate' || @@ -56,7 +54,7 @@ export function SubstepsToolbox( substeps.commandCreatorFnName === 'mix')) || substeps.substepType === THERMOCYCLER_PROFILE ? ( {i18n.format( - t(`protocol_steps:step_substeps`, { stepType: uiStepType }), + t(`protocol_steps:step_substeps`, { stepType: formData.stepName }), 'capitalize' )} } > - + {substeps.substepType === THERMOCYCLER_PROFILE ? ( - + ) : ( Wire this up +import { useSelector } from 'react-redux' +import { Trans, useTranslation } from 'react-i18next' +import { + ALIGN_CENTER, + ALIGN_FLEX_END, + DIRECTION_COLUMN, + FLEX_MAX_CONTENT, + Flex, + ListItem, + SPACING, + StyledText, + Tag, +} from '@opentrons/components' +import { getSavedStepForms } from '../../../../step-forms/selectors' + +import type { ProfileStepItem } from '../../../../form-types' +import type { ThermocyclerCycleType } from '../StepForm/StepTools/ThermocyclerTools/ThermocyclerCycle' +import type { ThermocyclerStepType } from '../StepForm/StepTools/ThermocyclerTools/ThermocyclerStep' + +interface ThermocyclerProfileSubstepsProps { + stepId: string +} +export function ThermocyclerProfileSubsteps( + props: ThermocyclerProfileSubstepsProps +): JSX.Element { + const { stepId } = props + + const savedStepForms = useSelector(getSavedStepForms) + const step = savedStepForms[stepId] + const orderedSubsteps = step.orderedProfileItems.map( + (id: string) => step.profileItemsById[id] + ) + + return ( + + {orderedSubsteps.map( + (substep: ThermocyclerStepType | ThermocyclerCycleType) => { + const content = + substep.type === 'profileCycle' ? ( + + {substep.steps.map((profileStep: ProfileStepItem) => { + const { + temperature, + durationMinutes, + durationSeconds, + } = profileStep + return ( + + ) + })} + + {`Repeat ${substep.repetitions} times `} + + + ) : ( + + ) + return ( + + {content} + + ) + } + )} + + ) +} + +interface ThermocyclerSubstepProps { + temperature: string + duration: string +} + +function ThermocyclerSubstep(props: ThermocyclerSubstepProps) { + const { temperature, duration } = props + const { t } = useTranslation(['application', 'protocol_steps']) + return ( + + , + tagTemperature: ( + + ), + tagDuration: , + }} + /> + + ) } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/ThermocyclerProfileSubsteps.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/ThermocyclerProfileSubsteps.test.tsx new file mode 100644 index 00000000000..b4fb8af436f --- /dev/null +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/ThermocyclerProfileSubsteps.test.tsx @@ -0,0 +1,78 @@ +import { describe, it, vi, beforeEach, expect } from 'vitest' +import { screen } from '@testing-library/react' +import { renderWithProviders } from '../../../../../__testing-utils__' +import { i18n } from '../../../../../assets/localization' +import { getSavedStepForms } from '../../../../../step-forms/selectors' +import { ThermocyclerProfileSubsteps } from '../ThermocyclerProfileSubsteps' +import type { FormData } from '../../../../../form-types' + +const render = ( + props: React.ComponentProps +) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} +vi.mock('../../../../../step-forms/selectors') +const THERMOCYCLER_STEP_ID = 'tcStep123' +const MOCK_THERMOCYCLER_ORDERED_SUBSTEP_IDS = [ + '292b0d70-fa06-4ab1-adc9-f26c589babf4', + '0965e0de-2d01-4e4e-8fb3-1e66306fe7e5', +] +const MOCK_THERMOCYCLER_SUBSTEP_ITEMS = { + '292b0d70-fa06-4ab1-adc9-f26c589babf4': { + id: '292b0d70-fa06-4ab1-adc9-f26c589babf4', + title: '', + steps: [ + { + durationMinutes: '00', + durationSeconds: '30', + id: 'f90cc374-2eeb-4205-80c6-63c5c77215a5', + temperature: '10', + title: 'cyclestep1', + type: 'profileStep', + }, + { + durationMinutes: '1', + durationSeconds: '30', + id: '462b3d8f-bb8a-4e11-ae98-8f1d46e8507e', + temperature: '55', + title: 'cyclestep2', + type: 'profileStep', + }, + ], + type: 'profileCycle', + repetitions: '28', + }, + '0965e0de-2d01-4e4e-8fb3-1e66306fe7e5': { + durationMinutes: '5', + durationSeconds: '00', + id: '0965e0de-2d01-4e4e-8fb3-1e66306fe7e5', + temperature: '39', + title: 'last step', + type: 'profileStep', + }, +} + +describe('TimelineToolbox', () => { + let props: React.ComponentProps + beforeEach(() => { + props = { stepId: THERMOCYCLER_STEP_ID } + vi.mocked(getSavedStepForms).mockReturnValue({ + [THERMOCYCLER_STEP_ID]: ({ + orderedProfileItems: MOCK_THERMOCYCLER_ORDERED_SUBSTEP_IDS, + profileItemsById: MOCK_THERMOCYCLER_SUBSTEP_ITEMS, + } as unknown) as FormData, + }) + }) + it('renders all profile steps, including cycles and steps', () => { + render(props) + expect(screen.getAllByText('Set block temperature to').length === 3) + screen.getByText('10°C') + screen.getByText('55°C') + screen.getByText('39°C') + screen.getByText('00:30') + screen.getByText('1:30') + screen.getByText('5:00') + }) +}) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx index 468ea45e01f..7f240f4da00 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx @@ -71,9 +71,9 @@ export function ProtocolSteps(): JSX.Element { gridGap={SPACING.spacing16} height="calc(100vh - 4rem)" justifyContent={JUSTIFY_SPACE_BETWEEN} + padding={SPACING.spacing12} > - {selectedSubstep ? : null} {enableHoyKeyDisplay ? ( - + @@ -127,6 +127,7 @@ export function ProtocolSteps(): JSX.Element { ) : null} + {selectedSubstep ? : null} {isMultiSelectMode ? : null}