Skip to content
Open
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
18 changes: 17 additions & 1 deletion src/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, describe, it } from "vitest";
import { getDurationText } from "../utils";
import { formatTimeNanos, getDurationText } from "../utils";
import { Duration } from "luxon";

describe("getDurationText", () => {
Expand Down Expand Up @@ -144,3 +144,19 @@ describe("getDurationText", () => {
});
});
});

describe("formatTimeNanos", () => {
it("formats millis and nanos correctly", () => {
expect(formatTimeNanos(1764892025356640223n)).toEqual({
inMillis: "Dec 4, 11:47:05.356 PM UTC",
inNanos: "Dec 4, 11:47:05.356640223 PM UTC",
});
});

it("zero prefixes nanos correctly", () => {
expect(formatTimeNanos(1764921600000000123n)).toEqual({
inMillis: "Dec 5, 8:00:00.000 AM UTC",
inNanos: "Dec 5, 8:00:00.000000123 AM UTC",
});
});
});
30 changes: 17 additions & 13 deletions src/features/SlotDetails/DetailedSlotStats/SlotDetailsHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Flex, Text } from "@radix-ui/themes";
import { Flex, Text, Tooltip } from "@radix-ui/themes";
import PeerIcon from "../../../components/PeerIcon";
import SlotClient from "../../../components/SlotClient";
import { useSlotInfo } from "../../../hooks/useSlotInfo";
Expand All @@ -10,9 +10,9 @@ import {
} from "../../../hooks/useSlotQuery";
import { epochAtom } from "../../../atoms";
import { useMemo } from "react";
import { DateTime } from "luxon";

import styles from "./detailedSlotStats.module.css";
import { formatTimeNanos } from "../../../utils";

export default function SlotDetailsHeader() {
const slot = useAtomValue(selectedSlotAtom);
Expand All @@ -25,15 +25,7 @@ export default function SlotDetailsHeader() {

const slotTime = useMemo(() => {
if (!slotPublish?.completed_time_nanos) return;
const seconds = Number(slotPublish.completed_time_nanos / 1_000_000_000n);
return DateTime.fromSeconds(seconds).toLocaleString({
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
timeZoneName: "short",
});
return formatTimeNanos(slotPublish.completed_time_nanos);
}, [slotPublish]);

if (slot === undefined) return;
Expand All @@ -53,7 +45,11 @@ export default function SlotDetailsHeader() {
icon={countryFlag}
/>
)}
<HorizontalLabelValue label="Slot Time" value={slotTime} />
<HorizontalLabelValue
label="Slot Time"
value={slotTime?.inMillis}
valueTooltip={slotTime?.inNanos}
/>
<HorizontalLabelValue
label="Block Hash"
value={schedulerStats?.block_hash}
Expand Down Expand Up @@ -82,18 +78,26 @@ export default function SlotDetailsHeader() {
interface HorizontalLabelValueProps {
label: string;
value?: string | number;
valueTooltip?: string | number;
icon?: string;
}

function HorizontalLabelValue({
label,
value,
valueTooltip,
icon,
}: HorizontalLabelValueProps) {
return (
<Flex gap="1">
<Text className={styles.label}>{label}</Text>
<Text className={styles.value}>{value}</Text>
{valueTooltip ? (
<Tooltip content={valueTooltip}>
<Text className={styles.value}>{value}</Text>
</Tooltip>
) : (
<Text className={styles.value}>{value}</Text>
)}
{icon && <Text className={styles.value}>{icon}</Text>}
</Flex>
);
Expand Down
31 changes: 31 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,34 @@ export function isAgave(client: ClientName) {
client === ClientName.AgaveBam
);
}

export function formatTimeNanos(time: bigint) {
const millis = Number(time / 1_000_000n);
const remainderNanos = Number(time % 1_000_000n);
const date = new Date(millis);
const formatter = new Intl.DateTimeFormat(undefined, {
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
timeZoneName: "short",
timeZone: "UTC",
fractionalSecondDigits: 3,
});
const formattedParts = formatter.formatToParts(date);
const zeroPrefixedNanos = remainderNanos.toString().padStart(6, "0");

let inMillis = "";
let inNanos = "";

for (const part of formattedParts) {
inMillis += part.value;
inNanos += part.value;
if (part.type === "fractionalSecond") {
inNanos += zeroPrefixedNanos;
}
}

return { inMillis, inNanos };
}