diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 000000000..ad93c14a0
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,5 @@
+{
+ "image": "mcr.microsoft.com/devcontainers/universal:2",
+ "features": {
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 7058bb35a..8956237d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "stellarexplorer",
- "version": "1.0.10",
+ "version": "1.1.0-beta",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -2110,6 +2110,39 @@
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
+ "chart.js": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.3.tgz",
+ "integrity": "sha512-3+7k/DbR92m6BsMUYP6M0dMsMVZpMnwkUyNSAbqolHKsbIzH2Q4LWVEHHYq7v0fmEV8whXE0DrjANulw9j2K5g==",
+ "requires": {
+ "chartjs-color": "^2.1.0",
+ "moment": "^2.10.2"
+ }
+ },
+ "chartjs-color": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz",
+ "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=",
+ "requires": {
+ "chartjs-color-string": "^0.5.0",
+ "color-convert": "^0.5.3"
+ },
+ "dependencies": {
+ "color-convert": {
+ "version": "0.5.3",
+ "resolved": "http://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
+ "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
+ }
+ }
+ },
+ "chartjs-color-string": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz",
+ "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==",
+ "requires": {
+ "color-name": "^1.0.0"
+ }
+ },
"cheerio": {
"version": "1.0.0-rc.2",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz",
@@ -2677,8 +2710,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "0.3.0",
@@ -8953,25 +8985,6 @@
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
},
- "json2csv": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/json2csv/-/json2csv-4.1.6.tgz",
- "integrity": "sha512-pmitnvvuX9OC6lL6T6F0sl6NsoXG94xLHKnKwdRSEpASFd3xdKHvsksPpNFZtDULP0AwOA0MGKrm1I0c7Enaxg==",
- "requires": {
- "commander": "^2.15.1",
- "jsonparse": "^1.3.1",
- "lodash.clonedeep": "^4.5.0",
- "lodash.get": "^4.4.2",
- "lodash.set": "^4.3.2"
- },
- "dependencies": {
- "commander": {
- "version": "2.16.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz",
- "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew=="
- }
- }
- },
"json3": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
@@ -8999,11 +9012,6 @@
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
"dev": true
},
- "jsonparse": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
- "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
- },
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -9205,11 +9213,6 @@
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
"dev": true
},
- "lodash.clonedeep": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
- "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
- },
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -9228,21 +9231,11 @@
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
- "lodash.get": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
- },
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
},
- "lodash.set": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
- "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
- },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -9601,6 +9594,11 @@
"minimist": "0.0.8"
}
},
+ "moment": {
+ "version": "2.23.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz",
+ "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA=="
+ },
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
diff --git a/package.json b/package.json
index fde2a72cb..e82d2c372 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "stellarexplorer",
"description": "Ledger explorer for the Stellar network",
- "version": "1.0.10",
+ "version": "1.1.0-beta",
"license": "Apache-2.0",
"author": "Chris Hatch",
"homepage": "https://steexp.com",
@@ -20,6 +20,7 @@
"node": "10.x.x"
},
"dependencies": {
+ "chart.js": "^2.7.3",
"fetch-ponyfill": "^4.1.0",
"node-localstorage": "^1.3.0",
"promise": "8.0.1",
diff --git a/src/App.css b/src/App.css
index 94fec56c4..d8890c827 100644
--- a/src/App.css
+++ b/src/App.css
@@ -2,7 +2,7 @@ body,
.navbar {
color: #96a2b4;
background-color: #3c4452 !important;
- font-family: 'Noto Sans', 'Noto Sans CJK {SC, TC}', sans-serif;
+ font-family: "Noto Sans", "Noto Sans CJK {SC, TC}", sans-serif;
}
hr {
@@ -35,7 +35,7 @@ table {
}
.monospace {
- font-family: 'Noto Sans Mono', monospace;
+ font-family: "Noto Sans Mono", monospace;
word-break: break-all;
}
@@ -61,7 +61,7 @@ table {
.modal-body img {
margin-top: 10px;
}
-.modal-body input[type=text] {
+.modal-body input[type="text"] {
width: 100%;
}
.modal-body input {
@@ -115,19 +115,19 @@ table {
overflow-wrap: break-word;
}
-[id*='-table'] {
+[id*="-table"] {
font-size: 14px !important;
}
-[id*='-table'] thead {
+[id*="-table"] thead {
color: #dce2ec;
}
-[id*='-table'] tbody {
+[id*="-table"] tbody {
color: #96a2b4;
}
-[id*='-table'] > tbody > tr > td {
+[id*="-table"] > tbody > tr > td {
padding-top: 10px;
padding-bottom: 10px;
border-top: 1px solid #4c5667;
@@ -363,7 +363,8 @@ ul.navbar-nav .divider-vertical {
outline: none;
}
-.Network-Selector button:not(:first-child), .Network-Selector span:not(:first-child) {
+.Network-Selector button:not(:first-child),
+.Network-Selector span:not(:first-child) {
margin-left: 5px;
}
@@ -443,15 +444,15 @@ ul.navbar-nav .divider-vertical {
border: none;
}
-div[id|='account-tabs-pane'] {
+div[id|="account-tabs-pane"] {
padding: 15px;
}
-a[id|='account-tabs-tab'] {
+a[id|="account-tabs-tab"] {
color: #96a2b4;
}
-a[id|='account-tabs-tab']:hover {
+a[id|="account-tabs-tab"]:hover {
color: #01c0c8 !important;
background-color: #3c4452 !important;
border: 1px solid #3c4452;
@@ -459,7 +460,7 @@ a[id|='account-tabs-tab']:hover {
border-color: #3c4452 !important;
}
-a[id|='account-tabs-tab'][aria-selected='true'] {
+a[id|="account-tabs-tab"][aria-selected="true"] {
color: #01c0c8 !important;
}
@@ -573,6 +574,14 @@ a:hover {
transition: all 0.18s ease-in-out;
}
+.c3-axis-y .tick,
+.c3-axis-x .tick,
+.c3-axis-x-label,
+.c3-axis-y-label,
+.c3-legend-item text {
+ stroke: white !important;
+}
+
/*
Mobile Rules
*/
@@ -591,7 +600,7 @@ Mobile Rules
table-layout: fixed;
}
- [id*='-table'] {
+ [id*="-table"] {
font-size: 12px !important;
}
diff --git a/src/App.js b/src/App.js
index af4912883..f578f90f8 100644
--- a/src/App.js
+++ b/src/App.js
@@ -86,6 +86,7 @@ const Anchors = Loadable('Anchors')
const Assets = Loadable('Assets')
const Effects = Loadable('Effects')
const Exchanges = Loadable('Exchanges')
+const Graphs = Loadable('Graphs')
const InflationPools = Loadable('InflationPools')
const Ledger = Loadable('Ledger')
const Ledgers = Loadable('Ledgers')
@@ -166,6 +167,7 @@ class App extends Component {
+
diff --git a/src/components/Graphs.js b/src/components/Graphs.js
new file mode 100644
index 000000000..1cc6d8a0e
--- /dev/null
+++ b/src/components/Graphs.js
@@ -0,0 +1,240 @@
+import React from 'react'
+import Col from 'react-bootstrap/lib/Col'
+import Grid from 'react-bootstrap/lib/Grid'
+import Row from 'react-bootstrap/lib/Row'
+import Tab from 'react-bootstrap/lib/Tab'
+import Tabs from 'react-bootstrap/lib/Tabs'
+import Chart from 'chart.js'
+
+class OpPie extends React.Component {
+ config = {
+ type: 'pie',
+ data: {
+ datasets: [
+ {
+ data: [12, 40, 1, 20, 9],
+ backgroundColor: ['red', 'orange', 'yellow', 'green', 'blue'],
+ label: 'Op Type',
+ },
+ ],
+ labels: ['Create', 'Offer', 'Set Options', 'Payment', 'Inflation'],
+ },
+ options: {
+ responsive: true,
+ },
+ }
+
+ componentDidMount() {
+ var ctx = document.getElementById('opPieChart').getContext('2d')
+ new Chart(ctx, this.config)
+ }
+
+ render() {
+ return
+ }
+}
+
+class RecentActivity extends React.Component {
+ activityData = {
+ labels: ['1', '2', '3', '4', '5', '6', '7', 8, 9, 10, 11, 12],
+ datasets: [
+ {
+ type: 'bar',
+ label: 'Tx Count',
+ backgroundColor: 'red',
+ data: [4, 1, 0, 20, 5, 3, 2, 1, 9, 1, 0, 3],
+ },
+ {
+ type: 'bar',
+ label: 'Op Count',
+ backgroundColor: 'blue',
+ data: [22, 1, 0, 100, 17, 4, 2, 1, 18, 5, 0, 9],
+ },
+ {
+ type: 'line',
+ label: 'Close Times',
+ borderColor: 'green',
+ data: [10, 7, 9, 2, 3, 5, 7, 1, 7, 8, 6],
+ yAxisID: 'y2',
+ },
+ ],
+ }
+
+ config = {
+ type: 'bar',
+ data: this.activityData,
+ options: {
+ title: {
+ display: true,
+ text: 'Recent Ledger Activity',
+ },
+ tooltips: {
+ mode: 'index',
+ intersect: false,
+ },
+ responsive: true,
+ scales: {
+ xAxes: [
+ {
+ stacked: true,
+ },
+ ],
+ yAxes: [
+ {
+ id: 'y1',
+ stacked: true,
+ },
+ {
+ id: 'y2',
+ stacked: true,
+ position: 'right',
+ },
+ ],
+ },
+ },
+ }
+
+ componentDidMount() {
+ var ctx = document.getElementById('recentActivityChart').getContext('2d')
+ new Chart(ctx, this.config)
+ }
+
+ render() {
+ return
+ }
+}
+
+class RecentTxCounts extends React.Component {
+ config = {
+ type: 'line',
+ data: {
+ labels: [
+ '12/04',
+ '12/05',
+ '12/06',
+ '12/07',
+ '12/08',
+ '12/09',
+ '12/10',
+ '12/11',
+ '12/12',
+ '12/13',
+ '12/14',
+ '12/15',
+ '12/16',
+ '12/17',
+ ],
+ datasets: [
+ {
+ label: 'Tx Count',
+ backgroundColor: 'blue',
+ borderColor: 'blue',
+ data: [
+ 24591,
+ 26782,
+ 57697,
+ 35375,
+ 28487,
+ 21839,
+ 29707,
+ 89790,
+ 62123,
+ 64793,
+ 27525,
+ 9501,
+ 9530,
+ 43663,
+ ],
+ fill: false,
+ },
+ ],
+ },
+ options: {
+ responsive: true,
+ title: {
+ display: true,
+ text: 'Tx Count Chart',
+ },
+ tooltips: {
+ mode: 'index',
+ intersect: false,
+ },
+ hover: {
+ mode: 'nearest',
+ intersect: true,
+ },
+ scales: {
+ xAxes: [
+ {
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Date',
+ },
+ },
+ ],
+ yAxes: [
+ {
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'No. of Transactions',
+ },
+ },
+ ],
+ },
+ },
+ }
+
+ componentDidMount() {
+ var ctx = document.getElementById('txCountChart').getContext('2d')
+ new Chart(ctx, this.config)
+ }
+
+ render() {
+ return
+ }
+}
+
+class Graphs extends React.Component {
+ state = {
+ key: undefined, // 'bar-simple',
+ }
+
+ constructor(props, context) {
+ super(props, context)
+ this.handleSelect = this.handleSelect.bind(this)
+ }
+
+ handleSelect(key) {
+ this.setState({key})
+ }
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
+
+export default Graphs
diff --git a/src/components/layout/Header.js b/src/components/layout/Header.js
index 52b49678f..3542bfe26 100644
--- a/src/components/layout/Header.js
+++ b/src/components/layout/Header.js
@@ -46,9 +46,9 @@ class Header extends React.Component {
/>