Merge pull request #151 from filecoin-project/@colin/analytics-explorations

@colin/analytics explorations
This commit is contained in:
CAKE 2020-08-10 18:34:58 -07:00 committed by GitHub
commit 948bac2781
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 846 additions and 0 deletions

181
components/stats/Chart.js vendored Normal file
View File

@ -0,0 +1,181 @@
import * as React from "react";
import CreateChart from "~/components/stats/CreateChart";
class Chart extends React.Component {
state = {
minX: {},
maxX: {},
minY: {},
maxY: {},
ticks: {},
xLabel: {},
yLabel: {},
organizedData: [],
};
componentDidMount() {
this.getXLabel();
this.getYLabel();
this.getMinX();
this.getMaxX();
this.getMinY();
this.getMaxY();
this.getTicks();
this.sepCategories();
}
//Set Axis Labels
getXLabel() {
const { data } = this.props;
let allLabels = Object.keys(data[0]);
this.setState({
xLabel: allLabels[0],
});
}
getYLabel() {
const { data } = this.props;
let allLabels = Object.keys(data[0]);
this.setState({
yLabel: allLabels[2],
});
}
//Get Min & Max X
getMinX() {
const { data } = this.props;
this.setState({
minX: data[0].date,
});
}
getMaxX() {
const { data } = this.props;
this.setState({
maxX: data[data.length - 1].date,
});
return data[data.length - 1].date;
}
//Get Min & Max Y Values
getMinY() {
const { data } = this.props;
let y = {};
let values = data.map((x) => {
y = x.value;
return y;
});
this.setState({
//Spread operator is slow!! refactor to use for loop or .reduce
minY: Math.min(...values),
});
}
getMaxY() {
const { data } = this.props;
let y = {};
let values = data.map((x) => {
y = x.value;
return y;
});
this.setState({
maxY: Math.max(...values),
});
return Math.max(...values);
}
//Work on logic to pull only 4 values evenly distributed
getTicks() {
const { data } = this.props;
const ticks = [];
const maxTicks = 4;
let y = {};
const dates = data.map((x) => {
y = x.date;
return y;
});
const delta = Math.ceil(dates.length / maxTicks);
for (let i = 0; i < dates.length; i = i + delta) {
ticks.push(dates[i]);
}
this.setState({
ticks: ticks,
});
}
//Organize Categories Into Seperate Arrays within a Larger Array
sepCategories() {
const { data } = this.props;
if (data) {
const oData = [];
const category1 = [];
const category2 = [];
const category3 = [];
data.forEach((data) => {
if (data.category == "1") {
category1.push(data);
}
if (data.category == "2") {
category2.push(data);
}
if (data.category == "3") {
category3.push(data);
}
});
oData.push(category1);
oData.push(category2);
oData.push(category3);
//!bug! Not sure why state is updated but then console.log's nothing
this.setState((prevState) => ({
organizedData: [...prevState.organizedData, oData],
}));
this.createCoordinates(oData);
}
}
//Map through arrays of arrays of an array of objects and add x and y key/value pairs to each object.
createCoordinates(z) {
const oData = z;
const mX = this.getMaxX();
const mY = this.getMaxY();
const deltaY = 600 / mY;
const deltaX = 600 / Date.parse(mX);
for (let group of oData) {
for (let i = 0; i < group.length; i++) {
if (group[i].category) {
let yPoints = group.map((y) => {
y["y"] = Math.floor(y.value * deltaY);
});
let xPoints = group.map((x) => {
x["x"] = Math.floor(Date.parse(x.date) * deltaX);
});
}
}
}
}
//Get All Y Coordinates
render() {
return (
<CreateChart
minX={this.state.minX}
maxX={this.state.maxX}
minY={this.state.minY}
maxY={this.state.maxY}
ticks={this.state.minX.ticks}
xLabel={this.state.xLabel}
yLabel={this.state.yLabel}
organizedData={this.state.organizedData}
/>
);
}
}
export default Chart;

View File

@ -0,0 +1,32 @@
import * as React from "react";
import HardChart from "~/components/stats/HardChart";
import Chart from "~/components/stats/Chart";
const MOCKDATA = [
{ date: "December 17, 1995 03:24:00", category: "1", value: 100 },
{ date: "December 17, 2000 03:24:00", category: "1", value: 150 },
{ date: "December 17, 2005 03:24:00", category: "1", value: 200 },
{ date: "December 17, 2010 03:24:00", category: "1", value: 100 },
{ date: "December 17, 2015 03:24:00", category: "2", value: 150 },
{ date: "December 17, 2020 03:24:00", category: "2", value: 200 },
{ date: "December 17, 2025 03:24:00", category: "2", value: 100 },
{ date: "December 17, 2030 03:24:00", category: "2", value: 150 },
{ date: "December 17, 2035 03:24:00", category: "3", value: 200 },
{ date: "December 17, 2040 03:24:00", category: "3", value: 100 },
{ date: "December 17, 2045 03:24:00", category: "3", value: 150 },
{ date: "December 17, 2050 03:24:00", category: "3", value: 200 },
];
function ChartParent() {
return (
<div>
<HardChart />
<div className="chart-container">
<Chart data={MOCKDATA} />
</div>
</div>
);
}
export default ChartParent;

View File

@ -0,0 +1,62 @@
import * as React from "react";
//WIP - Circle creation function is not set up correctly. Polylines
//and ticks functions are not created. Dream set up is to have preset color
//classes in css that are dynamically assigned to new categories.
class CreateChart extends React.Component {
//Function does not work. It should loop through
//organizedData to pull x and y and category name
//and then set those to the corrosponding attributes
//to ultimately return a cluster of unique circle elements
constructor(props) {
super(props);
this.myRef = React.createRef();
}
minX = this.props.minX;
organizedData = this.props.organizedData;
maxX = this.props.maxX;
minY = this.props.minY;
maxY = this.props.maxY;
ticks = this.props.ticks;
xLabel = this.props.xLabel;
yLabel = this.props.yLabel;
createCircles = () => {
const organizedData = this.props.organizedData;
for (let group of organizedData) {
for (let i = 0; i < group.length; i++) {
let circles = group.map((g) => {
let classN = g.category;
let x = g.x;
let y = g.y;
console.log(g);
this.newPathJSX;
});
}
}
};
newPathJSX = () => {
return <circle cx={x} cy={y} r="2" className={classN} />;
};
render() {
this.createCircles();
return (
<div className="container">
<svg className="graph" id="graph" viewBox="0 0 600 600">
{/*X Axis - could be made dynamic by allowing viewbox to be set by user or api*/}
<g>
<line className="x-line" x1="25" y1="550" x2="575" y2="550" />
</g>
</svg>
</div>
);
}
}
export default CreateChart;

View File

@ -0,0 +1,163 @@
import * as React from "react";
const STYLES_CONTAINER = {
width: "100%",
height: "auto",
};
const STYLES_GRAPH = {
viewBox: "0 0 600 600",
// backgroundColor: "#f7f7f7",
borderRadius: "4px",
height: "600px",
width: "600px",
};
const STYLES_XLINE = {
stroke: "#b2b2b2",
srokeWidth: "1",
fill: "none",
};
const STYLES_LINE1 = {
position: "relative",
stroke: "#0047ff",
fill: "none",
};
const STYLES_LINE2 = {
position: "relative",
stroke: "#1b1f23",
fill: "none",
};
const STYLES_LINE3 = {
position: "relative",
stroke: "#ffc940",
fill: "none",
};
const STYLES_CAT1 = {
fontSize: "0.75em",
fill: "#0047ff",
stroke: "none",
};
const STYLES_CAT2 = {
fontSize: "0.75em",
fill: "#1b1f23",
stroke: "none",
};
const STYLES_CAT3 = {
fontSize: "0.75em",
fill: "#ffc940",
stroke: "none",
};
function HardChart() {
return (
<div style={STYLES_CONTAINER}>
<svg style={STYLES_GRAPH}>
{/*Circle Plots*/}
<g>
<circle cx="25" cy="540" r="2" style={STYLES_CAT1} />
<circle cx="150" cy="500" r="2" style={STYLES_CAT1} />
<circle cx="300" cy="490" r="2" style={STYLES_CAT1} />
<circle cx="375" cy="350" r="2" style={STYLES_CAT1} />
<circle cx="520" cy="200" r="2" style={STYLES_CAT1} />
<circle cx="560" cy="10" r="2" style={STYLES_CAT1} />
<circle cx="25" cy="480" r="2" style={STYLES_CAT2} />
<circle cx="150" cy="420" r="2" style={STYLES_CAT2} />
<circle cx="300" cy="300" r="2" style={STYLES_CAT2} />
<circle cx="375" cy="250" r="2" style={STYLES_CAT2} />
<circle cx="520" cy="275" r="2" style={STYLES_CAT2} />
<circle cx="560" cy="300" r="2" style={STYLES_CAT2} />
<circle cx="25" cy="300" r="2" style={STYLES_CAT3} />
<circle cx="150" cy="350" r="2" style={STYLES_CAT3} />
<circle cx="300" cy="325" r="2" style={STYLES_CAT3} />
<circle cx="375" cy="375" r="2" style={STYLES_CAT3} />
<circle cx="520" cy="400" r="2" style={STYLES_CAT3} />
<circle cx="560" cy="420" r="2" style={STYLES_CAT3} />
</g>
{/*Connected Line Plots*/}
<g>
<polyline
style={STYLES_LINE1}
points="25,540 150,500 300,490 375,350 520,200 560,10"
>
<title>Category 1</title>
</polyline>
<polyline
style={STYLES_LINE2}
points="25,480 150,420 300,300 375,250 520,275 560,300"
>
<title>Category 2</title>
</polyline>
<polyline
style={STYLES_LINE3}
points="25,300 150,350 300,325 375,375 520,400 560,420"
>
<title>Category 3</title>
</polyline>
</g>
{/* Alt Configuration - Show Straight Lines connecting first/last plots
<g>
<line x1="10" y1="90" x2="190" y2="10" stroke="gray" />
<line x1="10" y1="20" x2="190" y2="70" stroke="gray" />
<line x1="10" y1="50" x2="190" y2="30" stroke="gray" />
</g>
*/}
{/*X Axis Line*/}
<g>
<line style={STYLES_XLINE} x1="25" y1="550" x2="575" y2="550" />
</g>
{/*X Axis Tick Marks*/}
<g>
<line style={STYLES_XLINE} x1="75" y1="550" x2="75" y2="560" />
<text className="chart-text" textAnchor="middle" x="75" y="575">
Sep 2017
</text>
<line style={STYLES_XLINE} x1="225" y1="550" x2="225" y2="560" />
<text className="chart-text" textAnchor="middle" x="225" y="575">
Jun 2018
</text>
<line style={STYLES_XLINE} x1="375" y1="550" x2="375" y2="560" />
<text className="chart-text" textAnchor="middle" x="375" y="575">
Mar 2019
</text>
<line style={STYLES_XLINE} x1="525" y1="550" x2="525" y2="560" />
<text className="chart-text" textAnchor="middle" x="525" y="575">
Dec 2019
</text>
</g>
{/* Alt Configuration - Show Legend
<g>
<polyline
points=" 215,100 215,40 285,40 285,100 215,100"
stroke="#b2b2b2"
fill="none"
/>
<text className="STYLES_CAT1" text-anchor="middle" x="250" y="60">
Category 1
</text>
<text className="STYLES_CAT2" text-anchor="middle" x="250" y="75">
Category 2
</text>
<text className="STYLES_CAT3" text-anchor="middle" x="250" y="90">
Category 3
</text>
</g>
*/}
</svg>
</div>
);
}
// const chartText = {
// fontSize: "0.9em",
// fill: "#b2b2b2",
// stroke: "none",
// };
export default HardChart;

408
pages/_/stats.js Normal file
View File

@ -0,0 +1,408 @@
import * as React from "react";
import * as Strings from "~/common/strings";
import * as Constants from "~/common/constants";
import * as System from "~/components/system";
import Section from "~/components/core/Section";
import ChartParent from "~/components/stats/ChartParent";
import { css } from "@emotion/react";
const STYLES_ROW = css`
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 6px 24px;
`;
const STYLES_TEXT = css`
min-width: 5%;
padding-top: 6px;
width: 100%;
`;
const STYLES_SUBTEXT = css`
margin-top: 8px;
font-size: 12px;
`;
const STYLES_SUBTEXT_HIGHLIGHT = css`
margin-top: 8px;
font-size: 12px;
color: ${Constants.system.brand};
`;
const STYLES_ITEM = css`
margin-bottom: 12px;
display: inline-flex;
flex-direction: column;
max-width: 220px;
margin-right: 32px;
`;
const STYLES_ITEM_GROUP = css`
display: flex;
align-items: flex-start;
justify-content: flex-start;
`;
const EXAMPLE_MINERS = {
columns: [
{ key: "miner", id: "id", name: "Miner" },
{
key: "cid",
name: "Raw Byte",
width: "228px",
type: "SLATE_LINK",
},
{
key: "amount",
name: "Adj. Power Growth",
width: "268px",
type: "NEW_WINDOW",
},
{
key: "size",
name: "24h Power Growth",
type: "NEW_WINDOW",
width: "188px",
},
],
rows: [
{
id: `file-1`,
icon: "PNG",
file: "test-image.jpg",
miner: "Example Miner A",
"deal-cid": "23Y7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-06 00:00:00 UTC"),
size: Strings.bytesToSize(66666, 3),
amount: Strings.formatAsFilecoin(2),
remaining: Strings.getRemainingTime(666666),
cid: "QmY7Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 4,
},
{
id: `file-2`,
icon: "PNG",
file: "test-image-2.jpg",
miner: "Example Miner A",
"deal-cid": "ABCDYh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-07 00:00:00 UTC"),
size: Strings.bytesToSize(77777, 3),
amount: Strings.formatAsFilecoin(2.04),
remaining: Strings.getRemainingTime(777777),
cid: "w2w2Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-3`,
icon: "PNG",
file: "test-image-3.jpg",
miner: "Example Miner B",
"deal-cid": "FHJKYh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-08 00:00:00 UTC"),
size: Strings.bytesToSize(88888, 3),
amount: Strings.formatAsFilecoin(2.08),
remaining: Strings.getRemainingTime(888888),
cid: "0707Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-4`,
icon: "PNG",
file: "test-image-4.jpg",
miner: "Example Miner C",
"deal-cid": "KKKKYh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-09 00:00:00 UTC"),
size: Strings.bytesToSize(9999999, 3),
amount: Strings.formatAsFilecoin(4.08),
remaining: Strings.getRemainingTime(999999),
cid: "1010Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-5`,
icon: "PNG",
file: "test-image-5.jpg",
miner: "Example Miner D",
"deal-cid": "WWWWWWWUquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-10 00:00:00 UTC"),
size: Strings.bytesToSize(4444444, 3),
amount: Strings.formatAsFilecoin(5.13),
remaining: Strings.getRemainingTime(797979),
cid: "1414Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-6`,
icon: "PNG",
file: "test-image-6.jpg",
miner: "Example Miner D",
"deal-cid": "XXXXUquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-11 00:00:00 UTC"),
size: Strings.bytesToSize(373737, 3),
amount: Strings.formatAsFilecoin(12.13),
remaining: Strings.getRemainingTime(828282),
cid: "3030Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-7`,
icon: "PNG",
file: "test-image-7.jpg",
miner: "Example Miner E",
"deal-cid": "HGHGHGXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-12 00:00:00 UTC"),
size: Strings.bytesToSize(373737, 3),
amount: Strings.formatAsFilecoin(12.13),
remaining: Strings.getRemainingTime(828282),
cid: "3030Yh4UquoXHLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 1,
},
{
id: `file-8`,
icon: "PNG",
file: "example-painting-a-1.jpg",
miner: "Example Miner F",
"deal-cid": "12CCCCCLPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-12 00:00:00 UTC"),
size: Strings.bytesToSize(444444, 3),
amount: Strings.formatAsFilecoin(2.13),
remaining: Strings.getRemainingTime(8282822),
cid: "asdfadsfPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-9`,
icon: "PNG",
file: "example-painting-a-2.jpg",
miner: "Example Miner F",
"deal-cid": "CGFDFASXbhXkhBvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-06-12 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: Strings.getRemainingTime(182822822),
cid: "asdfadsfPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-10`,
icon: "PNG",
file: "example-painting-a-3.jpg",
miner: "Example Miner F",
"deal-cid": "HHFGFDDFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-20 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: Strings.getRemainingTime(7432123),
cid: "asdfadsfPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-11`,
icon: "PNG",
file: "example-painting-a-4.jpg",
miner: "Example Miner F",
"deal-cid": "HHFGFDDFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-20 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: Strings.getRemainingTime(742988),
cid: "ppdmdfeFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-12`,
icon: "PNG",
file: "example-painting-a-5.jpg",
miner: "Example Miner F",
"deal-cid": "GHREREFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-24 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: Strings.getRemainingTime(320021),
cid: "dfsffdbPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 6,
errors: 0,
},
{
id: `file-13`,
icon: "PNG",
file: "pending-file-1.jpg",
miner: "Example Miner G",
"deal-cid": "13REREFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-24 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: null,
cid: "13sffdbPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 1,
},
{
id: `file-14`,
icon: "PNG",
file: "pending-file-2.jpg",
miner: "Example Miner G",
"deal-cid": "14REREFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-24 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: null,
cid: "14sffdbPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 2,
},
{
id: `file-15`,
icon: "PNG",
file: "pending-file-3.jpg",
miner: "Example Miner H",
"deal-cid": "15REREFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-24 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: null,
cid: "15sffdbPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 3,
},
{
id: `file-16`,
icon: "PNG",
file: "pending-file-4.jpg",
miner: "Example Miner I",
"deal-cid": "16REREFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-24 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: null,
cid: "16sffdbPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 4,
},
{
id: `file-17`,
icon: "PNG",
file: "pending-file-5.jpg",
miner: "Example Miner J",
"deal-cid": "17REREFGvFoPwmQUSa92pxnxjQuPU",
date: Strings.toDate("2014-07-24 00:00:00 UTC"),
size: Strings.bytesToSize(44432, 3),
amount: Strings.formatAsFilecoin(20.13),
remaining: null,
cid: "17sffdbPFo2XbhXkhBvFoPwmQUSa92pxnxjQuPU",
"retrieval-status": 5,
},
],
};
export default class StatsPage extends React.Component {
render() {
return (
<div>
<System.H1>Stats</System.H1>
<Section
onAction={this.props.onAction}
onNavigateTo={this.props.onNavigateTo}
title="Wallet"
buttons={[
{
name: "Export",
type: "SIDEBAR",
value: "SIDEBAR_CREATE_WALLET_ADDRESS",
},
]}
>
<div css={STYLES_ROW}>
<div css={STYLES_TEXT}>
<div css={STYLES_ITEM_GROUP}>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT}>Total File Balance</div>
</div>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT_HIGHLIGHT}>Value(FIL/ATTOLFIL)</div>
</div>
</div>
</div>
</div>
<div css={STYLES_ROW}>
<div css={STYLES_TEXT}>
<div css={STYLES_ITEM_GROUP}>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT}>Lifetime File Balance</div>
</div>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT_HIGHLIGHT}>Value(FIL/ATTOLFIL)</div>
</div>
</div>
</div>
</div>
</Section>
<Section
onAction={this.props.onAction}
onNavigateTo={this.props.onNavigateTo}
title="Network"
buttons={[
{
name: "Export",
type: "SIDEBAR",
value: "SIDEBAR_CREATE_WALLET_ADDRESS",
},
]}
>
<div css={STYLES_ROW}>
<div css={STYLES_TEXT}>
<div css={STYLES_ITEM_GROUP}>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT}>Total Power</div>
</div>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT_HIGHLIGHT}>Value(FIL/ATTOLFIL)</div>
</div>
</div>
</div>
</div>
<div css={STYLES_ROW}>
<div css={STYLES_TEXT}>
<div css={STYLES_ITEM_GROUP}>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT}>Tipset Height</div>
</div>
<div css={STYLES_ITEM}>
<div css={STYLES_SUBTEXT_HIGHLIGHT}>Value(FIL/ATTOLFIL)</div>
</div>
</div>
</div>
</div>
</Section>
<Section title="Miner List">
<System.Table
data={EXAMPLE_MINERS}
name="data"
onAction={this.props.onAction}
onNavigateTo={this.props.onNavigateTo}
/>
</Section>
<Section title="Node">
<ChartParent></ChartParent>
</Section>
</div>
);
}
}