Skip to content

Commit

Permalink
Added dropdown selector to show incomplete channels
Browse files Browse the repository at this point in the history
  • Loading branch information
mvpoyatt committed Sep 4, 2024
1 parent 3215328 commit 050fc64
Show file tree
Hide file tree
Showing 14 changed files with 288 additions and 123 deletions.
27 changes: 26 additions & 1 deletion app/(routes)/channels/channel-details.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { IdentifiedChannel, stateToString } from 'utils/types/channel';
import { LinkAndCopy } from 'components/link-and-copy';
import { CHAIN_CONFIGS, CHAIN } from 'utils/chains/configs';
import { Chain } from 'utils/types/chain';

export function ChannelDetails(channel: IdentifiedChannel | null) {
const [sourceChain, setSourceChain] = useState<Chain | undefined>();

useEffect(() => {
for (const chain of Object.keys(CHAIN_CONFIGS)) {
const chainName = chain as CHAIN;
const chainVals = CHAIN_CONFIGS[chainName];
if (channel?.portId?.toLowerCase().includes(chain)) {
setSourceChain(chainVals);
}
}
}, [channel]);

return !channel ? (
<>
<h2 className="mt-1 mb-2 mr-8">No Results</h2>
Expand All @@ -21,6 +36,11 @@ export function ChannelDetails(channel: IdentifiedChannel | null) {
<p className="font-mono text-[17px]/[24px]">{ stateToString(channel.state) }</p>
</div>
<Divider />
<div className="flex flex-row justify-between">
<p className="mr-8 font-medium">Create Time</p>
{channel.createTime && <p className="font-mono text-[17px]/[24px]">{new Date(channel.createTime*1000).toLocaleString()}</p>}
</div>
<Divider />
<div className="flex flex-row justify-between">
<p className="mr-8 font-medium">Counterparty Channel ID</p>
<p className="font-mono text-[17px]/[24px]">{ channel.counterparty.channelId }</p>
Expand All @@ -40,6 +60,11 @@ export function ChannelDetails(channel: IdentifiedChannel | null) {
<p className="mr-8 font-medium">Connection Hops</p>
<p className="font-mono text-[17px]/[24px]">{ channel.connectionHops[0] }, { channel.connectionHops[1] }</p>
</div>
<Divider />
<div className="flex flex-row justify-between">
<p className="mr-8 font-medium">Tx Hash</p>
<LinkAndCopy url={sourceChain?.txUrl} path="tx" hex={channel.transactionHash} />
</div>
</div>
</div>
);
Expand Down
125 changes: 106 additions & 19 deletions app/(routes)/channels/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ import {
useReactTable,
VisibilityState
} from '@tanstack/react-table';
import { Table } from 'components/table';
import { IdentifiedChannel, stateToString } from 'utils/types/channel';
import {
Table,
Modal,
StateCell,
ChainCell,
Arrow,
formatPortId,
formatConnectionHops,
FilterButton,
Select,
shortenHex
} from 'components';
import { ChannelDetails } from './channel-details';
import { Modal } from 'components/modal';
import { StateCell } from 'components/state-cell';
import { ChainCell, Arrow } from 'components/chain-cell';
import { formatPortId, formatConnectionHops } from 'components/format-strings';
import { IdentifiedChannel, stateToString } from 'utils/types/channel';
import { classNames } from 'utils/functions';
const { shuffle } = require('txt-shuffle');

const columnHelper = createColumnHelper<IdentifiedChannel>();
Expand All @@ -39,7 +47,7 @@ const columns = [
id: 'sourceClient',
cell: props => (
<div className="flex flex-row justify-between">
<div className="ml-4"><ChainCell chain={props.getValue()} /></div>
<div className="ml-2.5"><ChainCell chain={props.getValue()} /></div>
<Arrow />
</div>
),
Expand All @@ -51,7 +59,7 @@ const columns = [
id: 'destClient',
cell: props => (
<div className="flex flex-row justify-between">
<div className="ml-5"><ChainCell chain={props.getValue()} /></div>
<div className="ml-3"><ChainCell chain={props.getValue()} /></div>
</div>
),
enableColumnFilter: true,
Expand All @@ -75,6 +83,18 @@ const columns = [
header: 'Connection Hops',
id: 'connectionHops',
enableHiding: true
}),
columnHelper.accessor('createTime', {
header: 'Create Time',
enableHiding: true,
cell: props => new Date((props.getValue() || 0) * 1000).toLocaleString(),
enableColumnFilter: false
}),
columnHelper.accessor('transactionHash', {
header: 'Transaction Hash',
cell: props => shortenHex(props.getValue()),
enableHiding: true,
enableSorting: true
})
];

Expand All @@ -86,13 +106,18 @@ export default function Channels() {
const [searchId, setSearchId] = useState<string>('');
const [channelSearch, setChannelSearch] = useState(false);
const [foundChannel, setFoundChannel] = useState<IdentifiedChannel | null>(null);
const [showFilters, setShowFilters] = useState(false);
const [showInProgressChannels, setShowInProgressChannels] = useState(false);
const [pageNumber, setPageNumber] = useState(1);
const [loading, setLoading] = useState(true);
const [searchLoading, setSearchLoading] = useState(false);
const [error, setError] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
'connectionHops': false,
'counterparty_portId': false,
'createTime': false,
'transactionHash': false
});
const [sorting, setSorting] = useState<SortingState>([{
id: 'channelId',
Expand All @@ -101,8 +126,24 @@ export default function Channels() {

useEffect(() => {
loadData();
updateHeader('Universal Channels');
// Check if url contains a channelId to load by default
const searchParams = new URLSearchParams(window.location.search);
const channelId = searchParams.get('channelId');
if (channelId) {
searchChannels(channelId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
loadData(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageNumber]);

function updateHeader(newHeader: string) {
shuffle({
text: 'Universal Channels',
text: newHeader,
fps: 20,
delayResolve: 0,
direction: 'right',
Expand All @@ -111,18 +152,24 @@ export default function Channels() {
duration: 1,
onUpdate: (output: string) => {setHeader(output);}
});
// Check if url contains a channelId to load by default
const searchParams = new URLSearchParams(window.location.search);
const channelId = searchParams.get('channelId');
if (channelId) {
searchChannels(channelId);
}

function updateChannelType(channelType: string) {
loadData(channelType === 'in-progress');
if (channelType === 'universal') {
setShowInProgressChannels(false);
updateHeader('Universal Channels');
} else if (channelType === 'in-progress') {
updateHeader('In-Progress Channels');
setShowInProgressChannels(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}

function loadData() {
function loadData(inProgress = false) {
setLoading(true);
fetch('/api/channels')
const offset = (pageNumber - 1) * PAGE_SIZE;

fetch(`/api/channels${inProgress ? `?inProgress=true&offset=${offset}&limit=${PAGE_SIZE}` : ''}`)
.then(res => {
if (!res.ok) {
console.error(res.status);
Expand Down Expand Up @@ -235,13 +282,53 @@ export default function Channels() {
onClick={() => searchChannels(searchId)}>
Search
</button>
<FilterButton open={showFilters} setOpen={setShowFilters} />
</div>
<button onClick={() => loadData()} className="btn">
Reload
</button>
</div>

<Table {...{table, loading, rowDetails: ChannelDetails, pageLimit: PAGE_SIZE}} />
<div
className={classNames(
showFilters
? 'h-14 duration-100'
: 'h-0 duration-100 delay-100'
, 'w-full transition-all ease-in-out'
)}>
<div
className={classNames(
showFilters
? 'opacity-100 duration-100 delay-100'
: 'opacity-0 duration-100'
, 'relative flex flex-row space-x-4 items-center w-full mx-auto pt-4 transition-all ease-in-out'
)}>

<Select
options={
[
{value: 'universal', label: 'Universal'},
{value: 'in-progress', label: 'In-Progress'}
]
}
onChange={value => updateChannelType(value as string)}
containerClassName="w-36"
buttonClassName="inpt pl-4 cursor-default"
dropdownClassName="bg-vapor dark:bg-black"
/>
</div>
</div>

{showInProgressChannels ? (
// Only do server-side pagination when fetching in-progress channels
<Table {...{
table, loading, rowDetails: ChannelDetails, pageLimit: PAGE_SIZE, pageNumber, setPageNumber
}} />
) : (
<Table {...{
table, loading, rowDetails: ChannelDetails, pageLimit: PAGE_SIZE
}} />
)}
</div>
);
}
2 changes: 1 addition & 1 deletion app/(routes)/clients/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const columns = [
id: 'chain',
cell: props => (
<div className="">
<div className="ml-5"><ChainCell chain={props.getValue()} /></div>
<div className="ml-2.5"><ChainCell chain={props.getValue()} /></div>
</div>
),
enableHiding: true
Expand Down
36 changes: 5 additions & 31 deletions app/(routes)/packets/packet-details.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Link from 'next/link';
import { Packet, PacketStates, stateToString } from 'utils/types/packet';
import { CHAIN_CONFIGS, CHAIN, clientToDisplay } from 'utils/chains/configs';
import { Chain } from 'utils/types/chain';
import { classNames, numberWithCommas } from 'utils/functions';
import { CopyButton } from 'components/copy-button';
import { LinkAndCopy } from 'components/link-and-copy';
import { ethers } from 'ethers';
import { useEffect, useState } from 'react';

Expand Down Expand Up @@ -145,17 +144,17 @@ export function PacketDetails(packet: Packet | null) {
{/* Links */}
<div className="flex flex-row justify-between">
<p className="mr-8 font-medium">Source Port Address</p>
{linkAndCopy(sourceChain?.txUrl || '', 'address', packet.sourcePortAddress)}
<LinkAndCopy url={sourceChain?.txUrl} path="address" hex={packet.sourcePortAddress} />
</div>
<Divider />
<div className="flex flex-row justify-between">
<p className="mr-8 font-medium">Dest Port Address</p>
{linkAndCopy(destChain?.txUrl || '', 'address', packet.destPortAddress)}
<LinkAndCopy url={destChain?.txUrl} path="address" hex={packet.destPortAddress} />
</div>
<Divider />
<div className="flex flex-row justify-between">
<p className="mr-8 font-medium">Send Tx</p>
{linkAndCopy(sourceChain?.txUrl || '', 'tx', packet.sendTx)}
<LinkAndCopy url={sourceChain?.txUrl} path="tx" hex={packet.sendTx} />
</div>
<Divider />
<div className="flex flex-row justify-between">
Expand All @@ -181,31 +180,6 @@ function Divider () {
);
}

function linkAndCopy(url: string, path: string, hex?: string) {
if (!hex) {
return <p className="font-mono animate-pulse">...</p>;
}

hex = hex.toLowerCase();
if (hex[0] != '0' || hex[1] != 'x') {
let split = hex.split('.');
if (split.length > 0) {
hex = split.pop();
}
hex = '0x' + hex;
}

return (
<div className="whitespace-nowrap flex flex-row">
<Link href={url + path + '/' + hex} target="_blank"
className="text-light-blue dark:text-light-blue font-mono text-[17px]/[24px] hover:underline underline-offset-2">
{hex}
</Link>
<CopyButton str={hex} />
</div>
);
}

function formatDuration(duration: number) {
if (duration < 180) {
return `${duration}s`;
Expand Down Expand Up @@ -237,7 +211,7 @@ async function calcTxFunding(chainRpc: string, feesDeposited?: number, gasLimit?

function txWithFeeInfo(fundingStatus: number, url: string, txHash?: string) {
if (txHash) {
return linkAndCopy(url, 'tx', txHash);
return <LinkAndCopy url={url} path="tx" hex={txHash} />;
}
else if (fundingStatus > 0) {
return <p className="font-mono text-warning">~{numberWithCommas(Math.round(fundingStatus / 1000000000))} Gwei Underfunded</p>;
Expand Down
37 changes: 10 additions & 27 deletions app/(routes)/packets/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ import {
SortingState,
useReactTable }
from '@tanstack/react-table';
import { Table } from 'components/table';
import { Modal } from 'components/modal';
import {
Table,
Modal,
Select,
StateCell,
ChainCell,
Arrow,
shortenHex,
FilterButton } from 'components';
import { Packet } from 'utils/types/packet';
import { PacketDetails } from './packet-details';
import { stateToString } from 'utils/types/packet';
import { CHAIN_CONFIGS } from 'utils/chains/configs';
import { Select } from 'components/select';
import { StateCell } from 'components/state-cell';
import { ChainCell, Arrow } from 'components/chain-cell';
import { shortenHex } from 'components/format-strings';
import { classNames } from 'utils/functions';
import { FiChevronDown } from 'react-icons/fi';
import { Transition, Popover } from '@headlessui/react';
Expand Down Expand Up @@ -321,27 +324,7 @@ export default function Packets() {
onClick={() => searchPackets()}>
Search
</button>
<button
className="ml-3.5 pt-2.5 pb-3 px-2 grid justify-items-center items-center"
onClick={() => setShowFilters(!showFilters)}>
<div className={classNames(
showFilters
? 'translate-y-4'
: '',
'relative h-0.5 w-6 bg-vapor transition-transform duration-200 ease-in-out'
)}>
</div>
<div
className="h-0.5 w-[15.5px] bg-vapor">
</div>
<div className={classNames(
showFilters
? '-translate-y-4'
: '',
'relative h-0.5 w-[7px] bg-vapor transition-transform duration-200 ease-in-out'
)}>
</div>
</button>
<FilterButton open={showFilters} setOpen={setShowFilters}/>
</div>
<button
onClick={() => searchPackets()}
Expand Down
Loading

0 comments on commit 050fc64

Please sign in to comment.