Bump UI, HDKD keyring (new substrate crypto) (#813)

* Bump UI, HDKD keyring (new substrate crypto)

* Bump ui/* versions

* Pull in latest util-crypto, bp39 fix

* Bump common

* Small enhancements, cleanups (testing WIP)

* Bump

* Update after merge

* Bumps, fix transfer calculation (value may be non-existent)

* Bumpo dependencies

* Label extrinsic hash

* Signature updates

* Update deps

* Adjust status display

* Close status items on click

* Update withRouter duplication

* API bump, (some) creation fixes

* Move bip39 out of the worker (fast enough now via WASM)

* Update after master merge

* Cleanup deps (re-write yarn.lock)
This commit is contained in:
Jaco Greeff 2019-03-20 17:06:29 +01:00 committed by GitHub
parent d6da91ab0e
commit 96615d5957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 684 additions and 660 deletions

View File

@ -1,3 +1,7 @@
# 0.26.1
- Swap keyring to HDKD derivation, mnemonic keys are now not backwards compatible with those created earlier. (Defaults are still for ed25519)
# 0.25.1
- Swap to publishing -beta.x on merge (non-breaking testing)

View File

@ -4,8 +4,6 @@
[![npm](https://img.shields.io/npm/v/@polkadot/apps.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/apps)
[![travis](https://img.shields.io/travis/polkadot-js/apps.svg?style=flat-square)](https://travis-ci.com/polkadot-js/apps)
[![greenkeeper](https://img.shields.io/badge/greenkeeper-enabled-brightgreen.svg?style=flat-square)](https://greenkeeper.io/)
[![dependency](https://img.shields.io/david/polkadot-js/apps.svg?style=flat-square)](https://david-dm.org/polkadot-js/apps)
[![devDependency](https://img.shields.io/david/dev/polkadot-js/apps.svg?style=flat-square)](https://david-dm.org/polkadot-js/apps#info=devDependencies)
# @polkadot/apps

View File

@ -10,14 +10,14 @@
"packages/*"
],
"resolutions": {
"@polkadot/api": "^0.46.12",
"@polkadot/keyring": "^0.36.3",
"@polkadot/types": "^0.46.12",
"@polkadot/util": "^0.36.3",
"@polkadot/util-crypto": "^0.36.3",
"@polkadot/api": "^0.49.0-beta.1",
"@polkadot/keyring": "^0.39.0-beta.2",
"@polkadot/types": "^0.49.0-beta.1",
"@polkadot/util": "^0.39.0-beta.2",
"@polkadot/util-crypto": "^0.39.0-beta.2",
"babel-core": "^7.0.0-bridge.0",
"rxjs": "^6.4.0",
"typescript": "^3.3.3333"
"typescript": "^3.3.4000"
},
"scripts": {
"analyze": "yarn run build && cd packages/apps && yarn run source-map-explorer build/main.*.js",
@ -30,9 +30,9 @@
"start": "cd packages/apps && webpack --config webpack.config.js"
},
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/runtime": "^7.3.4",
"@polkadot/dev-react": "^0.26.1",
"@babel/core": "^7.4.0",
"@babel/runtime": "^7.4.0",
"@polkadot/dev-react": "^0.28.0-beta.1",
"@polkadot/ts": "^0.1.56",
"autoprefixer": "^9.4.9",
"empty": "^0.10.1",

View File

@ -10,7 +10,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6"
}
}

View File

@ -10,10 +10,10 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@types/file-saver": "^2.0.0",
"@types/yargs": "^12.0.9",
"@types/yargs": "^12.0.10",
"babel-plugin-module-resolver": "^3.1.1",
"file-saver": "^2.0.0",
"libsodium-wrappers": "^0.7.3",

View File

@ -4,19 +4,19 @@
import { I18nProps } from '@polkadot/ui-app/types';
import { ActionStatus } from '@polkadot/ui-app/Status/types';
import { KeypairType } from '@polkadot/util-crypto/types';
import { ComponentProps } from './types';
import FileSaver from 'file-saver';
import React from 'react';
import { AddressSummary, Button, Dropdown, Input, Modal, Password } from '@polkadot/ui-app';
import { InputAddress } from '@polkadot/ui-app/InputAddress';
import { hexToU8a, isHex, stringToU8a, u8aToHex } from '@polkadot/util';
import { mnemonicToSeed, mnemonicValidate, naclKeypairFromSeed, randomAsU8a } from '@polkadot/util-crypto';
import keyring from '@polkadot/ui-keyring';
import uiSettings from '@polkadot/ui-settings';
import { hexToU8a, isHex, stringToU8a, u8aToHex } from '@polkadot/util';
import { mnemonicGenerate, mnemonicToMiniSecret, mnemonicValidate, naclKeypairFromSeed, randomAsU8a, schnorrkelKeypairFromSeed } from '@polkadot/util-crypto';
import translate from './translate';
import FileSaver from 'file-saver';
const BipWorker = require('worker-loader?name=[name].[hash:8].js!./bipWorker');
type Props = ComponentProps & I18nProps & {
match: {
@ -36,6 +36,7 @@ type State = {
isPassValid: boolean,
isValid: boolean,
name: string,
pairType: KeypairType,
password: string,
seed: string,
seedOptions: Array<{ value: SeedType, text: string }>,
@ -51,18 +52,17 @@ function rawValidate (seed: string): boolean {
return seed.length <= 32 || isHexSeed(seed);
}
function rawToSeed (seed: string): Uint8Array {
return isHexSeed(seed)
? hexToU8a(seed)
: stringToU8a(seed.padEnd(32, ' '));
}
function addressFromSeed (seed: string, seedType: SeedType): string {
const keypair = naclKeypairFromSeed(
seedType === 'bip'
? mnemonicToSeed(seed)
: rawToSeed(seed)
);
function addressFromSeed (phrase: string, pairType: KeypairType, seedType: SeedType): string {
const seed = seedType === 'bip'
? mnemonicToMiniSecret(phrase)
: (
isHexSeed(phrase)
? hexToU8a(phrase)
: stringToU8a(phrase.padEnd(32))
);
const keypair = pairType === 'sr25519'
? schnorrkelKeypairFromSeed(seed)
: naclKeypairFromSeed(seed);
return keyring.encodeAddress(
keypair.publicKey
@ -70,7 +70,6 @@ function addressFromSeed (seed: string, seedType: SeedType): string {
}
class Creator extends React.PureComponent<Props, State> {
bipWorker: any;
state: State = { seedType: 'bip' } as State;
constructor (props: Props) {
@ -78,18 +77,8 @@ class Creator extends React.PureComponent<Props, State> {
const { match: { params: { seed } }, t } = this.props;
this.bipWorker = new BipWorker();
this.bipWorker.onmessage = (event: MessageEvent) => {
const { publicKey, seed } = event.data;
this.setState({
address: keyring.encodeAddress(publicKey),
isBipBusy: false,
seed
});
};
this.state = {
...this.emptyState(seed),
...this.emptyState('ed25519', seed),
seedOptions: [
{ value: 'bip', text: t('Mnemonic') },
{ value: 'raw', text: t('Raw seed') }
@ -141,7 +130,7 @@ class Creator extends React.PureComponent<Props, State> {
renderInput () {
const { t } = this.props;
const { isBipBusy, isNameValid, isPassValid, isSeedValid, name, password, seed, seedOptions, seedType, showWarning } = this.state;
const { isBipBusy, isNameValid, isPassValid, isSeedValid, name, pairType, password, seed, seedOptions, seedType, showWarning } = this.state;
return (
<div className='grow'>
@ -182,6 +171,14 @@ class Creator extends React.PureComponent<Props, State> {
/>
</Input>
</div>
<div className='ui--row'>
<Dropdown
defaultValue={pairType}
label={t('keypair crypto type')}
onChange={this.onChangePairType}
options={uiSettings.availableCryptos}
/>
</div>
<div className='ui--row'>
<Password
className='full'
@ -249,18 +246,11 @@ class Creator extends React.PureComponent<Props, State> {
);
}
private generateSeed (seedType: SeedType, _seed?: string | null): State {
if (seedType === 'bip') {
this.bipWorker.postMessage('create');
return {
isBipBusy: true,
seed: ''
} as State;
}
const seed = _seed || u8aToHex(randomAsU8a());
const address = addressFromSeed(seed, seedType);
private generateSeed (seedType: SeedType, pairType: KeypairType, _seed?: string | null): State {
const seed = seedType === 'bip'
? mnemonicGenerate()
: _seed || u8aToHex(randomAsU8a());
const address = addressFromSeed(seed, pairType, seedType);
return {
address,
@ -269,19 +259,20 @@ class Creator extends React.PureComponent<Props, State> {
} as State;
}
private emptyState (seed?: string | null): State {
private emptyState (pairType: KeypairType, seed?: string | null): State {
const seedType = seed
? 'raw'
: this.state.seedType;
return {
...this.generateSeed(seedType, seed),
...this.generateSeed(seedType, pairType, seed),
isNameValid: true,
isPassValid: false,
isSeedValid: true,
isValid: false,
name: 'new keypair',
password: '',
pairType,
seedType,
showWarning: false
};
@ -290,7 +281,7 @@ class Creator extends React.PureComponent<Props, State> {
private nextState (newState: State): void {
this.setState(
(prevState: State, props: Props): State => {
const { isBipBusy = prevState.isBipBusy, name = prevState.name, password = prevState.password, seed = prevState.seed, seedOptions = prevState.seedOptions, seedType = prevState.seedType, showWarning = prevState.showWarning } = newState;
const { isBipBusy = prevState.isBipBusy, name = prevState.name, pairType = prevState.pairType, password = prevState.password, seed = prevState.seed, seedOptions = prevState.seedOptions, seedType = prevState.seedType, showWarning = prevState.showWarning } = newState;
let address = prevState.address;
const isNameValid = !!name;
const isSeedValid = seedType === 'bip'
@ -299,7 +290,7 @@ class Creator extends React.PureComponent<Props, State> {
const isPassValid = keyring.isPassValid(password);
if (isSeedValid && seed !== prevState.seed) {
address = addressFromSeed(seed, seedType);
address = addressFromSeed(seed, pairType, seedType);
}
return {
@ -310,6 +301,7 @@ class Creator extends React.PureComponent<Props, State> {
isSeedValid,
isValid: isNameValid && isPassValid && isSeedValid,
name,
pairType,
password,
seed,
seedOptions,
@ -320,10 +312,6 @@ class Creator extends React.PureComponent<Props, State> {
);
}
private onChangeSeed = (seed: string): void => {
this.nextState({ seed } as State);
}
private onChangeName = (name: string): void => {
this.nextState({ name } as State);
}
@ -332,6 +320,17 @@ class Creator extends React.PureComponent<Props, State> {
this.nextState({ password } as State);
}
private onChangeSeed = (seed: string): void => {
this.nextState({ seed } as State);
}
private onChangePairType = (pairType: KeypairType): void => {
this.setState(({ seedType }: State) => ({
...this.generateSeed(seedType, pairType),
pairType
}));
}
private onShowWarning = (): void => {
this.nextState({ showWarning: true } as State);
}
@ -342,18 +341,14 @@ class Creator extends React.PureComponent<Props, State> {
private onCommit = (): void => {
const { basePath, onStatusChange, t } = this.props;
const { name, password, seed, seedType } = this.state;
const { name, pairType, password, seed } = this.state;
const status = {
action: 'create'
} as ActionStatus;
try {
const pair = seedType === 'bip'
? keyring.createAccountMnemonic(seed, password, { name })
: keyring.createAccount(rawToSeed(seed), password, { name });
const json = pair.toJson(password);
const { json, pair } = keyring.createUri(seed, password, { name }, pairType);
const blob = new Blob([JSON.stringify(json)], { type: 'application/json; charset=utf-8' });
FileSaver.saveAs(blob, `${pair.address()}.json`);
@ -376,7 +371,9 @@ class Creator extends React.PureComponent<Props, State> {
}
private onDiscard = (): void => {
this.setState(this.emptyState());
this.setState(({ pairType }) =>
this.emptyState(pairType)
);
}
private selectSeedType = (seedType: SeedType): void => {
@ -384,10 +381,10 @@ class Creator extends React.PureComponent<Props, State> {
return;
}
this.setState({
...this.generateSeed(seedType),
this.setState(({ pairType }: State) => ({
...this.generateSeed(seedType, pairType),
seedType
});
}));
}
}

View File

@ -9,8 +9,9 @@ import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { ComponentProps } from './types';
import React from 'react';
import { AddressSummary, Button, Input, InputAddress } from '@polkadot/ui-app';
import { AddressSummary, Button, Dropdown, Input, InputAddress } from '@polkadot/ui-app';
import keyring from '@polkadot/ui-keyring';
import uiSettings from '@polkadot/ui-settings';
import Backup from './Backup';
import ChangePass from './ChangePass';
@ -100,6 +101,9 @@ class Editor extends React.PureComponent<Props, State> {
const address = current
? current.address()
: undefined;
const type = current
? current.type
: 'ed25519';
return (
<div className='ui--grid'>
@ -128,6 +132,14 @@ class Editor extends React.PureComponent<Props, State> {
value={editedName}
/>
</div>
<div className='ui--row'>
<Dropdown
defaultValue={type}
isDisabled
label={t('keypair crypto type')}
options={uiSettings.availableCryptos}
/>
</div>
</div>
</div>
);

View File

@ -2,15 +2,22 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { mnemonicGenerate, mnemonicToSeed, naclKeypairFromSeed } from '@polkadot/util-crypto';
import { cryptoWaitReady, mnemonicGenerate, mnemonicToMiniSecret, naclKeypairFromSeed, schnorrkelKeypairFromSeed } from '@polkadot/util-crypto';
const ctx: Worker = self as any;
ctx.onmessage = () => {
cryptoWaitReady().catch(() => {
// ignore
});
ctx.onmessage = async ({ data: { pairType } }) => {
await cryptoWaitReady();
const seed = mnemonicGenerate();
const { publicKey } = naclKeypairFromSeed(
mnemonicToSeed(seed)
);
const miniSecret = mnemonicToMiniSecret(seed);
const { publicKey } = pairType === 'sr25519'
? schnorrkelKeypairFromSeed(miniSecret)
: naclKeypairFromSeed(miniSecret);
ctx.postMessage({
publicKey,

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6"
}
}

View File

@ -10,7 +10,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-reactive": "^0.26.0-beta.6"
}

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6"
}
}

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-params": "^0.26.0-beta.6",
"@polkadot/ui-signer": "^0.26.0-beta.6"

View File

@ -10,7 +10,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"snappyjs": "^0.6.0"
}

View File

@ -39,6 +39,7 @@ type Injected = {
util: typeof util,
window: null
};
type Props = ApiProps & AppProps & I18nProps & {
match: {
params: {
@ -48,6 +49,7 @@ type Props = ApiProps & AppProps & I18nProps & {
// FIXME wait for proper eslint integration in tslint, then hopefully remove this
history: any
};
type State = {
animated: boolean,
customExamples: Array<Snippet>,

View File

@ -10,7 +10,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-reactive": "^0.26.0-beta.6"
}

View File

@ -80,7 +80,6 @@ class General extends React.PureComponent<Props, State> {
defaultValue={i18nLang}
isDisabled
label={t('default interface language')}
onChange={this.onChangeLang}
options={uiSettings.availableLanguages}
/>
</div>
@ -140,10 +139,6 @@ class General extends React.PureComponent<Props, State> {
}));
}
private onChangeLang = (i18nLang: string): void => {
// ignore (for now), here to future-proof
}
private onChangeUiMode = (uiMode: string): void => {
this.setState(({ settings }: State) => ({
settings: {

View File

@ -10,7 +10,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/app-explorer": "^0.26.0-beta.6",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-reactive": "^0.26.0-beta.6"

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-params": "^0.26.0-beta.6"
}

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6"
}
}

View File

@ -10,7 +10,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-reactive": "^0.26.0-beta.6"
}

View File

@ -12,9 +12,9 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6",
"@polkadot/ui-assets": "^0.30.1",
"@polkadot/ui-assets": "^0.32.0-beta.1",
"@polkadot/ui-signer": "^0.26.0-beta.6",
"@types/react-tooltip": "^3.9.1",
"react-tooltip": "^3.9.2"

View File

@ -5,7 +5,6 @@
import { I18nProps } from '@polkadot/ui-app/types';
import { ApiProps } from '@polkadot/ui-api/types';
import { QueueProps } from '@polkadot/ui-app/Status/types';
import { RouteProps } from '../types';
import React from 'react';
import { withRouter } from 'react-router';
@ -58,17 +57,12 @@ class Content extends React.Component<Props> {
);
}
// inject router into component that we are rendering (in some cases react-router does
// not play 100% with styled-components because of the new vs old context usage, this
// is a workaround for that)
const ComponentRouted = (withRouter(Component as any) as any) as React.ComponentType<RouteProps>;
return (
<Wrapper>
<QueueConsumer>
{({ queueAction, stqueue, txqueue }: QueueProps) => (
<>
<ComponentRouted
<Component
basePath={`/${name}`}
location={location}
onStatusChange={queueAction}

View File

@ -8,7 +8,7 @@ import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { Route } from '../types';
import React from 'react';
import { withRouter } from 'react-router';
// import { withRouter } from 'react-router';
import { NavLink } from 'react-router-dom';
import { Icon, Menu } from '@polkadot/ui-app';
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
@ -31,7 +31,6 @@ interface Tooltip {
}
class Item extends React.PureComponent<Props> {
componentWillUpdate () {
ReactTooltip.rebuild();
}
@ -119,7 +118,6 @@ class Item extends React.PureComponent<Props> {
export default withMulti(
Item,
withRouter,
withApi,
withObservable(accountObservable.subject, { propName: 'allAccounts' })
);

View File

@ -8,9 +8,6 @@ import { SIDEBAR_MENU_THRESHOLD } from '../constants';
import './SideBar.css';
import React from 'react';
import { withRouter } from 'react-router';
import { withMulti } from '@polkadot/ui-api';
import { Button, Icon, Menu } from '@polkadot/ui-app';
import { classes } from '@polkadot/ui-app/util';
@ -31,7 +28,6 @@ type Props = I18nProps & {
};
class SideBar extends React.PureComponent<Props> {
render () {
const { isCollapsed } = this.props;
@ -182,8 +178,4 @@ class SideBar extends React.PureComponent<Props> {
}
}
export default withMulti(
SideBar,
translate,
withRouter
);
export default translate(SideBar);

View File

@ -30,9 +30,9 @@
},
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@polkadot/api": "^0.46.12",
"@polkadot/ui-util": "^0.28.8",
"@babel/runtime": "^7.4.0",
"@polkadot/api": "^0.49.0-beta.1",
"@polkadot/ui-util": "^0.32.0-beta.1",
"rxjs-compat": "^6.3.2"
}
}

View File

@ -43,7 +43,7 @@ export default class ApiWrapper extends React.PureComponent<Props, State> {
const api = new ApiPromise({ provider, signer });
this.setState({ api }, () => {
this.updateSubscriptions();
this.subscribeEvents();
});
};
const setApiUrl = (url: string = defaults.WS_URL): void =>
@ -58,32 +58,36 @@ export default class ApiWrapper extends React.PureComponent<Props, State> {
}
componentDidMount () {
this.updateSubscriptions();
this.subscribeEvents();
}
private updateSubscriptions () {
private subscribeEvents () {
const { api } = this.state;
[
this.subscribeIsConnected,
this.subscribeIsReady,
this.subscribeChain
].map((fn: Function) => {
api.on('connected', () => {
this.setState({ isApiConnected: true });
});
api.on('disconnected', () => {
this.setState({ isApiConnected: false });
});
api.on('ready', async () => {
try {
return fn(api);
await this.loadOnReady(api);
} catch (error) {
console.error(error);
return null;
console.error('Unable to load chain', error);
}
});
}
private subscribeChain = async (api: ApiPromise) => {
private async loadOnReady (api: ApiPromise) {
const [properties = new ChainProperties(), value] = await Promise.all([
api.rpc.system.properties() as Promise<ChainProperties | undefined>,
api.rpc.system.chain() as Promise<any>
]);
const section = Object.keys(api.tx)[0];
const method = Object.keys(api.tx[section])[0];
const chain = value
? value.toString()
: null;
@ -105,28 +109,11 @@ export default class ApiWrapper extends React.PureComponent<Props, State> {
type: 'ed25519'
});
this.setState({ chain, isDevelopment });
}
private subscribeIsConnected = (api: ApiPromise) => {
api.on('connected', () => {
this.setState({ isApiConnected: true });
});
api.on('disconnected', () => {
this.setState({ isApiConnected: false });
});
}
private subscribeIsReady = (api: ApiPromise) => {
api.on('ready', () => {
const section = Object.keys(api.tx)[0];
const method = Object.keys(api.tx[section])[0];
this.setState({
isApiReady: true,
apiDefaultTx: api.tx[section][method]
});
this.setState({
isApiReady: true,
apiDefaultTx: api.tx[section][method],
chain,
isDevelopment
});
}

View File

@ -5,6 +5,7 @@
import { ApiProps, CallState, Subtract } from '../types';
import { Options } from './types';
import memoize from 'memoizee';
import React from 'react';
import { assert, isNull, isUndefined } from '@polkadot/util';
@ -158,7 +159,7 @@ export default function withCall<P extends ApiProps> (endpoint: string, { at, at
await this.unsubscribe();
if (isSubscription) {
this.destroy = await apiMethod(...params, (value?: any) =>
this.destroy = await memoize(apiMethod)(...params, (value?: any) =>
this.triggerUpdate(this.props, value)
);
} else {

View File

@ -10,13 +10,13 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-api": "^0.26.0-beta.6",
"@polkadot/ui-identicon": "^0.28.8",
"@polkadot/ui-keyring": "^0.28.8",
"@polkadot/ui-identicon": "^0.32.0-beta.1",
"@polkadot/ui-keyring": "^0.32.0-beta.1",
"@polkadot/ui-reactive": "^0.26.0-beta.6",
"@polkadot/ui-settings": "^0.28.8",
"@polkadot/ui-util": "^0.28.8",
"@polkadot/ui-settings": "^0.32.0-beta.1",
"@polkadot/ui-util": "^0.32.0-beta.1",
"@types/chart.js": "^2.7.45",
"@types/classnames": "^2.2.7",
"@types/i18next": "^12.1.0",
@ -34,8 +34,8 @@
"react-dom": "^16.8.2",
"react-dropzone": "^7.0.1",
"react-i18next": "^10.1.2",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"semantic-ui-css": "^2.3.1",
"semantic-ui-react": "^0.85.0",
"store": "^2.0.12"

View File

@ -10,6 +10,7 @@ import styled from 'styled-components';
import { Method, getTypeDef } from '@polkadot/types';
import Params from '@polkadot/ui-params';
import Labelled from './Labelled';
import { classes } from './util';
export type Props = BareProps & {
@ -21,7 +22,6 @@ const Wrapper = styled.div`
.hash {
opacity: 0.5;
overflow: hidden;
padding: 0 0.5rem 0.75rem 1.75rem;
text-overflow: ellipsis;
}
`;
@ -48,9 +48,11 @@ export default class Call extends React.PureComponent<Props> {
{
hash
? (
<div className='hash'>
{hash.toHex()}
</div>
<Labelled label='extrinsic hash'>
<div className='hash'>
{hash.toHex()}
</div>
</Labelled>
)
: null
}

View File

@ -58,30 +58,50 @@ export default class Queue extends React.Component<Props, State> {
);
}
private clearAction (id: number): () => void {
return (): void => {
this.setState(
(prevState: State): State => ({
stqueue: prevState.stqueue.filter((item) => item.id !== id)
} as State)
);
};
}
queueAction = (status: ActionStatus): number => {
const id = ++nextId;
const removeItem = this.clearAction(id);
this.setState(
(prevState: State): State => ({
stqueue: prevState.stqueue.concat({
...status,
id,
isCompleted: false
isCompleted: false,
removeItem
})
} as State)
);
setTimeout(() => {
this.setState(
(prevState: State): State => ({
stqueue: prevState.stqueue.filter((item) => item.id !== id)
} as State)
);
}, REMOVE_TIMEOUT);
setTimeout(removeItem, REMOVE_TIMEOUT);
return id;
}
private clearStatus (id: number): () => void {
return () => {
this.setState(
(prevState: State): State => ({
txqueue: prevState.txqueue.map((item) =>
item.id === id
? { ...item, status: 'completed' }
: item
)
} as State)
);
};
}
queueSetTxStatus = (id: number, status: QueueTx$Status, result?: SubmittableResult, error?: Error): void => {
this.setState(
(prevState: State): State => ({
@ -107,17 +127,7 @@ export default class Queue extends React.Component<Props, State> {
this.addResultEvents(result);
if (STATUS_COMPLETE.includes(status)) {
setTimeout(() => {
this.setState(
(prevState: State): State => ({
txqueue: prevState.txqueue.map((item) =>
item.id === id
? { ...item, status: 'completed' }
: item
)
} as State)
);
}, REMOVE_TIMEOUT);
setTimeout(this.clearStatus(id), REMOVE_TIMEOUT);
}
}
@ -140,12 +150,14 @@ export default class Queue extends React.Component<Props, State> {
private queueAdd = (value: QueueTx$Extrinsic | QueueTx$Rpc | QueueTx): number => {
const id = ++nextId;
const rpc: RpcMethod = (value as QueueTx$Rpc).rpc || SUBMIT_RPC;
const removeItem = this.clearStatus(id);
this.setState(
(prevState: State): State => ({
txqueue: prevState.txqueue.concat([{
...value,
id,
removeItem,
rpc,
status: 'queued'
}])

View File

@ -38,7 +38,7 @@ class Status extends React.PureComponent<Props> {
);
}
private renderStatus = ({ account, action, id, message, status }: QueueStatus) => {
private renderStatus = ({ account, action, id, message, removeItem, status }: QueueStatus) => {
const addressRendered = account
? <AddressMini value={account} />
: undefined;
@ -46,6 +46,7 @@ class Status extends React.PureComponent<Props> {
return (
<div
className={classes('item', status)}
onClick={removeItem}
key={id}
>
<div className='wrapper'>
@ -68,7 +69,7 @@ class Status extends React.PureComponent<Props> {
);
}
private renderItem = ({ id, extrinsic, error, rpc, status }: QueueTx) => {
private renderItem = ({ id, extrinsic, error, removeItem, rpc, status }: QueueTx) => {
let { method, section } = rpc;
if (extrinsic) {
@ -85,6 +86,7 @@ class Status extends React.PureComponent<Props> {
return (
<div
className={classes('item', status)}
onClick={removeItem}
key={id}
>
<div className='wrapper'>

View File

@ -33,6 +33,7 @@ export type QueueTx = AccountInfo & {
id: number,
isUnsigned?: boolean,
result?: any,
removeItem: () => void,
rpc: RpcMethod,
signerCb?: SignerCallback,
signerOptions?: SignatureOptions,
@ -45,7 +46,8 @@ export type QueueTx = AccountInfo & {
export type QueueStatus = ActionStatus & {
id: number,
isCompleted: boolean
isCompleted: boolean,
removeItem: () => void
};
export type QueueTx$Result = {

View File

@ -5,7 +5,6 @@
import { BareProps } from './types';
import React from 'react';
import { withRouter } from 'react-router';
import { NavLink } from 'react-router-dom';
import { classes } from './util';
@ -22,7 +21,7 @@ type Props = BareProps & {
items: Array<TabItem>
};
class Tabs extends React.PureComponent<Props> {
export default class Tabs extends React.PureComponent<Props> {
render () {
const { className, hidden = [], items, style } = this.props;
@ -63,5 +62,3 @@ class Tabs extends React.PureComponent<Props> {
);
}
}
export default withRouter(Tabs as React.ComponentType<any>) as any as React.ComponentType<Props>;

View File

@ -310,6 +310,7 @@ header .ui--Button-Group {
position: fixed;
right: 0.25rem;
top: 0.25rem;
width: 20rem;
z-index: 1001;
.ui--IdentityIcon {
@ -320,36 +321,35 @@ header .ui--Button-Group {
display: block;
text-align: right;
> .wrapper {
display: inline-block;
> .wrapper > .container {
align-items: center;
background: #00688b;
border-radius: $small-corner;
color: white;
cursor: pointer;
display: flex;
justify-content: space-between;
margin-bottom: 0.25rem;
padding: 0 0.5rem;
text-align: center;
opacity: 0.95;
vertical-align: middle;
> .container {
align-items: center;
background: #00688b;
border-radius: $small-corner;
color: white;
display: flex;
margin-bottom: 0.25rem;
padding: 0 0.5rem;
text-align: center;
opacity: 0.95;
vertical-align: middle;
.desc {
flex: 1;
padding: 0.5rem 1rem;
.desc {
padding: 0.5rem 1rem;
.status {
font-weight: 700;
}
.status {
font-weight: 700;
}
}
.short {
font-size: 2.5rem;
padding: 0.5rem;
.short {
font-size: 2.5rem;
padding: 0.5rem;
i.icon {
line-height: 1;
}
i.icon {
line-height: 1;
}
}
}
@ -369,8 +369,9 @@ header .ui--Button-Group {
background: green;
}
&.dropped > .wrapper > .container ,
&.error > .wrapper > .container ,
&.dropped > .wrapper > .container,
&.error > .wrapper > .container,
&.invalid > .wrapper > .container,
&.usurped > .wrapper > .container {
background: red;
}

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6"
}
}

View File

@ -30,7 +30,7 @@
},
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"rxjs-compat": "^6.3.2"
}
}

View File

@ -10,7 +10,7 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.3.4",
"@babel/runtime": "^7.4.0",
"@polkadot/ui-app": "^0.26.0-beta.6"
}
}

View File

@ -39,7 +39,7 @@ class Transfer extends React.PureComponent<Props, State> {
};
static getDerivedStateFromProps ({ amount, balances_votingBalance = ZERO_BALANCE, fees, onChange }: Props): State {
let extraFees = fees.transferFee;
let extraFees = new BN(fees.transferFee);
if (balances_votingBalance.votingBalance.isZero()) {
extraFees = extraFees.add(fees.creationFee);

View File

@ -328,8 +328,7 @@ class Signer extends React.PureComponent<Props, State> {
const status = result.type.toLowerCase() as QueueTx$Status;
console.log('makeExtrinsicCall: updated status ::', result);
console.log('makeExtrinsicCall: updated status ::', JSON.stringify(result));
queueSetTxStatus(id, status, result);
if (isFunction(txUpdateCb)) {

892
yarn.lock

File diff suppressed because it is too large Load Diff