invert highlight on finalized table

This commit is contained in:
Victor Oliva
2024-11-09 09:26:30 +07:00
parent af376fca84
commit f585308e64
9 changed files with 163 additions and 162 deletions
+1 -1
View File
@@ -14,7 +14,7 @@
</head>
<body class="karla-400 dark">
<div id="root" class="flex justify-center"></div>
<div id="root" class="flex justify-center bg-white dark:bg-black"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
+1 -1
View File
@@ -12,7 +12,7 @@ export const Loading: FC<PropsWithChildren> = ({ children }) => {
return (
<div
className={twMerge(
"font-mono text-center p-2 text-sm text-polkadot-600 opacity-0 transition-opacity h-48 flex items-center justify-center",
"font-mono text-center p-2 text-sm text-foreground/70 opacity-0 transition-opacity h-48 flex items-center justify-center",
visible && "opacity-100",
)}
>
+2 -4
View File
@@ -7,10 +7,6 @@ dialog {
@apply bg-transparent;
}
:root {
color-scheme: dark;
}
.karla-400 {
font-family: "Karla", sans-serif;
font-optical-sizing: auto;
@@ -67,6 +63,7 @@ dialog {
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
color-scheme: light;
}
.dark {
@@ -94,6 +91,7 @@ dialog {
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
color-scheme: dark;
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ import { Link } from "react-router-dom"
import { map } from "rxjs"
import { blockInfoState$ } from "./block.state"
import { BlockStatusIcon, statusText } from "./Detail/BlockState"
import { filterEvt } from "./Events"
import { filterEvt } from "./events.state"
import { CopyText } from "@/components/Copy"
const maxBlockWeight$ = state(
+2 -1
View File
@@ -111,6 +111,7 @@ export const BlockTable = () => {
number={row.block.number}
finalized={finalized.number}
firstInGroup={row.position === 0}
idx={i}
>
{rows[i - 1]?.block.number !== row.block.number ? (
<td
@@ -136,7 +137,7 @@ export const BlockTable = () => {
<ForkRenderer row={row} />
</td>
<td className="max-w-xs w-full">
<div className="flex gap-1">
<div className="flex gap-1 pr-1">
<Popover content={<BlockPopover hash={row.block.hash} />}>
<button
className={twMerge(
+35
View File
@@ -0,0 +1,35 @@
import { CopyText } from "@/components/Copy"
import { JsonDisplay } from "@/components/JsonDisplay"
import { FC } from "react"
import { Link } from "react-router-dom"
import { BlockStatusIcon, statusText } from "./Detail/BlockState"
import { EventInfo, eventKey } from "./events.state"
export const EventPopover: FC<{ event: EventInfo }> = ({ event }) => {
return (
<div>
<div className="flex justify-between items-center gap-4 mb-2">
<h3 className="font-bold text-lg">
Event{" "}
<Link
to={`${event.hash}#event=${event.index}`}
className="text-primary/70 hover:text-primary"
>
{eventKey(event)}
</Link>
</h3>
<p className="flex gap-1">
Status:
<BlockStatusIcon state={event.status} />
{statusText[event.status]}
</p>
</div>
<p className="overflow-hidden text-ellipsis whitespace-nowrap flex items-center gap-2">
Block: {event.hash.slice(0, 18)}…
<CopyText text={event.hash} binary />
</p>
<p className="font-bold">{`${event.event.type}.${event.event.value.type}`}</p>
<JsonDisplay src={event.event.value.value} />
</div>
)
}
+8 -151
View File
@@ -1,23 +1,10 @@
import { Popover } from "@/components/Popover"
import type { SystemEvent } from "@polkadot-api/observable-client"
import { state, useStateObservable } from "@react-rxjs/core"
import { combineKeys } from "@react-rxjs/utils"
import { filter, map, takeWhile } from "rxjs"
import { useStateObservable } from "@react-rxjs/core"
import { twMerge } from "tailwind-merge"
import {
blockInfo$,
BlockState,
finalized$,
recordedBlocks$,
} from "./block.state"
import { MAX_LENGTH } from "./BlockTable"
import { FC } from "react"
import { JsonDisplay } from "@/components/JsonDisplay"
import { groupBy } from "@/lib/groupBy"
import { Link } from "react-router-dom"
import { BlockStatusIcon, statusText } from "./Detail/BlockState"
import { finalized$ } from "./block.state"
import { EventPopover } from "./EventPopover"
import { eventKey, recentEvents$ } from "./events.state"
import * as Finalizing from "./FinalizingTable"
import { CopyText } from "@/components/Copy"
export const Events = () => {
const events = useStateObservable(recentEvents$)
@@ -49,6 +36,7 @@ export const Events = () => {
key={`${evt.hash}-${evt.extrinsicNumber}-${evt.index}`}
number={events.length - idx}
finalized={events.length - finalizedIdx}
idx={idx}
firstInGroup
>
{eventKey(events[idx - 1]) !== key && (
@@ -59,11 +47,10 @@ export const Events = () => {
twMerge(
idx > 0 ? "border-y" : "border-b",
"border-card-foreground/25",
idx === finalizedIdx && "border-t-card-foreground/50",
idx === finalizedIdx - span &&
"border-b-card-foreground/50",
),
idx === finalizedIdx &&
"border-t-border-card-foreground/50",
idx === finalizedIdx - span &&
"border-b-border-card-foreground/50",
)}
rowSpan={span}
>
@@ -89,133 +76,3 @@ export const Events = () => {
</Finalizing.Root>
)
}
const EventPopover: FC<{ event: EventInfo }> = ({ event }) => {
return (
<div>
<div className="flex justify-between items-center gap-4 mb-2">
<h3 className="font-bold text-lg">
Event{" "}
<Link
to={`${event.hash}#event=${event.index}`}
className="text-primary/70 hover:text-primary"
>
{eventKey(event)}
</Link>
</h3>
<p className="flex gap-1">
Status:
<BlockStatusIcon state={event.status} />
{statusText[event.status]}
</p>
</div>
<p className="overflow-hidden text-ellipsis whitespace-nowrap flex items-center gap-2">
Block: {event.hash.slice(0, 18)}…
<CopyText text={event.hash} binary />
</p>
<p className="font-bold">{`${event.event.type}.${event.event.value.type}`}</p>
<JsonDisplay src={event.event.value.value} />
</div>
)
}
const blackList = new Set([
"System.*",
"Balances.Deposit",
"Treasury.Deposit",
"ParaInclusion.*",
"Balances.Withdraw",
"Balances.Endowed",
"Balances.Locked",
"TransactionPayment.TransactionFeePaid",
"Staking.Rewarded",
])
export const filterEvt = (evt: SystemEvent) =>
!blackList.has(`${evt.event.type}.*`) &&
!blackList.has(`${evt.event.type}.${evt.event.value.type}`)
interface EventInfo {
status: BlockState
hash: string
number: number
event: SystemEvent["event"]
extrinsicNumber: number
index: number
}
interface EventEllipsis {
number: number
extrinsicNumber: number
length: number
hash: string
index: number
}
const eventKey = (evt: EventInfo | EventEllipsis) =>
`${evt?.number.toLocaleString()}-${evt?.extrinsicNumber}`
const MAX_GROUP_LENGTH = 7
const recentEvents$ = state(
combineKeys(recordedBlocks$, (key) =>
blockInfo$(key).pipe(
map((block) => ({
status: block.status,
hash: block.hash,
number: block.number,
events: block.events
?.map((evt, index) => ({ ...evt, index }))
.filter((evt) => evt.phase.type === "ApplyExtrinsic")
.filter(filterEvt)
.map((evt) => ({
index: evt.index,
event: evt.event,
extrinsicNumber: (evt.phase as any).value as number,
})),
})),
takeWhile(
(r) =>
(r.status !== BlockState.Finalized &&
r.status !== BlockState.Pruned) ||
r.events == null,
true,
),
filter((result) => Boolean(result.events?.length)),
),
).pipe(
map((events) =>
[...events.values()]
.reverse()
.filter(
(evt) =>
evt.status === BlockState.Best ||
evt.status === BlockState.Finalized,
)
.flatMap(({ status, hash, number, events }) => {
const eventInfo = events!.map(
({ event, extrinsicNumber, index }): EventInfo => ({
status,
hash,
number,
event,
extrinsicNumber,
index,
}),
)
const groupedEventInfo = groupBy(eventInfo, eventKey)
return Object.values(groupedEventInfo).flatMap((group) => {
if (group.length > MAX_GROUP_LENGTH) {
const ellipsis: EventEllipsis = {
length: group.length - MAX_GROUP_LENGTH + 1,
extrinsicNumber: group[0].extrinsicNumber,
number,
hash,
index: group.length,
}
return [...group.slice(0, MAX_GROUP_LENGTH - 1), ellipsis]
}
return group
})
})
.slice(0, MAX_LENGTH),
),
),
[],
)
+5 -3
View File
@@ -16,12 +16,14 @@ export const Row: FC<
number: number
finalized: number
firstInGroup: boolean
idx: number
}>
> = ({ children, number, finalized, firstInGroup }) => (
> = ({ children, number, finalized, firstInGroup, idx }) => (
<tr
className={twMerge(
number <= finalized ? "bg-primary/5" : "",
number === finalized &&
number > finalized ? "bg-muted-foreground/5" : "",
idx > 0 &&
number === finalized &&
firstInGroup &&
"border-t border-card-foreground/50",
)}
+108
View File
@@ -0,0 +1,108 @@
import { groupBy } from "@/lib/groupBy"
import type { SystemEvent } from "@polkadot-api/observable-client"
import { state } from "@react-rxjs/core"
import { combineKeys } from "@react-rxjs/utils"
import { filter, map, takeWhile } from "rxjs"
import { blockInfo$, BlockState, recordedBlocks$ } from "./block.state"
import { MAX_LENGTH } from "./BlockTable"
const blackList = new Set([
"System.*",
"Balances.Deposit",
"Treasury.Deposit",
"ParaInclusion.*",
"Balances.Withdraw",
"Balances.Endowed",
"Balances.Locked",
"TransactionPayment.TransactionFeePaid",
"Staking.Rewarded",
])
export const filterEvt = (evt: SystemEvent) =>
!blackList.has(`${evt.event.type}.*`) &&
!blackList.has(`${evt.event.type}.${evt.event.value.type}`)
export interface EventInfo {
status: BlockState
hash: string
number: number
event: SystemEvent["event"]
extrinsicNumber: number
index: number
}
interface EventEllipsis {
number: number
extrinsicNumber: number
length: number
hash: string
index: number
}
export const eventKey = (evt: EventInfo | EventEllipsis) =>
`${evt?.number.toLocaleString()}-${evt?.extrinsicNumber}`
const MAX_GROUP_LENGTH = 7
export const recentEvents$ = state(
combineKeys(recordedBlocks$, (key) =>
blockInfo$(key).pipe(
map((block) => ({
status: block.status,
hash: block.hash,
number: block.number,
events: block.events
?.map((evt, index) => ({ ...evt, index }))
.filter((evt) => evt.phase.type === "ApplyExtrinsic")
.filter(filterEvt)
.map((evt) => ({
index: evt.index,
event: evt.event,
extrinsicNumber: (evt.phase as any).value as number,
})),
})),
takeWhile(
(r) =>
(r.status !== BlockState.Finalized &&
r.status !== BlockState.Pruned) ||
r.events == null,
true,
),
filter((result) => Boolean(result.events?.length)),
),
).pipe(
map((events) =>
[...events.values()]
.reverse()
.filter(
(evt) =>
evt.status === BlockState.Best ||
evt.status === BlockState.Finalized,
)
.flatMap(({ status, hash, number, events }) => {
const eventInfo = events!.map(
({ event, extrinsicNumber, index }): EventInfo => ({
status,
hash,
number,
event,
extrinsicNumber,
index,
}),
)
const groupedEventInfo = groupBy(eventInfo, eventKey)
return Object.values(groupedEventInfo).flatMap((group) => {
if (group.length > MAX_GROUP_LENGTH) {
const ellipsis: EventEllipsis = {
length: group.length - MAX_GROUP_LENGTH + 1,
extrinsicNumber: group[0].extrinsicNumber,
number,
hash,
index: group.length,
}
return [...group.slice(0, MAX_GROUP_LENGTH - 1), ellipsis]
}
return group
})
})
.slice(0, MAX_LENGTH),
),
),
[],
)