@@ -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