-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(app): add desktop modal for incompatible modules
feat(app): IncompatibleModules on desktop Display a modal on the desktop app if incompatible modules are attached to the robot you're currently viewing. This modal allows interaction with the navbar but otherwise is displayed at any time that the app is viewing a specific robot (i.e. prepare for run, device details) and that robot has incompatible modules attached.
- Loading branch information
Showing
6 changed files
with
238 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
{ | ||
"incompatible_modules_attached": "incompatible module detected", | ||
"remove_before_running_protocol": "Remove the following hardware before running a protocol:" | ||
"remove_before_running_protocol": "Remove the following hardware before running a protocol:", | ||
"needs_your_assistance": "{{robot_name}} needs your assistance", | ||
"remove_before_using": "You must remove incompatible modules before using this robot.", | ||
"is_not_compatible": "{{module_name}} is not compatible with the {{robot_type}}" | ||
} |
92 changes: 92 additions & 0 deletions
92
app/src/organisms/IncompatibleModule/IncompatibleModuleDesktopModalBody.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import * as React from 'react' | ||
import { useTranslation, Trans } from 'react-i18next' | ||
import { | ||
DIRECTION_COLUMN, | ||
DIRECTION_ROW, | ||
ALIGN_CENTER, | ||
JUSTIFY_FLEX_START, | ||
Flex, | ||
SPACING, | ||
StyledText, | ||
TYPOGRAPHY, | ||
OVERFLOW_SCROLL, | ||
Icon, | ||
COLORS, | ||
} from '@opentrons/components' | ||
import { getModuleDisplayName } from '@opentrons/shared-data' | ||
import type { AttachedModule } from '@opentrons/api-client' | ||
import { useIsFlex } from '../Devices/hooks' | ||
import { InterventionModal } from '../../molecules/InterventionModal' | ||
export interface IncompatibleModuleDesktopModalBodyProps { | ||
modules: AttachedModule[] | ||
robotName: string | ||
} | ||
|
||
export function IncompatibleModuleDesktopModalBody({ | ||
modules, | ||
robotName, | ||
}: IncompatibleModuleDesktopModalBodyProps): JSX.Element { | ||
const { t } = useTranslation('incompatible_modules') | ||
const isFlex = useIsFlex(robotName) | ||
const displayName = isFlex ? 'Flex' : 'OT-2' | ||
return ( | ||
<InterventionModal | ||
heading={ | ||
<Trans | ||
as="h4" | ||
fontSize={TYPOGRAPHY.fontSizeH4} | ||
t={t} | ||
i18nKey="needs_your_assistance" | ||
values={{ robot_name: robotName }} | ||
/> | ||
} | ||
type="error" | ||
> | ||
<Flex flexDirection={DIRECTION_COLUMN} padding={SPACING.spacing32}> | ||
<Flex | ||
overflowY={OVERFLOW_SCROLL} | ||
flexDirection={DIRECTION_COLUMN} | ||
gridGap={SPACING.spacing12} | ||
maxHeight="196px" | ||
as="ul" | ||
> | ||
{...modules.map(module => ( | ||
<li key={module.id}> | ||
<Flex | ||
flexDirection={DIRECTION_ROW} | ||
width="100%" | ||
justifyContent={JUSTIFY_FLEX_START} | ||
alignItems={ALIGN_CENTER} | ||
paddingBottom={SPACING.spacing12} | ||
> | ||
<Icon | ||
name="alert-circle" | ||
size={SPACING.spacing32} | ||
color={COLORS.red50} | ||
/> | ||
<StyledText | ||
as="p" | ||
key={module.id} | ||
fontWeight={TYPOGRAPHY.fontWeightSemiBold} | ||
paddingLeft={SPACING.spacing12} | ||
> | ||
<Trans | ||
i18nKey="is_not_compatible" | ||
values={{ | ||
module_name: getModuleDisplayName(module.moduleModel), | ||
robot_type: displayName, | ||
}} | ||
t={t} | ||
/> | ||
</StyledText> | ||
</Flex> | ||
</li> | ||
))} | ||
</Flex> | ||
<StyledText as="p" paddingTop={SPACING.spacing12}> | ||
<Trans t={t} i18nKey="remove_before_using" /> | ||
</StyledText> | ||
</Flex> | ||
</InterventionModal> | ||
) | ||
} |
27 changes: 17 additions & 10 deletions
27
app/src/organisms/IncompatibleModule/IncompatibleModuleTakeover.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,40 @@ | ||
import * as React from 'react' | ||
import { createPortal } from 'react-dom' | ||
import { IncompatibleModuleODDModalBody } from './IncompatibleModuleODDModalBody' | ||
import { IncompatibleModuleDesktopModalBody } from './IncompatibleModuleDesktopModalBody' | ||
import { getTopPortalEl, getModalPortalEl } from '../../App/portal' | ||
import { useIncompatibleModulesAttached } from './hooks' | ||
|
||
const POLL_INTERVAL_MS = 5000 | ||
|
||
export interface IncompatibleModuleTakeoverProps { | ||
isOnDevice: boolean | ||
robotName?: string | ||
} | ||
|
||
export function IncompatibleModuleTakeover({ | ||
isOnDevice, | ||
robotName, | ||
}: IncompatibleModuleTakeoverProps): JSX.Element { | ||
const incompatibleModules = useIncompatibleModulesAttached({ | ||
refetchInterval: POLL_INTERVAL_MS, | ||
}) | ||
return ( | ||
<> | ||
{incompatibleModules.length !== 0 ? ( | ||
isOnDevice ? ( | ||
createPortal( | ||
<IncompatibleModuleODDModalBody modules={incompatibleModules} />, | ||
getTopPortalEl() | ||
) | ||
) : ( | ||
<></> | ||
) | ||
) : null} | ||
{incompatibleModules.length !== 0 | ||
? isOnDevice | ||
? createPortal( | ||
<IncompatibleModuleODDModalBody modules={incompatibleModules} />, | ||
getTopPortalEl() | ||
) | ||
: createPortal( | ||
<IncompatibleModuleDesktopModalBody | ||
modules={incompatibleModules} | ||
robotName={robotName ?? ''} | ||
/>, | ||
getModalPortalEl() | ||
) | ||
: null} | ||
</> | ||
) | ||
} |
54 changes: 54 additions & 0 deletions
54
app/src/organisms/IncompatibleModule/__tests__/IncompatibleModuleDesktopModalBody.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import React from 'react' | ||
import { screen } from '@testing-library/react' | ||
import { describe, it, beforeEach, vi } from 'vitest' | ||
import { when } from 'vitest-when' | ||
import '@testing-library/jest-dom/vitest' | ||
import { renderWithProviders } from '../../../__testing-utils__' | ||
import { i18n } from '../../../i18n' | ||
import { IncompatibleModuleDesktopModalBody } from '../IncompatibleModuleDesktopModalBody' | ||
import { useIsFlex } from '../../Devices/hooks' | ||
import * as Fixtures from '../__fixtures__' | ||
|
||
vi.mock('../../Devices/hooks') | ||
|
||
const getRenderer = (isFlex: boolean) => { | ||
when(useIsFlex).calledWith('otie').thenReturn(isFlex) | ||
return ( | ||
props: React.ComponentProps<typeof IncompatibleModuleDesktopModalBody> | ||
) => { | ||
return renderWithProviders( | ||
<IncompatibleModuleDesktopModalBody {...props} />, | ||
{ | ||
i18nInstance: i18n, | ||
} | ||
)[0] | ||
} | ||
} | ||
|
||
describe('IncompatibleModuleDesktopModalBody', () => { | ||
let props: React.ComponentProps<typeof IncompatibleModuleDesktopModalBody> | ||
beforeEach(() => { | ||
props = { | ||
modules: [], | ||
robotName: 'otie', | ||
} | ||
}) | ||
|
||
it('should render i18nd footer text', () => { | ||
props = { ...props, modules: Fixtures.oneIncompatibleModule as any } | ||
getRenderer(true)(props) | ||
screen.getByText( | ||
'You must remove incompatible modules before using this robot.' | ||
) | ||
screen.getByText('otie needs your assistance') | ||
}) | ||
;['Flex', 'OT-2'].forEach(robotKind => | ||
it(`should render a module card that says ${robotKind}`, () => { | ||
props = { ...props, modules: Fixtures.oneIncompatibleModule as any } | ||
getRenderer(robotKind === 'Flex')(props) | ||
screen.getByText( | ||
`Thermocycler Module GEN1 is not compatible with the ${robotKind}` | ||
) | ||
}) | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters