Skip to content

Commit

Permalink
Index status explorer page (#2009)
Browse files Browse the repository at this point in the history
  • Loading branch information
cor authored May 31, 2024
2 parents c195d8c + 039cc93 commit 282dacb
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 161 deletions.
2 changes: 1 addition & 1 deletion app/src/lib/components/ui/table/table-cell.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export { className as class }
</script>

<td
class={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
class={cn('px-2 py-1 align-middle [&:has([role=checkbox])]:pr-0', className)}
{...$$restProps}
on:click
on:keydown
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/components/ui/table/table-head.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export { className as class }

<th
class={cn(
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
'h-12 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
className,
)}
{...$$restProps}
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/components/ui/table/table-row.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export { className as class }

<tr
class={cn(
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
'border-b border-secondary transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
className,
)}
{...$$restProps}
Expand Down
18 changes: 4 additions & 14 deletions app/src/lib/graphql/documents/index-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,14 @@ import { graphql } from "gql.tada"

export const indexStatusQuery = graphql(/* GraphQL */ `
query IndexStatusQuery {
data: v0_index_status(order_by: { id: asc }) {
id
v0_index_status(order_by: { id: asc }) {
chain_id
display_name
height
time
}
}
`)

export const indexStatusSubscription = graphql(/* GraphQL */ `
subscription IndexStatusSubscription {
data: v0_index_status(order_by: { id: asc }) {
id
chain_id
display_name
height
time
status
timestamp
tip_age_seconds
}
}
`)
2 changes: 0 additions & 2 deletions app/src/routes/explorer/(components)/cell-plain-text.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,3 @@ export let value: string
</script>

<p {...$$restProps}>{value}</p>

<style lang="postcss"></style>
7 changes: 7 additions & 0 deletions app/src/routes/explorer/(components)/cell-status.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import { cn } from "$lib/utilities/shadcn.ts"
export let value: string
</script>

<div class={cn(value === 'HEALTHY' ? 'bg-green-500 dark:bg-green-800' : 'bg-red-500 dark:bg-red-800', 'font-bold text-white inline px-2 py-1 rounded')} {...$$restProps}>{value}</div>
96 changes: 96 additions & 0 deletions app/src/routes/explorer/(components)/table.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script lang="ts" generics="T extends object" >
import { derived, get } from "svelte/store"
import {
flexRender,
type ColumnDef,
getCoreRowModel,
type TableOptions,
createSvelteTable,
getFilteredRowModel,
getPaginationRowModel
} from "@tanstack/svelte-table"
import { writable, type Writable } from "svelte/store"
import { cn } from "$lib/utilities/shadcn.ts"
import * as Table from "$lib/components/ui/table"
import { createVirtualizer } from "@tanstack/svelte-virtual"
import * as Card from "$lib/components/ui/card/index.ts"
export let columns: Array<ColumnDef<any>>
// https://github.com/TanStack/table/issues/4241
// @ts-ignore
export let dataStore: Writable<Array<any>>
const options = writable<TableOptions<any>>({
data: $dataStore,
enableHiding: true,
enableFilters: true,
// https://github.com/TanStack/table/issues/4241
// @ts-ignore
columns,
autoResetPageIndex: true,
enableColumnFilters: true,
enableColumnResizing: true,
enableMultiRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel()
})
let virtualListElement: HTMLDivElement
const table = createSvelteTable(options)
const rows = derived(table, $t => $t.getRowModel().rows)
$: virtualizer = createVirtualizer<HTMLDivElement, HTMLTableRowElement>({
overscan: 20,
count: $rows.length,
estimateSize: () => 34,
getScrollElement: () => virtualListElement
})
$: dataStore.subscribe(() => {
if (!$dataStore) return
$table.setPageSize($dataStore.length)
options.update(options => ({ ...options, data: $dataStore as unknown as Array<T> }))
})
</script>

<Card.Root>
<div bind:this={virtualListElement} >
<Table.Root>
<Table.Header>
{#each $table.getHeaderGroups() as headerGroup (headerGroup.id)}
<Table.Row>
{#each headerGroup.headers as header (header.id)}
<Table.Head
colspan={header.colSpan}
class={cn(`w-[${header.getSize()}px]`)}
>
<svelte:component
this={flexRender(header.column.columnDef.header, header.getContext())}
/>
</Table.Head>
{/each}
</Table.Row>
{/each}
</Table.Header>
<Table.Body class={cn(`h-[${$virtualizer.getTotalSize()}px]`)}>
{#each $virtualizer.getVirtualItems() as row, index (row.index)}
<Table.Row
class={cn(
index % 2 === 0 ? 'bg-secondary/10' : 'bg-transparent',
)}
>
{#each $rows[row.index].getVisibleCells() as cell, index (cell.id)}
<Table.Cell>
<svelte:component
this={flexRender(cell.column.columnDef.cell, cell.getContext())}
/>
</Table.Cell>
{/each}
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
</div>
</Card.Root>
5 changes: 5 additions & 0 deletions app/src/routes/explorer/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ onNavigate(navigation => {
})
</script>

<svelte:head>
<title>Union - Explorer</title>
</svelte:head>


<main class="flex flex-row flex-1 overflow-y-hidden">
<Resizable.PaneGroup direction="horizontal" class="w-full rounded-lg bg-re" {onLayoutChange}>
<Resizable.Pane
Expand Down
142 changes: 15 additions & 127 deletions app/src/routes/explorer/blocks/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
<script lang="ts">
import {
flexRender,
type ColumnDef,
getCoreRowModel,
type TableOptions,
createSvelteTable,
getFilteredRowModel,
getPaginationRowModel
} from "@tanstack/svelte-table"
import { flexRender, type ColumnDef } from "@tanstack/svelte-table"
import request from "graphql-request"
import { URLS } from "$lib/constants"
import { writable } from "svelte/store"
import { DurationUnits } from "svelte-ux"
import { cn } from "$lib/utilities/shadcn.ts"
import { CHAIN_MAP } from "$lib/constants/chains"
import * as Table from "$lib/components/ui/table"
import { createQuery } from "@tanstack/svelte-query"
import { removeArrayDuplicates } from "$lib/utilities"
import type { Override } from "$lib/utilities/types.ts"
import { createVirtualizer } from "@tanstack/svelte-virtual"
import Button from "$lib/components/ui/button/button.svelte"
import CellText from "../(components)/cell-plain-text.svelte"
import CellDurationText from "../(components)/cell-duration-text.svelte"
import { cosmosBlocksQuery } from "$lib/graphql/documents/cosmos-blocks.ts"
import Table from "../(components)/table.svelte"
$: cosmosBlocks = createQuery({
queryKey: ["cosmos-blocks"],
refetchInterval: 6_000,
Expand All @@ -44,15 +35,14 @@ $: if (blockData) {
removeArrayDuplicates([...(blockData as Array<CosmosBlock>), ...currentBlocks], "height")
)
}
const defaultColumns: Array<ColumnDef<CosmosBlock>> = [
const columns = [
{
accessorKey: "time",
size: 100,
meta: {
class: "ml-1.5 justify-start"
},
header: info => "Time",
header: () => "Time",
cell: info =>
flexRender(CellDurationText, {
totalUnits: 3,
Expand All @@ -64,7 +54,7 @@ const defaultColumns: Array<ColumnDef<CosmosBlock>> = [
},
{
accessorKey: "height",
header: info => "Height",
header: () => "Height",
size: 100,
meta: {
class: "w-full justify-start"
Expand All @@ -82,138 +72,36 @@ const defaultColumns: Array<ColumnDef<CosmosBlock>> = [
},
{
accessorKey: "chain_id",
header: info => "Chain ID",
header: () => "Chain ID",
meta: {
class: "w-full justify-start"
},
size: 100,
maxSize: 100,
size: 200,
cell: info =>
flexRender(CellText, {
value: CHAIN_MAP[info.getValue() as unknown as number].chainId,
class: "min-w-[105px] text-clip"
value: CHAIN_MAP[info.getValue() as unknown as number].chainId
})
},
{
accessorKey: "hash",
meta: {
class: "w-full justify-start ml-1.5"
class: "w-full justify-start"
},
header: info => flexRender(CellText, { value: "Hash", class: "text-left" }),
header: () => flexRender(CellText, { value: "Hash" }),
size: 1000,
cell: info =>
flexRender(Button, {
class: "py-0 px-2.5 max-w-[600px]",
class: "p-0 font-mono",
variant: "link",
target: "_blank",
value: info.getValue(),
rel: "noopener noreferrer",
href: `https://rpc.testnet.bonlulu.uno/block_by_hash?hash=${info.getValue()}`
})
}
]
const options = writable<TableOptions<CosmosBlock>>({
data: $blocksStore,
enableHiding: true,
enableFilters: true,
columns: defaultColumns,
autoResetPageIndex: true, // Automatically update pagination when data or page size changes
enableColumnFilters: true,
enableColumnResizing: true,
enableMultiRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel()
})
let virtualListElement: HTMLDivElement
const rerender = () =>
options.update(options => ({ ...options, data: $blocksStore as unknown as Array<CosmosBlock> }))
const table = createSvelteTable(options)
$: blocksStore.subscribe(() => {
if (!$blocksStore) return
$table.setPageSize($blocksStore.length)
rerender()
})
$: rows = $table.getRowModel().rows
$: virtualizer = createVirtualizer<HTMLDivElement, HTMLTableRowElement>({
overscan: 20,
count: rows.length,
estimateSize: () => 34,
getScrollElement: () => virtualListElement
})
] as Array<ColumnDef<CosmosBlock>>
</script>

<svelte:head>
<title>Union - Explorer</title>
</svelte:head>
<Table columns={columns} bind:dataStore={blocksStore}/>
{JSON.stringify($blocksStore, null, 2)}

<div
bind:this={virtualListElement}
class={cn('rounded-md border border-secondary border-solid w-full')}
>
<Table.Root class={cn('size-full mx-auto rounded-md w-full')}>
<Table.Header
class={cn('outline outline-1 outline-secondary sticky top-0 left-0 bottom-0 z-50')}
>
{#each $table.getHeaderGroups() as headerGroup (headerGroup.id)}
<Table.Row class="font-bold text-md sticky">
{#each headerGroup.headers as header (header.id)}
<Table.Head
colspan={header.colSpan}
class={cn('text-left px-2 sticky top-0', `w-[${header.getSize()}px]`)}
>
{#if !header.isPlaceholder}
<Button
variant="ghost"
disabled={!header.column.getCanSort()}
on:click={header.column.getToggleSortingHandler()}
class={cn(
header.column.columnDef.meta?.class,
'cursor-pointer select-none capitalize px-0 hover:bg-transparent text-md',
)}
>
<svelte:component
this={flexRender(header.column.columnDef.header, header.getContext())}
/>
</Button>
{/if}
</Table.Head>
{/each}
</Table.Row>
{/each}
</Table.Header>
<Table.Body class={cn('relative', `h-[${$virtualizer.getTotalSize()}px] w-full`)}>
{#each $virtualizer.getVirtualItems() as row, index (row.index)}
<Table.Row
class={cn(
'h-5 text-left overflow-auto',
'border-b-[1px] border-solid border-secondary',
index % 2 === 0 ? 'bg-secondary/10' : 'bg-transparent',
)}
>
{#each rows[row.index].getVisibleCells() as cell, index (cell.id)}
<Table.Cell class={cn('px-2 py-0 text-left')}>
<svelte:component
this={flexRender(cell.column.columnDef.cell, cell.getContext())}
/>
</Table.Cell>
{/each}
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
</div>

<style lang="postcss">
:global(tr td:last-child) {
font-variant-numeric: tabular-nums;
font-variant: common-ligatures tabular-nums;
}
</style>
Loading

0 comments on commit 282dacb

Please sign in to comment.