Footer.jsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. const FOOTER_SYNC_ID = 'footerSyncId';
  32. const CPU = 'cpu';
  33. const MEMORY = 'memory';
  34. const DISK = 'disk';
  35. const TRAFFIC = 'traffic';
  36. const TOP = 'Top';
  37. const BOTTOM = 'Bottom';
  38. const cpuLabelTop = 'Process load';
  39. const cpuLabelBottom = 'System load';
  40. const memoryLabelTop = 'Active memory';
  41. const memoryLabelBottom = 'Virtual memory';
  42. const diskLabelTop = 'Disk read';
  43. const diskLabelBottom = 'Disk write';
  44. const trafficLabelTop = 'Download';
  45. const trafficLabelBottom = 'Upload';
  46. // styles contains the constant styles of the component.
  47. const styles = {
  48. footer: {
  49. maxWidth: '100%',
  50. flexWrap: 'nowrap',
  51. margin: 0,
  52. },
  53. chartRowWrapper: {
  54. height: '100%',
  55. padding: 0,
  56. },
  57. doubleChartWrapper: {
  58. height: '100%',
  59. width: '99%',
  60. },
  61. link: {
  62. color: 'inherit',
  63. textDecoration: 'none',
  64. },
  65. };
  66. // themeStyles returns the styles generated from the theme for the component.
  67. const themeStyles: Object = (theme: Object) => ({
  68. footer: {
  69. backgroundColor: theme.palette.grey[900],
  70. color: theme.palette.getContrastText(theme.palette.grey[900]),
  71. zIndex: theme.zIndex.appBar,
  72. height: theme.spacing.unit * 10,
  73. },
  74. });
  75. export type Props = {
  76. classes: Object, // injected by withStyles()
  77. theme: Object,
  78. general: General,
  79. system: System,
  80. shouldUpdate: Object,
  81. };
  82. type State = {};
  83. // Footer renders the footer of the dashboard.
  84. class Footer extends Component<Props, State> {
  85. shouldComponentUpdate(nextProps: Readonly<Props>, nextState: Readonly<State>, nextContext: any) {
  86. return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined';
  87. }
  88. // halfHeightChart renders an area chart with half of the height of its parent.
  89. halfHeightChart = (chartProps, tooltip, areaProps, label, position) => (
  90. <ResponsiveContainer width='100%' height='50%'>
  91. <AreaChart {...chartProps}>
  92. {!tooltip || (<Tooltip cursor={false} content={<CustomTooltip tooltip={tooltip} />} />)}
  93. <Area isAnimationActive={false} strokeWidth={chartStrokeWidth} type='monotone' {...areaProps} />
  94. <ReferenceLine x={0} strokeWidth={0}>
  95. <Label fill={areaProps.fill} value={label} position={position} />
  96. </ReferenceLine>
  97. </AreaChart>
  98. </ResponsiveContainer>
  99. );
  100. // doubleChart renders a pair of charts separated by the baseline.
  101. doubleChart = (syncId, chartKey, topChart, bottomChart) => {
  102. if (!Array.isArray(topChart.data) || !Array.isArray(bottomChart.data)) {
  103. return null;
  104. }
  105. const topDefault = topChart.default || 0;
  106. const bottomDefault = bottomChart.default || 0;
  107. const topKey = `${chartKey}${TOP}`;
  108. const bottomKey = `${chartKey}${BOTTOM}`;
  109. const topColor = '#8884d8';
  110. const bottomColor = '#82ca9d';
  111. return (
  112. <div style={styles.doubleChartWrapper}>
  113. {this.halfHeightChart(
  114. {
  115. syncId,
  116. data: topChart.data.map(({value}) => ({[topKey]: value || topDefault})),
  117. margin: {top: 5, right: 5, bottom: 0, left: 5},
  118. },
  119. topChart.tooltip,
  120. {dataKey: topKey, stroke: topColor, fill: topColor},
  121. topChart.label,
  122. 'insideBottomLeft',
  123. )}
  124. {this.halfHeightChart(
  125. {
  126. syncId,
  127. data: bottomChart.data.map(({value}) => ({[bottomKey]: -value || -bottomDefault})),
  128. margin: {top: 0, right: 5, bottom: 5, left: 5},
  129. },
  130. bottomChart.tooltip,
  131. {dataKey: bottomKey, stroke: bottomColor, fill: bottomColor},
  132. bottomChart.label,
  133. 'insideTopLeft',
  134. )}
  135. </div>
  136. );
  137. };
  138. render() {
  139. const {general, system} = this.props;
  140. return (
  141. <Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
  142. <Grid item xs style={styles.chartRowWrapper}>
  143. <ChartRow>
  144. {this.doubleChart(
  145. FOOTER_SYNC_ID,
  146. CPU,
  147. {data: system.processCPU, tooltip: percentPlotter(cpuLabelTop), label: cpuLabelTop},
  148. {data: system.systemCPU, tooltip: percentPlotter(cpuLabelBottom, multiplier(-1)), label: cpuLabelBottom},
  149. )}
  150. {this.doubleChart(
  151. FOOTER_SYNC_ID,
  152. MEMORY,
  153. {data: system.activeMemory, tooltip: bytePlotter(memoryLabelTop), label: memoryLabelTop},
  154. {data: system.virtualMemory, tooltip: bytePlotter(memoryLabelBottom, multiplier(-1)), label: memoryLabelBottom},
  155. )}
  156. {this.doubleChart(
  157. FOOTER_SYNC_ID,
  158. DISK,
  159. {data: system.diskRead, tooltip: bytePerSecPlotter(diskLabelTop), label: diskLabelTop},
  160. {data: system.diskWrite, tooltip: bytePerSecPlotter(diskLabelBottom, multiplier(-1)), label: diskLabelBottom},
  161. )}
  162. {this.doubleChart(
  163. FOOTER_SYNC_ID,
  164. TRAFFIC,
  165. {data: system.networkIngress, tooltip: bytePerSecPlotter(trafficLabelTop), label: trafficLabelTop},
  166. {data: system.networkEgress, tooltip: bytePerSecPlotter(trafficLabelBottom, multiplier(-1)), label: trafficLabelBottom},
  167. )}
  168. </ChartRow>
  169. </Grid>
  170. <Grid item>
  171. <Typography type='caption' color='inherit'>
  172. <span style={commonStyles.light}>Geth</span> {general.version}
  173. </Typography>
  174. {general.commit && (
  175. <Typography type='caption' color='inherit'>
  176. <span style={commonStyles.light}>{'Commit '}</span>
  177. <a
  178. href={`https://github.com/ethereum/go-ethereum/commit/${general.commit}`}
  179. target='_blank'
  180. rel='noopener noreferrer'
  181. style={styles.link}
  182. >
  183. {general.commit.substring(0, 8)}
  184. </a>
  185. </Typography>
  186. )}
  187. </Grid>
  188. </Grid>
  189. );
  190. }
  191. }
  192. export default withStyles(themeStyles)(Footer);