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 1 commit
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
Prev Previous commit
Next Next commit
add temporary open file action to remove
  • Loading branch information
b-cooper committed May 7, 2024
commit 71e036413702593035557281dda0e80beececf80
2 changes: 1 addition & 1 deletion app-shell/src/config/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ const toVersion22 = (prevConfig: ConfigV21): ConfigV22 => {
...prevConfig,
version: 22 as const,
protocolEditorUi: {
width: 1024,
width: 1300,
minWidth: 600,
height: 768,
url: {
Expand Down
53 changes: 31 additions & 22 deletions app-shell/src/protocol-editor-ui.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
// sets up the main window ui
import { app, shell, BrowserWindow } from 'electron'
import { app, shell, BrowserWindow, ipcMain } from 'electron'
import path from 'path'

import { getConfig } from './config'
import { createLogger } from './log'
import { getProtocolSourceJSON } from './protocol-storage/file-system'
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
),
}
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 =
Expand Down Expand Up @@ -64,7 +64,16 @@ export function createProtocolEditorUi(srcFilePath: string): BrowserWindow {
subWindow.webContents.once('dom-ready', () => {
const protocolSourceJSON = getProtocolSourceJSON(srcFilePath)
protocolSourceJSON.then(json => {
subWindow.webContents.send('set-protocol-source-file', 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
)
})
})
})
});

Expand Down
13 changes: 12 additions & 1 deletion app-shell/src/protocol-storage/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { app, shell } from 'electron'
import type { StoredProtocolDir } from '@opentrons/app/src/redux/protocol-storage'
import type { Dirent } from 'fs'
import { analyzeProtocolSource } from '../protocol-analysis'
import { createProtocolEditorUi } from '../protocol-editor-ui'

/**
* Module for managing local protocol files on the host filesystem
Expand Down Expand Up @@ -186,3 +185,15 @@ export function editProtocol(
return srcFilePathsPromise
}

export function overwriteProtocol(
protocolSrcPath: string,
newFileName: string,
protocolData: string
): Promise<void> {
const newSrcFilePath = path.join(path.dirname(protocolSrcPath), newFileName)
return fs.remove(protocolSrcPath).then(() => {
return fs.writeFile(newSrcFilePath, JSON.stringify(protocolData))
}).catch(e => { console.error(e) })
}


9 changes: 0 additions & 9 deletions app/src/redux/shell/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,3 @@ remote.ipcRenderer.on(
callbackStore[shellHostname]?.[shellTopic]?.forEach(cb => cb(shellMessage))
}
)

// Instantiate the notify listener at runtime.
remote.ipcRenderer.on(
'set-protocol-source-file',
(...params) => {
console.log('GOT IPC MESSAGE', params)
}
)

82 changes: 45 additions & 37 deletions protocol-designer/src/components/FileSidebar/FileSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ export function FileSidebar(): JSX.Element {
const savedStepForms = useSelector(stepFormSelectors.getSavedStepForms)
const newProtocolModal = useSelector(selectors.getNewProtocolModal)
const hasUnsavedChanges = useSelector(loadFileSelectors.getHasUnsavedChanges)
const hasNativeFileSystemAccess = useSelector(loadFileSelectors.getHasNativeFileSystemAccess)
const canCreateNew = !newProtocolModal
const dispatch: ThunkDispatch<any> = useDispatch()

Expand All @@ -264,18 +265,6 @@ export function FileSidebar(): JSX.Element {
setShowExportWarningModal,
] = React.useState<boolean>(false)
const { t } = useTranslation(['alert', 'modules'])
const urlSearchParams = new URLSearchParams(window.location.search)
let protocolFileSrcPath: string | null = null
for (const [paramName, paramValue] of urlSearchParams.entries()) {
if (paramName === 'protocolSrcPath') {
protocolFileSrcPath = paramValue
}
}
React.useEffect(() => {
if (protocolFileSrcPath != null) {
dispatch(loadFileActions.loadProtocolFile({ currentTarget: { files: [FileSystemDirectoryEntry.getFile(protocolFileSrcPath)] } }))
}
}, [protocolFileSrcPath])
const isGripperAttached = Object.values(additionalEquipment).some(
equipment => equipment?.name === 'gripper'
)
Expand Down Expand Up @@ -379,6 +368,49 @@ export function FileSidebar(): JSX.Element {
dispatch(loadFileActions.saveProtocolFile())
},
})


const sidebarContents = hasNativeFileSystemAccess ? (
<div className={styles.button}>
<DeprecatedPrimaryButton
onClick={() => {
dispatch(loadFileActions.saveToFileSystem())
}}
disabled={!canDownload}
>
{t('save')}
</DeprecatedPrimaryButton>
</div>
) : (
<>
<OutlineButton onClick={createNewFile} className={styles.button}>
{t('create_new')}
</OutlineButton>

<OutlineButton Component="label" className={cx(styles.upload_button)}>
{t('import')}
<input type="file" onChange={loadFile} />
</OutlineButton>

<div className={styles.button}>
<DeprecatedPrimaryButton
onClick={() => {
if (hasWarning) {
resetScrollElements()
setShowExportWarningModal(true)
} else {
resetScrollElements()
setShowBlockingHint(true)
}
}}
disabled={!canDownload}
>
{t('export')}
</DeprecatedPrimaryButton>
</div>
</>
)

return (
<>
{blockingExportHint}
Expand Down Expand Up @@ -410,31 +442,7 @@ export function FileSidebar(): JSX.Element {
)}
<SidePanel title="Protocol File">
<div className={styles.file_sidebar}>
<OutlineButton onClick={createNewFile} className={styles.button}>
{t('create_new')}
</OutlineButton>

<OutlineButton Component="label" className={cx(styles.upload_button)}>
{t('import')}
<input type="file" onChange={loadFile} />
</OutlineButton>

<div className={styles.button}>
<DeprecatedPrimaryButton
onClick={() => {
if (hasWarning) {
resetScrollElements()
setShowExportWarningModal(true)
} else {
resetScrollElements()
setShowBlockingHint(true)
}
}}
disabled={!canDownload}
>
{t('export')}
</DeprecatedPrimaryButton>
</div>
{sidebarContents}
</div>
</SidePanel>
</>
Expand Down
4 changes: 2 additions & 2 deletions protocol-designer/src/configureStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
} from 'redux'
import thunk from 'redux-thunk'
import { trackEventMiddleware } from './analytics/middleware'
import { makePersistSubscriber, rehydratePersistedAction } from './persist'

Check failure on line 12 in protocol-designer/src/configureStore.ts

View workflow job for this annotation

GitHub Actions / js checks

'makePersistSubscriber' is defined but never used
import { fileUploadMessage } from './load-file/actions'
import { makeTimelineMiddleware } from './timelineMiddleware/makeTimelineMiddleware'
import { BaseState, Action } from './types'
Expand Down Expand Up @@ -93,8 +93,8 @@
)
)
// initial rehydration, and persistence subscriber
store.dispatch(rehydratePersistedAction())
store.subscribe(makePersistSubscriber(store))
// store.dispatch(rehydratePersistedAction())
// store.subscribe(makePersistSubscriber(store))

global.enablePrereleaseMode = () => {
store.dispatch({
Expand Down
4 changes: 4 additions & 0 deletions protocol-designer/src/file-data/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ const fileMetadata = handleActions(
// NOTE: 'last-modified' is updated "on-demand", in response to user clicking "save/export"
return { ...state, lastModified: Date.now() }
},
SAVE_TO_FILE_SYSTEM: (state: FileMetadataFields): FileMetadataFields => {
// NOTE: 'last-modified' is updated "on-demand", in response to user clicking "save"
return { ...state, lastModified: Date.now() }
},
},
defaultFields
)
Expand Down
32 changes: 0 additions & 32 deletions protocol-designer/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ import { initialize } from './initialize'
import { initializeMixpanel } from './analytics/mixpanel'
import { i18n } from './localization'

import type { Remote } from './types'
import { remove } from 'lodash'



// initialize Redux
const store = configureStore()
initialize(store)
Expand All @@ -35,31 +30,4 @@ const render = (Component: any): void => {
)
}



const emptyRemote: Remote = {} as any

export const remote: Remote = new Proxy(emptyRemote, {
get(_target, propName: string): unknown {
console.assert(
(global as any).APP_SHELL_REMOTE,
'Expected APP_SHELL_REMOTE to be attached to global scope; is app-shell/src/preload.ts properly configured?'
)

console.assert(
propName in (global as any).APP_SHELL_REMOTE,
`Expected APP_SHELL_REMOTE.${propName} to exist, is app-shell/src/preload.ts properly configured?`
)
return (global as any).APP_SHELL_REMOTE[propName] as Remote
},
})

// Instantiate the notify listener at runtime.
remote.ipcRenderer.on(
'set-protocol-source-file',
(...params) => {
console.log('GOT IPC MESSAGE', params)
}
)

render(App)
9 changes: 9 additions & 0 deletions protocol-designer/src/initialize.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { PDProtocolFile } from './file-types'
import { selectors as loadFileSelectors } from './load-file'
import { loadFileAction, openFileAction } from './load-file/actions'

Check failure on line 3 in protocol-designer/src/initialize.ts

View workflow job for this annotation

GitHub Actions / js checks

'openFileAction' is defined but never used
import { remote } from './shell/remote'

// TODO(Jr, 1/18/24): use i18n here!
export const initialize = (store: Record<string, any>): void => {
Expand All @@ -10,4 +13,10 @@
: undefined
}
}
remote.ipcRenderer.on(
'open-protocol-in-designer',
(_ipcEvent, protocolSource) => {
store.dispatch(loadFileAction(protocolSource as PDProtocolFile))
}
)
}
29 changes: 27 additions & 2 deletions protocol-designer/src/load-file/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {
FileUploadMessage,
LoadFileAction,
NewProtocolFields,
OpenFileAction,
} from './types'
import { remote } from '../shell/remote'
export interface FileUploadMessageAction {
type: 'FILE_UPLOAD_MESSAGE'
payload: FileUploadMessage
Expand All @@ -26,9 +28,12 @@ export const dismissFileUploadMessage = (): DismissFileUploadMessageAction => ({
type: 'DISMISS_FILE_UPLOAD_MESSAGE',
})
// expects valid, parsed JSON protocol.
export const loadFileAction = (payload: PDProtocolFile): LoadFileAction => ({
export const loadFileAction = (protocolFile: PDProtocolFile, hasFileSystemAccess: boolean = false): LoadFileAction => ({
type: 'LOAD_FILE',
payload: migration(payload),
payload: {
...migration(protocolFile),
hasFileSystemAccess
},
})
// load file thunk, handles file loading errors
export const loadProtocolFile = (
Expand Down Expand Up @@ -110,3 +115,23 @@ export const saveProtocolFile: () => ThunkAction<SaveProtocolFileAction> = () =>
const fileName = `${protocolName}.json`
saveFile(fileData, fileName)
}

export interface SaveToFileSystemAction {
type: 'SAVE_TO_FILE_SYSTEM'
}
export const saveToFileSystem: () => ThunkAction<SaveToFileSystemAction> = () => (
dispatch,
getState
) => {
// dispatching this should update the state, eg lastModified timestamp
dispatch({
type: 'SAVE_TO_FILE_SYSTEM',
})
const state = getState()
const fileData = fileDataSelectors.createFile(state)
const protocolName =
fileDataSelectors.getFileMetadata(state).protocolName || 'untitled'
const fileName = `${protocolName}.json`
remote.ipcRenderer.send('save-protocol-file-to-filesystem', fileName, fileData)
}

1 change: 1 addition & 0 deletions protocol-designer/src/load-file/migration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const migration = (
didMigrate: boolean
migrationsRan: string[]
} => {
console.log('IN MIgrATION', file)
const designerApplication =
file.designerApplication || file['designer-application']
// NOTE: default exists because any protocol that doesn't include the application version
Expand Down
Loading
Loading