diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/BatchEditToolbox/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/BatchEditToolbox/index.tsx index 81a6f259c95..db1c69ae982 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/BatchEditToolbox/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/BatchEditToolbox/index.tsx @@ -69,7 +69,6 @@ export const BatchEditToolbox = (): JSX.Element | null => { return ( {t('protocol_steps:batch_edit')} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx index 709cff49d7c..f101237cb45 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx @@ -206,7 +206,6 @@ export function StepFormToolbox(props: StepFormToolboxProps): JSX.Element { } - height="calc(100vh - 64px)" title={ diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx index cf4424af5f6..3650c23120e 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepOverflowMenu.tsx @@ -19,6 +19,8 @@ import { toggleViewSubstep, } from '../../../../ui/steps/actions/actions' import { + getBatchEditFormHasUnsavedChanges, + getCurrentFormHasUnsavedChanges, getSavedStepForms, getUnsavedForm, } from '../../../../step-forms/selectors' @@ -49,6 +51,12 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { multiSelectItemIds, } = props const { t } = useTranslation('protocol_steps') + const singleEditFormHasUnsavedChanges = useSelector( + getCurrentFormHasUnsavedChanges + ) + const batchEditFormHasUnstagedChanges = useSelector( + getBatchEditFormHasUnsavedChanges + ) const dispatch = useDispatch>() const formData = useSelector(getUnsavedForm) const savedStepFormData = useSelector(getSavedStepForms)[stepId] @@ -93,6 +101,7 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { {multiSelectItemIds != null && multiSelectItemIds.length > 0 ? ( <> { duplicateMultipleSteps() setStepOverflowMenu(false) @@ -117,6 +126,7 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { )} {isPipetteStep || isThermocyclerProfile ? ( { setStepOverflowMenu(false) dispatch(hoverOnStep(stepId)) @@ -127,6 +137,7 @@ export function StepOverflowMenu(props: StepOverflowMenuProps): JSX.Element { ) : null} { duplicateStep(stepId) setStepOverflowMenu(false) @@ -166,5 +177,8 @@ const MenuButton = styled.button` &:disabled { color: ${COLORS.grey40}; cursor: auto; + &:hover { + background-color: ${COLORS.transparent}; + } } ` diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx index 5605667bf59..922220b7e81 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/SubstepsToolbox.tsx @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux' import { FLEX_MAX_CONTENT, Flex, + Icon, PrimaryButton, SPACING, StyledText, @@ -48,6 +49,11 @@ export function SubstepsToolbox( return null } + const handleClose = (): void => { + dispatch(toggleViewSubstep(null)) + dispatch(hoverOnStep(null)) + } + return ('commandCreatorFnName' in substeps && (substeps.commandCreatorFnName === 'transfer' || substeps.commandCreatorFnName === 'consolidate' || @@ -57,14 +63,10 @@ export function SubstepsToolbox( } + onCloseClick={handleClose} confirmButton={ - { - dispatch(toggleViewSubstep(null)) - dispatch(hoverOnStep(null)) - }} - width="100%" - > + {t('shared:done')} } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx index e5a37810a3f..1dafa1d2c71 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx @@ -1,15 +1,22 @@ -import { describe, it, vi, beforeEach, expect } from 'vitest' +import { describe, it, vi, beforeEach } from 'vitest' import '@testing-library/jest-dom/vitest' import { fireEvent, screen } from '@testing-library/react' import { i18n } from '../../../../assets/localization' import { renderWithProviders } from '../../../../__testing-utils__' -import { getUnsavedForm } from '../../../../step-forms/selectors' -import { getSelectedSubstep } from '../../../../ui/steps/selectors' +import { + getSavedStepForms, + getUnsavedForm, +} from '../../../../step-forms/selectors' +import { + getSelectedStepId, + getSelectedSubstep, +} from '../../../../ui/steps/selectors' import { getEnableHotKeysDisplay } from '../../../../feature-flags/selectors' import { DeckSetupContainer } from '../../DeckSetup' import { OffDeck } from '../../Offdeck' import { ProtocolSteps } from '..' import { SubstepsToolbox, TimelineToolbox } from '../Timeline' +import type { SavedStepFormState } from '../../../../step-forms' vi.mock('../../Offdeck') vi.mock('../../../../step-forms/selectors') @@ -17,6 +24,7 @@ vi.mock('../../../../ui/steps/selectors') vi.mock('../../../../ui/labware/selectors') vi.mock('../StepForm') vi.mock('../../DeckSetup') +vi.mock('../StepSummary.tsx') vi.mock('../Timeline') vi.mock('../../../../feature-flags/selectors') @@ -26,6 +34,23 @@ const render = () => { })[0] } +const MOCK_STEP_FORMS = { + '0522fde8-25a3-4840-b84a-af7282bd80d5': { + moduleId: '781599b2-1eff-4594-8c96-06fcd54f4faa:heaterShakerModuleType', + pauseAction: 'untilTime', + pauseHour: '22', + pauseMessage: 'sdfg', + pauseMinute: '22', + pauseSecond: '11', + pauseTemperature: null, + pauseTime: null, + id: '0522fde8-25a3-4840-b84a-af7282bd80d5', + stepType: 'pause', + stepName: 'custom pause', + stepDetails: '', + }, +} + describe('ProtocolSteps', () => { beforeEach(() => { vi.mocked(TimelineToolbox).mockReturnValue(
mock TimelineToolbox
) @@ -37,6 +62,12 @@ describe('ProtocolSteps', () => { vi.mocked(getSelectedSubstep).mockReturnValue(null) vi.mocked(SubstepsToolbox).mockReturnValue(
mock SubstepsToolbox
) vi.mocked(getEnableHotKeysDisplay).mockReturnValue(true) + vi.mocked(getSavedStepForms).mockReturnValue( + MOCK_STEP_FORMS as SavedStepFormState + ) + vi.mocked(getSelectedStepId).mockReturnValue( + '0522fde8-25a3-4840-b84a-af7282bd80d5' + ) }) it('renders each component in ProtocolSteps', () => { @@ -52,15 +83,6 @@ describe('ProtocolSteps', () => { screen.getByText('mock OffDeck') }) - it('renders no toggle when formData does not equal moveLabware type', () => { - vi.mocked(getUnsavedForm).mockReturnValue({ - stepType: 'magnet', - id: 'mockId', - }) - render() - expect(screen.queryByText('Off-deck')).not.toBeInTheDocument() - }) - it('renders the substepToolbox when selectedSubstep is not null', () => { vi.mocked(getSelectedSubstep).mockReturnValue('mockId') render() @@ -73,4 +95,9 @@ describe('ProtocolSteps', () => { screen.getByText('Shift + Click to select all') screen.getByText('Command + Click for multi-select') }) + + it('renders the current step name', () => { + render() + screen.getByText('Custom pause') + }) }) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx index 7f240f4da00..c2ca9ced4ee 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react' +import { useState } from 'react' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { @@ -12,6 +12,7 @@ import { JUSTIFY_SPACE_BETWEEN, POSITION_FIXED, SPACING, + StyledText, Tag, ToggleGroup, } from '@opentrons/components' @@ -34,7 +35,7 @@ import { StepSummary } from './StepSummary' import { BatchEditToolbox } from './BatchEditToolbox' export function ProtocolSteps(): JSX.Element { - const { t } = useTranslation('starting_deck_state') + const { i18n, t } = useTranslation('starting_deck_state') const formData = useSelector(getUnsavedForm) const isMultiSelectMode = useSelector(getIsMultiSelectMode) const selectedSubstep = useSelector(getSelectedSubstep) @@ -45,14 +46,6 @@ export function ProtocolSteps(): JSX.Element { typeof leftString | typeof rightString >(leftString) - const formType = formData?.stepType - - useEffect(() => { - if (formData != null && formType !== 'moveLabware') { - setDeckView(leftString) - } - }, [formData, formType, deckView]) - const currentHoveredStepId = useSelector(getHoveredStepId) const currentSelectedStepId = useSelector(getSelectedStepId) const currentstepIdForStepSummary = @@ -76,29 +69,35 @@ export function ProtocolSteps(): JSX.Element { - {formData == null || formType === 'moveLabware' ? ( - - { - setDeckView(leftString) - }} - rightClick={() => { - setDeckView(rightString) - }} - /> - - ) : null} + + {currentStep != null ? ( + + {i18n.format(currentStep.stepName, 'capitalize')} + + ) : null} + { + setDeckView(leftString) + }} + rightClick={() => { + setDeckView(rightString) + }} + /> + ) : null} - {selectedSubstep ? : null} + {formData == null && selectedSubstep ? ( + + ) : null} {isMultiSelectMode ? : null} diff --git a/protocol-designer/src/top-selectors/labware-locations/index.ts b/protocol-designer/src/top-selectors/labware-locations/index.ts index 7741f3a7314..df674025b74 100644 --- a/protocol-designer/src/top-selectors/labware-locations/index.ts +++ b/protocol-designer/src/top-selectors/labware-locations/index.ts @@ -235,7 +235,7 @@ export const getUnoccupiedLabwareLocationOptions: Selector< ) }) .map(slotId => ({ name: slotId, value: slotId })) - const offDeck = { name: 'Off-deck', value: 'offDeck' } + const offDeck = { name: 'Off-Deck', value: 'offDeck' } const wasteChuteSlot = { name: 'Waste Chute in D3', value: WASTE_CHUTE_CUTOUT,