Cleanups on explorer Forks (#2482)

* Cleanups on explorer Forks

* Small opts
This commit is contained in:
Jaco Greeff 2020-03-30 09:01:59 +02:00 committed by GitHub
parent eb2167d540
commit 5dc1f908f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 143 deletions

View File

@ -28,11 +28,14 @@ function BlockByHash ({ className, value }: Props): React.ReactElement<Props> {
const getBlock = useCall<SignedBlock>(api.rpc.chain.getBlock as any, [value], { isSingle: true });
const getHeader = useCall<HeaderExtended>(api.derive.chain.getHeader as any, [value]);
const blockNumber = getHeader?.number.unwrap();
const parentHash = getHeader?.parentHash.toHex();
return (
<div className={className}>
<Table isFixed>
<Table.Head>
<th className='start'><h1>{getHeader ? formatNumber(getHeader.number.unwrap()) : '-'}</h1></th>
<th className='start' colSpan={getHeader ? 1 : 6}><h1>{formatNumber(blockNumber)}</h1></th>
{getHeader && (
<>
<th className='start'>{t('hash')}</th>
@ -48,7 +51,7 @@ function BlockByHash ({ className, value }: Props): React.ReactElement<Props> {
<tr>
<td className='address'>{getHeader.author && <AddressMini value={getHeader.author} />}</td>
<td className='hash overflow'>{getHeader.hash.toHex()}</td>
<td className='hash overflow'><Link to={`/explorer/query/${getHeader.parentHash.toHex()}`}>{getHeader.parentHash.toHex()}</Link></td>
<td className='hash overflow'><Link to={`/explorer/query/${parentHash}`}>{parentHash}</Link></td>
<td className='hash overflow'>{getHeader.extrinsicsRoot.toHex()}</td>
<td className='hash overflow'>{getHeader.stateRoot.toHex()}</td>
<td><LinkExternal data={value} type='block' /></td>
@ -59,7 +62,7 @@ function BlockByHash ({ className, value }: Props): React.ReactElement<Props> {
{getBlock && getHeader && (
<Columar>
<Extrinsics
blockNumber={getHeader.number.unwrap()}
blockNumber={blockNumber}
value={getBlock.block.extrinsics}
/>
<Events value={events} />

View File

@ -6,7 +6,7 @@
import { ApiProps } from '@polkadot/react-api/types';
import { Header } from '@polkadot/types/interfaces';
import React, { useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
import { CardSummary, IdentityIcon, SummaryBox } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
@ -211,84 +211,91 @@ function Forks ({ className }: Props): React.ReactElement<Props> | null {
const headersRef = useRef<Map<string, LinkHeader>>(new Map());
const firstNumRef = useRef('');
const _finalize = (hash: string): void => {
const hdr = headersRef.current.get(hash);
if (hdr && !hdr.isFinalized) {
hdr.isFinalized = true;
_finalize(hdr.parent);
}
};
// adds children for a specific header, retrieving based on matching parent
const _addChildren = (base: LinkHeader, children: LinkArray): LinkArray => {
const hdrs = (childrenRef.current.get(base.hash) || [])
.map((hash): LinkHeader | null => headersRef.current.get(hash) || null)
.filter((hdr): boolean => !!hdr) as LinkHeader[];
hdrs.forEach((hdr): void => {
children.push({ arr: _addChildren(hdr, []), hdr });
});
// caclulate the max height/width for this entry
base.height = calcHeight(children);
base.width = calcWidth(children);
// place the active (larger, finalized) columns first for the pyramid display
children.sort((a, b): number => {
if (a.hdr.width > b.hdr.width || a.hdr.height > b.hdr.height || a.hdr.isFinalized) {
return -1;
} else if (a.hdr.width < b.hdr.width || a.hdr.height < b.hdr.height || b.hdr.isFinalized) {
return 1;
}
return 0;
});
return children;
};
// create a tree list from the available headers
const _generateTree = (): Link => {
const root = createLink();
// add all the root entries first, we iterate from these
// We add the root entry explicitly, it exists as per init
(childrenRef.current.get('root') as string[]).forEach((hash): void => {
const _finalize = useCallback(
(hash: string): void => {
const hdr = headersRef.current.get(hash);
// if this fails, well, we have a bigger issue :(
if (hdr) {
root.arr.push({ arr: [], hdr: { ...hdr } });
if (hdr && !hdr.isFinalized) {
hdr.isFinalized = true;
_finalize(hdr.parent);
}
});
},
[]
);
// iterate through, adding the children for each of the root nodes
root.arr.forEach(({ arr, hdr }): void => {
_addChildren(hdr, arr);
});
// adds children for a specific header, retrieving based on matching parent
const _addChildren = useCallback(
(base: LinkHeader, children: LinkArray): LinkArray => {
// add the children
(childrenRef.current.get(base.hash) || [])
.map((hash): LinkHeader | undefined => headersRef.current.get(hash))
.filter((hdr): hdr is LinkHeader => !!hdr)
.forEach((hdr): void => {
children.push({ arr: _addChildren(hdr, []), hdr });
});
// align the columns with empty spacers - this aids in display
addColumnSpacers(root.arr);
// calculate the max height/width for this entry
base.height = calcHeight(children);
base.width = calcWidth(children);
root.hdr.height = calcHeight(root.arr);
root.hdr.width = calcWidth(root.arr);
// place the active (larger, finalized) columns first for the pyramid display
children.sort((a, b): number =>
(a.hdr.width > b.hdr.width || a.hdr.height > b.hdr.height || a.hdr.isFinalized)
? -1
: (a.hdr.width < b.hdr.width || a.hdr.height < b.hdr.height || b.hdr.isFinalized)
? 1
: 0
);
return root;
};
return children;
},
[]
);
useEffect((): () => void => {
let _subFinHead: UnsubFn | null = null;
let _subNewHead: UnsubFn | null = null;
// create a tree list from the available headers
const _generateTree = useCallback(
(): Link => {
const root = createLink();
// callback when finalized
const _newFinalized = (header: Header): void => {
// add all the root entries first, we iterate from these
// We add the root entry explicitly, it exists as per init
(childrenRef.current.get('root') || []).forEach((hash): void => {
const hdr = headersRef.current.get(hash);
// if this fails, well, we have a bigger issue :(
if (hdr) {
root.arr.push({ arr: [], hdr: { ...hdr } });
}
});
// iterate through, adding the children for each of the root nodes
root.arr.forEach(({ arr, hdr }): void => {
_addChildren(hdr, arr);
});
// align the columns with empty spacers - this aids in display
addColumnSpacers(root.arr);
root.hdr.height = calcHeight(root.arr);
root.hdr.width = calcWidth(root.arr);
return root;
},
[_addChildren]
);
// callback when finalized
const _newFinalized = useCallback(
(header: Header): void => {
_finalize(header.hash.toHex());
};
},
[_finalize]
);
// callback for the subscribe headers sub
const _newHeader = (header: Header): void => {
// callback for the subscribe headers sub
const _newHeader = useCallback(
(header: Header): void => {
// formatted block info
const bn = formatNumber(header.number);
const hash = header.hash.toHex();
@ -341,7 +348,13 @@ function Forks ({ className }: Props): React.ReactElement<Props> | null {
// do the magic, extract the info into something useful and add to state
setTree(_generateTree());
}
};
},
[api, _generateTree]
);
useEffect((): () => void => {
let _subFinHead: UnsubFn | null = null;
let _subNewHead: UnsubFn | null = null;
(async (): Promise<void> => {
_subFinHead = await api.rpc.chain.subscribeFinalizedHeads(_newFinalized);
@ -352,8 +365,7 @@ function Forks ({ className }: Props): React.ReactElement<Props> | null {
_subFinHead && _subFinHead();
_subNewHead && _subNewHead();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [api, _newFinalized, _newHeader]);
if (!tree) {
return null;
@ -384,32 +396,6 @@ export default React.memo(styled(Forks)`
border-spacing: 0.25rem;
font-family: monospace;
/* tr {
opacity: 0.05;
&:nth-child(1) { opacity: 1; }
&:nth-child(2) { opacity: 0.95; }
&:nth-child(3) { opacity: 0.9; }
&:nth-child(4) { opacity: 0.85; }
&:nth-child(5) { opacity: 0.8; }
&:nth-child(6) { opacity: 0.75; }
&:nth-child(7) { opacity: 0.70; }
&:nth-child(8) { opacity: 0.65; }
&:nth-child(9) { opacity: 0.6; }
&:nth-child(10) { opacity: 0.55; }
&:nth-child(11) { opacity: 0.6; }
&:nth-child(12) { opacity: 0.55; }
&:nth-child(13) { opacity: 0.5; }
&:nth-child(14) { opacity: 0.45; }
&:nth-child(15) { opacity: 0.4; }
&:nth-child(16) { opacity: 0.35; }
&:nth-child(17) { opacity: 0.3; }
&:nth-child(18) { opacity: 0.25; }
&:nth-child(19) { opacity: 0.2; }
&:nth-child(20) { opacity: 0.15; }
&:nth-child(21) { opacity: 0.1; }
} */
td {
padding: 0.25rem 0.5rem;
text-align: center;
@ -445,8 +431,8 @@ export default React.memo(styled(Forks)`
}
&.header {
background: #f5f5f5;
border: 1px solid #eee;
background: #fff;
border: 1px solid #e6e6e6;
border-radius: 0.25rem;
&.isEmpty {
@ -456,7 +442,6 @@ export default React.memo(styled(Forks)`
&.isFinalized {
background: rgba(0, 255, 0, 0.1);
border-color: rgba(0, 255, 0, 0.17);
}
&.isLink {
@ -468,7 +453,6 @@ export default React.memo(styled(Forks)`
&.isMissing {
background: rgba(255, 0, 0, 0.05);
border-color: rgba(255, 0, 0, 0.06);
}
}
}

View File

@ -29,8 +29,8 @@ interface Props {
type AccountExtend = [string, boolean, boolean];
interface Filtered {
elected: AccountExtend[];
validators: AccountExtend[];
elected?: AccountExtend[];
validators?: AccountExtend[];
waiting?: AccountExtend[];
}
@ -100,7 +100,7 @@ function getFiltered (stakingOverview: DeriveStakingOverview, favorites: string[
function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAuthors, next, recentlyOnline, setNominators, stakingOverview }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const [favorites, toggleFavorite] = useFavorites(STORE_FAVS_BASE);
const [{ elected, validators, waiting }, setFiltered] = useState<Filtered>({ elected: [], validators: [] });
const [{ elected, validators, waiting }, setFiltered] = useState<Filtered>({});
const [nameFilter, setNameFilter] = useState<string>('');
const [addressDetails, dispatchDetails] = useReducer(reduceDetails, {});
@ -111,7 +111,7 @@ function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAut
}, [favorites, isVisible, next, stakingOverview]);
useEffect((): void => {
stakingOverview && dispatchDetails(
stakingOverview && validators && dispatchDetails(
getDetails(stakingOverview, validators)
);
}, [stakingOverview, validators]);
@ -156,7 +156,7 @@ function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAut
<th>{t('last #')}</th>
<th>&nbsp;</th>
</Table.Head>
<Table.Body empty={stakingOverview && t('No active validators found')}>
<Table.Body empty={validators && t('No active validators found')}>
{_renderRows(validators, true)}
</Table.Body>
</Table>

View File

@ -82,8 +82,6 @@ const Memo = React.memo(styled(Table)`
}
table {
// border: 1px solid #e6e6e6;
border-radius: 0.25rem;
border-spacing: 0;
overflow: hidden;
width: 100%;
@ -138,20 +136,16 @@ const Memo = React.memo(styled(Table)`
tr {
width: 100%;
&.isHighlight {
td {
background: #ffffed;
}
&.isHighlight td {
background: #ffffed;
}
label {
opacity: 0.42;
}
&:hover {
label {
opacity: 1;
}
&:hover label {
opacity: 1;
}
&:not(:hover) {
@ -189,7 +183,6 @@ const Memo = React.memo(styled(Table)`
}
td {
// border-top: 1px solid #f2f2f2;
padding: 0.75rem 1rem;
text-align: left;
vertical-align: middle;
@ -209,7 +202,7 @@ const Memo = React.memo(styled(Table)`
}
.ui--Spinner {
margin: auto 0.5rem;
margin: 0.5rem auto;
.text {
margin-bottom: 0;
@ -219,13 +212,6 @@ const Memo = React.memo(styled(Table)`
&.address {
min-width: 11rem;
padding: 0.85rem 1rem;
> .ui--AddressMini,
> .ui--AddressMini.padded {
label.ui--AddressMini-label {
margin-bottom: -0.3rem;
}
}
}
&.button {
@ -238,10 +224,6 @@ const Memo = React.memo(styled(Table)`
border-top-width: 0;
}
&.empty {
opacity: 0.6;
}
&.hash {
font-family: monospace;
}
@ -279,27 +261,18 @@ const Memo = React.memo(styled(Table)`
}
th {
color: rgba(0, 0, 0, 0.6);
color: rgba(78, 78, 78, .66);
font-family: sans-serif;
font-weight: 400;
font-weight: 100;
text-align: right;
padding: 0.75rem 1rem 0.25rem;
vertical-align: baseline;
white-space: nowrap;
h1, h2 {
color: inherit;
font-size: 1.75rem;
}
&:first-child {
border-top-left-radius: 0.25rem;
}
&:last-child {
border-top-right-radius: 0.25rem;
}
&.isClickable {
cursor: pointer;
border-bottom: 2px solid transparent;