diff --git a/.flowconfig b/.flowconfig index e291c6545f..7e68a1c345 100644 --- a/.flowconfig +++ b/.flowconfig @@ -12,6 +12,6 @@ all=warn [options] include_warnings=true -module.name_mapper='^@polkadot/app-\(accounts\|explorer\|extrinsics\|home\|rpc\|settings\|storage\)\(.*\)$' -> '/packages/app-\1/src\2' +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-react-app\(.*\)$' -> '/packages/ui-react-app/src\1' diff --git a/flow-typed/semantic-ui-react.js b/flow-typed/semantic-ui-react.js index cdb52c30f7..4f757e1b38 100644 --- a/flow-typed/semantic-ui-react.js +++ b/flow-typed/semantic-ui-react.js @@ -7,6 +7,13 @@ declare module 'semantic-ui-react/dist/es/collections/Menu' { } declare module 'semantic-ui-react/dist/es/elements/Button' { + declare module.exports: React$StatelessFunctionalComponent<*> & { + Group: React$StatelessFunctionalComponent<*>, + Or: React$StatelessFunctionalComponent<*> + }; +} + +declare module 'semantic-ui-react/dist/es/elements/Divider' { declare module.exports: React$StatelessFunctionalComponent<*>; } diff --git a/flow-typed/store.js b/flow-typed/store.js new file mode 100644 index 0000000000..72aa863ded --- /dev/null +++ b/flow-typed/store.js @@ -0,0 +1,9 @@ +// @flow + +declare module 'store' { + declare module.exports: { + each: (fn: (value: any, key: string) => void) => void, + get: (key: string) => any, + set: (key: string, value: any) => void, + } +} diff --git a/lerna.json b/lerna.json index b1c50ec917..11ad0a7bbc 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "packages": [ "packages/*" ], - "version": "0.1.12" + "version": "0.2.0" } diff --git a/packages/app-accounts/LICENSE b/packages/app-accounts/LICENSE new file mode 100644 index 0000000000..3d150a620a --- /dev/null +++ b/packages/app-accounts/LICENSE @@ -0,0 +1,15 @@ +ISC License (ISC) + +Copyright 2017-2018 Jaco Greeff + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/app-accounts/README.md b/packages/app-accounts/README.md new file mode 100644 index 0000000000..75a8b16640 --- /dev/null +++ b/packages/app-accounts/README.md @@ -0,0 +1 @@ +# @polkadot/app-accounts diff --git a/packages/app-accounts/package.json b/packages/app-accounts/package.json new file mode 100644 index 0000000000..3dc321cb97 --- /dev/null +++ b/packages/app-accounts/package.json @@ -0,0 +1,16 @@ +{ + "name": "@polkadot/app-accounts", + "version": "0.2.0", + "main": "index.js", + "repository": "https://github.com/polkadot-js/apps.git", + "author": "Jaco Greeff ", + "license": "ISC", + "scripts": { + "build": "polkadot-dev-build-babel", + "check": "stylelint 'src/**/*.css' && eslint src && flow check", + "test": "jest --coverage" + }, + "devDependencies": { + "@polkadot/ui-react-app": "^0.2.0" + } +} diff --git a/packages/app-accounts/src/Address.js b/packages/app-accounts/src/Address.js new file mode 100644 index 0000000000..6aa0da6e78 --- /dev/null +++ b/packages/app-accounts/src/Address.js @@ -0,0 +1,41 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { BareProps } from '@polkadot/ui-react-app/types'; + +import React from 'react'; +import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; + +type Props = BareProps & { + address: string | null; +} + +export default function Address ({ address, className, style }: Props): React$Node { + return ( +
+ { + // flowlint-next-line sketchy-null-string:off + address + ? ( + + ) + : null + } +
+ { + // flowlint-next-line sketchy-null-string:off + address || 'unknown' + } +
+
+ ); +} diff --git a/packages/app-accounts/src/Creator.js b/packages/app-accounts/src/Creator.js new file mode 100644 index 0000000000..e39cd97914 --- /dev/null +++ b/packages/app-accounts/src/Creator.js @@ -0,0 +1,225 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { I18nProps, KeyringInstance } from '@polkadot/ui-react-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 isHex from '@polkadot/util/is/hex'; +import hexToU8a from '@polkadot/util/hex/toU8a'; +import u8aFromString from '@polkadot/util/u8a/fromString'; +import u8aToHex from '@polkadot/util/u8a/toHex'; +import keypairFromSeed from '@polkadot/util-crypto/nacl/keypair/fromSeed'; +import randomBytes from '@polkadot/util-crypto/random/asU8a'; +import addressEncode from '@polkadot/util-keyring/address/encode'; + +import Address from './Address'; +import translate from './translate'; + +type Props = I18nProps & { + keyring: KeyringInstance, + onBack: () => void +}; + +type State = { + address: string | null, + isNameValid: boolean, + isSeedValid: boolean, + isPassValid: boolean, + isPassVisible: boolean, + isValid: boolean, + name: string, + password: string, + seed: string +} + +function formatSeed (seed: string): Uint8Array { + return isHex(seed) + ? hexToU8a(seed) + : u8aFromString(seed.padEnd(32, ' ')); +} + +function addressFromSeed (seed: string): string { + const { publicKey } = keypairFromSeed(formatSeed(seed)); + + return addressEncode(publicKey); +} + +class Creator extends React.PureComponent { + constructor (props: Props) { + super(props); + + this.state = this.emptyState(); + } + + render (): React$Node { + const { className, style, t } = this.props; + const { address, isNameValid, isPassValid, isPassVisible, isSeedValid, isValid, name, password, seed } = this.state; + + return ( +
+
+
+ + +
+
+ +
+
+
+
+
+ + +
+
+
+
+ + + +
+
+
+ + +
+
+ ); + } + + emptyState (): State { + const seed = u8aToHex(randomBytes()); + const address = addressFromSeed(seed); + + return { + address, + isNameValid: true, + isPassValid: false, + isPassVisible: false, + isSeedValid: true, + isValid: false, + name: 'new keypair', + password: '', + seed + }; + } + + nextState (newState: $Shape): void { + this.setState( + (prevState: State, props: Props): $Shape => { + const { name = prevState.name, password = prevState.password, seed = prevState.seed } = newState; + let address = prevState.address; + const isNameValid = !!name; + const isSeedValid = isHex(seed) + ? seed.length === 66 + : seed.length <= 32; + const isPassValid = password.length > 0 && password.length <= 32; + + if (isSeedValid && seed !== prevState.seed) { + address = addressFromSeed(seed); + } + + return { + address, + isNameValid, + isPassValid, + isSeedValid, + isValid: isNameValid && isPassValid && isSeedValid, + name, + password, + seed + }; + } + ); + } + + // eslint-disable-next-line no-unused-vars + onChangeSeed = (event: SyntheticEvent<*>, { value }): void => { + this.nextState({ seed: value }); + } + + // eslint-disable-next-line no-unused-vars + onChangeName = (event: SyntheticEvent<*>, { value }): void => { + this.nextState({ name: value }); + } + + onChangePass = (event: SyntheticEvent<*>, { value }): void => { + this.nextState({ password: value }); + } + + onCommit = (): void => { + const { keyring, onBack } = this.props; + const { name, password, seed } = this.state; + const pair = keyring.addFromSeed( + formatSeed(seed), + { name } + ); + + keyring.saveJson(pair, password); + + onBack(); + } + + onDiscard = (): void => { + this.setState(this.emptyState()); + } + + togglePassword = (): void => { + this.setState({ isPassVisible: !this.state.isPassVisible }); + } +} + +export default translate(Creator); diff --git a/packages/app-accounts/src/Editor.js b/packages/app-accounts/src/Editor.js new file mode 100644 index 0000000000..d2e2313a2d --- /dev/null +++ b/packages/app-accounts/src/Editor.js @@ -0,0 +1,161 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { KeyringPair } from '@polkadot/util-keyring/types'; +import type { KeyringOptions } from '@polkadot/ui-react-app/InputAddress/types'; +import type { I18nProps, KeyringInstance } from '@polkadot/ui-react-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 InputAddress from '@polkadot/ui-react-app/src/InputAddress'; +import createOptions from '@polkadot/ui-react-app/src/InputAddress/options'; + +import translate from './translate'; + +type Props = I18nProps & { + keyring: KeyringInstance, + onBack: () => void +}; + +type State = { + currentPair: KeyringPair, + defaultPublicKey: Uint8Array, + editedName: string, + isEdited: boolean, + options: KeyringOptions +} + +class Editor extends React.PureComponent { + constructor (props: Props) { + super(props); + + const pairs = props.keyring.getPairs(); + const currentPair = pairs[pairs.length - 1]; + + this.state = this.createState(currentPair); + this.state.defaultPublicKey = currentPair.publicKey(); + this.state.options = this.createOptions(); + } + + render (): React$Node { + const { className, style, t } = this.props; + const { defaultPublicKey, editedName, isEdited, options } = this.state; + + return ( +
+
+ +
+
+
+ + +
+
+
+ + +
+
+ ); + } + + createOptions (): KeyringOptions { + return createOptions(this.props.keyring); + } + + createState (currentPair: KeyringPair): $Shape { + const { name = '' } = currentPair.getMeta(); + + return { + currentPair, + editedName: name, + isEdited: false + }; + } + + nextState (newState?: $Shape = {}): void { + this.setState( + (prevState: State): $Shape => { + let { currentPair = prevState.currentPair, editedName = prevState.editedName, options = prevState.options } = newState; + + if (currentPair.address() !== prevState.currentPair.address()) { + editedName = currentPair.getMeta().name || ''; + } + + const isEdited = editedName !== currentPair.getMeta().name; + + return { + currentPair, + editedName, + isEdited, + options + }; + } + ); + } + + onChangeAccount = (publicKey: Uint8Array): void => { + const { keyring } = this.props; + const currentPair = keyring.getPair(publicKey); + + this.nextState({ currentPair }); + } + + // eslint-disable-next-line no-unused-vars + onChangeName = (event: SyntheticEvent<*>, { value }): void => { + this.nextState({ editedName: value }); + } + + onCommit = (): void => { + const { currentPair, editedName } = this.state; + + currentPair.setMeta({ name: editedName }); + + this.nextState({ options: this.createOptions() }); + } + + onDiscard = (): void => { + const { currentPair } = this.state; + + this.nextState({ editedName: currentPair.getMeta().name }); + } +} + +export default translate(Editor); diff --git a/packages/app-accounts/src/index.css b/packages/app-accounts/src/index.css new file mode 100644 index 0000000000..dea33cca18 --- /dev/null +++ b/packages/app-accounts/src/index.css @@ -0,0 +1,35 @@ +/* Copyright 2017-2018 Jaco Greeff +/* This software may be modified and distributed under the terms +/* of the ISC license. See the LICENSE file for details. */ + +.accounts--App { + padding: 1em 2em; +} + +.accounts--App-navigation { + margin-bottom: 2em; + text-align: center; +} + +.accounts--Icon { + position: fixed; + top: 0.75em; + right: 0.75em; +} + +.accounts--Address { + opacity: 1 !important; + position: relative; +} + +.accounts--Address-icon { + position: absolute; + top: 2px; + left: 1rem; +} + +.accounts--Address-name { + font-family: monospace; + padding-left: 3rem; + opacity: 0.45; +} diff --git a/packages/app-accounts/src/index.js b/packages/app-accounts/src/index.js new file mode 100644 index 0000000000..832067501d --- /dev/null +++ b/packages/app-accounts/src/index.js @@ -0,0 +1,99 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { I18nProps } from '@polkadot/ui-react-app/types'; + +import './index.css'; + +import React from 'react'; +import Button from 'semantic-ui-react/dist/es/elements/Button'; + +import Creator from './Creator'; +import Editor from './Editor'; +import keyring from '@polkadot/ui-react-app/src/keyring'; +import translate from './translate'; + +type Props = I18nProps & {}; + +type Actions = 'create' | 'edit'; + +type State = { + currentAction: Actions, + currentAddress: string | null +} + +// FIXME React-router would probably be the best route, not home-grown +const Components: { [Actions]: React$ComponentType<*> } = { + 'create': Creator, + 'edit': Editor +}; + +class App extends React.PureComponent { + constructor (props: Props) { + super(props); + + this.state = { + currentAction: 'edit', + currentAddress: null + }; + } + + render (): React$Node { + const { className, style, t } = this.props; + const { currentAction } = this.state; + const Component = Components[currentAction]; + + return ( +
+
+ + + + + +
+ +
+ ); + } + + setCurrentAction (currentAction: Actions): void { + this.setState({ currentAction }); + } + + selectCreate = (): void => { + this.setCurrentAction('create'); + } + + selectEdit = (): void => { + this.setCurrentAction('edit'); + } +} + +export default translate(App); diff --git a/packages/app-accounts/src/translate.js b/packages/app-accounts/src/translate.js new file mode 100644 index 0000000000..fea295c6b2 --- /dev/null +++ b/packages/app-accounts/src/translate.js @@ -0,0 +1,8 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import { translate } from 'react-i18next'; + +export default translate(['accounts', 'ui']); diff --git a/packages/app-explorer/package.json b/packages/app-explorer/package.json index 9de1f606ef..d7d1cdb15a 100644 --- a/packages/app-explorer/package.json +++ b/packages/app-explorer/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/app-explorer", - "version": "0.1.12", + "version": "0.2.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -11,10 +11,10 @@ "test": "jest --coverage" }, "devDependencies": { - "@polkadot/primitives": "^0.12.8", - "@polkadot/primitives-codec": "^0.12.8", - "@polkadot/primitives-json": "^0.12.8", - "@polkadot/ui-react-app": "^0.1.12", - "@polkadot/util-crypto": "^0.19.5" + "@polkadot/primitives": "^0.12.9", + "@polkadot/primitives-codec": "^0.12.9", + "@polkadot/primitives-json": "^0.12.9", + "@polkadot/ui-react-app": "^0.2.0", + "@polkadot/util-crypto": "^0.19.6" } } diff --git a/packages/app-extrinsics/package.json b/packages/app-extrinsics/package.json index 2b8c780e47..454ef691e2 100644 --- a/packages/app-extrinsics/package.json +++ b/packages/app-extrinsics/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/app-extrinsics", - "version": "0.1.12", + "version": "0.2.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -11,9 +11,9 @@ "test": "jest --coverage" }, "devDependencies": { - "@polkadot/extrinsics": "^0.12.8", - "@polkadot/extrinsics-codec": "^0.12.8", - "@polkadot/ui-react-app": "^0.1.12", + "@polkadot/extrinsics": "^0.12.9", + "@polkadot/extrinsics-codec": "^0.12.9", + "@polkadot/ui-react-app": "^0.2.0", "react-dropzone": "^4.2.9" } } diff --git a/packages/app-extrinsics/src/Selection/Nonce.js b/packages/app-extrinsics/src/Nonce.js similarity index 100% rename from packages/app-extrinsics/src/Selection/Nonce.js rename to packages/app-extrinsics/src/Nonce.js diff --git a/packages/app-extrinsics/src/Selection/index.js b/packages/app-extrinsics/src/Selection.js similarity index 92% rename from packages/app-extrinsics/src/Selection/index.js rename to packages/app-extrinsics/src/Selection.js index 82b0f5159e..02cd3d404b 100644 --- a/packages/app-extrinsics/src/Selection/index.js +++ b/packages/app-extrinsics/src/Selection.js @@ -5,18 +5,16 @@ import type BN from 'bn.js'; import type { I18nProps } from '@polkadot/ui-react-app/types'; -import type { EncodedMessage, QueueTx } from '../types'; - -import './Selection.css'; +import type { EncodedMessage, QueueTx } from './types'; import React from 'react'; import Button from 'semantic-ui-react/dist/es/elements/Button'; import extrinsics from '@polkadot/extrinsics-substrate'; -import Account from '../Account'; -import Extrinsic from '../Extrinsic'; -import translate from '../translate'; +import Account from './Account'; +import Extrinsic from './Extrinsic'; import Nonce from './Nonce'; +import translate from './translate'; type Props = I18nProps & { onQueue: (value: QueueTx) => void @@ -73,7 +71,7 @@ class Selection extends React.PureComponent { onChange={this.onChangeNonce} value={publicKey} /> -
+
); } diff --git a/packages/apps/src/index.js b/packages/apps/src/index.js index 1d85a7c6c6..ea5cf6bc70 100644 --- a/packages/apps/src/index.js +++ b/packages/apps/src/index.js @@ -14,7 +14,9 @@ createApp((() => { const { app } = urlParams(); if (app) { - const route = routing.routes.find(({ name }) => name === app); + const route = routing.routes.find((route) => + route && route.name === app + ); return route ? route.component diff --git a/packages/apps/src/routing/accounts.js b/packages/apps/src/routing/accounts.js new file mode 100644 index 0000000000..71ddd20df0 --- /dev/null +++ b/packages/apps/src/routing/accounts.js @@ -0,0 +1,21 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { Routes } from '../types'; + +import Accounts from '@polkadot/app-accounts/src'; + +export default ([ + { + component: Accounts, + i18n: { + defaultValue: 'Accounts' + }, + icon: 'users', + isExact: false, + isHidden: false, + name: 'accounts' + } +]: Routes); diff --git a/packages/apps/src/routing/index.js b/packages/apps/src/routing/index.js index e382b64af8..91c86ae211 100644 --- a/packages/apps/src/routing/index.js +++ b/packages/apps/src/routing/index.js @@ -5,16 +5,18 @@ import type { Routing } from '../types'; -// import accounts from './accounts'; +import accounts from './accounts'; +// import addresses from './addresses'; import explorer from './explorer'; import extrinsics from './extrinsics'; // import home from './home'; // import settings from './settings'; import storage from './storage'; +// import vanitygen from './vanitygen'; export default ({ default: 'explorer', routes: [].concat( - explorer, extrinsics, storage + explorer, extrinsics, storage, null, accounts ) }: Routing); diff --git a/packages/apps/src/types.js b/packages/apps/src/types.js index 73e6d78176..8e848214e0 100644 --- a/packages/apps/src/types.js +++ b/packages/apps/src/types.js @@ -13,7 +13,7 @@ export type Route = { path?: string }; -export type Routes = Array; +export type Routes = Array; export type Routing = { default: string, diff --git a/packages/ui-react-app/package.json b/packages/ui-react-app/package.json index 1718ca10fd..1869818799 100644 --- a/packages/ui-react-app/package.json +++ b/packages/ui-react-app/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/ui-react-app", - "version": "0.1.12", + "version": "0.2.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -11,12 +11,12 @@ "test": "jest --coverage" }, "dependencies": { - "@polkadot/extrinsics-substrate": "^0.12.8", - "@polkadot/storage-substrate": "^0.12.8", - "@polkadot/ui-react": "^0.11.2", - "@polkadot/ui-react-rx": "^0.11.2", - "@polkadot/util": "^0.19.5", - "@polkadot/util-keyring": "^0.19.5", + "@polkadot/extrinsics-substrate": "^0.12.9", + "@polkadot/storage-substrate": "^0.12.9", + "@polkadot/ui-react": "^0.11.3", + "@polkadot/ui-react-rx": "^0.11.3", + "@polkadot/util": "^0.19.6", + "@polkadot/util-keyring": "^0.19.6", "i18next": "^11.1.1", "i18next-browser-languagedetector": "^2.2.0", "i18next-xhr-backend": "^1.5.1", @@ -25,7 +25,8 @@ "react-i18next": "^7.5.1", "react-router-dom": "^4.2.2", "semantic-ui-css": "^2.3.1", - "semantic-ui-react": "^0.79.1" + "semantic-ui-react": "^0.79.1", + "store": "^2.0.12" }, "devDepependencies": { "@polkadot/primitives": "^0.12.6" diff --git a/packages/ui-react-app/src/InputAddress/index.js b/packages/ui-react-app/src/InputAddress/index.js index 96212ae89c..74a1745bcc 100644 --- a/packages/ui-react-app/src/InputAddress/index.js +++ b/packages/ui-react-app/src/InputAddress/index.js @@ -3,7 +3,9 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { KeyringInstance } from '@polkadot/util-keyring/types'; import type { BareProps } from '../types'; +import type { KeyringOptions } from './types'; import './InputAddress.css'; @@ -11,29 +13,23 @@ import React from 'react'; import addressDecode from '@polkadot/util-keyring/address/decode'; import addressEncode from '@polkadot/util-keyring/address/encode'; -// TODO: We need to actually pass the keyring in, this is the testing keyring -import keyring from '../keyring'; import RxDropdown from '../RxDropdown'; -import PairDisplay from './PairDisplay'; +import createOptions from './options'; type Props = BareProps & { defaultValue?: Uint8Array, isError?: boolean, + keyring?: KeyringInstance, label?: string, - onChange: (value: Uint8Array) => void + onChange: (value: Uint8Array) => void, + options?: KeyringOptions }; -const options = keyring.getPairs().map((pair) => ({ - text: ( - - ), - value: pair.address() -})); - const transform = (value: string): Uint8Array => addressDecode(value); -export default function InputAddress ({ className, defaultValue, isError, label, onChange, style }: Props): React$Node { +export default function InputAddress ({ className, defaultValue, isError, keyring, label, onChange, options, style }: Props): React$Node { + const _options = options || createOptions(keyring); let _defaultValue; if (defaultValue) { @@ -47,7 +43,7 @@ export default function InputAddress ({ className, defaultValue, isError, label, isError={isError} label={label} onChange={onChange} - options={options} + options={_options} transform={transform} /> ); diff --git a/packages/ui-react-app/src/InputAddress/options.js b/packages/ui-react-app/src/InputAddress/options.js new file mode 100644 index 0000000000..3470733d11 --- /dev/null +++ b/packages/ui-react-app/src/InputAddress/options.js @@ -0,0 +1,23 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { KeyringInstance } from '@polkadot/util-keyring/types'; +import type { KeyringOptions } from './types'; + +import React from 'react'; + +import testKeyring from '../keyring'; +import PairDisplay from './PairDisplay'; + +export default function createOptions (keyring?: KeyringInstance = testKeyring): KeyringOptions { + return keyring + .getPairs() + .map((pair) => ({ + text: ( + + ), + value: pair.address() + })); +} diff --git a/packages/ui-react-app/src/InputAddress/types.js b/packages/ui-react-app/src/InputAddress/types.js new file mode 100644 index 0000000000..9418c227dd --- /dev/null +++ b/packages/ui-react-app/src/InputAddress/types.js @@ -0,0 +1,11 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +export type KeyringOption = { + text: React$Node, + value: string +}; + +export type KeyringOptions = Array; diff --git a/packages/ui-react-app/src/keyring.js b/packages/ui-react-app/src/keyring.js index 241d18233f..9d71acd798 100644 --- a/packages/ui-react-app/src/keyring.js +++ b/packages/ui-react-app/src/keyring.js @@ -3,8 +3,32 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { KeyringPair } from '@polkadot/util-keyring/types'; +import type { KeyringInstance } from './types'; + +import store from 'store'; import testKeyring from '@polkadot/util-keyring/testing'; const keyring = testKeyring(); -export default keyring; +const keyringExt: KeyringInstance = { + ...keyring, + loadJson: (): void => { + store.each((value, key: string) => { + if (!/account:/.test(key)) { + return; + } + + keyring.addFromJson(value); + }); + }, + saveJson: (pair: KeyringPair, password?: string): void => { + const json = pair.toJson(password); + + store.set(`account:${json.address}`, json); + } +}; + +keyringExt.loadJson(); + +export default keyringExt; diff --git a/packages/ui-react-app/src/styles/form.css b/packages/ui-react-app/src/styles/form.css index 2f0afb4edf..21b5351353 100644 --- a/packages/ui-react-app/src/styles/form.css +++ b/packages/ui-react-app/src/styles/form.css @@ -46,3 +46,13 @@ .ui--form > div.small { flex: 0 25%; } + +.ui--form-buttons { + margin: 1em 0; + text-align: right; +} + +.ui--form-buttons .button { + margin: 0 0 0 0.5rem; + text-align: left; +} diff --git a/packages/ui-react-app/src/types.js b/packages/ui-react-app/src/types.js index 8de569b892..ba5654b656 100644 --- a/packages/ui-react-app/src/types.js +++ b/packages/ui-react-app/src/types.js @@ -4,6 +4,7 @@ // @flow import type { RxApiInterface } from '@polkadot/api-rx/types'; +import type { KeyringInstance as UKeyringInstance, KeyringPair } from '@polkadot/util-keyring/types'; export type BareProps = { className?: string, @@ -25,3 +26,8 @@ export type BaseContext = { } } }; + +export type KeyringInstance = UKeyringInstance & { + loadJson: () => void, + saveJson: (pair: KeyringPair, password?: string) => void +}; diff --git a/yarn.lock b/yarn.lock index 9004ec2d22..9c104a44e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -622,49 +622,49 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@polkadot/api-format@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-format/-/api-format-0.10.2.tgz#867816c0fcc00e9e88197b1e0546849649f06be9" +"@polkadot/api-format@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@polkadot/api-format/-/api-format-0.10.3.tgz#d6d56af776c636e3423837a516ea6754dd41ccac" dependencies: - "@polkadot/primitives-json" "^0.12.8" - "@polkadot/util" "^0.19.5" + "@polkadot/primitives-json" "^0.12.9" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/api-jsonrpc@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-jsonrpc/-/api-jsonrpc-0.10.2.tgz#55836832ee3e48437edfabeca3e8f5fd20367f13" +"@polkadot/api-jsonrpc@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@polkadot/api-jsonrpc/-/api-jsonrpc-0.10.3.tgz#4abe9e5f59a7bf46830e2f775d70fdb6e54fd99c" dependencies: babel-runtime "^6.26.0" -"@polkadot/api-provider@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-provider/-/api-provider-0.10.2.tgz#4d84bdabed2e548277d3ffe87bbdc0e9f0976592" +"@polkadot/api-provider@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@polkadot/api-provider/-/api-provider-0.10.3.tgz#bb3201508a42e29b1fb7c96a07620a5302863036" dependencies: - "@polkadot/storage-substrate" "^0.12.8" - "@polkadot/util" "^0.19.5" - "@polkadot/util-crypto" "^0.19.5" - "@polkadot/util-keyring" "^0.19.5" + "@polkadot/storage-substrate" "^0.12.9" + "@polkadot/util" "^0.19.6" + "@polkadot/util-crypto" "^0.19.6" + "@polkadot/util-keyring" "^0.19.6" babel-runtime "^6.26.0" eventemitter3 "^2.0.3" isomorphic-fetch "^2.2.1" websocket "^1.0.25" -"@polkadot/api-rx@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-rx/-/api-rx-0.10.2.tgz#d38187b0d604e7033bfd92be40db8064ae8dc588" +"@polkadot/api-rx@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@polkadot/api-rx/-/api-rx-0.10.3.tgz#fd1f152c6a6ac75562e78b30325827e7f01edf5d" dependencies: - "@polkadot/api" "^0.10.2" - "@polkadot/api-provider" "^0.10.2" + "@polkadot/api" "^0.10.3" + "@polkadot/api-provider" "^0.10.3" rxjs "^5.5.10" -"@polkadot/api@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.10.2.tgz#8b8e28b1b73a42daaeccfb486171669520274073" +"@polkadot/api@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.10.3.tgz#6941c63ea6bddb2b7bde552e3543ee90c127ef4f" dependencies: - "@polkadot/api-format" "^0.10.2" - "@polkadot/api-jsonrpc" "^0.10.2" - "@polkadot/api-provider" "^0.10.2" - "@polkadot/util" "^0.19.5" + "@polkadot/api-format" "^0.10.3" + "@polkadot/api-jsonrpc" "^0.10.3" + "@polkadot/api-provider" "^0.10.3" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" "@polkadot/dev@^0.17.13": @@ -705,120 +705,120 @@ stylelint "^9.1.1" stylelint-config-standard "^18.2.0" -"@polkadot/extrinsics-codec@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/extrinsics-codec/-/extrinsics-codec-0.12.8.tgz#ea42e663ce337969b977efad8fa5eaace798c414" +"@polkadot/extrinsics-codec@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/extrinsics-codec/-/extrinsics-codec-0.12.9.tgz#1763b17682ee5e2313136e33d65ea9a5520b12a6" dependencies: - "@polkadot/util" "^0.19.5" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" bn.js "^4.11.8" -"@polkadot/extrinsics-substrate@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/extrinsics-substrate/-/extrinsics-substrate-0.12.8.tgz#c1929885fb6b155203109b96a561f74af496c897" +"@polkadot/extrinsics-substrate@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/extrinsics-substrate/-/extrinsics-substrate-0.12.9.tgz#9d26e0c3e7ea53b668002dd0989adb22e42c392b" dependencies: - "@polkadot/extrinsics" "^0.12.8" + "@polkadot/extrinsics" "^0.12.9" babel-runtime "^6.26.0" -"@polkadot/extrinsics@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/extrinsics/-/extrinsics-0.12.8.tgz#0e9201621cbe24a642e72233ff7303558b318d6a" +"@polkadot/extrinsics@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/extrinsics/-/extrinsics-0.12.9.tgz#1603cc55d95740a619e1ce883dc67fa3a677e761" dependencies: - "@polkadot/primitives" "^0.12.8" - "@polkadot/util" "^0.19.5" + "@polkadot/primitives" "^0.12.9" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/primitives-builder@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/primitives-builder/-/primitives-builder-0.12.8.tgz#448e7ef4830b9c182a43e82a364e7b731336f140" +"@polkadot/primitives-builder@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-builder/-/primitives-builder-0.12.9.tgz#17754262e39b0c526f51be0e3531f0e4b91fca88" dependencies: - "@polkadot/primitives" "^0.12.8" - "@polkadot/primitives-codec" "^0.12.8" - "@polkadot/util" "^0.19.5" - "@polkadot/util-crypto" "^0.19.5" - "@polkadot/util-triehash" "^0.19.5" + "@polkadot/primitives" "^0.12.9" + "@polkadot/primitives-codec" "^0.12.9" + "@polkadot/util" "^0.19.6" + "@polkadot/util-crypto" "^0.19.6" + "@polkadot/util-triehash" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/primitives-codec@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/primitives-codec/-/primitives-codec-0.12.8.tgz#503e925a7efd86342f96cc4e389bb2e9f9fe9f90" +"@polkadot/primitives-codec@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-codec/-/primitives-codec-0.12.9.tgz#659735a88589416311f31e74646dec7b50c1f503" dependencies: - "@polkadot/primitives" "^0.12.8" - "@polkadot/primitives-builder" "^0.12.8" - "@polkadot/primitives-rlp" "^0.12.8" - "@polkadot/util" "^0.19.5" - "@polkadot/util-keyring" "^0.19.5" + "@polkadot/primitives" "^0.12.9" + "@polkadot/primitives-builder" "^0.12.9" + "@polkadot/primitives-rlp" "^0.12.9" + "@polkadot/util" "^0.19.6" + "@polkadot/util-keyring" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/primitives-json@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/primitives-json/-/primitives-json-0.12.8.tgz#0e218ad1e5b822319e949b5ef9651e27c280b6b8" +"@polkadot/primitives-json@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-json/-/primitives-json-0.12.9.tgz#e6d2afde7d3cf746abbb2a3d1760d7c8fb1ef49d" dependencies: - "@polkadot/primitives" "^0.12.8" - "@polkadot/primitives-builder" "^0.12.8" - "@polkadot/util" "^0.19.5" + "@polkadot/primitives" "^0.12.9" + "@polkadot/primitives-builder" "^0.12.9" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/primitives-rlp@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/primitives-rlp/-/primitives-rlp-0.12.8.tgz#0701a328b9cb4bd855b6e02d77965691cdb81182" +"@polkadot/primitives-rlp@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-rlp/-/primitives-rlp-0.12.9.tgz#1151e61a510ba19d8f5e917d81676a2957ded306" dependencies: - "@polkadot/primitives" "^0.12.8" - "@polkadot/primitives-builder" "^0.12.8" - "@polkadot/primitives-json" "^0.12.8" - "@polkadot/util" "^0.19.5" - "@polkadot/util-crypto" "^0.19.5" + "@polkadot/primitives" "^0.12.9" + "@polkadot/primitives-builder" "^0.12.9" + "@polkadot/primitives-json" "^0.12.9" + "@polkadot/util" "^0.19.6" + "@polkadot/util-crypto" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/primitives@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/primitives/-/primitives-0.12.8.tgz#f1efe01c498e52013ce0c59784fa1bc248c15b1d" +"@polkadot/primitives@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/primitives/-/primitives-0.12.9.tgz#bc46d5487f4ddbf4596208e3e514afbe9f4b1248" dependencies: - "@polkadot/util" "^0.19.5" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/storage-substrate@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/storage-substrate/-/storage-substrate-0.12.8.tgz#5b74436958415cfd3b5f87285b9038a96bfbe64a" +"@polkadot/storage-substrate@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/storage-substrate/-/storage-substrate-0.12.9.tgz#3822255c8fef11308568d9a7a7694e389ed956f9" dependencies: - "@polkadot/storage" "^0.12.8" - "@polkadot/util" "^0.19.5" + "@polkadot/storage" "^0.12.9" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/storage@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@polkadot/storage/-/storage-0.12.8.tgz#47438ec44b10e42898f8ac19e27ce6c5769f2c11" +"@polkadot/storage@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@polkadot/storage/-/storage-0.12.9.tgz#d4540056036ab75b32cc12001b220bce57d3b1be" dependencies: - "@polkadot/primitives" "^0.12.8" - "@polkadot/util" "^0.19.5" + "@polkadot/primitives" "^0.12.9" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/ui-identicon@^0.11.2": - version "0.11.2" - resolved "https://registry.yarnpkg.com/@polkadot/ui-identicon/-/ui-identicon-0.11.2.tgz#5141d3d52f0272f7e3a8dabea86d5ec5292216d1" +"@polkadot/ui-identicon@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@polkadot/ui-identicon/-/ui-identicon-0.11.3.tgz#b5c28e4e46208db0c12c8639f27eb04a73be1f45" dependencies: babel-runtime "^6.26.0" color "^3.0.0" -"@polkadot/ui-react-rx@^0.11.2": - version "0.11.2" - resolved "https://registry.yarnpkg.com/@polkadot/ui-react-rx/-/ui-react-rx-0.11.2.tgz#6f2af3f25a23b2c4fb650bda6498f57d6f564b42" +"@polkadot/ui-react-rx@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@polkadot/ui-react-rx/-/ui-react-rx-0.11.3.tgz#a0659fd7ad9fc0e339a36725064edfcc9d9168cb" dependencies: - "@polkadot/api-rx" "^0.10.2" - "@polkadot/primitives" "^0.12.8" - "@polkadot/storage-substrate" "^0.12.8" - "@polkadot/util" "^0.19.5" + "@polkadot/api-rx" "^0.10.3" + "@polkadot/primitives" "^0.12.9" + "@polkadot/storage-substrate" "^0.12.9" + "@polkadot/util" "^0.19.6" -"@polkadot/ui-react@^0.11.2": - version "0.11.2" - resolved "https://registry.yarnpkg.com/@polkadot/ui-react/-/ui-react-0.11.2.tgz#a5d48d99a998c3cd9718663252d6e80f6c25cbd1" +"@polkadot/ui-react@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@polkadot/ui-react/-/ui-react-0.11.3.tgz#90c880466de8e47ba0d526f95976b32eb9663264" dependencies: - "@polkadot/ui-identicon" "^0.11.2" + "@polkadot/ui-identicon" "^0.11.3" babel-runtime "^6.26.0" -"@polkadot/util-crypto@^0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.19.5.tgz#570483b70434b14c3484531514297feab8c0ccd1" +"@polkadot/util-crypto@^0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.19.6.tgz#26cf820765dbb01b8b34b309c14aec36ab204b96" dependencies: babel-runtime "^6.26.0" blakejs "^1.1.0" @@ -826,34 +826,34 @@ tweetnacl "^1.0.0" xxhashjs "^0.2.2" -"@polkadot/util-keyring@^0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@polkadot/util-keyring/-/util-keyring-0.19.5.tgz#bb75140ea9e64a3e2a9f17f66e68c1826f7a3de6" +"@polkadot/util-keyring@^0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@polkadot/util-keyring/-/util-keyring-0.19.6.tgz#6c0e9221507303bcb3445f6b40252198bb9c631c" dependencies: - "@polkadot/util" "^0.19.5" - "@polkadot/util-crypto" "^0.19.5" + "@polkadot/util" "^0.19.6" + "@polkadot/util-crypto" "^0.19.6" babel-runtime "^6.26.0" bs58 "^4.0.1" -"@polkadot/util-rlp@^0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@polkadot/util-rlp/-/util-rlp-0.19.5.tgz#ae3cb42339cf54b84989fbcef093a815622d14c8" +"@polkadot/util-rlp@^0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@polkadot/util-rlp/-/util-rlp-0.19.6.tgz#f26fe2f926a381a09f81fa5c5a5e5fd155cb6c20" dependencies: - "@polkadot/util" "^0.19.5" + "@polkadot/util" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/util-triehash@^0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@polkadot/util-triehash/-/util-triehash-0.19.5.tgz#7d273367b041a58d026975593fcf0858c68b3ece" +"@polkadot/util-triehash@^0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@polkadot/util-triehash/-/util-triehash-0.19.6.tgz#e5c004da0ccd02ba769f7605484170e4dce1804b" dependencies: - "@polkadot/util" "^0.19.5" - "@polkadot/util-crypto" "^0.19.5" - "@polkadot/util-rlp" "^0.19.5" + "@polkadot/util" "^0.19.6" + "@polkadot/util-crypto" "^0.19.6" + "@polkadot/util-rlp" "^0.19.6" babel-runtime "^6.26.0" -"@polkadot/util@^0.19.5": - version "0.19.5" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.19.5.tgz#344b014d7050d458080a25656122d85a9f207a7e" +"@polkadot/util@^0.19.6": + version "0.19.6" + resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.19.6.tgz#fb2eca72e710090a8ef4c17e376d7540d1df06a8" dependencies: babel-runtime "^6.26.0" bn.js "^4.11.8" @@ -9428,6 +9428,10 @@ stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" +store@^2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/store/-/store-2.0.12.tgz#8c534e2a0b831f72b75fc5f1119857c44ef5d593" + stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"