feat(m7-amend): full-bleed scenario table with inline edit + docs

Frontend half of the 2026-05-15 amendment (backend shipped in 447f152).

- `MissionScenarioTable` component: per-scenario <table> with 7 cols
  (Test | Procédure | Exécution | Source de log | Commentaires | Logs
  SIEM | Cyber Incident) + Actions cell. Read mode truncates; double-
  click toggles a row into edit mode where each cell becomes the right
  control. detection_level lives inside the Commentaires cell as a
  pill + select (no 8th column).
- MissionDetailPage Tests tab uses the new component, lifts
  `editingTestId` so only one row across the whole mission is editable
  at a time. Esc reverts (prompt if dirty), double-click on a different
  row with a dirty draft also prompts.
- Full-bleed escape via `calc(50% - 50vw)` (same recipe as the M4 MITRE
  picker). 7 dense columns breathe on wide screens, no horizontal scroll.
- `draftDiff(test, draft)` returns `null` when nothing changed → no PUT
  on a no-op save. The diff carries only touched fields so the server's
  per-field perm gate stays clean.
- Datetime semantics: both datetime-local inputs reuse the M7 verbatim
  recipe (`iso.slice(0, 16)` + `${local}:00Z`), zero TZ shift.

Docs
- tasks/testing-m7.md §3.0 documents the column matrix + edit workflow.
- tasks/lessons.md captures the Pydantic ctx-serialisation pitfall, the
  naïve-datetime guard, the table-edit pattern.
- CHANGELOG section moves "Frontend (in progress)" → "Frontend (shipped)"
  and details the diff.

49 Playwright tests still green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-15 14:51:28 +02:00
parent 447f15213a
commit 9fc78e0832
6 changed files with 775 additions and 109 deletions

View File

@@ -43,6 +43,36 @@ Rapport HTML : `e2e/playwright-report/`.
- Une mission existante avec au moins **1 scenario** snapshotté contenant
**≥ 1 test** (voir `testing-m6.md` pour le chemin de création).
### 3.0 Vue tabulaire (`/missions/<id>` — onglet tests, amendement 2026-05-15)
L'onglet **tests** rend désormais un tableau plein écran **par scénario**
(un row par test). Largeur pleine viewport (`max-w-page` échappé via la
recette `calc(50% - 50vw)` — même mécanisme que le picker MITRE).
**Colonnes** :
| Colonne | Read mode | Edit mode | Perm requise |
|---------|-----------|-----------|--------------|
| **Test** | nom + chips MITRE | (read-only) | — |
| **Procédure** | snapshot_objective / description tronqués 180 chars | (read-only) | — |
| **Exécution** | `executed_at` + `red_command` tronqué | datetime-local + textarea command | `mission.write_red_fields` |
| **Source de log** | `blue_log_source` | input texte (placeholder `EDR / Firewall / NDR …`) | `mission.write_blue_fields` |
| **Commentaires** | pill state + pill detection_level + commentaire | select detection_level + textarea commentaire | `mission.write_blue_fields` |
| **Logs SIEM** | `blue_siem_logs` tronqué 240 chars | textarea 6 lignes | `mission.write_blue_fields` |
| **Cyber Incident** | `incident_at` / `incident_number` / `incident_recipient_email` empilés | 3 inputs (datetime-local / texte / email) | `mission.write_blue_fields` |
| **Actions** | lien `open ↗` vers `/missions/<id>/tests/<test_id>` (full detail + evidence) | boutons `Save` / `Cancel` | — |
**Workflow d'édition** :
1. Double-clic sur une ligne → la ligne entre en mode édition (les cellules
deviennent des inputs). Une seule ligne en édition à la fois — un double-clic
sur une autre ligne propose `Discard unsaved changes?` si la précédente
est dirty.
2. **Esc** = cancel (prompt si dirty).
3. **Save** = `PUT /missions/{id}/tests/{test_id}` avec **uniquement les champs
modifiés**. Les cellules qu'un user ne peut pas écrire restent disabled ;
le serveur revalide quoi qu'il arrive (defense in depth).
4. Pour l'upload de preuves : cliquer `open ↗` qui ouvre la page détail
(zone Red / zone Blue + dropzone evidence).
### 3.1 Page de test (`/missions/<id>/tests/<test_id>`)
1. Depuis `/missions/<id>`, onglet **tests**, cliquer une ligne (ou le nom du