diff options
Diffstat (limited to 'dashboard/assets/components/Footer.jsx')
-rw-r--r-- | dashboard/assets/components/Footer.jsx | 158 |
1 files changed, 82 insertions, 76 deletions
diff --git a/dashboard/assets/components/Footer.jsx b/dashboard/assets/components/Footer.jsx index 54b67c464..20830cbba 100644 --- a/dashboard/assets/components/Footer.jsx +++ b/dashboard/assets/components/Footer.jsx @@ -26,7 +26,17 @@ import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts'; import ChartRow from './ChartRow'; import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip'; import {styles as commonStyles} from '../common'; -import type {Content} from '../types/content'; +import type {General, System} from '../types/content'; + +const FOOTER_SYNC_ID = 'footerSyncId'; + +const CPU = 'cpu'; +const MEMORY = 'memory'; +const DISK = 'disk'; +const TRAFFIC = 'traffic'; + +const TOP = 'Top'; +const BOTTOM = 'Bottom'; // styles contains the constant styles of the component. const styles = { @@ -40,17 +50,16 @@ const styles = { padding: 0, }, doubleChartWrapper: { - height: '100%', - width: '99%', - paddingTop: 5, + height: '100%', + width: '99%', }, }; // themeStyles returns the styles generated from the theme for the component. const themeStyles: Object = (theme: Object) => ({ footer: { - backgroundColor: theme.palette.background.appBar, - color: theme.palette.getContrastText(theme.palette.background.appBar), + backgroundColor: theme.palette.grey[900], + color: theme.palette.getContrastText(theme.palette.grey[900]), zIndex: theme.zIndex.appBar, height: theme.spacing.unit * 10, }, @@ -59,111 +68,108 @@ const themeStyles: Object = (theme: Object) => ({ export type Props = { classes: Object, // injected by withStyles() theme: Object, - content: Content, + general: General, + system: System, shouldUpdate: Object, }; // Footer renders the footer of the dashboard. class Footer extends Component<Props> { shouldComponentUpdate(nextProps) { - return typeof nextProps.shouldUpdate.home !== 'undefined'; + return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined'; } - // info renders a label with the given values. - info = (about: string, value: ?string) => (value ? ( - <Typography type='caption' color='inherit'> - <span style={commonStyles.light}>{about}</span> {value} - </Typography> - ) : null); + // halfHeightChart renders an area chart with half of the height of its parent. + halfHeightChart = (chartProps, tooltip, areaProps) => ( + <ResponsiveContainer width='100%' height='50%'> + <AreaChart {...chartProps} > + {!tooltip || (<Tooltip cursor={false} content={<CustomTooltip tooltip={tooltip} />} />)} + <Area isAnimationActive={false} type='monotone' {...areaProps} /> + </AreaChart> + </ResponsiveContainer> + ); // doubleChart renders a pair of charts separated by the baseline. - doubleChart = (syncId, topChart, bottomChart) => { - const topKey = 'topKey'; - const bottomKey = 'bottomKey'; - const topDefault = topChart.default ? topChart.default : 0; - const bottomDefault = bottomChart.default ? bottomChart.default : 0; - const topTooltip = topChart.tooltip ? ( - <Tooltip cursor={false} content={<CustomTooltip tooltip={topChart.tooltip} />} /> - ) : null; - const bottomTooltip = bottomChart.tooltip ? ( - <Tooltip cursor={false} content={<CustomTooltip tooltip={bottomChart.tooltip} />} /> - ) : null; + doubleChart = (syncId, chartKey, topChart, bottomChart) => { + if (!Array.isArray(topChart.data) || !Array.isArray(bottomChart.data)) { + return null; + } + const topDefault = topChart.default || 0; + const bottomDefault = bottomChart.default || 0; + const topKey = `${chartKey}${TOP}`; + const bottomKey = `${chartKey}${BOTTOM}`; const topColor = '#8884d8'; const bottomColor = '#82ca9d'; - // Put the samples of the two charts into the same array in order to avoid problems - // at the synchronized area charts. If one of the two arrays doesn't have value at - // a given position, give it a 0 default value. - let data = [...topChart.data.map(({value}) => { - const d = {}; - d[topKey] = value || topDefault; - return d; - })]; - for (let i = 0; i < data.length && i < bottomChart.data.length; i++) { - // The value needs to be negative in order to plot it upside down. - const d = bottomChart.data[i]; - data[i][bottomKey] = d && d.value ? -d.value : bottomDefault; - } - data = [...data, ...bottomChart.data.slice(data.length).map(({value}) => { - const d = {}; - d[topKey] = topDefault; - d[bottomKey] = -value || bottomDefault; - return d; - })]; - return ( <div style={styles.doubleChartWrapper}> - <ResponsiveContainer width='100%' height='50%'> - <AreaChart data={data} syncId={syncId} > - {topTooltip} - <Area type='monotone' dataKey={topKey} stroke={topColor} fill={topColor} /> - </AreaChart> - </ResponsiveContainer> - <div style={{marginTop: -10, width: '100%', height: '50%'}}> - <ResponsiveContainer width='100%' height='100%'> - <AreaChart data={data} syncId={syncId} > - {bottomTooltip} - <Area type='monotone' dataKey={bottomKey} stroke={bottomColor} fill={bottomColor} /> - </AreaChart> - </ResponsiveContainer> - </div> + {this.halfHeightChart( + { + syncId, + data: topChart.data.map(({value}) => ({[topKey]: value || topDefault})), + margin: {top: 5, right: 5, bottom: 0, left: 5}, + }, + topChart.tooltip, + {dataKey: topKey, stroke: topColor, fill: topColor}, + )} + {this.halfHeightChart( + { + syncId, + data: bottomChart.data.map(({value}) => ({[bottomKey]: -value || -bottomDefault})), + margin: {top: 0, right: 5, bottom: 5, left: 5}, + }, + bottomChart.tooltip, + {dataKey: bottomKey, stroke: bottomColor, fill: bottomColor}, + )} </div> ); - } + }; render() { - const {content} = this.props; - const {general, home} = content; + const {general, system} = this.props; return ( <Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}> <Grid item xs style={styles.chartRowWrapper}> <ChartRow> {this.doubleChart( - 'all', - {data: home.processCPU, tooltip: percentPlotter('Process')}, - {data: home.systemCPU, tooltip: percentPlotter('System', multiplier(-1))}, + FOOTER_SYNC_ID, + CPU, + {data: system.processCPU, tooltip: percentPlotter('Process load')}, + {data: system.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))}, )} {this.doubleChart( - 'all', - {data: home.activeMemory, tooltip: bytePlotter('Active')}, - {data: home.virtualMemory, tooltip: bytePlotter('Virtual', multiplier(-1))}, + FOOTER_SYNC_ID, + MEMORY, + {data: system.activeMemory, tooltip: bytePlotter('Active memory')}, + {data: system.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))}, )} {this.doubleChart( - 'all', - {data: home.diskRead, tooltip: bytePerSecPlotter('Disk Read')}, - {data: home.diskWrite, tooltip: bytePerSecPlotter('Disk Write', multiplier(-1))}, + FOOTER_SYNC_ID, + DISK, + {data: system.diskRead, tooltip: bytePerSecPlotter('Disk read')}, + {data: system.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))}, )} {this.doubleChart( - 'all', - {data: home.networkIngress, tooltip: bytePerSecPlotter('Download')}, - {data: home.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))}, + FOOTER_SYNC_ID, + TRAFFIC, + {data: system.networkIngress, tooltip: bytePerSecPlotter('Download')}, + {data: system.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))}, )} </ChartRow> </Grid> <Grid item > - {this.info('Geth', general.version)} - {this.info('Commit', general.commit ? general.commit.substring(0, 7) : null)} + <Typography type='caption' color='inherit'> + <span style={commonStyles.light}>Geth</span> {general.version} + </Typography> + {general.commit && ( + <Typography type='caption' color='inherit'> + <span style={commonStyles.light}>{'Commit '}</span> + <a href={`https://github.com/ethereum/go-ethereum/commit/${general.commit}`} target='_blank' style={{color: 'inherit', textDecoration: 'none'}} > + {general.commit.substring(0, 8)} + </a> + </Typography> + )} </Grid> </Grid> ); |