Files
snowspeeder 5f3a015ea2
Test and deploy / test-and-deploy (push) Successful in 1m43s
Fix report pagination and rebuild saved plan navigation
2026-09-05 15:47:44 -04:00

72 lines
2.0 KiB
JavaScript

import { computeLedger } from "./ledger.js?v=__ASSET_VERSION__";
import { buildPlanCurve } from "./curve.js?v=__ASSET_VERSION__";
import { parseDuration } from "./time.js?v=__ASSET_VERSION__";
export const MILESTONES = [
["charge", "Charge"],
["tp", "Turning point"],
["yellow", "Yellow / dry end"],
["fc", "First crack"],
["drop", "Drop"],
];
export function sanitizeObservations(raw) {
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
const out = {};
for (const [key] of MILESTONES) {
if (raw[key] === undefined) continue;
const row = raw[key];
if (!row || typeof row !== "object" || Array.isArray(row)) return null;
const clean = {};
for (const field of ["timeS", "tempC"]) {
const v = row[field];
if (v === undefined || v === null) {
clean[field] = null;
continue;
}
if (
typeof v !== "number" ||
!Number.isFinite(v) ||
v < 0 ||
v > (field === "timeS" ? 7200 : 350)
)
return null;
clean[field] = v;
}
clean.note = String(row.note ?? "").slice(0, 2000);
out[key] = clean;
}
return out;
}
export function buildComparison(detail) {
const points = detail.plan
? buildPlanCurve(detail.plan, computeLedger(detail.plan))
: [];
return MILESTONES.map(([key, label]) => {
const target = points.find((p) => p.key === key);
const uploaded =
key === "tp"
? detail.parsed?.turningPoint
: detail.parsed?.milestones?.find((p) => p.key === key);
const saved = detail.observations?.[key],
legacy = detail.plan?.planActual?.[key];
const timeS =
saved?.timeS ?? uploaded?.timeS ?? parseDuration(legacy?.actualTime);
const legacyTemp =
legacy?.actualBt !== "" && legacy?.actualBt != null
? Number(legacy.actualBt)
: null;
const tempC =
saved?.tempC ??
uploaded?.tempC ??
(Number.isFinite(legacyTemp) ? legacyTemp : null);
return {
key,
label,
target,
timeS,
tempC,
note: saved?.note ?? legacy?.note ?? "",
deltaS: target && timeS != null ? timeS - target.timeS : null,
};
});
}