From 46a48539b77587fdeec521731b2fe4ab6c7cf521 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 13 Aug 2018 12:05:11 +0200 Subject: [PATCH] Additional block production overview on explorer (#212) * Cleanup Card layouts * Additional block production overview on explorer * Adjust Card padding for accounts * Observable calculations into ApiObservable * DRY-er combineLatest + .pipe(map(...)) * .pipe(map(...)) * Progress takes value + total, auto-colors * CardSummary with Progress * Small style updates * Cleanup withApiObservable (optional value name) * Cleanup progress props * Cleanup rpc method use * Auto-set the prop from withStorage * Cleanups in observable use * Cleanups to layout * Initial bestNumber * Poll for changes in ApiObservable * WIP (debug) * Initial conversion (untested) or subscribeStorage * s/apiObservable/observable/ * Starting to show stuff (after storage subscriptions). WIP. * Staking UI works, still WIP on rest. * Readability * Storage withObservableDiv, Closes https://github.com/polkadot-js/apps/issues/215 * Add encoding FIXMEs * 'nominee' on set click * Align withObservable with others (single line) * Retrieve ss58 encoded AccountId from storage * Update with latest api (null/undefined storage distinction) --- packages/app-example/package.json | 4 +- packages/app-example/src/comp-002.tsx | 10 +- packages/app-example/src/comp-003.tsx | 11 +- packages/app-example/src/comp-004.tsx | 19 +- packages/app-example/src/comp-005.tsx | 17 +- packages/app-example/src/comp-006.tsx | 23 +- packages/app-example/src/comp-007.tsx | 23 +- packages/app-explorer/package.json | 4 +- packages/app-explorer/src/BestHash.tsx | 4 +- .../src/BlockHeader/BlockHeader.css | 4 +- packages/app-explorer/src/BlockHeaders.tsx | 9 +- packages/app-explorer/src/Summary.tsx | 100 ++++++ packages/app-explorer/src/index.css | 22 +- packages/app-explorer/src/index.tsx | 22 +- packages/app-extrinsics/package.json | 2 +- packages/app-extrinsics/src/Account.tsx | 42 ++- packages/app-extrinsics/src/Nonce.tsx | 4 + packages/app-staking/package.json | 4 +- packages/app-staking/src/Account.tsx | 146 ++++---- packages/app-staking/src/Summary.tsx | 35 +- packages/app-staking/src/UnnominateButton.tsx | 24 +- packages/app-staking/src/index.css | 34 +- packages/app-staking/src/index.tsx | 52 +-- packages/app-storage/src/Query.tsx | 4 +- packages/ui-app/package.json | 4 +- packages/ui-app/src/Card.tsx | 28 ++ packages/ui-app/src/CardSummary.tsx | 59 ++++ packages/ui-app/src/Params/initValueArray.ts | 2 +- packages/ui-app/src/Params/valueToText.tsx | 67 ++-- packages/ui-app/src/Progress.tsx | 64 ++++ packages/ui-app/src/styles/components.css | 24 ++ packages/ui-app/src/styles/semantic.css | 4 + packages/ui-identicon/package.json | 2 +- packages/ui-keyring/package.json | 2 +- packages/ui-react-rx/package.json | 6 +- packages/ui-react-rx/src/ApiObservable.ts | 331 ++++++++++++++++-- packages/ui-react-rx/src/Balance.ts | 8 +- packages/ui-react-rx/src/BestNumber.ts | 16 +- packages/ui-react-rx/src/NodeTime.ts | 22 -- packages/ui-react-rx/src/Nonce.ts | 8 +- packages/ui-react-rx/src/TimeNow.ts | 13 + packages/ui-react-rx/src/TimePeriod.ts | 16 + packages/ui-react-rx/src/demo.tsx | 2 - packages/ui-react-rx/src/index.ts | 4 - packages/ui-react-rx/src/types.d.ts | 40 ++- packages/ui-react-rx/src/with/apiCall.tsx | 66 ---- packages/ui-react-rx/src/with/apiDiv.ts | 8 +- .../ui-react-rx/src/with/apiObservable.tsx | 120 ------- packages/ui-react-rx/src/with/index.ts | 17 - packages/ui-react-rx/src/with/observable.tsx | 91 +++-- .../ui-react-rx/src/with/observableDiv.ts | 14 + .../ui-react-rx/src/with/observableParams.ts | 16 - packages/ui-react-rx/src/with/storage.tsx | 148 -------- packages/ui-react-rx/src/with/storageDiv.ts | 19 - packages/ui-react-rx/src/with/types.d.ts | 13 +- packages/ui-react/package.json | 2 +- packages/ui-react/src/Elapsed.tsx | 80 +++++ packages/ui-signer/package.json | 2 +- yarn.lock | 158 ++++----- 59 files changed, 1151 insertions(+), 944 deletions(-) create mode 100644 packages/app-explorer/src/Summary.tsx create mode 100644 packages/ui-app/src/Card.tsx create mode 100644 packages/ui-app/src/CardSummary.tsx create mode 100644 packages/ui-app/src/Progress.tsx delete mode 100644 packages/ui-react-rx/src/NodeTime.ts create mode 100644 packages/ui-react-rx/src/TimeNow.ts create mode 100644 packages/ui-react-rx/src/TimePeriod.ts delete mode 100644 packages/ui-react-rx/src/with/apiCall.tsx delete mode 100644 packages/ui-react-rx/src/with/apiObservable.tsx delete mode 100644 packages/ui-react-rx/src/with/index.ts create mode 100644 packages/ui-react-rx/src/with/observableDiv.ts delete mode 100644 packages/ui-react-rx/src/with/observableParams.ts delete mode 100644 packages/ui-react-rx/src/with/storage.tsx delete mode 100644 packages/ui-react-rx/src/with/storageDiv.ts create mode 100644 packages/ui-react/src/Elapsed.tsx diff --git a/packages/app-example/package.json b/packages/app-example/package.json index 3b5250ac54..253b2fffb5 100644 --- a/packages/app-example/package.json +++ b/packages/app-example/package.json @@ -11,9 +11,9 @@ "license": "ISC", "dependencies": { "@babel/runtime": "^7.0.0-beta.51", - "@polkadot/storage": "^0.27.12", + "@polkadot/storage": "^0.28.9", "@polkadot/ui-react": "^0.19.29", "@polkadot/ui-react-rx": "^0.19.29", - "@polkadot/util-keyring": "^0.27.12" + "@polkadot/util-keyring": "^0.28.1" } } diff --git a/packages/app-example/src/comp-002.tsx b/packages/app-example/src/comp-002.tsx index e2aa3807ff..743a6862d9 100644 --- a/packages/app-example/src/comp-002.tsx +++ b/packages/app-example/src/comp-002.tsx @@ -4,19 +4,15 @@ import React from 'react'; -import storage from '@polkadot/storage'; -import withStorageDiv from '@polkadot/ui-react-rx/with/storageDiv'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; +import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv'; -const method = storage.staking.public.intentions; - -const Comp: React.ComponentType = withStorageDiv(method)( +const Comp: React.ComponentType = withObservableDiv('stakingIntentions')( (value: Uint8Array[]): string => { if (!value || !value.length) { return 'No intentions found'; } - return value.map(encodeAddress).join(', '); + return value.join(', '); } ); diff --git a/packages/app-example/src/comp-003.tsx b/packages/app-example/src/comp-003.tsx index 063fe212c6..ecd4585fad 100644 --- a/packages/app-example/src/comp-003.tsx +++ b/packages/app-example/src/comp-003.tsx @@ -9,9 +9,8 @@ import React from 'react'; import storage from '@polkadot/storage'; import withApi from '@polkadot/ui-react-rx/with/api'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; -type StorageProposal = [BN, any, Uint8Array]; +type StorageProposal = [BN, any, string]; type StateProposals = { [index: string]: number[] @@ -43,12 +42,10 @@ class Comp extends React.PureComponent { .subscribe((value: Array) => { this.setState({ proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => { - const address = encodeAddress(accountId); - - if (!proposals[address]) { - proposals[address] = [propIdx.toNumber()]; + if (!proposals[accountId]) { + proposals[accountId] = [propIdx.toNumber()]; } else { - proposals[address].push(propIdx.toNumber()); + proposals[accountId].push(propIdx.toNumber()); } return proposals; diff --git a/packages/app-example/src/comp-004.tsx b/packages/app-example/src/comp-004.tsx index a408943f0c..c608423f8f 100644 --- a/packages/app-example/src/comp-004.tsx +++ b/packages/app-example/src/comp-004.tsx @@ -9,17 +9,16 @@ import React from 'react'; import storage from '@polkadot/storage'; import withApi from '@polkadot/ui-react-rx/with/api'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; -type StorageProposal = [BN, any, Uint8Array]; -type StorageIntentions = Array; +type StorageProposal = [BN, any, string]; +type StorageIntentions = Array; type StateProposals = { [index: string]: number[] }; type State = { - intentions: Array, + intentions: StorageIntentions, proposals: StateProposals, subscriptions: Array }; @@ -50,9 +49,7 @@ class Comp extends React.PureComponent { return api.state .getStorage(storage.staking.public.intentions) .subscribe((intentions: StorageIntentions) => { - this.setState({ - intentions: intentions.map(encodeAddress) - }); + this.setState({ intentions }); }); } @@ -64,12 +61,10 @@ class Comp extends React.PureComponent { .subscribe((value: Array) => { this.setState({ proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => { - const address = encodeAddress(accountId); - - if (!proposals[address]) { - proposals[address] = [propIdx.toNumber()]; + if (!proposals[accountId]) { + proposals[accountId] = [propIdx.toNumber()]; } else { - proposals[address].push(propIdx.toNumber()); + proposals[accountId].push(propIdx.toNumber()); } return proposals; diff --git a/packages/app-example/src/comp-005.tsx b/packages/app-example/src/comp-005.tsx index 320355c7b2..8ac0aee3c8 100644 --- a/packages/app-example/src/comp-005.tsx +++ b/packages/app-example/src/comp-005.tsx @@ -9,12 +9,11 @@ import React from 'react'; import storage from '@polkadot/storage'; import withApi from '@polkadot/ui-react-rx/with/api'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; import Balance from '@polkadot/ui-react-rx/Balance'; -type StorageProposal = [BN, any, Uint8Array]; -type StorageIntentions = Array; +type StorageProposal = [BN, any, string]; +type StorageIntentions = Array; type StateProposals = { [index: string]: number[] @@ -52,9 +51,7 @@ class Comp extends React.PureComponent { return api.state .getStorage(storage.staking.public.intentions) .subscribe((intentions: StorageIntentions) => { - this.setState({ - intentions: intentions.map(encodeAddress) - }); + this.setState({ intentions }); }); } @@ -66,12 +63,10 @@ class Comp extends React.PureComponent { .subscribe((value: Array) => { this.setState({ proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => { - const address = encodeAddress(accountId); - - if (!proposals[address]) { - proposals[address] = [propIdx.toNumber()]; + if (!proposals[accountId]) { + proposals[accountId] = [propIdx.toNumber()]; } else { - proposals[address].push(propIdx.toNumber()); + proposals[accountId].push(propIdx.toNumber()); } return proposals; diff --git a/packages/app-example/src/comp-006.tsx b/packages/app-example/src/comp-006.tsx index d0b7df16aa..1ff13a93ff 100644 --- a/packages/app-example/src/comp-006.tsx +++ b/packages/app-example/src/comp-006.tsx @@ -9,13 +9,12 @@ import React from 'react'; import storage from '@polkadot/storage'; import withApi from '@polkadot/ui-react-rx/with/api'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; import Balance from '@polkadot/ui-react-rx/Balance'; -type StorageProposal = [BN, any, Uint8Array]; -type StorageIntentions = Array; -type StorageValidators = Array; +type StorageProposal = [BN, any, string]; +type StorageIntentions = Array; +type StorageValidators = Array; type StateProposals = { [index: string]: number[] @@ -56,9 +55,7 @@ class Comp extends React.PureComponent { return api.state .getStorage(storage.staking.public.intentions) .subscribe((intentions: StorageIntentions) => { - this.setState({ - intentions: intentions.map(encodeAddress) - }); + this.setState({ intentions }); }); } @@ -70,12 +67,10 @@ class Comp extends React.PureComponent { .subscribe((value: Array) => { this.setState({ proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => { - const address = encodeAddress(accountId); - - if (!proposals[address]) { - proposals[address] = [propIdx.toNumber()]; + if (!proposals[accountId]) { + proposals[accountId] = [propIdx.toNumber()]; } else { - proposals[address].push(propIdx.toNumber()); + proposals[accountId].push(propIdx.toNumber()); } return proposals; @@ -90,9 +85,7 @@ class Comp extends React.PureComponent { return api.state .getStorage(storage.session.public.validators) .subscribe((validators: StorageValidators) => { - this.setState({ - validators: validators.map(encodeAddress) - }); + this.setState({ validators }); }); } diff --git a/packages/app-example/src/comp-007.tsx b/packages/app-example/src/comp-007.tsx index 74b6ac0b95..7dca8aec71 100644 --- a/packages/app-example/src/comp-007.tsx +++ b/packages/app-example/src/comp-007.tsx @@ -10,11 +10,10 @@ import React from 'react'; import storage from '@polkadot/storage'; import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; import withApi from '@polkadot/ui-react-rx/with/api'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; -type StorageProposal = [BN, any, Uint8Array]; -type StorageIntentions = Array; -type StorageValidators = Array; +type StorageProposal = [BN, any, string]; +type StorageIntentions = Array; +type StorageValidators = Array; type StateBalances = { [index: string]: BN @@ -62,9 +61,7 @@ class Comp extends React.PureComponent { return api.state .getStorage(storage.staking.public.intentions) - .subscribe((storage: StorageIntentions) => { - const intentions = storage.map(encodeAddress); - + .subscribe((intentions: StorageIntentions) => { this.setState({ intentions }, () => { this.subscribeBalances(intentions); }); @@ -79,12 +76,10 @@ class Comp extends React.PureComponent { .subscribe((value: Array) => { this.setState({ proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => { - const address = encodeAddress(accountId); - - if (!proposals[address]) { - proposals[address] = [propIdx.toNumber()]; + if (!proposals[accountId]) { + proposals[accountId] = [propIdx.toNumber()]; } else { - proposals[address].push(propIdx.toNumber()); + proposals[accountId].push(propIdx.toNumber()); } return proposals; @@ -99,9 +94,7 @@ class Comp extends React.PureComponent { return api.state .getStorage(storage.session.public.validators) .subscribe((validators: StorageValidators) => { - this.setState({ - validators: validators.map(encodeAddress) - }); + this.setState({ validators }); }); } diff --git a/packages/app-explorer/package.json b/packages/app-explorer/package.json index 974078bd49..8a3e5b34c9 100644 --- a/packages/app-explorer/package.json +++ b/packages/app-explorer/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "@babel/runtime": "^7.0.0-beta.51", - "@polkadot/primitives": "^0.27.12", + "@polkadot/primitives": "^0.28.9", "@polkadot/ui-app": "^0.19.29", - "@polkadot/util-crypto": "^0.27.12" + "@polkadot/util-crypto": "^0.28.1" } } diff --git a/packages/app-explorer/src/BestHash.tsx b/packages/app-explorer/src/BestHash.tsx index 9441ba06a2..694da0bda4 100644 --- a/packages/app-explorer/src/BestHash.tsx +++ b/packages/app-explorer/src/BestHash.tsx @@ -5,10 +5,10 @@ import { Header } from '@polkadot/primitives/header'; import headerHash from '@polkadot/primitives/codec/header/hash'; -import withApiDiv from '@polkadot/ui-react-rx/with/apiDiv'; +import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv'; import u8aToHex from '@polkadot/util/u8a/toHex'; -const Component: React.ComponentType = withApiDiv({ name: 'newHead', section: 'chain' })( +const Component: React.ComponentType = withObservableDiv('chainNewHead')( (value?: Header): string | undefined => value ? u8aToHex(headerHash(value), 64) diff --git a/packages/app-explorer/src/BlockHeader/BlockHeader.css b/packages/app-explorer/src/BlockHeader/BlockHeader.css index 947a78f015..b84dfad78f 100644 --- a/packages/app-explorer/src/BlockHeader/BlockHeader.css +++ b/packages/app-explorer/src/BlockHeader/BlockHeader.css @@ -24,7 +24,7 @@ align-items: center; box-sizing: border-box; display: flex; - flex: 1 25%; + flex: 1 33%; font-size: 3rem; font-weight: 100; } @@ -36,7 +36,7 @@ .explorer--BlockHeader > .details { box-sizing: border-box; - flex: 1 75%; + flex: 1 67%; text-align: left; } diff --git a/packages/app-explorer/src/BlockHeaders.tsx b/packages/app-explorer/src/BlockHeaders.tsx index 2102fa889d..9596e8007b 100644 --- a/packages/app-explorer/src/BlockHeaders.tsx +++ b/packages/app-explorer/src/BlockHeaders.tsx @@ -6,17 +6,12 @@ import { Header } from '@polkadot/primitives/header'; import React from 'react'; -import withApiDiv from '@polkadot/ui-react-rx/with/apiDiv'; +import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv'; import BlockHeader from './BlockHeader'; let blockHeaders: Array
= []; -const apiMethod = { - name: 'newHead', - section: 'chain' -}; - const apiOptions = { transform: (header: Header): Array
=> { if (!header) { @@ -40,7 +35,7 @@ const apiOptions = { } }; -export default withApiDiv(apiMethod, apiOptions)( +export default withObservableDiv('chainNewHead', apiOptions)( (value: Array
= []) => value.map((value) => ( { + render () { + const { className, eraBlockLength, eraBlockProgress, sessionBlockProgress, sessionBrokenValue, sessionBrokenPercentLate, sessionLength, style, t } = this.props; + + return ( +
+
+ + + + + + +
+
+ + + +
+
+ + + +
+
+ ); + } +} + +export default withMulti( + Summary, + translate, + withObservable('eraBlockLength'), + withObservable('eraBlockProgress'), + withObservable('sessionBlockProgress'), + withObservable('sessionBrokenValue'), + withObservable('sessionLength'), + withObservable('sessionBrokenPercentLate') +); diff --git a/packages/app-explorer/src/index.css b/packages/app-explorer/src/index.css index 50530cc3c9..fc612d7c85 100644 --- a/packages/app-explorer/src/index.css +++ b/packages/app-explorer/src/index.css @@ -21,12 +21,30 @@ .explorer--BestHash { font-size: 1.5em; line-height: 1.2; - margin-bottom: 0.75em; } .explorer--BestNumber { font-size: 3rem; line-height: 3rem; + position: relative; + text-align: right; } -.explorer--BlockHeaders {} +.explorer--Summary { + align-items: stretch; + display: flex; + justify-content: space-between; + flex-wrap: wrap; + margin-bottom: 2em; +} + +.explorer--Summary-column { + display: flex; + flex: 0 1 auto; + text-align: left; +} + +.explorer--Summary-card { + flex: 0 1 auto; + text-align: left; +} diff --git a/packages/app-explorer/src/index.tsx b/packages/app-explorer/src/index.tsx index de8c7b1715..0272bc770b 100644 --- a/packages/app-explorer/src/index.tsx +++ b/packages/app-explorer/src/index.tsx @@ -2,41 +2,31 @@ // This software may be modified and distributed under the terms // of the ISC license. See the LICENSE file for details. -import { I18nProps } from '@polkadot/ui-app/types'; +import { BareProps } from '@polkadot/ui-app/types'; import './index.css'; import React from 'react'; import Page from '@polkadot/ui-app/Page'; import classes from '@polkadot/ui-app/util/classes'; -import BestNumber from '@polkadot/ui-react-rx/BestNumber'; -import BestHash from './BestHash'; +import Summary from './Summary'; import BlockHeaders from './BlockHeaders'; -import translate from './translate'; -type Props = I18nProps & {}; +type Props = BareProps & {}; -class ExplorerApp extends React.PureComponent { +export default class ExplorerApp extends React.PureComponent { render () { - const { className, style, t } = this.props; + const { className, style } = this.props; return ( - - + ); } } - -export default translate(ExplorerApp); diff --git a/packages/app-extrinsics/package.json b/packages/app-extrinsics/package.json index 34dc776ef1..134498f6c3 100644 --- a/packages/app-extrinsics/package.json +++ b/packages/app-extrinsics/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@babel/runtime": "^7.0.0-beta.51", - "@polkadot/extrinsics": "^0.27.12", + "@polkadot/extrinsics": "^0.28.9", "@polkadot/ui-app": "^0.19.29", "@polkadot/ui-signer": "^0.19.29", "react-dropzone": "^4.2.9" diff --git a/packages/app-extrinsics/src/Account.tsx b/packages/app-extrinsics/src/Account.tsx index 295c14cb56..02a34aca7b 100644 --- a/packages/app-extrinsics/src/Account.tsx +++ b/packages/app-extrinsics/src/Account.tsx @@ -41,8 +41,7 @@ class Account extends React.PureComponent { } render () { - const { className, defaultValue, isDisabled, isError, isInput, label, style, t, type, withLabel } = this.props; - const { publicKey } = this.state; + const { className, defaultValue, isDisabled, isError, isInput, label, style, type, withLabel } = this.props; return (
{ withLabel={withLabel} />
- - - + {this.renderBalance()} ); } - onChange = (publicKey: Uint8Array): void => { + private renderBalance (): React.ReactNode { + const { t, withLabel } = this.props; + const { publicKey } = this.state; + + if (!publicKey) { + return null; + } + + return ( + + + + ); + } + + private onChange = (publicKey: Uint8Array): void => { const { onChange } = this.props; this.setState({ publicKey }, () => diff --git a/packages/app-extrinsics/src/Nonce.tsx b/packages/app-extrinsics/src/Nonce.tsx index b6dee3d3f2..66822a2bc8 100644 --- a/packages/app-extrinsics/src/Nonce.tsx +++ b/packages/app-extrinsics/src/Nonce.tsx @@ -21,6 +21,10 @@ export default class Nonce extends React.PureComponent { render () { const { className, label, style, onChange, value } = this.props; + if (!value) { + return null; + } + return (
, + stakingNominating?: string, + stakingNominatorsFor?: Array, intentions: Array, isValidator: boolean, queueExtrinsic: QueueTx$ExtrinsicAdd, @@ -58,10 +57,15 @@ class Account extends React.PureComponent { const { isNominateOpen } = this.state; return ( -
+ { value={address} >
- {this.renderButtons()} {this.renderNominee()} {this.renderNominators()}
-
+ ); } @@ -97,29 +96,29 @@ class Account extends React.PureComponent { } private renderNominee () { - const { nominee } = this.props; + const { stakingNominating } = this.props; - if (!nominee) { + if (!stakingNominating) { return null; } return ( ); } private renderNominators () { - const { nominatorsFor } = this.props; + const { stakingNominatorsFor } = this.props; - if (!nominatorsFor) { + if (!stakingNominatorsFor) { return null; } - return nominatorsFor.map((nominator) => ( + return stakingNominatorsFor.map((nominator) => ( { } private renderButtons () { - const { address, intentions, nominee, t } = this.props; + const { address, intentions, stakingNominating, t } = this.props; const isIntending = intentions.includes(address); - const isNominating = !!nominee; + const isNominating = !!stakingNominating; const canStake = !isIntending && !isNominating; if (canStake) { return ( -
- -
+ +
+ +