Refactor TransactionCard components and show spinner during debugger

Rename shouldBlur to blur for brevity
pull/40/head
J M Rossy 2 years ago
parent 2a77083b3f
commit 4e2e720d13
  1. 2
      src/features/debugger/debugMessage.ts
  2. 4
      src/features/deliveryStatus/useMessageDeliveryStatus.tsx
  3. 40
      src/features/messages/MessageDetails.tsx
  4. 17
      src/features/messages/cards/ContentDetailsCard.tsx
  5. 12
      src/features/messages/cards/GasDetailsCard.tsx
  6. 12
      src/features/messages/cards/IcaDetailsCard.tsx
  7. 6
      src/features/messages/cards/TimelineCard.tsx
  8. 279
      src/features/messages/cards/TransactionCard.tsx

@ -203,7 +203,7 @@ async function tryCheckIgpGasFunded(
}
logger.debug('Amount of gas paid for to IGP:', gasAlreadyFunded.toString());
logger.debug('Amount of gas required:', deliveryGasEst);
logger.debug('Approximate amount of gas required:', deliveryGasEst);
if (gasAlreadyFunded.lte(0)) {
return { isFunded: false, igpDetails: 'Origin IGP has not received any gas payments' };
} else if (gasAlreadyFunded.lte(deliveryGasEst)) {

@ -16,7 +16,7 @@ export function useMessageDeliveryStatus({ message, pause }: { message: Message;
const multiProvider = useMultiProvider();
const serializedMessage = JSON.stringify(message);
const { data, error } = useQuery(
const { data, error, isFetching } = useQuery(
['messageDeliveryStatus', serializedMessage, pause],
async () => {
if (pause || !message || message.status === MessageStatus.Delivered) return null;
@ -79,5 +79,5 @@ export function useMessageDeliveryStatus({ message, pause }: { message: Message;
return [message];
}, [message, data]);
return { messageWithDeliveryStatus, debugInfo };
return { messageWithDeliveryStatus, debugInfo, isDeliveryStatusFetching: isFetching };
}

@ -16,7 +16,7 @@ import { ContentDetailsCard } from './cards/ContentDetailsCard';
import { GasDetailsCard } from './cards/GasDetailsCard';
import { IcaDetailsCard } from './cards/IcaDetailsCard';
import { TimelineCard } from './cards/TimelineCard';
import { TransactionCard } from './cards/TransactionCard';
import { DestinationTransactionCard, OriginTransactionCard } from './cards/TransactionCard';
import { useIsIcaMessage } from './ica';
import { usePiChainMessageQuery } from './pi-queries/usePiChainMessageQuery';
import { PLACEHOLDER_MESSAGE } from './placeholderMessages';
@ -60,12 +60,16 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
const isMessageFound = !!messageFromUrlParams || isGraphQlMessageFound || isPiMessageFound;
const isFetching = isGraphQlFetching || isPiFetching;
const isError = isGraphQlError || isPiError;
const shouldBlur = !isMessageFound;
const blur = !isMessageFound;
const isIcaMsg = useIsIcaMessage(_message);
// If message isn't delivered, attempt to check for
// more recent updates and possibly debug info
const { messageWithDeliveryStatus: message, debugInfo } = useMessageDeliveryStatus({
const {
messageWithDeliveryStatus: message,
debugInfo,
isDeliveryStatusFetching,
} = useMessageDeliveryStatus({
message: _message,
pause: !isMessageFound,
});
@ -94,28 +98,20 @@ export function MessageDetails({ messageId, message: messageFromUrlParams }: Pro
/>
</div>
<div className="flex flex-wrap items-stretch justify-between mt-5 gap-3">
<TransactionCard
title="Origin Transaction"
chainId={originChainId}
status={status}
transaction={origin}
helpText={helpText.origin}
shouldBlur={shouldBlur}
/>
<TransactionCard
title="Destination Transaction"
<OriginTransactionCard chainId={originChainId} transaction={origin} blur={blur} />
<DestinationTransactionCard
chainId={destChainId}
status={status}
transaction={destination}
debugInfo={debugInfo}
isStatusFetching={isDeliveryStatusFetching}
isPiMsg={message.isPiMsg}
helpText={helpText.destination}
shouldBlur={shouldBlur}
blur={blur}
/>
{!message.isPiMsg && <TimelineCard message={message} shouldBlur={shouldBlur} />}
<ContentDetailsCard message={message} shouldBlur={shouldBlur} />
<GasDetailsCard message={message} shouldBlur={shouldBlur} />
{isIcaMsg && <IcaDetailsCard message={message} shouldBlur={shouldBlur} />}
{!message.isPiMsg && <TimelineCard message={message} blur={blur} />}
<ContentDetailsCard message={message} blur={blur} />
<GasDetailsCard message={message} blur={blur} />
{isIcaMsg && <IcaDetailsCard message={message} blur={blur} />}
</div>
</>
);
@ -191,9 +187,3 @@ function useDynamicBannerColor(
return () => setBanner('');
}, [setBanner]);
}
const helpText = {
origin: 'Info about the transaction that initiated the message placement into the outbox.',
destination:
'Info about the transaction that triggered the delivery of the message from an inbox.',
};

@ -16,7 +16,7 @@ import { KeyValueRow } from './KeyValueRow';
interface Props {
message: Message;
shouldBlur: boolean;
blur: boolean;
}
export function ContentDetailsCard({
@ -30,7 +30,7 @@ export function ContentDetailsCard({
body,
decodedBody,
},
shouldBlur,
blur,
}: Props) {
const [bodyDecodeType, setBodyDecodeType] = useState<string>(decodedBody ? 'utf8' : 'hex');
useEffect(() => {
@ -74,21 +74,16 @@ export function ContentDetailsCard({
display={msgId}
displayWidth="w-64 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
/>
<KeyValueRow
label="Nonce:"
labelWidth="w-16"
display={nonce.toString()}
blurValue={shouldBlur}
blurValue={blur}
/>
<KeyValueRow label="Nonce:" labelWidth="w-16" display={nonce.toString()} blurValue={blur} />
<KeyValueRow
label="Sender:"
labelWidth="w-16"
display={sender}
displayWidth="w-64 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
blurValue={blur}
/>
<KeyValueRow
label="Recipient:"
@ -96,7 +91,7 @@ export function ContentDetailsCard({
display={recipient}
displayWidth="w-64 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
blurValue={blur}
/>
</div>
<div>

@ -16,7 +16,7 @@ import { KeyValueRow } from './KeyValueRow';
interface Props {
message: Message;
shouldBlur: boolean;
blur: boolean;
}
const unitOptions = [
@ -25,7 +25,7 @@ const unitOptions = [
{ value: 'wei', display: 'Wei' },
];
export function GasDetailsCard({ message, shouldBlur }: Props) {
export function GasDetailsCard({ message, blur }: Props) {
const [unit, setUnit] = useState(unitOptions[0].value);
const { totalGasAmount, totalPayment: totalPaymentWei, numPayments } = message;
@ -60,28 +60,28 @@ export function GasDetailsCard({ message, shouldBlur }: Props) {
label="Payment count:"
labelWidth="w-28"
display={numPayments?.toString() || '0'}
blurValue={shouldBlur}
blurValue={blur}
classes="basis-5/12"
/>
<KeyValueRow
label="Total gas amount:"
labelWidth="w-28"
display={totalGasAmount?.toString() || '0'}
blurValue={shouldBlur}
blurValue={blur}
classes="basis-5/12"
/>
<KeyValueRow
label="Total paid:"
labelWidth="w-28"
display={totalPaymentWei ? paymentFormatted : '0'}
blurValue={shouldBlur}
blurValue={blur}
classes="basis-5/12"
/>
<KeyValueRow
label="Average price:"
labelWidth="w-28"
display={avgPrice ? avgPrice.formatted : '-'}
blurValue={shouldBlur}
blurValue={blur}
classes="basis-5/12"
/>
</div>

@ -11,10 +11,10 @@ import { KeyValueRow } from './KeyValueRow';
interface Props {
message: Message;
shouldBlur: boolean;
blur: boolean;
}
export function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }: Props) {
export function IcaDetailsCard({ message: { originDomainId, body }, blur }: Props) {
const decodeResult = useMemo(() => tryDecodeIcaBody(body), [body]);
const {
@ -42,7 +42,7 @@ export function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }
display={decodeResult.sender}
displayWidth="w-60 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
blurValue={blur}
/>
<KeyValueRow
label="ICA Address:"
@ -58,7 +58,7 @@ export function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }
}
displayWidth="w-60 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
blurValue={blur}
/>
{decodeResult.calls.length ? (
decodeResult.calls.map((c, i) => (
@ -73,7 +73,7 @@ export function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }
display={c.destinationAddress}
displayWidth="w-60 sm:w-80"
showCopy={true}
blurValue={shouldBlur}
blurValue={blur}
/>
<KeyValueRow
label="Raw call bytes:"
@ -81,7 +81,7 @@ export function IcaDetailsCard({ message: { originDomainId, body }, shouldBlur }
display={c.callBytes}
displayWidth="w-60 sm:w-96 lg:w-112"
showCopy={true}
blurValue={shouldBlur}
blurValue={blur}
/>
</div>
</div>

@ -5,10 +5,10 @@ import { Message } from '../../../types';
interface Props {
message: Message;
shouldBlur?: boolean;
blur?: boolean;
}
export function TimelineCard({ message, shouldBlur }: Props) {
export function TimelineCard({ message, blur }: Props) {
const { stage, timings } = useMessageStage({ message });
return (
@ -17,7 +17,7 @@ export function TimelineCard({ message, shouldBlur }: Props) {
<h3 className="text-gray-500 font-medium text-md mr-2">Delivery Timeline</h3>
<HelpIcon size={16} text="A breakdown of the stages for delivering a message" />
</div> */}
<div className={`-mx-2 sm:mx-0 -my-2 ${shouldBlur && 'blur-xs'}`}>
<div className={`-mx-2 sm:mx-0 -my-2 ${blur && 'blur-xs'}`}>
<MessageTimeline status={message.status} stage={stage} timings={timings} />
</div>
</Card>

@ -1,3 +1,5 @@
import { PropsWithChildren, ReactNode } from 'react';
import { Spinner } from '../../../components/animation/Spinner';
import { ChainLogo } from '../../../components/icons/ChainLogo';
import { HelpIcon } from '../../../components/icons/HelpIcon';
@ -11,35 +13,109 @@ import { useMultiProvider } from '../../providers/multiProvider';
import { KeyValueRow } from './KeyValueRow';
interface TransactionCardProps {
title: string;
export function OriginTransactionCard({
chainId,
transaction,
blur,
}: {
chainId: ChainId;
status: MessageStatus;
transaction?: MessageTx;
debugInfo?: TransactionCardDebugInfo;
isPiMsg?: boolean;
helpText: string;
shouldBlur: boolean;
}
export interface TransactionCardDebugInfo {
status: MessageDebugStatus;
details: string;
transaction: MessageTx;
blur: boolean;
}) {
return (
<TransactionCard chainId={chainId} title="Origin Transaction" helpText={helpText.origin}>
<TransactionDetails chainId={chainId} transaction={transaction} blur={blur} />
</TransactionCard>
);
}
export function TransactionCard({
title,
export function DestinationTransactionCard({
chainId,
status,
transaction,
debugInfo,
isStatusFetching,
isPiMsg,
blur,
}: {
chainId: ChainId;
status: MessageStatus;
transaction?: MessageTx;
debugInfo?: {
status: MessageDebugStatus;
details: string;
};
isStatusFetching: boolean;
isPiMsg?: boolean;
blur: boolean;
}) {
let content: ReactNode;
if (transaction) {
content = <TransactionDetails chainId={chainId} transaction={transaction} blur={blur} />;
} else if (!debugInfo && isStatusFetching) {
content = (
<DeliveryStatus>
<div>Checking delivery status and inspecting message</div>
<Spinner classes="mt-4 scale-75" />
</DeliveryStatus>
);
} else if (status === MessageStatus.Failing) {
content = (
<DeliveryStatus>
<div className="text-gray-700">Delivery to destination chain is currently failing</div>
{debugInfo && (
<>
<div className="mt-4 text-gray-700 text-center">
{debugStatusToDesc[debugInfo.status]}
</div>
<div className="mt-4 text-gray-700 text-sm max-w-sm text-center break-words">
{debugInfo.details}
</div>
</>
)}
</DeliveryStatus>
);
} else if (status === MessageStatus.Pending) {
content = (
<DeliveryStatus>
<div>Delivery to destination chain still in progress.</div>
{isPiMsg && (
<div className="mt-2 text-gray-700 text-sm max-w-xs">
Please ensure a relayer is running for this chain.
</div>
)}
<Spinner classes="mt-4 scale-75" />
</DeliveryStatus>
);
} else {
content = (
<DeliveryStatus>
<div className="text-gray-700">{`Delivery to status is currently unknown. ${
isPiMsg
? 'Please ensure your chain config is correct and check back later.'
: 'Please check again later'
}`}</div>
</DeliveryStatus>
);
}
return (
<TransactionCard
chainId={chainId}
title="Destination Transaction"
helpText={helpText.destination}
>
{content}
</TransactionCard>
);
}
function TransactionCard({
chainId,
title,
helpText,
shouldBlur,
}: TransactionCardProps) {
const multiProvider = useMultiProvider();
const hash = transaction?.hash;
const txExplorerLink = hash ? multiProvider.tryGetExplorerTxUrl(chainId, { hash }) : null;
children,
}: PropsWithChildren<{ chainId: ChainId; title: string; helpText: string }>) {
return (
<Card classes="flex-1 min-w-fit space-y-3">
<div className="flex items-center justify-between">
@ -51,88 +127,87 @@ export function TransactionCard({
<HelpIcon size={16} text={helpText} />
</div>
</div>
{transaction && (
<>
<KeyValueRow
label="Chain:"
labelWidth="w-16"
display={`${getChainDisplayName(multiProvider, chainId)} (${chainId})`}
displayWidth="w-60 sm:w-64"
blurValue={shouldBlur}
/>
<KeyValueRow
label="Tx hash:"
labelWidth="w-16"
display={transaction.hash}
displayWidth="w-60 sm:w-64"
showCopy={true}
blurValue={shouldBlur}
/>
<KeyValueRow
label="From:"
labelWidth="w-16"
display={transaction.from}
displayWidth="w-60 sm:w-64"
showCopy={true}
blurValue={shouldBlur}
/>
<KeyValueRow
label="Time:"
labelWidth="w-16"
display={getHumanReadableTimeString(transaction.timestamp)}
subDisplay={`(${getDateTimeString(transaction.timestamp)})`}
displayWidth="w-60 sm:w-64"
blurValue={shouldBlur}
/>
<KeyValueRow
label="Block:"
labelWidth="w-16"
display={transaction.blockNumber.toString()}
displayWidth="w-60 sm:w-64"
blurValue={shouldBlur}
/>
{txExplorerLink && (
<a
className="block text-sm text-gray-500 pl-px underline"
href={txExplorerLink}
target="_blank"
rel="noopener noreferrer"
>
View in block explorer
</a>
)}
</>
)}
{!transaction && status === MessageStatus.Failing && (
<div className="flex flex-col items-center py-5">
<div className="text-gray-700 text-center">
Delivery to destination chain is currently failing
</div>
{debugInfo && (
<>
<div className="mt-4 text-gray-700 text-center">
{debugStatusToDesc[debugInfo.status]}
</div>
<div className="mt-4 text-gray-700 text-sm max-w-sm text-center break-words">
{debugInfo.details}
</div>
</>
)}
</div>
)}
{!transaction && (status === MessageStatus.Pending || status === MessageStatus.Unknown) && (
<div className="flex flex-col items-center py-5">
<div className="text-gray-500 text-center max-w-xs">
Delivery to destination chain still in progress.
</div>
{isPiMsg && (
<div className="mt-2 text-gray-500 text-center text-sm max-w-xs">
Please ensure a relayer is running for this chain.
</div>
)}
<Spinner classes="mt-4 scale-75" />
</div>
)}
{children}
</Card>
);
}
function TransactionDetails({
chainId,
transaction,
blur,
}: {
chainId: ChainId;
transaction: MessageTx;
blur: boolean;
}) {
const { hash, from, timestamp, blockNumber } = transaction;
const multiProvider = useMultiProvider();
const txExplorerLink = hash ? multiProvider.tryGetExplorerTxUrl(chainId, { hash }) : null;
return (
<>
<KeyValueRow
label="Chain:"
labelWidth="w-16"
display={`${getChainDisplayName(multiProvider, chainId)} (${chainId})`}
displayWidth="w-60 sm:w-64"
blurValue={blur}
/>
<KeyValueRow
label="Tx hash:"
labelWidth="w-16"
display={hash}
displayWidth="w-60 sm:w-64"
showCopy={true}
blurValue={blur}
/>
<KeyValueRow
label="From:"
labelWidth="w-16"
display={from}
displayWidth="w-60 sm:w-64"
showCopy={true}
blurValue={blur}
/>
<KeyValueRow
label="Time:"
labelWidth="w-16"
display={getHumanReadableTimeString(timestamp)}
subDisplay={`(${getDateTimeString(timestamp)})`}
displayWidth="w-60 sm:w-64"
blurValue={blur}
/>
<KeyValueRow
label="Block:"
labelWidth="w-16"
display={blockNumber.toString()}
displayWidth="w-60 sm:w-64"
blurValue={blur}
/>
{txExplorerLink && (
<a
className="block text-sm text-gray-500 pl-px underline"
href={txExplorerLink}
target="_blank"
rel="noopener noreferrer"
>
View in block explorer
</a>
)}
</>
);
}
function DeliveryStatus({ children }: PropsWithChildren<unknown>) {
return (
<div className="py-5 flex flex-col items-center text-gray-500 text-center">
<div className="max-w-xs">{children}</div>
</div>
);
}
const helpText = {
origin: 'Info about the transaction that initiated the message placement into the outbox.',
destination:
'Info about the transaction that triggered the delivery of the message from an inbox.',
};

Loading…
Cancel
Save