diff --git a/flow-typed/react-i18next.js b/flow-typed/react-i18next.js index 39357a8875..5efa99a1f3 100644 --- a/flow-typed/react-i18next.js +++ b/flow-typed/react-i18next.js @@ -3,7 +3,7 @@ declare type I18Next$Translate$Config = { defaultValue: string, replace?: { - [string]: string + [string]: any } }; diff --git a/packages/app-explorer/src/App.js b/packages/app-explorer/src/App.js deleted file mode 100644 index 4bf878987f..0000000000 --- a/packages/app-explorer/src/App.js +++ /dev/null @@ -1,35 +0,0 @@ -// 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 React from 'react'; -import BestNumber from '@polkadot/rx-react/BestNumber'; - -import BestHash from './BestHash'; -import BlockHeaders from './BlockHeaders'; -import translate from './translate'; - -type Props = I18nProps & {}; - -function App ({ className, style, t }: Props): React$Node { - return ( -
- - - -
- ); -} - -export default translate(App); diff --git a/packages/app-explorer/src/BestHash.js b/packages/app-explorer/src/BestHash.js index c93edb18dd..672f3833e4 100644 --- a/packages/app-explorer/src/BestHash.js +++ b/packages/app-explorer/src/BestHash.js @@ -6,21 +6,14 @@ import type { Header } from '@polkadot/primitives/header'; import headerHash from '@polkadot/primitives-codec/header/hash'; -import Div from '@polkadot/rx-react/Div'; -import withApiCall from '@polkadot/rx-react/with/apiCall'; +import withApiDiv from '@polkadot/rx-react/with/apiDiv'; import u8aToHexShort from '@polkadot/util/u8a/toHexShort'; -const apiMethod = { - method: 'newHead', - section: 'chain' -}; - -const props = { - className: 'explorer--BestHash', - format: (value?: Header): ?string => - value +export default withApiDiv({ name: 'newHead', section: 'chain' })( + (value?: Header): ?string => { + return value ? u8aToHexShort(headerHash(value)) - : value -}; - -export default withApiCall(apiMethod)(Div, props); + : value; + }, + { className: 'explorer--BestHash' } +); diff --git a/packages/app-explorer/src/BlockHeaders.js b/packages/app-explorer/src/BlockHeaders.js index 49e5587677..dde0f731f5 100644 --- a/packages/app-explorer/src/BlockHeaders.js +++ b/packages/app-explorer/src/BlockHeaders.js @@ -6,15 +6,14 @@ import type { Header } from '@polkadot/primitives/header'; import React from 'react'; -import Div from '@polkadot/rx-react/Div'; -import withApiCall from '@polkadot/rx-react/with/apiCall'; +import withApiDiv from '@polkadot/rx-react/with/apiDiv'; import BlockHeader from './BlockHeader'; let blockHeaders: Array
= []; const apiMethod = { - method: 'newHead', + name: 'newHead', section: 'chain' }; @@ -36,15 +35,14 @@ const apiOptions = { } }; -const props = { - className: 'explorer--BlockHeaders', - format: (value?: Array
= []): React$Node => - value.map((value) => ( +export default withApiDiv(apiMethod, apiOptions)( + (value?: Array
= []): Array => { + return value.map((value) => ( - )) -}; - -export default withApiCall(apiMethod, apiOptions)(Div, props); + )); + }, + { className: 'explorer--BlockHeaders' } +); diff --git a/packages/app-explorer/src/index.css b/packages/app-explorer/src/index.css index 6625e738fa..e0156a8cb1 100644 --- a/packages/app-explorer/src/index.css +++ b/packages/app-explorer/src/index.css @@ -3,7 +3,7 @@ /* of the ISC license. See the LICENSE file for details. */ .explorer--App { - padding: 1em; + padding: 1em 2em; } .explorer--App .rx--updated { diff --git a/packages/app-explorer/src/index.js b/packages/app-explorer/src/index.js index 78afb1d81f..907150b94d 100644 --- a/packages/app-explorer/src/index.js +++ b/packages/app-explorer/src/index.js @@ -3,8 +3,35 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { I18nProps } from '@polkadot/ui-react-app/types'; + import './index.css'; -import App from './App'; +import React from 'react'; +import BestNumber from '@polkadot/rx-react/BestNumber'; -export default App; +import BestHash from './BestHash'; +import BlockHeaders from './BlockHeaders'; +import translate from './translate'; + +type Props = I18nProps & {}; + +function App ({ className, style, t }: Props): React$Node { + return ( +
+ + + +
+ ); +} + +export default translate(App); diff --git a/packages/app-extrinsics/src/Account.js b/packages/app-extrinsics/src/Account.js index 21dd19140f..956d12e3e7 100644 --- a/packages/app-extrinsics/src/Account.js +++ b/packages/app-extrinsics/src/Account.js @@ -8,31 +8,35 @@ import type { I18nProps } from '@polkadot/ui-react-app/types'; import React from 'react'; import Label from 'semantic-ui-react/dist/es/elements/Label'; import Balance from '@polkadot/rx-react/Balance'; -import withObservableParams from '@polkadot/rx-react/with/observableParams'; import InputAddress from '@polkadot/ui-react-app/src/InputAddress'; import translate from './translate'; type Props = I18nProps & { + defaultValue?: Uint8Array, isError?: boolean, label: string, - subject: rxjs$BehaviorSubject + onChange: (publicKey: Uint8Array) => void }; -class Account extends React.PureComponent { - Balance: React$ComponentType<*>; +type State = { + publicKey?: Uint8Array +}; + +class Account extends React.PureComponent { + state: State; constructor (props: Props) { super(props); - this.Balance = withObservableParams(props.subject)(Balance, { - className: 'ui disabled dropdown selection' - }); + this.state = { + publicKey: props.defaultValue + }; } render (): React$Node { - const { className, label, subject, style, t } = this.props; - const Balance = this.Balance; + const { className, defaultValue, label, style, t } = this.props; + const { publicKey } = this.state; return (
{ >
@@ -52,11 +57,22 @@ class Account extends React.PureComponent { defaultValue: 'with an available balance of' })} - +
); } + + onChange = (publicKey: Uint8Array): void => { + const { onChange } = this.props; + + this.setState({ publicKey }, () => + onChange(publicKey) + ); + }; } export default translate(Account); diff --git a/packages/app-extrinsics/src/App.js b/packages/app-extrinsics/src/App.js deleted file mode 100644 index 68e899bbe0..0000000000 --- a/packages/app-extrinsics/src/App.js +++ /dev/null @@ -1,58 +0,0 @@ -// 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 type { QueueTx } from './types'; - -import React from 'react'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import withObservable from '@polkadot/rx-react/with/observable'; - -import Signer from './Signer'; -import Submission from './Submission'; -import Status from './Status'; -import translate from './translate'; - -type Props = I18nProps & {}; - -const CLOSE_STATUS = ['cancelled', 'error', 'sent']; - -const queue: rxjs$BehaviorSubject = new BehaviorSubject(({ - isValid: false, - status: 'incomplete' -}: $Shape)); - -const QueuedSigner = withObservable(queue)(Signer); -const QueuedStatus = withObservable(queue)(Status); - -queue.subscribe(({ status }) => { - if (CLOSE_STATUS.includes(status)) { - setTimeout(() => { - const tx = queue.getValue(); - - if (CLOSE_STATUS.includes(tx.status)) { - queue.next({ - ...tx, - status: 'incomplete' - }); - } - }, 5000); - } -}); - -function App ({ className, style }: Props): React$Node { - return ( -
- - - -
- ); -} - -export default translate(App); diff --git a/packages/app-extrinsics/src/Extrinsic.js b/packages/app-extrinsics/src/Extrinsic.js new file mode 100644 index 0000000000..35b3509ee3 --- /dev/null +++ b/packages/app-extrinsics/src/Extrinsic.js @@ -0,0 +1,102 @@ +// 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 { 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 { 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 isUndefined from '@polkadot/util/is/undefined'; + +import paramComponents from './Params'; + +type Props = BareProps & { + defaultValue: Extrinsic, + isError?: boolean, + isPrivate?: boolean, + labelMethod?: string, + labelSection?: string, + onChange: (values: EncodedMessage) => void +}; + +type State = { + extrinsic: Extrinsic, + values: Array +}; + +export default class ExtrinsicDisplay extends React.PureComponent { + state: State; + + constructor (props: Props) { + super(props); + + this.state = ({ + extrinsic: props.defaultValue + }: $Shape); + } + + render (): React$Node { + const { className, defaultValue, isError, isPrivate, labelMethod, labelSection, style } = this.props; + const { extrinsic } = this.state; + + return ( +
+
+ +
+ +
+ ); + } + + nextState (newState: $Shape): void { + this.setState(newState, () => { + const { onChange } = this.props; + const { extrinsic, values } = this.state; + const params = Object.values(extrinsic.params || {}); + const isValid = values.length === params.length && + params.reduce((isValid, param, index) => + isValid && + !isUndefined(values[index]) && + !isUndefined(values[index].value) && + values[index].isValid, true); + const value = isValid && extrinsic.params + ? encode(extrinsic, values.map((p) => p.value)) + : new Uint8Array([]); + + onChange({ + extrinsic, + isValid, + value + }); + }); + } + + onChangeExtrinsic = (extrinsic: Extrinsic): void => { + this.nextState({ extrinsic }); + }; + + onChangeValues = (values: Array): void => { + this.nextState({ values }); + } +} diff --git a/packages/app-extrinsics/src/Extrinsic/index.js b/packages/app-extrinsics/src/Extrinsic/index.js deleted file mode 100644 index 191917dc92..0000000000 --- a/packages/app-extrinsics/src/Extrinsic/index.js +++ /dev/null @@ -1,103 +0,0 @@ -// 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 type { EncodedParams } from '../types'; -import type { Subjects } from './types'; - -import React from 'react'; -import encodeExtrinsic from '@polkadot/extrinsics-codec/encode/extrinsic'; -import withObservable from '@polkadot/rx-react/with/observable'; -import InputExtrinsic from '@polkadot/ui-react-app/src/InputExtrinsic'; -import Params from '@polkadot/ui-react-app/src/Params'; -import isUndefined from '@polkadot/util/is/undefined'; - -import paramComponents from '../Params'; -import createSubjects from './subjects'; - -type Props = BareProps & { - isError?: boolean, - isPrivate?: boolean, - labelMethod?: string, - labelSection?: string, - subject: rxjs$BehaviorSubject -}; - -export default class Extrinsic extends React.PureComponent { - subjects: Subjects; - subscriptions: Array; - Params: React$ComponentType<*>; - - constructor (props: Props) { - super(props); - - this.subjects = createSubjects(props.subject); - this.Params = withObservable(this.subjects.method)(Params); - this.subscriptions = []; - } - - componentWillMount () { - this.subscriptions = [ - this.subjects.params.subscribe(this.onChange), - this.subjects.method.subscribe(this.onChange) - ]; - } - - componentWillUnmount () { - this.subscriptions.forEach((s) => - s.unsubscribe() - ); - } - - onChange = (): void => { - const extrinsic = this.subjects.method.getValue(); - const values = this.subjects.params.getValue(); - const isValid = !!extrinsic.params && - Object - .values(extrinsic.params) - .reduce((isValid, param, index) => { - return isValid && - !isUndefined(values[index]) && - !isUndefined(values[index].value) && - values[index].isValid; - }, !!values); - const raw = values.map((param) => param && param.value); - const data = extrinsic.params - ? encodeExtrinsic(extrinsic, raw) - : new Uint8Array([]); - - this.props.subject.next({ - data, - extrinsic, - isValid - }); - }; - - render (): React$Node { - const { className, isError, isPrivate, labelMethod, labelSection, style } = this.props; - const { Params, subjects } = this; - - return ( -
-
- -
- -
- ); - } -} diff --git a/packages/app-extrinsics/src/Extrinsic/subjects.js b/packages/app-extrinsics/src/Extrinsic/subjects.js deleted file mode 100644 index 6895c627a4..0000000000 --- a/packages/app-extrinsics/src/Extrinsic/subjects.js +++ /dev/null @@ -1,19 +0,0 @@ -// 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 { Extrinsic } from '@polkadot/extrinsics/types'; -import type { EncodedParams } from '../types'; -import type { Subjects } from './types'; - -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; - -export default function subjects (subject: rxjs$BehaviorSubject): Subjects { - const extrinsic = subject.getValue().extrinsic || ({}: $Shape); - - return { - method: new BehaviorSubject(extrinsic), - params: new BehaviorSubject([]) - }; -} diff --git a/packages/app-extrinsics/src/Extrinsic/types.js b/packages/app-extrinsics/src/Extrinsic/types.js deleted file mode 100644 index 8334330323..0000000000 --- a/packages/app-extrinsics/src/Extrinsic/types.js +++ /dev/null @@ -1,12 +0,0 @@ -// 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 { Extrinsic } from '@polkadot/extrinsics/types'; -import type { RawParam } from '@polkadot/ui-react-app/Params/types'; - -export type Subjects = { - method: rxjs$BehaviorSubject, - params: rxjs$BehaviorSubject> -}; diff --git a/packages/app-extrinsics/src/Params/Account.js b/packages/app-extrinsics/src/Params/Account.js index 13c5a19fb3..a7623eddf2 100644 --- a/packages/app-extrinsics/src/Params/Account.js +++ b/packages/app-extrinsics/src/Params/Account.js @@ -3,49 +3,31 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { Props } from '@polkadot/ui-react-app/Params/types'; +import type { Props as BaseProps } from '@polkadot/ui-react-app/Params/types'; import React from 'react'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import BaseAccount from '../Account'; -export default class Account extends React.PureComponent { - account: rxjs$BehaviorSubject; - subscriptions: Array +type Props = BaseProps & { + defaultValue?: Uint8Array +}; - constructor (props: Props) { - super(props); +export default function Account ({ className, defaultValue, index, isError, onChange, label, style }: Props): React$Node { + const _onChange = (value?: Uint8Array): void => + onChange(index, { + isValid: !!value && value.length === 32, + value + }); - this.account = new BehaviorSubject(new Uint8Array([])); - } - - componentWillMount () { - this.subscriptions = [ - this.account.subscribe((value: Uint8Array) => - this.props.subject.next({ - isValid: !!value && value.length === 32, - value - }) - ) - ]; - } - - componentWillUnmount () { - this.subscriptions.forEach((s) => - s.unsubscribe() - ); - } - - render (): React$Node { - const { isError, label } = this.props; - - return ( - - ); - } + return ( + + ); } diff --git a/packages/app-extrinsics/src/Params/Proposal.js b/packages/app-extrinsics/src/Params/Proposal.js index 9387c0fac9..ce825014ea 100644 --- a/packages/app-extrinsics/src/Params/Proposal.js +++ b/packages/app-extrinsics/src/Params/Proposal.js @@ -5,66 +5,47 @@ import type { Props as BaseProps } from '@polkadot/ui-react-app/Params/types'; import type { I18nProps } from '@polkadot/ui-react-app/types'; -import type { EncodedParams } from '../types'; +import type { EncodedMessage } from '../types'; import React from 'react'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import extrinsics from '@polkadot/extrinsics-substrate'; import Extrinsic from '../Extrinsic'; import translate from '../translate'; type Props = BaseProps & I18nProps; -class Proposal extends React.PureComponent { - extrinsic: rxjs$BehaviorSubject; - subscriptions: Array +const defaultValue = extrinsics.consensus.methods.private.setCode; - constructor (props: Props) { - super(props); +function Proposal ({ className, index, isError, onChange, label, style, t }: Props): React$Node { + const _onChange = ({ isValid, value }: EncodedMessage): void => + onChange(index, { + isValid, + value + }); - this.extrinsic = new BehaviorSubject(({ isValid: false }: $Shape)); - } - - componentWillMount () { - this.subscriptions = [ - this.extrinsic.subscribe(({ data, isValid }: EncodedParams) => - this.props.subject.next({ - isValid, - value: data - }) - ) - ]; - } - - componentWillUnmount () { - this.subscriptions.forEach((s) => - s.unsubscribe() - ); - } - - render (): React$Node { - const { isError, label, t } = this.props; - - return ( - - ); - } + return ( + + ); } export default translate(Proposal); diff --git a/packages/app-extrinsics/src/Selection/Nonce.js b/packages/app-extrinsics/src/Selection/Nonce.js new file mode 100644 index 0000000000..ae4f7b7592 --- /dev/null +++ b/packages/app-extrinsics/src/Selection/Nonce.js @@ -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. +// @flow + +import type BN from 'bn.js'; +import type { BareProps } from '@polkadot/ui-react-app/types'; + +import React from 'react'; +import Label from 'semantic-ui-react/dist/es/elements/Label'; +import RxNonce from '@polkadot/rx-react/Nonce'; + +type Props = BareProps & { + label: string, + onChange: (value: BN) => void, + value?: Uint8Array +}; + +export default function Nonce ({ className, label, style, onChange, value }: Props): React$Node { + return ( +
+
+ + +
+
+ ); +} diff --git a/packages/app-extrinsics/src/Submission/Submission.css b/packages/app-extrinsics/src/Selection/Selection.css similarity index 63% rename from packages/app-extrinsics/src/Submission/Submission.css rename to packages/app-extrinsics/src/Selection/Selection.css index 2c63e1165c..54fe562834 100644 --- a/packages/app-extrinsics/src/Submission/Submission.css +++ b/packages/app-extrinsics/src/Selection/Selection.css @@ -2,14 +2,14 @@ /* This software may be modified and distributed under the terms /* of the ISC license. See the LICENSE file for details. */ -.extrinsics--Submission {} +.extrinsics--Selection {} -.extrinsics--Submission-ButtonRow { +.extrinsics--Selection-ButtonRow { margin: 1em 0; text-align: right; } -.extrinsics--Submission-ButtonRow .button { - margin-left: 0.5rem; +.extrinsics--Selection-ButtonRow .button { + margin: 0 0 0 0.5rem; text-align: left; } diff --git a/packages/app-extrinsics/src/Selection/index.js b/packages/app-extrinsics/src/Selection/index.js new file mode 100644 index 0000000000..82b0f5159e --- /dev/null +++ b/packages/app-extrinsics/src/Selection/index.js @@ -0,0 +1,140 @@ +// 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 BN from 'bn.js'; +import type { I18nProps } from '@polkadot/ui-react-app/types'; +import type { EncodedMessage, QueueTx } from '../types'; + +import './Selection.css'; + +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 Nonce from './Nonce'; + +type Props = I18nProps & { + onQueue: (value: QueueTx) => void +}; + +type State = { + isValid: boolean, + encoded: EncodedMessage, + nonce: BN, + publicKey: Uint8Array +}; + +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); + } + + render () { + const { className, style, t } = this.props; + const { publicKey, isValid } = this.state; + + return ( +
+ + + +
+ +
+
+ ); + } + + nextState (newState: $Shape): void { + this.setState( + (prevState: State): State => { + const { encoded = prevState.encoded, nonce = prevState.nonce, publicKey = prevState.publicKey } = newState; + const isValid = !!( + publicKey && + publicKey.length && + encoded && + encoded.isValid + ); + + return { + encoded, + isValid, + nonce, + publicKey + }; + } + ); + } + + onChangeMessage = (encoded: EncodedMessage): void => { + this.nextState({ encoded }); + } + + onChangeNonce = (nonce: BN): void => { + this.nextState({ nonce }); + } + + onChangeSender = (publicKey: Uint8Array): void => { + this.nextState({ publicKey }); + } + + onQueue = (): void => { + const { onQueue } = this.props; + const { encoded: { extrinsic, isValid, value }, nonce, publicKey } = this.state; + + onQueue({ + extrinsic, + id: ++id, + isValid, + nonce, + publicKey, + status: 'queued', + value + }); + } +} + +export default translate(Selection); diff --git a/packages/app-extrinsics/src/Signer/Decoded.js b/packages/app-extrinsics/src/Signer/Decoded.js index 3043be44e3..7141594c2d 100644 --- a/packages/app-extrinsics/src/Signer/Decoded.js +++ b/packages/app-extrinsics/src/Signer/Decoded.js @@ -19,7 +19,7 @@ type Props = I18nProps & { value: QueueTx }; -function Decoded ({ className, style, t, value: { data, extrinsic, index, publicKey } }: Props): React$Node { +function Decoded ({ className, style, t, value: { extrinsic: { name, section }, nonce, publicKey, value } }: Props): React$Node { const from = addressEncode(publicKey); return ( @@ -35,7 +35,7 @@ function Decoded ({ className, style, t, value: { data, extrinsic, index, public

- You are about to sign a message from {from} calling {extrinsic.section}_{extrinsic.name} with an index of {index.toString()} + You are about to sign a message from {from} calling {section}_{name} with an index of {nonce.toString()}

@@ -43,7 +43,9 @@ function Decoded ({ className, style, t, value: { data, extrinsic, index, public defaultValue: 'The encoded parameters contains the data' })}

-

{u8aToHexShort(data, 512)}

+

+ {u8aToHexShort(value, 512)} +

diff --git a/packages/app-extrinsics/src/Signer/index.js b/packages/app-extrinsics/src/Signer/index.js index a21e91bd83..80934e0f71 100644 --- a/packages/app-extrinsics/src/Signer/index.js +++ b/packages/app-extrinsics/src/Signer/index.js @@ -19,23 +19,23 @@ import Decoded from './Decoded'; import submitExtrinsic from './submit'; type Props = I18nProps & ApiProps & { - subject: rxjs$BehaviorSubject, - value: QueueTx + onSetStatus: (id: number, status: string) => void, + queue: Array }; -function Signer ({ api, className, subject, style, t, value }: Props): React$Node { - if (value.status !== 'queued') { +function Signer ({ api, className, onSetStatus, queue, style, t }: Props): React$Node { + const first = queue.find(({ status }) => status === 'queued'); + + if (!first) { return null; } - const onClose = (): void => { - subject.next({ - ...value, - status: 'cancelled' - }); - }; - const onSign = (): void => { - submitExtrinsic(api, value, subject); + const onClose = (): void => + onSetStatus(first.id, 'cancelled'); + const onSign = async (): Promise => { + const status = await submitExtrinsic(api, first); + + onSetStatus(first.id, status); }; return ( @@ -50,7 +50,7 @@ function Signer ({ api, className, subject, style, t, value }: Props): React$Nod defaultValue: 'Sign and submit' })} - + - ); -} - -export default translate(Submit); diff --git a/packages/app-extrinsics/src/Submission/index.js b/packages/app-extrinsics/src/Submission/index.js deleted file mode 100644 index 485b98d14a..0000000000 --- a/packages/app-extrinsics/src/Submission/index.js +++ /dev/null @@ -1,95 +0,0 @@ -// 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 type { QueueTx } from '../types'; -import type { Subjects } from './types'; - -import './Submission.css'; - -import React from 'react'; -import withObservable from '@polkadot/rx-react/with/observable'; - -import Account from '../Account'; -import Extrinsic from '../Extrinsic'; -import translate from '../translate'; -import Nonce from './Nonce'; -import Submit from './Submit'; -import createSubjects from './subjects'; - -type Props = I18nProps & { - subject: rxjs$BehaviorSubject -}; - -class Submission extends React.PureComponent { - Submit: React$ComponentType<*>; - subjects: Subjects; - - constructor (props: Props) { - super(props); - - this.subjects = createSubjects(); - this.Submit = withObservable(this.subjects.call)(Submit); - } - - componentWillMount () { - this.subjects.index.subscribe(this.onChange); - this.subjects.method.subscribe(this.onChange); - this.subjects.sender.subscribe(this.onChange); - } - - onChange = (): void => { - const index = this.subjects.index.getValue(); - const message = this.subjects.method.getValue(); - const publicKey = this.subjects.sender.getValue(); - const isValid = !!(publicKey && publicKey.length && message && message.isValid); - - this.subjects.call.next({ - data: message.data, - extrinsic: message.extrinsic, - isValid, - index, - publicKey, - status: 'incomplete' - }); - }; - - render (): React$Node { - const { className, subject, style, t } = this.props; - const { Submit, subjects } = this; - - return ( -
- - - -
- -
-
- ); - } -} - -export default translate(Submission); diff --git a/packages/app-extrinsics/src/Submission/subjects.js b/packages/app-extrinsics/src/Submission/subjects.js deleted file mode 100644 index 4a8995dd04..0000000000 --- a/packages/app-extrinsics/src/Submission/subjects.js +++ /dev/null @@ -1,25 +0,0 @@ -// 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 { EncodedParams, QueueTx } from '../types'; -import type { Subjects } from './types'; - -import BN from 'bn.js'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import map from '@polkadot/extrinsics-substrate'; - -export default function createSubjects (): Subjects { - return { - index: new BehaviorSubject(new BN(0)), - call: new BehaviorSubject(({ - isValid: false - }: $Shape)), - method: new BehaviorSubject(({ - extrinsic: map.staking.methods.public.transfer, - isValid: false - }: $Shape)), - sender: new BehaviorSubject(new Uint8Array([])) - }; -} diff --git a/packages/app-extrinsics/src/Submission/types.js b/packages/app-extrinsics/src/Submission/types.js deleted file mode 100644 index fb2b6f289f..0000000000 --- a/packages/app-extrinsics/src/Submission/types.js +++ /dev/null @@ -1,14 +0,0 @@ -// 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 BN from 'bn.js'; -import type { EncodedParams, QueueTx } from '../types'; - -export type Subjects = { - call: rxjs$BehaviorSubject, - index: rxjs$BehaviorSubject, - method: rxjs$BehaviorSubject, - sender: rxjs$BehaviorSubject -}; diff --git a/packages/app-extrinsics/src/index.css b/packages/app-extrinsics/src/index.css index 0a8a7b6fe8..d7f3545d71 100644 --- a/packages/app-extrinsics/src/index.css +++ b/packages/app-extrinsics/src/index.css @@ -3,25 +3,29 @@ /* of the ISC license. See the LICENSE file for details. */ .extrinsics--App { - padding: 1em; + padding: 1em 2em; } .extrinsics--Status { - background: #bcdaf0; + bottom: 0; display: inline-block; - padding: 0.5rem 1rem; position: fixed; - bottom: 0.125rem; right: 0.125rem; - text-align: center; z-index: 1001; } -.extrinsics--Status .status { +.extrinsics--Status-Item { + background: #bcdaf0; + margin-bottom: 0.125rem; + padding: 0.5rem 1rem; + text-align: center; +} + +.extrinsics--Status-Item .status { font-weight: 700; } -.extrinsics--Status.error { +.extrinsics--Status-Item.error { background: red; color: white; } diff --git a/packages/app-extrinsics/src/index.js b/packages/app-extrinsics/src/index.js index 78afb1d81f..e92cf823ce 100644 --- a/packages/app-extrinsics/src/index.js +++ b/packages/app-extrinsics/src/index.js @@ -3,8 +3,76 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { BareProps } from '@polkadot/ui-react-app/types'; +import type { QueueTx, QueueTx$Status } from './types'; + import './index.css'; -import App from './App'; +import React from 'react'; -export default App; +import Selection from './Selection'; +import Signer from './Signer'; +import Status from './Status'; + +type Props = BareProps & {}; + +type State = { + queue: Array +}; + +export default class App extends React.PureComponent { + state: State; + + constructor (props: Props) { + super(props); + + this.state = { + queue: [] + }; + } + + render (): React$Node { + const { className, style } = this.props; + const { queue } = this.state; + + return ( +
+ + + +
+ ); + } + + setStatus = (id: number, status: QueueTx$Status): void => { + this.setState( + (prevState: State): State => ({ + queue: prevState.queue.map((item) => + item.id === id + ? { ...item, status } + : item + ) + }) + ); + + if (!['cancelled', 'error', 'sent'].includes(status)) { + return; + } + + setTimeout(() => this.setStatus(id, 'completed'), 5000); + } + + onQueue = (value: QueueTx): void => { + this.setState( + (prevState: State): State => ({ + queue: prevState.queue.concat([value]) + }) + ); + } +} diff --git a/packages/app-extrinsics/src/types.js b/packages/app-extrinsics/src/types.js index c1abc594ac..3203b5d5aa 100644 --- a/packages/app-extrinsics/src/types.js +++ b/packages/app-extrinsics/src/types.js @@ -6,16 +6,17 @@ import type BN from 'bn.js'; import type { Extrinsic } from '@polkadot/extrinsics/types'; -export type EncodedParams = { - data: Uint8Array, +export type EncodedMessage = { extrinsic: Extrinsic, - isValid: boolean + isValid: boolean, + value: Uint8Array }; -export type QueueTx$Status = 'incomplete' | 'cancelled' | 'error' | 'queued' | 'sent'; +export type QueueTx$Status = 'cancelled' | 'completed' | 'error' | 'incomplete' | 'queued' | 'sent'; -export type QueueTx = EncodedParams & { - index: BN, +export type QueueTx = EncodedMessage & { + id: number, + nonce: BN, publicKey: Uint8Array, status: QueueTx$Status }; diff --git a/packages/app-storage/src/App.js b/packages/app-storage/src/App.js deleted file mode 100644 index 1b55aa30b0..0000000000 --- a/packages/app-storage/src/App.js +++ /dev/null @@ -1,28 +0,0 @@ -// 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 React from 'react'; - -import Queries from './Queries'; -import Selection from './Selection'; -import translate from './translate'; - -type Props = I18nProps & {}; - -function App ({ className, style, t }: Props): React$Node { - return ( -
- - -
- ); -} - -export default translate(App); diff --git a/packages/app-storage/src/Queries/index.js b/packages/app-storage/src/Queries.js similarity index 62% rename from packages/app-storage/src/Queries/index.js rename to packages/app-storage/src/Queries.js index 0dc7e662d0..4e8043763f 100644 --- a/packages/app-storage/src/Queries/index.js +++ b/packages/app-storage/src/Queries.js @@ -4,20 +4,19 @@ // @flow import type { I18nProps } from '@polkadot/ui-react-app/types'; -import type { StorageQuery } from '../types'; +import type { StorageQuery } from './types'; import React from 'react'; -import withObservable from '@polkadot/rx-react/with/observable'; -import subjects from '../subjects'; -import translate from '../translate'; +import translate from './translate'; import Query from './Query'; type Props = I18nProps & { + onRemove: (id: number) => void, value?: Array }; -function Queries ({ className, style, value }: Props): React$Node { +function Queries ({ className, onRemove, style, value }: Props): React$Node { if (!value || !value.length) { return null; } @@ -27,16 +26,15 @@ function Queries ({ className, style, value }: Props): React$Node { className={['storage--Queries', className].join(' ')} style={style} > - {value.map((query) => ( + {value.map((query) => - ))} + )} ); } -export default translate( - withObservable(subjects.queries)(Queries) -); +export default translate(Queries); diff --git a/packages/app-storage/src/Queries/Remove.js b/packages/app-storage/src/Queries/Remove.js deleted file mode 100644 index 85457b862c..0000000000 --- a/packages/app-storage/src/Queries/Remove.js +++ /dev/null @@ -1,46 +0,0 @@ -// 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 React from 'react'; -import Button from 'semantic-ui-react/dist/es/elements/Button'; - -import subjects from '../subjects'; -import translate from '../translate'; -import cache from './cache'; - -type Props = I18nProps & { - value: number; -}; - -function Remove ({ className, style, value }: Props): React$Node { - const onRemove = (): void => { - const current = subjects.queries.getValue(); - - delete cache[value]; - - subjects.queries.next( - current - .filter(({ id }) => id !== value) - .reduce((next, item) => { - next.push(item); - - return next; - }, []) - ); - }; - - return ( -