diff --git a/backend/core/helpers.py b/backend/core/helpers.py
index 6a8b6988a..a01f0521e 100644
--- a/backend/core/helpers.py
+++ b/backend/core/helpers.py
@@ -803,6 +803,7 @@ def compile_risk_assessment_for_composer(user, risk_assessment_list: list):
v = {"value": count, "itemStyle": {"color": STATUS_COLOR_MAP[st[0]]}}
values.append(v)
labels.append(st[1])
+ local_lables = [camel_case(str(l)) for l in labels]
risk_assessment_objects = list()
@@ -843,6 +844,6 @@ def compile_risk_assessment_for_composer(user, risk_assessment_list: list):
"untreated_h_vh": untreated_h_vh,
"accepted": accepted,
},
- "security_measure_status": {"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 175ad1ecf..a44996839 100644
--- a/backend/core/models.py
+++ b/backend/core/models.py
@@ -655,6 +655,9 @@ def get_linked_requirements_count(self):
class PolicyManager(models.Manager):
+ def get_queryset(self):
+ return super().get_queryset().filter(category="policy")
+
def create(self, *args, **kwargs):
kwargs["category"] = "policy" # Ensure category is always "policy"
return super().create(*args, **kwargs)
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 62b32b7f1..0be0465df 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -35,7 +35,7 @@
"governance": "Governance",
"risk": "Risk",
"compliance": "Compliance",
- "organization": "Organisation",
+ "organization": "Organization",
"extra": "Extra",
"analytics": "Analytics",
"calendar": "Calendar",
@@ -224,6 +224,7 @@
"infosFound": "info{s} found",
"remediationPlan": "Remediation plan",
"treatmentPlan": "Treatment plan",
+ "plan": "Plan",
"asPDF": "as PDF",
"asCSV": "as CSV",
"draft": "Draft",
@@ -234,13 +235,10 @@
"riskLevel": "Risk level",
"cancel": "Cancel",
"save": "Save",
- "currentAssessment": "Current assessment",
- "scope": "Scope",
"assetsImpactedByTheRiskScenario": "Assets impacted by the risk scenario",
"ecistingMeasures": "Existing measures",
"theExistingSecurityMeasuresToManageThisRisk": "The existing security measures to manage this risk",
"currentRiskLevelGivenCurrentMeasures": "The current risk level given the current security measures",
- "targetAssessment": "Target assessment",
"riskLevelWhenAllExtraMeasuresDone": "The risk level when all extra measures are done",
"myUserGroups": "My user groups",
"changePasswordText": "You can change your password here. You'll need to log in with your new password after this operation",
@@ -346,5 +344,31 @@
"copyright": "Copyright",
"uploadYourLibrary": "Upload your own library",
"libraryFileInYaml": "Library file in YAML format",
- "rid": "RID"
+ "rid": "RID",
+ "scope": "Scope",
+ "auditor": "Auditor",
+ "lastUpdate": "Last update",
+ "riskScenarioAssetHelpText": "Assets impacted by this risk scenario",
+ "riskScenarioMeasureHelpText": "The existing security measures to manage this risk",
+ "currentAssessment": "Current assessment",
+ "targetAssessment": "Target assessment",
+ "currentRiskLevel": "Current risk level",
+ "residualRiskLevel": "Residual risk level",
+ "currentRiskLevelHelpText": "The risk level given the current measures",
+ "residualRiskLevelHelpText": "The risk level when all the extra measures are done",
+ "yourSelection": "Your selection",
+ "composerHint": "Hint: you can bookmark this page for future usage",
+ "composerTitle": "Here is the overview for the selected risk assessment",
+ "composerTitlePlural": "Here is the overview for the {number} selected risk assessments",
+ "statusOfAssociatedMeasures": "Status of associated measures",
+ "forTheSelectedScope": "For the selected scope, you have",
+ "untreatedRiskScenarios": "{count} untreated risk scenario{s}",
+ "acceptedRiskScenarios": "{count} accepted risk scenario{s}",
+ "reviewNeeded": "Review needed",
+ "ok": "Ok",
+ "inconsistenciesFoundComposer": "Found {count} inconsistenc{plural}. For more details, check",
+ "current": "Current",
+ "residual": "Residual",
+ "jumpToRiskAssessment": "Jump to risk assessment",
+ "additionalMeasures": "Additional measures"
}
diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json
index 9c5f200a8..13778fd5c 100644
--- a/frontend/messages/fr.json
+++ b/frontend/messages/fr.json
@@ -224,6 +224,7 @@
"infosFound": "info{s} trouvée{s}",
"remediationPlan": "Plan de remédiation",
"treatmentPlan": "Plan de traitement",
+ "plan": "Plan",
"asPDF": "en PDF",
"asCSV": "en CSV",
"draft": "Brouillon",
@@ -345,5 +346,31 @@
"dependencies": "Dépendances",
"copyright": "Droits d'auteur",
"uploadYourLibrary": "Téléchargez votre propre bibliothèque",
- "libraryFileInYaml": "Fichier de librairie en format YAML"
+ "libraryFileInYaml": "Fichier de librairie en format YAML",
+ "scope": "Périmètre",
+ "auditor": "Auditeur",
+ "lastUpdate": "Dernière mise à jour",
+ "riskScenarioAssetHelpText": "Biens sensibles impactés par ce scénario de risque",
+ "riskScenarioMeasureHelpText": "Les mesures de sécurité existantes pour gérer ce risque",
+ "currentAssessment": "Évaluation actuelle",
+ "targetAssessment": "Évaluation cible",
+ "currentRiskLevel": "Niveau de risque courrant",
+ "residualRiskLevel": "Niveau de risque résiduel",
+ "currentRiskLevelHelpText": "Le niveau de risque compte tenu des mesures actuelles",
+ "residualRiskLevelHelpText": "Le niveau de risque lorsque toutes les mesures supplémentaires sont prises",
+ "yourSelection": "Votre sélection",
+ "composerHint": "Astuce : vous pouvez ajouter cette page à vos favoris pour une utilisation future",
+ "composerTitle": "Voici l’aperçu de l’évaluation de risque sélectionnée",
+ "composerTitlePlural": "Voici l'aperçu des {number} évaluations de risques sélectionnées",
+ "statusOfAssociatedMeasures": "Statut des mesures associées",
+ "forTheSelectedScope": "Pour le périmètre sélectionné, vous avez",
+ "untreatedRiskScenarios": "{count} scénario{s} de risque non traité{s}",
+ "acceptedRiskScenarios": "{count} scénario{s} de risque accepté{s}",
+ "reviewNeeded": "Révision nécessaire",
+ "ok": "Ok",
+ "inconsistenciesFoundComposer": "Il y a {count} incohérence{s}. Pour plus de détail, vérifiez",
+ "current": "Courrant",
+ "residual": "Résiduel",
+ "jumpToRiskAssessment": "Passer à l'évaluation des risques",
+ "additionalMeasures": "Mesures supplémentaires"
}
diff --git a/frontend/src/app.postcss b/frontend/src/app.postcss
index 047c1affa..a8bf3e1cc 100644
--- a/frontend/src/app.postcss
+++ b/frontend/src/app.postcss
@@ -6,7 +6,7 @@
/* (all other styles here...) */
html,
body {
- @apply h-full overflow-scroll;
+ @apply h-full overflow-auto;
}
.capitalize-first:first-letter {
@apply capitalize;
diff --git a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
index fadc08ae0..a8bab7086 100644
--- a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
+++ b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
@@ -29,15 +29,17 @@
crumbs = tokens.map((t) => {
tokenPath += '/' + t;
if (t === $breadcrumbObject.id) {
- if ($breadcrumbObject.name) title = $breadcrumbObject.name;
- else title = $breadcrumbObject.email;
+ if ($breadcrumbObject.name) t = $breadcrumbObject.name;
+ else t = $breadcrumbObject.email;
} else if (t === 'folders') {
t = 'domains';
}
- t = t.replace(/-/g, ' ');
- t = capitalizeSecondWord(t);
+ else{
+ t = t.replace(/-/g, ' ');
+ t = capitalizeSecondWord(t);
+ }
return {
- label: $page.data.label || title || t,
+ label: $page.data.label || t,
href: Object.keys(listViewFields).includes(tokens[0]) ? tokenPath : null
};
});
diff --git a/frontend/src/lib/utils/locales.ts b/frontend/src/lib/utils/locales.ts
index 7a152d616..30bfa75a3 100644
--- a/frontend/src/lib/utils/locales.ts
+++ b/frontend/src/lib/utils/locales.ts
@@ -259,7 +259,9 @@ export function localItems(languageTag: string): LocalItems {
lossOfAccountabilityText: m.lossOfAccountabilityText({ languageTag: languageTag }),
lossOfAccountabilityChoice1: m.lossOfAccountabilityChoice1({ languageTag: languageTag }),
lossOfAccountabilityChoice2: m.lossOfAccountabilityChoice2({ languageTag: languageTag }),
- lossOfAccountabilityChoice3: m.lossOfAccountabilityChoice3({ languageTag: languageTag })
+ lossOfAccountabilityChoice3: m.lossOfAccountabilityChoice3({ languageTag: languageTag }),
+ composer: m.composer({ languageTag: languageTag }),
+ plan: m.plan({ languageTag: languageTag }),
};
return LOCAL_ITEMS;
}
diff --git a/frontend/src/routes/(app)/analytics/composer/+page.svelte b/frontend/src/routes/(app)/analytics/composer/+page.svelte
index cb3c19395..16bf41172 100644
--- a/frontend/src/routes/(app)/analytics/composer/+page.svelte
+++ b/frontend/src/routes/(app)/analytics/composer/+page.svelte
@@ -1,36 +1,47 @@
-
Your selection
+
{m.yourSelection()}
- Hint: you can bookmark this page for future usage
+ {m.composerHint()}
- Here is the overview for the {data.risk_assessment_objects.length <= 1
- ? 'selected risk_assessment'
- : `${data.risk_assessment_objects.length} selected risk assessments`}:
+ {data.risk_assessment_objects.length <= 1
+ ? m.composerTitle()
+ : m.composerTitlePlural({ number: data.risk_assessment_objects.length})}:
-
Current risk level per risk scenario
+
{m.currentRiskLevelPerScenario()}
object.color)}
/>
@@ -38,7 +49,7 @@
-
Status of associated measures
+
{m.statusOfAssociatedMeasures()}
-
Residual risk level per risk scenario
+
{m.residualRiskLevelPerScenario()}
For the selected scope, you have:{m.forTheSelectedScope()}:
-
- {data.counters.untreated} untreated risk scenario{data.counters.untreated > 1
- ? 's'
- : ''}
+ {m.untreatedRiskScenarios({
+ count: data.counters.untreated,
+ s: data.counters.untreated > 1 ? 's' : ''
+ })}
{#each data.riskscenarios.untreated as scenario}
- {scenario.name}
@@ -79,8 +91,10 @@
-
- and
- {data.counters.accepted} risk scenario{data.counters.accepted > 1 ? 's' : ''} accepted
+ {m.acceptedRiskScenarios({
+ count: data.counters.accepted,
+ s: data.counters.accepted > 1 ? 's' : ''
+ })}
{#each data.riskscenarios.accepted as scenario}
- {scenario.name}
@@ -116,9 +130,9 @@
{#if item.risk_assessment.quality_check.count > 0}
- Review needed
+ {m.reviewNeeded()}
{:else}
- Ok
+ {m.ok()}
{/if}
@@ -127,23 +141,23 @@
{#if item.risk_assessment.quality_check.count > 0}➡️
Found
- {item.risk_assessment.quality_check.count} inconsistenc{item
- .risk_assessment.quality_check.count > 1
- ? 'es'
- : 'y'} that you need to check (use
+ >{m.inconsistenciesFoundComposer({
+ count: item.risk_assessment.quality_check.count,
+ s: item.risk_assessment.quality_check.count > 1 ? 's' : '',
+ plural: item.risk_assessment.quality_check.count > 1 ? 'ies' : 'y'
+ })}
x-rays for more information).
+ >.
{/if}
|
- Current |
- Residual |
+ {m.current()} |
+ {m.residual()} |
{#each item.synth_table as lvl}
@@ -159,7 +173,7 @@
Jump to full risk risk_assessment {m.jumpToRiskAssessment()}
diff --git a/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.server.ts b/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.server.ts
index ac6a98ab6..fb1b469bd 100644
--- a/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.server.ts
+++ b/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.server.ts
@@ -1,5 +1,4 @@
import { BASE_API_URL } from '$lib/utils/constants';
-import type { UUID } from 'crypto';
import type { PageServerLoad } from './$types';
@@ -9,11 +8,12 @@ export const load = (async ({ fetch, params }) => {
const res = await fetch(endpoint);
const risk_assessment = await res.json();
- const folder = await fetch(`${BASE_API_URL}/folders/${risk_assessment.project.id.folder}/`).then(
+ const project = await fetch(`${BASE_API_URL}/projects/${risk_assessment.project.id}/`).then(
+ (res) => res.json()
+ );
+ const folder = await fetch(`${BASE_API_URL}/folders/${project.folder.id}/`).then(
(res) => res.json()
);
-
risk_assessment.folder = folder;
-
return { URLModel, risk_assessment };
}) satisfies PageServerLoad;
diff --git a/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.svelte b/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.svelte
index a09f84752..96711969b 100644
--- a/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.svelte
+++ b/frontend/src/routes/(app)/risk-assessments/[id=uuid]/plan/+page.svelte
@@ -1,5 +1,6 @@
-Associated risk scenarios:
+{m.associatedRiskScenarios()}:
@@ -69,27 +75,27 @@
{#if scenario.existing_measures}
- Existing measures: |
+ {m.existingMeasures()}: |
- lorem ipsum |
+ {scenario.existing_measures} |
{/if}
{#if scenario.security_measures.length > 0}
- Additional measures: |
+ {m.additionalMeasures()}: |
# |
- Name |
- Description |
- Type |
- Security function |
- ETA |
- Effort |
- Link |
- Status |
+ {m.name()} |
+ {m.description()} |
+ {m.type()} |
+ {m.securityFunction()} |
+ {m.eta()} |
+ {m.effort()} |
+ {m.link()} |
+ {m.status()} |
{#each scenario.security_measures as measure, index}
0)}
- No associated measure
+ {m.noSecurityMeasureYet()}
|
{/if}
diff --git a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte
index c02915c22..3ca45d39e 100644
--- a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte
+++ b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.svelte
@@ -147,7 +147,7 @@
{form}
options={getOptions({ objects: data.foreignKeys['risk_assessment'] })}
field="risk_assessment"
- label={m.riskAssessments()}
+ label={m.riskAssessment()}
/>
{m.version()}
@@ -159,7 +159,7 @@
{m.status()}
- {m.updatedAt()}
+ {m.lastUpdate()}
{new Date(data.scenario.updated_at).toLocaleString()}
@@ -193,7 +193,7 @@
options={getOptions({ objects: data.foreignKeys['assets'] })}
field="assets"
label={m.assets()}
- helpText={m.assetsImpactedByTheRiskScenario()}
+ helpText={m.riskScenarioAssetHelpText()}
/>
@@ -206,8 +206,8 @@
@@ -232,11 +232,11 @@
@@ -260,6 +260,7 @@
{form}
options={getOptions({ objects: data.foreignKeys['security_measures'] })}
field="security_measures"
+ label={m.securityMeasures()}
/>
@@ -284,12 +285,12 @@
@@ -309,10 +310,10 @@
class="btn bg-gray-400 text-white font-semibold w-full"
data-testid="cancel-button"
type="button"
- on:click={cancel}>Cancel{m.cancel()}
{m.save()}