Improve Address Book Search (#11350)

* fix: improve address filtering logic for better visibility control

* feat: add visibility toggle for addresses in the contacts overview

* feat: enhance account name resolution with custom matchers
This commit is contained in:
Arjun Porwal 2025-03-03 18:10:49 +05:30 committed by GitHub
parent db87ec3c83
commit e9de252577
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 25 deletions

View File

@ -8,6 +8,7 @@ import type { HexString } from '@polkadot/util/types';
import React, { useCallback, useEffect, useState } from 'react';
import { AddressInfo, AddressSmall, Button, ChainLock, Columar, Forget, LinkExternal, Menu, Popup, Table, Tags, TransferModal } from '@polkadot/react-components';
import { MATCHERS } from '@polkadot/react-components/AccountName';
import { useApi, useBalancesAll, useDeriveAccountInfo, useToggle } from '@polkadot/react-hooks';
import { keyring } from '@polkadot/ui-keyring';
import { isFunction } from '@polkadot/util';
@ -19,7 +20,9 @@ interface Props {
className?: string;
filter: string;
isFavorite: boolean;
isVisible: boolean;
toggleFavorite: (address: string) => void;
toggleVisible: (address: string, isVisible: boolean) => void
}
const isEditable = true;
@ -47,7 +50,7 @@ const BAL_OPTS_EXPANDED = {
vested: true
};
function Address ({ address, className = '', filter, isFavorite, toggleFavorite }: Props): React.ReactElement<Props> | null {
function Address ({ address, className = '', filter, isFavorite, isVisible, toggleFavorite, toggleVisible }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const api = useApi();
const info = useDeriveAccountInfo(address);
@ -58,7 +61,6 @@ function Address ({ address, className = '', filter, isFavorite, toggleFavorite
const [genesisHash, setGenesisHash] = useState<string | null>(null);
const [isForgetOpen, setIsForgetOpen] = useState(false);
const [isTransferOpen, setIsTransferOpen] = useState(false);
const [isVisible, setIsVisible] = useState(true);
const [isExpanded, toggleIsExpanded] = useToggle(false);
const _setTags = useCallback(
@ -75,16 +77,26 @@ function Address ({ address, className = '', filter, isFavorite, toggleFavorite
}, []);
useEffect((): void => {
const { identity, nickname } = info || {};
let known: string | null = null;
if (isFunction(api.apiIdentity.query.identity?.identityOf)) {
if (identity?.display) {
setAccName(identity.display);
}
} else if (nickname) {
setAccName(nickname);
for (let i = 0; known === null && i < MATCHERS.length; i++) {
known = MATCHERS[i](address);
}
}, [api, info]);
if (known) {
setAccName(known);
} else {
const { identity, nickname } = info || {};
if (isFunction(api.apiIdentity.query.identity?.identityOf)) {
if (identity?.display) {
setAccName(identity.display);
}
} else if (nickname) {
setAccName(nickname);
}
}
}, [address, api, info]);
useEffect((): void => {
const account = keyring.getAddress(address);
@ -94,18 +106,19 @@ function Address ({ address, className = '', filter, isFavorite, toggleFavorite
}, [_setTags, address]);
useEffect((): void => {
if (filter.length === 0) {
setIsVisible(true);
} else {
const _filter = filter.toLowerCase();
const _filter = filter.trim().toLowerCase();
let isVisible = true;
setIsVisible(
tags.reduce((result: boolean, tag: string): boolean => {
return result || tag.toLowerCase().includes(_filter);
}, accName.toLowerCase().includes(_filter))
);
if (_filter.length !== 0) {
isVisible = keyring.encodeAddress(address, 0).toLowerCase().includes(_filter) ||
address.toLowerCase().includes(_filter) ||
tags.reduce((result: boolean, tag: string): boolean => {
return result || tag.toLowerCase().includes(_filter);
}, accName.toLowerCase().includes(_filter));
}
}, [accName, filter, tags]);
toggleVisible(address, isVisible);
}, [accName, address, filter, tags, toggleVisible]);
const _onGenesisChange = useCallback(
(genesisHash: HexString | null): void => {

View File

@ -3,7 +3,7 @@
import type { ActionStatus } from '@polkadot/react-components/Status/types';
import React, { useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Button, FilterInput, styled, SummaryBox, Table } from '@polkadot/react-components';
import { useAddresses, useFavorites, useNextTick, useToggle } from '@polkadot/react-hooks';
@ -12,7 +12,7 @@ import CreateModal from '../modals/Create.js';
import { useTranslation } from '../translate.js';
import Address from './Address.js';
interface SortedAddress { address: string; isFavorite: boolean }
interface SortedAddress { address: string; isFavorite: boolean, isVisible: boolean }
interface Props {
className?: string;
@ -37,7 +37,7 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen
useEffect((): void => {
setSortedAddresses(
allAddresses
.map((address): SortedAddress => ({ address, isFavorite: favorites.includes(address) }))
.map((address): SortedAddress => ({ address, isFavorite: favorites.includes(address), isVisible: true }))
.sort((a, b): number =>
a.isFavorite === b.isFavorite
? 0
@ -48,6 +48,13 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen
);
}, [allAddresses, favorites]);
const toggleVisible = useCallback((address: string, isVisible: boolean) => {
setSortedAddresses((account) => account
?.map((e) => e.address === address ? { ...e, isVisible } : e)
.sort((a, b) => a.isVisible === b.isVisible ? 0 : b.isVisible ? 1 : -1)
);
}, []);
return (
<StyledDiv className={className}>
{isCreateOpen && (
@ -78,13 +85,15 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen
header={headerRef.current}
isSplit
>
{isNextTick && sortedAddresses?.map(({ address, isFavorite }): React.ReactNode => (
{isNextTick && sortedAddresses?.map(({ address, isFavorite, isVisible }): React.ReactNode => (
<Address
address={address}
filter={filterOn}
isFavorite={isFavorite}
isVisible={isVisible}
key={address}
toggleFavorite={toggleFavorite}
toggleVisible={toggleVisible}
/>
))}
</Table>

View File

@ -64,7 +64,7 @@ function createNumMatcher (prefix: string, name: string, add?: string): AddrMatc
};
}
const MATCHERS: AddrMatcher[] = [
export const MATCHERS: AddrMatcher[] = [
createAllMatcher('modlpy/socie', 'Society'),
createAllMatcher('modlpy/trsry', 'Treasury'),
createAllMatcher('modlpy/xcmch', 'XCM'),