Sprint 13 — SimulationFormPage 3-tab layout : aligne le pattern Tabs du sprint 11 (EngagementDetailPage 3→2 tabs) sur SimulationFormPage. Passe de la 2-col [Red Team | SOC] + C2TasksPanel en-dessous à 3 tabsRed Team / SOC / Tâche C2 avec sticky bar contextuelle, count pill C2 réactif, et state disabled gating SOC + C2 selon status + RBAC.
Tabs primitive étendu : ajout du support disabled per-item dans Tabs.tsx (cf. sprint 11). aria-disabled, classe .tab-underline-disabled, ArrowLeft/Right skip les tabs disabled (avec guard anti-boucle infinie si tous disabled).
useHashTab : nouveau param optionnel validIds?: string[] pour fallback gracieux si le hash pointe ailleurs. Back-compatible (EngagementDetailPage non modifiée).
RBAC strict : tab Tâche C2 désactivé pour les rôles SOC (back-end renvoie 403 sur /c2/tasks pour SOC depuis sprint 8 — sans ce gate, SOC voyait un panel cassé en cliquant le tab).
Branche basée sur sprint/12-i18n-fr (PR #14 toujours ouverte). Le diff incluera temporairement les commits sprint 11 + 12 jusqu'à ce que PR #14 merge — il se réduira automatiquement à sprint 13 seul.
E2E : non re-joué (mur Vite proxy connu). Smoke manuel ci-dessous.
Comment tester en local
git checkout sprint/13-sim-tabs
make build && make start
# http://127.0.0.1:5000
Scénarios :
RT par défaut (pending) — Ouvre une sim pending. Tab Red Team actif (underline bleu), tabs SOC (greyed text-steel, non-clickable) et Tâche C2 (normal — admin RT). Sticky bar [ENREGISTRER + MARQUER POUR RÉVISION + Supprimer (rouge à droite)]. Footer FR.
Pass to SOC (review_required) — Clique MARQUER POUR RÉVISION → status flip à review_required → tab SOC devient enabled. Clique-le. Le panel SOC apparaît avec les 4 fields (Source de log, Logs, Commentaire SOC, Numéro d'incident). Sticky bar bascule : [ENREGISTRER SOC + CLORE].
C2 tab admin — Clique Tâche C2 depuis n'importe quel status (admin/redteam). Count pill = nombre de tâches C2 (caché si 0). C2TasksPanel rendu plein écran. Pas de sticky bar sur ce tab (actions sont inline dans le tab Red Team).
C2 tab SOC — Login en SOC, ouvre une sim review_required. Tab SOC enabled (correct), tab Tâche C2 greyed (cohérent avec le 403 backend). Clique impossible.
Mode création — Nouveau sim depuis EngagementDetailPage. Tabs visibles, SOC + Tâche C2 greyed. Form minimal (Nom + Techniques MITRE). Sticky bar [CRÉER LA SIMULATION + ANNULER].
Done state — Sim en done. AlertBanner success au-dessus des tabs ("Cette simulation est terminée…"). Tous tabs enabled. Sticky bar SOC : [ENREGISTRER SOC + Réouvrir].
Hash sync — F5 sur #soc d'une sim pending → tab Red Team actif (safeTab fallback). URL bar auto-corrigée à #red-team via useEffect sync.
Keyboard nav — Focus un tab, ArrowRight cycle vers le suivant en skippant les disabled (RT → C2 si SOC disabled, pas RT → SOC bloqué).
Fichiers modifiés
Path
Type
Notes
frontend/src/components/Tabs.tsx
MOD
TabItem.disabled + click guard + nav skip-disabled + aria-disabled
- c2TabDisabled: add isSoc condition — SOC role has no access to /c2/tasks (backend 403)
- safeTab sync: useEffect before early returns using detail.data?.status; syncs
window.location.hash when hash points to a now-disabled tab after status transition
- create-mode submit button: type="submit" form="" → type="button" (form association fix)
- .tab-underline-disabled: text-graphite opacity-50 → text-steel (consistent with
btn-outline:disabled; better perceptual contrast)
- tests: 254 passing (+ SOC × C2 tab disabled assertion)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
You are not authorized to merge this pull request.
This pull request can be merged automatically.
This branch is out-of-date with the base branch
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
[Red Team | SOC]+ C2TasksPanel en-dessous à 3 tabsRed Team / SOC / Tâche C2avec sticky bar contextuelle, count pill C2 réactif, et statedisabledgating SOC + C2 selon status + RBAC.disabledper-item dansTabs.tsx(cf. sprint 11).aria-disabled, classe.tab-underline-disabled, ArrowLeft/Right skip les tabs disabled (avec guard anti-boucle infinie si tous disabled).useHashTab: nouveau param optionnelvalidIds?: string[]pour fallback gracieux si le hash pointe ailleurs. Back-compatible (EngagementDetailPage non modifiée)./c2/taskspour SOC depuis sprint 8 — sans ce gate, SOC voyait un panel cassé en cliquant le tab).Dépendance — sprints 11 + 12
Branche basée sur
sprint/12-i18n-fr(PR #14 toujours ouverte). Le diff incluera temporairement les commits sprint 11 + 12 jusqu'à ce que PR #14 merge — il se réduira automatiquement à sprint 13 seul.Test plan
tsc --noEmitclean,eslint --max-warnings=0clean.pnpm buildclean (✓ 2.54s) — PostCSS résout tous les@apply, leçon sprint 11feedback_css_apply_tokensrespectée.Comment tester en local
Scénarios :
pending) — Ouvre une simpending. TabRed Teamactif (underline bleu), tabsSOC(greyedtext-steel, non-clickable) etTâche C2(normal — admin RT). Sticky bar[ENREGISTRER + MARQUER POUR RÉVISION + Supprimer (rouge à droite)]. Footer FR.review_required) — CliqueMARQUER POUR RÉVISION→ status flip àreview_required→ tabSOCdevient enabled. Clique-le. Le panel SOC apparaît avec les 4 fields (Source de log, Logs, Commentaire SOC, Numéro d'incident). Sticky bar bascule :[ENREGISTRER SOC + CLORE].Tâche C2depuis n'importe quel status (admin/redteam). Count pill = nombre de tâches C2 (caché si 0). C2TasksPanel rendu plein écran. Pas de sticky bar sur ce tab (actions sont inline dans le tab Red Team).review_required. TabSOCenabled (correct), tabTâche C2greyed (cohérent avec le 403 backend). Clique impossible.SOC+Tâche C2greyed. Form minimal (Nom + Techniques MITRE). Sticky bar[CRÉER LA SIMULATION + ANNULER].done. AlertBanner success au-dessus des tabs ("Cette simulation est terminée…"). Tous tabs enabled. Sticky bar SOC :[ENREGISTRER SOC + Réouvrir].#socd'une simpending→ tabRed Teamactif (safeTab fallback). URL bar auto-corrigée à#red-teamviauseEffectsync.Fichiers modifiés
frontend/src/components/Tabs.tsxTabItem.disabled+ click guard + nav skip-disabled +aria-disabledfrontend/src/hooks/useHashTab.tsvalidIds?: string[]optionnel, back-compat sprint 11frontend/src/styles/index.css.tab-underline-disabled(text-steel cursor-not-allowed)frontend/src/pages/SimulationFormPage.tsxsafeTabguard + useEffect syncfrontend/src/i18n/fr.jsonsimulation.form.tab.{redTeam,soc,c2}DESIGN.mdCHANGELOG.mdfrontend/tests/components/Tabs.test.tsxfrontend/tests/SimulationFormPage.test.tsxDécisions verrouillées (de la phase planning)
aria-disabled){review_required, done}c2Tasks.lengthDécisions team-lead (appliquées)
red-team#red-team/#soc/#c2[Execute via C2]+[Import C2 history]: restent dans le tab Red Team (actions RT qui déclenchent C2)Findings résolus (reviews)
c2TabDisabled = isNew || isSoc) + nouveau testuseEffectsyncsafeTab ↔ activeTabquand stale hashtype="submit" form=""→type="button"sur new-sim submit.tab-underline-disabled:text-graphite opacity-50→text-steel(meilleur contraste)Out of scope (reconnu)
ForbiddenState/NotFoundStatecomponents (n'existent pas)Commits
🤖 Generated with Claude Code
- Tabs: disabled per-item (aria-disabled, native disabled, tab-underline-disabled, arrow-key skip); aria-controls wired - useHashTab: optional validIds fallback to defaultId - SimulationFormPage: 3-tab refactor; SOC tab gated on review_required|done; C2 tab disabled in create mode; contextual sticky bar hidden on C2 tab; safeTab guard against stale hash; SOC-blocked banner removed - fr.json: simulation.form.tab.{redTeam,soc,c2} keys - DESIGN.md: disabled tab variant + aria-controls documented - Tests: 253 passing (5 new Tabs disabled tests, SimulationFormPage rewritten for tab layout) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.