Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skunk command annotations for step grouping #15493

Closed
wants to merge 55 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
5e6d034
construct invariant context from runtime commands
b-cooper Jun 9, 2022
66bb15b
start creating timeline from run commands
b-cooper Jun 9, 2022
5cb0f21
organize module state constants
b-cooper Jun 10, 2022
809add2
POC for static deck setup in protocol timeline scrubber component
b-cooper Jun 10, 2022
46a29f3
add slider
b-cooper Jun 10, 2022
758f290
proof of concept with liquid and tip tracking
b-cooper Jun 14, 2022
d9bbfab
add display color and liquid entities
b-cooper Jun 14, 2022
9f2096e
get tip liquid state down to tip side view
b-cooper Jun 19, 2022
61117e7
add longer liquidless protocol example
b-cooper Jun 19, 2022
de26876
alignment and empty state for pipette viz
b-cooper Jun 20, 2022
99f78e2
multi channel support
b-cooper Jun 20, 2022
c474a52
jump to command
b-cooper Jun 20, 2022
930f121
add to new timeline route
b-cooper Jun 20, 2022
40333fa
Merge branch 'edge' into step-generation_get-timeline-from-commands
b-cooper Jul 21, 2022
f628f8e
add support for all commands in step generation as pass through
b-cooper Jul 21, 2022
5088edf
map initial aspirate and dispense commands
b-cooper Jul 21, 2022
2d1bd0a
window timeline scrubber and fix air in tips rendering
b-cooper Jul 21, 2022
26efb76
Merge branch 'edge' into step-generation_get-timeline-from-commands
b-cooper Jul 12, 2023
796abb5
make changes to things that were moved around
b-cooper Jul 12, 2023
e5b9576
begin modernizing scrubber
b-cooper Jul 12, 2023
098f5f0
modernize constants in scrubber
b-cooper Jul 19, 2023
98bcf17
visual adjustment
b-cooper Sep 8, 2023
9b5053c
Merge branch 'chore_release-7.0.0' into step-generation_get-timeline-…
b-cooper Sep 8, 2023
7a50537
update to current values
b-cooper Sep 8, 2023
dd845a8
feat(shared-data): json protocol schema 8
sfoster1 Oct 25, 2023
f248da7
add enum to annotations and structure types for commands etc
b-cooper Oct 25, 2023
d2c84e4
Merge branch 'edge' into step-generation_get-timeline-from-commands
b-cooper Oct 25, 2023
279363c
account for robot type
b-cooper Oct 26, 2023
fecc2ba
fix up ts config for protocol types
b-cooper Oct 26, 2023
2c96e76
Hackishly expose commandAnnotations in protocol analysis output.
SyntaxColoring Oct 17, 2023
57dd41d
command list from annotations
b-cooper Oct 19, 2023
c5b1ae5
prelim collapsible grouping
b-cooper Oct 20, 2023
2de8fc2
positioning of annotated group
b-cooper Oct 23, 2023
60edcc3
fix up type export
b-cooper Oct 26, 2023
644694b
Merge branch 'skunk_v8-command-annotations-in-analysis-output' into s…
b-cooper Oct 26, 2023
f05c50a
annotated steps
b-cooper Oct 26, 2023
cecefec
current parent node treatment
b-cooper Oct 27, 2023
a73f7aa
proof of concept new window
b-cooper Oct 27, 2023
c2e2078
Merge branch 'edge' into skunk_grouped-steps-timeline-scrubber-pd-window
b-cooper Nov 9, 2023
fa84d3d
Merge branch 'edge' into skunk_grouped-steps-timeline-scrubber-pd-window
b-cooper May 2, 2024
d09864e
remote global to pd
b-cooper May 6, 2024
71e0364
add temporary open file action to remove
b-cooper May 7, 2024
cca0b72
remove temporary changes
b-cooper May 7, 2024
288673d
cleanup grouping in annotated steps
b-cooper May 8, 2024
fe792e1
other viz commented out
b-cooper Jun 14, 2024
06d2fc3
Merge branch 'edge' into skunk_grouped-steps-timeline-scrubber-pd-window
b-cooper Jun 21, 2024
bdf5f95
fix up command text in scrubber
b-cooper Jun 21, 2024
363c5cc
remove merge cruft command text utils
b-cooper Jun 21, 2024
3d3da25
remove unnecessary changes
b-cooper Jun 21, 2024
3c6fa17
remove log statements
b-cooper Jun 21, 2024
41cbf02
revert spurious yarn change
b-cooper Jun 21, 2024
04340e5
remove changes from other work
b-cooper Jun 21, 2024
83e7361
remove timeline specific app changes
b-cooper Jun 21, 2024
fcaf048
revert step-generation changes
b-cooper Jun 21, 2024
e73d10d
feat(app): add protocol detail annotation-based step grouping view
b-cooper Jun 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/src/opentrons/cli/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,4 @@ class AnalyzeResults(BaseModel):
modules: List[LoadedModule]
liquids: List[Liquid]
errors: List[ErrorOccurrence]
commandAnnotations: List[Any]
12 changes: 11 additions & 1 deletion api/src/opentrons/protocol_reader/file_identifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import json
from dataclasses import dataclass
from typing import Any, Dict, Sequence, Union, Optional
from typing import Any, Dict, List, Sequence, Union, Optional

import anyio

Expand Down Expand Up @@ -45,6 +45,8 @@ class IdentifiedJsonMain:
metadata: Metadata
"""The protocol metadata extracted from this file."""

command_annotations: List[Any]


@dataclass(frozen=True)
class IdentifiedPythonMain:
Expand All @@ -62,6 +64,8 @@ class IdentifiedPythonMain:
metadata: Metadata
"""The protocol metadata extracted from this file."""

command_annotations: List[Any]


@dataclass(frozen=True)
class IdentifiedLabwareDefinition:
Expand Down Expand Up @@ -203,6 +207,7 @@ def _analyze_json_protocol(
metadata = json_contents["metadata"]
schema_version = json_contents["schemaVersion"]
robot_type = json_contents["robot"]["model"]
command_annotations = json_contents.get("commandAnnotations", [])
except KeyError as e:
raise FileIdentificationError(
message=error_message,
Expand All @@ -218,6 +223,9 @@ def _analyze_json_protocol(
message=error_message, detail={"kind": "json-metadata-not-object"}
)

if not isinstance(command_annotations, list):
raise FileIdentificationError(error_message)

if not isinstance(schema_version, int):
raise FileIdentificationError(
message=error_message,
Expand All @@ -239,6 +247,7 @@ def _analyze_json_protocol(
schema_version=schema_version,
robot_type=robot_type,
metadata=metadata,
command_annotations=command_annotations,
)


Expand Down Expand Up @@ -281,4 +290,5 @@ def _analyze_python_protocol(
metadata=parsed.metadata or {},
robot_type=parsed.robot_type,
api_level=parsed.api_level,
command_annotations=[],
)
2 changes: 2 additions & 0 deletions api/src/opentrons/protocol_reader/protocol_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ async def save(
config=self._map_config(role_analysis),
robot_type=role_analysis.main_file.robot_type,
metadata=role_analysis.main_file.metadata,
command_annotations=role_analysis.main_file.command_annotations,
)

async def read_saved(
Expand Down Expand Up @@ -167,6 +168,7 @@ async def read_saved(
config=self._map_config(role_analysis),
robot_type=role_analysis.main_file.robot_type,
metadata=role_analysis.main_file.metadata,
command_annotations=role_analysis.main_file.command_annotations,
)

@staticmethod
Expand Down
1 change: 1 addition & 0 deletions api/src/opentrons/protocol_reader/protocol_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,4 @@ class ProtocolSource:
metadata: Metadata
robot_type: RobotType
config: ProtocolConfig
command_annotations: List[Any]
83 changes: 83 additions & 0 deletions app-shell/src/protocol-editor-ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// sets up the main window ui
import { app, shell, BrowserWindow, ipcMain } from 'electron'
import path from 'path'

import { getConfig } from './config'
import { createLogger } from './log'
import {
PROTOCOLS_DIRECTORY_PATH,
analyzeProtocolByKey,
getProtocolSourceJSON,
overwriteProtocol,
} from './protocol-storage/file-system'

const protocolEditorUiConfig = getConfig('protocolEditorUi')
const log = createLogger('protocolEditorUi')

const WINDOW_OPTS = {
show: false,
useContentSize: true,
width: protocolEditorUiConfig.width,
minWidth: protocolEditorUiConfig.minWidth,
height: protocolEditorUiConfig.height,
// allow webPreferences to be set at launchtime from config
webPreferences: Object.assign(
{
preload: path.join(__dirname, './preload.js'),
nodeIntegration: false,
// TODO: remove this by using electron contextBridge to specify
// exact, argument-sanitation-involved methods instead of just
// binding the entire ipcRenderer in. This is necessary because
// as of electron 12, contextIsolation defaults to true.
contextIsolation: false,
},
protocolEditorUiConfig.webPreferences
),
}

const protocolEditorPath =
protocolEditorUiConfig.url.protocol === 'file:'
? path.join(app.getAppPath(), protocolEditorUiConfig.url.path)
: protocolEditorUiConfig.url.path

export function createProtocolEditorUi(srcFilePath: string): BrowserWindow {
log.debug('Creating protocol editor window', { options: WINDOW_OPTS })

const subWindow = new BrowserWindow(WINDOW_OPTS).once('ready-to-show', () => {
log.debug('Protocol Editor window ready to show')
subWindow.show()
})
const protocolEditorUrl = `${protocolEditorUiConfig.url.protocol}//${protocolEditorPath}`

log.info(`Loading ${protocolEditorUrl}`)
// eslint-disable-next-line @typescript-eslint/no-floating-promises
subWindow.loadURL(protocolEditorUrl)

// open new windows (<a target="_blank" ...) in browser windows
subWindow.webContents.setWindowOpenHandler(({ url }) => {
log.debug('Opening external link', { url })
// event.preventDefault()
// eslint-disable-next-line @typescript-eslint/no-floating-promises
shell.openExternal(url)
return { action: 'deny' }
})

subWindow.webContents.once('dom-ready', () => {
const protocolSourceJSON = getProtocolSourceJSON(srcFilePath)
protocolSourceJSON.then(json => {
subWindow.webContents.send('open-protocol-in-designer', json)
ipcMain.once(
'save-protocol-file-to-filesystem',
(_event, fileName, fileData) => {
overwriteProtocol(srcFilePath, fileName, fileData).then(() => {
const { protocolKey } =
/.*\/(?<protocolKey>.*)\/src.*/.exec(srcFilePath)?.groups ?? {}
return analyzeProtocolByKey(protocolKey, PROTOCOLS_DIRECTORY_PATH)
})
}
)
})
})

return subWindow
}
5 changes: 4 additions & 1 deletion app/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ SHELL := bash
# add node_modules/.bin to PATH
PATH := $(shell cd .. && yarn bin):$(PATH)

# dev server port
# app dev server port
PORT ?= 5173
# protocol editor dev server port
PD_PORT ?= 5178

# Path of source package
SRC_PATH = app
Expand Down Expand Up @@ -54,6 +56,7 @@ dist:
.PHONY: dev
dev: export NODE_ENV := development
dev: export PORT := $(PORT)
dev: export PD_PORT := $(PD_PORT)
dev:
concurrently --no-color --kill-others --names "server,shell" \
"$(MAKE) dev-server OPENTRONS_PROJECT=$(OPENTRONS_PROJECT)" \
Expand Down
7 changes: 7 additions & 0 deletions app/src/App/DesktopApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { IncompatibleModuleTakeover } from '../organisms/IncompatibleModule'
import { OPENTRONS_USB } from '../redux/discovery'
import { appShellRequestor } from '../redux/shell/remote'
import { useRobot, useIsFlex } from '../organisms/Devices/hooks'
import { ProtocolTimeline } from '../pages/Protocols/ProtocolDetails/ProtocolTimeline'
import { PortalRoot as ModalPortalRoot } from './portal'
import { DesktopAppFallback } from './DesktopAppFallback'

Expand All @@ -58,6 +59,12 @@ export const DesktopApp = (): JSX.Element => {
name: 'Protocol Details',
path: '/protocols/:protocolKey',
},
{
Component: ProtocolTimeline,
exact: true,
name: 'Protocol Timeline',
path: '/protocols/:protocolKey/timeline',
},
{
Component: Labware,
name: 'Labware',
Expand Down
1 change: 1 addition & 0 deletions app/src/assets/localization/en/app_settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"__dev_internal__forceHttpPolling": "Poll all network requests instead of using MQTT",
"__dev_internal__protocolStats": "Protocol Stats",
"__dev_internal__protocolTimeline": "Protocol Timeline",
"__dev_internal__enableRunNotes": "Display Notes During a Protocol Run",
"__dev_internal__enableQuickTransfer": "Enable Quick Transfer",
"__dev_internal__enableCsvFile": "Enable CSV File",
Expand Down
1 change: 1 addition & 0 deletions app/src/assets/localization/en/protocol_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"extension_mount": "extension mount",
"file_required": "File required",
"go_to_labware_definition": "Go to labware definition",
"go_to_timeline": "Go to timeline",
"gripper_pick_up_count_description": "individual move labware commands that use the gripper.",
"gripper_pick_up_count": "Grip Count",
"hardware": "hardware",
Expand Down
2 changes: 2 additions & 0 deletions app/src/assets/localization/en/protocol_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
"csv_file_required": "CSV file required for analysis. Add the CSV during run setup.",
"delete_protocol_message": " and its run history will be permanently deleted.",
"delete_this_protocol": "Delete this protocol?",
"edit": "edit",
"go_to_timeline": "Go to timeline",
"last_updated_at": "Updated {{date}}",
"left_mount": "left mount",
"loading_data": "Loading data...",
Expand Down
1 change: 1 addition & 0 deletions app/src/molecules/Command/MoveLabwareCommandText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { GRIPPER_WASTE_CHUTE_ADDRESSABLE_AREA } from '@opentrons/shared-data'
import { getLabwareName } from './utils'
import { getLabwareDisplayLocation } from './utils/getLabwareDisplayLocation'
import { getFinalLabwareLocation } from './utils/getFinalLabwareLocation'

import type {
MoveLabwareRunTimeCommand,
RobotType,
Expand Down
7 changes: 7 additions & 0 deletions app/src/molecules/Command/PipettingCommandText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ export const PipettingCommandText = ({
flow_rate: flowRate,
})
}
case 'moveToWell': {
return t('move_to_well', {
well_name: wellName,
labware: getLabwareName(analysis, labwareId),
labware_location: displayLocation,
})
}
case 'dropTip': {
const loadedLabware = getLoadedLabware(commandTextData, labwareId)
const labwareDefinitions = getLabwareDefinitionsFromCommands(
Expand Down
6 changes: 5 additions & 1 deletion app/src/molecules/Command/utils/getCommandTextData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import type { LegacyGoodRunData } from '@opentrons/api-client'
import type {
CompletedProtocolAnalysis,
ProtocolAnalysisOutput,
RunTimeCommand,
} from '@opentrons/shared-data'
import type { CommandTextData } from '../types'

export function getCommandTextData(
protocolData: CompletedProtocolAnalysis | LegacyGoodRunData,
protocolData:
| CompletedProtocolAnalysis
| LegacyGoodRunData
| ProtocolAnalysisOutput,
protocolCommands?: RunTimeCommand[]
): CommandTextData {
const { pipettes, labware, modules, liquids } = protocolData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export function getLabwareDisplayLocation(
if (location === 'offDeck') {
return t('off_deck')
} else if ('slotName' in location) {
return isOnDevice
return isOnDevice === true
? location.slotName
: t('slot', { slot_name: location.slotName })
} else if ('addressableAreaName' in location) {
return isOnDevice
return isOnDevice === true
? location.addressableAreaName
: t('slot', { slot_name: location.addressableAreaName })
} else if ('moduleId' in location) {
Expand All @@ -39,7 +39,7 @@ export function getLabwareDisplayLocation(
commandTextData,
location.moduleId
)
return isOnDevice
return isOnDevice === true
? `${getModuleDisplayName(moduleModel)}, ${slotName}`
: t('module_in_slot', {
count: getOccludedSlotCountForModule(
Expand Down
Loading
Loading