From b2f6d87de16d979b7eefb6bc8534801db6299feb Mon Sep 17 00:00:00 2001 From: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> Date: Sat, 29 Jun 2019 10:02:58 +0200 Subject: [PATCH] Use empty props from CardGrid (#1304) * empty for account, addressbook * staking empty screen * use multi only when values changed * lint * withCall paramPick transform * use paramPick and log things * swap logging * Display getMethod errors in withCall * Remove nested try * Use updateDb to trigger an update * fix bonding * Revert ifs * Update call.tsx * lint * stray logs --- packages/app-accounts/src/Overview.tsx | 51 ++++++++---- packages/app-address-book/src/Overview.tsx | 3 + .../app-js/src/snippets/storage-examples.ts | 4 +- .../app-staking/src/Actions/Account/index.tsx | 7 +- packages/app-staking/src/Actions/Accounts.tsx | 77 ++++++++++++++----- packages/app-staking/src/index.tsx | 5 +- packages/app-staking/src/types.ts | 4 +- packages/ui-api/src/with/call.tsx | 48 ++++++++---- packages/ui-api/src/with/types.ts | 1 + packages/ui-app/src/CardGrid.tsx | 4 +- packages/ui-app/src/Collection.tsx | 1 + 11 files changed, 145 insertions(+), 60 deletions(-) diff --git a/packages/app-accounts/src/Overview.tsx b/packages/app-accounts/src/Overview.tsx index d88f05fcd1..b895193e51 100644 --- a/packages/app-accounts/src/Overview.tsx +++ b/packages/app-accounts/src/Overview.tsx @@ -38,8 +38,9 @@ class Overview extends React.PureComponent { } render () { - const { accounts, onStatusChange, t } = this.props; + const { accounts, t } = this.props; const { isCreateOpen, isImportOpen } = this.state; + const emptyScreen = !isCreateOpen && !isImportOpen && (!accounts || Object.keys(accounts).length === 0); return ( { /> } + isEmpty={emptyScreen} + emptyText={t('No account yet?')} > - {isCreateOpen && ( - - )} - {isImportOpen && ( - - )} + {this.renderCreate()} + {this.renderImport()} {accounts && Object.keys(accounts).map((address) => ( { ); } + private renderCreate () { + const { isCreateOpen } = this.state; + const { onStatusChange } = this.props; + + if (!isCreateOpen) { + return null; + } + + return ( + + ); + } + + private renderImport () { + const { isImportOpen } = this.state; + const { onStatusChange } = this.props; + + if (!isImportOpen) { + return null; + } + + return ( + + ); + } + private toggleCreate = (): void => { this.setState(({ isCreateOpen }) => ({ isCreateOpen: !isCreateOpen diff --git a/packages/app-address-book/src/Overview.tsx b/packages/app-address-book/src/Overview.tsx index 2afaf7a097..7037d9907f 100644 --- a/packages/app-address-book/src/Overview.tsx +++ b/packages/app-address-book/src/Overview.tsx @@ -31,6 +31,7 @@ class Overview extends React.PureComponent { render () { const { addresses, onStatusChange, t } = this.props; const { isCreateOpen } = this.state; + const emptyScreen = !isCreateOpen && (!addresses || Object.keys(addresses).length === 0); return ( { /> } + isEmpty={emptyScreen} + emptyText={t('No contact found.')} > {isCreateOpen && ( { - console.log('Change detected, new balances: ', balance) +api.query.balances.freeBalance.multi([ALICE, BOB], (balances) => { + console.log('Change detected, new balances: ', balances) });` }; diff --git a/packages/app-staking/src/Actions/Account/index.tsx b/packages/app-staking/src/Actions/Account/index.tsx index caa0b2ffca..8353ab6614 100644 --- a/packages/app-staking/src/Actions/Account/index.tsx +++ b/packages/app-staking/src/Actions/Account/index.tsx @@ -80,19 +80,20 @@ class Account extends React.PureComponent { stashId: null }; - static getDerivedStateFromProps ({ staking_info }: Props): State | null { + static getDerivedStateFromProps ({ accountId, staking_info }: Props): State | null { + if (!staking_info) { return null; } - const { accountId, controllerId, nextSessionId, nominators, rewardDestination, stakers, stakingLedger, stashId, validatorPrefs } = staking_info; + const { controllerId, nextSessionId, nominators, rewardDestination, stakers, stakingLedger, stashId, validatorPrefs } = staking_info; const isStashNominating = nominators && nominators.length !== 0; const isStashValidating = !!validatorPrefs && !validatorPrefs.isEmpty && !isStashNominating; return { controllerId: toIdString(controllerId), destination: rewardDestination && rewardDestination.toNumber(), - isActiveStash: accountId.eq(stashId), + isActiveStash: accountId === toIdString(stashId), isStashNominating, isStashValidating, nominees: nominators && nominators.map(toIdString), diff --git a/packages/app-staking/src/Actions/Accounts.tsx b/packages/app-staking/src/Actions/Accounts.tsx index c490e30099..6079cffce0 100644 --- a/packages/app-staking/src/Actions/Accounts.tsx +++ b/packages/app-staking/src/Actions/Accounts.tsx @@ -2,22 +2,25 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { I18nProps } from '@polkadot/ui-app/types'; +import { ApiProps } from '@polkadot/ui-api/types'; import { ComponentProps } from '../types'; +import { I18nProps } from '@polkadot/ui-app/types'; +import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types'; +import { withCalls, withMulti } from '@polkadot/ui-api/with'; import React from 'react'; +import styled from 'styled-components'; import { Button, CardGrid, Icon } from '@polkadot/ui-app'; import createOption from '@polkadot/ui-keyring/options/item'; import { getAddressName } from '@polkadot/ui-app/util'; -import keyring from '@polkadot/ui-keyring'; -import styled from 'styled-components'; import Account from './Account'; -import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types'; import StartStaking from './NewStake'; import translate from '../translate'; -type Props = I18nProps & ComponentProps; +type Props = I18nProps & ComponentProps & ApiProps & { + myControllers?: Array +}; type State = { isNewStakeOpen: boolean @@ -30,8 +33,10 @@ class Accounts extends React.PureComponent { render () { const { className, recentlyOffline, t } = this.props; - const accounts = keyring.getAccounts(); + const { isNewStakeOpen } = this.state; const stashOptions = this.getStashOptions(); + const myStashes = this.getMyStashes(); + const isEmpty = !isNewStakeOpen && (!myStashes || myStashes.length === 0); return ( { /> } className={className} + emptyText={t('No funds staked yet.')} + isEmpty={isEmpty} > {this.renderNewStake()} - {accounts.map(({ address }, index) => ( + {myStashes && myStashes.map((address, index) => ( + address && { ); } + private getMyStashes () { + const { myControllers, allAccounts } = this.props; + const result: Array = []; + + if (!myControllers) { + return null; + } + + myControllers.forEach((value,index) => { + if (value.toString() !== '') { + allAccounts && result.push(Object.keys(allAccounts)[index]); + } + }); + + return result; + } + + private getStashOptions (): Array { + const { stashes } = this.props; + + return stashes.map((stashId) => + createOption(stashId, getAddressName(stashId, 'account')) + ); + } + private renderNewStake () { const { isNewStakeOpen } = this.state; @@ -82,18 +115,22 @@ class Accounts extends React.PureComponent { isNewStakeOpen: !isNewStakeOpen })); } - - private getStashOptions (): Array { - const { stashes } = this.props; - - return stashes.map((stashId) => - createOption(stashId, getAddressName(stashId, 'account')) - ); - } } -export default translate(styled(Accounts)` - .ui--CardGrid-buttons { - text-align: right; - } -`); +export default withMulti( + styled(Accounts)` + .ui--CardGrid-buttons { + text-align: right; + } + `, + translate, + withCalls( + ['query.staking.bonded', { + isMulti: true, + paramPick: ({ allAccounts }: Props) => { + return allAccounts && Object.keys(allAccounts); + }, + propName: 'myControllers' + }] + ) +); diff --git a/packages/app-staking/src/index.tsx b/packages/app-staking/src/index.tsx index d2b3dad38d..0a6b921471 100644 --- a/packages/app-staking/src/index.tsx +++ b/packages/app-staking/src/index.tsx @@ -18,8 +18,8 @@ import accountObservable from '@polkadot/ui-keyring/observable/accounts'; import './index.css'; -import basicMd from './md/basic.md'; import Accounts from './Actions/Accounts'; +import basicMd from './md/basic.md'; import Overview from './Overview'; import translate from './translate'; @@ -121,10 +121,11 @@ class App extends React.PureComponent { private renderComponent (Component: React.ComponentType) { return (): React.ReactNode => { const { controllers, recentlyOffline, stashes, validators } = this.state; - const { balances = {} } = this.props; + const { balances = {}, allAccounts } = this.props; return ( , recentlyOffline: RecentlyOfflineMap, diff --git a/packages/ui-api/src/with/call.tsx b/packages/ui-api/src/with/call.tsx index d263a2f018..901c5f909e 100644 --- a/packages/ui-api/src/with/call.tsx +++ b/packages/ui-api/src/with/call.tsx @@ -18,13 +18,15 @@ interface Method { multi: (params: Array, cb: (value?: any) => void) => Promise; } +type ApiMethodInfo = [Method, Array, boolean]; + type State = CallState; const NOOP = () => { // ignore }; -export default function withCall

(endpoint: string, { at, atProp, callOnResult, isMulti = false, params = [], paramName, paramValid = false, propName, transform = echoTransform }: Options = {}): (Inner: React.ComponentType) => React.ComponentType { +export default function withCall

(endpoint: string, { at, atProp, callOnResult, isMulti = false, params = [], paramName, paramPick, paramValid = false, propName, transform = echoTransform }: Options = {}): (Inner: React.ComponentType) => React.ComponentType { return (Inner: React.ComponentType): React.ComponentType> => { class WithPromise extends React.Component { state: State = { @@ -46,8 +48,8 @@ export default function withCall

(endpoint: string, { at, at } componentDidUpdate (prevProps: any) { - const newParams = this.getParams(this.props); const oldParams = this.getParams(prevProps); + const newParams = this.getParams(this.props); if (this.isActive && !isEqual(newParams, oldParams)) { this @@ -93,9 +95,11 @@ export default function withCall

(endpoint: string, { at, at } private getParams (props: any): [boolean, Array] { - const paramValue = paramName - ? props[paramName] - : undefined; + const paramValue = paramPick + ? paramPick(props) + : paramName + ? props[paramName] + : undefined; if (atProp) { at = props[atProp]; @@ -118,7 +122,7 @@ export default function withCall

(endpoint: string, { at, at return [true, values]; } - private getApiMethod (newParams: Array): [Method, Array, boolean] { + private getApiMethod (newParams: Array): ApiMethodInfo { const { api } = this.props; if (endpoint === 'subscribe') { @@ -162,29 +166,39 @@ export default function withCall

(endpoint: string, { at, at } const { api } = this.props; + let info: ApiMethodInfo | undefined; await api.isReady; try { - const [apiMethod, params, isSubscription] = this.getApiMethod(newParams); - assert(at || !atProp, 'Unable to perform query on non-existent at hash'); - await this.unsubscribe(); + info = this.getApiMethod(newParams); + } catch (error) { + console.error(endpoint, '::', error); + } + if (!info) { + return; + } + + const [apiMethod, params, isSubscription] = info; + const updateCb = (value?: any) => + this.triggerUpdate(this.props, value); + + await this.unsubscribe(); + + try { if (isSubscription) { - const updateCb = (value?: any) => - this.triggerUpdate(this.props, value); - this.destroy = isMulti ? await apiMethod.multi(params, updateCb) : await apiMethod(...params, updateCb); } else { - const value: any = at - ? await apiMethod.at(at, ...params) - : await apiMethod(...params); - - this.triggerUpdate(this.props, value); + updateCb( + at + ? await apiMethod.at(at, ...params) + : await apiMethod(...params) + ); } } catch (error) { // console.error(endpoint, '::', error); diff --git a/packages/ui-api/src/with/types.ts b/packages/ui-api/src/with/types.ts index 07af3c5124..c58a363018 100644 --- a/packages/ui-api/src/with/types.ts +++ b/packages/ui-api/src/with/types.ts @@ -20,6 +20,7 @@ export type Options = { isMulti?: boolean, params?: Array, paramName?: string, + paramPick?: (props: any) => any, paramValid?: boolean, propName?: string, transform?: Transform diff --git a/packages/ui-app/src/CardGrid.tsx b/packages/ui-app/src/CardGrid.tsx index f6d42c0b98..059149a820 100644 --- a/packages/ui-app/src/CardGrid.tsx +++ b/packages/ui-app/src/CardGrid.tsx @@ -14,8 +14,8 @@ type Props = CollectionProps; type State = CollectionState; class CardGrid extends Collection { - static getDerivedStateFromProps ({ children }: Props) { - if (!children || (children as Array).length <= 0) { + static getDerivedStateFromProps ({ children, isEmpty }: Props) { + if (isEmpty || !children || (children as Array).length <= 0) { return { isEmpty: true, showHeader: false }; } return { isEmpty: false, showHeader: true }; diff --git a/packages/ui-app/src/Collection.tsx b/packages/ui-app/src/Collection.tsx index 7a76144d3b..e313c6c118 100644 --- a/packages/ui-app/src/Collection.tsx +++ b/packages/ui-app/src/Collection.tsx @@ -11,6 +11,7 @@ export type CollectionProps = I18nProps & { children: React.ReactNode, className?: string, headerText?: React.ReactNode, + isEmpty?: boolean, emptyText?: React.ReactNode };