Skip to content

Commit f977cb5

Browse files
Test Userclaude
andcommitted
feat(scheduling): add Queue tab with provider lanes and execution analytics
Adds a new 'Queue' tab to the Scheduling page that visualizes: - Queue overview (running, pending, avg wait, oldest pending) - Provider lanes chart showing jobs grouped by provider bucket - Provider bucket summary with running/pending counts - Recent runs chart with execution history This completes Phase 4 of the Provider-Aware Queue PRD. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b9cead0 commit f977cb5

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

web/pages/Scheduling.tsx

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import Tabs from '../components/ui/Tabs';
1818
import ScheduleConfig from '../components/scheduling/ScheduleConfig.js';
1919
import type { IScheduleConfigForm } from '../components/scheduling/ScheduleConfig.js';
2020
import 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';
2124
import { useStore } from '../store/useStore';
2225
import type { INightWatchConfig, IQueueAnalytics, IQueueStatus } from '../api';
2326
import {
@@ -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

Comments
 (0)