100 lines
3.3 KiB
JavaScript
100 lines
3.3 KiB
JavaScript
'use strict';
|
|
const { Router } = require('express');
|
|
const { getAllTests, getConfig } = require('../db');
|
|
|
|
const router = Router();
|
|
|
|
router.get('/', (req, res) => {
|
|
const tests = getAllTests();
|
|
|
|
// ── Overall ───────────────────────────────────────────────────────────────
|
|
const totalCompleted = tests.filter(t => t.completed).length;
|
|
const overall = {
|
|
total: tests.length,
|
|
completed: totalCompleted,
|
|
completionRate: tests.length > 0 ? totalCompleted / tests.length : 0,
|
|
};
|
|
|
|
// ── Per device ────────────────────────────────────────────────────────────
|
|
const deviceMap = new Map();
|
|
for (const t of tests) {
|
|
if (!t.device) continue;
|
|
if (!deviceMap.has(t.device)) deviceMap.set(t.device, { total: 0, completed: 0 });
|
|
const d = deviceMap.get(t.device);
|
|
d.total++;
|
|
if (t.completed) d.completed++;
|
|
}
|
|
const devices = Array.from(deviceMap.entries())
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
.map(([name, d]) => ({
|
|
name,
|
|
total: d.total,
|
|
completed: d.completed,
|
|
completionRate: d.total > 0 ? d.completed / d.total : 0,
|
|
}));
|
|
|
|
// ── Elapsed = sum of individual test durations ────────────────────────────
|
|
const elapsedSeconds = tests.reduce((sum, t) => {
|
|
return t.completed && t.duration_seconds != null ? sum + t.duration_seconds : sum;
|
|
}, 0);
|
|
|
|
// ── Per-type averages and remaining counts ────────────────────────────────
|
|
const TYPES = ['COE', 'P2P', 'P3P'];
|
|
const byType = {};
|
|
let estimatedRemainingSeconds = 0;
|
|
let estimatePossible = true;
|
|
|
|
for (const type of TYPES) {
|
|
const typeTests = tests.filter(t => t.interference === type);
|
|
const completed = typeTests.filter(t => t.completed);
|
|
const withDuration = completed.filter(t => t.duration_seconds != null);
|
|
const remaining = typeTests.length - completed.length;
|
|
|
|
const calcAvg = withDuration.length > 0
|
|
? withDuration.reduce((s, t) => s + t.duration_seconds, 0) / withDuration.length
|
|
: null;
|
|
|
|
const manualValue = getConfig(`avg_time_${type.toLowerCase()}`);
|
|
|
|
let avgSeconds = null;
|
|
let avgSource = null;
|
|
|
|
if (manualValue !== null) {
|
|
avgSeconds = parseFloat(manualValue);
|
|
avgSource = calcAvg !== null ? 'manual_override' : 'manual';
|
|
} else if (calcAvg !== null) {
|
|
avgSeconds = calcAvg;
|
|
avgSource = 'calculated';
|
|
}
|
|
|
|
byType[type] = {
|
|
total: typeTests.length,
|
|
completed: completed.length,
|
|
remaining,
|
|
avgSeconds,
|
|
avgSource,
|
|
};
|
|
|
|
if (remaining > 0) {
|
|
if (avgSeconds !== null) {
|
|
estimatedRemainingSeconds += avgSeconds * remaining;
|
|
} else {
|
|
estimatePossible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
res.json({
|
|
overall,
|
|
devices,
|
|
timing: {
|
|
elapsedSeconds,
|
|
estimatedRemainingSeconds: estimatePossible ? estimatedRemainingSeconds : null,
|
|
byType,
|
|
},
|
|
});
|
|
});
|
|
|
|
module.exports = router;
|
|
|