diff options
Diffstat (limited to 'dashboard/assets')
-rw-r--r-- | dashboard/assets/common.jsx | 2 | ||||
-rw-r--r-- | dashboard/assets/components/Body.jsx | 10 | ||||
-rw-r--r-- | dashboard/assets/components/CustomTooltip.jsx | 2 | ||||
-rw-r--r-- | dashboard/assets/components/Dashboard.jsx | 45 | ||||
-rw-r--r-- | dashboard/assets/components/Logs.jsx | 310 | ||||
-rw-r--r-- | dashboard/assets/components/Main.jsx | 54 | ||||
-rw-r--r-- | dashboard/assets/index.html | 3 | ||||
-rw-r--r-- | dashboard/assets/types/content.jsx | 60 | ||||
-rw-r--r-- | dashboard/assets/yarn.lock | 195 |
9 files changed, 560 insertions, 121 deletions
diff --git a/dashboard/assets/common.jsx b/dashboard/assets/common.jsx index 08a7554ff..ed2f411fc 100644 --- a/dashboard/assets/common.jsx +++ b/dashboard/assets/common.jsx @@ -68,4 +68,4 @@ export const styles = { light: { color: 'rgba(255, 255, 255, 0.54)', }, -} +}; diff --git a/dashboard/assets/components/Body.jsx b/dashboard/assets/components/Body.jsx index 054e04064..abf8c2f0e 100644 --- a/dashboard/assets/components/Body.jsx +++ b/dashboard/assets/components/Body.jsx @@ -32,11 +32,12 @@ const styles = { }; export type Props = { - opened: boolean, + opened: boolean, changeContent: string => void, - active: string, - content: Content, - shouldUpdate: Object, + active: string, + content: Content, + shouldUpdate: Object, + send: string => void, }; // Body renders the body of the dashboard. @@ -52,6 +53,7 @@ class Body extends Component<Props> { active={this.props.active} content={this.props.content} shouldUpdate={this.props.shouldUpdate} + send={this.props.send} /> </div> ); diff --git a/dashboard/assets/components/CustomTooltip.jsx b/dashboard/assets/components/CustomTooltip.jsx index 3405f9305..f597c1caf 100644 --- a/dashboard/assets/components/CustomTooltip.jsx +++ b/dashboard/assets/components/CustomTooltip.jsx @@ -85,7 +85,7 @@ export type Props = { class CustomTooltip extends Component<Props> { render() { const {active, payload, tooltip} = this.props; - if (!active || typeof tooltip !== 'function') { + if (!active || typeof tooltip !== 'function' || !Array.isArray(payload) || payload.length < 1) { return null; } return tooltip(payload[0].value); diff --git a/dashboard/assets/components/Dashboard.jsx b/dashboard/assets/components/Dashboard.jsx index 8e6bf9869..63c2186ad 100644 --- a/dashboard/assets/components/Dashboard.jsx +++ b/dashboard/assets/components/Dashboard.jsx @@ -24,6 +24,7 @@ import Header from './Header'; import Body from './Body'; import {MENU} from '../common'; import type {Content} from '../types/content'; +import {inserter as logInserter} from './Logs'; // deepUpdate updates an object corresponding to the given update data, which has // the shape of the same structure as the original object. updater also has the same @@ -75,8 +76,11 @@ const appender = <T>(limit: number, mapper = replacer) => (update: Array<T>, pre ...update.map(sample => mapper(sample)), ].slice(-limit); -// defaultContent is the initial value of the state content. -const defaultContent: Content = { +// defaultContent returns the initial value of the state content. Needs to be a function in order to +// instantiate the object again, because it is used by the state, and isn't automatically cleaned +// when a new connection is established. The state is mutated during the update in order to avoid +// the execution of unnecessary operations (e.g. copy of the log array). +const defaultContent: () => Content = () => ({ general: { version: null, commit: null, @@ -95,10 +99,14 @@ const defaultContent: Content = { diskRead: [], diskWrite: [], }, - logs: { - log: [], + logs: { + chunks: [], + endTop: false, + endBottom: true, + topChanged: 0, + bottomChanged: 0, }, -}; +}); // updaters contains the state updater functions for each path of the state. // @@ -122,9 +130,7 @@ const updaters = { diskRead: appender(200), diskWrite: appender(200), }, - logs: { - log: appender(200), - }, + logs: logInserter(5), }; // styles contains the constant styles of the component. @@ -151,10 +157,11 @@ export type Props = { }; type State = { - active: string, // active menu - sideBar: boolean, // true if the sidebar is opened - content: Content, // the visualized data - shouldUpdate: Object, // labels for the components, which need to re-render based on the incoming message + active: string, // active menu + sideBar: boolean, // true if the sidebar is opened + content: Content, // the visualized data + shouldUpdate: Object, // labels for the components, which need to re-render based on the incoming message + server: ?WebSocket, }; // Dashboard is the main component, which renders the whole page, makes connection with the server and @@ -165,8 +172,9 @@ class Dashboard extends Component<Props, State> { this.state = { active: MENU.get('home').id, sideBar: true, - content: defaultContent, + content: defaultContent(), shouldUpdate: {}, + server: null, }; } @@ -181,7 +189,7 @@ class Dashboard extends Component<Props, State> { // PROD is defined by webpack. const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${PROD ? window.location.host : 'localhost:8080'}/api`); server.onopen = () => { - this.setState({content: defaultContent, shouldUpdate: {}}); + this.setState({content: defaultContent(), shouldUpdate: {}, server}); }; server.onmessage = (event) => { const msg: $Shape<Content> = JSON.parse(event.data); @@ -192,10 +200,18 @@ class Dashboard extends Component<Props, State> { this.update(msg); }; server.onclose = () => { + this.setState({server: null}); setTimeout(this.reconnect, 3000); }; }; + // send sends a message to the server, which can be accessed only through this function for safety reasons. + send = (msg: string) => { + if (this.state.server != null) { + this.state.server.send(msg); + } + }; + // update updates the content corresponding to the incoming message. update = (msg: $Shape<Content>) => { this.setState(prevState => ({ @@ -226,6 +242,7 @@ class Dashboard extends Component<Props, State> { active={this.state.active} content={this.state.content} shouldUpdate={this.state.shouldUpdate} + send={this.send} /> </div> ); diff --git a/dashboard/assets/components/Logs.jsx b/dashboard/assets/components/Logs.jsx new file mode 100644 index 000000000..203014276 --- /dev/null +++ b/dashboard/assets/components/Logs.jsx @@ -0,0 +1,310 @@ +// @flow + +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +import React, {Component} from 'react'; + +import List, {ListItem} from 'material-ui/List'; +import type {Record, Content, LogsMessage, Logs as LogsType} from '../types/content'; + +// requestBand says how wide is the top/bottom zone, eg. 0.1 means 10% of the container height. +const requestBand = 0.05; + +// fieldPadding is a global map with maximum field value lengths seen until now +// to allow padding log contexts in a bit smarter way. +const fieldPadding = new Map(); + +// createChunk creates an HTML formatted object, which displays the given array similarly to +// the server side terminal. +const createChunk = (records: Array<Record>) => { + let content = ''; + records.forEach((record) => { + const {t, ctx} = record; + let {lvl, msg} = record; + let color = '#ce3c23'; + switch (lvl) { + case 'trace': + case 'trce': + lvl = 'TRACE'; + color = '#3465a4'; + break; + case 'debug': + case 'dbug': + lvl = 'DEBUG'; + color = '#3d989b'; + break; + case 'info': + lvl = 'INFO '; + color = '#4c8f0f'; + break; + case 'warn': + lvl = 'WARN '; + color = '#b79a22'; + break; + case 'error': + case 'eror': + lvl = 'ERROR'; + color = '#754b70'; + break; + case 'crit': + lvl = 'CRIT '; + color = '#ce3c23'; + break; + default: + lvl = ''; + } + const time = new Date(t); + if (lvl === '' || !(time instanceof Date) || isNaN(time) || typeof msg !== 'string' || !Array.isArray(ctx)) { + content += '<span style="color:#ce3c23">Invalid log record</span><br />'; + return; + } + if (ctx.length > 0) { + msg += ' '.repeat(Math.max(40 - msg.length, 0)); + } + const month = `0${time.getMonth() + 1}`.slice(-2); + const date = `0${time.getDate()}`.slice(-2); + const hours = `0${time.getHours()}`.slice(-2); + const minutes = `0${time.getMinutes()}`.slice(-2); + const seconds = `0${time.getSeconds()}`.slice(-2); + content += `<span style="color:${color}">${lvl}</span>[${month}-${date}|${hours}:${minutes}:${seconds}] ${msg}`; + + for (let i = 0; i < ctx.length; i += 2) { + const key = ctx[i]; + const val = ctx[i + 1]; + let padding = fieldPadding.get(key); + if (typeof padding !== 'number' || padding < val.length) { + padding = val.length; + fieldPadding.set(key, padding); + } + let p = ''; + if (i < ctx.length - 2) { + p = ' '.repeat(padding - val.length); + } + content += ` <span style="color:${color}">${key}</span>=${val}${p}`; + } + content += '<br />'; + }); + return content; +}; + +// inserter is a state updater function for the main component, which inserts the new log chunk into the chunk array. +// limit is the maximum length of the chunk array, used in order to prevent the browser from OOM. +export const inserter = (limit: number) => (update: LogsMessage, prev: LogsType) => { + prev.topChanged = 0; + prev.bottomChanged = 0; + if (!Array.isArray(update.chunk) || update.chunk.length < 1) { + return prev; + } + if (!Array.isArray(prev.chunks)) { + prev.chunks = []; + } + const content = createChunk(update.chunk); + if (!update.source) { + // In case of stream chunk. + if (!prev.endBottom) { + return prev; + } + if (prev.chunks.length < 1) { + // This should never happen, because the first chunk is always a non-stream chunk. + return [{content, name: '00000000000000.log'}]; + } + prev.chunks[prev.chunks.length - 1].content += content; + prev.bottomChanged = 1; + return prev; + } + const chunk = { + content, + name: update.source.name, + }; + if (prev.chunks.length > 0 && update.source.name < prev.chunks[0].name) { + if (update.source.last) { + prev.endTop = true; + } + if (prev.chunks.length >= limit) { + prev.endBottom = false; + prev.chunks.splice(limit - 1, prev.chunks.length - limit + 1); + prev.bottomChanged = -1; + } + prev.chunks = [chunk, ...prev.chunks]; + prev.topChanged = 1; + return prev; + } + if (update.source.last) { + prev.endBottom = true; + } + if (prev.chunks.length >= limit) { + prev.endTop = false; + prev.chunks.splice(0, prev.chunks.length - limit + 1); + prev.topChanged = -1; + } + prev.chunks = [...prev.chunks, chunk]; + prev.bottomChanged = 1; + return prev; +}; + +// styles contains the constant styles of the component. +const styles = { + logListItem: { + padding: 0, + }, + logChunk: { + color: 'white', + fontFamily: 'monospace', + whiteSpace: 'nowrap', + width: 0, + }, +}; + +export type Props = { + container: Object, + content: Content, + shouldUpdate: Object, + send: string => void, +}; + +type State = { + requestAllowed: boolean, +}; + +// Logs renders the log page. +class Logs extends Component<Props, State> { + constructor(props: Props) { + super(props); + this.content = React.createRef(); + this.state = { + requestAllowed: true, + }; + } + + componentDidMount() { + const {container} = this.props; + container.scrollTop = container.scrollHeight - container.clientHeight; + } + + // onScroll is triggered by the parent component's scroll event, and sends requests if the scroll position is + // at the top or at the bottom. + onScroll = () => { + if (!this.state.requestAllowed || typeof this.content === 'undefined') { + return; + } + const {logs} = this.props.content; + if (logs.chunks.length < 1) { + return; + } + if (this.atTop()) { + if (!logs.endTop) { + this.setState({requestAllowed: false}); + this.props.send(JSON.stringify({ + Logs: { + Name: logs.chunks[0].name, + Past: true, + }, + })); + } + } else if (this.atBottom()) { + if (!logs.endBottom) { + this.setState({requestAllowed: false}); + this.props.send(JSON.stringify({ + Logs: { + Name: logs.chunks[logs.chunks.length - 1].name, + Past: false, + }, + })); + } + } + }; + + // atTop checks if the scroll position it at the top of the container. + atTop = () => this.props.container.scrollTop <= this.props.container.scrollHeight * requestBand; + + // atBottom checks if the scroll position it at the bottom of the container. + atBottom = () => { + const {container} = this.props; + return container.scrollHeight - container.scrollTop <= + container.clientHeight + container.scrollHeight * requestBand; + }; + + // beforeUpdate is called by the parent component, saves the previous scroll position + // and the height of the first log chunk, which can be deleted during the insertion. + beforeUpdate = () => { + let firstHeight = 0; + if (this.content && this.content.children[0] && this.content.children[0].children[0]) { + firstHeight = this.content.children[0].children[0].clientHeight; + } + return { + scrollTop: this.props.container.scrollTop, + firstHeight, + }; + }; + + // didUpdate is called by the parent component, which provides the container. Sends the first request if the + // visible part of the container isn't full, and resets the scroll position in order to avoid jumping when new + // chunk is inserted. + didUpdate = (prevProps, prevState, snapshot) => { + if (typeof this.props.shouldUpdate.logs === 'undefined' || typeof this.content === 'undefined' || snapshot === null) { + return; + } + const {logs} = this.props.content; + const {container} = this.props; + if (typeof container === 'undefined' || logs.chunks.length < 1) { + return; + } + if (this.content.clientHeight < container.clientHeight) { + // Only enters here at the beginning, when there isn't enough log to fill the container + // and the scroll bar doesn't appear. + if (!logs.endTop) { + this.setState({requestAllowed: false}); + this.props.send(JSON.stringify({ + Logs: { + Name: logs.chunks[0].name, + Past: true, + }, + })); + } + return; + } + const chunks = this.content.children[0].children; + let {scrollTop} = snapshot; + if (logs.topChanged > 0) { + scrollTop += chunks[0].clientHeight; + } else if (logs.bottomChanged > 0) { + if (logs.topChanged < 0) { + scrollTop -= snapshot.firstHeight; + } else if (logs.endBottom && this.atBottom()) { + scrollTop = container.scrollHeight - container.clientHeight; + } + } + container.scrollTop = scrollTop; + this.setState({requestAllowed: true}); + }; + + render() { + return ( + <div ref={(ref) => { this.content = ref; }}> + <List> + {this.props.content.logs.chunks.map((c, index) => ( + <ListItem style={styles.logListItem} key={index}> + <div style={styles.logChunk} dangerouslySetInnerHTML={{__html: c.content}} /> + </ListItem> + ))} + </List> + </div> + ); + } +} + +export default Logs; diff --git a/dashboard/assets/components/Main.jsx b/dashboard/assets/components/Main.jsx index fba8ca1f6..0018aaf75 100644 --- a/dashboard/assets/components/Main.jsx +++ b/dashboard/assets/components/Main.jsx @@ -21,6 +21,7 @@ import React, {Component} from 'react'; import withStyles from 'material-ui/styles/withStyles'; import {MENU} from '../common'; +import Logs from './Logs'; import Footer from './Footer'; import type {Content} from '../types/content'; @@ -32,7 +33,7 @@ const styles = { width: '100%', }, content: { - flex: 1, + flex: 1, overflow: 'auto', }, }; @@ -46,14 +47,40 @@ const themeStyles = theme => ({ }); export type Props = { - classes: Object, - active: string, - content: Content, + classes: Object, + active: string, + content: Content, shouldUpdate: Object, + send: string => void, }; // Main renders the chosen content. class Main extends Component<Props> { + constructor(props) { + super(props); + this.container = React.createRef(); + this.content = React.createRef(); + } + + getSnapshotBeforeUpdate() { + if (this.content && typeof this.content.beforeUpdate === 'function') { + return this.content.beforeUpdate(); + } + return null; + } + + componentDidUpdate(prevProps, prevState, snapshot) { + if (this.content && typeof this.content.didUpdate === 'function') { + this.content.didUpdate(prevProps, prevState, snapshot); + } + } + + onScroll = () => { + if (this.content && typeof this.content.onScroll === 'function') { + this.content.onScroll(); + } + }; + render() { const { classes, active, content, shouldUpdate, @@ -69,12 +96,27 @@ class Main extends Component<Props> { children = <div>Work in progress.</div>; break; case MENU.get('logs').id: - children = <div>{content.logs.log.map((log, index) => <div key={index}>{log}</div>)}</div>; + children = ( + <Logs + ref={(ref) => { this.content = ref; }} + container={this.container} + send={this.props.send} + content={this.props.content} + shouldUpdate={shouldUpdate} + /> + ); } return ( <div style={styles.wrapper}> - <div className={classes.content} style={styles.content}>{children}</div> + <div + className={classes.content} + style={styles.content} + ref={(ref) => { this.container = ref; }} + onScroll={this.onScroll} + > + {children} + </div> <Footer general={content.general} system={content.system} diff --git a/dashboard/assets/index.html b/dashboard/assets/index.html index 2491bf1ea..1211d1521 100644 --- a/dashboard/assets/index.html +++ b/dashboard/assets/index.html @@ -14,6 +14,9 @@ ::-webkit-scrollbar-thumb { background: #212121; } + ::-webkit-scrollbar-corner { + background: transparent; + } </style> </head> <body style="height: 100%; margin: 0"> diff --git a/dashboard/assets/types/content.jsx b/dashboard/assets/types/content.jsx index 0e2e0b49d..ff82c3572 100644 --- a/dashboard/assets/types/content.jsx +++ b/dashboard/assets/types/content.jsx @@ -18,24 +18,24 @@ export type Content = { general: General, - home: Home, - chain: Chain, - txpool: TxPool, + home: Home, + chain: Chain, + txpool: TxPool, network: Network, - system: System, - logs: Logs, + system: System, + logs: Logs, }; export type ChartEntries = Array<ChartEntry>; export type ChartEntry = { - time: Date, + time: Date, value: number, }; export type General = { - version: ?string, - commit: ?string, + version: ?string, + commit: ?string, }; export type Home = { @@ -55,16 +55,42 @@ export type Network = { }; export type System = { - activeMemory: ChartEntries, - virtualMemory: ChartEntries, - networkIngress: ChartEntries, - networkEgress: ChartEntries, - processCPU: ChartEntries, - systemCPU: ChartEntries, - diskRead: ChartEntries, - diskWrite: ChartEntries, + activeMemory: ChartEntries, + virtualMemory: ChartEntries, + networkIngress: ChartEntries, + networkEgress: ChartEntries, + processCPU: ChartEntries, + systemCPU: ChartEntries, + diskRead: ChartEntries, + diskWrite: ChartEntries, +}; + +export type Record = { + t: string, + lvl: Object, + msg: string, + ctx: Array<string> +}; + +export type Chunk = { + content: string, + name: string, }; export type Logs = { - log: Array<string>, + chunks: Array<Chunk>, + endTop: boolean, + endBottom: boolean, + topChanged: number, + bottomChanged: number, +}; + +export type LogsMessage = { + source: ?LogFile, + chunk: Array<Record>, +}; + +export type LogFile = { + name: string, + last: string, }; diff --git a/dashboard/assets/yarn.lock b/dashboard/assets/yarn.lock index 7480c719f..0098d202b 100644 --- a/dashboard/assets/yarn.lock +++ b/dashboard/assets/yarn.lock @@ -2,70 +2,77 @@ # yarn lockfile v1 -"@babel/code-frame@7.0.0-beta.40", "@babel/code-frame@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6" +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" dependencies: - "@babel/highlight" "7.0.0-beta.40" + "@babel/highlight" "7.0.0-beta.44" -"@babel/generator@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.40.tgz#ab61f9556f4f71dbd1138949c795bb9a21e302ea" +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" jsesc "^2.5.1" lodash "^4.2.0" source-map "^0.5.0" trim-right "^1.0.1" -"@babel/helper-function-name@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6" +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-get-function-arity@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz#ac0419cf067b0ec16453e1274f03878195791c6e" +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" -"@babel/highlight@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.40.tgz#b43d67d76bf46e1d10d227f68cddcd263786b255" +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^3.0.0" -"@babel/template@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.40.tgz#034988c6424eb5c3268fe6a608626de1f4410fc8" +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" dependencies: - "@babel/code-frame" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" - babylon "7.0.0-beta.40" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" lodash "^4.2.0" -"@babel/traverse@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.40.tgz#d140e449b2e093ef9fe1a2eecc28421ffb4e521e" +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" dependencies: - "@babel/code-frame" "7.0.0-beta.40" - "@babel/generator" "7.0.0-beta.40" - "@babel/helper-function-name" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" - babylon "7.0.0-beta.40" - debug "^3.0.1" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" globals "^11.1.0" invariant "^2.2.0" lodash "^4.2.0" -"@babel/types@7.0.0-beta.40", "@babel/types@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14" +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" dependencies: esutils "^2.0.2" lodash "^4.2.0" @@ -376,8 +383,8 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: js-tokens "^3.0.2" babel-core@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -389,24 +396,24 @@ babel-core@^6.26.0: babel-traverse "^6.26.0" babel-types "^6.26.0" babylon "^6.18.0" - convert-source-map "^1.5.0" - debug "^2.6.8" + convert-source-map "^1.5.1" + debug "^2.6.9" json5 "^0.5.1" lodash "^4.17.4" minimatch "^3.0.4" path-is-absolute "^1.0.1" - private "^0.1.7" + private "^0.1.8" slash "^1.0.0" - source-map "^0.5.6" + source-map "^0.5.7" babel-eslint@^8.2.1: - version "8.2.2" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.2.tgz#1102273354c6f0b29b4ea28a65f97d122296b68b" + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" dependencies: - "@babel/code-frame" "^7.0.0-beta.40" - "@babel/traverse" "^7.0.0-beta.40" - "@babel/types" "^7.0.0-beta.40" - babylon "^7.0.0-beta.40" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" eslint-scope "~3.7.1" eslint-visitor-keys "^1.0.0" @@ -550,8 +557,8 @@ babel-helpers@^6.24.1: babel-template "^6.24.1" babel-loader@^7.1.2: - version "7.1.3" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.3.tgz#ff5b440da716e9153abb946251a9ab7670037b16" + version "7.1.4" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015" dependencies: find-cache-dir "^1.0.0" loader-utils "^1.0.2" @@ -1081,9 +1088,9 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@7.0.0-beta.40, babylon@^7.0.0-beta.40: - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a" +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" babylon@^6.18.0: version "6.18.0" @@ -1413,7 +1420,15 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.1: +chalk@^2.0.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^2.1.0, chalk@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: @@ -1646,7 +1661,7 @@ content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" -convert-source-map@^1.5.0: +convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" @@ -1671,8 +1686,8 @@ core-js@^1.0.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0, core-js@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -1914,7 +1929,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6. dependencies: ms "2.0.0" -debug@^3.0.1, debug@^3.1.0: +debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2916,10 +2931,14 @@ global@~4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^11.0.1, globals@^11.1.0: +globals@^11.0.1: version "11.3.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0" +globals@^11.1.0: + version "11.5.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -3176,10 +3195,16 @@ hyphenate-style-name@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" -iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: +iconv-lite@0.4.19, iconv-lite@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@~0.4.13: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -3272,8 +3297,8 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" invariant@^2.2.0, invariant@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: loose-envify "^1.0.0" @@ -3863,10 +3888,14 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: +lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.3.0, lodash@~4.17.4: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" +lodash@^4.17.4, lodash@^4.2.0: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + loglevel@^1.4.1: version "1.6.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" @@ -3904,8 +3933,8 @@ macaddress@^0.2.8: resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" make-dir@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" dependencies: pify "^3.0.0" @@ -4895,7 +4924,7 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -private@^0.1.6, private@^0.1.7: +private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -5061,8 +5090,8 @@ rc@^1.1.7: strip-json-comments "~2.0.1" react-dom@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" + version "16.4.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -5138,8 +5167,8 @@ react-transition-group@^2.2.1: warning "^3.0.0" react@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" + version "16.4.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -5471,6 +5500,10 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -5914,12 +5947,18 @@ supports-color@^4.2.1: dependencies: has-flag "^2.0.0" -supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0: +supports-color@^5.1.0, supports-color@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" dependencies: has-flag "^3.0.0" +supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + svgo@^0.7.0: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" @@ -6108,8 +6147,8 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + version "0.7.18" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" uglify-js@^2.8.29: version "2.8.29" @@ -6395,8 +6434,8 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" whatwg-fetch@>=0.10.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" whet.extend@~0.9.9: version "0.9.9" |