implemented watcher and rerun logic

This commit is contained in:
2026-06-25 11:31:20 -04:00
parent 21402f7ee3
commit be13849a4f
15 changed files with 871 additions and 97 deletions
+1 -2
View File
@@ -121,8 +121,7 @@ export default function Calendar({ scheduleData = {}, daytimeDateKey = null, wee
<div className="flex gap-4 text-xs text-gray-400">
<span className="flex items-center gap-1.5"><span className="w-2.5 h-2.5 rounded-sm bg-gray-500 inline-block" />Pending</span>
<span className="flex items-center gap-1.5"><span className="w-2.5 h-2.5 rounded-sm bg-green-700 inline-block" />Completed</span>
<span className="flex items-center gap-1.5"><span className="w-2.5 h-2.5 rounded-sm bg-red-700 inline-block" />Failed</span>
<span className="flex items-center gap-1.5"><span className="w-2.5 h-2.5 rounded-sm bg-yellow-700 inline-block" />Invalid</span>
<span className="flex items-center gap-1.5"><span className="w-2.5 h-2.5 rounded-sm bg-red-700 inline-block" />Rerun Required</span>
</div>
</div>
)
+10 -8
View File
@@ -1,9 +1,11 @@
export default function FailedBanner({ failedTests, estimatedMinutes, onDecision }) {
if (!failedTests || failedTests.length === 0) return null
export default function FailedBanner({ rerunTests, onDecision }) {
if (!rerunTests || rerunTests.length === 0) return null
const hours = Math.floor(estimatedMinutes / 60)
const mins = estimatedMinutes % 60
const totalMinutes = rerunTests.reduce((sum, t) => sum + (t.estimated_minutes ?? 0), 0)
const hours = Math.floor(totalMinutes / 60)
const mins = totalMinutes % 60
const timeStr = hours > 0 ? `${hours}h ${mins}m` : `${mins}m`
const testIds = rerunTests.map(t => t.test_id).join(', ')
return (
<div className="flex items-start gap-4 px-6 py-3 bg-red-900/70 border-b border-red-700 text-red-100">
@@ -23,13 +25,13 @@ export default function FailedBanner({ failedTests, estimatedMinutes, onDecision
</svg>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium">
<span className="font-semibold">{failedTests.length} test{failedTests.length !== 1 ? 's' : ''}</span>
{' '}failed last night and require a rerun {' '}
<span className="font-mono text-red-200">{failedTests.join(', ')}</span>
<span className="font-semibold">{rerunTests.length} test{rerunTests.length !== 1 ? 's' : ''}</span>
{' '}require a rerun not completed in last overnight window:{' '}
<span className="font-mono text-red-200">{testIds}</span>
</p>
<p className="text-sm text-red-300 mt-0.5">
Estimated rerun time: <span className="font-semibold text-red-100">{timeStr}</span>
{' '} Rerun these tests during the day today?
{' '} Schedule rerun during daytime today?
</p>
</div>
<div className="flex gap-2 shrink-0">
+14
View File
@@ -14,6 +14,8 @@ function formatCompletionDate(value) {
export default function RightPanel({
completionDate,
startDateOverride,
onStartDateOverrideChange,
daytimeEnabled,
onDaytimeEnabledChange,
topPriority,
@@ -75,6 +77,18 @@ export default function RightPanel({
/>
</div>
<div>
<label className="block text-[11px] font-semibold uppercase tracking-wider text-gray-500 mb-1.5">
Start Date Override
</label>
<input
type="date"
value={startDateOverride}
onChange={(e) => onStartDateOverrideChange(e.target.value)}
className="w-full bg-gray-900 border border-gray-600 rounded-md px-2.5 py-1.5 text-xs text-gray-200 focus:outline-none focus:border-blue-500 font-mono"
/>
</div>
{/* Remake schedule */}
<button
onClick={onRemakeSchedule}
+88 -24
View File
@@ -1,10 +1,11 @@
import { useState, useEffect } from 'react'
function Field({ label, hint, children }) {
function Field({ label, hint, required = false, children }) {
return (
<div>
<label className="block text-xs font-semibold text-gray-300 mb-1">
{label}
{required && <span className="ml-1 text-red-400">*</span>}
{hint && <span className="ml-1.5 text-gray-500 font-normal">{hint}</span>}
</label>
{children}
@@ -15,8 +16,6 @@ function Field({ label, hint, children }) {
const INPUT_CLS =
'w-full bg-gray-900 border border-gray-600 rounded-md px-3 py-1.5 text-sm text-gray-200 placeholder-gray-600 focus:outline-none focus:border-blue-500 font-mono'
const TEXTAREA_CLS = INPUT_CLS + ' resize-none'
export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
const [form, setForm] = useState({ ...settings })
@@ -69,7 +68,7 @@ export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
File Paths
</p>
<div className="flex flex-col gap-3">
<Field label="P2P / COE CSV">
<Field label="P2P / COE CSV" required>
<input
type="text"
className={INPUT_CLS}
@@ -78,7 +77,7 @@ export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
onChange={(e) => set('p2pCoeCsvPath', e.target.value)}
/>
</Field>
<Field label="P3P CSV">
<Field label="P3P CSV" required>
<input
type="text"
className={INPUT_CLS}
@@ -87,7 +86,7 @@ export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
onChange={(e) => set('p3pCsvPath', e.target.value)}
/>
</Field>
<Field label="REF Result Directory">
<Field label="REF Result Directory" required>
<input
type="text"
className={INPUT_CLS}
@@ -96,7 +95,7 @@ export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
onChange={(e) => set('refResultDir', e.target.value)}
/>
</Field>
<Field label="DUT Result Directory">
<Field label="DUT Result Directory" required>
<input
type="text"
className={INPUT_CLS}
@@ -110,6 +109,88 @@ export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
<hr className="border-gray-700" />
{/* Section: Network Shares */}
<div>
<p className="text-[11px] font-bold uppercase tracking-widest text-gray-500 mb-3">
Network Shares
</p>
<div className="flex flex-col gap-3">
<Field label="SMB Username">
<input
type="text"
className={INPUT_CLS}
placeholder="username"
value={form.smbUsername ?? ''}
onChange={(e) => set('smbUsername', e.target.value)}
/>
</Field>
<Field label="SMB Password">
<input
type="password"
className={INPUT_CLS}
placeholder="password"
value={form.smbPassword ?? ''}
onChange={(e) => set('smbPassword', e.target.value)}
/>
</Field>
<Field label="SMB Domain">
<input
type="text"
className={INPUT_CLS}
placeholder="WORKGROUP or DOMAIN"
value={form.smbDomain ?? ''}
onChange={(e) => set('smbDomain', e.target.value)}
/>
</Field>
</div>
</div>
<hr className="border-gray-700" />
{/* Section: Runtime Overrides */}
<div>
<p className="text-[11px] font-bold uppercase tracking-widest text-gray-500 mb-3">
Runtime Overrides
</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
<Field label="P2P Minutes">
<input
type="number"
min="1"
step="1"
className={INPUT_CLS}
placeholder="80"
value={form.p2pRuntimeMinutes ?? ''}
onChange={(e) => set('p2pRuntimeMinutes', e.target.value)}
/>
</Field>
<Field label="COE Minutes">
<input
type="number"
min="1"
step="1"
className={INPUT_CLS}
placeholder="115"
value={form.coeRuntimeMinutes ?? ''}
onChange={(e) => set('coeRuntimeMinutes', e.target.value)}
/>
</Field>
<Field label="P3P Minutes">
<input
type="number"
min="1"
step="1"
className={INPUT_CLS}
placeholder="105"
value={form.p3pRuntimeMinutes ?? ''}
onChange={(e) => set('p3pRuntimeMinutes', e.target.value)}
/>
</Field>
</div>
</div>
<hr className="border-gray-700" />
{/* Section: Test Exclusion */}
<div>
<p className="text-[11px] font-bold uppercase tracking-widest text-gray-500 mb-3">
@@ -143,23 +224,6 @@ export default function SettingsModal({ isOpen, onClose, settings, onSave }) {
/>
</Field>
</div>
<hr className="border-gray-700" />
{/* Section: Schedule */}
<div>
<p className="text-[11px] font-bold uppercase tracking-widest text-gray-500 mb-3">
Schedule
</p>
<Field label="Start Date Override" hint="(YYYY-MM-DD, leave blank for today)">
<input
type="date"
className={INPUT_CLS}
value={form.startDateOverride ?? ''}
onChange={(e) => set('startDateOverride', e.target.value)}
/>
</Field>
</div>
</div>
{/* Footer */}
+1 -2
View File
@@ -1,8 +1,7 @@
const STATUS_STYLES = {
pending: 'bg-gray-600/60 text-gray-200 border-gray-500',
completed: 'bg-green-800/60 text-green-200 border-green-600',
failed: 'bg-red-800/60 text-red-200 border-red-600',
invalid: 'bg-yellow-800/60 text-yellow-200 border-yellow-600',
rerun: 'bg-red-800/60 text-red-200 border-red-600',
}
function formatConfig(config) {