Skip to content

Commit d772f99

Browse files
asuzuki-jumptradingjherrera-jump
authored andcommitted
feat: shreds card tiles
1 parent 217dda5 commit d772f99

File tree

7 files changed

+156
-77
lines changed

7 files changed

+156
-77
lines changed

src/api/entities.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ export const tileTypeSchema = z.enum([
7979
"snaprd",
8080
"snapdc",
8181
"snapin",
82+
// shred tiles
83+
"netlnk",
84+
"ipecho",
85+
"gossvf",
86+
"gossip",
87+
"repair",
88+
"replay",
89+
"exec",
90+
"tower",
91+
"send",
92+
"rpc",
8293
]);
8394

8495
export const tileSchema = z.object({
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { TileType } from "../../../api/types";
2+
import TileCard from "../SlotPerformance/TileCard";
3+
import styles from "../SlotPerformance/tilesPerformance.module.css";
4+
import { useTilesPerformance } from "../SlotPerformance/useTilesPerformance";
5+
6+
const tiles: TileType[] = [
7+
"netlnk",
8+
"ipecho",
9+
"gossvf",
10+
"gossip",
11+
"repair",
12+
"replay",
13+
"exec",
14+
"tower",
15+
"send",
16+
"rpc",
17+
];
18+
19+
export default function ShredTiles() {
20+
const { tileCounts, groupedLiveIdlePerTile, showLive, queryIdleData } =
21+
useTilesPerformance();
22+
23+
return (
24+
<div className={styles.container}>
25+
{tiles.map((tile) => (
26+
<TileCard
27+
key={tile}
28+
header={tile}
29+
tileCount={tileCounts[tile]}
30+
liveIdlePerTile={groupedLiveIdlePerTile?.[tile]}
31+
queryIdlePerTile={showLive ? undefined : queryIdleData?.[tile]}
32+
statLabel=""
33+
/>
34+
))}
35+
</div>
36+
);
37+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Flex } from "@radix-ui/themes";
2+
import Card from "../../../components/Card";
3+
import CardHeader from "../../../components/CardHeader";
4+
import ShredsTiles from "./ShredsTiles";
5+
6+
export default function ShredsProgression() {
7+
return (
8+
<Card>
9+
<Flex direction="column" height="100%" gap="2">
10+
<CardHeader text="Shreds" />
11+
<ShredsTiles />
12+
</Flex>
13+
</Card>
14+
);
15+
}

src/features/Overview/SlotPerformance/TilesPerformance.tsx

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,10 @@
11
import styles from "./tilesPerformance.module.css";
22
import TileCard from "./TileCard";
3-
import { useAtomValue } from "jotai";
4-
import { tilesAtom } from "../../../api/atoms";
5-
import {
6-
liveTileTimerfallAtom,
7-
selectedSlotAtom,
8-
tileCountAtom,
9-
} from "./atoms";
10-
import { useMemo } from "react";
11-
import type { TileType } from "../../../api/types";
12-
import { tileTypeSchema } from "../../../api/entities";
13-
import { useSlotQueryResponseDetailed } from "../../../hooks/useSlotQuery";
3+
import { useTilesPerformance } from "./useTilesPerformance";
144

155
export default function TilesPerformance() {
16-
const liveTileTimers = useAtomValue(liveTileTimerfallAtom);
17-
const slot = useAtomValue(selectedSlotAtom);
18-
const showLive = !slot;
19-
const tiles = useAtomValue(tilesAtom);
20-
const tileCounts = useAtomValue(tileCountAtom);
21-
22-
const groupedLiveIdlePerTile = liveTileTimers?.reduce<
23-
Record<TileType, number[]>
24-
>(
25-
(grouped, timer, i) => {
26-
const tile = tiles?.[i];
27-
if (!tile) return grouped;
28-
29-
const parsedTileKind = tileTypeSchema.safeParse(tile.kind);
30-
if (parsedTileKind.error) {
31-
return grouped;
32-
}
33-
34-
grouped[parsedTileKind.data] ??= [];
35-
grouped[parsedTileKind.data].push(timer);
36-
37-
return grouped;
38-
},
39-
{} as Record<TileType, number[]>,
40-
);
41-
42-
const query = useSlotQueryResponseDetailed(slot);
43-
44-
const queryIdleData = useMemo(() => {
45-
if (!query.response?.tile_timers?.length || showLive || !tiles) return;
46-
47-
return query.response.tile_timers.reduce<Record<string, number[][]>>(
48-
(aggTimerPerTileType, timers) => {
49-
if (!timers.tile_timers.length) return aggTimerPerTileType;
50-
const idleTimersPerTileType: Record<string, number[]> = {};
51-
52-
if (timers.tile_timers.length !== tiles.length) {
53-
console.warn(
54-
"Length mismatch between tiles and time timers",
55-
timers.tile_timers,
56-
tiles,
57-
);
58-
}
59-
60-
for (let i = 0; i < timers.tile_timers.length; i++) {
61-
const timer = timers.tile_timers[i];
62-
63-
const tile = tiles[i];
64-
if (!tile) continue;
65-
66-
idleTimersPerTileType[tile.kind] ??= [];
67-
idleTimersPerTileType[tile.kind].push(timer);
68-
}
69-
70-
for (const [tile, idlePerTile] of Object.entries(
71-
idleTimersPerTileType,
72-
)) {
73-
aggTimerPerTileType[tile] ??= [];
74-
aggTimerPerTileType[tile].push(idlePerTile);
75-
}
76-
77-
return aggTimerPerTileType;
78-
},
79-
{},
80-
);
81-
}, [query.response?.tile_timers, showLive, tiles]);
6+
const { tileCounts, groupedLiveIdlePerTile, showLive, queryIdleData } =
7+
useTilesPerformance();
828

839
const netType = tileCounts["net"] ? "net" : "sock";
8410

src/features/Overview/SlotPerformance/atoms.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,29 @@ export const liveTileTimerfallAtom = atom((get) => {
130130
return get(tileTimerAtom);
131131
});
132132

133+
export const groupedLiveIdlePerTileAtom = atom((get) => {
134+
const liveTileTimers = get(liveTileTimerfallAtom);
135+
const tiles = get(tilesAtom);
136+
137+
return liveTileTimers?.reduce<Record<TileType, number[]>>(
138+
(grouped, timer, i) => {
139+
const tile = tiles?.[i];
140+
if (!tile) return grouped;
141+
142+
const parsedTileKind = tileTypeSchema.safeParse(tile.kind);
143+
if (parsedTileKind.error) {
144+
return grouped;
145+
}
146+
147+
grouped[parsedTileKind.data] ??= [];
148+
grouped[parsedTileKind.data].push(timer);
149+
150+
return grouped;
151+
},
152+
{} as Record<TileType, number[]>,
153+
);
154+
});
155+
133156
export const snapshotTimerIndicesAtom = atom(
134157
(get): [TileType, number[]][] | undefined => {
135158
const tiles = get(tilesAtom);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { useAtomValue } from "jotai";
2+
import { useMemo } from "react";
3+
import { tilesAtom } from "../../../api/atoms";
4+
import { useSlotQueryResponseDetailed } from "../../../hooks/useSlotQuery";
5+
import {
6+
groupedLiveIdlePerTileAtom,
7+
selectedSlotAtom,
8+
tileCountAtom,
9+
} from "./atoms";
10+
11+
export function useTilesPerformance() {
12+
const slot = useAtomValue(selectedSlotAtom);
13+
const showLive = !slot;
14+
const tiles = useAtomValue(tilesAtom);
15+
const tileCounts = useAtomValue(tileCountAtom);
16+
const groupedLiveIdlePerTile = useAtomValue(groupedLiveIdlePerTileAtom);
17+
18+
const query = useSlotQueryResponseDetailed(slot);
19+
20+
const queryIdleData = useMemo(() => {
21+
if (!query.response?.tile_timers?.length || showLive || !tiles) return;
22+
23+
return query.response.tile_timers.reduce<Record<string, number[][]>>(
24+
(aggTimerPerTileType, timers) => {
25+
if (!timers.tile_timers.length) return aggTimerPerTileType;
26+
const idleTimersPerTileType: Record<string, number[]> = {};
27+
28+
if (timers.tile_timers.length !== tiles.length) {
29+
console.warn(
30+
"Length mismatch between tiles and time timers",
31+
timers.tile_timers,
32+
tiles,
33+
);
34+
}
35+
36+
for (let i = 0; i < timers.tile_timers.length; i++) {
37+
const timer = timers.tile_timers[i];
38+
39+
const tile = tiles[i];
40+
if (!tile) continue;
41+
42+
idleTimersPerTileType[tile.kind] ??= [];
43+
idleTimersPerTileType[tile.kind].push(timer);
44+
}
45+
46+
for (const [tile, idlePerTile] of Object.entries(
47+
idleTimersPerTileType,
48+
)) {
49+
aggTimerPerTileType[tile] ??= [];
50+
aggTimerPerTileType[tile].push(idlePerTile);
51+
}
52+
53+
return aggTimerPerTileType;
54+
},
55+
{},
56+
);
57+
}, [query.response?.tile_timers, showLive, tiles]);
58+
59+
return {
60+
tileCounts,
61+
groupedLiveIdlePerTile,
62+
showLive,
63+
queryIdleData,
64+
};
65+
}

src/features/Overview/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import SlotPerformance from "./SlotPerformance";
44
import ValidatorsCard from "./ValidatorsCard";
55
import SlotStatusCard from "./StatusCard";
66
import EpochCard from "./EpochCard";
7+
import ShredsProgression from "./ShredsProgression";
78

89
export default function Overview() {
910
return (
@@ -14,6 +15,7 @@ export default function Overview() {
1415
<ValidatorsCard />
1516
<TransactionsCard />
1617
</Flex>
18+
<ShredsProgression />
1719
<SlotPerformance />
1820
</Flex>
1921
);

0 commit comments

Comments
 (0)