1- import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card"
2- import { FileWarningIcon , FolderKanban } from "lucide-react"
1+ import { Card , CardContent } from "@/components/ui/card"
2+ import { FileWarningIcon , Calendar , Play , Database } from "lucide-react"
33import type { ReactNode } from "react"
44import { useEffect , useState } from "react"
55import jobsService from "@/services/JobsService"
@@ -15,6 +15,84 @@ export interface StatsBarProps {
1515 metrics ?: any
1616}
1717
18+ interface MetricSectionProps {
19+ title : string
20+ value : ReactNode
21+ icon : ReactNode
22+ textSize : string
23+ bgColor : string
24+ bgColorLight : string
25+ hasError ?: boolean
26+ tooltipContent ?: string
27+ }
28+
29+ function MetricSection ( {
30+ title,
31+ value,
32+ icon,
33+ textSize,
34+ bgColor,
35+ bgColorLight,
36+ hasError,
37+ tooltipContent,
38+ } : MetricSectionProps ) {
39+ return (
40+ < div
41+ className = { cn (
42+ "relative p-5 transition-all duration-300" ,
43+ hasError ? "bg-destructive/5" : `${ bgColorLight } /5` ,
44+ ) }
45+ >
46+ { ! hasError && (
47+ < div className = { cn ( "absolute top-0 right-0 w-1 h-full" , bgColor ) } />
48+ ) }
49+ < div className = "flex items-start justify-between" >
50+ < div className = "flex-1" >
51+ < p className = "text-sm font-medium uppercase tracking-wider text-muted-foreground mb-1" >
52+ { title }
53+ </ p >
54+ < div className = "flex items-baseline gap-2" >
55+ < WithError errorCpt = { `--` } hasError = { hasError } >
56+ < span
57+ className = { cn (
58+ "font-bold" ,
59+ textSize === "text-4xl"
60+ ? "text-4xl"
61+ : textSize === "text-3xl"
62+ ? "text-3xl"
63+ : "text-2xl" ,
64+ hasError ? "text-destructive" : "text-foreground" ,
65+ ) }
66+ >
67+ { value }
68+ </ span >
69+ </ WithError >
70+ </ div >
71+ </ div >
72+ < div
73+ className = { cn (
74+ "flex-shrink-0 ml-4" ,
75+ hasError ? "text-destructive" : bgColor ,
76+ ) }
77+ >
78+ { hasError ? (
79+ < Tooltip >
80+ < TooltipTrigger >
81+ < FileWarningIcon size = { 28 } />
82+ </ TooltipTrigger >
83+ < TooltipContent className = "text-destructive border-destructive" >
84+ { tooltipContent || "Error fetching data" }
85+ </ TooltipContent >
86+ </ Tooltip >
87+ ) : (
88+ icon
89+ ) }
90+ </ div >
91+ </ div >
92+ </ div >
93+ )
94+ }
95+
1896export default function StatsBar ( props : StatsBarProps ) {
1997 const [ jobMetrics , setJobMetrics ] = useState ( props . metrics ?? { } )
2098 const [ hasError , setHasError ] = useState ( false )
@@ -35,48 +113,59 @@ export default function StatsBar(props: StatsBarProps) {
35113 } , [ ] )
36114
37115 return (
38- < div className = "grid gap-4 md:grid-cols-2 lg:grid-cols-4" >
39- < Card className = { cn ( "border-border" , hasError && "border-destructive" ) } >
40- < CardHeader className = "flex flex-row items-center justify-between space-y-0 p-4 pb-2 text-foreground bg-background border-border rounded-t-xl" >
41- < CardTitle className = "text-sm font-medium" >
42- Number of Registered jobs
43- </ CardTitle >
44- { hasError ? (
45- < Tooltip >
46- < TooltipTrigger >
47- < FileWarningIcon className = "text-destructive" />
48- </ TooltipTrigger >
49- < TooltipContent className = "text-destructive border-destructive" >
50- Error fetching job metrics
51- </ TooltipContent >
52- </ Tooltip >
53- ) : (
54- < FolderKanban />
55- ) }
56- </ CardHeader >
57- < CardContent className = "p-4 pt-0" >
58- < div className = "text-2xl font-bold mb-2" >
59- < WithError errorCpt = { `...` } hasError = { hasError } >
60- { jobMetrics . job_count }
61- </ WithError >
62- </ div >
63- < div className = "flex flex-col gap-1" >
64- < p className = "text-xs text-muted-foreground flex items-center gap-1" >
65- < span className = "text-md font-bold" >
66- < WithError errorCpt = { `N/A` } hasError = { hasError } >
67- { jobMetrics . running_jobs_count }
68- </ WithError >
69- </ span >
70- are currently scheduled
71- </ p >
72- < p className = "text-xs text-muted-foreground flex items-center gap-1" >
73- < span className = "text-md font-bold" >
74- < WithError errorCpt = { `N/A` } hasError = { hasError } >
75- { jobMetrics . runningJobsCount }
76- </ WithError >
77- </ span >
78- are currently running
79- </ p >
116+ < div className = "w-full xl:w-1/2" >
117+ < Card
118+ className = { cn (
119+ "border-border overflow-hidden" ,
120+ hasError && "border-destructive" ,
121+ ) }
122+ >
123+ < CardContent className = "p-0" >
124+ < div className = "flex flex-col md:flex-row" >
125+ < div className = "flex-1" >
126+ < MetricSection
127+ title = "Registered Jobs"
128+ value = { jobMetrics . job_count }
129+ icon = { < Database size = { 28 } /> }
130+ textSize = "text-4xl"
131+ bgColor = "text-metric1"
132+ bgColorLight = "bg-metric1-light"
133+ hasError = { hasError }
134+ tooltipContent = "Error fetching registered jobs"
135+ />
136+ </ div >
137+
138+ < div className = "hidden md:block w-px bg-border my-5" />
139+ < div className = "md:hidden h-px bg-border mx-5" />
140+
141+ < div className = "flex-1" >
142+ < MetricSection
143+ title = "Scheduled Jobs"
144+ value = { jobMetrics . running_jobs_count }
145+ icon = { < Calendar size = { 28 } /> }
146+ textSize = "text-3xl"
147+ bgColor = "text-metric2"
148+ bgColorLight = "bg-metric2-light"
149+ hasError = { hasError }
150+ tooltipContent = "Error fetching scheduled jobs"
151+ />
152+ </ div >
153+
154+ < div className = "hidden md:block w-px bg-border my-5" />
155+ < div className = "md:hidden h-px bg-border mx-5" />
156+
157+ < div className = "flex-1" >
158+ < MetricSection
159+ title = "Running Jobs"
160+ value = { jobMetrics . runningJobsCount }
161+ icon = { < Play size = { 28 } className = "fill-current" /> }
162+ textSize = "text-2xl"
163+ bgColor = "text-metric3"
164+ bgColorLight = "bg-metric3-light"
165+ hasError = { hasError }
166+ tooltipContent = "Error fetching running jobs"
167+ />
168+ </ div >
80169 </ div >
81170 </ CardContent >
82171 </ Card >
0 commit comments