Add self-bond and operating costs to NodeTable
This commit is contained in:
@@ -212,7 +212,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
{
|
||||
id: "name",
|
||||
header: "",
|
||||
size: 190,
|
||||
size: 210,
|
||||
|
||||
Header: <ColumnHeading>Node</ColumnHeading>,
|
||||
accessorKey: "name",
|
||||
@@ -329,6 +329,40 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "selfBond",
|
||||
header: "Self-bond",
|
||||
accessorKey: "selfBond",
|
||||
Header: <ColumnHeading>Self-bond</ColumnHeading>,
|
||||
Cell: ({ row }) => {
|
||||
const value = row.original.selfBond;
|
||||
let color = "#000000";
|
||||
|
||||
if (value === 0) {
|
||||
color = "#EF4444";
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography
|
||||
variant="body4"
|
||||
sx={{ color, fontWeight: value === 0 ? 400 : 300 }}
|
||||
>
|
||||
{row.original.selfBond} NYM
|
||||
</Typography>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "operatingCosts",
|
||||
header: "Operating costs",
|
||||
accessorKey: "operatingCosts",
|
||||
Header: <ColumnHeading>Operating costs</ColumnHeading>,
|
||||
Cell: ({ row }) => (
|
||||
<Typography variant="body4">
|
||||
{row.original.operatingCosts} NYM
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "profitMarginPercentage",
|
||||
header: "Profit margin",
|
||||
|
||||
@@ -9,6 +9,7 @@ import { countryName } from "../../utils/countryName";
|
||||
import NodeTable from "./NodeTable";
|
||||
import { useState, useEffect } from "react";
|
||||
import AdvancedFilters from "./AdvancedFilters";
|
||||
import { formatBigNum } from "@/utils/formatBigNumbers";
|
||||
|
||||
// Utility function to calculate node saturation point
|
||||
function getNodeSaturationPoint(
|
||||
@@ -44,12 +45,24 @@ const mappedNSApiNodes = (
|
||||
"&"
|
||||
);
|
||||
|
||||
const selfBondFormatted = node.rewarding_details?.operator
|
||||
? formatBigNum(Number(node.rewarding_details.operator) / 1_000_000)
|
||||
: 0;
|
||||
|
||||
const operatingCostsFormatted = node.rewarding_details
|
||||
? Number(
|
||||
node.rewarding_details.cost_params.interval_operating_cost.amount
|
||||
) / 1_000_000
|
||||
: 0;
|
||||
|
||||
return {
|
||||
name: cleanMoniker,
|
||||
nodeId: node.node_id,
|
||||
identity_key: node.identity_key,
|
||||
countryCode: node.geoip?.country || null,
|
||||
countryName: countryName(node.geoip?.country || null) || null,
|
||||
selfBond: selfBondFormatted,
|
||||
operatingCosts: operatingCostsFormatted,
|
||||
profitMarginPercentage: node.rewarding_details
|
||||
? +node.rewarding_details.cost_params.profit_margin_percent * 100
|
||||
: 0,
|
||||
@@ -80,11 +93,60 @@ const NodeTableWithAction = () => {
|
||||
// All hooks at the top!
|
||||
const [activeFilter, setActiveFilter] = useState<
|
||||
"all" | "mixnodes" | "gateways"
|
||||
>("all");
|
||||
const [uptime, setUptime] = useState<[number, number]>([0, 100]);
|
||||
>(() => {
|
||||
const stored = sessionStorage.getItem("nodeTableActiveFilter");
|
||||
return (stored as "all" | "mixnodes" | "gateways") || "all";
|
||||
});
|
||||
const [uptime, setUptime] = useState<[number, number]>(() => {
|
||||
const stored = sessionStorage.getItem("nodeTableUptime");
|
||||
return stored ? JSON.parse(stored) : [0, 100];
|
||||
});
|
||||
const [saturation, setSaturation] = useState<[number, number]>([0, 100]);
|
||||
const [profitMargin, setProfitMargin] = useState<[number, number]>([0, 100]);
|
||||
const [advancedOpen, setAdvancedOpen] = useState(false);
|
||||
const [profitMargin, setProfitMargin] = useState<[number, number]>(() => {
|
||||
const stored = sessionStorage.getItem("nodeTableProfitMargin");
|
||||
return stored ? JSON.parse(stored) : [0, 100];
|
||||
});
|
||||
const [advancedOpen, setAdvancedOpen] = useState(() => {
|
||||
const stored = sessionStorage.getItem("nodeTableAdvancedOpen");
|
||||
return stored ? JSON.parse(stored) : false;
|
||||
});
|
||||
|
||||
// Wrapper functions to handle filter changes and sessionStorage
|
||||
const handleActiveFilterChange = (
|
||||
newFilter: "all" | "mixnodes" | "gateways"
|
||||
) => {
|
||||
setActiveFilter(newFilter);
|
||||
sessionStorage.setItem("nodeTableActiveFilter", newFilter);
|
||||
};
|
||||
|
||||
const handleUptimeChange = (newUptime: [number, number]) => {
|
||||
setUptime(newUptime);
|
||||
sessionStorage.setItem("nodeTableUptime", JSON.stringify(newUptime));
|
||||
};
|
||||
|
||||
const handleSaturationChange = (newSaturation: [number, number]) => {
|
||||
setSaturation(newSaturation);
|
||||
sessionStorage.setItem(
|
||||
"nodeTableSaturation",
|
||||
JSON.stringify(newSaturation)
|
||||
);
|
||||
};
|
||||
|
||||
const handleProfitMarginChange = (newProfitMargin: [number, number]) => {
|
||||
setProfitMargin(newProfitMargin);
|
||||
sessionStorage.setItem(
|
||||
"nodeTableProfitMargin",
|
||||
JSON.stringify(newProfitMargin)
|
||||
);
|
||||
};
|
||||
|
||||
const handleAdvancedOpenChange = (newAdvancedOpen: boolean) => {
|
||||
setAdvancedOpen(newAdvancedOpen);
|
||||
sessionStorage.setItem(
|
||||
"nodeTableAdvancedOpen",
|
||||
JSON.stringify(newAdvancedOpen)
|
||||
);
|
||||
};
|
||||
|
||||
// Use React Query to fetch epoch rewards
|
||||
const {
|
||||
@@ -125,9 +187,12 @@ const NodeTableWithAction = () => {
|
||||
...nsApiNodesData.map((n) => n.stakeSaturation || 0)
|
||||
);
|
||||
|
||||
// Ensure saturation filter always covers the full range when maxSaturation changes, but only after data is loaded
|
||||
// Initialize saturation from sessionStorage or set to maxSaturation when data is loaded
|
||||
useEffect(() => {
|
||||
if (nsApiNodesData.length > 0) {
|
||||
const stored = sessionStorage.getItem("nodeTableSaturation");
|
||||
if (stored) {
|
||||
setSaturation(JSON.parse(stored));
|
||||
} else if (nsApiNodesData.length > 0) {
|
||||
setSaturation([0, maxSaturation]);
|
||||
}
|
||||
}, [maxSaturation, nsApiNodesData.length]);
|
||||
@@ -209,16 +274,16 @@ const NodeTableWithAction = () => {
|
||||
<Stack spacing={3}>
|
||||
<AdvancedFilters
|
||||
open={advancedOpen}
|
||||
setOpen={setAdvancedOpen}
|
||||
setOpen={handleAdvancedOpenChange}
|
||||
uptime={uptime}
|
||||
setUptime={setUptime}
|
||||
setUptime={handleUptimeChange}
|
||||
saturation={saturation}
|
||||
setSaturation={setSaturation}
|
||||
setSaturation={handleSaturationChange}
|
||||
profitMargin={profitMargin}
|
||||
setProfitMargin={setProfitMargin}
|
||||
setProfitMargin={handleProfitMarginChange}
|
||||
maxSaturation={maxSaturation}
|
||||
activeFilter={activeFilter}
|
||||
setActiveFilter={setActiveFilter}
|
||||
setActiveFilter={handleActiveFilterChange}
|
||||
nodeCounts={nodeCounts}
|
||||
/>
|
||||
<NodeTable nodes={filteredNodes} />
|
||||
|
||||
@@ -226,7 +226,6 @@ export const NodeRoleCard = ({ paramId }: Props) => {
|
||||
}
|
||||
if (!nodeInfo) return null;
|
||||
|
||||
console.log("nodeInfo", nodeInfo);
|
||||
|
||||
const NodeRoles = nodeRoles.map((role) => (
|
||||
<Stack key={role} direction="row" gap={1}>
|
||||
|
||||
Reference in New Issue
Block a user