|
1 | 1 | import * as React from 'react'
|
2 | 2 | import { useTranslation } from 'react-i18next'
|
3 |
| - |
| 3 | +import styled, { css } from 'styled-components' |
4 | 4 | import {
|
5 | 5 | Box,
|
6 | 6 | Flex,
|
7 | 7 | ALIGN_CENTER,
|
8 |
| - JUSTIFY_SPACE_BETWEEN, |
| 8 | + COLORS, |
| 9 | + BORDERS, |
9 | 10 | SPACING,
|
10 | 11 | TYPOGRAPHY,
|
| 12 | + DIRECTION_COLUMN, |
| 13 | + POSITION_RELATIVE, |
| 14 | + ALIGN_FLEX_END, |
| 15 | + POSITION_ABSOLUTE, |
| 16 | + useOnClickOutside, |
11 | 17 | } from '@opentrons/components'
|
12 |
| - |
| 18 | +import { useMenuHandleClickOutside } from '../../atoms/MenuList/hooks' |
| 19 | +import { OverflowBtn } from '../../atoms/MenuList/OverflowBtn' |
| 20 | +import { MenuItem } from '../../atoms/MenuList/MenuItem' |
13 | 21 | import { StyledText } from '../../atoms/text'
|
| 22 | +import { GripperWizardFlows } from '../../organisms/GripperWizardFlows' |
| 23 | +import { formatLastCalibrated } from './CalibrationDetails/utils' |
| 24 | +import type { GripperData } from '@opentrons/api-client' |
14 | 25 |
|
15 |
| -export function RobotSettingsGripperCalibration(): JSX.Element { |
16 |
| - const { t } = useTranslation('device_settings') |
| 26 | +const StyledTable = styled.table` |
| 27 | + width: 100%; |
| 28 | + border-collapse: collapse; |
| 29 | + text-align: ${TYPOGRAPHY.textAlignLeft}; |
| 30 | +` |
| 31 | +const StyledTableHeader = styled.th` |
| 32 | + ${TYPOGRAPHY.labelSemiBold} |
| 33 | + padding: ${SPACING.spacing8}; |
| 34 | +` |
| 35 | +const StyledTableRow = styled.tr` |
| 36 | + padding: ${SPACING.spacing8}; |
| 37 | + border-bottom: ${BORDERS.lineBorder}; |
| 38 | +` |
| 39 | +const StyledTableCell = styled.td` |
| 40 | + padding: ${SPACING.spacing8}; |
| 41 | + text-overflow: wrap; |
| 42 | +` |
| 43 | + |
| 44 | +const BODY_STYLE = css` |
| 45 | + box-shadow: 0 0 0 1px ${COLORS.medGreyEnabled}; |
| 46 | + border-radius: 3px; |
| 47 | +` |
17 | 48 |
|
| 49 | +export interface RobotSettingsGripperCalibrationProps { |
| 50 | + gripper: GripperData |
| 51 | +} |
| 52 | + |
| 53 | +export function RobotSettingsGripperCalibration( |
| 54 | + props: RobotSettingsGripperCalibrationProps |
| 55 | +): JSX.Element { |
| 56 | + const { t } = useTranslation('device_settings') |
| 57 | + const { gripper } = props |
| 58 | + const { |
| 59 | + menuOverlay, |
| 60 | + handleOverflowClick, |
| 61 | + showOverflowMenu, |
| 62 | + setShowOverflowMenu, |
| 63 | + } = useMenuHandleClickOutside() |
| 64 | + const calsOverflowWrapperRef = useOnClickOutside<HTMLDivElement>({ |
| 65 | + onClickOutside: () => setShowOverflowMenu(false), |
| 66 | + }) |
| 67 | + const [showWizardFlow, setShowWizardFlow] = React.useState<boolean>(false) |
| 68 | + const gripperCalibrationLastModified = |
| 69 | + gripper.data.calibratedOffset?.last_modified |
18 | 70 | return (
|
19 | 71 | <Box paddingTop={SPACING.spacing24} paddingBottom={SPACING.spacing4}>
|
20 |
| - <Flex alignItems={ALIGN_CENTER} justifyContent={JUSTIFY_SPACE_BETWEEN}> |
21 |
| - <Box marginRight={SPACING.spacing32}> |
22 |
| - <Box css={TYPOGRAPHY.h3SemiBold} marginBottom={SPACING.spacing8}> |
23 |
| - {t('gripper_calibration_title')} |
24 |
| - </Box> |
25 |
| - <StyledText as="p" marginBottom={SPACING.spacing8}> |
26 |
| - {t('gripper_calibration_description')} |
27 |
| - </StyledText> |
28 |
| - </Box> |
29 |
| - </Flex> |
| 72 | + <Box css={TYPOGRAPHY.h3SemiBold} marginBottom={SPACING.spacing8}> |
| 73 | + {t('gripper_calibration_title')} |
| 74 | + </Box> |
| 75 | + <StyledText as="p" marginBottom={SPACING.spacing8}> |
| 76 | + {t('gripper_calibration_description')} |
| 77 | + </StyledText> |
| 78 | + <StyledTable> |
| 79 | + <thead> |
| 80 | + <tr> |
| 81 | + <StyledTableHeader>{t('gripper_serial')}</StyledTableHeader> |
| 82 | + <StyledTableHeader>{t('last_calibrated_label')}</StyledTableHeader> |
| 83 | + </tr> |
| 84 | + </thead> |
| 85 | + <tbody css={BODY_STYLE}> |
| 86 | + <StyledTableRow> |
| 87 | + <StyledTableCell> |
| 88 | + <StyledText as="p">{gripper.serialNumber}</StyledText> |
| 89 | + </StyledTableCell> |
| 90 | + <StyledTableCell> |
| 91 | + <Flex alignItems={ALIGN_CENTER}> |
| 92 | + {gripperCalibrationLastModified != null ? ( |
| 93 | + <StyledText as="p"> |
| 94 | + {formatLastCalibrated(gripperCalibrationLastModified)} |
| 95 | + </StyledText> |
| 96 | + ) : ( |
| 97 | + <StyledText as="p">{t('not_calibrated_short')}</StyledText> |
| 98 | + )} |
| 99 | + </Flex> |
| 100 | + </StyledTableCell> |
| 101 | + <StyledTableCell> |
| 102 | + <Flex |
| 103 | + flexDirection={DIRECTION_COLUMN} |
| 104 | + position={POSITION_RELATIVE} |
| 105 | + > |
| 106 | + <OverflowBtn |
| 107 | + alignSelf={ALIGN_FLEX_END} |
| 108 | + aria-label="CalibrationOverflowMenu_button_gripperCalibration" |
| 109 | + onClick={handleOverflowClick} |
| 110 | + /> |
| 111 | + {showWizardFlow ? ( |
| 112 | + <GripperWizardFlows |
| 113 | + flowType={'RECALIBRATE'} |
| 114 | + attachedGripper={gripper} |
| 115 | + closeFlow={() => setShowWizardFlow(false)} |
| 116 | + /> |
| 117 | + ) : null} |
| 118 | + {showOverflowMenu ? ( |
| 119 | + <Flex |
| 120 | + ref={calsOverflowWrapperRef} |
| 121 | + whiteSpace="nowrap" |
| 122 | + zIndex={10} |
| 123 | + borderRadius="4px 4px 0px 0px" |
| 124 | + boxShadow="0px 1px 3px rgba(0, 0, 0, 0.2)" |
| 125 | + position={POSITION_ABSOLUTE} |
| 126 | + backgroundColor={COLORS.white} |
| 127 | + top="2.3rem" |
| 128 | + right={0} |
| 129 | + flexDirection={DIRECTION_COLUMN} |
| 130 | + > |
| 131 | + <MenuItem onClick={() => setShowWizardFlow(true)}> |
| 132 | + {t( |
| 133 | + gripperCalibrationLastModified == null |
| 134 | + ? 'calibrate_gripper' |
| 135 | + : 'recalibrate_gripper' |
| 136 | + )} |
| 137 | + </MenuItem> |
| 138 | + </Flex> |
| 139 | + ) : null} |
| 140 | + {menuOverlay} |
| 141 | + </Flex> |
| 142 | + </StyledTableCell> |
| 143 | + </StyledTableRow> |
| 144 | + </tbody> |
| 145 | + </StyledTable> |
30 | 146 | </Box>
|
31 | 147 | )
|
32 | 148 | }
|
0 commit comments