From b11a6981a215ad015dd74d39cb6459bda657de41 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 11 May 2018 18:08:10 +0200 Subject: [PATCH] Optimise components (#39) * ui-react-app -> ui-app * CopyButton, Input & Password components * Convert all to use ui-app/{Input, Label} * Change to PureComponent where we have onChange listeners * Cleanup layouts * Swap dropdown components, remove uselexx constructors * Allow address/account forget * Bump * Searching with headers operational * flex grow/shrink for icon + account add * Fix balance & transaction display (account/address management) * Adjust balance layout * Equalise padding --- .flowconfig | 2 +- flow-typed/react-copy-to-clipboard.js | 2 +- flow-typed/store.js | 1 + lerna.json | 2 +- packages/app-accounts/package.json | 4 +- packages/app-accounts/src/Address.js | 126 ++++++++------ packages/app-accounts/src/Creator.js | 156 +++++++----------- packages/app-accounts/src/Editor.js | 132 +++++++++++---- packages/app-accounts/src/index.css | 18 +- packages/app-accounts/src/index.js | 30 +--- packages/app-addresses/package.json | 6 +- packages/app-addresses/src/Creator.js | 103 +++++------- packages/app-addresses/src/Editor.js | 98 +++++++---- packages/app-addresses/src/index.js | 30 +--- packages/app-explorer/package.json | 4 +- .../app-explorer/src/BlockHeader/index.js | 3 +- packages/app-explorer/src/BlockHeaders.js | 1 + packages/app-explorer/src/index.js | 3 +- packages/app-extrinsics/package.json | 4 +- packages/app-extrinsics/src/Account.js | 21 +-- packages/app-extrinsics/src/Extrinsic.js | 9 +- packages/app-extrinsics/src/Nonce.js | 13 +- packages/app-extrinsics/src/Params/Account.js | 37 +++-- .../app-extrinsics/src/Params/Proposal.js | 62 ++++--- packages/app-extrinsics/src/Params/index.js | 2 +- packages/app-extrinsics/src/Selection.js | 14 +- packages/app-extrinsics/src/Signer/Decoded.js | 3 +- packages/app-extrinsics/src/Signer/Signer.css | 10 +- packages/app-extrinsics/src/Signer/Unlock.js | 66 ++------ packages/app-extrinsics/src/Signer/index.js | 15 +- packages/app-extrinsics/src/Status.js | 2 +- packages/app-extrinsics/src/index.css | 6 +- packages/app-extrinsics/src/index.js | 14 +- packages/app-storage/package.json | 4 +- packages/app-storage/src/Queries.js | 2 +- packages/app-storage/src/Query/format.js | 1 + packages/app-storage/src/Query/index.js | 122 ++++++++------ packages/app-storage/src/Selection.js | 27 ++- packages/app-storage/src/index.js | 14 +- packages/app-vanitygen/package.json | 5 +- packages/app-vanitygen/src/Match.js | 88 +++++----- packages/app-vanitygen/src/index.js | 105 ++++++------ packages/apps/package.json | 14 +- packages/apps/src/App/index.js | 2 +- packages/apps/src/Connecting/index.js | 3 +- packages/apps/src/Content/index.js | 2 +- packages/apps/src/NotFound/index.js | 2 +- packages/apps/src/SideBar/Item.js | 2 +- packages/apps/src/SideBar/index.js | 2 +- packages/apps/src/index.js | 2 +- packages/{ui-react-app => ui-app}/LICENSE | 0 packages/ui-app/README.md | 1 + .../{ui-react-app => ui-app}/package.json | 7 +- packages/ui-app/src/CopyButton.js | 28 ++++ packages/ui-app/src/Dropdown.js | 66 ++++++++ packages/ui-app/src/Input.js | 69 ++++++++ .../src/InputAddress/InputAddress.css | 0 .../src/InputAddress/addressToAddress.js | 20 +++ .../src/InputAddress/index.js | 70 +++++--- .../src/InputExtrinsic/InputExtrinsic.css | 18 +- .../src/InputExtrinsic/SelectMethod.js | 7 +- .../src/InputExtrinsic/SelectSection.js | 6 +- .../src/InputExtrinsic/index.js | 32 ++-- .../src/InputExtrinsic/options/method.js | 7 +- .../src/InputExtrinsic/options/section.js | 0 .../src/InputStorage/SelectKey.js | 7 +- .../src/InputStorage/SelectSection.js | 6 +- .../src/InputStorage/index.js | 28 ++-- .../src/InputStorage/options/key.js | 7 +- .../src/InputStorage/options/section.js | 0 packages/ui-app/src/Labelled.js | 32 ++++ packages/ui-app/src/Params/Param/Account.js | 46 ++++++ packages/ui-app/src/Params/Param/Amount.js | 46 ++++++ packages/ui-app/src/Params/Param/Bare.js | 23 +++ .../src/Params/Param/Base.js | 18 +- packages/ui-app/src/Params/Param/Bool.js | 47 ++++++ .../src/Params/Param/Bytes.js | 48 +++--- .../src/Params/Param/File.js | 10 +- .../src/Params/Param/Hash.js | 0 .../src/Params/Param/Unknown.js | 0 .../ui-app/src/Params/Param/VoteThreshold.js | 49 ++++++ .../src/Params/Param/Wasm.js | 30 ++-- .../src/Params/Param/findComponent.js | 0 .../src/Params/Param/index.js | 43 +++-- .../src/Params/Params.css | 0 .../src/Params/index.js | 9 +- .../src/Params/initValue.js | 1 + .../src/Params/typeToText.js | 0 .../src/Params/types.js | 0 .../src/Params/values.js | 0 packages/ui-app/src/Password.js | 69 ++++++++ packages/{ui-react-app => ui-app}/src/i18n.js | 0 .../{ui-react-app => ui-app}/src/index.js | 1 + .../{ui-react-app => ui-app}/src/styles.js | 0 .../src/styles/app.css | 0 .../src/styles/form.css | 18 +- .../src/styles/rx.css | 0 .../src/styles/semantic.css | 2 +- .../{ui-react-app => ui-app}/src/translate.js | 0 .../{ui-react-app => ui-app}/src/types.js | 0 packages/ui-keyring/package.json | 2 +- packages/ui-keyring/src/account/forget.js | 22 +++ packages/ui-keyring/src/address/forget.js | 19 +++ packages/ui-keyring/src/address/get.js | 2 + packages/ui-keyring/src/index.js | 6 + packages/ui-keyring/src/options/KeyPair.css | 7 + packages/ui-keyring/src/options/KeyPair.js | 1 + packages/ui-keyring/src/options/header.js | 20 +++ packages/ui-keyring/src/options/index.js | 30 ++-- packages/ui-keyring/src/types.js | 6 + packages/ui-react-app/README.md | 1 - .../ui-react-app/src/Params/Param/Account.js | 36 ---- .../ui-react-app/src/Params/Param/Amount.js | 38 ----- .../ui-react-app/src/Params/Param/Bool.js | 39 ----- .../src/Params/Param/VoteThreshold.js | 41 ----- packages/ui-react-app/src/RxDropdown.js | 56 ------- 116 files changed, 1552 insertions(+), 1041 deletions(-) rename packages/{ui-react-app => ui-app}/LICENSE (100%) create mode 100644 packages/ui-app/README.md rename packages/{ui-react-app => ui-app}/package.json (87%) create mode 100644 packages/ui-app/src/CopyButton.js create mode 100644 packages/ui-app/src/Dropdown.js create mode 100644 packages/ui-app/src/Input.js rename packages/{ui-react-app => ui-app}/src/InputAddress/InputAddress.css (100%) create mode 100644 packages/ui-app/src/InputAddress/addressToAddress.js rename packages/{ui-react-app => ui-app}/src/InputAddress/index.js (64%) rename packages/{ui-react-app => ui-app}/src/InputExtrinsic/InputExtrinsic.css (64%) rename packages/{ui-react-app => ui-app}/src/InputExtrinsic/SelectMethod.js (91%) rename packages/{ui-react-app => ui-app}/src/InputExtrinsic/SelectSection.js (89%) rename packages/{ui-react-app => ui-app}/src/InputExtrinsic/index.js (79%) rename packages/{ui-react-app => ui-app}/src/InputExtrinsic/options/method.js (87%) rename packages/{ui-react-app => ui-app}/src/InputExtrinsic/options/section.js (100%) rename packages/{ui-react-app => ui-app}/src/InputStorage/SelectKey.js (90%) rename packages/{ui-react-app => ui-app}/src/InputStorage/SelectSection.js (89%) rename packages/{ui-react-app => ui-app}/src/InputStorage/index.js (79%) rename packages/{ui-react-app => ui-app}/src/InputStorage/options/key.js (88%) rename packages/{ui-react-app => ui-app}/src/InputStorage/options/section.js (100%) create mode 100644 packages/ui-app/src/Labelled.js create mode 100644 packages/ui-app/src/Params/Param/Account.js create mode 100644 packages/ui-app/src/Params/Param/Amount.js create mode 100644 packages/ui-app/src/Params/Param/Bare.js rename packages/{ui-react-app => ui-app}/src/Params/Param/Base.js (72%) create mode 100644 packages/ui-app/src/Params/Param/Bool.js rename packages/{ui-react-app => ui-app}/src/Params/Param/Bytes.js (52%) rename packages/{ui-react-app => ui-app}/src/Params/Param/File.js (92%) rename packages/{ui-react-app => ui-app}/src/Params/Param/Hash.js (100%) rename packages/{ui-react-app => ui-app}/src/Params/Param/Unknown.js (100%) create mode 100644 packages/ui-app/src/Params/Param/VoteThreshold.js rename packages/{ui-react-app => ui-app}/src/Params/Param/Wasm.js (56%) rename packages/{ui-react-app => ui-app}/src/Params/Param/findComponent.js (100%) rename packages/{ui-react-app => ui-app}/src/Params/Param/index.js (57%) rename packages/{ui-react-app => ui-app}/src/Params/Params.css (100%) rename packages/{ui-react-app => ui-app}/src/Params/index.js (93%) rename packages/{ui-react-app => ui-app}/src/Params/initValue.js (99%) rename packages/{ui-react-app => ui-app}/src/Params/typeToText.js (100%) rename packages/{ui-react-app => ui-app}/src/Params/types.js (100%) rename packages/{ui-react-app => ui-app}/src/Params/values.js (100%) create mode 100644 packages/ui-app/src/Password.js rename packages/{ui-react-app => ui-app}/src/i18n.js (100%) rename packages/{ui-react-app => ui-app}/src/index.js (99%) rename packages/{ui-react-app => ui-app}/src/styles.js (100%) rename packages/{ui-react-app => ui-app}/src/styles/app.css (100%) rename packages/{ui-react-app => ui-app}/src/styles/form.css (80%) rename packages/{ui-react-app => ui-app}/src/styles/rx.css (100%) rename packages/{ui-react-app => ui-app}/src/styles/semantic.css (97%) rename packages/{ui-react-app => ui-app}/src/translate.js (100%) rename packages/{ui-react-app => ui-app}/src/types.js (100%) create mode 100644 packages/ui-keyring/src/account/forget.js create mode 100644 packages/ui-keyring/src/address/forget.js create mode 100644 packages/ui-keyring/src/options/header.js delete mode 100644 packages/ui-react-app/README.md delete mode 100644 packages/ui-react-app/src/Params/Param/Account.js delete mode 100644 packages/ui-react-app/src/Params/Param/Amount.js delete mode 100644 packages/ui-react-app/src/Params/Param/Bool.js delete mode 100644 packages/ui-react-app/src/Params/Param/VoteThreshold.js delete mode 100644 packages/ui-react-app/src/RxDropdown.js diff --git a/.flowconfig b/.flowconfig index eec1e49457..d5f6528570 100644 --- a/.flowconfig +++ b/.flowconfig @@ -14,4 +14,4 @@ all=warn include_warnings=true module.name_mapper='^@polkadot/app-\(accounts\|addresses\|explorer\|extrinsics\|home\|rpc\|settings\|storage\|vanitygen\)\(.*\)$' -> '/packages/app-\1/src\2' module.name_mapper='^@polkadot/apps\(.*\)$' -> '/packages/apps/src\1' -module.name_mapper='^@polkadot/ui-\(keyring\|react-app\)\(.*\)$' -> '/packages/ui-\1/src\2' +module.name_mapper='^@polkadot/ui-\(app\|keyring\)\(.*\)$' -> '/packages/ui-\1/src\2' diff --git a/flow-typed/react-copy-to-clipboard.js b/flow-typed/react-copy-to-clipboard.js index 80efcc19c4..62255fb71e 100644 --- a/flow-typed/react-copy-to-clipboard.js +++ b/flow-typed/react-copy-to-clipboard.js @@ -1,5 +1,5 @@ // @flow declare module 'react-copy-to-clipboard' { - declare module.exports: React$ComponentType<{ text: string }>; + declare module.exports: React$ComponentType<{ text?: string }>; } diff --git a/flow-typed/store.js b/flow-typed/store.js index 72aa863ded..7a2a96230d 100644 --- a/flow-typed/store.js +++ b/flow-typed/store.js @@ -4,6 +4,7 @@ declare module 'store' { declare module.exports: { each: (fn: (value: any, key: string) => void) => void, get: (key: string) => any, + remove: (key: string) => any, set: (key: string, value: any) => void, } } diff --git a/lerna.json b/lerna.json index c02976e4b6..491b198005 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "packages": [ "packages/*" ], - "version": "0.3.4" + "version": "0.4.0" } diff --git a/packages/app-accounts/package.json b/packages/app-accounts/package.json index 86f1c67a9b..454f964c8c 100644 --- a/packages/app-accounts/package.json +++ b/packages/app-accounts/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/app-accounts", - "version": "0.3.4", + "version": "0.4.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -11,6 +11,6 @@ "test": "jest --coverage" }, "devDependencies": { - "@polkadot/ui-react-app": "^0.3.4" + "@polkadot/ui-app": "^0.4.0" } } diff --git a/packages/app-accounts/src/Address.js b/packages/app-accounts/src/Address.js index c689b983c0..48979175a1 100644 --- a/packages/app-accounts/src/Address.js +++ b/packages/app-accounts/src/Address.js @@ -3,63 +3,97 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { BareProps } from '@polkadot/ui-react-app/types'; +import type { BareProps } from '@polkadot/ui-app/types'; import React from 'react'; -import CopyToClipboard from 'react-copy-to-clipboard'; -import Button from 'semantic-ui-react/dist/es/elements/Button'; + +import CopyButton from '@polkadot/ui-app/src/CopyButton'; import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; import Balance from '@polkadot/ui-react-rx/Balance'; import Nonce from '@polkadot/ui-react-rx/Nonce'; +import addressDecode from '@polkadot/util-keyring/address/decode'; type Props = BareProps & { - value: null | { - address: string, - publicKey: Uint8Array - }; + value: string | null; } -export default function Address ({ className, style, value }: Props): React$Node { - if (!value) { - return null; +type State = { + address: string, + isValid: boolean, + publicKey: Uint8Array | null, + shortValue: string +} + +const DEFAULT_ADDR = '5'.padEnd(16, 'x'); +const DEFAULT_SHORT = `${DEFAULT_ADDR.slice(0, 7)}…${DEFAULT_ADDR.slice(-7)}`; + +export default class Address extends React.PureComponent { + state: State = ({}: $Shape); + + static getDerivedStateFromProps ({ value }: Props, { publicKey, shortValue }: State): State { + // flowlint-next-line sketchy-null-string:off + const address = value || DEFAULT_ADDR; + + try { + // $FlowFixMe yes, we expect a throw when invalid + publicKey = addressDecode(value); + shortValue = `${address.slice(0, 7)}…${address.slice(-7)}`; + } catch (error) { + publicKey = null; + } + + const isValid = !!publicKey && publicKey.length === 32; + + console.log('publicKey', publicKey); + + return { + address: isValid ? address : DEFAULT_ADDR, + isValid, + publicKey, + shortValue: isValid ? shortValue : DEFAULT_SHORT + }; } - const { address, publicKey } = value; - const short = `${address.slice(0, 7)}…${address.slice(-7)}`; + render (): React$Node { + const { className, style } = this.props; + const { address, isValid, publicKey, shortValue } = this.state; - return ( -
- -
-
- {short} -
- -
- - - {' transactions'} - -
- ); + +
+
+ {shortValue} +
+ +
+ { + !isValid + ? null + : [ + , + + {' transactions'} + + ] + } + + ); + } } diff --git a/packages/app-accounts/src/Creator.js b/packages/app-accounts/src/Creator.js index 4de3b58c22..f736cb342e 100644 --- a/packages/app-accounts/src/Creator.js +++ b/packages/app-accounts/src/Creator.js @@ -3,12 +3,13 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import React from 'react'; import Button from 'semantic-ui-react/dist/es/elements/Button'; -import Input from 'semantic-ui-react/dist/es/elements/Input'; -import Label from 'semantic-ui-react/dist/es/elements/Label'; + +import Input from '@polkadot/ui-app/src/Input'; +import Password from '@polkadot/ui-app/src/Password'; import keyring from '@polkadot/ui-keyring/src'; import isHex from '@polkadot/util/is/hex'; import hexToU8a from '@polkadot/util/hex/toU8a'; @@ -26,13 +27,11 @@ type Props = I18nProps & { }; type State = { - address: string | null, - publicKey: Uint8Array | null, + address: string, fieldName: string, isNameValid: boolean, isSeedValid: boolean, isPassValid: boolean, - isPassVisible: boolean, isValid: boolean, name: string, password: string, @@ -45,14 +44,12 @@ function formatSeed (seed: string): Uint8Array { : u8aFromString(seed.padEnd(32, ' ')); } -function infoFromSeed (seed: string): { address: string, publicKey: Uint8Array } { - const { publicKey } = keypairFromSeed(formatSeed(seed)); - const address = addressEncode(publicKey); - - return { - address, - publicKey - }; +function addressFromSeed (seed: string): string { + return addressEncode( + keypairFromSeed( + formatSeed(seed) + ).publicKey + ); } class Creator extends React.PureComponent { @@ -66,7 +63,7 @@ class Creator extends React.PureComponent { render (): React$Node { const { className, style, t } = this.props; - const { address, fieldName, isNameValid, isPassValid, isPassVisible, isSeedValid, isValid, name, password, publicKey, seed } = this.state; + const { address, fieldName, isNameValid, isPassValid, isSeedValid, isValid, name, password, seed } = this.state; return (
{ style={style} >
-
-
-
- - -
-
-
-
- - -
-
-
-
- - - -
-
-
+
+
+ +
+
+ +
+
+ +
+
+
); } - createState (currentPair: KeyringPair): $Shape { - const { name = '' } = currentPair.getMeta(); - + createState (currentPair: KeyringPair | null): $Shape { return { currentPair, - editedName: name, + editedName: currentPair + ? currentPair.getMeta().name || '' + : '', isEdited: false }; } @@ -121,13 +144,19 @@ class Editor extends React.PureComponent { this.setState( (prevState: State): $Shape => { let { currentPair = prevState.currentPair, editedName = prevState.editedName } = newState; + const previous = prevState.currentPair || { address: () => null }; + let isEdited = false; - if (currentPair.address() !== prevState.currentPair.address()) { - editedName = currentPair.getMeta().name || ''; + if (currentPair) { + if (currentPair.address() !== previous.address()) { + editedName = currentPair.getMeta().name || ''; + } else if (editedName !== currentPair.getMeta().name) { + isEdited = true; + } + } else { + editedName = ''; } - const isEdited = editedName !== currentPair.getMeta().name; - return { currentPair, editedName, @@ -145,14 +174,17 @@ class Editor extends React.PureComponent { }); } - // eslint-disable-next-line no-unused-vars - onChangeName = (event: SyntheticEvent<*>, { value }): void => { - this.nextState({ editedName: value }); + onChangeName = (editedName: string): void => { + this.nextState({ editedName }); } onCommit = (): void => { const { currentPair, editedName } = this.state; + if (!currentPair) { + return; + } + keyring.saveAccountMeta(currentPair, { name: editedName, whenEdited: Date.now() @@ -164,10 +196,38 @@ class Editor extends React.PureComponent { onDiscard = (): void => { const { currentPair } = this.state; + if (!currentPair) { + return; + } + this.nextState({ editedName: currentPair.getMeta().name }); } + + onForget = (): void => { + const { currentPair } = this.state; + + if (!currentPair) { + return; + } + + const address = currentPair.address(); + const pairs = keyring.getPairs().filter((item) => + item.address() !== address + ); + const nextPair = pairs[pairs.length - 1] || null; + const defaultPublicKey = nextPair + ? nextPair.publicKey() + : void 0; + + keyring.forgetAccount(address); + + this.nextState({ + currentPair: nextPair, + defaultPublicKey + }); + } } export default translate(Editor); diff --git a/packages/app-accounts/src/index.css b/packages/app-accounts/src/index.css index 874e5e1980..0b6a241b8e 100644 --- a/packages/app-accounts/src/index.css +++ b/packages/app-accounts/src/index.css @@ -15,6 +15,15 @@ text-align: center; } +.accounts--Address .rx--updated { + background: transparent !important; +} + +.accounts--Address.invalid { + filter: grayscale(100); + opacity: 0.45; +} + .accounts--Address-icon { display: block } @@ -24,7 +33,14 @@ opacity: 0.45; } -.accounts--Address-data {} +.accounts--Address-balance.rx--updated, +.accounts--Address-nonce.rx--updated { + opacity: 1; +} + +.accounts--Address-data { + padding: 0.5em 2em; +} .accounts--Address-data * { margin: 0 0.25rem !important; diff --git a/packages/app-accounts/src/index.js b/packages/app-accounts/src/index.js index c7b31cb6ef..4afb4395dd 100644 --- a/packages/app-accounts/src/index.js +++ b/packages/app-accounts/src/index.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import './index.css'; @@ -19,8 +19,7 @@ type Props = I18nProps & {}; type Actions = 'create' | 'edit'; type State = { - currentAction: Actions, - currentAddress: string | null + action: Actions } // FIXME React-router would probably be the best route, not home-grown @@ -30,19 +29,12 @@ const Components: { [Actions]: React$ComponentType<*> } = { }; class App extends React.PureComponent { - constructor (props: Props) { - super(props); - - this.state = { - currentAction: 'edit', - currentAddress: null - }; - } + state: State = { action: 'edit' }; render (): React$Node { const { className, style, t } = this.props; - const { currentAction } = this.state; - const Component = Components[currentAction]; + const { action } = this.state; + const Component = Components[action]; return (
{ +
); } - createState (currentAddress?: KeyringAddress): $Shape { + createState (currentAddress: KeyringAddress | null): $Shape { const { name = '' } = currentAddress ? currentAddress.getMeta() : {}; @@ -140,13 +148,18 @@ class Editor extends React.PureComponent { (prevState: State): $Shape => { let { currentAddress = prevState.currentAddress, editedName = prevState.editedName } = newState; const previous = prevState.currentAddress || { address: () => null }; + let isEdited = false; - if (currentAddress && currentAddress.address() !== previous.address()) { - editedName = currentAddress.getMeta().name || ''; + if (currentAddress && currentAddress.isValid()) { + if (currentAddress.address() !== previous.address()) { + editedName = currentAddress.getMeta().name || ''; + } else if (editedName !== currentAddress.getMeta().name) { + isEdited = true; + } + } else { + editedName = ''; } - const isEdited = !!currentAddress && editedName !== currentAddress.getMeta().name; - return { currentAddress, editedName, @@ -157,16 +170,15 @@ class Editor extends React.PureComponent { } onChangeAddress = (publicKey: Uint8Array): void => { - const currentAddress = keyring.getAddress(publicKey); + const currentAddress = keyring.getAddress(publicKey) || null; this.nextState({ currentAddress }); } - // eslint-disable-next-line no-unused-vars - onChangeName = (event: SyntheticEvent<*>, { value }): void => { - this.nextState({ editedName: value }); + onChangeName = (editedName: string): void => { + this.nextState({ editedName }); } onCommit = (): void => { @@ -195,6 +207,30 @@ class Editor extends React.PureComponent { editedName: currentAddress.getMeta().name }); } + + onForget = (): void => { + const { currentAddress } = this.state; + + if (!currentAddress) { + return; + } + + const address = currentAddress.address(); + const addresses = keyring.getAddresses().filter((item) => + item.address() !== address + ); + const nextAddress = addresses[0] || null; + const defaultPublicKey = nextAddress + ? nextAddress.publicKey() + : void 0; + + keyring.forgetAddress(address); + + this.nextState({ + currentAddress: nextAddress, + defaultPublicKey + }); + } } export default translate(Editor); diff --git a/packages/app-addresses/src/index.js b/packages/app-addresses/src/index.js index 922c557c35..936f8a1e75 100644 --- a/packages/app-addresses/src/index.js +++ b/packages/app-addresses/src/index.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import './index.css'; @@ -19,8 +19,7 @@ type Props = I18nProps & {}; type Actions = 'create' | 'edit'; type State = { - currentAction: Actions, - currentAddress: string | null + action: Actions } // FIXME React-router would probably be the best route, not home-grown @@ -30,19 +29,12 @@ const Components: { [Actions]: React$ComponentType<*> } = { }; class App extends React.PureComponent { - constructor (props: Props) { - super(props); - - this.state = { - currentAction: 'edit', - currentAddress: null - }; - } + state: State = { action: 'edit' }; render (): React$Node { const { className, style, t } = this.props; - const { currentAction } = this.state; - const Component = Components[currentAction]; + const { action } = this.state; + const Component = Components[action]; return (
{
-
- + -
+ ); } diff --git a/packages/app-extrinsics/src/Extrinsic.js b/packages/app-extrinsics/src/Extrinsic.js index a626519c6a..f215e151e8 100644 --- a/packages/app-extrinsics/src/Extrinsic.js +++ b/packages/app-extrinsics/src/Extrinsic.js @@ -4,14 +4,15 @@ // @flow import type { Extrinsic } from '@polkadot/extrinsics/types'; -import type { BareProps } from '@polkadot/ui-react-app/types'; -import type { RawParam } from '@polkadot/ui-react-app/Params/types'; +import type { BareProps } from '@polkadot/ui-app/types'; +import type { RawParam } from '@polkadot/ui-app/Params/types'; import type { EncodedMessage } from './types'; import React from 'react'; + import encode from '@polkadot/extrinsics-codec/encode/extrinsic'; -import InputExtrinsic from '@polkadot/ui-react-app/src/InputExtrinsic'; -import Params from '@polkadot/ui-react-app/src/Params'; +import InputExtrinsic from '@polkadot/ui-app/src/InputExtrinsic'; +import Params from '@polkadot/ui-app/src/Params'; import isUndefined from '@polkadot/util/is/undefined'; import paramComponents from './Params'; diff --git a/packages/app-extrinsics/src/Nonce.js b/packages/app-extrinsics/src/Nonce.js index 8cdbcec673..347f4686db 100644 --- a/packages/app-extrinsics/src/Nonce.js +++ b/packages/app-extrinsics/src/Nonce.js @@ -4,10 +4,11 @@ // @flow import type BN from 'bn.js'; -import type { BareProps } from '@polkadot/ui-react-app/types'; +import type { BareProps } from '@polkadot/ui-app/types'; import React from 'react'; -import Label from 'semantic-ui-react/dist/es/elements/Label'; + +import Labelled from '@polkadot/ui-app/src/Labelled'; import RxNonce from '@polkadot/ui-react-rx/Nonce'; type Props = BareProps & { @@ -22,14 +23,16 @@ export default function Nonce ({ className, label, style, onChange, value }: Pro className={['ui--row', className].join(' ')} style={style} > -
- + -
+ ); } diff --git a/packages/app-extrinsics/src/Params/Account.js b/packages/app-extrinsics/src/Params/Account.js index 5d3e21b63a..dcb9d1c148 100644 --- a/packages/app-extrinsics/src/Params/Account.js +++ b/packages/app-extrinsics/src/Params/Account.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { Props as BaseProps } from '@polkadot/ui-react-app/Params/types'; +import type { Props as BaseProps } from '@polkadot/ui-app/Params/types'; import React from 'react'; @@ -13,22 +13,29 @@ type Props = BaseProps & { defaultValue?: Uint8Array }; -export default function Account ({ className, defaultValue, index, isError, onChange, label, style }: Props): React$Node { - const _onChange = (value?: Uint8Array): void => +export default class Account extends React.PureComponent { + render (): React$Node { + const { className, defaultValue, isError, label, style } = this.props; + + return ( + + ); + } + + onChange = (value?: Uint8Array): void => { + const { index, onChange } = this.props; + onChange(index, { isValid: !!value && value.length === 32, value }); - - return ( - - ); + } } diff --git a/packages/app-extrinsics/src/Params/Proposal.js b/packages/app-extrinsics/src/Params/Proposal.js index ce825014ea..cc58172b13 100644 --- a/packages/app-extrinsics/src/Params/Proposal.js +++ b/packages/app-extrinsics/src/Params/Proposal.js @@ -3,11 +3,12 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { Props as BaseProps } from '@polkadot/ui-react-app/Params/types'; -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { Props as BaseProps } from '@polkadot/ui-app/Params/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { EncodedMessage } from '../types'; import React from 'react'; + import extrinsics from '@polkadot/extrinsics-substrate'; import Extrinsic from '../Extrinsic'; @@ -17,35 +18,42 @@ type Props = BaseProps & I18nProps; const defaultValue = extrinsics.consensus.methods.private.setCode; -function Proposal ({ className, index, isError, onChange, label, style, t }: Props): React$Node { - const _onChange = ({ isValid, value }: EncodedMessage): void => +class Proposal extends React.PureComponent { + render (): React$Node { + const { className, isError, label, style, t } = this.props; + + return ( + + ); + } + + onChange = ({ isValid, value }: EncodedMessage): void => { + const { index, onChange } = this.props; + onChange(index, { isValid, value }); - - return ( - - ); + } } export default translate(Proposal); diff --git a/packages/app-extrinsics/src/Params/index.js b/packages/app-extrinsics/src/Params/index.js index dcef1fc1b8..cd9cd8c7b5 100644 --- a/packages/app-extrinsics/src/Params/index.js +++ b/packages/app-extrinsics/src/Params/index.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { ComponentMap } from '@polkadot/ui-react-app/Params/types'; +import type { ComponentMap } from '@polkadot/ui-app/Params/types'; import Account from './Account'; import Proposal from './Proposal'; diff --git a/packages/app-extrinsics/src/Selection.js b/packages/app-extrinsics/src/Selection.js index a805c94abf..54008511c6 100644 --- a/packages/app-extrinsics/src/Selection.js +++ b/packages/app-extrinsics/src/Selection.js @@ -4,7 +4,7 @@ // @flow import type BN from 'bn.js'; -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { EncodedMessage, QueueTx } from './types'; import React from 'react'; @@ -32,15 +32,9 @@ const defaultExtrinsic = extrinsics.staking.methods.public.transfer; let id = 0; class Selection extends React.PureComponent { - state: State; - - constructor (props: Props) { - super(props); - - this.state = ({ - isValid: false - }: $Shape); - } + state: State = ({ + isValid: false + }: $Shape); render () { const { className, style, t } = this.props; diff --git a/packages/app-extrinsics/src/Signer/Decoded.js b/packages/app-extrinsics/src/Signer/Decoded.js index 56beb57de7..20538bcfc3 100644 --- a/packages/app-extrinsics/src/Signer/Decoded.js +++ b/packages/app-extrinsics/src/Signer/Decoded.js @@ -3,12 +3,13 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { QueueTx } from '../types'; import BN from 'bn.js'; import React from 'react'; import { Trans } from 'react-i18next'; + import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; import u8aToHexShort from '@polkadot/util/u8a/toHexShort'; import addressEncode from '@polkadot/util-keyring/address/encode'; diff --git a/packages/app-extrinsics/src/Signer/Signer.css b/packages/app-extrinsics/src/Signer/Signer.css index e7ad37d1b5..640b253d34 100644 --- a/packages/app-extrinsics/src/Signer/Signer.css +++ b/packages/app-extrinsics/src/Signer/Signer.css @@ -11,8 +11,16 @@ line-height: 1.5em; } +.extrinsics--Signer-Decoded { + padding-top: 2rem; +} + .extrinsics--Signer-Unlock { - padding-top: 1.5em; + padding-top: 1.5rem; +} + +.extrinsics--Signer-Content { + padding: 1.5rem 3rem !important; } .extrinsics--Signer-Content .expanded { diff --git a/packages/app-extrinsics/src/Signer/Unlock.js b/packages/app-extrinsics/src/Signer/Unlock.js index 0d8dc3eae1..17185b3dca 100644 --- a/packages/app-extrinsics/src/Signer/Unlock.js +++ b/packages/app-extrinsics/src/Signer/Unlock.js @@ -3,13 +3,12 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { KeyringPair } from '@polkadot/util-keyring/types'; import React from 'react'; -import Button from 'semantic-ui-react/dist/es/elements/Button'; -import Input from 'semantic-ui-react/dist/es/elements/Input'; -import Label from 'semantic-ui-react/dist/es/elements/Label'; + +import Password from '@polkadot/ui-app/src/Password'; import keyring from '@polkadot/ui-keyring/src'; import translate from '../translate'; @@ -26,20 +25,13 @@ type State = { fieldName: string, isError: boolean, isLocked: boolean, - isVisible: boolean, pair: KeyringPair } class Unlock extends React.PureComponent { - constructor (props: Props) { - super(props); + state: State = ({}: $Shape); - this.state = ({ - isVisible: false - }: $Shape); - } - - static getDerivedStateFromProps ({ error, password, value }: Props, { isVisible }: State): $Shape { + static getDerivedStateFromProps ({ error, password, value }: Props): $Shape { const pair = keyring.getPair(value); const isLocked = !pair.hasSecretKey(); @@ -47,16 +39,13 @@ class Unlock extends React.PureComponent { fieldName: `pass_${Date.now()}`, isError: !!error, isLocked, - isVisible: password.length === 0 - ? false - : isVisible, pair }; } render (): React$Node { - const { className, password, style, t } = this.props; - const { fieldName, isError, isLocked, isVisible } = this.state; + const { className, onChange, password, style, t } = this.props; + const { fieldName, isError, isLocked } = this.state; if (!isLocked) { return null; @@ -67,42 +56,21 @@ class Unlock extends React.PureComponent { className={['extrinsics--Signer-Unlock', className].join(' ')} style={style} > -
-
-
); } - - // eslint-disable-next-line no-unused-vars - onChange = (event: SyntheticEvent<*>, { value }): void => { - this.props.onChange(value); - } - - togglePassword = (): void => { - this.setState({ - isVisible: !this.state.isVisible - }); - } } export default translate(Unlock); diff --git a/packages/app-extrinsics/src/Signer/index.js b/packages/app-extrinsics/src/Signer/index.js index 836a1ae0f9..a3be804e19 100644 --- a/packages/app-extrinsics/src/Signer/index.js +++ b/packages/app-extrinsics/src/Signer/index.js @@ -4,7 +4,7 @@ // @flow import type { ApiProps } from '@polkadot/ui-react-rx/types'; -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { QueueTx } from '../types'; import './Signer.css'; @@ -12,6 +12,7 @@ import './Signer.css'; import React from 'react'; import Button from 'semantic-ui-react/dist/es/elements/Button'; import Modal from 'semantic-ui-react/dist/es/modules/Modal'; + import keyring from '@polkadot/ui-keyring/src'; import withApi from '@polkadot/ui-react-rx/with/api'; @@ -37,14 +38,10 @@ type State = { }; class Signer extends React.PureComponent { - constructor (props: Props) { - super(props); - - this.state = { - password: '', - unlockError: null - }; - } + state: State = { + password: '', + unlockError: null + }; static getDerivedStateFromProps ({ queue }: Props, { currentItem, password, unlockError }: State): $Shape { const nextItem = queue.find(({ status }) => diff --git a/packages/app-extrinsics/src/Status.js b/packages/app-extrinsics/src/Status.js index 7e884f0cb1..ad5c53dc3f 100644 --- a/packages/app-extrinsics/src/Status.js +++ b/packages/app-extrinsics/src/Status.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { BareProps } from '@polkadot/ui-react-app/types'; +import type { BareProps } from '@polkadot/ui-app/types'; import type { QueueTx } from './types'; import React from 'react'; diff --git a/packages/app-extrinsics/src/index.css b/packages/app-extrinsics/src/index.css index d7f3545d71..44bc435ff7 100644 --- a/packages/app-extrinsics/src/index.css +++ b/packages/app-extrinsics/src/index.css @@ -7,16 +7,16 @@ } .extrinsics--Status { - bottom: 0; display: inline-block; position: fixed; - right: 0.125rem; + right: 0.25rem; + top: 0.125rem; z-index: 1001; } .extrinsics--Status-Item { background: #bcdaf0; - margin-bottom: 0.125rem; + margin: 0.125rem; padding: 0.5rem 1rem; text-align: center; } diff --git a/packages/app-extrinsics/src/index.js b/packages/app-extrinsics/src/index.js index e6c2671e62..2de0cd28fa 100644 --- a/packages/app-extrinsics/src/index.js +++ b/packages/app-extrinsics/src/index.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { BareProps } from '@polkadot/ui-react-app/types'; +import type { BareProps } from '@polkadot/ui-app/types'; import type { QueueTx, QueueTx$Status } from './types'; import './index.css'; @@ -21,15 +21,9 @@ type State = { }; export default class App extends React.PureComponent { - state: State; - - constructor (props: Props) { - super(props); - - this.state = { - queue: [] - }; - } + state: State = { + queue: [] + }; render (): React$Node { const { className, style } = this.props; diff --git a/packages/app-storage/package.json b/packages/app-storage/package.json index 9f028b57d3..8e7216cafc 100644 --- a/packages/app-storage/package.json +++ b/packages/app-storage/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/app-storage", - "version": "0.3.4", + "version": "0.4.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -11,6 +11,6 @@ "test": "jest --coverage" }, "devDependencies": { - "@polkadot/ui-react-app": "^0.3.4" + "@polkadot/ui-app": "^0.4.0" } } diff --git a/packages/app-storage/src/Queries.js b/packages/app-storage/src/Queries.js index 4e8043763f..4d7cb79c84 100644 --- a/packages/app-storage/src/Queries.js +++ b/packages/app-storage/src/Queries.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { StorageQuery } from './types'; import React from 'react'; diff --git a/packages/app-storage/src/Query/format.js b/packages/app-storage/src/Query/format.js index 913b68e892..7d0713e050 100644 --- a/packages/app-storage/src/Query/format.js +++ b/packages/app-storage/src/Query/format.js @@ -6,6 +6,7 @@ import type { Param$Type, Param$TypeArray } from '@polkadot/primitives/param'; import React from 'react'; + // import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; import addressEncode from '@polkadot/util-keyring/address/encode'; import u8aToBn from '@polkadot/util/u8a/toBn'; diff --git a/packages/app-storage/src/Query/index.js b/packages/app-storage/src/Query/index.js index 85de6ab9a1..3d156f7afd 100644 --- a/packages/app-storage/src/Query/index.js +++ b/packages/app-storage/src/Query/index.js @@ -3,13 +3,14 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { I18nProps } from '@polkadot/ui-app/types'; import type { StorageQuery } from '../types'; import React from 'react'; import Button from 'semantic-ui-react/dist/es/elements/Button'; -import Label from 'semantic-ui-react/dist/es/elements/Label'; -import typeToText from '@polkadot/ui-react-app/src/Params/typeToText'; + +import Labelled from '@polkadot/ui-app/src/Labelled'; +import typeToText from '@polkadot/ui-app/src/Params/typeToText'; import withStorageDiv from '@polkadot/ui-react-rx/with/storageDiv'; import translate from '../translate'; @@ -20,61 +21,82 @@ type Props = I18nProps & { value: StorageQuery }; +type State = { + inputs: Array, + Component: React$ComponentType<*>; +}; + const cache = []; -function Query ({ className, onRemove, style, value: { id, key, params } }: Props): React$Node { - const CachedQuery = (() => { - if (!cache[id]) { - const values = params.map(({ value }) => value); +class Query extends React.PureComponent { + state: State = ({}: $Shape); - cache[id] = withStorageDiv(key, { params: values })( - (value) => - format(key.type, value), - { className: 'ui disabled dropdown selection' } - ); - } + static getDerivedStateFromProps ({ value: { id, key, params } }: Props, prevState: State): State | null { + const Component = ((): React$ComponentType<*> => { + if (!cache[id]) { + const values = params.map(({ value }) => value); - return cache[id]; - })(); + cache[id] = withStorageDiv(key, { params: values })( + (value) => + format(key.type, value), + { className: 'ui disabled dropdown selection' } + ); + } + + return cache[id]; + })(); + const inputs = Object + .keys(key.params || {}) + .map((name, index) => { + // $FlowFixMe key.params exists + const formatted = format(key.params[name].type, params[index].value, 12); + + return ( + {name}={formatted} + ); + }); + + return { + Component, + inputs + }; + } + + render (): React$Node { + const { className, style, value: { key } } = this.props; + const { Component, inputs } = this.state; + + return ( +
+ {key.section}.{key.name}({inputs}): {typeToText(key.type)}
+ } + > + + + +