feat: support asset filter (#10423)
This commit is contained in:
parent
ad67bab70f
commit
3392970904
@ -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": "",
|
||||||
|
|||||||
@ -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": "可用的",
|
||||||
|
|||||||
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
55
packages/page-assets/src/Overview/Query.tsx
Normal file
55
packages/page-assets/src/Overview/Query.tsx
Normal 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);
|
||||||
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user