From f793e65328b33ec3dd5b0b3e608d1722f32dc0c7 Mon Sep 17 00:00:00 2001 From: Ed Cormany Date: Fri, 20 Sep 2024 12:11:27 -0400 Subject: [PATCH 01/12] =?UTF-8?q?docs(api):=20further=20guidance=20on=20LP?= =?UTF-8?q?D=20=E2=80=93=20time=20consumption=20and=20using=20clean=20tips?= =?UTF-8?q?=20(#16313)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Overview Provide more clarity on LPD requiring fresh, dry tips. Also note that it takes quite some time, so protocol authors should be cautious about enabling it globally. ## Test Plan and Hands on Testing Sandbox links - [Global LPD](http://sandbox.docs.opentrons.com/docs-lpd-timing-and-wet-tips/v2/pipettes/loading.html#liquid-presence-detection) - [Atomic LPD](http://sandbox.docs.opentrons.com/docs-lpd-timing-and-wet-tips/v2/basic_commands/liquids.html#detect-liquids) ## Changelog - Additions to both sections where we talk about LPD. - Removed an old RST comment. ## Review requests Is this clear enough about the risks/downsides of using global LPD, especially with complex commands? ## Risk assessment none --- api/docs/v2/basic_commands/liquids.rst | 12 ++++++++---- api/docs/v2/pipettes/loading.rst | 14 +++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) 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 From c742a9f42dfac596c645429633ae3fae2416a72c Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Fri, 20 Sep 2024 13:05:08 -0400 Subject: [PATCH 02/12] fix(api): dont move gen1s all the way up (#16316) Gen1 pipettes need more z margin than usual when moving around at maximum z for some reason. ## testing - [x] run through dtwiz with a gen1 of any kind Closes RQA-3229 --- .../commands/move_to_addressable_area.py | 16 ++++ .../protocol_engine/execution/movement.py | 2 + .../opentrons/protocol_engine/state/motion.py | 5 +- .../commands/test_move_to_addressable_area.py | 94 ++++++++++++++++++- .../execution/test_movement_handler.py | 14 ++- 5 files changed, 124 insertions(+), 7 deletions(-) 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 d215fae7189..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,6 +4,8 @@ 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 @@ -94,6 +96,19 @@ async def execute( 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( @@ -108,6 +123,7 @@ 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( 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/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 112cb8ada3e..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,11 +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 ( @@ -15,10 +17,28 @@ ) -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( @@ -35,6 +55,73 @@ 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", + 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( + 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", @@ -44,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)) 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) From ce9ac0ed9865f0b68912c8445a025b0cca28605c Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Fri, 20 Sep 2024 15:06:36 -0400 Subject: [PATCH 03/12] chore(robot-server): Work around tests hanging because server shutdown is hanging (#16317) --- .../http_api/persistence/test_reset.py | 10 +++++++- .../http_api/protocols/test_persistence.py | 25 ++++++++----------- .../tests/integration/robot_client.py | 22 ++++++++++++++++ 3 files changed, 41 insertions(+), 16 deletions(-) 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) From dcf80f348e9580f85dae2f7da50cf29e711c0a58 Mon Sep 17 00:00:00 2001 From: syao1226 <146495172+syao1226@users.noreply.github.com> Date: Mon, 23 Sep 2024 09:38:13 -0400 Subject: [PATCH 04/12] fix(protocol-designer): capitalize step types (#16309) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix RQA-3214 # Overview Capitalizing the step types listed on Protocol timeline. ## Test Plan and Hands on Testing Screenshot 2024-09-20 at 9 56 45 AM ## Changelog - Created a `utils.ts` file - Added a function to capitalize the first letter of first word when the input title contains a number before it. ## Review requests ## Risk assessment --------- Co-authored-by: shiyaochen Co-authored-by: shiyaochen --- .../ProtocolSteps/Timeline/StepContainer.tsx | 4 +++- .../ProtocolSteps/Timeline/__tests__/utils.test.tsx | 13 +++++++++++++ .../pages/Designer/ProtocolSteps/Timeline/utils.ts | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/utils.test.tsx create mode 100644 protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/utils.ts 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()}` + ) From 01914de94622b43d7a74679ebc422506f978d3b9 Mon Sep 17 00:00:00 2001 From: koji Date: Mon, 23 Sep 2024 10:45:53 -0400 Subject: [PATCH 05/12] fix(protocol-designer): remove margins from protocol overview (#16308) * fix(protocol-designer): remove margins from protocol overview --- .../src/pages/ProtocolOverview/index.tsx | 145 +++++++++--------- 1 file changed, 69 insertions(+), 76 deletions(-) diff --git a/protocol-designer/src/pages/ProtocolOverview/index.tsx b/protocol-designer/src/pages/ProtocolOverview/index.tsx index 790413e73d7..818a5b5a0c7 100644 --- a/protocol-designer/src/pages/ProtocolOverview/index.tsx +++ b/protocol-designer/src/pages/ProtocolOverview/index.tsx @@ -337,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] @@ -380,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')} + + + @@ -458,12 +452,10 @@ export function ProtocolOverview(): JSX.Element { ) : null} - - - - {t('liquid_defs')} - - + + + {t('liquid_defs')} + {Object.keys(allIngredientGroupFields).length > 0 ? ( Object.values(allIngredientGroupFields).map( @@ -495,8 +487,8 @@ export function ProtocolOverview(): JSX.Element { )} - - + + {t('step')} @@ -518,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 ? ( ) : ( From 89f8d77986bd1bff09a764487558a01f1ea6fe65 Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Mon, 23 Sep 2024 11:15:33 -0400 Subject: [PATCH 06/12] refactor(app): move ProtocolUpload hooks, start moving Devices hooks (#16324) The original aim of this PR was to untangle `app/src/organisms/Devices` from everything, particularly in the ODD, that imports it, but it got way too big so this is sort of the first half. It - Moves the remaining run control hooks from `ProtocolUpload` to the run resources - Removes some last pages imports from organisms (these had to do with OT-2 calibration) - Move a first pass of analytics hooks from devices to `redux-resources` - Move some of the key redux interface hooks (`useIsRobot`, `useIsFlex`, dependencies, friends) to `redux-resources` There are no code changes other than imports, mock statements, and new index files. --- app/src/App/DesktopApp.tsx | 2 +- app/src/App/__tests__/DesktopApp.test.tsx | 4 +- .../__tests__/UpdateBanner.test.tsx | 4 +- app/src/molecules/UpdateBanner/index.tsx | 2 +- .../__tests__/useHistoricRunDetails.test.tsx | 2 +- .../__tests__/Breadcrumbs.test.tsx | 7 +- app/src/organisms/Breadcrumbs/index.tsx | 6 +- .../organisms/CalibrationTaskList/index.tsx | 10 +- .../ChooseProtocolSlideout/index.tsx | 2 +- .../ChooseRobotToRunProtocolSlideout.test.tsx | 3 +- .../index.tsx | 2 +- .../Devices/HistoricalProtocolRun.tsx | 4 +- .../HistoricalProtocolRunOverflowMenu.tsx | 4 +- .../Devices/InstrumentsAndModules.tsx | 3 +- .../Devices/ProtocolRun/BackToTopButton.tsx | 2 +- .../TerminalRunBannerContainer.tsx | 8 +- .../hooks/useActionButtonProperties.ts | 2 +- .../hooks/useIsFixtureMismatch.ts | 2 +- .../RunHeaderContent/ActionButton/index.tsx | 7 +- .../RunHeaderSectionLower.tsx | 8 +- .../RunHeaderSectionUpper.tsx | 2 +- .../hooks/useRunHeaderDropTip.ts | 3 +- .../modals/ConfirmCancelModal.tsx | 5 +- .../__tests__/hooks.test.tsx | 2 +- .../__tests__/ConfirmCancelModal.test.tsx | 6 +- .../useRunHeaderModalContainer.ts | 8 +- .../RunHeaderProtocolName.tsx | 2 +- .../__tests__/ProtocolRunHeader.test.tsx | 11 +- .../ProtocolRunHeader/hooks/useIsDoorOpen.ts | 2 +- .../hooks/useRunAnalytics.ts | 10 +- .../ProtocolRunHeader/hooks/useRunErrors.ts | 2 +- .../ProtocolRun/ProtocolRunHeader/index.tsx | 9 +- .../ProtocolRunRunTimeParameters.tsx | 3 +- .../Devices/ProtocolRun/ProtocolRunSetup.tsx | 5 +- .../Devices/ProtocolRun/RunTimer.tsx | 4 +- .../SetupFlexPipetteCalibrationItem.tsx | 2 +- .../SetupInstrumentCalibration.tsx | 8 +- .../__tests__/SetupLabware.test.tsx | 1 + .../ProtocolRun/SetupLabware/index.tsx | 8 +- .../SetupLabwarePositionCheck.test.tsx | 4 +- .../SetupLabwarePositionCheck/index.tsx | 9 +- .../SetupLiquids/SetupLiquidsList.tsx | 2 +- .../__tests__/SetupLiquidsList.test.tsx | 4 +- .../ChooseModuleToConfigureModal.tsx | 2 +- .../SetupModuleAndDeck/SetupModulesList.tsx | 3 +- .../SetupModuleAndDeck/SetupModulesMap.tsx | 3 +- .../__tests__/LocationConflictModal.test.tsx | 4 +- .../__tests__/SetupModulesAndDeck.test.tsx | 3 +- .../__tests__/SetupModulesList.test.tsx | 4 +- .../ProtocolRun/SetupModuleAndDeck/index.tsx | 2 +- .../ProtocolRun/SetupRobotCalibration.tsx | 5 +- .../__tests__/BackToTopButton.test.tsx | 4 +- .../__tests__/LabwareInfoOverlay.test.tsx | 4 +- .../ProtocolRunRuntimeParameters.test.tsx | 6 +- .../__tests__/ProtocolRunSetup.test.tsx | 8 +- .../SetupFlexPipetteCalibrationItem.test.tsx | 1 + .../SetupPipetteCalibration.test.tsx | 1 + .../SetupPipetteCalibrationItem.test.tsx | 1 + .../__tests__/SetupRobotCalibration.test.tsx | 10 +- app/src/organisms/Devices/RobotCard.tsx | 2 +- app/src/organisms/Devices/RobotOverview.tsx | 8 +- .../AdvancedTabSlideouts/DeviceResetModal.tsx | 2 +- .../DeviceResetSlideout.tsx | 3 +- .../RenameRobotSlideout.tsx | 2 +- .../__tests__/DeviceResetModal.test.tsx | 2 +- .../__tests__/DeviceResetSlideout.test.tsx | 3 +- .../__tests__/RenameRobotSlideout.test.tsx | 4 +- .../AdvancedTab/RobotInformation.tsx | 2 +- .../AdvancedTab/RobotServerVersion.tsx | 2 +- .../AdvancedTab/Troubleshooting.tsx | 2 +- .../__tests__/DeviceReset.test.tsx | 2 +- .../__tests__/RobotInformation.test.tsx | 4 +- .../__tests__/RobotServerVersion.test.tsx | 4 +- .../__tests__/Troubleshooting.test.tsx | 4 +- .../ConnectNetwork/DisconnectModal.tsx | 2 +- .../__tests__/DisconnectModal.test.tsx | 4 +- .../RobotSettings/RobotSettingsAdvanced.tsx | 3 +- .../RobotSettings/RobotSettingsNetworking.tsx | 4 +- .../__tests__/RobotSettingsAdvanced.test.tsx | 4 +- .../RobotSettingsNetworking.test.tsx | 5 +- .../organisms/Devices/RobotStatusHeader.tsx | 2 +- .../__tests__/HistoricalProtocolRun.test.tsx | 4 +- ...HistoricalProtocolRunOverflowMenu.test.tsx | 8 +- .../__tests__/InstrumentsAndModules.test.tsx | 5 +- .../__tests__/RecentProtocolRuns.test.tsx | 3 +- .../Devices/__tests__/RobotCard.test.tsx | 1 + .../Devices/__tests__/RobotOverview.test.tsx | 3 +- .../__tests__/RobotStatusHeader.test.tsx | 4 +- app/src/organisms/Devices/constants.ts | 1 - .../hooks/__tests__/useIsRobotBusy.test.ts | 5 +- .../__tests__/useLPCDisabledReason.test.tsx | 6 +- .../useModuleCalibrationStatus.test.tsx | 4 +- ...seModuleRenderInfoForProtocolById.test.tsx | 9 +- .../usePipetteOffsetCalibration.test.tsx | 4 +- .../useProtocolAnalysisErrors.test.tsx | 2 +- .../useRunCalibrationStatus.test.tsx | 5 +- .../useRunCreatedAtTimestamp.test.tsx | 2 +- .../hooks/__tests__/useRunHasStarted.test.tsx | 4 +- .../useRunPipetteInfoByMount.test.tsx | 4 +- ...nStartedOrLegacySessionInProgress.test.tsx | 4 +- .../hooks/__tests__/useRunStatuses.test.tsx | 4 +- .../useTrackCreateProtocolRunEvent.test.tsx | 10 +- .../useUnmatchedModulesForProtocol.test.tsx | 4 +- app/src/organisms/Devices/hooks/index.ts | 9 - .../Devices/hooks/useCalibrationTaskList.ts | 34 +++- .../Devices/hooks/useDeckCalibrationData.ts | 2 +- .../Devices/hooks/useDeckCalibrationStatus.ts | 2 +- .../organisms/Devices/hooks/useIsRobotBusy.ts | 2 +- .../Devices/hooks/useIsRobotViewable.ts | 2 +- .../Devices/hooks/useLPCDisabledReason.tsx | 2 +- .../Devices/hooks/useLastRunCommand.ts | 3 +- .../hooks/useModuleCalibrationStatus.ts | 2 +- .../useModuleRenderInfoForProtocolById.ts | 2 +- .../hooks/usePipetteOffsetCalibration.ts | 2 +- .../Devices/hooks/useRunCalibrationStatus.ts | 10 +- .../Devices/hooks/useRunCreatedAtTimestamp.ts | 3 +- .../Devices/hooks/useRunHasStarted.ts | 2 +- .../Devices/hooks/useRunPipetteInfoByMount.ts | 8 +- .../useRunStartedOrLegacySessionInProgress.ts | 3 +- .../organisms/Devices/hooks/useRunStatuses.ts | 3 +- .../hooks/useTrackCreateProtocolRunEvent.ts | 6 +- .../hooks/useUnmatchedModulesForProtocol.ts | 7 +- app/src/organisms/Devices/utils.ts | 45 ----- .../__tests__/TipsAttachedModal.test.tsx | 4 +- .../ErrorRecoveryWizard.tsx | 11 +- .../ErrorRecoveryFlows/RunPausedSplash.tsx | 6 +- .../__tests__/ErrorRecoveryFlows.test.tsx | 3 +- .../ErrorRecoveryFlows/hooks/index.ts | 2 - .../ErrorRecoveryFlows/hooks/useERUtils.ts | 8 +- .../hooks/useRecoveryCommands.ts | 6 +- .../__tests__/BeforeBeginning.test.tsx | 2 +- .../IncompatibleModuleDesktopModalBody.tsx | 2 +- ...ncompatibleModuleDesktopModalBody.test.tsx | 4 +- .../PauseInterventionContent.tsx | 4 +- .../__tests__/InterventionModal.test.tsx | 4 +- app/src/organisms/InterventionModal/index.tsx | 2 +- .../__tests__/PickUpTip.test.tsx | 4 +- .../__tests__/ReturnTip.test.tsx | 4 +- .../ModuleCard/ModuleOverflowMenu.tsx | 4 +- .../ModuleCard/__tests__/ModuleCard.test.tsx | 7 +- .../__tests__/ModuleOverflowMenu.test.tsx | 6 +- app/src/organisms/ModuleCard/index.tsx | 10 +- .../__tests__/LiquidDetails.test.tsx | 2 +- .../__tests__/ProtocolSetupLiquids.test.tsx | 2 +- .../ProtocolSetupModulesAndDeck.tsx | 2 +- .../ProtocolSetupModulesAndDeck.test.tsx | 4 +- .../ProtocolSetupParameters/ChooseNumber.tsx | 4 +- .../ProtocolSetupParameters.tsx | 6 +- .../ViewOnlyParameters.tsx | 6 +- .../__tests__/ChooseNumber.test.tsx | 6 +- .../ProtocolSetupParameters.test.tsx | 8 +- .../__tests__/ViewOnlyParameters.test.tsx | 10 +- .../ODD/ProtocolSetup/__fixtures__/index.ts} | 0 .../RobotDashboard/RecentRunProtocolCard.tsx | 2 +- .../__tests__/RecentRunProtocolCard.test.tsx | 9 +- .../RunningProtocol/ConfirmCancelRunModal.tsx | 4 +- .../CurrentRunningProtocolCommand.tsx | 2 +- .../RunningProtocolCommandList.tsx | 2 +- .../__tests__/ConfirmCancelRunModal.test.tsx | 9 +- .../__tests__/AttachProbe.test.tsx | 2 +- .../__tests__/BeforeBeginning.test.tsx | 2 +- .../__tests__/Carriage.test.tsx | 2 +- .../__tests__/DetachPipette.test.tsx | 2 +- .../__tests__/DetachProbe.test.tsx | 2 +- .../__tests__/MountPipette.test.tsx | 2 +- .../__tests__/MountingPlate.test.tsx | 2 +- .../__tests__/Results.test.tsx | 2 +- .../organisms/ProtocolUpload/hooks/index.ts | 7 - .../CalibrationDataDownload.tsx | 3 +- .../ModuleCalibrationOverflowMenu.tsx | 8 +- .../PipetteOffsetCalibrationItems.tsx | 2 +- .../ModuleCalibrationOverflowMenu.test.tsx | 8 +- .../PipetteOffsetCalibrationItems.test.tsx | 5 +- .../RobotSettingsDeckCalibration.tsx | 3 +- .../RobotSettingsPipetteOffsetCalibration.tsx | 2 +- .../CalibrationDataDownload.test.tsx | 4 +- .../RobotSettingsCalibration.test.tsx | 4 +- .../RobotSettingsDeckCalibration.test.tsx | 3 +- ...tSettingsPipetteOffsetCalibration.test.tsx | 3 +- .../RobotSettingsCalibration/index.tsx | 3 +- app/src/organisms/RunPreview/index.tsx | 2 +- .../__tests__/RunProgressMeter.test.tsx | 4 +- app/src/organisms/RunProgressMeter/index.tsx | 6 +- .../RunTimeControl/__tests__/hooks.test.tsx | 182 +----------------- app/src/organisms/RunTimeControl/hooks.ts | 128 +----------- .../__tests__/CalibrationDashboard.test.tsx | 1 + .../hooks/useDashboardCalibrateDeck.tsx | 7 +- .../hooks/useDashboardCalibratePipOffset.tsx | 12 +- .../hooks/useDashboardCalibrateTipLength.tsx | 12 +- .../Devices/CalibrationDashboard/index.tsx | 2 +- .../DeviceDetails/DeviceDetailsComponent.tsx | 2 +- .../__tests__/DeviceDetails.test.tsx | 4 +- .../__tests__/DeviceDetailsComponent.test.tsx | 4 +- .../Desktop/Devices/DeviceDetails/index.tsx | 3 +- .../__tests__/ProtocolRunDetails.test.tsx | 3 +- .../Devices/ProtocolRunDetails/index.tsx | 3 +- .../__tests__/RobotSettings.test.tsx | 4 +- .../Desktop/Devices/RobotSettings/index.tsx | 2 +- .../__tests__/Parameters.test.tsx | 2 +- .../__tests__/ProtocolDetails.test.tsx | 2 +- .../__tests__/ProtocolSetup.test.tsx | 11 +- app/src/pages/ODD/ProtocolSetup/index.tsx | 13 +- app/src/pages/ODD/RunSummary/index.tsx | 21 +- .../__tests__/RunningProtocol.test.tsx | 12 +- app/src/pages/ODD/RunningProtocol/index.tsx | 14 +- .../useProtocolRunAnalyticsData.test.tsx | 16 +- .../__tests__/useRobotAnalyticsData.test.tsx | 3 +- .../useTrackProtocolRunEvent.test.tsx | 4 +- .../redux-resources/analytics/hooks/index.ts | 4 + .../hooks/useProtocolRunAnalyticsData.ts | 65 +++++++ .../analytics}/hooks/useRecoveryAnalytics.ts | 34 ++-- .../analytics}/hooks/useRobotAnalyticsData.ts | 2 +- .../hooks/useTrackProtocolRunEvent.ts | 2 +- app/src/redux-resources/analytics/index.ts | 1 + .../hooks/__tests__/useIsFlex.test.tsx | 0 .../robots}/hooks/__tests__/useRobot.test.tsx | 0 app/src/redux-resources/robots/hooks/index.ts | 3 + .../robots}/hooks/useIsFlex.ts | 0 .../robots}/hooks/useRobot.ts | 0 .../robots}/hooks/useRobotType.ts | 2 +- app/src/redux-resources/robots/index.ts | 1 + .../__fixtures__/storedProtocolAnalysis.ts | 0 .../useStoredProtocolAnalysis.test.tsx | 0 app/src/resources/analysis/hooks/index.ts | 1 + .../hooks/useStoredProtocolAnalysis.ts | 28 +-- app/src/resources/analysis/index.ts | 1 + .../useIsEstopNotDisengaged.test.tsx | 4 +- .../devices/hooks/useIsEstopNotDisengaged.ts | 2 +- .../__tests__/useCanDisconnect.test.tsx | 4 +- .../networking/__tests__/useWifiList.test.ts | 4 +- .../networking/hooks/useCanDisconnect.ts | 2 +- .../resources/networking/hooks/useWifiList.ts | 2 +- .../__tests__/useProtocolMetadata.test.tsx | 4 +- app/src/resources/protocols/hooks/index.ts | 3 +- .../protocols}/hooks/useCurrentProtocol.ts | 2 +- .../protocols}/hooks/useProtocolMetadata.ts | 2 +- app/src/resources/protocols/index.ts | 2 + .../runs}/__fixtures__/index.ts | 0 .../runs}/__tests__/useCloneRun.test.tsx | 4 +- .../__tests__/useMostRecentRunId.test.tsx | 4 +- .../useProtocolDetailsForRun.test.tsx | 6 +- .../runs/__tests__/useRunStatus.test.ts | 51 +++++ .../runs/__tests__/useRunTimestamps.test.ts | 118 ++++++++++++ app/src/resources/runs/constants.ts | 3 + app/src/resources/runs/index.ts | 11 ++ .../hooks => resources/runs}/useCloneRun.ts | 4 +- .../runs}/useCloseCurrentRun.ts | 0 .../hooks => resources/runs}/useCurrentRun.ts | 3 +- .../runs}/useCurrentRunCommands.ts | 3 +- .../runs}/useMostRecentRunId.ts | 2 +- .../runs}/useProtocolDetailsForRun.ts | 2 +- .../hooks => resources/runs}/useRestartRun.ts | 0 .../runs}/useRunCommands.ts | 2 +- app/src/resources/runs/useRunStatus.ts | 47 +++++ app/src/resources/runs/useRunTimestamps.ts | 79 ++++++++ app/src/transformations/analysis/index.ts | 1 + .../analysis/parseProtocolAnalysisOutput.ts | 28 +++ app/src/transformations/analytics/index.ts | 1 + .../parseProtocolRunAnalyticsData.ts} | 64 +----- .../__tests__/formatDuration.test.tsx | 39 ++++ .../__tests__/formatInterval.test.tsx | 39 +--- .../transformations/formatDuration.ts} | 16 -- .../transformations/formatInterval.ts | 15 ++ .../commands/transformations/index.ts | 2 + .../runs/getRunTimeParameterFilesForRun.ts | 27 +++ .../runs/getRunTimeParameterValuesForRun.ts | 19 ++ app/src/transformations/runs/index.ts | 2 + 267 files changed, 1055 insertions(+), 1005 deletions(-) rename app/src/{pages/ODD/ProtocolDetails/fixtures.ts => organisms/ODD/ProtocolSetup/__fixtures__/index.ts} (100%) delete mode 100644 app/src/organisms/ProtocolUpload/hooks/index.ts rename app/src/{organisms/Devices => redux-resources/analytics}/hooks/__tests__/useProtocolRunAnalyticsData.test.tsx (93%) rename app/src/{organisms/Devices => redux-resources/analytics}/hooks/__tests__/useRobotAnalyticsData.test.tsx (97%) rename app/src/{organisms/Devices => redux-resources/analytics}/hooks/__tests__/useTrackProtocolRunEvent.test.tsx (97%) create mode 100644 app/src/redux-resources/analytics/hooks/index.ts create mode 100644 app/src/redux-resources/analytics/hooks/useProtocolRunAnalyticsData.ts rename app/src/{organisms/ErrorRecoveryFlows => redux-resources/analytics}/hooks/useRecoveryAnalytics.ts (79%) rename app/src/{organisms/Devices => redux-resources/analytics}/hooks/useRobotAnalyticsData.ts (97%) rename app/src/{organisms/Devices => redux-resources/analytics}/hooks/useTrackProtocolRunEvent.ts (95%) create mode 100644 app/src/redux-resources/analytics/index.ts rename app/src/{organisms/Devices => redux-resources/robots}/hooks/__tests__/useIsFlex.test.tsx (100%) rename app/src/{organisms/Devices => redux-resources/robots}/hooks/__tests__/useRobot.test.tsx (100%) create mode 100644 app/src/redux-resources/robots/hooks/index.ts rename app/src/{organisms/Devices => redux-resources/robots}/hooks/useIsFlex.ts (100%) rename app/src/{organisms/Devices => redux-resources/robots}/hooks/useRobot.ts (100%) rename app/src/{organisms/Devices => redux-resources/robots}/hooks/useRobotType.ts (83%) create mode 100644 app/src/redux-resources/robots/index.ts rename app/src/{organisms/Devices => resources/analysis}/hooks/__fixtures__/storedProtocolAnalysis.ts (100%) rename app/src/{organisms/Devices => resources/analysis}/hooks/__tests__/useStoredProtocolAnalysis.test.tsx (100%) create mode 100644 app/src/resources/analysis/hooks/index.ts rename app/src/{organisms/Devices => resources/analysis}/hooks/useStoredProtocolAnalysis.ts (53%) create mode 100644 app/src/resources/analysis/index.ts rename app/src/{organisms/Devices => resources/protocols}/hooks/__tests__/useProtocolMetadata.test.tsx (93%) rename app/src/{organisms/ProtocolUpload => resources/protocols}/hooks/useCurrentProtocol.ts (88%) rename app/src/{organisms/Devices => resources/protocols}/hooks/useProtocolMetadata.ts (93%) create mode 100644 app/src/resources/protocols/index.ts rename app/src/{organisms/RunTimeControl => resources/runs}/__fixtures__/index.ts (100%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/__tests__/useCloneRun.test.tsx (97%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/__tests__/useMostRecentRunId.test.tsx (90%) rename app/src/{organisms/Devices/hooks => resources/runs}/__tests__/useProtocolDetailsForRun.test.tsx (95%) create mode 100644 app/src/resources/runs/__tests__/useRunStatus.test.ts create mode 100644 app/src/resources/runs/__tests__/useRunTimestamps.test.ts create mode 100644 app/src/resources/runs/constants.ts rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useCloneRun.ts (96%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useCloseCurrentRun.ts (100%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useCurrentRun.ts (77%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useCurrentRunCommands.ts (79%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useMostRecentRunId.ts (79%) rename app/src/{organisms/Devices/hooks => resources/runs}/useProtocolDetailsForRun.ts (97%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useRestartRun.ts (100%) rename app/src/{organisms/ProtocolUpload/hooks => resources/runs}/useRunCommands.ts (88%) create mode 100644 app/src/resources/runs/useRunStatus.ts create mode 100644 app/src/resources/runs/useRunTimestamps.ts create mode 100644 app/src/transformations/analysis/index.ts create mode 100644 app/src/transformations/analysis/parseProtocolAnalysisOutput.ts create mode 100644 app/src/transformations/analytics/index.ts rename app/src/{organisms/Devices/hooks/useProtocolRunAnalyticsData.ts => transformations/analytics/parseProtocolRunAnalyticsData.ts} (53%) create mode 100644 app/src/transformations/commands/transformations/__tests__/formatDuration.test.tsx rename app/src/{organisms/RunTimeControl => transformations/commands/transformations}/__tests__/formatInterval.test.tsx (53%) rename app/src/{organisms/RunTimeControl/utils.ts => transformations/commands/transformations/formatDuration.ts} (63%) create mode 100644 app/src/transformations/commands/transformations/formatInterval.ts create mode 100644 app/src/transformations/runs/getRunTimeParameterFilesForRun.ts create mode 100644 app/src/transformations/runs/getRunTimeParameterValuesForRun.ts create mode 100644 app/src/transformations/runs/index.ts 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/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 322d4f7c6b8..bd771f92f40 100644 --- a/app/src/organisms/ChooseProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/index.tsx @@ -59,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' 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/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 92f89fbbc9b..9c8168c7f11 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionLower.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionLower.tsx @@ -15,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' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx index eecd8b0bc53..df397d937d1 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderContent/RunHeaderSectionUpper.tsx @@ -14,7 +14,7 @@ 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 '.' 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 53c9c34fdfd..f5fc97c22e2 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx @@ -34,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' 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/__tests__/SetupLabware.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx index e292b39031f..fee5fe31dae 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx @@ -30,6 +30,7 @@ vi.mock('/app/redux/config') vi.mock('../../../hooks') vi.mock('../../../hooks/useLPCSuccessToast') vi.mock('/app/resources/runs') +vi.mock('/app/redux-resources/robots') const ROBOT_NAME = 'otie' const RUN_ID = '1' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/index.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/index.tsx index b14038275b4..502d2dd5c8a 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/index.tsx @@ -11,11 +11,9 @@ import { import { useToggleGroup } from '/app/molecules/ToggleGroup/useToggleGroup' import { getModuleTypesThatRequireExtraAttention } from '../utils/getModuleTypesThatRequireExtraAttention' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' -import { - useIsFlex, - useModuleRenderInfoForProtocolById, - useStoredProtocolAnalysis, -} from '../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' +import { useModuleRenderInfoForProtocolById } from '../../hooks' import { SetupLabwareMap } from './SetupLabwareMap' import { SetupLabwareList } from './SetupLabwareList' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx index 39f1f095a16..59b78ba440c 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx @@ -21,16 +21,16 @@ import { useRunCalibrationStatus, useRunHasStarted, useUnmatchedModulesForProtocol, - useRobotType, } from '../../../hooks' import { SetupLabwarePositionCheck } from '..' import { useNotifyRunQuery } from '/app/resources/runs' +import { useRobotType } from '/app/redux-resources/robots' import type { Mock } from 'vitest' vi.mock('../../../../LabwarePositionCheck/useLaunchLPC') vi.mock('../../utils/getModuleTypesThatRequireExtraAttention') -vi.mock('../../../../RunTimeControl/hooks') +vi.mock('/app/redux-resources/robots') vi.mock('/app/redux/config') vi.mock('../../../hooks') vi.mock('../../../hooks/useLPCSuccessToast') diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/index.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/index.tsx index bb5a92b60f8..c0813f5b36d 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/index.tsx @@ -21,16 +21,13 @@ import { useProtocolQuery } from '@opentrons/react-api-client' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useLPCSuccessToast } from '../../hooks/useLPCSuccessToast' -import { - useRobotType, - useLPCDisabledReason, - useStoredProtocolAnalysis, -} from '../../hooks' +import { useLPCDisabledReason } from '../../hooks' +import { useStoredProtocolAnalysis } from '/app/resources/analysis' import { CurrentOffsetsTable } from './CurrentOffsetsTable' import { useLaunchLPC } from '../../../LabwarePositionCheck/useLaunchLPC' import { getLatestCurrentOffsets } from './utils' import { useNotifyRunQuery } from '/app/resources/runs' - +import { useRobotType } from '/app/redux-resources/robots' import type { LabwareOffset } from '@opentrons/api-client' interface SetupLabwarePositionCheckProps { diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx index c578d9587dc..82bddc9685f 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/SetupLiquidsList.tsx @@ -32,7 +32,7 @@ import { ANALYTICS_EXPAND_LIQUID_SETUP_ROW, ANALYTICS_OPEN_LIQUID_LABWARE_DETAIL_MODAL, } from '/app/redux/analytics' -import { useIsFlex } from '../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { getLocationInfoNames } from '../utils/getLocationInfoNames' import { LiquidsLabwareDetailsModal } from './LiquidsLabwareDetailsModal' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx index c8942139cd2..80a3384dd24 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLiquids/__tests__/SetupLiquidsList.test.tsx @@ -15,7 +15,7 @@ import { ANALYTICS_EXPAND_LIQUID_SETUP_ROW, ANALYTICS_OPEN_LIQUID_LABWARE_DETAIL_MODAL, } from '/app/redux/analytics' -import { useIsFlex } from '../../../hooks' +import { useIsFlex } from '/app/redux-resources/robots' import { getLocationInfoNames } from '../../utils/getLocationInfoNames' import { SetupLiquidsList } from '../SetupLiquidsList' import { getTotalVolumePerLiquidId, getVolumePerWell } from '../utils' @@ -54,7 +54,7 @@ const MOCK_LABWARE_INFO_BY_LIQUID_ID = { vi.mock('../utils') vi.mock('../../utils/getLocationInfoNames') -vi.mock('../../../hooks') +vi.mock('/app/redux-resources/robots') vi.mock('../LiquidsLabwareDetailsModal') vi.mock('@opentrons/shared-data', async importOriginal => { 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 ace9b4977b1..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 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/__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/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/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/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/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/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' From 36014592524e95231074222b1cc406456347ad26 Mon Sep 17 00:00:00 2001 From: koji Date: Mon, 23 Sep 2024 11:47:34 -0400 Subject: [PATCH 07/12] fix(protocol-designer): remove margins from onboarding screens (#16303) * fix(protocol-designer): remove margins from onboarding screens --- .../localization/en/create_new_protocol.json | 2 +- .../src/assets/localization/en/shared.json | 2 +- .../CreateNewProtocolWizard/AddMetadata.tsx | 6 +- .../SelectFixtures.tsx | 63 ++++++++-------- .../CreateNewProtocolWizard/SelectGripper.tsx | 47 ++++++------ .../CreateNewProtocolWizard/SelectModules.tsx | 22 +++--- .../SelectPipettes.tsx | 74 ++++++++----------- .../CreateNewProtocolWizard/SelectRobot.tsx | 6 +- .../CreateNewProtocolWizard/WizardBody.tsx | 32 ++++---- .../pages/Landing/__tests__/Landing.test.tsx | 2 +- protocol-designer/src/pages/Landing/index.tsx | 51 +++++++------ 11 files changed, 141 insertions(+), 166 deletions(-) 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/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/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 efedd52f79b..6524a6efbd1 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectPipettes.tsx @@ -91,10 +91,10 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { // initialize pipette name once all fields are filled out React.useEffect(() => { if ( - pipetteType != null && - pipetteVolume != null && - robotType === OT2_ROBOT_TYPE && - pipetteGen != null + (pipetteType != null && + pipetteVolume != null && + robotType === FLEX_ROBOT_TYPE) || + (robotType === OT2_ROBOT_TYPE && pipetteGen != null) ) { setValue( `pipettesByMount.${defaultMount}.pipetteName`, @@ -127,7 +127,7 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { { @@ -150,12 +150,11 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { flexDirection={DIRECTION_COLUMN} height="41.5vh" overflowY={OVERFLOW_AUTO} - marginBottom={SPACING.spacing16} - marginTop={SPACING.spacing60} + gridGap={SPACING.spacing32} > {t('pip_type')} @@ -192,29 +191,24 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { {pipetteType != null && robotType === OT2_ROBOT_TYPE ? ( - - - {t('pip_gen')} - - - {PIPETTE_GENS.map(gen => ( - { - setPipetteGen(gen) - setPipetteVolume(null) - }} - buttonLabel={gen} - buttonValue={gen} - isSelected={pipetteGen === gen} - /> - ))} - + + {t('pip_gen')} + + + {PIPETTE_GENS.map(gen => ( + { + setPipetteGen(gen) + setPipetteVolume(null) + }} + buttonLabel={gen} + buttonValue={gen} + isSelected={pipetteGen === gen} + /> + ))} ) : null} @@ -224,12 +218,9 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { robotType === OT2_ROBOT_TYPE) ? ( - + {t('pip_vol')} @@ -287,7 +278,7 @@ export function SelectPipettes(props: WizardTileProps): JSX.Element | null { return ( - + {t('add_custom_tips')} @@ -381,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 b6b16f2a722..7abc5d2b47d 100644 --- a/protocol-designer/src/pages/CreateNewProtocolWizard/SelectRobot.tsx +++ b/protocol-designer/src/pages/CreateNewProtocolWizard/SelectRobot.tsx @@ -28,11 +28,7 @@ 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} + { 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 { } /> - From 426ecab4f26e860dd91d8a9ad5847951be577682 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:31:14 -0400 Subject: [PATCH 08/12] feat(protocol-designer): move labware tools wire up (#16314) closes AUTH-808 --- components/src/atoms/Checkbox/index.tsx | 12 ++- components/src/atoms/CheckboxField/index.tsx | 10 +- .../src/molecules/DropdownMenu/index.tsx | 66 ++++++++----- components/src/organisms/Toolbox/index.tsx | 4 +- .../localization/en/protocol_steps.json | 2 + .../fields/LabwareLocationField/index.tsx | 2 +- .../molecules/CheckboxStepFormField/index.tsx | 59 ++++++++++++ .../molecules/DropdownStepFormField/index.tsx | 34 +++++++ protocol-designer/src/molecules/index.ts | 2 + .../StepForm/StepFormToolbox.tsx | 1 + .../MoveLabwareTools/LabwareLocationField.tsx | 92 +++++++++++++++++++ .../MoveLabwareTools/MoveLabwareField.tsx | 18 ++++ .../StepTools/MoveLabwareTools/index.tsx | 55 ++++++++++- 13 files changed, 324 insertions(+), 33 deletions(-) create mode 100644 protocol-designer/src/molecules/CheckboxStepFormField/index.tsx create mode 100644 protocol-designer/src/molecules/DropdownStepFormField/index.tsx create mode 100644 protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/LabwareLocationField.tsx create mode 100644 protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepTools/MoveLabwareTools/MoveLabwareField.tsx 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 924d554cd0d..1bfba999eca 100644 --- a/components/src/molecules/DropdownMenu/index.tsx +++ b/components/src/molecules/DropdownMenu/index.tsx @@ -22,6 +22,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 */ @@ -35,6 +36,7 @@ export interface DropdownOption { value: string /** optional dropdown option for adding the liquid color icon */ liquidColor?: string + disabled?: boolean } export type DropdownBorder = 'rounded' | 'neutral' @@ -55,9 +57,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 @@ -73,6 +77,7 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { caption, tooltipText, tabIndex = 0, + error, } = props const [targetProps, tooltipProps] = useHoverTooltip() const [showDropdownMenu, setShowDropdownMenu] = React.useState(false) @@ -134,13 +139,22 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { setShowDropdownMenu(!showDropdownMenu) } + 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: ${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}; @@ -150,12 +164,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} ${COLORS.blue50}; + border: 1px ${BORDERS.styleSolid} ${error ? COLORS.red50 : COLORS.blue50}; } &:focus-visible { @@ -170,16 +183,16 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { } ` return ( - + {title !== null ? ( - - + + {title} - + {tooltipText != null ? ( <> @@ -208,18 +221,20 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element { {currentOption.liquidColor != null ? ( ) : null} - - {currentOption.name} - + + {currentOption.name} + + {showDropdownMenu ? ( @@ -262,14 +277,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 183669414bf..77ac2e12d68 100644 --- a/components/src/organisms/Toolbox/index.tsx +++ b/components/src/organisms/Toolbox/index.tsx @@ -25,6 +25,7 @@ export interface ToolboxProps { closeButtonText?: string side?: 'left' | 'right' horizontalSide?: 'top' | 'bottom' + childrenPadding?: string } export function Toolbox(props: ToolboxProps): JSX.Element { @@ -41,6 +42,7 @@ export function Toolbox(props: ToolboxProps): JSX.Element { confirmButton, side = 'right', horizontalSide = 'bottom', + childrenPadding = SPACING.spacing16, } = props const slideOutRef = React.useRef(null) @@ -108,7 +110,7 @@ export function Toolbox(props: ToolboxProps): JSX.Element { ) : null} + {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/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/StepForm/StepFormToolbox.tsx index 628b196c998..0ecd1347caa 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} + + + + + + + ) } From 4280a11fda594379b9feb147a84c95f0c99fdfe4 Mon Sep 17 00:00:00 2001 From: Jethary Alcid <66035149+jerader@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:48:39 -0400 Subject: [PATCH 09/12] feat(protocol-designer, components): timeline and form alerts (#16318) closes AUTH-803 --- app/src/molecules/UpdateBanner/index.tsx | 4 +- .../AdvancedSettings/U2EInformation.tsx | 2 +- .../CalibrationPanels/ChooseTipRack.tsx | 2 +- .../Introduction/InvalidationWarning.tsx | 2 +- .../organisms/ChooseRobotSlideout/index.tsx | 2 +- .../DeviceDetailsDeckConfiguration/index.tsx | 2 +- .../Devices/CalibrationStatusBanner.tsx | 2 +- app/src/organisms/Devices/EstopBanner.tsx | 2 +- .../Devices/HistoricalProtocolRunDrawer.tsx | 2 +- .../Devices/InstrumentsAndModules.tsx | 2 +- .../Devices/PipetteCard/FlexPipetteCard.tsx | 2 +- .../PipetteRecalibrationWarning.tsx | 2 +- .../ProtocolAnalysisErrorBanner.tsx | 2 +- .../TerminalRunBannerContainer.tsx | 3 +- .../RunHeaderBannerContainer/index.tsx | 3 +- .../ProtocolRunRunTimeParameters.tsx | 2 +- .../OT2MultipleModulesHelp.tsx | 2 +- .../UnMatchedModuleWarning.tsx | 2 +- .../SetupPipetteCalibrationItem.tsx | 2 +- app/src/organisms/Devices/ReachableBanner.tsx | 3 +- .../RenameRobotSlideout.tsx | 2 +- .../AdvancedTab/UpdateRobotSoftware.tsx | 2 +- .../UpdateBuildroot/UpdateRobotModal.tsx | 2 +- .../__tests__/InstrumentsAndModules.test.tsx | 6 +- .../EmergencyStop/EstopPressedModal.tsx | 2 +- .../organisms/ErrorRecoveryBanner/index.tsx | 2 +- app/src/organisms/GripperCard/index.tsx | 2 +- .../ModuleCard/AboutModuleSlideout.tsx | 8 +- app/src/organisms/ModuleCard/ErrorInfo.tsx | 2 +- app/src/organisms/ModuleCard/index.tsx | 2 +- .../ModuleWizardFlows/AttachProbe.tsx | 2 +- .../ModuleWizardFlows/SelectLocation.tsx | 2 +- .../PipetteWizardFlows/AttachProbe.tsx | 2 +- .../PipetteWizardFlows/BeforeBeginning.tsx | 2 +- .../PipetteWizardFlows/DetachPipette.tsx | 4 +- .../PipetteWizardFlows/MountPipette.tsx | 2 +- .../ProtocolAnalysisStale.tsx | 3 +- .../ProtocolAnalysisFailure/index.tsx | 2 +- .../ProtocolParameters/index.tsx | 2 +- .../organisms/ProtocolStatusBanner/index.tsx | 3 +- app/src/organisms/UpdateAppModal/index.tsx | 2 +- app/src/organisms/UpdateRobotBanner/index.tsx | 2 +- .../Desktop/AppSettings/GeneralSettings.tsx | 2 +- .../Desktop/Devices/RobotSettings/index.tsx | 2 +- .../src/molecules}/Banner/Banner.stories.tsx | 12 +- .../Banner/__tests__/Banner.test.tsx | 8 +- .../src/molecules}/Banner/index.tsx | 17 +- components/src/molecules/index.ts | 3 +- .../components/KnowledgeBaseLink/index.tsx | 5 +- .../src/organisms/Alerts/ErrorContents.tsx | 60 +++++++ .../src/organisms/Alerts/FormAlerts.tsx | 165 ++++++++++++++++++ .../src/organisms/Alerts/KnowledgeLink.tsx | 17 ++ .../src/organisms/Alerts/TerminalItemLink.tsx | 22 +++ .../src/organisms/Alerts/TimelineAlerts.tsx | 54 ++++++ .../src/organisms/Alerts/WarningContents.tsx | 41 +++++ .../Alerts/__tests__/FormAlerts.test.tsx | 77 ++++++++ .../Alerts/__tests__/TimelineAlerts.test.tsx | 44 +++++ .../src/organisms/Alerts/index.ts | 2 + .../src/organisms/Alerts/linkConstants.ts | 16 ++ .../src/organisms/Alerts/types.ts | 14 ++ protocol-designer/src/organisms/index.ts | 1 + .../Designer/DeckSetup/DeckSetupContainer.tsx | 14 +- .../StepForm/StepFormToolbox.tsx | 11 +- .../Timeline/ConnectedStepInfo.tsx | 11 +- .../ProtocolSteps/Timeline/StepContainer.tsx | 24 ++- .../Timeline/__tests__/StepContainer.test.tsx | 2 + .../pages/Designer/ProtocolSteps/index.tsx | 1 - 67 files changed, 625 insertions(+), 103 deletions(-) rename {app/src/atoms => components/src/molecules}/Banner/Banner.stories.tsx (73%) rename {app/src/atoms => components/src/molecules}/Banner/__tests__/Banner.test.tsx (92%) rename {app/src/atoms => components/src/molecules}/Banner/index.tsx (91%) create mode 100644 protocol-designer/src/organisms/Alerts/ErrorContents.tsx create mode 100644 protocol-designer/src/organisms/Alerts/FormAlerts.tsx create mode 100644 protocol-designer/src/organisms/Alerts/KnowledgeLink.tsx create mode 100644 protocol-designer/src/organisms/Alerts/TerminalItemLink.tsx create mode 100644 protocol-designer/src/organisms/Alerts/TimelineAlerts.tsx create mode 100644 protocol-designer/src/organisms/Alerts/WarningContents.tsx create mode 100644 protocol-designer/src/organisms/Alerts/__tests__/FormAlerts.test.tsx create mode 100644 protocol-designer/src/organisms/Alerts/__tests__/TimelineAlerts.test.tsx create mode 100644 protocol-designer/src/organisms/Alerts/index.ts create mode 100644 protocol-designer/src/organisms/Alerts/linkConstants.ts create mode 100644 protocol-designer/src/organisms/Alerts/types.ts diff --git a/app/src/molecules/UpdateBanner/index.tsx b/app/src/molecules/UpdateBanner/index.tsx index 12927dc5eea..7f0f70aeceb 100644 --- a/app/src/molecules/UpdateBanner/index.tsx +++ b/app/src/molecules/UpdateBanner/index.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next' import { ALIGN_START, Btn, + Banner, DIRECTION_COLUMN, Flex, SPACING, @@ -11,9 +12,8 @@ import { TYPOGRAPHY, useHoverTooltip, } from '@opentrons/components' - -import { Banner } from '/app/atoms/Banner' import { useIsFlex } from '/app/redux-resources/robots' + import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' interface UpdateBannerProps { diff --git a/app/src/organisms/AdvancedSettings/U2EInformation.tsx b/app/src/organisms/AdvancedSettings/U2EInformation.tsx index cfd1c59f5f0..edbf398da2d 100644 --- a/app/src/organisms/AdvancedSettings/U2EInformation.tsx +++ b/app/src/organisms/AdvancedSettings/U2EInformation.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next' import { ALIGN_CENTER, Box, + Banner, COLORS, DIRECTION_COLUMN, Flex, @@ -15,7 +16,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { getU2EAdapterDevice, getU2EWindowsDriverStatus, diff --git a/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx b/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx index 7a09addeb70..94541d6b7c7 100644 --- a/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx +++ b/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx @@ -5,6 +5,7 @@ import head from 'lodash/head' import isEqual from 'lodash/isEqual' import { ALIGN_CENTER, + Banner, Box, COLORS, DIRECTION_COLUMN, @@ -25,7 +26,6 @@ import { getTipLengthForPipetteAndTiprack, } from '/app/redux/calibration/' import { Select } from '/app/atoms/SelectField/Select' -import { Banner } from '/app/atoms/Banner' import { Divider } from '/app/atoms/structure' import { NeedHelpLink } from './NeedHelpLink' import { ChosenTipRackRender } from './ChosenTipRackRender' diff --git a/app/src/organisms/CalibrationPanels/Introduction/InvalidationWarning.tsx b/app/src/organisms/CalibrationPanels/Introduction/InvalidationWarning.tsx index fd047275c46..8f22e01fabc 100644 --- a/app/src/organisms/CalibrationPanels/Introduction/InvalidationWarning.tsx +++ b/app/src/organisms/CalibrationPanels/Introduction/InvalidationWarning.tsx @@ -1,12 +1,12 @@ import * as React from 'react' import { Flex, + Banner, SPACING, TYPOGRAPHY, LegacyStyledText, } from '@opentrons/components' import { useTranslation } from 'react-i18next' -import { Banner } from '/app/atoms/Banner' import * as Sessions from '/app/redux/sessions' interface InvalidationWarningProps { diff --git a/app/src/organisms/ChooseRobotSlideout/index.tsx b/app/src/organisms/ChooseRobotSlideout/index.tsx index 109d1832163..521405f0b42 100644 --- a/app/src/organisms/ChooseRobotSlideout/index.tsx +++ b/app/src/organisms/ChooseRobotSlideout/index.tsx @@ -7,6 +7,7 @@ import { css } from 'styled-components' import { ALIGN_CENTER, ALIGN_FLEX_END, + Banner, BORDERS, COLORS, CURSOR_AUTO, @@ -47,7 +48,6 @@ import { RE_ROBOT_MODEL_OT2, RE_ROBOT_MODEL_OT3, } from '/app/redux/discovery' -import { Banner } from '/app/atoms/Banner' import { Slideout } from '/app/atoms/Slideout' import { MultiSlideout } from '/app/atoms/Slideout/MultiSlideout' import { ToggleButton } from '/app/atoms/buttons' diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx index 2e717a4638a..98fc9a0f31c 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/index.tsx @@ -5,6 +5,7 @@ import { css } from 'styled-components' import { ALIGN_CENTER, ALIGN_FLEX_START, + Banner, BORDERS, COLORS, DeckConfigurator, @@ -29,7 +30,6 @@ import { } from '@opentrons/shared-data' import { useNotifyCurrentMaintenanceRun } from '/app/resources/maintenance_runs' -import { Banner } from '/app/atoms/Banner' import { DeckFixtureSetupInstructionsModal } from './DeckFixtureSetupInstructionsModal' import { useIsRobotViewable, useRunStatuses } from '../Devices/hooks' import { useIsEstopNotDisengaged } from '/app/resources/devices/hooks/useIsEstopNotDisengaged' diff --git a/app/src/organisms/Devices/CalibrationStatusBanner.tsx b/app/src/organisms/Devices/CalibrationStatusBanner.tsx index 0a16d516658..e1a305e3d58 100644 --- a/app/src/organisms/Devices/CalibrationStatusBanner.tsx +++ b/app/src/organisms/Devices/CalibrationStatusBanner.tsx @@ -4,6 +4,7 @@ import { Link as RouterLink } from 'react-router-dom' import { ALIGN_CENTER, + Banner, COLORS, DIRECTION_ROW, Flex, @@ -14,7 +15,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { useCalibrationTaskList } from './hooks' interface CalibrationStatusBannerProps { diff --git a/app/src/organisms/Devices/EstopBanner.tsx b/app/src/organisms/Devices/EstopBanner.tsx index f006be1ed47..2a88b56bf89 100644 --- a/app/src/organisms/Devices/EstopBanner.tsx +++ b/app/src/organisms/Devices/EstopBanner.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { Btn, + Banner, DIRECTION_ROW, Flex, SPACING, @@ -9,7 +10,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { NOT_PRESENT, PHYSICALLY_ENGAGED, diff --git a/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx b/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx index 26316a4b990..bb0b419f830 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx @@ -6,6 +6,7 @@ import { css } from 'styled-components' import { ALIGN_CENTER, ALIGN_END, + Banner, BORDERS, Box, COLORS, @@ -27,7 +28,6 @@ import { } from '@opentrons/shared-data' import { useCsvFileQuery } from '@opentrons/react-api-client' import { DownloadCsvFileLink } from './DownloadCsvFileLink' -import { Banner } from '/app/atoms/Banner' import { useMostRecentCompletedAnalysis } from '../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useDeckCalibrationData } from './hooks' import { OffsetVector } from '/app/molecules/OffsetVector' diff --git a/app/src/organisms/Devices/InstrumentsAndModules.tsx b/app/src/organisms/Devices/InstrumentsAndModules.tsx index b8b2e786bb5..2c375d83e12 100644 --- a/app/src/organisms/Devices/InstrumentsAndModules.tsx +++ b/app/src/organisms/Devices/InstrumentsAndModules.tsx @@ -10,6 +10,7 @@ import { import { ALIGN_CENTER, ALIGN_FLEX_START, + Banner, COLORS, DIRECTION_COLUMN, Flex, @@ -20,7 +21,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { PipetteRecalibrationWarning } from './PipetteCard/PipetteRecalibrationWarning' import { useCurrentRunId } from '/app/resources/runs' import { useIsFlex } from '/app/redux-resources/robots' diff --git a/app/src/organisms/Devices/PipetteCard/FlexPipetteCard.tsx b/app/src/organisms/Devices/PipetteCard/FlexPipetteCard.tsx index a1042e92881..be99be7c6af 100644 --- a/app/src/organisms/Devices/PipetteCard/FlexPipetteCard.tsx +++ b/app/src/organisms/Devices/PipetteCard/FlexPipetteCard.tsx @@ -3,6 +3,7 @@ import { Trans, useTranslation } from 'react-i18next' import { css } from 'styled-components' import { CURSOR_POINTER, + Banner, LegacyStyledText, SPACING, TYPOGRAPHY, @@ -17,7 +18,6 @@ import { useCurrentSubsystemUpdateQuery, useHost, } from '@opentrons/react-api-client' -import { Banner } from '/app/atoms/Banner' import { InstrumentCard } from '/app/molecules/InstrumentCard' import { ChoosePipette } from '../../PipetteWizardFlows/ChoosePipette' import { FLOWS } from '../../PipetteWizardFlows/constants' diff --git a/app/src/organisms/Devices/PipetteCard/PipetteRecalibrationWarning.tsx b/app/src/organisms/Devices/PipetteCard/PipetteRecalibrationWarning.tsx index 452d97766d3..0007328b315 100644 --- a/app/src/organisms/Devices/PipetteCard/PipetteRecalibrationWarning.tsx +++ b/app/src/organisms/Devices/PipetteCard/PipetteRecalibrationWarning.tsx @@ -2,13 +2,13 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { Box, + Banner, DIRECTION_COLUMN, Flex, SPACING, LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' export const PipetteRecalibrationWarning = (): JSX.Element | null => { const { t } = useTranslation('device_details') diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/ProtocolAnalysisErrorBanner.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/ProtocolAnalysisErrorBanner.tsx index 183e51fb1eb..1f4501d74b6 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/ProtocolAnalysisErrorBanner.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/ProtocolAnalysisErrorBanner.tsx @@ -4,6 +4,7 @@ import { Trans, useTranslation } from 'react-i18next' import { ALIGN_CENTER, + Banner, Btn, Flex, JUSTIFY_FLEX_END, @@ -16,7 +17,6 @@ import { } from '@opentrons/components' import { getTopPortalEl } from '../../../../../App/portal' -import { Banner } from '/app/atoms/Banner' import type { AnalysisError } from '@opentrons/shared-data' diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx index 3df355a0b3c..6116f4be3b1 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/TerminalRunBannerContainer.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next' import { SPACING, TYPOGRAPHY, + Banner, JUSTIFY_SPACE_BETWEEN, Flex, StyledText, @@ -11,8 +12,6 @@ import { ALIGN_CENTER, } from '@opentrons/components' import { RUN_STATUS_STOPPED, RUN_STATUS_SUCCEEDED } from '@opentrons/api-client' - -import { Banner } from '/app/atoms/Banner' import { useCloseCurrentRun, useIsRunCurrent, diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/index.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/index.tsx index d2e41230640..48a26bf1b85 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/index.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader/RunHeaderBannerContainer/index.tsx @@ -1,10 +1,9 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { Box, SPACING } from '@opentrons/components' +import { Box, SPACING, Banner } from '@opentrons/components' import { ProtocolAnalysisErrorBanner } from './ProtocolAnalysisErrorBanner' -import { Banner } from '/app/atoms/Banner' import { TerminalRunBannerContainer, useTerminalRunBannerContainer, diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx index f5fc97c22e2..27990c8e798 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx @@ -13,6 +13,7 @@ import { } from '@opentrons/shared-data' import { ALIGN_CENTER, + Banner, BORDERS, Chip, COLORS, @@ -31,7 +32,6 @@ import { useHoverTooltip, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { Divider } from '/app/atoms/structure' import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis' import { useNotifyRunQuery, useRunStatus } from '/app/resources/runs' diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/OT2MultipleModulesHelp.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/OT2MultipleModulesHelp.tsx index 4661052add2..5517e944a23 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/OT2MultipleModulesHelp.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/OT2MultipleModulesHelp.tsx @@ -3,6 +3,7 @@ import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' import { ALIGN_FLEX_END, + Banner, Box, DIRECTION_COLUMN, DIRECTION_ROW, @@ -16,7 +17,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { getTopPortalEl } from '../../../../App/portal' -import { Banner } from '/app/atoms/Banner' import multipleModuleHelp from '/app/assets/images/Moam_modal_image.png' const HOW_TO_MULTIPLE_MODULES_HREF = diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/UnMatchedModuleWarning.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/UnMatchedModuleWarning.tsx index f2151f2626c..224053fa5eb 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/UnMatchedModuleWarning.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/UnMatchedModuleWarning.tsx @@ -2,12 +2,12 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { DIRECTION_COLUMN, + Banner, Flex, SPACING, LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' export const UnMatchedModuleWarning = (): JSX.Element | null => { const { t } = useTranslation('protocol_setup') diff --git a/app/src/organisms/Devices/ProtocolRun/SetupPipetteCalibrationItem.tsx b/app/src/organisms/Devices/ProtocolRun/SetupPipetteCalibrationItem.tsx index 1e5f271fe57..653942b9c00 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupPipetteCalibrationItem.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupPipetteCalibrationItem.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { Link as RRDLink } from 'react-router-dom' import { + Banner, Box, Flex, LegacyTooltip, @@ -19,7 +20,6 @@ import { WRAP, } from '@opentrons/components' import { TertiaryButton } from '/app/atoms/buttons' -import { Banner } from '/app/atoms/Banner' import * as PipetteConstants from '/app/redux/pipettes/constants' import { useDeckCalibrationData } from '../hooks' import { SetupCalibrationItem } from './SetupCalibrationItem' diff --git a/app/src/organisms/Devices/ReachableBanner.tsx b/app/src/organisms/Devices/ReachableBanner.tsx index d729203c5d9..35c56cad8b9 100644 --- a/app/src/organisms/Devices/ReachableBanner.tsx +++ b/app/src/organisms/Devices/ReachableBanner.tsx @@ -1,7 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { SPACING } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' +import { SPACING, Banner } from '@opentrons/components' import { REACHABLE } from '/app/redux/discovery' import type { DiscoveredRobot } from '/app/redux/discovery/types' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx index 1ae6e89a5ff..5c02dc8eb95 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx @@ -5,6 +5,7 @@ import { useForm, Controller } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { COLORS, + Banner, DIRECTION_COLUMN, Flex, InputField, @@ -21,7 +22,6 @@ import { } from '/app/redux/discovery' import { useTrackEvent, ANALYTICS_RENAME_ROBOT } from '/app/redux/analytics' import { Slideout } from '/app/atoms/Slideout' -import { Banner } from '/app/atoms/Banner' import { useIsFlex } from '/app/redux-resources/robots' import type { Resolver, FieldError } from 'react-hook-form' diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx index bb480e9a140..afe1481e68f 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx @@ -5,6 +5,7 @@ import { css } from 'styled-components' import { ALIGN_CENTER, + Banner, Box, Flex, JUSTIFY_SPACE_BETWEEN, @@ -22,7 +23,6 @@ import { ExternalLink } from '/app/atoms/Link/ExternalLink' import { TertiaryButton } from '/app/atoms/buttons' import { getRobotUpdateDisplayInfo } from '/app/redux/robot-update' import { useDispatchStartRobotUpdate } from '/app/redux/robot-update/hooks' -import { Banner } from '/app/atoms/Banner' import type { State } from '/app/redux/types' diff --git a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx index 0f01f83e33d..0506a3b20b9 100644 --- a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx @@ -5,6 +5,7 @@ import styled, { css } from 'styled-components' import { ALIGN_CENTER, + Banner, BORDERS, DIRECTION_COLUMN, Flex, @@ -30,7 +31,6 @@ import { import { ExternalLink } from '/app/atoms/Link/ExternalLink' import { ReleaseNotes } from '/app/molecules/ReleaseNotes' import { useIsRobotBusy } from '../../hooks' -import { Banner } from '/app/atoms/Banner' import { useDispatchStartRobotUpdate } from '/app/redux/robot-update/hooks' import type { State, Dispatch } from '/app/redux/types' diff --git a/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx b/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx index cb9ab747ed3..813fab1ecd6 100644 --- a/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx +++ b/app/src/organisms/Devices/__tests__/InstrumentsAndModules.test.tsx @@ -11,7 +11,6 @@ import { } from '@opentrons/react-api-client' import { i18n } from '/app/i18n' -import { Banner } from '/app/atoms/Banner' import { mockMagneticModule } from '/app/redux/modules/__fixtures__' import { useIsFlex } from '/app/redux-resources/robots' import { useIsRobotViewable, useRunStatuses } from '../hooks' @@ -42,7 +41,6 @@ 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('/app/resources/devices/hooks/useIsEstopNotDisengaged') @@ -122,7 +120,9 @@ describe('InstrumentsAndModules', () => { it('renders the protocol loaded banner when protocol is loaded and not terminal state', () => { vi.mocked(useCurrentRunId).mockReturnValue('RUNID') render() - expect(vi.mocked(Banner)).toHaveBeenCalled() + screen.getByText( + 'Robot must be on the network to see connected instruments and modules' + ) }) it('renders 1 pipette card when a 96 channel is attached', () => { when(useIsFlex).calledWith(ROBOT_NAME).thenReturn(true) diff --git a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx index 47aee918e90..b36962d4045 100644 --- a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx +++ b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx @@ -4,6 +4,7 @@ import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { ALIGN_CENTER, + Banner, BORDERS, Chip, COLORS, @@ -24,7 +25,6 @@ import { import { useAcknowledgeEstopDisengageMutation } from '@opentrons/react-api-client' import { getTopPortalEl } from '../../App/portal' -import { Banner } from '/app/atoms/Banner' import { SmallButton } from '/app/atoms/buttons' import { OddModal } from '/app/molecules/OddModal' import { getIsOnDevice } from '/app/redux/config' diff --git a/app/src/organisms/ErrorRecoveryBanner/index.tsx b/app/src/organisms/ErrorRecoveryBanner/index.tsx index 6a2d12607cd..a01ca4e4dbd 100644 --- a/app/src/organisms/ErrorRecoveryBanner/index.tsx +++ b/app/src/organisms/ErrorRecoveryBanner/index.tsx @@ -4,6 +4,7 @@ import { useSelector } from 'react-redux' import { Flex, + Banner, DIRECTION_COLUMN, SPACING, StyledText, @@ -11,7 +12,6 @@ import { import { getUserId } from '/app/redux/config' import { useClientDataRecovery } from '/app/resources/client_data' -import { Banner } from '/app/atoms/Banner' import type { RecoveryIntent } from '/app/resources/client_data' import type { StyleProps } from '@opentrons/components' diff --git a/app/src/organisms/GripperCard/index.tsx b/app/src/organisms/GripperCard/index.tsx index fd720a99e0f..34ade2ce899 100644 --- a/app/src/organisms/GripperCard/index.tsx +++ b/app/src/organisms/GripperCard/index.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { Trans, useTranslation } from 'react-i18next' import { css } from 'styled-components' import { + Banner, CURSOR_POINTER, LegacyStyledText, SPACING, @@ -9,7 +10,6 @@ import { } from '@opentrons/components' import { getGripperDisplayName } from '@opentrons/shared-data' import { useCurrentSubsystemUpdateQuery } from '@opentrons/react-api-client' -import { Banner } from '/app/atoms/Banner' import { InstrumentCard } from '/app/molecules/InstrumentCard' import { GripperWizardFlows } from '../GripperWizardFlows' import { AboutGripperSlideout } from './AboutGripperSlideout' diff --git a/app/src/organisms/ModuleCard/AboutModuleSlideout.tsx b/app/src/organisms/ModuleCard/AboutModuleSlideout.tsx index 61cf06a970c..ba079b33a57 100644 --- a/app/src/organisms/ModuleCard/AboutModuleSlideout.tsx +++ b/app/src/organisms/ModuleCard/AboutModuleSlideout.tsx @@ -4,6 +4,7 @@ import { css } from 'styled-components' import { RUN_STATUS_RUNNING, RUN_STATUS_FINISHING } from '@opentrons/api-client' import { ALIGN_START, + Banner, Btn, COLORS, DIRECTION_COLUMN, @@ -15,17 +16,16 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { getModuleDisplayName } from '@opentrons/shared-data' -import { Slideout } from '/app/atoms/Slideout' -import { Banner } from '/app/atoms/Banner' +import { Slideout } from '../../atoms/Slideout' import { useCurrentRunStatus } from '../RunTimeControl/hooks' import type { AttachedModule } from '/app/redux/modules/types' interface AboutModuleSlideoutProps { module: AttachedModule - onCloseClick: () => unknown + onCloseClick: () => void isExpanded: boolean - firmwareUpdateClick: () => unknown + firmwareUpdateClick: () => void } const ALERT_ITEM_STYLE = css` diff --git a/app/src/organisms/ModuleCard/ErrorInfo.tsx b/app/src/organisms/ModuleCard/ErrorInfo.tsx index 57caacbdc56..249490b9131 100644 --- a/app/src/organisms/ModuleCard/ErrorInfo.tsx +++ b/app/src/organisms/ModuleCard/ErrorInfo.tsx @@ -8,6 +8,7 @@ import { } from '@opentrons/shared-data' import { ALIGN_START, + Banner, Btn, DIRECTION_COLUMN, DIRECTION_ROW, @@ -19,7 +20,6 @@ import { LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { getTopPortalEl } from '../../App/portal' import type { AttachedModule } from '/app/redux/modules/types' diff --git a/app/src/organisms/ModuleCard/index.tsx b/app/src/organisms/ModuleCard/index.tsx index f8f847c2a93..e0f246d0ea1 100644 --- a/app/src/organisms/ModuleCard/index.tsx +++ b/app/src/organisms/ModuleCard/index.tsx @@ -4,6 +4,7 @@ import { useDispatch, useSelector } from 'react-redux' import { ALIGN_START, + Banner, BORDERS, Box, COLORS, @@ -41,7 +42,6 @@ import { dismissRequest, SUCCESS, } from '/app/redux/robot-api' -import { Banner } from '/app/atoms/Banner' import { UpdateBanner } from '/app/molecules/UpdateBanner' import { useChainLiveCommands } from '/app/resources/runs' import { useCurrentRunStatus } from '/app/organisms/RunTimeControl/hooks' diff --git a/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx b/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx index 18fc3657732..33717d93f88 100644 --- a/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx +++ b/app/src/organisms/ModuleWizardFlows/AttachProbe.tsx @@ -3,6 +3,7 @@ import { css } from 'styled-components' import { Trans, useTranslation } from 'react-i18next' import { Flex, + Banner, RESPONSIVENESS, SPACING, LegacyStyledText, @@ -20,7 +21,6 @@ import type { CutoutId, CutoutFixtureId, } from '@opentrons/shared-data' -import { Banner } from '/app/atoms/Banner' import { GenericWizardTile } from '/app/molecules/GenericWizardTile' import type { ModuleCalibrationWizardStepProps } from './types' diff --git a/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx b/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx index c7b9e98005f..7e7efd10a8b 100644 --- a/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx +++ b/app/src/organisms/ModuleWizardFlows/SelectLocation.tsx @@ -17,6 +17,7 @@ import { SINGLE_SLOT_FIXTURES, } from '@opentrons/shared-data' import { + Banner, DeckConfigurator, RESPONSIVENESS, SIZE_1, @@ -24,7 +25,6 @@ import { LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { GenericWizardTile } from '/app/molecules/GenericWizardTile' import type { ModuleCalibrationWizardStepProps } from './types' import type { diff --git a/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx b/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx index 24086bc6e6f..dcb3c323770 100644 --- a/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx +++ b/app/src/organisms/PipetteWizardFlows/AttachProbe.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { css } from 'styled-components' import { Trans, useTranslation } from 'react-i18next' import { + Banner, COLORS, Flex, RESPONSIVENESS, @@ -10,7 +11,6 @@ import { TYPOGRAPHY, } from '@opentrons/components' import { LEFT, WASTE_CHUTE_CUTOUT } from '@opentrons/shared-data' -import { Banner } from '/app/atoms/Banner' import { GenericWizardTile } from '/app/molecules/GenericWizardTile' import { SimpleWizardBody, diff --git a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx index f781e435f2a..a0147b440c7 100644 --- a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx +++ b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { Trans, useTranslation } from 'react-i18next' import { COLORS, + Banner, DIRECTION_COLUMN, Flex, SPACING, @@ -14,7 +15,6 @@ import { WEIGHT_OF_96_CHANNEL, WASTE_CHUTE_CUTOUT, } from '@opentrons/shared-data' -import { Banner } from '/app/atoms/Banner' import { SimpleWizardBody, SimpleWizardInProgressBody, diff --git a/app/src/organisms/PipetteWizardFlows/DetachPipette.tsx b/app/src/organisms/PipetteWizardFlows/DetachPipette.tsx index 8d5db88c879..46e5f92e389 100644 --- a/app/src/organisms/PipetteWizardFlows/DetachPipette.tsx +++ b/app/src/organisms/PipetteWizardFlows/DetachPipette.tsx @@ -6,18 +6,18 @@ import { useInstrumentsQuery } from '@opentrons/react-api-client' import { ALIGN_CENTER, ALIGN_FLEX_END, + Banner, Btn, COLORS, Flex, JUSTIFY_SPACE_BETWEEN, + LegacyStyledText, PrimaryButton, RESPONSIVENESS, SIZE_1, SPACING, - LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { GenericWizardTile } from '/app/molecules/GenericWizardTile' import { SimpleWizardBody, diff --git a/app/src/organisms/PipetteWizardFlows/MountPipette.tsx b/app/src/organisms/PipetteWizardFlows/MountPipette.tsx index 6234d5247a0..47caab54ff2 100644 --- a/app/src/organisms/PipetteWizardFlows/MountPipette.tsx +++ b/app/src/organisms/PipetteWizardFlows/MountPipette.tsx @@ -6,12 +6,12 @@ import { } from '@opentrons/shared-data' import { Flex, + Banner, JUSTIFY_CENTER, SIZE_1, SPACING, LegacyStyledText, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { GenericWizardTile } from '/app/molecules/GenericWizardTile' import { Skeleton } from '/app/atoms/Skeleton' import { CheckPipetteButton } from './CheckPipetteButton' diff --git a/app/src/organisms/ProtocolAnalysisFailure/ProtocolAnalysisStale.tsx b/app/src/organisms/ProtocolAnalysisFailure/ProtocolAnalysisStale.tsx index aa961fae559..2cbd85417f2 100644 --- a/app/src/organisms/ProtocolAnalysisFailure/ProtocolAnalysisStale.tsx +++ b/app/src/organisms/ProtocolAnalysisFailure/ProtocolAnalysisStale.tsx @@ -4,6 +4,7 @@ import { useTranslation, Trans } from 'react-i18next' import { ALIGN_CENTER, + Banner, Btn, Flex, JUSTIFY_SPACE_BETWEEN, @@ -13,8 +14,6 @@ import { WRAP_REVERSE, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' - import type { Dispatch } from '/app/redux/types' import { analyzeProtocol } from '/app/redux/protocol-storage' interface ProtocolAnalysisStaleProps { diff --git a/app/src/organisms/ProtocolAnalysisFailure/index.tsx b/app/src/organisms/ProtocolAnalysisFailure/index.tsx index a5d35f32a42..c16f63b3838 100644 --- a/app/src/organisms/ProtocolAnalysisFailure/index.tsx +++ b/app/src/organisms/ProtocolAnalysisFailure/index.tsx @@ -7,6 +7,7 @@ import { css } from 'styled-components' import { ALIGN_CENTER, Btn, + Banner, Flex, JUSTIFY_FLEX_END, Modal, @@ -19,7 +20,6 @@ import { } from '@opentrons/components' import { analyzeProtocol } from '/app/redux/protocol-storage' -import { Banner } from '/app/atoms/Banner' import { getTopPortalEl } from '../../App/portal' import type { Dispatch } from '/app/redux/types' diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx b/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx index 6e7067204d0..6b7d6ce7a60 100644 --- a/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx +++ b/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx @@ -2,6 +2,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { + Banner, DIRECTION_COLUMN, Flex, InfoScreen, @@ -9,7 +10,6 @@ import { SPACING, StyledText, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import type { RunTimeParameter } from '@opentrons/shared-data' diff --git a/app/src/organisms/ProtocolStatusBanner/index.tsx b/app/src/organisms/ProtocolStatusBanner/index.tsx index 6037d88596a..f7259f97d03 100644 --- a/app/src/organisms/ProtocolStatusBanner/index.tsx +++ b/app/src/organisms/ProtocolStatusBanner/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { SPACING, LegacyStyledText } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' +import { SPACING, Banner, LegacyStyledText } from '@opentrons/components' import type { IconProps } from '@opentrons/components' diff --git a/app/src/organisms/UpdateAppModal/index.tsx b/app/src/organisms/UpdateAppModal/index.tsx index b29c4e66528..4b32029316c 100644 --- a/app/src/organisms/UpdateAppModal/index.tsx +++ b/app/src/organisms/UpdateAppModal/index.tsx @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next' import { ALIGN_CENTER, + Banner, BORDERS, COLORS, DIRECTION_COLUMN, @@ -28,7 +29,6 @@ import { import { ExternalLink } from '/app/atoms/Link/ExternalLink' import { ReleaseNotes } from '/app/molecules/ReleaseNotes' -import { Banner } from '/app/atoms/Banner' import { ProgressBar } from '/app/atoms/ProgressBar' import { useRemoveActiveAppUpdateToast } from '../Alerts' diff --git a/app/src/organisms/UpdateRobotBanner/index.tsx b/app/src/organisms/UpdateRobotBanner/index.tsx index 57fcae39aff..513cd4965e8 100644 --- a/app/src/organisms/UpdateRobotBanner/index.tsx +++ b/app/src/organisms/UpdateRobotBanner/index.tsx @@ -5,11 +5,11 @@ import { Btn, DIRECTION_COLUMN, Flex, + Banner, SPACING, LegacyStyledText, TYPOGRAPHY, } from '@opentrons/components' -import { Banner } from '/app/atoms/Banner' import { getRobotUpdateDisplayInfo } from '/app/redux/robot-update' import { handleUpdateBuildroot } from '../Devices/RobotSettings/UpdateBuildroot' diff --git a/app/src/pages/Desktop/AppSettings/GeneralSettings.tsx b/app/src/pages/Desktop/AppSettings/GeneralSettings.tsx index 45918056041..e4931a8995c 100644 --- a/app/src/pages/Desktop/AppSettings/GeneralSettings.tsx +++ b/app/src/pages/Desktop/AppSettings/GeneralSettings.tsx @@ -7,6 +7,7 @@ import { useSelector, useDispatch } from 'react-redux' import { ALIGN_CENTER, ALIGN_START, + Banner, Box, COLORS, DIRECTION_COLUMN, @@ -24,7 +25,6 @@ import { import { TertiaryButton, ToggleButton } from '/app/atoms/buttons' import { ExternalLink } from '/app/atoms/Link/ExternalLink' import { Divider } from '/app/atoms/structure' -import { Banner } from '/app/atoms/Banner' import { CURRENT_VERSION, getAvailableShellUpdate, diff --git a/app/src/pages/Desktop/Devices/RobotSettings/index.tsx b/app/src/pages/Desktop/Devices/RobotSettings/index.tsx index 15f289764b4..6ae85003218 100644 --- a/app/src/pages/Desktop/Devices/RobotSettings/index.tsx +++ b/app/src/pages/Desktop/Devices/RobotSettings/index.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { useParams, Navigate } from 'react-router-dom' import { + Banner, BORDERS, Box, COLORS, @@ -25,7 +26,6 @@ import { 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/redux-resources/robots' import { Line } from '/app/atoms/structure' import { NavTab } from '/app/molecules/NavTab' diff --git a/app/src/atoms/Banner/Banner.stories.tsx b/components/src/molecules/Banner/Banner.stories.tsx similarity index 73% rename from app/src/atoms/Banner/Banner.stories.tsx rename to components/src/molecules/Banner/Banner.stories.tsx index de756b10de6..b3370a40dc6 100644 --- a/app/src/atoms/Banner/Banner.stories.tsx +++ b/components/src/molecules/Banner/Banner.stories.tsx @@ -1,10 +1,11 @@ import * as React from 'react' -import { LegacyStyledText, TYPOGRAPHY } from '@opentrons/components' +import { StyledText } from '../../atoms/StyledText' import { Banner } from './index' + import type { Meta, StoryObj } from '@storybook/react' const meta: Meta = { - title: 'App/Atoms/Banner', + title: 'Library/Molecules/Banner', component: Banner, } @@ -35,12 +36,7 @@ export const OverriddenExitIcon: Story = { console.log('close') }, closeButton: ( - - {'Exit'} - + {'Exit'} ), }, } diff --git a/app/src/atoms/Banner/__tests__/Banner.test.tsx b/components/src/molecules/Banner/__tests__/Banner.test.tsx similarity index 92% rename from app/src/atoms/Banner/__tests__/Banner.test.tsx rename to components/src/molecules/Banner/__tests__/Banner.test.tsx index 07187f23db2..62109e1aaf9 100644 --- a/app/src/atoms/Banner/__tests__/Banner.test.tsx +++ b/components/src/molecules/Banner/__tests__/Banner.test.tsx @@ -1,14 +1,12 @@ import * as React from 'react' import { describe, it, vi, expect, beforeEach } from 'vitest' import { fireEvent, screen } from '@testing-library/react' -import { renderWithProviders } from '/app/__testing-utils__' -import { i18n } from '/app/i18n' +import { renderWithProviders } from '../../../testing/utils' + import { Banner } from '..' const render = (props: React.ComponentProps) => { - return renderWithProviders(, { - i18nInstance: i18n, - })[0] + return renderWithProviders()[0] } describe('Banner', () => { diff --git a/app/src/atoms/Banner/index.tsx b/components/src/molecules/Banner/index.tsx similarity index 91% rename from app/src/atoms/Banner/index.tsx rename to components/src/molecules/Banner/index.tsx index 1061dd50ac9..c15dbabd663 100644 --- a/app/src/atoms/Banner/index.tsx +++ b/components/src/molecules/Banner/index.tsx @@ -1,19 +1,16 @@ import * as React from 'react' import { css } from 'styled-components' +import { Btn, Flex } from '../../primitives' +import { Icon } from '../../icons' +import { BORDERS, COLORS } from '../../helix-design-system' +import { RESPONSIVENESS, SPACING, TYPOGRAPHY } from '../../ui-style-constants' import { ALIGN_CENTER, - BORDERS, - Btn, - COLORS, DIRECTION_ROW, - Flex, - Icon, JUSTIFY_SPACE_BETWEEN, - RESPONSIVENESS, - SPACING, - TYPOGRAPHY, -} from '@opentrons/components' -import type { IconProps, StyleProps } from '@opentrons/components' +} from '../../styles' +import type { StyleProps } from '../../primitives' +import type { IconProps } from '../../icons' export type BannerType = | 'success' diff --git a/components/src/molecules/index.ts b/components/src/molecules/index.ts index 09fbefa3fc5..3bc14d46e3e 100644 --- a/components/src/molecules/index.ts +++ b/components/src/molecules/index.ts @@ -1,7 +1,8 @@ +export * from './Banner' export * from './DeckInfoLabel' +export * from './DeckLabel' export * from './DropdownMenu' export * from './InfoScreen' export * from './LiquidIcon' export * from './ParametersTable' export * from './Tabs' -export * from './DeckLabel' diff --git a/protocol-designer/src/components/KnowledgeBaseLink/index.tsx b/protocol-designer/src/components/KnowledgeBaseLink/index.tsx index 31fbefe73cd..693c09d23a5 100644 --- a/protocol-designer/src/components/KnowledgeBaseLink/index.tsx +++ b/protocol-designer/src/components/KnowledgeBaseLink/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import { Link } from '@opentrons/components' export const KNOWLEDGEBASE_ROOT_URL = 'https://support.opentrons.com/s/protocol-designer' @@ -26,13 +27,13 @@ interface Props { /** Link which opens a page on the knowledge base to a new tab/window */ export function KnowledgeBaseLink(props: Props): JSX.Element { return ( - {props.children} - + ) } diff --git a/protocol-designer/src/organisms/Alerts/ErrorContents.tsx b/protocol-designer/src/organisms/Alerts/ErrorContents.tsx new file mode 100644 index 00000000000..20266686d6d --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/ErrorContents.tsx @@ -0,0 +1,60 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { START_TERMINAL_ITEM_ID } from '../../steplist' +import { KnowledgeBaseLink } from '../../components/KnowledgeBaseLink' +import { TerminalItemLink } from './TerminalItemLink' + +import type { AlertLevel } from './types' + +interface ErrorContentsProps { + errorType: string + level: AlertLevel +} +export const ErrorContents = ( + props: ErrorContentsProps +): JSX.Element | null => { + const { errorType, level } = props + const { t } = useTranslation(['alert', 'shared']) + + if (level === 'timeline') { + const bodyText = t(`timeline.error.${errorType}.body`, { + defaultValue: '', + }) + switch (errorType) { + case 'INSUFFICIENT_TIPS': + return ( + <> + {bodyText} + + + ) + case 'MODULE_PIPETTE_COLLISION_DANGER': + return ( + <> + {bodyText} + + {t('shared:here')} + + + ) + case 'NO_TIP_ON_PIPETTE': + return ( + <> + {t(`timeline.error.${errorType}.body1`)} + + {t(`timeline.error.${errorType}.link`)} + + {t(`timeline.error.${errorType}.body2`)} + + ) + default: + return bodyText + } + } else if (level === 'form') { + return t(`form.error.${errorType}.body`, { + defaultValue: '', + }) + } else { + return null + } +} diff --git a/protocol-designer/src/organisms/Alerts/FormAlerts.tsx b/protocol-designer/src/organisms/Alerts/FormAlerts.tsx new file mode 100644 index 00000000000..90ec773c99b --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/FormAlerts.tsx @@ -0,0 +1,165 @@ +import * as React from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { useTranslation } from 'react-i18next' +import { + Banner, + DIRECTION_COLUMN, + Flex, + SPACING, + StyledText, +} from '@opentrons/components' +import * as timelineWarningSelectors from '../../top-selectors/timelineWarnings' +import { getSelectedStepId } from '../../ui/steps' +import { + actions as dismissActions, + selectors as dismissSelectors, +} from '../../dismiss' +import { selectors as stepFormSelectors } from '../../step-forms' +import { + getVisibleFormErrors, + getVisibleFormWarnings, + getVisibleProfileFormLevelErrors, +} from '../../pages/Designer/ProtocolSteps/StepForm/utils' +import { WarningContents } from './WarningContents' + +import type { ProfileItem } from '@opentrons/step-generation' +import type { StepFieldName } from '../../form-types' +import type { ProfileFormError } from '../../steplist/formLevel/profileErrors' +import type { MakeAlert } from './types' + +interface FormAlertsProps { + focusedField?: StepFieldName | null + dirtyFields?: StepFieldName[] +} + +function FormAlertsComponent(props: FormAlertsProps): JSX.Element { + const { focusedField, dirtyFields } = props + const { t } = useTranslation('alert') + const dispatch = useDispatch() + const formLevelErrorsForUnsavedForm = useSelector( + stepFormSelectors.getFormLevelErrorsForUnsavedForm + ) + const formWarningsForSelectedStep = useSelector( + dismissSelectors.getFormWarningsForSelectedStep + ) + const timelineWarningsForSelectedStep = useSelector( + timelineWarningSelectors.getTimelineWarningsForSelectedStep + ) + const unsavedForm = useSelector(stepFormSelectors.getHydratedUnsavedForm) + const dynamicFieldFormErrors = useSelector( + stepFormSelectors.getDynamicFieldFormErrorsForUnsavedForm + ) + const stepId = useSelector(getSelectedStepId) + + const timelineWarnings = timelineWarningsForSelectedStep.map(warning => ({ + title: t(`timeline.warning.${warning.type}.title`), + description: ( + + ), + dismissId: warning.type, + })) + + const visibleFormWarnings = getVisibleFormWarnings({ + focusedField, + dirtyFields: dirtyFields ?? [], + errors: formWarningsForSelectedStep, + }) + const visibleFormErrors = getVisibleFormErrors({ + focusedField, + dirtyFields: dirtyFields ?? [], + errors: formLevelErrorsForUnsavedForm, + }) + + const profileItemsById: Record | null | undefined = + unsavedForm?.profileItemsById + + let visibleDynamicFieldFormErrors: ProfileFormError[] = [] + + if (profileItemsById != null) { + visibleDynamicFieldFormErrors = getVisibleProfileFormLevelErrors({ + focusedField, + dirtyFields: dirtyFields ?? [], + errors: dynamicFieldFormErrors, + profileItemsById, + }) + } + + const makeHandleCloseWarning = (dismissId?: string | null) => () => { + console.assert( + dismissId, + 'expected dismissId, Alert cannot dismiss warning' + ) + if (dismissId) { + dismissWarning(dismissId) + } + } + + const makeAlert: MakeAlert = (alertType, data, key) => ( + + + + + {data.title} + + + {data.description} + + + + + ) + const formErrors = [ + ...visibleFormErrors.map(error => ({ + title: error.title, + description: error.body || null, + })), + ...visibleDynamicFieldFormErrors.map(error => ({ + title: error.title, + description: error.body || null, + })), + ] + + const formWarnings = visibleFormWarnings.map(warning => ({ + title: warning.title, + description: warning.body || null, + dismissId: warning.type, + })) + + const dismissWarning = (dismissId: string): void => { + const isTimelineWarning = Object.values(timelineWarnings).some( + warning => warning.dismissId === dismissId + ) + if (isTimelineWarning && stepId) { + dispatch( + dismissActions.dismissTimelineWarning({ + type: dismissId, + }) + ) + } else { + dispatch( + dismissActions.dismissFormWarning({ + type: dismissId, + }) + ) + } + } + return ( + + {formErrors.map((error, key) => makeAlert('error', error, key))} + {formWarnings.map((warning, key) => makeAlert('warning', warning, key))} + {timelineWarnings.map((warning, key) => + makeAlert('warning', warning, key) + )} + + ) +} + +export const FormAlerts = React.memo(FormAlertsComponent) diff --git a/protocol-designer/src/organisms/Alerts/KnowledgeLink.tsx b/protocol-designer/src/organisms/Alerts/KnowledgeLink.tsx new file mode 100644 index 00000000000..f953cb9cf64 --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/KnowledgeLink.tsx @@ -0,0 +1,17 @@ +import * as React from 'react' +import { Link } from '@opentrons/components' +import { links } from './linkConstants' + +interface KnowledgeLinkProps { + to: keyof typeof links + children: React.ReactNode +} + +export function KnowledgeLink(props: KnowledgeLinkProps): JSX.Element { + const { to, children } = props + return ( + + {children} + + ) +} diff --git a/protocol-designer/src/organisms/Alerts/TerminalItemLink.tsx b/protocol-designer/src/organisms/Alerts/TerminalItemLink.tsx new file mode 100644 index 00000000000..c26580cd1bd --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/TerminalItemLink.tsx @@ -0,0 +1,22 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { useDispatch } from 'react-redux' +import { Link } from '@opentrons/components' +import { actions as stepsActions } from '../../ui/steps' +import type { TerminalItemId } from '../../steplist' + +interface TerminalItemLinkProps { + terminalId: TerminalItemId +} + +export const TerminalItemLink = (props: TerminalItemLinkProps): JSX.Element => { + const { terminalId } = props + const { t } = useTranslation('nav') + const dispatch = useDispatch() + + const handleClick = (): void => { + dispatch(stepsActions.selectTerminalItem(terminalId)) + } + + return {t(`terminal_item.${terminalId}`)} +} diff --git a/protocol-designer/src/organisms/Alerts/TimelineAlerts.tsx b/protocol-designer/src/organisms/Alerts/TimelineAlerts.tsx new file mode 100644 index 00000000000..1281efefeb1 --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/TimelineAlerts.tsx @@ -0,0 +1,54 @@ +import * as React from 'react' + +import { useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' +import { + ALIGN_CENTER, + Banner, + DIRECTION_COLUMN, + Flex, + SPACING, + StyledText, +} from '@opentrons/components' +import { getRobotStateTimeline } from '../../file-data/selectors' +import { ErrorContents } from './ErrorContents' +import type { CommandCreatorError } from '@opentrons/step-generation' +import type { MakeAlert } from './types' + +function TimelineAlertsComponent(): JSX.Element { + const { t } = useTranslation('alert') + + const timeline = useSelector(getRobotStateTimeline) + + const timelineErrors = (timeline.errors || ([] as CommandCreatorError[])).map( + (error: CommandCreatorError) => ({ + title: t(`timeline.error.${error.type}.title`, error.message), + description: , + }) + ) + + const makeAlert: MakeAlert = (alertType, data, key) => ( + + + {data.title} + + {data.description} + + + + ) + + return ( + <>{timelineErrors.map((error, key) => makeAlert('error', error, key))} + ) +} + +export const TimelineAlerts = React.memo(TimelineAlertsComponent) diff --git a/protocol-designer/src/organisms/Alerts/WarningContents.tsx b/protocol-designer/src/organisms/Alerts/WarningContents.tsx new file mode 100644 index 00000000000..adcee24b13c --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/WarningContents.tsx @@ -0,0 +1,41 @@ +import * as React from 'react' +import { useTranslation } from 'react-i18next' +import { START_TERMINAL_ITEM_ID } from '../../steplist' +import { TerminalItemLink } from './TerminalItemLink' + +import type { AlertLevel } from './types' + +interface WarningContentsProps { + warningType: string + level: AlertLevel +} +export function WarningContents( + props: WarningContentsProps +): JSX.Element | null { + const { warningType, level } = props + const { t } = useTranslation('alert') + + if (level === 'timeline') { + switch (warningType) { + case 'ASPIRATE_FROM_PRISTINE_WELL': + return ( + <> + {t(`timeline.warning.${warningType}.body`, { + defaultValue: '', + })} + + + ) + default: + return t(`timeline.warning.${warningType}.body`, { + defaultValue: '', + }) + } + } else if (props.level === 'form') { + return t(`form.warning.${warningType}.body`, { + defaultValue: '', + }) + } else { + return null + } +} diff --git a/protocol-designer/src/organisms/Alerts/__tests__/FormAlerts.test.tsx b/protocol-designer/src/organisms/Alerts/__tests__/FormAlerts.test.tsx new file mode 100644 index 00000000000..61779994ec1 --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/__tests__/FormAlerts.test.tsx @@ -0,0 +1,77 @@ +import * as React from 'react' +import { describe, it, vi, beforeEach, expect } from 'vitest' +import '@testing-library/jest-dom/vitest' +import { fireEvent, screen } from '@testing-library/react' +import { FormAlerts } from '../FormAlerts' +import { i18n } from '../../../assets/localization' +import { renderWithProviders } from '../../../__testing-utils__' +import { + getDynamicFieldFormErrorsForUnsavedForm, + getFormLevelErrorsForUnsavedForm, + getHydratedUnsavedForm, +} from '../../../step-forms/selectors' +import { getFormWarningsForSelectedStep } from '../../../dismiss/selectors' +import { getTimelineWarningsForSelectedStep } from '../../../top-selectors/timelineWarnings' +import { getSelectedStepId } from '../../../ui/steps' +import { + dismissFormWarning, + dismissTimelineWarning, +} from '../../../dismiss/actions' + +vi.mock('../../../dismiss/actions') +vi.mock('../../../ui/steps') +vi.mock('../../../top-selectors/timelineWarnings') +vi.mock('../../../dismiss/selectors') +vi.mock('../../../step-forms/selectors') + +const render = (props: React.ComponentProps) => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('FormAlerts', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + focusedField: null, + dirtyFields: [], + } + vi.mocked(getFormLevelErrorsForUnsavedForm).mockReturnValue([]) + vi.mocked(getFormWarningsForSelectedStep).mockReturnValue([]) + vi.mocked(getTimelineWarningsForSelectedStep).mockReturnValue([]) + vi.mocked(getHydratedUnsavedForm).mockReturnValue(null) + vi.mocked(getDynamicFieldFormErrorsForUnsavedForm).mockReturnValue([]) + vi.mocked(getSelectedStepId).mockReturnValue('123') + }) + + it('renders a timeline warning that is dismissible', () => { + vi.mocked(getTimelineWarningsForSelectedStep).mockReturnValue([ + { + message: 'mock message', + type: 'LABWARE_IN_WASTE_CHUTE_HAS_LIQUID', + }, + ]) + render(props) + screen.getByText('Moving labware into waste chute') + screen.getByText( + 'This labware has remaining liquid, be advised that once you dispose of it, there is no way to get it back later in the protocol.' + ) + fireEvent.click(screen.getByTestId('Banner_close-button')) + expect(vi.mocked(dismissTimelineWarning)).toHaveBeenCalled() + }) + it('renders a form level warning that is dismissible', () => { + vi.mocked(getFormWarningsForSelectedStep).mockReturnValue([ + { + type: 'TIP_POSITIONED_LOW_IN_TUBE', + title: 'mockTitle', + dependentFields: [], + }, + ]) + render(props) + screen.getByText('mockTitle') + fireEvent.click(screen.getByTestId('Banner_close-button')) + expect(vi.mocked(dismissFormWarning)).toHaveBeenCalled() + }) +}) diff --git a/protocol-designer/src/organisms/Alerts/__tests__/TimelineAlerts.test.tsx b/protocol-designer/src/organisms/Alerts/__tests__/TimelineAlerts.test.tsx new file mode 100644 index 00000000000..9eea32b8434 --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/__tests__/TimelineAlerts.test.tsx @@ -0,0 +1,44 @@ +import * as React from 'react' +import { describe, it, vi, beforeEach, expect } from 'vitest' +import '@testing-library/jest-dom/vitest' +import { fireEvent, screen } from '@testing-library/react' +import { i18n } from '../../../assets/localization' +import { renderWithProviders } from '../../../__testing-utils__' +import { getRobotStateTimeline } from '../../../file-data/selectors' +import { selectTerminalItem } from '../../../ui/steps/actions/actions' +import { TimelineAlerts } from '../TimelineAlerts' + +vi.mock('../../../file-data/selectors') +vi.mock('../../../ui/steps/actions/actions') + +const render = () => { + return renderWithProviders(, { + i18nInstance: i18n, + })[0] +} + +describe('TimelineAlerts', () => { + beforeEach(() => { + vi.mocked(getRobotStateTimeline).mockReturnValue({ + timeline: {} as any, + errors: [{ message: 'mockMessage', type: 'INSUFFICIENT_TIPS' }], + }) + }) + + it('renders the insufficient tips timeline error and clicking on the button turns it into the starting deck state terminal id ', () => { + render() + screen.getByText('Not enough tips to complete action') + screen.getByText('Add another tip rack to an empty slot in') + fireEvent.click(screen.getByText('Starting Deck State')) + expect(vi.mocked(selectTerminalItem)).toHaveBeenCalled() + }) + it('renders the no tip on pipette timeline error and the knowledge link', () => { + vi.mocked(getRobotStateTimeline).mockReturnValue({ + timeline: {} as any, + errors: [{ message: 'mockMessage', type: 'NO_TIP_ON_PIPETTE' }], + }) + render() + screen.getByText('No tip on pipette at the start of step') + screen.getByText('Air gap dispense setting') + }) +}) diff --git a/protocol-designer/src/organisms/Alerts/index.ts b/protocol-designer/src/organisms/Alerts/index.ts new file mode 100644 index 00000000000..7dd2f93a279 --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/index.ts @@ -0,0 +1,2 @@ +export * from './FormAlerts' +export * from './TimelineAlerts' diff --git a/protocol-designer/src/organisms/Alerts/linkConstants.ts b/protocol-designer/src/organisms/Alerts/linkConstants.ts new file mode 100644 index 00000000000..13b251961bd --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/linkConstants.ts @@ -0,0 +1,16 @@ +export const KNOWLEDGEBASE_ROOT_URL = + 'https://support.opentrons.com/s/protocol-designer' + +export const links = { + airGap: `https://support.opentrons.com/en/articles/4398106-air-gap`, + multiDispense: `https://support.opentrons.com/en/articles/4170341-paths`, + protocolSteps: `https://support.opentrons.com/s/protocol-designer?tabset-92ba3=2`, + customLabware: `https://support.opentrons.com/en/articles/3136504-creating-custom-labware-definitions`, + recommendedLabware: + 'https://support.opentrons.com/s/article/What-labware-can-I-use-with-my-modules', + pipetteGen1MultiModuleCollision: + 'https://support.opentrons.com/en/articles/4168741-module-placement', + betaReleases: `https://support.opentrons.com/en/articles/3854833-opentrons-beta-software-releases`, + magneticModuleGenerations: + 'http://support.opentrons.com/en/articles/1820112-magnetic-module', +} as const diff --git a/protocol-designer/src/organisms/Alerts/types.ts b/protocol-designer/src/organisms/Alerts/types.ts new file mode 100644 index 00000000000..0453688d667 --- /dev/null +++ b/protocol-designer/src/organisms/Alerts/types.ts @@ -0,0 +1,14 @@ +export type AlertLevel = 'timeline' | 'form' +type AlertType = 'error' | 'warning' + +interface AlertData { + title: string + description: React.ReactNode + dismissId?: string +} + +export type MakeAlert = ( + alertType: AlertType, + data: AlertData, + key: number | string +) => JSX.Element diff --git a/protocol-designer/src/organisms/index.ts b/protocol-designer/src/organisms/index.ts index f2ba204e3bb..ad42e5e7a53 100644 --- a/protocol-designer/src/organisms/index.ts +++ b/protocol-designer/src/organisms/index.ts @@ -1,4 +1,5 @@ export * from './AnnouncementModal' +export * from './Alerts' export * from './AssignLiquidsModal' export * from './DefineLiquidsModal' export * from './EditInstrumentsModal' diff --git a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx index a552bd43a11..6d3460f161f 100644 --- a/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx +++ b/protocol-designer/src/pages/Designer/DeckSetup/DeckSetupContainer.tsx @@ -29,10 +29,9 @@ import { getDeckSetupForActiveItem } from '../../../top-selectors/labware-locati import { getDisableModuleRestrictions } from '../../../feature-flags/selectors' import { getRobotType } from '../../../file-data/selectors' import { getHasGen1MultiChannelPipette } from '../../../step-forms' -import { SlotDetailsContainer } from '../../../organisms' +import { SlotDetailsContainer, TimelineAlerts } from '../../../organisms' import { selectZoomedIntoSlot } from '../../../labware-ingred/actions' import { selectors } from '../../../labware-ingred/selectors' -import { Alerts } from '../../../components/alerts/Alerts' import { DeckSetupDetails } from './DeckSetupDetails' import { animateZoom, @@ -174,6 +173,11 @@ export function DeckSetupContainer(props: DeckSetupTabType): JSX.Element { return ( <> + {tab === 'protocolSteps' ? ( + + + + ) : null} - {tab === 'protocolSteps' ? ( - - {/* TODO: update the alerts to match latest designs */} - - - ) : null} - {/* TODO: update alerts */} - {/* */} - } > + diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx index 303cc347592..0eb319325cc 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' -import { COLORS, useConditionalConfirm } from '@opentrons/components' +import { useConditionalConfirm } from '@opentrons/components' import * as timelineWarningSelectors from '../../../../top-selectors/timelineWarnings' import { selectors as dismissSelectors } from '../../../../dismiss' import { selectors as stepFormSelectors } from '../../../../step-forms' @@ -19,6 +19,7 @@ import { ConfirmDeleteModal, } from '../../../../components/modals/ConfirmDeleteModal' import { stepIconsByType } from '../../../../form-types' +import { getOrderedStepIds } from '../../../../step-forms/selectors' import { StepContainer } from './StepContainer' import type { ThunkDispatch } from 'redux-thunk' @@ -36,6 +37,7 @@ export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { const { stepId, stepNumber } = props const { t } = useTranslation('application') const dispatch = useDispatch>() + const stepIds = useSelector(getOrderedStepIds) const step = useSelector(stepFormSelectors.getSavedStepForms)[stepId] const argsAndErrors = useSelector(stepFormSelectors.getArgsAndErrorsByStepId)[ stepId @@ -48,6 +50,10 @@ export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { const hasFormLevelWarningsPerStep = useSelector( dismissSelectors.getHasFormLevelWarningsPerStep ) + const stepListAfterErrors = + errorStepId != null ? stepIds.slice(stepIds.indexOf(errorStepId) + 1) : [] + const stepAfterError = + stepId != null ? stepListAfterErrors.includes(stepId) : false const hasWarnings = hasTimelineWarningsPerStep[stepId] || hasFormLevelWarningsPerStep[stepId] @@ -101,11 +107,12 @@ export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { /> )} void selected?: boolean hovered?: boolean + hasError?: boolean + isStepAfterError?: boolean } export function StepContainer(props: StepContainerProps): JSX.Element { @@ -49,6 +53,8 @@ export function StepContainer(props: StepContainerProps): JSX.Element { hovered, iconColor, title, + hasError = false, + isStepAfterError = false, } = props const formData = useSelector(getUnsavedForm) const [top, setTop] = React.useState(0) @@ -67,6 +73,10 @@ export function StepContainer(props: StepContainerProps): JSX.Element { backgroundColor = COLORS.blue30 color = COLORS.black90 } + if (hasError) { + backgroundColor = COLORS.red50 + color = COLORS.white + } const handleOverflowClick = (event: React.MouseEvent): void => { const { clientY } = event @@ -103,7 +113,13 @@ export function StepContainer(props: StepContainerProps): JSX.Element { return ( <> - + )} - {hovered && !isStartingOrEndingState && formData == null ? ( + {selected && !isStartingOrEndingState && formData == null ? ( { e.preventDefault() e.stopPropagation() diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepContainer.test.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepContainer.test.tsx index 095a7a98684..62ed8662131 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepContainer.test.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/__tests__/StepContainer.test.tsx @@ -28,6 +28,8 @@ describe('StepContainer', () => { selected: false, hovered: false, stepId: 'mockStepId', + hasError: false, + isStepAfterError: false, } vi.mocked(StepOverflowMenu).mockReturnValue(
mock StepOverflowMenu
diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx index ba5b73aba25..e933c468d14 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/index.tsx @@ -21,7 +21,6 @@ export function ProtocolSteps(): JSX.Element { const formData = useSelector(getUnsavedForm) const leftString = t('onDeck') const rightString = t('offDeck') - const [deckView, setDeckView] = React.useState< typeof leftString | typeof rightString >(leftString) From 82e50ed202e10a2381965258a8f8ab5f81695a63 Mon Sep 17 00:00:00 2001 From: Brayan Almonte Date: Mon, 23 Sep 2024 14:53:17 -0400 Subject: [PATCH 10/12] feat(api, robot-server, shared-data): Add single and multi wavelength read capabilities to the Plate Reader. (#16273) The Byonoy Absorbance 96 Plate Reader can initialize in either `single` or `multi` measure modes, depending on the mode the device can read a single or multiple wavelengths at once. In `single` mode the device can optionally take a `reference wavelength` as a parameter, so the returned data is processed automatically on the device. This functionality was always available in the Byonoy library, we now expose that API through the Opentrons hardware controller and Protocol Engine to be used in a protocol. --- .../drivers/absorbance_reader/abstract.py | 14 +++- .../drivers/absorbance_reader/async_byonoy.py | 74 ++++++++++++------ .../drivers/absorbance_reader/driver.py | 19 +++-- .../drivers/absorbance_reader/hid_protocol.py | 34 ++++++++- .../drivers/absorbance_reader/simulator.py | 12 ++- api/src/opentrons/drivers/types.py | 24 +++++- .../modules/absorbance_reader.py | 70 +++++++++++++---- .../hardware_control/modules/types.py | 3 +- .../protocol_api/core/engine/module_core.py | 23 ++++-- api/src/opentrons/protocol_api/core/module.py | 10 ++- .../opentrons/protocol_api/module_contexts.py | 31 ++++++-- .../commands/absorbance_reader/initialize.py | 53 ++++++++++++- .../commands/absorbance_reader/read.py | 34 +++++---- .../absorbance_reader_substate.py | 9 ++- .../protocol_engine/state/modules.py | 45 +++++++---- api/src/opentrons/protocol_engine/types.py | 3 + .../drivers/absorbance_reader/test_driver.py | 76 ++++++++++++++++--- .../engine/test_absorbance_reader_core.py | 43 +++++++++-- .../modules/module_data_mapper.py | 10 ++- .../robot_server/modules/module_models.py | 14 +++- shared-data/command/schemas/9.json | 36 ++++++--- 21 files changed, 499 insertions(+), 138 deletions(-) diff --git a/api/src/opentrons/drivers/absorbance_reader/abstract.py b/api/src/opentrons/drivers/absorbance_reader/abstract.py index 6dc403fdff9..600497cbd6d 100644 --- a/api/src/opentrons/drivers/absorbance_reader/abstract.py +++ b/api/src/opentrons/drivers/absorbance_reader/abstract.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod -from typing import Dict, List, Tuple +from typing import Dict, List, Optional, Tuple from opentrons.drivers.types import ( + ABSMeasurementMode, AbsorbanceReaderLidStatus, AbsorbanceReaderDeviceState, AbsorbanceReaderPlatePresence, @@ -32,11 +33,18 @@ async def get_available_wavelengths(self) -> List[int]: ... @abstractmethod - async def get_single_measurement(self, wavelength: int) -> List[float]: + async def initialize_measurement( + self, + wavelengths: List[int], + mode: ABSMeasurementMode = ABSMeasurementMode.SINGLE, + reference_wavelength: Optional[int] = None, + ) -> None: + """Initialize measurement for the device in single or multi mode for the given wavelengths""" ... @abstractmethod - async def initialize_measurement(self, wavelength: int) -> None: + async def get_measurement(self) -> List[List[float]]: + """Gets one or more measurements based on the current configuration.""" ... @abstractmethod diff --git a/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py b/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py index 6f3ab10afcd..d08e6166ec9 100644 --- a/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py +++ b/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py @@ -3,18 +3,20 @@ import re from concurrent.futures.thread import ThreadPoolExecutor from functools import partial -from typing import Optional, List, Dict, Tuple +from typing import Any, Optional, List, Dict, Tuple from .hid_protocol import ( AbsorbanceHidInterface as AbsProtocol, ErrorCodeNames, DeviceStateNames, SlotStateNames, + MeasurementConfig, ) from opentrons.drivers.types import ( AbsorbanceReaderLidStatus, AbsorbanceReaderPlatePresence, AbsorbanceReaderDeviceState, + ABSMeasurementMode, ) from opentrons.drivers.rpi_drivers.types import USBPort from opentrons.hardware_control.modules.errors import AbsorbanceReaderDisconnectedError @@ -22,7 +24,7 @@ SN_PARSER = re.compile(r'ATTRS{serial}=="(?P.+?)"') VERSION_PARSER = re.compile(r"Absorbance (?PV\d+\.\d+\.\d+)") -SERIAL_PARSER = re.compile(r"SN: (?PBYO[A-Z]{3}[0-9]{5})") +SERIAL_PARSER = re.compile(r"(?PBYO[A-Z]{3}[0-9]{5})") class AsyncByonoy: @@ -110,7 +112,7 @@ def __init__( self._loop = loop self._supported_wavelengths: Optional[list[int]] = None self._device_handle: Optional[int] = None - self._current_config: Optional[AbsProtocol.MeasurementConfig] = None + self._current_config: Optional[MeasurementConfig] = None async def open(self) -> bool: """ @@ -225,23 +227,25 @@ async def get_supported_wavelengths(self) -> list[int]: self._supported_wavelengths = wavelengths return wavelengths - async def get_single_measurement(self, wavelength: int) -> List[float]: - """Get a single measurement based on the current configuration.""" + async def get_measurement(self) -> List[List[float]]: + """Gets one or more measurements based on the current configuration.""" handle = self._verify_device_handle() assert ( - self._current_config - and self._current_config.sample_wavelength == wavelength - ) + self._current_config is not None + ), "Cannot get measurement without initializing." + measure_func: Any = self._interface.byonoy_abs96_single_measure + if isinstance(self._current_config, AbsProtocol.MultiMeasurementConfig): + measure_func = self._interface.byonoy_abs96_multiple_measure err, measurements = await self._loop.run_in_executor( executor=self._executor, func=partial( - self._interface.byonoy_abs96_single_measure, + measure_func, handle, self._current_config, ), ) - self._raise_if_error(err.name, f"Error getting single measurement: {err}") - return measurements + self._raise_if_error(err.name, f"Error getting measurement: {err}") + return measurements if isinstance(measurements[0], List) else [measurements] # type: ignore async def get_plate_presence(self) -> AbsorbanceReaderPlatePresence: """Get the state of the plate for the reader.""" @@ -263,33 +267,53 @@ def _get_supported_wavelengths(self) -> List[int]: self._supported_wavelengths = wavelengths return wavelengths - def _initialize_measurement(self, conf: AbsProtocol.MeasurementConfig) -> None: + def _initialize_measurement(self, conf: MeasurementConfig) -> None: handle = self._verify_device_handle() - err = self._interface.byonoy_abs96_initialize_single_measurement(handle, conf) + if isinstance(conf, AbsProtocol.SingleMeasurementConfig): + err = self._interface.byonoy_abs96_initialize_single_measurement( + handle, conf + ) + else: + err = self._interface.byonoy_abs96_initialize_multiple_measurement( + handle, conf + ) self._raise_if_error(err.name, f"Error initializing measurement: {err}") self._current_config = conf - def _set_sample_wavelength(self, wavelength: int) -> AbsProtocol.MeasurementConfig: + def _initialize( + self, + mode: ABSMeasurementMode, + wavelengths: List[int], + reference_wavelength: Optional[int] = None, + ) -> None: if not self._supported_wavelengths: self._get_supported_wavelengths() assert self._supported_wavelengths - if wavelength in self._supported_wavelengths: - conf = self._interface.ByonoyAbs96SingleMeasurementConfig() - conf.sample_wavelength = wavelength - return conf + conf: MeasurementConfig + if set(wavelengths).issubset(self._supported_wavelengths): + if mode == ABSMeasurementMode.SINGLE: + conf = self._interface.ByonoyAbs96SingleMeasurementConfig() + conf.sample_wavelength = wavelengths[0] or 0 + conf.reference_wavelength = reference_wavelength or 0 + else: + conf = self._interface.ByonoyAbs96MultipleMeasurementConfig() + conf.sample_wavelengths = wavelengths else: raise ValueError( - f"Unsupported wavelength: {wavelength}, expected: {self._supported_wavelengths}" + f"Unsupported wavelength: {wavelengths}, expected: {self._supported_wavelengths}" ) - - def _initialize(self, wavelength: int) -> None: - conf = self._set_sample_wavelength(wavelength) self._initialize_measurement(conf) - async def initialize(self, wavelength: int) -> None: - """Initialize the device so we can start reading samples from it.""" + async def initialize( + self, + mode: ABSMeasurementMode, + wavelengths: List[int], + reference_wavelength: Optional[int] = None, + ) -> None: + """initialize the device so we can start reading samples from it.""" await self._loop.run_in_executor( - executor=self._executor, func=partial(self._initialize, wavelength) + executor=self._executor, + func=partial(self._initialize, mode, wavelengths, reference_wavelength), ) def _verify_device_handle(self) -> int: diff --git a/api/src/opentrons/drivers/absorbance_reader/driver.py b/api/src/opentrons/drivers/absorbance_reader/driver.py index be6fdaa5c15..5899fef89d0 100644 --- a/api/src/opentrons/drivers/absorbance_reader/driver.py +++ b/api/src/opentrons/drivers/absorbance_reader/driver.py @@ -4,11 +4,14 @@ from typing import Dict, Optional, List, Tuple, TYPE_CHECKING from opentrons.drivers.types import ( + ABSMeasurementMode, AbsorbanceReaderLidStatus, AbsorbanceReaderDeviceState, AbsorbanceReaderPlatePresence, ) -from opentrons.drivers.absorbance_reader.abstract import AbstractAbsorbanceReaderDriver +from opentrons.drivers.absorbance_reader.abstract import ( + AbstractAbsorbanceReaderDriver, +) from opentrons.drivers.rpi_drivers.types import USBPort if TYPE_CHECKING: @@ -60,12 +63,16 @@ async def get_lid_status(self) -> AbsorbanceReaderLidStatus: async def get_available_wavelengths(self) -> List[int]: return await self._connection.get_supported_wavelengths() - async def get_single_measurement(self, wavelength: int) -> List[float]: - # TODO (cb, 08-02-2024): The list of measurements for 96 wells is rotated 180 degrees (well A1 is where well H12 should be) this must be corrected - return await self._connection.get_single_measurement(wavelength) + async def initialize_measurement( + self, + wavelengths: List[int], + mode: ABSMeasurementMode = ABSMeasurementMode.SINGLE, + reference_wavelength: Optional[int] = None, + ) -> None: + await self._connection.initialize(mode, wavelengths, reference_wavelength) - async def initialize_measurement(self, wavelength: int) -> None: - await self._connection.initialize(wavelength) + async def get_measurement(self) -> List[List[float]]: + return await self._connection.get_measurement() async def get_status(self) -> AbsorbanceReaderDeviceState: return await self._connection.get_device_status() diff --git a/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py b/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py index 8816b2e2903..d05059889ae 100644 --- a/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py +++ b/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py @@ -1,9 +1,11 @@ from typing import ( Dict, + Optional, Protocol, List, Literal, Tuple, + Union, runtime_checkable, TypeVar, ) @@ -69,8 +71,13 @@ class SlotState(Protocol): value: int @runtime_checkable - class MeasurementConfig(Protocol): + class SingleMeasurementConfig(Protocol): sample_wavelength: int + reference_wavelength: Optional[int] + + @runtime_checkable + class MultiMeasurementConfig(Protocol): + sample_wavelengths: List[int] @runtime_checkable class DeviceInfo(Protocol): @@ -84,7 +91,10 @@ class DeviceState(Protocol): name: DeviceStateNames value: int - def ByonoyAbs96SingleMeasurementConfig(self) -> MeasurementConfig: + def ByonoyAbs96SingleMeasurementConfig(self) -> SingleMeasurementConfig: + ... + + def ByonoyAbs96MultipleMeasurementConfig(self) -> MultiMeasurementConfig: ... def byonoy_open_device(self, device: Device) -> Tuple[ErrorCode, int]: @@ -130,14 +140,30 @@ def byonoy_abs96_get_available_wavelengths( ... def byonoy_abs96_initialize_single_measurement( - self, device_handle: int, conf: MeasurementConfig + self, device_handle: int, conf: SingleMeasurementConfig + ) -> ErrorCode: + ... + + def byonoy_abs96_initialize_multiple_measurement( + self, device_handle: int, conf: MultiMeasurementConfig ) -> ErrorCode: ... def byonoy_abs96_single_measure( - self, device_handle: int, conf: MeasurementConfig + self, device_handle: int, conf: SingleMeasurementConfig ) -> Tuple[ErrorCode, List[float]]: ... + def byonoy_abs96_multiple_measure( + self, device_handle: int, conf: MultiMeasurementConfig + ) -> Tuple[ErrorCode, List[List[float]]]: + ... + def byonoy_available_devices(self) -> List[Device]: ... + + +MeasurementConfig = Union[ + AbsorbanceHidInterface.SingleMeasurementConfig, + AbsorbanceHidInterface.MultiMeasurementConfig, +] diff --git a/api/src/opentrons/drivers/absorbance_reader/simulator.py b/api/src/opentrons/drivers/absorbance_reader/simulator.py index 6a2a0aa6228..c4d7af2c1eb 100644 --- a/api/src/opentrons/drivers/absorbance_reader/simulator.py +++ b/api/src/opentrons/drivers/absorbance_reader/simulator.py @@ -2,6 +2,7 @@ from opentrons.util.async_helpers import ensure_yield from opentrons.drivers.types import ( + ABSMeasurementMode, AbsorbanceReaderLidStatus, AbsorbanceReaderDeviceState, AbsorbanceReaderPlatePresence, @@ -54,11 +55,16 @@ async def get_available_wavelengths(self) -> List[int]: return [450, 570, 600, 650] @ensure_yield - async def get_single_measurement(self, wavelength: int) -> List[float]: - return [0.0] + async def get_measurement(self) -> List[List[float]]: + return [[0.0]] @ensure_yield - async def initialize_measurement(self, wavelength: int) -> None: + async def initialize_measurement( + self, + wavelengths: List[int], + mode: ABSMeasurementMode = ABSMeasurementMode.SINGLE, + reference_wavelength: Optional[int] = None, + ) -> None: pass @ensure_yield diff --git a/api/src/opentrons/drivers/types.py b/api/src/opentrons/drivers/types.py index a4047ca64da..f01001bdef8 100644 --- a/api/src/opentrons/drivers/types.py +++ b/api/src/opentrons/drivers/types.py @@ -1,6 +1,6 @@ """ Type definitions for modules in this tree """ from dataclasses import dataclass -from typing import Dict, NamedTuple, Optional +from typing import Any, Dict, List, NamedTuple, Optional from enum import Enum @@ -83,3 +83,25 @@ class AbsorbanceReaderDeviceState(str, Enum): OK = "ok" BROKEN_FW = "broken_fw" ERROR = "error" + + +class ABSMeasurementMode(Enum): + """The current mode configured for reading the Absorbance Reader.""" + + SINGLE = "single" + MULTI = "multi" + + +@dataclass +class ABSMeasurementConfig: + measure_mode: ABSMeasurementMode + sample_wavelengths: List[int] + reference_wavelength: Optional[int] + + @property + def data(self) -> Dict[str, Any]: + return { + "measureMode": self.measure_mode.value, + "sampleWavelengths": self.sample_wavelengths, + "referenceWavelength": self.reference_wavelength, + } diff --git a/api/src/opentrons/hardware_control/modules/absorbance_reader.py b/api/src/opentrons/hardware_control/modules/absorbance_reader.py index e68b535c4bc..da7c4746086 100644 --- a/api/src/opentrons/hardware_control/modules/absorbance_reader.py +++ b/api/src/opentrons/hardware_control/modules/absorbance_reader.py @@ -12,6 +12,8 @@ AbsorbanceReaderLidStatus, AbsorbanceReaderPlatePresence, AbsorbanceReaderDeviceState, + ABSMeasurementMode, + ABSMeasurementConfig, ) from opentrons.hardware_control.execution_manager import ExecutionManager @@ -194,13 +196,21 @@ def __init__( self._device_info = device_info self._reader = reader self._poller = poller + self._measurement_config: Optional[ABSMeasurementConfig] = None + self._device_status = AbsorbanceReaderStatus.IDLE self._error: Optional[str] = None self._reader.register_error_handler(self._enter_error_state) @property def status(self) -> AbsorbanceReaderStatus: - """Return some string describing status.""" - return AbsorbanceReaderStatus.IDLE + """Return some string describing the device status.""" + state = self._reader.device_state + if state not in [ + AbsorbanceReaderDeviceState.UNKNOWN, + AbsorbanceReaderDeviceState.OK, + ]: + return AbsorbanceReaderStatus.ERROR + return self._device_status @property def lid_status(self) -> AbsorbanceReaderLidStatus: @@ -210,6 +220,20 @@ def lid_status(self) -> AbsorbanceReaderLidStatus: def plate_presence(self) -> AbsorbanceReaderPlatePresence: return self._reader.plate_presence + @property + def uptime(self) -> int: + """Time in ms this device has been running for.""" + return self._reader.uptime + + @property + def supported_wavelengths(self) -> List[int]: + """The wavelengths in nm this plate reader supports.""" + return self._reader.supported_wavelengths + + @property + def measurement_config(self) -> Optional[ABSMeasurementConfig]: + return self._measurement_config + @property def device_info(self) -> Mapping[str, str]: """Return a dict of the module's static information (serial, etc)""" @@ -218,12 +242,17 @@ def device_info(self) -> Mapping[str, str]: @property def live_data(self) -> LiveData: """Return a dict of the module's dynamic information""" + conf = self._measurement_config.data if self._measurement_config else dict() return { "status": self.status.value, "data": { + "uptime": self.uptime, + "deviceStatus": self.status.value, "lidStatus": self.lid_status.value, "platePresence": self.plate_presence.value, - "sampleWavelength": 400, + "measureMode": conf.get("measureMode", ""), + "sampleWavelengths": conf.get("sampleWavelengths", []), + "referenceWavelength": conf.get("referenceWavelength", 0), }, } @@ -309,17 +338,32 @@ async def cleanup(self) -> None: """ await self.deactivate() - async def set_sample_wavelength(self, wavelength: int) -> None: - """Set the Absorbance Reader's active wavelength.""" - await self._driver.initialize_measurement(wavelength) - - async def start_measure(self, wavelength: int) -> List[float]: - """Initiate a single measurement.""" - return await self._driver.get_single_measurement(wavelength) + async def set_sample_wavelength( + self, + mode: ABSMeasurementMode, + wavelengths: List[int], + reference_wavelength: Optional[int] = None, + ) -> None: + """Set the Absorbance Reader's measurement mode and active wavelength.""" + if mode == ABSMeasurementMode.SINGLE: + assert ( + len(wavelengths) == 1 + ), "Cannot initialize single read mode with more than 1 wavelength." + + await self._driver.initialize_measurement(wavelengths, mode) + self._measurement_config = ABSMeasurementConfig( + measure_mode=mode, + sample_wavelengths=wavelengths, + reference_wavelength=reference_wavelength, + ) - async def get_current_wavelength(self) -> None: - """Get the Absorbance Reader's current active wavelength.""" - pass # TODO: implement + async def start_measure(self) -> List[List[float]]: + """Initiate a measurement depending on the measurement mode.""" + try: + self._device_status = AbsorbanceReaderStatus.MEASURING + return await self._driver.get_measurement() + finally: + self._device_status = AbsorbanceReaderStatus.IDLE async def get_current_lid_status(self) -> AbsorbanceReaderLidStatus: """Get the Absorbance Reader's current lid status.""" diff --git a/api/src/opentrons/hardware_control/modules/types.py b/api/src/opentrons/hardware_control/modules/types.py index c7b3c920c79..6c9f6a3e915 100644 --- a/api/src/opentrons/hardware_control/modules/types.py +++ b/api/src/opentrons/hardware_control/modules/types.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from typing import ( Dict, + List, NamedTuple, Callable, Any, @@ -46,7 +47,7 @@ class ThermocyclerStep(ThermocyclerStepBase, total=False): class LiveData(TypedDict): status: str - data: Dict[str, Union[float, str, bool, None]] + data: Dict[str, Union[float, str, bool, List[int], None]] class ModuleType(str, Enum): diff --git a/api/src/opentrons/protocol_api/core/engine/module_core.py b/api/src/opentrons/protocol_api/core/engine/module_core.py index 643111122ce..729037425a8 100644 --- a/api/src/opentrons/protocol_api/core/engine/module_core.py +++ b/api/src/opentrons/protocol_api/core/engine/module_core.py @@ -18,6 +18,7 @@ ) from opentrons.protocol_engine import commands as cmd +from opentrons.protocol_engine.types import ABSMeasureMode from opentrons.types import DeckSlotName from opentrons.protocol_engine.clients import SyncClient as ProtocolEngineClient from opentrons.protocol_engine.errors.exceptions import ( @@ -525,25 +526,31 @@ class AbsorbanceReaderCore(ModuleCore, AbstractAbsorbanceReaderCore): """Absorbance Reader core logic implementation for Python protocols.""" _sync_module_hardware: SynchronousAdapter[hw_modules.AbsorbanceReader] - _initialized_value: Optional[int] = None + _initialized_value: Optional[List[int]] = None - def initialize(self, wavelength: int) -> None: + def initialize( + self, + mode: ABSMeasureMode, + wavelengths: List[int], + reference_wavelength: Optional[int] = None, + ) -> None: """Initialize the Absorbance Reader by taking zero reading.""" + # TODO: check that the wavelengths are within the supported wavelengths self._engine_client.execute_command( cmd.absorbance_reader.InitializeParams( moduleId=self.module_id, - sampleWavelength=wavelength, + measureMode=mode, + sampleWavelengths=wavelengths, + referenceWavelength=reference_wavelength, ), ) - self._initialized_value = wavelength + self._initialized_value = wavelengths - def read(self) -> Optional[Dict[str, float]]: + def read(self) -> Optional[Dict[int, Dict[str, float]]]: """Initiate a read on the Absorbance Reader, and return the results. During Analysis, this will return None.""" if self._initialized_value: self._engine_client.execute_command( - cmd.absorbance_reader.ReadAbsorbanceParams( - moduleId=self.module_id, sampleWavelength=self._initialized_value - ) + cmd.absorbance_reader.ReadAbsorbanceParams(moduleId=self.module_id) ) if not self._engine_client.state.config.use_virtual_modules: read_result = ( diff --git a/api/src/opentrons/protocol_api/core/module.py b/api/src/opentrons/protocol_api/core/module.py index e6968de91d6..90abea1d0ec 100644 --- a/api/src/opentrons/protocol_api/core/module.py +++ b/api/src/opentrons/protocol_api/core/module.py @@ -16,6 +16,7 @@ MagneticStatus, SpeedStatus, ) +from opentrons.protocol_engine.types import ABSMeasureMode from opentrons.types import DeckSlotName @@ -355,11 +356,16 @@ def get_serial_number(self) -> str: """Get the module's unique hardware serial number.""" @abstractmethod - def initialize(self, wavelength: int) -> None: + def initialize( + self, + mode: ABSMeasureMode, + wavelengths: List[int], + reference_wavelength: Optional[int] = None, + ) -> None: """Initialize the Absorbance Reader by taking zero reading.""" @abstractmethod - def read(self) -> Optional[Dict[str, float]]: + def read(self) -> Optional[Dict[int, Dict[str, float]]]: """Get an absorbance reading from the Absorbance Reader.""" @abstractmethod diff --git a/api/src/opentrons/protocol_api/module_contexts.py b/api/src/opentrons/protocol_api/module_contexts.py index b2abeca24e4..f9fcc18ca00 100644 --- a/api/src/opentrons/protocol_api/module_contexts.py +++ b/api/src/opentrons/protocol_api/module_contexts.py @@ -3,6 +3,7 @@ import logging from typing import List, Dict, Optional, Union, cast +from opentrons.protocol_engine.types import ABSMeasureMode from opentrons_shared_data.labware.types import LabwareDefinition from opentrons_shared_data.module.types import ModuleModel, ModuleType @@ -1003,11 +1004,31 @@ def is_lid_on(self) -> bool: return self._core.is_lid_on() @requires_version(2, 21) - def initialize(self, wavelength: int) -> None: - """Initialize the Absorbance Reader by taking zero reading.""" - self._core.initialize(wavelength) + def initialize( + self, + mode: ABSMeasureMode, + wavelengths: List[int], + reference_wavelength: Optional[int] = None, + ) -> None: + """Take a zero reading on the Absorbance Plate Reader Module. + + :param mode: Either ``"single"`` or ``"multi"``. + + - In single measurement mode, :py:meth:`.AbsorbanceReaderContext.read` uses + one sample wavelength and an optional reference wavelength. + - In multiple measurement mode, :py:meth:`.AbsorbanceReaderContext.read` uses + a list of up to six sample wavelengths. + :param wavelengths: A list of wavelengths, in mm, to measure. + - Must contain only one item when initializing a single measurement. + - Must contain one to six items when initializing a multiple measurement. + :param reference_wavelength: An optional reference wavelength, in mm. Cannot be + used with multiple measurements. + """ + self._core.initialize( + mode, wavelengths, reference_wavelength=reference_wavelength + ) @requires_version(2, 21) - def read(self) -> Optional[Dict[str, float]]: - """Initiate read on the Absorbance Reader. Returns a dictionary of values ordered by well name.""" + def read(self) -> Optional[Dict[int, Dict[str, float]]]: + """Initiate read on the Absorbance Reader. Returns a dictionary of wavelengths to dictionary of values ordered by well name.""" return self._core.read() diff --git a/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py b/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py index 53150280a80..97df3057990 100644 --- a/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py +++ b/api/src/opentrons/protocol_engine/commands/absorbance_reader/initialize.py @@ -1,10 +1,13 @@ """Command models to initialize an Absorbance Reader.""" from __future__ import annotations -from typing import Optional, Literal, TYPE_CHECKING +from typing import List, Optional, Literal, TYPE_CHECKING from typing_extensions import Type from pydantic import BaseModel, Field +from opentrons.drivers.types import ABSMeasurementMode +from opentrons.protocol_engine.types import ABSMeasureMode + from ..command import AbstractCommandImpl, BaseCommand, BaseCommandCreate, SuccessData from ...errors.error_occurrence import ErrorOccurrence @@ -20,7 +23,13 @@ class InitializeParams(BaseModel): """Input parameters to initialize an absorbance reading.""" moduleId: str = Field(..., description="Unique ID of the absorbance reader.") - sampleWavelength: int = Field(..., description="Sample wavelength in nm.") + measureMode: ABSMeasureMode = Field( + ..., description="Initialize single or multi measurement mode." + ) + sampleWavelengths: List[int] = Field(..., description="Sample wavelengths in nm.") + referenceWavelength: Optional[int] = Field( + ..., description="Optional reference wavelength in nm." + ) class InitializeResult(BaseModel): @@ -54,7 +63,45 @@ async def execute( ) if abs_reader is not None: - await abs_reader.set_sample_wavelength(wavelength=params.sampleWavelength) + # Validate the parameters before initializing. + sample_wavelengths = set(params.sampleWavelengths) + sample_wavelengths_len = len(params.sampleWavelengths) + reference_wavelength = params.referenceWavelength + supported_wavelengths = set(abs_reader.supported_wavelengths) + unsupported_wavelengths = sample_wavelengths.difference( + supported_wavelengths + ) + if unsupported_wavelengths: + raise ValueError(f"Unsupported wavelengths: {unsupported_wavelengths}") + + if params.measureMode == "single": + if sample_wavelengths_len != 1: + raise ValueError( + f"single requires one sample wavelength, provided {sample_wavelengths}" + ) + if ( + reference_wavelength is not None + and reference_wavelength not in supported_wavelengths + ): + raise ValueError( + f"Reference wavelength {reference_wavelength} not supported {supported_wavelengths}" + ) + + if params.measureMode == "multi": + if sample_wavelengths_len < 1 or sample_wavelengths_len > 6: + raise ValueError( + f"multi requires 1-6 sample wavelengths, provided {sample_wavelengths}" + ) + if reference_wavelength is not None: + raise RuntimeError( + "Reference wavelength cannot be used with multi mode." + ) + + await abs_reader.set_sample_wavelength( + ABSMeasurementMode(params.measureMode), + params.sampleWavelengths, + reference_wavelength=params.referenceWavelength, + ) return SuccessData( public=InitializeResult(), diff --git a/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py b/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py index f361f819c5e..b101cdb70b8 100644 --- a/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py +++ b/api/src/opentrons/protocol_engine/commands/absorbance_reader/read.py @@ -18,16 +18,17 @@ class ReadAbsorbanceParams(BaseModel): - """Input parameters for a single absorbance reading.""" + """Input parameters for an absorbance reading.""" moduleId: str = Field(..., description="Unique ID of the Absorbance Reader.") - sampleWavelength: int = Field(..., description="Sample wavelength in nm.") class ReadAbsorbanceResult(BaseModel): - """Result data from running an aborbance reading, returned as a dictionary map of values by well name (eg. ("A1": 0.0, ...)).""" + """Result data from running an aborbance reading, returned as a dictionary map of wavelengths containing a map of values by well name (eg. {450: {"A1": 0.0, ...}}).""" - data: Optional[Dict[str, float]] = Field(..., description="Absorbance data points.") + data: Optional[Dict[int, Dict[str, float]]] = Field( + ..., description="Absorbance data points per wavelength." + ) class ReadAbsorbanceImpl( @@ -47,7 +48,7 @@ def __init__( async def execute( self, params: ReadAbsorbanceParams ) -> SuccessData[ReadAbsorbanceResult, None]: - """Initiate a single absorbance measurement.""" + """Initiate an absorbance measurement.""" abs_reader_substate = self._state_view.modules.get_absorbance_reader_substate( module_id=params.moduleId ) @@ -62,16 +63,21 @@ async def execute( ) if abs_reader is not None: - result = await abs_reader.start_measure(wavelength=params.sampleWavelength) - converted_values = ( - self._state_view.modules.convert_absorbance_reader_data_points( - data=result + results = await abs_reader.start_measure() + if abs_reader._measurement_config is not None: + asbsorbance_result: Dict[int, Dict[str, float]] = {} + sample_wavelengths = abs_reader._measurement_config.sample_wavelengths + for wavelength, result in zip(sample_wavelengths, results): + converted_values = ( + self._state_view.modules.convert_absorbance_reader_data_points( + data=result + ) + ) + asbsorbance_result[wavelength] = converted_values + return SuccessData( + public=ReadAbsorbanceResult(data=asbsorbance_result), + private=None, ) - ) - return SuccessData( - public=ReadAbsorbanceResult(data=converted_values), - private=None, - ) return SuccessData( public=ReadAbsorbanceResult(data=None), diff --git a/api/src/opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py b/api/src/opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py index 1b92948fc90..33b96aa0881 100644 --- a/api/src/opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py +++ b/api/src/opentrons/protocol_engine/state/module_substates/absorbance_reader_substate.py @@ -1,11 +1,12 @@ """Heater-Shaker Module sub-state.""" from dataclasses import dataclass -from typing import NewType, Optional, Dict +from typing import List, NewType, Optional, Dict from opentrons.protocol_engine.errors import CannotPerformModuleAction AbsorbanceReaderId = NewType("AbsorbanceReaderId", str) AbsorbanceReaderLidId = NewType("AbsorbanceReaderLidId", str) +AbsorbanceReaderMeasureMode = NewType("AbsorbanceReaderMeasureMode", str) @dataclass(frozen=True) @@ -16,8 +17,10 @@ class AbsorbanceReaderSubState: configured: bool measured: bool is_lid_on: bool - data: Optional[Dict[str, float]] - configured_wavelength: Optional[int] + data: Optional[Dict[int, Dict[str, float]]] + configured_wavelengths: Optional[List[int]] + measure_mode: Optional[AbsorbanceReaderMeasureMode] + reference_wavelength: Optional[int] lid_id: Optional[str] def raise_if_lid_status_not_expected(self, lid_on_expected: bool) -> None: diff --git a/api/src/opentrons/protocol_engine/state/modules.py b/api/src/opentrons/protocol_engine/state/modules.py index 3327020f93e..cf609560e9b 100644 --- a/api/src/opentrons/protocol_engine/state/modules.py +++ b/api/src/opentrons/protocol_engine/state/modules.py @@ -29,6 +29,9 @@ from opentrons.protocol_engine.commands.calibration.calibrate_module import ( CalibrateModuleResult, ) +from opentrons.protocol_engine.state.module_substates.absorbance_reader_substate import ( + AbsorbanceReaderMeasureMode, +) from opentrons.types import DeckSlotName, MountType from ..errors import ModuleNotConnectedError @@ -319,7 +322,9 @@ def _update_absorbance_reader_lid_id( measured=prev_state.measured, is_lid_on=prev_state.is_lid_on, data=prev_state.data, - configured_wavelength=prev_state.configured_wavelength, + measure_mode=prev_state.measure_mode, + configured_wavelengths=prev_state.configured_wavelengths, + reference_wavelength=prev_state.reference_wavelength, lid_id=lid_id, ) @@ -398,7 +403,9 @@ def _add_module_substate( # noqa: C901 measured=False, is_lid_on=True, data=None, - configured_wavelength=None, + measure_mode=None, + configured_wavelengths=None, + reference_wavelength=None, lid_id=lid_labware_id, ) else: @@ -610,7 +617,9 @@ def _handle_absorbance_reader_commands( # Get current values configured = absorbance_reader_substate.configured - configured_wavelength = absorbance_reader_substate.configured_wavelength + measure_mode = absorbance_reader_substate.measure_mode + configured_wavelengths = absorbance_reader_substate.configured_wavelengths + reference_wavelength = absorbance_reader_substate.reference_wavelength is_lid_on = absorbance_reader_substate.is_lid_on lid_id = absorbance_reader_substate.lid_id data = absorbance_reader_substate.data @@ -621,41 +630,49 @@ def _handle_absorbance_reader_commands( configured=True, measured=False, is_lid_on=is_lid_on, - data=None, - configured_wavelength=command.params.sampleWavelength, lid_id=lid_id, + measure_mode=AbsorbanceReaderMeasureMode(command.params.measureMode), + configured_wavelengths=command.params.sampleWavelengths, + reference_wavelength=command.params.referenceWavelength, + data=None, ) elif isinstance(command.result, absorbance_reader.ReadAbsorbanceResult): self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState( module_id=AbsorbanceReaderId(module_id), configured=configured, - configured_wavelength=configured_wavelength, - is_lid_on=is_lid_on, measured=True, - data=command.result.data, + is_lid_on=is_lid_on, lid_id=lid_id, + measure_mode=measure_mode, + configured_wavelengths=configured_wavelengths, + reference_wavelength=reference_wavelength, + data=command.result.data, ) elif isinstance(command.result, absorbance_reader.OpenLidResult): self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState( module_id=AbsorbanceReaderId(module_id), configured=configured, - configured_wavelength=configured_wavelength, - is_lid_on=False, measured=True, - data=data, + is_lid_on=False, lid_id=lid_id, + measure_mode=measure_mode, + configured_wavelengths=configured_wavelengths, + reference_wavelength=reference_wavelength, + data=data, ) elif isinstance(command.result, absorbance_reader.CloseLidResult): self._state.substate_by_module_id[module_id] = AbsorbanceReaderSubState( module_id=AbsorbanceReaderId(module_id), configured=configured, - configured_wavelength=configured_wavelength, - is_lid_on=True, measured=True, - data=data, + is_lid_on=True, lid_id=lid_id, + measure_mode=measure_mode, + configured_wavelengths=configured_wavelengths, + reference_wavelength=reference_wavelength, + data=data, ) diff --git a/api/src/opentrons/protocol_engine/types.py b/api/src/opentrons/protocol_engine/types.py index 519d39b6ec7..e011b43fd7f 100644 --- a/api/src/opentrons/protocol_engine/types.py +++ b/api/src/opentrons/protocol_engine/types.py @@ -1089,3 +1089,6 @@ class CSVParameter(RTPBase): CSVRunTimeParamFilesType = Mapping[StrictStr, StrictStr] CSVRuntimeParamPaths = Dict[str, Path] + + +ABSMeasureMode = Literal["single", "multi"] diff --git a/api/tests/opentrons/drivers/absorbance_reader/test_driver.py b/api/tests/opentrons/drivers/absorbance_reader/test_driver.py index ff633e38760..a9c34fd500c 100644 --- a/api/tests/opentrons/drivers/absorbance_reader/test_driver.py +++ b/api/tests/opentrons/drivers/absorbance_reader/test_driver.py @@ -1,3 +1,4 @@ +from typing import cast from mock import MagicMock import pytest import asyncio @@ -9,7 +10,7 @@ AbsorbanceHidInterface, ) from opentrons.drivers.absorbance_reader.async_byonoy import AsyncByonoy -from opentrons.drivers.types import AbsorbanceReaderLidStatus +from opentrons.drivers.types import ABSMeasurementMode, AbsorbanceReaderLidStatus @pytest.fixture @@ -78,8 +79,8 @@ async def test_driver_get_device_info( ) -> None: DEVICE_INFO = MagicMock(AbsorbanceHidInterface.DeviceInfo) - DEVICE_INFO.ref_no = "" - DEVICE_INFO.sn = "SN: BYOMAA00013 REF: DE MAA 001" + DEVICE_INFO.ref_no = "DE MAA 001" + DEVICE_INFO.sn = "BYOMAA00013" DEVICE_INFO.version = "Absorbance V1.0.2 2024-04-18" mock_interface.byonoy_get_device_information.return_value = ( @@ -134,7 +135,7 @@ async def test_driver_get_supported_wavelengths( assert wavelengths == SUPPORTED_WAVELENGTHS -async def test_driver_initialize_and_read( +async def test_driver_initialize_and_read_single( mock_interface: MagicMock, connected_driver: AbsorbanceReaderDriver, ) -> None: @@ -143,28 +144,79 @@ async def test_driver_initialize_and_read( mock_interface.byonoy_abs96_initialize_single_measurement.return_value = ( MockErrorCode.BYONOY_ERROR_NO_ERROR ) - mock_interface.ByonoyAbs96SingleMeasurementConfig = MagicMock( - spec=AbsorbanceHidInterface.MeasurementConfig - ) + + class MeasurementConfig(AbsorbanceHidInterface.SingleMeasurementConfig): + def __init__(self) -> None: + self.sample_wavelength = 0 + self.reference_wavelength = 0 + + mock_interface.ByonoyAbs96SingleMeasurementConfig = MeasurementConfig # current config should not have been setup yet assert not connected_driver._connection._current_config - await connected_driver.initialize_measurement(450) + await connected_driver.initialize_measurement([450], mode=ABSMeasurementMode.SINGLE) - conf = connected_driver._connection._current_config + conf = cast( + AbsorbanceHidInterface.SingleMeasurementConfig, + connected_driver._connection._current_config, + ) assert conf and conf.sample_wavelength == 450 mock_interface.byonoy_abs96_initialize_single_measurement.assert_called_once_with( 1, conf ) - # setup up mock interface - MEASURE_RESULT = [0.1] * 96 + # setup up mock interface with a single reading + MEASURE_RESULT = [[0.1] * 96] mock_interface.byonoy_abs96_single_measure.return_value = ( MockErrorCode.BYONOY_ERROR_NO_ERROR, MEASURE_RESULT, ) - result = await connected_driver.get_single_measurement(450) + result = await connected_driver.get_measurement() mock_interface.byonoy_abs96_single_measure.assert_called_once_with(1, conf) assert result == MEASURE_RESULT + + +async def test_driver_initialize_and_read_multi( + mock_interface: MagicMock, + connected_driver: AbsorbanceReaderDriver, +) -> None: + # set up mock interface + connected_driver._connection._supported_wavelengths = [450, 500, 600] + mock_interface.byonoy_abs96_initialize_multiple_measurement.return_value = ( + MockErrorCode.BYONOY_ERROR_NO_ERROR + ) + + class MeasurementConfig(AbsorbanceHidInterface.MultiMeasurementConfig): + def __init__(self) -> None: + self.sample_wavelengths = [0] + + mock_interface.ByonoyAbs96MultipleMeasurementConfig = MeasurementConfig + + # current config should not have been setup yet + assert not connected_driver._connection._current_config + await connected_driver.initialize_measurement( + [450, 500, 600], mode=ABSMeasurementMode.MULTI + ) + + conf = cast( + AbsorbanceHidInterface.MultiMeasurementConfig, + connected_driver._connection._current_config, + ) + assert conf and conf.sample_wavelengths == [450, 500, 600] + mock_interface.byonoy_abs96_initialize_multiple_measurement.assert_called_once_with( + 1, conf + ) + + # setup up mock interface with multiple readings + MEASURE_RESULT = [[0.1] * 96, [0.2] * 96, [0.3] * 96] + mock_interface.byonoy_abs96_multiple_measure.return_value = ( + MockErrorCode.BYONOY_ERROR_NO_ERROR, + MEASURE_RESULT, + ) + + result = await connected_driver.get_measurement() + mock_interface.byonoy_abs96_multiple_measure.assert_called_once_with(1, conf) + + assert result == MEASURE_RESULT diff --git a/api/tests/opentrons/protocol_api/core/engine/test_absorbance_reader_core.py b/api/tests/opentrons/protocol_api/core/engine/test_absorbance_reader_core.py index 613ee3cfbe3..405d737d55b 100644 --- a/api/tests/opentrons/protocol_api/core/engine/test_absorbance_reader_core.py +++ b/api/tests/opentrons/protocol_api/core/engine/test_absorbance_reader_core.py @@ -62,32 +62,65 @@ def test_initialize( decoy: Decoy, mock_engine_client: EngineClient, subject: AbsorbanceReaderCore ) -> None: """It should set the sample wavelength with the engine client.""" - subject.initialize(wavelength=123) + subject.initialize("single", [123]) decoy.verify( mock_engine_client.execute_command( cmd.absorbance_reader.InitializeParams( moduleId="1234", - sampleWavelength=123, + measureMode="single", + sampleWavelengths=[123], + referenceWavelength=None, ), ), times=1, ) - assert subject._initialized_value == 123 + assert subject._initialized_value == [123] + + # Test reference wavelength + subject.initialize("single", [124], 450) + + decoy.verify( + mock_engine_client.execute_command( + cmd.absorbance_reader.InitializeParams( + moduleId="1234", + measureMode="single", + sampleWavelengths=[124], + referenceWavelength=450, + ), + ), + times=1, + ) + assert subject._initialized_value == [124] + + # Test initialize multi + subject.initialize("multi", [124, 125, 126]) + + decoy.verify( + mock_engine_client.execute_command( + cmd.absorbance_reader.InitializeParams( + moduleId="1234", + measureMode="multi", + sampleWavelengths=[124, 125, 126], + referenceWavelength=None, + ), + ), + times=1, + ) + assert subject._initialized_value == [124, 125, 126] def test_read( decoy: Decoy, mock_engine_client: EngineClient, subject: AbsorbanceReaderCore ) -> None: """It should call absorbance reader to read with the engine client.""" - subject._initialized_value = 123 + subject._initialized_value = [123] subject.read() decoy.verify( mock_engine_client.execute_command( cmd.absorbance_reader.ReadAbsorbanceParams( moduleId="1234", - sampleWavelength=123, ), ), times=1, diff --git a/robot-server/robot_server/modules/module_data_mapper.py b/robot-server/robot_server/modules/module_data_mapper.py index 52f95489216..f0c623fdab3 100644 --- a/robot-server/robot_server/modules/module_data_mapper.py +++ b/robot-server/robot_server/modules/module_data_mapper.py @@ -1,5 +1,5 @@ """Module identification and response data mapping.""" -from typing import Annotated, Type, cast, Optional +from typing import Annotated, List, Type, cast, Optional from fastapi import Depends from opentrons_shared_data.module import load_definition @@ -147,7 +147,13 @@ def map_data( AbsorbanceReaderPlatePresence, live_data["data"].get("platePresence"), ), - sampleWavelength=cast(int, live_data["data"].get("sampleWavelength")), + measureMode=cast(str, live_data["data"].get("measureMode")), + sampleWavelengths=cast( + List[int], live_data["data"].get("sampleWavelengths") + ), + referenceWavelength=cast( + int, live_data["data"].get("referenceWavelength") + ), ) else: assert False, f"Invalid module type {module_type}" diff --git a/robot-server/robot_server/modules/module_models.py b/robot-server/robot_server/modules/module_models.py index 3f59911cd39..f9acaf59a8b 100644 --- a/robot-server/robot_server/modules/module_models.py +++ b/robot-server/robot_server/modules/module_models.py @@ -2,7 +2,7 @@ from datetime import datetime from pydantic import BaseModel, Field from pydantic.generics import GenericModel -from typing import Generic, Optional, TypeVar, Union +from typing import Generic, List, Optional, TypeVar, Union from typing_extensions import Literal from opentrons.calibration_storage.types import SourceType @@ -323,9 +323,17 @@ class AbsorbanceReaderModuleData(BaseModel): ..., description="Plate presence status.", ) - sampleWavelength: int = Field( + measureMode: str = Field( ..., - description="The current sample wavelength, in nanometers.", + description="The measirement mode (single or multi) the device is configured for.", + ) + sampleWavelengths: List[int] = Field( + ..., + description="The current list of sample wavelengths, in nanometers.", + ) + referenceWavelength: Optional[int] = Field( + ..., + description="The reference wavelength used for single measurement mode.", ) diff --git a/shared-data/command/schemas/9.json b/shared-data/command/schemas/9.json index 263330eb6de..97d25dd6432 100644 --- a/shared-data/command/schemas/9.json +++ b/shared-data/command/schemas/9.json @@ -4003,13 +4003,32 @@ "description": "Unique ID of the absorbance reader.", "type": "string" }, - "sampleWavelength": { - "title": "Samplewavelength", - "description": "Sample wavelength in nm.", + "measureMode": { + "title": "Measuremode", + "description": "Initialize single or multi measurement mode.", + "enum": ["single", "multi"], + "type": "string" + }, + "sampleWavelengths": { + "title": "Samplewavelengths", + "description": "Sample wavelengths in nm.", + "type": "array", + "items": { + "type": "integer" + } + }, + "referenceWavelength": { + "title": "Referencewavelength", + "description": "Optional reference wavelength in nm.", "type": "integer" } }, - "required": ["moduleId", "sampleWavelength"] + "required": [ + "moduleId", + "measureMode", + "sampleWavelengths", + "referenceWavelength" + ] }, "InitializeCreate": { "title": "InitializeCreate", @@ -4043,21 +4062,16 @@ }, "ReadAbsorbanceParams": { "title": "ReadAbsorbanceParams", - "description": "Input parameters for a single absorbance reading.", + "description": "Input parameters for an absorbance reading.", "type": "object", "properties": { "moduleId": { "title": "Moduleid", "description": "Unique ID of the Absorbance Reader.", "type": "string" - }, - "sampleWavelength": { - "title": "Samplewavelength", - "description": "Sample wavelength in nm.", - "type": "integer" } }, - "required": ["moduleId", "sampleWavelength"] + "required": ["moduleId"] }, "ReadAbsorbanceCreate": { "title": "ReadAbsorbanceCreate", From 5eefbdd77dc494f17b88dd2bf148e042b18abf60 Mon Sep 17 00:00:00 2001 From: Max Marrone Date: Mon, 23 Sep 2024 15:09:25 -0400 Subject: [PATCH 11/12] refactor(robot-server): Fix half-written comment (#16330) --- .../maintenance_runs/maintenance_run_orchestrator_store.py | 3 +++ robot-server/robot_server/runs/error_recovery_mapping.py | 6 +----- robot-server/robot_server/runs/run_orchestrator_store.py | 3 +++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/robot-server/robot_server/maintenance_runs/maintenance_run_orchestrator_store.py b/robot-server/robot_server/maintenance_runs/maintenance_run_orchestrator_store.py index 4aa0c38b323..9bb1012a789 100644 --- a/robot-server/robot_server/maintenance_runs/maintenance_run_orchestrator_store.py +++ b/robot-server/robot_server/maintenance_runs/maintenance_run_orchestrator_store.py @@ -175,6 +175,9 @@ async def create( RobotTypeEnum.robot_literal_to_enum(self._robot_type) ), ), + # Maintenance runs have no `/actions` endpoint that a client can POST to + # to resume normal operation after it enters recovery mode, so they should + # never be allowed to enter recovery mode. error_recovery_policy=error_recovery_policy.never_recover, deck_configuration=deck_configuration, notify_publishers=notify_publishers, diff --git a/robot-server/robot_server/runs/error_recovery_mapping.py b/robot-server/robot_server/runs/error_recovery_mapping.py index fcc5c2f2f54..fb936eddadd 100644 --- a/robot-server/robot_server/runs/error_recovery_mapping.py +++ b/robot-server/robot_server/runs/error_recovery_mapping.py @@ -50,11 +50,7 @@ def default_error_recovery_policy( failed_command: Command, defined_error_data: Optional[CommandDefinedErrorData], ) -> ErrorRecoveryType: - """The `ErrorRecoveryPolicy` to use when none has been set on a run. - - This is only appropriate for normal protocol runs, not maintenance runs, - since it assumes - """ + """The `ErrorRecoveryPolicy` to use when none has been set on a run.""" # Although error recovery can theoretically work on OT-2s, we haven't tested it, # and it's generally scarier because the OT-2 has much less hardware feedback. robot_is_flex = config.robot_type == "OT-3 Standard" diff --git a/robot-server/robot_server/runs/run_orchestrator_store.py b/robot-server/robot_server/runs/run_orchestrator_store.py index 8b52430a12e..2e8d8146dd8 100644 --- a/robot-server/robot_server/runs/run_orchestrator_store.py +++ b/robot-server/robot_server/runs/run_orchestrator_store.py @@ -178,6 +178,9 @@ async def get_default_orchestrator(self) -> RunOrchestrator: deck_type=self._deck_type, block_on_door_open=False, ), + # Error recovery mode would not make sense outside the context of a run-- + # for example, there would be no equivalent to the `POST /runs/{id}/actions` + # endpoint to resume normal operation. error_recovery_policy=error_recovery_policy.never_recover, ) self._default_run_orchestrator = RunOrchestrator.build_orchestrator( From 058854cae3d88f4b326b2caa83002b5a2ac45e74 Mon Sep 17 00:00:00 2001 From: Brayan Almonte Date: Mon, 23 Sep 2024 15:25:18 -0400 Subject: [PATCH 12/12] feat(api): Update absorbance reader driver namespace for byonoy_devices library version 2024.9.0 (#16289) --- .../drivers/absorbance_reader/async_byonoy.py | 58 ++++++------- .../drivers/absorbance_reader/hid_protocol.py | 86 +++++++++---------- .../drivers/absorbance_reader/test_driver.py | 60 +++++++------ 3 files changed, 92 insertions(+), 112 deletions(-) diff --git a/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py b/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py index d08e6166ec9..dc88c1b2dec 100644 --- a/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py +++ b/api/src/opentrons/drivers/absorbance_reader/async_byonoy.py @@ -74,13 +74,13 @@ async def create( loop = loop or asyncio.get_running_loop() executor = ThreadPoolExecutor(max_workers=1) - import pybyonoy_device_library as byonoy # type: ignore[import-not-found] + import byonoy_devices as byonoy # type: ignore[import-not-found] interface: AbsProtocol = byonoy device_sn = cls.serial_number_from_port(usb_port.name) found: List[AbsProtocol.Device] = await loop.run_in_executor( - executor=executor, func=byonoy.byonoy_available_devices + executor=executor, func=byonoy.available_devices ) device = cls.match_device_with_sn(device_sn, found) @@ -123,7 +123,7 @@ async def open(self) -> bool: err, device_handle = await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_open_device, self._device), + func=partial(self._interface.open_device, self._device), ) self._raise_if_error(err.name, f"Error opening device: {err}") self._device_handle = device_handle @@ -134,7 +134,7 @@ async def close(self) -> None: handle = self._verify_device_handle() await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_free_device, handle), + func=partial(self._interface.free_device, handle), ) self._device_handle = None @@ -145,7 +145,7 @@ async def is_open(self) -> bool: handle = self._verify_device_handle() return await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_device_open, handle), + func=partial(self._interface.device_open, handle), ) async def get_device_information(self) -> Dict[str, str]: @@ -153,7 +153,7 @@ async def get_device_information(self) -> Dict[str, str]: handle = self._verify_device_handle() err, device_info = await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_get_device_information, handle), + func=partial(self._interface.get_device_information, handle), ) self._raise_if_error(err.name, f"Error getting device information: {err}") serial_match = SERIAL_PARSER.match(device_info.sn) @@ -172,7 +172,7 @@ async def get_device_status(self) -> AbsorbanceReaderDeviceState: handle = self._verify_device_handle() err, status = await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_get_device_status, handle), + func=partial(self._interface.get_device_status, handle), ) self._raise_if_error(err.name, f"Error getting device status: {err}") return self.convert_device_state(status.name) @@ -184,11 +184,9 @@ async def update_firmware(self, firmware_file_path: str) -> Tuple[bool, str]: return False, f"Firmware file not found: {firmware_file_path}" err = await self._loop.run_in_executor( executor=self._executor, - func=partial( - self._interface.byonoy_update_device, handle, firmware_file_path - ), + func=partial(self._interface.update_device, handle, firmware_file_path), ) - if err.name != "BYONOY_ERROR_NO_ERROR": + if err.name != "NO_ERROR": return False, f"Byonoy update failed with error: {err}" return True, "" @@ -197,7 +195,7 @@ async def get_device_uptime(self) -> int: handle = self._verify_device_handle() err, uptime = await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_get_device_uptime, handle), + func=partial(self._interface.get_device_uptime, handle), ) self._raise_if_error(err.name, "Error getting device uptime: ") return uptime @@ -207,7 +205,7 @@ async def get_lid_status(self) -> AbsorbanceReaderLidStatus: handle = self._verify_device_handle() err, lid_info = await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_get_device_parts_aligned, handle), + func=partial(self._interface.get_device_parts_aligned, handle), ) self._raise_if_error(err.name, f"Error getting lid status: {err}") return ( @@ -219,9 +217,7 @@ async def get_supported_wavelengths(self) -> list[int]: handle = self._verify_device_handle() err, wavelengths = await self._loop.run_in_executor( executor=self._executor, - func=partial( - self._interface.byonoy_abs96_get_available_wavelengths, handle - ), + func=partial(self._interface.abs96_get_available_wavelengths, handle), ) self._raise_if_error(err.name, "Error getting available wavelengths: ") self._supported_wavelengths = wavelengths @@ -233,9 +229,9 @@ async def get_measurement(self) -> List[List[float]]: assert ( self._current_config is not None ), "Cannot get measurement without initializing." - measure_func: Any = self._interface.byonoy_abs96_single_measure + measure_func: Any = self._interface.abs96_single_measure if isinstance(self._current_config, AbsProtocol.MultiMeasurementConfig): - measure_func = self._interface.byonoy_abs96_multiple_measure + measure_func = self._interface.abs96_multiple_measure err, measurements = await self._loop.run_in_executor( executor=self._executor, func=partial( @@ -252,7 +248,7 @@ async def get_plate_presence(self) -> AbsorbanceReaderPlatePresence: handle = self._verify_device_handle() err, presence = await self._loop.run_in_executor( executor=self._executor, - func=partial(self._interface.byonoy_get_device_slot_status, handle), + func=partial(self._interface.get_device_slot_status, handle), ) self._raise_if_error(err.name, f"Error getting slot status: {err}") return self.convert_plate_presence(presence.name) @@ -260,9 +256,7 @@ async def get_plate_presence(self) -> AbsorbanceReaderPlatePresence: def _get_supported_wavelengths(self) -> List[int]: handle = self._verify_device_handle() wavelengths: List[int] - err, wavelengths = self._interface.byonoy_abs96_get_available_wavelengths( - handle - ) + err, wavelengths = self._interface.abs96_get_available_wavelengths(handle) self._raise_if_error(err.name, f"Error getting available wavelengths: {err}") self._supported_wavelengths = wavelengths return wavelengths @@ -270,13 +264,9 @@ def _get_supported_wavelengths(self) -> List[int]: def _initialize_measurement(self, conf: MeasurementConfig) -> None: handle = self._verify_device_handle() if isinstance(conf, AbsProtocol.SingleMeasurementConfig): - err = self._interface.byonoy_abs96_initialize_single_measurement( - handle, conf - ) + err = self._interface.abs96_initialize_single_measurement(handle, conf) else: - err = self._interface.byonoy_abs96_initialize_multiple_measurement( - handle, conf - ) + err = self._interface.abs96_initialize_multiple_measurement(handle, conf) self._raise_if_error(err.name, f"Error initializing measurement: {err}") self._current_config = conf @@ -292,11 +282,11 @@ def _initialize( conf: MeasurementConfig if set(wavelengths).issubset(self._supported_wavelengths): if mode == ABSMeasurementMode.SINGLE: - conf = self._interface.ByonoyAbs96SingleMeasurementConfig() + conf = self._interface.Abs96SingleMeasurementConfig() conf.sample_wavelength = wavelengths[0] or 0 conf.reference_wavelength = reference_wavelength or 0 else: - conf = self._interface.ByonoyAbs96MultipleMeasurementConfig() + conf = self._interface.Abs96MultipleMeasurementConfig() conf.sample_wavelengths = wavelengths else: raise ValueError( @@ -328,12 +318,12 @@ def _raise_if_error( msg: str = "Error occurred: ", ) -> None: if err_name in [ - "BYONOY_ERROR_DEVICE_CLOSED", - "BYONOY_ERROR_DEVICE_COMMUNICATION_FAILURE", - "BYONOY_ERROR_UNSUPPORTED_OPERATION", + "DEVICE_CLOSED", + "DEVICE_COMMUNICATION_FAILURE", + "UNSUPPORTED_OPERATION", ]: raise AbsorbanceReaderDisconnectedError(self._device.sn) - if err_name != "BYONOY_ERROR_NO_ERROR": + if err_name != "NO_ERROR": raise RuntimeError(msg, err_name) @staticmethod diff --git a/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py b/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py index d05059889ae..c418a652130 100644 --- a/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py +++ b/api/src/opentrons/drivers/absorbance_reader/hid_protocol.py @@ -13,28 +13,28 @@ Response = TypeVar("Response") ErrorCodeNames = Literal[ - "BYONOY_ERROR_NO_ERROR", - "BYONOY_ERROR_UNKNOWN_ERROR", - "BYONOY_ERROR_DEVICE_CLOSED", - "BYONOY_ERROR_INVALID_ARGUMENT", - "BYONOY_ERROR_NO_MEMORY", - "BYONOY_ERROR_UNSUPPORTED_OPERATION", - "BYONOY_ERROR_DEVICE_COMMUNICATION_FAILURE", - "BYONOY_ERROR_DEVICE_OPERATION_FAILED", - "BYONOY_ERROR_DEVICE_OPEN_PREFIX", - "BYONOY_ERROR_DEVICE_NOT_FOUND", - "BYONOY_ERROR_DEVICE_TOO_NEW", - "BYONOY_ERROR_DEVICE_ALREADY_OPEN", - "BYONOY_ERROR_FIRMWARE_UPDATE_ERROR_PREFIX", - "BYONOY_ERROR_FIRMWARE_UPDATE_FILE_NOT_FOUND", - "BYONOY_ERROR_FIRMWARE_UPDATE_FILE_NOT_VALID", - "BYONOY_ERROR_FIRMWARE_UPDATE_FAILED", - "BYONOY_ERROR_FILE_ERROR_PREFIX", - "BYONOY_ERROR_FILE_WRITE_ERROR", - "BYONOY_ERROR_MEASUTEMNT_ERROR_PREFIX", - "BYONOY_ERROR_MEASUTEMNT_SLOT_NOT_EMPTY", - "BYONOY_ERROR_NOT_INITIALIZED", - "BYONOY_ERROR_INTERNAL", + "NO_ERROR", + "UNKNOWN_ERROR", + "DEVICE_CLOSED", + "INVALID_ARGUMENT", + "NO_MEMORY", + "UNSUPPORTED_OPERATION", + "DEVICE_COMMUNICATION_FAILURE", + "DEVICE_OPERATION_FAILED", + "DEVICE_OPEN_PREFIX", + "DEVICE_NOT_FOUND", + "DEVICE_TOO_NEW", + "DEVICE_ALREADY_OPEN", + "FIRMWARE_UPDATE_ERROR_PREFIX", + "FIRMWARE_UPDATE_FILE_NOT_FOUND", + "FIRMWARE_UPDATE_FILE_NOT_VALID", + "FIRMWARE_UPDATE_FAILED", + "FILE_ERROR_PREFIX", + "FILE_WRITE_ERROR", + "MEASUTEMNT_ERROR_PREFIX", + "MEASUTEMNT_SLOT_NOT_EMPTY", + "NOT_INITIALIZED", + "INTERNAL", ] SlotStateNames = Literal[ @@ -91,75 +91,67 @@ class DeviceState(Protocol): name: DeviceStateNames value: int - def ByonoyAbs96SingleMeasurementConfig(self) -> SingleMeasurementConfig: + def Abs96SingleMeasurementConfig(self) -> SingleMeasurementConfig: ... - def ByonoyAbs96MultipleMeasurementConfig(self) -> MultiMeasurementConfig: + def Abs96MultipleMeasurementConfig(self) -> MultiMeasurementConfig: ... - def byonoy_open_device(self, device: Device) -> Tuple[ErrorCode, int]: + def open_device(self, device: Device) -> Tuple[ErrorCode, int]: ... - def byonoy_free_device(self, device_handle: int) -> Tuple[ErrorCode, bool]: + def free_device(self, device_handle: int) -> Tuple[ErrorCode, bool]: ... - def byonoy_device_open(self, device_handle: int) -> bool: + def device_open(self, device_handle: int) -> bool: ... - def byonoy_get_device_information( + def get_device_information( self, device_handle: int ) -> Tuple[ErrorCode, DeviceInfo]: ... - def byonoy_update_device( - self, device_handle: int, firmware_file_path: str - ) -> ErrorCode: + def update_device(self, device_handle: int, firmware_file_path: str) -> ErrorCode: ... - def byonoy_get_device_status( - self, device_handle: int - ) -> Tuple[ErrorCode, DeviceState]: + def get_device_status(self, device_handle: int) -> Tuple[ErrorCode, DeviceState]: ... - def byonoy_get_device_uptime(self, device_handle: int) -> Tuple[ErrorCode, int]: + def get_device_uptime(self, device_handle: int) -> Tuple[ErrorCode, int]: ... - def byonoy_get_device_slot_status( - self, device_handle: int - ) -> Tuple[ErrorCode, SlotState]: + def get_device_slot_status(self, device_handle: int) -> Tuple[ErrorCode, SlotState]: ... - def byonoy_get_device_parts_aligned( - self, device_handle: int - ) -> Tuple[ErrorCode, bool]: + def get_device_parts_aligned(self, device_handle: int) -> Tuple[ErrorCode, bool]: ... - def byonoy_abs96_get_available_wavelengths( + def abs96_get_available_wavelengths( self, device_handle: int ) -> Tuple[ErrorCode, List[int]]: ... - def byonoy_abs96_initialize_single_measurement( + def abs96_initialize_single_measurement( self, device_handle: int, conf: SingleMeasurementConfig ) -> ErrorCode: ... - def byonoy_abs96_initialize_multiple_measurement( + def abs96_initialize_multiple_measurement( self, device_handle: int, conf: MultiMeasurementConfig ) -> ErrorCode: ... - def byonoy_abs96_single_measure( + def abs96_single_measure( self, device_handle: int, conf: SingleMeasurementConfig ) -> Tuple[ErrorCode, List[float]]: ... - def byonoy_abs96_multiple_measure( + def abs96_multiple_measure( self, device_handle: int, conf: MultiMeasurementConfig ) -> Tuple[ErrorCode, List[List[float]]]: ... - def byonoy_available_devices(self) -> List[Device]: + def available_devices(self) -> List[Device]: ... diff --git a/api/tests/opentrons/drivers/absorbance_reader/test_driver.py b/api/tests/opentrons/drivers/absorbance_reader/test_driver.py index a9c34fd500c..0284f277e2c 100644 --- a/api/tests/opentrons/drivers/absorbance_reader/test_driver.py +++ b/api/tests/opentrons/drivers/absorbance_reader/test_driver.py @@ -24,8 +24,8 @@ def mock_device() -> MagicMock: class MockErrorCode(Enum): - BYONOY_ERROR_NO_ERROR = "no_error" - BYONOY_ERROR = "error" + NO_ERROR = "no_error" + ERROR = "error" @pytest.fixture @@ -53,20 +53,20 @@ async def test_driver_connect_disconnect( mock_interface: MagicMock, driver: AbsorbanceReaderDriver, ) -> None: - mock_interface.byonoy_open_device.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR, + mock_interface.open_device.return_value = ( + MockErrorCode.NO_ERROR, 1, ) assert not await driver.is_connected() await driver.connect() - mock_interface.byonoy_open_device.assert_called_once() + mock_interface.open_device.assert_called_once() assert await driver.is_connected() assert driver._connection._verify_device_handle() assert driver._connection._device_handle == 1 - mock_interface.byonoy_free_device.return_value = MockErrorCode.BYONOY_ERROR_NO_ERROR + mock_interface.free_device.return_value = MockErrorCode.NO_ERROR await driver.disconnect() assert not await driver.is_connected() @@ -83,14 +83,14 @@ async def test_driver_get_device_info( DEVICE_INFO.sn = "BYOMAA00013" DEVICE_INFO.version = "Absorbance V1.0.2 2024-04-18" - mock_interface.byonoy_get_device_information.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR, + mock_interface.get_device_information.return_value = ( + MockErrorCode.NO_ERROR, DEVICE_INFO, ) info = await connected_driver.get_device_info() - mock_interface.byonoy_get_device_information.assert_called_once() + mock_interface.get_device_information.assert_called_once() assert info == {"serial": "BYOMAA00013", "model": "ABS96", "version": "v1.0.2"} @@ -105,14 +105,14 @@ async def test_driver_get_lid_status( module_status: AbsorbanceReaderLidStatus, ) -> None: - mock_interface.byonoy_get_device_parts_aligned.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR, + mock_interface.get_device_parts_aligned.return_value = ( + MockErrorCode.NO_ERROR, parts_aligned, ) status = await connected_driver.get_lid_status() - mock_interface.byonoy_get_device_parts_aligned.assert_called_once() + mock_interface.get_device_parts_aligned.assert_called_once() assert status == module_status @@ -121,8 +121,8 @@ async def test_driver_get_supported_wavelengths( connected_driver: AbsorbanceReaderDriver, ) -> None: SUPPORTED_WAVELENGTHS = [450, 500] - mock_interface.byonoy_abs96_get_available_wavelengths.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR, + mock_interface.abs96_get_available_wavelengths.return_value = ( + MockErrorCode.NO_ERROR, SUPPORTED_WAVELENGTHS, ) @@ -130,7 +130,7 @@ async def test_driver_get_supported_wavelengths( wavelengths = await connected_driver.get_available_wavelengths() - mock_interface.byonoy_abs96_get_available_wavelengths.assert_called_once() + mock_interface.abs96_get_available_wavelengths.assert_called_once() assert connected_driver._connection._supported_wavelengths == SUPPORTED_WAVELENGTHS assert wavelengths == SUPPORTED_WAVELENGTHS @@ -141,8 +141,8 @@ async def test_driver_initialize_and_read_single( ) -> None: # set up mock interface connected_driver._connection._supported_wavelengths = [450, 500] - mock_interface.byonoy_abs96_initialize_single_measurement.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR + mock_interface.abs96_initialize_single_measurement.return_value = ( + MockErrorCode.NO_ERROR ) class MeasurementConfig(AbsorbanceHidInterface.SingleMeasurementConfig): @@ -150,7 +150,7 @@ def __init__(self) -> None: self.sample_wavelength = 0 self.reference_wavelength = 0 - mock_interface.ByonoyAbs96SingleMeasurementConfig = MeasurementConfig + mock_interface.Abs96SingleMeasurementConfig = MeasurementConfig # current config should not have been setup yet assert not connected_driver._connection._current_config @@ -161,19 +161,17 @@ def __init__(self) -> None: connected_driver._connection._current_config, ) assert conf and conf.sample_wavelength == 450 - mock_interface.byonoy_abs96_initialize_single_measurement.assert_called_once_with( - 1, conf - ) + mock_interface.abs96_initialize_single_measurement.assert_called_once_with(1, conf) # setup up mock interface with a single reading MEASURE_RESULT = [[0.1] * 96] - mock_interface.byonoy_abs96_single_measure.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR, + mock_interface.abs96_single_measure.return_value = ( + MockErrorCode.NO_ERROR, MEASURE_RESULT, ) result = await connected_driver.get_measurement() - mock_interface.byonoy_abs96_single_measure.assert_called_once_with(1, conf) + mock_interface.abs96_single_measure.assert_called_once_with(1, conf) assert result == MEASURE_RESULT @@ -184,15 +182,15 @@ async def test_driver_initialize_and_read_multi( ) -> None: # set up mock interface connected_driver._connection._supported_wavelengths = [450, 500, 600] - mock_interface.byonoy_abs96_initialize_multiple_measurement.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR + mock_interface.abs96_initialize_multiple_measurement.return_value = ( + MockErrorCode.NO_ERROR ) class MeasurementConfig(AbsorbanceHidInterface.MultiMeasurementConfig): def __init__(self) -> None: self.sample_wavelengths = [0] - mock_interface.ByonoyAbs96MultipleMeasurementConfig = MeasurementConfig + mock_interface.Abs96MultipleMeasurementConfig = MeasurementConfig # current config should not have been setup yet assert not connected_driver._connection._current_config @@ -205,18 +203,18 @@ def __init__(self) -> None: connected_driver._connection._current_config, ) assert conf and conf.sample_wavelengths == [450, 500, 600] - mock_interface.byonoy_abs96_initialize_multiple_measurement.assert_called_once_with( + mock_interface.abs96_initialize_multiple_measurement.assert_called_once_with( 1, conf ) # setup up mock interface with multiple readings MEASURE_RESULT = [[0.1] * 96, [0.2] * 96, [0.3] * 96] - mock_interface.byonoy_abs96_multiple_measure.return_value = ( - MockErrorCode.BYONOY_ERROR_NO_ERROR, + mock_interface.abs96_multiple_measure.return_value = ( + MockErrorCode.NO_ERROR, MEASURE_RESULT, ) result = await connected_driver.get_measurement() - mock_interface.byonoy_abs96_multiple_measure.assert_called_once_with(1, conf) + mock_interface.abs96_multiple_measure.assert_called_once_with(1, conf) assert result == MEASURE_RESULT