import * as React from 'react'; import Measure, { BoundingRect, ContentRect } from 'react-measure'; import { Types, Maybe } from '../../common'; import { Icon, Tooltip, PolkadotIcon } from '../'; import Jdenticon from './Jdenticon'; import checkIcon from '../../icons/check.svg'; import finalizedIcon from '../../icons/finalized.svg'; import hatchingIcon from '../../icons/hatching.svg'; import './ConsensusBlock.css'; export namespace ConsensusBlock { export interface Props { authorities: Types.Authority[]; authoritySetId: Maybe; height: Types.BlockNumber; firstInRow: boolean; lastInRow: boolean; compact: boolean; measure: boolean; consensusView: Types.ConsensusView; changeBlocks: (first: boolean, boundsRect: BoundingRect) => void; } } export class ConsensusBlock extends React.Component { public state = { lastConsensusView: '', }; public shouldComponentUpdate(nextProps: ConsensusBlock.Props): boolean { if ( this.props.authorities.length === 0 && nextProps.authorities.length === 0 ) { return false; } const positionInfoChanged = this.props.firstInRow !== nextProps.firstInRow || this.props.lastInRow !== nextProps.lastInRow; if (positionInfoChanged) { return true; } const newConsensusInfo = JSON.stringify(nextProps.consensusView) !== this.state.lastConsensusView; if (newConsensusInfo) { return true; } return false; } public render() { this.state.lastConsensusView = JSON.stringify(this.props.consensusView); const finalizedByWhom = this.props.authorities.filter((authority) => this.isFinalized(authority) ); const ratio = finalizedByWhom.length + '/' + this.props.authorities.length; let titleFinal = {ratio}; const majorityFinalized = finalizedByWhom.length / this.props.authorities.length >= 2 / 3; if (majorityFinalized && !this.props.compact) { titleFinal = FINAL; } else if (majorityFinalized && this.props.compact) { const hash = this.getFinalizedHash(finalizedByWhom[0]); titleFinal = ( ); } const handleOnResize = (contentRect: ContentRect) => { this.props.changeBlocks( this.props.firstInRow, contentRect.bounds as BoundingRect ); }; const get = (measureRef: Maybe<(ref: Element | null) => void>) => { return (
{this.props.firstInRow && !this.props.compact ? ( ) : null} {this.props.authorities.map((authority) => ( ))} {this.props.authorities.map((authority, row) => this.renderMatriceRow(authority, this.props.authorities, row) )}
  {this.displayBlockNumber()} {titleFinal} {this.getAuthorityContent(authority)}
); }; if (this.props.measure) { return ( {({ measureRef }) => get(measureRef)} ); } else { return get(null); } } private displayBlockNumber(): string { const blockNumber = String(this.props.height); return blockNumber.length > 2 ? '…' + blockNumber.substr(blockNumber.length - 2, blockNumber.length) : blockNumber; } private isFinalized(authority: Types.Authority): boolean { if (!authority || authority.NodeId == null || authority.Address == null) { return false; } const { Address: addr } = authority; const consensus = this.props.consensusView; return ( consensus != null && addr in consensus && addr in consensus[addr] && consensus[addr][addr].Finalized === true ); } private getFinalizedHash(authority: Types.Authority): Maybe { if (this.isFinalized(authority)) { const { Address: addr } = authority; return this.props.consensusView[addr][addr].FinalizedHash; } return null; } private renderMatriceRow( authority: Types.Authority, authorities: Types.Authority[], row: number ): JSX.Element { let finalizedInfo =  ; let finalizedHash; if (authority.NodeId != null && this.isFinalized(authority)) { const matrice = this.props.consensusView[authority.Address][ authority.Address ]; finalizedInfo = matrice.ImplicitFinalized ? ( ) : ( ); finalizedHash = matrice.FinalizedHash ? ( ) : (
 
); } const name = authority.Name ? ( {authority.Name} ) : ( no data received from node ); const firstName = this.props.firstInRow ? ( {name} ) : ( '' ); return ( {firstName} {this.getAuthorityContent(authority)} {finalizedInfo} {finalizedHash} {authorities.map((columnNode, column) => { const evenOdd = ((row % 2) + column) % 2 === 0 ? 'even' : 'odd'; return ( {this.getCellContent(authority, columnNode)} ); })} ); } private getAuthorityContent(authority: Types.Authority): JSX.Element { return (
); } private getCellContent( rowAuthority: Types.Authority, columnAuthority: Types.Authority ) { const consensusInfo = this.props.consensusView && rowAuthority.Address && rowAuthority.Address in this.props.consensusView && columnAuthority.Address in this.props.consensusView[rowAuthority.Address] ? this.props.consensusView[rowAuthority.Address][ columnAuthority.Address ] : null; const prevote = consensusInfo && consensusInfo.Prevote; const implicitPrevote = consensusInfo && consensusInfo.ImplicitPrevote; const precommit = consensusInfo && consensusInfo.Precommit; const implicitPrecommit = consensusInfo && consensusInfo.ImplicitPrecommit; if (rowAuthority.Address !== columnAuthority.Address) { let statPrevote; let statPrecommit; if (implicitPrevote) { statPrevote = ; } if (implicitPrecommit) { statPrecommit = ; } if (prevote) { statPrevote = ; } if (precommit) { statPrecommit = ; } return ( {statPrevote} {statPrecommit} ); } else { return ; } } }