Browse Source

ui manager for apps and search

master
Valentin D. Pinkman 7 years ago
parent
commit
cd75857b8e
No known key found for this signature in database GPG Key ID: E7D110669FFB8D3E
  1. 2
      src/commands/index.js
  2. 19
      src/commands/isDashboardOpen.js
  3. 2
      src/commands/listApps.js
  4. 9
      src/components/EnsureDeviceApp/index.js
  5. 106
      src/components/ManagerPage/AppSearchBar.js
  6. 37
      src/components/ManagerPage/AppsList.js
  7. 36
      src/components/ManagerPage/EnsureDashboard.js
  8. 37
      src/components/ManagerPage/EnsureDevice.js
  9. 41
      src/components/ManagerPage/EnsureGenuine.js
  10. 8
      src/components/ManagerPage/FirmwareUpdate.js
  11. 22
      src/components/ManagerPage/ManagerApp.js
  12. 249
      src/components/ManagerPage/Workflow.js
  13. 132
      src/components/ManagerPage/index.js
  14. 18
      src/components/base/Button/index.js
  15. 3
      src/helpers/devices/getIsGenuine.js
  16. 22
      src/helpers/devices/isDashboardOpen.js
  17. 9
      src/helpers/firmware/installFinalFirmware.js
  18. 9
      src/helpers/firmware/installOsuFirmware.js
  19. 18
      src/icons/Trash.js
  20. 14
      static/i18n/en/manager.yml
  21. BIN
      static/images/logos/connectDevice.png

2
src/commands/index.js

@ -13,6 +13,7 @@ import installFinalFirmware from 'commands/installFinalFirmware'
import installMcu from 'commands/installMcu'
import installOsuFirmware from 'commands/installOsuFirmware'
import isCurrencyAppOpened from 'commands/isCurrencyAppOpened'
import isDashboardOpen from 'commands/isDashboardOpen'
import libcoreGetVersion from 'commands/libcoreGetVersion'
import libcoreScanAccounts from 'commands/libcoreScanAccounts'
import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast'
@ -37,6 +38,7 @@ const all: Array<Command<any, any>> = [
installMcu,
installOsuFirmware,
isCurrencyAppOpened,
isDashboardOpen,
libcoreGetVersion,
libcoreScanAccounts,
libcoreSignAndBroadcast,

19
src/commands/isDashboardOpen.js

@ -0,0 +1,19 @@
// @flow
import { createCommand, Command } from 'helpers/ipc'
import { fromPromise } from 'rxjs/observable/fromPromise'
import { withDevice } from 'helpers/deviceAccess'
import isDashboardOpen from '../helpers/devices/isDashboardOpen'
type Input = {
devicePath: string,
}
type Result = boolean
const cmd: Command<Input, Result> = createCommand('isDashboardOpen', ({ devicePath }) =>
fromPromise(withDevice(devicePath)(transport => isDashboardOpen(transport))),
)
export default cmd

2
src/commands/listApps.js

@ -13,7 +13,7 @@ type Input = *
type Result = *
const cmd: Command<Input, Result> = createCommand('listApps', () =>
/* { targetId } */ fromPromise(listApps()),
/* { targetId } */ fromPromise(listApps(/* targetId */)),
)
export default cmd

9
src/components/EnsureDeviceApp/index.js

@ -10,6 +10,7 @@ import { getDevices } from 'reducers/devices'
import type { State as StoreState } from 'reducers/index'
import getAddress from 'commands/getAddress'
import isCurrencyAppOpened from 'commands/isCurrencyAppOpened'
import isDashboardOpen from 'commands/isDashboardOpen'
import { CHECK_APP_INTERVAL_WHEN_VALID, CHECK_APP_INTERVAL_WHEN_INVALID } from 'config/constants'
@ -139,11 +140,11 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
throw new Error(`${currency.name} app is not opened on the device`)
}
} else {
// TODO: real check if user is on the device dashboard
if (!deviceSelected) {
throw new Error('No device')
const isDashboard = isDashboardOpen.send({ devicePath: deviceSelected.path }).toPromise()
if (!isDashboard) {
throw new Error(`dashboard is not opened`)
}
await sleep(1) // WTF
}
this.handleStatusChange(this.state.deviceStatus, 'success')

106
src/components/ManagerPage/AppSearchBar.js

@ -0,0 +1,106 @@
// @flow
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import Box from 'components/base/Box'
import Search from 'components/base/Search'
import SearchIcon from 'icons/Search'
import CrossIcon from 'icons/Cross'
type LedgerApp = {
name: string,
version: string,
icon: string,
app: Object,
bolos_version: {
min: number,
max: number,
},
}
type Props = {
list: Array<LedgerApp>,
children: (list: Array<LedgerApp>) => React$Node,
}
type State = {
query: string,
focused: boolean,
}
const SearchBarWrapper = styled(Box).attrs({
horizontal: true,
borderRadius: 4,
})`
height: 42px;
width: 100%;
margin: 0 0 20px 0;
background-color: white;
padding: 0 13px;
`
const Input = styled.input`
width: 100%;
border: 0;
margin: 0 13px;
flex: 1;
outline: none;
background: transparent;
color: black;
font-family: 'Open Sans';
font-weight: 600;
`
class AppSearchBar extends PureComponent<Props, State> {
state = {
query: '',
focused: false,
}
handleChange = (e: any) => this.setState({ query: e.target.value })
handleFocus = (bool: boolean) => () => this.setState({ focused: bool })
reset = () => {
const { input } = this
this.setState(state => ({ ...state, query: '' }), () => input && input.focus())
}
input = null
render() {
const { children, list } = this.props
const { query, focused } = this.state
const color = focused ? 'black' : 'grey'
return (
<Box>
<SearchBarWrapper align="center">
<SearchIcon size={16} style={{ color }} />
<Input
innerRef={c => (this.input = c)}
type="text"
value={query}
onChange={this.handleChange}
onFocus={this.handleFocus(true)}
onBlur={this.handleFocus(false)}
/>
{!!query && <CrossIcon size={16} cursor="pointer" onClick={this.reset} />}
</SearchBarWrapper>
<Search
fuseOptions={{
threshold: 0.5,
keys: ['name'],
}}
value={query}
items={list}
render={items => children(items)}
/>
</Box>
)
}
}
export default AppSearchBar

37
src/components/ManagerPage/AppsList.js

@ -14,6 +14,7 @@ import Modal, { ModalBody } from 'components/base/Modal'
import type { Device, T } from 'types/common'
import ManagerApp from './ManagerApp'
import AppSearchBar from './AppSearchBar'
const List = styled(Box).attrs({
horizontal: true,
@ -72,7 +73,7 @@ class AppsList extends PureComponent<Props, State> {
async fetchAppList() {
try {
// const { targetId } = this.props
// const { targetId } = this.props // TODO: REUSE THIS WHEN SERVER IS UP
const appsList = CACHED_APPS || (await listApps.send().toPromise())
CACHED_APPS = appsList
if (!this._unmounted) {
@ -116,19 +117,25 @@ class AppsList extends PureComponent<Props, State> {
handleCloseModal = () => this.setState({ status: 'idle' })
renderList() {
const { status, error } = this.state
const { status, error, appsList } = this.state
return (
<List>
{this.state.appsList.map(c => (
<ManagerApp
key={`${c.name}_${c.version}_${c.bolos_version.min}`}
name={c.name}
version={`Version ${c.version}`}
icon={ICONS_FALLBACK[c.icon] || c.icon}
onInstall={this.handleInstallApp(c)}
onUninstall={this.handleUninstallApp(c)}
/>
))}
<Box>
<AppSearchBar list={appsList}>
{items => (
<List>
{items.map(c => (
<ManagerApp
key={`${c.name}_${c.version}_${c.bolos_version.min}`}
name={c.name}
version={`Version ${c.version}`}
icon={ICONS_FALLBACK[c.icon] || c.icon}
onInstall={this.handleInstallApp(c)}
onUninstall={this.handleUninstallApp(c)}
/>
))}
</List>
)}
</AppSearchBar>
<Modal
isOpened={status !== 'idle' && status !== 'loading'}
render={() => (
@ -150,7 +157,7 @@ class AppsList extends PureComponent<Props, State> {
</ModalBody>
)}
/>
</List>
</Box>
)
}
@ -159,7 +166,7 @@ class AppsList extends PureComponent<Props, State> {
return (
<Box flow={6}>
<Box>
<Box mb={4} color="dark" ff="Museo Sans" fontSize={6}>
<Box mb={4} color="dark" ff="Museo Sans" fontSize={5}>
{t('manager:allApps')}
</Box>
{this.renderList()}

36
src/components/ManagerPage/EnsureDashboard.js

@ -1,9 +1,9 @@
// @flow
import React, { PureComponent, Fragment } from 'react'
import { translate } from 'react-i18next'
import { PureComponent } from 'react'
import isEqual from 'lodash/isEqual'
import type { Device, T } from 'types/common'
import type { Node } from 'react'
import type { Device } from 'types/common'
import getDeviceInfo from 'commands/getDeviceInfo'
@ -14,18 +14,19 @@ type DeviceInfo = {
mcu: boolean,
}
type Error = {
message: string,
stack: string,
}
type Props = {
t: T,
device: Device,
children: Function,
device: ?Device,
children: (deviceInfo: ?DeviceInfo, error: ?Error) => Node,
}
type State = {
deviceInfo: ?DeviceInfo,
error: ?{
message: string,
stack: string,
},
error: ?Error,
}
class EnsureDashboard extends PureComponent<Props, State> {
@ -74,19 +75,10 @@ class EnsureDashboard extends PureComponent<Props, State> {
render() {
const { deviceInfo, error } = this.state
const { children, t } = this.props
if (deviceInfo) {
return children(deviceInfo)
}
const { children } = this.props
return error ? (
<Fragment>
<span>{error.message}</span>
<span>{t('manager:erros:noDashboard')}</span>
</Fragment>
) : null
return children(deviceInfo, error)
}
}
export default translate()(EnsureDashboard)
export default EnsureDashboard

37
src/components/ManagerPage/EnsureDevice.js

@ -1,39 +1,28 @@
// @flow
import React, { PureComponent } from 'react'
import { PureComponent } from 'react'
import { connect } from 'react-redux'
import { translate } from 'react-i18next'
import { compose } from 'redux'
import type { Device, T } from 'types/common'
import type { Node } from 'react'
import type { Device } from 'types/common'
import { getCurrentDevice, getDevices } from 'reducers/devices'
const mapStateToProps = state => ({
device: getCurrentDevice(state),
nbDevices: getDevices(state).length,
})
import { getCurrentDevice } from 'reducers/devices'
type Props = {
t: T,
device: ?Device,
nbDevices: number,
children: Function,
device: Device,
children: (device: Device) => Node,
}
type State = {}
class EnsureDevice extends PureComponent<Props, State> {
static defaultProps = {
device: null,
}
render() {
const { device, nbDevices, children, t } = this.props
return device ? children(device, nbDevices) : <span>{t('manager:errors.noDevice')}</span>
const { device, children } = this.props
return children(device)
}
}
export default compose(
translate(),
connect(mapStateToProps),
)(EnsureDevice)
const mapStateToProps = state => ({
device: getCurrentDevice(state),
})
export default connect(mapStateToProps)(EnsureDevice)

41
src/components/ManagerPage/EnsureGenuine.js

@ -1,36 +1,36 @@
// @flow
import React, { PureComponent, Fragment } from 'react'
import { translate } from 'react-i18next'
import { PureComponent } from 'react'
import isEqual from 'lodash/isEqual'
import type { Node } from 'react'
import type { Device, T } from 'types/common'
import type { Device } from 'types/common'
import getIsGenuine from 'commands/getIsGenuine'
type Error = {
message: string,
stack: string,
}
type Props = {
t: T,
device: Device,
children: Node,
device: ?Device,
children: (isGenuine: ?boolean, error: ?Error) => Node,
}
type State = {
genuine: boolean,
error: ?{
message: string,
stack: string,
},
genuine: ?boolean,
error: ?Error,
}
class EnsureGenuine extends PureComponent<Props, State> {
static defaultProps = {
children: null,
children: () => null,
firmwareInfo: null,
}
state = {
error: null,
genuine: false,
genuine: null,
}
componentDidMount() {
@ -68,19 +68,10 @@ class EnsureGenuine extends PureComponent<Props, State> {
render() {
const { error, genuine } = this.state
const { children, t } = this.props
if (genuine) {
return children
}
const { children } = this.props
return error ? (
<Fragment>
<span>{error.message}</span>
<span>{t('manager:errors.noGenuine')}</span>
</Fragment>
) : null
return children(genuine, error)
}
}
export default translate()(EnsureGenuine)
export default EnsureGenuine

8
src/components/ManagerPage/FirmwareUpdate.js

@ -12,6 +12,7 @@ import installOsuFirmware from 'commands/installOsuFirmware'
import Box, { Card } from 'components/base/Box'
import Button from 'components/base/Button'
import Text from 'components/base/Text'
let CACHED_LATEST_FIRMWARE = null
@ -97,12 +98,11 @@ class FirmwareUpdate extends PureComponent<Props, State> {
return (
<Box flow={4} {...props}>
<Box color="dark" ff="Museo Sans" fontSize={6}>
{t('manager:firmwareUpdate')}
</Box>
<Card flow={2} {...props}>
<Box horizontal align="center" flow={2}>
<Box ff="Museo Sans">{`${t('manager:latestFirmware')}: ${latestFirmware.name}`}</Box>
<Text ff="Open Sans|Regular" fontSize={4}>{`${t('manager:latestFirmware')}: ${
latestFirmware.name
}`}</Text>
<Button outline onClick={this.installFirmware(latestFirmware)}>
{t('manager:install')}
</Button>

22
src/components/ManagerPage/ManagerApp.js

@ -6,27 +6,29 @@ import { translate } from 'react-i18next'
import type { T } from 'types/common'
import Trash from 'icons/Trash'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import Button from 'components/base/Button'
const Container = styled(Box).attrs({
align: 'center',
horizontal: true,
m: 3,
p: 4,
boxShadow: 0,
borderRadius: 4,
flow: 3,
})`
width: 156px;
height: 186px;
width: 342px;
background: white;
line-height: normal;
`
const AppIcon = styled.img`
display: block;
width: 50px;
height: 50px;
width: 36px;
height: 36px;
`
const AppName = styled(Box).attrs({
@ -36,7 +38,6 @@ const AppName = styled(Box).attrs({
})`
display: block;
width: 115px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -48,16 +49,16 @@ type Props = {
version: string,
icon: string,
onInstall: Function,
// onUninstall: Function,
onUninstall: Function,
}
function ManagerApp(props: Props) {
const { name, version, icon, onInstall, t } = props
const { name, version, icon, onInstall, onUninstall, t } = props
const iconUrl = `https://api.ledgerwallet.com/update/assets/icons/${icon}`
return (
<Container>
<AppIcon src={iconUrl} />
<Box align="center">
<Box flex="1">
<AppName>{name}</AppName>
<Text ff="Open Sans|Regular" fontSize={3} color="grey">
{version}
@ -66,6 +67,9 @@ function ManagerApp(props: Props) {
<Button outline onClick={onInstall}>
{t('manager:install')}
</Button>
<Button outline onClick={onUninstall} outlineColor="grey">
<Trash size={16} fill="grey" />
</Button>
</Container>
)
}

249
src/components/ManagerPage/Workflow.js

@ -0,0 +1,249 @@
// @flow
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import { Trans, translate } from 'react-i18next'
import isNull from 'lodash/isNull'
import type { Node } from 'react'
import type { Device, T } from 'types/common'
import { i } from 'helpers/staticPath'
import Box from 'components/base/Box'
import Space from 'components/base/Space'
import Spinner from 'components/base/Spinner'
import Text from 'components/base/Text'
import IconCheck from 'icons/Check'
import IconExclamationCircle from 'icons/ExclamationCircle'
import IconUsb from 'icons/Usb'
import IconHome from 'icons/Home'
import EnsureDevice from './EnsureDevice'
import EnsureDashboard from './EnsureDashboard'
import EnsureGenuine from './EnsureGenuine'
type DeviceInfo = {
targetId: number | string,
version: string,
final: boolean,
mcu: boolean,
}
type Error = {
message: string,
stack: string,
}
type Props = {
t: T,
renderMcuUpdate: (deviceInfo: DeviceInfo) => Node,
renderFinalUpdate: (deviceInfo: DeviceInfo) => Node,
renderDashboard: (device: Device, deviceInfo: DeviceInfo) => Node,
renderError: (dashboardError: ?Error, genuineError: ?Error) => Node,
}
type State = {}
const Step = styled(Box).attrs({
borderRadius: 1,
justifyContent: 'center',
fontSize: 4,
})`
border: 1px solid
${p =>
p.validated
? p.theme.colors.wallet
: p.hasErrors
? p.theme.colors.alertRed
: p.theme.colors.fog};
`
const StepIcon = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
})`
width: 64px;
`
const StepContent = styled(Box).attrs({
color: 'dark',
horizontal: true,
alignItems: 'center',
})`
height: 60px;
line-height: 1.2;
strong {
font-weight: 600;
}
`
const StepCheck = ({ checked, hasErrors }: { checked: ?boolean, hasErrors?: boolean }) => (
<Box pr={5}>
{checked ? (
<Box color="wallet">
<IconCheck size={16} />
</Box>
) : hasErrors ? (
<Box color="alertRed">
<IconExclamationCircle size={16} />
</Box>
) : (
<Spinner size={16} />
)}
</Box>
)
StepCheck.defaultProps = {
hasErrors: false,
}
const WrapperIconCurrency = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
})`
border: 1px solid ${p => p.theme.colors[p.color]};
border-radius: 8px;
height: 24px;
width: 24px;
`
class Workflow extends PureComponent<Props, State> {
render() {
const { renderDashboard, renderFinalUpdate, renderMcuUpdate, renderError, t } = this.props
return (
<EnsureDevice>
{(device: Device) => (
<EnsureDashboard device={device}>
{(deviceInfo: ?DeviceInfo, dashboardError: ?Error) => (
<EnsureGenuine device={device}>
{(isGenuine: ?boolean, genuineError: ?Error) => {
if (dashboardError || genuineError) {
return renderError ? (
renderError(dashboardError, genuineError)
) : (
<div>
{dashboardError && <span>{dashboardError.message}</span>}
{genuineError && <span>{genuineError.message}</span>}
</div>
)
}
if (deviceInfo && deviceInfo.mcu) {
return renderMcuUpdate(deviceInfo)
}
if (deviceInfo && deviceInfo.final) {
return renderFinalUpdate(deviceInfo)
}
if (isGenuine && deviceInfo && device && !dashboardError && !genuineError) {
return renderDashboard(device, deviceInfo)
}
return (
<Box align="center">
<Space of={152} />
<Box align="center" style={{ maxWidth: 460, padding: '0 10px' }}>
<img
src={i('logos/connectDevice.png')}
alt="connect your device"
style={{ marginBottom: 30, maxWidth: 360, width: '100%' }}
/>
<Text
ff="Museo Sans|Regular"
fontSize={7}
color="black"
style={{ marginBottom: 10 }}
>
{t('manager:plugYourDevice:title')}
</Text>
<Text ff="Museo Sans|Light" fontSize={5} color="grey" align="center">
{t('manager:plugYourDevice:desc')}
</Text>
</Box>
<Box flow={4} style={{ maxWidth: 460, padding: '60px 10px 0' }}>
{/* DEVICE CHECK */}
<Step validated={!!device}>
<StepContent>
<StepIcon>
<IconUsb size={36} />
</StepIcon>
<Box grow shrink>
<Trans i18nKey="deviceConnect:step1.connect" parent="div">
{'Connect your '}
<strong>Ledger device</strong>
{' to your computer and enter your '}
<strong>PIN code</strong>
{' on your device'}
</Trans>
</Box>
<StepCheck checked={!!device} />
</StepContent>
</Step>
{/* DASHBOARD CHECK */}
<Step
validated={!!device && !!deviceInfo}
hasErrors={!!device && !!dashboardError}
>
<StepContent>
<StepIcon>
<WrapperIconCurrency>
<IconHome size={12} />
</WrapperIconCurrency>
</StepIcon>
<Box grow shrink>
<Trans i18nKey="deviceConnect:dashboard.open" parent="div">
{'Go to the '}
<strong>{'dashboard'}</strong>
{' on your device'}
</Trans>
</Box>
<StepCheck
checked={!!device && !!deviceInfo}
hasErrors={!!device && !!dashboardError}
/>
</StepContent>
</Step>
{/* GENUINE CHECK */}
<Step
validated={(!!device && !isNull(isGenuine) && isGenuine) || undefined}
hasErrors={(!!device && !isNull(isGenuine) && !isGenuine) || undefined}
>
<StepContent>
<StepIcon>
<WrapperIconCurrency>
<IconCheck size={12} />
</WrapperIconCurrency>
</StepIcon>
<Box grow shrink>
<Trans i18nKey="deviceConnect:stepGenuine.open" parent="div">
{'Confirm '}
<strong>{'authentication'}</strong>
{' on your device'}
</Trans>
</Box>
<StepCheck
checked={(!!device && !isNull(isGenuine) && isGenuine) || undefined}
hasErrors={
(!!device && !isNull(isGenuine) && !isGenuine) || undefined
}
/>
</StepContent>
</Step>
</Box>
</Box>
)
}}
</EnsureGenuine>
)}
</EnsureDashboard>
)}
</EnsureDevice>
)
}
}
export default translate()(Workflow)

132
src/components/ManagerPage/index.js

@ -1,62 +1,82 @@
// @flow
// import React, { Fragment } from 'react'
import React from 'react'
// import { translate } from 'react-i18next'
import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import type { Node } from 'react'
// import type { T, Device } from 'types/common'
import type { Device } from 'types/common'
import type { T, Device } from 'types/common'
import Box from 'components/base/Box'
import Text from 'components/base/Text'
import AppsList from './AppsList'
// import DeviceInfos from './DeviceInfos'
// import FirmwareUpdate from './FirmwareUpdate'
import EnsureDevice from './EnsureDevice'
// import EnsureDashboard from './EnsureDashboard'
// import EnsureGenuine from './EnsureGenuine'
// type DeviceInfo = {
// targetId: number | string,
// version: string,
// final: boolean,
// mcu: boolean,
// }
// type Props = {
// t: T,
// }
// const ManagerPage = ({ t }: Props): Node => (
// <EnsureDevice>
// {(device: Device) => (
// <EnsureDashboard device={device}>
// {(deviceInfo: DeviceInfo) => (
// <Fragment>
// {deviceInfo.mcu && <span> bootloader mode </span>}
// {deviceInfo.final && <span> osu mode </span>}
// {!deviceInfo.mcu &&
// !deviceInfo.final && (
// <EnsureGenuine device={device} t={t}>
// <FirmwareUpdate
// infos={{
// targetId: deviceInfo.targetId,
// version: deviceInfo.version,
// }}
// device={device}
// t={t}
// />
// <AppsList device={device} targetId={deviceInfo.targetId} />
// </EnsureGenuine>
// )}
// </Fragment>
// )}
// </EnsureDashboard>
// )}
// </EnsureDevice>
// )
const ManagerPage = (): Node => (
<EnsureDevice>{(device: Device) => <AppsList device={device} />}</EnsureDevice>
)
export default ManagerPage
import FirmwareUpdate from './FirmwareUpdate'
import Workflow from './Workflow'
type DeviceInfo = {
targetId: number | string,
version: string,
final: boolean,
mcu: boolean,
}
type Error = {
message: string,
stack: string,
}
type Props = {
t: T,
}
type State = {
modalOpen: boolean,
}
class ManagerPage extends PureComponent<Props, State> {
render(): Node {
const { t } = this.props
return (
<Workflow
renderError={(dashboardError: ?Error, genuineError: ?Error) => {
if (dashboardError) return <span>Dashboard Error: {dashboardError.message}</span>
if (genuineError) return <span>Genuine Error: {genuineError.message}</span>
return <span>Error</span>
}}
renderFinalUpdate={(deviceInfo: DeviceInfo) => (
<p>UPDATE FINAL FIRMARE (TEMPLATE + ACTION WIP) {deviceInfo.final}</p>
)}
renderMcuUpdate={(deviceInfo: DeviceInfo) => (
<p>FLASH MCU (TEMPLATE + ACTION WIP) {deviceInfo.mcu}</p>
)}
renderDashboard={(device: Device, deviceInfo: DeviceInfo) => (
<Box flow={4}>
<Box>
<Text ff="Museo Sans|Regular" fontSize={7} color="black">
{t('manager:title')}
</Text>
<Text ff="Museo Sans|Light" fontSize={5}>
{t('manager:subtitle')}
</Text>
</Box>
<Box mt={7}>
<FirmwareUpdate
infos={{
targetId: deviceInfo.targetId,
version: deviceInfo.version,
}}
device={device}
t={t}
/>
</Box>
<Box>
<AppsList device={device} targetId={deviceInfo.targetId} />
</Box>
</Box>
)}
/>
)
}
}
export default translate()(ManagerPage)

18
src/components/base/Button/index.js

@ -37,12 +37,22 @@ const buttonStyles = {
outline: {
default: p => `
background: transparent;
border: 1px solid ${p.theme.colors.wallet};
color: ${p.theme.colors.wallet};
border: 1px solid ${
p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet
};
color: ${
p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet
};
`,
active: p => `
color: ${darken(p.theme.colors.wallet, 0.1)};
border-color: ${darken(p.theme.colors.wallet, 0.1)};
color: ${darken(
p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet,
0.1,
)};
border-color: ${darken(
p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet,
0.1,
)};
`,
},
outlineGrey: {

3
src/helpers/devices/getIsGenuine.js

@ -2,4 +2,5 @@
// import type Transport from '@ledgerhq/hw-transport'
export default async (/* transport: Transport<*> */) => new Promise(resolve => resolve(true))
export default async (/* transport: Transport<*> */) =>
new Promise(resolve => setTimeout(() => resolve(true), 1000))

22
src/helpers/devices/isDashboardOpen.js

@ -0,0 +1,22 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import { getFirmwareInfo } from 'helpers/common'
type Result = boolean
export default async (transport: Transport<*>): Promise<Result> => {
try {
const { targetId, version } = await getFirmwareInfo(transport)
if (targetId && version) {
return true
}
return false
} catch (err) {
const error = Error(err.message)
error.stack = err.stack
throw error
}
}

9
src/helpers/firmware/installFinalFirmware.js

@ -4,17 +4,14 @@ import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog, buildParamsFromFirmware } from 'helpers/common'
type Input = {
firmware: Object,
}
type Input = Object
type Result = *
const buildOsuParams = buildParamsFromFirmware('final')
export default async (transport: Transport<*>, data: Input): Result => {
export default async (transport: Transport<*>, firmware: Input): Result => {
try {
const osuData = buildOsuParams(data.firmware)
const osuData = buildOsuParams(firmware)
await createSocketDialog(transport, '/update/install', osuData)
return { success: true }
} catch (err) {

9
src/helpers/firmware/installOsuFirmware.js

@ -4,18 +4,15 @@ import type Transport from '@ledgerhq/hw-transport'
import { createSocketDialog, buildParamsFromFirmware } from 'helpers/common'
type Input = {
devicePath: string,
firmware: Object,
}
type Input = Object
type Result = Promise<{ success: boolean, error?: any }>
const buildOsuParams = buildParamsFromFirmware('osu')
export default async (transport: Transport<*>, data: Input): Result => {
export default async (transport: Transport<*>, firmware: Input): Result => {
try {
const osuData = buildOsuParams(data.firmware)
const osuData = buildOsuParams(firmware)
await createSocketDialog(transport, '/update/install', osuData)
return { success: true }
} catch (err) {

18
src/icons/Trash.js

@ -0,0 +1,18 @@
// @flow
import React from 'react'
const path = (
<g transform="translate(670.57 190.38)">
<path
d="m-658.54-187.18h3.2002a0.80037 0.80037 0 0 1 0 1.5993h-0.80049v10.4a2.3999 2.3999 0 0 1-2.3999 2.3999h-8.0001a2.3999 2.3999 0 0 1-2.3999-2.3999v-10.4h-0.79878a0.80037 0.80037 0 1 1 0-1.5993h3.1991v-0.80049a2.3999 2.3999 0 0 1 2.3999-2.3999h3.2003a2.3999 2.3999 0 0 1 2.3999 2.3999zm-1.5993 0v-0.80049a0.80037 0.80037 0 0 0-0.80049-0.80049h-3.2003a0.80037 0.80037 0 0 0-0.79878 0.80049v0.80049zm0.80049 1.5993a0.84357 0.84357 0 0 1-1e-3 0h-6.3995a0.84357 0.84357 0 0 1-2e-3 0h-1.5976v10.4c0 0.44224 0.35825 0.79877 0.79878 0.79877h8.0001a0.80037 0.80037 0 0 0 0.8005-0.79877v-10.4zm-5.6004 3.2003a0.80037 0.80037 0 1 1 1.5993 0v4.7997a0.80037 0.80037 0 0 1-1.5993 0zm3.1992 0a0.80049 0.80049 0 1 1 1.601 0v4.7997a0.80049 0.80049 0 0 1-1.601 0z"
strokeWidth="1.2"
/>
</g>
)
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 17.6" height={size} width={size} {...p}>
{path}
</svg>
)

14
static/i18n/en/manager.yml

@ -2,14 +2,16 @@ tabs:
apps: Apps
device: My device
install: Install
allApps: All apps
allApps: Apps
title: Manager
subtitle: Get all your apps here
firmwareUpdate: Firmware update
latestFirmware: Latest firmware
latestFirmware: Firmware
plugYourDevice:
title: Plug your device
desc: Lorem Ipsum is simply dummy text of the printing and typesetting industry’s standard dummy text
desc: Please connect your Ledger device and follow the steps below to access the manager
cta: Plug my device
errors:
noDevice: Please make sur your device is connected
noDashboard: Please make sure your device is on the dashboard screen
noGenuine: You did not approve request on your device or your device is not genuine
noDevice: Please make sur your device is connected (TEMPLATE NEEDED)
noDashboard: Please make sure your device is on the dashboard screen (TEMPLATED NEEDED)
noGenuine: You did not approve request on your device or your device is not genuine (TEMPLATE NEEDED)

BIN
static/images/logos/connectDevice.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Loading…
Cancel
Save