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(app): display alert-circle in robot tab if any calibration is marked bad #6948

Merged
merged 4 commits into from
Nov 9, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
9 changes: 7 additions & 2 deletions app/src/components/Navbar/NavbarLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,18 @@ export function NavbarLink(props: NavbarLinkProps): React.Node {
iconName,
disabledReason,
notificationReason,
warningReason,
...styleProps
} = props

const [targetProps, tooltipProps] = useHoverTooltip({
placement: TOOLTIP_RIGHT,
})
const tooltipContents = disabledReason ?? notificationReason ?? null
const tooltipContents =
disabledReason ?? notificationReason ?? warningReason ?? null
const hasNotification = Boolean(notificationReason)
const isDisabled = Boolean(disabledReason)
const hasWarning = Boolean(warningReason)

const LinkComponent = isDisabled ? 'div' : NavLink
const linkProps = isDisabled ? styleProps : { to: path, ...styleProps }
Expand All @@ -84,7 +87,9 @@ export function NavbarLink(props: NavbarLinkProps): React.Node {
>
<NotificationIcon
name={iconName}
childName={hasNotification ? 'circle' : null}
childName={
hasNotification ? 'circle' : hasWarning ? 'alert-circle' : null
}
width="100%"
paddingX={SPACING_2}
/>
Expand Down
14 changes: 14 additions & 0 deletions app/src/components/Navbar/__tests__/NavbarLink.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,20 @@ describe('NavbarLink component', () => {
expect(icon.prop('childName')).toBe('circle')
})

it('should render a warning if there is a reason to', () => {
const wrapper = render({
id: 'foo',
path: '/foo',
title: 'Foo',
iconName: 'alert',
warningReason: 'hello',
})
const icon = wrapper.find(NotificationIcon)

expect(icon.prop('name')).toBe('alert')
expect(icon.prop('childName')).toBe('alert-circle')
})

it('should render the link title', () => {
const wrapper = render({
id: 'foo',
Expand Down
6 changes: 5 additions & 1 deletion app/src/nav/__tests__/selectors.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const EXPECTED_ROBOTS = {
title: 'Robot',
iconName: 'ot-connect',
notificationReason: null,
warningReason: null,
}

const EXPECTED_UPLOAD = {
Expand Down Expand Up @@ -295,7 +296,10 @@ describe('nav selectors', () => {
mockGetDeckCalibrationStatus.mockReturnValue(DECK_CAL_STATUS_IDENTITY)
},
expected: [
EXPECTED_ROBOTS,
{
...EXPECTED_ROBOTS,
warningReason: expect.stringMatching(/Robot calibration recommended/),
},
{
...EXPECTED_UPLOAD,
disabledReason: expect.stringMatching(/calibrate your deck/i),
Expand Down
27 changes: 26 additions & 1 deletion app/src/nav/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { getConnectedRobot } from '../discovery'
import {
getProtocolPipettesMatching,
getProtocolPipettesCalibrated,
getAttachedPipetteCalibrations,
PIPETTE_MOUNTS,
} from '../pipettes'
import { selectors as RobotSelectors } from '../robot'
import { UPGRADE, getBuildrootUpdateAvailable } from '../buildroot'
Expand Down Expand Up @@ -41,6 +43,7 @@ const CALIBRATE_DECK_TO_PROCEED = 'Calibrate your deck to proceed'
const APP_UPDATE_AVAILABLE = 'An app update is available'
const DRIVER_UPDATE_AVAILABLE = 'A driver update is available'
const ROBOT_UPDATE_AVAILABLE = 'A robot software update is available'
const ROBOT_CALIBRATION_RECOMMENDED = 'Robot calibration recommended'

const getConnectedRobotPipettesMatch = (state: State): boolean => {
const connectedRobot = getConnectedRobot(state)
Expand Down Expand Up @@ -75,6 +78,25 @@ const getDeckCalibrationOk = (state: State): boolean => {
return deckCalStatus === DECK_CAL_STATUS_OK
}

const getRobotCalibrationOk = (state: State): boolean => {
const connectedRobot = getConnectedRobot(state)
if (!connectedRobot) return false

const deckCalOk = getDeckCalibrationOk(state)
const pipCal = getAttachedPipetteCalibrations(state, connectedRobot.name)
for (const m of PIPETTE_MOUNTS) {
if (pipCal) {
if (
pipCal[m]?.offset?.status?.markedBad ||
pipCal[m]?.tipLength?.status?.markedBad
) {
return false
}
}
}
return deckCalOk
}

const getRunDisabledReason: State => string | null = createSelector(
getConnectedRobot,
RobotSelectors.getSessionIsLoaded,
Expand All @@ -94,13 +116,16 @@ const getRunDisabledReason: State => string | null = createSelector(
)

export const getRobotsLocation: State => NavLocation = createSelector(
getConnectedRobot,
getConnectedRobotUpdateAvailable,
update => ({
getRobotCalibrationOk,
(robot, update, robotCalOk) => ({
id: 'robots',
path: '/robots',
title: ROBOT,
iconName: 'ot-connect',
notificationReason: update ? ROBOT_UPDATE_AVAILABLE : null,
warningReason: robot && !robotCalOk ? ROBOT_CALIBRATION_RECOMMENDED : null,
})
)

Expand Down
1 change: 1 addition & 0 deletions app/src/nav/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type NavLocation = {|
iconName: IconName,
disabledReason?: string | null,
notificationReason?: string | null,
warningReason?: string | null,
|}

export type SubnavLocation = {|
Expand Down