github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/dashboard/assets/components/Footer.jsx (about) 1 // @flow 2 3 // This file is part of the go-sberex library. The go-sberex library is 4 // free software: you can redistribute it and/or modify it under the terms 5 // of the GNU Lesser General Public License as published by the Free 6 // Software Foundation, either version 3 of the License, or (at your option) 7 // any later version. 8 // 9 // The go-sberex 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 GNU Lesser 12 // General Public License <http://www.gnu.org/licenses/> for more details. 13 14 import React, {Component} from 'react'; 15 16 import withStyles from 'material-ui/styles/withStyles'; 17 import Typography from 'material-ui/Typography'; 18 import Grid from 'material-ui/Grid'; 19 import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts'; 20 21 import ChartRow from './ChartRow'; 22 import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip'; 23 import {styles as commonStyles} from '../common'; 24 import type {Content} from '../types/content'; 25 26 // styles contains the constant styles of the component. 27 const styles = { 28 footer: { 29 maxWidth: '100%', 30 flexWrap: 'nowrap', 31 margin: 0, 32 }, 33 chartRowWrapper: { 34 height: '100%', 35 padding: 0, 36 }, 37 doubleChartWrapper: { 38 height: '100%', 39 width: '99%', 40 paddingTop: 5, 41 }, 42 }; 43 44 // themeStyles returns the styles generated from the theme for the component. 45 const themeStyles: Object = (theme: Object) => ({ 46 footer: { 47 backgroundColor: theme.palette.background.appBar, 48 color: theme.palette.getContrastText(theme.palette.background.appBar), 49 zIndex: theme.zIndex.appBar, 50 height: theme.spacing.unit * 10, 51 }, 52 }); 53 54 export type Props = { 55 classes: Object, // injected by withStyles() 56 theme: Object, 57 content: Content, 58 shouldUpdate: Object, 59 }; 60 61 // Footer renders the footer of the dashboard. 62 class Footer extends Component<Props> { 63 shouldComponentUpdate(nextProps) { 64 return typeof nextProps.shouldUpdate.home !== 'undefined'; 65 } 66 67 // info renders a label with the given values. 68 info = (about: string, value: ?string) => (value ? ( 69 <Typography type='caption' color='inherit'> 70 <span style={commonStyles.light}>{about}</span> {value} 71 </Typography> 72 ) : null); 73 74 // doubleChart renders a pair of charts separated by the baseline. 75 doubleChart = (syncId, topChart, bottomChart) => { 76 const topKey = 'topKey'; 77 const bottomKey = 'bottomKey'; 78 const topDefault = topChart.default ? topChart.default : 0; 79 const bottomDefault = bottomChart.default ? bottomChart.default : 0; 80 const topTooltip = topChart.tooltip ? ( 81 <Tooltip cursor={false} content={<CustomTooltip tooltip={topChart.tooltip} />} /> 82 ) : null; 83 const bottomTooltip = bottomChart.tooltip ? ( 84 <Tooltip cursor={false} content={<CustomTooltip tooltip={bottomChart.tooltip} />} /> 85 ) : null; 86 const topColor = '#8884d8'; 87 const bottomColor = '#82ca9d'; 88 89 // Put the samples of the two charts into the same array in order to avoid problems 90 // at the synchronized area charts. If one of the two arrays doesn't have value at 91 // a given position, give it a 0 default value. 92 let data = [...topChart.data.map(({value}) => { 93 const d = {}; 94 d[topKey] = value || topDefault; 95 return d; 96 })]; 97 for (let i = 0; i < data.length && i < bottomChart.data.length; i++) { 98 // The value needs to be negative in order to plot it upside down. 99 const d = bottomChart.data[i]; 100 data[i][bottomKey] = d && d.value ? -d.value : bottomDefault; 101 } 102 data = [...data, ...bottomChart.data.slice(data.length).map(({value}) => { 103 const d = {}; 104 d[topKey] = topDefault; 105 d[bottomKey] = -value || bottomDefault; 106 return d; 107 })]; 108 109 return ( 110 <div style={styles.doubleChartWrapper}> 111 <ResponsiveContainer width='100%' height='50%'> 112 <AreaChart data={data} syncId={syncId} > 113 {topTooltip} 114 <Area type='monotone' dataKey={topKey} stroke={topColor} fill={topColor} /> 115 </AreaChart> 116 </ResponsiveContainer> 117 <div style={{marginTop: -10, width: '100%', height: '50%'}}> 118 <ResponsiveContainer width='100%' height='100%'> 119 <AreaChart data={data} syncId={syncId} > 120 {bottomTooltip} 121 <Area type='monotone' dataKey={bottomKey} stroke={bottomColor} fill={bottomColor} /> 122 </AreaChart> 123 </ResponsiveContainer> 124 </div> 125 </div> 126 ); 127 } 128 129 render() { 130 const {content} = this.props; 131 const {general, home} = content; 132 133 return ( 134 <Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}> 135 <Grid item xs style={styles.chartRowWrapper}> 136 <ChartRow> 137 {this.doubleChart( 138 'all', 139 {data: home.processCPU, tooltip: percentPlotter('Process')}, 140 {data: home.systemCPU, tooltip: percentPlotter('System', multiplier(-1))}, 141 )} 142 {this.doubleChart( 143 'all', 144 {data: home.activeMemory, tooltip: bytePlotter('Active')}, 145 {data: home.virtualMemory, tooltip: bytePlotter('Virtual', multiplier(-1))}, 146 )} 147 {this.doubleChart( 148 'all', 149 {data: home.diskRead, tooltip: bytePerSecPlotter('Disk Read')}, 150 {data: home.diskWrite, tooltip: bytePerSecPlotter('Disk Write', multiplier(-1))}, 151 )} 152 {this.doubleChart( 153 'all', 154 {data: home.networkIngress, tooltip: bytePerSecPlotter('Download')}, 155 {data: home.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))}, 156 )} 157 </ChartRow> 158 </Grid> 159 <Grid item > 160 {this.info('Geth', general.version)} 161 {this.info('Commit', general.commit ? general.commit.substring(0, 7) : null)} 162 </Grid> 163 </Grid> 164 ); 165 } 166 } 167 168 export default withStyles(themeStyles)(Footer);