User feedback: the execution timestamp is the anchor the blue team
correlates their logs against, so it should be the *first* thing in the
red form, not the last (where it lived alongside the override toggle).
Moved the executed-at block above Command/Output/Comment and wrapped it
in a tinted red sub-card (border-red/40 bg-red/5) so it reads as the
form's headline. The block now shows:
- the current `executed_at` (with an `· overridden` hint when applicable),
or a "Not yet executed" stub when the test is still pending,
- the override toggle (disabled until the test reaches executed/reviewed),
- the local datetime-local input + a small "Browser local time — server
stores UTC" hint so an operator typing 10:30 in Paris isn't surprised
to see 08:30Z in the JSON.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reported by the user: the blue-side dropzone said "≤ 25 MB each" but
nowhere did it list the accepted extensions, and the OS file picker
showed "All files" — so an operator could spend the time picking a
`.exe` only to get a 400 back.
- New constants `EVIDENCE_ALLOWED_EXTENSIONS` + `EVIDENCE_MAX_BYTES` in
`lib/missions.ts`. Manual mirror of the backend whitelist (commented
cross-reference). One source of truth on the client.
- Dropzone now prints `Accepted: .png · .jpg · .jpeg · .pdf · .txt ·
.log · .json · .csv · .evtx · .zip · max 25 MB / file`
(testid `evidence-allowed-formats`).
- File input gains `accept=".png,.jpg,..."` so the OS picker pre-filters
to those extensions instead of "All files".
- `handleFiles` rejects drag-and-drops of unsupported extensions on the
client too (still re-checked server-side — defence in depth, not a
security boundary).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The naive `new Date(executedAt).toISOString().slice(0, 16)` round-trip on
every keystroke silently shifted the hour by the local TZ offset (Europe
input field is local-time but we kept reformatting via UTC), so the user
could only edit the date — the time component snapped back to UTC every
render.
Fix: keep the local state in `YYYY-MM-DDTHH:MM` form (`executedAtLocal`)
and only convert to/from a UTC ISO at the boundaries — initial sync from
server and submit. Two small helpers `isoToLocalInputValue` /
`localInputValueToIso` carry the conversion explicitly.
Also tightened the useEffect on both Red and Blue zones to depend on
`test.id` instead of the whole `test` object, so polling refetches no
longer wipe an in-progress edit (the 15 s activity poll returns a fresh
object reference even when the row's contents are unchanged).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>