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

feat(app): Get protocolDisplayData based on protocol schema #3531

Merged
merged 8 commits into from
Jun 12, 2019
105 changes: 84 additions & 21 deletions app/src/protocol/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'path'
import startCase from 'lodash/startCase'
import { createSelector } from 'reselect'
import { getter } from '@thi.ng/paths'
import { getProtocolSchemaVersion } from '@opentrons/shared-data'
import {
fileToProtocolFile,
parseProtocolData,
Expand Down Expand Up @@ -101,22 +102,45 @@ type NumberGetter = (?ProtocolData) => ?number
type StringSelector = OutputSelector<State, void, ?string>
type NumberSelector = OutputSelector<State, void, ?number>
type ProtocolTypeSelector = OutputSelector<State, void, ProtocolType | null>
type ProtocolInfoSelector = OutputSelector<
State,
void,
{
protocolName: ?string,
lastModified: ?number,
appName: ?string,
appVersion: ?string,
}
>
type CreatorAppSelector = OutputSelector<
State,
void,
{ name: ?string, version: ?string }
>

const getName: StringGetter = getter('metadata.protocol-name')
const protocolV1V2GetterPaths = {
name: 'metadata.protocol-name',
lastModified: 'metadata.last-modified',
appName: 'designer-application.application-name',
appVersion: 'designer-application.application-version',
}

const PROTOCOL_GETTER_PATHS_BY_SCHEMA = {
'1': protocolV1V2GetterPaths,
'2': protocolV1V2GetterPaths,
'3': {
name: 'metadata.protocolName',
lastModified: 'metadata.lastModified',
appName: 'designerApplication.name',
appVersion: 'designerApplication.version',
},
}

const getAuthor: StringGetter = getter('metadata.author')
const getDesc: StringGetter = getter('metadata.description')
const getCreated: NumberGetter = getter('metadata.created')
const getLastModified: NumberGetter = getter('metadata.last-modified')
const getSource: StringGetter = getter('metadata.source')
const getAppName: StringGetter = getter('designer-application.application-name')
const getAppVersion: StringGetter = getter(
'designer-application.application-version'
)

const stripDirAndExtension = f => path.basename(f, path.extname(f))

export const getProtocolFile = (state: State) => state.protocol.file
Expand All @@ -128,15 +152,50 @@ export const getProtocolFilename: StringSelector = createSelector(
file => file && file.name
)

export const getProtocolLastModified: NumberSelector = createSelector(
getProtocolFile,
file => file && file.lastModified
// TODO: (ka 2019-06-11): Investigate removing this unused? selector
// export const getProtocolLastModified: NumberSelector = createSelector(
// getProtocolFile,
// file => file && file.lastModified
// )

export const getProtocolDisplayData: $Shape<ProtocolInfoSelector> = createSelector(
getProtocolData,
getProtocolFilename,
(data, name) => {
if (!data)
return {
protocolName: name && stripDirAndExtension(name),
lastModified: null,
appName: null,
appVersion: null,
}
const version = (data && getProtocolSchemaVersion(data)) || 1
Kadee80 marked this conversation as resolved.
Show resolved Hide resolved
const getName = getter(PROTOCOL_GETTER_PATHS_BY_SCHEMA[version]['name'])
const getLastModified = getter(
PROTOCOL_GETTER_PATHS_BY_SCHEMA[version]['lastModified']
)
const getAppName = getter(
PROTOCOL_GETTER_PATHS_BY_SCHEMA[version]['appName']
)
const getAppVersion = getter(
PROTOCOL_GETTER_PATHS_BY_SCHEMA[version]['appVersion']
)
const protocolName = getName(data) || (name && stripDirAndExtension(name))
const lastModified = getLastModified(data) || getCreated(data)
const appName = getAppName(data)
const appVersion = getAppVersion(data)
return {
protocolName: protocolName,
lastModified: lastModified,
appName: appName,
appVersion: appVersion,
}
}
)

export const getProtocolName: StringSelector = createSelector(
getProtocolFilename,
getProtocolData,
(name, data) => getName(data) || (name && stripDirAndExtension(name))
getProtocolDisplayData,
displayData => displayData.protocolName
)

export const getProtocolAuthor: StringSelector = createSelector(
Expand All @@ -156,9 +215,8 @@ export const getProtocolSource: StringSelector = createSelector(

export const getProtocolLastUpdated: NumberSelector = createSelector(
getProtocolFile,
getProtocolData,
(file, data) =>
getLastModified(data) || getCreated(data) || (file && file.lastModified)
getProtocolDisplayData,
(file, displayData) => displayData.lastModified || (file && file.lastModified)
)

export const getProtocolType: ProtocolTypeSelector = createSelector(
Expand All @@ -167,8 +225,13 @@ export const getProtocolType: ProtocolTypeSelector = createSelector(
)

export const getProtocolCreatorApp: CreatorAppSelector = createSelector(
getProtocolData,
data => ({ name: getAppName(data), version: getAppVersion(data) })
getProtocolDisplayData,
displayData => {
return {
name: displayData.appName,
version: displayData.appVersion,
}
}
)

const METHOD_OT_API = 'Opentrons API'
Expand All @@ -178,11 +241,11 @@ export const getProtocolMethod: StringSelector = createSelector(
getProtocolFile,
getProtocolContents,
getProtocolData,
(file, contents, data) => {
getProtocolCreatorApp,
(file, contents, data, app) => {
const isJson = file && fileIsJson(file)
const appName = getAppName(data)
const appVersion = getAppVersion(data)
const readableName = appName && startCase(appName)
const appVersion = app && app.version
const readableName = app && startCase(app.name)

if (!file || !contents) return null
if (isJson === true && !readableName) return METHOD_UNKNOWN
Expand Down
1 change: 1 addition & 0 deletions app/src/protocol/protocol-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function parseProtocolData(
}
} else if (metadata) {
// grab Python protocol metadata, if any
// $FlowFixMe: (ka, 2019-06-10): cant differentiate which file schema file is needed
return { metadata }
}

Expand Down
6 changes: 5 additions & 1 deletion app/src/protocol/types.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// @flow
// protocol type defs
import type { SchemaV1ProtocolFile } from '@opentrons/shared-data'
import type {
SchemaV1ProtocolFile,
SchemaV3ProtocolFile,
} from '@opentrons/shared-data'

// data may be a full JSON protocol or just a metadata dict from Python
export type ProtocolData =
| SchemaV1ProtocolFile<{}>
| SchemaV3ProtocolFile<{}>
Kadee80 marked this conversation as resolved.
Show resolved Hide resolved
| { metadata: $PropertyType<SchemaV1ProtocolFile<{}>, 'metadata'> }
// NOTE: add union of additional versions after schema is bumped

Expand Down
3 changes: 1 addition & 2 deletions shared-data/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ export * from './pipettes'
export * from './types'
export * from './labwareTools'
export * from './modules'
export * from '../protocol/flowTypes/schemaV1'
export * from '../protocol/flowTypes/schemaV3'
export * from '../protocol'
20 changes: 20 additions & 0 deletions shared-data/protocol/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow
import type { SchemaV1ProtocolFile } from './flowTypes/schemaV1'
import type { SchemaV3ProtocolFile } from './flowTypes/schemaV3'

type ProtocolData =
| $Shape<SchemaV1ProtocolFile<{}>>
| $Shape<SchemaV3ProtocolFile<{}>>

// $FlowFixMe: (ka, 2019-06-10): cant differentiate which file schema file is needed
export function getProtocolSchemaVersion(data: ProtocolData): ?number {
if (data.schemaVersion) {
return data.schemaVersion
} else if (data['protocol-schema']) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be stricter about the "legacy" protocol-schema key, we could do very explicit if (data['protocol-schema'] == '1.0.0') return 1; else if (data['protocol-schema'] == '2.0.0') return 2. If it's '3lolz' or even if it's 3.0.0 or 3, those are invalid ways to designate a protocol as v3

I know this strictness is totally overkill for how this fn is used in this PR, but we're going to use this fn for protocol migration very soon and for that I'm not comfortable with it being this permissive

return Number(data['protocol-schema'].charAt(0))
}
return null
}

export * from './flowTypes/schemaV1'
export * from './flowTypes/schemaV3'