99} from "~/components/ui/breadcrumb" ;
1010import { Separator } from "~/components/ui/separator" ;
1111import { SidebarTrigger } from "~/components/ui/sidebar" ;
12+ import { Skeleton } from "~/components/ui/skeleton" ;
1213import {
1314 Table ,
1415 TableBody ,
@@ -68,9 +69,10 @@ export default function Jobs() {
6869 } ) ;
6970
7071 const jobs = jobQuery . data ?. items ?? [ ] ;
72+ const isLoading = jobQuery . isLoading ;
7173
7274 return (
73- < >
75+ < div className = "flex h-full flex-col" >
7476 < header className = "flex h-16 shrink-0 items-center justify-between gap-2 border-b px-4" >
7577 < div className = "flex items-center gap-2" >
7678 < SidebarTrigger className = "-ml-1" />
@@ -87,41 +89,111 @@ export default function Jobs() {
8789 </ Breadcrumb >
8890 </ div >
8991 </ header >
90- < Table >
91- < TableHeader >
92- < TableRow className = "bg-muted/50" >
93- < TableHead className = "text-muted-foreground" > ID</ TableHead >
94- < TableHead className = "text-muted-foreground" > Status</ TableHead >
95- < TableHead className = "text-muted-foreground" > Created At</ TableHead >
96- < TableHead className = "text-muted-foreground" > Updated At</ TableHead >
97- </ TableRow >
98- </ TableHeader >
9992
100- < TableBody >
101- { jobs . map ( ( { job } ) => {
102- return (
103- < TableRow key = { job . id } >
104- < TableCell className = "font-mono" > { job . id } </ TableCell >
105- < TableCell >
106- < JobStatusBadge status = { job . status } />
107- </ TableCell >
108- < TableCell >
109- { prettyMs (
110- new Date ( job . createdAt ) . getTime ( ) -
111- new Date ( job . updatedAt ) . getTime ( ) ,
112- ) }
113- </ TableCell >
114- < TableCell >
115- { prettyMs (
116- new Date ( job . updatedAt ) . getTime ( ) -
117- new Date ( job . createdAt ) . getTime ( ) ,
118- ) }
119- </ TableCell >
93+ < div className = "flex-1 overflow-auto" >
94+ { isLoading ? (
95+ < div className = "space-y-4 p-4" >
96+ < Skeleton className = "h-12 w-full" />
97+ < Skeleton className = "h-12 w-full" />
98+ < Skeleton className = "h-12 w-full" />
99+ </ div >
100+ ) : jobs . length === 0 ? (
101+ < div className = "flex flex-col items-center justify-center py-16 text-center" >
102+ < div className = "rounded-full bg-muted p-4" >
103+ < svg
104+ className = "h-8 w-8 text-muted-foreground"
105+ fill = "none"
106+ viewBox = "0 0 24 24"
107+ stroke = "currentColor"
108+ >
109+ < path
110+ strokeLinecap = "round"
111+ strokeLinejoin = "round"
112+ strokeWidth = { 2 }
113+ d = "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
114+ />
115+ </ svg >
116+ </ div >
117+ < h3 className = "mt-4 text-lg font-semibold" > No jobs yet</ h3 >
118+ < p className = "mt-2 text-sm text-muted-foreground" >
119+ Jobs will appear here when deployments are executed
120+ </ p >
121+ </ div >
122+ ) : (
123+ < Table className = "border-b" >
124+ < TableHeader >
125+ < TableRow className = "bg-muted/50" >
126+ < TableHead className = "font-medium" > Deployment</ TableHead >
127+ < TableHead className = "font-medium" > Environment</ TableHead >
128+ < TableHead className = "font-medium" > Resource</ TableHead >
129+ < TableHead className = "font-medium" > Version</ TableHead >
130+ < TableHead className = "font-medium" > External ID</ TableHead >
131+ < TableHead className = "font-medium" > Status</ TableHead >
132+ < TableHead className = "font-medium" > Created</ TableHead >
133+ < TableHead className = "font-medium" > Updated</ TableHead >
120134 </ TableRow >
121- ) ;
122- } ) }
123- </ TableBody >
124- </ Table >
125- </ >
135+ </ TableHeader >
136+
137+ < TableBody >
138+ { jobs . map (
139+ ( { job, resource, environment, deployment, release } ) => {
140+ return (
141+ < TableRow
142+ key = { job . id }
143+ className = "cursor-pointer hover:bg-muted/50"
144+ >
145+ < TableCell className = "font-medium" >
146+ { deployment ?. name ?? (
147+ < span className = "text-muted-foreground" > —</ span >
148+ ) }
149+ </ TableCell >
150+ < TableCell >
151+ { environment ?. name ?? (
152+ < span className = "text-muted-foreground" > —</ span >
153+ ) }
154+ </ TableCell >
155+ < TableCell >
156+ { resource ?. name ?? (
157+ < span className = "text-muted-foreground" > —</ span >
158+ ) }
159+ </ TableCell >
160+ < TableCell className = "font-mono font-medium" >
161+ { release . version . tag }
162+ </ TableCell >
163+ < TableCell className = "font-mono font-medium" >
164+ { job . externalId ?? (
165+ < span className = "text-muted-foreground" > —</ span >
166+ ) }
167+ </ TableCell >
168+ < TableCell >
169+ < JobStatusBadge status = { job . status } />
170+ </ TableCell >
171+ < TableCell className = "text-muted-foreground" >
172+ { prettyMs (
173+ Date . now ( ) - new Date ( job . createdAt ) . getTime ( ) ,
174+ {
175+ compact : true ,
176+ } ,
177+ ) } { " " }
178+ ago
179+ </ TableCell >
180+ < TableCell className = "text-muted-foreground" >
181+ { prettyMs (
182+ Date . now ( ) - new Date ( job . updatedAt ) . getTime ( ) ,
183+ {
184+ compact : true ,
185+ } ,
186+ ) } { " " }
187+ ago
188+ </ TableCell >
189+ </ TableRow >
190+ ) ;
191+ } ,
192+ ) }
193+ </ TableBody >
194+ </ Table >
195+ ) }
196+ </ div >
197+ </ div >
126198 ) ;
127199}
0 commit comments