237 lines
6.2 KiB
TypeScript
237 lines
6.2 KiB
TypeScript
import * as React from 'react';
|
|
import { Types, SortedCollection, Maybe, Compare } from './common';
|
|
import { Chain, Ago } from './components';
|
|
import { Row, Column } from './components/List';
|
|
import { Connection } from './Connection';
|
|
import { Persistent, PersistentObject, PersistentSet } from './persist';
|
|
import {
|
|
bindState,
|
|
State,
|
|
Update,
|
|
Node,
|
|
ChainData,
|
|
comparePinnedChains,
|
|
StateSettings,
|
|
} from './state';
|
|
import { getHashData } from './utils';
|
|
|
|
import innerCircleIcon from './assets/inner-circle.svg';
|
|
import outerCircleIcon from './assets/outer-circle.svg';
|
|
|
|
import './App.css';
|
|
|
|
export default class App extends React.Component {
|
|
private chainsCache: ChainData[] = [];
|
|
// Custom state for finer control over updates
|
|
private readonly appState: Readonly<State>;
|
|
private readonly appUpdate: Update;
|
|
private readonly settings: PersistentObject<StateSettings>;
|
|
private readonly pins: PersistentSet<Types.NodeName>;
|
|
private readonly sortBy: Persistent<Maybe<number>>;
|
|
private readonly connection: Promise<Connection>;
|
|
|
|
constructor(props: Record<string, unknown>) {
|
|
super(props);
|
|
|
|
//todo! Check what's important to set to true, false
|
|
this.settings = new PersistentObject(
|
|
'settings',
|
|
{
|
|
validator: true,
|
|
location: true,
|
|
implementation: true,
|
|
networkId: true,
|
|
peers: true,
|
|
txs: true,
|
|
upload: false,
|
|
download: false,
|
|
stateCacheSize: false,
|
|
dbCacheSize: false,
|
|
diskRead: false,
|
|
diskWrite: false,
|
|
blocknumber: true,
|
|
blockhash: true,
|
|
finalized: false,
|
|
finalizedhash: false,
|
|
blocktime: true,
|
|
blockpropagation: true,
|
|
blocklasttime: false,
|
|
uptime: false,
|
|
version: false,
|
|
target_os: false,
|
|
target_arch: false,
|
|
cpu: false,
|
|
cpu_hashrate_score: true,
|
|
cpu_vendor: true,
|
|
core_count: false,
|
|
mem: true,
|
|
memory: false,
|
|
linux_distro: false,
|
|
linux_kernel: false,
|
|
memory_memcpy_score: true,
|
|
disk_sequential_write_score: true,
|
|
disk_random_write_score: true,
|
|
is_virtual_machine: false,
|
|
},
|
|
(settings) => {
|
|
const selectedColumns = this.selectedColumns(settings);
|
|
|
|
this.sortBy.set(null);
|
|
this.appUpdate({ settings, selectedColumns, sortBy: null });
|
|
}
|
|
);
|
|
|
|
this.pins = new PersistentSet<Types.NodeName>('pinned_names', (pins) => {
|
|
const { nodes } = this.appState;
|
|
|
|
nodes.mutEachAndSort((node) => node.setPinned(pins.has(node.name)));
|
|
|
|
this.appUpdate({ nodes, pins });
|
|
});
|
|
|
|
this.sortBy = new Persistent<Maybe<number>>('sortBy', null, (sortBy) => {
|
|
const compare = this.getComparator(sortBy);
|
|
|
|
this.appState.nodes.setComparator(compare);
|
|
this.appUpdate({ sortBy });
|
|
});
|
|
|
|
const { tab = '' } = getHashData();
|
|
|
|
this.appUpdate = bindState(this, {
|
|
status: 'offline',
|
|
best: 0 as Types.BlockNumber,
|
|
finalized: 0 as Types.BlockNumber,
|
|
blockTimestamp: 0 as Types.Timestamp,
|
|
blockAverage: null,
|
|
timeDiff: 0 as Types.Milliseconds,
|
|
subscribed: null,
|
|
chains: new Map(),
|
|
nodes: new SortedCollection(Node.compare),
|
|
settings: this.settings.raw(),
|
|
pins: this.pins.get(),
|
|
sortBy: this.sortBy.get(),
|
|
selectedColumns: this.selectedColumns(this.settings.raw()),
|
|
tab,
|
|
chainStats: null,
|
|
});
|
|
this.appState = this.appUpdate({});
|
|
|
|
const comparator = this.getComparator(this.sortBy.get());
|
|
|
|
this.appState.nodes.setComparator(comparator);
|
|
this.connection = Connection.create(
|
|
this.pins,
|
|
this.appState,
|
|
this.appUpdate
|
|
);
|
|
|
|
setInterval(() => (this.chainsCache = []), 10000);
|
|
}
|
|
|
|
public render() {
|
|
const { timeDiff, subscribed, status, tab } = this.appState;
|
|
const chains = this.chains();
|
|
const subscribedData = subscribed
|
|
? this.appState.chains.get(subscribed)
|
|
: null;
|
|
|
|
Ago.timeDiff = timeDiff;
|
|
|
|
if (chains.length === 0) {
|
|
return (
|
|
<div className="App App-no-telemetry">
|
|
<div className="App-no-telemetry-spinner">
|
|
<img src={innerCircleIcon} />
|
|
<img src={outerCircleIcon} />
|
|
</div>
|
|
<div className="App-no-telemetry-text">
|
|
Waiting for Ghosties…
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="App">
|
|
<Chain
|
|
appState={this.appState}
|
|
appUpdate={this.appUpdate}
|
|
connection={this.connection}
|
|
settings={this.settings}
|
|
pins={this.pins}
|
|
sortBy={this.sortBy}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
public componentDidMount() {
|
|
window.addEventListener('hashchange', this.onHashChange);
|
|
}
|
|
|
|
public componentWillUnmount() {
|
|
window.removeEventListener('hashchange', this.onHashChange);
|
|
}
|
|
|
|
private onHashChange = () => {
|
|
const { tab = '' } = getHashData();
|
|
|
|
this.appUpdate({ tab });
|
|
};
|
|
|
|
private chains(): ChainData[] {
|
|
if (this.chainsCache.length === this.appState.chains.size) {
|
|
return this.chainsCache;
|
|
}
|
|
|
|
this.chainsCache = Array.from(this.appState.chains.values()).sort(
|
|
(a, b) => {
|
|
const pinned = comparePinnedChains(a.genesisHash, b.genesisHash);
|
|
|
|
if (pinned !== 0) {
|
|
return pinned;
|
|
}
|
|
|
|
return b.nodeCount - a.nodeCount;
|
|
}
|
|
);
|
|
|
|
return this.chainsCache;
|
|
}
|
|
|
|
private selectedColumns(settings: StateSettings): Column[] {
|
|
return Row.columns.filter(
|
|
({ setting }) => setting == null || settings[setting]
|
|
);
|
|
}
|
|
|
|
private getComparator(sortBy: Maybe<number>): Compare<Node> {
|
|
const columns = this.appState.selectedColumns;
|
|
|
|
if (sortBy != null) {
|
|
const [index, rev] = sortBy < 0 ? [~sortBy, -1] : [sortBy, 1];
|
|
const column = columns[index];
|
|
|
|
if (column != null && column.sortBy) {
|
|
const key = column.sortBy;
|
|
|
|
return (a, b) => {
|
|
const aKey = key(a);
|
|
const bKey = key(b);
|
|
|
|
if (aKey < bKey) {
|
|
return -1 * rev;
|
|
} else if (aKey > bKey) {
|
|
return 1 * rev;
|
|
} else {
|
|
return Node.compare(a, b);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
return Node.compare;
|
|
}
|
|
}
|