Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subintents #1012

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
213 changes: 202 additions & 11 deletions apps/dashboard/src/pages/search-pages/transaction/Overview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,39 @@
import AwaitedRow from '@components/info-box/AwaitedRow.svelte'
import AddressesList from '@components/_base/address/AddressesList.svelte'
import { fullDateFormatter } from '@dashboard/lib/formatters/full-date'
import Accordion from '@components/_base/accordion/Accordion.svelte'
import Address from '@components/_base/address/Address.svelte'
import Row from '@components/info-box/Row.svelte'
import AcceptsStake from '@dashboard/lib/accepts-stake/AcceptsStake.svelte'

export let txId: string
export let tx: Promise<
| ReturnType<
Awaited<ReturnType<typeof getTransactionDetailsNew>>['_unsafeUnwrap']
>
| undefined
>
export let manifest: Promise<string | undefined>

const subintentParentHash = (
hash: string,
_subintents: NonNullable<Awaited<Awaited<typeof tx>>>['subintents']
) =>
_subintents.find(({ child_subintent_hashes }) =>
child_subintent_hashes.includes(hash)
)?.subintent_hash ?? txId

const subintentParentIndex = (
hash: string,
_subintents: NonNullable<Awaited<Awaited<typeof tx>>>['subintents']
) =>
_subintents.findIndex(({ child_subintent_hashes }) =>
child_subintent_hashes.includes(hash)
)

const subintentIndex = (
hash: string,
_subintents: NonNullable<Awaited<Awaited<typeof tx>>>['subintents']
) => _subintents.findIndex(({ subintent_hash }) => subintent_hash === hash)
</script>

<div class="surface-2">
Expand Down Expand Up @@ -84,16 +109,112 @@
{/if}
</AwaitedRow>

<AwaitedRow
text="Transaction manifest"
promise={manifest}
modifiers="label-full"
let:data
>
<CodeBox
--code-box-min-height="300px"
text={data ?? 'Failed to decode manifest'}
/>
<AwaitedRow text="Intents" promise={tx} modifiers="label-full" let:data>
{@const subintents = data?.subintents}
{@const rootChildIntents = data?.child_subintents}

<div style:width="100%" style:margin="1rem 0">
<div class="accordion">
<Accordion header="ROOT INTENT">
<div class="content" slot="content">
<Row text="Hash">
<svelte:fragment slot="right">
<Address value={txId} autoShorten />
</svelte:fragment>
</Row>

<Row text="Message">
<svelte:fragment slot="right">
{data?.message ?? 'N/A'}
</svelte:fragment>
</Row>

<Row text="Manifest" modifiers="label-full">
<svelte:fragment slot="right">
<CodeBox
--code-box-min-height="300px"
text={data?.manifest ?? 'Failed to decode manifest'}
/>
</svelte:fragment>
</Row>

{#if subintents && rootChildIntents && rootChildIntents.length > 0}
<Row text="Child Subintents" modifiers="label-full">
<div slot="right" class="children">
{#each rootChildIntents as hash}
{@const index = subintentIndex(hash, subintents)}
<div class="relation">
<div style:text-wrap="nowrap">
{`INDEX ${index}`}
</div>
</div>
{/each}
</div>
</Row>
{/if}
</div>
</Accordion>
</div>
</div>

{#if subintents && subintents.length > 0}
{#each subintents as { subintent_hash, manifest_instructions, child_subintent_hashes, message }, i}
{@const parent = subintentParentIndex(subintent_hash, subintents)}
<div style:width="100%" style:margin="1rem 0">
<div class="accordion">
<Accordion header="SUBINTENT INDEX {i}">
<div class="content" slot="content">
<Row text="subintent hash">
<svelte:fragment slot="right">
<Address value={subintent_hash} autoShorten />
</svelte:fragment>
</Row>

<Row text="Message">
<svelte:fragment slot="right">
{message ?? 'N/A'}
</svelte:fragment>
</Row>

<Row text="Parent">
<div class="relation" slot="right">
<div style:text-wrap="nowrap">
{parent >= 0
? `SUBINTENT INDEX ${parent}`
: 'ROOT INTENT'}
</div>
</div>
</Row>

<Row text="Manifest" modifiers="label-full">
<svelte:fragment slot="right">
<CodeBox
text={manifest_instructions}
--code-box-min-height="200px"
/>
</svelte:fragment>
</Row>

{#if child_subintent_hashes.length > 0}
<Row text="Child Subintents" modifiers="label-full">
<div slot="right" class="children">
{#each child_subintent_hashes as hash}
{@const index = subintentIndex(hash, subintents)}
<div class="relation">
<div style:text-wrap="nowrap">
{index >= 0 ? `INDEX ${index}` : 'ROOT'}
</div>
</div>
{/each}
</div>
</Row>
{/if}
</div>
</Accordion>
</div>
</div>
{/each}
{/if}
</AwaitedRow>

<AwaitedRow
Expand All @@ -106,3 +227,73 @@
</AwaitedRow>
</InfoBox>
</div>

<style lang="scss">
.accordion {
:global(.subheader-icon) {
@include mixins.mobile {
top: unset;
right: var(--spacing-lg);
}
}

:global(.header-text) {
font-size: var(--text-lg);
font-weight: var(--font-weight-bold-2);

@include mixins.desktop {
margin-bottom: 0;
}
}

:global(.header-wrapper) {
background: var(--color-grey-5);
padding: var(--spacing-md) var(--spacing-lg);
border-radius: var(--border-radius-md);
}
}

.content {
background: var(--color-grey-5);
padding: var(--spacing-xl) var(--spacing-lg);
display: flex;
flex-direction: column;
gap: var(--spacing-lg);

.subintent-title {
display: block;
margin-bottom: var(--spacing-lg);
}

:global(:not(.label-full) > .label) {
@include mixins.desktop {
margin-bottom: 0 !important;
}
}
}

.child-hashes {
:global(.addresses-list) {
align-items: flex-start;
}
}

.relation {
display: flex;
gap: var(--spacing-xs);
align-items: center;

> div {
background: var(--color-grey-4);
padding: var(--spacing-xs) var(--spacing-md);
border-radius: var(--border-radius-md);
font-weight: var(--font-weight-bold-2);
}
}

.children {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-md);
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import SearchPage from '@dashboard/pages/search-pages/SearchPage.svelte'
import type { LayoutData } from './$types'

export let data: LayoutData
</script>

<SearchPage
title="Subintent"
address={data.id}
activeTab={data.pageName}
menuItems={[[{ id: 'summary', label: 'Summary' }]]}
>
<slot />
</SearchPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { gatewayApi } from '@api/gateway'
import type { LayoutLoad } from './$types'

export const load: LayoutLoad = ({ params }) => {
const subintent = gatewayApi.transaction.innerClient
.transactionSubintentStatus({
transactionSubintentStatusRequest: {
subintent_hash: params.subintent
}
})
.then((response) => ({
status: response.subintent_status,
description: response.subintent_status_description,
finalizedAt: response.finalized_at_transaction_intent_hash
}))

return {
id: params.subintent,
subintent
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts">
import { goto } from '$app/navigation'
import type { LayoutData } from './$types'

export let data: LayoutData

goto(`${data.id}/summary`, { replaceState: true })
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script lang="ts">
import IconNew from '@components/_base/icon/IconNew.svelte'
import Checkmark from '@icons/checkmark-green.svg'
import SkeletonLoader from '@components/_base/skeleton-loader/SkeletonLoader.svelte'
import type { PageData } from './$types'
import { shortenAddress } from '@utils'
import Link from '@components/_base/link/Link.svelte'

export let data: PageData
</script>

<div class="tx-summary card">
<div class="message-box">
<div class="header">
<div class="header-section">
{#await data.subintent}
<SkeletonLoader />
{:then { status }}
{#if status === 'CommittedSuccess'}
<h4>Finalized at:</h4>
{/if}
{/await}
</div>
{#await data.subintent}
<SkeletonLoader />
{:then { status }}
<div
class="header-section status-section"
class:success={status === 'CommittedSuccess'}
>
<div class="main-status">
{#if status === 'CommittedSuccess'}
<IconNew icon={Checkmark} />
{/if}
{status === 'CommittedSuccess' ? 'Success' : 'Unknown Status'}
</div>
</div>
{/await}
</div>
</div>

{#await data.subintent then { finalizedAt }}
{#if finalizedAt}
<Link
url="/transaction/{finalizedAt}"
text={shortenAddress(finalizedAt)}
/>
{/if}
{/await}
</div>

<style lang="scss">
.header-section {
display: flex;
flex-direction: column;
gap: var(--spacing-md);

&.status-section {
align-items: flex-end;

&.success {
color: var(--theme-success-primary);
.main-status {
color: var(--theme-success-primary);
}
}
}
}

.manifest-class {
color: var(--color-grey-2);
}

.main-status {
display: flex;
font-size: var(--text-xl);
align-items: center;
gap: var(--spacing-sm);
}

.tx-summary {
.message-box {
display: flex;
flex-direction: column;

.header {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--spacing-2xl);
font-size: var(--text-lg);
font-weight: var(--font-weight-bold-2);
}
}
}
</style>
Loading
Loading