mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-05-01 06:37:59 +00:00
Added ago timers
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import * as React from 'react';
|
||||
import './Tile.css';
|
||||
import { timestamp, Types } from '@dotstats/common';
|
||||
|
||||
export namespace Ago {
|
||||
export interface Props {
|
||||
when: Types.Timestamp,
|
||||
}
|
||||
|
||||
export interface State {
|
||||
now: Types.Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
const tickers = new Map<Ago, (ts: Types.Timestamp) => void>();
|
||||
|
||||
function tick() {
|
||||
const now = timestamp();
|
||||
|
||||
for (const ticker of tickers.values()) {
|
||||
ticker(now);
|
||||
}
|
||||
|
||||
setTimeout(tick, 100);
|
||||
}
|
||||
|
||||
tick();
|
||||
|
||||
export namespace Ago {
|
||||
export interface State {
|
||||
now: Types.Timestamp
|
||||
}
|
||||
}
|
||||
|
||||
export class Ago extends React.Component<Ago.Props, Ago.State> {
|
||||
public static timeDiff = 0 as Types.Milliseconds;
|
||||
|
||||
public state: Ago.State;
|
||||
|
||||
constructor(props: Ago.Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
now: (timestamp() + Ago.timeDiff) as Types.Timestamp
|
||||
};
|
||||
}
|
||||
|
||||
public componentWillMount() {
|
||||
tickers.set(this, (now) => {
|
||||
this.setState({
|
||||
now: (now + Ago.timeDiff) as Types.Timestamp
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
tickers.delete(this);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const ago = Math.max(this.state.now - this.props.when, 0) / 1000;
|
||||
|
||||
let agoStr: string;
|
||||
|
||||
if (ago < 10) {
|
||||
agoStr = `${ago.toFixed(1)}s`;
|
||||
} else if (ago < 60) {
|
||||
agoStr = `${ago | 0}s`;
|
||||
} else {
|
||||
agoStr = `${ ago / 60 | 0}m`;
|
||||
}
|
||||
|
||||
return <span title={new Date(this.props.when).toUTCString()}>{agoStr} ago</span>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
.Icon {
|
||||
fill: currentColor;
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Icon svg {
|
||||
width: auto;
|
||||
height: 1em;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import ReactSVG from 'react-svg';
|
||||
import './Icon.css';
|
||||
|
||||
export interface Props {
|
||||
src: string,
|
||||
alt: string,
|
||||
className?: string,
|
||||
};
|
||||
|
||||
export class Icon extends React.Component<{}, Props> {
|
||||
public props: Props;
|
||||
|
||||
public shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { alt, className, src } = this.props;
|
||||
|
||||
return <ReactSVG title={alt} className={`Icon ${ className || '' }`} path={src} />;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import * as React from 'react';
|
||||
import { formatNumber, trimHash } from '../utils';
|
||||
import { Ago } from './Ago';
|
||||
import { Types } from '@dotstats/common';
|
||||
|
||||
export namespace Node {
|
||||
export interface Props {
|
||||
id: Types.NodeId,
|
||||
nodeDetails: Types.NodeDetails,
|
||||
nodeStats: Types.NodeStats,
|
||||
blockDetails: Types.BlockDetails,
|
||||
}
|
||||
}
|
||||
|
||||
export function Node(props: Node.Props) {
|
||||
const [name, implementation, version] = props.nodeDetails;
|
||||
const [height, hash, blockTime, blockTimestamp] = props.blockDetails;
|
||||
const [peers, txcount] = props.nodeStats;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>{name}</td>
|
||||
<td>{implementation} v{version}</td>
|
||||
<td>{peers}</td>
|
||||
<td>{txcount}</td>
|
||||
<td>#{formatNumber(height)}</td>
|
||||
<td><span title={hash}>{trimHash(hash, 16)}</span></td>
|
||||
<td>{(blockTime / 1000).toFixed(3)}s</td>
|
||||
<td><Ago when={blockTimestamp} /></td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.Tile {
|
||||
font-size: 2.5em;
|
||||
padding: 20px;
|
||||
text-align: left;
|
||||
width: 7em;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import * as React from 'react';
|
||||
import './Tile.css';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
export namespace Tile {
|
||||
export interface Props {
|
||||
title: string,
|
||||
icon: string,
|
||||
children?: React.ReactNode,
|
||||
}
|
||||
}
|
||||
|
||||
export function Tile(props: Tile.Props) {
|
||||
return (
|
||||
<div className="Tile">
|
||||
<Icon src={props.icon} alt={props.title} /> {props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './Icon';
|
||||
export * from './Node';
|
||||
export * from './Tile';
|
||||
export * from './Ago';
|
||||
Reference in New Issue
Block a user