11import { createFileRoute } from '@tanstack/react-router'
22import Card , { CardHeader , CardInfoField } from '#/components/Card.tsx'
3- import { ChevronLeft , ChevronRight } from 'lucide-react'
43import { useState } from 'react'
54import { Button } from '#/components/Buttons.tsx'
5+ import Chart from '#/components/Chart.tsx'
66
77export const Route = createFileRoute ( '/jobs' ) ( {
88 component : JobsPage ,
99} )
1010
11- // Sample utilization data
12- type UsageData = {
11+ export type UsageData = {
1312 component : string // Component that we observe. E.g. GPU, CPU, etc.
1413 observations : number [ ]
1514}
1615
17- function generateUsageData ( ) : UsageData {
16+ function generateSampleUsageData ( ) : UsageData {
1817 const components = [ 'GPU' , 'CPU' , 'RAM' ]
1918
2019 return {
@@ -62,11 +61,11 @@ const sampleJobs: Job[] = [
6261 cpuUtilization : '95%' ,
6362 networkIO : { down : '1.2 GB/s' , up : '340 MB/s' } ,
6463 usageHistory : [
65- generateUsageData ( ) ,
66- generateUsageData ( ) ,
67- generateUsageData ( ) ,
68- generateUsageData ( ) ,
69- generateUsageData ( ) ,
64+ generateSampleUsageData ( ) ,
65+ generateSampleUsageData ( ) ,
66+ generateSampleUsageData ( ) ,
67+ generateSampleUsageData ( ) ,
68+ generateSampleUsageData ( ) ,
7069 ] ,
7170 } ,
7271 {
@@ -84,11 +83,11 @@ const sampleJobs: Job[] = [
8483 cpuUtilization : '95%' ,
8584 networkIO : { down : '1.2 GB/s' , up : '340 MB/s' } ,
8685 usageHistory : [
87- generateUsageData ( ) ,
88- generateUsageData ( ) ,
89- generateUsageData ( ) ,
90- generateUsageData ( ) ,
91- generateUsageData ( ) ,
86+ generateSampleUsageData ( ) ,
87+ generateSampleUsageData ( ) ,
88+ generateSampleUsageData ( ) ,
89+ generateSampleUsageData ( ) ,
90+ generateSampleUsageData ( ) ,
9291 ] ,
9392 } ,
9493 {
@@ -106,11 +105,11 @@ const sampleJobs: Job[] = [
106105 cpuUtilization : '95%' ,
107106 networkIO : { down : '1.2 GB/s' , up : '340 MB/s' } ,
108107 usageHistory : [
109- generateUsageData ( ) ,
110- generateUsageData ( ) ,
111- generateUsageData ( ) ,
112- generateUsageData ( ) ,
113- generateUsageData ( ) ,
108+ generateSampleUsageData ( ) ,
109+ generateSampleUsageData ( ) ,
110+ generateSampleUsageData ( ) ,
111+ generateSampleUsageData ( ) ,
112+ generateSampleUsageData ( ) ,
114113 ] ,
115114 } ,
116115 {
@@ -128,11 +127,11 @@ const sampleJobs: Job[] = [
128127 cpuUtilization : '95%' ,
129128 networkIO : { down : '1.2 GB/s' , up : '340 MB/s' } ,
130129 usageHistory : [
131- generateUsageData ( ) ,
132- generateUsageData ( ) ,
133- generateUsageData ( ) ,
134- generateUsageData ( ) ,
135- generateUsageData ( ) ,
130+ generateSampleUsageData ( ) ,
131+ generateSampleUsageData ( ) ,
132+ generateSampleUsageData ( ) ,
133+ generateSampleUsageData ( ) ,
134+ generateSampleUsageData ( ) ,
136135 ] ,
137136 } ,
138137]
@@ -145,146 +144,6 @@ type JobCardProps = {
145144 onDelete : ( id : string ) => void
146145}
147146
148- function Chart ( {
149- data,
150- index,
151- numComponents,
152- onPrev,
153- onNext,
154- } : {
155- data : UsageData
156- index : number
157- numComponents : number
158- onPrev : ( ) => void
159- onNext : ( ) => void
160- } ) {
161- const max = 100
162- const width = 600
163- const height = 180
164- const padLeft = 40
165- const padRight = 10
166- const padTop = 10
167- const padBottom = 30
168- const chartW = width - padLeft - padRight
169- const chartH = height - padTop - padBottom
170-
171- const points = data . observations . map ( ( val , i ) => {
172- const x = padLeft + ( i / ( data . observations . length - 1 ) ) * chartW
173- const y = padTop + chartH - ( val / max ) * chartH
174- return `${ x } ,${ y } `
175- } )
176-
177- const areaPoints = [
178- `${ padLeft } ,${ padTop + chartH } ` ,
179- ...points ,
180- `${ padLeft + chartW } ,${ padTop + chartH } ` ,
181- ] . join ( ' ' )
182-
183- const linePoints = points . join ( ' ' )
184-
185- const yLabels = [ 100 , 80 , 60 , 40 , 20 , 0 ]
186- const xLabels = [
187- '00:00' ,
188- '02:00' ,
189- '04:00' ,
190- '06:00' ,
191- '08:00' ,
192- '10:00' ,
193- '12:00' ,
194- '14:00' ,
195- '16:00' ,
196- '18:00' ,
197- '20:00' ,
198- '22:00' ,
199- '24:00' ,
200- ]
201-
202- return (
203- < div className = "mt-4" >
204- < h3 className = "text-center font-semibold text-sm mb-1" >
205- { data . component }
206- </ h3 >
207- < div className = "flex items-center gap-2" >
208- < button
209- onClick = { onPrev }
210- className = "text-gray-400 hover:text-main p-1"
211- aria-label = "Previous Component"
212- >
213- < ChevronLeft size = { 24 } />
214- </ button >
215- < svg viewBox = { `0 0 ${ width } ${ height } ` } className = "flex-1" >
216- { /* Y-axis labels and grid */ }
217- { yLabels . map ( ( label ) => {
218- const y = padTop + chartH - ( label / max ) * chartH
219- return (
220- < g key = { label } >
221- < text
222- x = { padLeft - 5 }
223- y = { y + 3 }
224- textAnchor = "end"
225- fontSize = "9"
226- fill = "#999"
227- >
228- { label } %
229- </ text >
230- < line
231- x1 = { padLeft }
232- y1 = { y }
233- x2 = { padLeft + chartW }
234- y2 = { y }
235- stroke = "#e5e7eb"
236- strokeWidth = "0.5"
237- />
238- </ g >
239- )
240- } ) }
241- { /* X-axis labels */ }
242- { xLabels . map ( ( label , i ) => {
243- const x = padLeft + ( i / ( xLabels . length - 1 ) ) * chartW
244- return (
245- < text
246- key = { label }
247- x = { x }
248- y = { height - 5 }
249- textAnchor = "middle"
250- fontSize = "8"
251- fill = "#999"
252- >
253- { label }
254- </ text >
255- )
256- } ) }
257- { /* Area fill */ }
258- < polygon points = { areaPoints } fill = "rgba(234,179,8,0.15)" />
259- { /* Line */ }
260- < polyline
261- points = { linePoints }
262- fill = "none"
263- stroke = "#eab308"
264- strokeWidth = "2"
265- />
266- </ svg >
267- < button
268- onClick = { onNext }
269- className = "text-gray-400 hover:text-main p-1"
270- aria-label = "Next Component"
271- >
272- < ChevronRight size = { 24 } />
273- </ button >
274- </ div >
275- { /* Pagination dots */ }
276- < div className = "flex justify-center gap-1.5 mt-1" >
277- { Array . from ( { length : numComponents } ) . map ( ( _ , i ) => (
278- < span
279- key = { i }
280- className = { `w-2 h-2 rounded-full ${ i === index ? 'bg-main' : 'bg-gray-300' } ` }
281- />
282- ) ) }
283- </ div >
284- </ div >
285- )
286- }
287-
288147function JobCard ( {
289148 job,
290149 onStart,
0 commit comments