invert highlight on finalized table
This commit is contained in:
+1
-1
@@ -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>
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
[],
|
||||
)
|
||||
|
||||
@@ -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",
|
||||
)}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
[],
|
||||
)
|
||||
Reference in New Issue
Block a user