From f887f68cfb2ee21301a3e951b3889fd1292e01b0 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sun, 2 Jun 2019 10:13:38 +0200 Subject: [PATCH] Combine AddressSummary & Row (#1260) * Combine AddressSummary & Row * Cleanup address rendering * Tiny tags cleanups * Remove unused ui--AddressSummary overrides * Column component * Columar * Cleanups * Remove hot client * Backport data padding --- packages/app-accounts/src/index.css | 7 +- packages/app-address-book/src/Address.tsx | 2 +- .../src/BlockHeader/BlockHeader.css | 19 +- packages/app-explorer/src/BlockHeaders.tsx | 20 +- .../app-explorer/src/BlockInfo/ByHash.tsx | 9 +- .../app-explorer/src/BlockInfo/Events.tsx | 16 +- .../app-explorer/src/BlockInfo/Extrinsics.tsx | 72 +-- packages/app-explorer/src/BlockInfo/Logs.tsx | 10 +- packages/app-explorer/src/Events.tsx | 54 +- packages/app-explorer/src/Main.tsx | 24 +- packages/app-explorer/src/index.css | 4 +- .../app-staking/src/Overview/CurrentList.tsx | 79 +-- packages/app-staking/src/index.css | 11 - packages/apps/webpack.config.js | 2 +- packages/ui-app/src/AddressMini.tsx | 2 - packages/ui-app/src/AddressRow.tsx | 545 +++++++++++++++++- packages/ui-app/src/AddressSummary.tsx | 435 -------------- packages/ui-app/src/Card.tsx | 9 - packages/ui-app/src/Columar.tsx | 35 ++ packages/ui-app/src/Column.tsx | 53 ++ packages/ui-app/src/index.tsx | 3 +- packages/ui-app/src/styles/app.css | 1 + packages/ui-app/src/styles/components.css | 200 ------- packages/ui-app/src/styles/media.css | 3 + 24 files changed, 745 insertions(+), 870 deletions(-) delete mode 100644 packages/ui-app/src/AddressSummary.tsx create mode 100644 packages/ui-app/src/Columar.tsx create mode 100644 packages/ui-app/src/Column.tsx diff --git a/packages/app-accounts/src/index.css b/packages/app-accounts/src/index.css index fef43c14e9..85226c208b 100644 --- a/packages/app-accounts/src/index.css +++ b/packages/app-accounts/src/index.css @@ -2,11 +2,6 @@ /* This software may be modified and distributed under the terms /* of the Apache-2.0 license. See the LICENSE file for details. */ -.app--accounts-Modal .ui--AddressSummary { - display: inline-block; - margin-bottom: 1rem; -} - .accounts--Creator-advanced { margin-top: 1rem; -} \ No newline at end of file +} diff --git a/packages/app-address-book/src/Address.tsx b/packages/app-address-book/src/Address.tsx index 30a613f55c..e9172f7043 100644 --- a/packages/app-address-book/src/Address.tsx +++ b/packages/app-address-book/src/Address.tsx @@ -149,7 +149,7 @@ class Address extends React.PureComponent { icon='trash' key='forget' size='small' - tooltip={t('Forget this account')} + tooltip={t('Forget this address')} /> )} diff --git a/packages/app-explorer/src/BlockHeader/BlockHeader.css b/packages/app-explorer/src/BlockHeader/BlockHeader.css index 6338ddb8a1..fb19d9c5f2 100644 --- a/packages/app-explorer/src/BlockHeader/BlockHeader.css +++ b/packages/app-explorer/src/BlockHeader/BlockHeader.css @@ -2,19 +2,12 @@ /* This software may be modified and distributed under the terms /* of the Apache-2.0 license. See the LICENSE file for details. */ -@keyframes fadein { - from { opacity: 0; } - to { opacity: 1; } -} - header > .explorer--BlockHeader { border: none; box-shadow: none; } .explorer--BlockHeader { - animation: fadein 1s; - .author { font-size: 1rem; text-align: right; @@ -25,15 +18,6 @@ header > .explorer--BlockHeader { } } - .header-outer { - padding: 0.5rem; - overflow: hidden; - } - - .header-outer + details { - margin-top: -0.5rem; - } - .header { color: rgba(0, 0, 0, 0.6); display: flex; @@ -74,6 +58,7 @@ header > .explorer--BlockHeader { .contains { border: 0; + margin-top: 0.5rem; text-align: center; > .info { @@ -89,7 +74,7 @@ header > .explorer--BlockHeader { > label { display: inline-block; } - + > span, > label { vertical-align: middle; diff --git a/packages/app-explorer/src/BlockHeaders.tsx b/packages/app-explorer/src/BlockHeaders.tsx index 803fa2f69a..ecf30e84c7 100644 --- a/packages/app-explorer/src/BlockHeaders.tsx +++ b/packages/app-explorer/src/BlockHeaders.tsx @@ -43,18 +43,14 @@ class BlockHeaders extends React.PureComponent { render () { const { headers = [] } = this.props; - return ( -
- {headers.map((header, index) => ( - - ))} -
- ); + return headers.map((header, index) => ( + + )); } } diff --git a/packages/app-explorer/src/BlockInfo/ByHash.tsx b/packages/app-explorer/src/BlockInfo/ByHash.tsx index 482c05f67d..b17fe7b5fc 100644 --- a/packages/app-explorer/src/BlockInfo/ByHash.tsx +++ b/packages/app-explorer/src/BlockInfo/ByHash.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { HeaderExtended } from '@polkadot/api-derive'; import { EventRecord, SignedBlock } from '@polkadot/types'; import { withCalls } from '@polkadot/ui-api'; +import { Columar } from '@polkadot/ui-app'; import BlockHeader from '../BlockHeader'; import translate from '../translate'; @@ -39,9 +40,11 @@ class BlockByHash extends React.PureComponent { withExplorer /> - - - + + + + + ); } diff --git a/packages/app-explorer/src/BlockInfo/Events.tsx b/packages/app-explorer/src/BlockInfo/Events.tsx index c853e158fa..5195685d69 100644 --- a/packages/app-explorer/src/BlockInfo/Events.tsx +++ b/packages/app-explorer/src/BlockInfo/Events.tsx @@ -6,6 +6,7 @@ import { I18nProps } from '@polkadot/ui-app/types'; import React from 'react'; import { EventRecord } from '@polkadot/types'; +import { Column } from '@polkadot/ui-app'; import EventsDisplay from '../Events'; import translate from '../translate'; @@ -27,15 +28,12 @@ class Events extends React.PureComponent { })); return ( -
-

{t('events')}

-
- -
-
+ + + ); } } diff --git a/packages/app-explorer/src/BlockInfo/Extrinsics.tsx b/packages/app-explorer/src/BlockInfo/Extrinsics.tsx index 5b4e20e7ae..df2a58aa78 100644 --- a/packages/app-explorer/src/BlockInfo/Extrinsics.tsx +++ b/packages/app-explorer/src/BlockInfo/Extrinsics.tsx @@ -5,7 +5,7 @@ import { I18nProps } from '@polkadot/ui-app/types'; import React from 'react'; -import { AddressMini, Call, LinkPolkascan } from '@polkadot/ui-app'; +import { AddressMini, Call, Column, LinkPolkascan } from '@polkadot/ui-app'; import { formatNumber } from '@polkadot/util'; import { Extrinsic, Method } from '@polkadot/types'; @@ -21,10 +21,9 @@ class Extrinsics extends React.PureComponent { const { label, t } = this.props; return ( -
-

{label || t('extrinsics')}

+ {this.renderContent()} -
+ ); } @@ -33,17 +32,13 @@ class Extrinsics extends React.PureComponent { if (!value || !value.length) { return ( -
+
{t('no pending extrinsics are in the queue')} -
+ ); } - return ( -
- {value.map(this.renderExtrinsic)} -
- ); + return value.map(this.renderExtrinsic); } // FIXME This is _very_ similar to what we have in democracy/Item @@ -51,36 +46,31 @@ class Extrinsics extends React.PureComponent { const { meta, method, section } = Method.findFunction(extrinsic.callIndex); return ( -
-
-
-

- {section}.{method} (#{formatNumber(index)}) -

- {this.renderSigner(extrinsic)} -
-
- { - meta && meta.documentation - ? meta.documentation.join(' ') - : 'Details' - } - -
- { - extrinsic.isSigned - ? - : null - } -
-
+
+
+

+ {section}.{method} (#{formatNumber(index)}) +

+ {this.renderSigner(extrinsic)} +
+
+ { + meta && meta.documentation + ? meta.documentation.join(' ') + : 'Details' + } + +
+ { + extrinsic.isSigned + ? + : null + } +
); } diff --git a/packages/app-explorer/src/BlockInfo/Logs.tsx b/packages/app-explorer/src/BlockInfo/Logs.tsx index c8d83843d3..aa0e79adbe 100644 --- a/packages/app-explorer/src/BlockInfo/Logs.tsx +++ b/packages/app-explorer/src/BlockInfo/Logs.tsx @@ -6,6 +6,7 @@ import { I18nProps } from '@polkadot/ui-app/types'; import React from 'react'; import { DigestItem, Struct, Tuple, U8a, Vector, getTypeDef } from '@polkadot/types'; +import { Column } from '@polkadot/ui-app'; import Params from '@polkadot/ui-params'; import translate from '../translate'; @@ -23,12 +24,9 @@ class Logs extends React.PureComponent { } return ( -
-

{t('logs')}

-
- {value.map(this.renderItem)} -
-
+ + {value.map(this.renderItem)} + ); } diff --git a/packages/app-explorer/src/Events.tsx b/packages/app-explorer/src/Events.tsx index 1bca2b39b3..0944687020 100644 --- a/packages/app-explorer/src/Events.tsx +++ b/packages/app-explorer/src/Events.tsx @@ -23,7 +23,7 @@ class Events extends React.PureComponent { const { emptyLabel, events, t } = this.props; if (!events || events.length === 0) { - return emptyLabel || t('no events available'); + return
{emptyLabel || t('no events available')}
; } return events.map(this.renderEvent); @@ -40,35 +40,33 @@ class Events extends React.PureComponent { } return ( -
-
-
-

- {event.section}.{event.method} { - extIndex !== -1 - ? `(#${formatNumber(extIndex)})` - : '' - } -

-
-
- - { - event.meta && event.meta.documentation - ? event.meta.documentation.join(' ') - : 'Details' - } - - -
-
-
+
+

+ {event.section}.{event.method} { + extIndex !== -1 + ? `(#${formatNumber(extIndex)})` + : '' + } +

+
+
+ + { + event.meta && event.meta.documentation + ? event.meta.documentation.join(' ') + : 'Details' + } + + +
+ ); } } diff --git a/packages/app-explorer/src/Main.tsx b/packages/app-explorer/src/Main.tsx index 971553917c..3fb859b357 100644 --- a/packages/app-explorer/src/Main.tsx +++ b/packages/app-explorer/src/Main.tsx @@ -6,7 +6,7 @@ import { I18nProps } from '@polkadot/ui-app/types'; import { KeyedEvent } from './types'; import React from 'react'; -import styled from 'styled-components'; +import { Columar, Column } from '@polkadot/ui-app'; import BlockHeaders from './BlockHeaders'; import Events from './Events'; @@ -18,14 +18,6 @@ type Props = I18nProps & { events: Array }; -const Wrapper = styled.div` - .column { - flex: 0 0 50%; - min-width: 0; - padding: 0 1em 1em; - } -`; - class Main extends React.PureComponent { render () { const { events, t } = this.props; @@ -34,16 +26,14 @@ class Main extends React.PureComponent { <> - -
-

{t('recent blocks')}

+ + -
-
-

{t('recent events')}

+ + -
-
+ + ); } diff --git a/packages/app-explorer/src/index.css b/packages/app-explorer/src/index.css index 99e80a1a29..f6a55d4118 100644 --- a/packages/app-explorer/src/index.css +++ b/packages/app-explorer/src/index.css @@ -54,8 +54,8 @@ .explorer--BlockByHash-header-right { position: absolute; - top: -0.5rem; - right: 0rem; + top: 0.25rem; + right: 0.5rem; } .explorer--query { diff --git a/packages/app-staking/src/Overview/CurrentList.tsx b/packages/app-staking/src/Overview/CurrentList.tsx index b65618ee57..91a4482aac 100644 --- a/packages/app-staking/src/Overview/CurrentList.tsx +++ b/packages/app-staking/src/Overview/CurrentList.tsx @@ -7,7 +7,7 @@ import { I18nProps } from '@polkadot/ui-app/types'; import { ValidatorFilter, RecentlyOfflineMap } from '../types'; import React from 'react'; -import { Dropdown, FilterOverlay } from '@polkadot/ui-app'; +import { Columar, Column, Dropdown, FilterOverlay } from '@polkadot/ui-app'; import translate from '../translate'; import Address from './Address'; @@ -48,7 +48,7 @@ class CurrentList extends React.PureComponent { } render () { - const { t } = this.props; + const { current, next, t } = this.props; const { filter, filterOptions } = this.state; return (
@@ -61,73 +61,42 @@ class CurrentList extends React.PureComponent { value={filter} /> -
-
- {this.renderCurrent()} -
-
- {this.renderNext()} -
-
+ + + {this.renderColumn(current, t('validator (stash)'))} + + + {this.renderColumn(next, t('intention (stash)'))} + +
); } - private renderCurrent () { - const { current, t } = this.props; - - return ( - <> -

- {t('validators', { - replace: { - count: current.length - } - })} -

- {this.renderColumn(current, t('validator (stash)'))} - - ); - } - - private renderNext () { - const { next, t } = this.props; - - return ( - <> -

{t('next up')}

- {this.renderColumn(next, t('intention (stash)'))} - - ); - } - private renderColumn (addresses: Array, defaultName: string) { const { balances, lastAuthor, lastBlock, recentlyOffline, t } = this.props; const { filter } = this.state; if (addresses.length === 0) { return ( -
{t('no addresses found')}
+
{t('no addresses found')}
); } - return ( -
- {addresses.map((address) => ( -
- ))} -
- ); + return addresses.map((address) => ( +
+ )); } + private onChangeFilter = (filter: ValidatorFilter): void => { this.setState({ filter }); } diff --git a/packages/app-staking/src/index.css b/packages/app-staking/src/index.css index 1279b6c816..21b1fdcb9b 100644 --- a/packages/app-staking/src/index.css +++ b/packages/app-staking/src/index.css @@ -114,14 +114,3 @@ .staking--accounts-info .staking--label { margin: 0 2.25rem -0.75rem 0; } - -.ui--AddressSummary { - display: flex; - justify-content: space-between; - padding: 0; - - .ui--AddressSummary-base, - .ui--AddressSummary-children { - min-width: 0; - } -} diff --git a/packages/apps/webpack.config.js b/packages/apps/webpack.config.js index 26a199708d..b13e8b63b4 100644 --- a/packages/apps/webpack.config.js +++ b/packages/apps/webpack.config.js @@ -33,7 +33,7 @@ function createWebpack ({ alias = {}, context, name = 'index' }) { `./src/${name}.tsx`, isProd ? null - : 'webpack-plugin-serve/client' + : null // 'webpack-plugin-serve/client' ].filter((entry) => entry), mode: ENV, output: { diff --git a/packages/ui-app/src/AddressMini.tsx b/packages/ui-app/src/AddressMini.tsx index 80ffa02984..64e96727ce 100644 --- a/packages/ui-app/src/AddressMini.tsx +++ b/packages/ui-app/src/AddressMini.tsx @@ -90,7 +90,6 @@ export default class AddressMini extends React.PureComponent { return ( ); @@ -106,7 +105,6 @@ export default class AddressMini extends React.PureComponent { return ( diff --git a/packages/ui-app/src/AddressRow.tsx b/packages/ui-app/src/AddressRow.tsx index b4685d7d16..341df19a77 100644 --- a/packages/ui-app/src/AddressRow.tsx +++ b/packages/ui-app/src/AddressRow.tsx @@ -2,32 +2,110 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import { AccountId, AccountIndex, Address } from '@polkadot/types'; +import { I18nProps } from './types'; + +import BN from 'bn.js'; +import { Label } from 'semantic-ui-react'; import React from 'react'; -import { withCalls } from '@polkadot/ui-api'; +import styled from 'styled-components'; +import { withCalls, withMulti } from '@polkadot/ui-api'; +import { Button, Input, InputTags } from '@polkadot/ui-app'; +import BaseIdentityIcon from '@polkadot/ui-identicon'; +import keyring from '@polkadot/ui-keyring'; -import { classes } from './util'; -import { AddressSummary, Props } from './AddressSummary'; +import AddressInfo, { BalanceActiveType } from './AddressInfo'; +import CopyButton from './CopyButton'; +import IdentityIcon from './IdentityIcon'; +import LinkPolkascan from './LinkPolkascan'; import translate from './translate'; +import { classes, getAddrName, getAddrTags, toShortAddress } from './util'; -const DEFAULT_ICON_SIZE = 64; +export type Props = I18nProps & { + accounts_idAndIndex?: [AccountId?, AccountIndex?], + bonded?: BN | Array, + buttons?: React.ReactNode, + children?: React.ReactNode, + defaultName?: string, + extraInfo?: React.ReactNode, + isEditable?: boolean, + isInline?: boolean, + value: AccountId | AccountIndex | Address | string | null, + withBalance?: boolean | BalanceActiveType, + withExplorer?: boolean, + withIcon?: boolean, + withIndex?: boolean, + withTags?: boolean +}; + +type State = { + address: string, + isEditingName: boolean, + isEditingTags: boolean, + name: string, + tags: string[] +}; + +const DEFAULT_ADDR = '5'.padEnd(16, 'x'); +const ICON_SIZE = 48; + +class AddressRow extends React.PureComponent { + state: State; + + constructor (props: Props) { + super(props); + + this.state = this.createState(); + } + + static defaultProps = { + defaultName: '' + }; + + static getDerivedStateFromProps ({ accounts_idAndIndex = [], defaultName, value }: Props, prevState: State) { + const [_accountId] = accounts_idAndIndex; + const accountId = _accountId || value; + const address = accountId + ? accountId.toString() + : DEFAULT_ADDR; + const name = getAddrName(address, false, defaultName) || ''; + const tags = getAddrTags(address); + const state = { tags } as State; + let hasChanged = false; + + if (address !== prevState.address) { + state.address = address; + hasChanged = true; + } + + if (!prevState.isEditingName && name !== prevState.name) { + state.name = name; + hasChanged = true; + } + + return hasChanged + ? state + : null; + } -class AddressRow extends AddressSummary { render () { - const { className, style, identIconSize = DEFAULT_ICON_SIZE, isInline, value, withIndex } = this.props; + const { accounts_idAndIndex = [], className, isInline, style } = this.props; + const [accountId, accountIndex] = accounts_idAndIndex; + const isValid = accountId || accountIndex; return (
- {this.renderIcon('ui--AddressRow-icon', identIconSize)} + {this.renderIcon()} {this.renderButtons()}
-
+
{this.renderName()} {this.renderAddress()} - {this.renderAccountIndex(withIndex)} + {this.renderAccountIndex()}
{this.renderBalances()} {this.renderTags()} @@ -38,11 +116,450 @@ class AddressRow extends AddressSummary {
); } + + private createState () { + const { accounts_idAndIndex = [], defaultName, value } = this.props; + const [_accountId] = accounts_idAndIndex; + const accountId = _accountId || value; + const address = accountId + ? accountId.toString() + : DEFAULT_ADDR; + const name = getAddrName(address, false, defaultName) || ''; + const tags = getAddrTags(address); + + return { + address, + isEditingName: false, + isEditingTags: false, + name, + tags + }; + } + + protected renderAddress () { + const { address } = this.state; + + return ( +
+ + {toShortAddress(address)} + +
+ ); + } + + protected renderButtons () { + const { buttons } = this.props; + + return buttons + ?
{buttons}
+ : null; + } + + protected renderExplorer () { + const { value, withExplorer } = this.props; + + if (!withExplorer) { + return null; + } + + return ( +
+ +
+ ); + } + + protected renderName () { + const { isEditable } = this.props; + const { isEditingName, name } = this.state; + + return isEditingName + ? ( + + ) + : ( +
+ {name} + {isEditable && this.renderEditIcon()} +
+ ); + } + + protected onChangeName = (name: string) => { + this.setState({ name }); + } + + protected onChangeTags = (tags: string[]) => { + this.setState({ tags }); + } + + protected renderAccountIndex () { + const { accounts_idAndIndex = [], withIndex } = this.props; + const [, accountIndex] = accounts_idAndIndex; + + if (!accountIndex || !withIndex) { + return null; + } + + return ( +
+ {accountIndex.toString()} +
+ ); + } + + protected renderBalances () { + const { accounts_idAndIndex = [], withBalance } = this.props; + const [accountId] = accounts_idAndIndex; + + if (!withBalance || !accountId) { + return null; + } + + return ( +
+ +
+ ); + } + + protected renderChildren () { + const { children } = this.props; + // we need children, or when an array, at least 1 non-empty value + const hasChildren = !children + ? false + : Array.isArray(children) + ? children.filter((child) => child).length !== 0 + : true; + + if (!hasChildren) { + return null; + } + + return ( +
+ {children} +
+ ); + } + + protected renderEditIcon () { + return ( +