Footer.jsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // @flow
  2. // Copyright 2017 The go-ethereum Authors
  3. // This file is part of the go-ethereum library.
  4. //
  5. // The go-ethereum library is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Lesser General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // The go-ethereum library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public License
  16. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  17. import React, {Component} from 'react';
  18. import withStyles from '@material-ui/core/styles/withStyles';
  19. import Typography from '@material-ui/core/Typography';
  20. import Grid from '@material-ui/core/Grid';
  21. import ResponsiveContainer from 'recharts/es6/component/ResponsiveContainer';
  22. import AreaChart from 'recharts/es6/chart/AreaChart';
  23. import Area from 'recharts/es6/cartesian/Area';
  24. import ReferenceLine from 'recharts/es6/cartesian/ReferenceLine';
  25. import Label from 'recharts/es6/component/Label';
  26. import Tooltip from 'recharts/es6/component/Tooltip';
  27. import ChartRow from 'ChartRow';
  28. import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from 'CustomTooltip';
  29. import {chartStrokeWidth, styles as commonStyles} from '../common';
  30. import type {General, System} from '../types/content';
  31. import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
  32. import {faNetworkWired} from "@fortawesome/free-solid-svg-icons";
  33. import Toolbar from "@material-ui/core/Toolbar";
  34. const FOOTER_SYNC_ID = 'footerSyncId';
  35. const CPU = 'cpu';
  36. const MEMORY = 'memory';
  37. const DISK = 'disk';
  38. const TRAFFIC = 'traffic';
  39. const TOP = 'Top';
  40. const BOTTOM = 'Bottom';
  41. const cpuLabelTop = 'Process load';
  42. const cpuLabelBottom = 'System load';
  43. const memoryLabelTop = 'Active memory';
  44. const memoryLabelBottom = 'Virtual memory';
  45. const diskLabelTop = 'Disk read';
  46. const diskLabelBottom = 'Disk write';
  47. const trafficLabelTop = 'Download';
  48. const trafficLabelBottom = 'Upload';
  49. // styles contains the constant styles of the component.
  50. const styles = {
  51. footer: {
  52. maxWidth: '100%',
  53. flexWrap: 'nowrap',
  54. margin: 0,
  55. },
  56. chartRowWrapper: {
  57. height: '100%',
  58. padding: 0,
  59. },
  60. doubleChartWrapper: {
  61. height: '100%',
  62. width: '99%',
  63. },
  64. link: {
  65. color: 'inherit',
  66. textDecoration: 'none',
  67. },
  68. };
  69. // themeStyles returns the styles generated from the theme for the component.
  70. const themeStyles: Object = (theme: Object) => ({
  71. footer: {
  72. backgroundColor: theme.palette.grey[900],
  73. color: theme.palette.getContrastText(theme.palette.grey[900]),
  74. zIndex: theme.zIndex.appBar,
  75. height: theme.spacing.unit * 10,
  76. },
  77. });
  78. export type Props = {
  79. classes: Object, // injected by withStyles()
  80. theme: Object,
  81. general: General,
  82. system: System,
  83. shouldUpdate: Object,
  84. };
  85. type State = {};
  86. // Footer renders the footer of the dashboard.
  87. class Footer extends Component<Props, State> {
  88. shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<State>, nextContext: any) {
  89. return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined';
  90. }
  91. // halfHeightChart renders an area chart with half of the height of its parent.
  92. halfHeightChart = (chartProps, tooltip, areaProps, label, position) => (
  93. <ResponsiveContainer width='100%' height='50%'>
  94. <AreaChart {...chartProps}>
  95. {!tooltip || (<Tooltip cursor={false} content={<CustomTooltip tooltip={tooltip} />} />)}
  96. <Area isAnimationActive={false} strokeWidth={chartStrokeWidth} type='monotone' {...areaProps} />
  97. <ReferenceLine x={0} strokeWidth={0}>
  98. <Label fill={areaProps.fill} value={label} position={position} />
  99. </ReferenceLine>
  100. </AreaChart>
  101. </ResponsiveContainer>
  102. );
  103. // doubleChart renders a pair of charts separated by the baseline.
  104. doubleChart = (syncId, chartKey, topChart, bottomChart) => {
  105. if (!Array.isArray(topChart.data) || !Array.isArray(bottomChart.data)) {
  106. return null;
  107. }
  108. const topDefault = topChart.default || 0;
  109. const bottomDefault = bottomChart.default || 0;
  110. const topKey = `${chartKey}${TOP}`;
  111. const bottomKey = `${chartKey}${BOTTOM}`;
  112. const topColor = '#8884d8';
  113. const bottomColor = '#82ca9d';
  114. return (
  115. <div style={styles.doubleChartWrapper}>
  116. {this.halfHeightChart(
  117. {
  118. syncId,
  119. data: topChart.data.map(({value}) => ({[topKey]: value || topDefault})),
  120. margin: {top: 5, right: 5, bottom: 0, left: 5},
  121. },
  122. topChart.tooltip,
  123. {dataKey: topKey, stroke: topColor, fill: topColor},
  124. topChart.label,
  125. 'insideBottomLeft',
  126. )}
  127. {this.halfHeightChart(
  128. {
  129. syncId,
  130. data: bottomChart.data.map(({value}) => ({[bottomKey]: -value || -bottomDefault})),
  131. margin: {top: 0, right: 5, bottom: 5, left: 5},
  132. },
  133. bottomChart.tooltip,
  134. {dataKey: bottomKey, stroke: bottomColor, fill: bottomColor},
  135. bottomChart.label,
  136. 'insideTopLeft',
  137. )}
  138. </div>
  139. );
  140. };
  141. render() {
  142. const {general, system} = this.props;
  143. let network = '';
  144. switch (general.genesis) {
  145. case '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3':
  146. network = 'main';
  147. break;
  148. case '0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d':
  149. network = 'ropsten';
  150. break;
  151. case '0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177':
  152. network = 'rinkeby';
  153. break;
  154. case '0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a':
  155. network = 'görli';
  156. break;
  157. default:
  158. network = `unknown (${general.genesis.substring(0, 8)})`;
  159. }
  160. return (
  161. <Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
  162. <Grid item xs style={styles.chartRowWrapper}>
  163. <ChartRow>
  164. {this.doubleChart(
  165. FOOTER_SYNC_ID,
  166. CPU,
  167. {data: system.processCPU, tooltip: percentPlotter(cpuLabelTop), label: cpuLabelTop},
  168. {data: system.systemCPU, tooltip: percentPlotter(cpuLabelBottom, multiplier(-1)), label: cpuLabelBottom},
  169. )}
  170. {this.doubleChart(
  171. FOOTER_SYNC_ID,
  172. MEMORY,
  173. {data: system.activeMemory, tooltip: bytePlotter(memoryLabelTop), label: memoryLabelTop},
  174. {data: system.virtualMemory, tooltip: bytePlotter(memoryLabelBottom, multiplier(-1)), label: memoryLabelBottom},
  175. )}
  176. {this.doubleChart(
  177. FOOTER_SYNC_ID,
  178. DISK,
  179. {data: system.diskRead, tooltip: bytePerSecPlotter(diskLabelTop), label: diskLabelTop},
  180. {data: system.diskWrite, tooltip: bytePerSecPlotter(diskLabelBottom, multiplier(-1)), label: diskLabelBottom},
  181. )}
  182. {this.doubleChart(
  183. FOOTER_SYNC_ID,
  184. TRAFFIC,
  185. {data: system.networkIngress, tooltip: bytePerSecPlotter(trafficLabelTop), label: trafficLabelTop},
  186. {data: system.networkEgress, tooltip: bytePerSecPlotter(trafficLabelBottom, multiplier(-1)), label: trafficLabelBottom},
  187. )}
  188. </ChartRow>
  189. </Grid>
  190. <Grid item>
  191. <Typography type='caption' color='inherit'>
  192. <span style={commonStyles.light}>Geth</span> {general.version}
  193. </Typography>
  194. {general.commit && (
  195. <Typography type='caption' color='inherit'>
  196. <span style={commonStyles.light}>{'Commit '}</span>
  197. <a
  198. href={`https://github.com/ethereum/go-ethereum/commit/${general.commit}`}
  199. target='_blank'
  200. rel='noopener noreferrer'
  201. style={styles.link}
  202. >
  203. {general.commit.substring(0, 8)}
  204. </a>
  205. </Typography>
  206. )}
  207. <Typography style={styles.headerText}>
  208. <span style={commonStyles.light}>Network</span> {network}
  209. </Typography>
  210. </Grid>
  211. </Grid>
  212. );
  213. }
  214. }
  215. export default withStyles(themeStyles)(Footer);