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; private readonly appUpdate: Update; private readonly settings: PersistentObject; private readonly pins: PersistentSet; private readonly sortBy: Persistent>; private readonly connection: Promise; constructor(props: Record) { 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('pinned_names', (pins) => { const { nodes } = this.appState; nodes.mutEachAndSort((node) => node.setPinned(pins.has(node.name))); this.appUpdate({ nodes, pins }); }); this.sortBy = new Persistent>('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 (
Waiting for Ghosties…
); } return (
); } 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): Compare { 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; } }