From 8efbb7b5a6f20c8631e8c8ecba8f3522e3f44e78 Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Wed, 8 Jan 2025 17:09:33 +0100 Subject: [PATCH] Add documentation score --- backend/core/helpers.py | 4 + ...sment_show_documentation_score_and_more.py | 24 ++++ backend/core/models.py | 23 +++- backend/core/views.py | 8 +- frontend/messages/ar.json | 7 +- frontend/messages/cs.json | 6 +- frontend/messages/de.json | 7 +- frontend/messages/en.json | 7 +- frontend/messages/es.json | 7 +- frontend/messages/fr.json | 7 +- frontend/messages/hi.json | 7 +- frontend/messages/id.json | 7 +- frontend/messages/it.json | 7 +- frontend/messages/nl.json | 7 +- frontend/messages/pl.json | 7 +- frontend/messages/pt.json | 7 +- frontend/messages/ro.json | 7 +- frontend/messages/sv.json | 7 +- frontend/messages/ur.json | 7 +- .../ModelForm/ComplianceAssessmentForm.svelte | 8 ++ .../src/lib/components/Forms/Score.svelte | 105 +++++++++++------- frontend/src/lib/utils/schemas.ts | 4 +- .../[id=uuid]/+page.svelte | 9 +- .../[id=uuid]/TreeViewItemContent.svelte | 6 +- .../[id=uuid]/TreeViewItemLead.svelte | 24 ++-- .../[id=uuid]/table-mode/+page.server.ts | 6 +- .../[id=uuid]/table-mode/+page.svelte | 18 ++- .../[id=uuid]/+page.svelte | 19 +++- .../[id=uuid]/edit/+page.svelte | 1 + 29 files changed, 262 insertions(+), 101 deletions(-) create mode 100644 backend/core/migrations/0047_complianceassessment_show_documentation_score_and_more.py diff --git a/backend/core/helpers.py b/backend/core/helpers.py index d9b3c707a..b999f6339 100644 --- a/backend/core/helpers.py +++ b/backend/core/helpers.py @@ -286,6 +286,7 @@ def get_sorted_requirement_nodes_rec(start: list) -> dict: "result": req_as.result if req_as else None, "is_scored": req_as.is_scored if req_as else None, "score": req_as.score if req_as else None, + "documentation_score": req_as.documentation_score if req_as else None, "max_score": max_score if req_as else None, "question": req_as.answer if req_as else node.question, "mapping_inference": req_as.mapping_inference if req_as else None, @@ -324,6 +325,9 @@ def get_sorted_requirement_nodes_rec(start: list) -> dict: "status": child_req_as.status if child_req_as else None, "is_scored": child_req_as.is_scored if child_req_as else None, "score": child_req_as.score if child_req_as else None, + "documentation_score": child_req_as.documentation_score + if child_req_as + else None, "max_score": max_score if child_req_as else None, "question": child_req_as.answer if child_req_as else child.question, "mapping_inference": child_req_as.mapping_inference diff --git a/backend/core/migrations/0047_complianceassessment_show_documentation_score_and_more.py b/backend/core/migrations/0047_complianceassessment_show_documentation_score_and_more.py new file mode 100644 index 000000000..9bc0563fb --- /dev/null +++ b/backend/core/migrations/0047_complianceassessment_show_documentation_score_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.4 on 2025-01-08 10:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0046_riskassessment_ebios_rm_study"), + ] + + operations = [ + migrations.AddField( + model_name="complianceassessment", + name="show_documentation_score", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="requirementassessment", + name="documentation_score", + field=models.IntegerField( + blank=True, null=True, verbose_name="Documentation Score" + ), + ), + ] diff --git a/backend/core/models.py b/backend/core/models.py index 69329e78a..b769a18d2 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -2728,6 +2728,7 @@ class ComplianceAssessment(Assessment): scores_definition = models.JSONField( blank=True, null=True, verbose_name=_("Score definition") ) + show_documentation_score = models.BooleanField(default=False) class Meta: verbose_name = _("Compliance assessment") @@ -2801,7 +2802,8 @@ def create_requirement_assessments( def get_global_score(self): requirement_assessments_scored = ( RequirementAssessment.objects.filter(compliance_assessment=self) - .exclude(score=None) + # ----- REMOVE THIS COMMENT AFTER REVIEW ----- # + # .exclude(score=None) # If is_scored is True we must consider the score in the global score right ? .exclude(status=RequirementAssessment.Result.NOT_APPLICABLE) .exclude(is_scored=False) .exclude(requirement__assessable=False) @@ -2813,12 +2815,18 @@ def get_global_score(self): ) score = 0 n = 0 + for ras in requirement_assessments_scored: if not (ig) or (ig & set(ras.requirement.implementation_groups)): - score += ras.score + score += ras.score or 0 n += 1 + if self.show_documentation_score: + score += ras.documentation_score or 0 + n += 1 if n > 0: - return round(score / n, 1) + global_score = score / n + # We use this instead of using the python round function so that the python backend outputs the same result as the javascript frontend. + return int(global_score * 10) / 10 else: return -1 @@ -3241,14 +3249,17 @@ class Result(models.TextChoices): verbose_name=_("Result"), default=Result.NOT_ASSESSED, ) + is_scored = models.BooleanField( + default=False, + verbose_name=_("Is scored"), + ) score = models.IntegerField( blank=True, null=True, verbose_name=_("Score"), ) - is_scored = models.BooleanField( - default=False, - verbose_name=_("Is scored"), + documentation_score = models.IntegerField( + blank=True, null=True, verbose_name=_("Documentation Score") ) evidences = models.ManyToManyField( Evidence, diff --git a/backend/core/views.py b/backend/core/views.py index 41c3fa5c1..62ebf28ad 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -2547,8 +2547,11 @@ def quality_check(self, request): ] return Response({"results": res}) - @method_decorator(cache_page(60 * SHORT_CACHE_TTL)) - @method_decorator(vary_on_cookie) + # ----- REMOVE THESE COMMENTS AFTER REVIEW ----- # + # I disabled cache because i must wait before the documentation_score being hidden/displayed in the requirement-assessment edit view after changing the show_documentation_score value of the ComplianceAssessment + # @method_decorator(cache_page(60 * SHORT_CACHE_TTL)) + # The vary_on_cookie is also disabled because it seem to only be here to support the cache_page disabled cache_page decorator + # @method_decorator(vary_on_cookie) @action(detail=True, methods=["get"]) def global_score(self, request, pk): """Returns the global score of the compliance assessment""" @@ -2561,6 +2564,7 @@ def global_score(self, request, pk): "scores_definition": get_referential_translation( compliance_assessment.framework, "scores_definition", get_language() ), + "show_documentation_score": compliance_assessment.show_documentation_score, } ) diff --git a/frontend/messages/ar.json b/frontend/messages/ar.json index 140e43bd2..d7594b5c1 100644 --- a/frontend/messages/ar.json +++ b/frontend/messages/ar.json @@ -862,8 +862,11 @@ "addTag": "إضافة علامة", "tagsHelpText": "تُستخدم العلامات لتصنيف العناصر وتصفيتها. يمكنك إضافة علامات في قسم \"إضافي\"", "forgotPassword": "هل نسيت كلمة السر", - "scoreSemiColon": "نتيجة:", + "score": "نتيجة", "mappingInferenceHelpText": "هذه المتغيرات ثابتة ولن تتغير اعتمادًا على المصدر.", "bringTheEvidences": "أحضر الأدلة", - "bringTheEvidencesHelpText": "في حالة التعطيل، سيتم تكرار الكائن بدون أدلته" + "bringTheEvidencesHelpText": "في حالة التعطيل، سيتم تكرار الكائن بدون أدلته", + "documentationScore": "درجة التوثيق", + "useDocumentationScore": "استخدام درجة التوثيق", + "useDocumentationScoreHelpText": "ستتوفر درجة ثانية (درجة التوثيق) لتقييم المتطلبات." } diff --git a/frontend/messages/cs.json b/frontend/messages/cs.json index 7cf5c7b3d..5e9d2c8ff 100644 --- a/frontend/messages/cs.json +++ b/frontend/messages/cs.json @@ -555,6 +555,7 @@ "youCanSetNewPassword": "Zde si můžete nastavit nové heslo", "userWillBeDisconnected": "Uživatel bude odpojen a bude se muset znovu přihlásit", "scoresDefinition": "Definice skóre", + "score": "Skóre", "selectedImplementationGroups": "Vybrané implementační skupiny", "implementationGroupsDefinition": "Definice implementačních skupin", "threatRadarChart": "Radarový graf hrozeb", @@ -854,5 +855,8 @@ "addTag": "Přidat štítek", "tagsHelpText": "Štítky pomáhají kategorizovat a filtrovat více objektů. Můžete je spravovat v menu Extra.", "bringTheEvidences": "Přineste důkazy", - "bringTheEvidencesHelpText": "Pokud je zakázáno, objekt bude duplikován bez jeho důkazů" + "bringTheEvidencesHelpText": "Pokud je zakázáno, objekt bude duplikován bez jeho důkazů", + "documentationScore": "Skóre dokumentace", + "useDocumentationScore": "Použití skóre dokumentace", + "useDocumentationScoreHelpText": "Pro posouzení požadavků bude k dispozici druhé bodové skóre (skóre dokumentace)." } diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 204cf4ce8..f41ac73be 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -861,8 +861,11 @@ "addTag": "Tag hinzufügen", "tagsHelpText": "Tags werden zum Kategorisieren und Filtern der Elemente verwendet. Sie können Tags im Abschnitt Extra hinzufügen", "forgotPassword": "Passwort vergessen", - "scoreSemiColon": "Punktzahl:", + "score": "Punktzahl", "mappingInferenceHelpText": "Diese Variablen sind fest und ändern sich je nach Quelle nicht.", "bringTheEvidences": "Bringen Sie die Beweise", - "bringTheEvidencesHelpText": "Wenn deaktiviert, wird das Objekt ohne seine Beweise dupliziert" + "bringTheEvidencesHelpText": "Wenn deaktiviert, wird das Objekt ohne seine Beweise dupliziert", + "documentationScore": "Bewertung der Dokumentation", + "useDocumentationScore": "Dokumentationsnote verwenden", + "useDocumentationScoreHelpText": "Eine zweite Punktzahl (Dokumentationspunktzahl) wird verfügbar sein, um die Anforderungen zu bewerten." } diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 2592b7cea..9ea30e86b 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -893,7 +893,7 @@ "youCanSetPasswordHere": "You can set your password here", "forgotPassword": "Forgot password", "ssoSettingsUpdated": "SSO settings updated", - "scoreSemiColon": "Score:", + "score": "Score", "mappingInferenceHelpText": "These variables are fixed and will not change depending on the source.", "priority": "Priority", "p1": "P1", @@ -1082,5 +1082,8 @@ "missionsAndOrganizationalServices": "Missions and organizational services", "human": "Human", "material": "Material", - "environmental": "Environmental" + "environmental": "Environmental", + "documentationScore": "Documentation score", + "useDocumentationScore": "Use documentation score", + "useDocumentationScoreHelpText": "A second score (the documentation score) will be available for scoring the requirements." } diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 7f9df84b5..f16c901f4 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -861,8 +861,11 @@ "addTag": "Agregar etiqueta", "tagsHelpText": "Las etiquetas se utilizan para categorizar y filtrar los elementos. Puedes agregar etiquetas en la sección Extra", "forgotPassword": "Has olvidado tu contraseña", - "scoreSemiColon": "Puntaje:", + "score": "Puntaje", "mappingInferenceHelpText": "Estas variables son fijas y no cambiarán dependiendo de la fuente.", "bringTheEvidences": "Traer las evidencias", - "bringTheEvidencesHelpText": "Si está deshabilitado, el objeto se duplicará sin sus evidencias." + "bringTheEvidencesHelpText": "Si está deshabilitado, el objeto se duplicará sin sus evidencias.", + "documentationScore": "Puntuación de la documentación", + "useDocumentationScore": "Utilizar la puntuación de la documentación", + "useDocumentationScoreHelpText": "Se dispondrá de una segunda puntuación (puntuación de la documentación) para evaluar los requisitos." } diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index a08ecb74c..aca55e1cb 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -893,7 +893,7 @@ "youCanSetPasswordHere": "Vous pouvez définir votre mot de passe ici", "forgotPassword": "Mot de passe oublié", "ssoSettingsUpdated": "Paramètres SSO mis à jour", - "scoreSemiColon": "Score:", + "score": "Score", "mappingInferenceHelpText": "Ces variables sont fixes et ne changeront pas en fonction de la source.", "priority": "Priorité", "p1": "P1", @@ -1082,5 +1082,8 @@ "missionsAndOrganizationalServices": "Missions et service de l'organisation", "human": "Humain", "material": "Matériel", - "environmental": "Environnemental" + "environmental": "Environnemental", + "documentationScore": "Score de documentation", + "useDocumentationScore": "Utiliser le score de documentation", + "useDocumentationScoreHelpText": "Un deuxième score (le score de documentation) sera disponible pour évaluer les exigences." } diff --git a/frontend/messages/hi.json b/frontend/messages/hi.json index f2fe79858..4061ddd9f 100644 --- a/frontend/messages/hi.json +++ b/frontend/messages/hi.json @@ -861,8 +861,11 @@ "addTag": "टैग जोड़ें", "tagsHelpText": "टैग का उपयोग आइटम को वर्गीकृत और फ़िल्टर करने के लिए किया जाता है। आप अतिरिक्त अनुभाग में टैग जोड़ सकते हैं", "forgotPassword": "पासवर्ड भूल गए", - "scoreSemiColon": "अंक:", + "score": "अंक", "mappingInferenceHelpText": "ये चर निश्चित हैं और स्रोत के आधार पर परिवर्तित नहीं होंगे।", "bringTheEvidences": "सबूत लाओ", - "bringTheEvidencesHelpText": "यदि अक्षम किया गया है, तो ऑब्जेक्ट को उसके साक्ष्य के बिना डुप्लिकेट किया जाएगा" + "bringTheEvidencesHelpText": "यदि अक्षम किया गया है, तो ऑब्जेक्ट को उसके साक्ष्य के बिना डुप्लिकेट किया जाएगा", + "documentationScore": "दस्तावेज़ीकरण स्कोर", + "useDocumentationScore": "दस्तावेज़ स्कोर का उपयोग करें", + "useDocumentationScoreHelpText": "आवश्यकताओं का आकलन करने के लिए दूसरी रेटिंग (दस्तावेज़ीकरण स्कोर) उपलब्ध होगी।" } diff --git a/frontend/messages/id.json b/frontend/messages/id.json index 269ccfeec..4e3c3c519 100644 --- a/frontend/messages/id.json +++ b/frontend/messages/id.json @@ -894,7 +894,7 @@ "youCanSetPasswordHere": "Anda dapat mengatur kata sandi Anda di sini", "forgotPassword": "Lupa kata sandi", "ssoSettingsUpdated": "Pengaturan SSO diperbarui", - "scoreSemiColon": "Skor:", + "score": "Skor", "mappingInferenceHelpText": "Variabel-variabel ini tetap dan tidak akan berubah tergantung pada sumber.", "priority": "Prioritas", "p1": "P1", @@ -1083,5 +1083,8 @@ "missionsAndOrganizationalServices": "Misi dan layanan organisasi", "human": "Manusia", "material": "Materi", - "environmental": "Lingkungan" + "environmental": "Lingkungan", + "documentationScore": "Skor dokumentasi", + "useDocumentationScore": "Gunakan skor dokumentasi", + "useDocumentationScoreHelpText": "Skor kedua (skor dokumentasi) akan tersedia untuk menilai persyaratan." } diff --git a/frontend/messages/it.json b/frontend/messages/it.json index e4d8778e2..8385e745c 100644 --- a/frontend/messages/it.json +++ b/frontend/messages/it.json @@ -861,8 +861,11 @@ "addTag": "Aggiungi tag", "tagsHelpText": "I tag vengono utilizzati per categorizzare e filtrare gli elementi. Puoi aggiungere tag nella sezione Extra", "forgotPassword": "Ha dimenticato la password", - "scoreSemiColon": "Punto:", + "score": "Punto", "mappingInferenceHelpText": "Queste variabili sono fisse e non cambiano a seconda della fonte.", "bringTheEvidences": "Portare le prove", - "bringTheEvidencesHelpText": "Se disabilitato, l'oggetto verrà duplicato senza le sue prove" + "bringTheEvidencesHelpText": "Se disabilitato, l'oggetto verrà duplicato senza le sue prove", + "documentationScore": "Punteggio della documentazione", + "useDocumentationScore": "Utilizzare il punteggio della documentazione", + "useDocumentationScoreHelpText": "Un secondo punteggio (punteggio di documentazione) sarà disponibile per valutare i requisiti." } diff --git a/frontend/messages/nl.json b/frontend/messages/nl.json index 925c032ee..f97e57d26 100644 --- a/frontend/messages/nl.json +++ b/frontend/messages/nl.json @@ -861,8 +861,11 @@ "addTag": "Tag toevoegen", "tagsHelpText": "Tags worden gebruikt om de items te categoriseren en te filteren. U kunt tags toevoegen in de sectie Extra", "forgotPassword": "Wachtwoord vergeten", - "scoreSemiColon": "Punt:", + "score": "Punt", "mappingInferenceHelpText": "Deze variabelen zijn vast en veranderen niet, afhankelijk van de bron.", "bringTheEvidences": "Breng de bewijzen", - "bringTheEvidencesHelpText": "Als dit is uitgeschakeld, wordt het object gedupliceerd zonder de bijbehorende bewijzen" + "bringTheEvidencesHelpText": "Als dit is uitgeschakeld, wordt het object gedupliceerd zonder de bijbehorende bewijzen", + "documentationScore": "Documentatie score", + "useDocumentationScore": "Documentatiescore gebruiken", + "useDocumentationScoreHelpText": "Een tweede score (documentatiescore) zal beschikbaar zijn om de vereisten te beoordelen." } diff --git a/frontend/messages/pl.json b/frontend/messages/pl.json index 79df7b273..bd2e68607 100644 --- a/frontend/messages/pl.json +++ b/frontend/messages/pl.json @@ -861,8 +861,11 @@ "addTag": "Dodaj tag", "tagsHelpText": "Tagi służą do kategoryzowania i filtrowania elementów. Możesz dodać tagi w sekcji Extra", "forgotPassword": "Zapomniałem hasła", - "scoreSemiColon": "Wynik:", + "score": "Wynik", "mappingInferenceHelpText": "Te zmienne są stałe i nie zmieniają się w zależności od źródła.", "bringTheEvidences": "Przynieś dowody", - "bringTheEvidencesHelpText": "Jeśli wyłączone, obiekt zostanie zduplikowany bez dowodów" + "bringTheEvidencesHelpText": "Jeśli wyłączone, obiekt zostanie zduplikowany bez dowodów", + "documentationScore": "Wynik dokumentacji", + "useDocumentationScore": "Korzystanie z punktacji dokumentacji", + "useDocumentationScoreHelpText": "Drugi wynik (wynik dokumentacji) będzie dostępny do oceny wymagań." } diff --git a/frontend/messages/pt.json b/frontend/messages/pt.json index 13966f18f..e03533c6d 100644 --- a/frontend/messages/pt.json +++ b/frontend/messages/pt.json @@ -861,8 +861,11 @@ "addTag": "Adicionar etiqueta", "tagsHelpText": "As tags são usadas para categorizar e filtrar os itens. Você pode adicionar tags na seção Extra", "forgotPassword": "Esqueceu sua senha", - "scoreSemiColon": "Pontuação:", + "score": "Pontuação", "mappingInferenceHelpText": "Essas variáveis são fixas e não mudarão dependendo da fonte.", "bringTheEvidences": "Traga as evidências", - "bringTheEvidencesHelpText": "Se desabilitado, o objeto será duplicado sem suas evidências" + "bringTheEvidencesHelpText": "Se desabilitado, o objeto será duplicado sem suas evidências", + "documentationScore": "Pontuação da documentação", + "useDocumentationScore": "Utilizar a pontuação da documentação", + "useDocumentationScoreHelpText": "Uma segunda pontuação (a pontuação da documentação) estará disponível para avaliar os requisitos." } diff --git a/frontend/messages/ro.json b/frontend/messages/ro.json index 9a06bfe07..aa8da9c56 100644 --- a/frontend/messages/ro.json +++ b/frontend/messages/ro.json @@ -861,8 +861,11 @@ "addTag": "Adăugați etichetă", "tagsHelpText": "Etichetele sunt folosite pentru a clasifica și filtra articolele. Puteți adăuga etichete în secțiunea Extra", "forgotPassword": "Aţi uitat parola", - "scoreSemiColon": "Scor:", + "score": "Scor", "mappingInferenceHelpText": "Aceste variabile sunt fixe și nu se vor modifica în funcție de sursă.", "bringTheEvidences": "Aduceți dovezile", - "bringTheEvidencesHelpText": "Dacă este dezactivat, obiectul va fi duplicat fără dovezile sale" + "bringTheEvidencesHelpText": "Dacă este dezactivat, obiectul va fi duplicat fără dovezile sale", + "documentationScore": "Punctajul documentației", + "useDocumentationScore": "Utilizați punctajul documentației", + "useDocumentationScoreHelpText": "Un al doilea punctaj (punctajul pentru documentație) va fi disponibil pentru evaluarea cerințelor." } diff --git a/frontend/messages/sv.json b/frontend/messages/sv.json index f419f7c69..937f9b046 100644 --- a/frontend/messages/sv.json +++ b/frontend/messages/sv.json @@ -861,8 +861,11 @@ "youCanSetPasswordHere": "Du kan ställa in ditt lösenord här.", "forgotPassword": "Glömt lösenord", "ssoSettingsUpdated": "SSO-inställningar uppdaterade", - "scoreSemiColon": "Göra:", + "score": "Göra", "mappingInferenceHelpText": "Dessa variabler är fasta och kommer inte att ändras beroende på källan.", "bringTheEvidences": "Kom med bevisen", - "bringTheEvidencesHelpText": "Om det är inaktiverat kommer objektet att dupliceras utan dess bevis" + "bringTheEvidencesHelpText": "Om det är inaktiverat kommer objektet att dupliceras utan dess bevis", + "documentationScore": "Poäng för dokumentation", + "useDocumentationScore": "Använd poängsättning av dokumentation", + "useDocumentationScoreHelpText": "En andra poäng (dokumentationspoängen) kommer att finnas tillgänglig för att bedöma kraven." } diff --git a/frontend/messages/ur.json b/frontend/messages/ur.json index d6bb0a32d..084f661b7 100644 --- a/frontend/messages/ur.json +++ b/frontend/messages/ur.json @@ -861,8 +861,11 @@ "addTag": "ٹیگ شامل کریں۔", "tagsHelpText": "ٹیگز اشیاء کی درجہ بندی اور فلٹر کرنے کے لیے استعمال ہوتے ہیں۔ آپ اضافی سیکشن میں ٹیگ شامل کر سکتے ہیں۔", "forgotPassword": "پاس ورڈ بھول گئے۔", - "scoreSemiColon": "سکور:", + "score": "سکور", "mappingInferenceHelpText": "یہ متغیرات طے شدہ ہیں اور ماخذ کے لحاظ سے تبدیل نہیں ہوں گے۔", "bringTheEvidences": "ثبوت لے کر آئیں", - "bringTheEvidencesHelpText": "اگر غیر فعال ہو تو، اعتراض کو اس کے ثبوت کے بغیر نقل کر دیا جائے گا۔" + "bringTheEvidencesHelpText": "اگر غیر فعال ہو تو، اعتراض کو اس کے ثبوت کے بغیر نقل کر دیا جائے گا۔", + "documentationScore": "دستاویزی سکور", + "useDocumentationScore": "دستاویزی سکور استعمال کریں۔", + "useDocumentationScoreHelpText": "ضروریات کو پورا کرنے کے لیے دوسرا سکور (دستاویزی سکور) دستیاب ہوگا۔" } diff --git a/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte b/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte index 0bba0a55c..b35c08620 100644 --- a/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte @@ -99,6 +99,14 @@ } }} /> + {#if model.selectOptions['selected_implementation_groups'] && model.selectOptions['selected_implementation_groups'].length} import * as m from '$paraglide/messages'; - import { SECURITY_OBJECTIVE_SCALE_MAP } from '$lib/utils/constants'; import { displayScoreColor, formatScoreValue } from '$lib/utils/helpers'; import { ProgressRadial, RangeSlider, SlideToggle } from '@skeletonlabs/skeleton'; import { formFieldProxy, type SuperForm } from 'sveltekit-superforms'; - import { page } from '$app/stores'; import { createEventDispatcher } from 'svelte'; - function securityObjectiveDisplay(level: number) { - return SECURITY_OBJECTIVE_SCALE_MAP[$page.data.settings.security_objective_scale][level]; - } - export let label: string | undefined = undefined; export let field: string; export let fullDonut: boolean = false; export let inversedColors: boolean = false; - export let security_objective: boolean = false; export let styles: string = ''; export let min_score = 0; export let max_score = 100; + export let show_documentation_score: boolean = false; export let score_step = 1; export let always_enabled = false; export let helpText: string | undefined = undefined; @@ -34,10 +28,12 @@ export let form: SuperForm>; const { value, errors, constraints } = formFieldProxy(form, field); + const documentationScore = formFieldProxy(form, 'documentation_score')['value']; const isScored = formFieldProxy(form, `is_scored`)['value']; $: $value = $isScored ? ($value ?? min_score) : $value; + $: $documentationScore = $isScored ? ($documentationScore ?? min_score) : $documentationScore; if (always_enabled) { $isScored = true; @@ -45,16 +41,28 @@ export let is_scored = $isScored; export let score = $value; + export let documentation_score = $documentationScore; $: is_scored = $isScored; $: score = $value; + $: documentation_score = $documentationScore; const dispatch = createEventDispatcher(); - let previous = [$isScored, $value]; + let previous = [$isScored, $value, $documentationScore]; $: { - if ((previous[0] !== $isScored || previous[1] !== $value) && previous[0] !== undefined) { - dispatch('change', { isScored: $isScored, score: $value }); + if ( + (previous[0] !== $isScored || + previous[1] !== $value || + previous[2] !== $documentationScore) && + previous[0] !== undefined && + previous[2] !== undefined + ) { + dispatch('change', { + isScored: $isScored, + score: $value, + documentationScore: $documentationScore + }); } - previous = [$isScored, $value]; + previous = [$isScored, $value, $documentationScore]; } $: if (max_score === 100) score_step = 5; @@ -82,9 +90,9 @@ {/each} {/if} -
+
{#if isApplicable} -
+
-
- {#if !always_enabled} - -

{m.scoringHelpText()}

- {/if} +
{#if $isScored && scores_definition && $value !== null} {#each scores_definition as definition} {#if definition.score === $value} @@ -116,28 +114,55 @@ {/if} {/each} {/if} - {#if security_objective} - {securityObjectiveDisplay($value) ?? ($isScored ? $value : '--')} - {:else} - {$isScored ? $value : '--'}{m.scoringHelpText()}

{/if} + {$isScored ? $value : '--'} + {m.score()} + {#if show_documentation_score} +
+ {$isScored ? $documentationScore : '--'} + {m.documentationScore()} +
+ {/if}
+ {#if show_documentation_score} + + {/if}
{:else}

diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts index 80e692d56..ac8c3651c 100644 --- a/frontend/src/lib/utils/schemas.ts +++ b/frontend/src/lib/utils/schemas.ts @@ -219,8 +219,9 @@ export const RequirementAssessmentSchema = z.object({ answer: jsonSchema, status: z.string(), result: z.string(), - score: z.number().optional().nullable(), is_scored: z.boolean().optional(), + score: z.number().optional().nullable(), + documentation_score: z.number().optional().nullable(), comment: z.string().optional().nullable(), folder: z.string(), requirement: z.string(), @@ -264,6 +265,7 @@ export const ComplianceAssessmentSchema = z.object({ status: z.string().optional().nullable(), selected_implementation_groups: z.array(z.string().optional()).optional(), framework: z.string(), + show_documentation_score: z.boolean().optional().default(false), eta: z.union([z.literal('').transform(() => null), z.string().date()]).nullish(), due_date: z.union([z.literal('').transform(() => null), z.string().date()]).nullish(), authors: z.array(z.string().optional()).optional(), diff --git a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.svelte index dfd41fa6b..bced2c4dc 100644 --- a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.svelte @@ -41,6 +41,7 @@ import { displayScoreColor } from '$lib/utils/helpers'; import { expandedNodesState } from '$lib/utils/stores'; import { ProgressRadial } from '@skeletonlabs/skeleton'; + import { nodeIsDragged } from '@unovis/ts/components/graph/modules/node/style'; $: tree = data.tree; @@ -90,7 +91,10 @@ } if (node.is_scored && node.assessable && node.result !== 'not_applicable') { resultCounts['scored'] = (resultCounts['scored'] || 0) + 1; - resultCounts['total_score'] = (resultCounts['total_score'] || 0) + node.score; + const nodeMeanScore = data.compliance_assessment.show_documentation_score + ? (node.score + node.documentation_score) / 2 + : node.score; + resultCounts['total_score'] = (resultCounts['total_score'] || 0) + nodeMeanScore; } if (node.children && Object.keys(node.children).length > 0) { @@ -105,7 +109,6 @@ }; function transformToTreeView(nodes: Node[]) { - if (!tree) return []; return nodes.map(([id, node]) => { node.resultCounts = countResults(node); const hasAssessableChildren = Object.keys(node.children || {}).length > 0; @@ -127,7 +130,9 @@ statusColor: complianceStatusColorMap[node.status], resultColor: complianceResultColorMap[node.result], score: node.score, + documentationScore: node.documentation_score, isScored: node.is_scored, + showDocumentationScore: data.compliance_assessment.show_documentation_score, max_score: node.max_score }, children: node.children ? transformToTreeView(Object.entries(node.children)) : [] diff --git a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/TreeViewItemContent.svelte b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/TreeViewItemContent.svelte index 1fcbf0078..9a434ef9f 100644 --- a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/TreeViewItemContent.svelte +++ b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/TreeViewItemContent.svelte @@ -93,8 +93,8 @@ } ); - function nodeScore(): number { - if (!resultCounts) return -1; + function nodeScore(): number | null { + if (!resultCounts) return null; let mean = resultCounts['total_score'] / resultCounts['scored']; return Math.floor(mean * 10) / 10; } @@ -277,7 +277,7 @@

{/each}
- {#if nodeScore() >= 0} + {#if nodeScore() !== null} {leadResult} - {#if score !== null && statusI18n !== 'notApplicable' && isScored} - + + {#if statusI18n !== 'notApplicable' && isScored} + {score} + {#if showDocumentationScore} {score}{documentationScore} - + {/if} {/if}
{/if} diff --git a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.server.ts b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.server.ts index 5dd37367c..823ba513e 100644 --- a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.server.ts +++ b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.server.ts @@ -24,7 +24,8 @@ export const load = (async ({ fetch, params }) => { const evidenceCreateSchema = modelSchema('evidences'); const scoreSchema = z.object({ is_scored: z.boolean().optional(), - score: z.number().optional().nullable() + score: z.number().optional().nullable(), + documentation_score: z.number().optional().nullable() }); const requirement_assessments = await Promise.all( tableMode.requirement_assessments.map(async (requirementAssessment) => { @@ -43,7 +44,8 @@ export const load = (async ({ fetch, params }) => { const scoreForm = await superValidate( { is_scored: requirementAssessment.is_scored, - score: requirementAssessment.score + score: requirementAssessment.score, + documentation_score: requirementAssessment.documentation_score }, zod(scoreSchema) ); diff --git a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.svelte b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.svelte index c4cf39d39..f7d4c756c 100644 --- a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.svelte +++ b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/table-mode/+page.svelte @@ -181,13 +181,19 @@ function updateScore(requirementAssessment) { const isScored = requirementAssessment.is_scored; const score = requirementAssessment.score; - requirementAssessmentScores[requirementAssessment.id] = [isScored, score]; + const documentationScore = requirementAssessment.documentation_score; + requirementAssessmentScores[requirementAssessment.id] = [isScored, score, documentationScore]; setTimeout(() => { const currentScoreValue = requirementAssessmentScores[requirementAssessment.id]; - if (isScored === currentScoreValue[0] && score === currentScoreValue[1]) { + if ( + isScored === currentScoreValue[0] && + score === currentScoreValue[1] && + documentationScore === currentScoreValue[2] + ) { updateBulk(requirementAssessment, { is_scored: isScored, - score: score + score: score, + documentation_score: documentationScore }); } }, 500); // There must be 500ms without a score change for a request to be sent and modify the score of the RequirementAsessment in the backend @@ -372,15 +378,17 @@ {/if}
updateScore(requirementAssessment)} /> diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte index 5ee61eee1..cf637b571 100644 --- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/+page.svelte @@ -65,7 +65,8 @@ complianceResultColorMap[mappingInference.result] === '#000000' ? 'text-white' : ''; const max_score = data.complianceAssessmentScore.max_score; - const value = data.requirementAssessment.score; + const score = data.requirementAssessment.score; + const documentationScore = data.requirementAssessment.documentation_score; let tabSet = $page.data.user.is_third_party ? 1 : 0; @@ -90,12 +91,22 @@ {#if data.requirementAssessment.is_scored} {value}{score} + {#if data.complianceAssessmentScore.show_documentation_score} + {documentationScore} + {/if} {/if}
{#if data.requirement.description} diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte index 16d57668c..b48fce286 100644 --- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte +++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.svelte @@ -441,6 +441,7 @@ min_score={data.compliance_assessment_score.min_score} max_score={data.compliance_assessment_score.max_score} scores_definition={data.compliance_assessment_score.scores_definition} + show_documentation_score={data.compliance_assessment_score.show_documentation_score} field="score" label="Score" />