Merge pull request #18 from hyperlane-xyz/show-chain-names

Show chain names in table
Remove debug toast message
pull/19/head
J M Rossy 2 years ago committed by GitHub
commit 3d26929b8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      src/components/icons/ChainIcon.tsx
  2. 2
      src/components/icons/ChainToChain.tsx
  3. 8
      src/components/icons/InterchainAccount.tsx
  4. 2
      src/components/layout/AppLayout.tsx
  5. 2
      src/components/search/MiniSearchBar.tsx
  6. 2
      src/components/search/SearchBar.tsx
  7. 35
      src/consts/chains.ts
  8. 18
      src/features/messages/MessageSearch.tsx
  9. 36
      src/features/messages/MessageTable.tsx
  10. 2
      src/utils/addresses.ts
  11. 12
      src/utils/chains.ts

@ -53,16 +53,16 @@ const CHAIN_TO_ICON = {
[moonbaseAlphaChain.id]: Moonbeam,
};
function _ChainIcon({ chainId, size = 44 }: { chainId?: number; size?: number }) {
function _ChainIcon({ chainId, size = 40 }: { chainId?: number; size?: number }) {
const imageSrc = (chainId && CHAIN_TO_ICON[chainId]) || QuestionMark;
return (
<div
style={{ width: `${size}px`, height: `${size}px` }}
className="flex items-center justify-center rounded-full bg-beige-300 transition-all"
className="flex items-center justify-center rounded-full bg-gray-100 transition-all"
title={getChainDisplayName(chainId)}
>
<Image src={imageSrc} alt="" width={Math.floor(size / 2.2)} height={Math.floor(size / 2.2)} />
<Image src={imageSrc} alt="" width={Math.floor(size / 1.8)} height={Math.floor(size / 1.8)} />
</div>
);
}

@ -9,7 +9,7 @@ import { ChainIcon } from './ChainIcon';
function _ChainToChain({
originChainId,
destinationChainId,
size = 44,
size = 40,
arrowSize = 32,
isNarrow = false,
}: {

@ -17,16 +17,16 @@ function _InterchainAccount({ size = 44, arrowSize = 32 }: { size?: number; arro
<div className="flex items-center justify-center sm:space-x-1 md:space-x-2">
<div
style={{ width: `${size}px`, height: `${size}px` }}
className="flex items-center justify-center rounded-full bg-beige-300 transition-all"
className="flex items-center justify-center rounded-full bg-gray-100 transition-all"
>
<Image src={Key} alt="" width={Math.floor(size / 2.2)} height={Math.floor(size / 2.2)} />
<Image src={Key} alt="" width={Math.floor(size / 2)} height={Math.floor(size / 2.2)} />
</div>
<Image src={ArrowRightIcon} width={arrowSize} height={arrowSize} alt="" />
<div
style={{ width: `${size}px`, height: `${size}px` }}
className="flex items-center justify-center rounded-full bg-beige-300 transition-all"
className="flex items-center justify-center rounded-full bg-gray-100 transition-all"
>
<Image src={Asterisk} alt="" width={Math.floor(size / 3)} height={Math.floor(size / 3)} />
<Image src={Asterisk} alt="" width={Math.floor(size / 2.6)} height={Math.floor(size / 3)} />
</div>
</div>
);

@ -15,7 +15,7 @@ export function AppLayout({ pathName, children }: PropsWithChildren<Props>) {
<Head>
{/* https://nextjs.org/docs/messages/no-document-viewport-meta */}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{`Hyperlane Explorer [BETA] | ${getHeadTitle(pathName)}`}</title>
<title>{`Hyperlane Explorer | ${getHeadTitle(pathName)}`}</title>
</Head>
<div className="h-full min-h-screen w-full min-w-screen bg-gray-100">
<div className="max-w-5xl mx-auto flex flex-col justify-between min-h-screen">

@ -30,7 +30,7 @@ export function MiniSearchBar() {
placeholder="Hash or address"
className="w-32 focus:w-64 py-2 px-2.5 h-8 text-sm rounded placeholder:text-gray-500 focus:outline-none transition-[width] ease-in-out duration-500"
/>
<div className="h-8 w-8 flex items-center justify-center rounded bg-beige-300">
<div className="h-8 w-8 flex items-center justify-center rounded bg-gray-200">
<IconButton
type="submit"
imgSrc={SearchIcon}

@ -28,7 +28,7 @@ export function SearchBar({ value, placeholder, onChangeValue, isFetching }: Pro
placeholder={placeholder}
className="p-2 sm:px-4 md:px-5 flex-1 h-10 sm:h-12 rounded placeholder:text-gray-500 focus:outline-none"
/>
<div className="h-10 sm:h-12 w-10 sm:w-12 flex items-center justify-center rounded bg-beige-300">
<div className="h-10 sm:h-12 w-10 sm:w-12 flex items-center justify-center rounded bg-gray-200">
{isFetching && <Spinner classes="scale-[30%] mr-2.5" />}
{!isFetching && !value && <Image src={SearchIcon} width={20} height={20} alt="" />}
{!isFetching && value && (

@ -23,9 +23,15 @@ export const alfajoresChain: Chain = {
testnet: true,
};
// Override to set name to just Arbitrum
const arbitrumChain = {
...chain.arbitrum,
name: 'Arbitrum',
};
export const auroraTestnetChain: Chain = {
id: 1313161555,
name: 'Aurora Testnet',
name: 'Aurora',
network: 'auroraTestnet',
nativeCurrency: {
decimals: 18,
@ -129,7 +135,7 @@ export const celoMainnetChain: Chain = {
export const fujiTestnetChain: Chain = {
id: 43113,
name: 'Fuji Testnet',
name: 'Fuji',
network: 'fuji',
nativeCurrency: {
decimals: 18,
@ -198,6 +204,12 @@ export const moonbeamChain: Chain = {
testnet: false,
};
// Override to set name to just Mumbai
const polygonMumbaiChain = {
...chain.polygonMumbai,
name: 'Mumbai',
};
export const zksync2testnetChain: Chain = {
id: 280,
name: 'ZkSync Testnet',
@ -300,9 +312,9 @@ export const chainIdToExplorerApi = {
export const mainnetChains = [
chain.mainnet,
chain.arbitrum,
chain.optimism,
chain.polygon,
arbitrumChain,
avalancheChain,
bscChain,
celoMainnetChain,
@ -316,31 +328,18 @@ export const testnetChains = [
chain.arbitrumRinkeby,
chain.optimismGoerli,
chain.optimismKovan,
chain.polygonMumbai,
fujiTestnetChain,
bscTestnetChain,
alfajoresChain,
auroraTestnetChain,
moonbaseAlphaChain,
polygonMumbaiChain,
zksync2testnetChain,
];
export const prodAndTestChains = [...mainnetChains, ...testnetChains];
export const allChains = [
...allChainsWagmi,
avalancheChain,
bscChain,
celoMainnetChain,
avalancheChain,
bscChain,
fujiTestnetChain,
alfajoresChain,
bscTestnetChain,
auroraTestnetChain,
moonbaseAlphaChain,
zksync2testnetChain,
];
export const allChains = [...allChainsWagmi, ...prodAndTestChains];
export const chainIdToChain = allChains.reduce<Record<number, Chain>>((result, chain) => {
result[chain.id] = chain;

@ -1,6 +1,5 @@
import { useRouter } from 'next/router';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { toast } from 'react-toastify';
import { useQuery } from 'urql';
import { Fade } from '../../components/animation/Fade';
@ -29,18 +28,7 @@ const LATEST_QUERY_LIMIT = 12;
const SEARCH_QUERY_LIMIT = 40;
const QUERY_SEARCH_PARAM = 'search';
let showedWarning = false;
export function MessageSearch() {
// TODO remove when live for real
useEffect(() => {
if (!showedWarning) {
showedWarning = true;
toast.info(
'Welcome! This explorer is still under construction but feel free to look around!',
);
}
}, []);
const router = useRouter();
// Search text input
@ -101,8 +89,10 @@ export function MessageSearch() {
placeholder="Search by address or transaction hash"
/>
<div className="w-full min-h-[38rem] mt-5 bg-white shadow-md border border-blue-50 rounded overflow-auto relative">
<div className="px-2 py-3 sm:px-4 md:px-5 flex items-center justify-between bg-gray-50">
<h2 className="pl-1 text-gray-700">{!hasInput ? 'Latest Messages' : 'Search Results'}</h2>
<div className="px-2 py-3 sm:px-4 md:px-5 flex items-center justify-between">
<h2 className="pl-0.5 text-gray-700">
{!hasInput ? 'Latest Messages' : 'Search Results'}
</h2>
<SearchFilterBar
originChainFilter={originChainFilter}
onChangeOriginFilter={onChangeOriginFilter}

@ -1,8 +1,9 @@
import { useRouter } from 'next/router';
import { ChainToChain } from '../../components/icons/ChainToChain';
import { ChainIcon } from '../../components/icons/ChainIcon';
import { MessageStatus, MessageStub } from '../../types';
import { shortenAddress } from '../../utils/addresses';
import { getChainDisplayName } from '../../utils/chains';
import { getHumanReadableDuration, getHumanReadableTimeString } from '../../utils/time';
export function MessageTable({
@ -16,9 +17,10 @@ export function MessageTable({
return (
<table className="w-full mb-1">
<tr className="px-2 py-2 sm:px-4 md:px-5 md:py-2.5 border-b border-gray-100 bg-gray-50">
<th className={`${styles.header} pr-1`}>Chains</th>
<th className={styles.header}>Sender</th>
<tr className="border-b border-gray-100">
<th className={`${styles.header} xs:text-left pl-3 sm:pl-6`}>Origin</th>
<th className={`${styles.header} xs:text-left pl-1 sm:pl-2`}>Destination</th>
<th className={`${styles.header} hidden sm:table-cell`}>Sender</th>
<th className={`${styles.header} hidden sm:table-cell`}>Recipient</th>
<th className={styles.header}>Time sent</th>
<th className={`${styles.header} hidden lg:table-cell`}>Duration</th>
@ -27,7 +29,7 @@ export function MessageTable({
{messageList.map((m) => (
<tr
key={`message-${m.id}`}
className={`px-2 py-2 sm:px-4 md:px-5 md:py-2.5 cursor-pointer hover:bg-gray-100 active:bg-gray-200 border-b border-gray-100 last:border-0 ${
className={`cursor-pointer hover:bg-gray-100 active:bg-gray-200 border-b border-gray-100 last:border-0 ${
isFetching && 'blur-xs'
} transition-all duration-500`}
onClick={() => router.push(`/message/${m.id}`)}
@ -62,16 +64,21 @@ export function MessageSummaryRow({ message }: { message: MessageStub }) {
return (
<>
<td className="py-2.5">
<ChainToChain
originChainId={originChainId}
destinationChainId={destinationChainId}
size={38}
arrowSize={30}
isNarrow={true}
/>
<td className="py-3.5">
<div className="flex items-center pl-3 sm:pl-5">
<ChainIcon chainId={originChainId} size={26} />
<div className={styles.valueChainName}>{getChainDisplayName(originChainId, true)}</div>
</div>
</td>
<td>
<div className="flex items-center">
<ChainIcon chainId={destinationChainId} size={26} />
<div className={styles.valueChainName}>
{getChainDisplayName(destinationChainId, true)}
</div>
</div>
</td>
<td className="hidden sm:table-cell">
<div className={styles.value}>{shortenAddress(sender) || 'Invalid Address'}</div>
</td>
<td className="hidden sm:table-cell">
@ -100,6 +107,7 @@ export function MessageSummaryRow({ message }: { message: MessageStub }) {
const styles = {
header: 'text-sm text-gray-700 font-normal pt-2 pb-3 text-center',
value: 'text-sm text-center',
value: 'text-sm text-center px-1',
valueChainName: 'text-sm ml-2',
valueTruncated: 'text-sm text-center truncate',
};

@ -37,7 +37,7 @@ export function shortenAddress(address: string, capitalize?: boolean) {
try {
const normalized = normalizeAddress(address);
const shortened =
normalized.substring(0, 6) + '...' + normalized.substring(normalized.length - 4);
normalized.substring(0, 5) + '...' + normalized.substring(normalized.length - 4);
return capitalize ? capitalizeAddress(shortened) : shortened;
} catch (error) {
logger.error('Unable to shorten invalid address', address, error);

@ -1,14 +1,20 @@
import { chain } from 'wagmi';
import { ChainName, Chains, Mainnets } from '@hyperlane-xyz/sdk';
import { chainIdToName } from '../consts/chains';
import { bscChain, chainIdToChain, chainIdToName, moonbaseAlphaChain } from '../consts/chains';
import { Environment } from '../consts/environments';
import { logger } from './logger';
import { toTitleCase } from './string';
export function getChainDisplayName(chainId?: number) {
export function getChainDisplayName(chainId?: number, shortName = false) {
if (!chainId) return 'Unknown';
return toTitleCase(chainIdToName[chainId] || 'Unknown');
if (shortName && chainId === bscChain.id) return 'Binance';
if (shortName && chainId === moonbaseAlphaChain.id) return 'Moonbase';
if (shortName && chainId === chain.optimismGoerli.id) return 'Opt. Goerli';
if (shortName && chainId === chain.arbitrumGoerli.id) return 'Arb. Goerli';
return toTitleCase(chainIdToChain[chainId]?.name || 'Unknown');
}
export function getChainEnvironment(chain: number | string) {

Loading…
Cancel
Save