diff --git a/api/docs/v2/basic_commands/liquids.rst b/api/docs/v2/basic_commands/liquids.rst index 9e2e4ff8782..59ccf337892 100644 --- a/api/docs/v2/basic_commands/liquids.rst +++ b/api/docs/v2/basic_commands/liquids.rst @@ -263,14 +263,15 @@ This example aspirates enough air to fill the remaining volume in a pipette:: Detect Liquids ============== -The :py:meth:`.InstrumentContext.detect_liquid_presence` method tells a Flex pipette to check for liquid in a well. It returns ``True`` if the pressure sensors in the pipette detect a liquid and ``False`` if the sensors do not. +The :py:meth:`.InstrumentContext.detect_liquid_presence` method tells a Flex pipette to check for liquid in a well. It returns ``True`` if the pressure sensors in the pipette detect a liquid and ``False`` if the sensors do not. When ``detect_liquid_presence()`` finds an empty well it won't raise an error or stop your protocol. -Aspiration isn't required to use ``detect_liquid_presence()``. This is a standalone method that can be called when you want the robot to record the presence or absence of a liquid. When ``detect_liquid_presence()`` finds an empty well it won't raise an error or stop your protocol. +``detect_liquid_presence()`` is a standalone method to record the presence or absence of a liquid. You don't have to aspirate after detecting liquid presence. However, you should always pick up a tip immediately prior to checking for liquid, and either aspirate or drop the tip immediately after. This ensures that the pipette uses a clean, dry tip to check for liquid, and prevents cross-contamination. A potential use of liquid detection is to try aspirating from another well if the first well is found to contain no liquid. .. code-block:: python + pipette.pick_up_tip() if pipette.detect_liquid_presence(reservoir["A1"]): pipette.aspirate(100, reservoir["A1"]) else: @@ -283,13 +284,16 @@ A potential use of liquid detection is to try aspirating from another well if th Require Liquids =============== -The :py:meth:`.InstrumentContext.require_liquid_presence` method tells a Flex pipette to check for `and require` liquid in a well. +The :py:meth:`.InstrumentContext.require_liquid_presence` method tells a Flex pipette to check for `and require` liquid in a well. When ``require_liquid_presence()`` finds an empty well, it raises an error and pauses the protocol to let you resolve the problem. -Aspiration isn't required to use ``require_liquid_presence()``. This is a standalone method that can be called when you want the robot to react to a missing liquid or empty well. When ``require_liquid_presence()`` finds an empty well, it raises an error and pauses the protocol to let you resolve the problem. See also :ref:`lpd`. +``require_liquid_presence()`` is a standalone method to react to a missing liquid or empty well. You don't have to aspirate after requiring liquid presence. However, you should always pick up a tip immediately prior to checking for liquid, and either aspirate or drop the tip immediately after. This ensures that the pipette uses a clean, dry tip to check for liquid, and prevents cross-contamination. .. code-block:: python + pipette.pick_up_tip() pipette.require_liquid_presence(reservoir["A1"]) pipette.aspirate(100, reservoir["A1"]) # only occurs if liquid found +You can also require liquid presence for all aspirations performed with a given pipette. See :ref:`lpd`. + .. versionadded:: 2.20 diff --git a/api/docs/v2/pipettes/loading.rst b/api/docs/v2/pipettes/loading.rst index e97eb78592b..797ed4c4338 100644 --- a/api/docs/v2/pipettes/loading.rst +++ b/api/docs/v2/pipettes/loading.rst @@ -221,15 +221,17 @@ Another example is a Flex protocol that uses a waste chute. Say you want to only Liquid Presence Detection ========================= -Liquid presence detection is a pressure-based feature that allows Opentrons Flex pipettes to detect the presence or absence of liquids in a well, reservoir, tube, or other container. It gives you the ability to identify, avoid, and recover from liquid-related protocol errors. You can enable this feature for an entire protocol run or toggle it on and off as required. Liquid presence detection is disabled by default. +Liquid presence detection is a pressure-based feature that allows Opentrons Flex pipettes to detect the presence or absence of liquids in a well, reservoir, tube, or other container. It gives you the ability to identify, avoid, and recover from liquid-related protocol errors. + +When detecting liquid, the pipette slowly moves a fresh, empty tip downward from the top of the well until it contacts the liquid. The downward probing motion can take anywhere from 5 to 50 seconds, depending on the depth of the well and how much liquid it contains. For example, it will take much less time to detect liquid in a full flat well plate than in an empty (or nearly empty) large tube. + +You can enable this feature for an entire protocol run or toggle it on and off as required. Consider the amount of time automatic detection will add to your protocol. If you only need to detect liquid infrequently, use the :ref:`corresponding building block commands ` instead. Automatic liquid presence detection is disabled by default. Pipette Compatibility --------------------- Liquid presence detection works with Flex 1-, 8-, and 96-channel pipettes only. 1-channel pipettes have one pressure sensor. The 8-channel pipette pressure sensors are on channels 1 and 8 (positions A1 and H1). The 96-channel pipette pressure sensors are on channels 1 and 96 (positions A1 and H12). Other channels on multi-channel pipettes do not have sensors and cannot detect liquid. -.. add text with link to revised pipette sensor section in manual? - Enabling Globally ----------------- @@ -245,9 +247,11 @@ To automatically use liquid presence detection, add the optional Boolean argumen ) .. note:: - Accurate liquid detection requires fresh, dry pipette tips. Protocols using this feature must discard used tips after an aspirate/dispense cycle and pick up new tips before the next cycle. The API will raise an error if liquid detection is active and your protocol attempts to reuse a pipette tip or if the robot thinks the tip is wet. + Accurate liquid detection requires fresh, dry pipette tips. Protocols using this feature must discard used tips after an aspirate/dispense cycle and pick up new tips before the next cycle. :ref:`Complex commands ` may include aspirate steps after a tip is already wet. When global liquid detection is enabled, use :ref:`building block commands ` to ensure that your protocol picks up a tip immediately before aspiration. + + The API will not raise an error during liquid detection if a tip is empty but wet. It will raise an error if liquid detection is active and your protocol attempts to aspirate with liquid in the tip. -Let's take a look at how all this works. First, tell the robot to pick up a clean tip, aspirate 100 µL from a reservoir, and dispense that volume into a well plate. +Let's take a look at how all this works. With automatic liquid detection enabled, tell the robot to pick up a clean tip, aspirate 100 µL from a reservoir, and dispense that volume into a well plate: .. code-block:: python diff --git a/api/docs/v2/versioning.rst b/api/docs/v2/versioning.rst index 8a4eae39718..72430f9104f 100644 --- a/api/docs/v2/versioning.rst +++ b/api/docs/v2/versioning.rst @@ -137,6 +137,8 @@ Changes in API Versions Version 2.20 ------------ +- Detect liquid presence within a well. The :py:meth:`.InstrumentContext.detect_liquid_presence()` and :py:meth:`.InstrumentContext.require_liquid_presence()` building block commands check for liquid any point in your protocol. You can also :ref:`enable liquid presence detection ` for all aspirations when loading a pipette, although this will add significant time to your protocol. +- Define CSV runtime parameters and use their contents in a protocol with new :ref:`data manipulation methods `. See the :ref:`cherrypicking use case ` for a full example. - :py:meth:`.configure_nozzle_layout` now accepts row, single, and partial column layout constants. See :ref:`partial-tip-pickup`. - You can now call :py:obj:`.ProtocolContext.define_liquid()` without supplying a ``description`` or ``display_color``. diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py index aaa36c513d7..e39a2e200bf 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/open_labware_latch.py @@ -6,6 +6,7 @@ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence +from ...state import update_types if TYPE_CHECKING: from opentrons.protocol_engine.state.state import StateView @@ -54,6 +55,8 @@ async def execute( self, params: OpenLabwareLatchParams ) -> SuccessData[OpenLabwareLatchResult, None]: """Open a Heater-Shaker's labware latch.""" + state_update = update_types.StateUpdate() + # Allow propagation of ModuleNotLoadedError and WrongModuleTypeError. hs_module_substate = self._state_view.modules.get_heater_shaker_module_substate( module_id=params.moduleId @@ -72,6 +75,7 @@ async def execute( await self._movement.home( axes=self._state_view.motion.get_robot_mount_axes() ) + state_update.clear_all_pipette_locations() # Allow propagation of ModuleNotAttachedError. hs_hardware_module = self._equipment.get_module_hardware_api( @@ -84,6 +88,7 @@ async def execute( return SuccessData( public=OpenLabwareLatchResult(pipetteRetracted=pipette_should_retract), private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py index 2aaeac05a95..e3cf35142d6 100644 --- a/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py +++ b/api/src/opentrons/protocol_engine/commands/heater_shaker/set_and_wait_for_shake_speed.py @@ -6,6 +6,7 @@ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence +from ...state import update_types if TYPE_CHECKING: from opentrons.protocol_engine.state.state import StateView @@ -56,6 +57,8 @@ async def execute( params: SetAndWaitForShakeSpeedParams, ) -> SuccessData[SetAndWaitForShakeSpeedResult, None]: """Set and wait for a Heater-Shaker's target shake speed.""" + state_update = update_types.StateUpdate() + # Allow propagation of ModuleNotLoadedError and WrongModuleTypeError. hs_module_substate = self._state_view.modules.get_heater_shaker_module_substate( module_id=params.moduleId @@ -77,6 +80,7 @@ async def execute( await self._movement.home( axes=self._state_view.motion.get_robot_mount_axes() ) + state_update.clear_all_pipette_locations() # Allow propagation of ModuleNotAttachedError. hs_hardware_module = self._equipment.get_module_hardware_api( @@ -91,6 +95,7 @@ async def execute( pipetteRetracted=pipette_should_retract ), private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/home.py b/api/src/opentrons/protocol_engine/commands/home.py index 9455470602a..93d988772dc 100644 --- a/api/src/opentrons/protocol_engine/commands/home.py +++ b/api/src/opentrons/protocol_engine/commands/home.py @@ -5,6 +5,7 @@ from typing_extensions import Literal from opentrons.types import MountType +from ..state import update_types from ..types import MotorAxis from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ..errors.error_occurrence import ErrorOccurrence @@ -51,6 +52,8 @@ def __init__(self, movement: MovementHandler, **kwargs: object) -> None: async def execute(self, params: HomeParams) -> SuccessData[HomeResult, None]: """Home some or all motors to establish positional accuracy.""" + state_update = update_types.StateUpdate() + if ( params.skipIfMountPositionOk is None or not await self._movement.check_for_valid_position( @@ -58,7 +61,12 @@ async def execute(self, params: HomeParams) -> SuccessData[HomeResult, None]: ) ): await self._movement.home(axes=params.axes) - return SuccessData(public=HomeResult(), private=None) + + # todo(mm, 2024-09-17): Clearing all pipette locations *unconditionally* is to + # preserve prior behavior, but we might only want to do this if we actually home. + state_update.clear_all_pipette_locations() + + return SuccessData(public=HomeResult(), private=None, state_update=state_update) class Home(BaseCommand[HomeParams, HomeResult, ErrorOccurrence]): diff --git a/api/src/opentrons/protocol_engine/commands/move_labware.py b/api/src/opentrons/protocol_engine/commands/move_labware.py index f02c0acde01..463b346457e 100644 --- a/api/src/opentrons/protocol_engine/commands/move_labware.py +++ b/api/src/opentrons/protocol_engine/commands/move_labware.py @@ -6,7 +6,9 @@ from typing_extensions import Literal from opentrons.types import Point +from ..state import update_types from ..types import ( + CurrentWell, LabwareLocation, DeckSlotLocation, OnLabwareLocation, @@ -96,6 +98,8 @@ async def execute( # noqa: C901 self, params: MoveLabwareParams ) -> SuccessData[MoveLabwareResult, None]: """Move a loaded labware to a new location.""" + state_update = update_types.StateUpdate() + # Allow propagation of LabwareNotLoadedError. current_labware = self._state_view.labware.get(labware_id=params.labwareId) current_labware_definition = self._state_view.labware.get_definition( @@ -209,12 +213,28 @@ async def execute( # noqa: C901 user_offset_data=user_offset_data, post_drop_slide_offset=post_drop_slide_offset, ) + # All mounts will have been retracted as part of the gripper move. + state_update.clear_all_pipette_locations() elif params.strategy == LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE: # Pause to allow for manual labware movement await self._run_control.wait_for_resume() + # We may have just moved the labware that contains the current well out from + # under the pipette. Clear the current location to reflect the fact that the + # pipette is no longer over any labware. This is necessary for safe path + # planning in case the next movement goes to the same labware (now in a new + # place). + pipette_location = self._state_view.pipettes.get_current_location() + if ( + isinstance(pipette_location, CurrentWell) + and pipette_location.labware_id == params.labwareId + ): + state_update.clear_all_pipette_locations() + return SuccessData( - public=MoveLabwareResult(offsetId=new_offset_id), private=None + public=MoveLabwareResult(offsetId=new_offset_id), + private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/move_relative.py b/api/src/opentrons/protocol_engine/commands/move_relative.py index 38ac0806217..dc559648ea3 100644 --- a/api/src/opentrons/protocol_engine/commands/move_relative.py +++ b/api/src/opentrons/protocol_engine/commands/move_relative.py @@ -4,6 +4,8 @@ from typing import TYPE_CHECKING, Optional, Type from typing_extensions import Literal + +from ..state import update_types from ..types import MovementAxis, DeckPoint from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ..errors.error_occurrence import ErrorOccurrence @@ -48,14 +50,25 @@ async def execute( self, params: MoveRelativeParams ) -> SuccessData[MoveRelativeResult, None]: """Move (jog) a given pipette a relative distance.""" + state_update = update_types.StateUpdate() + x, y, z = await self._movement.move_relative( pipette_id=params.pipetteId, axis=params.axis, distance=params.distance, ) + deck_point = DeckPoint.construct(x=x, y=y, z=z) + state_update.pipette_location = update_types.PipetteLocationUpdate( + pipette_id=params.pipetteId, + # TODO(jbl 2023-02-14): Need to investigate whether move relative should clear current location + new_location=update_types.NO_CHANGE, + new_deck_point=deck_point, + ) return SuccessData( - public=MoveRelativeResult(position=DeckPoint(x=x, y=y, z=z)), private=None + public=MoveRelativeResult(position=deck_point), + private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py index 1a68b5ce570..cfdfbe77133 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area.py @@ -4,7 +4,10 @@ from typing import TYPE_CHECKING, Optional, Type from typing_extensions import Literal +from opentrons_shared_data.pipette.types import PipetteNameType + from ..errors import LocationNotAccessibleByPipetteError +from ..state import update_types from ..types import DeckPoint, AddressableOffsetVector from ..resources import fixture_validation from .pipetting_common import ( @@ -88,9 +91,24 @@ async def execute( self, params: MoveToAddressableAreaParams ) -> SuccessData[MoveToAddressableAreaResult, None]: """Move the requested pipette to the requested addressable area.""" + state_update = update_types.StateUpdate() + self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration( params.addressableAreaName ) + loaded_pipette = self._state_view.pipettes.get(params.pipetteId) + if loaded_pipette.pipetteName in ( + PipetteNameType.P10_SINGLE, + PipetteNameType.P10_MULTI, + PipetteNameType.P50_MULTI, + PipetteNameType.P50_SINGLE, + PipetteNameType.P300_SINGLE, + PipetteNameType.P300_MULTI, + PipetteNameType.P1000_SINGLE, + ): + extra_z_offset: Optional[float] = 5.0 + else: + extra_z_offset = None if fixture_validation.is_staging_slot(params.addressableAreaName): raise LocationNotAccessibleByPipetteError( @@ -105,11 +123,19 @@ async def execute( minimum_z_height=params.minimumZHeight, speed=params.speed, stay_at_highest_possible_z=params.stayAtHighestPossibleZ, + highest_possible_z_extra_offset=extra_z_offset, + ) + deck_point = DeckPoint.construct(x=x, y=y, z=z) + state_update.set_pipette_location( + pipette_id=params.pipetteId, + new_addressable_area_name=params.addressableAreaName, + new_deck_point=deck_point, ) return SuccessData( public=MoveToAddressableAreaResult(position=DeckPoint(x=x, y=y, z=z)), private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py index ca4022c9f5c..44244dcb25c 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_addressable_area_for_drop_tip.py @@ -5,6 +5,7 @@ from typing_extensions import Literal from ..errors import LocationNotAccessibleByPipetteError +from ..state import update_types from ..types import DeckPoint, AddressableOffsetVector from ..resources import fixture_validation from .pipetting_common import ( @@ -100,6 +101,8 @@ async def execute( self, params: MoveToAddressableAreaForDropTipParams ) -> SuccessData[MoveToAddressableAreaForDropTipResult, None]: """Move the requested pipette to the requested addressable area in preperation of a drop tip.""" + state_update = update_types.StateUpdate() + self._state_view.addressable_areas.raise_if_area_not_in_deck_configuration( params.addressableAreaName ) @@ -126,12 +129,19 @@ async def execute( speed=params.speed, ignore_tip_configuration=params.ignoreTipConfiguration, ) + deck_point = DeckPoint.construct(x=x, y=y, z=z) + state_update.set_pipette_location( + pipette_id=params.pipetteId, + new_addressable_area_name=params.addressableAreaName, + new_deck_point=deck_point, + ) return SuccessData( public=MoveToAddressableAreaForDropTipResult( position=DeckPoint(x=x, y=y, z=z) ), private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py b/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py index 71e45b05e60..fbc9f20e790 100644 --- a/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py +++ b/api/src/opentrons/protocol_engine/commands/move_to_coordinates.py @@ -5,6 +5,8 @@ from typing import Optional, Type, TYPE_CHECKING from typing_extensions import Literal + +from ..state import update_types from ..types import DeckPoint from .pipetting_common import PipetteIdMixin, MovementMixin, DestinationPositionResult from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData @@ -50,6 +52,8 @@ async def execute( self, params: MoveToCoordinatesParams ) -> SuccessData[MoveToCoordinatesResult, None]: """Move the requested pipette to the requested coordinates.""" + state_update = update_types.StateUpdate() + x, y, z = await self._movement.move_to_coordinates( pipette_id=params.pipetteId, deck_coordinates=params.coordinates, @@ -57,10 +61,15 @@ async def execute( additional_min_travel_z=params.minimumZHeight, speed=params.speed, ) + deck_point = DeckPoint.construct(x=x, y=y, z=z) + state_update.pipette_location = update_types.PipetteLocationUpdate( + pipette_id=params.pipetteId, new_location=None, new_deck_point=deck_point + ) return SuccessData( public=MoveToCoordinatesResult(position=DeckPoint(x=x, y=y, z=z)), private=None, + state_update=state_update, ) diff --git a/api/src/opentrons/protocol_engine/commands/retract_axis.py b/api/src/opentrons/protocol_engine/commands/retract_axis.py index d989f1fd793..29e09acc064 100644 --- a/api/src/opentrons/protocol_engine/commands/retract_axis.py +++ b/api/src/opentrons/protocol_engine/commands/retract_axis.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Optional, Type from typing_extensions import Literal +from ..state import update_types from ..types import MotorAxis from .command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ..errors.error_occurrence import ErrorOccurrence @@ -49,8 +50,12 @@ async def execute( self, params: RetractAxisParams ) -> SuccessData[RetractAxisResult, None]: """Retract the specified axis.""" + state_update = update_types.StateUpdate() await self._movement.retract_axis(axis=params.axis) - return SuccessData(public=RetractAxisResult(), private=None) + state_update.clear_all_pipette_locations() + return SuccessData( + public=RetractAxisResult(), private=None, state_update=state_update + ) class RetractAxis(BaseCommand[RetractAxisParams, RetractAxisResult, ErrorOccurrence]): diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py index 1e0761d03ab..12e1ab4b13f 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/close_lid.py @@ -7,6 +7,7 @@ from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence +from ...state import update_types from opentrons.protocol_engine.types import MotorAxis if TYPE_CHECKING: @@ -47,6 +48,8 @@ async def execute( self, params: CloseLidParams ) -> SuccessData[CloseLidResult, None]: """Close a Thermocycler's lid.""" + state_update = update_types.StateUpdate() + thermocycler_state = self._state_view.modules.get_thermocycler_module_substate( params.moduleId ) @@ -61,11 +64,14 @@ async def execute( MotorAxis.Y, ] + self._state_view.motion.get_robot_mount_axes() await self._movement.home(axes=axes_to_home) + state_update.clear_all_pipette_locations() if thermocycler_hardware is not None: await thermocycler_hardware.close() - return SuccessData(public=CloseLidResult(), private=None) + return SuccessData( + public=CloseLidResult(), private=None, state_update=state_update + ) class CloseLid(BaseCommand[CloseLidParams, CloseLidResult, ErrorOccurrence]): diff --git a/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py b/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py index 762cf9172ed..e874a0b678c 100644 --- a/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py +++ b/api/src/opentrons/protocol_engine/commands/thermocycler/open_lid.py @@ -6,6 +6,7 @@ from pydantic import BaseModel, Field from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData +from ...state import update_types from ...errors.error_occurrence import ErrorOccurrence from opentrons.protocol_engine.types import MotorAxis @@ -43,6 +44,8 @@ def __init__( async def execute(self, params: OpenLidParams) -> SuccessData[OpenLidResult, None]: """Open a Thermocycler's lid.""" + state_update = update_types.StateUpdate() + thermocycler_state = self._state_view.modules.get_thermocycler_module_substate( params.moduleId ) @@ -57,11 +60,14 @@ async def execute(self, params: OpenLidParams) -> SuccessData[OpenLidResult, Non MotorAxis.Y, ] + self._state_view.motion.get_robot_mount_axes() await self._movement.home(axes=axes_to_home) + state_update.clear_all_pipette_locations() if thermocycler_hardware is not None: await thermocycler_hardware.open() - return SuccessData(public=OpenLidResult(), private=None) + return SuccessData( + public=OpenLidResult(), private=None, state_update=state_update + ) class OpenLid(BaseCommand[OpenLidParams, OpenLidResult, ErrorOccurrence]): diff --git a/api/src/opentrons/protocol_engine/execution/movement.py b/api/src/opentrons/protocol_engine/execution/movement.py index ae4fe27db10..a0ebbeac2b6 100644 --- a/api/src/opentrons/protocol_engine/execution/movement.py +++ b/api/src/opentrons/protocol_engine/execution/movement.py @@ -151,6 +151,7 @@ async def move_to_addressable_area( speed: Optional[float] = None, stay_at_highest_possible_z: bool = False, ignore_tip_configuration: Optional[bool] = True, + highest_possible_z_extra_offset: Optional[float] = None, ) -> Point: """Move to a specific addressable area.""" # Check for presence of heater shakers on deck, and if planned @@ -201,6 +202,7 @@ async def move_to_addressable_area( minimum_z_height=minimum_z_height, stay_at_max_travel_z=stay_at_highest_possible_z, ignore_tip_configuration=ignore_tip_configuration, + max_travel_z_extra_margin=highest_possible_z_extra_offset, ) speed = self._state_store.pipettes.get_movement_speed( diff --git a/api/src/opentrons/protocol_engine/state/motion.py b/api/src/opentrons/protocol_engine/state/motion.py index d5c9cee53bc..c58ef24ac8a 100644 --- a/api/src/opentrons/protocol_engine/state/motion.py +++ b/api/src/opentrons/protocol_engine/state/motion.py @@ -151,6 +151,7 @@ def get_movement_waypoints_to_addressable_area( minimum_z_height: Optional[float] = None, stay_at_max_travel_z: bool = False, ignore_tip_configuration: Optional[bool] = True, + max_travel_z_extra_margin: Optional[float] = None, ) -> List[motion_planning.Waypoint]: """Calculate waypoints to a destination that's specified as an addressable area.""" location = self._pipettes.get_current_location() @@ -169,7 +170,9 @@ def get_movement_waypoints_to_addressable_area( # beneath max_travel_z. Investigate why motion_planning.get_waypoints() does not # let us travel at max_travel_z, and whether it's safe to make it do that. # Possibly related: https://github.com/Opentrons/opentrons/pull/6882#discussion_r514248062 - max_travel_z - motion_planning.waypoints.MINIMUM_Z_MARGIN, + max_travel_z + - motion_planning.waypoints.MINIMUM_Z_MARGIN + - (max_travel_z_extra_margin or 0.0), ) destination = base_destination_at_max_z + Point( offset.x, offset.y, offset.z diff --git a/api/src/opentrons/protocol_engine/state/pipettes.py b/api/src/opentrons/protocol_engine/state/pipettes.py index 0ff0bf847ba..7c77bd979e4 100644 --- a/api/src/opentrons/protocol_engine/state/pipettes.py +++ b/api/src/opentrons/protocol_engine/state/pipettes.py @@ -152,7 +152,6 @@ def _handle_command( # noqa: C901 self, action: Union[SucceedCommandAction, FailCommandAction] ) -> None: self._update_current_location(action) - self._update_deck_point(action) self._update_volumes(action) if not isinstance(action, SucceedCommandAction): @@ -281,7 +280,7 @@ def _handle_command( # noqa: C901 default_dispense=tip_configuration.default_dispense_flowrate.values_by_api_level, ) - def _update_current_location( # noqa: C901 + def _update_current_location( self, action: Union[SucceedCommandAction, FailCommandAction] ) -> None: if isinstance(action, SucceedCommandAction): @@ -293,8 +292,17 @@ def _update_current_location( # noqa: C901 assert_type(action.error, EnumeratedError) return - if location_update != update_types.NO_CHANGE: - match location_update.new_location: + if location_update is update_types.NO_CHANGE: + pass + elif location_update is update_types.CLEAR: + self._state.current_location = None + self._state.current_deck_point = CurrentDeckPoint( + mount=None, deck_point=None + ) + else: + new_logical_location = location_update.new_location + new_deck_point = location_update.new_deck_point + match new_logical_location: case update_types.Well(labware_id=labware_id, well_name=well_name): self._state.current_location = CurrentWell( pipette_id=location_update.pipette_id, @@ -312,142 +320,11 @@ def _update_current_location( # noqa: C901 self._state.current_location = None case update_types.NO_CHANGE: pass - - # todo(mm, 2024-08-29): Port the following isinstance() checks to - # use `state_update`. https://opentrons.atlassian.net/browse/EXEC-639 - - # These commands leave the pipette in a new location. - # Update current_location to reflect that. - if isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, - ( - commands.MoveToAddressableAreaResult, - commands.MoveToAddressableAreaForDropTipResult, - ), - ): - self._state.current_location = CurrentAddressableArea( - pipette_id=action.command.params.pipetteId, - addressable_area_name=action.command.params.addressableAreaName, - ) - - # These commands leave the pipette in a place that we can't logically associate - # with a well. Clear current_location to reflect the fact that it's now unknown. - # - # TODO(mc, 2021-11-12): Wipe out current_location on movement failures, too. - # TODO(jbl 2023-02-14): Need to investigate whether move relative should clear current location - elif isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, - ( - commands.HomeResult, - commands.RetractAxisResult, - commands.MoveToCoordinatesResult, - commands.thermocycler.OpenLidResult, - commands.thermocycler.CloseLidResult, - ), - ): - self._state.current_location = None - - # Heater-Shaker commands may have left the pipette in a place that we can't - # associate with a logical location, depending on their result. - elif isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, - ( - commands.heater_shaker.SetAndWaitForShakeSpeedResult, - commands.heater_shaker.OpenLabwareLatchResult, - ), - ): - if action.command.result.pipetteRetracted: - self._state.current_location = None - - # A moveLabware command may have moved the labware that contains the current - # well out from under the pipette. Clear the current location to reflect the - # fact that the pipette is no longer over any labware. - # - # This is necessary for safe motion planning in case the next movement - # goes to the same labware (now in a new place). - elif isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, commands.MoveLabwareResult - ): - moved_labware_id = action.command.params.labwareId - if action.command.params.strategy == "usingGripper": - # All mounts will have been retracted. - self._state.current_location = None - elif ( - isinstance(self._state.current_location, CurrentWell) - and self._state.current_location.labware_id == moved_labware_id - ): - self._state.current_location = None - - def _update_deck_point( # noqa: C901 - self, action: Union[SucceedCommandAction, FailCommandAction] - ) -> None: - if isinstance(action, SucceedCommandAction): - location_update = action.state_update.pipette_location - elif isinstance(action.error, DefinedErrorData): - location_update = action.error.state_update.pipette_location - else: - # The command failed with some undefined error. We have nothing to do. - assert_type(action.error, EnumeratedError) - return - - if ( - location_update is not update_types.NO_CHANGE - and location_update.new_deck_point is not update_types.NO_CHANGE - ): - loaded_pipette = self._state.pipettes_by_id[location_update.pipette_id] - self._state.current_deck_point = CurrentDeckPoint( - mount=loaded_pipette.mount, deck_point=location_update.new_deck_point - ) - - # todo(mm, 2024-08-29): Port the following isinstance() checks to - # use `state_update`. https://opentrons.atlassian.net/browse/EXEC-639 - # - # These isinstance() checks mostly mirror self._update_current_location(). - # See there for explanations. - - if isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, - ( - commands.MoveToCoordinatesResult, - commands.MoveRelativeResult, - commands.MoveToAddressableAreaResult, - commands.MoveToAddressableAreaForDropTipResult, - ), - ): - pipette_id = action.command.params.pipetteId - deck_point = action.command.result.position - loaded_pipette = self._state.pipettes_by_id[pipette_id] - self._state.current_deck_point = CurrentDeckPoint( - mount=loaded_pipette.mount, deck_point=deck_point - ) - - elif isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, - ( - commands.HomeResult, - commands.RetractAxisResult, - commands.thermocycler.OpenLidResult, - commands.thermocycler.CloseLidResult, - ), - ): - self._clear_deck_point() - - elif isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, - ( - commands.heater_shaker.SetAndWaitForShakeSpeedResult, - commands.heater_shaker.OpenLabwareLatchResult, - ), - ): - if action.command.result.pipetteRetracted: - self._clear_deck_point() - - elif isinstance(action, SucceedCommandAction) and isinstance( - action.command.result, commands.MoveLabwareResult - ): - if action.command.params.strategy == "usingGripper": - # All mounts will have been retracted. - self._clear_deck_point() + if new_deck_point is not update_types.NO_CHANGE: + loaded_pipette = self._state.pipettes_by_id[location_update.pipette_id] + self._state.current_deck_point = CurrentDeckPoint( + mount=loaded_pipette.mount, deck_point=new_deck_point + ) def _update_volumes( self, action: Union[SucceedCommandAction, FailCommandAction] @@ -492,10 +369,6 @@ def _update_volumes( pipette_id = action.command.params.pipetteId self._state.aspirated_volume_by_id[pipette_id] = 0 - def _clear_deck_point(self) -> None: - """Reset last deck point to default None value for mount and point.""" - self._state.current_deck_point = CurrentDeckPoint(mount=None, deck_point=None) - class PipetteView(HasState[PipetteState]): """Read-only view of computed pipettes state.""" diff --git a/api/src/opentrons/protocol_engine/state/update_types.py b/api/src/opentrons/protocol_engine/state/update_types.py index a71b1897b42..230e967bb07 100644 --- a/api/src/opentrons/protocol_engine/state/update_types.py +++ b/api/src/opentrons/protocol_engine/state/update_types.py @@ -26,6 +26,24 @@ class _NoChangeEnum(enum.Enum): """ +class _ClearEnum(enum.Enum): + CLEAR = enum.auto() + + +CLEAR: typing.Final = _ClearEnum.CLEAR +"""A sentinel value to indicate that a value should be cleared. + +Useful when `None` is semantically unclear or has some other meaning. +""" + + +ClearType: typing.TypeAlias = typing.Literal[_ClearEnum.CLEAR] +"""The type of `CLEAR`, as `NoneType` is to `None`. + +Unfortunately, mypy doesn't let us write `Literal[CLEAR]`. Use this instead. +""" + + @dataclasses.dataclass(frozen=True) class Well: """Designates a well in a labware.""" @@ -61,10 +79,7 @@ class PipetteLocationUpdate: class StateUpdate: """Represents an update to perform on engine state.""" - # todo(mm, 2024-08-29): Extend this with something to represent clearing both the - # deck point and the logical location, for e.g. home commands. Consider an explicit - # `CLEAR` sentinel if `None` is confusing. - pipette_location: PipetteLocationUpdate | NoChangeType = NO_CHANGE + pipette_location: PipetteLocationUpdate | NoChangeType | ClearType = NO_CHANGE # These convenience functions let the caller avoid the boilerplate of constructing a # complicated dataclass tree, and they give us a @@ -118,3 +133,7 @@ def set_pipette_location( # noqa: D102 new_location=Well(labware_id=new_labware_id, well_name=new_well_name), new_deck_point=new_deck_point, ) + + def clear_all_pipette_locations(self) -> None: + """Mark all pipettes as having an unknown location.""" + self.pipette_location = CLEAR diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py index 3a834d7a410..6a5e7e97db2 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_open_labware_latch.py @@ -1,8 +1,10 @@ """Test Heater Shaker open labware latch command implementation.""" from decoy import Decoy +import pytest from opentrons.hardware_control.modules import HeaterShaker +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.state.state import StateView from opentrons.protocol_engine.state.module_substates import ( HeaterShakerModuleSubState, @@ -17,11 +19,20 @@ from opentrons.protocol_engine.types import MotorAxis +@pytest.mark.parametrize( + ("pipette_blocking_hs_latch", "expect_pipette_retracted"), + [ + (False, False), + (True, True), + ], +) async def test_open_labware_latch( decoy: Decoy, state_view: StateView, equipment: EquipmentHandler, movement: MovementHandler, + pipette_blocking_hs_latch: bool, + expect_pipette_retracted: bool, ) -> None: """It should be able to open the module's labware latch.""" subject = OpenLabwareLatchImpl( @@ -46,7 +57,7 @@ async def test_open_labware_latch( state_view.motion.check_pipette_blocking_hs_latch( HeaterShakerModuleId("heater-shaker-id") ) - ).then_return(True) + ).then_return(pipette_blocking_hs_latch) # Get stubbed hardware module decoy.when( @@ -55,14 +66,23 @@ async def test_open_labware_latch( decoy.when(state_view.motion.get_robot_mount_axes()).then_return( [MotorAxis.EXTENSION_Z] ) + result = await subject.execute(data) - decoy.verify( - hs_module_substate.raise_if_shaking(), - await movement.home( - [MotorAxis.EXTENSION_Z], - ), - await hs_hardware.open_labware_latch(), - ) + + decoy.verify(hs_module_substate.raise_if_shaking()) + if expect_pipette_retracted: + decoy.verify( + await movement.home( + [MotorAxis.EXTENSION_Z], + ) + ) + decoy.verify(await hs_hardware.open_labware_latch()) assert result == SuccessData( - public=heater_shaker.OpenLabwareLatchResult(pipetteRetracted=True), private=None + public=heater_shaker.OpenLabwareLatchResult( + pipetteRetracted=expect_pipette_retracted + ), + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR) + if expect_pipette_retracted + else update_types.StateUpdate(), ) diff --git a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py index 6d2b6cae716..005f46f89cb 100644 --- a/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py +++ b/api/tests/opentrons/protocol_engine/commands/heater_shaker/test_set_and_wait_for_shake_speed.py @@ -1,8 +1,10 @@ """Test Heater Shaker set shake speed command implementation.""" from decoy import Decoy +import pytest from opentrons.hardware_control.modules import HeaterShaker +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.state.state import StateView from opentrons.protocol_engine.state.module_substates import ( HeaterShakerModuleSubState, @@ -17,11 +19,20 @@ from opentrons.protocol_engine.types import MotorAxis +@pytest.mark.parametrize( + ("pipette_blocking_hs_shaker", "expect_pipette_retracted"), + [ + (False, False), + (True, True), + ], +) async def test_set_and_wait_for_shake_speed( decoy: Decoy, state_view: StateView, equipment: EquipmentHandler, movement: MovementHandler, + pipette_blocking_hs_shaker: bool, + expect_pipette_retracted: bool, ) -> None: """It should be able to set the module's shake speed.""" subject = SetAndWaitForShakeSpeedImpl( @@ -49,7 +60,7 @@ async def test_set_and_wait_for_shake_speed( state_view.motion.check_pipette_blocking_hs_shaker( HeaterShakerModuleId("heater-shaker-id") ) - ).then_return(True) + ).then_return(pipette_blocking_hs_shaker) # Stub speed validation from hs module view decoy.when(hs_module_substate.validate_target_speed(rpm=1234.56)).then_return(1234) @@ -61,15 +72,20 @@ async def test_set_and_wait_for_shake_speed( decoy.when(state_view.motion.get_robot_mount_axes()).then_return( [MotorAxis.EXTENSION_Z] ) + result = await subject.execute(data) - decoy.verify( - hs_module_substate.raise_if_labware_latch_not_closed(), - await movement.home( - [MotorAxis.EXTENSION_Z], - ), - await hs_hardware.set_speed(rpm=1234), - ) + + decoy.verify(hs_module_substate.raise_if_labware_latch_not_closed()) + if expect_pipette_retracted: + decoy.verify(await movement.home([MotorAxis.EXTENSION_Z])) + decoy.verify(await hs_hardware.set_speed(rpm=1234)) + assert result == SuccessData( - public=heater_shaker.SetAndWaitForShakeSpeedResult(pipetteRetracted=True), + public=heater_shaker.SetAndWaitForShakeSpeedResult( + pipetteRetracted=expect_pipette_retracted + ), private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR) + if expect_pipette_retracted + else update_types.StateUpdate(), ) diff --git a/api/tests/opentrons/protocol_engine/commands/test_home.py b/api/tests/opentrons/protocol_engine/commands/test_home.py index f68c1b6de27..5a9446d6308 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_home.py +++ b/api/tests/opentrons/protocol_engine/commands/test_home.py @@ -1,6 +1,7 @@ """Test home commands.""" from decoy import Decoy +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.types import MotorAxis from opentrons.types import MountType from opentrons.protocol_engine.execution import MovementHandler @@ -21,7 +22,11 @@ async def test_home_implementation(decoy: Decoy, movement: MovementHandler) -> N result = await subject.execute(data) - assert result == SuccessData(public=HomeResult(), private=None) + assert result == SuccessData( + public=HomeResult(), + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) decoy.verify(await movement.home(axes=[MotorAxis.X, MotorAxis.Y])) @@ -33,7 +38,11 @@ async def test_home_all_implementation(decoy: Decoy, movement: MovementHandler) result = await subject.execute(data) - assert result == SuccessData(public=HomeResult(), private=None) + assert result == SuccessData( + public=HomeResult(), + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) decoy.verify(await movement.home(axes=None)) @@ -52,7 +61,11 @@ async def test_home_with_invalid_position( ) result = await subject.execute(data) - assert result == SuccessData(public=HomeResult(), private=None) + assert result == SuccessData( + public=HomeResult(), + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) decoy.verify(await movement.home(axes=[MotorAxis.X, MotorAxis.Y]), times=1) decoy.reset() @@ -61,6 +74,10 @@ async def test_home_with_invalid_position( await movement.check_for_valid_position(mount=MountType.LEFT) ).then_return(True) result = await subject.execute(data) - assert result == SuccessData(public=HomeResult(), private=None) + assert result == SuccessData( + public=HomeResult(), + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) decoy.verify(await movement.home(axes=[MotorAxis.X, MotorAxis.Y]), times=0) diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_labware.py b/api/tests/opentrons/protocol_engine/commands/test_move_labware.py index f523a8bd2d9..b80da9d902d 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_labware.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_labware.py @@ -6,11 +6,13 @@ from opentrons_shared_data.labware.labware_definition import Parameters, Dimensions from opentrons_shared_data.gripper.constants import GRIPPER_PADDLE_WIDTH +from opentrons.protocol_engine.state import update_types from opentrons.types import DeckSlotName, Point from opentrons.protocols.models import LabwareDefinition from opentrons.protocol_engine import errors, Config from opentrons.protocol_engine.resources import labware_validation from opentrons.protocol_engine.types import ( + CurrentWell, DeckSlotLocation, ModuleLocation, OnLabwareLocation, @@ -258,6 +260,65 @@ async def test_gripper_move_labware_implementation( offsetId="wowzers-a-new-offset-id", ), private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) + + +@pytest.mark.parametrize( + ("current_labware_id", "moved_labware_id", "expect_cleared_location"), + [ + ("lw1", "lw2", False), + ("lw1", "lw1", True), + ], +) +async def test_clears_location_if_current_labware_moved_from_under_pipette( + decoy: Decoy, + equipment: EquipmentHandler, + labware_movement: LabwareMovementHandler, + state_view: StateView, + run_control: RunControlHandler, + current_labware_id: str, + moved_labware_id: str, + expect_cleared_location: bool, +) -> None: + """If it moves the labware that the pipette is currently over, it should clear the location.""" + subject = MoveLabwareImplementation( + state_view=state_view, + equipment=equipment, + labware_movement=labware_movement, + run_control=run_control, + ) + + from_location = DeckSlotLocation(slotName=DeckSlotName.SLOT_A1) + to_location = DeckSlotLocation(slotName=DeckSlotName.SLOT_A2) + + decoy.when(state_view.labware.get(labware_id=moved_labware_id)).then_return( + LoadedLabware( + id=moved_labware_id, + loadName="load-name", + definitionUri="opentrons-test/load-name/1", + location=from_location, + offsetId=None, + ) + ) + + decoy.when(state_view.pipettes.get_current_location()).then_return( + CurrentWell( + pipette_id="pipette-id", labware_id=current_labware_id, well_name="A1" + ) + ) + + result = await subject.execute( + params=MoveLabwareParams( + labwareId=moved_labware_id, + newLocation=to_location, + strategy=LabwareMovementStrategy.MANUAL_MOVE_WITHOUT_PAUSE, + ) + ) + assert ( + result.state_update.pipette_location == update_types.CLEAR + if expect_cleared_location + else update_types.NO_CHANGE ) @@ -348,6 +409,7 @@ async def test_gripper_move_to_waste_chute_implementation( offsetId="wowzers-a-new-offset-id", ), private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), ) diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_relative.py b/api/tests/opentrons/protocol_engine/commands/test_move_relative.py index f8f49956721..ee874206f92 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_relative.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_relative.py @@ -1,6 +1,7 @@ """Test move relative commands.""" from decoy import Decoy +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.types import DeckPoint, MovementAxis from opentrons.protocol_engine.execution import MovementHandler from opentrons.types import Point @@ -36,5 +37,13 @@ async def test_move_relative_implementation( result = await subject.execute(data) assert result == SuccessData( - public=MoveRelativeResult(position=DeckPoint(x=1, y=2, z=3)), private=None + public=MoveRelativeResult(position=DeckPoint(x=1, y=2, z=3)), + private=None, + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="pipette-id", + new_location=update_types.NO_CHANGE, + new_deck_point=DeckPoint(x=1, y=2, z=3), + ) + ), ) diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py index 95d80d86590..2b64f617b9f 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area.py @@ -1,10 +1,13 @@ """Test move to addressable area commands.""" from decoy import Decoy +import pytest -from opentrons.protocol_engine import DeckPoint, AddressableOffsetVector +from opentrons_shared_data.pipette.types import PipetteNameType +from opentrons.protocol_engine import DeckPoint, AddressableOffsetVector, LoadedPipette from opentrons.protocol_engine.execution import MovementHandler +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.state.state import StateView -from opentrons.types import Point +from opentrons.types import Point, MountType from opentrons.protocol_engine.commands.command import SuccessData from opentrons.protocol_engine.commands.move_to_addressable_area import ( @@ -14,10 +17,92 @@ ) -async def test_move_to_addressable_area_implementation( +@pytest.mark.parametrize( + "pipette_name", + ( + pipette_name + for pipette_name in PipetteNameType + if pipette_name + not in ( + PipetteNameType.P10_SINGLE, + PipetteNameType.P10_MULTI, + PipetteNameType.P50_MULTI, + PipetteNameType.P50_SINGLE, + PipetteNameType.P300_SINGLE, + PipetteNameType.P300_MULTI, + PipetteNameType.P1000_SINGLE, + ) + ), +) +async def test_move_to_addressable_area_implementation_non_gen1( + decoy: Decoy, + state_view: StateView, + movement: MovementHandler, + pipette_name: PipetteNameType, +) -> None: + """A MoveToAddressableArea command should have an execution implementation.""" + subject = MoveToAddressableAreaImplementation( + movement=movement, state_view=state_view + ) + + data = MoveToAddressableAreaParams( + pipetteId="abc", + addressableAreaName="123", + offset=AddressableOffsetVector(x=1, y=2, z=3), + forceDirect=True, + minimumZHeight=4.56, + speed=7.89, + stayAtHighestPossibleZ=True, + ) + + decoy.when(state_view.pipettes.get("abc")).then_return( + LoadedPipette(id="abc", pipetteName=pipette_name, mount=MountType.LEFT) + ) + decoy.when( + await movement.move_to_addressable_area( + pipette_id="abc", + addressable_area_name="123", + offset=AddressableOffsetVector(x=1, y=2, z=3), + force_direct=True, + minimum_z_height=4.56, + speed=7.89, + stay_at_highest_possible_z=True, + highest_possible_z_extra_offset=None, + ) + ).then_return(Point(x=9, y=8, z=7)) + + result = await subject.execute(data) + + assert result == SuccessData( + public=MoveToAddressableAreaResult(position=DeckPoint(x=9, y=8, z=7)), + private=None, + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="abc", + new_location=update_types.AddressableArea(addressable_area_name="123"), + new_deck_point=DeckPoint(x=9, y=8, z=7), + ) + ), + ) + + +@pytest.mark.parametrize( + "pipette_name", + ( + PipetteNameType.P10_SINGLE, + PipetteNameType.P10_MULTI, + PipetteNameType.P50_MULTI, + PipetteNameType.P50_SINGLE, + PipetteNameType.P300_SINGLE, + PipetteNameType.P300_MULTI, + PipetteNameType.P1000_SINGLE, + ), +) +async def test_move_to_addressable_area_implementation_with_gen1( decoy: Decoy, state_view: StateView, movement: MovementHandler, + pipette_name: PipetteNameType, ) -> None: """A MoveToAddressableArea command should have an execution implementation.""" subject = MoveToAddressableAreaImplementation( @@ -34,6 +119,9 @@ async def test_move_to_addressable_area_implementation( stayAtHighestPossibleZ=True, ) + decoy.when(state_view.pipettes.get("abc")).then_return( + LoadedPipette(id="abc", pipetteName=pipette_name, mount=MountType.LEFT) + ) decoy.when( await movement.move_to_addressable_area( pipette_id="abc", @@ -43,6 +131,7 @@ async def test_move_to_addressable_area_implementation( minimum_z_height=4.56, speed=7.89, stay_at_highest_possible_z=True, + highest_possible_z_extra_offset=5.0, ) ).then_return(Point(x=9, y=8, z=7)) @@ -51,4 +140,11 @@ async def test_move_to_addressable_area_implementation( assert result == SuccessData( public=MoveToAddressableAreaResult(position=DeckPoint(x=9, y=8, z=7)), private=None, + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="abc", + new_location=update_types.AddressableArea(addressable_area_name="123"), + new_deck_point=DeckPoint(x=9, y=8, z=7), + ) + ), ) diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py index bea5ebc6bca..ebcb3db1243 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_addressable_area_for_drop_tip.py @@ -3,6 +3,7 @@ from opentrons.protocol_engine import DeckPoint, AddressableOffsetVector from opentrons.protocol_engine.execution import MovementHandler +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.state.state import StateView from opentrons.types import Point @@ -58,4 +59,11 @@ async def test_move_to_addressable_area_for_drop_tip_implementation( assert result == SuccessData( public=MoveToAddressableAreaForDropTipResult(position=DeckPoint(x=9, y=8, z=7)), private=None, + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="abc", + new_location=update_types.AddressableArea(addressable_area_name="123"), + new_deck_point=DeckPoint(x=9, y=8, z=7), + ) + ), ) diff --git a/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py b/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py index 6038ea9ef6e..81d74657953 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py +++ b/api/tests/opentrons/protocol_engine/commands/test_move_to_coordinates.py @@ -3,6 +3,7 @@ from opentrons.hardware_control import HardwareControlAPI from opentrons.protocol_engine.execution import MovementHandler +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.state.state import StateView from opentrons.protocol_engine.types import DeckPoint from opentrons.types import Point @@ -58,4 +59,11 @@ async def test_move_to_coordinates_implementation( assert result == SuccessData( public=MoveToCoordinatesResult(position=DeckPoint(x=4.44, y=5.55, z=6.66)), private=None, + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="pipette-id", + new_location=None, + new_deck_point=DeckPoint(x=4.44, y=5.55, z=6.66), + ) + ), ) diff --git a/api/tests/opentrons/protocol_engine/commands/test_retract_axis.py b/api/tests/opentrons/protocol_engine/commands/test_retract_axis.py index a580875d779..7442460f9b1 100644 --- a/api/tests/opentrons/protocol_engine/commands/test_retract_axis.py +++ b/api/tests/opentrons/protocol_engine/commands/test_retract_axis.py @@ -1,6 +1,7 @@ """Test retractAxis command.""" from decoy import Decoy +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.types import MotorAxis from opentrons.protocol_engine.execution import MovementHandler @@ -22,5 +23,9 @@ async def test_retract_axis_implementation( data = RetractAxisParams(axis=MotorAxis.Y) result = await subject.execute(data) - assert result == SuccessData(public=RetractAxisResult(), private=None) + assert result == SuccessData( + public=RetractAxisResult(), + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) decoy.verify(await movement.retract_axis(axis=MotorAxis.Y)) diff --git a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py index 101af301946..0a3fc6e9fdf 100644 --- a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py +++ b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_close_lid.py @@ -3,6 +3,7 @@ from opentrons.hardware_control.modules import Thermocycler +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.types import MotorAxis from opentrons.protocol_engine.state.state import StateView from opentrons.protocol_engine.state.module_substates import ( @@ -55,4 +56,8 @@ async def test_close_lid( await tc_hardware.close(), times=1, ) - assert result == SuccessData(public=expected_result, private=None) + assert result == SuccessData( + public=expected_result, + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) diff --git a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py index 2d665138306..a3e547a88d7 100644 --- a/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py +++ b/api/tests/opentrons/protocol_engine/commands/thermocycler/test_open_lid.py @@ -3,6 +3,7 @@ from opentrons.hardware_control.modules import Thermocycler +from opentrons.protocol_engine.state import update_types from opentrons.protocol_engine.types import MotorAxis from opentrons.protocol_engine.state.state import StateView from opentrons.protocol_engine.state.module_substates import ( @@ -53,4 +54,8 @@ async def test_open_lid( await tc_hardware.open(), times=1, ) - assert result == SuccessData(public=expected_result, private=None) + assert result == SuccessData( + public=expected_result, + private=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) diff --git a/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py b/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py index 7737775c4fb..0fd5134aa27 100644 --- a/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py +++ b/api/tests/opentrons/protocol_engine/execution/test_movement_handler.py @@ -1,7 +1,7 @@ """MovementHandler command subject.""" import pytest from decoy import Decoy -from typing import NamedTuple +from typing import NamedTuple, Optional from opentrons.types import MountType, Point, DeckSlotName, Mount from opentrons.hardware_control import API as HardwareAPI @@ -297,6 +297,10 @@ async def test_move_to_well_from_starting_location( ) +@pytest.mark.parametrize( + "stay_at_max_z,z_extra_offset", + [(True, None), (True, 5.0), (False, None), (False, 5.0)], +) async def test_move_to_addressable_area( decoy: Decoy, state_store: StateStore, @@ -304,6 +308,8 @@ async def test_move_to_addressable_area( heater_shaker_movement_flagger: HeaterShakerMovementFlagger, mock_gantry_mover: GantryMover, subject: MovementHandler, + stay_at_max_z: bool, + z_extra_offset: Optional[float], ) -> None: """Move requests should call hardware controller with movement data.""" decoy.when( @@ -353,8 +359,9 @@ async def test_move_to_addressable_area( max_travel_z=42.0, force_direct=True, minimum_z_height=12.3, - stay_at_max_travel_z=True, + stay_at_max_travel_z=stay_at_max_z, ignore_tip_configuration=False, + max_travel_z_extra_margin=z_extra_offset, ) ).then_return( [Waypoint(Point(1, 2, 3), CriticalPoint.XY_CENTER), Waypoint(Point(4, 5, 6))] @@ -378,8 +385,9 @@ async def test_move_to_addressable_area( force_direct=True, minimum_z_height=12.3, speed=45.6, - stay_at_highest_possible_z=True, + stay_at_highest_possible_z=stay_at_max_z, ignore_tip_configuration=False, + highest_possible_z_extra_offset=z_extra_offset, ) assert result == Point(x=4, y=5, z=6) diff --git a/api/tests/opentrons/protocol_engine/state/test_pipette_store.py b/api/tests/opentrons/protocol_engine/state/test_pipette_store.py index 22c58b77e5b..0ba973e4cd1 100644 --- a/api/tests/opentrons/protocol_engine/state/test_pipette_store.py +++ b/api/tests/opentrons/protocol_engine/state/test_pipette_store.py @@ -1,27 +1,21 @@ """Tests for pipette state changes in the protocol_engine state store.""" import pytest -from datetime import datetime -from typing import Optional, Union from opentrons_shared_data.pipette.types import PipetteNameType from opentrons_shared_data.pipette import pipette_definition from opentrons.protocol_engine.state import update_types -from opentrons.types import DeckSlotName, MountType, Point +from opentrons.types import MountType, Point from opentrons.protocol_engine import commands as cmd from opentrons.protocol_engine.types import ( CurrentAddressableArea, DeckPoint, - DeckSlotLocation, LoadedPipette, - OFF_DECK_LOCATION, - LabwareMovementStrategy, FlowRates, CurrentWell, TipGeometry, ) from opentrons.protocol_engine.actions import ( - FailCommandAction, SetPipetteMovementSpeedAction, SucceedCommandAction, ) @@ -48,12 +42,8 @@ create_drop_tip_in_place_command, create_succeeded_command, create_unsafe_drop_tip_in_place_command, - create_move_to_well_command, create_blow_out_command, create_blow_out_in_place_command, - create_move_labware_command, - create_move_to_coordinates_command, - create_move_relative_command, create_prepare_to_aspirate_command, create_unsafe_blow_out_in_place_command, ) @@ -66,35 +56,6 @@ def subject() -> PipetteStore: return PipetteStore() -def _create_move_to_well_action( - pipette_id: str, - labware_id: str, - well_name: str, - deck_point: DeckPoint, -) -> SucceedCommandAction: - command = create_move_to_well_command( - pipette_id=pipette_id, - labware_id=labware_id, - well_name=well_name, - destination=deck_point, - ) - action = SucceedCommandAction( - command=command, - private_result=None, - state_update=update_types.StateUpdate( - pipette_location=update_types.PipetteLocationUpdate( - pipette_id=pipette_id, - new_location=update_types.Well( - labware_id=labware_id, - well_name=well_name, - ), - new_deck_point=deck_point, - ) - ), - ) - return action - - def test_sets_initial_state(subject: PipetteStore) -> None: """It should initialize its state object properly.""" result = subject.state @@ -191,6 +152,38 @@ def test_location_state_update(subject: PipetteStore) -> None: mount=MountType.RIGHT, deck_point=DeckPoint(x=333, y=444, z=555) ) + # Repopulate the locations, then test clearing all pipette locations: + subject.handle_action( + SucceedCommandAction( + command=dummy_command, + private_result=None, + state_update=update_types.StateUpdate( + pipette_location=update_types.PipetteLocationUpdate( + pipette_id="pipette-id", + new_location=update_types.AddressableArea( + addressable_area_name="na na na na na" + ), + new_deck_point=DeckPoint(x=333, y=444, z=555), + ) + ), + ) + ) + assert subject.state.current_location is not None + assert subject.state.current_deck_point != CurrentDeckPoint( + mount=None, deck_point=None + ) + subject.handle_action( + SucceedCommandAction( + command=dummy_command, + private_result=None, + state_update=update_types.StateUpdate(pipette_location=update_types.CLEAR), + ) + ) + assert subject.state.current_location is None + assert subject.state.current_deck_point == CurrentDeckPoint( + mount=None, deck_point=None + ) + def test_handles_load_pipette(subject: PipetteStore) -> None: """It should add the pipette data to the state.""" @@ -434,260 +427,6 @@ def test_blow_out_clears_volume( assert subject.state.aspirated_volume_by_id["pipette-id"] is None -@pytest.mark.parametrize( - "command", - [ - cmd.Home( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.HomeParams(), - result=cmd.HomeResult(), - ), - cmd.MoveToCoordinates( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.MoveToCoordinatesParams( - pipetteId="pipette-id", - coordinates=DeckPoint(x=1.1, y=2.2, z=3.3), - ), - result=cmd.MoveToCoordinatesResult(), - ), - cmd.thermocycler.OpenLid( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.thermocycler.OpenLidParams(moduleId="xyz"), - result=cmd.thermocycler.OpenLidResult(), - ), - cmd.thermocycler.CloseLid( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.thermocycler.CloseLidParams(moduleId="xyz"), - result=cmd.thermocycler.CloseLidResult(), - ), - cmd.heater_shaker.SetAndWaitForShakeSpeed( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.heater_shaker.SetAndWaitForShakeSpeedParams( - moduleId="xyz", - rpm=123, - ), - result=cmd.heater_shaker.SetAndWaitForShakeSpeedResult( - pipetteRetracted=True - ), - ), - cmd.heater_shaker.OpenLabwareLatch( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.heater_shaker.OpenLabwareLatchParams(moduleId="xyz"), - result=cmd.heater_shaker.OpenLabwareLatchResult(pipetteRetracted=True), - ), - ], -) -def test_movement_commands_without_well_clear_current_well( - subject: PipetteStore, command: cmd.Command -) -> None: - """Commands that make the current well unknown should clear the current well.""" - load_pipette_command = create_load_pipette_command( - pipette_id="pipette-id", - pipette_name=PipetteNameType.P300_SINGLE, - mount=MountType.LEFT, - ) - subject.handle_action( - SucceedCommandAction(private_result=None, command=load_pipette_command) - ) - - subject.handle_action( - _create_move_to_well_action( - pipette_id="pipette-id", - labware_id="labware-id", - well_name="well-name", - deck_point=DeckPoint(x=1, y=2, z=3), - ) - ) - - subject.handle_action(SucceedCommandAction(command=command, private_result=None)) - - assert subject.state.current_location is None - - -@pytest.mark.parametrize( - "command", - [ - cmd.heater_shaker.SetAndWaitForShakeSpeed( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.heater_shaker.SetAndWaitForShakeSpeedParams( - moduleId="xyz", - rpm=123, - ), - result=cmd.heater_shaker.SetAndWaitForShakeSpeedResult( - pipetteRetracted=False - ), - ), - cmd.heater_shaker.OpenLabwareLatch( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.heater_shaker.OpenLabwareLatchParams(moduleId="xyz"), - result=cmd.heater_shaker.OpenLabwareLatchResult(pipetteRetracted=False), - ), - ], -) -def test_heater_shaker_command_without_movement( - subject: PipetteStore, command: cmd.Command -) -> None: - """Heater Shaker commands that don't move pipettes shouldn't clear current_well or deck point.""" - load_pipette_command = create_load_pipette_command( - pipette_id="pipette-id", - pipette_name=PipetteNameType.P300_SINGLE, - mount=MountType.LEFT, - ) - subject.handle_action( - SucceedCommandAction(private_result=None, command=load_pipette_command) - ) - - subject.handle_action( - _create_move_to_well_action( - pipette_id="pipette-id", - labware_id="labware-id", - well_name="well-name", - deck_point=DeckPoint(x=1, y=2, z=3), - ) - ) - - subject.handle_action(SucceedCommandAction(private_result=None, command=command)) - - assert subject.state.current_location == CurrentWell( - pipette_id="pipette-id", - labware_id="labware-id", - well_name="well-name", - ) - - assert subject.state.current_deck_point == CurrentDeckPoint( - mount=MountType.LEFT, deck_point=DeckPoint(x=1, y=2, z=3) - ) - - -@pytest.mark.parametrize( - ("move_labware_command", "expected_current_well"), - ( - ( - create_move_labware_command( - labware_id="non-matching-labware-id", - strategy=LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE, - new_location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), - offset_id=None, - ), - # Current well NOT cleared, - # because MoveLabware command had "non-matching-labware-id". - CurrentWell( - pipette_id="pipette-id", - labware_id="matching-labware-id", - well_name="well-name", - ), - ), - ( - create_move_labware_command( - labware_id="matching-labware-id", - strategy=LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE, - new_location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), - offset_id=None, - ), - # Current well IS cleared, - # because MoveLabware command had "matching-labware-id". - None, - ), - ( - create_move_labware_command( - labware_id="non-matching-labware-id", - strategy=LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE, - new_location=OFF_DECK_LOCATION, - offset_id=None, - ), - # Current well NOT cleared, - # because MoveLabware command had "non-matching-labware-id". - CurrentWell( - pipette_id="pipette-id", - labware_id="matching-labware-id", - well_name="well-name", - ), - ), - ( - create_move_labware_command( - labware_id="matching-labware-id", - strategy=LabwareMovementStrategy.MANUAL_MOVE_WITH_PAUSE, - new_location=OFF_DECK_LOCATION, - offset_id=None, - ), - # Current well IS cleared, - # because MoveLabware command had "matching-labware-id". - None, - ), - ( - create_move_labware_command( - labware_id="non-matching-labware-id", - new_location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), - strategy=LabwareMovementStrategy.USING_GRIPPER, - offset_id=None, - ), - # Current well IS cleared, - # because MoveLabware command used gripper. - None, - ), - ), -) -def test_move_labware_clears_current_well( - subject: PipetteStore, - move_labware_command: cmd.MoveLabware, - expected_current_well: Optional[CurrentWell], -) -> None: - """Labware movement commands should sometimes clear the current well. - - It should be cleared when- - * the current well belongs to the labware that was moved, - * or gripper was used to move labware - - Otherwise, it should be left alone. - """ - load_pipette_command = create_load_pipette_command( - pipette_id="pipette-id", - pipette_name=PipetteNameType.P300_SINGLE, - mount=MountType.LEFT, - ) - subject.handle_action( - SucceedCommandAction(private_result=None, command=load_pipette_command) - ) - - subject.handle_action( - _create_move_to_well_action( - pipette_id="pipette-id", - labware_id="matching-labware-id", - well_name="well-name", - deck_point=DeckPoint(x=1, y=2, z=3), - ) - ) - - subject.handle_action( - SucceedCommandAction(private_result=None, command=move_labware_command) - ) - assert subject.state.current_location == expected_current_well - - def test_set_movement_speed(subject: PipetteStore) -> None: """It should issue an action to set the movement speed.""" pipette_id = "pipette-id" @@ -773,131 +512,6 @@ def test_add_pipette_config( assert subject.state.flow_rates_by_id["pipette-id"].default_blow_out == {"c": 3.0} -@pytest.mark.parametrize( - "action", - ( - SucceedCommandAction( - command=create_move_to_coordinates_command( - pipette_id="pipette-id", - coordinates=DeckPoint(x=11, y=22, z=33), - ), - private_result=None, - ), - SucceedCommandAction( - command=create_move_relative_command( - pipette_id="pipette-id", - destination=DeckPoint(x=11, y=22, z=33), - ), - private_result=None, - ), - ), -) -def test_movement_commands_update_deck_point( - action: Union[SucceedCommandAction, FailCommandAction], - subject: PipetteStore, -) -> None: - """It should save the last used pipette, labware, and well for movement commands.""" - load_pipette_command = create_load_pipette_command( - pipette_id="pipette-id", - pipette_name=PipetteNameType.P300_SINGLE, - mount=MountType.LEFT, - ) - - subject.handle_action( - SucceedCommandAction(private_result=None, command=load_pipette_command) - ) - subject.handle_action(action) - - assert subject.state.current_deck_point == CurrentDeckPoint( - mount=MountType.LEFT, deck_point=DeckPoint(x=11, y=22, z=33) - ) - - -@pytest.mark.parametrize( - "command", - ( - cmd.Home( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.HomeParams(), - result=cmd.HomeResult(), - ), - cmd.thermocycler.OpenLid( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.thermocycler.OpenLidParams(moduleId="xyz"), - result=cmd.thermocycler.OpenLidResult(), - ), - cmd.thermocycler.CloseLid( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.thermocycler.CloseLidParams(moduleId="xyz"), - result=cmd.thermocycler.CloseLidResult(), - ), - cmd.heater_shaker.SetAndWaitForShakeSpeed( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.heater_shaker.SetAndWaitForShakeSpeedParams( - moduleId="xyz", - rpm=123, - ), - result=cmd.heater_shaker.SetAndWaitForShakeSpeedResult( - pipetteRetracted=True - ), - ), - cmd.heater_shaker.OpenLabwareLatch( - id="command-id-2", - key="command-key-2", - status=cmd.CommandStatus.SUCCEEDED, - createdAt=datetime(year=2021, month=1, day=1), - params=cmd.heater_shaker.OpenLabwareLatchParams(moduleId="xyz"), - result=cmd.heater_shaker.OpenLabwareLatchResult(pipetteRetracted=True), - ), - create_move_labware_command( - new_location=DeckSlotLocation(slotName=DeckSlotName.SLOT_1), - strategy=LabwareMovementStrategy.USING_GRIPPER, - ), - ), -) -def test_homing_commands_clear_deck_point( - command: cmd.Command, - subject: PipetteStore, -) -> None: - """Commands that homed the robot should clear the deck point.""" - load_pipette_command = create_load_pipette_command( - pipette_id="pipette-id", - pipette_name=PipetteNameType.P300_SINGLE, - mount=MountType.LEFT, - ) - subject.handle_action( - SucceedCommandAction(private_result=None, command=load_pipette_command) - ) - subject.handle_action( - _create_move_to_well_action( - pipette_id="pipette-id", - labware_id="labware-id", - well_name="well-name", - deck_point=DeckPoint(x=1, y=2, z=3), - ) - ) - assert subject.state.current_deck_point == CurrentDeckPoint( - mount=MountType.LEFT, deck_point=DeckPoint(x=1, y=2, z=3) - ) - - subject.handle_action(SucceedCommandAction(private_result=None, command=command)) - assert subject.state.current_deck_point == CurrentDeckPoint( - mount=None, deck_point=None - ) - - @pytest.mark.parametrize( "previous", [ diff --git a/app/src/App/DesktopApp.tsx b/app/src/App/DesktopApp.tsx index 070e3428563..ee191db1f37 100644 --- a/app/src/App/DesktopApp.tsx +++ b/app/src/App/DesktopApp.tsx @@ -34,7 +34,7 @@ import { import { IncompatibleModuleTakeover } from '/app/organisms/IncompatibleModule' import { OPENTRONS_USB } from '/app/redux/discovery' import { appShellRequestor } from '/app/redux/shell/remote' -import { useRobot, useIsFlex } from '/app/organisms/Devices/hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { ProtocolTimeline } from '/app/pages/Desktop/Protocols/ProtocolDetails/ProtocolTimeline' import { PortalRoot as ModalPortalRoot } from './portal' import { DesktopAppFallback } from './DesktopAppFallback' diff --git a/app/src/App/__tests__/DesktopApp.test.tsx b/app/src/App/__tests__/DesktopApp.test.tsx index 001c1ca1cd9..e43cae4a097 100644 --- a/app/src/App/__tests__/DesktopApp.test.tsx +++ b/app/src/App/__tests__/DesktopApp.test.tsx @@ -16,13 +16,12 @@ import { RobotSettings } from '/app/pages/Desktop/Devices/RobotSettings' import { GeneralSettings } from '/app/pages/Desktop/AppSettings/GeneralSettings' import { AlertsModal } from '/app/organisms/Alerts/AlertsModal' import { useFeatureFlag } from '/app/redux/config' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { ProtocolTimeline } from '/app/pages/Desktop/Protocols/ProtocolDetails/ProtocolTimeline' import { useSoftwareUpdatePoll } from '../hooks' import { DesktopApp } from '../DesktopApp' vi.mock('/app/organisms/Breadcrumbs') -vi.mock('/app/organisms/Devices/hooks') vi.mock('/app/pages/Desktop/AppSettings/GeneralSettings') vi.mock('/app/pages/Desktop/Devices/CalibrationDashboard') vi.mock('/app/pages/Desktop/Devices/DeviceDetails') @@ -33,6 +32,7 @@ vi.mock('/app/pages/Desktop/Devices/RobotSettings') vi.mock('/app/organisms/Alerts/AlertsModal') vi.mock('/app/pages/Desktop/Protocols/ProtocolDetails/ProtocolTimeline') vi.mock('/app/redux/config') +vi.mock('/app/redux-resources/robots') vi.mock('../hooks') const render = (path = '/') => { diff --git a/app/src/organisms/LabwareDetails/images/agilent_1_reservoir_290ml_side_view.jpg b/app/src/assets/images/labware/agilent_1_reservoir_290ml_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/agilent_1_reservoir_290ml_side_view.jpg rename to app/src/assets/images/labware/agilent_1_reservoir_290ml_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg b/app/src/assets/images/labware/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg rename to app/src/assets/images/labware/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg diff --git a/app/src/organisms/LabwareDetails/images/axygen_1_reservoir_90ml_side_view.jpg b/app/src/assets/images/labware/axygen_1_reservoir_90ml_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/axygen_1_reservoir_90ml_side_view.jpg rename to app/src/assets/images/labware/axygen_1_reservoir_90ml_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/biorad_384_wellplate_50ul.jpg b/app/src/assets/images/labware/biorad_384_wellplate_50ul.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/biorad_384_wellplate_50ul.jpg rename to app/src/assets/images/labware/biorad_384_wellplate_50ul.jpg diff --git a/app/src/organisms/LabwareDetails/images/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg b/app/src/assets/images/labware/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg rename to app/src/assets/images/labware/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/circularWell.svg b/app/src/assets/images/labware/circularWell.svg similarity index 100% rename from app/src/organisms/LabwareDetails/images/circularWell.svg rename to app/src/assets/images/labware/circularWell.svg diff --git a/app/src/organisms/LabwareDetails/images/corning_12_wellplate_6.9ml_flat_photo_three_quarters.jpg b/app/src/assets/images/labware/corning_12_wellplate_6.9ml_flat_photo_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/corning_12_wellplate_6.9ml_flat_photo_three_quarters.jpg rename to app/src/assets/images/labware/corning_12_wellplate_6.9ml_flat_photo_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/corning_24_wellplate_3.4ml_flat_photo_three_quarters.jpg b/app/src/assets/images/labware/corning_24_wellplate_3.4ml_flat_photo_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/corning_24_wellplate_3.4ml_flat_photo_three_quarters.jpg rename to app/src/assets/images/labware/corning_24_wellplate_3.4ml_flat_photo_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/corning_384_wellplate_112ul_flat_photo_three_quarters.jpg b/app/src/assets/images/labware/corning_384_wellplate_112ul_flat_photo_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/corning_384_wellplate_112ul_flat_photo_three_quarters.jpg rename to app/src/assets/images/labware/corning_384_wellplate_112ul_flat_photo_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/corning_48_wellplate_1.6ml_flat_photo_three_quarters.jpg b/app/src/assets/images/labware/corning_48_wellplate_1.6ml_flat_photo_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/corning_48_wellplate_1.6ml_flat_photo_three_quarters.jpg rename to app/src/assets/images/labware/corning_48_wellplate_1.6ml_flat_photo_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg b/app/src/assets/images/labware/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg rename to app/src/assets/images/labware/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/corning_96_wellplate_360ul_flat_three_quarters.jpg b/app/src/assets/images/labware/corning_96_wellplate_360ul_flat_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/corning_96_wellplate_360ul_flat_three_quarters.jpg rename to app/src/assets/images/labware/corning_96_wellplate_360ul_flat_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/deep_well_plate_adapter.jpg b/app/src/assets/images/labware/deep_well_plate_adapter.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/deep_well_plate_adapter.jpg rename to app/src/assets/images/labware/deep_well_plate_adapter.jpg diff --git a/app/src/organisms/LabwareDetails/images/eppendorf_1.5ml_safelock_snapcap_tube.jpg b/app/src/assets/images/labware/eppendorf_1.5ml_safelock_snapcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/eppendorf_1.5ml_safelock_snapcap_tube.jpg rename to app/src/assets/images/labware/eppendorf_1.5ml_safelock_snapcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/eppendorf_2ml_safelock_snapcap_tube.jpg b/app/src/assets/images/labware/eppendorf_2ml_safelock_snapcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/eppendorf_2ml_safelock_snapcap_tube.jpg rename to app/src/assets/images/labware/eppendorf_2ml_safelock_snapcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/falcon_15ml_conical_tube.jpg b/app/src/assets/images/labware/falcon_15ml_conical_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/falcon_15ml_conical_tube.jpg rename to app/src/assets/images/labware/falcon_15ml_conical_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/falcon_50ml_15ml_conical_tubes.jpg b/app/src/assets/images/labware/falcon_50ml_15ml_conical_tubes.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/falcon_50ml_15ml_conical_tubes.jpg rename to app/src/assets/images/labware/falcon_50ml_15ml_conical_tubes.jpg diff --git a/app/src/organisms/LabwareDetails/images/falcon_50ml_conical_tube.jpg b/app/src/assets/images/labware/falcon_50ml_conical_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/falcon_50ml_conical_tube.jpg rename to app/src/assets/images/labware/falcon_50ml_conical_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/favicon.ico b/app/src/assets/images/labware/favicon.ico similarity index 100% rename from app/src/organisms/LabwareDetails/images/favicon.ico rename to app/src/assets/images/labware/favicon.ico diff --git a/app/src/organisms/LabwareDetails/images/flat_bottom_aluminum.png b/app/src/assets/images/labware/flat_bottom_aluminum.png similarity index 100% rename from app/src/organisms/LabwareDetails/images/flat_bottom_aluminum.png rename to app/src/assets/images/labware/flat_bottom_aluminum.png diff --git a/app/src/organisms/LabwareDetails/images/flat_bottom_plate_adapter.jpg b/app/src/assets/images/labware/flat_bottom_plate_adapter.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/flat_bottom_plate_adapter.jpg rename to app/src/assets/images/labware/flat_bottom_plate_adapter.jpg diff --git a/app/src/organisms/LabwareDetails/images/geb_1000ul_tip_side_view.jpg b/app/src/assets/images/labware/geb_1000ul_tip_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/geb_1000ul_tip_side_view.jpg rename to app/src/assets/images/labware/geb_1000ul_tip_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/geb_10ul_tip_side_view.jpg b/app/src/assets/images/labware/geb_10ul_tip_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/geb_10ul_tip_side_view.jpg rename to app/src/assets/images/labware/geb_10ul_tip_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/generic_2ml_screwcap_tube.jpg b/app/src/assets/images/labware/generic_2ml_screwcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/generic_2ml_screwcap_tube.jpg rename to app/src/assets/images/labware/generic_2ml_screwcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/generic_pcr_strip_200ul_tubes.jpg b/app/src/assets/images/labware/generic_pcr_strip_200ul_tubes.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/generic_pcr_strip_200ul_tubes.jpg rename to app/src/assets/images/labware/generic_pcr_strip_200ul_tubes.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_0.5ml_screwcap_tube.jpg b/app/src/assets/images/labware/nest_0.5ml_screwcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_0.5ml_screwcap_tube.jpg rename to app/src/assets/images/labware/nest_0.5ml_screwcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_1.5ml_screwcap_tube.jpg b/app/src/assets/images/labware/nest_1.5ml_screwcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_1.5ml_screwcap_tube.jpg rename to app/src/assets/images/labware/nest_1.5ml_screwcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_1.5ml_snapcap_tube.jpg b/app/src/assets/images/labware/nest_1.5ml_snapcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_1.5ml_snapcap_tube.jpg rename to app/src/assets/images/labware/nest_1.5ml_snapcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_12_reservoir_15ml_three_quarters.jpg b/app/src/assets/images/labware/nest_12_reservoir_15ml_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_12_reservoir_15ml_three_quarters.jpg rename to app/src/assets/images/labware/nest_12_reservoir_15ml_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_15ml_conical_tube.jpg b/app/src/assets/images/labware/nest_15ml_conical_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_15ml_conical_tube.jpg rename to app/src/assets/images/labware/nest_15ml_conical_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_1_reservoir_195ml_three_quarters.jpg b/app/src/assets/images/labware/nest_1_reservoir_195ml_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_1_reservoir_195ml_three_quarters.jpg rename to app/src/assets/images/labware/nest_1_reservoir_195ml_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_1_reservoir_290ml.jpg b/app/src/assets/images/labware/nest_1_reservoir_290ml.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_1_reservoir_290ml.jpg rename to app/src/assets/images/labware/nest_1_reservoir_290ml.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_2ml_screwcap_tube.jpg b/app/src/assets/images/labware/nest_2ml_screwcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_2ml_screwcap_tube.jpg rename to app/src/assets/images/labware/nest_2ml_screwcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_2ml_snapcap_tube.jpg b/app/src/assets/images/labware/nest_2ml_snapcap_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_2ml_snapcap_tube.jpg rename to app/src/assets/images/labware/nest_2ml_snapcap_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_50ml_15ml_conical_tubes.jpg b/app/src/assets/images/labware/nest_50ml_15ml_conical_tubes.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_50ml_15ml_conical_tubes.jpg rename to app/src/assets/images/labware/nest_50ml_15ml_conical_tubes.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_50ml_conical_tube.jpg b/app/src/assets/images/labware/nest_50ml_conical_tube.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_50ml_conical_tube.jpg rename to app/src/assets/images/labware/nest_50ml_conical_tube.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_96_wellplate_100ul_pcr_full_skirt_three_quarters.jpg b/app/src/assets/images/labware/nest_96_wellplate_100ul_pcr_full_skirt_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_96_wellplate_100ul_pcr_full_skirt_three_quarters.jpg rename to app/src/assets/images/labware/nest_96_wellplate_100ul_pcr_full_skirt_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_96_wellplate_200ul_flat_three_quarters.jpg b/app/src/assets/images/labware/nest_96_wellplate_200ul_flat_three_quarters.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_96_wellplate_200ul_flat_three_quarters.jpg rename to app/src/assets/images/labware/nest_96_wellplate_200ul_flat_three_quarters.jpg diff --git a/app/src/organisms/LabwareDetails/images/nest_96_wellplate_2ml_deep.jpg b/app/src/assets/images/labware/nest_96_wellplate_2ml_deep.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/nest_96_wellplate_2ml_deep.jpg rename to app/src/assets/images/labware/nest_96_wellplate_2ml_deep.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_10_tuberack_4_6_side_view.jpg b/app/src/assets/images/labware/opentrons_10_tuberack_4_6_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_10_tuberack_4_6_side_view.jpg rename to app/src/assets/images/labware/opentrons_10_tuberack_4_6_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_15_tuberack_side_view.jpg b/app/src/assets/images/labware/opentrons_15_tuberack_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_15_tuberack_side_view.jpg rename to app/src/assets/images/labware/opentrons_15_tuberack_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_24_aluminumblock_side_view.jpg b/app/src/assets/images/labware/opentrons_24_aluminumblock_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_24_aluminumblock_side_view.jpg rename to app/src/assets/images/labware/opentrons_24_aluminumblock_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_24_tuberack_side_view.jpg b/app/src/assets/images/labware/opentrons_24_tuberack_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_24_tuberack_side_view.jpg rename to app/src/assets/images/labware/opentrons_24_tuberack_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_6_tuberack_side_view.jpg b/app/src/assets/images/labware/opentrons_6_tuberack_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_6_tuberack_side_view.jpg rename to app/src/assets/images/labware/opentrons_6_tuberack_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_96_aluminumblock_side_view.jpg b/app/src/assets/images/labware/opentrons_96_aluminumblock_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_96_aluminumblock_side_view.jpg rename to app/src/assets/images/labware/opentrons_96_aluminumblock_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/opentrons_96_deep_well_temp_mod_adapter.png b/app/src/assets/images/labware/opentrons_96_deep_well_temp_mod_adapter.png similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_96_deep_well_temp_mod_adapter.png rename to app/src/assets/images/labware/opentrons_96_deep_well_temp_mod_adapter.png diff --git a/app/src/organisms/LabwareDetails/images/opentrons_flat_aluminumblock_side_view.jpg b/app/src/assets/images/labware/opentrons_flat_aluminumblock_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/opentrons_flat_aluminumblock_side_view.jpg rename to app/src/assets/images/labware/opentrons_flat_aluminumblock_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/pcr_plate_adapter.jpg b/app/src/assets/images/labware/pcr_plate_adapter.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/pcr_plate_adapter.jpg rename to app/src/assets/images/labware/pcr_plate_adapter.jpg diff --git a/app/src/organisms/LabwareDetails/images/rectangularWell.svg b/app/src/assets/images/labware/rectangularWell.svg similarity index 100% rename from app/src/organisms/LabwareDetails/images/rectangularWell.svg rename to app/src/assets/images/labware/rectangularWell.svg diff --git a/app/src/organisms/LabwareDetails/images/thermoscientificnunc_96_wellplate_1300ul.jpg b/app/src/assets/images/labware/thermoscientificnunc_96_wellplate_1300ul.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/thermoscientificnunc_96_wellplate_1300ul.jpg rename to app/src/assets/images/labware/thermoscientificnunc_96_wellplate_1300ul.jpg diff --git a/app/src/organisms/LabwareDetails/images/thermoscientificnunc_96_wellplate_2000ul.jpg b/app/src/assets/images/labware/thermoscientificnunc_96_wellplate_2000ul.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/thermoscientificnunc_96_wellplate_2000ul.jpg rename to app/src/assets/images/labware/thermoscientificnunc_96_wellplate_2000ul.jpg diff --git a/app/src/organisms/LabwareDetails/images/tipone_200ul_tip_side_view.jpg b/app/src/assets/images/labware/tipone_200ul_tip_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/tipone_200ul_tip_side_view.jpg rename to app/src/assets/images/labware/tipone_200ul_tip_side_view.jpg diff --git a/app/src/assets/images/labware/tipone_96_tiprack_200ul_side_view.jpg b/app/src/assets/images/labware/tipone_96_tiprack_200ul_side_view.jpg old mode 100755 new mode 100644 diff --git a/app/src/organisms/LabwareDetails/images/universal_flat_adapter.jpg b/app/src/assets/images/labware/universal_flat_adapter.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/universal_flat_adapter.jpg rename to app/src/assets/images/labware/universal_flat_adapter.jpg diff --git a/app/src/organisms/LabwareDetails/images/usascientific_12_reservoir_22ml_side_view.jpg b/app/src/assets/images/labware/usascientific_12_reservoir_22ml_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/usascientific_12_reservoir_22ml_side_view.jpg rename to app/src/assets/images/labware/usascientific_12_reservoir_22ml_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/usascientific_96_wellplate_2.4ml_deep_side_view.jpg b/app/src/assets/images/labware/usascientific_96_wellplate_2.4ml_deep_side_view.jpg similarity index 100% rename from app/src/organisms/LabwareDetails/images/usascientific_96_wellplate_2.4ml_deep_side_view.jpg rename to app/src/assets/images/labware/usascientific_96_wellplate_2.4ml_deep_side_view.jpg diff --git a/app/src/organisms/LabwareDetails/images/wellShapeFlat.svg b/app/src/assets/images/labware/wellShapeFlat.svg similarity index 100% rename from app/src/organisms/LabwareDetails/images/wellShapeFlat.svg rename to app/src/assets/images/labware/wellShapeFlat.svg diff --git a/app/src/organisms/LabwareDetails/images/wellShapeU.svg b/app/src/assets/images/labware/wellShapeU.svg similarity index 100% rename from app/src/organisms/LabwareDetails/images/wellShapeU.svg rename to app/src/assets/images/labware/wellShapeU.svg diff --git a/app/src/organisms/LabwareDetails/images/wellShapeV.svg b/app/src/assets/images/labware/wellShapeV.svg similarity index 100% rename from app/src/organisms/LabwareDetails/images/wellShapeV.svg rename to app/src/assets/images/labware/wellShapeV.svg diff --git a/app/src/local-resources/labware/hooks/index.ts b/app/src/local-resources/labware/hooks/index.ts new file mode 100644 index 00000000000..86c1116e270 --- /dev/null +++ b/app/src/local-resources/labware/hooks/index.ts @@ -0,0 +1 @@ +export * from './useAllLabware' diff --git a/app/src/local-resources/labware/hooks/useAllLabware.ts b/app/src/local-resources/labware/hooks/useAllLabware.ts new file mode 100644 index 00000000000..28d4325b2eb --- /dev/null +++ b/app/src/local-resources/labware/hooks/useAllLabware.ts @@ -0,0 +1,50 @@ +import { useSelector } from 'react-redux' +import { getValidCustomLabware } from '/app/redux/custom-labware' +import { getAllDefinitions } from '../utils' +import type { LabwareSort, LabwareFilter, LabwareDefAndDate } from '../types' + +export function useAllLabware( + sortBy: LabwareSort, + filterBy: LabwareFilter +): LabwareDefAndDate[] { + const fullLabwareList: LabwareDefAndDate[] = [] + const labwareDefinitions = getAllDefinitions() + labwareDefinitions.forEach(def => fullLabwareList.push({ definition: def })) + const customLabwareList = useSelector(getValidCustomLabware) + customLabwareList.forEach(customLabware => + 'definition' in customLabware + ? fullLabwareList.push({ + modified: customLabware.modified, + definition: customLabware.definition, + filename: customLabware.filename, + }) + : null + ) + const sortLabware = (a: LabwareDefAndDate, b: LabwareDefAndDate): number => { + if ( + a.definition.metadata.displayName.toUpperCase() < + b.definition.metadata.displayName.toUpperCase() + ) { + return sortBy === 'alphabetical' ? -1 : 1 + } + if ( + a.definition.metadata.displayName.toUpperCase() > + b.definition.metadata.displayName.toUpperCase() + ) { + return sortBy === 'alphabetical' ? 1 : -1 + } + return 0 + } + + if (filterBy === 'customLabware') { + return (customLabwareList as LabwareDefAndDate[]).sort(sortLabware) + } + fullLabwareList.sort(sortLabware) + if (filterBy !== 'all') { + return fullLabwareList.filter( + labwareItem => + labwareItem.definition.metadata.displayCategory === filterBy + ) + } + return fullLabwareList +} diff --git a/app/src/local-resources/labware/index.ts b/app/src/local-resources/labware/index.ts new file mode 100644 index 00000000000..505591b2909 --- /dev/null +++ b/app/src/local-resources/labware/index.ts @@ -0,0 +1,3 @@ +export * from './hooks' +export * from './utils' +export type * from './types' diff --git a/app/src/pages/Desktop/Labware/types.ts b/app/src/local-resources/labware/types.ts similarity index 66% rename from app/src/pages/Desktop/Labware/types.ts rename to app/src/local-resources/labware/types.ts index 24696b11844..99ea299573d 100644 --- a/app/src/pages/Desktop/Labware/types.ts +++ b/app/src/local-resources/labware/types.ts @@ -5,35 +5,12 @@ import type { LabwareBrand, } from '@opentrons/shared-data' -export type { - LabwareDefinition2 as LabwareDefinition, - LabwareParameters, - LabwareOffset, - LabwareWell, - LabwareWellShapeProperties, - LabwareWellProperties, - LabwareWellMap, - LabwareWellGroupMetadata, - LabwareVolumeUnits, - LabwareDisplayCategory, - LabwareBrand, -} from '@opentrons/shared-data' - -export interface LabwareWellGroupProperties { - xOffsetFromLeft: number - yOffsetFromTop: number - xSpacing: number | null - ySpacing: number | null - wellCount: number - shape: LabwareWellShapeProperties | null - depth: number | null - totalLiquidVolume: number | null - metadata: LabwareWellGroupMetadata - brand: LabwareBrand | null +export interface LabwareDefAndDate { + definition: LabwareDefinition + modified?: number + filename?: string } -export type LabwareList = LabwareDefinition[] - export type LabwareFilter = | 'all' | 'wellPlate' @@ -45,3 +22,16 @@ export type LabwareFilter = | 'adapter' export type LabwareSort = 'alphabetical' | 'reverse' + +export interface LabwareWellGroupProperties { + xOffsetFromLeft: number + yOffsetFromTop: number + xSpacing: number | null + ySpacing: number | null + wellCount: number + shape: LabwareWellShapeProperties | null + depth: number | null + totalLiquidVolume: number | null + metadata: LabwareWellGroupMetadata + brand: LabwareBrand | null +} diff --git a/app/src/pages/Desktop/Labware/helpers/__mocks__/getAllDefs.ts b/app/src/local-resources/labware/utils/__mocks__/getAllDefs.ts similarity index 100% rename from app/src/pages/Desktop/Labware/helpers/__mocks__/getAllDefs.ts rename to app/src/local-resources/labware/utils/__mocks__/getAllDefs.ts diff --git a/app/src/pages/Desktop/Labware/helpers/definitions.ts b/app/src/local-resources/labware/utils/getAllDefinitions.ts similarity index 97% rename from app/src/pages/Desktop/Labware/helpers/definitions.ts rename to app/src/local-resources/labware/utils/getAllDefinitions.ts index bab954a8151..db25fde06a1 100644 --- a/app/src/pages/Desktop/Labware/helpers/definitions.ts +++ b/app/src/local-resources/labware/utils/getAllDefinitions.ts @@ -1,9 +1,9 @@ import groupBy from 'lodash/groupBy' import { LABWAREV2_DO_NOT_LIST } from '@opentrons/shared-data' -import { getAllDefs } from './getAllDefs' import type { LabwareDefinition2 } from '@opentrons/shared-data' +import { getAllDefs } from './getAllDefs' -const getOnlyLatestDefs = ( +export const getOnlyLatestDefs = ( labwareList: LabwareDefinition2[] ): LabwareDefinition2[] => { // group by namespace + loadName diff --git a/app/src/pages/Desktop/Labware/helpers/getAllDefs.ts b/app/src/local-resources/labware/utils/getAllDefs.ts similarity index 100% rename from app/src/pages/Desktop/Labware/helpers/getAllDefs.ts rename to app/src/local-resources/labware/utils/getAllDefs.ts diff --git a/app/src/local-resources/labware/utils/index.ts b/app/src/local-resources/labware/utils/index.ts new file mode 100644 index 00000000000..f1368b03c6f --- /dev/null +++ b/app/src/local-resources/labware/utils/index.ts @@ -0,0 +1 @@ +export * from './getAllDefinitions' diff --git a/app/src/molecules/JogControls/DirectionControl.tsx b/app/src/molecules/JogControls/DirectionControl.tsx index 046ef173eed..8b05e533e4d 100644 --- a/app/src/molecules/JogControls/DirectionControl.tsx +++ b/app/src/molecules/JogControls/DirectionControl.tsx @@ -13,16 +13,17 @@ import { COLORS, DIRECTION_COLUMN, DIRECTION_ROW, + DISPLAY_GRID, Flex, HandleKeypress, Icon, JUSTIFY_CENTER, JUSTIFY_FLEX_START, JUSTIFY_SPACE_BETWEEN, + LegacyStyledText, PrimaryButton, RESPONSIVENESS, SPACING, - LegacyStyledText, TEXT_ALIGN_LEFT, TYPOGRAPHY, } from '@opentrons/components' @@ -302,7 +303,7 @@ export function DirectionControl(props: DirectionControlProps): JSX.Element { } const ARROW_GRID_STYLES = css` - display: grid; + display: ${DISPLAY_GRID}; max-width: 8.75rem; grid-template-columns: repeat(6, 1fr); grid-template-areas: diff --git a/app/src/molecules/JogControls/StepSizeControl.tsx b/app/src/molecules/JogControls/StepSizeControl.tsx index 29f455b4f55..69e290677b3 100644 --- a/app/src/molecules/JogControls/StepSizeControl.tsx +++ b/app/src/molecules/JogControls/StepSizeControl.tsx @@ -8,12 +8,13 @@ import { COLORS, DIRECTION_COLUMN, DIRECTION_ROW, + DISPLAY_GRID, Flex, HandleKeypress, Icon, + LegacyStyledText, PrimaryButton, SPACING, - LegacyStyledText, TEXT_TRANSFORM_CAPITALIZE, TYPOGRAPHY, } from '@opentrons/components' @@ -35,7 +36,7 @@ const stepSizeTranslationKeyByStep: { [stepSize: number]: string } = { } const BUTTON_WRAPPER_STYLE = css` - display: grid; + display: ${DISPLAY_GRID}; grid-auto-flow: column; grid-gap: ${SPACING.spacing8}; margin-top: ${SPACING.spacing16}; diff --git a/app/src/molecules/UpdateBanner/__tests__/UpdateBanner.test.tsx b/app/src/molecules/UpdateBanner/__tests__/UpdateBanner.test.tsx index eea0d077f4b..c40d1e2e197 100644 --- a/app/src/molecules/UpdateBanner/__tests__/UpdateBanner.test.tsx +++ b/app/src/molecules/UpdateBanner/__tests__/UpdateBanner.test.tsx @@ -4,12 +4,12 @@ import '@testing-library/jest-dom/vitest' import { when } from 'vitest-when' import { fireEvent, screen } from '@testing-library/react' import { i18n } from '/app/i18n' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' import { UpdateBanner } from '..' import { renderWithProviders } from '/app/__testing-utils__' -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') const render = (props: React.ComponentProps) => { diff --git a/app/src/molecules/UpdateBanner/index.tsx b/app/src/molecules/UpdateBanner/index.tsx index bdce9d53d1e..12927dc5eea 100644 --- a/app/src/molecules/UpdateBanner/index.tsx +++ b/app/src/molecules/UpdateBanner/index.tsx @@ -13,7 +13,7 @@ import { } from '@opentrons/components' import { Banner } from '/app/atoms/Banner' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' interface UpdateBannerProps { diff --git a/app/src/organisms/ApplyHistoricOffsets/hooks/__tests__/useHistoricRunDetails.test.tsx b/app/src/organisms/ApplyHistoricOffsets/hooks/__tests__/useHistoricRunDetails.test.tsx index f43f72ce60b..5fe40a9333e 100644 --- a/app/src/organisms/ApplyHistoricOffsets/hooks/__tests__/useHistoricRunDetails.test.tsx +++ b/app/src/organisms/ApplyHistoricOffsets/hooks/__tests__/useHistoricRunDetails.test.tsx @@ -5,7 +5,7 @@ import { renderHook, waitFor } from '@testing-library/react' import { useNotifyAllRunsQuery } from '/app/resources/runs/useNotifyAllRunsQuery' import { useHistoricRunDetails } from '../useHistoricRunDetails' -import { mockRunningRun } from '../../../RunTimeControl/__fixtures__' +import { mockRunningRun } from '/app/resources/runs/__fixtures__' import { mockSuccessQueryResults } from '../../../../__fixtures__' import type { RunData } from '@opentrons/api-client' diff --git a/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx b/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx index 1f79e4ed585..22216e8b830 100644 --- a/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx +++ b/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx @@ -6,10 +6,8 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import { fireEvent, screen } from '@testing-library/react' import { i18n } from '/app/i18n' -import { - useRobot, - useRunCreatedAtTimestamp, -} from '/app/organisms/Devices/hooks' +import { useRunCreatedAtTimestamp } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { getProtocolDisplayName } from '/app/organisms/ProtocolsLanding/utils' import { getIsOnDevice } from '/app/redux/config' import { renderWithProviders } from '/app/__testing-utils__' @@ -21,6 +19,7 @@ import { Breadcrumbs } from '..' import type { State } from '/app/redux/types' vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/ProtocolsLanding/utils') vi.mock('/app/redux/config') vi.mock('/app/redux/protocol-storage') diff --git a/app/src/organisms/Breadcrumbs/index.tsx b/app/src/organisms/Breadcrumbs/index.tsx index af84a02096e..f67493c2998 100644 --- a/app/src/organisms/Breadcrumbs/index.tsx +++ b/app/src/organisms/Breadcrumbs/index.tsx @@ -18,15 +18,13 @@ import { } from '@opentrons/components' import { ApiHostProvider } from '@opentrons/react-api-client' -import { - useRobot, - useRunCreatedAtTimestamp, -} from '/app/organisms/Devices/hooks' +import { useRunCreatedAtTimestamp } from '/app/organisms/Devices/hooks' import { getProtocolDisplayName } from '/app/organisms/ProtocolsLanding/utils' import { getIsOnDevice } from '/app/redux/config' import { OPENTRONS_USB } from '/app/redux/discovery' import { getStoredProtocol } from '/app/redux/protocol-storage' import { appShellRequestor } from '/app/redux/shell/remote' +import { useRobot } from '/app/redux-resources/robots' import type { DesktopRouteParams } from '../../App/types' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/CalibrationTaskList/index.tsx b/app/src/organisms/CalibrationTaskList/index.tsx index 72ae2d91898..069e6ba4ebf 100644 --- a/app/src/organisms/CalibrationTaskList/index.tsx +++ b/app/src/organisms/CalibrationTaskList/index.tsx @@ -24,12 +24,14 @@ import { useAttachedPipettes, useCalibrationTaskList, useRunHasStarted, -} from '../Devices/hooks' +} from '/app/organisms/Devices/hooks' import { useCurrentRunId } from '/app/resources/runs' -import type { DashboardCalOffsetInvoker } from '/app/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset' -import type { DashboardCalTipLengthInvoker } from '/app/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateTipLength' -import type { DashboardCalDeckInvoker } from '/app/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateDeck' +import type { + DashboardCalOffsetInvoker, + DashboardCalTipLengthInvoker, + DashboardCalDeckInvoker, +} from '/app/organisms/Devices/hooks' interface CalibrationTaskListProps { robotName: string diff --git a/app/src/organisms/ChooseProtocolSlideout/index.tsx b/app/src/organisms/ChooseProtocolSlideout/index.tsx index ec7fff8d6c3..bd771f92f40 100644 --- a/app/src/organisms/ChooseProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/index.tsx @@ -16,6 +16,7 @@ import { DIRECTION_COLUMN, DIRECTION_ROW, DISPLAY_BLOCK, + DISPLAY_GRID, DropdownMenu, Flex, Icon, @@ -58,7 +59,7 @@ import { FileCard } from '../ChooseRobotSlideout/FileCard' import { getRunTimeParameterFilesForRun, getRunTimeParameterValuesForRun, -} from '../Devices/utils' +} from '/app/transformations/runs' import { getAnalysisStatus } from '../ProtocolsLanding/utils' import type { DropdownOption } from '@opentrons/components' @@ -754,7 +755,7 @@ function StoredProtocolList(props: StoredProtocolListProps): JSX.Element { }} > diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx index d70a8bb1640..068cd0825f0 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx @@ -7,7 +7,6 @@ import { when } from 'vitest-when' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { useTrackCreateProtocolRunEvent } from '/app/organisms/Devices/hooks' -import { useCloseCurrentRun } from '/app/organisms/ProtocolUpload/hooks' import { useCurrentRunStatus } from '/app/organisms/RunTimeControl/hooks' import { getConnectableRobots, @@ -31,7 +30,7 @@ import { useCreateRunFromProtocol } from '../useCreateRunFromProtocol' import { useOffsetCandidatesForAnalysis } from '../../ApplyHistoricOffsets/hooks/useOffsetCandidatesForAnalysis' import { ChooseRobotToRunProtocolSlideout } from '../' import { useNotifyDataReady } from '/app/resources/useNotifyDataReady' -import { useCurrentRunId } from '/app/resources/runs' +import { useCurrentRunId, useCloseCurrentRun } from '/app/resources/runs' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx index f1c234ce19f..9b3446bf3d2 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx @@ -28,7 +28,7 @@ import { useTrackCreateProtocolRunEvent } from '../Devices/hooks' import { getRunTimeParameterFilesForRun, getRunTimeParameterValuesForRun, -} from '../Devices/utils' +} from '/app/transformations/runs' import { ApplyHistoricOffsets } from '../ApplyHistoricOffsets' import { useOffsetCandidatesForAnalysis } from '../ApplyHistoricOffsets/hooks/useOffsetCandidatesForAnalysis' import { ChooseRobotSlideout } from '../ChooseRobotSlideout' diff --git a/app/src/organisms/AddCustomLabwareSlideout/__tests__/AddCustomLabwareSlideout.test.tsx b/app/src/organisms/Desktop/Labware/AddCustomLabwareSlideout/__tests__/AddCustomLabwareSlideout.test.tsx similarity index 96% rename from app/src/organisms/AddCustomLabwareSlideout/__tests__/AddCustomLabwareSlideout.test.tsx rename to app/src/organisms/Desktop/Labware/AddCustomLabwareSlideout/__tests__/AddCustomLabwareSlideout.test.tsx index 9ae38c45961..451e63491fd 100644 --- a/app/src/organisms/AddCustomLabwareSlideout/__tests__/AddCustomLabwareSlideout.test.tsx +++ b/app/src/organisms/Desktop/Labware/AddCustomLabwareSlideout/__tests__/AddCustomLabwareSlideout.test.tsx @@ -11,7 +11,7 @@ import { renderWithProviders } from '/app/__testing-utils__' import { AddCustomLabwareSlideout } from '..' vi.mock('/app/redux/custom-labware') -vi.mock('/app/pages/Desktop/Labware/helpers/getAllDefs') +vi.mock('/app/local-resources/labware') vi.mock('/app/redux/analytics') let mockTrackEvent: any diff --git a/app/src/organisms/AddCustomLabwareSlideout/index.tsx b/app/src/organisms/Desktop/Labware/AddCustomLabwareSlideout/index.tsx similarity index 100% rename from app/src/organisms/AddCustomLabwareSlideout/index.tsx rename to app/src/organisms/Desktop/Labware/AddCustomLabwareSlideout/index.tsx diff --git a/app/src/organisms/LabwareCard/CustomLabwareOverflowMenu.tsx b/app/src/organisms/Desktop/Labware/LabwareCard/CustomLabwareOverflowMenu.tsx similarity index 99% rename from app/src/organisms/LabwareCard/CustomLabwareOverflowMenu.tsx rename to app/src/organisms/Desktop/Labware/LabwareCard/CustomLabwareOverflowMenu.tsx index 13dfb3f3804..6183fdf00de 100644 --- a/app/src/organisms/LabwareCard/CustomLabwareOverflowMenu.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareCard/CustomLabwareOverflowMenu.tsx @@ -30,7 +30,7 @@ import { } from '@opentrons/components' import { Divider } from '/app/atoms/structure' -import { getTopPortalEl } from '../../App/portal' +import { getTopPortalEl } from '/app/App/portal' import { deleteCustomLabwareFile, openCustomLabwareDirectory, diff --git a/app/src/organisms/LabwareCard/__tests__/CustomLabwareOverflowMenu.test.tsx b/app/src/organisms/Desktop/Labware/LabwareCard/__tests__/CustomLabwareOverflowMenu.test.tsx similarity index 100% rename from app/src/organisms/LabwareCard/__tests__/CustomLabwareOverflowMenu.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareCard/__tests__/CustomLabwareOverflowMenu.test.tsx diff --git a/app/src/organisms/LabwareCard/__tests__/LabwareCard.test.tsx b/app/src/organisms/Desktop/Labware/LabwareCard/__tests__/LabwareCard.test.tsx similarity index 94% rename from app/src/organisms/LabwareCard/__tests__/LabwareCard.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareCard/__tests__/LabwareCard.test.tsx index 652d89386a5..35423948e56 100644 --- a/app/src/organisms/LabwareCard/__tests__/LabwareCard.test.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareCard/__tests__/LabwareCard.test.tsx @@ -3,14 +3,14 @@ import { screen } from '@testing-library/react' import { describe, it, vi, beforeEach } from 'vitest' import { renderWithProviders, nestedTextMatcher } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useAllLabware } from '/app/pages/Desktop/Labware/hooks' +import { useAllLabware } from '/app/local-resources/labware' import { mockDefinition } from '/app/redux/custom-labware/__fixtures__' import { CustomLabwareOverflowMenu } from '../CustomLabwareOverflowMenu' import { LabwareCard } from '..' import type * as OpentronsComponents from '@opentrons/components' -vi.mock('/app/pages/Desktop/Labware/hooks') +vi.mock('/app/local-resources/labware') vi.mock('../CustomLabwareOverflowMenu') vi.mock('@opentrons/components', async importOriginal => { diff --git a/app/src/organisms/LabwareCard/hooks.tsx b/app/src/organisms/Desktop/Labware/LabwareCard/hooks.tsx similarity index 100% rename from app/src/organisms/LabwareCard/hooks.tsx rename to app/src/organisms/Desktop/Labware/LabwareCard/hooks.tsx diff --git a/app/src/organisms/LabwareCard/index.tsx b/app/src/organisms/Desktop/Labware/LabwareCard/index.tsx similarity index 97% rename from app/src/organisms/LabwareCard/index.tsx rename to app/src/organisms/Desktop/Labware/LabwareCard/index.tsx index 6b38a8c6ce9..b94f088d87a 100644 --- a/app/src/organisms/LabwareCard/index.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareCard/index.tsx @@ -18,11 +18,12 @@ import { SPACING, LegacyStyledText, TYPOGRAPHY, + DISPLAY_GRID, } from '@opentrons/components' import { UNIVERSAL_FLAT_ADAPTER_X_DIMENSION } from '../LabwareDetails/Gallery' import { CustomLabwareOverflowMenu } from './CustomLabwareOverflowMenu' -import type { LabwareDefAndDate } from '/app/pages/Desktop/Labware/hooks' +import type { LabwareDefAndDate } from '/app/local-resources/labware' export interface LabwareCardProps { labware: LabwareDefAndDate @@ -51,7 +52,7 @@ export function LabwareCard(props: LabwareCardProps): JSX.Element { height="auto" onClick={props.onClick} cursor="pointer" - display="grid" + display={DISPLAY_GRID} gridTemplateColumns=" minmax(5rem, 1fr) minmax(7.5rem, 1fr) 4fr minmax( 3rem, 1fr diff --git a/app/src/organisms/LabwareDetails/Dimensions.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/Dimensions.tsx similarity index 94% rename from app/src/organisms/LabwareDetails/Dimensions.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/Dimensions.tsx index c0f5fc18d20..61e3cd422d5 100644 --- a/app/src/organisms/LabwareDetails/Dimensions.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/Dimensions.tsx @@ -4,7 +4,7 @@ import round from 'lodash/round' import { Box, SPACING, getFootprintDiagram } from '@opentrons/components' import { LabeledValue } from './StyledComponents/LabeledValue' import { ExpandingTitle } from './StyledComponents/ExpandingTitle' -import type { LabwareDefinition } from '/app/pages/Desktop/Labware/types' +import type { LabwareDefinition2 as LabwareDefinition } from '@opentrons/shared-data' const toFixed = (n: number): string => round(n, 2).toFixed(2) diff --git a/app/src/organisms/LabwareDetails/Gallery.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/Gallery.tsx similarity index 96% rename from app/src/organisms/LabwareDetails/Gallery.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/Gallery.tsx index 3feddb482c5..ca5f7b89de6 100644 --- a/app/src/organisms/LabwareDetails/Gallery.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/Gallery.tsx @@ -11,9 +11,10 @@ import { SPACING_AUTO, SPACING, } from '@opentrons/components' + import { labwareImages } from './labware-images' -import type { LabwareDefinition } from '/app/pages/Desktop/Labware/types' +import type { LabwareDefinition2 as LabwareDefinition } from '@opentrons/shared-data' export const UNIVERSAL_FLAT_ADAPTER_X_DIMENSION = 127.4 diff --git a/app/src/organisms/LabwareDetails/InsertDetails.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/InsertDetails.tsx similarity index 95% rename from app/src/organisms/LabwareDetails/InsertDetails.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/InsertDetails.tsx index 705c6f7b49d..93035580764 100644 --- a/app/src/organisms/LabwareDetails/InsertDetails.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/InsertDetails.tsx @@ -12,7 +12,7 @@ import { WellProperties } from './WellProperties' import { WellDimensions } from './WellDimensions' import { ManufacturerDetails } from './ManufacturerDetails' -import type { LabwareDefinition } from '/app/pages/Desktop/Labware/types' +import type { LabwareDefinition2 as LabwareDefinition } from '@opentrons/shared-data' export interface InsertDetailsProps { definition: LabwareDefinition diff --git a/app/src/organisms/LabwareDetails/ManufacturerDetails.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/ManufacturerDetails.tsx similarity index 96% rename from app/src/organisms/LabwareDetails/ManufacturerDetails.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/ManufacturerDetails.tsx index bacccd4a951..7f0443f50b1 100644 --- a/app/src/organisms/LabwareDetails/ManufacturerDetails.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/ManufacturerDetails.tsx @@ -12,7 +12,7 @@ import { SPACING, LegacyStyledText, } from '@opentrons/components' -import type { LabwareBrand } from '/app/pages/Desktop/Labware/types' +import type { LabwareBrand } from '@opentrons/shared-data' export interface ManufacturerDetailsProps { brand: LabwareBrand diff --git a/app/src/organisms/LabwareDetails/StyledComponents/ExpandingTitle.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/ExpandingTitle.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/StyledComponents/ExpandingTitle.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/ExpandingTitle.tsx diff --git a/app/src/organisms/LabwareDetails/StyledComponents/LabeledValue.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/LabeledValue.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/StyledComponents/LabeledValue.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/LabeledValue.tsx diff --git a/app/src/organisms/LabwareDetails/StyledComponents/__tests__/ExpandingTitle.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/__tests__/ExpandingTitle.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/StyledComponents/__tests__/ExpandingTitle.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/__tests__/ExpandingTitle.test.tsx diff --git a/app/src/organisms/LabwareDetails/StyledComponents/__tests__/LabeledValue.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/__tests__/LabeledValue.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/StyledComponents/__tests__/LabeledValue.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/StyledComponents/__tests__/LabeledValue.test.tsx diff --git a/app/src/organisms/LabwareDetails/WellCount.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/WellCount.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/WellCount.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/WellCount.tsx diff --git a/app/src/organisms/LabwareDetails/WellDimensions.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/WellDimensions.tsx similarity index 93% rename from app/src/organisms/LabwareDetails/WellDimensions.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/WellDimensions.tsx index 5fdea6cadf9..b1cf98a147a 100644 --- a/app/src/organisms/LabwareDetails/WellDimensions.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/WellDimensions.tsx @@ -5,10 +5,8 @@ import { Box, SPACING, getMeasurementDiagram } from '@opentrons/components' import { LabeledValue } from './StyledComponents/LabeledValue' import { ExpandingTitle } from './StyledComponents/ExpandingTitle' -import type { - LabwareWellGroupProperties, - LabwareParameters, -} from '/app/pages/Desktop/Labware/types' +import type { LabwareParameters } from '@opentrons/shared-data' +import type { LabwareWellGroupProperties } from '/app/local-resources/labware' const toFixed = (n: number): string => round(n, 2).toFixed(2) diff --git a/app/src/organisms/LabwareDetails/WellProperties.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/WellProperties.tsx similarity index 94% rename from app/src/organisms/LabwareDetails/WellProperties.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/WellProperties.tsx index 75da0a5edce..71f7ef4b3a7 100644 --- a/app/src/organisms/LabwareDetails/WellProperties.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/WellProperties.tsx @@ -13,11 +13,12 @@ import { } from '@opentrons/components' import { getDisplayVolume } from '@opentrons/shared-data' +import type { LabwareWellGroupProperties } from '/app/local-resources/labware' + import type { - LabwareDefinition, - LabwareWellGroupProperties, + LabwareDefinition2 as LabwareDefinition, LabwareVolumeUnits, -} from '/app/pages/Desktop/Labware/types' +} from '@opentrons/shared-data' export interface AllWellPropertiesProps { definition: LabwareDefinition diff --git a/app/src/organisms/LabwareDetails/WellSpacing.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/WellSpacing.tsx similarity index 95% rename from app/src/organisms/LabwareDetails/WellSpacing.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/WellSpacing.tsx index 94ccccfb046..e7a268d9ff7 100644 --- a/app/src/organisms/LabwareDetails/WellSpacing.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/WellSpacing.tsx @@ -5,7 +5,7 @@ import { getSpacingDiagram } from '@opentrons/components' import { LabeledValue } from './StyledComponents/LabeledValue' import { ExpandingTitle } from './StyledComponents/ExpandingTitle' -import type { LabwareWellGroupProperties } from '/app/pages/Desktop/Labware/types' +import type { LabwareWellGroupProperties } from '/app/local-resources/labware' const toFixed = (n: number): string => round(n, 2).toFixed(2) diff --git a/app/src/organisms/LabwareDetails/__tests__/Dimensions.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/Dimensions.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/Dimensions.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/Dimensions.test.tsx diff --git a/app/src/organisms/LabwareDetails/__tests__/Gallery.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/Gallery.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/Gallery.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/Gallery.test.tsx diff --git a/app/src/organisms/LabwareDetails/__tests__/LabwareDetails.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/LabwareDetails.test.tsx similarity index 97% rename from app/src/organisms/LabwareDetails/__tests__/LabwareDetails.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/LabwareDetails.test.tsx index 5c7ed3e868b..1c06bc0e5ce 100644 --- a/app/src/organisms/LabwareDetails/__tests__/LabwareDetails.test.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/LabwareDetails.test.tsx @@ -4,7 +4,7 @@ import { describe, it, beforeEach, afterEach, vi, expect } from 'vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useAllLabware } from '/app/pages/Desktop/Labware/hooks' +import { useAllLabware } from '/app/local-resources/labware' import { mockOpentronsLabwareDetailsDefinition } from '/app/redux/custom-labware/__fixtures__' import { CustomLabwareOverflowMenu } from '../../LabwareCard/CustomLabwareOverflowMenu' import { Dimensions } from '../Dimensions' @@ -17,7 +17,7 @@ import { WellSpacing } from '../WellSpacing' import { LabwareDetails } from '..' -vi.mock('/app/pages/Desktop/Labware/hooks') +vi.mock('/app/local-resources/labware') vi.mock('../../LabwareCard/CustomLabwareOverflowMenu') vi.mock('../Dimensions') vi.mock('../Gallery') diff --git a/app/src/organisms/LabwareDetails/__tests__/ManufacturerDetails.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/ManufacturerDetails.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/ManufacturerDetails.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/ManufacturerDetails.test.tsx diff --git a/app/src/organisms/LabwareDetails/__tests__/WellCount.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellCount.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/WellCount.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellCount.test.tsx diff --git a/app/src/organisms/LabwareDetails/__tests__/WellDimensions.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellDimensions.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/WellDimensions.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellDimensions.test.tsx diff --git a/app/src/organisms/LabwareDetails/__tests__/WellProperties.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellProperties.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/WellProperties.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellProperties.test.tsx diff --git a/app/src/organisms/LabwareDetails/__tests__/WellSpacing.test.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellSpacing.test.tsx similarity index 100% rename from app/src/organisms/LabwareDetails/__tests__/WellSpacing.test.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/__tests__/WellSpacing.test.tsx diff --git a/app/src/organisms/LabwareDetails/helpers/labels.ts b/app/src/organisms/Desktop/Labware/LabwareDetails/helpers/labels.ts similarity index 86% rename from app/src/organisms/LabwareDetails/helpers/labels.ts rename to app/src/organisms/Desktop/Labware/LabwareDetails/helpers/labels.ts index 27cf6d76bb8..204c9114dc6 100644 --- a/app/src/organisms/LabwareDetails/helpers/labels.ts +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/helpers/labels.ts @@ -1,8 +1,7 @@ import uniqBy from 'lodash/uniqBy' -import type { - LabwareWellGroupProperties, - LabwareDefinition, -} from '/app/pages/Desktop/Labware/types' +import type { LabwareWellGroupProperties } from '/app/local-resources/labware' +import type { LabwareDefinition2 as LabwareDefinition } from '@opentrons/shared-data' + const WELL_TYPE_BY_CATEGORY = { tubeRack: 'tube', tipRack: 'tip', diff --git a/app/src/organisms/LabwareDetails/index.tsx b/app/src/organisms/Desktop/Labware/LabwareDetails/index.tsx similarity index 99% rename from app/src/organisms/LabwareDetails/index.tsx rename to app/src/organisms/Desktop/Labware/LabwareDetails/index.tsx index fc8e73a16a4..2b0f252bfc6 100644 --- a/app/src/organisms/LabwareDetails/index.tsx +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/index.tsx @@ -35,7 +35,7 @@ import { ManufacturerDetails } from './ManufacturerDetails' import { InsertDetails } from './InsertDetails' import { Gallery } from './Gallery' import { CustomLabwareOverflowMenu } from '../LabwareCard/CustomLabwareOverflowMenu' -import type { LabwareDefAndDate } from '/app/pages/Desktop/Labware/hooks' +import type { LabwareDefAndDate } from '/app/local-resources/labware' const CLOSE_ICON_STYLE = css` border-radius: 50%; diff --git a/app/src/organisms/LabwareDetails/labware-images.ts b/app/src/organisms/Desktop/Labware/LabwareDetails/labware-images.ts similarity index 56% rename from app/src/organisms/LabwareDetails/labware-images.ts rename to app/src/organisms/Desktop/Labware/LabwareDetails/labware-images.ts index 294ec2f1420..c8125c0bf50 100644 --- a/app/src/organisms/LabwareDetails/labware-images.ts +++ b/app/src/organisms/Desktop/Labware/LabwareDetails/labware-images.ts @@ -1,65 +1,64 @@ // images by labware load name -// TODO(mc, 2019-05-29): shared-data? components-library? -import agilent_1_reservoir_290ml_side_view from './images/agilent_1_reservoir_290ml_side_view.jpg' -import axygen_1_reservoir_90ml_side_view from './images/axygen_1_reservoir_90ml_side_view.jpg' -import biorad_96_wellplate_200ul_pcr_photo_three_quarters from './images/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg' -import corning_12_wellplate_6_9ml_flat_photo_three_quarters from './images/corning_12_wellplate_6.9ml_flat_photo_three_quarters.jpg' -import corning_24_wellplate_3_4ml_flat_photo_three_quarters from './images/corning_24_wellplate_3.4ml_flat_photo_three_quarters.jpg' -import corning_384_wellplate_112ul_flat_photo_three_quarters from './images/corning_384_wellplate_112ul_flat_photo_three_quarters.jpg' -import corning_96_wellplate_360ul_flat_three_quarters from './images/corning_96_wellplate_360ul_flat_three_quarters.jpg' -import corning_48_wellplate_1_6ml_flat_photo_three_quarters from './images/corning_48_wellplate_1.6ml_flat_photo_three_quarters.jpg' -import corning_6_wellplate_16_8ml_flat_photo_three_quarters from './images/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg' -import eppendorf_1000ul_tip_eptips_side_view from './images/eppendorf_1000ul_tip_eptips_side_view.jpg' -import eppendorf_10ul_tips_eptips_side_view from './images/eppendorf_10ul_tips_eptips_side_view.jpg' -import geb_96_tiprack_1000ul_side_view from './images/geb_96_tiprack_1000ul_side_view.jpg' -import geb_1000ul_tip_side_view from './images/geb_1000ul_tip_side_view.jpg' -import geb_96_tiprack_10ul_side_view from './images/geb_96_tiprack_10ul_side_view.jpg' -import geb_10ul_tip_side_view from './images/geb_10ul_tip_side_view.jpg' -import nest_1_reservoir_195ml_three_quarters from './images/nest_1_reservoir_195ml_three_quarters.jpg' -import nest_1_reservoir_290ml from './images/nest_1_reservoir_290ml.jpg' -import nest_12_reservoir_15ml_three_quarters from './images/nest_12_reservoir_15ml_three_quarters.jpg' -import nest_96_wellplate_100ul_pcr_full_skirt_three_quarters from './images/nest_96_wellplate_100ul_pcr_full_skirt_three_quarters.jpg' -import nest_96_wellplate_200ul_flat_three_quarters from './images/nest_96_wellplate_200ul_flat_three_quarters.jpg' -import nest_96_wellplate_2ml_deep from './images/nest_96_wellplate_2ml_deep.jpg' -import opentrons_10_tuberack_4_6_side_view from './images/opentrons_10_tuberack_4_6_side_view.jpg' -import falcon_50ml_15ml_conical_tubes from './images/falcon_50ml_15ml_conical_tubes.jpg' -import opentrons_15_tuberack_side_view from './images/opentrons_15_tuberack_side_view.jpg' -import falcon_15ml_conical_tube from './images/falcon_15ml_conical_tube.jpg' -import nest_50ml_15ml_conical_tubes from './images/nest_50ml_15ml_conical_tubes.jpg' -import nest_15ml_conical_tube from './images/nest_15ml_conical_tube.jpg' -import opentrons_6_tuberack_side_view from './images/opentrons_6_tuberack_side_view.jpg' -import nest_50ml_conical_tube from './images/nest_50ml_conical_tube.jpg' -import opentrons_24_aluminumblock_side_view from './images/opentrons_24_aluminumblock_side_view.jpg' -import generic_2ml_screwcap_tube from './images/generic_2ml_screwcap_tube.jpg' -import nest_0_5ml_screwcap_tube from './images/nest_0.5ml_screwcap_tube.jpg' -import nest_1_5ml_screwcap_tube from './images/nest_1.5ml_screwcap_tube.jpg' -import nest_1_5ml_snapcap_tube from './images/nest_1.5ml_snapcap_tube.jpg' -import nest_2ml_screwcap_tube from './images/nest_2ml_screwcap_tube.jpg' -import nest_2ml_snapcap_tube from './images/nest_2ml_snapcap_tube.jpg' -import opentrons_24_tuberack_side_view from './images/opentrons_24_tuberack_side_view.jpg' -import eppendorf_1_5ml_safelock_snapcap_tube from './images/eppendorf_1.5ml_safelock_snapcap_tube.jpg' -import eppendorf_2ml_safelock_snapcap_tube from './images/eppendorf_2ml_safelock_snapcap_tube.jpg' -import falcon_50ml_conical_tube from './images/falcon_50ml_conical_tube.jpg' -import generic_pcr_strip_200ul_tubes from './images/generic_pcr_strip_200ul_tubes.jpg' -import opentrons_96_tiprack_1000ul_side_view from './images/opentrons_96_tiprack_1000ul_side_view.jpg' -import opentrons_96_tiprack_10ul_side_view from './images/opentrons_96_tiprack_10ul_side_view.jpg' -import opentrons_96_tiprack_300ul_side_view from './images/opentrons_96_tiprack_300ul_side_view.jpg' -import tipone_96_tiprack_200ul_side_view from './images/tipone_96_tiprack_200ul_side_view.jpg' -import tipone_200ul_tip_side_view from './images/tipone_200ul_tip_side_view.jpg' -import usascientific_12_reservoir_22ml_side_view from './images/usascientific_12_reservoir_22ml_side_view.jpg' -import usascientific_96_wellplate_2_4ml_deep_side_view from './images/usascientific_96_wellplate_2.4ml_deep_side_view.jpg' -import thermoscientificnunc_96_wellplate_1300ul from './images/thermoscientificnunc_96_wellplate_1300ul.jpg' -import thermoscientificnunc_96_wellplate_2000ul from './images/thermoscientificnunc_96_wellplate_2000ul.jpg' -import appliedbiosystemsmicroamp_384_wellplate_40ul from './images/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg' -import biorad_384_wellplate_50ul from './images/biorad_384_wellplate_50ul.jpg' -import deep_well_plate_adapter from './images/deep_well_plate_adapter.jpg' -import flat_bottom_plate_adapter from './images/flat_bottom_plate_adapter.jpg' -import pcr_plate_adapter from './images/pcr_plate_adapter.jpg' -import universal_flat_adapter from './images/universal_flat_adapter.jpg' -import flat_bottom_aluminum from './images/flat_bottom_aluminum.png' -import opentrons_96_aluminumblock_side_view from './images/opentrons_96_aluminumblock_side_view.jpg' -import opentrons_96_deep_well_temp_mod_adapter_img from './images/opentrons_96_deep_well_temp_mod_adapter.png' +import agilent_1_reservoir_290ml_side_view from '/app/assets/images/labware/agilent_1_reservoir_290ml_side_view.jpg' +import axygen_1_reservoir_90ml_side_view from '/app/assets/images/labware/axygen_1_reservoir_90ml_side_view.jpg' +import biorad_96_wellplate_200ul_pcr_photo_three_quarters from '/app/assets/images/labware/biorad_96_wellplate_200ul_pcr_photo_three_quarters.jpg' +import corning_12_wellplate_6_9ml_flat_photo_three_quarters from '/app/assets/images/labware/corning_12_wellplate_6.9ml_flat_photo_three_quarters.jpg' +import corning_24_wellplate_3_4ml_flat_photo_three_quarters from '/app/assets/images/labware/corning_24_wellplate_3.4ml_flat_photo_three_quarters.jpg' +import corning_384_wellplate_112ul_flat_photo_three_quarters from '/app/assets/images/labware/corning_384_wellplate_112ul_flat_photo_three_quarters.jpg' +import corning_96_wellplate_360ul_flat_three_quarters from '/app/assets/images/labware/corning_96_wellplate_360ul_flat_three_quarters.jpg' +import corning_48_wellplate_1_6ml_flat_photo_three_quarters from '/app/assets/images/labware/corning_48_wellplate_1.6ml_flat_photo_three_quarters.jpg' +import corning_6_wellplate_16_8ml_flat_photo_three_quarters from '/app/assets/images/labware/corning_6_wellplate_16.8ml_flat_photo_three_quarters.jpg' +import eppendorf_1000ul_tip_eptips_side_view from '/app/assets/images/labware/eppendorf_1000ul_tip_eptips_side_view.jpg' +import eppendorf_10ul_tips_eptips_side_view from '/app/assets/images/labware/eppendorf_10ul_tips_eptips_side_view.jpg' +import geb_96_tiprack_1000ul_side_view from '/app/assets/images/labware/geb_96_tiprack_1000ul_side_view.jpg' +import geb_1000ul_tip_side_view from '/app/assets/images/labware/geb_1000ul_tip_side_view.jpg' +import geb_96_tiprack_10ul_side_view from '/app/assets/images/labware/geb_96_tiprack_10ul_side_view.jpg' +import geb_10ul_tip_side_view from '/app/assets/images/labware/geb_10ul_tip_side_view.jpg' +import nest_1_reservoir_195ml_three_quarters from '/app/assets/images/labware/nest_1_reservoir_195ml_three_quarters.jpg' +import nest_1_reservoir_290ml from '/app/assets/images/labware/nest_1_reservoir_290ml.jpg' +import nest_12_reservoir_15ml_three_quarters from '/app/assets/images/labware/nest_12_reservoir_15ml_three_quarters.jpg' +import nest_96_wellplate_100ul_pcr_full_skirt_three_quarters from '/app/assets/images/labware/nest_96_wellplate_100ul_pcr_full_skirt_three_quarters.jpg' +import nest_96_wellplate_200ul_flat_three_quarters from '/app/assets/images/labware/nest_96_wellplate_200ul_flat_three_quarters.jpg' +import nest_96_wellplate_2ml_deep from '/app/assets/images/labware/nest_96_wellplate_2ml_deep.jpg' +import opentrons_10_tuberack_4_6_side_view from '/app/assets/images/labware/opentrons_10_tuberack_4_6_side_view.jpg' +import falcon_50ml_15ml_conical_tubes from '/app/assets/images/labware/falcon_50ml_15ml_conical_tubes.jpg' +import opentrons_15_tuberack_side_view from '/app/assets/images/labware/opentrons_15_tuberack_side_view.jpg' +import falcon_15ml_conical_tube from '/app/assets/images/labware/falcon_15ml_conical_tube.jpg' +import nest_50ml_15ml_conical_tubes from '/app/assets/images/labware/nest_50ml_15ml_conical_tubes.jpg' +import nest_15ml_conical_tube from '/app/assets/images/labware/nest_15ml_conical_tube.jpg' +import opentrons_6_tuberack_side_view from '/app/assets/images/labware/opentrons_6_tuberack_side_view.jpg' +import nest_50ml_conical_tube from '/app/assets/images/labware/nest_50ml_conical_tube.jpg' +import opentrons_24_aluminumblock_side_view from '/app/assets/images/labware/opentrons_24_aluminumblock_side_view.jpg' +import generic_2ml_screwcap_tube from '/app/assets/images/labware/generic_2ml_screwcap_tube.jpg' +import nest_0_5ml_screwcap_tube from '/app/assets/images/labware/nest_0.5ml_screwcap_tube.jpg' +import nest_1_5ml_screwcap_tube from '/app/assets/images/labware/nest_1.5ml_screwcap_tube.jpg' +import nest_1_5ml_snapcap_tube from '/app/assets/images/labware/nest_1.5ml_snapcap_tube.jpg' +import nest_2ml_screwcap_tube from '/app/assets/images/labware/nest_2ml_screwcap_tube.jpg' +import nest_2ml_snapcap_tube from '/app/assets/images/labware/nest_2ml_snapcap_tube.jpg' +import opentrons_24_tuberack_side_view from '/app/assets/images/labware/opentrons_24_tuberack_side_view.jpg' +import eppendorf_1_5ml_safelock_snapcap_tube from '/app/assets/images/labware/eppendorf_1.5ml_safelock_snapcap_tube.jpg' +import eppendorf_2ml_safelock_snapcap_tube from '/app/assets/images/labware/eppendorf_2ml_safelock_snapcap_tube.jpg' +import falcon_50ml_conical_tube from '/app/assets/images/labware/falcon_50ml_conical_tube.jpg' +import generic_pcr_strip_200ul_tubes from '/app/assets/images/labware/generic_pcr_strip_200ul_tubes.jpg' +import opentrons_96_tiprack_1000ul_side_view from '/app/assets/images/labware/opentrons_96_tiprack_1000ul_side_view.jpg' +import opentrons_96_tiprack_10ul_side_view from '/app/assets/images/labware/opentrons_96_tiprack_10ul_side_view.jpg' +import opentrons_96_tiprack_300ul_side_view from '/app/assets/images/labware/opentrons_96_tiprack_300ul_side_view.jpg' +import tipone_96_tiprack_200ul_side_view from '/app/assets/images/labware/tipone_96_tiprack_200ul_side_view.jpg' +import tipone_200ul_tip_side_view from '/app/assets/images/labware/tipone_200ul_tip_side_view.jpg' +import usascientific_12_reservoir_22ml_side_view from '/app/assets/images/labware/usascientific_12_reservoir_22ml_side_view.jpg' +import usascientific_96_wellplate_2_4ml_deep_side_view from '/app/assets/images/labware/usascientific_96_wellplate_2.4ml_deep_side_view.jpg' +import thermoscientificnunc_96_wellplate_1300ul from '/app/assets/images/labware/thermoscientificnunc_96_wellplate_1300ul.jpg' +import thermoscientificnunc_96_wellplate_2000ul from '/app/assets/images/labware/thermoscientificnunc_96_wellplate_2000ul.jpg' +import appliedbiosystemsmicroamp_384_wellplate_40ul from '/app/assets/images/labware/appliedbiosystemsmicroamp_384_wellplate_40ul.jpg' +import biorad_384_wellplate_50ul from '/app/assets/images/labware/biorad_384_wellplate_50ul.jpg' +import deep_well_plate_adapter from '/app/assets/images/labware/deep_well_plate_adapter.jpg' +import flat_bottom_plate_adapter from '/app/assets/images/labware/flat_bottom_plate_adapter.jpg' +import pcr_plate_adapter from '/app/assets/images/labware/pcr_plate_adapter.jpg' +import universal_flat_adapter from '/app/assets/images/labware/universal_flat_adapter.jpg' +import flat_bottom_aluminum from '/app/assets/images/labware/flat_bottom_aluminum.png' +import opentrons_96_aluminumblock_side_view from '/app/assets/images/labware/opentrons_96_aluminumblock_side_view.jpg' +import opentrons_96_deep_well_temp_mod_adapter_img from '/app/assets/images/labware/opentrons_96_deep_well_temp_mod_adapter.png' export const labwareImages: Record = { agilent_1_reservoir_290ml: [agilent_1_reservoir_290ml_side_view], axygen_1_reservoir_90ml: [axygen_1_reservoir_90ml_side_view], diff --git a/app/src/organisms/Devices/HistoricalProtocolRun.tsx b/app/src/organisms/Devices/HistoricalProtocolRun.tsx index 0309c227edc..e843ecec15d 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRun.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRun.tsx @@ -14,9 +14,9 @@ import { LegacyStyledText, CURSOR_POINTER, } from '@opentrons/components' -import { formatInterval } from '../RunTimeControl/utils' +import { formatInterval } from '/app/transformations/commands' import { formatTimestamp } from './utils' -import { EMPTY_TIMESTAMP } from './constants' +import { EMPTY_TIMESTAMP } from '/app/resources/runs' import { HistoricalProtocolRunOverflowMenu as OverflowMenu } from './HistoricalProtocolRunOverflowMenu' import { HistoricalProtocolRunDrawer as Drawer } from './HistoricalProtocolRunDrawer' import type { RunData } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx index 8df2dcdb1fd..4e4723a5ccd 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx @@ -33,8 +33,10 @@ import { ANALYTICS_PROTOCOL_RUN_ACTION, } from '/app/redux/analytics' import { useIsRobotOnWrongVersionOfSoftware } from '/app/redux/robot-update' -import { useDownloadRunLog, useTrackProtocolRunEvent, useRobot } from './hooks' +import { useDownloadRunLog } from './hooks' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' +import { useRobot } from '/app/redux-resources/robots' import type { Run } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/InstrumentsAndModules.tsx b/app/src/organisms/Devices/InstrumentsAndModules.tsx index 9b25901e6ff..b8b2e786bb5 100644 --- a/app/src/organisms/Devices/InstrumentsAndModules.tsx +++ b/app/src/organisms/Devices/InstrumentsAndModules.tsx @@ -23,8 +23,9 @@ import { import { Banner } from '/app/atoms/Banner' import { PipetteRecalibrationWarning } from './PipetteCard/PipetteRecalibrationWarning' import { useCurrentRunId } from '/app/resources/runs' +import { useIsFlex } from '/app/redux-resources/robots' import { ModuleCard } from '../ModuleCard' -import { useIsFlex, useIsRobotViewable, useRunStatuses } from './hooks' +import { useIsRobotViewable, useRunStatuses } from './hooks' import { getShowPipetteCalibrationWarning } from './utils' import { PipetteCard } from './PipetteCard' import { FlexPipetteCard } from './PipetteCard/FlexPipetteCard' diff --git a/app/src/organisms/Devices/ProtocolRun/BackToTopButton.tsx b/app/src/organisms/Devices/ProtocolRun/BackToTopButton.tsx index 822856b0705..385d6537272 100644 --- a/app/src/organisms/Devices/ProtocolRun/BackToTopButton.tsx +++ b/app/src/organisms/Devices/ProtocolRun/BackToTopButton.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { Link } from 'react-router-dom' -import { useRobot } from '../hooks' +import { useRobot } from '/app/redux-resources/robots' import { getRobotSerialNumber } from '/app/redux/discovery' import { SecondaryButton } from '@opentrons/components' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx index 6f015df520a..3df355a0b3c 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx @@ -13,9 +13,11 @@ import { import { RUN_STATUS_STOPPED, RUN_STATUS_SUCCEEDED } from '@opentrons/api-client' import { Banner } from '/app/atoms/Banner' -import { useCloseCurrentRun } from '../../../../ProtocolUpload/hooks' -import { useIsRunCurrent } from '/app/resources/runs' -import { useMostRecentRunId } from '../../../../ProtocolUpload/hooks/useMostRecentRunId' +import { + useCloseCurrentRun, + useIsRunCurrent, + useMostRecentRunId, +} from '/app/resources/runs' import type { RunHeaderBannerContainerProps } from '.' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useActionButtonProperties.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useActionButtonProperties.ts index 7830393f47b..d47788130c4 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useActionButtonProperties.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useActionButtonProperties.ts @@ -13,7 +13,7 @@ import { ANALYTICS_PROTOCOL_RUN_ACTION, useTrackEvent, } from '/app/redux/analytics' -import { useTrackProtocolRunEvent } from '../../../../../hooks' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' import { useIsHeaterShakerInProtocol } from '../../../../../../ModuleCard/hooks' import { isAnyHeaterShakerShaking } from '../../../RunHeaderModalContainer/modals' import { diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useIsFixtureMismatch.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useIsFixtureMismatch.ts index a9292a6dcdf..ebac2a7bec3 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useIsFixtureMismatch.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/hooks/useIsFixtureMismatch.ts @@ -1,5 +1,5 @@ import { useMostRecentCompletedAnalysis } from '../../../../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useRobotType } from '../../../../../hooks' +import { useRobotType } from '/app/redux-resources/robots' import { getIsFixtureMismatch, useDeckConfigurationCompatibility, diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/index.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/index.tsx index a8ffba6a3b8..00bca7d21b7 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/ActionButton/index.tsx @@ -16,13 +16,12 @@ import { import { useModuleCalibrationStatus, - useProtocolDetailsForRun, - useRobot, - useRobotAnalyticsData, useRunCalibrationStatus, useUnmatchedModulesForProtocol, } from '../../../../hooks' -import { useCurrentRunId } from '/app/resources/runs' +import { useRobot } from '/app/redux-resources/robots' +import { useRobotAnalyticsData } from '/app/redux-resources/analytics' +import { useCurrentRunId, useProtocolDetailsForRun } from '/app/resources/runs' import { useActionBtnDisabledUtils, useActionButtonProperties } from './hooks' import { getFallbackRobotSerialNumber, isRunAgainStatus } from '../../utils' import { useIsRobotOnWrongVersionOfSoftware } from '/app/redux/robot-update' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionLower.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionLower.tsx index 0b6d3062635..9c8168c7f11 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionLower.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionLower.tsx @@ -6,6 +6,7 @@ import { BORDERS, Box, COLORS, + DISPLAY_GRID, Flex, JUSTIFY_FLEX_END, SecondaryButton, @@ -14,12 +15,12 @@ import { import { RUN_STATUS_RUNNING } from '@opentrons/api-client' import { formatTimestamp } from '../../../utils' -import { EMPTY_TIMESTAMP } from '../../../constants' +import { useRunControls } from '../../../../RunTimeControl/hooks' import { - useRunControls, + EMPTY_TIMESTAMP, useRunTimestamps, -} from '../../../../RunTimeControl/hooks' -import { useCloseCurrentRun } from '../../../../ProtocolUpload/hooks' + useCloseCurrentRun, +} from '/app/resources/runs' import { LabeledValue } from './LabeledValue' import { isCancellableStatus } from '../utils' @@ -69,7 +70,7 @@ export function RunHeaderSectionLower({ } const SECTION_STYLE = css` - display: grid; + display: ${DISPLAY_GRID}; grid-template-columns: 4fr 6fr 4fr; background-color: ${COLORS.grey10}; padding: ${SPACING.spacing8}; diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx index 65428c7c9b8..df397d937d1 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx @@ -2,14 +2,19 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { css } from 'styled-components' -import { Box, Flex, JUSTIFY_FLEX_END } from '@opentrons/components' +import { + Box, + DISPLAY_GRID, + Flex, + JUSTIFY_FLEX_END, +} from '@opentrons/components' import { LabeledValue } from './LabeledValue' import { DisplayRunStatus } from '../DisplayRunStatus' import { RunTimer } from '../../RunTimer' import { ActionButton } from './ActionButton' import { useRunCreatedAtTimestamp } from '../../../hooks' -import { useRunTimestamps } from '../../../../RunTimeControl/hooks' +import { useRunTimestamps } from '/app/resources/runs' import type { RunHeaderContentProps } from '.' @@ -50,6 +55,6 @@ export function RunHeaderSectionUpper( } const SECTION_STYLE = css` - display: grid; + display: ${DISPLAY_GRID}; grid-template-columns: 4fr 3fr 3fr 4fr; ` diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/hooks/useRunHeaderDropTip.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/hooks/useRunHeaderDropTip.ts index 592e305adec..77f9c35ce8f 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/hooks/useRunHeaderDropTip.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/hooks/useRunHeaderDropTip.ts @@ -9,8 +9,7 @@ import { useTipAttachmentStatus, } from '../../../../../DropTipWizardFlows' import { useProtocolDropTipModal } from '../modals' -import { useCloseCurrentRun } from '../../../../../ProtocolUpload/hooks' -import { useIsRunCurrent } from '/app/resources/runs' +import { useCloseCurrentRun, useIsRunCurrent } from '/app/resources/runs' import { isTerminalRunStatus } from '../../utils' import type { RobotType } from '@opentrons/shared-data' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/ConfirmCancelModal.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/ConfirmCancelModal.tsx index b4cc41a4cd5..083b7f752fc 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/ConfirmCancelModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/ConfirmCancelModal.tsx @@ -22,8 +22,9 @@ import { } from '@opentrons/api-client' import { useStopRunMutation } from '@opentrons/react-api-client' -import { getTopPortalEl } from '../../../../../../App/portal' -import { useTrackProtocolRunEvent, useIsFlex } from '../../../../hooks' +import { getTopPortalEl } from '/app/App/portal' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' +import { useIsFlex } from '/app/redux-resources/robots' import { ANALYTICS_PROTOCOL_RUN_ACTION } from '/app/redux/analytics' import type { RunStatus } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/HeaterShakerIsRunningModal/__tests__/hooks.test.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/HeaterShakerIsRunningModal/__tests__/hooks.test.tsx index c6eb01dc382..75941043fd3 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/HeaterShakerIsRunningModal/__tests__/hooks.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/HeaterShakerIsRunningModal/__tests__/hooks.test.tsx @@ -6,7 +6,7 @@ import { renderHook } from '@testing-library/react' import { HEATERSHAKER_MODULE_V1 } from '@opentrons/shared-data' -import { RUN_ID_1 } from '../../../../../../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { useMostRecentCompletedAnalysis } from '../../../../../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useHeaterShakerModuleIdsFromRun } from '../hooks' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/__tests__/ConfirmCancelModal.test.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/__tests__/ConfirmCancelModal.test.tsx index abce7211481..c12f6a150cf 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/__tests__/ConfirmCancelModal.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/__tests__/ConfirmCancelModal.test.tsx @@ -12,7 +12,8 @@ import { useStopRunMutation } from '@opentrons/react-api-client' import { i18n } from '/app/i18n' import { renderWithProviders } from '/app/__testing-utils__' -import { useIsFlex, useTrackProtocolRunEvent } from '../../../../../hooks' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' +import { useIsFlex } from '/app/redux-resources/robots' import { useTrackEvent } from '/app/redux/analytics' import { ConfirmCancelModal } from '../ConfirmCancelModal' @@ -25,8 +26,9 @@ vi.mock('@opentrons/react-api-client', async importOriginal => { useStopRunMutation: vi.fn(), } }) -vi.mock('../../../../../hooks') vi.mock('/app/redux/analytics') +vi.mock('/app/redux-resources/analytics') +vi.mock('/app/redux-resources/robots') const render = (props: React.ComponentProps) => { return renderWithProviders(, { diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts index 2704eb81445..8cc270b9061 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/useRunHeaderModalContainer.ts @@ -12,17 +12,13 @@ import { useRunHeaderDropTip, } from './hooks' import { useErrorRecoveryFlows } from '../../../../ErrorRecoveryFlows' -import { - useProtocolDetailsForRun, - useRobot, - useRobotType, -} from '../../../hooks' +import { useProtocolDetailsForRun } from '/app/resources/runs' import { getFallbackRobotSerialNumber } from '../utils' import { ANALYTICS_PROTOCOL_PROCEED_TO_RUN, useTrackEvent, } from '/app/redux/analytics' - +import { useRobot, useRobotType } from '/app/redux-resources/robots' import type { AttachedModule, RunStatus, Run } from '@opentrons/api-client' import type { UseErrorRecoveryResult } from '../../../../ErrorRecoveryFlows' import type { diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderProtocolName.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderProtocolName.tsx index 7225ce280e0..9e3addadbc2 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderProtocolName.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderProtocolName.tsx @@ -8,7 +8,7 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { useProtocolDetailsForRun } from '../../hooks' +import { useProtocolDetailsForRun } from '/app/resources/runs' interface RunHeaderProtocolNameProps { runId: string diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/__tests__/ProtocolRunHeader.test.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/__tests__/ProtocolRunHeader.test.tsx index de7691bb394..e06718390c6 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/__tests__/ProtocolRunHeader.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/__tests__/ProtocolRunHeader.test.tsx @@ -9,9 +9,12 @@ import { useModulesQuery } from '@opentrons/react-api-client' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { ProtocolRunHeader } from '..' -import { useRunStatus } from '../../../../RunTimeControl/hooks' -import { useIsRobotViewable, useProtocolDetailsForRun } from '../../../hooks' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useIsRobotViewable } from '../../../hooks' +import { + useRunStatus, + useProtocolDetailsForRun, + useNotifyRunQuery, +} from '/app/resources/runs' import { RunHeaderModalContainer } from '../RunHeaderModalContainer' import { RunHeaderBannerContainer } from '../RunHeaderBannerContainer' import { RunHeaderContent } from '../RunHeaderContent' @@ -25,7 +28,7 @@ import { vi.mock('react-router-dom') vi.mock('@opentrons/react-api-client') -vi.mock('../../../../RunTimeControl/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../../../hooks') vi.mock('/app/resources/runs') vi.mock('../RunHeaderModalContainer') diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useIsDoorOpen.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useIsDoorOpen.ts index 81f3d50effa..ea852d63c72 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useIsDoorOpen.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useIsDoorOpen.ts @@ -3,7 +3,7 @@ import { useSelector } from 'react-redux' import { useDoorQuery } from '@opentrons/react-api-client' import { getRobotSettings } from '/app/redux/robot-settings' -import { useIsFlex } from '../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { EQUIPMENT_POLL_MS } from '../constants' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts index 2ced80e1c6d..896f432336c 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunAnalytics.ts @@ -1,10 +1,12 @@ import * as React from 'react' -import { useRobotAnalyticsData, useTrackProtocolRunEvent } from '../../../hooks' -import { useRunStatus } from '../../../../RunTimeControl/hooks' -import { useIsRunCurrent } from '/app/resources/runs' +import { + useRobotAnalyticsData, + useTrackProtocolRunEvent, + useRecoveryAnalytics, +} from '/app/redux-resources/analytics' +import { useIsRunCurrent, useRunStatus } from '/app/resources/runs' import { ANALYTICS_PROTOCOL_RUN_ACTION } from '/app/redux/analytics' -import { useRecoveryAnalytics } from '../../../../ErrorRecoveryFlows/hooks' import { isTerminalRunStatus } from '../utils' interface UseRunAnalyticsProps { diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunErrors.ts b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunErrors.ts index 58d39855f44..302f23f0a1e 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunErrors.ts +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/hooks/useRunErrors.ts @@ -1,7 +1,7 @@ import { useRunCommandErrors } from '@opentrons/react-api-client' import { isTerminalRunStatus } from '../utils' -import { useMostRecentRunId } from '../../../../ProtocolUpload/hooks/useMostRecentRunId' +import { useMostRecentRunId } from '/app/resources/runs/useMostRecentRunId' import { getHighestPriorityError } from '../../../../ODD/RunningProtocol' import type { RunStatus, Run } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/index.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/index.tsx index 94dd3a898c7..9de0be2702b 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/index.tsx @@ -12,10 +12,13 @@ import { import { useModulesQuery } from '@opentrons/react-api-client' import { RUN_STATUS_IDLE, RUN_STATUS_RUNNING } from '@opentrons/api-client' -import { useRunStatus } from '../../../RunTimeControl/hooks' -import { useIsRobotViewable, useProtocolDetailsForRun } from '../../hooks' +import { useIsRobotViewable } from '../../hooks' import { RunProgressMeter } from '../../../RunProgressMeter' -import { useNotifyRunQuery } from '/app/resources/runs' +import { + useNotifyRunQuery, + useProtocolDetailsForRun, + useRunStatus, +} from '/app/resources/runs' import { RunHeaderProtocolName } from './RunHeaderProtocolName' import { RunHeaderModalContainer, diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx index 27454629276..f5fc97c22e2 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx @@ -18,6 +18,7 @@ import { COLORS, DIRECTION_COLUMN, DIRECTION_ROW, + DISPLAY_GRID, DISPLAY_INLINE, Flex, Icon, @@ -33,8 +34,7 @@ import { import { Banner } from '/app/atoms/Banner' import { Divider } from '/app/atoms/structure' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useRunStatus } from '../../RunTimeControl/hooks' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery, useRunStatus } from '/app/resources/runs' import type { RunTimeParameter } from '@opentrons/shared-data' import type { RunStatus } from '@opentrons/api-client' @@ -259,7 +259,7 @@ const StyledTable = styled.table` text-align: left; ` const StyledTableHeaderContainer = styled.thead` - display: grid; + display: ${DISPLAY_GRID}; grid-template-columns: 0.35fr 0.35fr; grid-gap: ${SPACING.spacing48}; border-bottom: ${BORDERS.lineBorder}; @@ -275,7 +275,7 @@ interface StyledTableRowProps { } const StyledTableRow = styled.tr` - display: grid; + display: ${DISPLAY_GRID}; grid-template-columns: 0.35fr 0.35fr; grid-gap: ${SPACING.spacing48}; border-bottom: ${props => (props.isLast ? 'none' : BORDERS.lineBorder)}; diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunSetup.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunSetup.tsx index 3f298fa215e..e216298f07a 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunSetup.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunSetup.tsx @@ -29,15 +29,14 @@ import { getRequiredDeckConfig, } from '/app/resources/deck_configuration/utils' import { useDeckConfigurationCompatibility } from '/app/resources/deck_configuration/hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { - useIsFlex, useModuleCalibrationStatus, useProtocolAnalysisErrors, - useRobot, useRunCalibrationStatus, useRunHasStarted, useRunPipetteInfoByMount, - useStoredProtocolAnalysis, useUnmatchedModulesForProtocol, } from '../hooks' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' diff --git a/app/src/organisms/Devices/ProtocolRun/RunTimer.tsx b/app/src/organisms/Devices/ProtocolRun/RunTimer.tsx index 609ae40dda5..ba285e0bb12 100644 --- a/app/src/organisms/Devices/ProtocolRun/RunTimer.tsx +++ b/app/src/organisms/Devices/ProtocolRun/RunTimer.tsx @@ -7,8 +7,8 @@ import { LegacyStyledText, } from '@opentrons/components' -import { formatInterval } from '/app/organisms/RunTimeControl/utils' -import { EMPTY_TIMESTAMP } from '../constants' +import { formatInterval } from '/app/transformations/commands' +import { EMPTY_TIMESTAMP } from '/app/resources/runs' import type { CSSProp } from 'styled-components' export function RunTimer({ diff --git a/app/src/organisms/Devices/ProtocolRun/SetupFlexPipetteCalibrationItem.tsx b/app/src/organisms/Devices/ProtocolRun/SetupFlexPipetteCalibrationItem.tsx index e7e7b1b2234..fda16d0fa2a 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupFlexPipetteCalibrationItem.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupFlexPipetteCalibrationItem.tsx @@ -16,7 +16,7 @@ import { import { useInstrumentsQuery } from '@opentrons/react-api-client' import { TertiaryButton } from '/app/atoms/buttons' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useStoredProtocolAnalysis } from '../hooks' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { PipetteWizardFlows } from '../../PipetteWizardFlows' import { FLOWS } from '../../PipetteWizardFlows/constants' import { SetupCalibrationItem } from './SetupCalibrationItem' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupInstrumentCalibration.tsx b/app/src/organisms/Devices/ProtocolRun/SetupInstrumentCalibration.tsx index 2175fd260a4..e2ff193bcd9 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupInstrumentCalibration.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupInstrumentCalibration.tsx @@ -12,11 +12,9 @@ import { import * as PipetteConstants from '/app/redux/pipettes/constants' import { getShowPipetteCalibrationWarning } from '../utils' import { PipetteRecalibrationWarning } from '../PipetteCard/PipetteRecalibrationWarning' -import { - useRunPipetteInfoByMount, - useStoredProtocolAnalysis, - useIsFlex, -} from '../hooks' +import { useRunPipetteInfoByMount } from '../hooks' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' +import { useIsFlex } from '/app/redux-resources/robots' import { SetupPipetteCalibrationItem } from './SetupPipetteCalibrationItem' import { SetupFlexPipetteCalibrationItem } from './SetupFlexPipetteCalibrationItem' import { SetupGripperCalibrationItem } from './SetupGripperCalibrationItem' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx index 427dedac876..0b950e16720 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx @@ -11,12 +11,13 @@ import { DIRECTION_COLUMN, DIRECTION_ROW, DISPLAY_FLEX, + DISPLAY_GRID, Flex, Icon, JUSTIFY_CENTER, JUSTIFY_SPACE_BETWEEN, - MODULE_ICON_NAME_BY_TYPE, LabwareRender, + MODULE_ICON_NAME_BY_TYPE, SIZE_AUTO, SPACING, StyledText, @@ -55,7 +56,7 @@ import type { ModuleTypesThatRequireExtraAttention } from '../utils/getModuleTyp import type { NestedLabwareInfo } from './getNestedLabwareInfo' const LabwareRow = styled.div` - display: grid; + display: ${DISPLAY_GRID}; grid-template-columns: 90px 12fr; border-style: ${BORDERS.styleSolid}; border-width: 1px; diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx index 8f4c25d5979..feb3b1be340 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/SetupLabwareMap.tsx @@ -184,7 +184,7 @@ export function SetupLabwareMap({ ) return ( - + { const actualSharedData = await importOriginal() diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx index 09fd987b414..96b165742e9 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx @@ -29,7 +29,7 @@ import { OddModal } from '/app/molecules/OddModal' import { FixtureOption } from '../../../DeviceDetailsDeckConfiguration/AddFixtureModal' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' import { SmallButton } from '/app/atoms/buttons' -import { useCloseCurrentRun } from '../../../ProtocolUpload/hooks' +import { useCloseCurrentRun } from '/app/resources/runs' import type { ModuleModel, DeckDefinition } from '@opentrons/shared-data' import type { AttachedModule } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesList.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesList.tsx index d73e2f0b98b..058c000f953 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesList.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesList.tsx @@ -34,6 +34,7 @@ import { TC_MODULE_LOCATION_OT3, } from '@opentrons/shared-data' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { TertiaryButton } from '/app/atoms/buttons' import { StatusLabel } from '/app/atoms/StatusLabel' import { useChainLiveCommands } from '/app/resources/runs' @@ -42,9 +43,7 @@ import { ModuleWizardFlows } from '../../../ModuleWizardFlows' import { getModulePrepCommands } from '../../getModulePrepCommands' import { getModuleTooHot } from '../../getModuleTooHot' import { - useIsFlex, useModuleRenderInfoForProtocolById, - useRobot, useUnmatchedModulesForProtocol, useRunCalibrationStatus, } from '../../hooks' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesMap.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesMap.tsx index 5ca6d567eb1..cbf220b8d8a 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesMap.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/SetupModulesMap.tsx @@ -16,10 +16,11 @@ import { import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { getAttachedProtocolModuleMatches } from '../../../ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/utils' import { ModuleInfo } from '../../ModuleInfo' -import { useAttachedModules, useStoredProtocolAnalysis } from '../../hooks' +import { useAttachedModules } from '../../hooks' import { getProtocolModulesInfo } from '../utils/getProtocolModulesInfo' import { getStandardDeckViewLayerBlockList } from '../utils/getStandardDeckViewLayerBlockList' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' const ATTACHED_MODULE_POLL_MS = 5000 const DECK_CONFIG_POLL_MS = 5000 @@ -78,7 +79,6 @@ export const SetupModulesMap = ({ return ( diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx index 1ea14fbbc4a..dfc61ee1bc7 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/LocationConflictModal.test.tsx @@ -17,7 +17,7 @@ import { import { i18n } from '/app/i18n' import { mockHeaterShaker } from '/app/redux/modules/__fixtures__' -import { useCloseCurrentRun } from '../../../../ProtocolUpload/hooks' +import { useCloseCurrentRun } from '/app/resources/runs' import { LocationConflictModal } from '../LocationConflictModal' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' @@ -26,7 +26,7 @@ import type { DeckConfiguration } from '@opentrons/shared-data' vi.mock('@opentrons/react-api-client') vi.mock('/app/resources/deck_configuration') -vi.mock('../../../../ProtocolUpload/hooks') +vi.mock('/app/resources/runs') const mockFixture = { cutoutId: 'cutoutB3', diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesAndDeck.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesAndDeck.test.tsx index bd60638356c..4ba84391917 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesAndDeck.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesAndDeck.test.tsx @@ -10,17 +10,18 @@ import { getRequiredDeckConfig, } from '/app/resources/deck_configuration/utils' import { - useIsFlex, useRunHasStarted, useUnmatchedModulesForProtocol, useModuleCalibrationStatus, } from '../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { SetupModuleAndDeck } from '../index' import { SetupModulesList } from '../SetupModulesList' import { SetupModulesMap } from '../SetupModulesMap' import { SetupFixtureList } from '../SetupFixtureList' vi.mock('../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../SetupModulesList') vi.mock('../SetupModulesMap') vi.mock('../SetupFixtureList') diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx index 02d2e61d1a8..0be86e2df3b 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/__tests__/SetupModulesList.test.tsx @@ -13,15 +13,14 @@ import { mockMagneticModuleGen2, mockThermocycler, } from '/app/redux/modules/__fixtures__' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { useChainLiveCommands } from '/app/resources/runs' import { ModuleSetupModal } from '../../../../ModuleCard/ModuleSetupModal' import { ModuleWizardFlows } from '../../../../ModuleWizardFlows' import { - useIsFlex, useModuleRenderInfoForProtocolById, useUnmatchedModulesForProtocol, useRunCalibrationStatus, - useRobot, } from '../../../hooks' import { OT2MultipleModulesHelp } from '../OT2MultipleModulesHelp' import { UnMatchedModuleWarning } from '../UnMatchedModuleWarning' @@ -33,6 +32,7 @@ import type { DiscoveredRobot } from '/app/redux/discovery/types' vi.mock('@opentrons/react-api-client') vi.mock('../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../LocationConflictModal') vi.mock('../UnMatchedModuleWarning') vi.mock('../../../../ModuleCard/ModuleSetupModal') diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx index 71f7b997360..9af9469f322 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/index.tsx @@ -21,11 +21,11 @@ import { getIsFixtureMismatch, getRequiredDeckConfig, } from '/app/resources/deck_configuration/utils' +import { useRobotType } from '/app/redux-resources/robots' import { useRunHasStarted, useUnmatchedModulesForProtocol, useModuleCalibrationStatus, - useRobotType, } from '../../hooks' import { SetupModulesMap } from './SetupModulesMap' import { SetupModulesList } from './SetupModulesList' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupRobotCalibration.tsx b/app/src/organisms/Devices/ProtocolRun/SetupRobotCalibration.tsx index ff0807b3cec..ff0e2bd4f99 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupRobotCalibration.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupRobotCalibration.tsx @@ -16,12 +16,13 @@ import { ANALYTICS_PROCEED_TO_MODULE_SETUP_STEP, ANALYTICS_PROCEED_TO_LABWARE_SETUP_STEP, } from '/app/redux/analytics' -import { useIsFlex, useRunHasStarted } from '../hooks' +import { useRunHasStarted } from '../hooks' import { SetupDeckCalibration } from './SetupDeckCalibration' import { SetupInstrumentCalibration } from './SetupInstrumentCalibration' import { SetupTipLengthCalibration } from './SetupTipLengthCalibration' -import { useRunStatus } from '../../RunTimeControl/hooks' +import { useRunStatus } from '/app/resources/runs' import { RUN_STATUS_STOPPED } from '@opentrons/api-client' +import { useIsFlex } from '/app/redux-resources/robots' import type { ProtocolCalibrationStatus } from '/app/redux/calibration/types' import type { StepKey } from './ProtocolRunSetup' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupStep.tsx b/app/src/organisms/Devices/ProtocolRun/SetupStep.tsx index 9ddb1daf9af..4aefec39518 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupStep.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupStep.tsx @@ -8,9 +8,11 @@ import { COLORS, DIRECTION_COLUMN, DIRECTION_ROW, + DISPLAY_GRID, Flex, Icon, JUSTIFY_SPACE_BETWEEN, + OVERFLOW_HIDDEN, SPACING, StyledText, TYPOGRAPHY, @@ -32,16 +34,14 @@ interface SetupStepProps { } const EXPANDED_STYLE = css` - transition: max-height 300ms ease-in, visibility 400ms ease; + transition: grid-template-rows 300ms ease-in, visibility 400ms ease; + grid-template-rows: 1fr; visibility: visible; - max-height: 180vh; - overflow: hidden; ` const COLLAPSED_STYLE = css` - transition: max-height 500ms ease-out, visibility 600ms ease; + transition: grid-template-rows 500ms ease-out, visibility 600ms ease; + grid-template-rows: 0fr; visibility: hidden; - max-height: 0vh; - overflow: hidden; ` const ACCORDION_STYLE = css` border-radius: 50%; @@ -104,7 +104,12 @@ export function SetupStep({ - {children} + + {children} + ) } diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx index 3afe7f62c3f..8c2c3f79038 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx @@ -12,12 +12,12 @@ import { ANALYTICS_PROTOCOL_PROCEED_TO_RUN, } from '/app/redux/analytics' import { BackToTopButton } from '../BackToTopButton' -import { useRobot } from '../../hooks' +import { useRobot } from '/app/redux-resources/robots' import type { Mock } from 'vitest' vi.mock('/app/redux/analytics') -vi.mock('../../hooks') +vi.mock('/app/redux-resources/robots') const ROBOT_NAME = 'otie' const RUN_ID = '1' diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/LabwareInfoOverlay.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/LabwareInfoOverlay.test.tsx index 38732efae10..629c60e9209 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/LabwareInfoOverlay.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/LabwareInfoOverlay.test.tsx @@ -8,7 +8,7 @@ import { } from '@opentrons/shared-data' import { nestedTextMatcher, renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useCurrentRun } from '../../../ProtocolUpload/hooks' +import { useCurrentRun } from '/app/resources/runs' import { getLabwareLocation } from '../utils/getLabwareLocation' import { LabwareInfoOverlay } from '../LabwareInfoOverlay' import { getLabwareDefinitionUri } from '../utils/getLabwareDefinitionUri' @@ -19,7 +19,7 @@ import type { LoadedLabware, } from '@opentrons/shared-data' -vi.mock('../../../ProtocolUpload/hooks') +vi.mock('/app/resources/runs') vi.mock('../utils/getLabwareLocation') vi.mock('../../hooks') vi.mock('../utils/getLabwareDefinitionUri') diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx index a48e89079e0..5e295c6b7a6 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx @@ -6,12 +6,11 @@ import { InfoScreen } from '@opentrons/components' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useRunStatus } from '../../../RunTimeControl/hooks' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery, useRunStatus } from '/app/resources/runs' import { mockSucceededRun, mockIdleUnstartedRun, -} from '../../../RunTimeControl/__fixtures__' +} from '/app/resources/runs/__fixtures__' import { ProtocolRunRuntimeParameters } from '../ProtocolRunRunTimeParameters' import type { UseQueryResult } from 'react-query' @@ -29,7 +28,6 @@ vi.mock('@opentrons/components', async importOriginal => { } }) vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') -vi.mock('../../../RunTimeControl/hooks') vi.mock('/app/resources/runs') vi.mock('/app/redux/config') diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunSetup.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunSetup.test.tsx index ea01431ef9e..9dfd04b716f 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunSetup.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunSetup.test.tsx @@ -21,17 +21,17 @@ import { } from '/app/resources/deck_configuration/utils' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useDeckConfigurationCompatibility } from '/app/resources/deck_configuration/hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { - useIsFlex, useModuleCalibrationStatus, useProtocolAnalysisErrors, - useRobot, useRunCalibrationStatus, useRunHasStarted, useRunPipetteInfoByMount, - useStoredProtocolAnalysis, useUnmatchedModulesForProtocol, } from '../../hooks' + import { SetupLabware } from '../SetupLabware' import { SetupRobotCalibration } from '../SetupRobotCalibration' import { SetupLiquids } from '../SetupLiquids' @@ -54,6 +54,8 @@ vi.mock('/app/redux/config') vi.mock('/app/resources/deck_configuration/utils') vi.mock('/app/resources/deck_configuration/hooks') vi.mock('/app/resources/runs/useNotifyRunQuery') +vi.mock('/app/redux-resources/robots') +vi.mock('/app/resources/analysis') vi.mock('@opentrons/shared-data', async importOriginal => { const actualSharedData = await importOriginal() return { diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupFlexPipetteCalibrationItem.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupFlexPipetteCalibrationItem.test.tsx index 29d46d08fae..c957030ad73 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupFlexPipetteCalibrationItem.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupFlexPipetteCalibrationItem.test.tsx @@ -17,6 +17,7 @@ vi.mock('@opentrons/react-api-client') vi.mock('../../../PipetteWizardFlows') vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('../../hooks') +vi.mock('/app/resources/analysis') const RUN_ID = '1' const modifiedSimpleV6Protocol = ({ diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibration.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibration.test.tsx index 4f3085d873f..2848c2b578f 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibration.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibration.test.tsx @@ -15,6 +15,7 @@ import type { PipetteInfo } from '../../hooks' vi.mock('../../hooks') vi.mock('../SetupPipetteCalibrationItem') +vi.mock('/app/redux-resources/robots') vi.mock('/app/resources/runs') const ROBOT_NAME = 'otie' diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibrationItem.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibrationItem.test.tsx index 8514340b068..f2857d5e6e8 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibrationItem.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupPipetteCalibrationItem.test.tsx @@ -12,6 +12,7 @@ import { SetupPipetteCalibrationItem } from '../SetupPipetteCalibrationItem' import { MemoryRouter } from 'react-router-dom' vi.mock('../../hooks') +vi.mock('/app/redux-resources/robots') const ROBOT_NAME = 'otie' const RUN_ID = '1' diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupRobotCalibration.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupRobotCalibration.test.tsx index a10fac56c81..5b364dfc99a 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/SetupRobotCalibration.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/SetupRobotCalibration.test.tsx @@ -9,12 +9,10 @@ import { useTrackEvent, ANALYTICS_PROCEED_TO_MODULE_SETUP_STEP, } from '/app/redux/analytics' +import { useIsFlex } from '/app/redux-resources/robots' import { mockDeckCalData } from '/app/redux/calibration/__fixtures__' -import { - useDeckCalibrationData, - useIsFlex, - useRunHasStarted, -} from '../../hooks' +import { useDeckCalibrationData, useRunHasStarted } from '../../hooks' + import { SetupDeckCalibration } from '../SetupDeckCalibration' import { SetupInstrumentCalibration } from '../SetupInstrumentCalibration' import { SetupTipLengthCalibration } from '../SetupTipLengthCalibration' @@ -22,6 +20,8 @@ import { SetupRobotCalibration } from '../SetupRobotCalibration' vi.mock('/app/redux/analytics') vi.mock('../../hooks') +vi.mock('/app/resources/runs') +vi.mock('/app/redux-resources/robots') vi.mock('../SetupDeckCalibration') vi.mock('../SetupInstrumentCalibration') vi.mock('../SetupTipLengthCalibration') diff --git a/app/src/organisms/Devices/RobotCard.tsx b/app/src/organisms/Devices/RobotCard.tsx index 622de37b62c..bf70a6f2ead 100644 --- a/app/src/organisms/Devices/RobotCard.tsx +++ b/app/src/organisms/Devices/RobotCard.tsx @@ -37,7 +37,7 @@ import { InstrumentContainer } from '/app/atoms/InstrumentContainer' import { CONNECTABLE, getRobotModelByName } from '/app/redux/discovery' import { ModuleIcon } from '/app/molecules/ModuleIcon' import { UpdateRobotBanner } from '../UpdateRobotBanner' -import { useIsFlex } from './hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { ReachableBanner } from './ReachableBanner' import { RobotOverflowMenu } from './RobotOverflowMenu' import { RobotStatusHeader } from './RobotStatusHeader' diff --git a/app/src/organisms/Devices/RobotOverview.tsx b/app/src/organisms/Devices/RobotOverview.tsx index f8261b848d5..6a69961a199 100644 --- a/app/src/organisms/Devices/RobotOverview.tsx +++ b/app/src/organisms/Devices/RobotOverview.tsx @@ -24,6 +24,7 @@ import OT2_PNG from '/app/assets/images/OT2-R_HERO.png' import FLEX_PNG from '/app/assets/images/FLEX.png' import { ToggleButton } from '/app/atoms/buttons' import { getConfig } from '/app/redux/config' +import { useRobot } from '/app/redux-resources/robots' import { CONNECTABLE, getRobotAddressesByName, @@ -34,12 +35,7 @@ import { UpdateRobotBanner } from '../UpdateRobotBanner' import { RobotStatusHeader } from './RobotStatusHeader' import { ReachableBanner } from './ReachableBanner' import { RobotOverviewOverflowMenu } from './RobotOverviewOverflowMenu' -import { - useIsRobotBusy, - useIsRobotViewable, - useLights, - useRobot, -} from './hooks' +import { useIsRobotBusy, useIsRobotViewable, useLights } from './hooks' import { CalibrationStatusBanner } from './CalibrationStatusBanner' import { ErrorRecoveryBanner, diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx index 82bdf63c346..5b3497f3d89 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx @@ -24,7 +24,7 @@ import { PENDING, } from '/app/redux/robot-api' import { getResetConfigOptions, resetConfig } from '/app/redux/robot-admin' -import { useIsFlex } from '../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import type { State } from '/app/redux/types' import type { ResetConfigRequest } from '/app/redux/robot-admin/types' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx index 52c2d14f9f5..d4ddba6e764 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetSlideout.tsx @@ -34,11 +34,10 @@ import { } from '/app/redux/analytics' import { useDeckCalibrationData, - useIsFlex, usePipetteOffsetCalibrations, useTipLengthCalibrations, - useRobot, } from '../../../hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { useNotifyAllRunsQuery } from '/app/resources/runs' import type { State, Dispatch } from '/app/redux/types' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx index a0172fbed9e..1ae6e89a5ff 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx @@ -22,7 +22,7 @@ import { import { useTrackEvent, ANALYTICS_RENAME_ROBOT } from '/app/redux/analytics' import { Slideout } from '/app/atoms/Slideout' import { Banner } from '/app/atoms/Banner' -import { useIsFlex } from '../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import type { Resolver, FieldError } from 'react-hook-form' import type { UpdatedRobotName } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx index c9fb021faff..a74236888fa 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetModal.test.tsx @@ -11,7 +11,7 @@ import { DeviceResetModal } from '../DeviceResetModal' import type { DispatchApiRequestType } from '/app/redux/robot-api' -vi.mock('../../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/robot-admin') vi.mock('/app/redux/robot-api') diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetSlideout.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetSlideout.test.tsx index 057b1bbc499..c42b289f7b0 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetSlideout.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/DeviceResetSlideout.test.tsx @@ -6,12 +6,13 @@ import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { getResetConfigOptions } from '/app/redux/robot-admin' -import { useIsFlex } from '../../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { DeviceResetSlideout } from '../DeviceResetSlideout' vi.mock('/app/redux/config') vi.mock('/app/redux/discovery') vi.mock('/app/redux/robot-admin/selectors') +vi.mock('/app/redux-resources/robots') vi.mock('../../../../hooks') const mockOnCloseClick = vi.fn() diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx index 51b07a3e6d7..7a121176b11 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/__tests__/RenameRobotSlideout.test.tsx @@ -17,11 +17,11 @@ import { } from '/app/redux/discovery/__fixtures__' import { RenameRobotSlideout } from '../RenameRobotSlideout' -import { useIsFlex } from '../../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' vi.mock('/app/redux/discovery/selectors') vi.mock('/app/redux/analytics') -vi.mock('../../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/discovery', async importOriginal => { const actual = await importOriginal() return { diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotInformation.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotInformation.tsx index 20aee5e9162..9e7528bbcdc 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotInformation.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotInformation.tsx @@ -9,7 +9,7 @@ import { LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { getRobotSerialNumber, getRobotFirmwareVersion, diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx index 1a9e12a24c4..650b4d0bb3c 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/RobotServerVersion.tsx @@ -17,8 +17,8 @@ import { TertiaryButton } from '/app/atoms/buttons' import { getRobotApiVersion } from '/app/redux/discovery' import { getRobotUpdateDisplayInfo } from '/app/redux/robot-update' import { UpdateRobotBanner } from '../../../UpdateRobotBanner' -import { useIsFlex, useRobot } from '../../hooks' import { handleUpdateBuildroot } from '../UpdateBuildroot' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/Troubleshooting.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/Troubleshooting.tsx index c02358f42cb..45b2b96f462 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/Troubleshooting.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/Troubleshooting.tsx @@ -23,7 +23,7 @@ import { useHost } from '@opentrons/react-api-client' import { TertiaryButton } from '/app/atoms/buttons' import { useToaster } from '/app/organisms/ToasterOven' import { CONNECTABLE } from '/app/redux/discovery' -import { useRobot } from '../../hooks' +import { useRobot } from '/app/redux-resources/robots' import type { IconProps } from '@opentrons/components' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/DeviceReset.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/DeviceReset.test.tsx index 0f3440f6610..986e966c13d 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/DeviceReset.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/DeviceReset.test.tsx @@ -11,7 +11,7 @@ import { DeviceReset } from '../DeviceReset' const mockUpdateIsEXpanded = vi.fn() -vi.mock('../../../../ProtocolUpload/hooks') +vi.mock('/app/resources/runs') const render = (isRobotBusy = false) => { return renderWithProviders( diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotInformation.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotInformation.test.tsx index 851b686bd0c..985e8b970f0 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotInformation.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotInformation.test.tsx @@ -10,11 +10,11 @@ import { getRobotFirmwareVersion, getRobotProtocolApiVersion, } from '/app/redux/discovery' -import { useRobot } from '../../../hooks' +import { useRobot } from '/app/redux-resources/robots' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' import { RobotInformation } from '../RobotInformation' -vi.mock('../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/discovery/selectors') const MOCK_ROBOT_SERIAL_NUMBER = '0.0.0' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotServerVersion.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotServerVersion.test.tsx index 0409a65925a..face0f2e2c7 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotServerVersion.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/RobotServerVersion.test.tsx @@ -8,11 +8,11 @@ import { i18n } from '/app/i18n' import { getRobotApiVersion } from '/app/redux/discovery' import { getRobotUpdateDisplayInfo } from '/app/redux/robot-update' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' -import { useRobot } from '../../../hooks' import { handleUpdateBuildroot } from '../../UpdateBuildroot' import { RobotServerVersion } from '../RobotServerVersion' +import { useRobot } from '/app/redux-resources/robots' -vi.mock('../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/robot-update/selectors') vi.mock('/app/redux/discovery/selectors') vi.mock('../../UpdateBuildroot') diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/Troubleshooting.test.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/Troubleshooting.test.tsx index f1f3741d373..6c690e4b114 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/Troubleshooting.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/__tests__/Troubleshooting.test.tsx @@ -13,7 +13,7 @@ import { mockConnectableRobot, mockUnreachableRobot, } from '/app/redux/discovery/__fixtures__' -import { useRobot } from '../../../hooks' +import { useRobot } from '/app/redux-resources/robots' import { Troubleshooting } from '../Troubleshooting' import type { HostConfig } from '@opentrons/api-client' @@ -22,7 +22,7 @@ import type { ToasterContextType } from '../../../../ToasterOven/ToasterContext' vi.mock('@opentrons/react-api-client') vi.mock('/app/organisms/ToasterOven') vi.mock('/app/redux/discovery/selectors') -vi.mock('../../../hooks') +vi.mock('/app/redux-resources/robots') const ROBOT_NAME = 'otie' const HOST_CONFIG: HostConfig = { hostname: 'localhost' } diff --git a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx index 2b2b297e8cc..251c40a26e0 100644 --- a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx @@ -19,7 +19,7 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { CONNECTABLE } from '/app/redux/discovery' import { clearWifiStatus, diff --git a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx index 961e5bfedee..5a6b46acdc7 100644 --- a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/__tests__/DisconnectModal.test.tsx @@ -6,7 +6,7 @@ import { renderWithProviders } from '/app/__testing-utils__' import { when } from 'vitest-when' import { i18n } from '/app/i18n' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { useWifiList } from '/app/resources/networking/hooks' import { mockConnectableRobot, @@ -34,7 +34,7 @@ import type { RequestState } from '/app/redux/robot-api/types' import type { State } from '/app/redux/types' vi.mock('/app/resources/networking/hooks') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/networking') vi.mock('/app/redux/robot-api') diff --git a/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx b/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx index ae9c9309afa..1d33e4dd41d 100644 --- a/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx +++ b/app/src/organisms/Devices/RobotSettings/RobotSettingsAdvanced.tsx @@ -14,7 +14,7 @@ import { import { Divider } from '/app/atoms/structure' import { ToggleButton } from '/app/atoms/buttons' -import { useIsFlex, useIsRobotBusy, useRobot } from '../hooks' +import { useIsRobotBusy } from '../hooks' import { DeviceReset, DisplayRobotName, @@ -31,6 +31,7 @@ import { UsageSettings, UseOlderAspirateBehavior, } from './AdvancedTab' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { updateSetting, getRobotSettings, diff --git a/app/src/organisms/Devices/RobotSettings/RobotSettingsNetworking.tsx b/app/src/organisms/Devices/RobotSettings/RobotSettingsNetworking.tsx index cc86c9771da..0ad19fff922 100644 --- a/app/src/organisms/Devices/RobotSettings/RobotSettingsNetworking.tsx +++ b/app/src/organisms/Devices/RobotSettings/RobotSettingsNetworking.tsx @@ -28,8 +28,8 @@ import { OPENTRONS_USB, } from '/app/redux/discovery' import { fetchStatus, getNetworkInterfaces } from '/app/redux/networking' - -import { useIsFlex, useIsRobotBusy } from '../hooks' +import { useIsFlex } from '/app/redux-resources/robots' +import { useIsRobotBusy } from '../hooks' import { DisconnectModal } from './ConnectNetwork/DisconnectModal' import { SelectNetwork } from './SelectNetwork' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' diff --git a/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx b/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx index 881b541b542..94769e6d161 100644 --- a/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsAdvanced.test.tsx @@ -8,7 +8,8 @@ import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { getShellUpdateState } from '/app/redux/shell' -import { useIsFlex, useIsRobotBusy } from '../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' +import { useIsRobotBusy } from '../../hooks' import { DeviceReset, DisplayRobotName, @@ -29,6 +30,7 @@ import { RobotSettingsAdvanced } from '../RobotSettingsAdvanced' import type { ShellUpdateState } from '/app/redux/shell/types' import type * as ShellUpdate from '/app/redux/shell/update' +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/robot-settings/selectors') vi.mock('/app/redux/discovery/selectors') vi.mock('/app/redux/shell/update', async importOriginal => { diff --git a/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsNetworking.test.tsx b/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsNetworking.test.tsx index 82038e041a8..e39ca5d6281 100644 --- a/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsNetworking.test.tsx +++ b/app/src/organisms/Devices/RobotSettings/__tests__/RobotSettingsNetworking.test.tsx @@ -16,7 +16,9 @@ import { import * as Networking from '/app/redux/networking' import { useCanDisconnect, useWifiList } from '/app/resources/networking/hooks' import * as Fixtures from '/app/redux/networking/__fixtures__' -import { useIsFlex, useIsRobotBusy } from '../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' +import { useIsRobotBusy } from '../../hooks' + import { DisconnectModal } from '../ConnectNetwork/DisconnectModal' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' import { RobotSettingsNetworking } from '../RobotSettingsNetworking' @@ -28,6 +30,7 @@ vi.mock('/app/redux/discovery/selectors') vi.mock('/app/redux/networking') vi.mock('/app/redux/robot-api/selectors') vi.mock('/app/resources/networking/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../../hooks') vi.mock('../ConnectNetwork/DisconnectModal') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') diff --git a/app/src/organisms/Devices/RobotStatusHeader.tsx b/app/src/organisms/Devices/RobotStatusHeader.tsx index 5abc3d33a5f..51afab298b4 100644 --- a/app/src/organisms/Devices/RobotStatusHeader.tsx +++ b/app/src/organisms/Devices/RobotStatusHeader.tsx @@ -25,7 +25,7 @@ import { } from '@opentrons/components' import { QuaternaryButton } from '/app/atoms/buttons' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useCurrentRunStatus } from '/app/organisms/RunTimeControl/hooks' import { getRobotAddressesByName, diff --git a/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx b/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx index 3933ba3bb24..e91517e45e8 100644 --- a/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx +++ b/app/src/organisms/Devices/__tests__/HistoricalProtocolRun.test.tsx @@ -6,7 +6,7 @@ import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { getStoredProtocols } from '/app/redux/protocol-storage' import { storedProtocolData as storedProtocolDataFixture } from '/app/redux/protocol-storage/__fixtures__' -import { useRunStatus, useRunTimestamps } from '../../RunTimeControl/hooks' +import { useRunStatus, useRunTimestamps } from '/app/resources/runs' import { HistoricalProtocolRun } from '../HistoricalProtocolRun' import { HistoricalProtocolRunOverflowMenu } from '../HistoricalProtocolRunOverflowMenu' @@ -14,7 +14,7 @@ import type { RunStatus, RunData } from '@opentrons/api-client' import type { RunTimeParameter } from '@opentrons/shared-data' vi.mock('/app/redux/protocol-storage') -vi.mock('../../RunTimeControl/hooks') +vi.mock('/app/resources/runs') vi.mock('../HistoricalProtocolRunOverflowMenu') const run = { diff --git a/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx b/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx index 54b3531d155..bd6aa3e5cba 100644 --- a/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx +++ b/app/src/organisms/Devices/__tests__/HistoricalProtocolRunOverflowMenu.test.tsx @@ -10,7 +10,9 @@ import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' import runRecord from '../ProtocolRun/ProtocolRunHeader/RunHeaderModalContainer/modals/__fixtures__/runRecord.json' -import { useDownloadRunLog, useTrackProtocolRunEvent, useRobot } from '../hooks' +import { useDownloadRunLog } from '../hooks' +import { useRobot } from '/app/redux-resources/robots' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' import { useRunControls } from '../../RunTimeControl/hooks' import { useTrackEvent, @@ -26,13 +28,15 @@ import type { CommandsData } from '@opentrons/api-client' vi.mock('/app/redux/analytics') vi.mock('/app/redux/robot-update/selectors') -vi.mock('../../Devices/hooks') +vi.mock('/app/redux-resources/robots') +vi.mock('/app/organisms/Devices/hooks') vi.mock('../../RunTimeControl/hooks') vi.mock('/app/redux/analytics') vi.mock('/app/redux/config') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') vi.mock('/app/resources/runs') vi.mock('/app/redux/robot-update') +vi.mock('/app/redux-resources/analytics') vi.mock('@opentrons/react-api-client') const render = ( diff --git a/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx b/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx index 92e105d49df..cb9ab747ed3 100644 --- a/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx +++ b/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx @@ -13,7 +13,8 @@ import { import { i18n } from '/app/i18n' import { Banner } from '/app/atoms/Banner' import { mockMagneticModule } from '/app/redux/modules/__fixtures__' -import { useIsFlex, useIsRobotViewable, useRunStatuses } from '../hooks' +import { useIsFlex } from '/app/redux-resources/robots' +import { useIsRobotViewable, useRunStatuses } from '../hooks' import { ModuleCard } from '../../ModuleCard' import { InstrumentsAndModules } from '../InstrumentsAndModules' import { GripperCard } from '../../GripperCard' @@ -40,9 +41,9 @@ vi.mock('../PipetteCard') vi.mock('../PipetteCard/FlexPipetteCard') vi.mock('../PipetteCard/PipetteRecalibrationWarning') vi.mock('/app/resources/runs') +vi.mock('/app/redux-resources/robots') vi.mock('/app/atoms/Banner') vi.mock('../utils') -vi.mock('../../RunTimeControl/hooks') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') const ROBOT_NAME = 'otie' diff --git a/app/src/organisms/Devices/__tests__/RecentProtocolRuns.test.tsx b/app/src/organisms/Devices/__tests__/RecentProtocolRuns.test.tsx index 5d624818489..bb183476da5 100644 --- a/app/src/organisms/Devices/__tests__/RecentProtocolRuns.test.tsx +++ b/app/src/organisms/Devices/__tests__/RecentProtocolRuns.test.tsx @@ -13,9 +13,8 @@ import type { UseQueryResult } from 'react-query' import type { Runs } from '@opentrons/api-client' import type { AxiosError } from 'axios' -vi.mock('/app/resources/runs') vi.mock('../hooks') -vi.mock('../../ProtocolUpload/hooks') +vi.mock('/app/resources/runs') vi.mock('../HistoricalProtocolRun') const render = () => { diff --git a/app/src/organisms/Devices/__tests__/RobotCard.test.tsx b/app/src/organisms/Devices/__tests__/RobotCard.test.tsx index ee7505f768e..e5c09e3ebb8 100644 --- a/app/src/organisms/Devices/__tests__/RobotCard.test.tsx +++ b/app/src/organisms/Devices/__tests__/RobotCard.test.tsx @@ -41,6 +41,7 @@ import type { State } from '/app/redux/types' vi.mock('/app/redux/robot-update/selectors') vi.mock('/app/redux/discovery/selectors') vi.mock('../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../../UpdateRobotBanner') vi.mock('/app/redux/config') vi.mock('../RobotOverflowMenu') diff --git a/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx b/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx index 9099a9a5dff..8f9a570dd7b 100644 --- a/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx +++ b/app/src/organisms/Devices/__tests__/RobotOverview.test.tsx @@ -22,11 +22,11 @@ import { OPENTRONS_USB, ROBOT_MODEL_OT3, } from '/app/redux/discovery/constants' +import { useRobot } from '/app/redux-resources/robots' import { useCalibrationTaskList, useIsRobotBusy, useLights, - useRobot, useRunStatuses, useIsRobotViewable, } from '../hooks' @@ -67,6 +67,7 @@ vi.mock('/app/redux/config') vi.mock('/app/redux/discovery/selectors') vi.mock('/app/resources/runs') vi.mock('../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../RobotStatusHeader') vi.mock('../../UpdateRobotBanner') vi.mock('../RobotOverviewOverflowMenu') diff --git a/app/src/organisms/Devices/__tests__/RobotStatusHeader.test.tsx b/app/src/organisms/Devices/__tests__/RobotStatusHeader.test.tsx index 60bcee283d5..627c08bcdfe 100644 --- a/app/src/organisms/Devices/__tests__/RobotStatusHeader.test.tsx +++ b/app/src/organisms/Devices/__tests__/RobotStatusHeader.test.tsx @@ -16,7 +16,7 @@ import { OPENTRONS_USB, } from '/app/redux/discovery' import { getNetworkInterfaces } from '/app/redux/networking' -import { useIsFlex } from '../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { RobotStatusHeader } from '../RobotStatusHeader' import { useNotifyRunQuery, useCurrentRunId } from '/app/resources/runs' @@ -28,7 +28,7 @@ vi.mock('@opentrons/react-api-client') vi.mock('/app/organisms/RunTimeControl/hooks') vi.mock('/app/redux/discovery') vi.mock('/app/redux/networking') -vi.mock('../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/resources/runs') const MOCK_OTIE = { diff --git a/app/src/organisms/Devices/constants.ts b/app/src/organisms/Devices/constants.ts index 9752f0fb347..a923216fd9f 100644 --- a/app/src/organisms/Devices/constants.ts +++ b/app/src/organisms/Devices/constants.ts @@ -3,7 +3,6 @@ import type { LabwareDefinition2, PipetteName } from '@opentrons/shared-data' import { getLatestLabwareDef } from '/app/assets/labware/getLabware' export const RUN_LOG_WINDOW_SIZE = 60 // number of command items rendered at a time -export const EMPTY_TIMESTAMP = '--:--:--' // NOTE: this map is a duplicate of the TIP_RACK_LOOKUP_BY_MAX_VOL // found at robot_server/robot/calibration/constants.py diff --git a/app/src/organisms/Devices/hooks/__tests__/useIsRobotBusy.test.ts b/app/src/organisms/Devices/hooks/__tests__/useIsRobotBusy.test.ts index d5f0b1da5c5..138b8cb604a 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useIsRobotBusy.test.ts +++ b/app/src/organisms/Devices/hooks/__tests__/useIsRobotBusy.test.ts @@ -11,7 +11,7 @@ import { PHYSICALLY_ENGAGED, } from '../../../EmergencyStop' import { useIsRobotBusy } from '../useIsRobotBusy' -import { useIsFlex } from '../useIsFlex' +import { useIsFlex } from '/app/redux-resources/robots' import { useNotifyCurrentMaintenanceRun } from '/app/resources/maintenance_runs' import { useNotifyAllRunsQuery } from '/app/resources/runs' @@ -20,8 +20,7 @@ import type { Sessions, Runs } from '@opentrons/api-client' import type { AxiosError } from 'axios' vi.mock('@opentrons/react-api-client') -vi.mock('../../../ProtocolUpload/hooks') -vi.mock('../useIsFlex') +vi.mock('/app/redux-resources/robots') vi.mock('/app/resources/runs') vi.mock('/app/resources/maintenance_runs') diff --git a/app/src/organisms/Devices/hooks/__tests__/useLPCDisabledReason.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useLPCDisabledReason.test.tsx index 612d27fef81..a22c66b7dd0 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useLPCDisabledReason.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useLPCDisabledReason.test.tsx @@ -9,12 +9,13 @@ import { simple_v6 as _uncastedSimpleV6Protocol, } from '@opentrons/shared-data' import { i18n } from '/app/i18n' -import { RUN_ID_1 } from '../../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { useLPCDisabledReason } from '../useLPCDisabledReason' + import { useRunCalibrationStatus, useRunHasStarted, - useStoredProtocolAnalysis, useUnmatchedModulesForProtocol, } from '..' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' @@ -23,6 +24,7 @@ import type * as SharedData from '@opentrons/shared-data' import type { State } from '/app/redux/types' vi.mock('..') +vi.mock('/app/resources/analysis') vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('@opentrons/shared-data', async importOriginal => { const actualSharedData = await importOriginal() diff --git a/app/src/organisms/Devices/hooks/__tests__/useModuleCalibrationStatus.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useModuleCalibrationStatus.test.tsx index ddcfcf6b3cb..abeb36c7469 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useModuleCalibrationStatus.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useModuleCalibrationStatus.test.tsx @@ -5,10 +5,10 @@ import { vi, it, expect, describe, beforeEach, afterEach } from 'vitest' import { when } from 'vitest-when' import { - useIsFlex, useModuleCalibrationStatus, useModuleRenderInfoForProtocolById, } from '..' +import { useIsFlex } from '/app/redux-resources/robots' import { mockMagneticModuleGen2 } from '/app/redux/modules/__fixtures__' @@ -17,7 +17,7 @@ import type { ModuleModel, ModuleType } from '@opentrons/shared-data' import { Provider } from 'react-redux' import { createStore } from 'redux' -vi.mock('../useIsFlex') +vi.mock('/app/redux-resources/robots') vi.mock('../useModuleRenderInfoForProtocolById') let wrapper: React.FunctionComponent<{ children: React.ReactNode }> diff --git a/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx index 828b4cd4d2e..a3bf76d7b2b 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useModuleRenderInfoForProtocolById.test.tsx @@ -16,11 +16,8 @@ import { mockTemperatureModuleGen2, mockThermocycler, } from '/app/redux/modules/__fixtures__' -import { - useAttachedModules, - useModuleRenderInfoForProtocolById, - useStoredProtocolAnalysis, -} from '..' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' +import { useAttachedModules, useModuleRenderInfoForProtocolById } from '..' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' import type { @@ -35,7 +32,7 @@ import type { AttachedModule } from '/app/redux/modules/types' vi.mock('../../ProtocolRun/utils/getProtocolModulesInfo') vi.mock('../useAttachedModules') -vi.mock('../useStoredProtocolAnalysis') +vi.mock('/app/resources/analysis') vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('/app/resources/deck_configuration') diff --git a/app/src/organisms/Devices/hooks/__tests__/usePipetteOffsetCalibration.test.tsx b/app/src/organisms/Devices/hooks/__tests__/usePipetteOffsetCalibration.test.tsx index 73b096a5acf..e3f2cf6618f 100644 --- a/app/src/organisms/Devices/hooks/__tests__/usePipetteOffsetCalibration.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/usePipetteOffsetCalibration.test.tsx @@ -12,7 +12,7 @@ import { } from '/app/redux/calibration' import { mockPipetteOffsetCalibration1 } from '/app/redux/calibration/pipette-offset/__fixtures__' import { useDispatchApiRequest } from '/app/redux/robot-api' -import { useRobot } from '../useRobot' +import { useRobot } from '/app/redux-resources/robots' import { usePipetteOffsetCalibration } from '..' import type { Store } from 'redux' @@ -22,7 +22,7 @@ import type { AttachedPipette, Mount } from '/app/redux/pipettes/types' vi.mock('/app/redux/calibration') vi.mock('/app/redux/robot-api') -vi.mock('../useRobot') +vi.mock('/app/redux-resources/robots') const store: Store = createStore(vi.fn(), {}) diff --git a/app/src/organisms/Devices/hooks/__tests__/useProtocolAnalysisErrors.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useProtocolAnalysisErrors.test.tsx index daaa7267aaa..4b83f86d33e 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useProtocolAnalysisErrors.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useProtocolAnalysisErrors.test.tsx @@ -10,7 +10,7 @@ import { import { useProtocolAnalysisErrors } from '..' import { useNotifyRunQuery } from '/app/resources/runs' -import { RUN_ID_2 } from '../../../RunTimeControl/__fixtures__' +import { RUN_ID_2 } from '/app/resources/runs/__fixtures__' import type { UseQueryResult } from 'react-query' import type { Run, Protocol } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/hooks/__tests__/useRunCalibrationStatus.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRunCalibrationStatus.test.tsx index 5f31a766d99..a8554d8c033 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRunCalibrationStatus.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRunCalibrationStatus.test.tsx @@ -8,9 +8,9 @@ import { mockTipRackDefinition } from '/app/redux/custom-labware/__fixtures__' import { useRunCalibrationStatus, useDeckCalibrationStatus, - useIsFlex, useRunPipetteInfoByMount, } from '..' +import { useIsFlex } from '/app/redux-resources/robots' import { useNotifyRunQuery } from '/app/resources/runs' import type { PipetteInfo } from '..' @@ -18,9 +18,10 @@ import { Provider } from 'react-redux' import { createStore } from 'redux' vi.mock('../useDeckCalibrationStatus') -vi.mock('../useIsFlex') vi.mock('../useRunPipetteInfoByMount') vi.mock('/app/resources/runs') +vi.mock('/app/resources/analysis') +vi.mock('/app/redux-resources/robots') let wrapper: React.FunctionComponent<{ children: React.ReactNode }> diff --git a/app/src/organisms/Devices/hooks/__tests__/useRunCreatedAtTimestamp.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRunCreatedAtTimestamp.test.tsx index e94eb672ffc..7327bd17a13 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRunCreatedAtTimestamp.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRunCreatedAtTimestamp.test.tsx @@ -2,7 +2,7 @@ import { renderHook } from '@testing-library/react' import { vi, it, expect, describe, beforeEach } from 'vitest' import { when } from 'vitest-when' -import { mockIdleUnstartedRun } from '../../../RunTimeControl/__fixtures__' +import { mockIdleUnstartedRun } from '/app/resources/runs/__fixtures__' import { formatTimestamp } from '../../utils' import { useRunCreatedAtTimestamp } from '../useRunCreatedAtTimestamp' import { useNotifyRunQuery } from '/app/resources/runs' diff --git a/app/src/organisms/Devices/hooks/__tests__/useRunHasStarted.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRunHasStarted.test.tsx index 969c12e8984..b6f1637fd98 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRunHasStarted.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRunHasStarted.test.tsx @@ -4,10 +4,10 @@ import { when } from 'vitest-when' import { RUN_STATUS_IDLE, RUN_STATUS_RUNNING } from '@opentrons/api-client' -import { useRunStatus } from '/app/organisms/RunTimeControl/hooks' +import { useRunStatus } from '/app/resources/runs' import { useRunHasStarted } from '../useRunHasStarted' -vi.mock('/app/organisms/RunTimeControl/hooks') +vi.mock('/app/resources/runs') const MOCK_RUN_ID = '1' diff --git a/app/src/organisms/Devices/hooks/__tests__/useRunPipetteInfoByMount.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRunPipetteInfoByMount.test.tsx index c5d1809c805..ba38f656fc9 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRunPipetteInfoByMount.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRunPipetteInfoByMount.test.tsx @@ -26,8 +26,8 @@ import { useAttachedPipetteCalibrations, useAttachedPipettes, useRunPipetteInfoByMount, - useStoredProtocolAnalysis, } from '..' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import _uncastedModifiedSimpleV6Protocol from '../__fixtures__/modifiedSimpleV6.json' import type * as SharedData from '@opentrons/shared-data' @@ -46,7 +46,7 @@ vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('../useAttachedPipetteCalibrations') vi.mock('../useAttachedPipettes') vi.mock('../useTipLengthCalibrations') -vi.mock('../useStoredProtocolAnalysis') +vi.mock('/app/resources/analysis') const PIPETTE_CALIBRATIONS = { left: { diff --git a/app/src/organisms/Devices/hooks/__tests__/useRunStartedOrLegacySessionInProgress.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRunStartedOrLegacySessionInProgress.test.tsx index b27fa8eeef1..17aaa591586 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRunStartedOrLegacySessionInProgress.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRunStartedOrLegacySessionInProgress.test.tsx @@ -2,8 +2,7 @@ import { useAllSessionsQuery } from '@opentrons/react-api-client' import { RUN_STATUS_IDLE, RUN_STATUS_RUNNING } from '@opentrons/api-client' import { vi, it, expect, describe, beforeEach, afterEach } from 'vitest' -import { useCurrentRunId } from '/app/resources/runs' -import { useRunStatus } from '../../../RunTimeControl/hooks' +import { useCurrentRunId, useRunStatus } from '/app/resources/runs' import { useRunStartedOrLegacySessionInProgress } from '..' import type { UseQueryResult } from 'react-query' @@ -11,7 +10,6 @@ import type { Sessions } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') vi.mock('/app/resources/runs') -vi.mock('../../../RunTimeControl/hooks') describe('useRunStartedOrLegacySessionInProgress', () => { beforeEach(() => { diff --git a/app/src/organisms/Devices/hooks/__tests__/useRunStatuses.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useRunStatuses.test.tsx index 03851bd4a04..ab37d965966 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRunStatuses.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useRunStatuses.test.tsx @@ -14,12 +14,10 @@ import { } from '@opentrons/api-client' import { vi, it, expect, describe, beforeEach } from 'vitest' -import { useCurrentRunId } from '/app/resources/runs' -import { useRunStatus } from '../../../RunTimeControl/hooks' +import { useCurrentRunId, useRunStatus } from '/app/resources/runs' import { useRunStatuses } from '..' vi.mock('/app/resources/runs') -vi.mock('../../../RunTimeControl/hooks') describe('useRunStatuses', () => { beforeEach(() => { diff --git a/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx index 1c9c3d8e6c7..88ec0f8a9fe 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useTrackCreateProtocolRunEvent.test.tsx @@ -5,10 +5,10 @@ import { QueryClient, QueryClientProvider } from 'react-query' import { vi, it, expect, describe, beforeEach, afterEach } from 'vitest' import { waitFor, renderHook } from '@testing-library/react' -import { STORED_PROTOCOL_ANALYSIS } from '../__fixtures__/storedProtocolAnalysis' +import { STORED_PROTOCOL_ANALYSIS } from '/app/resources/analysis/hooks/__fixtures__/storedProtocolAnalysis' import { useTrackCreateProtocolRunEvent } from '../useTrackCreateProtocolRunEvent' -import { parseProtocolRunAnalyticsData } from '../useProtocolRunAnalyticsData' -import { parseProtocolAnalysisOutput } from '../useStoredProtocolAnalysis' +import { parseProtocolRunAnalyticsData } from '/app/transformations/analytics' +import { parseProtocolAnalysisOutput } from '/app/transformations/analysis' import { useTrackEvent } from '/app/redux/analytics' import { storedProtocolData } from '/app/redux/protocol-storage/__fixtures__' @@ -17,8 +17,8 @@ import type { Store } from 'redux' import type { ProtocolAnalyticsData } from '/app/redux/analytics/types' vi.mock('../../hooks') -vi.mock('../useProtocolRunAnalyticsData') -vi.mock('../useStoredProtocolAnalysis') +vi.mock('/app/transformations/analytics') +vi.mock('/app/transformations/analysis') vi.mock('/app/redux/discovery') vi.mock('/app/redux/pipettes') vi.mock('/app/redux/analytics') diff --git a/app/src/organisms/Devices/hooks/__tests__/useUnmatchedModulesForProtocol.test.tsx b/app/src/organisms/Devices/hooks/__tests__/useUnmatchedModulesForProtocol.test.tsx index f1d4668d638..000b34926d2 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useUnmatchedModulesForProtocol.test.tsx +++ b/app/src/organisms/Devices/hooks/__tests__/useUnmatchedModulesForProtocol.test.tsx @@ -4,10 +4,10 @@ import { renderHook } from '@testing-library/react' import { mockConnectedRobot } from '/app/redux/discovery/__fixtures__' import { mockTemperatureModule } from '/app/redux/modules/__fixtures__' +import { useRobot } from '/app/redux-resources/robots' import { useAttachedModules, useModuleRenderInfoForProtocolById, - useRobot, useUnmatchedModulesForProtocol, } from '..' @@ -15,7 +15,7 @@ import type { ModuleDefinition } from '@opentrons/shared-data' vi.mock('../useAttachedModules') vi.mock('../useModuleRenderInfoForProtocolById') -vi.mock('../useRobot') +vi.mock('/app/redux-resources/robots') const mockMagneticBlockDef = { labwareOffset: { x: 5, y: 5, z: 5 }, diff --git a/app/src/organisms/Devices/hooks/index.ts b/app/src/organisms/Devices/hooks/index.ts index f8cdeaa68e8..f60c5a29c27 100644 --- a/app/src/organisms/Devices/hooks/index.ts +++ b/app/src/organisms/Devices/hooks/index.ts @@ -5,7 +5,6 @@ export * from './useDeckCalibrationData' export * from './useDeckCalibrationStatus' export * from './useDownloadRunLog' export * from './useCalibrationTaskList' -export * from './useIsFlex' export * from './useIsRobotBusy' export * from './useIsRobotViewable' export * from './useLights' @@ -16,23 +15,15 @@ export * from './useModuleRenderInfoForProtocolById' export * from './useModuleCalibrationStatus' export * from './usePipetteOffsetCalibrations' export * from './usePipetteOffsetCalibration' -export * from './useProtocolDetailsForRun' -export * from './useRobot' -export * from './useRobotType' export * from './useRunCalibrationStatus' export * from './useRunCreatedAtTimestamp' export * from './useRunHasStarted' export * from './useRunPipetteInfoByMount' -export * from './useStoredProtocolAnalysis' export * from './useTipLengthCalibrations' export * from './useUnmatchedModulesForProtocol' export * from './useProtocolAnalysisErrors' -export * from './useProtocolMetadata' export * from './useRunStartedOrLegacySessionInProgress' -export * from './useProtocolRunAnalyticsData' -export * from './useRobotAnalyticsData' export * from './useTrackCreateProtocolRunEvent' -export * from './useTrackProtocolRunEvent' export * from './useRunStatuses' export * from './useSyncRobotClock' export * from './useIsLegacySessionInProgress' diff --git a/app/src/organisms/Devices/hooks/useCalibrationTaskList.ts b/app/src/organisms/Devices/hooks/useCalibrationTaskList.ts index 13052b52fac..9d0c8627eec 100644 --- a/app/src/organisms/Devices/hooks/useCalibrationTaskList.ts +++ b/app/src/organisms/Devices/hooks/useCalibrationTaskList.ts @@ -19,9 +19,37 @@ import type { TaskProps, } from '../../TaskList/types' import type { AttachedPipette } from '/app/redux/pipettes/types' -import type { DashboardCalOffsetInvoker } from '/app/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset' -import type { DashboardCalTipLengthInvoker } from '/app/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateTipLength' -import type { DashboardCalDeckInvoker } from '/app/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateDeck' +import type { + PipetteOffsetCalibrationSessionParams, + TipLengthCalibrationSessionParams, +} from '/app/redux/sessions/types' + +export interface DashboardOffsetCalInvokerProps { + params: Pick & + Partial> +} + +export type DashboardCalOffsetInvoker = ( + props: DashboardOffsetCalInvokerProps +) => void + +export interface DashboardTipLengthCalInvokerProps { + params: Pick & + Partial> + hasBlockModalResponse: boolean | null + invalidateHandler?: () => void +} + +export type DashboardCalTipLengthInvoker = ( + props: DashboardTipLengthCalInvokerProps +) => void + +export interface DashboardCalDeckInvokerProps { + invalidateHandler?: () => void +} +export type DashboardCalDeckInvoker = ( + props?: DashboardCalDeckInvokerProps +) => void const CALIBRATION_DATA_POLL_MS = 5000 diff --git a/app/src/organisms/Devices/hooks/useDeckCalibrationData.ts b/app/src/organisms/Devices/hooks/useDeckCalibrationData.ts index 16f7c17bdc2..ea6ef4284dd 100644 --- a/app/src/organisms/Devices/hooks/useDeckCalibrationData.ts +++ b/app/src/organisms/Devices/hooks/useDeckCalibrationData.ts @@ -4,7 +4,7 @@ import { } from '/app/redux/calibration' import { useCalibrationStatusQuery } from '@opentrons/react-api-client' -import { useRobot } from './useRobot' +import { useRobot } from '/app/redux-resources/robots' import type { DeckCalibrationData } from '@opentrons/api-client' /** diff --git a/app/src/organisms/Devices/hooks/useDeckCalibrationStatus.ts b/app/src/organisms/Devices/hooks/useDeckCalibrationStatus.ts index 9cb62e765db..62fbe84fd70 100644 --- a/app/src/organisms/Devices/hooks/useDeckCalibrationStatus.ts +++ b/app/src/organisms/Devices/hooks/useDeckCalibrationStatus.ts @@ -1,5 +1,5 @@ import { useCalibrationStatusQuery } from '@opentrons/react-api-client' -import { useRobot } from './useRobot' +import { useRobot } from '/app/redux-resources/robots' import type { DeckCalibrationStatus } from '/app/redux/calibration/types' export function useDeckCalibrationStatus( diff --git a/app/src/organisms/Devices/hooks/useIsRobotBusy.ts b/app/src/organisms/Devices/hooks/useIsRobotBusy.ts index f59d5a6fc95..60ccc59b1e5 100644 --- a/app/src/organisms/Devices/hooks/useIsRobotBusy.ts +++ b/app/src/organisms/Devices/hooks/useIsRobotBusy.ts @@ -8,7 +8,7 @@ import { import { useNotifyCurrentMaintenanceRun } from '/app/resources/maintenance_runs' import { useNotifyAllRunsQuery } from '/app/resources/runs' import { DISENGAGED } from '../../EmergencyStop' -import { useIsFlex } from './useIsFlex' +import { useIsFlex } from '/app/redux-resources/robots' const ROBOT_STATUS_POLL_MS = 30000 diff --git a/app/src/organisms/Devices/hooks/useIsRobotViewable.ts b/app/src/organisms/Devices/hooks/useIsRobotViewable.ts index 77e3da157c4..b665cd2913f 100644 --- a/app/src/organisms/Devices/hooks/useIsRobotViewable.ts +++ b/app/src/organisms/Devices/hooks/useIsRobotViewable.ts @@ -1,4 +1,4 @@ -import { useRobot } from './useRobot' +import { useRobot } from '/app/redux-resources/robots' import { CONNECTABLE } from '/app/redux/discovery' diff --git a/app/src/organisms/Devices/hooks/useLPCDisabledReason.tsx b/app/src/organisms/Devices/hooks/useLPCDisabledReason.tsx index 4c2d3be90d1..02da1596d00 100644 --- a/app/src/organisms/Devices/hooks/useLPCDisabledReason.tsx +++ b/app/src/organisms/Devices/hooks/useLPCDisabledReason.tsx @@ -2,11 +2,11 @@ import isEmpty from 'lodash/isEmpty' import some from 'lodash/some' import { useTranslation } from 'react-i18next' import { getLoadedLabwareDefinitionsByUri } from '@opentrons/shared-data' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useRunCalibrationStatus, useRunHasStarted, - useStoredProtocolAnalysis, useUnmatchedModulesForProtocol, } from '.' diff --git a/app/src/organisms/Devices/hooks/useLastRunCommand.ts b/app/src/organisms/Devices/hooks/useLastRunCommand.ts index 5ccfb5f95db..b061b46c7c8 100644 --- a/app/src/organisms/Devices/hooks/useLastRunCommand.ts +++ b/app/src/organisms/Devices/hooks/useLastRunCommand.ts @@ -1,7 +1,6 @@ import { RUN_STATUSES_TERMINAL } from '@opentrons/api-client' -import { useNotifyAllCommandsQuery } from '/app/resources/runs' -import { useRunStatus } from '../../RunTimeControl/hooks' +import { useNotifyAllCommandsQuery, useRunStatus } from '/app/resources/runs' import type { UseQueryOptions } from 'react-query' import type { diff --git a/app/src/organisms/Devices/hooks/useModuleCalibrationStatus.ts b/app/src/organisms/Devices/hooks/useModuleCalibrationStatus.ts index 47b709a80d5..a963524f148 100644 --- a/app/src/organisms/Devices/hooks/useModuleCalibrationStatus.ts +++ b/app/src/organisms/Devices/hooks/useModuleCalibrationStatus.ts @@ -3,8 +3,8 @@ import { MAGNETIC_BLOCK_TYPE, ABSORBANCE_READER_TYPE, } from '@opentrons/shared-data' +import { useIsFlex } from '/app/redux-resources/robots' import { useModuleRenderInfoForProtocolById } from './useModuleRenderInfoForProtocolById' -import { useIsFlex } from './useIsFlex' import type { ProtocolCalibrationStatus } from './useRunCalibrationStatus' export function useModuleCalibrationStatus( diff --git a/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts b/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts index 9bb5a6c1f99..beeacfa16ba 100644 --- a/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts +++ b/app/src/organisms/Devices/hooks/useModuleRenderInfoForProtocolById.ts @@ -10,7 +10,7 @@ import { import { getProtocolModulesInfo } from '../ProtocolRun/utils/getProtocolModulesInfo' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useAttachedModules } from './useAttachedModules' -import { useStoredProtocolAnalysis } from './useStoredProtocolAnalysis' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' import type { CutoutConfig } from '@opentrons/shared-data' diff --git a/app/src/organisms/Devices/hooks/usePipetteOffsetCalibration.ts b/app/src/organisms/Devices/hooks/usePipetteOffsetCalibration.ts index 9e6f1e2383c..ff6522f56ed 100644 --- a/app/src/organisms/Devices/hooks/usePipetteOffsetCalibration.ts +++ b/app/src/organisms/Devices/hooks/usePipetteOffsetCalibration.ts @@ -6,7 +6,7 @@ import { fetchPipetteOffsetCalibrations, } from '/app/redux/calibration' import { useDispatchApiRequest } from '/app/redux/robot-api' -import { useRobot } from '.' +import { useRobot } from '/app/redux-resources/robots' import type { PipetteOffsetCalibration } from '/app/redux/calibration/types' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/Devices/hooks/useRunCalibrationStatus.ts b/app/src/organisms/Devices/hooks/useRunCalibrationStatus.ts index 2df9fdc2902..8f006ec50c5 100644 --- a/app/src/organisms/Devices/hooks/useRunCalibrationStatus.ts +++ b/app/src/organisms/Devices/hooks/useRunCalibrationStatus.ts @@ -1,13 +1,11 @@ import { MATCH, INEXACT_MATCH } from '/app/redux/pipettes' -import { - useDeckCalibrationStatus, - useIsFlex, - useRunPipetteInfoByMount, - useStoredProtocolAnalysis, -} from '.' +import { useDeckCalibrationStatus, useRunPipetteInfoByMount } from '.' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { isGripperInCommands } from '/app/resources/protocols/utils' +import { useIsFlex } from '/app/redux-resources/robots' import { useInstrumentsQuery } from '@opentrons/react-api-client' + import type { GripperData, Instruments, diff --git a/app/src/organisms/Devices/hooks/useRunCreatedAtTimestamp.ts b/app/src/organisms/Devices/hooks/useRunCreatedAtTimestamp.ts index 79bbac5a70c..90726956035 100644 --- a/app/src/organisms/Devices/hooks/useRunCreatedAtTimestamp.ts +++ b/app/src/organisms/Devices/hooks/useRunCreatedAtTimestamp.ts @@ -1,6 +1,5 @@ import { formatTimestamp } from '../utils' -import { EMPTY_TIMESTAMP } from '../constants' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery, EMPTY_TIMESTAMP } from '/app/resources/runs' export function useRunCreatedAtTimestamp(runId: string | null): string { const runRecord = useNotifyRunQuery(runId) diff --git a/app/src/organisms/Devices/hooks/useRunHasStarted.ts b/app/src/organisms/Devices/hooks/useRunHasStarted.ts index da7e812d372..6dcfd61baba 100644 --- a/app/src/organisms/Devices/hooks/useRunHasStarted.ts +++ b/app/src/organisms/Devices/hooks/useRunHasStarted.ts @@ -1,5 +1,5 @@ import { RUN_STATUS_IDLE } from '@opentrons/api-client' -import { useRunStatus } from '/app/organisms/RunTimeControl/hooks' +import { useRunStatus } from '/app/resources/runs' export function useRunHasStarted(runId: string | null): boolean { const runStatus = useRunStatus(runId) diff --git a/app/src/organisms/Devices/hooks/useRunPipetteInfoByMount.ts b/app/src/organisms/Devices/hooks/useRunPipetteInfoByMount.ts index 27eb18ab5eb..d8cef97edc1 100644 --- a/app/src/organisms/Devices/hooks/useRunPipetteInfoByMount.ts +++ b/app/src/organisms/Devices/hooks/useRunPipetteInfoByMount.ts @@ -6,11 +6,9 @@ import { } from '@opentrons/shared-data' import { useAllTipLengthCalibrationsQuery } from '@opentrons/react-api-client' import { MATCH, INEXACT_MATCH, INCOMPATIBLE } from '/app/redux/pipettes' -import { - useAttachedPipetteCalibrations, - useAttachedPipettes, - useStoredProtocolAnalysis, -} from '.' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' +import { useAttachedPipetteCalibrations, useAttachedPipettes } from '.' + import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import type { PickUpTipRunTimeCommand, diff --git a/app/src/organisms/Devices/hooks/useRunStartedOrLegacySessionInProgress.ts b/app/src/organisms/Devices/hooks/useRunStartedOrLegacySessionInProgress.ts index 4be61d44304..c5623bf6725 100644 --- a/app/src/organisms/Devices/hooks/useRunStartedOrLegacySessionInProgress.ts +++ b/app/src/organisms/Devices/hooks/useRunStartedOrLegacySessionInProgress.ts @@ -1,7 +1,6 @@ import { useAllSessionsQuery } from '@opentrons/react-api-client' import { RUN_STATUS_IDLE } from '@opentrons/api-client' -import { useCurrentRunId } from '/app/resources/runs' -import { useRunStatus } from '../../RunTimeControl/hooks' +import { useCurrentRunId, useRunStatus } from '/app/resources/runs' export function useRunStartedOrLegacySessionInProgress(): boolean { const runId = useCurrentRunId() diff --git a/app/src/organisms/Devices/hooks/useRunStatuses.ts b/app/src/organisms/Devices/hooks/useRunStatuses.ts index 95ce265c379..b12e56aecf8 100644 --- a/app/src/organisms/Devices/hooks/useRunStatuses.ts +++ b/app/src/organisms/Devices/hooks/useRunStatuses.ts @@ -10,8 +10,7 @@ import { RUN_STATUS_BLOCKED_BY_OPEN_DOOR, RUN_STATUS_AWAITING_RECOVERY_BLOCKED_BY_OPEN_DOOR, } from '@opentrons/api-client' -import { useCurrentRunId } from '/app/resources/runs' -import { useRunStatus } from '../../RunTimeControl/hooks' +import { useCurrentRunId, useRunStatus } from '/app/resources/runs' import type { RunStatus } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts b/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts index 9ff17bf4358..0fe34cf4af0 100644 --- a/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts +++ b/app/src/organisms/Devices/hooks/useTrackCreateProtocolRunEvent.ts @@ -1,9 +1,9 @@ import { useTrackEvent } from '/app/redux/analytics' -import { parseProtocolRunAnalyticsData } from './useProtocolRunAnalyticsData' -import { parseProtocolAnalysisOutput } from './useStoredProtocolAnalysis' +import { parseProtocolRunAnalyticsData } from '/app/transformations/analytics' +import { parseProtocolAnalysisOutput } from '/app/transformations/analysis' import type { StoredProtocolData } from '/app/redux/protocol-storage' -import { useRobot } from './useRobot' +import { useRobot } from '/app/redux-resources/robots' type CreateProtocolRunEventName = | 'createProtocolRecordRequest' diff --git a/app/src/organisms/Devices/hooks/useUnmatchedModulesForProtocol.ts b/app/src/organisms/Devices/hooks/useUnmatchedModulesForProtocol.ts index f48ced52ed3..d73e179e9fd 100644 --- a/app/src/organisms/Devices/hooks/useUnmatchedModulesForProtocol.ts +++ b/app/src/organisms/Devices/hooks/useUnmatchedModulesForProtocol.ts @@ -2,11 +2,8 @@ import reduce from 'lodash/reduce' import type { AttachedModule } from '/app/redux/modules/types' -import { - useAttachedModules, - useModuleRenderInfoForProtocolById, - useRobot, -} from '.' +import { useRobot } from '/app/redux-resources/robots' +import { useAttachedModules, useModuleRenderInfoForProtocolById } from '.' import { NON_CONNECTING_MODULE_TYPES, getModuleType, diff --git a/app/src/organisms/Devices/utils.ts b/app/src/organisms/Devices/utils.ts index 37e49697eea..da0b0666280 100644 --- a/app/src/organisms/Devices/utils.ts +++ b/app/src/organisms/Devices/utils.ts @@ -9,10 +9,7 @@ import type { Instruments, PipetteData, PipetteOffsetCalibration, - RunTimeParameterFilesCreateData, - RunTimeParameterValuesCreateData, } from '@opentrons/api-client' -import type { RunTimeParameter } from '@opentrons/shared-data' /** * formats a string if it is in ISO 8601 date format @@ -93,45 +90,3 @@ export function getShowPipetteCalibrationWarning( }) ?? false ) } - -/** - * prepares object to send to endpoints requiring RunTimeParameterValuesCreateData - * @param {RunTimeParameter[]} runTimeParameters array of updated RunTimeParameter overrides - * @returns {RunTimeParameterValuesCreateData} object mapping variable name to value - */ -export function getRunTimeParameterValuesForRun( - runTimeParameters: RunTimeParameter[] -): RunTimeParameterValuesCreateData { - return runTimeParameters.reduce((acc, param) => { - const { variableName } = param - if (param.type !== 'csv_file' && param.value !== param.default) { - return { ...acc, [variableName]: param.value } - } - return acc - }, {}) -} - -/** - * prepares object to send to endpoints requiring RunTimeParameterFilesCreateData - * @param {RunTimeParameter[]} runTimeParameters array of updated RunTimeParameter overrides - * @param {Record} [fileIdMap] mapping of variable name to file ID created and returned by robot server - * @returns {RunTimeParameterFilesCreateData} object mapping variable name to file ID - */ -export function getRunTimeParameterFilesForRun( - runTimeParameters: RunTimeParameter[], - fileIdMap?: Record -): RunTimeParameterFilesCreateData { - return runTimeParameters.reduce((acc, param) => { - const { variableName } = param - if (param.type === 'csv_file' && param.file?.id != null) { - return { ...acc, [variableName]: param.file.id } - } else if ( - param.type === 'csv_file' && - fileIdMap != null && - variableName in fileIdMap - ) { - return { ...acc, [variableName]: fileIdMap[variableName] } - } - return acc - }, {}) -} diff --git a/app/src/organisms/DropTipWizardFlows/__tests__/TipsAttachedModal.test.tsx b/app/src/organisms/DropTipWizardFlows/__tests__/TipsAttachedModal.test.tsx index 3c160f61e24..07acb2c43e2 100644 --- a/app/src/organisms/DropTipWizardFlows/__tests__/TipsAttachedModal.test.tsx +++ b/app/src/organisms/DropTipWizardFlows/__tests__/TipsAttachedModal.test.tsx @@ -9,7 +9,7 @@ import { i18n } from '/app/i18n' import { handleTipsAttachedModal } from '../TipsAttachedModal' import { LEFT } from '@opentrons/shared-data' import { mockPipetteInfo } from '/app/redux/pipettes/__fixtures__' -import { useCloseCurrentRun } from '../../ProtocolUpload/hooks' +import { useCloseCurrentRun } from '/app/resources/runs' import { useDropTipWizardFlows } from '..' import type { Mock } from 'vitest' @@ -17,7 +17,7 @@ import type { PipetteModelSpecs } from '@opentrons/shared-data' import type { HostConfig } from '@opentrons/api-client' import type { PipetteWithTip } from '../hooks' -vi.mock('../../ProtocolUpload/hooks') +vi.mock('/app/resources/runs/useCloseCurrentRun') vi.mock('..') const MOCK_ACTUAL_PIPETTE = { diff --git a/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryWizard.tsx b/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryWizard.tsx index 98493f13f90..1f01ca85028 100644 --- a/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryWizard.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/ErrorRecoveryWizard.tsx @@ -28,13 +28,10 @@ import { getErrorKind } from './utils' import { RECOVERY_MAP } from './constants' import type { RobotType } from '@opentrons/shared-data' -import type { RecoveryContentProps } from './types' -import type { - ERUtilsResults, - UseRecoveryAnalyticsResult, - useRetainedFailedCommandBySource, -} from './hooks' +import type { RecoveryRoute, RouteStep, RecoveryContentProps } from './types' +import type { ERUtilsResults, useRetainedFailedCommandBySource } from './hooks' import type { ErrorRecoveryFlowsProps } from '.' +import type { UseRecoveryAnalyticsResult } from '/app/redux-resources/analytics' export interface UseERWizardResult { hasLaunchedRecovery: boolean @@ -68,7 +65,7 @@ export type ErrorRecoveryWizardProps = ErrorRecoveryFlowsProps & robotType: RobotType isOnDevice: boolean isDoorOpen: boolean - analytics: UseRecoveryAnalyticsResult + analytics: UseRecoveryAnalyticsResult failedCommand: ReturnType } diff --git a/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx b/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx index 94858293982..4e2642aac85 100644 --- a/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/RunPausedSplash.tsx @@ -36,10 +36,12 @@ import type { RobotType } from '@opentrons/shared-data' import type { ErrorRecoveryFlowsProps } from '.' import type { ERUtilsResults, - UseRecoveryAnalyticsResult, UseRecoveryTakeoverResult, useRetainedFailedCommandBySource, } from './hooks' +import type { RecoveryRoute, RouteStep } from './types' + +import type { UseRecoveryAnalyticsResult } from '/app/redux-resources/analytics' export function useRunPausedSplash( isOnDevice: boolean, @@ -61,7 +63,7 @@ type RunPausedSplashProps = ERUtilsResults & { robotType: RobotType robotName: string toggleERWizAsActiveUser: UseRecoveryTakeoverResult['toggleERWizAsActiveUser'] - analytics: UseRecoveryAnalyticsResult + analytics: UseRecoveryAnalyticsResult } export function RunPausedSplash( props: RunPausedSplashProps diff --git a/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx index 10336b92d64..5276023bb83 100644 --- a/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/__tests__/ErrorRecoveryFlows.test.tsx @@ -17,9 +17,9 @@ import { useCurrentlyRecoveringFrom, useERUtils, useShowDoorInfo, - useRecoveryAnalytics, useRecoveryTakeover, } from '../hooks' +import { useRecoveryAnalytics } from '/app/redux-resources/analytics' import { getIsOnDevice } from '/app/redux/config' import { useERWizard, ErrorRecoveryWizard } from '../ErrorRecoveryWizard' import { useRunPausedSplash, RunPausedSplash } from '../RunPausedSplash' @@ -31,6 +31,7 @@ vi.mock('../hooks') vi.mock('../useRecoveryCommands') vi.mock('/app/redux/config') vi.mock('../RunPausedSplash') +vi.mock('/app/redux-resources/analytics') vi.mock('@opentrons/react-api-client') vi.mock('react-redux', async () => { const actual = await vi.importActual('react-redux') diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts index 923b84f2273..4a97b82afc1 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts +++ b/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts @@ -5,7 +5,6 @@ export { useShowDoorInfo } from './useShowDoorInfo' export { useRecoveryCommands } from './useRecoveryCommands' export { useRouteUpdateActions } from './useRouteUpdateActions' export { useERUtils } from './useERUtils' -export { useRecoveryAnalytics } from './useRecoveryAnalytics' export { useRecoveryTakeover } from './useRecoveryTakeover' export { useRetainedFailedCommandBySource } from './useRetainedFailedCommandBySource' @@ -14,6 +13,5 @@ export type { UseRecoveryCommandsResult } from './useRecoveryCommands' export type { RecoveryTipStatusUtils } from './useRecoveryTipStatus' export type { ERUtilsResults } from './useERUtils' export type { UseFailedLabwareUtilsResult } from './useFailedLabwareUtils' -export type { UseRecoveryAnalyticsResult } from './useRecoveryAnalytics' export type { UseRecoveryTakeoverResult } from './useRecoveryTakeover' export type { FailedCommandBySource } from './useRetainedFailedCommandBySource' diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts index 41be1997597..fdb7ca0ad22 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts +++ b/app/src/organisms/ErrorRecoveryFlows/hooks/useERUtils.ts @@ -15,11 +15,11 @@ import { useRecoveryOptionCopy } from './useRecoveryOptionCopy' import { useRecoveryActionMutation } from './useRecoveryActionMutation' import { useRunningStepCounts } from '/app/resources/protocols/hooks' import { useRecoveryToasts } from './useRecoveryToasts' -import { useRecoveryAnalytics } from './useRecoveryAnalytics' +import { useRecoveryAnalytics } from '/app/redux-resources/analytics' import type { PipetteData } from '@opentrons/api-client' import type { RobotType } from '@opentrons/shared-data' -import type { IRecoveryMap } from '../types' +import type { IRecoveryMap, RouteStep, RecoveryRoute } from '../types' import type { ErrorRecoveryFlowsProps } from '..' import type { UseRouteUpdateActionsResult } from './useRouteUpdateActions' import type { UseRecoveryCommandsResult } from './useRecoveryCommands' @@ -32,7 +32,7 @@ import type { } from './useRecoveryRouting' import type { RecoveryActionMutationResult } from './useRecoveryActionMutation' import type { StepCounts } from '/app/resources/protocols/hooks' -import type { UseRecoveryAnalyticsResult } from './useRecoveryAnalytics' +import type { UseRecoveryAnalyticsResult } from '/app/redux-resources/analytics' import type { UseRecoveryTakeoverResult } from './useRecoveryTakeover' import type { useRetainedFailedCommandBySource } from './useRetainedFailedCommandBySource' @@ -59,7 +59,7 @@ export interface ERUtilsResults { stepCounts: StepCounts commandsAfterFailedCommand: ReturnType subMapUtils: SubMapUtils - analytics: UseRecoveryAnalyticsResult + analytics: UseRecoveryAnalyticsResult } const SUBSEQUENT_COMMAND_DEPTH = 2 diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts index 6ab37727101..ddf5eda3bbf 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts +++ b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts @@ -25,11 +25,11 @@ import type { RecoveryPolicyRulesParams, } from '@opentrons/api-client' import type { WellGroup } from '@opentrons/components' -import type { FailedCommand } from '../types' +import type { FailedCommand, RecoveryRoute, RouteStep } from '../types' import type { UseFailedLabwareUtilsResult } from './useFailedLabwareUtils' import type { UseRouteUpdateActionsResult } from './useRouteUpdateActions' import type { RecoveryToasts } from './useRecoveryToasts' -import type { UseRecoveryAnalyticsResult } from './useRecoveryAnalytics' +import type { UseRecoveryAnalyticsResult } from '/app/redux-resources/analytics' import type { CurrentRecoveryOptionUtils } from './useRecoveryRouting' import type { ErrorRecoveryFlowsProps } from '../index' @@ -39,7 +39,7 @@ interface UseRecoveryCommandsParams { failedLabwareUtils: UseFailedLabwareUtilsResult routeUpdateActions: UseRouteUpdateActionsResult recoveryToastUtils: RecoveryToasts - analytics: UseRecoveryAnalyticsResult + analytics: UseRecoveryAnalyticsResult selectedRecoveryOption: CurrentRecoveryOptionUtils['selectedRecoveryOption'] } export interface UseRecoveryCommandsResult { diff --git a/app/src/organisms/GripperWizardFlows/__tests__/BeforeBeginning.test.tsx b/app/src/organisms/GripperWizardFlows/__tests__/BeforeBeginning.test.tsx index 9aa89038335..d2a2fda6b64 100644 --- a/app/src/organisms/GripperWizardFlows/__tests__/BeforeBeginning.test.tsx +++ b/app/src/organisms/GripperWizardFlows/__tests__/BeforeBeginning.test.tsx @@ -4,7 +4,7 @@ import { describe, it, vi, beforeEach, expect } from 'vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { InProgressModal } from '/app/molecules/InProgressModal/InProgressModal' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { BeforeBeginning } from '../BeforeBeginning' import { GRIPPER_FLOW_TYPES } from '../constants' diff --git a/app/src/organisms/IncompatibleModule/IncompatibleModuleDesktopModalBody.tsx b/app/src/organisms/IncompatibleModule/IncompatibleModuleDesktopModalBody.tsx index 862ddb817d4..036c0db566f 100644 --- a/app/src/organisms/IncompatibleModule/IncompatibleModuleDesktopModalBody.tsx +++ b/app/src/organisms/IncompatibleModule/IncompatibleModuleDesktopModalBody.tsx @@ -15,7 +15,7 @@ import { } from '@opentrons/components' import { getModuleDisplayName } from '@opentrons/shared-data' import type { AttachedModule } from '@opentrons/api-client' -import { useIsFlex } from '../Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { InterventionModal } from '/app/molecules/InterventionModal' export interface IncompatibleModuleDesktopModalBodyProps { modules: AttachedModule[] diff --git a/app/src/organisms/IncompatibleModule/__tests__/IncompatibleModuleDesktopModalBody.test.tsx b/app/src/organisms/IncompatibleModule/__tests__/IncompatibleModuleDesktopModalBody.test.tsx index 8deb560b991..245073c15a6 100644 --- a/app/src/organisms/IncompatibleModule/__tests__/IncompatibleModuleDesktopModalBody.test.tsx +++ b/app/src/organisms/IncompatibleModule/__tests__/IncompatibleModuleDesktopModalBody.test.tsx @@ -6,10 +6,10 @@ import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { IncompatibleModuleDesktopModalBody } from '../IncompatibleModuleDesktopModalBody' -import { useIsFlex } from '../../Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import * as Fixtures from '../__fixtures__' -vi.mock('../../Devices/hooks') +vi.mock('/app/redux-resources/robots') const getRenderer = (isFlex: boolean) => { when(useIsFlex).calledWith('otie').thenReturn(isFlex) diff --git a/app/src/organisms/InterventionModal/PauseInterventionContent.tsx b/app/src/organisms/InterventionModal/PauseInterventionContent.tsx index f3f617f20fd..36f313873f6 100644 --- a/app/src/organisms/InterventionModal/PauseInterventionContent.tsx +++ b/app/src/organisms/InterventionModal/PauseInterventionContent.tsx @@ -15,8 +15,8 @@ import { LegacyStyledText, } from '@opentrons/components' -import { EMPTY_TIMESTAMP } from '../Devices/constants' -import { formatInterval } from '../RunTimeControl/utils' +import { EMPTY_TIMESTAMP } from '/app/resources/runs' +import { formatInterval } from '/app/transformations/commands' import { InterventionCommandMessage } from './InterventionCommandMessage' const PAUSE_INTERVENTION_CONTENT_STYLE = css` diff --git a/app/src/organisms/InterventionModal/__tests__/InterventionModal.test.tsx b/app/src/organisms/InterventionModal/__tests__/InterventionModal.test.tsx index 0f7e6381b65..2a6acb3be85 100644 --- a/app/src/organisms/InterventionModal/__tests__/InterventionModal.test.tsx +++ b/app/src/organisms/InterventionModal/__tests__/InterventionModal.test.tsx @@ -16,7 +16,7 @@ import { truncatedCommandMessage, } from '../__fixtures__' import { InterventionModal, useInterventionModal } from '..' -import { useIsFlex } from '../../Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import type { CompletedProtocolAnalysis } from '@opentrons/shared-data' import type { RunData } from '@opentrons/api-client' @@ -25,7 +25,7 @@ const ROBOT_NAME = 'Otie' const mockOnResumeHandler = vi.fn() -vi.mock('../../Devices/hooks') +vi.mock('/app/redux-resources/robots') describe('useInterventionModal', () => { const defaultProps = { diff --git a/app/src/organisms/InterventionModal/index.tsx b/app/src/organisms/InterventionModal/index.tsx index ee235540142..dff08559f9d 100644 --- a/app/src/organisms/InterventionModal/index.tsx +++ b/app/src/organisms/InterventionModal/index.tsx @@ -33,7 +33,7 @@ import { getIsOnDevice } from '/app/redux/config' import { PauseInterventionContent } from './PauseInterventionContent' import { MoveLabwareInterventionContent } from './MoveLabwareInterventionContent' import { isInterventionCommand } from './utils' -import { useRobotType } from '../Devices/hooks' +import { useRobotType } from '/app/redux-resources/robots' import type { IconName } from '@opentrons/components' import type { CompletedProtocolAnalysis } from '@opentrons/shared-data' diff --git a/app/src/organisms/LabwareDetails/images/eppendorf_1000ul_tip_eptips_side_view.jpg b/app/src/organisms/LabwareDetails/images/eppendorf_1000ul_tip_eptips_side_view.jpg deleted file mode 100644 index 9aaaf771e12..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/eppendorf_1000ul_tip_eptips_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/eppendorf_10ul_tips_eptips_side_view.jpg b/app/src/organisms/LabwareDetails/images/eppendorf_10ul_tips_eptips_side_view.jpg deleted file mode 100644 index 718c6bd1ac6..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/eppendorf_10ul_tips_eptips_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/geb_96_tiprack_1000ul_side_view.jpg b/app/src/organisms/LabwareDetails/images/geb_96_tiprack_1000ul_side_view.jpg deleted file mode 100644 index c201e8363fb..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/geb_96_tiprack_1000ul_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/geb_96_tiprack_10ul_side_view.jpg b/app/src/organisms/LabwareDetails/images/geb_96_tiprack_10ul_side_view.jpg deleted file mode 100644 index 2273fa6248f..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/geb_96_tiprack_10ul_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_1000ul_side_view.jpg b/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_1000ul_side_view.jpg deleted file mode 100644 index eccd58b346d..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_1000ul_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_10ul_side_view.jpg b/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_10ul_side_view.jpg deleted file mode 100644 index cfcd1521639..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_10ul_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_300ul_side_view.jpg b/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_300ul_side_view.jpg deleted file mode 100644 index 9ac4d287cf2..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/opentrons_96_tiprack_300ul_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwareDetails/images/tipone_96_tiprack_200ul_side_view.jpg b/app/src/organisms/LabwareDetails/images/tipone_96_tiprack_200ul_side_view.jpg deleted file mode 100644 index 45a5adc05ad..00000000000 Binary files a/app/src/organisms/LabwareDetails/images/tipone_96_tiprack_200ul_side_view.jpg and /dev/null differ diff --git a/app/src/organisms/LabwarePositionCheck/__tests__/PickUpTip.test.tsx b/app/src/organisms/LabwarePositionCheck/__tests__/PickUpTip.test.tsx index 1bc2468a6ab..c852c5eee5a 100644 --- a/app/src/organisms/LabwarePositionCheck/__tests__/PickUpTip.test.tsx +++ b/app/src/organisms/LabwarePositionCheck/__tests__/PickUpTip.test.tsx @@ -3,7 +3,7 @@ import { fireEvent, screen, waitFor } from '@testing-library/react' import { it, describe, beforeEach, vi, afterEach, expect } from 'vitest' import { FLEX_ROBOT_TYPE, HEATERSHAKER_MODULE_V1 } from '@opentrons/shared-data' import { i18n } from '/app/i18n' -import { useProtocolMetadata } from '../../Devices/hooks' +import { useProtocolMetadata } from '/app/resources/protocols' import { getIsOnDevice } from '/app/redux/config' import { PickUpTip } from '../PickUpTip' import { SECTIONS } from '../constants' @@ -12,7 +12,7 @@ import type { CommandData } from '@opentrons/api-client' import { nestedTextMatcher, renderWithProviders } from '/app/__testing-utils__' import type { Mock } from 'vitest' -vi.mock('../../Devices/hooks') +vi.mock('/app/resources/protocols') vi.mock('/app/redux/config') const mockStartPosition = { x: 10, y: 20, z: 30 } diff --git a/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx b/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx index a3860c24cd7..0c44d4ecf89 100644 --- a/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx +++ b/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx @@ -8,12 +8,12 @@ import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { SECTIONS } from '../constants' import { mockCompletedAnalysis } from '../__fixtures__' -import { useProtocolMetadata } from '../../Devices/hooks' +import { useProtocolMetadata } from '/app/resources/protocols' import { getIsOnDevice } from '/app/redux/config' import { ReturnTip } from '../ReturnTip' -vi.mock('../../Devices/hooks') vi.mock('/app/redux/config') +vi.mock('/app/resources/protocols') const render = (props: React.ComponentProps) => { return renderWithProviders(, { diff --git a/app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx b/app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx index 8de9cb1f880..fe27d5376c6 100644 --- a/app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx +++ b/app/src/organisms/ModuleCard/ModuleOverflowMenu.tsx @@ -19,10 +19,10 @@ import { } from '@opentrons/shared-data' import { useCurrentRunId } from '/app/resources/runs' import { - useIsFlex, useRunStatuses, useIsLegacySessionInProgress, -} from '../Devices/hooks' +} from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useModuleOverflowMenu } from './hooks' import type { AttachedModule } from '/app/redux/modules/types' diff --git a/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx b/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx index 5a1e1fedcb0..e426c310216 100644 --- a/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx +++ b/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx @@ -17,9 +17,9 @@ import { import { mockRobot } from '/app/redux/robot-api/__fixtures__' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' import { FAILURE, getRequestById, PENDING, SUCCESS } from '/app/redux/robot-api' -import { useCurrentRunStatus } from '../../RunTimeControl/hooks' -import { useToaster } from '../../ToasterOven' -import { useIsFlex } from '../../Devices/hooks' +import { useCurrentRunStatus } from '/app/organisms/RunTimeControl/hooks' +import { useToaster } from '/app/organisms/ToasterOven' +import { useIsFlex } from '/app/redux-resources/robots' import { MagneticModuleData } from '../MagneticModuleData' import { TemperatureModuleData } from '../TemperatureModuleData' import { ThermocyclerModuleData } from '../ThermocyclerModuleData' @@ -47,6 +47,7 @@ vi.mock('../ModuleOverflowMenu') vi.mock('../../RunTimeControl/hooks') vi.mock('../FirmwareUpdateFailedModal') vi.mock('/app/redux/robot-api') +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/ToasterOven') vi.mock('/app/organisms/Devices/hooks') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') diff --git a/app/src/organisms/ModuleCard/__tests__/ModuleOverflowMenu.test.tsx b/app/src/organisms/ModuleCard/__tests__/ModuleOverflowMenu.test.tsx index a90bfc17ecb..c840dfe1cff 100644 --- a/app/src/organisms/ModuleCard/__tests__/ModuleOverflowMenu.test.tsx +++ b/app/src/organisms/ModuleCard/__tests__/ModuleOverflowMenu.test.tsx @@ -14,15 +14,15 @@ import { import { useRunStatuses, useIsLegacySessionInProgress, - useIsFlex, -} from '../../Devices/hooks' +} from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useCurrentRunId } from '/app/resources/runs' import { ModuleOverflowMenu } from '../ModuleOverflowMenu' import type { TemperatureStatus } from '@opentrons/api-client' vi.mock('../../Devices/hooks') -vi.mock('../../RunTimeControl/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/resources/runs') const render = (props: React.ComponentProps) => { diff --git a/app/src/organisms/ModuleCard/index.tsx b/app/src/organisms/ModuleCard/index.tsx index 225ffa0216d..f8f847c2a93 100644 --- a/app/src/organisms/ModuleCard/index.tsx +++ b/app/src/organisms/ModuleCard/index.tsx @@ -44,10 +44,10 @@ import { import { Banner } from '/app/atoms/Banner' import { UpdateBanner } from '/app/molecules/UpdateBanner' import { useChainLiveCommands } from '/app/resources/runs' -import { useCurrentRunStatus } from '../RunTimeControl/hooks' -import { useIsFlex } from '/app/organisms/Devices/hooks' -import { getModuleTooHot } from '../Devices/getModuleTooHot' -import { useToaster } from '../ToasterOven' +import { useCurrentRunStatus } from '/app/organisms/RunTimeControl/hooks' +import { useIsFlex } from '/app/redux-resources/robots' +import { getModuleTooHot } from '/app/organisms/Devices/getModuleTooHot' +import { useToaster } from '/app/organisms/ToasterOven' import { MagneticModuleData } from './MagneticModuleData' import { TemperatureModuleData } from './TemperatureModuleData' import { ThermocyclerModuleData } from './ThermocyclerModuleData' @@ -60,7 +60,7 @@ import { HeaterShakerModuleData } from './HeaterShakerModuleData' import { HeaterShakerSlideout } from './HeaterShakerSlideout' import { TestShakeSlideout } from './TestShakeSlideout' import { ModuleWizardFlows } from '../ModuleWizardFlows' -import { getModulePrepCommands } from '../Devices/getModulePrepCommands' +import { getModulePrepCommands } from '/app/organisms/Devices/getModulePrepCommands' import { getModuleCardImage } from './utils' import { FirmwareUpdateFailedModal } from './FirmwareUpdateFailedModal' import { ErrorInfo } from './ErrorInfo' diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/LiquidDetails.test.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/LiquidDetails.test.tsx index bf306507773..0100a7a27da 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/LiquidDetails.test.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/LiquidDetails.test.tsx @@ -4,7 +4,7 @@ import { describe, it, beforeEach, vi } from 'vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { RUN_ID_1 } from '../../../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { getLocationInfoNames } from '../../../../Devices/ProtocolRun/utils/getLocationInfoNames' import { getVolumePerWell } from '../../../../Devices/ProtocolRun/SetupLiquids/utils' import { LiquidDetails } from '../LiquidDetails' diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/ProtocolSetupLiquids.test.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/ProtocolSetupLiquids.test.tsx index cccd36241c5..15a705119f5 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/ProtocolSetupLiquids.test.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupLiquids/__tests__/ProtocolSetupLiquids.test.tsx @@ -9,7 +9,7 @@ import { import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { RUN_ID_1 } from '../../../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { getTotalVolumePerLiquidId } from '../../../../Devices/ProtocolRun/SetupLiquids/utils' import { useMostRecentCompletedAnalysis } from '../../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { LiquidDetails } from '../LiquidDetails' diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/ProtocolSetupModulesAndDeck.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/ProtocolSetupModulesAndDeck.tsx index 5d6ed7565e6..0b30a532c30 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/ProtocolSetupModulesAndDeck.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/ProtocolSetupModulesAndDeck.tsx @@ -23,7 +23,7 @@ import { ChildNavigation } from '/app/organisms/ChildNavigation' import { useAttachedModules } from '/app/organisms/Devices/hooks' import { getProtocolModulesInfo } from '/app/organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' import { useMostRecentCompletedAnalysis } from '/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useRunStatus } from '../../../RunTimeControl/hooks' +import { useRunStatus } from '/app/resources/runs' import { getAttachedProtocolModuleMatches, getUnmatchedModulesForProtocol, diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx index 9b97db1eccf..f59e0df775b 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupModulesAndDeck/__tests__/ProtocolSetupModulesAndDeck.test.tsx @@ -13,7 +13,7 @@ import { import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useChainLiveCommands } from '/app/resources/runs' +import { useChainLiveCommands, useRunStatus } from '/app/resources/runs' import { mockRobotSideAnalysis } from '/app/molecules/Command/__fixtures__' import { useAttachedModules, @@ -36,7 +36,6 @@ import { FixtureTable } from '../FixtureTable' import { ModulesAndDeckMapView } from '../ModulesAndDeckMapView' import { ProtocolSetupModulesAndDeck } from '..' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' -import { useRunStatus } from '../../../../RunTimeControl/hooks' import type { CutoutConfig, DeckConfiguration } from '@opentrons/shared-data' import type { UseQueryResult } from 'react-query' @@ -55,7 +54,6 @@ vi.mock( '../../../../Devices/ProtocolRun/SetupModuleAndDeck/LocationConflictModal' ) vi.mock('../ModulesAndDeckMapView') -vi.mock('../../../../RunTimeControl/hooks') const ROBOT_NAME = 'otie' const RUN_ID = '1' diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ChooseNumber.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ChooseNumber.tsx index 53475939420..179fbffb5df 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ChooseNumber.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ChooseNumber.tsx @@ -11,8 +11,8 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { useToaster } from '../../../ToasterOven' -import { ChildNavigation } from '../../../ChildNavigation' +import { useToaster } from '/app/organisms/ToasterOven' +import { ChildNavigation } from '/app/organisms/ChildNavigation' import { NumericalKeyboard } from '/app/atoms/SoftwareKeyboard' import type { NumberParameter } from '@opentrons/shared-data' diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ProtocolSetupParameters.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ProtocolSetupParameters.tsx index 56a76db6dcb..3264213f10d 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ProtocolSetupParameters.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ProtocolSetupParameters.tsx @@ -22,13 +22,13 @@ import { import { getRunTimeParameterFilesForRun, getRunTimeParameterValuesForRun, -} from '../../../Devices/utils' -import { ChildNavigation } from '../../../ChildNavigation' +} from '/app/transformations/runs' +import { ChildNavigation } from '/app/organisms/ChildNavigation' import { ResetValuesModal } from './ResetValuesModal' import { ChooseEnum } from './ChooseEnum' import { ChooseNumber } from './ChooseNumber' import { ChooseCsvFile } from './ChooseCsvFile' -import { useToaster } from '../../../ToasterOven' +import { useToaster } from '/app/organisms/ToasterOven' import { ProtocolSetupStep } from '../ProtocolSetupStep' import type { CompletedProtocolAnalysis, diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ViewOnlyParameters.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ViewOnlyParameters.tsx index 2339ae7cc88..c8c892902a4 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ViewOnlyParameters.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/ViewOnlyParameters.tsx @@ -18,9 +18,9 @@ import { LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { ChildNavigation } from '../../../ChildNavigation' -import { useToaster } from '../../../ToasterOven' +import { useMostRecentCompletedAnalysis } from '/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { ChildNavigation } from '/app/organisms/ChildNavigation' +import { useToaster } from '/app/organisms/ToasterOven' import type { SetupScreens } from '../types' diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx index c8e354fe39d..6c7d29eeb49 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ChooseNumber.test.tsx @@ -4,13 +4,13 @@ import { fireEvent, screen } from '@testing-library/react' import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useToaster } from '../../../../ToasterOven' -import { mockRunTimeParameterData } from '/app/pages/ODD/ProtocolDetails/fixtures' +import { useToaster } from '/app/organisms/ToasterOven' +import { mockRunTimeParameterData } from '../../__fixtures__' import { ChooseNumber } from '../ChooseNumber' import type { NumberParameter } from '@opentrons/shared-data' -vi.mock('../../../../ToasterOven') +vi.mock('/app/organisms/ToasterOven') const mockHandleGoBack = vi.fn() const mockIntNumberParameterData = mockRunTimeParameterData[5] as NumberParameter diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx index 65ebf91787c..0906ae6ae72 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx @@ -15,8 +15,8 @@ import { renderWithProviders } from '/app/__testing-utils__' import { ChooseEnum } from '../ChooseEnum' import { ChooseNumber } from '../ChooseNumber' import { ChooseCsvFile } from '../ChooseCsvFile' -import { mockRunTimeParameterData } from '/app/pages/ODD/ProtocolDetails/fixtures' -import { useToaster } from '../../../../ToasterOven' +import { mockRunTimeParameterData } from '../../__fixtures__' +import { useToaster } from '/app/organisms/ToasterOven' import { ProtocolSetupParameters } from '..' import type { NavigateFunction } from 'react-router-dom' @@ -29,9 +29,9 @@ vi.mock('../ChooseEnum') vi.mock('../ChooseNumber') vi.mock('../ChooseCsvFile') vi.mock('/app/redux/config') -vi.mock('../../../../ToasterOven') +vi.mock('/app/organisms/ToasterOven') vi.mock('@opentrons/react-api-client') -vi.mock('../../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') +vi.mock('/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('react-router-dom', async importOriginal => { const reactRouterDom = await importOriginal() return { diff --git a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx index 425329e4fcb..b360ed71251 100644 --- a/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx +++ b/app/src/organisms/ODD/ProtocolSetup/ProtocolSetupParameters/__tests__/ViewOnlyParameters.test.tsx @@ -4,13 +4,13 @@ import { it, describe, beforeEach, vi, expect } from 'vitest' import { fireEvent, screen } from '@testing-library/react' import { i18n } from '/app/i18n' import { renderWithProviders } from '/app/__testing-utils__' -import { useMostRecentCompletedAnalysis } from '../../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useToaster } from '../../../../ToasterOven' -import { mockRunTimeParameterData } from '/app/pages/ODD/ProtocolDetails/fixtures' +import { useMostRecentCompletedAnalysis } from '/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { useToaster } from '/app/organisms/ToasterOven' +import { mockRunTimeParameterData } from '../../__fixtures__' import { ViewOnlyParameters } from '../ViewOnlyParameters' -vi.mock('../../../../LabwarePositionCheck/useMostRecentCompletedAnalysis') -vi.mock('../../../../ToasterOven') +vi.mock('/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis') +vi.mock('/app/organisms/ToasterOven') const RUN_ID = 'mockId' const render = (props: React.ComponentProps) => { return renderWithProviders(, { diff --git a/app/src/pages/ODD/ProtocolDetails/fixtures.ts b/app/src/organisms/ODD/ProtocolSetup/__fixtures__/index.ts similarity index 100% rename from app/src/pages/ODD/ProtocolDetails/fixtures.ts rename to app/src/organisms/ODD/ProtocolSetup/__fixtures__/index.ts diff --git a/app/src/organisms/ODD/RobotDashboard/RecentRunProtocolCard.tsx b/app/src/organisms/ODD/RobotDashboard/RecentRunProtocolCard.tsx index 88c7e53a845..26d03fed45d 100644 --- a/app/src/organisms/ODD/RobotDashboard/RecentRunProtocolCard.tsx +++ b/app/src/organisms/ODD/RobotDashboard/RecentRunProtocolCard.tsx @@ -35,7 +35,7 @@ import { } from '/app/redux/analytics' import { Skeleton } from '/app/atoms/Skeleton' import { useMissingProtocolHardware } from '/app/transformations/commands' -import { useCloneRun } from '../../ProtocolUpload/hooks' +import { useCloneRun } from '/app/resources/runs' import { useRerunnableStatusText } from './hooks' import type { RunData, RunStatus } from '@opentrons/api-client' diff --git a/app/src/organisms/ODD/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx b/app/src/organisms/ODD/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx index ca7a51dfb21..e3bdb0fd63c 100644 --- a/app/src/organisms/ODD/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx +++ b/app/src/organisms/ODD/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx @@ -17,15 +17,14 @@ import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { Skeleton } from '/app/atoms/Skeleton' import { useMissingProtocolHardware } from '/app/transformations/commands' -import { useTrackProtocolRunEvent } from '../../../Devices/hooks' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' import { useTrackEvent, ANALYTICS_PROTOCOL_PROCEED_TO_RUN, } from '/app/redux/analytics' -import { useCloneRun } from '../../../ProtocolUpload/hooks' +import { useCloneRun, useNotifyAllRunsQuery } from '/app/resources/runs' import { useRerunnableStatusText } from '../hooks' import { RecentRunProtocolCard } from '../' -import { useNotifyAllRunsQuery } from '/app/resources/runs' import type { NavigateFunction } from 'react-router-dom' import type { ProtocolHardware } from '/app/transformations/commands' @@ -43,13 +42,11 @@ vi.mock('react-router-dom', async importOriginal => { vi.mock('@opentrons/react-api-client') vi.mock('/app/atoms/Skeleton') vi.mock('/app/transformations/commands') -vi.mock('/app/pages/ODD/ProtocolDetails') -vi.mock('/app/organisms/Devices/hooks') vi.mock('/app/organisms/RunTimeControl/hooks') -vi.mock('/app/organisms/ProtocolUpload/hooks') vi.mock('/app/redux/analytics') vi.mock('../hooks') vi.mock('/app/resources/runs') +vi.mock('/app/redux-resources/analytics') const RUN_ID = 'mockRunId' const ROBOT_NAME = 'otie' diff --git a/app/src/organisms/ODD/RunningProtocol/ConfirmCancelRunModal.tsx b/app/src/organisms/ODD/RunningProtocol/ConfirmCancelRunModal.tsx index 0044cc477bc..c0036d03953 100644 --- a/app/src/organisms/ODD/RunningProtocol/ConfirmCancelRunModal.tsx +++ b/app/src/organisms/ODD/RunningProtocol/ConfirmCancelRunModal.tsx @@ -20,8 +20,8 @@ import { import { SmallButton } from '/app/atoms/buttons' import { OddModal } from '/app/molecules/OddModal' -import { useTrackProtocolRunEvent } from '/app/organisms/Devices/hooks' -import { useRunStatus } from '/app/organisms/RunTimeControl/hooks' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' +import { useRunStatus } from '/app/resources/runs' import { ANALYTICS_PROTOCOL_RUN_ACTION } from '/app/redux/analytics' import { getLocalRobot } from '/app/redux/discovery' import { CancelingRunModal } from './CancelingRunModal' diff --git a/app/src/organisms/ODD/RunningProtocol/CurrentRunningProtocolCommand.tsx b/app/src/organisms/ODD/RunningProtocol/CurrentRunningProtocolCommand.tsx index e3bff58decd..8b2e6c9bcc1 100644 --- a/app/src/organisms/ODD/RunningProtocol/CurrentRunningProtocolCommand.tsx +++ b/app/src/organisms/ODD/RunningProtocol/CurrentRunningProtocolCommand.tsx @@ -35,7 +35,7 @@ import type { RunTimeCommand, } from '@opentrons/shared-data' import type { RunCommandSummary, RunStatus } from '@opentrons/api-client' -import type { TrackProtocolRunEvent } from '../../Devices/hooks' +import type { TrackProtocolRunEvent } from '/app/redux-resources/analytics' import type { RobotAnalyticsData } from '/app/redux/analytics/types' const ODD_ANIMATION_OPTIMIZATIONS = ` diff --git a/app/src/organisms/ODD/RunningProtocol/RunningProtocolCommandList.tsx b/app/src/organisms/ODD/RunningProtocol/RunningProtocolCommandList.tsx index 4d8f20413ff..f351a46541f 100644 --- a/app/src/organisms/ODD/RunningProtocol/RunningProtocolCommandList.tsx +++ b/app/src/organisms/ODD/RunningProtocol/RunningProtocolCommandList.tsx @@ -34,7 +34,7 @@ import type { RobotType, } from '@opentrons/shared-data' import type { RunStatus } from '@opentrons/api-client' -import type { TrackProtocolRunEvent } from '../../Devices/hooks' +import type { TrackProtocolRunEvent } from '/app/redux-resources/analytics' import type { RobotAnalyticsData } from '/app/redux/analytics/types' const TITLE_TEXT_STYLE = css` diff --git a/app/src/organisms/ODD/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx b/app/src/organisms/ODD/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx index 7e59deff9f5..55c4b3fec65 100644 --- a/app/src/organisms/ODD/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx +++ b/app/src/organisms/ODD/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx @@ -13,8 +13,8 @@ import { import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useTrackProtocolRunEvent } from '/app/organisms/Devices/hooks' -import { useRunStatus } from '/app/organisms/RunTimeControl/hooks' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' +import { useRunStatus } from '/app/resources/runs' import { useTrackEvent } from '/app/redux/analytics' import { getLocalRobot } from '/app/redux/discovery' import { mockConnectedRobot } from '/app/redux/discovery/__fixtures__' @@ -24,10 +24,9 @@ import { CancelingRunModal } from '../CancelingRunModal' import type { NavigateFunction } from 'react-router-dom' vi.mock('@opentrons/react-api-client') -vi.mock('/app/organisms/Devices/hooks') -vi.mock('/app/organisms/RunTimeControl/hooks') +vi.mock('/app/resources/runs') +vi.mock('/app/redux-resources/analytics') vi.mock('/app/redux/analytics') -vi.mock('../../../ProtocolUpload/hooks') vi.mock('../CancelingRunModal') vi.mock('/app/redux/discovery') const mockNavigate = vi.fn() diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx index 34fbcaa9baf..2a1a15d651d 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/AttachProbe.test.tsx @@ -11,7 +11,7 @@ import { mock96ChannelAttachedPipetteInformation, mockAttachedPipetteInformation, } from '/app/redux/pipettes/__fixtures__' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { FLOWS } from '../constants' import { AttachProbe } from '../AttachProbe' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/BeforeBeginning.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/BeforeBeginning.test.tsx index 1413a8a603a..72932f4c1ed 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/BeforeBeginning.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/BeforeBeginning.test.tsx @@ -14,7 +14,7 @@ import { i18n } from '/app/i18n' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' import { InProgressModal } from '/app/molecules/InProgressModal/InProgressModal' // import { NeedHelpLink } from '../../CalibrationPanels' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { BeforeBeginning } from '../BeforeBeginning' import { FLOWS } from '../constants' import { getIsGantryEmpty } from '../utils' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/Carriage.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/Carriage.test.tsx index e55b41a87ad..b4b8960ae59 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/Carriage.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/Carriage.test.tsx @@ -7,7 +7,7 @@ import { LEFT, NINETY_SIX_CHANNEL } from '@opentrons/shared-data' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { FLOWS } from '../constants' import { Carriage } from '../Carriage' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/DetachPipette.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/DetachPipette.test.tsx index b71a23b2d90..9e30b7c2bf4 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/DetachPipette.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/DetachPipette.test.tsx @@ -15,7 +15,7 @@ import { mockAttachedPipetteInformation, } from '/app/redux/pipettes/__fixtures__' import { InProgressModal } from '/app/molecules/InProgressModal/InProgressModal' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { FLOWS } from '../constants' import { DetachPipette } from '../DetachPipette' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/DetachProbe.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/DetachProbe.test.tsx index 57817b3e4c9..e6d3262c76f 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/DetachProbe.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/DetachProbe.test.tsx @@ -8,7 +8,7 @@ import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' import { InProgressModal } from '/app/molecules/InProgressModal/InProgressModal' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { FLOWS } from '../constants' import { DetachProbe } from '../DetachProbe' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/MountPipette.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/MountPipette.test.tsx index 996264589c9..aa7d50f534c 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/MountPipette.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/MountPipette.test.tsx @@ -11,7 +11,7 @@ import { import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { FLOWS } from '../constants' import { CheckPipetteButton } from '../CheckPipetteButton' import { MountPipette } from '../MountPipette' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/MountingPlate.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/MountingPlate.test.tsx index 201492533a7..b4d91966dbb 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/MountingPlate.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/MountingPlate.test.tsx @@ -6,7 +6,7 @@ import { LEFT, NINETY_SIX_CHANNEL } from '@opentrons/shared-data' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { FLOWS } from '../constants' import { MountingPlate } from '../MountingPlate' diff --git a/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx b/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx index 41f918bf08e..e2d93c7e4f2 100644 --- a/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx +++ b/app/src/organisms/PipetteWizardFlows/__tests__/Results.test.tsx @@ -14,7 +14,7 @@ import { renderWithProviders } from '/app/__testing-utils__' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' import { useIsOEMMode } from '/app/resources/robot-settings/hooks' import { i18n } from '/app/i18n' -import { RUN_ID_1 } from '../../RunTimeControl/__fixtures__' +import { RUN_ID_1 } from '/app/resources/runs/__fixtures__' import { Results } from '../Results' import { FLOWS } from '../constants' diff --git a/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx b/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx index 4c180b59f88..3a9ae7e5db8 100644 --- a/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx +++ b/app/src/organisms/ProtocolDetails/ProtocolLabwareDetails.tsx @@ -20,11 +20,11 @@ import { } from '@opentrons/components' import { getLabwareDefURI } from '@opentrons/shared-data' import { Divider } from '/app/atoms/structure' -import { getTopPortalEl } from '../../App/portal' -import { LabwareDetails } from '../LabwareDetails' +import { getTopPortalEl } from '/app/App/portal' +import { LabwareDetails } from '../Desktop/Labware/LabwareDetails' import type { LoadLabwareRunTimeCommand } from '@opentrons/shared-data' -import type { LabwareDefAndDate } from '/app/pages/Desktop/Labware/hooks' +import type { LabwareDefAndDate } from '/app/local-resources/labware' interface ProtocolLabwareDetailsProps { requiredLabwareDetails: LoadLabwareRunTimeCommand[] | null diff --git a/app/src/organisms/ProtocolDetails/index.tsx b/app/src/organisms/ProtocolDetails/index.tsx index e4a27365e37..5df7bd33e4a 100644 --- a/app/src/organisms/ProtocolDetails/index.tsx +++ b/app/src/organisms/ProtocolDetails/index.tsx @@ -19,21 +19,22 @@ import { DIRECTION_COLUMN, DIRECTION_ROW, DISPLAY_FLEX, + DISPLAY_GRID, Flex, Icon, JUSTIFY_CENTER, JUSTIFY_SPACE_BETWEEN, + LegacyStyledText, Link, + Modal, OVERFLOW_WRAP_ANYWHERE, POSITION_RELATIVE, PrimaryButton, ProtocolDeck, - Tabs, SIZE_1, SIZE_5, - Modal, SPACING, - LegacyStyledText, + Tabs, TYPOGRAPHY, } from '@opentrons/components' import { @@ -81,13 +82,13 @@ import type { StoredProtocolData } from '/app/redux/protocol-storage' import type { State, Dispatch } from '/app/redux/types' const GRID_STYLE = css` - display: grid; + display: ${DISPLAY_GRID}; width: 100%; grid-template-columns: 26.6% 26.6% 26.6% 20.2%; ` const TWO_COL_GRID_STYLE = css` - display: grid; + display: ${DISPLAY_GRID}; grid-gap: ${SPACING.spacing24}; grid-template-columns: 22.5% 77.5%; ` @@ -503,7 +504,7 @@ export function ProtocolDetails( diff --git a/app/src/organisms/ProtocolUpload/hooks/index.ts b/app/src/organisms/ProtocolUpload/hooks/index.ts deleted file mode 100644 index c53b3d97ce0..00000000000 --- a/app/src/organisms/ProtocolUpload/hooks/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './useCloseCurrentRun' -export * from './useCurrentProtocol' -export * from './useCurrentRun' -export * from './useCurrentRunCommands' -export * from './useCloneRun' -export * from './useRestartRun' -export * from './useRunCommands' diff --git a/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx b/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx index bdc89e6a79d..5cb809fd041 100644 --- a/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx +++ b/app/src/organisms/QuickTransferFlow/SelectDestLabware.tsx @@ -17,7 +17,7 @@ import { getCompatibleLabwareByCategory } from './utils' import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { SmallButton } from '/app/atoms/buttons' -import type { LabwareFilter } from '/app/pages/Desktop/Labware/types' +import type { LabwareFilter } from '/app/local-resources/labware' import type { QuickTransferWizardState, QuickTransferWizardAction, diff --git a/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx b/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx index 7f6fd371c14..7807fe46b89 100644 --- a/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx +++ b/app/src/organisms/QuickTransferFlow/SelectSourceLabware.tsx @@ -17,7 +17,7 @@ import { getCompatibleLabwareByCategory } from './utils' import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { SmallButton } from '/app/atoms/buttons' -import type { LabwareFilter } from '/app/pages/Desktop/Labware/types' +import type { LabwareFilter } from '/app/local-resources/labware' import type { QuickTransferWizardState, QuickTransferWizardAction, diff --git a/app/src/organisms/QuickTransferFlow/utils/generateCompatibleLabwareForPipette.ts b/app/src/organisms/QuickTransferFlow/utils/generateCompatibleLabwareForPipette.ts index 64a9bf84e1e..29e0847bf02 100644 --- a/app/src/organisms/QuickTransferFlow/utils/generateCompatibleLabwareForPipette.ts +++ b/app/src/organisms/QuickTransferFlow/utils/generateCompatibleLabwareForPipette.ts @@ -1,5 +1,5 @@ import { makeWellSetHelpers, getLabwareDefURI } from '@opentrons/shared-data' -import { getAllDefinitions as getAllLatestDefValues } from '/app/pages/Desktop/Labware/helpers/definitions' +import { getAllDefinitions as getAllLatestDefValues } from '/app/local-resources/labware' import type { PipetteV2Specs, WellSetHelpers } from '@opentrons/shared-data' diff --git a/app/src/organisms/QuickTransferFlow/utils/getCompatibleLabwareByCategory.ts b/app/src/organisms/QuickTransferFlow/utils/getCompatibleLabwareByCategory.ts index 84321eaf944..cb52a095a33 100644 --- a/app/src/organisms/QuickTransferFlow/utils/getCompatibleLabwareByCategory.ts +++ b/app/src/organisms/QuickTransferFlow/utils/getCompatibleLabwareByCategory.ts @@ -6,7 +6,7 @@ import { } from '../constants' import type { LabwareDefinition2 } from '@opentrons/shared-data' -import type { LabwareFilter } from '/app/pages/Desktop/Labware/types' +import type { LabwareFilter } from '/app/local-resources/labware' export function getCompatibleLabwareByCategory( pipetteChannels: 1 | 8 | 96, diff --git a/app/src/organisms/RobotSettingsCalibration/CalibrationDataDownload.tsx b/app/src/organisms/RobotSettingsCalibration/CalibrationDataDownload.tsx index e8f0e9b9d88..5aae1a1425f 100644 --- a/app/src/organisms/RobotSettingsCalibration/CalibrationDataDownload.tsx +++ b/app/src/organisms/RobotSettingsCalibration/CalibrationDataDownload.tsx @@ -20,15 +20,14 @@ import { import { TertiaryButton } from '/app/atoms/buttons' import { useDeckCalibrationData, - useIsFlex, usePipetteOffsetCalibrations, - useRobot, useTipLengthCalibrations, } from '/app/organisms/Devices/hooks' import { useTrackEvent, ANALYTICS_CALIBRATION_DATA_DOWNLOADED, } from '/app/redux/analytics' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' // TODO(bc, 2022-02-08): replace with support article when available diff --git a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/ModuleCalibrationOverflowMenu.tsx b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/ModuleCalibrationOverflowMenu.tsx index c5bddca39c5..79aa70395ef 100644 --- a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/ModuleCalibrationOverflowMenu.tsx +++ b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/ModuleCalibrationOverflowMenu.tsx @@ -18,10 +18,10 @@ import { } from '@opentrons/components' import { useChainLiveCommands } from '/app/resources/runs' -import { useRunStatuses } from '../../Devices/hooks' -import { getModulePrepCommands } from '../../Devices/getModulePrepCommands' -import { ModuleWizardFlows } from '../../ModuleWizardFlows' -import { getModuleTooHot } from '../../Devices/getModuleTooHot' +import { useRunStatuses } from '/app/organisms/Devices/hooks' +import { getModulePrepCommands } from '/app/organisms/Devices/getModulePrepCommands' +import { ModuleWizardFlows } from '/app/organisms/ModuleWizardFlows' +import { getModuleTooHot } from '/app/organisms/Devices/getModuleTooHot' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' import type { AttachedModule } from '/app/redux/modules/types' diff --git a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/PipetteOffsetCalibrationItems.tsx b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/PipetteOffsetCalibrationItems.tsx index 39b28861876..f6bba1f6921 100644 --- a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/PipetteOffsetCalibrationItems.tsx +++ b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/PipetteOffsetCalibrationItems.tsx @@ -19,9 +19,9 @@ import { getCustomLabwareDefinitions } from '/app/redux/custom-labware' import { LEFT } from '/app/redux/pipettes' import { useAttachedPipettes, - useIsFlex, useAttachedPipettesFromInstrumentsQuery, } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import type { State } from '/app/redux/types' import type { FormattedPipetteOffsetCalibration } from '..' diff --git a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/ModuleCalibrationOverflowMenu.test.tsx b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/ModuleCalibrationOverflowMenu.test.tsx index d6473115675..bf37956c884 100644 --- a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/ModuleCalibrationOverflowMenu.test.tsx +++ b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/ModuleCalibrationOverflowMenu.test.tsx @@ -4,19 +4,19 @@ import { when } from 'vitest-when' import { describe, it, expect, vi, beforeEach } from 'vitest' import { i18n } from '/app/i18n' import { renderWithProviders } from '/app/__testing-utils__' -import { ModuleWizardFlows } from '../../../ModuleWizardFlows' +import { ModuleWizardFlows } from '/app/organisms/ModuleWizardFlows' import { useChainLiveCommands } from '/app/resources/runs' import { mockThermocyclerGen2 } from '/app/redux/modules/__fixtures__' -import { useRunStatuses } from '../../../Devices/hooks' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' +import { useRunStatuses } from '/app/organisms/Devices/hooks' import { ModuleCalibrationOverflowMenu } from '../ModuleCalibrationOverflowMenu' import type { Mount } from '@opentrons/components' vi.mock('@opentrons/react-api-client') -vi.mock('../../../ModuleWizardFlows') -vi.mock('../../../Devices/hooks') +vi.mock('/app/organisms/ModuleWizardFlows') +vi.mock('/app/organisms/Devices/hooks') vi.mock('/app/resources/runs') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') diff --git a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/PipetteOffsetCalibrationItems.test.tsx b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/PipetteOffsetCalibrationItems.test.tsx index d4025443a86..57e528d1554 100644 --- a/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/PipetteOffsetCalibrationItems.test.tsx +++ b/app/src/organisms/RobotSettingsCalibration/CalibrationDetails/__tests__/PipetteOffsetCalibrationItems.test.tsx @@ -11,9 +11,9 @@ import { } from '/app/redux/pipettes/__fixtures__' import { useAttachedPipettes, - useIsFlex, useAttachedPipettesFromInstrumentsQuery, -} from '../../../Devices/hooks' +} from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { renderWithProviders } from '/app/__testing-utils__' import { PipetteOffsetCalibrationItems } from '../PipetteOffsetCalibrationItems' import { OverflowMenu } from '../OverflowMenu' @@ -63,6 +63,7 @@ vi.mock('/app/redux/sessions/selectors') vi.mock('/app/redux/discovery') vi.mock('/app/assets/labware/findLabware') vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../OverflowMenu') const mockAttachedPipettes: AttachedPipettesByMount = { diff --git a/app/src/organisms/RobotSettingsCalibration/RobotSettingsDeckCalibration.tsx b/app/src/organisms/RobotSettingsCalibration/RobotSettingsDeckCalibration.tsx index ca14e8db3d1..6b48db62339 100644 --- a/app/src/organisms/RobotSettingsCalibration/RobotSettingsDeckCalibration.tsx +++ b/app/src/organisms/RobotSettingsCalibration/RobotSettingsDeckCalibration.tsx @@ -12,7 +12,8 @@ import { } from '@opentrons/components' import { formatLastModified } from '/app/organisms/CalibrationPanels/utils' -import { useDeckCalibrationData, useRobot } from '/app/organisms/Devices/hooks' +import { useDeckCalibrationData } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import * as RobotApi from '/app/redux/robot-api' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/RobotSettingsCalibration/RobotSettingsPipetteOffsetCalibration.tsx b/app/src/organisms/RobotSettingsCalibration/RobotSettingsPipetteOffsetCalibration.tsx index b59b6be3d03..78a9ee9db51 100644 --- a/app/src/organisms/RobotSettingsCalibration/RobotSettingsPipetteOffsetCalibration.tsx +++ b/app/src/organisms/RobotSettingsCalibration/RobotSettingsPipetteOffsetCalibration.tsx @@ -12,9 +12,9 @@ import { useInstrumentsQuery } from '@opentrons/react-api-client' import { useAttachedPipettesFromInstrumentsQuery, - useIsFlex, usePipetteOffsetCalibrations, } from '../Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { getShowPipetteCalibrationWarning } from '../Devices/utils' import { PipetteRecalibrationWarning } from '../Devices/PipetteCard/PipetteRecalibrationWarning' import { PipetteOffsetCalibrationItems } from './CalibrationDetails/PipetteOffsetCalibrationItems' diff --git a/app/src/organisms/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx b/app/src/organisms/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx index a7ba764f7f0..cb5a764bc53 100644 --- a/app/src/organisms/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx +++ b/app/src/organisms/RobotSettingsCalibration/__tests__/CalibrationDataDownload.test.tsx @@ -37,11 +37,10 @@ import { import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' import { useDeckCalibrationData, - useIsFlex, usePipetteOffsetCalibrations, - useRobot, useTipLengthCalibrations, } from '/app/organisms/Devices/hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { renderWithProviders } from '/app/__testing-utils__' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' import { CalibrationDataDownload } from '../CalibrationDataDownload' @@ -57,6 +56,7 @@ vi.mock('file-saver', async importOriginal => { vi.mock('@opentrons/react-api-client') vi.mock('/app/redux/analytics') vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/resources/devices/hooks/useIsEstopNotDisengaged') let mockTrackEvent: any diff --git a/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsCalibration.test.tsx b/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsCalibration.test.tsx index 4fa99a7f68d..03ca54a3d48 100644 --- a/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsCalibration.test.tsx +++ b/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsCalibration.test.tsx @@ -20,13 +20,12 @@ import { mockAttachedPipetteInformation, } from '/app/redux/pipettes/__fixtures__' import { - useIsFlex, usePipetteOffsetCalibrations, - useRobot, useAttachedPipettes, useRunStatuses, useAttachedPipettesFromInstrumentsQuery, } from '/app/organisms/Devices/hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { CalibrationDataDownload } from '../CalibrationDataDownload' import { CalibrationHealthCheck } from '../CalibrationHealthCheck' @@ -50,6 +49,7 @@ vi.mock('/app/organisms/CalibrationStatusCard') vi.mock('/app/redux/config') vi.mock('/app/redux/sessions/selectors') vi.mock('/app/redux/robot-api/selectors') +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/Devices/hooks') vi.mock('../CalibrationDataDownload') vi.mock('../CalibrationHealthCheck') diff --git a/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsDeckCalibration.test.tsx b/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsDeckCalibration.test.tsx index bee9866267f..7f0c90b02a0 100644 --- a/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsDeckCalibration.test.tsx +++ b/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsDeckCalibration.test.tsx @@ -12,9 +12,9 @@ import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' import { mockAttachedPipette } from '/app/redux/pipettes/__fixtures__' import { useDeckCalibrationData, - useRobot, useAttachedPipettes, } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { renderWithProviders } from '/app/__testing-utils__' import { RobotSettingsDeckCalibration } from '../RobotSettingsDeckCalibration' @@ -23,6 +23,7 @@ import type { AttachedPipettesByMount } from '/app/redux/pipettes/types' vi.mock('/app/organisms/CalibrationStatusCard') vi.mock('/app/redux/robot-api/selectors') +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/Devices/hooks') const mockAttachedPipettes: AttachedPipettesByMount = { diff --git a/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsPipetteOffsetCalibration.test.tsx b/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsPipetteOffsetCalibration.test.tsx index db842e179fe..5c88977ca7c 100644 --- a/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsPipetteOffsetCalibration.test.tsx +++ b/app/src/organisms/RobotSettingsCalibration/__tests__/RobotSettingsPipetteOffsetCalibration.test.tsx @@ -10,12 +10,12 @@ import { mockPipetteOffsetCalibration3, } from '/app/redux/calibration/pipette-offset/__fixtures__' import { - useIsFlex, usePipetteOffsetCalibrations, useAttachedPipettesFromInstrumentsQuery, } from '/app/organisms/Devices/hooks' import { renderWithProviders } from '/app/__testing-utils__' import { mockAttachedPipetteInformation } from '/app/redux/pipettes/__fixtures__' +import { useIsFlex } from '/app/redux-resources/robots' import { RobotSettingsPipetteOffsetCalibration } from '../RobotSettingsPipetteOffsetCalibration' import { PipetteOffsetCalibrationItems } from '../CalibrationDetails/PipetteOffsetCalibrationItems' @@ -23,6 +23,7 @@ import { PipetteOffsetCalibrationItems } from '../CalibrationDetails/PipetteOffs import type { FormattedPipetteOffsetCalibration } from '..' vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../CalibrationDetails/PipetteOffsetCalibrationItems') const mockFormattedPipetteOffsetCalibrations: FormattedPipetteOffsetCalibration[] = [] diff --git a/app/src/organisms/RobotSettingsCalibration/index.tsx b/app/src/organisms/RobotSettingsCalibration/index.tsx index 8276d107f74..22bff478880 100644 --- a/app/src/organisms/RobotSettingsCalibration/index.tsx +++ b/app/src/organisms/RobotSettingsCalibration/index.tsx @@ -22,11 +22,10 @@ import { CalibrateDeck } from '/app/organisms/CalibrateDeck' import { CalibrationStatusCard } from '/app/organisms/CalibrationStatusCard' import { CheckCalibration } from '/app/organisms/CheckCalibration' import { - useRobot, useRunStatuses, - useIsFlex, useAttachedPipettesFromInstrumentsQuery, } from '/app/organisms/Devices/hooks' +import { useRobot, useIsFlex } from '/app/redux-resources/robots' import { HowCalibrationWorksModal } from '/app/organisms/HowCalibrationWorksModal' import { CONNECTABLE } from '/app/redux/discovery' import * as RobotApi from '/app/redux/robot-api' diff --git a/app/src/organisms/RunPreview/index.tsx b/app/src/organisms/RunPreview/index.tsx index 8ab0704014a..6cb9b50e052 100644 --- a/app/src/organisms/RunPreview/index.tsx +++ b/app/src/organisms/RunPreview/index.tsx @@ -25,11 +25,11 @@ import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostR import { useNotifyAllCommandsAsPreSerializedList, useNotifyRunQuery, + useRunStatus, } from '/app/resources/runs' import { CommandText, CommandIcon } from '/app/molecules/Command' import { Divider } from '/app/atoms/structure' import { NAV_BAR_WIDTH } from '../../App/constants' -import { useRunStatus } from '../RunTimeControl/hooks' import { useLastRunCommand } from '../Devices/hooks/useLastRunCommand' import type { RunStatus } from '@opentrons/api-client' diff --git a/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx b/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx index f00d0d0896f..143a1f3afb4 100644 --- a/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx +++ b/app/src/organisms/RunProgressMeter/__tests__/RunProgressMeter.test.tsx @@ -18,11 +18,12 @@ import { InterventionModal, } from '../../InterventionModal' import { ProgressBar } from '/app/atoms/ProgressBar' -import { useRunControls, useRunStatus } from '../../RunTimeControl/hooks' +import { useRunControls } from '../../RunTimeControl/hooks' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useNotifyRunQuery, useNotifyAllCommandsQuery, + useRunStatus, } from '/app/resources/runs' import { useDownloadRunLog } from '../../Devices/hooks' import { @@ -54,6 +55,7 @@ vi.mock('/app/atoms/ProgressBar') vi.mock('../../InterventionModal') vi.mock('../../Devices/hooks/useLastRunCommand') vi.mock('/app/resources/protocols/hooks') +vi.mock('/app/redux-resources/robots') const render = (props: React.ComponentProps) => { return renderWithProviders(, { diff --git a/app/src/organisms/RunProgressMeter/index.tsx b/app/src/organisms/RunProgressMeter/index.tsx index 6bc2d1510c3..cd5ca1c3b24 100644 --- a/app/src/organisms/RunProgressMeter/index.tsx +++ b/app/src/organisms/RunProgressMeter/index.tsx @@ -31,15 +31,17 @@ import { import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { getModalPortalEl } from '../../App/portal' -import { useRunControls, useRunStatus } from '../RunTimeControl/hooks' +import { useRunControls } from '../RunTimeControl/hooks' import { InterventionModal, useInterventionModal } from '../InterventionModal' import { ProgressBar } from '/app/atoms/ProgressBar' -import { useDownloadRunLog, useRobotType } from '../Devices/hooks' +import { useDownloadRunLog } from '../Devices/hooks' import { InterventionTicks } from './InterventionTicks' import { useNotifyRunQuery, useNotifyAllCommandsQuery, + useRunStatus, } from '/app/resources/runs' +import { useRobotType } from '/app/redux-resources/robots' import { useRunningStepCounts } from '/app/resources/protocols/hooks' import { useRunProgressCopy } from './hooks' diff --git a/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx b/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx index 8e37eb70ab0..7450fb34e4e 100644 --- a/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx +++ b/app/src/organisms/RunTimeControl/__tests__/hooks.test.tsx @@ -4,27 +4,19 @@ import { describe, it, expect, vi, beforeEach } from 'vitest' import '@testing-library/jest-dom/vitest' import { useRunActionMutations } from '@opentrons/react-api-client' -import { useCloneRun, useRunCommands } from '../../ProtocolUpload/hooks' +import { useRunControls, useCurrentRunStatus, useRunErrors } from '../hooks' import { - useRunControls, + useNotifyRunQuery, + useCurrentRunId, useRunStatus, - useCurrentRunStatus, - useRunTimestamps, - useRunErrors, -} from '../hooks' -import { useNotifyRunQuery, useCurrentRunId } from '/app/resources/runs' + useCloneRun, +} from '/app/resources/runs' import { RUN_ID_2, mockPausedRun, mockRunningRun, - mockFailedRun, - mockStoppedRun, - mockSucceededRun, - mockIdleUnstartedRun, - mockIdleStartedRun, - mockCommand, -} from '../__fixtures__' +} from '/app/resources/runs/__fixtures__' import type { UseQueryResult } from 'react-query' import type { Run } from '@opentrons/api-client' @@ -38,7 +30,7 @@ vi.mock('@opentrons/react-api-client', async importOriginal => { } }) -vi.mock('../../ProtocolUpload/hooks') +vi.mock('/app/resources/protocols') vi.mock('/app/resources/runs') describe('useRunControls hook', () => { @@ -78,176 +70,18 @@ describe('useRunControls hook', () => { }) }) -describe('useRunStatus hook', () => { - it('returns the run status of the run', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockRunningRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunStatus(RUN_ID_2)) - expect(result.current).toBe('running') - }) - - it('returns a "idle" run status if idle and run unstarted', () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockIdleUnstartedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunStatus(RUN_ID_2)) - expect(result.current).toBe('idle') - }) - - it('returns a "running" run status if idle and run started', () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockIdleStartedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunStatus(RUN_ID_2)) - expect(result.current).toBe('running') - }) -}) - describe('useCurrentRunStatus hook', () => { beforeEach(() => { when(useCurrentRunId).calledWith().thenReturn(RUN_ID_2) }) it('returns the run status of the current run', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockRunningRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(useCurrentRunStatus) - expect(result.current).toBe('running') - }) - - it('returns a "idle" run status if idle and run unstarted', () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockIdleUnstartedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(useCurrentRunStatus) - expect(result.current).toBe('idle') - }) - - it('returns a "running" run status if idle and run started', () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockIdleStartedRun }, - } as unknown) as UseQueryResult) - + when(useRunStatus).calledWith(RUN_ID_2).thenReturn('running') const { result } = renderHook(useCurrentRunStatus) expect(result.current).toBe('running') }) }) -describe('useRunTimestamps hook', () => { - beforeEach(() => { - when(useRunCommands) - .calledWith(RUN_ID_2, { cursor: null, pageLength: 1 }, expect.any(Object)) - .thenReturn([mockCommand.data as any]) - }) - - it('returns the start time of the current run', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockRunningRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.startedAt).toBe('2021-10-25T12:54:53.366581+00:00') - }) - - it('returns null when pause is not the last action', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockRunningRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.pausedAt).toBe(null) - }) - - it('returns the pause time of the current run when pause is the last action', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockPausedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.pausedAt).toBe('2021-10-25T13:23:31.366581+00:00') - }) - - it('returns stopped time null when stop is not the last action', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockRunningRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.stoppedAt).toBe(null) - }) - - it('returns the stop time of the current run when stop is the last action', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockStoppedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.stoppedAt).toBe('2021-10-25T13:58:22.366581+00:00') - }) - - it('returns the complete time of a successful current run', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockSucceededRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.completedAt).toBe('noon thirty') - }) - - it('returns the complete time of a failed current run', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockFailedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.completedAt).toBe('noon forty-five') - }) - - it('returns the complete time of a stopped current run', async () => { - when(useNotifyRunQuery) - .calledWith(RUN_ID_2, expect.any(Object)) - .thenReturn(({ - data: { data: mockStoppedRun }, - } as unknown) as UseQueryResult) - - const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) - expect(result.current.completedAt).toBe('2021-10-25T13:58:22.366581+00:00') - }) -}) - describe('useRunErrors hook', () => { it('returns errors if present', async () => { const fixtureErrors = [ diff --git a/app/src/organisms/RunTimeControl/hooks.ts b/app/src/organisms/RunTimeControl/hooks.ts index 050a9058c84..5e519baa2b0 100644 --- a/app/src/organisms/RunTimeControl/hooks.ts +++ b/app/src/organisms/RunTimeControl/hooks.ts @@ -1,27 +1,16 @@ -import last from 'lodash/last' -import * as React from 'react' - -import { - RUN_ACTION_TYPE_PLAY, - RUN_ACTION_TYPE_PAUSE, - RUN_STATUS_IDLE, - RUN_STATUS_RUNNING, - RUN_STATUS_STOPPED, - RUN_STATUS_FAILED, - RUN_STATUS_FINISHING, - RUN_STATUS_SUCCEEDED, - RUN_ACTION_TYPE_STOP, - RUN_STATUS_STOP_REQUESTED, - RUN_STATUSES_TERMINAL, -} from '@opentrons/api-client' import { useRunActionMutations } from '@opentrons/react-api-client' -import { useCloneRun, useRunCommands } from '../ProtocolUpload/hooks' -import { useNotifyRunQuery, useCurrentRunId } from '/app/resources/runs' +import { + useNotifyRunQuery, + useCurrentRunId, + useRunStatus, + useCloneRun, + DEFAULT_RUN_QUERY_REFETCH_INTERVAL, +} from '/app/resources/runs' import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostRecentCompletedAnalysis' import type { UseQueryOptions } from 'react-query' -import type { RunAction, RunStatus, Run, RunData } from '@opentrons/api-client' +import type { RunStatus, Run, RunData } from '@opentrons/api-client' export interface RunControls { play: () => void @@ -73,42 +62,6 @@ export function useRunControls( } } -const DEFAULT_STATUS_REFETCH_INTERVAL = 10000 // 10 seconds -export function useRunStatus( - runId: string | null, - options?: UseQueryOptions -): RunStatus | null { - const lastRunStatus = React.useRef(null) - - const { data } = useNotifyRunQuery(runId ?? null, { - refetchInterval: DEFAULT_STATUS_REFETCH_INTERVAL, - enabled: - lastRunStatus.current == null || - !(RUN_STATUSES_TERMINAL as RunStatus[]).includes(lastRunStatus.current), - onSuccess: data => (lastRunStatus.current = data?.data?.status ?? null), - ...options, - }) - - const runStatus = data?.data?.status as RunStatus - - const actions = data?.data?.actions as RunAction[] - const firstPlay = actions?.find( - action => action.actionType === RUN_ACTION_TYPE_PLAY - ) - const runStartTime = firstPlay?.createdAt - - // display an idle status as 'running' in the UI after a run has started. - // todo(mm, 2024-06-24): This may not be necessary anymore. It looks like it was - // working around prior (?) server behavior where a run's status would briefly flicker - // to idle in between commands. - const adjustedRunStatus: RunStatus | null = - runStatus === RUN_STATUS_IDLE && runStartTime != null - ? RUN_STATUS_RUNNING - : runStatus - - return adjustedRunStatus -} - export function useCurrentRunStatus( options?: UseQueryOptions ): RunStatus | null { @@ -117,71 +70,6 @@ export function useCurrentRunStatus( return useRunStatus(currentRunId, options) } -export interface RunTimestamps { - startedAt: string | null - pausedAt: string | null - stoppedAt: string | null - completedAt: string | null -} - -const DEFAULT_RUN_QUERY_REFETCH_INTERVAL = 5000 -export function useRunTimestamps(runId: string | null): RunTimestamps { - const runStatus = useRunStatus(runId) - const { actions = [], errors = [] } = - useNotifyRunQuery(runId, { - refetchInterval: DEFAULT_RUN_QUERY_REFETCH_INTERVAL, - })?.data?.data ?? {} - const runCommands = - useRunCommands( - runId, - { cursor: null, pageLength: 1 }, - { - enabled: - runStatus === RUN_STATUS_SUCCEEDED || - runStatus === RUN_STATUS_STOPPED || - runStatus === RUN_STATUS_FAILED || - runStatus === RUN_STATUS_STOP_REQUESTED || - runStatus === RUN_STATUS_FINISHING, - refetchInterval: false, - } - ) ?? [] - - const firstPlay = actions.find( - action => action.actionType === RUN_ACTION_TYPE_PLAY - ) - const lastAction = last(actions) - - const lastCommand = last(runCommands) - const lastActionAt = lastAction?.createdAt ?? null - const lastErrorAt = last(errors)?.createdAt - const lastCommandAt = lastCommand?.completedAt - - const startedAt = firstPlay?.createdAt ?? null - const pausedAt = - lastAction?.actionType === RUN_ACTION_TYPE_PAUSE ? lastActionAt : null - const stoppedAt = - lastAction?.actionType === RUN_ACTION_TYPE_STOP ? lastActionAt : null - let completedAt = null - switch (runStatus) { - case RUN_STATUS_STOPPED: - completedAt = lastActionAt ?? null - break - case RUN_STATUS_FAILED: - completedAt = lastErrorAt ?? null - break - case RUN_STATUS_SUCCEEDED: - completedAt = lastCommandAt ?? null - break - } - - return { - startedAt, - pausedAt, - stoppedAt, - completedAt, - } -} - export function useRunErrors(runId: string | null): RunData['errors'] { const { data: runRecord } = useNotifyRunQuery(runId, { refetchInterval: DEFAULT_RUN_QUERY_REFETCH_INTERVAL, diff --git a/app/src/pages/Desktop/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx b/app/src/pages/Desktop/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx index 767ba94d4af..c8e4935bf21 100644 --- a/app/src/pages/Desktop/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx +++ b/app/src/pages/Desktop/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx @@ -18,6 +18,7 @@ import { expectedTaskList } from '/app/organisms/Devices/hooks/__fixtures__/task import { mockLeftProtoPipette } from '/app/redux/pipettes/__fixtures__' import { useNotifyAllRunsQuery } from '/app/resources/runs' +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/Devices/hooks') vi.mock('../hooks/useDashboardCalibratePipOffset') vi.mock('../hooks/useDashboardCalibrateTipLength') diff --git a/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateDeck.tsx b/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateDeck.tsx index faf8111bf0d..9ce182dd812 100644 --- a/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateDeck.tsx +++ b/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateDeck.tsx @@ -13,6 +13,7 @@ import * as Sessions from '/app/redux/sessions' import { getDeckCalibrationSession } from '/app/redux/sessions/deck-calibration/selectors' import type { State } from '/app/redux/types' +import type { DashboardCalDeckInvoker } from '/app/organisms/Devices/hooks/useCalibrationTaskList' import type { DeckCalibrationSession } from '/app/redux/sessions' import type { SessionCommandString } from '/app/redux/sessions/types' import type { RequestState } from '/app/redux/robot-api/types' @@ -21,12 +22,6 @@ import type { RequestState } from '/app/redux/robot-api/types' const spinnerCommandBlockList: SessionCommandString[] = [ Sessions.sharedCalCommands.JOG, ] -export interface DashboardCalDeckInvokerProps { - invalidateHandler?: () => void -} -export type DashboardCalDeckInvoker = ( - props?: DashboardCalDeckInvokerProps -) => void export function useDashboardCalibrateDeck( robotName: string diff --git a/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset.tsx b/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset.tsx index 7719f46c3e1..b78a616f6cc 100644 --- a/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset.tsx +++ b/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibratePipOffset.tsx @@ -12,12 +12,11 @@ import * as RobotApi from '/app/redux/robot-api' import * as Sessions from '/app/redux/sessions' import { getPipetteOffsetCalibrationSession } from '/app/redux/sessions/pipette-offset-calibration/selectors' import { pipetteOffsetCalibrationStarted } from '/app/redux/analytics' - +import type { DashboardCalOffsetInvoker } from '/app/organisms/Devices/hooks/useCalibrationTaskList' import type { State } from '/app/redux/types' import type { SessionCommandString, PipetteOffsetCalibrationSession, - PipetteOffsetCalibrationSessionParams, } from '/app/redux/sessions/types' import type { RequestState } from '/app/redux/robot-api/types' @@ -26,15 +25,6 @@ const spinnerCommandBlockList: SessionCommandString[] = [ Sessions.sharedCalCommands.JOG, ] -export interface DashboardOffsetCalInvokerProps { - params: Pick & - Partial> -} - -export type DashboardCalOffsetInvoker = ( - props: DashboardOffsetCalInvokerProps -) => void - export function useDashboardCalibratePipOffset( robotName: string, onComplete: (() => unknown) | null = null diff --git a/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateTipLength.tsx b/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateTipLength.tsx index 03c93e9bfcc..d8da4848f5f 100644 --- a/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateTipLength.tsx +++ b/app/src/pages/Desktop/Devices/CalibrationDashboard/hooks/useDashboardCalibrateTipLength.tsx @@ -22,23 +22,13 @@ import type { TipLengthCalibrationSessionParams, } from '/app/redux/sessions/types' import type { State } from '/app/redux/types' +import type { DashboardCalTipLengthInvoker } from '/app/organisms/Devices/hooks/useCalibrationTaskList' // tip length calibration commands for which the full page spinner should not appear const spinnerCommandBlockList: SessionCommandString[] = [ Sessions.sharedCalCommands.JOG, ] -export interface DashboardTipLengthCalInvokerProps { - params: Pick & - Partial> - hasBlockModalResponse: boolean | null - invalidateHandler?: () => void -} - -export type DashboardCalTipLengthInvoker = ( - props: DashboardTipLengthCalInvokerProps -) => void - export function useDashboardCalibrateTipLength( robotName: string ): [DashboardCalTipLengthInvoker, JSX.Element | null] { diff --git a/app/src/pages/Desktop/Devices/CalibrationDashboard/index.tsx b/app/src/pages/Desktop/Devices/CalibrationDashboard/index.tsx index 76edb05d0bd..2a29daa1fd4 100644 --- a/app/src/pages/Desktop/Devices/CalibrationDashboard/index.tsx +++ b/app/src/pages/Desktop/Devices/CalibrationDashboard/index.tsx @@ -7,7 +7,7 @@ import { appShellRequestor } from '/app/redux/shell/remote' import { useDashboardCalibrateDeck } from './hooks/useDashboardCalibrateDeck' import { useDashboardCalibratePipOffset } from './hooks/useDashboardCalibratePipOffset' import { useDashboardCalibrateTipLength } from './hooks/useDashboardCalibrateTipLength' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import type { DesktopRouteParams } from '../../../../App/types' diff --git a/app/src/pages/Desktop/Devices/DeviceDetails/DeviceDetailsComponent.tsx b/app/src/pages/Desktop/Devices/DeviceDetails/DeviceDetailsComponent.tsx index c100282c9ec..63ed9ca0991 100644 --- a/app/src/pages/Desktop/Devices/DeviceDetails/DeviceDetailsComponent.tsx +++ b/app/src/pages/Desktop/Devices/DeviceDetails/DeviceDetailsComponent.tsx @@ -16,7 +16,7 @@ import { InstrumentsAndModules } from '/app/organisms/Devices/InstrumentsAndModu import { RecentProtocolRuns } from '/app/organisms/Devices/RecentProtocolRuns' import { EstopBanner } from '/app/organisms/Devices/EstopBanner' import { DISENGAGED, useEstopContext } from '/app/organisms/EmergencyStop' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' interface DeviceDetailsComponentProps { robotName: string diff --git a/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx b/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx index d437e2757d5..4729c3d6b59 100644 --- a/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx +++ b/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx @@ -7,12 +7,13 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom' import { renderWithProviders } from '/app/__testing-utils__' import { i18n } from '/app/i18n' -import { useRobot, useSyncRobotClock } from '/app/organisms/Devices/hooks' +import { useSyncRobotClock } from '/app/organisms/Devices/hooks' import { InstrumentsAndModules } from '/app/organisms/Devices/InstrumentsAndModules' import { RecentProtocolRuns } from '/app/organisms/Devices/RecentProtocolRuns' import { RobotOverview } from '/app/organisms/Devices/RobotOverview' import { getScanning } from '/app/redux/discovery' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' +import { useRobot } from '/app/redux-resources/robots' import { DeviceDetails } from '..' import type { State } from '/app/redux/types' @@ -22,6 +23,7 @@ vi.mock('/app/organisms/Devices/InstrumentsAndModules') vi.mock('/app/organisms/Devices/RecentProtocolRuns') vi.mock('/app/organisms/Devices/RobotOverview') vi.mock('/app/redux/discovery') +vi.mock('/app/redux-resources/robots') const render = (path = '/') => { return renderWithProviders( diff --git a/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetailsComponent.test.tsx b/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetailsComponent.test.tsx index 42c0903e39a..a436cbe672a 100644 --- a/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetailsComponent.test.tsx +++ b/app/src/pages/Desktop/Devices/DeviceDetails/__tests__/DeviceDetailsComponent.test.tsx @@ -11,11 +11,11 @@ import { RecentProtocolRuns } from '/app/organisms/Devices/RecentProtocolRuns' import { RobotOverview } from '/app/organisms/Devices/RobotOverview' import { DISENGAGED, NOT_PRESENT } from '/app/organisms/EmergencyStop' import { DeviceDetailsDeckConfiguration } from '/app/organisms/DeviceDetailsDeckConfiguration' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { DeviceDetailsComponent } from '../DeviceDetailsComponent' vi.mock('@opentrons/react-api-client') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/Devices/InstrumentsAndModules') vi.mock('/app/organisms/Devices/RecentProtocolRuns') vi.mock('/app/organisms/Devices/RobotOverview') diff --git a/app/src/pages/Desktop/Devices/DeviceDetails/index.tsx b/app/src/pages/Desktop/Devices/DeviceDetails/index.tsx index 944f46f5dc7..1a261c43b41 100644 --- a/app/src/pages/Desktop/Devices/DeviceDetails/index.tsx +++ b/app/src/pages/Desktop/Devices/DeviceDetails/index.tsx @@ -4,10 +4,11 @@ import { Navigate, useParams } from 'react-router-dom' import { ApiHostProvider } from '@opentrons/react-api-client' -import { useRobot, useSyncRobotClock } from '/app/organisms/Devices/hooks' +import { useSyncRobotClock } from '/app/organisms/Devices/hooks' import { getScanning, OPENTRONS_USB } from '/app/redux/discovery' import { appShellRequestor } from '/app/redux/shell/remote' import { DeviceDetailsComponent } from './DeviceDetailsComponent' +import { useRobot } from '/app/redux-resources/robots' import type { DesktopRouteParams } from '../../../../App/types' diff --git a/app/src/pages/Desktop/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx b/app/src/pages/Desktop/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx index f66ba14c947..8c6e304cf42 100644 --- a/app/src/pages/Desktop/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx +++ b/app/src/pages/Desktop/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx @@ -9,7 +9,6 @@ import { i18n } from '/app/i18n' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' import { useModuleRenderInfoForProtocolById, - useRobot, useRunStatuses, useSyncRobotClock, useRunHasStarted, @@ -22,6 +21,7 @@ import { RunPreviewComponent } from '/app/organisms/RunPreview' import { ProtocolRunRuntimeParameters } from '/app/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters' import { useCurrentRunId } from '/app/resources/runs' import { mockRobotSideAnalysis } from '/app/molecules/Command/__fixtures__' +import { useRobot } from '/app/redux-resources/robots' import { ProtocolRunDetails } from '..' import type { ModuleModel, ModuleType } from '@opentrons/shared-data' @@ -35,6 +35,7 @@ vi.mock('/app/organisms/Devices/ProtocolRun/ProtocolRunModuleControls') vi.mock('/app/resources/runs') vi.mock('/app/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters') vi.mock('/app/redux/config') +vi.mock('/app/redux-resources/robots') const MOCK_MAGNETIC_MODULE_COORDS = [10, 20, 0] diff --git a/app/src/pages/Desktop/Devices/ProtocolRunDetails/index.tsx b/app/src/pages/Desktop/Devices/ProtocolRunDetails/index.tsx index ba1e4124ac5..ee7d82553d4 100644 --- a/app/src/pages/Desktop/Devices/ProtocolRunDetails/index.tsx +++ b/app/src/pages/Desktop/Devices/ProtocolRunDetails/index.tsx @@ -24,8 +24,6 @@ import { import { ApiHostProvider } from '@opentrons/react-api-client' import { useModuleRenderInfoForProtocolById, - useRobot, - useRobotType, useRunHasStarted, useRunStatuses, useSyncRobotClock, @@ -44,6 +42,7 @@ import { OPENTRONS_USB } from '/app/redux/discovery' import { fetchProtocols } from '/app/redux/protocol-storage' import { appShellRequestor } from '/app/redux/shell/remote' import { useMostRecentCompletedAnalysis } from '/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { useRobot, useRobotType } from '/app/redux-resources/robots' import type { ViewportListRef } from 'react-viewport-list' import type { diff --git a/app/src/pages/Desktop/Devices/RobotSettings/__tests__/RobotSettings.test.tsx b/app/src/pages/Desktop/Devices/RobotSettings/__tests__/RobotSettings.test.tsx index d10a7919dae..aa8343c1bd8 100644 --- a/app/src/pages/Desktop/Devices/RobotSettings/__tests__/RobotSettings.test.tsx +++ b/app/src/pages/Desktop/Devices/RobotSettings/__tests__/RobotSettings.test.tsx @@ -8,7 +8,7 @@ import { i18n } from '/app/i18n' import { RobotSettingsCalibration } from '/app/organisms/RobotSettingsCalibration' import { RobotSettingsNetworking } from '/app/organisms/Devices/RobotSettings/RobotSettingsNetworking' import { RobotSettingsAdvanced } from '/app/organisms/Devices/RobotSettings/RobotSettingsAdvanced' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { RobotSettings } from '..' import { when } from 'vitest-when' import { @@ -21,7 +21,7 @@ import { getRobotUpdateSession } from '/app/redux/robot-update' vi.mock('/app/organisms/RobotSettingsCalibration') vi.mock('/app/organisms/Devices/RobotSettings/RobotSettingsNetworking') vi.mock('/app/organisms/Devices/RobotSettings/RobotSettingsAdvanced') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/discovery/selectors') vi.mock('/app/redux/robot-update') diff --git a/app/src/pages/Desktop/Devices/RobotSettings/index.tsx b/app/src/pages/Desktop/Devices/RobotSettings/index.tsx index a02eb45a235..15f289764b4 100644 --- a/app/src/pages/Desktop/Devices/RobotSettings/index.tsx +++ b/app/src/pages/Desktop/Devices/RobotSettings/index.tsx @@ -26,7 +26,7 @@ import { appShellRequestor } from '/app/redux/shell/remote' import { getRobotUpdateSession } from '/app/redux/robot-update' import { getDevtoolsEnabled } from '/app/redux/config' import { Banner } from '/app/atoms/Banner' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { Line } from '/app/atoms/structure' import { NavTab } from '/app/molecules/NavTab' import { RobotSettingsCalibration } from '/app/organisms/RobotSettingsCalibration' diff --git a/app/src/pages/Desktop/Labware/__tests__/Labware.test.tsx b/app/src/pages/Desktop/Labware/__tests__/Labware.test.tsx index 1a4182966f4..b5133473704 100644 --- a/app/src/pages/Desktop/Labware/__tests__/Labware.test.tsx +++ b/app/src/pages/Desktop/Labware/__tests__/Labware.test.tsx @@ -8,18 +8,20 @@ import { useTrackEvent, ANALYTICS_OPEN_LABWARE_CREATOR_FROM_BOTTOM_OF_LABWARE_LIBRARY_LIST, } from '/app/redux/analytics' -import { LabwareCard } from '/app/organisms/LabwareCard' -import { AddCustomLabwareSlideout } from '/app/organisms/AddCustomLabwareSlideout' +import { LabwareCard } from '/app/organisms/Desktop/Labware/LabwareCard' +import { AddCustomLabwareSlideout } from '/app/organisms/Desktop/Labware/AddCustomLabwareSlideout' import { useToaster } from '/app/organisms/ToasterOven' -import { useAllLabware, useLabwareFailure, useNewLabwareName } from '../hooks' +import { useLabwareFailure, useNewLabwareName } from '../hooks' import { Labware } from '..' +import { useAllLabware } from '/app/local-resources/labware' import { mockDefinition } from '/app/redux/custom-labware/__fixtures__' -vi.mock('/app/organisms/LabwareCard') -vi.mock('/app/organisms/AddCustomLabwareSlideout') +vi.mock('/app/organisms/Desktop/Labware/LabwareCard') +vi.mock('/app/organisms/Desktop/Labware/AddCustomLabwareSlideout') vi.mock('/app/organisms/ToasterOven') vi.mock('../hooks') vi.mock('/app/redux/analytics') +vi.mock('/app/local-resources/labware') const mockTrackEvent = vi.fn() const mockMakeSnackbar = vi.fn() diff --git a/app/src/pages/Desktop/Labware/__tests__/hooks.test.tsx b/app/src/pages/Desktop/Labware/__tests__/hooks.test.tsx index 23ef20d72b3..14783cd6fe5 100644 --- a/app/src/pages/Desktop/Labware/__tests__/hooks.test.tsx +++ b/app/src/pages/Desktop/Labware/__tests__/hooks.test.tsx @@ -5,7 +5,7 @@ import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { renderHook } from '@testing-library/react' import { i18n } from '/app/i18n' import { I18nextProvider } from 'react-i18next' -import { getAllDefs } from '../helpers/getAllDefs' +import { getAllDefs } from '/app/local-resources/labware/utils/getAllDefs' import { getValidCustomLabware, @@ -17,14 +17,15 @@ import { mockValidLabware, } from '/app/redux/custom-labware/__fixtures__' -import { useAllLabware, useLabwareFailure, useNewLabwareName } from '../hooks' +import { useLabwareFailure, useNewLabwareName } from '../hooks' +import { useAllLabware } from '/app/local-resources/labware' import type { Store } from 'redux' import type { State } from '/app/redux/types' import type { FailedLabwareFile } from '/app/redux/custom-labware/types' vi.mock('/app/redux/custom-labware') -vi.mock('../helpers/getAllDefs') +vi.mock('/app/local-resources/labware/utils/getAllDefs') describe('useAllLabware hook', () => { const store: Store = createStore(vi.fn(), {}) diff --git a/app/src/pages/Desktop/Labware/hooks.tsx b/app/src/pages/Desktop/Labware/hooks.tsx index d9c9d1a1ed1..f6cac84c9f1 100644 --- a/app/src/pages/Desktop/Labware/hooks.tsx +++ b/app/src/pages/Desktop/Labware/hooks.tsx @@ -5,66 +5,9 @@ import { clearAddCustomLabwareFailure, getAddNewLabwareName, clearNewLabwareName, - getValidCustomLabware, } from '/app/redux/custom-labware' -import { getAllDefinitions } from './helpers/definitions' import type { Dispatch } from '/app/redux/types' -import type { LabwareDefinition2 as LabwareDefinition } from '@opentrons/shared-data' -import type { LabwareFilter, LabwareSort } from './types' - -export interface LabwareDefAndDate { - definition: LabwareDefinition - modified?: number - filename?: string -} - -export function useAllLabware( - sortBy: LabwareSort, - filterBy: LabwareFilter -): LabwareDefAndDate[] { - const fullLabwareList: LabwareDefAndDate[] = [] - const labwareDefinitions = getAllDefinitions() - labwareDefinitions.forEach(def => fullLabwareList.push({ definition: def })) - const customLabwareList = useSelector(getValidCustomLabware) - customLabwareList.forEach(customLabware => - 'definition' in customLabware - ? fullLabwareList.push({ - modified: customLabware.modified, - definition: customLabware.definition, - filename: customLabware.filename, - }) - : null - ) - const sortLabware = (a: LabwareDefAndDate, b: LabwareDefAndDate): number => { - if ( - a.definition.metadata.displayName.toUpperCase() < - b.definition.metadata.displayName.toUpperCase() - ) { - return sortBy === 'alphabetical' ? -1 : 1 - } - if ( - a.definition.metadata.displayName.toUpperCase() > - b.definition.metadata.displayName.toUpperCase() - ) { - return sortBy === 'alphabetical' ? 1 : -1 - } - return 0 - } - - if (filterBy === 'customLabware') { - return (customLabwareList as LabwareDefAndDate[]).sort(sortLabware) - } - fullLabwareList.sort(sortLabware) - if (filterBy !== 'all') { - return fullLabwareList.filter( - labwareItem => - labwareItem.definition.metadata.displayCategory === filterBy - ) - } - return fullLabwareList -} - export function useLabwareFailure(): { labwareFailureMessage: string | null clearLabwareFailure: () => unknown diff --git a/app/src/pages/Desktop/Labware/index.tsx b/app/src/pages/Desktop/Labware/index.tsx index 819e0b37b2f..955f8a26fc1 100644 --- a/app/src/pages/Desktop/Labware/index.tsx +++ b/app/src/pages/Desktop/Labware/index.tsx @@ -35,16 +35,20 @@ import { ANALYTICS_OPEN_LABWARE_CREATOR_FROM_BOTTOM_OF_LABWARE_LIBRARY_LIST, } from '/app/redux/analytics' import { addCustomLabwareFileFromCreator } from '/app/redux/custom-labware' -import { LabwareCard } from '/app/organisms/LabwareCard' -import { AddCustomLabwareSlideout } from '/app/organisms/AddCustomLabwareSlideout' -import { LabwareDetails } from '/app/organisms/LabwareDetails' +import { LabwareCard } from '/app/organisms/Desktop/Labware/LabwareCard' +import { AddCustomLabwareSlideout } from '/app/organisms/Desktop/Labware/AddCustomLabwareSlideout' +import { LabwareDetails } from '/app/organisms/Desktop/Labware/LabwareDetails' import { useToaster } from '/app/organisms/ToasterOven' import { useFeatureFlag } from '/app/redux/config' -import { useAllLabware, useLabwareFailure, useNewLabwareName } from './hooks' +import { useLabwareFailure, useNewLabwareName } from './hooks' +import { useAllLabware } from '/app/local-resources/labware' import type { DropdownOption } from '@opentrons/components' -import type { LabwareFilter, LabwareSort } from './types' -import type { LabwareDefAndDate } from './hooks' +import type { + LabwareFilter, + LabwareSort, + LabwareDefAndDate, +} from '/app/local-resources/labware' const LABWARE_CREATOR_HREF = 'https://labware.opentrons.com/create/' const labwareDisplayCategoryFilters: LabwareFilter[] = [ diff --git a/app/src/pages/ODD/ProtocolDetails/__tests__/Parameters.test.tsx b/app/src/pages/ODD/ProtocolDetails/__tests__/Parameters.test.tsx index eca000b7abb..3332f0a1746 100644 --- a/app/src/pages/ODD/ProtocolDetails/__tests__/Parameters.test.tsx +++ b/app/src/pages/ODD/ProtocolDetails/__tests__/Parameters.test.tsx @@ -7,7 +7,7 @@ import { useToaster } from '/app/organisms/ToasterOven' import { renderWithProviders } from '/app/__testing-utils__' import { useRunTimeParameters } from '/app/pages/Desktop/Protocols/hooks' import { Parameters } from '../Parameters' -import { mockRunTimeParameterData } from '../fixtures' +import { mockRunTimeParameterData } from '/app/organisms/ODD/ProtocolSetup/__fixtures__' vi.mock('/app/organisms/ToasterOven') vi.mock('/app/pages/Desktop/Protocols/hooks') diff --git a/app/src/pages/ODD/ProtocolDetails/__tests__/ProtocolDetails.test.tsx b/app/src/pages/ODD/ProtocolDetails/__tests__/ProtocolDetails.test.tsx index ebd7206e9ac..3d37ec354b9 100644 --- a/app/src/pages/ODD/ProtocolDetails/__tests__/ProtocolDetails.test.tsx +++ b/app/src/pages/ODD/ProtocolDetails/__tests__/ProtocolDetails.test.tsx @@ -17,6 +17,7 @@ import { useHardwareStatusText } from '/app/organisms/ODD/RobotDashboard/hooks' import { useOffsetCandidatesForAnalysis } from '/app/organisms/ApplyHistoricOffsets/hooks/useOffsetCandidatesForAnalysis' import { useRunTimeParameters } from '/app/pages/Desktop/Protocols/hooks' import { ProtocolSetupParameters } from '/app/organisms/ODD/ProtocolSetup/ProtocolSetupParameters' +import { mockRunTimeParameterData } from '/app/organisms/ODD/ProtocolSetup/__fixtures__' import { formatTimeWithUtcLabel } from '/app/resources/runs' import { useMissingProtocolHardware } from '/app/transformations/commands' import { ProtocolDetails } from '..' @@ -24,7 +25,6 @@ import { Deck } from '../Deck' import { Hardware } from '../Hardware' import { Labware } from '../Labware' import { Parameters } from '../Parameters' -import { mockRunTimeParameterData } from '../fixtures' import type { HostConfig } from '@opentrons/api-client' diff --git a/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx b/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx index b93bd172389..4e0dd816006 100644 --- a/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx +++ b/app/src/pages/ODD/ProtocolSetup/__tests__/ProtocolSetup.test.tsx @@ -30,10 +30,10 @@ import { useLPCDisabledReason, useModuleCalibrationStatus, useProtocolAnalysisErrors, - useRobotType, useRunCreatedAtTimestamp, - useTrackProtocolRunEvent, } from '/app/organisms/Devices/hooks' +import { useRobotType } from '/app/redux-resources/robots' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' import { getLocalRobot } from '/app/redux/discovery' import { ANALYTICS_PROTOCOL_RUN_ACTION } from '/app/redux/analytics' import { getProtocolModulesInfo } from '/app/organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' @@ -54,7 +54,6 @@ import { mockProtocolModuleInfo } from '/app/organisms/ODD/ProtocolSetup/Protoco import { useProtocolHasRunTimeParameters, useRunControls, - useRunStatus, } from '/app/organisms/RunTimeControl/hooks' import { useIsHeaterShakerInProtocol } from '/app/organisms/ModuleCard/hooks' import { useNotifyDeckConfigurationQuery } from '/app/resources/deck_configuration/useNotifyDeckConfigurationQuery' @@ -62,9 +61,9 @@ import { useDeckConfigurationCompatibility } from '/app/resources/deck_configura import { ConfirmAttachedModal } from '../ConfirmAttachedModal' import { ConfirmSetupStepsCompleteModal } from '../ConfirmSetupStepsCompleteModal' import { ProtocolSetup } from '../' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery, useRunStatus } from '/app/resources/runs' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' -import { mockRunTimeParameterData } from '/app/pages/ODD/ProtocolDetails/fixtures' +import { mockRunTimeParameterData } from '/app/organisms/ODD/ProtocolSetup/__fixtures__' import type { UseQueryResult } from 'react-query' import type * as SharedData from '@opentrons/shared-data' @@ -124,6 +123,8 @@ vi.mock('/app/resources/runs') vi.mock('/app/resources/deck_configuration/hooks') vi.mock('/app/resources/deck_configuration/useNotifyDeckConfigurationQuery') vi.mock('../ConfirmSetupStepsCompleteModal') +vi.mock('/app/redux-resources/analytics') +vi.mock('/app/redux-resources/robots') const render = (path = '/') => { return renderWithProviders( diff --git a/app/src/pages/ODD/ProtocolSetup/index.tsx b/app/src/pages/ODD/ProtocolSetup/index.tsx index 82a06b8d252..a5b6b088c29 100644 --- a/app/src/pages/ODD/ProtocolSetup/index.tsx +++ b/app/src/pages/ODD/ProtocolSetup/index.tsx @@ -38,10 +38,12 @@ import { useLPCDisabledReason, useModuleCalibrationStatus, useProtocolAnalysisErrors, +} from '/app/organisms/Devices/hooks' +import { useRobotType } from '/app/redux-resources/robots' +import { useRobotAnalyticsData, - useRobotType, useTrackProtocolRunEvent, -} from '/app/organisms/Devices/hooks' +} from '/app/redux-resources/analytics' import { getProtocolModulesInfo } from '/app/organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' import { @@ -61,10 +63,7 @@ import { } from '/app/organisms/ODD/ProtocolSetup' import { useLaunchLPC } from '/app/organisms/LabwarePositionCheck/useLaunchLPC' import { ConfirmCancelRunModal } from '/app/organisms/ODD/RunningProtocol' -import { - useRunControls, - useRunStatus, -} from '/app/organisms/RunTimeControl/hooks' +import { useRunControls } from '/app/organisms/RunTimeControl/hooks' import { useToaster } from '/app/organisms/ToasterOven' import { useIsHeaterShakerInProtocol } from '/app/organisms/ModuleCard/hooks' import { getLocalRobot, getRobotSerialNumber } from '/app/redux/discovery' @@ -80,7 +79,7 @@ import { getLatestCurrentOffsets } from '/app/organisms/Devices/ProtocolRun/Setu import { CloseButton, PlayButton } from './Buttons' import { useDeckConfigurationCompatibility } from '/app/resources/deck_configuration/hooks' import { getRequiredDeckConfig } from '/app/resources/deck_configuration/utils' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery, useRunStatus } from '/app/resources/runs' import type { Run } from '@opentrons/api-client' import type { CutoutFixtureId, CutoutId } from '@opentrons/shared-data' diff --git a/app/src/pages/ODD/RunSummary/index.tsx b/app/src/pages/ODD/RunSummary/index.tsx index a0afb16a767..0db79ec7061 100644 --- a/app/src/pages/ODD/RunSummary/index.tsx +++ b/app/src/pages/ODD/RunSummary/index.tsx @@ -40,20 +40,15 @@ import { useDeleteRunMutation, useRunCommandErrors, } from '@opentrons/react-api-client' - -import { - useRunTimestamps, - useRunControls, -} from '/app/organisms/RunTimeControl/hooks' +import { useRunControls } from '/app/organisms/RunTimeControl/hooks' +import { useRunCreatedAtTimestamp } from '/app/organisms/Devices/hooks' +import { onDeviceDisplayFormatTimestamp } from '/app/organisms/Devices/utils' +import { RunTimer } from '/app/organisms/Devices/ProtocolRun/RunTimer' import { - useRunCreatedAtTimestamp, useTrackProtocolRunEvent, useRobotAnalyticsData, -} from '/app/organisms/Devices/hooks' -import { useCloseCurrentRun } from '/app/organisms/ProtocolUpload/hooks' -import { onDeviceDisplayFormatTimestamp } from '/app/organisms/Devices/utils' -import { EMPTY_TIMESTAMP } from '/app/organisms/Devices/constants' -import { RunTimer } from '/app/organisms/Devices/ProtocolRun/RunTimer' + useRecoveryAnalytics, +} from '/app/redux-resources/analytics' import { useTrackEvent, ANALYTICS_PROTOCOL_RUN_ACTION, @@ -65,12 +60,14 @@ import { formatTimeWithUtcLabel, useIsRunCurrent, useNotifyRunQuery, + useRunTimestamps, + useCloseCurrentRun, + EMPTY_TIMESTAMP, } from '/app/resources/runs' import { useTipAttachmentStatus, handleTipsAttachedModal, } from '/app/organisms/DropTipWizardFlows' -import { useRecoveryAnalytics } from '/app/organisms/ErrorRecoveryFlows/hooks' import type { IconName } from '@opentrons/components' import type { OnDeviceRouteParams } from '../../../App/types' diff --git a/app/src/pages/ODD/RunningProtocol/__tests__/RunningProtocol.test.tsx b/app/src/pages/ODD/RunningProtocol/__tests__/RunningProtocol.test.tsx index 464e9c725fe..509c2610ef8 100644 --- a/app/src/pages/ODD/RunningProtocol/__tests__/RunningProtocol.test.tsx +++ b/app/src/pages/ODD/RunningProtocol/__tests__/RunningProtocol.test.tsx @@ -24,17 +24,15 @@ import { RunningProtocolSkeleton, } from '/app/organisms/ODD/RunningProtocol' import { mockUseAllCommandsResponseNonDeterministic } from '/app/organisms/RunProgressMeter/__fixtures__' -import { - useRunStatus, - useRunTimestamps, -} from '/app/organisms/RunTimeControl/hooks' import { getLocalRobot } from '/app/redux/discovery' import { CancelingRunModal } from '/app/organisms/ODD/RunningProtocol/CancelingRunModal' -import { useTrackProtocolRunEvent } from '/app/organisms/Devices/hooks' +import { useTrackProtocolRunEvent } from '/app/redux-resources/analytics' import { useMostRecentCompletedAnalysis } from '/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' import { OpenDoorAlertModal } from '/app/organisms/OpenDoorAlertModal' import { RunningProtocol } from '..' import { + useRunStatus, + useRunTimestamps, useNotifyRunQuery, useNotifyAllCommandsQuery, } from '/app/resources/runs' @@ -53,9 +51,9 @@ import type { UseQueryResult } from 'react-query' import type { ProtocolAnalyses, RunCommandSummary } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/analytics') +vi.mock('/app/redux-resources/robots') vi.mock('/app/organisms/Devices/hooks/useLastRunCommandKey') -vi.mock('/app/organisms/RunTimeControl/hooks') vi.mock('/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('/app/organisms/RunTimeControl/hooks') vi.mock('/app/organisms/ODD/RunningProtocol') diff --git a/app/src/pages/ODD/RunningProtocol/index.tsx b/app/src/pages/ODD/RunningProtocol/index.tsx index bf81cb46d3b..8c22d077427 100644 --- a/app/src/pages/ODD/RunningProtocol/index.tsx +++ b/app/src/pages/ODD/RunningProtocol/index.tsx @@ -28,25 +28,25 @@ import { import { StepMeter } from '/app/atoms/StepMeter' import { useMostRecentCompletedAnalysis } from '/app/organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { useNotifyRunQuery } from '/app/resources/runs' +import { + useRunStatus, + useRunTimestamps, + useNotifyRunQuery, +} from '/app/resources/runs' import { InterventionModal, useInterventionModal, } from '/app/organisms/InterventionModal' -import { - useRunStatus, - useRunTimestamps, -} from '/app/organisms/RunTimeControl/hooks' import { CurrentRunningProtocolCommand, RunningProtocolCommandList, RunningProtocolSkeleton, } from '/app/organisms/ODD/RunningProtocol' +import { useRobotType } from '/app/redux-resources/robots' import { useTrackProtocolRunEvent, useRobotAnalyticsData, - useRobotType, -} from '/app/organisms/Devices/hooks' +} from '/app/redux-resources/analytics' import { CancelingRunModal } from '/app/organisms/ODD/RunningProtocol/CancelingRunModal' import { ConfirmCancelRunModal } from '/app/organisms/ODD/RunningProtocol/ConfirmCancelRunModal' import { getLocalRobot } from '/app/redux/discovery' diff --git a/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx b/app/src/redux-resources/analytics/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx similarity index 93% rename from app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx rename to app/src/redux-resources/analytics/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx index 9066cc1bc4f..9430bbfc521 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx +++ b/app/src/redux-resources/analytics/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx @@ -9,19 +9,19 @@ import { QueryClient, QueryClientProvider } from 'react-query' import { useProtocolRunAnalyticsData } from '../useProtocolRunAnalyticsData' import { hash } from '/app/redux/analytics/hash' import { getStoredProtocol } from '/app/redux/protocol-storage' -import { useStoredProtocolAnalysis, useProtocolDetailsForRun } from '../' -import { useProtocolMetadata } from '../useProtocolMetadata' -import { useRunTimestamps } from '../../../RunTimeControl/hooks' -import { formatInterval } from '../../../RunTimeControl/utils' +import { useProtocolDetailsForRun, useRunTimestamps } from '/app/resources/runs' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' +import { useProtocolMetadata } from '/app/resources/protocols' +import { formatInterval } from '/app/transformations/commands' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' import type { Store } from 'redux' vi.mock('/app/redux/analytics/hash') vi.mock('/app/redux/protocol-storage') -vi.mock('../../hooks') -vi.mock('../useProtocolMetadata') -vi.mock('../../../RunTimeControl/hooks') -vi.mock('../../../RunTimeControl/utils') +vi.mock('/app/resources/protocols') +vi.mock('/app/resources/analysis') +vi.mock('/app/resources/runs') +vi.mock('/app/transformations/commands') let wrapper: React.FunctionComponent<{ children: React.ReactNode }> let store: Store = createStore(vi.fn(), {}) diff --git a/app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx b/app/src/redux-resources/analytics/hooks/__tests__/useRobotAnalyticsData.test.tsx similarity index 97% rename from app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx rename to app/src/redux-resources/analytics/hooks/__tests__/useRobotAnalyticsData.test.tsx index a5c82ca6a7d..cbc3e546404 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useRobotAnalyticsData.test.tsx +++ b/app/src/redux-resources/analytics/hooks/__tests__/useRobotAnalyticsData.test.tsx @@ -6,7 +6,7 @@ import { createStore } from 'redux' import { Provider } from 'react-redux' import { QueryClient, QueryClientProvider } from 'react-query' -import { useRobot } from '../' +import { useRobot } from '/app/redux-resources/robots' import { useRobotAnalyticsData } from '../useRobotAnalyticsData' import { getAttachedPipettes } from '/app/redux/pipettes' import { getRobotSettings } from '/app/redux/robot-settings' @@ -24,6 +24,7 @@ import type { AttachedPipettesByMount } from '/app/redux/pipettes/types' vi.mock('@opentrons/react-api-client') vi.mock('../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/discovery') vi.mock('/app/redux/pipettes') vi.mock('/app/redux/robot-settings') diff --git a/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx b/app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx similarity index 97% rename from app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx rename to app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx index 8a82f5d5aaf..14d3e47f73b 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useTrackProtocolRunEvent.test.tsx +++ b/app/src/redux-resources/analytics/hooks/__tests__/useTrackProtocolRunEvent.test.tsx @@ -13,12 +13,12 @@ import { ANALYTICS_PROTOCOL_RUN_ACTION, } from '/app/redux/analytics' import { mockConnectableRobot } from '/app/redux/discovery/__fixtures__' -import { useRobot } from '../useRobot' +import { useRobot } from '/app/redux-resources/robots' import type { Store } from 'redux' import type { Mock } from 'vitest' -vi.mock('../useRobot') +vi.mock('/app/redux-resources/robots') vi.mock('../useProtocolRunAnalyticsData') vi.mock('/app/redux/discovery') vi.mock('/app/redux/pipettes') diff --git a/app/src/redux-resources/analytics/hooks/index.ts b/app/src/redux-resources/analytics/hooks/index.ts new file mode 100644 index 00000000000..174cb14f315 --- /dev/null +++ b/app/src/redux-resources/analytics/hooks/index.ts @@ -0,0 +1,4 @@ +export * from './useRobotAnalyticsData' +export * from './useTrackProtocolRunEvent' +export * from './useProtocolRunAnalyticsData' +export * from './useRecoveryAnalytics' diff --git a/app/src/redux-resources/analytics/hooks/useProtocolRunAnalyticsData.ts b/app/src/redux-resources/analytics/hooks/useProtocolRunAnalyticsData.ts new file mode 100644 index 00000000000..5181ff90d31 --- /dev/null +++ b/app/src/redux-resources/analytics/hooks/useProtocolRunAnalyticsData.ts @@ -0,0 +1,65 @@ +import { useSelector } from 'react-redux' + +import { getStoredProtocol } from '/app/redux/protocol-storage' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' +import { useProtocolMetadata } from '/app/resources/protocols' +import { useProtocolDetailsForRun, useRunTimestamps } from '/app/resources/runs' + +import type { ProtocolAnalysisOutput } from '@opentrons/shared-data' +import type { ProtocolAnalyticsData } from '/app/redux/analytics/types' + +import type { State } from '/app/redux/types' +import type { DiscoveredRobot } from '/app/redux/discovery/types' +import { parseProtocolRunAnalyticsData } from '/app/transformations/analytics' + +type GetProtocolRunAnalyticsData = () => Promise<{ + protocolRunAnalyticsData: ProtocolAnalyticsData + runTime: string +}> + +/** + * + * @param {string | null} runId + * @returns {{ getProtocolRunAnalyticsData: GetProtocolRunAnalyticsData }} + * Function returned returns a promise that resolves to protocol analytics + * data properties for use in event trackEvent + */ +export function useProtocolRunAnalyticsData( + runId: string | null, + robot: DiscoveredRobot | null +): { + getProtocolRunAnalyticsData: GetProtocolRunAnalyticsData +} { + const robotProtocolMetadata = useProtocolMetadata() + const { protocolData: robotProtocolAnalysis } = useProtocolDetailsForRun( + runId + ) + const storedProtocolAnalysis = useStoredProtocolAnalysis(runId) + const storedProtocol = useSelector((state: State) => + getStoredProtocol( + state, + storedProtocolAnalysis?.metadata?.protocolKey as string | undefined + ) + ) + const protocolAnalysis = + robotProtocolAnalysis != null && robotProtocolMetadata != null + ? { + ...robotProtocolAnalysis, + metadata: robotProtocolMetadata, + config: storedProtocolAnalysis?.config, + createdAt: storedProtocolAnalysis?.createdAt ?? '', + errors: storedProtocolAnalysis?.errors, + files: storedProtocolAnalysis?.files ?? [], + } + : storedProtocolAnalysis + const { startedAt } = useRunTimestamps(runId) + + const getProtocolRunAnalyticsData = parseProtocolRunAnalyticsData( + protocolAnalysis as ProtocolAnalysisOutput | null, + storedProtocol, + startedAt, + robot + ) + + return { getProtocolRunAnalyticsData } +} diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts b/app/src/redux-resources/analytics/hooks/useRecoveryAnalytics.ts similarity index 79% rename from app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts rename to app/src/redux-resources/analytics/hooks/useRecoveryAnalytics.ts index ad4ae1fb538..599b10328f3 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryAnalytics.ts +++ b/app/src/redux-resources/analytics/hooks/useRecoveryAnalytics.ts @@ -9,25 +9,30 @@ import { useTrackEvent, } from '/app/redux/analytics' -import type { RunStatus } from '@opentrons/api-client' -import type { FailedCommand, RecoveryRoute, RouteStep } from '../types' +import type { RunStatus, RunCommandSummary } from '@opentrons/api-client' type InitialActionType = 'cancel-run' | 'launch-recovery' type CommandResult = 'succeeded' | 'failed' -export interface UseRecoveryAnalyticsResult { +export interface UseRecoveryAnalyticsResult< + RecoveryRouteType, + RecoveryRouteStepType +> { /* Report the error which occurs error recovery is currently handling. */ reportErrorEvent: ( - failedCommand: FailedCommand | null, + failedCommand: RunCommandSummary | null, initialAction: InitialActionType ) => void /* Report which recovery option the user selected. */ - reportActionSelectedEvent: (selectedRecoveryOption: RecoveryRoute) => void + reportActionSelectedEvent: (selectedRecoveryOption: RecoveryRouteType) => void /* Report when the user views the error details and where they currently are in Error Recovery. */ - reportViewErrorDetailsEvent: (route: RecoveryRoute, step: RouteStep) => void + reportViewErrorDetailsEvent: ( + route: RecoveryRouteType, + step: RecoveryRouteStepType + ) => void /* Report the ultimate result of a selected recovery action, ie, does it result in the run resuming or does the action fail? */ reportActionSelectedResult: ( - selectedRecoveryOption: RecoveryRoute | null, + selectedRecoveryOption: RecoveryRouteType | null, result: CommandResult ) => void /* Report whether the run succeeds or fails if the run entered error recovery at least once. */ @@ -37,11 +42,14 @@ export interface UseRecoveryAnalyticsResult { ) => void } -export function useRecoveryAnalytics(): UseRecoveryAnalyticsResult { +export function useRecoveryAnalytics< + RecoveryRouteType, + RecoveryRouteStepType +>(): UseRecoveryAnalyticsResult { const doTrackEvent = useTrackEvent() const reportErrorEvent = ( - failedCommand: FailedCommand | null, + failedCommand: RunCommandSummary | null, initialAction: InitialActionType ): void => { if (failedCommand != null) { @@ -57,7 +65,7 @@ export function useRecoveryAnalytics(): UseRecoveryAnalyticsResult { } const reportActionSelectedEvent = ( - selectedRecoveryOption: RecoveryRoute + selectedRecoveryOption: RecoveryRouteType ): void => { doTrackEvent({ name: ANALYTICS_RECOVERY_ACTION_SELECTED, @@ -68,8 +76,8 @@ export function useRecoveryAnalytics(): UseRecoveryAnalyticsResult { } const reportViewErrorDetailsEvent = ( - route: RecoveryRoute, - step: RouteStep + route: RecoveryRouteType, + step: RecoveryRouteStepType ): void => { doTrackEvent({ name: ANALYTICS_RECOVERY_VIEW_ERROR_DETAILS, @@ -81,7 +89,7 @@ export function useRecoveryAnalytics(): UseRecoveryAnalyticsResult { } const reportActionSelectedResult = ( - selectedRecoveryOption: RecoveryRoute | null, + selectedRecoveryOption: RecoveryRouteType | null, result: CommandResult ): void => { if (selectedRecoveryOption != null) { diff --git a/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts b/app/src/redux-resources/analytics/hooks/useRobotAnalyticsData.ts similarity index 97% rename from app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts rename to app/src/redux-resources/analytics/hooks/useRobotAnalyticsData.ts index bf76f8fa94d..bfedb714eb3 100644 --- a/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts +++ b/app/src/redux-resources/analytics/hooks/useRobotAnalyticsData.ts @@ -1,7 +1,7 @@ import * as React from 'react' import { useSelector, useDispatch } from 'react-redux' -import { useRobot } from './' +import { useRobot } from '/app/redux-resources/robots' import { getAttachedPipettes } from '/app/redux/pipettes' import { getRobotSettings, fetchSettings } from '/app/redux/robot-settings' import { diff --git a/app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts b/app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts similarity index 95% rename from app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts rename to app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts index 6392eb91300..2f9f085fd64 100644 --- a/app/src/organisms/Devices/hooks/useTrackProtocolRunEvent.ts +++ b/app/src/redux-resources/analytics/hooks/useTrackProtocolRunEvent.ts @@ -1,6 +1,6 @@ import { useTrackEvent } from '/app/redux/analytics' import { useProtocolRunAnalyticsData } from './useProtocolRunAnalyticsData' -import { useRobot } from './useRobot' +import { useRobot } from '/app/redux-resources/robots' interface ProtocolRunAnalyticsEvent { name: string diff --git a/app/src/redux-resources/analytics/index.ts b/app/src/redux-resources/analytics/index.ts new file mode 100644 index 00000000000..fc78d35129c --- /dev/null +++ b/app/src/redux-resources/analytics/index.ts @@ -0,0 +1 @@ +export * from './hooks' diff --git a/app/src/organisms/Devices/hooks/__tests__/useIsFlex.test.tsx b/app/src/redux-resources/robots/hooks/__tests__/useIsFlex.test.tsx similarity index 100% rename from app/src/organisms/Devices/hooks/__tests__/useIsFlex.test.tsx rename to app/src/redux-resources/robots/hooks/__tests__/useIsFlex.test.tsx diff --git a/app/src/organisms/Devices/hooks/__tests__/useRobot.test.tsx b/app/src/redux-resources/robots/hooks/__tests__/useRobot.test.tsx similarity index 100% rename from app/src/organisms/Devices/hooks/__tests__/useRobot.test.tsx rename to app/src/redux-resources/robots/hooks/__tests__/useRobot.test.tsx diff --git a/app/src/redux-resources/robots/hooks/index.ts b/app/src/redux-resources/robots/hooks/index.ts new file mode 100644 index 00000000000..43c2e9a805b --- /dev/null +++ b/app/src/redux-resources/robots/hooks/index.ts @@ -0,0 +1,3 @@ +export * from './useRobot' +export * from './useIsFlex' +export * from './useRobotType' diff --git a/app/src/organisms/Devices/hooks/useIsFlex.ts b/app/src/redux-resources/robots/hooks/useIsFlex.ts similarity index 100% rename from app/src/organisms/Devices/hooks/useIsFlex.ts rename to app/src/redux-resources/robots/hooks/useIsFlex.ts diff --git a/app/src/organisms/Devices/hooks/useRobot.ts b/app/src/redux-resources/robots/hooks/useRobot.ts similarity index 100% rename from app/src/organisms/Devices/hooks/useRobot.ts rename to app/src/redux-resources/robots/hooks/useRobot.ts diff --git a/app/src/organisms/Devices/hooks/useRobotType.ts b/app/src/redux-resources/robots/hooks/useRobotType.ts similarity index 83% rename from app/src/organisms/Devices/hooks/useRobotType.ts rename to app/src/redux-resources/robots/hooks/useRobotType.ts index 324e7af911a..c1f60086fe2 100644 --- a/app/src/organisms/Devices/hooks/useRobotType.ts +++ b/app/src/redux-resources/robots/hooks/useRobotType.ts @@ -1,5 +1,5 @@ import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE } from '@opentrons/shared-data' -import { useIsFlex } from './useIsFlex' +import { useIsFlex } from '/app/redux-resources/robots' import type { RobotType } from '@opentrons/shared-data' export function useRobotType(robotName: string): RobotType { diff --git a/app/src/redux-resources/robots/index.ts b/app/src/redux-resources/robots/index.ts new file mode 100644 index 00000000000..fc78d35129c --- /dev/null +++ b/app/src/redux-resources/robots/index.ts @@ -0,0 +1 @@ +export * from './hooks' diff --git a/app/src/redux/custom-labware/__fixtures__/index.ts b/app/src/redux/custom-labware/__fixtures__/index.ts index ba7db7d218f..56954b88652 100644 --- a/app/src/redux/custom-labware/__fixtures__/index.ts +++ b/app/src/redux/custom-labware/__fixtures__/index.ts @@ -1,5 +1,5 @@ import type { LabwareDefinition2 } from '@opentrons/shared-data' -import type { LabwareWellGroupProperties } from '/app/pages/Desktop/Labware/types' +import type { LabwareWellGroupProperties } from '/app/local-resources/labware' import type * as Types from '../types' export const mockDefinition: LabwareDefinition2 = { diff --git a/app/src/organisms/Devices/hooks/__fixtures__/storedProtocolAnalysis.ts b/app/src/resources/analysis/hooks/__fixtures__/storedProtocolAnalysis.ts similarity index 100% rename from app/src/organisms/Devices/hooks/__fixtures__/storedProtocolAnalysis.ts rename to app/src/resources/analysis/hooks/__fixtures__/storedProtocolAnalysis.ts diff --git a/app/src/organisms/Devices/hooks/__tests__/useStoredProtocolAnalysis.test.tsx b/app/src/resources/analysis/hooks/__tests__/useStoredProtocolAnalysis.test.tsx similarity index 100% rename from app/src/organisms/Devices/hooks/__tests__/useStoredProtocolAnalysis.test.tsx rename to app/src/resources/analysis/hooks/__tests__/useStoredProtocolAnalysis.test.tsx diff --git a/app/src/resources/analysis/hooks/index.ts b/app/src/resources/analysis/hooks/index.ts new file mode 100644 index 00000000000..a61b0fa4ba4 --- /dev/null +++ b/app/src/resources/analysis/hooks/index.ts @@ -0,0 +1 @@ +export * from './useStoredProtocolAnalysis' diff --git a/app/src/organisms/Devices/hooks/useStoredProtocolAnalysis.ts b/app/src/resources/analysis/hooks/useStoredProtocolAnalysis.ts similarity index 53% rename from app/src/organisms/Devices/hooks/useStoredProtocolAnalysis.ts rename to app/src/resources/analysis/hooks/useStoredProtocolAnalysis.ts index de0f570e3f4..429ff0ef5da 100644 --- a/app/src/organisms/Devices/hooks/useStoredProtocolAnalysis.ts +++ b/app/src/resources/analysis/hooks/useStoredProtocolAnalysis.ts @@ -1,40 +1,14 @@ import { useSelector } from 'react-redux' import { useProtocolQuery } from '@opentrons/react-api-client' -import { - parseRequiredModulesEntity, - parseInitialLoadedLabwareEntity, - parsePipetteEntity, -} from '@opentrons/shared-data' import { getStoredProtocol } from '/app/redux/protocol-storage' import { useNotifyRunQuery } from '/app/resources/runs' +import { parseProtocolAnalysisOutput } from '/app/transformations/analysis' import type { ProtocolAnalysisOutput } from '@opentrons/shared-data' import type { State } from '/app/redux/types' -export const parseProtocolAnalysisOutput = ( - storedProtocolAnalysis: ProtocolAnalysisOutput | null -): ProtocolAnalysisOutput | null => { - const pipetteEntity = parsePipetteEntity( - storedProtocolAnalysis?.commands ?? [] - ) - const moduleEntity = parseRequiredModulesEntity( - storedProtocolAnalysis?.commands ?? [] - ) - const labwareEntity = parseInitialLoadedLabwareEntity( - storedProtocolAnalysis?.commands ?? [] - ) - return storedProtocolAnalysis != null - ? { - ...storedProtocolAnalysis, - pipettes: storedProtocolAnalysis.pipettes ?? pipetteEntity, - labware: storedProtocolAnalysis.labware ?? labwareEntity, - modules: storedProtocolAnalysis.modules ?? moduleEntity, - } - : null -} - export function useStoredProtocolAnalysis( runId: string | null ): ProtocolAnalysisOutput | null { diff --git a/app/src/resources/analysis/index.ts b/app/src/resources/analysis/index.ts new file mode 100644 index 00000000000..fc78d35129c --- /dev/null +++ b/app/src/resources/analysis/index.ts @@ -0,0 +1 @@ +export * from './hooks' diff --git a/app/src/resources/devices/__tests__/useIsEstopNotDisengaged.test.tsx b/app/src/resources/devices/__tests__/useIsEstopNotDisengaged.test.tsx index 069c1998527..dff94d57e64 100644 --- a/app/src/resources/devices/__tests__/useIsEstopNotDisengaged.test.tsx +++ b/app/src/resources/devices/__tests__/useIsEstopNotDisengaged.test.tsx @@ -1,6 +1,6 @@ import { when } from 'vitest-when' import { describe, it, expect, vi, beforeEach } from 'vitest' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useEstopQuery } from '@opentrons/react-api-client' import { DISENGAGED, @@ -11,7 +11,7 @@ import { import { useIsEstopNotDisengaged } from '../hooks/useIsEstopNotDisengaged' vi.mock('@opentrons/react-api-client') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') const ROBOT_NAME = 'mockRobot' const mockEstopStatus = { diff --git a/app/src/resources/devices/hooks/useIsEstopNotDisengaged.ts b/app/src/resources/devices/hooks/useIsEstopNotDisengaged.ts index 62dc2497c7c..5feeab664f1 100644 --- a/app/src/resources/devices/hooks/useIsEstopNotDisengaged.ts +++ b/app/src/resources/devices/hooks/useIsEstopNotDisengaged.ts @@ -1,5 +1,5 @@ import { useEstopQuery } from '@opentrons/react-api-client' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { DISENGAGED } from '/app/organisms/EmergencyStop' /** diff --git a/app/src/resources/networking/__tests__/useCanDisconnect.test.tsx b/app/src/resources/networking/__tests__/useCanDisconnect.test.tsx index 7bd9d65b5f4..a363e81e30c 100644 --- a/app/src/resources/networking/__tests__/useCanDisconnect.test.tsx +++ b/app/src/resources/networking/__tests__/useCanDisconnect.test.tsx @@ -7,7 +7,7 @@ import { SECURITY_WPA_EAP } from '@opentrons/api-client' import { renderHook } from '@testing-library/react' import { getRobotApiVersionByName } from '/app/redux/discovery' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useCanDisconnect } from '../hooks/useCanDisconnect' import { useWifiList } from '../hooks/useWifiList' @@ -16,7 +16,7 @@ import type { Store } from 'redux' import type { State } from '/app/redux/types' vi.mock('../hooks/useWifiList') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/discovery') const store: Store = createStore(state => state, {}) diff --git a/app/src/resources/networking/__tests__/useWifiList.test.ts b/app/src/resources/networking/__tests__/useWifiList.test.ts index a9b49dc4a33..3e9df3158b3 100644 --- a/app/src/resources/networking/__tests__/useWifiList.test.ts +++ b/app/src/resources/networking/__tests__/useWifiList.test.ts @@ -2,13 +2,13 @@ import { when } from 'vitest-when' import { describe, it, expect, vi, beforeEach } from 'vitest' import { SECURITY_WPA_EAP } from '@opentrons/api-client' import { useWifiQuery } from '@opentrons/react-api-client' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import { useWifiList } from '../hooks' import type { UseQueryResult } from 'react-query' import type { WifiNetwork, WifiListResponse } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') -vi.mock('/app/organisms/Devices/hooks') +vi.mock('/app/redux-resources/robots') const mockWifiNetwork: WifiNetwork = { ssid: 'linksys', diff --git a/app/src/resources/networking/hooks/useCanDisconnect.ts b/app/src/resources/networking/hooks/useCanDisconnect.ts index 05184ae0de8..fcf37aff980 100644 --- a/app/src/resources/networking/hooks/useCanDisconnect.ts +++ b/app/src/resources/networking/hooks/useCanDisconnect.ts @@ -1,6 +1,6 @@ import { useSelector } from 'react-redux' import Semver from 'semver' -import { useIsFlex } from '/app/organisms/Devices/hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { getRobotApiVersionByName } from '/app/redux/discovery' import { useWifiList } from './useWifiList' diff --git a/app/src/resources/networking/hooks/useWifiList.ts b/app/src/resources/networking/hooks/useWifiList.ts index 7cacb76556d..1e9e4ccd196 100644 --- a/app/src/resources/networking/hooks/useWifiList.ts +++ b/app/src/resources/networking/hooks/useWifiList.ts @@ -1,7 +1,7 @@ import uniqBy from 'lodash/uniqBy' import orderBy from 'lodash/orderBy' import { useWifiQuery } from '@opentrons/react-api-client' -import { useRobot } from '/app/organisms/Devices/hooks' +import { useRobot } from '/app/redux-resources/robots' import type { WifiNetwork } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/hooks/__tests__/useProtocolMetadata.test.tsx b/app/src/resources/protocols/hooks/__tests__/useProtocolMetadata.test.tsx similarity index 93% rename from app/src/organisms/Devices/hooks/__tests__/useProtocolMetadata.test.tsx rename to app/src/resources/protocols/hooks/__tests__/useProtocolMetadata.test.tsx index d2cea52bef4..340b74815fb 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useProtocolMetadata.test.tsx +++ b/app/src/resources/protocols/hooks/__tests__/useProtocolMetadata.test.tsx @@ -5,13 +5,13 @@ import { when } from 'vitest-when' import { Provider } from 'react-redux' import { createStore } from 'redux' import { renderHook } from '@testing-library/react' -import { useCurrentProtocol } from '../../../ProtocolUpload/hooks' +import { useCurrentProtocol } from '../useCurrentProtocol' import { useProtocolMetadata } from '../useProtocolMetadata' import type { Store } from 'redux' import type { State } from '/app/redux/types' -vi.mock('../../../ProtocolUpload/hooks') +vi.mock('../useCurrentProtocol') describe('useProtocolMetadata', () => { const store: Store = createStore(vi.fn(), {}) diff --git a/app/src/resources/protocols/hooks/index.ts b/app/src/resources/protocols/hooks/index.ts index 577968f6a3e..d71b9d0b57d 100644 --- a/app/src/resources/protocols/hooks/index.ts +++ b/app/src/resources/protocols/hooks/index.ts @@ -1,4 +1,5 @@ export { useLastRunProtocolCommand } from './useLastRunProtocolCommand' export { useRunningStepCounts } from './useRunningStepCounts' - +export { useCurrentProtocol } from './useCurrentProtocol' +export { useProtocolMetadata } from './useProtocolMetadata' export type { StepCounts } from './useRunningStepCounts' diff --git a/app/src/organisms/ProtocolUpload/hooks/useCurrentProtocol.ts b/app/src/resources/protocols/hooks/useCurrentProtocol.ts similarity index 88% rename from app/src/organisms/ProtocolUpload/hooks/useCurrentProtocol.ts rename to app/src/resources/protocols/hooks/useCurrentProtocol.ts index 9704734d8f5..6ab0064c27a 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useCurrentProtocol.ts +++ b/app/src/resources/protocols/hooks/useCurrentProtocol.ts @@ -1,5 +1,5 @@ import { useProtocolQuery } from '@opentrons/react-api-client' -import { useCurrentRun } from './useCurrentRun' +import { useCurrentRun } from '/app/resources/runs' import type { Protocol } from '@opentrons/api-client' diff --git a/app/src/organisms/Devices/hooks/useProtocolMetadata.ts b/app/src/resources/protocols/hooks/useProtocolMetadata.ts similarity index 93% rename from app/src/organisms/Devices/hooks/useProtocolMetadata.ts rename to app/src/resources/protocols/hooks/useProtocolMetadata.ts index 5079a89005b..43592fee26c 100644 --- a/app/src/organisms/Devices/hooks/useProtocolMetadata.ts +++ b/app/src/resources/protocols/hooks/useProtocolMetadata.ts @@ -1,4 +1,4 @@ -import { useCurrentProtocol } from '../../ProtocolUpload/hooks' +import { useCurrentProtocol } from './useCurrentProtocol' import type { RobotType } from '@opentrons/shared-data' interface ProtocolMetadata { author?: string diff --git a/app/src/resources/protocols/index.ts b/app/src/resources/protocols/index.ts new file mode 100644 index 00000000000..f3723b374bf --- /dev/null +++ b/app/src/resources/protocols/index.ts @@ -0,0 +1,2 @@ +export * from './hooks' +export * from './utils' diff --git a/app/src/organisms/RunTimeControl/__fixtures__/index.ts b/app/src/resources/runs/__fixtures__/index.ts similarity index 100% rename from app/src/organisms/RunTimeControl/__fixtures__/index.ts rename to app/src/resources/runs/__fixtures__/index.ts diff --git a/app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx b/app/src/resources/runs/__tests__/useCloneRun.test.tsx similarity index 97% rename from app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx rename to app/src/resources/runs/__tests__/useCloneRun.test.tsx index c40a3f21a3e..585093605a7 100644 --- a/app/src/organisms/ProtocolUpload/hooks/__tests__/useCloneRun.test.tsx +++ b/app/src/resources/runs/__tests__/useCloneRun.test.tsx @@ -11,12 +11,12 @@ import { } from '@opentrons/react-api-client' import { useCloneRun } from '../useCloneRun' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery } from '../useNotifyRunQuery' import type { HostConfig } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') -vi.mock('/app/resources/runs') +vi.mock('/app/resources/runs/useNotifyRunQuery') const HOST_CONFIG: HostConfig = { hostname: 'localhost' } const RUN_ID_NO_RTP: string = 'run_id_no_rtp' diff --git a/app/src/organisms/ProtocolUpload/hooks/__tests__/useMostRecentRunId.test.tsx b/app/src/resources/runs/__tests__/useMostRecentRunId.test.tsx similarity index 90% rename from app/src/organisms/ProtocolUpload/hooks/__tests__/useMostRecentRunId.test.tsx rename to app/src/resources/runs/__tests__/useMostRecentRunId.test.tsx index d22def6500f..5dd73a11baa 100644 --- a/app/src/organisms/ProtocolUpload/hooks/__tests__/useMostRecentRunId.test.tsx +++ b/app/src/resources/runs/__tests__/useMostRecentRunId.test.tsx @@ -2,10 +2,10 @@ import { when } from 'vitest-when' import { renderHook } from '@testing-library/react' import { describe, it, afterEach, vi, expect } from 'vitest' -import { useNotifyAllRunsQuery } from '/app/resources/runs' +import { useNotifyAllRunsQuery } from '../useNotifyAllRunsQuery' import { useMostRecentRunId } from '../useMostRecentRunId' -vi.mock('/app/resources/runs') +vi.mock('/app/resources/runs/useNotifyAllRunsQuery') describe('useMostRecentRunId hook', () => { afterEach(() => { diff --git a/app/src/organisms/Devices/hooks/__tests__/useProtocolDetailsForRun.test.tsx b/app/src/resources/runs/__tests__/useProtocolDetailsForRun.test.tsx similarity index 95% rename from app/src/organisms/Devices/hooks/__tests__/useProtocolDetailsForRun.test.tsx rename to app/src/resources/runs/__tests__/useProtocolDetailsForRun.test.tsx index 36963c6ec0a..09bcb147389 100644 --- a/app/src/organisms/Devices/hooks/__tests__/useProtocolDetailsForRun.test.tsx +++ b/app/src/resources/runs/__tests__/useProtocolDetailsForRun.test.tsx @@ -7,15 +7,15 @@ import { useProtocolQuery, } from '@opentrons/react-api-client' import { useProtocolDetailsForRun } from '..' -import { useNotifyRunQuery } from '/app/resources/runs' -import { RUN_ID_2 } from '../../../RunTimeControl/__fixtures__' +import { useNotifyRunQuery } from '../useNotifyRunQuery' +import { RUN_ID_2 } from '../__fixtures__' import type { Protocol, Run } from '@opentrons/api-client' import type { UseQueryResult } from 'react-query' import type { CompletedProtocolAnalysis } from '@opentrons/shared-data' vi.mock('@opentrons/react-api-client') -vi.mock('/app/resources/runs') +vi.mock('../useNotifyRunQuery') const PROTOCOL_ID = 'fake_protocol_id' const PROTOCOL_ANALYSIS = { diff --git a/app/src/resources/runs/__tests__/useRunStatus.test.ts b/app/src/resources/runs/__tests__/useRunStatus.test.ts new file mode 100644 index 00000000000..8bf791eec5d --- /dev/null +++ b/app/src/resources/runs/__tests__/useRunStatus.test.ts @@ -0,0 +1,51 @@ +import { describe, it, vi, expect } from 'vitest' +import { when } from 'vitest-when' +import { renderHook } from '@testing-library/react' +import { useRunStatus } from '../useRunStatus' +import { useNotifyRunQuery } from '../useNotifyRunQuery' +import { + RUN_ID_2, + mockRunningRun, + mockIdleUnstartedRun, + mockIdleStartedRun, +} from '../__fixtures__' + +import type { UseQueryResult } from 'react-query' +import type { Run } from '@opentrons/api-client' + +vi.mock('../useNotifyRunQuery') + +describe('useRunStatus hook', () => { + it('returns the run status of the run', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockRunningRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunStatus(RUN_ID_2)) + expect(result.current).toBe('running') + }) + + it('returns a "idle" run status if idle and run unstarted', () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockIdleUnstartedRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunStatus(RUN_ID_2)) + expect(result.current).toBe('idle') + }) + + it('returns a "running" run status if idle and run started', () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockIdleStartedRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunStatus(RUN_ID_2)) + expect(result.current).toBe('running') + }) +}) diff --git a/app/src/resources/runs/__tests__/useRunTimestamps.test.ts b/app/src/resources/runs/__tests__/useRunTimestamps.test.ts new file mode 100644 index 00000000000..1417be1e96d --- /dev/null +++ b/app/src/resources/runs/__tests__/useRunTimestamps.test.ts @@ -0,0 +1,118 @@ +import { describe, it, vi, beforeEach, expect } from 'vitest' +import { when } from 'vitest-when' +import { renderHook } from '@testing-library/react' + +import { useRunTimestamps } from '../useRunTimestamps' +import { useRunCommands } from '../useRunCommands' +import { useNotifyRunQuery } from '../useNotifyRunQuery' +import { + RUN_ID_2, + mockPausedRun, + mockRunningRun, + mockFailedRun, + mockStoppedRun, + mockSucceededRun, + mockCommand, +} from '../__fixtures__' + +import type { UseQueryResult } from 'react-query' +import type { Run } from '@opentrons/api-client' + +vi.mock('../useRunCommands') +vi.mock('../useNotifyRunQuery') + +describe('useRunTimestamps hook', () => { + beforeEach(() => { + when(useRunCommands) + .calledWith(RUN_ID_2, { cursor: null, pageLength: 1 }, expect.any(Object)) + .thenReturn([mockCommand.data as any]) + }) + + it('returns the start time of the current run', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockRunningRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.startedAt).toBe('2021-10-25T12:54:53.366581+00:00') + }) + + it('returns null when pause is not the last action', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockRunningRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.pausedAt).toBe(null) + }) + + it('returns the pause time of the current run when pause is the last action', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockPausedRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.pausedAt).toBe('2021-10-25T13:23:31.366581+00:00') + }) + + it('returns stopped time null when stop is not the last action', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockRunningRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.stoppedAt).toBe(null) + }) + + it('returns the stop time of the current run when stop is the last action', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockStoppedRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.stoppedAt).toBe('2021-10-25T13:58:22.366581+00:00') + }) + + it('returns the complete time of a successful current run', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockSucceededRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.completedAt).toBe('noon thirty') + }) + + it('returns the complete time of a failed current run', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockFailedRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.completedAt).toBe('noon forty-five') + }) + + it('returns the complete time of a stopped current run', async () => { + when(useNotifyRunQuery) + .calledWith(RUN_ID_2, expect.any(Object)) + .thenReturn(({ + data: { data: mockStoppedRun }, + } as unknown) as UseQueryResult) + + const { result } = renderHook(() => useRunTimestamps(RUN_ID_2)) + expect(result.current.completedAt).toBe('2021-10-25T13:58:22.366581+00:00') + }) +}) diff --git a/app/src/resources/runs/constants.ts b/app/src/resources/runs/constants.ts new file mode 100644 index 00000000000..094228a4509 --- /dev/null +++ b/app/src/resources/runs/constants.ts @@ -0,0 +1,3 @@ +export const EMPTY_TIMESTAMP = '--:--:--' +export const DEFAULT_STATUS_REFETCH_INTERVAL = 10000 // 10 seconds +export const DEFAULT_RUN_QUERY_REFETCH_INTERVAL = 5000 diff --git a/app/src/resources/runs/index.ts b/app/src/resources/runs/index.ts index fa5d6a4fb02..31d4f09acde 100644 --- a/app/src/resources/runs/index.ts +++ b/app/src/resources/runs/index.ts @@ -6,3 +6,14 @@ export * from './useNotifyAllCommandsQuery' export * from './useNotifyAllCommandsAsPreSerializedList' export * from './useCurrentRunId' export * from './useIsRunCurrent' +export * from './useProtocolDetailsForRun' +export * from './useCurrentRun' +export * from './useRunTimestamps' +export * from './useRunCommands' +export * from './useRunStatus' +export * from './useCloneRun' +export * from './useCloseCurrentRun' +export * from './useCurrentRunCommands' +export * from './useMostRecentRunId' +export * from './useRestartRun' +export * from './constants' diff --git a/app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts b/app/src/resources/runs/useCloneRun.ts similarity index 96% rename from app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts rename to app/src/resources/runs/useCloneRun.ts index a1be96c9bec..64b22f8d0a8 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useCloneRun.ts +++ b/app/src/resources/runs/useCloneRun.ts @@ -5,11 +5,11 @@ import { useCreateRunMutation, useCreateProtocolAnalysisMutation, } from '@opentrons/react-api-client' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery } from './useNotifyRunQuery' import { getRunTimeParameterValuesForRun, getRunTimeParameterFilesForRun, -} from '../../Devices/utils' +} from '/app/transformations/runs' import type { Run } from '@opentrons/api-client' diff --git a/app/src/organisms/ProtocolUpload/hooks/useCloseCurrentRun.ts b/app/src/resources/runs/useCloseCurrentRun.ts similarity index 100% rename from app/src/organisms/ProtocolUpload/hooks/useCloseCurrentRun.ts rename to app/src/resources/runs/useCloseCurrentRun.ts diff --git a/app/src/organisms/ProtocolUpload/hooks/useCurrentRun.ts b/app/src/resources/runs/useCurrentRun.ts similarity index 77% rename from app/src/organisms/ProtocolUpload/hooks/useCurrentRun.ts rename to app/src/resources/runs/useCurrentRun.ts index 3e414a48aa0..0198c1cde3c 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useCurrentRun.ts +++ b/app/src/resources/runs/useCurrentRun.ts @@ -1,4 +1,5 @@ -import { useNotifyRunQuery, useCurrentRunId } from '/app/resources/runs' +import { useNotifyRunQuery } from './useNotifyRunQuery' +import { useCurrentRunId } from './useCurrentRunId' import type { Run } from '@opentrons/api-client' diff --git a/app/src/organisms/ProtocolUpload/hooks/useCurrentRunCommands.ts b/app/src/resources/runs/useCurrentRunCommands.ts similarity index 79% rename from app/src/organisms/ProtocolUpload/hooks/useCurrentRunCommands.ts rename to app/src/resources/runs/useCurrentRunCommands.ts index c04f2b0d1db..d666fa7f912 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useCurrentRunCommands.ts +++ b/app/src/resources/runs/useCurrentRunCommands.ts @@ -1,5 +1,4 @@ -import { useCurrentRunId } from '/app/resources/runs' -import { useRunCommands } from './useRunCommands' +import { useCurrentRunId, useRunCommands } from '/app/resources/runs' import type { UseQueryOptions } from 'react-query' import type { CommandsData, diff --git a/app/src/organisms/ProtocolUpload/hooks/useMostRecentRunId.ts b/app/src/resources/runs/useMostRecentRunId.ts similarity index 79% rename from app/src/organisms/ProtocolUpload/hooks/useMostRecentRunId.ts rename to app/src/resources/runs/useMostRecentRunId.ts index c0221ae27a4..9e44c2e73b7 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useMostRecentRunId.ts +++ b/app/src/resources/runs/useMostRecentRunId.ts @@ -1,6 +1,6 @@ import last from 'lodash/last' -import { useNotifyAllRunsQuery } from '/app/resources/runs' +import { useNotifyAllRunsQuery } from './useNotifyAllRunsQuery' export function useMostRecentRunId(): string | null { const { data: allRuns } = useNotifyAllRunsQuery() diff --git a/app/src/organisms/Devices/hooks/useProtocolDetailsForRun.ts b/app/src/resources/runs/useProtocolDetailsForRun.ts similarity index 97% rename from app/src/organisms/Devices/hooks/useProtocolDetailsForRun.ts rename to app/src/resources/runs/useProtocolDetailsForRun.ts index 6f3909affb7..8bc1c655350 100644 --- a/app/src/organisms/Devices/hooks/useProtocolDetailsForRun.ts +++ b/app/src/resources/runs/useProtocolDetailsForRun.ts @@ -6,7 +6,7 @@ import { useProtocolAnalysisAsDocumentQuery, } from '@opentrons/react-api-client' -import { useNotifyRunQuery } from '/app/resources/runs' +import { useNotifyRunQuery } from './useNotifyRunQuery' import type { RobotType, diff --git a/app/src/organisms/ProtocolUpload/hooks/useRestartRun.ts b/app/src/resources/runs/useRestartRun.ts similarity index 100% rename from app/src/organisms/ProtocolUpload/hooks/useRestartRun.ts rename to app/src/resources/runs/useRestartRun.ts diff --git a/app/src/organisms/ProtocolUpload/hooks/useRunCommands.ts b/app/src/resources/runs/useRunCommands.ts similarity index 88% rename from app/src/organisms/ProtocolUpload/hooks/useRunCommands.ts rename to app/src/resources/runs/useRunCommands.ts index 543262fbf54..2075133eca2 100644 --- a/app/src/organisms/ProtocolUpload/hooks/useRunCommands.ts +++ b/app/src/resources/runs/useRunCommands.ts @@ -1,4 +1,4 @@ -import { useNotifyAllCommandsQuery } from '/app/resources/runs' +import { useNotifyAllCommandsQuery } from './useNotifyAllCommandsQuery' import type { UseQueryOptions } from 'react-query' import type { diff --git a/app/src/resources/runs/useRunStatus.ts b/app/src/resources/runs/useRunStatus.ts new file mode 100644 index 00000000000..3953331b7d8 --- /dev/null +++ b/app/src/resources/runs/useRunStatus.ts @@ -0,0 +1,47 @@ +import * as React from 'react' +import { + RUN_ACTION_TYPE_PLAY, + RUN_STATUS_IDLE, + RUN_STATUS_RUNNING, + RUN_STATUSES_TERMINAL, +} from '@opentrons/api-client' +import { useNotifyRunQuery } from './useNotifyRunQuery' +import { DEFAULT_STATUS_REFETCH_INTERVAL } from './constants' + +import type { UseQueryOptions } from 'react-query' +import type { RunStatus, RunAction, Run } from '@opentrons/api-client' + +export function useRunStatus( + runId: string | null, + options?: UseQueryOptions +): RunStatus | null { + const lastRunStatus = React.useRef(null) + + const { data } = useNotifyRunQuery(runId ?? null, { + refetchInterval: DEFAULT_STATUS_REFETCH_INTERVAL, + enabled: + lastRunStatus.current == null || + !(RUN_STATUSES_TERMINAL as RunStatus[]).includes(lastRunStatus.current), + onSuccess: data => (lastRunStatus.current = data?.data?.status ?? null), + ...options, + }) + + const runStatus = data?.data?.status as RunStatus + + const actions = data?.data?.actions as RunAction[] + const firstPlay = actions?.find( + action => action.actionType === RUN_ACTION_TYPE_PLAY + ) + const runStartTime = firstPlay?.createdAt + + // display an idle status as 'running' in the UI after a run has started. + // todo(mm, 2024-06-24): This may not be necessary anymore. It looks like it was + // working around prior (?) server behavior where a run's status would briefly flicker + // to idle in between commands. + const adjustedRunStatus: RunStatus | null = + runStatus === RUN_STATUS_IDLE && runStartTime != null + ? RUN_STATUS_RUNNING + : runStatus + + return adjustedRunStatus +} diff --git a/app/src/resources/runs/useRunTimestamps.ts b/app/src/resources/runs/useRunTimestamps.ts new file mode 100644 index 00000000000..f3ae3f1a803 --- /dev/null +++ b/app/src/resources/runs/useRunTimestamps.ts @@ -0,0 +1,79 @@ +import last from 'lodash/last' +import { + RUN_ACTION_TYPE_PLAY, + RUN_ACTION_TYPE_PAUSE, + RUN_STATUS_STOPPED, + RUN_STATUS_FAILED, + RUN_STATUS_FINISHING, + RUN_STATUS_SUCCEEDED, + RUN_ACTION_TYPE_STOP, + RUN_STATUS_STOP_REQUESTED, +} from '@opentrons/api-client' +import { DEFAULT_RUN_QUERY_REFETCH_INTERVAL } from './constants' +import { useRunCommands } from './useRunCommands' +import { useNotifyRunQuery } from './useNotifyRunQuery' +import { useRunStatus } from './useRunStatus' + +export interface RunTimestamps { + startedAt: string | null + pausedAt: string | null + stoppedAt: string | null + completedAt: string | null +} + +export function useRunTimestamps(runId: string | null): RunTimestamps { + const runStatus = useRunStatus(runId) + const { actions = [], errors = [] } = + useNotifyRunQuery(runId, { + refetchInterval: DEFAULT_RUN_QUERY_REFETCH_INTERVAL, + })?.data?.data ?? {} + const runCommands = + useRunCommands( + runId, + { cursor: null, pageLength: 1 }, + { + enabled: + runStatus === RUN_STATUS_SUCCEEDED || + runStatus === RUN_STATUS_STOPPED || + runStatus === RUN_STATUS_FAILED || + runStatus === RUN_STATUS_STOP_REQUESTED || + runStatus === RUN_STATUS_FINISHING, + refetchInterval: false, + } + ) ?? [] + + const firstPlay = actions.find( + action => action.actionType === RUN_ACTION_TYPE_PLAY + ) + const lastAction = last(actions) + + const lastCommand = last(runCommands) + const lastActionAt = lastAction?.createdAt ?? null + const lastErrorAt = last(errors)?.createdAt + const lastCommandAt = lastCommand?.completedAt + + const startedAt = firstPlay?.createdAt ?? null + const pausedAt = + lastAction?.actionType === RUN_ACTION_TYPE_PAUSE ? lastActionAt : null + const stoppedAt = + lastAction?.actionType === RUN_ACTION_TYPE_STOP ? lastActionAt : null + let completedAt = null + switch (runStatus) { + case RUN_STATUS_STOPPED: + completedAt = lastActionAt ?? null + break + case RUN_STATUS_FAILED: + completedAt = lastErrorAt ?? null + break + case RUN_STATUS_SUCCEEDED: + completedAt = lastCommandAt ?? null + break + } + + return { + startedAt, + pausedAt, + stoppedAt, + completedAt, + } +} diff --git a/app/src/transformations/analysis/index.ts b/app/src/transformations/analysis/index.ts new file mode 100644 index 00000000000..07ba04fd741 --- /dev/null +++ b/app/src/transformations/analysis/index.ts @@ -0,0 +1 @@ +export * from './parseProtocolAnalysisOutput' diff --git a/app/src/transformations/analysis/parseProtocolAnalysisOutput.ts b/app/src/transformations/analysis/parseProtocolAnalysisOutput.ts new file mode 100644 index 00000000000..f22a58490f4 --- /dev/null +++ b/app/src/transformations/analysis/parseProtocolAnalysisOutput.ts @@ -0,0 +1,28 @@ +import { + parseRequiredModulesEntity, + parseInitialLoadedLabwareEntity, + parsePipetteEntity, +} from '@opentrons/shared-data' +import type { ProtocolAnalysisOutput } from '@opentrons/shared-data' + +export const parseProtocolAnalysisOutput = ( + storedProtocolAnalysis: ProtocolAnalysisOutput | null +): ProtocolAnalysisOutput | null => { + const pipetteEntity = parsePipetteEntity( + storedProtocolAnalysis?.commands ?? [] + ) + const moduleEntity = parseRequiredModulesEntity( + storedProtocolAnalysis?.commands ?? [] + ) + const labwareEntity = parseInitialLoadedLabwareEntity( + storedProtocolAnalysis?.commands ?? [] + ) + return storedProtocolAnalysis != null + ? { + ...storedProtocolAnalysis, + pipettes: storedProtocolAnalysis.pipettes ?? pipetteEntity, + labware: storedProtocolAnalysis.labware ?? labwareEntity, + modules: storedProtocolAnalysis.modules ?? moduleEntity, + } + : null +} diff --git a/app/src/transformations/analytics/index.ts b/app/src/transformations/analytics/index.ts new file mode 100644 index 00000000000..87288186ae7 --- /dev/null +++ b/app/src/transformations/analytics/index.ts @@ -0,0 +1 @@ +export * from './parseProtocolRunAnalyticsData' diff --git a/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts b/app/src/transformations/analytics/parseProtocolRunAnalyticsData.ts similarity index 53% rename from app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts rename to app/src/transformations/analytics/parseProtocolRunAnalyticsData.ts index 175a390ead5..1dd4947f21c 100644 --- a/app/src/organisms/Devices/hooks/useProtocolRunAnalyticsData.ts +++ b/app/src/transformations/analytics/parseProtocolRunAnalyticsData.ts @@ -1,18 +1,10 @@ -import { useSelector } from 'react-redux' - +import { EMPTY_TIMESTAMP } from '/app/resources/runs' import { hash } from '/app/redux/analytics/hash' -import { getStoredProtocol } from '/app/redux/protocol-storage' import { getRobotSerialNumber } from '/app/redux/discovery' -import { useStoredProtocolAnalysis, useProtocolDetailsForRun } from './' -import { useProtocolMetadata } from './useProtocolMetadata' -import { useRunTimestamps } from '../../RunTimeControl/hooks' -import { formatInterval } from '../../RunTimeControl/utils' -import { EMPTY_TIMESTAMP } from '../constants' +import { formatInterval } from '/app/transformations/commands' import type { ProtocolAnalysisOutput } from '@opentrons/shared-data' -import type { ProtocolAnalyticsData } from '/app/redux/analytics/types' import type { StoredProtocolData } from '/app/redux/protocol-storage/types' -import type { State } from '/app/redux/types' import type { DiscoveredRobot } from '/app/redux/discovery/types' export const parseProtocolRunAnalyticsData = ( @@ -69,55 +61,3 @@ export const parseProtocolRunAnalyticsData = ( startedAt != null ? formatInterval(startedAt, Date()) : EMPTY_TIMESTAMP, })) } - -type GetProtocolRunAnalyticsData = () => Promise<{ - protocolRunAnalyticsData: ProtocolAnalyticsData - runTime: string -}> - -/** - * - * @param {string | null} runId - * @returns {{ getProtocolRunAnalyticsData: GetProtocolRunAnalyticsData }} - * Function returned returns a promise that resolves to protocol analytics - * data properties for use in event trackEvent - */ -export function useProtocolRunAnalyticsData( - runId: string | null, - robot: DiscoveredRobot | null -): { - getProtocolRunAnalyticsData: GetProtocolRunAnalyticsData -} { - const robotProtocolMetadata = useProtocolMetadata() - const { protocolData: robotProtocolAnalysis } = useProtocolDetailsForRun( - runId - ) - const storedProtocolAnalysis = useStoredProtocolAnalysis(runId) - const storedProtocol = useSelector((state: State) => - getStoredProtocol( - state, - storedProtocolAnalysis?.metadata?.protocolKey as string | undefined - ) - ) - const protocolAnalysis = - robotProtocolAnalysis != null && robotProtocolMetadata != null - ? { - ...robotProtocolAnalysis, - metadata: robotProtocolMetadata, - config: storedProtocolAnalysis?.config, - createdAt: storedProtocolAnalysis?.createdAt ?? '', - errors: storedProtocolAnalysis?.errors, - files: storedProtocolAnalysis?.files ?? [], - } - : storedProtocolAnalysis - const { startedAt } = useRunTimestamps(runId) - - const getProtocolRunAnalyticsData = parseProtocolRunAnalyticsData( - protocolAnalysis as ProtocolAnalysisOutput | null, - storedProtocol, - startedAt, - robot - ) - - return { getProtocolRunAnalyticsData } -} diff --git a/app/src/transformations/commands/transformations/__tests__/formatDuration.test.tsx b/app/src/transformations/commands/transformations/__tests__/formatDuration.test.tsx new file mode 100644 index 00000000000..21ffb0f565b --- /dev/null +++ b/app/src/transformations/commands/transformations/__tests__/formatDuration.test.tsx @@ -0,0 +1,39 @@ +import { describe, it, expect } from 'vitest' +import { formatDuration } from '../formatDuration' + +describe('formatDuration', () => { + it('should format a duration', () => { + const duration = { + hours: 2, + minutes: 40, + seconds: 2, + } + + const expected = '02:40:02' + + expect(formatDuration(duration)).toEqual(expected) + }) + + it('should format a short duration with plenty of zeroes', () => { + const duration = { + seconds: 2, + } + + const expected = '00:00:02' + + expect(formatDuration(duration)).toEqual(expected) + }) + + it('should format a longer duration', () => { + const duration = { + days: 3, + hours: 2, + minutes: 40, + seconds: 2, + } + + const expected = '74:40:02' + + expect(formatDuration(duration)).toEqual(expected) + }) +}) diff --git a/app/src/organisms/RunTimeControl/__tests__/formatInterval.test.tsx b/app/src/transformations/commands/transformations/__tests__/formatInterval.test.tsx similarity index 53% rename from app/src/organisms/RunTimeControl/__tests__/formatInterval.test.tsx rename to app/src/transformations/commands/transformations/__tests__/formatInterval.test.tsx index b5aa8543e0e..1ff98cecf79 100644 --- a/app/src/organisms/RunTimeControl/__tests__/formatInterval.test.tsx +++ b/app/src/transformations/commands/transformations/__tests__/formatInterval.test.tsx @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest' -import { formatDuration, formatInterval } from '../utils' +import { formatInterval } from '../formatInterval' describe('formatInterval', () => { it('should format a date string interval', () => { @@ -29,40 +29,3 @@ describe('formatInterval', () => { expect(formatInterval(start, end)).toEqual(expected) }) }) - -describe('formatDuration', () => { - it('should format a duration', () => { - const duration = { - hours: 2, - minutes: 40, - seconds: 2, - } - - const expected = '02:40:02' - - expect(formatDuration(duration)).toEqual(expected) - }) - - it('should format a short duration with plenty of zeroes', () => { - const duration = { - seconds: 2, - } - - const expected = '00:00:02' - - expect(formatDuration(duration)).toEqual(expected) - }) - - it('should format a longer duration', () => { - const duration = { - days: 3, - hours: 2, - minutes: 40, - seconds: 2, - } - - const expected = '74:40:02' - - expect(formatDuration(duration)).toEqual(expected) - }) -}) diff --git a/app/src/organisms/RunTimeControl/utils.ts b/app/src/transformations/commands/transformations/formatDuration.ts similarity index 63% rename from app/src/organisms/RunTimeControl/utils.ts rename to app/src/transformations/commands/transformations/formatDuration.ts index e95efcaf164..f744d9dba5d 100644 --- a/app/src/organisms/RunTimeControl/utils.ts +++ b/app/src/transformations/commands/transformations/formatDuration.ts @@ -1,7 +1,5 @@ -import { intervalToDuration } from 'date-fns' import padStart from 'lodash/padStart' import type { Duration } from 'date-fns' - /** * utility to format a date-fns duration object to hh:mm:ss * @param duration date-fns duration object @@ -19,17 +17,3 @@ export function formatDuration(duration: Duration): string { return `${paddedHours}:${paddedMinutes}:${paddedSeconds}` } - -/** - * utility to format a date interval to a hh:mm:ss duration - * @param start date string - * @param end date string - * @returns string in format hh:mm:ss, e.g. 03:15:45 - */ -export function formatInterval(start: string, end: string): string { - const duration = intervalToDuration({ - start: new Date(start), - end: new Date(end), - }) - return formatDuration(duration) -} diff --git a/app/src/transformations/commands/transformations/formatInterval.ts b/app/src/transformations/commands/transformations/formatInterval.ts new file mode 100644 index 00000000000..e59c61dcb2d --- /dev/null +++ b/app/src/transformations/commands/transformations/formatInterval.ts @@ -0,0 +1,15 @@ +import { intervalToDuration } from 'date-fns' +import { formatDuration } from './formatDuration' +/** + * utility to format a date interval to a hh:mm:ss duration + * @param start date string + * @param end date string + * @returns string in format hh:mm:ss, e.g. 03:15:45 + */ +export function formatInterval(start: string, end: string): string { + const duration = intervalToDuration({ + start: new Date(start), + end: new Date(end), + }) + return formatDuration(duration) +} diff --git a/app/src/transformations/commands/transformations/index.ts b/app/src/transformations/commands/transformations/index.ts index 47b64721bc9..e82277ab337 100644 --- a/app/src/transformations/commands/transformations/index.ts +++ b/app/src/transformations/commands/transformations/index.ts @@ -1,2 +1,4 @@ export * from './getLabwareSetupItemGroups' export * from './getProtocolUsesGripper' +export * from './formatDuration' +export * from './formatInterval' diff --git a/app/src/transformations/runs/getRunTimeParameterFilesForRun.ts b/app/src/transformations/runs/getRunTimeParameterFilesForRun.ts new file mode 100644 index 00000000000..583a9a887b3 --- /dev/null +++ b/app/src/transformations/runs/getRunTimeParameterFilesForRun.ts @@ -0,0 +1,27 @@ +import type { RunTimeParameter } from '@opentrons/shared-data' +import type { RunTimeParameterFilesCreateData } from '@opentrons/api-client' + +/** + * prepares object to send to endpoints requiring RunTimeParameterFilesCreateData + * @param {RunTimeParameter[]} runTimeParameters array of updated RunTimeParameter overrides + * @param {Record} [fileIdMap] mapping of variable name to file ID created and returned by robot server + * @returns {RunTimeParameterFilesCreateData} object mapping variable name to file ID + */ +export function getRunTimeParameterFilesForRun( + runTimeParameters: RunTimeParameter[], + fileIdMap?: Record +): RunTimeParameterFilesCreateData { + return runTimeParameters.reduce((acc, param) => { + const { variableName } = param + if (param.type === 'csv_file' && param.file?.id != null) { + return { ...acc, [variableName]: param.file.id } + } else if ( + param.type === 'csv_file' && + fileIdMap != null && + variableName in fileIdMap + ) { + return { ...acc, [variableName]: fileIdMap[variableName] } + } + return acc + }, {}) +} diff --git a/app/src/transformations/runs/getRunTimeParameterValuesForRun.ts b/app/src/transformations/runs/getRunTimeParameterValuesForRun.ts new file mode 100644 index 00000000000..2a7a94f4470 --- /dev/null +++ b/app/src/transformations/runs/getRunTimeParameterValuesForRun.ts @@ -0,0 +1,19 @@ +import type { RunTimeParameter } from '@opentrons/shared-data' +import type { RunTimeParameterValuesCreateData } from '@opentrons/api-client' + +/** + * prepares object to send to endpoints requiring RunTimeParameterValuesCreateData + * @param {RunTimeParameter[]} runTimeParameters array of updated RunTimeParameter overrides + * @returns {RunTimeParameterValuesCreateData} object mapping variable name to value + */ +export function getRunTimeParameterValuesForRun( + runTimeParameters: RunTimeParameter[] +): RunTimeParameterValuesCreateData { + return runTimeParameters.reduce((acc, param) => { + const { variableName } = param + if (param.type !== 'csv_file' && param.value !== param.default) { + return { ...acc, [variableName]: param.value } + } + return acc + }, {}) +} diff --git a/app/src/transformations/runs/index.ts b/app/src/transformations/runs/index.ts new file mode 100644 index 00000000000..c8f12cd7d79 --- /dev/null +++ b/app/src/transformations/runs/index.ts @@ -0,0 +1,2 @@ +export * from './getRunTimeParameterValuesForRun' +export * from './getRunTimeParameterFilesForRun' diff --git a/components/src/atoms/Checkbox/index.tsx b/components/src/atoms/Checkbox/index.tsx index 58da8c1fe4b..db8972d6dda 100644 --- a/components/src/atoms/Checkbox/index.tsx +++ b/components/src/atoms/Checkbox/index.tsx @@ -26,6 +26,10 @@ export interface CheckboxProps { tabIndex?: number /** if disabled is true, mouse events will not trigger onClick callback */ disabled?: boolean + /** optional borderRadius type */ + type?: 'round' | 'neutral' + /** optional width for helix */ + width?: string } export function Checkbox(props: CheckboxProps): JSX.Element { const { @@ -34,18 +38,22 @@ export function Checkbox(props: CheckboxProps): JSX.Element { onClick, tabIndex = 0, disabled = false, + width = FLEX_MAX_CONTENT, + type = 'round', } = props const truncatedLabel = truncateString(labelText, 25) const CHECKBOX_STYLE = css` - width: ${FLEX_MAX_CONTENT}; + width: ${width}; grid-gap: ${SPACING.spacing12}; border: none; align-items: ${ALIGN_CENTER}; flex-direction: ${DIRECTION_ROW}; color: ${isChecked ? COLORS.white : COLORS.black90}; background-color: ${isChecked ? COLORS.blue50 : COLORS.blue35}; - border-radius: ${BORDERS.borderRadiusFull}; + border-radius: ${type === 'round' + ? BORDERS.borderRadiusFull + : BORDERS.borderRadius8}; padding: ${SPACING.spacing12} ${SPACING.spacing16}; justify-content: ${JUSTIFY_SPACE_BETWEEN}; cursor: ${CURSOR_POINTER}; diff --git a/components/src/atoms/CheckboxField/index.tsx b/components/src/atoms/CheckboxField/index.tsx index ae7134fcbb5..08efd6796f6 100644 --- a/components/src/atoms/CheckboxField/index.tsx +++ b/components/src/atoms/CheckboxField/index.tsx @@ -4,7 +4,12 @@ import { SPACING, TYPOGRAPHY } from '../../ui-style-constants' import { COLORS, BORDERS } from '../../helix-design-system' import { Flex, Box } from '../../primitives' import { Icon } from '../../icons' -import { ALIGN_CENTER, CURSOR_POINTER, JUSTIFY_CENTER } from '../../styles' +import { + ALIGN_CENTER, + CURSOR_AUTO, + CURSOR_POINTER, + JUSTIFY_CENTER, +} from '../../styles' export interface CheckboxFieldProps { /** change handler */ @@ -94,7 +99,8 @@ const INNER_STYLE_NO_VALUE = css` } &:disabled { - color: ${COLORS.grey60}; + color: ${COLORS.grey50}; + cursor: ${CURSOR_AUTO}; } ` diff --git a/components/src/molecules/DropdownMenu/index.tsx b/components/src/molecules/DropdownMenu/index.tsx index 632fafbe367..a0260b97596 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -23,6 +23,7 @@ import { useOnClickOutside } from '../../interaction-enhancers' import { LegacyStyledText } from '../../atoms/StyledText/LegacyStyledText' import { MenuItem } from '../../atoms/MenuList/MenuItem' import { Tooltip } from '../../atoms/Tooltip' +import { StyledText } from '../../atoms/StyledText' import { LiquidIcon } from '../LiquidIcon' /** this is the max height to display 10 items */ @@ -36,6 +37,7 @@ export interface DropdownOption { value: string /** optional dropdown option for adding the liquid color icon */ liquidColor?: string + disabled?: boolean } export type DropdownBorder = 'rounded' | 'neutral' @@ -56,9 +58,11 @@ export interface DropdownMenuProps { /** dropdown item caption */ caption?: string | null /** text for tooltip */ - tooltipText?: string + tooltipText?: string | null /** html tabindex property */ tabIndex?: number + /** optional error */ + error?: string | null } // TODO: (smb: 4/15/22) refactor this to use html select for accessibility @@ -74,6 +78,7 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { caption, tooltipText, tabIndex = 0, + error, } = props const [targetProps, tooltipProps] = useHoverTooltip() const [showDropdownMenu, setShowDropdownMenu] = React.useState(false) @@ -139,13 +144,22 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { const isDisabled = filterOptions.length === 0 + let defaultBorderColor = COLORS.grey50 + let hoverBorderColor = COLORS.grey55 + if (showDropdownMenu) { + defaultBorderColor = COLORS.blue50 + hoverBorderColor = COLORS.blue50 + } else if (error) { + defaultBorderColor = COLORS.red50 + hoverBorderColor = COLORS.red50 + } + const DROPDOWN_STYLE = css` flex-direction: ${DIRECTION_ROW}; background-color: ${COLORS.white}; cursor: ${isDisabled ? CURSOR_DEFAULT : CURSOR_POINTER}; padding: ${SPACING.spacing8} ${SPACING.spacing12}; - border: 1px ${BORDERS.styleSolid} - ${showDropdownMenu ? COLORS.blue50 : COLORS.grey50}; + border: 1px ${BORDERS.styleSolid} ${defaultBorderColor}; border-radius: ${dropdownType === 'rounded' ? BORDERS.borderRadiusFull : BORDERS.borderRadius4}; @@ -155,13 +169,11 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { height: 2.25rem; &:hover { - border: 1px ${BORDERS.styleSolid} - ${showDropdownMenu ? COLORS.blue50 : COLORS.grey55}; + border: 1px ${BORDERS.styleSolid} ${hoverBorderColor}; } &:active { - border: 1px ${BORDERS.styleSolid} - ${isDisabled ? COLORS.grey55 : COLORS.blue50}; + border: 1px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.blue50}; } &:focus-visible { @@ -176,16 +188,16 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { } ` return ( - + {title !== null ? ( - - + + {title} - + {tooltipText != null ? ( <> @@ -214,18 +226,20 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { {currentOption.liquidColor != null ? ( ) : null} - - {currentOption.name} - + + {currentOption.name} + + {showDropdownMenu ? ( @@ -269,14 +283,15 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { )} {caption != null ? ( - + {caption} ) : null} + {error != null ? ( + + {error} + + ) : null} ) } diff --git a/components/src/organisms/Toolbox/index.tsx b/components/src/organisms/Toolbox/index.tsx index 25796ebd190..77ac2e12d68 100644 --- a/components/src/organisms/Toolbox/index.tsx +++ b/components/src/organisms/Toolbox/index.tsx @@ -25,7 +25,7 @@ export interface ToolboxProps { closeButtonText?: string side?: 'left' | 'right' horizontalSide?: 'top' | 'bottom' - padding?: string + childrenPadding?: string } export function Toolbox(props: ToolboxProps): JSX.Element { @@ -42,7 +42,7 @@ export function Toolbox(props: ToolboxProps): JSX.Element { confirmButton, side = 'right', horizontalSide = 'bottom', - padding = SPACING.spacing16, + childrenPadding = SPACING.spacing16, } = props const slideOutRef = React.useRef(null) @@ -110,7 +110,7 @@ export function Toolbox(props: ToolboxProps): JSX.Element { ) : null} +
{enableRedesign ? ( diff --git a/protocol-designer/src/assets/localization/en/create_new_protocol.json b/protocol-designer/src/assets/localization/en/create_new_protocol.json index 0a832517db9..463d2c67268 100644 --- a/protocol-designer/src/assets/localization/en/create_new_protocol.json +++ b/protocol-designer/src/assets/localization/en/create_new_protocol.json @@ -25,7 +25,7 @@ "remove": "Remove", "rename_error": "Labware names must be 115 characters or fewer.", "rename_labware": "Rename labware", - "robot_pips": "Robot pipettes", + "robot_pipettes": "Robot pipettes", "robot_type": "What kind of robot do you have?", "show_all_tips": "Show all tips", "show_default_tips": "Show default tips", diff --git a/protocol-designer/src/assets/localization/en/protocol_steps.json b/protocol-designer/src/assets/localization/en/protocol_steps.json index dc06ab1bbe4..42e8c91064f 100644 --- a/protocol-designer/src/assets/localization/en/protocol_steps.json +++ b/protocol-designer/src/assets/localization/en/protocol_steps.json @@ -2,9 +2,11 @@ "delete": "Delete step", "duplicate": "Duplicate step", "final_deck_state": "Final deck state", + "new_location": "New location", "protocol_steps": "Protocol steps", "protocol_timeline": "Protocol timeline", "rename": "Rename step", + "select_labware": "Select labware", "starting_deck_state": "Starting deck state", "view_commands": "View commands" } diff --git a/protocol-designer/src/assets/localization/en/shared.json b/protocol-designer/src/assets/localization/en/shared.json index afe8f157fa5..6e86fc6e607 100644 --- a/protocol-designer/src/assets/localization/en/shared.json +++ b/protocol-designer/src/assets/localization/en/shared.json @@ -119,6 +119,6 @@ "wasteChute": "Waste chute", "wasteChuteAndStagingArea": "Waste chute and staging area slot", "we_are_improving": "We’re working to improve Protocol Designer. Part of the process involves watching real user sessions to understand which parts of the interface are working and which could use improvement. We never share sessions outside of Opentrons.", - "welcome": "Welcome to Protocol Designer", + "welcome": "Welcome to Protocol Designer!", "yes": "Yes" } diff --git a/protocol-designer/src/assets/localization/en/starting_deck_state.json b/protocol-designer/src/assets/localization/en/starting_deck_state.json index 6886098ddbf..43b6499b218 100644 --- a/protocol-designer/src/assets/localization/en/starting_deck_state.json +++ b/protocol-designer/src/assets/localization/en/starting_deck_state.json @@ -19,6 +19,7 @@ "duplicate": "Duplicate labware", "edit_hw_lw": "Edit hardware/labware", "edit_labware": "Edit labware", + "edit_liquid": "Edit liquid", "edit_protocol": "Edit protocol", "edit_slot": "Edit slot", "edit": "Edit", diff --git a/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx b/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx index 294960d7cde..dcbf677a254 100644 --- a/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx +++ b/protocol-designer/src/components/StepEditForm/fields/LabwareLocationField/index.tsx @@ -22,8 +22,8 @@ export function LabwareLocationField( useGripper: boolean } & { canSave: boolean } & { labware: string } ): JSX.Element { - const { t } = useTranslation('form') const { labware, useGripper, value } = props + const { t } = useTranslation('form') const additionalEquipmentEntities = useSelector( getAdditionalEquipmentEntities ) diff --git a/protocol-designer/src/components/portals/TopPortal.tsx b/protocol-designer/src/components/portals/TopPortal.tsx index 10eec819895..6e503924e6c 100644 --- a/protocol-designer/src/components/portals/TopPortal.tsx +++ b/protocol-designer/src/components/portals/TopPortal.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import { Box } from '@opentrons/components' const PORTAL_ROOT_ID = 'top-portal-root' @@ -6,5 +7,5 @@ export const getTopPortalEl = (): HTMLElement => document.getElementById(PORTAL_ROOT_ID) ?? document.body export function PortalRoot(): JSX.Element { - return
+ return } diff --git a/protocol-designer/src/molecules/CheckboxStepFormField/index.tsx b/protocol-designer/src/molecules/CheckboxStepFormField/index.tsx new file mode 100644 index 00000000000..99511d2461d --- /dev/null +++ b/protocol-designer/src/molecules/CheckboxStepFormField/index.tsx @@ -0,0 +1,59 @@ +import * as React from 'react' +import { + Checkbox, + Flex, + SPACING, + TOOLTIP_TOP, + Tooltip, + useHoverTooltip, +} from '@opentrons/components' +import type { Placement } from '@opentrons/components' +import type { FieldProps } from '../../pages/Designer/ProtocolSteps/StepForm/types' + +type CheckboxStepFormFieldProps = FieldProps & { + children?: React.ReactElement + label?: string + tooltipContent?: React.ReactNode + tooltipPlacement?: Placement +} + +export function CheckboxStepFormField( + props: CheckboxStepFormFieldProps +): JSX.Element { + const { + disabled, + isIndeterminate, + label, + tooltipContent, + updateValue, + value, + children, + tooltipPlacement = TOOLTIP_TOP, + } = props + + const [targetProps, tooltipProps] = useHoverTooltip({ + placement: tooltipPlacement, + }) + return ( + <> + {tooltipContent && ( + {tooltipContent} + )} + + + { + updateValue(!value) + }} + labelText={label ?? ''} + disabled={disabled} + /> + + {value && !disabled && !isIndeterminate ? children : null} + + + ) +} diff --git a/protocol-designer/src/molecules/DropdownStepFormField/index.tsx b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx new file mode 100644 index 00000000000..41faf034b0c --- /dev/null +++ b/protocol-designer/src/molecules/DropdownStepFormField/index.tsx @@ -0,0 +1,34 @@ +import * as React from 'react' +import { DropdownMenu, Flex, SPACING } from '@opentrons/components' +import type { Options } from '@opentrons/components' +import type { FieldProps } from '../../pages/Designer/ProtocolSteps/StepForm/types' + +export interface DropdownStepFormFieldProps extends FieldProps { + options: Options + title: string +} + +export function DropdownStepFormField( + props: DropdownStepFormFieldProps +): JSX.Element { + const { options, value, updateValue, title, errorToShow } = props + const availableOptionId = options.find(opt => opt.value === value) + + return ( + + { + updateValue(value) + }} + /> + + ) +} diff --git a/protocol-designer/src/molecules/index.ts b/protocol-designer/src/molecules/index.ts index ae458bce67b..b12df75dc80 100644 --- a/protocol-designer/src/molecules/index.ts +++ b/protocol-designer/src/molecules/index.ts @@ -1 +1,3 @@ +export * from './CheckboxStepFormField' +export * from './DropdownStepFormField' export * from './SettingsIcon' diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/AddMetadata.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/AddMetadata.tsx index da621add9f4..d44823d22c7 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/AddMetadata.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/AddMetadata.tsx @@ -41,11 +41,7 @@ export function AddMetadata(props: WizardTileProps): JSX.Element | null { proceed(1) }} > - + {t('name')} {/* TODO(ja, 8/9/24): add new input field */} diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx index e07ff5fc526..635a84f6dd3 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectFixtures.tsx @@ -80,45 +80,40 @@ export function SelectFixtures(props: WizardTileProps): JSX.Element | null { }} proceed={handleProceed} > - - - + + + {t('which_fixtures')} + + + {filteredAdditionalEquipment.map(equipment => ( + { + if (numSlotsAvailable === 0) { + makeSnackbar(t('slots_limit_reached') as string) + } else { + setValue('additionalEquipment', [ + ...additionalEquipment, + equipment, + ]) + } + }} + /> + ))} + - - {filteredAdditionalEquipment.map(equipment => ( - { - if (numSlotsAvailable === 0) { - makeSnackbar(t('slots_limit_reached') as string) - } else { - setValue('additionalEquipment', [ - ...additionalEquipment, - equipment, - ]) - } - }} - /> - ))} - - - + + {t('fixtures_added')} - + {filteredDuplicateStagingAreas.map(ae => { const numStagingAreas = filteredAdditionalEquipmentWithoutGripper.filter( additionalEquipment => additionalEquipment === 'stagingArea' diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectGripper.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectGripper.tsx index fcbb8a47d4c..cc3b44a06e9 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectGripper.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectGripper.tsx @@ -50,30 +50,29 @@ export function SelectGripper(props: WizardTileProps): JSX.Element | null { }} proceed={handleProceed} > - - - {t('need_gripper')} - - - { - handleGripperSelection('yes') - }} - buttonLabel={t('shared:yes')} - buttonValue="yes" - isSelected={gripperStatus === 'yes'} - /> - { - handleGripperSelection('no') - }} - buttonLabel={t('shared:no')} - buttonValue="no" - isSelected={gripperStatus === 'no'} - /> + + + + {t('need_gripper')} + + + { + handleGripperSelection('yes') + }} + buttonLabel={t('shared:yes')} + buttonValue="yes" + isSelected={gripperStatus === 'yes'} + /> + { + handleGripperSelection('no') + }} + buttonLabel={t('shared:no')} + buttonValue="no" + isSelected={gripperStatus === 'no'} + /> + diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx index bf47b8303da..0a2c843bf7c 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectModules.tsx @@ -110,13 +110,10 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null { proceed(1) }} > - - + + {filteredSupportedModules.length > 0 ? ( - + {t('which_mods')} ) : null} @@ -169,13 +166,11 @@ export function SelectModules(props: WizardTileProps): JSX.Element | null { Object.keys(modules).length > 0 && Object.keys(filteredModules).length > 0 ? ( - + {t('modules_added')} { const num = parseInt(value) const moamModules = diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx index 261d658b297..6524a6efbd1 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx @@ -52,6 +52,8 @@ import type { WizardTileProps, } from './types' +const MAX_TIPRACKS_ALLOWED = 3 + export function SelectPipettes(props: WizardTileProps): JSX.Element | null { const { goBack, proceed, watch, setValue } = props const { t } = useTranslation(['create_new_protocol', 'shared']) @@ -73,7 +75,7 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { const robotType = fields.robotType const defaultMount = mount ?? 'left' const has96Channel = pipettesByMount.left.pipetteName === 'p1000_96' - const selectedPip = + const selectedPipetteName = pipetteType === '96' || pipetteGen === 'GEN1' ? `${pipetteVolume}_${pipetteType}` : `${pipetteVolume}_${pipetteType}_${pipetteGen.toLowerCase()}` @@ -88,10 +90,18 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { // initialize pipette name once all fields are filled out React.useEffect(() => { - if (pipetteType != null && pipetteVolume != null) { - setValue(`pipettesByMount.${defaultMount}.pipetteName`, selectedPip) + if ( + (pipetteType != null && + pipetteVolume != null && + robotType === FLEX_ROBOT_TYPE) || + (robotType === OT2_ROBOT_TYPE && pipetteGen != null) + ) { + setValue( + `pipettesByMount.${defaultMount}.pipetteName`, + selectedPipetteName + ) } - }, [pipetteType, pipetteGen, pipetteVolume, selectedPip]) + }, [pipetteType, pipetteGen, pipetteVolume, selectedPipetteName]) const isDisabled = page === 'add' && pipettesByMount[defaultMount].tiprackDefURI == null @@ -117,7 +127,7 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { { @@ -137,24 +147,23 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { > {page === 'add' ? ( - <> - + + {t('pip_type')} {PIPETTE_TYPES[robotType].map(type => { return type.value === '96' && - (pipettesByMount.left.pipetteName != null || - pipettesByMount.right.pipetteName != null) ? null : ( + pipettesByMount.left.pipetteName != null && + pipettesByMount.right.pipetteName != null ? null : ( { @@ -177,16 +186,14 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { ) })} - + + {pipetteType != null && robotType === OT2_ROBOT_TYPE ? ( - + {t('pip_gen')} @@ -211,12 +218,9 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { robotType === OT2_ROBOT_TYPE) ? ( - + {t('pip_vol')} @@ -264,61 +268,63 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { ) : null} - {allPipetteOptions.includes(selectedPip as PipetteName) + {allPipetteOptions.includes(selectedPipetteName as PipetteName) ? (() => { const tiprackOptions = getTiprackOptions({ - allLabware: allLabware, - allowAllTipracks: allowAllTipracks, - selectedPipetteName: selectedPip, + allLabware, + allowAllTipracks, + selectedPipetteName, }) return ( - - {t('pip_tips')} - - - {Object.entries(tiprackOptions).map( - ([value, name]) => ( - { - const updatedValues = selectedValues.includes( - value - ) - ? selectedValues.filter(v => v !== value) - : [...selectedValues, value] - setValue( - `pipettesByMount.${defaultMount}.tiprackDefURI`, - updatedValues.slice(0, 3) - ) - if (selectedValues.length === 3) { - makeSnackbar( - t('up_to_3_tipracks') as string - ) - } - }} - /> - ) - )} - + + {t('pip_tips')} + + + {Object.entries(tiprackOptions).map( + ([value, name]) => ( + { + const updatedValues = selectedValues.includes( + value + ) + ? selectedValues.filter(v => v !== value) + : [...selectedValues, value] + setValue( + `pipettesByMount.${defaultMount}.tiprackDefURI`, + updatedValues.slice(0, 3) + ) + if ( + selectedValues.length === + MAX_TIPRACKS_ALLOWED + ) { + makeSnackbar( + t('up_to_3_tipracks') as string + ) + } + }} + /> + ) + )} + + + {t('add_custom_tips')} @@ -363,13 +369,9 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { : null} ) : ( - + diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectRobot.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectRobot.tsx index 68d9856e760..7abc5d2b47d 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectRobot.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectRobot.tsx @@ -28,14 +28,10 @@ export function SelectRobot(props: WizardTileProps): JSX.Element { proceed(1) }} > - - + + {t('robot_type')} - { diff --git a/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx b/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx index 498a9392685..2bee3452bd8 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/WizardBody.tsx @@ -54,30 +54,28 @@ export function WizardBody(props: WizardBodyProps): JSX.Element { borderRadius={BORDERS.borderRadius16} justifyContent={JUSTIFY_SPACE_BETWEEN} > - + {t('shared:step_count', { current: stepNumber })} - - {header} - - {subHeader != null ? ( - - {subHeader} - - ) : null} - {children} + + + {header} + {subHeader != null ? ( + + {subHeader} + + ) : null} + + {children} + 0 + const slotOverflowBody = ( <> {showNickNameModal && nickNameId != null ? ( @@ -214,7 +227,7 @@ export function SlotOverflowMenu( }} > - {t('add_liquid')} + {selectionHasLiquids ? t('edit_liquid') : t('add_liquid')} diff --git a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/SlotOverflowMenu.test.tsx b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/SlotOverflowMenu.test.tsx index ad2841337f8..56acf2873d6 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/__tests__/SlotOverflowMenu.test.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/__tests__/SlotOverflowMenu.test.tsx @@ -14,6 +14,7 @@ import { EditNickNameModal } from '../../../../organisms' import { deleteModule } from '../../../../step-forms/actions' import { deleteDeckFixture } from '../../../../step-forms/actions/additionalItems' import { getDeckSetupForActiveItem } from '../../../../top-selectors/labware-locations' +import { selectors as labwareIngredSelectors } from '../../../../labware-ingred/selectors' import { SlotOverflowMenu } from '../SlotOverflowMenu' import type { NavigateFunction } from 'react-router-dom' @@ -24,6 +25,7 @@ const mockNavigate = vi.fn() vi.mock('../../../../top-selectors/labware-locations') vi.mock('../../../../step-forms/actions') vi.mock('../../../../labware-ingred/actions') +vi.mock('../../../../labware-ingred/selectors') vi.mock('../../../../step-forms/actions/additionalItems') vi.mock('../../../../organisms') vi.mock('react-router-dom', async importOriginal => { @@ -82,7 +84,9 @@ describe('SlotOverflowMenu', () => { vi.mocked(EditNickNameModal).mockReturnValue(
mockEditNickNameModal
) + vi.mocked(labwareIngredSelectors.getLiquidsByLabwareId).mockReturnValue({}) }) + it('should renders all buttons as enabled and clicking on them calls ctas', () => { render(props) fireEvent.click( @@ -114,4 +118,17 @@ describe('SlotOverflowMenu', () => { expect(props.setShowMenuList).toHaveBeenCalled() expect(screen.getAllByRole('button')).toHaveLength(2) }) + it('renders Edit liquid button when there is liquid on the labware', () => { + vi.mocked(labwareIngredSelectors.getLiquidsByLabwareId).mockReturnValue({ + labId2: { well1: { '0': { volume: 10 } } }, + }) + render(props) + fireEvent.click( + screen.getByRole('button', { name: 'Edit hardware/labware' }) + ) + + fireEvent.click(screen.getByRole('button', { name: 'Edit liquid' })) + expect(mockNavigate).toHaveBeenCalled() + expect(vi.mocked(openIngredientSelector)).toHaveBeenCalled() + }) }) diff --git a/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx b/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx index 08c3b7c780a..f5b271ed685 100644 --- a/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx +++ b/protocol-designer/src/pages/Designer/Offdeck/OffDeckDetails.tsx @@ -50,7 +50,7 @@ export function OffDeckDetails(props: OffDeckDetailsProps): JSX.Element { ) })} - - - + {tab === 'startingDeck' ? ( + + + + ) : null}
diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx index 2e316af83bb..246794ffc9c 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx @@ -93,6 +93,7 @@ export function StepFormToolbox(props: StepFormToolboxProps): JSX.Element { /> */} option.value !== 'offDeck' + ) + } + + if (!useGripper && getHasWasteChute(additionalEquipmentEntities)) { + unoccupiedLabwareLocationsOptions = unoccupiedLabwareLocationsOptions.filter( + option => option.value !== WASTE_CHUTE_CUTOUT + ) + } + + const location: string = value as string + + const bothFieldsSelected = labware != null && value != null + const labwareDisplayName = + labware != null ? labwareEntities[labware]?.def.metadata.displayName : '' + let locationString = `slot ${location}` + if (location != null) { + if (robotState?.modules[location] != null) { + const moduleSlot = robotState?.modules[location].slot ?? '' + locationString = `${getModuleDisplayName( + moduleEntities[location].model + )} in slot ${moduleSlot}` + } else if (robotState?.labware[location] != null) { + const adapterSlot = robotState?.labware[location].slot + locationString = + robotState?.modules[adapterSlot] != null + ? `${getModuleDisplayName( + moduleEntities[adapterSlot].model + )} in slot ${robotState?.modules[adapterSlot].slot}` + : `slot ${robotState?.labware[location].slot}` ?? '' + } + } + return ( + + ) +} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx new file mode 100644 index 00000000000..fdc24facebd --- /dev/null +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx @@ -0,0 +1,18 @@ +import * as React from 'react' +import { useSelector } from 'react-redux' +import { useTranslation } from 'react-i18next' +import { getMoveLabwareOptions } from '../../../../../../ui/labware/selectors' +import { DropdownStepFormField } from '../../../../../../molecules' +import type { FieldProps } from '../../types' + +export function MoveLabwareField(props: FieldProps): JSX.Element { + const options = useSelector(getMoveLabwareOptions) + const { t } = useTranslation('protocol_steps') + return ( + + ) +} diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/index.tsx index 1343331cbaf..db856549b3f 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/index.tsx @@ -1,5 +1,56 @@ import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' +import { Box, COLORS, DIRECTION_COLUMN, Flex } from '@opentrons/components' +import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' +import { getRobotType } from '../../../../../../file-data/selectors' +import { CheckboxStepFormField } from '../../../../../../molecules' +import { + getAdditionalEquipment, + getCurrentFormCanBeSaved, +} from '../../../../../../step-forms/selectors' +import { MoveLabwareField } from './MoveLabwareField' +import { LabwareLocationField } from './LabwareLocationField' -export function MoveLabwareTools(): JSX.Element { - return
TODO: wire this up
+import type { StepFormProps } from '../../types' + +export function MoveLabwareTools(props: StepFormProps): JSX.Element { + const { propsForFields } = props + const { t, i18n } = useTranslation(['application', 'form', 'tooltip']) + const robotType = useSelector(getRobotType) + const canSave = useSelector(getCurrentFormCanBeSaved) + const additionalEquipment = useSelector(getAdditionalEquipment) + const isGripperAttached = Object.values(additionalEquipment).some( + equipment => equipment?.name === 'gripper' + ) + + return ( + + {robotType === FLEX_ROBOT_TYPE ? ( + + ) : null} + + + + + + + ) } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx index e945ad3f64f..7da23cda081 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx @@ -19,6 +19,7 @@ import { import { getUnsavedForm } from '../../../../step-forms/selectors' import { getTopPortalEl } from '../../../../components/portals/TopPortal' import { StepOverflowMenu } from './StepOverflowMenu' +import { capitalizeFirstLetterAfterNumber } from './utils' import type { IconName } from '@opentrons/components' @@ -99,6 +100,7 @@ export function StepContainer(props: StepContainerProps): JSX.Element { setStepOverflowMenu(false) } } + return ( <> @@ -126,7 +128,7 @@ export function StepContainer(props: StepContainerProps): JSX.Element { )} {formData != null ? null : ( - {title} + {capitalizeFirstLetterAfterNumber(title)} )}
diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/utils.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/utils.test.tsx new file mode 100644 index 00000000000..1d6c2149c95 --- /dev/null +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/utils.test.tsx @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest' +import { capitalizeFirstLetterAfterNumber } from '../utils' + +describe('capitalizeFirstLetterAfterNumber', () => { + it('should capitalize the first letter of a step type', () => { + expect(capitalizeFirstLetterAfterNumber('1. heater-shaker')).toBe( + '1. Heater-shaker' + ) + expect(capitalizeFirstLetterAfterNumber('22. thermocycler')).toBe( + '22. Thermocycler' + ) + }) +}) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/utils.ts b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/utils.ts new file mode 100644 index 00000000000..660ac545474 --- /dev/null +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/utils.ts @@ -0,0 +1,5 @@ +export const capitalizeFirstLetterAfterNumber = (title: string): string => + title.replace( + /(^[\d\W]*)([a-zA-Z])/, + (match, prefix, firstLetter) => `${prefix}${firstLetter.toUpperCase()}` + ) 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 7b2834c7e3d..11747efd1ab 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/__tests__/ProtocolSteps.test.tsx @@ -1,11 +1,16 @@ 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 '@testing-library/jest-dom/vitest' +import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../../__testing-utils__' +import { getUnsavedForm } from '../../../../step-forms/selectors' import { DeckSetupContainer } from '../../DeckSetup' -import { TimelineToolbox } from '../Timeline' +import { OffDeck } from '../../Offdeck' import { ProtocolSteps } from '..' +import { TimelineToolbox } from '../Timeline' +vi.mock('../../Offdeck') +vi.mock('../../../../step-forms/selectors') vi.mock('../StepForm') vi.mock('../../DeckSetup') vi.mock('../Timeline') @@ -14,13 +19,34 @@ const render = () => { } describe('ProtocolSteps', () => { - it('renders each component in ProtocolSteps', () => { + beforeEach(() => { vi.mocked(TimelineToolbox).mockReturnValue(
mock TimelineToolbox
) vi.mocked(DeckSetupContainer).mockReturnValue(
mock DeckSetupContainer
) + vi.mocked(OffDeck).mockReturnValue(
mock OffDeck
) + vi.mocked(getUnsavedForm).mockReturnValue(null) + }) + + it('renders each component in ProtocolSteps', () => { render() screen.getByText('mock TimelineToolbox') screen.getByText('mock DeckSetupContainer') }) + + it('renders the toggle when formData is null', () => { + render() + screen.getByText('mock DeckSetupContainer') + fireEvent.click(screen.getByText('offDeck')) + 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('offDeck')).not.toBeInTheDocument() + }) }) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx index 62189202c96..ba5b73aba25 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx @@ -1,18 +1,70 @@ import * as React from 'react' -import { COLORS, Flex, POSITION_ABSOLUTE, SPACING } from '@opentrons/components' +import { useSelector } from 'react-redux' +import { useTranslation } from 'react-i18next' +import { + ALIGN_CENTER, + COLORS, + DIRECTION_COLUMN, + Flex, + JUSTIFY_CENTER, + SPACING, + ToggleGroup, +} from '@opentrons/components' +import { getUnsavedForm } from '../../../step-forms/selectors' import { DeckSetupContainer } from '../DeckSetup' +import { OffDeck } from '../Offdeck' import { TimelineToolbox } from './Timeline' import { StepForm } from './StepForm' export function ProtocolSteps(): JSX.Element { + const { t } = useTranslation(['starting_deck_state']) + const formData = useSelector(getUnsavedForm) + const leftString = t('onDeck') + const rightString = t('offDeck') + + const [deckView, setDeckView] = React.useState< + typeof leftString | typeof rightString + >(leftString) + + const formType = formData?.stepType + + React.useEffect(() => { + if (formData != null && formType !== 'moveLabware') { + setDeckView(leftString) + } + }, [formData, formType, deckView]) + return ( <> - - - - + + - + {formData == null || formType === 'moveLabware' ? ( + { + setDeckView(leftString) + }} + rightClick={() => { + setDeckView(rightString) + }} + /> + ) : null} + {deckView === leftString ? ( + + ) : ( + + )} ) diff --git a/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx b/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx index b340fc6d471..aad8d261588 100644 --- a/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx +++ b/protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx @@ -33,7 +33,7 @@ describe('Landing', () => { it('renders the landing page image and text', () => { render() screen.getByLabelText('welcome image') - screen.getByText('Welcome to Protocol Designer') + screen.getByText('Welcome to Protocol Designer!') screen.getByText( 'The easiest way to automate liquid handling on your Opentrons robot. No code required.' ) diff --git a/protocol-designer/src/pages/Landing/index.tsx b/protocol-designer/src/pages/Landing/index.tsx index 80c2d022d43..1fb00c32da4 100644 --- a/protocol-designer/src/pages/Landing/index.tsx +++ b/protocol-designer/src/pages/Landing/index.tsx @@ -9,6 +9,7 @@ import { CURSOR_POINTER, DIRECTION_COLUMN, Flex, + JUSTIFY_CENTER, LargeButton, SPACING, StyledText, @@ -19,6 +20,7 @@ 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' export function Landing(): JSX.Element { @@ -45,32 +47,40 @@ export function Landing(): JSX.Element { backgroundColor={COLORS.grey20} flexDirection={DIRECTION_COLUMN} alignItems={ALIGN_CENTER} - paddingTop="14.875rem" - height="calc(100vh - 56px)" + justifyContent={JUSTIFY_CENTER} + height="calc(100vh - 3.5rem)" width="100%" + gridGap={SPACING.spacing32} > - - - {t('welcome')} - - - {t('no-code-required')} - + + + + + {t('welcome')} + + + {t('no-code-required')} + + + { dispatch(toggleNewProtocolModal(true)) }} - marginY={SPACING.spacing32} buttonText={ @@ -79,7 +89,6 @@ export function Landing(): JSX.Element { } /> - diff --git a/protocol-designer/src/pages/ProtocolOverview/index.tsx b/protocol-designer/src/pages/ProtocolOverview/index.tsx index 91b7d5d6367..818a5b5a0c7 100644 --- a/protocol-designer/src/pages/ProtocolOverview/index.tsx +++ b/protocol-designer/src/pages/ProtocolOverview/index.tsx @@ -33,6 +33,7 @@ import { FLEX_ROBOT_TYPE, OT2_ROBOT_TYPE, } from '@opentrons/shared-data' + import { getAdditionalEquipmentEntities, getInitialDeckSetup, @@ -336,36 +337,31 @@ export function ProtocolOverview(): JSX.Element { - - + + {t('protocol_metadata')} - { - setShowEditMetadataModal(true) - }} - css={BUTTON_LINK_STYLE} - data-testid="ProtocolOverview_MetadataEditButton" - > - - {t('edit')} - - + + { + setShowEditMetadataModal(true) + }} + css={BUTTON_LINK_STYLE} + data-testid="ProtocolOverview_MetadataEditButton" + > + + {t('edit')} + + + - + {metaDataInfo.map(info => { const [title, value] = Object.entries(info)[0] @@ -379,36 +375,35 @@ export function ProtocolOverview(): JSX.Element { ) })} + + + - - - - - + + {t('instruments')} - { - setShowEditInstrumentsModal(true) - }} - css={BUTTON_LINK_STYLE} - > - - {t('edit')} - - + + { + setShowEditInstrumentsModal(true) + }} + css={BUTTON_LINK_STYLE} + > + + {t('edit')} + + + @@ -457,12 +452,10 @@ export function ProtocolOverview(): JSX.Element { ) : null} - - - - {t('liquid_defs')} - - + + + {t('liquid_defs')} + {Object.keys(allIngredientGroupFields).length > 0 ? ( Object.values(allIngredientGroupFields).map( @@ -494,8 +487,8 @@ export function ProtocolOverview(): JSX.Element { )} - - + + {t('step')} @@ -517,28 +510,33 @@ export function ProtocolOverview(): JSX.Element { - + - + {t('starting_deck')} - { - setShowMaterialsListModal(true) - }} - css={BUTTON_LINK_STYLE} - > - - {t('materials_list')} - - + + { + setShowMaterialsListModal(true) + }} + css={BUTTON_LINK_STYLE} + > + + {t('materials_list')} + + + - + {deckView === leftString ? ( ) : ( diff --git a/robot-server/robot_server/app_setup.py b/robot-server/robot_server/app_setup.py index 736991100ca..2a4d8b1f3da 100644 --- a/robot-server/robot_server/app_setup.py +++ b/robot-server/robot_server/app_setup.py @@ -1,7 +1,6 @@ """Main FastAPI application.""" -import asyncio -import logging -from typing import Optional +import contextlib +from typing import AsyncGenerator, Optional from pathlib import Path from fastapi import FastAPI @@ -11,13 +10,9 @@ from .errors.exception_handlers import exception_handlers from .hardware import ( - fbl_init, - fbl_mark_hardware_init_complete, - fbl_mark_persistence_init_complete, + FrontButtonLightBlinker, start_initializing_hardware, clean_up_hardware, - fbl_start_blinking, - fbl_clean_up, ) from .persistence.fastapi_dependencies import ( start_initializing_persistence, @@ -25,29 +20,78 @@ ) from .router import router from .service.logging import initialize_logging -from .service.task_runner import ( - initialize_task_runner, - clean_up_task_runner, -) -from .settings import get_settings +from .service.task_runner import set_up_task_runner +from .settings import RobotServerSettings, get_settings from .runs.dependencies import ( start_light_control_task, mark_light_control_startup_finished, ) from .service.notifications import ( - initialize_notifications, - clean_up_notification_client, + set_up_notification_client, + initialize_pe_publisher_notifier, ) -log = logging.getLogger(__name__) + +@contextlib.asynccontextmanager +async def _lifespan(app: FastAPI) -> AsyncGenerator[None, None]: + """The server's startup and shutdown logic. + + Entering this context manager sets up our custom global objects + so they'll be ready when we process requests. + + Exiting this context manager cleans everything up. + """ + async with contextlib.AsyncExitStack() as exit_stack: + settings = get_settings() + persistence_directory = _get_persistence_directory(settings) + + initialize_logging() + + await exit_stack.enter_async_context(set_up_task_runner(app.state)) + + blinker = FrontButtonLightBlinker() + exit_stack.push_async_callback(blinker.clean_up) + + start_initializing_hardware( + app_state=app.state, + callbacks=[ + # Flex light control: + (start_light_control_task, True), + (mark_light_control_startup_finished, False), + # OT-2 light control: + (lambda _app_state, hw_api: blinker.start_blinking(hw_api), True), + ( + lambda _app_state, _hw_api: blinker.mark_hardware_init_complete(), + False, + ), + ], + ) + exit_stack.push_async_callback(clean_up_hardware, app.state) + + start_initializing_persistence( + app_state=app.state, + persistence_directory_root=persistence_directory, + done_callbacks=[ + # For OT-2 light control only. The Flex status bar isn't handled here + # because it's currently tied to hardware and run status, not to + # initialization of the persistence layer. + blinker.mark_persistence_init_complete + ], + ) + exit_stack.push_async_callback(clean_up_persistence, app.state) + + exit_stack.enter_context(set_up_notification_client(app.state)) + initialize_pe_publisher_notifier(app.state) + + yield # Start handling HTTP requests. app = FastAPI( - title="Opentrons OT-2 HTTP API Spec", + title="Opentrons HTTP API Spec", description=( - "This OpenAPI spec describes the HTTP API of the Opentrons " - "OT-2. It may be retrieved from a robot on port 31950 at " + "This OpenAPI spec describes the HTTP API for Opentrons " + "robots. It may be retrieved from a robot on port 31950 at " "/openapi. Some schemas used in requests and responses use " "the `x-patternProperties` key to mean the JSON Schema " "`patternProperties` behavior." @@ -57,6 +101,7 @@ # Disable documentation hosting via Swagger UI, normally at /docs. # We instead focus on the docs hosted by ReDoc, at /redoc. docs_url=None, + lifespan=_lifespan, ) # cors @@ -72,62 +117,8 @@ app.include_router(router=router) -@app.on_event("startup") -async def on_startup() -> None: - """Handle app startup.""" - settings = get_settings() - +def _get_persistence_directory(settings: RobotServerSettings) -> Optional[Path]: if settings.persistence_directory == "automatically_make_temporary": - persistence_directory: Optional[Path] = None + return None else: - persistence_directory = settings.persistence_directory - - initialize_logging() - initialize_task_runner(app_state=app.state) - fbl_init(app_state=app.state) - start_initializing_hardware( - app_state=app.state, - callbacks=[ - # Flex light control: - (start_light_control_task, True), - (mark_light_control_startup_finished, False), - # OT-2 light control: - (fbl_start_blinking, True), - (fbl_mark_hardware_init_complete, False), - ], - ) - start_initializing_persistence( - app_state=app.state, - persistence_directory_root=persistence_directory, - done_callbacks=[ - # For OT-2 light control only. The Flex status bar isn't handled here - # because it's currently tied to hardware and run status, not to - # initialization of the persistence layer. - fbl_mark_persistence_init_complete - ], - ) - initialize_notifications( - app_state=app.state, - ) - - -@app.on_event("shutdown") -async def on_shutdown() -> None: - """Handle app shutdown.""" - # FIXME(mm, 2024-01-31): Cleaning up everything concurrently like this is prone to - # race conditions, e.g if we clean up hardware before we clean up the background - # task that's blinking the front button light (which uses the hardware). - # Startup and shutdown should be in FILO order. - shutdown_results = await asyncio.gather( - fbl_clean_up(app.state), - clean_up_hardware(app.state), - clean_up_persistence(app.state), - clean_up_task_runner(app.state), - clean_up_notification_client(app.state), - return_exceptions=True, - ) - - shutdown_errors = [r for r in shutdown_results if isinstance(r, BaseException)] - - for e in shutdown_errors: - log.warning("Error during shutdown", exc_info=e) + return settings.persistence_directory diff --git a/robot-server/robot_server/hardware.py b/robot-server/robot_server/hardware.py index e6a49ebed7f..2ccdba30105 100644 --- a/robot-server/robot_server/hardware.py +++ b/robot-server/robot_server/hardware.py @@ -74,9 +74,6 @@ _hw_api_accessor = AppStateAccessor[ThreadManagedHardware]("hardware_api") _init_task_accessor = AppStateAccessor["asyncio.Task[None]"]("hardware_init_task") -_front_button_light_blinker_accessor = AppStateAccessor["_FrontButtonLightBlinker"]( - "front_button_light_blinker" -) _postinit_task_accessor = AppStateAccessor["asyncio.Task[None]"]( "hardware_postinit_task" ) @@ -97,9 +94,6 @@ def start_initializing_hardware( """Initialize the hardware API singleton, attaching it to global state. Returns immediately while the hardware API initializes in the background. - - Any defined callbacks will be called after the hardware API is initialized, but - before the post-init tasks are executed. """ initialize_task = _init_task_accessor.get_from(app_state) @@ -133,7 +127,9 @@ async def clean_up_hardware(app_state: AppState) -> None: # TODO(mm, 2024-01-30): Consider merging this with the Flex's LightController. -class _FrontButtonLightBlinker: +class FrontButtonLightBlinker: + """Blinks the OT-2's front button light during certain stages of startup.""" + def __init__(self) -> None: self._hardware_and_task: Optional[ Tuple[HardwareControlAPI, "asyncio.Task[None]"] @@ -141,11 +137,27 @@ def __init__(self) -> None: self._hardware_init_complete = False self._persistence_init_complete = False - async def set_hardware(self, hardware: HardwareControlAPI) -> None: + async def start_blinking(self, hardware: HardwareControlAPI) -> None: + """Start blinking the OT-2's front button light. + + This should be called once during server startup, as soon as the hardware is + initialized enough to support the front button light. + + Note that this is preceded by two other visually indistinguishable stages of + blinking: + 1. A separate system process blinks the light while this process's Python + interpreter is initializing. + 2. build_hardware_controller() blinks the light internally while it's doing hardware + initialization. + + Blinking will continue until `mark_hardware_init_complete()` and + `mark_persistence_init_complete()` have both been called. + """ assert self._hardware_and_task is None, "hardware should only be set once." async def blink_forever() -> None: while True: + # This should no-op on a Flex. await hardware.set_lights(button=True) await asyncio.sleep(0.5) await hardware.set_lights(button=False) @@ -156,14 +168,17 @@ async def blink_forever() -> None: self._hardware_and_task = (hardware, task) async def mark_hardware_init_complete(self) -> None: + """See `start_blinking()`.""" self._hardware_init_complete = True await self._maybe_stop_blinking() async def mark_persistence_init_complete(self) -> None: + """See `start_blinking()`.""" self._persistence_init_complete = True await self._maybe_stop_blinking() async def clean_up(self) -> None: + """Free resources used by the `FrontButtonLightBlinker`.""" if self._hardware_and_task is not None: _, task = self._hardware_and_task task.cancel() @@ -183,62 +198,6 @@ def _all_complete(self) -> bool: return self._persistence_init_complete and self._hardware_init_complete -def fbl_init(app_state: AppState) -> None: - """Prepare to blink the OT-2's front button light. - - This should be called once during server startup. - """ - if should_use_ot3(): - # This is only for the OT-2's front button light. - # The Flex's status bar is handled elsewhere -- see LightController. - return - _front_button_light_blinker_accessor.set_on(app_state, _FrontButtonLightBlinker()) - - -async def fbl_start_blinking(app_state: AppState, hardware: HardwareControlAPI) -> None: - """Start blinking the OT-2's front button light. - - This should be called once during server startup, as soon as the hardware is - initialized enough to support the front button light. - - Note that this is preceded by two other visually indistinguishable stages of - blinking: - 1. A separate system process blinks the light while this process's Python - interpreter is initializing. - 2. build_hardware_controller() blinks the light internally while it's doing hardware - initialization. - - Blinking will continue until `fbl_mark_hardware_init_complete()` and - `fbl_mark_persistence_init_complete()` have both been called. - """ - blinker = _front_button_light_blinker_accessor.get_from(app_state) - if blinker is not None: # May be None on a Flex. - await blinker.set_hardware(hardware) - - -async def fbl_mark_hardware_init_complete( - app_state: AppState, hardware: HardwareControlAPI -) -> None: - """See `fbl_start_blinking()`.""" - blinker = _front_button_light_blinker_accessor.get_from(app_state) - if blinker is not None: # May be None on a Flex. - await blinker.mark_hardware_init_complete() - - -async def fbl_mark_persistence_init_complete(app_state: AppState) -> None: - """See `fbl_start_blinking()`.""" - blinker = _front_button_light_blinker_accessor.get_from(app_state) - if blinker is not None: # May be None on a Flex. - await blinker.mark_persistence_init_complete() - - -async def fbl_clean_up(app_state: AppState) -> None: - """Clean up the background task that blinks the OT-2's front button light.""" - blinker = _front_button_light_blinker_accessor.get_from(app_state) - if blinker is not None: - await blinker.clean_up() - - # TODO(mm, 2022-10-18): Deduplicate this background initialization infrastructure # with similar code used for initializing the persistence layer. async def get_thread_manager( diff --git a/robot-server/robot_server/persistence/database.py b/robot-server/robot_server/persistence/database.py index 7204e47517f..3146926a050 100644 --- a/robot-server/robot_server/persistence/database.py +++ b/robot-server/robot_server/persistence/database.py @@ -23,6 +23,9 @@ sqlite_rowid = sqlalchemy.column("_ROWID_") +# todo(mm, 2024-08-07): Now that FastAPI supports a `lifespan` context manager +# instead of separate startup/shutdown functions, we should transition to using +# `sql_engine_ctx()` everywhere instead of using this. def create_sql_engine(path: Path) -> sqlalchemy.engine.Engine: """Return an engine for accessing the given SQLite database file. diff --git a/robot-server/robot_server/persistence/fastapi_dependencies.py b/robot-server/robot_server/persistence/fastapi_dependencies.py index dedb1a3efd5..63da8a349dc 100644 --- a/robot-server/robot_server/persistence/fastapi_dependencies.py +++ b/robot-server/robot_server/persistence/fastapi_dependencies.py @@ -59,7 +59,7 @@ class DatabaseFailedToInitialize(ErrorDetails): def start_initializing_persistence( # noqa: C901 app_state: AppState, persistence_directory_root: Optional[Path], - done_callbacks: Iterable[Callable[[AppState], Awaitable[None]]], + done_callbacks: Iterable[Callable[[], Awaitable[None]]], ) -> None: """Initialize the persistence layer to get it ready for use by endpoint functions. @@ -143,7 +143,7 @@ async def wait_until_done_then_trigger_callbacks() -> None: await sql_engine_init_task finally: for callback in done_callbacks: - await callback(app_state) + await callback() asyncio.create_task(wait_until_done_then_trigger_callbacks()) diff --git a/robot-server/robot_server/service/notifications/__init__.py b/robot-server/robot_server/service/notifications/__init__.py index 3b40ee17379..7ffa1a8d3ab 100644 --- a/robot-server/robot_server/service/notifications/__init__.py +++ b/robot-server/robot_server/service/notifications/__init__.py @@ -1,12 +1,14 @@ """Notification service creation and management.""" -from .initialize_notifications import initialize_notifications - from .notification_client import ( NotificationClient, get_notification_client, - clean_up_notification_client, + set_up_notification_client, +) +from .publisher_notifier import ( + PublisherNotifier, + get_pe_notify_publishers, + initialize_pe_publisher_notifier, ) -from .publisher_notifier import PublisherNotifier, get_pe_notify_publishers from .publishers import ( MaintenanceRunsPublisher, RunsPublisher, @@ -24,8 +26,8 @@ "RunsPublisher", "DeckConfigurationPublisher", # initialization and teardown - "initialize_notifications", - "clean_up_notification_client", + "set_up_notification_client", + "initialize_pe_publisher_notifier", # for use by FastAPI "get_notification_client", "get_pe_notify_publishers", diff --git a/robot-server/robot_server/service/notifications/initialize_notifications.py b/robot-server/robot_server/service/notifications/initialize_notifications.py deleted file mode 100644 index 06e75d2af09..00000000000 --- a/robot-server/robot_server/service/notifications/initialize_notifications.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Utilities for initializing the notification service.""" -from server_utils.fastapi_utils.app_state import AppState - -from .notification_client import initialize_notification_client -from .publisher_notifier import initialize_pe_publisher_notifier - - -def initialize_notifications(app_state: AppState) -> None: - """Initialize the notification system for the given app state.""" - initialize_notification_client(app_state) - initialize_pe_publisher_notifier(app_state) diff --git a/robot-server/robot_server/service/notifications/notification_client.py b/robot-server/robot_server/service/notifications/notification_client.py index 50d0238e4d7..052bb272cf9 100644 --- a/robot-server/robot_server/service/notifications/notification_client.py +++ b/robot-server/robot_server/service/notifications/notification_client.py @@ -1,9 +1,10 @@ """An interface for managing interactions with the notification broker and relevant lifecycle utilities.""" +import contextlib import random import logging import paho.mqtt.client as mqtt from fastapi import Depends -from typing import Annotated, Any, Dict, Optional +from typing import Annotated, Any, Dict, Generator, Optional from enum import Enum @@ -165,10 +166,15 @@ def _on_disconnect( ]("notification_client") -def initialize_notification_client(app_state: AppState) -> None: - """Create a new `NotificationClient` and store it on `app_state`. +@contextlib.contextmanager +def set_up_notification_client(app_state: AppState) -> Generator[None, None, None]: + """Set up the server's singleton `NotificationClient`. - Intended to be called just once, when the server starts up. + When this context manager is entered, the `NotificationClient` is initialized + and placed on `app_state` for later retrieval by endpoints via + `get_notification_client()`. + + When this context manager is exited, the `NotificationClient` is cleaned up. """ notification_client: NotificationClient = NotificationClient() _notification_client_accessor.set_on(app_state, notification_client) @@ -181,19 +187,9 @@ def initialize_notification_client(app_state: AppState) -> None: exc_info=True, ) - -# todo(mm, 2024-08-20): When ASGI app teardown no longer uses asyncio.gather(), -# this can be non-async. -async def clean_up_notification_client(app_state: AppState) -> None: - """Clean up the `NotificationClient` stored on `app_state`. - - Intended to be called just once, when the server shuts down. - """ - notification_client: Optional[ - NotificationClient - ] = _notification_client_accessor.get_from(app_state) - - if notification_client is not None: + try: + yield + finally: notification_client.disconnect() diff --git a/robot-server/robot_server/service/task_runner.py b/robot-server/robot_server/service/task_runner.py index 4d671b9fd07..0fc6ed6b37a 100644 --- a/robot-server/robot_server/service/task_runner.py +++ b/robot-server/robot_server/service/task_runner.py @@ -6,8 +6,9 @@ from __future__ import annotations import asyncio +import contextlib from logging import getLogger -from typing import Annotated, Any, Awaitable, Callable, Set +from typing import Annotated, Any, AsyncGenerator, Awaitable, Callable, Set from fastapi import Depends from server_utils.fastapi_utils.app_state import ( AppState, @@ -70,23 +71,21 @@ async def cancel_all_and_clean_up(self) -> None: log.debug("Background tasks stopped.") -def initialize_task_runner(app_state: AppState) -> None: - """Create a new `TaskRunner` and store it on `app_state` +@contextlib.asynccontextmanager +async def set_up_task_runner(app_state: AppState) -> AsyncGenerator[None, None]: + """Set up the server's global singleton `TaskRunner`. - Intended to be called just once, when the server starts up. + When this context manager is entered, the `TaskRunner` is set up and stored on + the given `AppState` for later access. When it's exited, the `TaskRunner` is + cleaned up. """ - _task_runner_accessor.set_on(app_state, TaskRunner()) - - -async def clean_up_task_runner(app_state: AppState) -> None: - """Clean up the `TaskRunner` stored on `app_state`. - - Intended to be called just once, when the server shuts down. - """ - task_runner = _task_runner_accessor.get_from(app_state) - - if task_runner is not None: + task_runner = TaskRunner() + try: + _task_runner_accessor.set_on(app_state, TaskRunner()) + yield + finally: await task_runner.cancel_all_and_clean_up() + _task_runner_accessor.set_on(app_state, None) def get_task_runner( diff --git a/robot-server/tests/integration/http_api/persistence/test_reset.py b/robot-server/tests/integration/http_api/persistence/test_reset.py index 8b4ad48ad19..ffff3aed08e 100644 --- a/robot-server/tests/integration/http_api/persistence/test_reset.py +++ b/robot-server/tests/integration/http_api/persistence/test_reset.py @@ -4,10 +4,11 @@ from shutil import copytree from tempfile import TemporaryDirectory +import anyio import httpx from tests.integration.dev_server import DevServer -from tests.integration.robot_client import RobotClient +from tests.integration.robot_client import RobotClient, poll_until_all_analyses_complete from tests.integration.protocol_files import get_py_protocol, get_json_protocol from .persistence_snapshots_dir import PERSISTENCE_SNAPSHOTS_DIR @@ -98,6 +99,13 @@ async def test_upload_protocols_and_reset_persistence_dir() -> None: with get_json_protocol(secrets.token_urlsafe(16)) as file: await robot_client.post_protocol([Path(file.name)]) + with anyio.fail_after(30): + # todo(mm, 2024-09-20): This works around a bug where robot-server + # shutdown will hang if there is an ongoing analysis. This slows down + # this test and should be removed when that bug is fixed. + # https://opentrons.atlassian.net/browse/EXEC-716 + await poll_until_all_analyses_complete(robot_client) + await robot_client.post_setting_reset_options({"runsHistory": True}) result = await robot_client.get_protocols() diff --git a/robot-server/tests/integration/http_api/protocols/test_persistence.py b/robot-server/tests/integration/http_api/protocols/test_persistence.py index 633f363b259..8a128bbafac 100644 --- a/robot-server/tests/integration/http_api/protocols/test_persistence.py +++ b/robot-server/tests/integration/http_api/protocols/test_persistence.py @@ -3,12 +3,13 @@ import secrets from typing import Callable, Dict, IO, List +import anyio import pytest from robot_server.persistence.file_and_directory_names import LATEST_VERSION_DIRECTORY from tests.integration.dev_server import DevServer -from tests.integration.robot_client import RobotClient +from tests.integration.robot_client import RobotClient, poll_until_all_analyses_complete from tests.integration.protocol_files import get_py_protocol, get_json_protocol @@ -39,7 +40,7 @@ async def test_protocols_and_analyses_persist( await robot_client.post_protocol([Path(file.name)]) await asyncio.wait_for( - _wait_for_all_analyses_to_complete(robot_client), timeout=30 + poll_until_all_analyses_complete(robot_client), timeout=30 ) # The protocols response will include analysis statuses. Fetch it @@ -108,6 +109,13 @@ async def test_protocol_labware_files_persist() -> None: # we can ignore the whole field in this test to avoid the nondeterminism. del protocol_detail["analysisSummaries"] + with anyio.fail_after(30): + # todo(mm, 2024-09-20): This works around a bug where robot-server + # shutdown will hang if there is an ongoing analysis. This slows down + # this test and should be removed when that bug is fixed. + # https://opentrons.atlassian.net/browse/EXEC-716 + await poll_until_all_analyses_complete(robot_client) + server.stop() assert await robot_client.dead(), "Dev Robot did not stop." server.start() @@ -168,16 +176,3 @@ async def _get_all_analyses(robot_client: RobotClient) -> Dict[str, List[object] analyses_by_protocol_id[protocol_id] = analyses_on_this_protocol return analyses_by_protocol_id - - -async def _wait_for_all_analyses_to_complete(robot_client: RobotClient) -> None: - async def _all_analyses_are_complete() -> bool: - protocols = (await robot_client.get_protocols()).json() - for protocol in protocols["data"]: - for analysis_summary in protocol["analysisSummaries"]: - if analysis_summary["status"] != "completed": - return False - return True - - while not await _all_analyses_are_complete(): - await asyncio.sleep(0.1) diff --git a/robot-server/tests/integration/robot_client.py b/robot-server/tests/integration/robot_client.py index c33f36b5385..3c0af8c8bf0 100644 --- a/robot-server/tests/integration/robot_client.py +++ b/robot-server/tests/integration/robot_client.py @@ -14,6 +14,7 @@ _SHUTDOWN_WAIT = 20 _RUN_POLL_INTERVAL = 0.1 +_ANALYSIS_POLL_INTERVAL = 0.1 class RobotClient: @@ -398,3 +399,24 @@ async def poll_until_run_completes( else: # The run is still ongoing. Wait a beat, then poll again. await asyncio.sleep(poll_interval) + + +async def poll_until_all_analyses_complete( + robot_client: RobotClient, poll_interval: float = _ANALYSIS_POLL_INTERVAL +) -> None: + """Wait until all pending analyses have completed. + + You probably want to wrap this in an `anyio.fail_after()` timeout in case something causes + an analysis to hang forever. + """ + + async def _all_analyses_are_complete() -> bool: + protocols = (await robot_client.get_protocols()).json() + for protocol in protocols["data"]: + for analysis_summary in protocol["analysisSummaries"]: + if analysis_summary["status"] != "completed": + return False + return True + + while not await _all_analyses_are_complete(): + await asyncio.sleep(poll_interval)