knapsack scheduling algorithm

This commit is contained in:
2026-07-12 14:19:58 -04:00
parent 031da48ddd
commit 9e100d60d0
56 changed files with 1936 additions and 1286 deletions
+30 -2
View File
@@ -1,4 +1,5 @@
import DayColumn from './DayColumn'
import { getDeviceAccentClass } from './TestCard'
function addDays(date, n) {
const d = new Date(date)
@@ -47,7 +48,14 @@ function getNextTestWindow() {
}
// scheduleData: { "YYYY-MM-DD": { shift1: [...], shift2: [...], shift3: [...] }, ... }
export default function Calendar({ scheduleData = {}, daytimeDateKey = null, weekStart, onWeekChange }) {
export default function Calendar({
scheduleData = {},
daytimeDateKey = null,
weekStart,
onWeekChange,
windowLookup = new Map(),
onWindowSelect,
}) {
const today = new Date()
today.setHours(0, 0, 0, 0)
@@ -58,6 +66,18 @@ export default function Calendar({ scheduleData = {}, daytimeDateKey = null, wee
// Reorder columns: Sun Mon Tue Wed Thu Fri Sat
// weekStart is Monday, so days[0]=Mon ... days[6]=Sun → put Sunday first
const orderedDays = [ ...days.slice(0, 7)]
const deviceLegendItems = Array.from(
new Set(
Object.values(scheduleData)
.flatMap((day) => [
...(day?.shift1 ?? []),
...(day?.shift2 ?? []),
...(day?.shift3 ?? []),
])
.map((test) => test?.device)
.filter(Boolean),
),
).sort((a, b) => String(a).localeCompare(String(b)))
return (
<div className="flex flex-col gap-3 h-full">
@@ -112,16 +132,24 @@ export default function Calendar({ scheduleData = {}, daytimeDateKey = null, wee
activeShifts={activeShifts}
shifts={shifts}
showShift2={isWeekend || (daytimeDateKey !== null && key === daytimeDateKey)}
windowLookup={windowLookup}
onWindowSelect={onWindowSelect}
/>
)
})}
</div>
{/* Legend */}
<div className="flex gap-4 text-xs text-gray-400">
<div className="flex flex-wrap gap-x-6 gap-y-2 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" />Rerun Required</span>
{deviceLegendItems.map((device) => (
<span key={device} className="flex items-center gap-1.5">
<span className={`w-2.5 h-2.5 rounded-sm inline-block ${getDeviceAccentClass(device)}`} />
{device}
</span>
))}
</div>
</div>
)