diff --git a/backend/core/helpers.py b/backend/core/helpers.py index a01f0521e..99e5a1d74 100644 --- a/backend/core/helpers.py +++ b/backend/core/helpers.py @@ -1,5 +1,4 @@ from datetime import date, timedelta -from re import sub from django.db.models import Count from django.shortcuts import get_object_or_404 @@ -8,6 +7,7 @@ from core.serializers import SecurityFunctionReadSerializer, ThreatReadSerializer from .models import * +from .utils import camel_case STATUS_COLOR_MAP = { # TODO: Move these kinds of color maps to frontend "--": "#fac858", @@ -25,12 +25,6 @@ } -def camel_case(s): - s = sub(r"(_|-)+", " ", s).title().replace(" ", "") - - return "".join([s[0].lower(), s[1:]]) - - def security_measure_priority(user: User): def get_quadrant(security_measure): if security_measure.effort in ["S", "M"]: @@ -253,6 +247,7 @@ def get_sorted_requirement_nodes_rec( "leaf_content": req.display_long(), "status": req_as.status, "status_display": req_as.get_status_display(), + "status_i18n": camel_case(req_as.status), "style": "leaf", "threats": ThreatReadSerializer( req.threats.all(), many=True @@ -844,6 +839,10 @@ def compile_risk_assessment_for_composer(user, risk_assessment_list: list): "untreated_h_vh": untreated_h_vh, "accepted": accepted, }, - "security_measure_status": {"localLables":local_lables, "labels": labels, "values": values}, + "security_measure_status": { + "localLables": local_lables, + "labels": labels, + "values": values, + }, "colors": get_risk_color_ordered_list(user, risk_assessment_list), } diff --git a/backend/core/models.py b/backend/core/models.py index 70bd43223..1d9aa0003 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -7,6 +7,7 @@ from .base_models import * from .validators import validate_file_size, validate_file_name +from .utils import camel_case from iam.models import FolderMixin from django.core import serializers @@ -779,9 +780,9 @@ def quality_check(self) -> dict: if not self.authors.all(): info_lst.append( { - "msg": _( - "{}: No author assigned to this risk assessment" - ).format(str(self)), + "msg": _("{}: No author assigned to this risk assessment").format( + str(self) + ), "obj_type": "risk_assessment", "object": _object, } @@ -1281,6 +1282,7 @@ def donut_render(self) -> dict: count = ( RequirementAssessment.objects.filter(status=st) .filter(compliance_assessment=self) + .filter(requirement__assessable=True) .count() ) total = RequirementAssessment.objects.filter( @@ -1288,6 +1290,7 @@ def donut_render(self) -> dict: ).count() v = { "name": st.label, + "localName": camel_case(st.value), "value": count, "itemStyle": {"color": color_map[st]}, } diff --git a/backend/core/utils.py b/backend/core/utils.py index 83f52fa42..9d8514d76 100644 --- a/backend/core/utils.py +++ b/backend/core/utils.py @@ -1,7 +1,14 @@ from django.utils.translation import gettext_lazy as _ +from re import sub from enum import Enum +def camel_case(s): + s = sub(r"(_|-)+", " ", s).title().replace(" ", "") + + return "".join([s[0].lower(), s[1:]]) + + class RoleCodename(Enum): ADMINISTRATOR = "BI-RL-ADM" DOMAIN_MANAGER = "BI-RL-DMA" diff --git a/backend/core/views.py b/backend/core/views.py index 34f6eb424..e15b5f2bd 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -1348,7 +1348,7 @@ def generate_html( ) assessments = RequirementAssessment.objects.filter( - compliance_assessment=compliance_assessment + compliance_assessment=compliance_assessment, ).all() node_per_urn = {r.urn: r for r in requirement_nodes} @@ -1366,7 +1366,9 @@ def bar_graph(node: RequirementNode): content = "" compliance_assessments_status = [] candidates = [ - c for c in assessments if not (node) or c == node or node in ancestors[c] + c + for c in assessments.filter(requirement__assessable=True) + if not (node) or c == node or node in ancestors[c] ] total = len(candidates) for st in RequirementAssessment.Status: @@ -1388,9 +1390,11 @@ def bar_graph(node: RequirementNode): content += "bg-green-500" elif stat[0] == "not_applicable": content += "bg-black text-white dark:bg-white dark:text-black" - content += ( - '" style="width:' + str(stat[1]) + '%"> ' + str(stat[1]) + "%" - ) + content += '" style="width:' + str(stat[1]) + '%"> ' + if stat[0] != "to_do": + content += str(stat[1]) + "%" + + content += "" content += "" return content diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 0be0465df..955bff10e 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -370,5 +370,11 @@ "current": "Current", "residual": "Residual", "jumpToRiskAssessment": "Jump to risk assessment", - "additionalMeasures": "Additional measures" + "additionalMeasures": "Additional measures", + "toDo": "To do", + "inProgress": "In progress", + "nonCompliant": "Non compliant", + "partiallyCompliant": "Partially compliant", + "compliant": "Compliant", + "notApplicable": "Not applicable" } diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index 13778fd5c..e1c7f411b 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -372,5 +372,11 @@ "current": "Courrant", "residual": "Résiduel", "jumpToRiskAssessment": "Passer à l'évaluation des risques", - "additionalMeasures": "Mesures supplémentaires" + "additionalMeasures": "Mesures supplémentaires", + "toDo": "À faire", + "inProgress": "En cours", + "nonCompliant": "Non conforme", + "partiallyCompliant": "Partiellement conforme", + "compliant": "Conforme", + "notApplicable": "Non applicable" } diff --git a/frontend/src/lib/components/Chart/DonutChart.svelte b/frontend/src/lib/components/Chart/DonutChart.svelte index 13c203b1f..c5d9fb1eb 100644 --- a/frontend/src/lib/components/Chart/DonutChart.svelte +++ b/frontend/src/lib/components/Chart/DonutChart.svelte @@ -76,4 +76,5 @@ }); -
\ No newline at end of file + + diff --git a/frontend/src/lib/utils/locales.ts b/frontend/src/lib/utils/locales.ts index 30bfa75a3..5a3747001 100644 --- a/frontend/src/lib/utils/locales.ts +++ b/frontend/src/lib/utils/locales.ts @@ -262,6 +262,12 @@ export function localItems(languageTag: string): LocalItems { lossOfAccountabilityChoice3: m.lossOfAccountabilityChoice3({ languageTag: languageTag }), composer: m.composer({ languageTag: languageTag }), plan: m.plan({ languageTag: languageTag }), + toDo: m.toDo({ languageTag: languageTag }), + inProgress: m.inProgress({ languageTag: languageTag }), + nonCompliant: m.nonCompliant({ languageTag: languageTag }), + partiallyCompliant: m.partiallyCompliant({ languageTag: languageTag }), + compliant: m.compliant({ languageTag: languageTag }), + notApplicable: m.notApplicable({ languageTag: languageTag }) }; return LOCAL_ITEMS; } diff --git a/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/+page.svelte index be8dcb9c8..fb3099aa4 100644 --- a/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/compliance-assessments/[id=uuid]/+page.svelte @@ -57,6 +57,7 @@ lead: node.status ? TreeViewItemLead : '', leadProps: { status: node.status, + statusI18n: node.status_i18n, assessable: node.assessable, statusDisplay: node.status_display, statusColor: complianceColorMap[node.status] @@ -141,7 +142,7 @@ name="compliance_assessments" s_label="compliance_assessments" values={compliance_assessment_donut_values.values} - colors={compliance_assessment_donut_values.values.map(object => object.itemStyle.color)} + colors={compliance_assessment_donut_values.values.map((object) => object.itemStyle.color)} />