Skip to content

Commit b530765

Browse files
committed
Region filtering in table
1 parent 26ce85d commit b530765

File tree

3 files changed

+148
-15
lines changed

3 files changed

+148
-15
lines changed

src/components/RankingTable.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,24 @@ td:nth-child(3), th:nth-child(3) {
7777
width: 25%; /* Adjusts KPI values width */
7878
}
7979
}
80+
81+
/* Region Selector Dropdown Styling */
82+
.region-selector {
83+
display: flex;
84+
align-items: center;
85+
margin-bottom: 15px;
86+
}
87+
88+
.region-selector label {
89+
color: var(--text-color);
90+
margin-right: 10px;
91+
}
92+
93+
.region-selector select {
94+
padding: 8px;
95+
border-radius: 5px;
96+
border: 1px solid var(--border-color);
97+
background-color: var(--input-background);
98+
color: var(--text-color);
99+
cursor: pointer;
100+
}

src/components/RankingTable.js

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,68 @@
1-
import React from "react";
1+
import React, { useState, useEffect } from "react";
22
import PropTypes from "prop-types";
33
import "./RankingTable.css";
44

55
const RankingTable = ({ orchestrators, selectedKPI }) => {
6+
const [selectedRegion, setSelectedRegion] = useState("global");
7+
8+
// Set initial position once when parentRef becomes available
9+
useEffect(() => {
10+
setSelectedRegion("global");
11+
}, [selectedKPI]);
12+
613
const kpiLabel = {
714
avgPrice: "Price",
815
avgDiscoveryTime: "Discovery Time",
9-
avgRTR: "Realtime ratio",
16+
avgRTR: "Realtime Ratio",
1017
};
1118

12-
// Validate data
13-
const validOrchestrators = orchestrators.filter((orch) =>
14-
orch[selectedKPI] !== undefined && orch[selectedKPI] > 0.0
15-
);
19+
// Extract unique regions for dropdown options
20+
const uniqueRegions = [
21+
"global",
22+
...new Set(
23+
orchestrators.flatMap((orch) =>
24+
orch.instances.flatMap((instance) => {
25+
if (selectedKPI === "avgRTR") {
26+
return instance.livepeer_regions;
27+
} else {
28+
return instance.regions;
29+
30+
}
31+
}
32+
)
33+
)
34+
),
35+
];
36+
37+
// Handle dropdown change
38+
const handleRegionChange = (event) => {
39+
setSelectedRegion(event.target.value);
40+
};
41+
42+
// Validate and filter orchestrators based on the selected KPI and region
43+
const validOrchestrators = orchestrators.filter((orch) => {
44+
// If global, return all orchestrators with valid KPI values
45+
if (selectedRegion === "global") {
46+
return orch[selectedKPI] !== undefined && orch[selectedKPI] > 0.0;
47+
}
48+
49+
// If filtering by specific region
50+
return orch.instances.some((instance) => {
51+
if (selectedKPI === "avgRTR") {
52+
return (
53+
instance.livepeer_regions.includes(selectedRegion) &&
54+
instance.avgRTRByRegion[selectedRegion] !== undefined &&
55+
instance.avgRTRByRegion[selectedRegion] > 0.0
56+
);
57+
} else {
58+
return (
59+
instance.regions.includes(selectedRegion) &&
60+
instance.avgPriceByRegion[selectedRegion] !== undefined &&
61+
instance.avgPriceByRegion[selectedRegion] > 0.0
62+
);
63+
}
64+
});
65+
});
1666

1767
const sortedOrchestrators = [...validOrchestrators].sort((a, b) => {
1868
const valueA = a[selectedKPI] >= 0 ? a[selectedKPI] : Infinity;
@@ -23,6 +73,19 @@ const RankingTable = ({ orchestrators, selectedKPI }) => {
2373
return (
2474
<div className="ranking-table">
2575
<h4>Ranking Table</h4>
76+
77+
{/* Dropdown for Region Selection */}
78+
<div className="region-selector">
79+
<label htmlFor="region-select">Select Region:</label>
80+
<select id="region-select" value={selectedRegion} onChange={handleRegionChange}>
81+
{uniqueRegions.map((region) => (
82+
<option key={region} value={region}>
83+
{region}
84+
</option>
85+
))}
86+
</select>
87+
</div>
88+
2689
<table>
2790
<thead>
2891
<tr>
@@ -32,15 +95,33 @@ const RankingTable = ({ orchestrators, selectedKPI }) => {
3295
</tr>
3396
</thead>
3497
<tbody>
35-
{sortedOrchestrators.map((orchestrator, index) => (
36-
<tr key={orchestrator.id}>
37-
<td>{index + 1}</td>
38-
<td>{orchestrator.name}</td>
39-
<td>
40-
{orchestrator[selectedKPI] >= 0 ? orchestrator[selectedKPI]?.toFixed(2) || 0 : "?"}
41-
</td>
42-
</tr>
43-
))}
98+
{sortedOrchestrators.map((orchestrator, index) => {
99+
// Determine which value to display based on selected region
100+
let value = 0;
101+
102+
if (selectedRegion === "global") {
103+
value = orchestrator[selectedKPI];
104+
} else {
105+
const instance = orchestrator.instances.find((inst) =>
106+
selectedKPI === "avgRTR"
107+
? inst.livepeer_regions.includes(selectedRegion)
108+
: inst.regions.includes(selectedRegion)
109+
);
110+
if (instance) {
111+
value = selectedKPI === "avgRTR"
112+
? instance.avgRTRByRegion[selectedRegion]
113+
: instance.avgPriceByRegion[selectedRegion];
114+
}
115+
}
116+
117+
return (
118+
<tr key={orchestrator.id}>
119+
<td>{index + 1}</td>
120+
<td>{orchestrator.name}</td>
121+
<td>{value >= 0 ? value?.toFixed(2) || 0 : "?"}</td>
122+
</tr>
123+
);
124+
})}
44125
</tbody>
45126
</table>
46127
</div>
@@ -56,6 +137,18 @@ RankingTable.propTypes = {
56137
avgDiscoveryTime: PropTypes.number,
57138
avgRTR: PropTypes.number,
58139
avgSR: PropTypes.number,
140+
instances: PropTypes.arrayOf(
141+
PropTypes.shape({
142+
id: PropTypes.string.isRequired,
143+
regions: PropTypes.arrayOf(PropTypes.string).isRequired,
144+
livepeer_regions: PropTypes.arrayOf(PropTypes.string).isRequired,
145+
price: PropTypes.number,
146+
avgRTR: PropTypes.number,
147+
avgPriceByRegion: PropTypes.object,
148+
avgDiscoveryTimeByRegion: PropTypes.object,
149+
avgRTRByRegion: PropTypes.object,
150+
})
151+
).isRequired,
59152
})
60153
).isRequired,
61154
selectedKPI: PropTypes.oneOf(["avgPrice", "avgDiscoveryTime", "avgRTR"]).isRequired,

src/hooks/useProcessedData.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ const useProcessedData = () => {
3939
.map((stats) => stats.avgDiscoveryTime || Infinity)
4040
.reduce((best, current) => Math.min(best, current), Infinity);
4141

42+
// Store regional stats for avgPrice and avgDiscoveryTime
43+
const regionalStats = orchestratorData.regionalStats || {};
44+
const avgPriceByRegion = {};
45+
const avgDiscoveryTimeByRegion = {};
46+
regions.forEach((region) => {
47+
const stats = regionalStats[region] || {};
48+
avgPriceByRegion[region] = stats.avgPrice || 0;
49+
avgDiscoveryTimeByRegion[region] = stats.avgDiscoveryTime || Infinity;
50+
});
51+
// Store avgRTR per livepeer region
52+
const avgRTRByRegion = {};
53+
livepeerRegions.forEach((region) => {
54+
const leaderboard = leaderboardResults[region] || {};
55+
avgRTRByRegion[region] = leaderboard.latestRTR || 0;
56+
});
57+
4258
return {
4359
id: instanceId,
4460
price: instanceData.price || 0,
@@ -51,6 +67,9 @@ const useProcessedData = () => {
5167
bestDiscoveryTime: bestDiscoveryTime === Infinity ? null : bestDiscoveryTime,
5268
avgRTR: avgRTR || 0,
5369
avgSR: avgSR || 0,
70+
avgPriceByRegion,
71+
avgDiscoveryTimeByRegion,
72+
avgRTRByRegion,
5473
};
5574
}
5675
);

0 commit comments

Comments
 (0)