diff --git a/dashboard/src/components/Accountant.tsx b/dashboard/src/components/Accountant.tsx index b4035c01..9f4cfe6c 100644 --- a/dashboard/src/components/Accountant.tsx +++ b/dashboard/src/components/Accountant.tsx @@ -1,12 +1,14 @@ -import { ExpandMore } from '@mui/icons-material'; +import { ExpandMore, Search } from '@mui/icons-material'; import { Accordion, AccordionDetails, AccordionSummary, Box, Card, + InputAdornment, LinearProgress, Link, + TextField, Tooltip, Typography, } from '@mui/material'; @@ -14,11 +16,12 @@ import { SortingState, createColumnHelper, getCoreRowModel, + getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table'; -import { useMemo, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { CloudGovernorInfo } from '../hooks/useCloudGovernorInfo'; import useGetAccountantAccounts, { Account } from '../hooks/useGetAccountantAccounts'; import useGetAccountantPendingTransfers, { @@ -38,7 +41,7 @@ import numeral from 'numeral'; type PendingTransferForAcct = PendingTransfer & { isEnqueuedInGov: boolean }; type AccountWithTokenData = Account & { - tokenData?: TokenDataEntry; + tokenData: TokenDataEntry; tvlTvm: number; adjBalance: number; }; @@ -196,11 +199,13 @@ const accountsColumns = [ header: () => 'Chain', cell: (info) => `${chainIdToName(info.getValue())} (${info.getValue()})`, sortingFn: `text`, + enableGlobalFilter: false, }), accountsColumnHelper.accessor('key.token_chain', { header: () => 'Token Chain', cell: (info) => `${chainIdToName(info.getValue())} (${info.getValue()})`, sortingFn: `text`, + enableGlobalFilter: false, }), accountsColumnHelper.accessor('tokenData.native_address', { header: () => 'Native Address', @@ -211,9 +216,13 @@ const accountsColumns = [ accountsColumnHelper.accessor('tokenData.symbol', { header: () => 'Symbol', }), + accountsColumnHelper.accessor('tokenData.coin_gecko_coin_id', { + header: () => 'Coin Gecko ID', + }), accountsColumnHelper.accessor('tokenData.price_usd', { header: () => 'Price', cell: (info) => (info.getValue() ? numeral(info.getValue()).format('$0,0.0000') : ''), + enableGlobalFilter: false, }), accountsColumnHelper.accessor('adjBalance', { header: () => 'Adjusted Balance', @@ -221,6 +230,7 @@ const accountsColumns = [ info.getValue() < 1 ? info.getValue().toFixed(4) : numeral(info.getValue()).format('0,0.0000'), + enableGlobalFilter: false, }), accountsColumnHelper.accessor('tvlTvm', { header: () => 'TVL/TVM', @@ -228,15 +238,18 @@ const accountsColumns = [ info.getValue() < 1 ? `$${info.getValue().toFixed(4)}` : numeral(info.getValue()).format('$0,0.0000'), + enableGlobalFilter: false, }), accountsColumnHelper.accessor('tokenData.decimals', { header: () => 'Decimals', + enableGlobalFilter: false, }), accountsColumnHelper.accessor('key.token_address', { header: () => 'Token Address', }), accountsColumnHelper.accessor('balance', { header: () => 'Raw Balance', + enableGlobalFilter: false, }), ]; @@ -312,6 +325,16 @@ function Accountant({ governorInfo }: { governorInfo: CloudGovernorInfo }) { ...a, adjBalance: 0, tvlTvm: 0, + tokenData: { + coin_gecko_coin_id: '', + decimals: 0, + name: '', + native_address: '', + price_usd: '', + symbol: '', + token_address: '', + token_chain: 0, + }, }; const adjBalance = Number(a.balance) / 10 ** Math.min(thisTokenData.decimals, 8); const tvlTvm = adjBalance * Number(thisTokenData.price_usd); @@ -376,18 +399,25 @@ function Accountant({ governorInfo }: { governorInfo: CloudGovernorInfo }) { getSortedRowModel: getSortedRowModel(), onSortingChange: setOverviewSorting, }); + const [accountsGlobalFilter, setAccountsGlobalFilter] = useState(''); + const handleAccountsGlobalFilterChange = useCallback((e: any) => { + setAccountsGlobalFilter(e.target.value); + }, []); const [accountsSorting, setAccountsSorting] = useState([]); const accounts = useReactTable({ columns: accountsColumns, data: accountsWithTokenData, state: { + globalFilter: accountsGlobalFilter, sorting: accountsSorting, }, - getRowId: (key) => JSON.stringify(key), + getRowId: (token) => JSON.stringify(token.key), getCoreRowModel: getCoreRowModel(), - getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), autoResetPageIndex: false, + onGlobalFilterChange: setAccountsGlobalFilter, onSortingChange: setAccountsSorting, }); const pendingByChain = useMemo( @@ -483,7 +513,23 @@ function Accountant({ governorInfo }: { governorInfo: CloudGovernorInfo }) { Accounts ({accountsInfo.length}) - table={accounts} paginated /> + + + + ), + }} + placeholder="Search Token" + /> + table={accounts} paginated noWrap /> diff --git a/dashboard/src/components/Governor.tsx b/dashboard/src/components/Governor.tsx index 2b9a7253..892924c8 100644 --- a/dashboard/src/components/Governor.tsx +++ b/dashboard/src/components/Governor.tsx @@ -10,28 +10,31 @@ import { GovernorGetEnqueuedVAAsResponse_Entry, GovernorGetTokenListResponse_Entry, } from '@certusone/wormhole-sdk-proto-web/lib/cjs/publicrpc/v1/publicrpc'; -import { ExpandMore } from '@mui/icons-material'; +import { ExpandMore, Search } from '@mui/icons-material'; import { Accordion, AccordionDetails, AccordionSummary, Box, Card, + InputAdornment, LinearProgress, Link, + TextField, Tooltip, Typography, } from '@mui/material'; import { createColumnHelper, getCoreRowModel, + getFilteredRowModel, getPaginationRowModel, getSortedRowModel, SortingState, useReactTable, } from '@tanstack/react-table'; import numeral from 'numeral'; -import React, { useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import useGovernorInfo from '../hooks/useGovernorInfo'; import chainIdToName from '../utils/chainIdToName'; import { @@ -161,6 +164,7 @@ const tokenColumns = [ header: () => 'Chain', cell: (info) => `${chainIdToName(info.getValue())} (${info.getValue()})`, sortingFn: `text`, + enableGlobalFilter: false, }), tokenColumnHelper.accessor('originAddress', { header: () => 'Token', @@ -199,6 +203,7 @@ const tokenColumns = [ tokenColumnHelper.accessor('price', { header: () => Price, cell: (info) => ${numeral(info.getValue()).format('0,0.0000')}, + enableGlobalFilter: false, }), ]; @@ -267,16 +272,24 @@ function Governor() { getSortedRowModel: getSortedRowModel(), onSortingChange: setEnqueuedSorting, }); + const [tokenGlobalFilter, setTokenGlobalFilter] = useState(''); + const handleTokenGlobalFilterChange = useCallback((e: any) => { + setTokenGlobalFilter(e.target.value); + }, []); const [tokenSorting, setTokenSorting] = useState([]); const tokenTable = useReactTable({ columns: tokenColumns, data: displayTokens, state: { + globalFilter: tokenGlobalFilter, sorting: tokenSorting, }, getRowId: (token) => `${token.originChainId}_${token.originAddress}`, getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), + onGlobalFilterChange: setTokenGlobalFilter, onSortingChange: setTokenSorting, }); return ( @@ -350,6 +363,22 @@ function Governor() { Tokens ({governorInfo.tokens.length}) + + + + ), + }} + placeholder="Search Address" + /> table={tokenTable} /> diff --git a/dashboard/src/components/MainnetGovernor.tsx b/dashboard/src/components/MainnetGovernor.tsx index dea67007..842c67af 100644 --- a/dashboard/src/components/MainnetGovernor.tsx +++ b/dashboard/src/components/MainnetGovernor.tsx @@ -9,6 +9,7 @@ import { ExpandMore, KeyboardArrowDown, KeyboardArrowRight, + Search, WarningAmberOutlined, } from '@mui/icons-material'; import { @@ -18,8 +19,10 @@ import { Box, Card, IconButton, + InputAdornment, LinearProgress, Link, + TextField, Tooltip, Typography, } from '@mui/material'; @@ -29,12 +32,13 @@ import { createColumnHelper, getCoreRowModel, getExpandedRowModel, + getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table'; import numeral from 'numeral'; -import React, { useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { AvailableNotionalByChain, CloudGovernorInfo, @@ -254,6 +258,7 @@ const tokenColumns = [ header: () => 'Chain', cell: (info) => `${chainIdToName(info.getValue())} (${info.getValue()})`, sortingFn: `text`, + enableGlobalFilter: false, }), tokenColumnHelper.accessor('originAddress', { header: () => 'Token', @@ -291,6 +296,7 @@ const tokenColumns = [ tokenColumnHelper.accessor('price', { header: () => Price, cell: (info) => ${numeral(info.getValue()).format('0,0.0000')}, + enableGlobalFilter: false, }), ]; @@ -368,16 +374,24 @@ function MainnetGovernor({ governorInfo }: { governorInfo: CloudGovernorInfo }) getSortedRowModel: getSortedRowModel(), onSortingChange: setEnqueuedSorting, }); + const [tokenGlobalFilter, setTokenGlobalFilter] = useState(''); + const handleTokenGlobalFilterChange = useCallback((e: any) => { + setTokenGlobalFilter(e.target.value); + }, []); const [tokenSorting, setTokenSorting] = useState([]); const tokenTable = useReactTable({ columns: tokenColumns, data: displayTokens, state: { + globalFilter: tokenGlobalFilter, sorting: tokenSorting, }, getRowId: (token) => `${token.originChainId}_${token.originAddress}`, getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), + onGlobalFilterChange: setTokenGlobalFilter, onSortingChange: setTokenSorting, }); const enqueuedByChain: ChainIdToEnqueuedCount = useMemo( @@ -482,7 +496,23 @@ function MainnetGovernor({ governorInfo }: { governorInfo: CloudGovernorInfo }) Tokens ({governorInfo.tokens.length}) - table={tokenTable} /> + + + + ), + }} + placeholder="Search Address" + /> + table={tokenTable} paginated /> diff --git a/dashboard/src/components/Table.tsx b/dashboard/src/components/Table.tsx index abd96834..087dded2 100644 --- a/dashboard/src/components/Table.tsx +++ b/dashboard/src/components/Table.tsx @@ -27,77 +27,83 @@ import { flexRender, Table as TanTable } from '@tanstack/react-table'; function Table({ table, + noWrap = false, paginated = false, showRowCount = false, conditionalRowStyle, }: { table: TanTable; + noWrap?: boolean; paginated?: boolean; showRowCount?: boolean; conditionalRowStyle?: (a: T) => SxProps | undefined; }) { const theme = useTheme(); return ( - - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - - {header.isPlaceholder - ? null - : flexRender(header.column.columnDef.header, header.getContext())} - - - {{ - asc: , - desc: , - }[header.column.getIsSorted() as string] ?? null} + <> + + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + + {header.isPlaceholder + ? null + : flexRender(header.column.columnDef.header, header.getContext())} + + + {{ + asc: , + desc: , + }[header.column.getIsSorted() as string] ?? null} + - - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} - - ))} - - {paginated || showRowCount ? ( + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + ))} + + + + {paginated || showRowCount ? ( + - total + headerGroup.headers.length, 0)} - > + {table.getCoreRowModel().rows.length} Rows @@ -159,9 +165,9 @@ function Table({ - ) : null} - - + + ) : null} + ); } export default Table;