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

refactor(labware-creator): split apart sections into separate components #7735

Merged
merged 1 commit into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as React from 'react'
import { useFormikContext } from 'formik'
import cx from 'classnames'
import { PrimaryButton } from '@opentrons/components'
import { Dropdown } from '../../components/Dropdown'
import { labwareTypeOptions } from '../../fields'
import { getFormAlerts } from '../utils/getFormAlerts'
import { SectionBody } from './SectionBody'

import styles from '../../styles.css'
import type { LabwareFields } from '../../fields'

interface Props {
showDropDownOptions: boolean
disabled: boolean
labwareTypeChildFields: any
onClick: () => void
}

const getContent = (props: Props): JSX.Element => {
const {
disabled,
labwareTypeChildFields,
onClick,
showDropDownOptions,
} = props
return (
<div className={styles.labware_type_fields}>
{showDropDownOptions && (
<>
<Dropdown name="labwareType" options={labwareTypeOptions} />
{labwareTypeChildFields}
</>
)}

<PrimaryButton
className={styles.start_creating_btn}
disabled={disabled}
onClick={onClick}
>
start creating labware
</PrimaryButton>
</div>
)
}

export const CreateNewDefinition = (props: Props): JSX.Element => {
const fieldList: Array<keyof LabwareFields> = [
'labwareType',
'tubeRackInsertLoadName',
'aluminumBlockType',
'aluminumBlockChildType',
]
const { values, errors, touched } = useFormikContext<LabwareFields>()

return (
<div className={styles.new_definition_section}>
<SectionBody
label="Create a new definition"
headingClassName={cx(styles.setup_heading, {
[styles.disabled_section]: !props.showDropDownOptions,
})}
>
<>
{getFormAlerts({ values, touched, errors, fieldList })}
{getContent({ ...props })}
</>
</SectionBody>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from 'react'
import { useFormikContext } from 'formik'
import { yesNoOptions } from '../../fields'
import { getFormAlerts } from '../utils/getFormAlerts'
import { RadioField } from '../RadioField'
import { SectionBody } from './SectionBody'

import styles from '../../styles.css'
import type { LabwareFields } from '../../fields'

export const Regularity = (): JSX.Element => {
const fieldList: Array<keyof LabwareFields> = ['homogeneousWells']
const { values, errors, touched } = useFormikContext<LabwareFields>()

const ret = (
<SectionBody label="Regularity">
<>
{getFormAlerts({ values, touched, errors, fieldList })}
<div className={styles.flex_row}>
<div className={styles.homogenous_wells_section}>
<RadioField name="homogeneousWells" options={yesNoOptions} />
</div>
</div>
</>
</SectionBody>
)
return ret
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react'
import styles from '../Section.css'

interface Props {
children: JSX.Element
headingClassName?: string
label: string
}

export const SectionBody = (props: Props): JSX.Element => (
<div className={styles.section_wrapper}>
<h2 className={props.headingClassName || styles.section_header}>
{props.label}
</h2>
{props.children}
</div>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as React from 'react'
import { PrimaryButton } from '@opentrons/components'
import { ImportLabware } from '../ImportLabware'
import styles from '../../styles.css'

interface Props {
disabled: boolean
labwareTypeChildFields: any
lastUploaded: any
onClick: () => void
onUpload: (
event:
| React.DragEvent<HTMLLabelElement>
| React.ChangeEvent<HTMLInputElement>
) => void
}

export const UploadExisting = (props: Props): JSX.Element => {
const {
disabled,
labwareTypeChildFields,
lastUploaded,
onClick,
onUpload,
} = props
return (
<div className={styles.upload_existing_section}>
<h2 className={styles.setup_heading}>
Edit a file you’ve built with our labware creator omg!
</h2>
{lastUploaded === null ? (
<ImportLabware onUpload={onUpload} />
) : (
<div className={styles.labware_type_fields}>
{labwareTypeChildFields}
<PrimaryButton
className={styles.start_creating_btn}
onClick={onClick}
disabled={disabled}
>
start editing labware
</PrimaryButton>
</div>
)}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from 'react'
import compact from 'lodash/compact'
import uniq from 'lodash/uniq'
import { AlertItem } from '@opentrons/components'
import { getIsHidden } from '../../formSelectors'
import { IRREGULAR_LABWARE_ERROR, LINK_CUSTOM_LABWARE_FORM } from '../../fields'
import { LinkOut } from '../LinkOut'

import type { FormikTouched, FormikErrors } from 'formik'
import type { LabwareFields } from '../../fields'

interface Props {
values: LabwareFields
fieldList: Array<keyof LabwareFields>
touched: FormikTouched<LabwareFields>
errors: FormikErrors<LabwareFields>
}

export const getFormAlerts = (props: Props): JSX.Element[] | null => {
const { values, fieldList, touched, errors } = props
if (fieldList != null && fieldList.length > 0) {
const numFieldsHidden = fieldList
.map(field => getIsHidden(field, values))
.filter(Boolean).length

if (numFieldsHidden === fieldList.length) {
// all fields are hidden, don't render this Section
return null
}
}

// show Formik errors (from Yup) as WARNINGs for all dirty fields within this Section
const dirtyFieldNames = fieldList.filter(name => touched[name])
const allErrors: string[] = uniq(
compact(dirtyFieldNames.map(name => errors[name]))
)

return allErrors.map(error => {
if (error === IRREGULAR_LABWARE_ERROR) {
return (
<AlertItem
key={error}
type="error"
title={
<>
Your labware is not compatible with the Labware Creator. Please
fill out{' '}
<LinkOut href={LINK_CUSTOM_LABWARE_FORM}>this form</LinkOut> to
request a custom labware definition.
</>
}
/>
)
}
return <AlertItem key={error} type="warning" title={error} />
})
}
83 changes: 17 additions & 66 deletions labware-library/src/labware-creator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { AlertItem, AlertModal, PrimaryButton } from '@opentrons/components'
import labwareSchema from '@opentrons/shared-data/labware/schemas/2.json'
import { makeMaskToDecimal, maskToInteger, maskLoadName } from './fieldMasks'
import {
labwareTypeOptions,
tubeRackInsertOptions,
aluminumBlockAutofills,
aluminumBlockTypeOptions,
Expand Down Expand Up @@ -42,7 +41,6 @@ import { RadioField } from './components/RadioField'
import { Section } from './components/Section'
import { TextField } from './components/TextField'
import { HeightGuidingText } from './components/HeightGuidingText'
import { ImportLabware } from './components/ImportLabware'
import { ImportErrorModal } from './components/ImportErrorModal'
import {
HeightImg,
Expand All @@ -65,6 +63,9 @@ import type {
LabwareFields,
ProcessedLabwareFields,
} from './fields'
import { CreateNewDefinition } from './components/sections/CreateNewDefinition'
import { UploadExisting } from './components/sections/UploadExisting'
import { Regularity } from './components/sections/Regularity'

const ajv = new Ajv()
const validateLabwareSchema = ajv.compile(labwareSchema)
Expand Down Expand Up @@ -495,75 +496,25 @@ export const LabwareCreator = (): JSX.Element => {
<h2>Custom Labware Creator BETA</h2>
<IntroCopy />
<div className={styles.flex_row}>
<div className={styles.new_definition_section}>
<Section
label="Create a new definition"
fieldList={[
'labwareType',
'tubeRackInsertLoadName',
'aluminumBlockType',
'aluminumBlockChildType',
]}
headingClassName={cx(styles.setup_heading, {
[styles.disabled_section]: lastUploaded !== null,
})}
>
<div className={styles.labware_type_fields}>
{lastUploaded === null ? (
<>
<Dropdown
name="labwareType"
options={labwareTypeOptions}
/>
{labwareTypeChildFields}
</>
) : null}

<PrimaryButton
className={styles.start_creating_btn}
disabled={!canProceedToForm || lastUploaded !== null}
onClick={scrollToForm}
>
start creating labware
</PrimaryButton>
</div>
</Section>
</div>
<div className={styles.upload_existing_section}>
<h2 className={styles.setup_heading}>
Edit a file you’ve built with our labware creator
</h2>
{lastUploaded === null ? (
<ImportLabware onUpload={onUpload} />
) : (
<div className={styles.labware_type_fields}>
{labwareTypeChildFields}
<PrimaryButton
className={styles.start_creating_btn}
onClick={scrollToForm}
disabled={!canProceedToForm}
>
start editing labware
</PrimaryButton>
</div>
)}
</div>
<CreateNewDefinition
showDropDownOptions={lastUploaded === null}
disabled={!canProceedToForm || lastUploaded !== null}
labwareTypeChildFields={labwareTypeChildFields}
onClick={scrollToForm}
/>
<UploadExisting
disabled={!canProceedToForm}
labwareTypeChildFields={labwareTypeChildFields}
lastUploaded={lastUploaded}
onClick={scrollToForm}
onUpload={onUpload}
/>
</div>
<div ref={scrollRef} />
{showCreatorForm && (
<>
{/* PAGE 1 - Labware */}
<Section label="Regularity" fieldList={['homogeneousWells']}>
{/* tubeRackSides: Array<string> maybe?? */}
<div className={styles.flex_row}>
<div className={styles.homogenous_wells_section}>
<RadioField
name="homogeneousWells"
options={yesNoOptions}
/>
</div>
</div>
</Section>
<Regularity />
<Section
label="Footprint"
fieldList={['footprintXDimension', 'footprintYDimension']}
Expand Down