Skip to content

Commit

Permalink
Merge branch 'edge' into refactor_app-rtp-components
Browse files Browse the repository at this point in the history
  • Loading branch information
ncdiehl committed Mar 15, 2024
2 parents 815cef8 + eb19a5e commit 422c606
Show file tree
Hide file tree
Showing 100 changed files with 910 additions and 461 deletions.
20 changes: 0 additions & 20 deletions api-client/src/maintenance_runs/createMaintenanceRunAction.ts

This file was deleted.

1 change: 0 additions & 1 deletion api-client/src/maintenance_runs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ export { getMaintenanceRun } from './getMaintenanceRun'
export { deleteMaintenanceRun } from './deleteMaintenanceRun'
export { createMaintenanceRun } from './createMaintenanceRun'
export { createMaintenanceCommand } from './createMaintenanceCommand'
export { createMaintenanceRunAction } from './createMaintenanceRunAction'
export { createMaintenanceRunLabwareDefinition } from './createMaintenanceRunLabwareDefinition'
export { getCurrentMaintenanceRun } from './getCurrentMaintenanceRun'

Expand Down
22 changes: 2 additions & 20 deletions api-client/src/maintenance_runs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import type {
RunCommandSummary,
LabwareOffsetCreateData,
RunStatus,
RunAction,
} from '../runs'

export interface MaintenanceRunData {
id: string
createdAt: string
status: RunStatus
current: boolean
actions: MaintenanceRunAction[]
actions: RunAction[]
errors: MaintenanceRunError[]
pipettes: LoadedPipette[]
modules: LoadedModule[]
Expand All @@ -29,25 +30,6 @@ export interface MaintenanceRun {
data: MaintenanceRunData
}

export const MAINTENANCE_RUN_ACTION_TYPE_PLAY: 'play' = 'play'
export const MAINTENANCE_RUN_ACTION_TYPE_PAUSE: 'pause' = 'pause'
export const MAINTENANCE_RUN_ACTION_TYPE_STOP: 'stop' = 'stop'

export type MaintenanceRunActionType =
| typeof MAINTENANCE_RUN_ACTION_TYPE_PLAY
| typeof MAINTENANCE_RUN_ACTION_TYPE_PAUSE
| typeof MAINTENANCE_RUN_ACTION_TYPE_STOP

export interface MaintenanceRunAction {
id: string
createdAt: string
actionType: MaintenanceRunActionType
}

export interface MaintenanceCreateRunActionData {
actionType: MaintenanceRunActionType
}

export interface MaintenanceCommandData {
data: RunCommandSummary
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/opentrons/protocol_engine/protocol_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def estop(self, maintenance_run: bool) -> None:
if self._state_store.commands.get_is_stopped():
return
current_id = (
self._state_store.commands.state.running_command_id
self._state_store.commands.get_running_command_id()
or self._state_store.commands.state.queued_command_ids.head(None)
)

Expand Down
72 changes: 41 additions & 31 deletions api/src/opentrons/protocol_engine/state/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,45 +271,30 @@ def handle_action(self, action: Action) -> None: # noqa: C901
error=action.error,
)
prev_entry = self._state.commands_by_id[action.command_id]
self._state.commands_by_id[action.command_id] = CommandEntry(
index=prev_entry.index,
# TODO(mc, 2022-06-06): add new "cancelled" status or similar
# and don't set `completedAt` in commands other than the
# specific one that failed
command=prev_entry.command.copy(
update={
"error": error_occurrence,
"completedAt": action.failed_at,
"status": CommandStatus.FAILED,
}
),
# TODO(mc, 2022-06-06): add new "cancelled" status or similar
self._update_to_failed(
command_id=action.command_id,
failed_at=action.failed_at,
error_occurrence=error_occurrence,
)

self._state.failed_command = self._state.commands_by_id[action.command_id]

if prev_entry.command.intent == CommandIntent.SETUP:
other_command_ids_to_fail = [
*[i for i in self._state.queued_setup_command_ids],
]
other_command_ids_to_fail = self._state.queued_setup_command_ids
for id in other_command_ids_to_fail:
self._update_to_failed(
command_id=id, failed_at=action.failed_at, error_occurrence=None
)
self._state.queued_setup_command_ids.clear()
else:
other_command_ids_to_fail = [
*[i for i in self._state.queued_command_ids],
]
other_command_ids_to_fail = self._state.queued_command_ids
for id in other_command_ids_to_fail:
self._update_to_failed(
command_id=id, failed_at=action.failed_at, error_occurrence=None
)
self._state.queued_command_ids.clear()

for command_id in other_command_ids_to_fail:
prev_entry = self._state.commands_by_id[command_id]

self._state.commands_by_id[command_id] = CommandEntry(
index=prev_entry.index,
command=prev_entry.command.copy(
update={
"completedAt": action.failed_at,
"status": CommandStatus.FAILED,
}
),
)

if self._state.running_command_id == action.command_id:
self._state.running_command_id = None

Expand Down Expand Up @@ -378,6 +363,24 @@ def handle_action(self, action: Action) -> None: # noqa: C901
elif action.door_state == DoorState.CLOSED:
self._state.is_door_blocking = False

def _update_to_failed(
self,
command_id: str,
failed_at: datetime,
error_occurrence: Optional[ErrorOccurrence],
) -> None:
prev_entry = self._state.commands_by_id[command_id]
updated_command = prev_entry.command.copy(
update={
"completedAt": failed_at,
"status": CommandStatus.FAILED,
**({"error": error_occurrence} if error_occurrence else {}),
}
)
self._state.commands_by_id[command_id] = CommandEntry(
index=prev_entry.index, command=updated_command
)

@staticmethod
def _map_run_exception_to_error_occurrence(
error_id: str, created_at: datetime, exception: Exception
Expand Down Expand Up @@ -516,6 +519,10 @@ def get_error(self) -> Optional[ErrorOccurrence]:
else:
return run_error or finish_error

def get_running_command_id(self) -> Optional[str]:
"""Return the ID of the command that's currently running, if there is one."""
return self._state.running_command_id

def get_current(self) -> Optional[CurrentCommand]:
"""Return the "current" command, if any.
Expand Down Expand Up @@ -632,6 +639,9 @@ def get_all_commands_final(self) -> bool:
)

if no_command_running and no_command_to_execute:
# TODO(mm, 2024-03-14): This is a slow O(n) scan. When a long run ends and
# we reach this loop, it can disrupt the robot server.
# https://opentrons.atlassian.net/browse/EXEC-55
for command_id in self._state.all_command_ids:
command = self._state.commands_by_id[command_id].command
if command.error and command.intent != CommandIntent.SETUP:
Expand Down
13 changes: 11 additions & 2 deletions api/tests/opentrons/protocol_engine/state/test_command_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,15 @@ def test_get_okay_to_clear(subject: CommandView, expected_is_okay: bool) -> None
assert subject.get_is_okay_to_clear() is expected_is_okay


def test_get_running_command_id() -> None:
"""It should return the running command ID."""
subject_with_running = get_command_view(running_command_id="command-id")
assert subject_with_running.get_running_command_id() == "command-id"

subject_without_running = get_command_view(running_command_id=None)
assert subject_without_running.get_running_command_id() is None


def test_get_current() -> None:
"""It should return the "current" command."""
subject = get_command_view(
Expand Down Expand Up @@ -851,7 +860,7 @@ def test_get_slice_default_cursor_running() -> None:


def test_get_slice_default_cursor_queued() -> None:
"""It should select a cursor based on the next queued command, if present."""
"""It should select a cursor automatically."""
command_1 = create_succeeded_command(command_id="command-id-1")
command_2 = create_succeeded_command(command_id="command-id-2")
command_3 = create_succeeded_command(command_id="command-id-3")
Expand All @@ -861,7 +870,7 @@ def test_get_slice_default_cursor_queued() -> None:
subject = get_command_view(
commands=[command_1, command_2, command_3, command_4, command_5],
running_command_id=None,
queued_command_ids=["command-id-4", "command-id-4", "command-id-5"],
queued_command_ids=[command_4.id, command_5.id],
)

result = subject.get_slice(cursor=None, length=2)
Expand Down
4 changes: 2 additions & 2 deletions api/tests/opentrons/protocol_engine/test_protocol_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ async def test_estop_during_command(
decoy.when(model_utils.get_timestamp()).then_return(timestamp)
decoy.when(model_utils.generate_id()).then_return(error_id)
decoy.when(state_store.commands.get_is_stopped()).then_return(False)
decoy.when(state_store.commands.state.running_command_id).then_return(command_id)
decoy.when(state_store.commands.get_running_command_id()).then_return(command_id)
decoy.when(state_store.commands.state.queued_command_ids).then_return(
fake_command_set
)
Expand Down Expand Up @@ -793,7 +793,7 @@ async def test_estop_without_command(
decoy.when(model_utils.get_timestamp()).then_return(timestamp)
decoy.when(model_utils.generate_id()).then_return(error_id)
decoy.when(state_store.commands.get_is_stopped()).then_return(False)
decoy.when(state_store.commands.state.running_command_id).then_return(None)
decoy.when(state_store.commands.get_running_command_id()).then_return(None)

expected_stop = StopAction(from_estop=True)
expected_hardware_stop = HardwareStoppedAction(
Expand Down
14 changes: 13 additions & 1 deletion app/src/assets/localization/en/protocol_details.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{
"author": "author",
"both_mounts": "Both Mounts",
"choices": "{{count}} choices",
"choose_robot_to_run": "Choose Robot to Run\n{{protocol_name}}",
"clear_and_proceed_to_setup": "Clear and proceed to setup",
"connect_modules_to_see_controls": "Connect modules to see controls",
"connected": "connected",
"connection_status": "connection status",
"creation_method": "creation method",
"deck_view": "Deck View",
"default_value": "Default Value",
"delete_protocol_perm": "{{name}} and its run history will be permanently deleted.",
"delete_protocol": "Delete Protocol",
"delete_this_protocol": "Delete this protocol?",
Expand All @@ -20,18 +23,25 @@
"labware": "labware",
"last_analyzed": "last analyzed",
"last_updated": "last updated",
"both_mounts": "Both Mounts",
"left_mount": "left mount",
"left_right": "Left, Right",
"liquid_name": "liquid name",
"liquids_not_in_protocol": "no liquids are specified for this protocol",
"liquids": "liquids",
"listed_values_are_view_only": "Listed values are view-only",
"location": "location",
"modules": "modules",
"name": "Name",
"no_available_robots_found": "No available robots found",
"no_parameters": "No parameters specified in this protocol",
"no_summary": "no summary specified for this protocol.",
"not_connected": "not connected",
"not_in_protocol": "no {{section}} is specified for this protocol",
"off": "Off",
"on_off": "On, off",
"on": "On",
"org_or_author": "org/author",
"parameters": "Parameters",
"pipette_aspirate_count_description": "individual aspirate commands per pipette.",
"pipette_aspirate_count": "{{pipette}} aspirate count",
"pipette_dispense_count_description": "individual dispense commands per pipette.",
Expand All @@ -44,6 +54,7 @@
"protocol_outdated_app_analysis": "This protocol's analysis is out of date. It may produce different results if you run it now.",
"python_api_version": "Python API {{version}}",
"quantity": "Quantity",
"range": "Range",
"read_less": "read less",
"read_more": "read more",
"right_mount": "right mount",
Expand All @@ -56,6 +67,7 @@
"sending": "Sending",
"show_in_folder": "Show in folder",
"slot": "Slot {{slotName}}",
"start_setup_customize_values": "Start setup to customize values",
"start_setup": "Start setup",
"successfully_sent": "Successfully sent",
"total_volume": "total volume",
Expand Down
2 changes: 1 addition & 1 deletion app/src/atoms/Banner/Banner.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
} as Meta

const Template: Story<React.ComponentProps<typeof Banner>> = args => (
<Banner {...args} />
<Banner {...args}>{'Banner component'}</Banner>
)

export const Primary = Template.bind({})
Expand Down
5 changes: 2 additions & 3 deletions app/src/atoms/Banner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
IconProps,
JUSTIFY_SPACE_BETWEEN,
RESPONSIVENESS,
SIZE_1,
SPACING,
TYPOGRAPHY,
} from '@opentrons/components'
Expand Down Expand Up @@ -91,7 +90,7 @@ export function Banner(props: BannerProps): JSX.Element {
const bannerProps = BANNER_PROPS_BY_TYPE[type]
const iconProps = {
...(icon ?? bannerProps.icon),
size: size ?? SIZE_1,
size: size ?? '1rem',
marginRight: iconMarginRight ?? SPACING.spacing8,
marginLeft: iconMarginLeft ?? '0rem',
color: BANNER_PROPS_BY_TYPE[type].color,
Expand Down Expand Up @@ -143,7 +142,7 @@ export function Banner(props: BannerProps): JSX.Element {
</Btn>
) : null}
{(isCloseActionLoading ?? false) && (
<Icon name="ot-spinner" size={SIZE_1} aria-label="ot-spinner" spin />
<Icon name="ot-spinner" size="1rem" aria-label="ot-spinner" spin />
)}
</Flex>
)
Expand Down
16 changes: 8 additions & 8 deletions app/src/atoms/InlineNotification/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import * as React from 'react'
import {
Icon,
JUSTIFY_SPACE_BETWEEN,
IconProps,
Flex,
DIRECTION_ROW,
ALIGN_CENTER,
BORDERS,
Btn,
COLORS,
DIRECTION_ROW,
Flex,
Icon,
IconProps,
JUSTIFY_SPACE_BETWEEN,
SPACING,
TYPOGRAPHY,
BORDERS,
Btn,
} from '@opentrons/components'
import { StyledText } from '../text'

Expand Down Expand Up @@ -94,7 +94,7 @@ export function InlineNotification(
>
{fullHeading}
</span>
{message && fullmessage}
{message != null && fullmessage}
</StyledText>
</Flex>
{onCloseClick && (
Expand Down
2 changes: 1 addition & 1 deletion app/src/atoms/Skeleton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface SkeletonProps {
export const Skeleton = (props: SkeletonProps): JSX.Element => {
const { width, height, backgroundSize, borderRadius } = props
const SKELETON_STYLE = css`
border-radius: ${borderRadius ?? BORDERS.borderRadius4};
border-radius: ${borderRadius ?? BORDERS.borderRadius8};
animation: shimmer 2s infinite linear;
background: linear-gradient(
to right,
Expand Down
2 changes: 1 addition & 1 deletion app/src/atoms/Snackbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export function Snackbar(props: SnackbarProps): JSX.Element {
<Flex
css={animationStyle}
alignItems={ALIGN_CENTER}
borderRadius={BORDERS.borderRadius12}
borderRadius={BORDERS.borderRadius8}
boxShadow={BORDERS.shadowSmall}
backgroundColor={COLORS.black90}
maxWidth="max-content"
Expand Down
2 changes: 1 addition & 1 deletion app/src/atoms/buttons/SubmitPrimaryButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const SubmitPrimaryButton = (
): JSX.Element => {
const SUBMIT_INPUT_STYLE = css`
background-color: ${COLORS.blue50};
border-radius: ${BORDERS.borderRadius4};
border-radius: ${BORDERS.borderRadius8};
padding: ${SPACING.spacing8} ${SPACING.spacing16};
color: ${COLORS.white};
${TYPOGRAPHY.pSemiBold}
Expand Down
Loading

0 comments on commit 422c606

Please sign in to comment.