Skip to content

Commit 3aec6f7

Browse files
authored
Merge pull request #313 from LGSI-KarumuriHari/main
fix(dashboard): Update filter logic to use nodes as source [#294]
2 parents b1e64cb + 97b32ed commit 3aec6f7

File tree

3 files changed

+421
-248
lines changed

3 files changed

+421
-248
lines changed

src/tools/dashboard/.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
VITE_SETTING_SERVICE_API_URL=http://0.0.0.0:8080
1+
VITE_SETTING_SERVICE_API_URL=http://0.0.0.0:8080
2+
VITE_SETTING_SERVICE_TIMEOUT=7000

src/tools/dashboard/src/components/Dashboard.tsx

Lines changed: 209 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -40,127 +40,229 @@ export function Dashboard() {
4040

4141
// Move pods state to Dashboard level
4242

43-
// Lgsi pod data
43+
// Lgsi changes: pod data
4444
const [podsToUse, setPods] = useState<Pod[]>([]);
4545
const [podsFetchSuccess, setPodsFetchSuccess] = useState(false);
46+
const [recentEvents, setRecentEvents] = useState<any[]>([]); // Mock recent events
4647

4748
useEffect(() => {
4849
const settingserviceApiUrl = import.meta.env.VITE_SETTING_SERVICE_API_URL;
50+
const _timeout = import.meta.env.VITE_SETTING_SERVICE_TIMEOUT || 5000;
4951
if (!settingserviceApiUrl) return;
50-
fetch(`${settingserviceApiUrl}/api/v1/metrics`)
51-
.then(res => res.json())
52-
.then(data => {
53-
// Filter for containers only
54-
const containers = Array.isArray(data)
55-
? data.filter(
52+
const fetchPods = () => {
53+
fetch(`${settingserviceApiUrl}/api/v1/metrics`)
54+
.then(res => res.json())
55+
.then(data => {
56+
// Filter for containers only
57+
console.log("Fetched metrics data:", data);
58+
const containers = Array.isArray(data)
59+
? data.filter(
5660
(item: any) =>
5761
item.component === "container" &&
5862
item.metric_type === "ContainerInfo" &&
5963
item.value &&
6064
item.value.value
6165
)
62-
: [];
63-
if (containers.length > 0) {
64-
// Map API data to Pod[]
65-
const mappedPods = containers.map((item: any, idx: number) => {
66-
const val = item.value.value;
67-
return {
68-
name: (val.names && val.names[0]) || val.id || `pod-${idx}`,
69-
image: val.image || "",
70-
labels: item.labels || {},
71-
node: (val.state && (val.state.node_name || val.state.hostname)) || (val.config.Hostname) || "",
72-
status: (val.state && (val.state.status || val.state.Status)) || "",
73-
cpuUsage: val.stats?.CpuTotalUsage || "",
74-
memoryUsage: val.stats?.MemoryUsage || "",
75-
age: item.timestamp || "",
76-
ready: "", // Not available in this API, leave blank or compute if possible
77-
restarts: 0, // Not available, default to 0
78-
ip: item.labels?.ip || "",
66+
: [];
67+
if (containers.length > 0) {
68+
// Map API data to Pod[]
69+
const mappedPods = containers.map((item: any, idx: number) => {
70+
const val = item.value.value;
71+
let age = item.timestamp || "";
72+
if (val.state && val.state.StartedAt) {
73+
const started = new Date(val.state.StartedAt);
74+
const now = new Date();
75+
const diffMs = now.getTime() - started.getTime();
76+
const diffSec = Math.floor(diffMs / 1000);
77+
if (diffSec < 60) age = `${diffSec}s`;
78+
else if (diffSec < 3600) age = `${Math.floor(diffSec / 60)}m`;
79+
else if (diffSec < 86400) age = `${Math.floor(diffSec / 3600)}h`;
80+
else age = `${Math.floor(diffSec / 86400)}d`;
81+
}
82+
83+
// Format CPU usage (show as millicores if possible)
84+
let cpuUsage = "";
85+
if (val.stats?.CpuTotalUsage) {
86+
const cpuRaw = Number(val.stats.CpuTotalUsage);
87+
if (!isNaN(cpuRaw)) {
88+
// Show as millicores (m) if value is large, else as cores
89+
cpuUsage = cpuRaw >= 1000000
90+
? `${(cpuRaw / 1000000).toFixed(2)} cores`
91+
: `${cpuRaw} m`;
92+
}
93+
}
94+
95+
// Format memory usage (show as MB or KB)
96+
let memoryUsage = "";
97+
if (val.stats?.MemoryUsage) {
98+
const memRaw = Number(val.stats.MemoryUsage);
99+
if (!isNaN(memRaw)) {
100+
if (memRaw > 1024 * 1024) {
101+
memoryUsage = `${(memRaw / 1024 / 1024).toFixed(2)} MB`;
102+
} else if (memRaw > 1024) {
103+
memoryUsage = `${(memRaw / 1024).toFixed(2)} KB`;
104+
} else {
105+
memoryUsage = `${memRaw} B`;
106+
}
107+
}
108+
}
109+
110+
return {
111+
name: (val.names && val.names[0]) || val.id || `pod-${idx}`,
112+
image: val.image || "",
113+
labels: item.labels || {},
114+
node: (val.state && (val.state.node_name || val.state.hostname)) || (val.config.Hostname) || "",
115+
status: (val.state && (val.state.status || val.state.Status)) || "",
116+
cpuUsage: val.stats.CpuTotalUsage,
117+
memoryUsage,
118+
age,
119+
ready: "", // Not available in this API, leave blank or compute if possible
120+
restarts: 0, // Not available, default to 0
121+
ip: item.labels?.ip || "",
122+
};
123+
});
124+
setPods(mappedPods);
125+
setPodsFetchSuccess(true);
126+
console.log("✅ Pods API (metrics) fetched:", mappedPods);
127+
setRecentEvents(prev => {
128+
const newEvent = {
129+
type: "Fetched",
130+
resource: "Pod",
131+
name: "Pods fetch success",
132+
time: new Date().toLocaleTimeString(),
133+
status: "success",
134+
};
135+
136+
// Find the most recent event for this resource
137+
const latestSameResourceEvent = prev.find(
138+
e => e.resource === newEvent.resource
139+
);
140+
141+
// Only add if the latest event for this resource is not the same type, status, and name
142+
if (
143+
latestSameResourceEvent &&
144+
latestSameResourceEvent.type === newEvent.type &&
145+
latestSameResourceEvent.status === newEvent.status &&
146+
latestSameResourceEvent.name === newEvent.name
147+
) {
148+
return prev;
149+
}
150+
return [newEvent, ...prev];
151+
});
152+
} else {
153+
setPodsFetchSuccess(false);
154+
}
155+
})
156+
.catch(e => {
157+
setPodsFetchSuccess(false);
158+
console.error("❌ Pods API (metrics) fetch failed:", e);
159+
160+
setRecentEvents(prev => {
161+
const newEvent = {
162+
type: "Fetched",
163+
resource: "Pod",
164+
name: "Pods fetch failed",
165+
time: new Date().toLocaleTimeString(),
166+
status: "error",
79167
};
168+
169+
// Find the most recent event for this resource
170+
const latestSameResourceEvent = prev.find(
171+
e => e.resource === newEvent.resource
172+
);
173+
174+
// Only add if the latest event for this resource is not the same type, status, and name
175+
if (
176+
latestSameResourceEvent &&
177+
latestSameResourceEvent.type === newEvent.type &&
178+
latestSameResourceEvent.status === newEvent.status &&
179+
latestSameResourceEvent.name === newEvent.name
180+
) {
181+
return prev;
182+
}
183+
return [newEvent, ...prev];
80184
});
81-
setPods(mappedPods);
82-
setPodsFetchSuccess(true);
83-
console.log("✅ Pods API (metrics) fetched:", mappedPods);
84-
} else {
85-
setPodsFetchSuccess(false);
86-
}
87-
})
88-
.catch(e => {
89-
setPodsFetchSuccess(false);
90-
console.error("❌ Pods API (metrics) fetch failed:", e);
91-
});
185+
186+
});
187+
}
188+
189+
fetchPods();
190+
const interval = setInterval(fetchPods, _timeout);
191+
return () => clearInterval(interval);
192+
92193
}, []);
93194

195+
const pods = podsFetchSuccess ? podsToUse : [];
94196

95-
const pods = podsFetchSuccess && podsToUse.length > 0
96-
? podsToUse
97-
: [
98-
{
99-
name: "frontend-app-7d4b8c9f8d-xyz12",
100-
image: "nginx:1.21",
101-
labels: { app: "frontend", version: "v1.2.0" },
102-
node: "worker-node-1",
103-
status: "Running",
104-
cpuUsage: "45m",
105-
memoryUsage: "128Mi",
106-
age: "2d",
107-
ready: "1/1",
108-
restarts: 0,
109-
ip: "10.244.1.15",
110-
},
111-
{
112-
name: "frontend-app-7d4b8c9f8d-abc34",
113-
image: "nginx:1.21",
114-
labels: { app: "frontend", version: "v1.2.0" },
115-
node: "worker-node-2",
116-
status: "Running",
117-
cpuUsage: "38m",
118-
memoryUsage: "115Mi",
119-
age: "2d",
120-
ready: "1/1",
121-
restarts: 0,
122-
ip: "10.244.2.18",
123-
},
124-
{
125-
name: "backend-api-5f6a7b8c9d-def56",
126-
image: "node:18-alpine",
127-
labels: { app: "backend", tier: "api" },
128-
node: "worker-node-1",
129-
status: "Running",
130-
cpuUsage: "120m",
131-
memoryUsage: "256Mi",
132-
age: "5d",
133-
ready: "1/1",
134-
restarts: 1,
135-
ip: "10.244.1.22",
136-
},
137-
{
138-
name: "redis-cache-8e9f0a1b2c-ghi78",
139-
image: "redis:7-alpine",
140-
labels: { app: "redis", role: "cache" },
141-
node: "worker-node-3",
142-
status: "Running",
143-
cpuUsage: "25m",
144-
memoryUsage: "64Mi",
145-
age: "1d",
146-
ready: "1/1",
147-
restarts: 0,
148-
ip: "10.244.3.9",
149-
},
150-
{
151-
name: "database-migration-1a2b3c4d5e-jkl90",
152-
image: "postgres:14",
153-
labels: { job: "migration", app: "database" },
154-
node: "worker-node-2",
155-
status: "Pending",
156-
cpuUsage: "0m",
157-
memoryUsage: "0Mi",
158-
age: "30m",
159-
ready: "0/1",
160-
restarts: 0,
161-
ip: "N/A",
162-
},
163-
];
197+
// const pods = podsFetchSuccess && podsToUse.length > 0
198+
// ? podsToUse
199+
// : [
200+
// {
201+
// name: "frontend-app-7d4b8c9f8d-xyz12",
202+
// image: "nginx:1.21",
203+
// labels: { app: "frontend", version: "v1.2.0" },
204+
// node: "worker-node-1",
205+
// status: "Running",
206+
// cpuUsage: "45m",
207+
// memoryUsage: "128Mi",
208+
// age: "2d",
209+
// ready: "1/1",
210+
// restarts: 0,
211+
// ip: "10.244.1.15",
212+
// },
213+
// {
214+
// name: "frontend-app-7d4b8c9f8d-abc34",
215+
// image: "nginx:1.21",
216+
// labels: { app: "frontend", version: "v1.2.0" },
217+
// node: "worker-node-2",
218+
// status: "Running",
219+
// cpuUsage: "38m",
220+
// memoryUsage: "115Mi",
221+
// age: "2d",
222+
// ready: "1/1",
223+
// restarts: 0,
224+
// ip: "10.244.2.18",
225+
// },
226+
// {
227+
// name: "backend-api-5f6a7b8c9d-def56",
228+
// image: "node:18-alpine",
229+
// labels: { app: "backend", tier: "api" },
230+
// node: "worker-node-1",
231+
// status: "Running",
232+
// cpuUsage: "120m",
233+
// memoryUsage: "256Mi",
234+
// age: "5d",
235+
// ready: "1/1",
236+
// restarts: 1,
237+
// ip: "10.244.1.22",
238+
// },
239+
// {
240+
// name: "redis-cache-8e9f0a1b2c-ghi78",
241+
// image: "redis:7-alpine",
242+
// labels: { app: "redis", role: "cache" },
243+
// node: "worker-node-3",
244+
// status: "Running",
245+
// cpuUsage: "25m",
246+
// memoryUsage: "64Mi",
247+
// age: "1d",
248+
// ready: "1/1",
249+
// restarts: 0,
250+
// ip: "10.244.3.9",
251+
// },
252+
// {
253+
// name: "database-migration-1a2b3c4d5e-jkl90",
254+
// image: "postgres:14",
255+
// labels: { job: "migration", app: "database" },
256+
// node: "worker-node-2",
257+
// status: "Pending",
258+
// cpuUsage: "0m",
259+
// memoryUsage: "0Mi",
260+
// age: "30m",
261+
// ready: "0/1",
262+
// restarts: 0,
263+
// ip: "N/A",
264+
// },
265+
// ];
164266

165267
// Calculate running pods count
166268
const runningPodsCount = pods.filter(
@@ -184,6 +286,8 @@ export function Dashboard() {
184286
onPodClick={(podName) => handleViewChange("pod-detail", podName)}
185287
pods={pods}
186288
setPods={setPods}
289+
recentEvents={recentEvents}
290+
setRecentEvents={setRecentEvents}
187291
/>
188292
);
189293
case "services":
@@ -236,7 +340,7 @@ export function Dashboard() {
236340
currentView={currentView === "pod-detail" ? "workloads" : currentView}
237341
onViewChange={setCurrentView}
238342
collapsed={true}
239-
onToggle={() => {}}
343+
onToggle={() => { }}
240344
/>
241345
<div className="flex-1 flex flex-col min-w-0">
242346
<Header compact={true} podCount={runningPodsCount} pods={pods} />

0 commit comments

Comments
 (0)