diff --git a/package.json b/package.json index 9f81a036..662dd626 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "qrcode": "^1.2.0", "query-string": "^5.1.0", "raven": "^2.4.1", - "raven-js": "^3.22.2", + "raven-js": "^3.22.3", "react": "^16.2.0", "react-dom": "^16.2.0", "react-i18next": "^7.3.6", @@ -121,7 +121,7 @@ "eslint-config-airbnb": "^16.1.0", "eslint-config-prettier": "^2.9.0", "eslint-import-resolver-babel-module": "^4.0.0", - "eslint-plugin-flowtype": "^2.43.0", + "eslint-plugin-flowtype": "^2.44.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-jsx-a11y": "^6.0.3", "eslint-plugin-react": "^7.6.1", diff --git a/src/components/DevToolbar.js b/src/components/DevToolbar.js index a9255799..5c37a4c3 100644 --- a/src/components/DevToolbar.js +++ b/src/components/DevToolbar.js @@ -1,5 +1,7 @@ // @flow +/* eslint-disable import/no-named-as-default-member */ + import React, { PureComponent } from 'react' import { remote, ipcRenderer } from 'electron' import { translate } from 'react-i18next' @@ -17,6 +19,7 @@ import color from 'color' import Box from 'components/base/Box' import Bar from 'components/base/Bar' import CopyToClipboard from 'components/base/CopyToClipboard' +import { ChartWrapper } from 'components/base/Chart' import theme from 'styles/theme' @@ -35,6 +38,11 @@ type ColorType = { }, } +type SimpleType = { + name: string, + val: string, +} + const transform = flow( reduce.convert({ cap: false })((acc, cur, key) => { const c = color(cur) @@ -53,6 +61,14 @@ const transform = flow( ) const colors: Array<ColorType> = transform(theme.colors) +const spaces: Array<SimpleType> = theme.space.map((s, i) => ({ + name: s.toString(), + val: i.toString(), +})) +const fontSizes: Array<SimpleType> = theme.fontSizes.map((s, i) => ({ + name: s.toString(), + val: i.toString(), +})) const Container = styled(Box).attrs({ bg: 'night', @@ -62,35 +78,30 @@ const Container = styled(Box).attrs({ fontSize: 3, })`` -const Colors = styled(Box).attrs({ +const Title = styled(Box).attrs({ + color: 'white', +})` + text-transform: uppercase; +` + +const Items = styled(Box).attrs({ horizontal: true, flow: 4, })`` -const Cl = styled(Box).attrs({ +const Item = styled(Box).attrs({ align: 'center', - justify: 'center', - p: 2, -})` - border: 2px solid white; - flex: 1; - cursor: pointer; -` - -const Color = ({ onClick, color }: { onClick: Function, color: ColorType }) => ( - <Cl bg={color.val} color={color.isDark ? 'white' : 'night'} onClick={onClick}> - {color.name} - </Cl> -) - -const Lang = styled(Box).attrs({ bg: 'night', - color: 'white', borderColor: 'white', - borderWidth: 2, borderRadius: 1, - p: 2, + borderWidth: 2, + color: 'white', + justify: 'center', + py: 2, + px: 4, })` + flex: 1; + overflow: hidden; cursor: pointer; ` @@ -144,17 +155,17 @@ class DevToolbar extends PureComponent<any, State> { return ( <Container> <Box grow flow={4}> - <Box flow={4} horizontal> + <Section title="Languages" horizontal> {Object.keys(i18n.store.data).map(lang => ( - <Lang key={lang} onClick={this.handleChangeLanguage(lang)}> + <Item key={lang} onClick={this.handleChangeLanguage(lang)} style={{ flex: 0 }}> {lang} - </Lang> + </Item> ))} - </Box> + </Section> <Bar size={2} color="white" /> - <Box flow={4}> - {chunk(colors, 8).map((c, i) => ( - <Colors + <Section title="Colors"> + {chunk(colors, 5).map((c, i) => ( + <Items key={i} // eslint-disable-line react/no-array-index-key > {c.map(color => ( @@ -164,42 +175,107 @@ class DevToolbar extends PureComponent<any, State> { render={copy => <Color color={color} onClick={copy} />} /> ))} - </Colors> + </Items> ))} - </Box> + </Section> + <Section title="Space"> + {chunk(spaces, 5).map((s, i) => ( + <Items + key={i} // eslint-disable-line react/no-array-index-key + > + {s.map(space => ( + <CopyToClipboard + key={space.val} + data={space.val} + render={copy => <Item onClick={copy}>{space.name}</Item>} + /> + ))} + </Items> + ))} + </Section> + <Section title="Font Sizes"> + {chunk(fontSizes, 5).map((f, i) => ( + <Items + key={i} // eslint-disable-line react/no-array-index-key + > + {f.map(fontSize => ( + <CopyToClipboard + key={fontSize.val} + data={fontSize.val} + render={copy => <Item onClick={copy}>{fontSize.name}</Item>} + /> + ))} + </Items> + ))} + </Section> <Bar size={2} color="white" /> - <Box flow={4} horizontal> - {Object.keys(cpuUsage) - .sort() - .map(k => ( - <Box key={k}> - <Box horizontal align="center" flow={2}> - <Box fontSize={1}>{last(cpuUsage[k]).value}%</Box> - <Box>{k}</Box> - </Box> - <Box> - <AreaChart - width={100} - height={40} - data={cpuUsage[k]} - margin={{ top: 10, right: 0, left: 0, bottom: 0 }} - > - <Area - type="monotone" - stroke="#8884d8" - fill="#8884d8" - dataKey="value" - isAnimationActive={false} + <Section title="CPU Usage"> + {chunk(Object.keys(cpuUsage).sort(), 2).map((l, i) => ( + <Items + key={i} // eslint-disable-line react/no-array-index-key + > + {l.map(k => ( + <Box key={k} style={{ flex: 1 }}> + <Box horizontal align="center" flow={2}> + <Box fontSize={1}>{last(cpuUsage[k]).value}%</Box> + <Box>{k}</Box> + </Box> + <Box> + <ChartWrapper + render={({ width }) => ( + <AreaChart + width={width} + height={40} + data={cpuUsage[k]} + margin={{ top: 10, right: 0, left: 0, bottom: 0 }} + > + <Area + type="monotone" + stroke="#8884d8" + fill="#8884d8" + dataKey="value" + isAnimationActive={false} + /> + </AreaChart> + )} /> - </AreaChart> + </Box> </Box> - </Box> - ))} - </Box> + ))} + </Items> + ))} + </Section> </Box> </Container> ) } } +const Color = ({ onClick, color }: { onClick: Function, color: ColorType }) => ( + <Item bg={color.val} color={color.isDark ? 'white' : 'night'} onClick={onClick}> + {color.name} + </Item> +) + +const Section = ({ + title, + children, + horizontal, +}: { + title: string, + children: any, + horizontal?: boolean, +}) => ( + <Box flow={2}> + <Title>{title}</Title> + <Box flow={4} horizontal={horizontal}> + {children} + </Box> + </Box> +) + +Section.defaultProps = { + horizontal: false, +} + export default translate()(DevToolbar) diff --git a/src/components/base/Chart/index.js b/src/components/base/Chart/index.js index 4d33409c..1b826d1f 100644 --- a/src/components/base/Chart/index.js +++ b/src/components/base/Chart/index.js @@ -16,7 +16,7 @@ type State = { width: number, } -class Container extends PureComponent<Props, State> { +export class ChartWrapper extends PureComponent<Props, State> { state = { isAnimationActive: true, width: 0, @@ -83,7 +83,7 @@ export const AreaChart = ({ margin?: Object, tiny?: boolean, }) => ( - <Container + <ChartWrapper render={({ width, isAnimationActive }) => ( <ReactAreaChart width={width} height={height} data={data} margin={margin}> {linearGradient && ( diff --git a/src/components/layout/Dev.js b/src/components/layout/Dev.js index b0dd5b1e..a728ed52 100644 --- a/src/components/layout/Dev.js +++ b/src/components/layout/Dev.js @@ -4,6 +4,8 @@ import React, { PureComponent } from 'react' import styled from 'styled-components' import Box from 'components/base/Box' +import GrowScroll from 'components/base/GrowScroll' + import DevToolbar from 'components/DevToolbar' const Container = styled(Box).attrs({ @@ -16,7 +18,9 @@ class Dev extends PureComponent<{}> { render() { return ( <Container> - <DevToolbar /> + <GrowScroll> + <DevToolbar /> + </GrowScroll> </Container> ) } diff --git a/src/helpers/cpuUsage.js b/src/helpers/cpuUsage.js new file mode 100644 index 00000000..acf7b69a --- /dev/null +++ b/src/helpers/cpuUsage.js @@ -0,0 +1,43 @@ +const TIMEOUT_CPU_USAGE = 5e3 + +const cpuUsage = (startTime, startUsage) => { + const now = Date.now() + + while (Date.now() - now < 500); + + const newStartTime = process.hrtime() + const newStartUsage = process.cpuUsage() + + const elapTime = process.hrtime(startTime) + const elapUsage = process.cpuUsage(startUsage) + + startTime = newStartTime + startUsage = newStartUsage + + const elapTimeMS = elapTime[0] * 1e3 + elapTime[1] / 1e6 + + const elapUserMS = elapUsage.user / 1e3 + const elapSystMS = elapUsage.system / 1e3 + const cpuPercent = (100 * (elapUserMS + elapSystMS) / elapTimeMS).toFixed(1) + + return { + cpuPercent, + newStartTime: startTime, + newStartUsage: startUsage, + } +} + +export default callback => { + const initCpuUsage = (startTime, startUsage) => { + const { cpuPercent, newStartTime, newStartUsage } = cpuUsage(startTime, startUsage) + + callback(cpuPercent) + + setTimeout(() => initCpuUsage(newStartTime, newStartUsage), TIMEOUT_CPU_USAGE) + } + + const startTime = process.hrtime() + const startUsage = process.cpuUsage() + + initCpuUsage(startTime, startUsage) +} diff --git a/src/internals/index.js b/src/internals/index.js index 2c700f30..71499d21 100644 --- a/src/internals/index.js +++ b/src/internals/index.js @@ -3,9 +3,11 @@ import objectPath from 'object-path' import capitalize from 'lodash/capitalize' +import cpuUsage from 'helpers/cpuUsage' + const { FORK_TYPE } = process.env -process.title = `Ledger Wallet Desktop ${capitalize(FORK_TYPE)}` +process.title = `${require('../../package.json').productName} ${capitalize(FORK_TYPE)}` // eslint-disable-line global-require function sendEvent(type: string, data: any, options: Object = { kill: true }) { process.send({ type, data, options }) @@ -37,31 +39,7 @@ const onMessage = payload => { process.on('message', onMessage) if (__DEV__) { - const TIMEOUT_CPU_USAGE = 5e3 - - let startTime = process.hrtime() - let startUsage = process.cpuUsage() - - const cpuUsage = () => { - const now = Date.now() - - while (Date.now() - now < 500); - - const newStartTime = process.hrtime() - const newStartUsage = process.cpuUsage() - - const elapTime = process.hrtime(startTime) - const elapUsage = process.cpuUsage(startUsage) - - startTime = newStartTime - startUsage = newStartUsage - - const elapTimeMS = elapTime[0] * 1e3 + elapTime[1] / 1e6 - - const elapUserMS = elapUsage.user / 1e3 - const elapSystMS = elapUsage.system / 1e3 - const cpuPercent = (100 * (elapUserMS + elapSystMS) / elapTimeMS).toFixed(1) - + cpuUsage(cpuPercent => sendEvent( 'usage.cpu', { @@ -72,10 +50,6 @@ if (__DEV__) { window: 'DevWindow', kill: false, }, - ) - - setTimeout(cpuUsage, TIMEOUT_CPU_USAGE) - } - - cpuUsage() + ), + ) } diff --git a/src/main/app.js b/src/main/app.js index 18470cf2..0e2f3b00 100644 --- a/src/main/app.js +++ b/src/main/app.js @@ -75,11 +75,11 @@ function createMainWindow() { titleBarStyle: 'hiddenInset', } : {}), - width, height, - minWidth: MIN_WIDTH, minHeight: MIN_HEIGHT, + minWidth: MIN_WIDTH, show: false, + width, } const window = new BrowserWindow(windowOptions) @@ -117,8 +117,8 @@ function createMainWindow() { } function createDevWindow() { - const MIN_HEIGHT = 400 - const MIN_WIDTH = 600 + const MIN_HEIGHT = 500 + const MIN_WIDTH = 360 const savedDimensions = db.getIn('settings', 'window.DevWindow.dimensions', {}) const savedPositions = db.getIn('settings', 'window.DevWindow.positions', null) @@ -131,8 +131,11 @@ function createDevWindow() { ...(savedPositions !== null ? savedPositions : {}), fullscreenable: false, height, + minHeight: MIN_HEIGHT, + minWidth: MIN_WIDTH, show: false, skipTaskbar: true, + title: 'Dev Tools', width, } @@ -142,10 +145,6 @@ function createDevWindow() { const url = getDefaultUrl() - if (devTools) { - window.webContents.openDevTools() - } - saveWindowSettings(window) window.loadURL(`${url}/#/dev`) @@ -154,6 +153,9 @@ function createDevWindow() { window.show() }) + // Don't want to use HTML <title> + window.on('page-title-updated', e => e.preventDefault()) + return window } diff --git a/src/main/bridge.js b/src/main/bridge.js index e4f6f62d..67220517 100644 --- a/src/main/bridge.js +++ b/src/main/bridge.js @@ -5,6 +5,8 @@ import { BrowserWindow, ipcMain } from 'electron' import objectPath from 'object-path' import { resolve } from 'path' +import cpuUsage from 'helpers/cpuUsage' + import setupAutoUpdater, { quitAndInstall } from './autoUpdate' const processes = [] @@ -13,6 +15,13 @@ function cleanProcesses() { processes.forEach(kill => kill()) } +function sendEventToWindow(name, { type, data }) { + const anotherWindow = BrowserWindow.getAllWindows().find(w => w.name === name) + if (anotherWindow) { + anotherWindow.webContents.send('msg', { type, data }) + } +} + function onForkChannel(forkType, callType) { return (event: any, payload) => { const { type, data } = payload @@ -36,8 +45,7 @@ function onForkChannel(forkType, callType) { const { type, data, options = {} } = payload if (options.window) { - const devWindow = BrowserWindow.getAllWindows().find(w => w.name === options.window) - devWindow.webContents.send('msg', { type, data }) + sendEventToWindow(options.window, { type, data }) } else { if (callType === 'async') { event.sender.send('msg', { type, data }) @@ -80,3 +88,12 @@ ipcMain.on('msg', (event: any, payload) => { const send = (type: string, data: *) => event.sender.send('msg', { type, data }) handler(send, data, type) }) + +if (__DEV__) { + cpuUsage(cpuPercent => + sendEventToWindow('DevWindow', { + type: 'usage.cpu', + data: { name: 'main', value: cpuPercent }, + }), + ) +} diff --git a/yarn.lock b/yarn.lock index dee05ea6..ee97107e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3761,9 +3761,9 @@ eslint-module-utils@^2.1.1: debug "^2.6.8" pkg-dir "^1.0.0" -eslint-plugin-flowtype@^2.43.0: - version "2.43.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.43.0.tgz#47cdac5f01cda53f1c3e8477f0c83fee66a1606e" +eslint-plugin-flowtype@^2.44.0: + version "2.44.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.44.0.tgz#c0610d0018801e1fbe1eaec1c2174de1338ab4ee" dependencies: lodash "^4.15.0" @@ -7444,9 +7444,9 @@ range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" -raven-js@^3.22.2: - version "3.22.2" - resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.22.2.tgz#85785928ebd664049e54efd0db8ff28da0cbb374" +raven-js@^3.22.3: + version "3.22.3" + resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.22.3.tgz#8330dcc102b699ffbc2f48790978b997bf4d8f75" raven@^2.4.1: version "2.4.1"