Skip to content

Commit

Permalink
Workshop 2 UX (#1180)
Browse files Browse the repository at this point in the history
Co-authored-by: eric-intuitem <[email protected]>
  • Loading branch information
Mohamed-Hacene and eric-intuitem authored Dec 13, 2024
1 parent 6d2efe8 commit 2da47d8
Show file tree
Hide file tree
Showing 21 changed files with 507 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.1.4 on 2024-12-12 18:40

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("ebios_rm", "0003_remove_ebiosrmstudy_risk_assessments"),
]

operations = [
migrations.RemoveField(
model_name="roto",
name="pertinence",
),
migrations.AlterField(
model_name="roto",
name="feared_events",
field=models.ManyToManyField(
blank=True,
related_name="ro_to_couples",
to="ebios_rm.fearedevent",
verbose_name="Feared events",
),
),
]
24 changes: 18 additions & 6 deletions backend/ebios_rm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ class Pertinence(models.IntegerChoices):
on_delete=models.CASCADE,
)
feared_events = models.ManyToManyField(
FearedEvent, verbose_name=_("Feared events"), related_name="ro_to_couples"
FearedEvent,
verbose_name=_("Feared events"),
related_name="ro_to_couples",
blank=True,
)

risk_origin = models.CharField(
Expand All @@ -211,11 +214,6 @@ class Pertinence(models.IntegerChoices):
choices=Resources.choices,
default=Resources.UNDEFINED,
)
pertinence = models.PositiveSmallIntegerField(
verbose_name=_("Pertinence"),
choices=Pertinence.choices,
default=Pertinence.UNDEFINED,
)
activity = models.PositiveSmallIntegerField(
verbose_name=_("Activity"), default=0, validators=[MaxValueValidator(4)]
)
Expand All @@ -234,6 +232,20 @@ def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)

@property
def get_pertinence(self):
PERTINENCE_MATRIX = [
[1, 1, 2, 2],
[1, 2, 3, 3],
[2, 3, 3, 4],
[2, 3, 4, 4],
]
if self.motivation == 0 or self.resources == 0:
return self.Pertinence(self.Pertinence.UNDEFINED).label
return self.Pertinence(
PERTINENCE_MATRIX[self.motivation - 1][self.resources - 1]
).label


class Stakeholder(AbstractBaseModel, FolderMixin):
class Category(models.TextChoices):
Expand Down
2 changes: 1 addition & 1 deletion backend/ebios_rm/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ class RoToReadSerializer(BaseModelSerializer):
folder = FieldsRelatedField()
feared_events = FieldsRelatedField(["folder", "id"], many=True)

pertinence = serializers.CharField(source="get_pertinence_display")
motivation = serializers.CharField(source="get_motivation_display")
resources = serializers.CharField(source="get_resources_display")
pertinence = serializers.CharField(source="get_pertinence")

class Meta:
model = RoTo
Expand Down
8 changes: 1 addition & 7 deletions backend/ebios_rm/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ def likelihood(self, request, pk):
class FearedEventViewSet(BaseModelViewSet):
model = FearedEvent

filterset_fields = [
"ebios_rm_study",
]
filterset_fields = ["ebios_rm_study", "ro_to_couples"]

@action(detail=True, name="Get risk matrix", url_path="risk-matrix")
def risk_matrix(self, request, pk=None):
Expand Down Expand Up @@ -112,10 +110,6 @@ def motivation(self, request):
def resources(self, request):
return Response(dict(RoTo.Resources.choices))

@action(detail=False, name="Get pertinence choices")
def pertinence(self, request):
return Response(dict(RoTo.Pertinence.choices))


class StakeholderViewSet(BaseModelViewSet):
model = Stakeholder
Expand Down
7 changes: 3 additions & 4 deletions documentation/architecture/data-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ The object risk_origin_target_objective (workshop 2) contains the following fiel
- target objective (text)
- motivation (--/1 very low/2 low/3 significant/4 strong) (--/très peu/peu/assez/fortement motivé)
- resources (--/1 limited/2 significant/3 important/4 unlimited) (--/limitées/significatives/importantes/illimitées)
- pertinence (--/1 Irrelevant/2 partially relevant/3 fairly relevant/4 highly relevant) (--/peu pertinent/moyennement pertient/plutôt pertinent/très pertinent)
- pertinence (--/1 Irrelevant/2 partially relevant/3 fairly relevant/4 highly relevant) (--/peu pertinent/moyennement pertient/plutôt pertinent/très pertinent) -> calculated
- activity (--/1/2/3/4)
- selected
- justification
Expand Down Expand Up @@ -1267,7 +1267,7 @@ The frontend for risk study shall propose the following steps:
```mermaid
erDiagram
DOMAIN ||--o{ EBIOS_RM_STUDY : contains
DOMAIN ||--o{ STAKEHOLDER : contains
DOMAIN ||--o{ STAKEHOLDER : contains
DOMAIN ||--o{ OPERATIONAL_SCENARIO : contains
DOMAIN ||--o{ FEARED_EVENT : contains
DOMAIN ||--o{ RO_TO : contains
Expand All @@ -1289,7 +1289,7 @@ erDiagram
EBIOS_RM_STUDY }o--o| ENTITY : studies
EBIOS_RM_STUDY }o--o{ COMPLIANCE_ASSESSMENT: leverages
EBIOS_RM_STUDY }o--|| RISK_MATRIX : leverages
EBIOS_RM_STUDY }o--o{ RISK_ASSESSMENT : generates
EBIOS_RM_STUDY |o--o{ RISK_ASSESSMENT : generates
ATTACK_PATH }o--|| RO_TO : derives
RO_TO }o--o{ FEARED_EVENT : corresponds_to
OPERATIONAL_SCENARIO }o--|{ ATTACK_PATH : derives
Expand Down Expand Up @@ -1326,7 +1326,6 @@ erDiagram
string target_objective
int motivation
int resources
int pertinence
int activity
bool selected
string justification
Expand Down
6 changes: 5 additions & 1 deletion frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,7 @@
"ebiosRmMatrixHelpText": "Risk matrix used as a reference for the study. Defaults to `urn:intuitem:risk:library:risk-matrix-4x4-ebios-rm`",
"activityOne": "Activity 1",
"activityTwo": "Activity 2",
"activityThree": "Activity 3",
"ebiosRmStudy": "Ebios RM study",
"qualifications": "Qualifications",
"impacts": "Impacts",
Expand Down Expand Up @@ -980,7 +981,10 @@
"attackPaths": "Attack paths",
"currentCriticality": "Current criticality",
"residualCriticality": "Residual criticality",
"errorAssetGraphMustNotContainCycles": "The asset graph must not contain cycles.",
"notSelected": "Not selected",
"identifyRoTo": "Identify RO/TO",
"evaluateRoTo": "Evaluate RO/TO",
"selectRoTo": "Select RO/TO",
"resetPasswordHere": "You can reset your password here.",
"resetPassword": "Reset password",
"ebiosRm": "Ebios RM",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/Forms/ModelForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
{:else if URLModel === 'feared-events'}
<FearedEventForm {form} {model} {cacheLocks} {formDataCache} {initialData} />
{:else if URLModel === 'ro-to'}
<RoToForm {form} {model} {cacheLocks} {formDataCache} {initialData} />
<RoToForm {form} {model} {cacheLocks} {formDataCache} {initialData} {context} />
{:else if URLModel === 'stakeholders'}
<StakeholderForm {form} {model} {cacheLocks} {formDataCache} {context} />
{:else if URLModel === 'attack-paths'}
Expand Down
184 changes: 119 additions & 65 deletions frontend/src/lib/components/Forms/ModelForm/RoToForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,27 @@
import { getOptions } from '$lib/utils/crud';
import TextArea from '../TextArea.svelte';
import NumberField from '../NumberField.svelte';
import { page } from '$app/stores';
export let form: SuperValidated<any>;
export let model: ModelInfo;
export let cacheLocks: Record<string, CacheLock> = {};
export let formDataCache: Record<string, any> = {};
export let initialData: Record<string, any> = {};
export let context: string;
const activityBackground = context === 'edit' ? 'bg-white' : 'bg-surface-100-800-token';
let activeActivity: string | null = null;
$page.url.searchParams.forEach((value, key) => {
if (key === 'activity' && value === 'one') {
activeActivity = 'one';
} else if (key === 'activity' && value === 'two') {
activeActivity = 'two';
} else if (key === 'activity' && value === 'three') {
activeActivity = 'three';
}
});
</script>

<AutocompleteSelect
Expand All @@ -25,68 +40,107 @@
label={m.ebiosRmStudy()}
hidden={initialData.ebios_rm_study}
/>
<AutocompleteSelect
multiple
{form}
options={getOptions({
objects: model.foreignKeys['feared_events'],
extra_fields: [['folder', 'str']],
label: 'auto'
})}
field="feared_events"
label={m.fearedEvents()}
/>
<Select
{form}
options={model.selectOptions['risk-origin']}
field="risk_origin"
label={m.riskOrigin()}
cacheLock={cacheLocks['risk_origin']}
bind:cachedValue={formDataCache['risk_origin']}
/>
<TextArea
{form}
field="target_objective"
label={m.targetObjective()}
cacheLock={cacheLocks['target_objective']}
bind:cachedValue={formDataCache['target_objective']}
/>
<Select
{form}
options={model.selectOptions['motivation']}
field="motivation"
label={m.motivation()}
cacheLock={cacheLocks['motivation']}
bind:cachedValue={formDataCache['motivation']}
/>
<Select
{form}
options={model.selectOptions['resources']}
field="resources"
label={m.resources()}
cacheLock={cacheLocks['resources']}
bind:cachedValue={formDataCache['resources']}
/>
<Select
{form}
options={model.selectOptions['pertinence']}
field="pertinence"
label={m.pertinence()}
cacheLock={cacheLocks['pertinence']}
bind:cachedValue={formDataCache['pertinence']}
/>
<NumberField
{form}
field="activity"
label={m.activity()}
cacheLock={cacheLocks['activity']}
bind:cachedValue={formDataCache['activity']}
/>
<Checkbox {form} field="is_selected" label={m.isSelected()} />
<TextArea
{form}
field="justification"
label={m.justification()}
cacheLock={cacheLocks['justification']}
bind:cachedValue={formDataCache['justification']}
/>
<div
class="relative p-2 space-y-2 rounded-md {activeActivity === 'one'
? 'border-2 border-primary-500'
: 'border-2 border-gray-300 border-dashed'}"
>
<p
class="absolute -top-3 {activityBackground} font-bold {activeActivity === 'one'
? 'text-primary-500'
: 'text-gray-500'}"
>
{m.activityOne()}
</p>
<Select
{form}
options={model.selectOptions['risk-origin']}
field="risk_origin"
label={m.riskOrigin()}
cacheLock={cacheLocks['risk_origin']}
bind:cachedValue={formDataCache['risk_origin']}
/>
<TextArea
{form}
field="target_objective"
label={m.targetObjective()}
cacheLock={cacheLocks['target_objective']}
bind:cachedValue={formDataCache['target_objective']}
/>
</div>
<div
class="relative p-2 space-y-2 rounded-md {activeActivity === 'two'
? 'border-2 border-primary-500'
: 'border-2 border-gray-300 border-dashed'}"
>
<p
class="absolute -top-3 {activityBackground} font-bold {activeActivity === 'two'
? 'text-primary-500'
: 'text-gray-500'}"
>
{m.activityTwo()}
</p>
<Select
{form}
options={model.selectOptions['motivation']}
field="motivation"
label={m.motivation()}
cacheLock={cacheLocks['motivation']}
bind:cachedValue={formDataCache['motivation']}
/>
<Select
{form}
options={model.selectOptions['resources']}
field="resources"
label={m.resources()}
cacheLock={cacheLocks['resources']}
bind:cachedValue={formDataCache['resources']}
/>
<!-- <Select
{form}
options={model.selectOptions['pertinence']}
field="pertinence"
label={m.pertinence()}
cacheLock={cacheLocks['pertinence']}
bind:cachedValue={formDataCache['pertinence']}
/> -->
<NumberField
{form}
field="activity"
label={m.activity()}
cacheLock={cacheLocks['activity']}
bind:cachedValue={formDataCache['activity']}
/>
</div>
<div
class="relative p-2 space-y-2 rounded-md {activeActivity === 'three'
? 'border-2 border-primary-500'
: 'border-2 border-gray-300 border-dashed'}"
>
<p
class="absolute -top-3 {activityBackground} font-bold {activeActivity === 'three'
? 'text-primary-500'
: 'text-gray-500'}"
>
{m.activityThree()}
</p>
<Checkbox {form} field="is_selected" label={m.isSelected()} />
<AutocompleteSelect
multiple
{form}
options={getOptions({
objects: model.foreignKeys['feared_events'],
extra_fields: [['folder', 'str']],
label: 'auto'
})}
field="feared_events"
label={m.fearedEvents()}
/>
<TextArea
{form}
field="justification"
label={m.justification()}
cacheLock={cacheLocks['justification']}
bind:cachedValue={formDataCache['justification']}
/>
</div>
3 changes: 2 additions & 1 deletion frontend/src/lib/components/ModelTable/ModelTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
// Props (styles)
export let element: CssClasses = 'table';
export let text: CssClasses = 'text-xs';
export let backgroundColor: CssClasses = 'bg-white';
export let color: CssClasses = '';
export let regionHead: CssClasses = '';
export let regionHeadCell: CssClasses = 'uppercase bg-white text-gray-700';
Expand Down Expand Up @@ -94,7 +95,7 @@
// Replace $$props.class with classProp for compatibility
let classProp = ''; // Replacing $$props.class
$: classesBase = `${classProp || 'bg-white'}`;
$: classesBase = `${classProp || backgroundColor}`;
$: classesTable = `${element} ${text} ${color}`;
import { goto } from '$app/navigation';
Expand Down
Loading

0 comments on commit 2da47d8

Please sign in to comment.