chore: make filter its own component

This commit is contained in:
Edd
2023-06-14 15:24:42 +01:00
parent 7f58fb7e23
commit b7ebc7ce12
5 changed files with 187 additions and 174 deletions
@@ -0,0 +1,181 @@
import { t } from '@vegaprotocol/i18n';
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuItemIndicator,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
Icon,
DropdownMenuSubContent,
} from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import type { Dispatch, SetStateAction } from 'react';
// All possible transaction types. Should be generated.
export type FilterOption =
| 'Amend LiquidityProvision Order'
| 'Amend Order'
| 'Batch Market Instructions'
| 'Cancel LiquidityProvision Order'
| 'Cancel Order'
| 'Cancel Transfer Funds'
| 'Chain Event'
| 'Delegate'
| 'Ethereum Key Rotate Submission'
| 'Issue Signatures'
| 'Key Rotate Submission'
| 'Liquidity Provision Order'
| 'Node Signature'
| 'Node Vote'
| 'Proposal'
| 'Protocol Upgrade'
| 'Register new Node'
| 'State Variable Proposal'
| 'Submit Oracle Data'
| 'Submit Order'
| 'Transfer Funds'
| 'Undelegate'
| 'Validator Heartbeat'
| 'Vote on Proposal'
| 'Withdraw';
// Alphabetised list of transaction types to appear at the top level
export const PrimaryFilterOptions: FilterOption[] = [
'Amend LiquidityProvision Order',
'Amend Order',
'Batch Market Instructions',
'Cancel LiquidityProvision Order',
'Cancel Order',
'Cancel Transfer Funds',
'Delegate',
'Liquidity Provision Order',
'Proposal',
'Submit Oracle Data',
'Submit Order',
'Transfer Funds',
'Undelegate',
'Vote on Proposal',
'Withdraw',
];
// Alphabetised list of transaction types to nest under a 'More...' submenu
export const SecondaryFilterOptions: FilterOption[] = [
'Chain Event',
'Ethereum Key Rotate Submission',
'Issue Signatures',
'Key Rotate Submission',
'Node Signature',
'Node Vote',
'Protocol Upgrade',
'Register new Node',
'State Variable Proposal',
'Validator Heartbeat',
];
export const AllFilterOptions: FilterOption[] = [
...PrimaryFilterOptions,
...SecondaryFilterOptions,
];
export function getFilterLabel(filters: Set<string>) {
if (!filters || filters.size !== 1) {
return <span>{t('Filter')}</span>;
}
return (
<span>
{t('Filters')}: <code>{Array.from(filters)[0]}</code>
</span>
);
}
// Effectively a copy & paste of the Vega DropdownMenuItem styles
const itemClass = classNames(
'relative flex gap-2 items-center rounded-sm p-2 text-sm',
'cursor-default',
'hover:bg-white dark:hover:bg-vega-dark-200',
'focus:bg-white dark:focus:bg-vega-dark-200',
'select-none',
'whitespace-nowrap'
);
export interface TxFilterProps {
filters: Set<FilterOption>;
setFilters: Dispatch<SetStateAction<Set<FilterOption>>>;
}
/**
* Renders a structured dropdown menu of all of the available transaction
* types. It allows a user to select one transaction type to view. Later
* it will support multiple selection, but until the API supports that it is
* one or all.
* @param filters null or Set of tranaction types
* @param setFilters A function to update the filters prop
* @returns
*/
export const TxsFilter = ({ filters, setFilters }: TxFilterProps) => {
return (
<DropdownMenu
modal={false}
trigger={
<DropdownMenuTrigger>{getFilterLabel(filters)}</DropdownMenuTrigger>
}
>
<DropdownMenuContent>
{filters.size > 1 ? null : (
<>
<DropdownMenuCheckboxItem
onCheckedChange={() => setFilters(new Set(AllFilterOptions))}
>
{t('Clear filters')} <Icon name="cross" />
</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
</>
)}
{PrimaryFilterOptions.map((f) => (
<DropdownMenuCheckboxItem
key={f}
checked={filters.has(f)}
onCheckedChange={() => {
// NOTE: These act like radio buttons until the API supports multiple filters
setFilters(new Set([f]));
}}
id={`radio-${f}`}
>
{f}
<DropdownMenuItemIndicator>
<Icon name="tick-circle" />
</DropdownMenuItemIndicator>
</DropdownMenuCheckboxItem>
))}
<DropdownMenuSub>
<DropdownMenuSubTrigger className={itemClass}>
{t('More Types')}
<Icon name="chevron-right" />
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
{SecondaryFilterOptions.map((f) => (
<DropdownMenuCheckboxItem
key={f}
checked={filters.has(f)}
onCheckedChange={(checked) => {
// NOTE: These act like radio buttons until the API supports multiple filters
setFilters(new Set([f]));
}}
id={`radio-${f}`}
>
{f}
<DropdownMenuItemIndicator>
<Icon name="tick-circle" className="inline" />
</DropdownMenuItemIndicator>
</DropdownMenuCheckboxItem>
))}
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>
);
};
@@ -40,7 +40,6 @@ describe('Txs infinite list', () => {
it('should display a "no items" message when no items provided', () => {
render(
<TxsInfiniteList
filters=""
txs={undefined}
areTxsLoading={false}
hasMoreTxs={false}
@@ -58,7 +57,6 @@ describe('Txs infinite list', () => {
const txs = generateTxs(1);
render(
<TxsInfiniteList
filters=""
txs={txs}
areTxsLoading={false}
hasMoreTxs={false}
@@ -76,7 +74,6 @@ describe('Txs infinite list', () => {
render(
<MemoryRouter>
<TxsInfiniteList
filters=""
txs={txs}
areTxsLoading={false}
hasMoreTxs={false}
@@ -102,7 +99,6 @@ describe('Txs infinite list', () => {
render(
<MemoryRouter>
<TxsInfiniteList
filters=""
txs={txs}
areTxsLoading={false}
hasMoreTxs={true}
@@ -122,7 +118,6 @@ describe('Txs infinite list', () => {
render(
<MemoryRouter>
<TxsInfiniteList
filters=""
txs={txs}
areTxsLoading={false}
hasMoreTxs={false}
@@ -142,7 +137,6 @@ describe('Txs infinite list', () => {
render(
<MemoryRouter>
<TxsInfiniteList
filters=""
txs={txs}
areTxsLoading={false}
hasMoreTxs={true}
@@ -9,7 +9,6 @@ import EmptyList from '../empty-list/empty-list';
import { Loader } from '@vegaprotocol/ui-toolkit';
interface TxsInfiniteListProps {
filters: string;
hasMoreTxs: boolean;
areTxsLoading: boolean | undefined;
txs: BlockExplorerTransactionResult[] | undefined;
@@ -61,7 +60,6 @@ const Item = ({ index, style, isLoading, error }: ItemProps) => {
};
export const TxsInfiniteList = ({
filters,
hasMoreTxs,
areTxsLoading,
txs,
@@ -75,15 +73,13 @@ export const TxsInfiniteList = ({
const hasMountedRef = useRef(false);
useEffect(() => {
// We only need to reset cached items when "sortOrder" changes.
// This effect will run on mount too; there's no need to reset in that case.
if (hasMountedRef.current) {
if (infiniteLoaderRef.current) {
infiniteLoaderRef.current.resetloadMoreItemsCache(true);
}
}
hasMountedRef.current = true;
}, [filters]);
}, [loadMoreTxs]);
if (!txs) {
if (!areTxsLoading) {
@@ -98,8 +94,6 @@ export const TxsInfiniteList = ({
}
}
console.dir(txs);
// If there are more items to be loaded then add an extra row to hold a loading indicator.
const itemCount = hasMoreTxs ? txs.length + 1 : txs.length;
@@ -83,7 +83,6 @@ const Party = () => {
<SubHeading>{t('Transactions')}</SubHeading>
{!error && txsData ? (
<TxsInfiniteList
filters={'all'}
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}
txs={txsData}
+5 -160
View File
@@ -4,107 +4,12 @@ import { BlocksRefetch } from '../../../components/blocks';
import { TxsInfiniteList } from '../../../components/txs';
import { useTxsData } from '../../../hooks/use-txs-data';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuItemIndicator,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
Icon,
DropdownMenuSubContent,
} from '@vegaprotocol/ui-toolkit';
import { useState } from 'react';
import classNames from 'classnames';
import { AllFilterOptions, TxsFilter } from '../../../components/txs/tx-filter';
const BE_TXS_PER_REQUEST = 15;
type FilterOption =
| 'Amend LiquidityProvision Order'
| 'Amend Order'
| 'Batch Market Instructions'
| 'Cancel LiquidityProvision Order'
| 'Cancel Order'
| 'Cancel Transfer Funds'
| 'Chain Event'
| 'Delegate'
| 'Ethereum Key Rotate Submission'
| 'Issue Signatures'
| 'Key Rotate Submission'
| 'Liquidity Provision Order'
| 'Node Signature'
| 'Node Vote'
| 'Proposal'
| 'Protocol Upgrade'
| 'Register new Node'
| 'State Variable Proposal'
| 'Submit Oracle Data'
| 'Submit Order'
| 'Transfer Funds'
| 'Undelegate'
| 'Validator Heartbeat'
| 'Vote on Proposal'
| 'Withdraw';
const PrimaryFilterOptions: FilterOption[] = [
'Amend LiquidityProvision Order',
'Amend Order',
'Batch Market Instructions',
'Cancel LiquidityProvision Order',
'Cancel Order',
'Cancel Transfer Funds',
'Delegate',
'Liquidity Provision Order',
'Proposal',
'Submit Oracle Data',
'Submit Order',
'Transfer Funds',
'Undelegate',
'Vote on Proposal',
'Withdraw',
];
const SecondaryFilterOptions: FilterOption[] = [
'Chain Event',
'Ethereum Key Rotate Submission',
'Issue Signatures',
'Key Rotate Submission',
'Node Signature',
'Node Vote',
'Protocol Upgrade',
'Register new Node',
'State Variable Proposal',
'Validator Heartbeat',
];
const AllFilterOptions: FilterOption[] = [
...PrimaryFilterOptions,
...SecondaryFilterOptions,
];
const itemClass = classNames(
'relative flex gap-2 items-center rounded-sm p-2 text-sm',
'cursor-default',
'hover:bg-white dark:hover:bg-vega-dark-200',
'focus:bg-white dark:focus:bg-vega-dark-200',
'select-none',
'whitespace-nowrap'
);
export function getFilterLabel(filters: Set<string>) {
if (!filters || filters.size !== 1) {
return <span>Filter</span>;
}
return (
<span>
Filters: <code>{Array.from(filters)[0]}</code>
</span>
);
}
export const TxsList = () => {
useDocumentTitle(['Transactions']);
@@ -123,6 +28,7 @@ export const TxsListFiltered = () => {
filters && filters.size === 1
? `filters[cmd.type]=${Array.from(filters)[0]}`
: '';
const { hasMoreTxs, loadTxs, error, txsData, refreshTxs, loading } =
useTxsData({
limit: BE_TXS_PER_REQUEST,
@@ -133,71 +39,10 @@ export const TxsListFiltered = () => {
<>
<menu className="mb-2">
<BlocksRefetch refetch={refreshTxs} />
<DropdownMenu
modal={false}
trigger={
<DropdownMenuTrigger>{getFilterLabel(filters)}</DropdownMenuTrigger>
}
>
<DropdownMenuContent>
{filters.size > 1 ? null : (
<>
<DropdownMenuCheckboxItem
onCheckedChange={(checked) =>
setFilters(new Set(AllFilterOptions))
}
>
Clear filters <Icon name="cross" />
</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
</>
)}
{PrimaryFilterOptions.map((f) => (
<DropdownMenuCheckboxItem
key={f}
checked={filters.has(f)}
onCheckedChange={(checked) => {
// NOTE: These act like radio buttons until the API supports multiple filters
setFilters(new Set([f]));
}}
id={`radio-${f}`}
>
{f}
<DropdownMenuItemIndicator>
<Icon name="tick-circle" />
</DropdownMenuItemIndicator>
</DropdownMenuCheckboxItem>
))}
<DropdownMenuSub>
<DropdownMenuSubTrigger className={itemClass}>
More Types
<Icon name="chevron-right" />
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
{SecondaryFilterOptions.map((f) => (
<DropdownMenuCheckboxItem
key={f}
checked={filters.has(f)}
onCheckedChange={(checked) => {
// NOTE: These act like radio buttons until the API supports multiple filters
setFilters(new Set([f]));
}}
id={`radio-${f}`}
>
{f}
<DropdownMenuItemIndicator>
<Icon name="tick-circle" className="inline" />
</DropdownMenuItemIndicator>
</DropdownMenuCheckboxItem>
))}
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuContent>
</DropdownMenu>
<TxsFilter filters={filters} setFilters={setFilters} />
</menu>
<TxsInfiniteList
filters={f}
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}
txs={txsData}