github.com/tuotoo/go-ethereum@v1.7.4-0.20171121184211-049797d40a24/dashboard/assets/components/Dashboard.jsx (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 import React, {Component} from 'react'; 18 import PropTypes from 'prop-types'; 19 import {withStyles} from 'material-ui/styles'; 20 21 import SideBar from './SideBar.jsx'; 22 import Header from './Header.jsx'; 23 import Main from "./Main.jsx"; 24 import {isNullOrUndefined, LIMIT, TAGS, DATA_KEYS,} from "./Common.jsx"; 25 26 // Styles for the Dashboard component. 27 const styles = theme => ({ 28 appFrame: { 29 position: 'relative', 30 display: 'flex', 31 width: '100%', 32 height: '100%', 33 background: theme.palette.background.default, 34 }, 35 }); 36 37 // Dashboard is the main component, which renders the whole page, makes connection with the server and listens for messages. 38 // When there is an incoming message, updates the page's content correspondingly. 39 class Dashboard extends Component { 40 constructor(props) { 41 super(props); 42 this.state = { 43 active: TAGS.home.id, // active menu 44 sideBar: true, // true if the sidebar is opened 45 memory: [], 46 traffic: [], 47 logs: [], 48 shouldUpdate: {}, 49 }; 50 } 51 52 // componentDidMount initiates the establishment of the first websocket connection after the component is rendered. 53 componentDidMount() { 54 this.reconnect(); 55 } 56 57 // reconnect establishes a websocket connection with the server, listens for incoming messages 58 // and tries to reconnect on connection loss. 59 reconnect = () => { 60 const server = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/api"); 61 62 server.onmessage = event => { 63 const msg = JSON.parse(event.data); 64 if (isNullOrUndefined(msg)) { 65 return; 66 } 67 this.update(msg); 68 }; 69 70 server.onclose = () => { 71 setTimeout(this.reconnect, 3000); 72 }; 73 }; 74 75 // update analyzes the incoming message, and updates the charts' content correspondingly. 76 update = msg => { 77 console.log(msg); 78 this.setState(prevState => { 79 let newState = []; 80 newState.shouldUpdate = {}; 81 const insert = (key, values, limit) => { 82 newState[key] = [...prevState[key], ...values]; 83 while (newState[key].length > limit) { 84 newState[key].shift(); 85 } 86 newState.shouldUpdate[key] = true; 87 }; 88 // (Re)initialize the state with the past data. 89 if (!isNullOrUndefined(msg.history)) { 90 const memory = DATA_KEYS.memory; 91 const traffic = DATA_KEYS.traffic; 92 newState[memory] = []; 93 newState[traffic] = []; 94 if (!isNullOrUndefined(msg.history.memorySamples)) { 95 newState[memory] = msg.history.memorySamples.map(elem => isNullOrUndefined(elem.value) ? 0 : elem.value); 96 while (newState[memory].length > LIMIT.memory) { 97 newState[memory].shift(); 98 } 99 newState.shouldUpdate[memory] = true; 100 } 101 if (!isNullOrUndefined(msg.history.trafficSamples)) { 102 newState[traffic] = msg.history.trafficSamples.map(elem => isNullOrUndefined(elem.value) ? 0 : elem.value); 103 while (newState[traffic].length > LIMIT.traffic) { 104 newState[traffic].shift(); 105 } 106 newState.shouldUpdate[traffic] = true; 107 } 108 } 109 // Insert the new data samples. 110 if (!isNullOrUndefined(msg.memory)) { 111 insert(DATA_KEYS.memory, [isNullOrUndefined(msg.memory.value) ? 0 : msg.memory.value], LIMIT.memory); 112 } 113 if (!isNullOrUndefined(msg.traffic)) { 114 insert(DATA_KEYS.traffic, [isNullOrUndefined(msg.traffic.value) ? 0 : msg.traffic.value], LIMIT.traffic); 115 } 116 if (!isNullOrUndefined(msg.log)) { 117 insert(DATA_KEYS.logs, [msg.log], LIMIT.log); 118 } 119 120 return newState; 121 }); 122 }; 123 124 // The change of the active label on the SideBar component will trigger a new render in the Main component. 125 changeContent = active => { 126 this.setState(prevState => prevState.active !== active ? {active: active} : {}); 127 }; 128 129 openSideBar = () => { 130 this.setState({sideBar: true}); 131 }; 132 133 closeSideBar = () => { 134 this.setState({sideBar: false}); 135 }; 136 137 render() { 138 // The classes property is injected by withStyles(). 139 const {classes} = this.props; 140 141 return ( 142 <div className={classes.appFrame}> 143 <Header 144 opened={this.state.sideBar} 145 open={this.openSideBar} 146 /> 147 <SideBar 148 opened={this.state.sideBar} 149 close={this.closeSideBar} 150 changeContent={this.changeContent} 151 /> 152 <Main 153 opened={this.state.sideBar} 154 active={this.state.active} 155 memory={this.state.memory} 156 traffic={this.state.traffic} 157 logs={this.state.logs} 158 shouldUpdate={this.state.shouldUpdate} 159 /> 160 </div> 161 ); 162 } 163 } 164 165 Dashboard.propTypes = { 166 classes: PropTypes.object.isRequired, 167 }; 168 169 export default withStyles(styles)(Dashboard);