diff --git a/backend/app/services/campaign_crud_service.py b/backend/app/services/campaign_crud_service.py index edae68b..3dc7714 100644 --- a/backend/app/services/campaign_crud_service.py +++ b/backend/app/services/campaign_crud_service.py @@ -25,6 +25,7 @@ from app.services.campaign_service import ( TACTIC_TO_PHASE, ) from app.services.campaign_scheduler_service import calculate_next_run +from app.services.status_service import recalculate_technique_status # ── Serialization helpers ──────────────────────────────────────────────── @@ -465,11 +466,21 @@ def delete_campaign( # Optionally delete the associated tests if delete_tests: + affected_technique_ids: set = set() for test_id in test_ids: test = db.query(Test).filter(Test.id == test_id).first() if test: + if test.technique_id: + affected_technique_ids.add(test.technique_id) db.delete(test) db.flush() + # Recalculate status_global for every affected technique so the + # coverage metrics stay consistent after test deletion. + for tech_id in affected_technique_ids: + technique = db.query(Technique).filter(Technique.id == tech_id).first() + if technique: + recalculate_technique_status(db, technique) + db.flush() # Null-out parent_campaign_id on child campaigns to avoid FK violation db.query(Campaign).filter(Campaign.parent_campaign_id == campaign.id).update( diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 499519b..75ba504 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -82,6 +82,7 @@ function SidebarLink({ item }: { item: NavItem }) { `flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors ${ isActive