Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d17044a
explorer: Auto-update transactions until they reach max confirmation
oJshua Aug 20, 2020
c079ac3
convert to side effect
oJshua Aug 20, 2020
bbbe09e
proper cleanup
oJshua Aug 20, 2020
40729fd
minor cleanup
oJshua Aug 21, 2020
6be6044
pull isAutoRefresh from context, refactor, and add loading indicator …
oJshua Aug 21, 2020
b78b2e6
Merge remote-tracking branch 'upstream/master' into feature/65-autore…
oJshua Aug 24, 2020
a9c40c4
split effects into two, manage interval in one effect only
oJshua Aug 25, 2020
e3b532a
simplify interval
oJshua Aug 25, 2020
47225d9
move autoRefresh up a level, use computed value
oJshua Aug 25, 2020
caa0435
flip conditional for readability
oJshua Aug 25, 2020
6f90799
accidentally factored out not found case
oJshua Aug 25, 2020
73b2359
add attempts bailout
oJshua Aug 25, 2020
ac1c382
run prettier
oJshua Aug 25, 2020
8acf812
bailout after 5 polls of 0 confirmations
oJshua Aug 25, 2020
51d8528
explorer: Auto-update transactions until they reach max confirmation
oJshua Aug 20, 2020
d2b6e98
convert to side effect
oJshua Aug 20, 2020
9b674f7
proper cleanup
oJshua Aug 20, 2020
caa666d
minor cleanup
oJshua Aug 21, 2020
4c9f1e4
pull isAutoRefresh from context, refactor, and add loading indicator …
oJshua Aug 21, 2020
f78b413
split effects into two, manage interval in one effect only
oJshua Aug 25, 2020
a32cb26
simplify interval
oJshua Aug 25, 2020
28745cf
move autoRefresh up a level, use computed value
oJshua Aug 25, 2020
9a8589d
flip conditional for readability
oJshua Aug 25, 2020
0b0a3ce
accidentally factored out not found case
oJshua Aug 25, 2020
534953b
add attempts bailout
oJshua Aug 25, 2020
11f85cd
run prettier
oJshua Aug 25, 2020
96b75d7
bailout after 5 polls of 0 confirmations
oJshua Aug 25, 2020
547565c
Merge branch 'feature/65-autorefresh-transaction-until-max' of github…
oJshua Aug 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 78 additions & 33 deletions explorer/src/pages/TransactionDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,18 @@ import { intoTransactionInstruction } from "utils/tx";
import { TokenDetailsCard } from "components/instruction/token/TokenDetailsCard";
import { FetchStatus } from "providers/cache";

type Props = { signature: TransactionSignature };
export function TransactionDetailsPage({ signature: raw }: Props) {
const AUTO_REFRESH_TIMEOUT = 2000;
const ZERO_CONFIRMATION_BAILOUT = 5;

type SignatureProps = {
signature: TransactionSignature;
};

type AutoRefreshProps = {
autoRefreshInProcess: boolean;
};

export function TransactionDetailsPage({ signature: raw }: SignatureProps) {
let signature: TransactionSignature | undefined;

try {
Expand All @@ -40,6 +50,20 @@ export function TransactionDetailsPage({ signature: raw }: Props) {
}
} catch (err) {}

const status = useTransactionStatus(signature);

let autoRefreshInProcess = false;

if (
status?.data?.info &&
status.data.info.confirmations === 0 &&
status.attempts > ZERO_CONFIRMATION_BAILOUT
) {
autoRefreshInProcess = false;
} else if (status?.data?.info && status.data.info.confirmations !== "max") {
autoRefreshInProcess = true;
}

return (
<div className="container mt-n3">
<div className="header">
Expand All @@ -52,28 +76,29 @@ export function TransactionDetailsPage({ signature: raw }: Props) {
<ErrorCard text={`Signature "${raw}" is not valid`} />
) : (
<>
<StatusCard signature={signature} />
<AccountsCard signature={signature} />
<StatusCard
signature={signature}
autoRefreshInProcess={autoRefreshInProcess}
/>
<AccountsCard
signature={signature}
autoRefreshInProcess={autoRefreshInProcess}
/>
<InstructionsSection signature={signature} />
</>
)}
</div>
);
}

function StatusCard({ signature }: Props) {
function StatusCard({
signature,
autoRefreshInProcess,
}: SignatureProps & AutoRefreshProps) {
const fetchStatus = useFetchTransactionStatus();
const status = useTransactionStatus(signature);
const fetchDetails = useFetchTransactionDetails();
const details = useTransactionDetails(signature);
const { firstAvailableBlock, status: clusterStatus } = useCluster();
const refresh = React.useCallback(
(signature: string) => {
fetchStatus(signature);
fetchDetails(signature);
},
[fetchStatus, fetchDetails]
);

// Fetch transaction on load
React.useEffect(() => {
Expand All @@ -82,7 +107,24 @@ function StatusCard({ signature }: Props) {
}
}, [signature, clusterStatus]); // eslint-disable-line react-hooks/exhaustive-deps

if (!status || status.status === FetchStatus.Fetching) {
// Effect to set and clear interval for auto-refresh
React.useEffect(() => {
if (autoRefreshInProcess) {
let intervalHandle: NodeJS.Timeout = setInterval(
() => fetchStatus(signature),
AUTO_REFRESH_TIMEOUT
);

return () => {
clearInterval(intervalHandle);
};
}
}, [autoRefreshInProcess, fetchStatus, signature]);

if (
!status ||
(status.status === FetchStatus.Fetching && !autoRefreshInProcess)
) {
return <LoadingCard />;
} else if (status.status === FetchStatus.FetchFailed) {
return (
Expand All @@ -102,6 +144,7 @@ function StatusCard({ signature }: Props) {
}

const { info } = status.data;

const renderResult = () => {
let statusClass = "success";
let statusText = "Success";
Expand Down Expand Up @@ -134,13 +177,17 @@ function StatusCard({ signature }: Props) {
<div className="card">
<div className="card-header align-items-center">
<h3 className="card-header-title">Overview</h3>
<button
className="btn btn-white btn-sm"
onClick={() => refresh(signature)}
>
<span className="fe fe-refresh-cw mr-2"></span>
Refresh
</button>
{autoRefreshInProcess ? (
<span className="spinner-grow spinner-grow-sm"></span>
) : (
<button
className="btn btn-white btn-sm"
onClick={() => fetchStatus(signature)}
>
<span className="fe fe-refresh-cw mr-2"></span>
Refresh
</button>
)}
</div>

<TableCardBody>
Expand Down Expand Up @@ -211,12 +258,13 @@ function StatusCard({ signature }: Props) {
);
}

function AccountsCard({ signature }: Props) {
function AccountsCard({
signature,
autoRefreshInProcess,
}: SignatureProps & AutoRefreshProps) {
const { url } = useCluster();
const details = useTransactionDetails(signature);
const fetchStatus = useFetchTransactionStatus();
const fetchDetails = useFetchTransactionDetails();
const refreshStatus = () => fetchStatus(signature);
const refreshDetails = () => fetchDetails(signature);
const transaction = details?.data?.transaction?.transaction;
const message = transaction?.message;
Expand All @@ -231,14 +279,11 @@ function AccountsCard({ signature }: Props) {

if (!status?.data?.info) {
return null;
} else if (!details) {
return (
<ErrorCard
retry={refreshStatus}
text="Details are not available until the transaction reaches MAX confirmations"
/>
);
} else if (details.status === FetchStatus.Fetching) {
} else if (
!details ||
details.status === FetchStatus.Fetching ||
autoRefreshInProcess
) {
return <LoadingCard />;
} else if (details.status === FetchStatus.FetchFailed) {
return <ErrorCard retry={refreshDetails} text="Fetch Failed" />;
Expand Down Expand Up @@ -317,7 +362,7 @@ function AccountsCard({ signature }: Props) {
);
}

function InstructionsSection({ signature }: Props) {
function InstructionsSection({ signature }: SignatureProps) {
const status = useTransactionStatus(signature);
const details = useTransactionDetails(signature);
const fetchDetails = useFetchTransactionDetails();
Expand Down
10 changes: 10 additions & 0 deletions explorer/src/providers/cache.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum FetchStatus {
export type CacheEntry<T> = {
status: FetchStatus;
data?: T;
attempts: number;
};

export type State<T> = {
Expand Down Expand Up @@ -94,6 +95,15 @@ export function reducer<T, U>(
case ActionType.Update: {
const key = action.key;
const entry = state.entries[key];

if (entry && entry.attempts === undefined) {
entry.attempts = 0;
}

if (action.status === FetchStatus.Fetched) {
entry.attempts++;
}

const entries = {
...state.entries,
[key]: {
Expand Down
6 changes: 5 additions & 1 deletion explorer/src/providers/transactions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export function useTransactions() {
}

export function useTransactionStatus(
signature: TransactionSignature
signature: TransactionSignature | undefined
): Cache.CacheEntry<TransactionStatus> | undefined {
const context = React.useContext(StateContext);

Expand All @@ -141,6 +141,10 @@ export function useTransactionStatus(
);
}

if (signature === undefined) {
return undefined;
}

return context.entries[signature];
}

Expand Down