Skip to content
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
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"react": "16.8.6",
"react-dom": "16.8.6",
"react-hot-loader": "4.12.19",
"react-redux": "7.1.0",
"react-redux": "7.2.1",
"react-router-dom": "5.1.1",
"redux": "4.0.5",
"redux-observable": "1.1.0",
Expand Down
3 changes: 3 additions & 0 deletions app/src/alerts/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
export const ALERT_U2E_DRIVER_OUTDATED: 'u2eDriverOutdated' =
'u2eDriverOutdated'

export const ALERT_APP_UPDATE_AVAILABLE: 'appUpdateAvailable' =
'appUpdateAvailable'

// action types
export const ALERT_TRIGGERED: 'alerts:ALERT_TRIGGERED' =
'alerts:ALERT_TRIGGERED'
Expand Down
3 changes: 2 additions & 1 deletion app/src/alerts/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import typeof {
ALERT_U2E_DRIVER_OUTDATED,
ALERT_APP_UPDATE_AVAILABLE,
ALERT_TRIGGERED,
ALERT_DISMISSED,
} from './constants.js'

export type AlertId = ALERT_U2E_DRIVER_OUTDATED
export type AlertId = ALERT_U2E_DRIVER_OUTDATED | ALERT_APP_UPDATE_AVAILABLE

export type AlertTriggeredAction = {|
type: ALERT_TRIGGERED,
Expand Down
47 changes: 28 additions & 19 deletions app/src/components/Alerts/__tests__/Alerts.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// @flow
import * as React from 'react'
import { Provider } from 'react-redux'
import { mount } from 'enzyme'
import noop from 'lodash/noop'

import { mountWithStore } from '@opentrons/components/__utils__'
import * as AppAlerts from '../../../alerts'
import { Alerts } from '..'
import { LostConnectionAlert } from '../../LostConnectionAlert'
import { AnalyticsSettingsModal } from '../../analytics-settings'
import { U2EDriverOutdatedAlert } from '../U2EDriverOutdatedAlert'
import { UpdateAppModal } from '../../app-settings'

import type { State } from '../../../types'
import type { AlertId } from '../../../alerts/types'
Expand All @@ -25,25 +24,20 @@ jest.mock('../U2EDriverOutdatedAlert', () => ({
U2EDriverOutdatedAlert: () => <></>,
}))

jest.mock('../../app-settings', () => ({
UpdateAppModal: () => <></>,
}))

jest.mock('../../../alerts/selectors')

const getActiveAlerts: JestMockFn<[State], $ReadOnlyArray<AlertId>> =
AppAlerts.getActiveAlerts

describe('app-wide Alerts component', () => {
const dispatch = jest.fn()
const MOCK_STATE: State = ({ mockState: true }: any)
const MOCK_STORE = {
dispatch,
getState: () => MOCK_STATE,
subscribe: noop,
}
const MOCK_STATE: State = ({ mockState: true }: any)

describe('app-wide Alerts component', () => {
const render = () => {
return mount(<Alerts />, {
wrappingComponent: Provider,
wrappingComponentProps: { store: MOCK_STORE },
})
return mountWithStore(<Alerts />, { initialState: MOCK_STATE })
}

const stubActiveAlerts = alertIds => {
Expand All @@ -64,19 +58,19 @@ describe('app-wide Alerts component', () => {
// TODO(mc, 2020-05-07): LostConnectionAlert currently controls its own
// render; move its logic into `state.alerts`
it('should render LostConnectionAlert', () => {
const wrapper = render()
const { wrapper } = render()
expect(wrapper.exists(LostConnectionAlert)).toBe(true)
})

// TODO(mc, 2020-05-07): AnalyticsSettingsModal currently controls its own
// render; move its logic into `state.alerts`
it('should render AnalyticsSettingsModal', () => {
const wrapper = render()
const { wrapper } = render()
expect(wrapper.exists(AnalyticsSettingsModal)).toBe(true)
})

it('should render a U2EDriverOutdatedAlert if alert is triggered', () => {
const wrapper = render()
const { wrapper, store } = render()
expect(wrapper.exists(U2EDriverOutdatedAlert)).toBe(false)

stubActiveAlerts([AppAlerts.ALERT_U2E_DRIVER_OUTDATED])
Expand All @@ -85,8 +79,23 @@ describe('app-wide Alerts component', () => {

wrapper.find(U2EDriverOutdatedAlert).invoke('dismissAlert')(true)

expect(dispatch).toHaveBeenCalledWith(
expect(store.dispatch).toHaveBeenCalledWith(
AppAlerts.alertDismissed(AppAlerts.ALERT_U2E_DRIVER_OUTDATED, true)
)
})

it('should render an UpdateAppModal if appUpdateAvailable alert is triggered', () => {
const { wrapper, store } = render()
expect(wrapper.exists(UpdateAppModal)).toBe(false)

stubActiveAlerts([AppAlerts.ALERT_APP_UPDATE_AVAILABLE])
wrapper.setProps({})
expect(wrapper.exists(UpdateAppModal)).toBe(true)

wrapper.find(UpdateAppModal).invoke('dismissAlert')(true)

expect(store.dispatch).toHaveBeenCalledWith(
AppAlerts.alertDismissed(AppAlerts.ALERT_APP_UPDATE_AVAILABLE, true)
)
})
})
3 changes: 3 additions & 0 deletions app/src/components/Alerts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import head from 'lodash/head'
import * as AppAlerts from '../../alerts'
import { LostConnectionAlert } from '../LostConnectionAlert'
import { AnalyticsSettingsModal } from '../analytics-settings'
import { UpdateAppModal } from '../app-settings'
import { U2EDriverOutdatedAlert } from './U2EDriverOutdatedAlert'

import type { State, Dispatch } from '../../types'
Expand Down Expand Up @@ -36,6 +37,8 @@ export function Alerts(): React.Node {

{activeAlert === AppAlerts.ALERT_U2E_DRIVER_OUTDATED ? (
<U2EDriverOutdatedAlert dismissAlert={dismissAlert} />
) : activeAlert === AppAlerts.ALERT_APP_UPDATE_AVAILABLE ? (
<UpdateAppModal dismissAlert={dismissAlert} />
) : null}
</>
)
Expand Down
50 changes: 0 additions & 50 deletions app/src/components/AppSettings/AppInfoCard.js

This file was deleted.

49 changes: 0 additions & 49 deletions app/src/components/AppSettings/__tests__/AppInfoCard.test.js

This file was deleted.

34 changes: 0 additions & 34 deletions app/src/components/AppSettings/index.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
// @flow
import * as React from 'react'
import styles from './styles.css'
import { C_BLUE, SPACING_3, Link, Text } from '@opentrons/components'

type SkipAppUpdateMessageProps = {|
onClick: () => mixed,
|}

const SKIP_APP_MESSAGE =
'If you wish to skip this app update and only sync your robot server with your current app version, please '
const CLICK_HERE = 'click here'

export function SkipAppUpdateMessage(
props: SkipAppUpdateMessageProps
): React.Node {
return (
<p className={styles.sync_message}>
<Text paddingLeft={SPACING_3}>
{SKIP_APP_MESSAGE}
<a className={styles.sync_link} onClick={props.onClick} disabled>
click here
</a>
<Link href="#" color={C_BLUE} onClick={props.onClick}>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: <a href="#" ... misbehaves, in that it will trigger react-router routing. I've replaced this with a more semantically correct <button> in #6715 that is styled like a link

{CLICK_HERE}
</Link>
.
</p>
</Text>
)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// @flow
import * as React from 'react'
import { useSelector } from 'react-redux'
import { Link } from 'react-router-dom'

import { getRobotApiVersion } from '../../../discovery'
import { CURRENT_VERSION, getShellUpdateState } from '../../../shell'
import { CURRENT_VERSION, getAvailableShellUpdate } from '../../../shell'

import { AlertModal } from '@opentrons/components'
import { Portal } from '../../portal'
import { UpdateAppModal } from '../../app-settings'
import { UpdateAppMessage } from './UpdateAppMessage'
import { VersionList } from './VersionList'
import { SkipAppUpdateMessage } from './SkipAppUpdateMessage'
Expand All @@ -29,31 +30,36 @@ const REINSTALL_MESSAGE =

export function VersionInfoModal(props: VersionInfoModalProps): React.Node {
const { robot, robotUpdateType, close, proceed } = props
const appUpdate = useSelector(getShellUpdateState)
const [showUpdateAppModal, setShowUpdateAppModal] = React.useState(false)
const availableAppUpdateVersion = useSelector(getAvailableShellUpdate)
const robotVersion = getRobotApiVersion(robot)
const appUpdateVersion = appUpdate.info?.version

if (showUpdateAppModal)
return (
<Portal>
<UpdateAppModal closeModal={close} />
</Portal>
)

const versionProps = {
robotVersion: robotVersion != null ? robotVersion : null,
appVersion: CURRENT_VERSION,
availableUpdate:
appUpdateVersion != null ? appUpdateVersion : CURRENT_VERSION,
availableUpdate: availableAppUpdateVersion ?? CURRENT_VERSION,
}

let heading = ''
let primaryButton = { className: styles.view_update_button }
let message = null
let secondaryMessage = null

if (appUpdate.available) {
heading = `App Version ${versionProps.availableUpdate} Available`
if (availableAppUpdateVersion !== null) {
heading = `App Version ${availableAppUpdateVersion} Available`
message = <UpdateAppMessage {...versionProps} />
secondaryMessage = <SkipAppUpdateMessage onClick={proceed} />
primaryButton = {
...primaryButton,
Component: Link,
to: '/more/app/update',
children: 'View App Update',
onClick: () => setShowUpdateAppModal(true),
}
} else if (robotUpdateType === 'upgrade' || robotUpdateType === 'downgrade') {
heading = 'Robot Update Available'
Expand Down
Loading