From 0ee3a4176f71ecd9effc9d005c342c3921dc094b Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Wed, 15 May 2024 17:16:24 +0200 Subject: [PATCH] feat: add audit action plan --- backend/core/views.py | 16 ++- frontend/messages/en.json | 5 +- frontend/messages/fr.json | 4 +- frontend/src/lib/utils/locales.ts | 1 + .../[id=uuid]/action-plan/+page.server.ts | 5 +- .../[id=uuid]/action-plan/+page.svelte | 136 ++++++++++++++++-- 6 files changed, 142 insertions(+), 25 deletions(-) diff --git a/backend/core/views.py b/backend/core/views.py index 05349415d..dce44f593 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -1196,7 +1196,12 @@ def action_plan(self, request, pk): object_type=ComplianceAssessment, ) if UUID(pk) in viewable_objects: - response = {"planned": dict(), "active": dict(), "inactive": dict(), "none": dict()} + response = { + "planned": list(), + "active": list(), + "inactive": list(), + "none": list(), + } compliance_assessment_object = self.get_object() requirement_assessments_objects = ( compliance_assessment_object.get_requirement_assessments() @@ -1204,15 +1209,14 @@ def action_plan(self, request, pk): applied_controls = AppliedControlReadSerializer( AppliedControl.objects.filter( requirement_assessments__in=requirement_assessments_objects - ), + ).distinct(), many=True, ).data for applied_control in applied_controls: - response[applied_control["status"].lower()].update( - applied_control - ) if applied_control["status"] else response["none"].update( + applied_control["requirements_count"] = RequirementAssessment.objects.filter(compliance_assessment=compliance_assessment_object).filter(applied_controls=applied_control["id"]).count() + response[applied_control["status"].lower()].append( applied_control - ) + ) if applied_control["status"] else response["none"].append(applied_control) return Response(response) def perform_create(self, serializer): diff --git a/frontend/messages/en.json b/frontend/messages/en.json index a273e827d..a9aecab19 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -516,5 +516,8 @@ "implementationGroupsDefinition": "Implementation groups definition", "threatRadarChart": "Threat radar", "noThreatsMapped": "No threats mapped. Consider attaching threats to your risk scenarios for a better overview.", - "actionPlan": "Action plan" + "actionPlan": "Action plan", + "noStatus": "No status", + "actionPlanHelpText": "Separated by status and sorted by eta", + "requirementsCount": "Requirements count" } diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index 054a35e36..bf8a1d3b7 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -164,8 +164,8 @@ "currentRisk": "Risque courant", "residualRisk": "Risque résiduel", "planned": "Planifié", - "active": "Active", - "inactive": "Inactive", + "active": "Actif", + "inactive": "Inactif", "watchlist": "Liste de surveillance", "watchlistDescription": "Objets expirés ou expirant bientôt", "measuresToReview": "Mesures à revoir", diff --git a/frontend/src/lib/utils/locales.ts b/frontend/src/lib/utils/locales.ts index 849354c78..6722f27ae 100644 --- a/frontend/src/lib/utils/locales.ts +++ b/frontend/src/lib/utils/locales.ts @@ -336,6 +336,7 @@ export function localItems(languageTag: string): LocalItems { languageTag: languageTag }), actionPlan: m.actionPlan({ languageTag: languageTag }), + requirementsCount: m.requirementsCount({ languageTag: languageTag }), }; return LOCAL_ITEMS; } diff --git a/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.server.ts b/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.server.ts index 30f8443c9..7b2360ca0 100644 --- a/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.server.ts +++ b/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.server.ts @@ -5,8 +5,11 @@ import type { PageServerLoad } from './$types'; export const load = (async ({ fetch, params }) => { const URLModel = 'compliance-assessments'; const endpoint = `${BASE_API_URL}/${URLModel}/${params.id}/`; + const actionPlanEndpoint = `${BASE_API_URL}/${URLModel}/${params.id}/action_plan/`; const res = await fetch(endpoint); + const actionPlanRes = await fetch(actionPlanEndpoint); const compliance_assessment = await res.json(); - return { URLModel, compliance_assessment }; + const actionPlan = await actionPlanRes.json(); + return { URLModel, compliance_assessment, actionPlan }; }) satisfies PageServerLoad; \ No newline at end of file diff --git a/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.svelte b/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.svelte index 46b6575ed..f50fe90ad 100644 --- a/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.svelte +++ b/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/action-plan/+page.svelte @@ -1,24 +1,67 @@ -
+

{m.project()}:

- -

{m.associatedRiskScenarios()}:

\ No newline at end of file +
+
+

{m.associatedAppliedControls()}

+

+ {m.actionPlanHelpText()} +

+
+
+ + {m.planned()} + {m.active()} + {m.inactive()} + {m.noStatus()} + +
+ {#if tabSet === 0} + + {/if} + {#if tabSet === 1} + + {/if} + {#if tabSet === 2} + + {/if} + {#if tabSet === 3} + + {/if} +
+
+
+
+ +