aboutsummaryrefslogtreecommitdiffstats
path: root/dashboard/assets
diff options
context:
space:
mode:
authorKurkó Mihály <kurkomisi@users.noreply.github.com>2018-07-11 15:59:04 +0800
committerPéter Szilágyi <peterke@gmail.com>2018-07-11 15:59:04 +0800
commita9835c1816bc49ee54c82b4f2a5b05cbcd89881b (patch)
treee1badefd627aa3a7c4e1937eab22b8fe3eb204d1 /dashboard/assets
parent2eedbe799f5eb8766e4808d8a1810cc1c90c4b93 (diff)
downloadgo-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.tar
go-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.tar.gz
go-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.tar.bz2
go-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.tar.lz
go-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.tar.xz
go-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.tar.zst
go-tangerine-a9835c1816bc49ee54c82b4f2a5b05cbcd89881b.zip
cmd, dashboard, log: log collection and exploration (#17097)
* cmd, dashboard, internal, log, node: logging feature * cmd, dashboard, internal, log: requested changes * dashboard, vendor: gofmt, govendor, use vendored file watcher * dashboard, log: gofmt -s -w, goimports * dashboard, log: gosimple
Diffstat (limited to 'dashboard/assets')
-rw-r--r--dashboard/assets/common.jsx2
-rw-r--r--dashboard/assets/components/Body.jsx10
-rw-r--r--dashboard/assets/components/CustomTooltip.jsx2
-rw-r--r--dashboard/assets/components/Dashboard.jsx45
-rw-r--r--dashboard/assets/components/Logs.jsx310
-rw-r--r--dashboard/assets/components/Main.jsx54
-rw-r--r--dashboard/assets/index.html3
-rw-r--r--dashboard/assets/types/content.jsx60
-rw-r--r--dashboard/assets/yarn.lock195
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&nbsp;';
+ color = '#4c8f0f';
+ break;
+ case 'warn':
+ lvl = 'WARN&nbsp;';
+ color = '#b79a22';
+ break;
+ case 'error':
+ case 'eror':
+ lvl = 'ERROR';
+ color = '#754b70';
+ break;
+ case 'crit':
+ lvl = 'CRIT&nbsp;';
+ 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 += '&nbsp;'.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 = '&nbsp;'.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"