From 560048a0cdc4fefdab576c74730be14ec4e1ba67 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 9 Jan 2020 17:54:22 +0100 Subject: [PATCH] Filter accounts/addresses by tag or name (#2102) * Filter accounts/addresses by tag or name * Filter identity names (as available) * Adjust filter input label --- packages/app-accounts/src/Account.tsx | 32 ++++++++++++++++------ packages/app-accounts/src/Overview.tsx | 17 ++++++------ packages/app-address-book/src/Address.tsx | 32 ++++++++++++++++------ packages/app-address-book/src/Overview.tsx | 17 ++++++------ packages/react-components/src/Input.tsx | 4 ++- packages/react-components/src/Labelled.tsx | 13 +++++++-- 6 files changed, 78 insertions(+), 37 deletions(-) diff --git a/packages/app-accounts/src/Account.tsx b/packages/app-accounts/src/Account.tsx index 19bb4c5335..ec994c1691 100644 --- a/packages/app-accounts/src/Account.tsx +++ b/packages/app-accounts/src/Account.tsx @@ -2,13 +2,14 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import { DeriveAccountInfo } from '@polkadot/api-derive/types'; import { ActionStatus } from '@polkadot/react-components/Status/types'; import React, { useState, useEffect } from 'react'; import { Label } from 'semantic-ui-react'; import styled from 'styled-components'; import { AddressInfo, AddressSmall, Button, ChainLock, Forget, Icon, InputTags, LinkPolkascan, Menu, Popup, Input } from '@polkadot/react-components'; -import { useApi, useToggle } from '@polkadot/react-hooks'; +import { useApi, useCall, useToggle } from '@polkadot/react-hooks'; import keyring from '@polkadot/ui-keyring'; import Backup from './modals/Backup'; @@ -20,15 +21,16 @@ import { useTranslation } from './translate'; interface Props { address: string; - allowTags: string[]; className?: string; + filter: string; isFavorite: boolean; toggleFavorite: (address: string) => void; } -function Account ({ address, allowTags, className, isFavorite, toggleFavorite }: Props): React.ReactElement | null { +function Account ({ address, className, filter, isFavorite, toggleFavorite }: Props): React.ReactElement | null { const { t } = useTranslation(); const api = useApi(); + const info = useCall(api.api.derive.accounts.info as any, [address]); const [tags, setTags] = useState([]); const [accName, setAccName] = useState(''); const [genesisHash, setGenesisHash] = useState(null); @@ -46,6 +48,18 @@ function Account ({ address, allowTags, className, isFavorite, toggleFavorite }: const _setTags = (tags: string[]): void => setTags(tags.sort()); + useEffect((): void => { + const { identity, nickname } = info || {}; + + if (api.api.query.identity?.identityOf) { + if (identity?.display) { + setAccName(identity.display); + } + } else if (nickname) { + setAccName(nickname); + } + }, [info]); + useEffect((): void => { const account = keyring.getAccount(address); @@ -60,16 +74,18 @@ function Account ({ address, allowTags, className, isFavorite, toggleFavorite }: }, [address]); useEffect((): void => { - if (allowTags.length === 0) { + if (filter.length === 0) { setIsVisible(true); } else { + const _filter = filter.toLowerCase(); + setIsVisible( - allowTags.reduce((result: boolean, tag: string): boolean => { - return result || tags.includes(tag); - }, false) + tags.reduce((result: boolean, tag: string): boolean => { + return result || tag.toLowerCase().includes(_filter); + }, accName.toLowerCase().includes(_filter)) ); } - }, [allowTags, tags]); + }, [accName, filter, tags]); if (!isVisible) { return null; diff --git a/packages/app-accounts/src/Overview.tsx b/packages/app-accounts/src/Overview.tsx index da45251258..244bc1a286 100644 --- a/packages/app-accounts/src/Overview.tsx +++ b/packages/app-accounts/src/Overview.tsx @@ -9,7 +9,7 @@ import styled from 'styled-components'; import keyring from '@polkadot/ui-keyring'; import { getLedger, isLedger } from '@polkadot/react-api'; import { useAccounts, useFavorites } from '@polkadot/react-hooks'; -import { Button, InputTags, Table } from '@polkadot/react-components'; +import { Button, Input, Table } from '@polkadot/react-components'; import CreateModal from './modals/Create'; import ImportModal from './modals/Import'; @@ -43,7 +43,7 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement([]); - const [tags, setTags] = useState([]); + const [filter, setFilter] = useState(''); useEffect((): void => { setSortedAccounts( @@ -121,12 +121,11 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement
-
@@ -134,7 +133,7 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement ( void; } @@ -28,9 +29,10 @@ const WITH_EXTENDED = { nonce: true }; const isEditable = true; -function Address ({ address, allowTags, className, isFavorite, toggleFavorite }: Props): React.ReactElement | null { +function Address ({ address, className, filter, isFavorite, toggleFavorite }: Props): React.ReactElement | null { const { t } = useTranslation(); const api = useApi(); + const info = useCall(api.api.derive.accounts.info as any, [address]); const [tags, setTags] = useState([]); const [accName, setAccName] = useState(''); const [current, setCurrent] = useState(null); @@ -44,6 +46,18 @@ function Address ({ address, allowTags, className, isFavorite, toggleFavorite }: const _setTags = (tags: string[]): void => setTags(tags.sort()); + useEffect((): void => { + const { identity, nickname } = info || {}; + + if (api.api.query.identity?.identityOf) { + if (identity?.display) { + setAccName(identity.display); + } + } else if (nickname) { + setAccName(nickname); + } + }, [info]); + useEffect((): void => { const current = keyring.getAddress(address); @@ -59,16 +73,18 @@ function Address ({ address, allowTags, className, isFavorite, toggleFavorite }: }, [address]); useEffect((): void => { - if (allowTags.length === 0) { + if (filter.length === 0) { setIsVisible(true); } else { + const _filter = filter.toLowerCase(); + setIsVisible( - allowTags.reduce((result: boolean, tag: string): boolean => { - return result || tags.includes(tag); - }, false) + tags.reduce((result: boolean, tag: string): boolean => { + return result || tag.toLowerCase().includes(_filter); + }, accName.toLowerCase().includes(_filter)) ); } - }, [allowTags, tags]); + }, [accName, filter, tags]); if (!isVisible) { return null; diff --git a/packages/app-address-book/src/Overview.tsx b/packages/app-address-book/src/Overview.tsx index 9cc4269507..b0a52a4198 100644 --- a/packages/app-address-book/src/Overview.tsx +++ b/packages/app-address-book/src/Overview.tsx @@ -6,7 +6,7 @@ import { ComponentProps as Props } from './types'; import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; -import { Button, InputTags, Table } from '@polkadot/react-components'; +import { Button, Input, Table } from '@polkadot/react-components'; import { useAddresses, useFavorites } from '@polkadot/react-hooks'; import CreateModal from './modals/Create'; @@ -23,7 +23,7 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement([]); - const [tags, setTags] = useState([]); + const [filter, setFilter] = useState(''); useEffect((): void => { setSortedAddresses( @@ -61,12 +61,11 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement
-
@@ -74,7 +73,7 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement (
let counter = 0; -export default function Input ({ autoFocus = false, children, className, defaultValue, help, icon, isEditable = false, isAction = false, isDisabled = false, isError = false, isHidden = false, isReadOnly = false, label, labelExtra, max, maxLength, min, name, onBlur, onChange, onEnter, onEscape, onKeyDown, onKeyUp, onPaste, placeholder, style, tabIndex, type = 'text', value, withEllipsis, withLabel }: Props): React.ReactElement { +export default function Input ({ autoFocus = false, children, className, defaultValue, help, icon, isEditable = false, isAction = false, isDisabled = false, isError = false, isFull = false, isHidden = false, isReadOnly = false, label, labelExtra, max, maxLength, min, name, onBlur, onChange, onEnter, onEscape, onKeyDown, onKeyUp, onPaste, placeholder, style, tabIndex, type = 'text', value, withEllipsis, withLabel }: Props): React.ReactElement { const [stateName] = useState(`in_${counter++}_at_${Date.now()}`); const _onBlur = (): void => { @@ -120,6 +121,7 @@ export default function Input ({ autoFocus = false, children, className, default label { + left: 1.55rem; + } + } + .labelExtra { color: rgba(78, 78, 78, .85); font-weight: 100; @@ -123,7 +132,7 @@ const Wrapper = styled.div` } `; -export default function Labelled ({ className, children, help, isHidden, isOuter, isSmall, label = defaultLabel, labelExtra, style, withEllipsis, withLabel = true }: Props): React.ReactElement | null { +export default function Labelled ({ className, children, help, isFull, isHidden, isOuter, isSmall, label = defaultLabel, labelExtra, style, withEllipsis, withLabel = true }: Props): React.ReactElement | null { if (isHidden) { return null; } else if (!withLabel) { @@ -134,7 +143,7 @@ export default function Labelled ({ className, children, help, isHidden, isOuter return (