diff --git a/backend/core/models.py b/backend/core/models.py index 7407d4853..3b0860c8a 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -1501,7 +1501,7 @@ def get_descendants(self) -> set[Self]: children = self.get_children() sub_children = set() for child in children: - sub_children.append(child) + sub_children.add(child) sub_children.update(child.get_descendants()) return sub_children diff --git a/backend/core/serializers.py b/backend/core/serializers.py index 6595dd66a..75547b1ff 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -210,10 +210,11 @@ class RiskAssessmentReadSerializer(AssessmentReadSerializer): risk_scenarios = FieldsRelatedField(many=True) risk_scenarios_count = serializers.IntegerField(source="risk_scenarios.count") risk_matrix = FieldsRelatedField() + ebios_rm_study = FieldsRelatedField(["id", "name"]) class Meta: model = RiskAssessment - exclude = ["ebios_rm_study"] + exclude = [] class AssetWriteSerializer(BaseModelSerializer): diff --git a/backend/ebios_rm/migrations/0009_alter_roto_activity.py b/backend/ebios_rm/migrations/0009_alter_roto_activity.py new file mode 100644 index 000000000..86b3f5d53 --- /dev/null +++ b/backend/ebios_rm/migrations/0009_alter_roto_activity.py @@ -0,0 +1,29 @@ +# Generated by Django 5.1.4 on 2024-12-20 12:16 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("ebios_rm", "0008_remove_attackpath_ro_to_couple_strategicscenario_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="roto", + name="activity", + field=models.PositiveSmallIntegerField( + choices=[ + (0, "undefined"), + (1, "very_low"), + (2, "low"), + (3, "moderate"), + (4, "important"), + ], + default=0, + validators=[django.core.validators.MaxValueValidator(4)], + verbose_name="Activity", + ), + ), + ] diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py index ba5884409..5b35766fc 100644 --- a/backend/ebios_rm/models.py +++ b/backend/ebios_rm/models.py @@ -272,6 +272,13 @@ class Resources(models.IntegerChoices): IMPORTANT = 3, "important" UNLIMITED = 4, "unlimited" + class Activity(models.IntegerChoices): + UNDEFINED = 0, "undefined" + VERY_LOW = 1, "very_low" + LOW = 2, "low" + MODERATE = 3, "moderate" + IMPORTANT = 4, "important" + class Pertinence(models.IntegerChoices): UNDEFINED = 0, "undefined" IRRELAVANT = 1, "irrelevant" @@ -306,7 +313,10 @@ class Pertinence(models.IntegerChoices): default=Resources.UNDEFINED, ) activity = models.PositiveSmallIntegerField( - verbose_name=_("Activity"), default=0, validators=[MaxValueValidator(4)] + verbose_name=_("Activity"), + choices=Activity.choices, + default=Activity.UNDEFINED, + validators=[MaxValueValidator(4)], ) is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False) justification = models.TextField(verbose_name=_("Justification"), blank=True) @@ -645,7 +655,7 @@ def ro_to(self): def get_assets(self): initial_assets = Asset.objects.filter( - feared_events__in=self.ro_to.feared_events.all(), is_selected=True + feared_events__in=self.ro_to.feared_events.filter(is_selected=True) ) assets = set() for asset in initial_assets: diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py index b23c78876..908a63477 100644 --- a/backend/ebios_rm/serializers.py +++ b/backend/ebios_rm/serializers.py @@ -97,6 +97,7 @@ class RoToReadSerializer(BaseModelSerializer): motivation = serializers.CharField(source="get_motivation_display") resources = serializers.CharField(source="get_resources_display") + activity = serializers.CharField(source="get_activity_display") pertinence = serializers.CharField(source="get_pertinence") class Meta: diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py index 871119cd0..92f8c7ca2 100644 --- a/backend/ebios_rm/views.py +++ b/backend/ebios_rm/views.py @@ -88,7 +88,7 @@ def update_workshop_step_status(self, request, pk, workshop, step): class FearedEventViewSet(BaseModelViewSet): model = FearedEvent - filterset_fields = ["ebios_rm_study", "ro_to_couples"] + filterset_fields = ["ebios_rm_study", "ro_to_couples", "is_selected"] @action(detail=True, name="Get risk matrix", url_path="risk-matrix") def risk_matrix(self, request, pk=None): @@ -140,6 +140,10 @@ def motivation(self, request): def resources(self, request): return Response(dict(RoTo.Resources.choices)) + @action(detail=False, name="Get activity choices") + def activity(self, request): + return Response(dict(RoTo.Activity.choices)) + class StakeholderViewSet(BaseModelViewSet): model = Stakeholder diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 3a82e3e6d..bc835ab48 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1013,5 +1013,10 @@ "goBackToEbiosRmStudy": "Go back to Ebios RM study", "addStrategicScenario": "Add strategic scenario", "markAsDone": "Mark as done", - "markAsInProgress": "Mark as in progress" + "markAsInProgress": "Mark as in progress", + "ebiosRmRiskMatrix": "4x4 risk matrix from EBIOS-RM", + "riskAnalyses": "Risk analyses", + "client": "Client", + "partner": "Partner", + "supplier": "Supplier" } diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index a7e674606..c45e90e64 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -1011,5 +1011,8 @@ "strategicScenario": "Scénario stratégique", "strategicScenarios": "Scénarios stratégiques", "goBackToEbiosRmStudy": "Retour à l'étude", - "addStrategicScenario": "Ajouter un scénario stratégique" + "addStrategicScenario": "Ajouter un scénario stratégique", + "client": "Client", + "partner": "Partenaire", + "supplier": "Fournisseur" } diff --git a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte index ff92026a7..3e94cd211 100644 --- a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte +++ b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte @@ -9,6 +9,8 @@ let crumbs: Array<{ label: string; href: string; icon?: string }> = []; + const disableWorkhopLink = ['workshop1', 'workshop2', 'workshop3', 'workshop4', 'workshop5']; // Disable workshops links in breadcrumb + $: { // Remove zero-length tokens. const tokens = $page.url.pathname.split('/').filter((t) => t !== ''); @@ -35,7 +37,8 @@ label: $page.data.label || t, href: Object.keys(listViewFields).includes(tokens[0]) && - !listViewFields[tokens[0]].breadcrumb_link_disabled + !listViewFields[tokens[0]].breadcrumb_link_disabled && + !disableWorkhopLink.includes(t) // Disable workshops links in breadcrumb ? tokenPath : null }; diff --git a/frontend/src/lib/components/DetailView/DetailView.svelte b/frontend/src/lib/components/DetailView/DetailView.svelte index 4a2f12545..95303fcc8 100644 --- a/frontend/src/lib/components/DetailView/DetailView.svelte +++ b/frontend/src/lib/components/DetailView/DetailView.svelte @@ -345,7 +345,7 @@ {value} {:else if ISO_8601_REGEX.test(value) && (key === 'created_at' || key === 'updated_at' || key === 'expiry_date' || key === 'accepted_at' || key === 'rejected_at' || key === 'revoked_at' || key === 'eta')} {formatDateOrDateTime(value, languageTag())} - {:else if m[toCamelCase((value.str || value.name) ?? value)]} + {:else if m[toCamelCase(value.str || value.name)]} {safeTranslate((value.str || value.name) ?? value)} {:else} {(value.str || value.name) ?? value} diff --git a/frontend/src/lib/components/Forms/ModelForm/EbiosRmForm.svelte b/frontend/src/lib/components/Forms/ModelForm/EbiosRmForm.svelte index d85c44fc0..82e9d11e7 100644 --- a/frontend/src/lib/components/Forms/ModelForm/EbiosRmForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm/EbiosRmForm.svelte @@ -67,6 +67,7 @@ cacheLock={cacheLocks['risk_matrix']} bind:cachedValue={formDataCache['risk_matrix']} label={m.riskMatrix()} + placeholder={m.ebiosRmRiskMatrix()} helpText={m.ebiosRmMatrixHelpText()} /> {:else if context === 'ebiosRmStudy'} diff --git a/frontend/src/lib/components/Forms/ModelForm/RoToForm.svelte b/frontend/src/lib/components/Forms/ModelForm/RoToForm.svelte index a78db0a56..ac229b4f6 100644 --- a/frontend/src/lib/components/Forms/ModelForm/RoToForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm/RoToForm.svelte @@ -96,16 +96,9 @@ cacheLock={cacheLocks['resources']} bind:cachedValue={formDataCache['resources']} /> - - e.stopPropagation()}>{val.str} {:else if val.str} - {val.str} + {safeTranslate(val.str)} {:else if unsafeTranslate(val.split(':')[0])} {unsafeTranslate(val.split(':')[0] + 'Colon')} diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts index 24a0698d6..fc57fe0a5 100644 --- a/frontend/src/lib/utils/crud.ts +++ b/frontend/src/lib/utils/crud.ts @@ -645,14 +645,15 @@ export const URL_MODEL_MAP: ModelMap = { field: 'feared_events', urlModel: 'feared-events', endpointUrl: 'ebios-rm/feared-events', - urlParams: 'ebios_rm_study=', + urlParams: 'is_selected=true&ebios_rm_study=', detail: true } ], selectFields: [ { field: 'risk-origin' }, { field: 'motivation', valueType: 'number' }, - { field: 'resources', valueType: 'number' } + { field: 'resources', valueType: 'number' }, + { field: 'activity', valueType: 'number' } ] }, stakeholders: { diff --git a/frontend/src/lib/utils/i18n.ts b/frontend/src/lib/utils/i18n.ts index ad8357744..4cdc174d2 100644 --- a/frontend/src/lib/utils/i18n.ts +++ b/frontend/src/lib/utils/i18n.ts @@ -14,6 +14,9 @@ export function unsafeTranslate(key: string, params = {}, options = {}): string if (Object.hasOwn(m, toCamelCase(key))) { return m[toCamelCase(key)](params, options); } + if (typeof key === 'boolean') { + return key ? '✅' : '❌'; + } } /** diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-1/ebios-rm-study/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-1/ebios-rm-study/+page.svelte index 251499d38..7f380d6a1 100644 --- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-1/ebios-rm-study/+page.svelte +++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-1/ebios-rm-study/+page.svelte @@ -70,13 +70,20 @@
- {#if ebiosRmStudy.ref_id} - - {m.refIdSemiColon()} - {ebiosRmStudy.ref_id} - - {/if} + + +

{m.goBackToEbiosRmStudy()}

+
+ {#if ebiosRmStudy.ref_id} + + {m.refIdSemiColon()} + {ebiosRmStudy.ref_id} + + {/if} {ebiosRmStudy.name} - v{ebiosRmStudy.version} diff --git a/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte index cbd6b572f..62c469a08 100644 --- a/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte @@ -43,6 +43,13 @@
+ + +

{m.goBackToEbiosRmStudy()}

+

+ {#if risk_assessment.ebios_rm_study} +
+
+ {/if}
{m.description()}: diff --git a/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte index 5c4b2d4c2..734d9b10c 100644 --- a/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte @@ -70,7 +70,7 @@

{m.riskOrigin()} - {roto.risk_origin} / + {safeTranslate(roto.risk_origin)} /

{m.targetObjective()} @@ -116,7 +116,7 @@

{m.activity()} = - {roto.activity} + {safeTranslate(roto.activity)}