-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- **feat(app): show modern precomputed traces** - **feat(app): cleanup traces stepper** - **feat(traces): display names** - **chore: cleanup**
- Loading branch information
Showing
5 changed files
with
333 additions
and
226 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<script lang="ts"> | ||
import { cn } from "$lib/utilities/shadcn" | ||
import Button from "$lib/components/ui/button/button.svelte" | ||
import { type Readable, derived } from "svelte/store" | ||
import SpinnerSvg from "./spinner-svg.svelte" | ||
import type { Step, RawTrace } from "$lib/stepper-types.ts" | ||
import { toIsoString } from "$lib/utilities/date" | ||
import Truncate from "$lib/components/truncate.svelte" | ||
import { createEventDispatcher } from "svelte" | ||
export let steps: Readable<Array<RawTrace>> | ||
// const dispatch = createEventDispatcher() | ||
// | ||
let pSteps = derived(steps, $steps => { | ||
let processedSteps = $steps | ||
// patch gaps (see #2544) | ||
for (const [index, step] of processedSteps.entries()) { | ||
const gap = processedSteps.slice(index).find(step => step.status === "COMPLETED") !== undefined | ||
if (gap && (step.status === "IN_PROGRESS" || step.status === "PENDING")) { | ||
processedSteps[index].status = "COMPLETED" | ||
} | ||
} | ||
return processedSteps | ||
}) | ||
// | ||
// const cancel = () => { | ||
// dispatch("cancel") | ||
// } | ||
</script> | ||
|
||
<ol class="max-w-full w-full -my-4"> <!-- offset padding surplus !--> | ||
{#each $steps as step, index} | ||
<li class="flex gap-4 w-full"> | ||
<div class="flex flex-col items-center"> | ||
<!-- top step connector !--> | ||
<div class={cn( | ||
"w-1 flex-1", | ||
index !== 0 ? "dark:bg-muted-foreground bg-black" : "", | ||
index !== 0 ? "dark:bg-muted-foreground bg-black" : "", | ||
)}></div> | ||
<!-- stepper icon !--> | ||
<div class={cn( | ||
"size-12 border-4 relative transition-all duration-300", | ||
step.status === "PENDING" ? "bg-white" : | ||
step.status === "IN_PROGRESS" ? "bg-white" : | ||
step.status === "COMPLETED" ? "bg-accent" : | ||
step.status === "ERROR" ? "bg-black" : | ||
step.status === "WARNING" ? "bg-yellow-300" : "" | ||
)}> | ||
<div class={cn("absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-black transition-all duration-300", | ||
step.status === "COMPLETED" ? "w-1 h-7 rotate-45 translate-x-[2px]" : | ||
step.status === "ERROR" ? "w-1 h-8 rotate-45 bg-white" : | ||
step.status === "WARNING" ? "w-1 h-4 -translate-y-[12px]" : "w-2 h-2" | ||
)}></div> | ||
<div class={cn("absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-black transition-all duration-300", | ||
step.status === "COMPLETED" ? "w-1 h-4 -rotate-45 -translate-x-3 -translate-y-[2px]" : | ||
step.status === "ERROR" ? "w-1 h-8 -rotate-45 bg-white" : | ||
step.status === "WARNING" ? "w-1 h-1 translate-y-[8px]" : "w-2 h-2" | ||
)}></div> | ||
{#if step.status === "IN_PROGRESS"} | ||
<SpinnerSvg className="absolute text-accent w-8 h-8 left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"/> | ||
{/if} | ||
</div> | ||
<!-- bottom step connector !--> | ||
<div class={cn("w-1 flex-1", | ||
index === $stepsUpToError.length - 1 ? "bg-transparent" : "dark:bg-muted-foreground", | ||
index !== $steps.length - 1 && | ||
step.status !== "ERROR" && | ||
step.status !== "WARNING" ? "bg-black" : "") | ||
}></div> | ||
</div> | ||
<div class="font-bold py-4 flex flex-col min-h-[80px] max-w-[calc(100%-80px)] break-words justify-center"> | ||
{#if step.traceDetails} | ||
{@const trace = step.traceDetails} | ||
<p class="text-xs -mb-1 text-muted-foreground">{toIsoString(new Date(trace.timestamp)).split('T')[1]} on {trace.chain_display_name} at {#if trace.block_url}<a class="underline" href={trace.block_url}>{trace.block}</a>{:else}{trace.block}{/if}</p> | ||
{/if} | ||
<div>{step.title}</div> | ||
{#if step.traceDetails} | ||
{@const trace = step.traceDetails} | ||
{#if trace.tx_url !== undefined} | ||
<a href={trace.tx_url} class="-mt-1 block underline text-xs text-muted-foreground"><Truncate class="underline" value={trace.tx} type="hash"/></a> | ||
{:else} | ||
<p class="text-xs text-muted-foreground"><Truncate value={trace.tx} type="hash"/></p> | ||
{/if} | ||
{:else if step.description} | ||
<div class="font-normal break-words">{step.description}</div> | ||
{/if} | ||
</div> | ||
</li> | ||
{/each} | ||
</ol> | ||
|
||
|
||
{#if $stepsUpToError.length < $steps.length && onRetry !== undefined} | ||
|
||
<div class="flex gap-1 mt-6 w-full"> | ||
|
||
<Button | ||
variant="default" | ||
on:click={onRetry} | ||
class='!hover:bg-foreground !hover:text-primary-foreground hover:text-accent w-full' | ||
> | ||
{$stepsUpToError.slice(-1)[0].status === "WARNING" ? "CONTINUE" : "RETRY" } | ||
|
||
</Button> | ||
|
||
<Button | ||
on:click={cancel} | ||
variant="outline" | ||
class='text-primary text-md font-bold !hover:bg-foreground !hover:text-primary-foreground w-full' | ||
> | ||
CANCEL | ||
</Button> | ||
</div> | ||
|
||
{/if} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
<script lang="ts"> | ||
import { cn } from "$lib/utilities/shadcn" | ||
import Button from "$lib/components/ui/button/button.svelte" | ||
import { type Readable, derived } from "svelte/store" | ||
import SpinnerSvg from "./spinner-svg.svelte" | ||
import type { Step, RawTrace, Trace, StepStatus } from "$lib/stepper-types.ts" | ||
import { toIsoString } from "$lib/utilities/date" | ||
import Truncate from "$lib/components/truncate.svelte" | ||
import { createEventDispatcher } from "svelte" | ||
import { toDisplayName } from "$lib/utilities/chains.ts" | ||
import type { Chain } from "$lib/types" | ||
export let traces: Array<RawTrace> | ||
export let chains: Array<Chain> | ||
const DISPLAY_NAMES: Record<StepStatus, Record<string, string>> = { | ||
COMPLETED: { | ||
PACKET_SEND: "Packet Sent", | ||
PACKET_RECV: "Packet Received", | ||
WRITE_ACK: "Acknowledgement Written", | ||
PACKET_ACK: "Packet Acknowledged", | ||
PACKET_SEND_LC_UPDATE_L0: "L0 Light Client Updated", | ||
PACKET_SEND_LC_UPDATE_L1: "L1 Light Client Updated", | ||
PACKET_SEND_LC_UPDATE_L2: "L2 Light Client Updated", | ||
WRITE_ACK_LC_UPDATE_L0: "L0 Light Client Updated (Ack)", | ||
WRITE_ACK_LC_UPDATE_L1: "L1 Light Client Updated (Ack)", | ||
WRITE_ACK_LC_UPDATE_L2: "L2 Light Client Updated (Ack)" | ||
}, | ||
PENDING: { | ||
PACKET_SEND: "Send Packet", | ||
PACKET_RECV: "Receive Packet", | ||
WRITE_ACK: "Write Acknowledgement", | ||
PACKET_ACK: "Acknowledge Packet", | ||
PACKET_SEND_LC_UPDATE_L0: "Update L0 Light Client", | ||
PACKET_SEND_LC_UPDATE_L1: "Update L1 Light Client", | ||
PACKET_SEND_LC_UPDATE_L2: "Update L2 Light Client", | ||
WRITE_ACK_LC_UPDATE_L0: "Update L0 Light Client (Ack)", | ||
WRITE_ACK_LC_UPDATE_L1: "Update L1 Light Client (Ack)", | ||
WRITE_ACK_LC_UPDATE_L2: "Update L2 Light Client (Ack)" | ||
}, | ||
IN_PROGRESS: { | ||
PACKET_SEND: "Sending Packet", | ||
PACKET_RECV: "Receiving Packet", | ||
WRITE_ACK: "Writing Acknowledgement", | ||
PACKET_ACK: "Acknowledging Packet", | ||
PACKET_SEND_LC_UPDATE_L0: "Updating L0 Light Client", | ||
PACKET_SEND_LC_UPDATE_L1: "Updating L1 Light Client", | ||
PACKET_SEND_LC_UPDATE_L2: "Updating L2 Light Client", | ||
WRITE_ACK_LC_UPDATE_L0: "Updating L0 Light Client (Ack)", | ||
WRITE_ACK_LC_UPDATE_L1: "Updating L1 Light Client (Ack)", | ||
WRITE_ACK_LC_UPDATE_L2: "Updating L2 Light Client (Ack)" | ||
}, | ||
WARNING: {}, | ||
ERROR: {} | ||
} | ||
$: pTraces = ((): Array<Trace> => { | ||
let processedTraces = traces.map(t => { | ||
let explorer = chains.find(c => c.chain_id === t.chain.chain_id)?.explorers?.at(0) | ||
return { | ||
...t, | ||
status: t.transaction_hash ? "COMPLETED" : ("PENDING" as StepStatus), | ||
block_url: explorer ? `${explorer.block_url}${t.height}` : null, | ||
transaction_url: explorer ? `${explorer.tx_url}${t.transaction_hash}` : null | ||
} | ||
}) | ||
for (const [index, step] of processedTraces.entries()) { | ||
if (step.status === "COMPLETED") { | ||
const next = processedTraces.at(index + 1) | ||
if (!next || next.status === "COMPLETED") { | ||
continue | ||
} | ||
next.status = "IN_PROGRESS" | ||
} | ||
} | ||
return processedTraces.map(t => ({ ...t, type: DISPLAY_NAMES[t.status][t.type] ?? t.type })) | ||
})() | ||
</script> | ||
|
||
<ol class="max-w-full w-full -my-4"> <!-- offset padding surplus !--> | ||
{#each pTraces as trace, index} | ||
<li class="flex gap-4 w-full"> | ||
<div class="flex flex-col items-center"> | ||
<!-- top trace connector !--> | ||
<div class={cn( | ||
"w-1 flex-1", | ||
index !== 0 ? "dark:bg-neutral-500 bg-black" : "", | ||
)}></div> | ||
<div class={cn( | ||
"size-12 border-4 dark:border-neutral-500 relative transition-all duration-300", | ||
trace.status === "PENDING" ? "bg-white dark:bg-neutral-700" : | ||
trace.status === "IN_PROGRESS" ? "bg-white dark:bg-neutral-700" : | ||
trace.status === "COMPLETED" ? "bg-accent" : | ||
trace.status === "ERROR" ? "bg-black" : | ||
trace.status === "WARNING" ? "bg-yellow-300" : "" | ||
)}> | ||
<div class={cn("absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-black transition-all duration-300", | ||
trace.status === "COMPLETED" ? "w-1 h-7 rotate-45 translate-x-[2px]" : | ||
trace.status === "ERROR" ? "w-1 h-8 rotate-45 bg-white" : | ||
trace.status === "WARNING" ? "w-1 h-4 -translate-y-[12px]" : "w-2 h-2" | ||
)}></div> | ||
<div class={cn("absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-black transition-all duration-300", | ||
trace.status === "COMPLETED" ? "w-1 h-4 -rotate-45 -translate-x-3 -translate-y-[2px]" : | ||
trace.status === "ERROR" ? "w-1 h-8 -rotate-45 bg-white" : | ||
trace.status === "WARNING" ? "w-1 h-1 translate-y-[8px]" : "w-2 h-2" | ||
)}></div> | ||
{#if trace.status === "IN_PROGRESS"} | ||
<SpinnerSvg className="absolute text-accent w-8 h-8 left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"/> | ||
{/if} | ||
</div> | ||
<!-- bottom trace connector !--> | ||
<div class={cn("w-1 flex-1", | ||
index === pTraces.length - 1 ? "bg-transparent" : "dark:bg-neutral-500 bg-black", | ||
index !== pTraces.length - 1 && | ||
trace.status !== "ERROR" && | ||
trace.status !== "WARNING" ? "bg-black" : "") | ||
}></div> | ||
</div> | ||
<div class="font-bold py-4 flex flex-col min-h-[80px] max-w-[calc(100%-80px)] break-words justify-center"> | ||
{#if trace.timestamp} | ||
<p class="text-xs -mb-1 text-muted-foreground">{toIsoString(new Date(trace.timestamp)).split('T')[1]} on {toDisplayName(trace.chain.chain_id, chains)} at {#if trace.block_url}<a class="underline" href={trace.block_url}>{trace.height}</a>{:else}{trace.height}{/if}</p> | ||
{/if} | ||
<div>{trace.type}</div> | ||
{#if trace.transaction_hash} | ||
{#if trace.transaction_url} | ||
<a href={trace.transaction_url} class="-mt-1 block underline text-xs text-muted-foreground"><Truncate class="underline" value={trace.transaction_hash} type="hash"/></a> | ||
{:else} | ||
<p class="text-xs text-muted-foreground"><Truncate value={trace.transaction_hash} type="hash"/></p> | ||
{/if} | ||
{/if} | ||
</div> | ||
</li> | ||
{/each} | ||
</ol> | ||
|
||
|
Oops, something went wrong.