Skip to content

Commit f48d0b6

Browse files
committed
feat: add next leader to the table
1 parent 5ce90e8 commit f48d0b6

12 files changed

+159
-97
lines changed

solfees-fe/src/common/isReal.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { CustomRow, CustomRowBasic } from "./prepareValidatorRow.ts";
2+
3+
// TODO probably we should change CommitmentStatus to Enum and compare as if(elt.commitment in CommitmentStatus) to find extended statuses
4+
export function isReal(
5+
slot: CustomRow["slots"][number] | CustomRowBasic["slots"][number]
6+
): slot is CustomRowBasic["slots"][number] {
7+
return slot.commitment !== "next-leader" && slot.commitment !== "scheduled";
8+
}

solfees-fe/src/common/prepareValidatorRow.ts

+22-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { CommitmentStatus, SlotContent } from "../store/websocketStore.ts";
22

3-
export type CustomRow = {
3+
export type ExtendedCommitmentStatus = CommitmentStatus | "next-leader" | "scheduled";
4+
type ExtendedSlotContent = Omit<SlotContent, "commitment"> & {
5+
commitment: ExtendedCommitmentStatus;
6+
};
7+
8+
export type CustomRowBasic = {
49
id: string;
510
leader: string;
611
slots: {
7-
commitment: CommitmentStatus;
12+
commitment: ExtendedCommitmentStatus;
813
slot: number;
914
}[];
1015
transactions: {
@@ -22,15 +27,18 @@ export type CustomRow = {
2227
fee1: number[];
2328
fee2: number[];
2429
};
30+
export type CustomRow = Omit<CustomRowBasic, "slots"> & {
31+
slots: { slot: number; commitment: ExtendedCommitmentStatus }[];
32+
};
2533
type FxType = (arg: [id: string, slots: SlotContent[]]) => CustomRow;
2634

27-
const getFakeSlot = (leader: string, newSlotId: number): SlotContent => ({
35+
export const getFakeSlot = (leader: string, newSlotId: number): ExtendedSlotContent => ({
2836
leader,
2937
slot: newSlotId,
3038
totalTransactionsFiltered: 0,
3139
feeLevels: [0, 0, 0],
3240
feeAverage: 0,
33-
commitment: "fake" as "confirmed",
41+
commitment: "scheduled",
3442
totalUnitsConsumed: 0,
3543
totalFee: 0,
3644
hash: "",
@@ -40,7 +48,7 @@ const getFakeSlot = (leader: string, newSlotId: number): SlotContent => ({
4048
time: 0,
4149
});
4250

43-
function fillGaps(list: SlotContent[]): SlotContent[] {
51+
function fillGaps(list: SlotContent[]): ExtendedSlotContent[] {
4452
if (!list.length) return list;
4553
if (list.length === 4) return list;
4654
const groupIdx = ((list?.[0]?.slot || 0) / 4) | 0;
@@ -51,7 +59,7 @@ function fillGaps(list: SlotContent[]): SlotContent[] {
5159
const isFourth = list.find((elt) => (elt.slot / 4) % 1 === 0.75);
5260

5361
const newLeader = list?.[0]?.leader || "UNKNOWN";
54-
const newList: typeof list = [];
62+
const newList: ExtendedSlotContent[] = [];
5563
isFirst ? newList.push({ ...isFirst }) : newList.push(getFakeSlot(newLeader, groupIdx * 4));
5664
isSecond ? newList.push({ ...isSecond }) : newList.push(getFakeSlot(newLeader, groupIdx * 4 + 1));
5765
isThird ? newList.push({ ...isThird }) : newList.push(getFakeSlot(newLeader, groupIdx * 4 + 2));
@@ -66,6 +74,13 @@ function fillGaps(list: SlotContent[]): SlotContent[] {
6674
export const prepareValidatorRow: FxType = ([id, rawSlots]) => {
6775
const slots = fillGaps(rawSlots);
6876
const leader = slots[0]?.leader || "UNKNOWN";
77+
return prepareSingeRow(id, leader, slots);
78+
};
79+
export function prepareSingeRow(
80+
id: string,
81+
leader: string,
82+
slots: ExtendedSlotContent[]
83+
): CustomRow {
6984
return {
7085
id,
7186
leader,
@@ -97,4 +112,4 @@ export const prepareValidatorRow: FxType = ([id, rawSlots]) => {
97112
fee1: slots.map((elt) => elt.feeLevels[1] || 0),
98113
fee2: slots.map((elt) => elt.feeLevels[2] || 0),
99114
};
100-
};
115+
}

solfees-fe/src/components/layout/NextSlotInformer.tsx

-27
This file was deleted.
+32-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Text } from "@consta/uikit/Text";
22
import { CustomRow } from "../../common/prepareValidatorRow.ts";
33
import { withTooltip } from "@consta/uikit/withTooltip";
4+
import { isReal } from "../../common/isReal.ts";
45

56
interface Props {
67
items: CustomRow["computeUnits"];
8+
slots: CustomRow["slots"];
79
}
810

911
const TextWithTooltip = withTooltip({ content: "Top tooltip" })(Text);
@@ -26,25 +28,39 @@ const amountFormatter = (amount: number): string => {
2628
return result;
2729
};
2830

29-
export const ComputeUnits = ({ items }: Props) => {
31+
export const ComputeUnits = ({ items, slots }: Props) => {
3032
return (
3133
<div className="px-3 min-w-0">
32-
{items.map((elt, idx) => (
33-
<div key={elt.amount === 0 ? idx : elt.amount} className="flex justify-end">
34-
<TextWithTooltip
35-
className="flex justify-end text-right gap-1 shrink-0"
36-
tooltipProps={{
37-
content: tooltipFormatter.format(elt.amount),
38-
direction: "leftCenter",
39-
appearTimeout: 0,
40-
exitTimeout: 0,
41-
}}
34+
{items.map((elt, idx) => {
35+
const currentSlot = slots[idx];
36+
const isFilled = currentSlot ? isReal(currentSlot) : false;
37+
38+
return (
39+
<div
40+
key={elt.amount === 0 ? idx : elt.amount}
41+
className="flex justify-end whitespace-pre"
4242
>
43-
<Text font="mono">{amountFormatter(elt.amount)}</Text>
44-
<Text font="mono">({percentFormatter.format(elt.percent).replace(/,/g, " ")})</Text>
45-
</TextWithTooltip>
46-
</div>
47-
))}
43+
{isFilled ? (
44+
<TextWithTooltip
45+
className="flex justify-end text-right gap-1 shrink-0"
46+
tooltipProps={{
47+
content: tooltipFormatter.format(elt.amount),
48+
direction: "leftCenter",
49+
appearTimeout: 0,
50+
exitTimeout: 0,
51+
}}
52+
>
53+
<Text font="mono">{amountFormatter(elt.amount)}</Text>
54+
<Text font="mono">({percentFormatter.format(elt.percent).replace(/,/g, " ")})</Text>
55+
</TextWithTooltip>
56+
) : (
57+
<Text font="mono" className="flex-shrink-0">
58+
{" "}
59+
</Text>
60+
)}
61+
</div>
62+
);
63+
})}
4864
</div>
4965
);
5066
};
+14-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Text } from "@consta/uikit/Text";
22
import { CustomRow } from "../../common/prepareValidatorRow.ts";
3+
import { isReal } from "../../common/isReal.ts";
34

45
interface Props {
5-
list: CustomRow["earnedSol"];
6+
items: CustomRow["earnedSol"];
7+
slots: CustomRow["slots"];
68
}
79

810
function formatValue(value: number): string {
@@ -15,14 +17,19 @@ function formatValue(value: number): string {
1517
.replace(/\s/g, "")
1618
: value.toFixed(9);
1719
}
18-
export const EarnedSol = ({ list }: Props) => {
20+
export const EarnedSol = ({ items, slots }: Props) => {
1921
return (
2022
<div className="px-3 text-right">
21-
{list.map((elt, idx) => (
22-
<Text key={idx} font="mono">
23-
{formatValue(elt)}
24-
</Text>
25-
))}
23+
{items.map((elt, idx) => {
24+
const currentSlot = slots[idx];
25+
const isFilled = currentSlot ? isReal(currentSlot) : false;
26+
27+
return (
28+
<Text key={idx} font="mono" className="whitespace-pre">
29+
{isFilled ? formatValue(elt) : " "}
30+
</Text>
31+
);
32+
})}
2633
</div>
2734
);
2835
};
+15-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import { Text } from "@consta/uikit/Text";
2+
import { CustomRow } from "../../common/prepareValidatorRow.ts";
3+
import { isReal } from "../../common/isReal.ts";
24

35
interface Props {
4-
list: number[];
6+
items: number[];
7+
slots: CustomRow["slots"];
58
}
6-
export const SimpleCell = ({ list }: Props) => {
9+
export const SimpleCell = ({ items, slots }: Props) => {
710
return (
811
<div className="px-3 text-right">
9-
{list.map((elt, idx) => (
10-
<Text key={idx} font="mono">
11-
{elt.toLocaleString("en-US", { maximumFractionDigits: 2 })}
12-
</Text>
13-
))}
12+
{items.map((elt, idx) => {
13+
const currentSlot = slots[idx];
14+
const isFilled = currentSlot ? isReal(currentSlot) : false;
15+
16+
return (
17+
<Text key={idx} font="mono" className="whitespace-pre">
18+
{isFilled ? elt.toLocaleString("en-US", { maximumFractionDigits: 2 }) : " "}
19+
</Text>
20+
);
21+
})}
1422
</div>
1523
);
1624
};

solfees-fe/src/components/ui/Slots.tsx

+13-8
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,26 @@ import { IconCopy } from "@consta/icons/IconCopy";
99
import { IconWarning } from "@consta/icons/IconWarning";
1010
import { IconProcessing } from "@consta/icons/IconProcessing";
1111
import { IconWatchStroked } from "@consta/icons/IconWatchStroked";
12+
import { CustomRow, ExtendedCommitmentStatus } from "../../common/prepareValidatorRow.ts";
13+
import { IconLoading } from "@consta/icons/IconLoading";
1214

1315
interface Props {
14-
items: {
15-
commitment: CommitmentStatus;
16-
slot: number;
17-
}[];
16+
items: CustomRow["slots"];
1817
}
1918

2019
type ComProps = {
21-
value: CommitmentStatus;
20+
value: CustomRow["slots"][number]["commitment"];
2221
};
2322

24-
const statuses: (CommitmentStatus | "fake")[] = ["processed", "confirmed", "finalized", "fake"];
25-
const colors: IconPropView[] = ["link", "primary", "success", "ghost"];
26-
const icons = [IconProcessing, IconCheck, IconAllDone, IconWatchStroked];
23+
const statuses: ExtendedCommitmentStatus[] = [
24+
"processed",
25+
"confirmed",
26+
"finalized",
27+
"scheduled",
28+
"next-leader",
29+
];
30+
const colors: IconPropView[] = ["link", "primary", "success", "ghost", "disabled"];
31+
const icons = [IconProcessing, IconCheck, IconAllDone, IconLoading, IconWatchStroked];
2732
export const AnimateIconBaseIcons = ({ value }: ComProps) => {
2833
const idx = statuses.findIndex((elt) => elt === value);
2934
return (

solfees-fe/src/components/ui/Transactions.tsx

+12-6
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { Text } from "@consta/uikit/Text";
22
import { useWebSocketStore } from "../../store/websocketStore.ts";
33
import { useShallow } from "zustand/react/shallow";
44
import { CustomRow } from "../../common/prepareValidatorRow.ts";
5+
import { isReal } from "../../common/isReal.ts";
56

67
interface Props {
78
items: CustomRow["transactions"];
9+
slots: CustomRow["slots"];
810
}
911

1012
function buildTransactions(slots: CustomRow["transactions"], withFiltered = false) {
@@ -32,17 +34,21 @@ function buildTransactions(slots: CustomRow["transactions"], withFiltered = fals
3234
return alignedWithKeys;
3335
}
3436

35-
export const Transactions = ({ items }: Props) => {
37+
export const Transactions = ({ items, slots }: Props) => {
3638
const hasRW = useWebSocketStore(useShallow((state) => !!state.readwriteKeys.length));
3739
const hasRO = useWebSocketStore(useShallow((state) => !!state.readonlyKeys.length));
3840

3941
return (
4042
<div className="px-3 text-right">
41-
{buildTransactions(items, hasRO || hasRW).map((elt) => (
42-
<Text key={elt.key} font="mono" className="whitespace-pre">
43-
{elt.value}
44-
</Text>
45-
))}
43+
{buildTransactions(items, hasRO || hasRW).map((elt, idx) => {
44+
const currentSlot = slots[idx];
45+
const isFilled = currentSlot ? isReal(currentSlot) : false;
46+
return (
47+
<Text key={elt.key} font="mono" className="whitespace-pre">
48+
{isFilled ? elt.value : " "}
49+
</Text>
50+
);
51+
})}
4652
</div>
4753
);
4854
};

solfees-fe/src/components/ui/Validator.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import { CustomRow } from "../../common/prepareValidatorRow.ts";
2+
13
interface Props {
24
leader: string;
5+
slots: CustomRow["slots"];
36
}
4-
export const Validator = ({ leader }: Props) => {
7+
export const Validator = ({ leader, slots }: Props) => {
8+
const isNext = slots.some((elt) => elt.commitment === "next-leader");
59
return (
610
<div className="px-3 w-full h-full flex flex-col flex-nowrap justify-center">
7-
<h1 className="font-bold">Validator Name:</h1>
11+
<h1 className="font-bold">{isNext ? "Next" : ""} Validator Name:</h1>
812
<a
913
className="hover:underline"
1014
href={`https://www.validators.app/validators/${leader}?locale=en&network=mainnet`}

0 commit comments

Comments
 (0)