Skip to content

Commit

Permalink
Merge branch 'edge' into exec-331-override-border-radius-4
Browse files Browse the repository at this point in the history
  • Loading branch information
mjhuff committed Mar 18, 2024
2 parents 65d877a + fe9a09f commit 7e77a2f
Show file tree
Hide file tree
Showing 127 changed files with 1,578 additions and 684 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
15 changes: 14 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,26 @@
"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",
"num_choices": "{{num}} choices",
"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 +55,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 +68,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
39 changes: 12 additions & 27 deletions app/src/atoms/Chip/Chip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import type { Story, Meta } from '@storybook/react'

export default {
title: 'ODD/Atoms/Chip',
argTypes: {
type: {
options: ['basic', 'error', 'info', 'neutral', 'success', 'warning'],
control: {
type: 'select',
},
defaultValue: 'basic',
},
},
component: Chip,
parameters: touchScreenViewport,
} as Meta
Expand All @@ -25,32 +34,8 @@ const Template: Story<ChipStorybookProps> = ({ ...args }) => (
</Flex>
)

export const Basic = Template.bind({})
Basic.args = {
export const ChipComponent = Template.bind({})
ChipComponent.args = {
type: 'basic',
text: 'Basic chip text',
}

export const Error = Template.bind({})
Error.args = {
type: 'error',
text: 'Not connected',
}

export const Success = Template.bind({})
Success.args = {
type: 'success',
text: 'Connected',
}

export const Warning = Template.bind({})
Warning.args = {
type: 'warning',
text: 'Missing 1 module',
}

export const Neutral = Template.bind({})
Neutral.args = {
type: 'neutral',
text: 'Not connected',
text: 'Chip component',
}
Loading

0 comments on commit 7e77a2f

Please sign in to comment.