Skip to content

Commit 8702b77

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 3a65e1b commit 8702b77

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
@@ -23,6 +23,9 @@ import Tabs from '../components/ui/Tabs';
2323
import ScheduleConfig from '../components/scheduling/ScheduleConfig.js';
2424
import type { IScheduleConfigForm } from '../components/scheduling/ScheduleConfig.js';
2525
import ScheduleTimeline from '../components/scheduling/ScheduleTimeline.js';
26+
import ProviderLanesChart from '../components/scheduling/ProviderLanesChart.js';
27+
import ProviderBucketSummary from '../components/scheduling/ProviderBucketSummary.js';
28+
import RecentRunsChart from '../components/scheduling/RecentRunsChart.js';
2629
import { useStore } from '../store/useStore';
2730
import type { INightWatchConfig, IQueueAnalytics, IQueueStatus, QueueMode } from '../api';
2831
import {
@@ -1023,6 +1026,109 @@ const Scheduling: React.FC = () => {
10231026
</div>
10241027
),
10251028
},
1029+
{
1030+
id: 'queue',
1031+
label: 'Queue',
1032+
content: (
1033+
<div className="space-y-6">
1034+
{/* Queue Overview Card */}
1035+
<Card className="p-6">
1036+
<h3 className="text-lg font-semibold text-slate-200 mb-4">Queue Overview</h3>
1037+
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
1038+
<div className="bg-slate-950/40 rounded-lg p-4 border border-slate-800">
1039+
<div className="text-xs uppercase tracking-wide text-slate-500 mb-1">Running</div>
1040+
<div className="text-2xl font-bold text-green-400">
1041+
{queueStatus?.running ? 1 : 0}
1042+
</div>
1043+
{queueStatus?.running && (
1044+
<div className="text-xs text-slate-400 mt-1 truncate" title={queueStatus.running.projectName}>
1045+
{queueStatus.running.jobType} · {queueStatus.running.projectName}
1046+
</div>
1047+
)}
1048+
</div>
1049+
<div className="bg-slate-950/40 rounded-lg p-4 border border-slate-800">
1050+
<div className="text-xs uppercase tracking-wide text-slate-500 mb-1">Pending</div>
1051+
<div className="text-2xl font-bold text-blue-400">
1052+
{queueStatus?.pending.total ?? 0}
1053+
</div>
1054+
</div>
1055+
<div className="bg-slate-950/40 rounded-lg p-4 border border-slate-800">
1056+
<div className="text-xs uppercase tracking-wide text-slate-500 mb-1">Avg Wait</div>
1057+
<div className="text-2xl font-bold text-slate-200">
1058+
{queueStatus?.averageWaitSeconds != null
1059+
? `${Math.floor(queueStatus.averageWaitSeconds / 60)}m`
1060+
: '—'}
1061+
</div>
1062+
</div>
1063+
<div className="bg-slate-950/40 rounded-lg p-4 border border-slate-800">
1064+
<div className="text-xs uppercase tracking-wide text-slate-500 mb-1">Oldest Pending</div>
1065+
<div className="text-2xl font-bold text-slate-200">
1066+
{queueStatus?.oldestPendingAge != null
1067+
? `${Math.floor(queueStatus.oldestPendingAge / 60)}m`
1068+
: '—'}
1069+
</div>
1070+
</div>
1071+
</div>
1072+
</Card>
1073+
1074+
{/* Provider Lanes */}
1075+
<Card className="p-6">
1076+
<div className="flex items-center justify-between mb-4">
1077+
<div>
1078+
<h3 className="text-lg font-semibold text-slate-200">Provider Lanes</h3>
1079+
<p className="text-xs text-slate-500 mt-0.5">
1080+
Running and pending jobs grouped by provider bucket
1081+
</p>
1082+
</div>
1083+
</div>
1084+
{queueStatus ? (
1085+
<ProviderLanesChart status={queueStatus} />
1086+
) : (
1087+
<div className="text-sm text-slate-500 py-2">Loading queue status...</div>
1088+
)}
1089+
</Card>
1090+
1091+
{/* Provider Bucket Summary */}
1092+
<Card className="p-6">
1093+
<div className="flex items-center justify-between mb-4">
1094+
<div>
1095+
<h3 className="text-lg font-semibold text-slate-200">Provider Buckets</h3>
1096+
<p className="text-xs text-slate-500 mt-0.5">
1097+
Running and pending counts per provider bucket
1098+
</p>
1099+
</div>
1100+
</div>
1101+
{queueAnalytics ? (
1102+
<ProviderBucketSummary analytics={queueAnalytics} />
1103+
) : (
1104+
<div className="text-sm text-slate-500 py-2">Loading analytics...</div>
1105+
)}
1106+
</Card>
1107+
1108+
{/* Recent Runs */}
1109+
<Card className="p-6">
1110+
<div className="flex items-center justify-between mb-4">
1111+
<div>
1112+
<h3 className="text-lg font-semibold text-slate-200">Recent Runs</h3>
1113+
<p className="text-xs text-slate-500 mt-0.5">
1114+
Last 24 hours of job executions
1115+
</p>
1116+
</div>
1117+
{queueAnalytics?.averageWaitSeconds != null && (
1118+
<div className="text-xs text-slate-500">
1119+
Avg wait: {Math.floor(queueAnalytics.averageWaitSeconds / 60)}m
1120+
</div>
1121+
)}
1122+
</div>
1123+
{queueAnalytics ? (
1124+
<RecentRunsChart analytics={queueAnalytics} />
1125+
) : (
1126+
<div className="text-sm text-slate-500 py-2">Loading analytics...</div>
1127+
)}
1128+
</Card>
1129+
</div>
1130+
),
1131+
},
10261132
];
10271133

10281134
return (

0 commit comments

Comments
 (0)