feat: support asset filter (#10423)

This commit is contained in:
Levi 2024-04-04 22:20:55 +08:00 committed by GitHub
parent ad67bab70f
commit 3392970904
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 81 additions and 7 deletions

View File

@ -1145,6 +1145,7 @@
"approval / {{percent}}%": "", "approval / {{percent}}%": "",
"approval type": "", "approval type": "",
"approved": "", "approved": "",
"asset id or name to query": "",
"asset decimals": "", "asset decimals": "",
"asset id": "", "asset id": "",
"asset name": "", "asset name": "",

View File

@ -925,6 +925,7 @@
"amount to use for estimation": "用于估算的金额", "amount to use for estimation": "用于估算的金额",
"approval type": "批准类型", "approval type": "批准类型",
"approved": "已赞成", "approved": "已赞成",
"asset id or name to query": "要查询的资产id或名称",
"asset id": "资产 id", "asset id": "资产 id",
"auto-selected targets for nomination": "自动选择的提名对象", "auto-selected targets for nomination": "自动选择的提名对象",
"available": "可用的", "available": "可用的",

View File

@ -1,9 +1,10 @@
// Copyright 2017-2024 @polkadot/app-assets authors & contributors // Copyright 2017-2024 @polkadot/app-assets authors & contributors
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import type { DropdownItemProps } from 'semantic-ui-react';
import type { AssetInfo, AssetInfoComplete } from '../types.js'; import type { AssetInfo, AssetInfoComplete } from '../types.js';
import React, { useEffect, useMemo, useRef, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Dropdown, styled, Table } from '@polkadot/react-components'; import { Dropdown, styled, Table } from '@polkadot/react-components';
import { formatNumber } from '@polkadot/util'; import { formatNumber } from '@polkadot/util';
@ -39,9 +40,9 @@ function Balances ({ className, infos = [] }: Props): React.ReactElement<Props>
); );
const assetOptions = useMemo( const assetOptions = useMemo(
() => completeInfos.map(({ id, metadata }, index) => ({ () => completeInfos.map(({ id, metadata }) => ({
text: `${metadata.name.toUtf8()} (${formatNumber(id)})`, text: `${metadata.name.toUtf8()} (${formatNumber(id)})`,
value: index value: id.toNumber()
})), })),
[completeInfos] [completeInfos]
); );
@ -53,10 +54,20 @@ function Balances ({ className, infos = [] }: Props): React.ReactElement<Props>
[info] [info]
); );
const onSearch = useCallback(
(options: DropdownItemProps[], value: string): DropdownItemProps[] =>
options.filter((options) => {
const { text: optText, value: optValue } = options as { text: string, value: number };
return parseInt(value) === optValue || optText.includes(value);
}),
[]
);
useEffect((): void => { useEffect((): void => {
setInfo(() => setInfo(() =>
infoIndex >= 0 && infoIndex < completeInfos.length infoIndex >= 0
? completeInfos[infoIndex] ? completeInfos.find(({ id }) => id.toNumber() === infoIndex) ?? null
: null : null
); );
}, [completeInfos, infoIndex]); }, [completeInfos, infoIndex]);
@ -71,6 +82,7 @@ function Balances ({ className, infos = [] }: Props): React.ReactElement<Props>
isFull isFull
label={t('the asset to query for balances')} label={t('the asset to query for balances')}
onChange={setInfoIndex} onChange={setInfoIndex}
onSearch={onSearch}
options={assetOptions} options={assetOptions}
value={infoIndex} value={infoIndex}
/> />

View File

@ -0,0 +1,55 @@
// Copyright 2017-2024 @polkadot/app-explorer authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React, { useCallback, useState } from 'react';
import { Button, FilterOverlay, Input, styled } from '@polkadot/react-components';
import { useTranslation } from '../translate.js';
interface Props {
className?: string;
onQuery?: (value: string) => void;
}
function Query ({ className = '', onQuery }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [input, setInput] = useState('');
const _onChange = useCallback(
(value: string): void => setInput(value),
[]
);
const _onQuery = useCallback(
(): void => {
onQuery && onQuery(input);
},
[input, onQuery]
);
return (
<StyledFilterOverlay className={`${className} ui--FilterOverlay hasOwnMaxWidth`}>
<Input
className='asset--query'
onChange={_onChange}
onEnter={_onQuery}
placeholder={t('asset id or name to query')}
withLabel={false}
>
<Button
icon='play'
onClick={_onQuery}
/>
</Input>
</StyledFilterOverlay>
);
}
const StyledFilterOverlay = styled(FilterOverlay)`
.asset--query {
width: 20em;
}
`;
export default React.memo(Query);

View File

@ -4,12 +4,13 @@
import type { BN } from '@polkadot/util'; import type { BN } from '@polkadot/util';
import type { AssetInfo } from '../types.js'; import type { AssetInfo } from '../types.js';
import React from 'react'; import React, { useState } from 'react';
import { Button } from '@polkadot/react-components'; import { Button } from '@polkadot/react-components';
import Create from './Create/index.js'; import Create from './Create/index.js';
import Assets from './Assets.js'; import Assets from './Assets.js';
import Query from './Query.js';
import Summary from './Summary.js'; import Summary from './Summary.js';
interface Props { interface Props {
@ -20,16 +21,20 @@ interface Props {
} }
function Overview ({ className, ids, infos, openId }: Props): React.ReactElement<Props> { function Overview ({ className, ids, infos, openId }: Props): React.ReactElement<Props> {
const [keyword, setKeyword] = useState('');
const filteredInfos = keyword ? infos?.filter(({ key, metadata }) => key === keyword || metadata?.name.toUtf8().includes(keyword)) : infos;
return ( return (
<div className={className}> <div className={className}>
<Summary numAssets={ids?.length} /> <Summary numAssets={ids?.length} />
<Query onQuery={setKeyword} />
<Button.Group> <Button.Group>
<Create <Create
assetIds={ids} assetIds={ids}
openId={openId} openId={openId}
/> />
</Button.Group> </Button.Group>
<Assets infos={infos} /> <Assets infos={filteredInfos} />
</div> </div>
); );
} }