@@ -18,6 +18,9 @@ import Tabs from '../components/ui/Tabs';
1818import ScheduleConfig from '../components/scheduling/ScheduleConfig.js' ;
1919import type { IScheduleConfigForm } from '../components/scheduling/ScheduleConfig.js' ;
2020import ScheduleTimeline from '../components/scheduling/ScheduleTimeline.js' ;
21+ import ProviderLanesChart from '../components/scheduling/ProviderLanesChart.js' ;
22+ import ProviderBucketSummary from '../components/scheduling/ProviderBucketSummary.js' ;
23+ import RecentRunsChart from '../components/scheduling/RecentRunsChart.js' ;
2124import { useStore } from '../store/useStore' ;
2225import type { INightWatchConfig , IQueueAnalytics , IQueueStatus } from '../api' ;
2326import {
@@ -775,6 +778,109 @@ const Scheduling: React.FC = () => {
775778 </ Card >
776779 ) ,
777780 } ,
781+ {
782+ id : 'queue' ,
783+ label : 'Queue' ,
784+ content : (
785+ < div className = "space-y-6" >
786+ { /* Queue Overview Card */ }
787+ < Card className = "p-6" >
788+ < h3 className = "text-lg font-semibold text-slate-200 mb-4" > Queue Overview</ h3 >
789+ < div className = "grid grid-cols-2 md:grid-cols-4 gap-4" >
790+ < div className = "bg-slate-950/40 rounded-lg p-4 border border-slate-800" >
791+ < div className = "text-xs uppercase tracking-wide text-slate-500 mb-1" > Running</ div >
792+ < div className = "text-2xl font-bold text-green-400" >
793+ { queueStatus ?. running ? 1 : 0 }
794+ </ div >
795+ { queueStatus ?. running && (
796+ < div className = "text-xs text-slate-400 mt-1 truncate" title = { queueStatus . running . projectName } >
797+ { queueStatus . running . jobType } · { queueStatus . running . projectName }
798+ </ div >
799+ ) }
800+ </ div >
801+ < div className = "bg-slate-950/40 rounded-lg p-4 border border-slate-800" >
802+ < div className = "text-xs uppercase tracking-wide text-slate-500 mb-1" > Pending</ div >
803+ < div className = "text-2xl font-bold text-blue-400" >
804+ { queueStatus ?. pending . total ?? 0 }
805+ </ div >
806+ </ div >
807+ < div className = "bg-slate-950/40 rounded-lg p-4 border border-slate-800" >
808+ < div className = "text-xs uppercase tracking-wide text-slate-500 mb-1" > Avg Wait</ div >
809+ < div className = "text-2xl font-bold text-slate-200" >
810+ { queueStatus ?. averageWaitSeconds != null
811+ ? `${ Math . floor ( queueStatus . averageWaitSeconds / 60 ) } m`
812+ : '—' }
813+ </ div >
814+ </ div >
815+ < div className = "bg-slate-950/40 rounded-lg p-4 border border-slate-800" >
816+ < div className = "text-xs uppercase tracking-wide text-slate-500 mb-1" > Oldest Pending</ div >
817+ < div className = "text-2xl font-bold text-slate-200" >
818+ { queueStatus ?. oldestPendingAge != null
819+ ? `${ Math . floor ( queueStatus . oldestPendingAge / 60 ) } m`
820+ : '—' }
821+ </ div >
822+ </ div >
823+ </ div >
824+ </ Card >
825+
826+ { /* Provider Lanes */ }
827+ < Card className = "p-6" >
828+ < div className = "flex items-center justify-between mb-4" >
829+ < div >
830+ < h3 className = "text-lg font-semibold text-slate-200" > Provider Lanes</ h3 >
831+ < p className = "text-xs text-slate-500 mt-0.5" >
832+ Running and pending jobs grouped by provider bucket
833+ </ p >
834+ </ div >
835+ </ div >
836+ { queueStatus ? (
837+ < ProviderLanesChart status = { queueStatus } />
838+ ) : (
839+ < div className = "text-sm text-slate-500 py-2" > Loading queue status...</ div >
840+ ) }
841+ </ Card >
842+
843+ { /* Provider Bucket Summary */ }
844+ < Card className = "p-6" >
845+ < div className = "flex items-center justify-between mb-4" >
846+ < div >
847+ < h3 className = "text-lg font-semibold text-slate-200" > Provider Buckets</ h3 >
848+ < p className = "text-xs text-slate-500 mt-0.5" >
849+ Running and pending counts per provider bucket
850+ </ p >
851+ </ div >
852+ </ div >
853+ { queueAnalytics ? (
854+ < ProviderBucketSummary analytics = { queueAnalytics } />
855+ ) : (
856+ < div className = "text-sm text-slate-500 py-2" > Loading analytics...</ div >
857+ ) }
858+ </ Card >
859+
860+ { /* Recent Runs */ }
861+ < Card className = "p-6" >
862+ < div className = "flex items-center justify-between mb-4" >
863+ < div >
864+ < h3 className = "text-lg font-semibold text-slate-200" > Recent Runs</ h3 >
865+ < p className = "text-xs text-slate-500 mt-0.5" >
866+ Last 24 hours of job executions
867+ </ p >
868+ </ div >
869+ { queueAnalytics ?. averageWaitSeconds != null && (
870+ < div className = "text-xs text-slate-500" >
871+ Avg wait: { Math . floor ( queueAnalytics . averageWaitSeconds / 60 ) } m
872+ </ div >
873+ ) }
874+ </ div >
875+ { queueAnalytics ? (
876+ < RecentRunsChart analytics = { queueAnalytics } />
877+ ) : (
878+ < div className = "text-sm text-slate-500 py-2" > Loading analytics...</ div >
879+ ) }
880+ </ Card >
881+ </ div >
882+ ) ,
883+ } ,
778884 ] ;
779885
780886 return (
0 commit comments