diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx
index 7a6b07f9ae5..0b3ccb5c141 100644
--- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx
+++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunRunTimeParameters.tsx
@@ -2,6 +2,7 @@ import * as React from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
+import { formatRunTimeParameterValue } from '@opentrons/shared-data'
import {
ALIGN_CENTER,
BORDERS,
@@ -12,14 +13,13 @@ import {
SPACING,
StyledText,
TYPOGRAPHY,
+ NoParameters,
} from '@opentrons/components'
import { Banner } from '../../../atoms/Banner'
import { Divider } from '../../../atoms/structure'
// import { Chip } from '../../../atoms/Chip'
-import { NoParameter } from '../../ProtocolDetails/ProtocolParameters/NoParameter'
import { useMostRecentCompletedAnalysis } from '../../LabwarePositionCheck/useMostRecentCompletedAnalysis'
-import { formatRunTimeParameterValue } from '../../ProtocolDetails/ProtocolParameters/utils'
import type { RunTimeParameter } from '@opentrons/shared-data'
@@ -221,7 +221,7 @@ export function ProtocolRunRuntimeParameters({
{!hasParameter ? (
-
+
) : (
<>
diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx
index 368c666d33f..8844f551d08 100644
--- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx
+++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunRuntimeParameters.test.tsx
@@ -3,9 +3,9 @@ import { describe, it, vi, beforeEach, afterEach, expect } from 'vitest'
import { screen } from '@testing-library/react'
import { when } from 'vitest-when'
+import { NoParameters } from '@opentrons/components'
import { renderWithProviders } from '../../../../__testing-utils__'
import { i18n } from '../../../../i18n'
-import { NoParameter } from '../../../ProtocolDetails/ProtocolParameters/NoParameter'
import { useMostRecentCompletedAnalysis } from '../../../LabwarePositionCheck/useMostRecentCompletedAnalysis'
import { ProtocolRunRuntimeParameters } from '../ProtocolRunRunTimeParameters'
@@ -15,7 +15,13 @@ import type {
RunTimeParameter,
} from '@opentrons/shared-data'
-vi.mock('../../../ProtocolDetails/ProtocolParameters/NoParameter')
+vi.mock('@opentrons/components', async importOriginal => {
+ const actual = await importOriginal()
+ return {
+ ...actual,
+ NoParameters: vi.fn(),
+ }
+})
vi.mock('../../../LabwarePositionCheck/useMostRecentCompletedAnalysis')
const RUN_ID = 'mockId'
@@ -88,7 +94,7 @@ describe('ProtocolRunRuntimeParameters', () => {
props = {
runId: RUN_ID,
}
- vi.mocked(NoParameter).mockReturnValue(mock NoParameter
)
+ vi.mocked(NoParameters).mockReturnValue(mock NoParameter
)
when(vi.mocked(useMostRecentCompletedAnalysis))
.calledWith(RUN_ID)
.thenReturn({
diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/ProtocolParameters.test.tsx b/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/ProtocolParameters.test.tsx
index 5e3574200b6..707aa5256cf 100644
--- a/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/ProtocolParameters.test.tsx
+++ b/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/ProtocolParameters.test.tsx
@@ -4,13 +4,10 @@ import { screen } from '@testing-library/react'
import { renderWithProviders } from '../../../../__testing-utils__'
import { i18n } from '../../../../i18n'
-import { NoParameter } from '../NoParameter'
import { ProtocolParameters } from '..'
import type { RunTimeParameter } from '@opentrons/shared-data'
-vi.mock('../NoParameter')
-
const mockRunTimeParameter: RunTimeParameter[] = [
{
displayName: 'Trash Tips',
@@ -87,7 +84,6 @@ describe('ProtocolParameters', () => {
props = {
runTimeParameters: mockRunTimeParameter,
}
- vi.mocked(NoParameter).mockReturnValue(mock NoParameter
)
})
afterEach(() => {
@@ -131,6 +127,6 @@ describe('ProtocolParameters', () => {
runTimeParameters: [],
}
render(props)
- screen.getByText('mock NoParameter')
+ screen.getByText('No parameters specified in this protocol')
})
})
diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx b/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx
index 00dc73793d4..d7a64fd2396 100644
--- a/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx
+++ b/app/src/organisms/ProtocolDetails/ProtocolParameters/index.tsx
@@ -1,18 +1,16 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
-import styled from 'styled-components'
import {
- BORDERS,
DIRECTION_COLUMN,
Flex,
SPACING,
StyledText,
TYPOGRAPHY,
+ ParametersTable,
+ NoParameters,
} from '@opentrons/components'
import { Banner } from '../../../atoms/Banner'
-import { NoParameter } from './NoParameter'
-import { formatRunTimeParameterValue } from './utils'
import type { RunTimeParameter } from '@opentrons/shared-data'
@@ -47,112 +45,11 @@ export function ProtocolParameters({
-
+
) : (
-
+
)}
)
}
-
-interface ProtocolParameterItemsProps {
- runTimeParameters: RunTimeParameter[]
-}
-
-function ProtocolParameterItems({
- runTimeParameters,
-}: ProtocolParameterItemsProps): JSX.Element {
- const { t } = useTranslation('protocol_details')
- const formatRange = (
- runTimeParameter: RunTimeParameter,
- minMax: string
- ): string => {
- const { type } = runTimeParameter
- const choices =
- 'choices' in runTimeParameter ? runTimeParameter.choices : []
- const count = choices.length
-
- switch (type) {
- case 'int':
- case 'float':
- return minMax
- case 'boolean':
- return t('on_off')
- case 'str':
- if (count > 2) {
- return t('choices', { count })
- } else {
- return choices.map(choice => choice.displayName).join(', ')
- }
- }
- return ''
- }
-
- return (
-
-
- {t('name')}
- {t('default_value')}
- {t('range')}
-
-
- {runTimeParameters.map((parameter: RunTimeParameter, index: number) => {
- const min = 'min' in parameter ? parameter.min : 0
- const max = 'max' in parameter ? parameter.max : 0
- return (
-
-
- {parameter.displayName}
-
-
-
- {formatRunTimeParameterValue(parameter, t)}
-
-
-
-
- {formatRange(parameter, `${min}-${max}`)}
-
-
-
- )
- })}
-
-
- )
-}
-
-const StyledTable = styled.table`
- width: 100%;
- border-collapse: collapse;
- text-align: left;
-`
-
-const StyledTableHeader = styled.th`
- ${TYPOGRAPHY.labelSemiBold}
- padding: ${SPACING.spacing8};
- border-bottom: ${BORDERS.lineBorder};
-`
-
-interface StyledTableRowProps {
- isLast: boolean
-}
-
-const StyledTableRow = styled.tr`
- padding: ${SPACING.spacing8};
- border-bottom: ${props => (props.isLast ? 'none' : BORDERS.lineBorder)};
-`
-
-interface StyledTableCellProps {
- isLast: boolean
-}
-
-const StyledTableCell = styled.td`
- padding-left: ${SPACING.spacing8};
- padding-top: ${SPACING.spacing12};
- padding-bottom: ${props => (props.isLast ? 0 : SPACING.spacing12)};
-`
diff --git a/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx b/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx
index 9fac5f99c56..8eea44ba0cd 100644
--- a/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx
+++ b/app/src/organisms/ProtocolSetupParameters/ViewOnlyParameters.tsx
@@ -1,5 +1,6 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
+import { formatRunTimeParameterValue } from '@opentrons/shared-data'
import {
ALIGN_CENTER,
BORDERS,
@@ -16,7 +17,6 @@ import { ChildNavigation } from '../ChildNavigation'
import { Chip } from '../../atoms/Chip'
import { useToaster } from '../ToasterOven'
import { mockData } from './index'
-import { formatRunTimeParameterValue } from '../ProtocolDetails/ProtocolParameters/utils'
import type { SetupScreens } from '../../pages/ProtocolSetup'
diff --git a/app/src/organisms/ProtocolSetupParameters/index.tsx b/app/src/organisms/ProtocolSetupParameters/index.tsx
index d92e54a6234..c99c4ebeff6 100644
--- a/app/src/organisms/ProtocolSetupParameters/index.tsx
+++ b/app/src/organisms/ProtocolSetupParameters/index.tsx
@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
import { useHistory } from 'react-router-dom'
import { useCreateRunMutation, useHost } from '@opentrons/react-api-client'
import { useQueryClient } from 'react-query'
+import { formatRunTimeParameterValue } from '@opentrons/shared-data'
import {
ALIGN_CENTER,
DIRECTION_COLUMN,
@@ -13,7 +14,6 @@ import {
import { ProtocolSetupStep } from '../../pages/ProtocolSetup'
import { ChildNavigation } from '../ChildNavigation'
import { ResetValuesModal } from './ResetValuesModal'
-import { formatRunTimeParameterValue } from '../ProtocolDetails/ProtocolParameters/utils'
import type { RunTimeParameter } from '@opentrons/shared-data'
import type { LabwareOffsetCreateData } from '@opentrons/api-client'
diff --git a/app/src/pages/ProtocolDetails/Parameters.tsx b/app/src/pages/ProtocolDetails/Parameters.tsx
index f2304893374..0e12e8d7997 100644
--- a/app/src/pages/ProtocolDetails/Parameters.tsx
+++ b/app/src/pages/ProtocolDetails/Parameters.tsx
@@ -1,6 +1,7 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
+import { formatRunTimeParameterValue } from '@opentrons/shared-data'
import {
BORDERS,
COLORS,
@@ -13,7 +14,6 @@ import {
import { useToaster } from '../../organisms/ToasterOven'
import { useRunTimeParameters } from '../Protocols/hooks'
import { EmptySection } from './EmptySection'
-import { formatRunTimeParameterValue } from '../../organisms/ProtocolDetails/ProtocolParameters/utils'
import type { RunTimeParameter } from '@opentrons/shared-data'
const Table = styled('table')`
diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/NoParameter.tsx b/components/src/molecules/ParametersTable/NoParameters.tsx
similarity index 52%
rename from app/src/organisms/ProtocolDetails/ProtocolParameters/NoParameter.tsx
rename to components/src/molecules/ParametersTable/NoParameters.tsx
index 2dd3f2d1441..b0afb82530f 100644
--- a/app/src/organisms/ProtocolDetails/ProtocolParameters/NoParameter.tsx
+++ b/components/src/molecules/ParametersTable/NoParameters.tsx
@@ -1,21 +1,16 @@
import * as React from 'react'
-import { useTranslation } from 'react-i18next'
-import {
- ALIGN_CENTER,
- BORDERS,
- COLORS,
- DIRECTION_COLUMN,
- Flex,
- Icon,
- SPACING,
- StyledText,
- TYPOGRAPHY,
-} from '@opentrons/components'
-
-export function NoParameter(): JSX.Element {
- const { t } = useTranslation('protocol_details')
+import { BORDERS, COLORS } from '../../helix-design-system'
+import { SPACING, TYPOGRAPHY } from '../../ui-style-constants/index'
+import { StyledText } from '../../atoms/StyledText'
+import { Icon } from '../../icons'
+import { Flex } from '../../primitives'
+import { ALIGN_CENTER, DIRECTION_COLUMN } from '../../styles'
+interface NoParametersProps {
+ t?: any
+}
+export function NoParameters({ t }: NoParametersProps): JSX.Element {
return (
- {t('no_parameters')}
+ {t != null
+ ? t('no_parameters')
+ : 'No parameters specified in this protocol'}
)
diff --git a/components/src/molecules/ParametersTable/ParametersTable.stories.tsx b/components/src/molecules/ParametersTable/ParametersTable.stories.tsx
new file mode 100644
index 00000000000..ce55f700dc3
--- /dev/null
+++ b/components/src/molecules/ParametersTable/ParametersTable.stories.tsx
@@ -0,0 +1,159 @@
+import * as React from 'react'
+import { ParametersTable } from '@opentrons/components'
+import type { Story, Meta } from '@storybook/react'
+import type { RunTimeParameter } from '@opentrons/shared-data'
+
+export default {
+ title: 'Library/Molecules/ParametersTable',
+} as Meta
+
+const Template: Story> = args => (
+
+)
+
+const runTimeParameters: RunTimeParameter[] = [
+ {
+ value: false,
+ displayName: 'Dry Run',
+ variableName: 'DRYRUN',
+ description: 'Is this a dry or wet run? Wet is true, dry is false',
+ type: 'boolean',
+ default: false,
+ },
+ {
+ value: true,
+ displayName: 'Use Gripper',
+ variableName: 'USE_GRIPPER',
+ description: 'For using the gripper.',
+ type: 'boolean',
+ default: true,
+ },
+ {
+ value: true,
+ displayName: 'Trash Tips',
+ variableName: 'TIP_TRASH',
+ description:
+ 'to throw tip into the trash or to not throw tip into the trash',
+ type: 'boolean',
+ default: true,
+ },
+ {
+ value: true,
+ displayName: 'Deactivate Temperatures',
+ variableName: 'DEACTIVATE_TEMP',
+ description: 'deactivate temperature on the module',
+ type: 'boolean',
+ default: true,
+ },
+ {
+ value: 4,
+ displayName: 'Columns of Samples',
+ variableName: 'COLUMNS',
+ description: 'How many columns do you want?',
+ type: 'int',
+ min: 1,
+ max: 14,
+ default: 4,
+ },
+ {
+ value: 6,
+ displayName: 'PCR Cycles',
+ variableName: 'PCR_CYCLES',
+ description: 'number of PCR cycles on a thermocycler',
+ type: 'int',
+ min: 1,
+ max: 10,
+ default: 6,
+ },
+ {
+ value: 6.5,
+ displayName: 'EtoH Volume',
+ variableName: 'ETOH_VOLUME',
+ description: '70% ethanol volume',
+ type: 'float',
+ suffix: 'mL',
+ min: 1.5,
+ max: 10.0,
+ default: 6.5,
+ },
+ {
+ value: 'none',
+ displayName: 'Default Module Offsets',
+ variableName: 'DEFAULT_OFFSETS',
+ description: 'default module offsets for temp, H-S, and none',
+ type: 'str',
+ choices: [
+ {
+ displayName: 'No offsets',
+ value: 'none',
+ },
+ {
+ displayName: 'temp offset',
+ value: '1',
+ },
+ {
+ displayName: 'heater-shaker offset',
+ value: '2',
+ },
+ ],
+ default: 'none',
+ },
+ {
+ value: 'left',
+ displayName: 'pipette mount',
+ variableName: 'mont',
+ description: 'pipette mount',
+ type: 'str',
+ choices: [
+ {
+ displayName: 'Left',
+ value: 'left',
+ },
+ {
+ displayName: 'Right',
+ value: 'right',
+ },
+ ],
+ default: 'left',
+ },
+ {
+ value: 'flex',
+ displayName: 'short test case',
+ variableName: 'short 2 options',
+ description: 'this play 2 short options',
+ type: 'str',
+ choices: [
+ {
+ displayName: 'OT-2',
+ value: 'ot2',
+ },
+ {
+ displayName: 'Flex',
+ value: 'flex',
+ },
+ ],
+ default: 'flex',
+ },
+ {
+ value: 'flex',
+ displayName: 'long test case',
+ variableName: 'long 2 options',
+ description: 'this play 2 long options',
+ type: 'str',
+ choices: [
+ {
+ displayName: 'I am kind of long text version',
+ value: 'ot2',
+ },
+ {
+ displayName: 'I am kind of long text version. Today is 3/15',
+ value: 'flex',
+ },
+ ],
+ default: 'flex',
+ },
+]
+export const Default = Template.bind({})
+Default.args = {
+ runTimeParameters: runTimeParameters,
+}
diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/NoParameter.test.tsx b/components/src/molecules/ParametersTable/__tests__/NoParameters.test.tsx
similarity index 55%
rename from app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/NoParameter.test.tsx
rename to components/src/molecules/ParametersTable/__tests__/NoParameters.test.tsx
index 40cfb8f48de..5b2e7f2927d 100644
--- a/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/NoParameter.test.tsx
+++ b/components/src/molecules/ParametersTable/__tests__/NoParameters.test.tsx
@@ -2,28 +2,25 @@ import * as React from 'react'
import { screen } from '@testing-library/react'
import { describe, it, expect } from 'vitest'
-import { BORDERS, COLORS } from '@opentrons/components'
+import { renderWithProviders } from '../../../testing/utils'
+import { BORDERS, COLORS } from '../../../helix-design-system'
+import { NoParameters } from '../NoParameters'
-import { renderWithProviders } from '../../../../__testing-utils__'
-import { i18n } from '../../../../i18n'
-
-import { NoParameter } from '../NoParameter'
-
-const render = () => {
- return renderWithProviders(, {
- i18nInstance: i18n,
- })
+const render = (props: React.ComponentProps) => {
+ return renderWithProviders()
}
-describe('NoParameter', () => {
+const tMock = (key: string) => key
+
+describe('NoParameters', () => {
it('should render text and icon with proper color', () => {
- render()
+ render({})
screen.getByLabelText('alert')
screen.getByText('No parameters specified in this protocol')
})
it('should have proper styles', () => {
- render()
+ render({})
expect(screen.getByTestId('NoRunTimeParameter')).toHaveStyle(
`background-color: ${COLORS.grey30}`
)
@@ -34,4 +31,11 @@ describe('NoParameter', () => {
`color: ${COLORS.grey60}`
)
})
+
+ it('should render the raw i18n value if a t is provided', () => {
+ render({
+ t: tMock,
+ })
+ screen.getByText('no_parameters')
+ })
})
diff --git a/components/src/molecules/ParametersTable/__tests__/ParametersTable.test.tsx b/components/src/molecules/ParametersTable/__tests__/ParametersTable.test.tsx
new file mode 100644
index 00000000000..1c9cd2d571c
--- /dev/null
+++ b/components/src/molecules/ParametersTable/__tests__/ParametersTable.test.tsx
@@ -0,0 +1,119 @@
+import * as React from 'react'
+import { renderWithProviders } from '../../../testing/utils'
+import { describe, it, beforeEach } from 'vitest'
+import { screen } from '@testing-library/react'
+import { ParametersTable } from '../index'
+
+import type { RunTimeParameter } from '@opentrons/shared-data'
+
+const tMock = (key: string) => key
+const mockRunTimeParameter: RunTimeParameter[] = [
+ {
+ displayName: 'Trash Tips',
+ variableName: 'TIP_TRASH',
+ description:
+ 'to throw tip into the trash or to not throw tip into the trash',
+ type: 'boolean',
+ default: true,
+ value: true,
+ },
+ {
+ displayName: 'EtoH Volume',
+ variableName: 'ETOH_VOLUME',
+ description: '70% ethanol volume',
+ type: 'float',
+ suffix: 'mL',
+ min: 1.5,
+ max: 10.0,
+ default: 6.5,
+ value: 6.5,
+ },
+ {
+ displayName: 'Default Module Offsets',
+ variableName: 'DEFAULT_OFFSETS',
+ description: 'default module offsets for temp, H-S, and none',
+ type: 'str',
+ value: 'none',
+ choices: [
+ {
+ displayName: 'No offsets',
+ value: 'none',
+ },
+ {
+ displayName: 'temp offset',
+ value: '1',
+ },
+ {
+ displayName: 'heater-shaker offset',
+ value: '2',
+ },
+ ],
+ default: 'none',
+ },
+ {
+ displayName: 'pipette mount',
+ variableName: 'mont',
+ description: 'pipette mount',
+ type: 'str',
+ value: 'left',
+ choices: [
+ {
+ displayName: 'Left',
+ value: 'left',
+ },
+ {
+ displayName: 'Right',
+ value: 'right',
+ },
+ ],
+ default: 'left',
+ },
+]
+
+const render = (props: React.ComponentProps) => {
+ return renderWithProviders()
+}
+
+describe('ParametersTabl', () => {
+ let props: React.ComponentProps
+
+ beforeEach(() => {
+ props = {
+ runTimeParameters: mockRunTimeParameter,
+ }
+ })
+
+ it('should render table header', () => {
+ render(props)
+ screen.getByText('Name')
+ screen.getByText('Default Value')
+ screen.getByText('Range')
+ })
+
+ it('should render parameters default information', () => {
+ render(props)
+ screen.getByText('Trash Tips')
+ screen.getByText('On')
+ screen.getByText('On, off')
+
+ screen.getByText('EtoH Volume')
+ screen.getByText('6.5 mL')
+ screen.getByText('1.5-10')
+
+ screen.getByText('Default Module Offsets')
+ screen.getByText('No offsets')
+ screen.getByText('3 choices')
+
+ screen.getByText('pipette mount')
+ screen.getByText('Left')
+ screen.getByText('Left, Right')
+ })
+
+ it('should render the raw i18n values if a t prop is provided', () => {
+ props.t = tMock
+ render(props)
+ screen.getByText('name')
+ screen.getByText('default_value')
+ screen.getByText('range')
+ })
+})
diff --git a/components/src/molecules/ParametersTable/index.tsx b/components/src/molecules/ParametersTable/index.tsx
new file mode 100644
index 00000000000..4ff5cdeeb18
--- /dev/null
+++ b/components/src/molecules/ParametersTable/index.tsx
@@ -0,0 +1,117 @@
+import * as React from 'react'
+import styled from 'styled-components'
+import { formatRunTimeParameterValue } from '@opentrons/shared-data'
+import { BORDERS } from '../../helix-design-system'
+import { SPACING, TYPOGRAPHY } from '../../ui-style-constants/index'
+import { StyledText } from '../../atoms/StyledText'
+
+import type { RunTimeParameter } from '@opentrons/shared-data'
+
+interface ProtocolParameterItemsProps {
+ runTimeParameters: RunTimeParameter[]
+ t?: any
+}
+
+/** used in both the desktop app and Protocol Library
+ * to display the run time parameters table
+ */
+export function ParametersTable({
+ runTimeParameters,
+ t,
+}: ProtocolParameterItemsProps): JSX.Element {
+ const formatRange = (
+ runTimeParameter: RunTimeParameter,
+ minMax: string
+ ): string => {
+ const { type } = runTimeParameter
+ const choices =
+ 'choices' in runTimeParameter ? runTimeParameter.choices : []
+ const count = choices.length
+
+ switch (type) {
+ case 'int':
+ case 'float':
+ return minMax
+ case 'boolean':
+ return t != null ? t('on_off') : 'On, off'
+ case 'str':
+ if (count > 2) {
+ return t != null ? t('choices', { count }) : `${count} choices`
+ } else {
+ return choices.map(choice => choice.displayName).join(', ')
+ }
+ }
+ return ''
+ }
+
+ return (
+
+
+ {t != null ? t('name') : 'Name'}
+
+ {t != null ? t('default_value') : 'Default Value'}
+
+
+ {t != null ? t('range') : 'Range'}
+
+
+
+ {runTimeParameters.map((parameter: RunTimeParameter, index: number) => {
+ const min = 'min' in parameter ? parameter.min : 0
+ const max = 'max' in parameter ? parameter.max : 0
+ return (
+
+
+ {parameter.displayName}
+
+
+
+ {formatRunTimeParameterValue(parameter, t)}
+
+
+
+
+ {formatRange(parameter, `${min}-${max}`)}
+
+
+
+ )
+ })}
+
+
+ )
+}
+
+const StyledTable = styled.table`
+ width: 100%;
+ border-collapse: collapse;
+ text-align: left;
+`
+
+const StyledTableHeader = styled.th`
+ ${TYPOGRAPHY.labelSemiBold}
+ padding: ${SPACING.spacing8};
+ border-bottom: ${BORDERS.lineBorder};
+`
+
+interface StyledTableRowProps {
+ isLast: boolean
+}
+
+const StyledTableRow = styled.tr`
+ padding: ${SPACING.spacing8};
+ border-bottom: ${props => (props.isLast ? 'none' : BORDERS.lineBorder)};
+`
+
+interface StyledTableCellProps {
+ isLast: boolean
+}
+
+const StyledTableCell = styled.td`
+ padding-left: ${SPACING.spacing8};
+ padding-top: ${SPACING.spacing12};
+ padding-bottom: ${props => (props.isLast ? 0 : SPACING.spacing12)};
+`
diff --git a/components/src/molecules/index.tsx b/components/src/molecules/index.tsx
index ce1c0c63e31..3231c2f93a9 100644
--- a/components/src/molecules/index.tsx
+++ b/components/src/molecules/index.tsx
@@ -1,2 +1,4 @@
export * from './LocationIcon'
export * from './RoundTab'
+export * from './ParametersTable'
+export * from './ParametersTable/NoParameters'
diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/utils.test.ts b/shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts
similarity index 88%
rename from app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/utils.test.ts
rename to shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts
index 66eddcc0efd..bfdad493913 100644
--- a/app/src/organisms/ProtocolDetails/ProtocolParameters/__tests__/utils.test.ts
+++ b/shared-data/js/helpers/__tests__/formatRunTimeParameterValue.test.ts
@@ -1,8 +1,7 @@
-import { useTranslation } from 'react-i18next'
import { describe, it, expect, vi } from 'vitest'
-import { formatRunTimeParameterValue } from '../utils'
+import { formatRunTimeParameterValue } from '../formatRunTimeParameterValue'
-import type { RunTimeParameter } from '@opentrons/shared-data'
+import type { RunTimeParameter } from '../../types'
const capitalizeFirstLetter = (str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1)
@@ -10,14 +9,6 @@ const capitalizeFirstLetter = (str: string): string => {
const mockTFunction = vi.fn(str => capitalizeFirstLetter(str))
-vi.mock('react-i18next', async importOriginal => {
- const actual = await importOriginal()
- return {
- ...actual,
- t: mockTFunction,
- }
-})
-
describe('utils-formatRunTimeParameterValue', () => {
it('should return value with suffix when type is int', () => {
const mockData = {
diff --git a/app/src/organisms/ProtocolDetails/ProtocolParameters/utils.ts b/shared-data/js/helpers/formatRunTimeParameterValue.ts
similarity index 79%
rename from app/src/organisms/ProtocolDetails/ProtocolParameters/utils.ts
rename to shared-data/js/helpers/formatRunTimeParameterValue.ts
index b21b3eaf3c7..ffbab087849 100644
--- a/app/src/organisms/ProtocolDetails/ProtocolParameters/utils.ts
+++ b/shared-data/js/helpers/formatRunTimeParameterValue.ts
@@ -1,9 +1,8 @@
-import { useTranslation } from 'react-i18next'
-import type { RunTimeParameter } from '@opentrons/shared-data'
+import { RunTimeParameter } from '../types'
export const formatRunTimeParameterValue = (
runTimeParameter: RunTimeParameter,
- t: ReturnType['t']
+ t?: any
): string => {
const { type, default: defaultValue } = runTimeParameter
const suffix =
@@ -17,7 +16,11 @@ export const formatRunTimeParameterValue = (
? `${defaultValue.toString()} ${suffix}`
: defaultValue.toString()
case 'boolean':
- return Boolean(defaultValue) ? t('on') : t('off')
+ if (t != null) {
+ return Boolean(defaultValue) ? t('on') : t('off')
+ } else {
+ return Boolean(defaultValue) ? 'On' : 'Off'
+ }
case 'str':
if ('choices' in runTimeParameter && runTimeParameter.choices != null) {
const choice = runTimeParameter.choices.find(
diff --git a/shared-data/js/helpers/index.ts b/shared-data/js/helpers/index.ts
index 5cddd22336e..2d78f16ca1f 100644
--- a/shared-data/js/helpers/index.ts
+++ b/shared-data/js/helpers/index.ts
@@ -28,6 +28,7 @@ export * from './getOccludedSlotCountForModule'
export * from './labwareInference'
export * from './getAddressableAreasInProtocol'
export * from './getSimplestFlexDeckConfig'
+export * from './formatRunTimeParameterValue'
export const getLabwareDefIsStandard = (def: LabwareDefinition2): boolean =>
def?.namespace === OPENTRONS_LABWARE_NAMESPACE