diff --git a/src/App.js b/src/App.js
index 07d41c45..4ae00bb3 100755
--- a/src/App.js
+++ b/src/App.js
@@ -28,6 +28,7 @@ import Bx2NavDrawer from './v2/Bx2NavDrawer';
import Bx2BlankComponent from './v2/Bx2BlankComponent';
import Bx2PanelValidatorsOverview from './v2/Bx2PanelValidatorsOverview';
import Bx2PanelValidators from './v2/Bx2PanelValidators';
+import Bx2PanelValidatorDetail from './v2/Bx2PanelValidatorDetail';
import {stylesV2, themeV2} from './v2/ThemeV2';
const history = createBrowserHistory();
@@ -48,6 +49,9 @@ const Bx2PanelValidatorsOverviewThemed = withStyles(stylesV2)(
Bx2PanelValidatorsOverview,
);
const Bx2PanelValidatorsThemed = withStyles(stylesV2)(Bx2PanelValidators);
+const Bx2PanelValidatorDetailThemed = withStyles(stylesV2)(
+ Bx2PanelValidatorDetail,
+);
const Bx2BlankComponentThemed = withStyles(stylesV2)(Bx2BlankComponent);
class App extends Component {
@@ -708,6 +712,16 @@ class App extends Component {
)}
/>
+ (
+
+ )}
+ />
- {window.location.pathname.includes('v2') ? : }
+ {window.location.pathname.includes('v2') ? : }
,
document.getElementById('root'),
);
diff --git a/src/v2/Bx2EntityLink.jsx b/src/v2/Bx2EntityLink.jsx
index 9c384465..6a393d7a 100644
--- a/src/v2/Bx2EntityLink.jsx
+++ b/src/v2/Bx2EntityLink.jsx
@@ -47,6 +47,21 @@ class Bx2EntityLink extends React.Component {
);
}
+ renderValidatorId() {
+ return (
+
+
+ {this.props.validator_id.substring(0, 22) +
+ (this.props.validator_id.length > 22 ? '\u2026' : '')}
+
+
+ );
+ }
+
renderAccountId() {
return (
@@ -72,7 +87,7 @@ class Bx2EntityLink extends React.Component {
}
render() {
- const {node, ent, blk, txn, acct_id, prg_id} = this.props;
+ const {node, ent, blk, txn, validator_id, acct_id, prg_id} = this.props;
if (node) {
return this.renderNode();
@@ -90,6 +105,10 @@ class Bx2EntityLink extends React.Component {
return this.renderTransaction();
}
+ if (validator_id) {
+ return this.renderValidatorId();
+ }
+
if (acct_id) {
return this.renderAccountId();
}
diff --git a/src/v2/Bx2PanelValidatorDetail.jsx b/src/v2/Bx2PanelValidatorDetail.jsx
new file mode 100644
index 00000000..a0878e36
--- /dev/null
+++ b/src/v2/Bx2PanelValidatorDetail.jsx
@@ -0,0 +1,269 @@
+import React, {Component} from 'react';
+import {
+ ComposableMap,
+ ZoomableGroup,
+ Geographies,
+ Geography,
+ Markers,
+ Marker,
+} from 'react-simple-maps';
+import {makeStyles} from '@material-ui/core/styles';
+import BxEntityLink from './Bx2EntityLink';
+import BxHelpLink from './Bx2HelpLink';
+import Paper from '@material-ui/core/Paper';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Typography from '@material-ui/core/Typography';
+import _ from 'lodash';
+import PropTypes from 'prop-types';
+import {Link as RouterLink} from 'react-router-dom';
+import Link from '@material-ui/core/Link';
+import Tooltip from '@material-ui/core/Tooltip';
+
+function arrowGenerator(color) {
+ return {
+ '&[x-placement*="bottom"] $arrow': {
+ top: 0,
+ left: 0,
+ marginTop: '-0.95em',
+ width: '3em',
+ height: '1em',
+ '&::before': {
+ borderWidth: '0 1em 1em 1em',
+ borderColor: `transparent transparent ${color} transparent`,
+ },
+ },
+ '&[x-placement*="top"] $arrow': {
+ bottom: 0,
+ left: 0,
+ marginBottom: '-0.95em',
+ width: '3em',
+ height: '1em',
+ '&::before': {
+ borderWidth: '1em 1em 0 1em',
+ borderColor: `${color} transparent transparent transparent`,
+ },
+ },
+ '&[x-placement*="right"] $arrow': {
+ left: 0,
+ marginLeft: '-0.95em',
+ height: '3em',
+ width: '1em',
+ '&::before': {
+ borderWidth: '1em 1em 1em 0',
+ borderColor: `transparent ${color} transparent transparent`,
+ },
+ },
+ '&[x-placement*="left"] $arrow': {
+ right: 0,
+ marginRight: '-0.95em',
+ height: '3em',
+ width: '1em',
+ '&::before': {
+ borderWidth: '1em 0 1em 1em',
+ borderColor: `transparent transparent transparent ${color}`,
+ },
+ },
+ };
+}
+
+const useStylesArrow = makeStyles(theme => ({
+ tooltip: {
+ position: 'relative',
+ },
+ arrow: {
+ position: 'absolute',
+ fontSize: 6,
+ width: '3em',
+ height: '3em',
+ '&::before': {
+ content: '""',
+ margin: 'auto',
+ display: 'block',
+ width: 0,
+ height: 0,
+ borderStyle: 'solid',
+ },
+ },
+ popper: arrowGenerator(theme.palette.grey[700]),
+}));
+
+function ArrowTooltip(props) {
+ const {arrow, ...classes} = useStylesArrow();
+ const [arrowRef, setArrowRef] = React.useState(null);
+
+ return (
+
+ {props.title}
+
+
+ }
+ />
+ );
+}
+
+class Bx2PanelValidatorDetail extends Component {
+ makeMarker(node) {
+ return {
+ name: node.pubkey,
+ coordinates: [node.lng, node.lat],
+ };
+ }
+
+ renderValidators() {
+ const {nodes, id} = this.props;
+ const node = _.find(nodes, x => x.pubkey === id) || {};
+
+ return (
+
+
+
+ Validator Detail : {id}
+
+
+
+ Return to list
+
+
+
+
+
+
+
+ Node Pubkey
+
+
+
+ Vote Pubkey
+
+
+
+
+ Stake
+
+
+
+ Commission
+
+
+
+ Uptime
+
+
+
+
+
+ {_.map([node], row => (
+
+
+
+
+
+
+
+ {(row.voteAccount && row.voteAccount.stake) || 0} Lamports
+
+ TODO
+ TODO
+
+ ))}
+
+
+
+
+
+
+
+
+ {(geographies, projection) =>
+ geographies.map((geography, i) => (
+
+ ))
+ }
+
+
+ {[node].map((node, i) => (
+
+
+
+
+
+ ))}
+
+
+
+
+
+ );
+ }
+
+ render() {
+ const {nodes} = this.props;
+
+ if (nodes) {
+ return this.renderValidators();
+ }
+
+ return (
+
+
+ (ERROR - No data.)
+
+
+ );
+ }
+}
+
+Bx2PanelValidatorDetail.propTypes = {
+ nodes: PropTypes.array.isRequired,
+ id: PropTypes.string.isRequired,
+};
+
+export default Bx2PanelValidatorDetail;
diff --git a/src/v2/Bx2PanelValidators.jsx b/src/v2/Bx2PanelValidators.jsx
index f73907c1..42361d42 100644
--- a/src/v2/Bx2PanelValidators.jsx
+++ b/src/v2/Bx2PanelValidators.jsx
@@ -60,7 +60,7 @@ class Bx2PanelValidators extends React.Component {
scope="row"
title={JSON.stringify(row, null, 2)}
>
-
+
-
+