Skip to content

Commit 8af25ee

Browse files
authored
feat: include a graph on strategic scenario and ebios RM report improvements (#2970)
* feat: visual graph for strategic scenario * wip * fixup * graph * fixing ebios rm report and graph items translation
1 parent c14ffad commit 8af25ee

File tree

9 files changed

+813
-164
lines changed

9 files changed

+813
-164
lines changed

frontend/messages/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,9 @@
13971397
"ebiosRM": "Ebios RM",
13981398
"ebiosRMStudies": "Ebios RM studies",
13991399
"riskOrigin": "Risk origin",
1400+
"riskOrigins": "Risk origins",
14001401
"targetObjective": "Target objective",
1402+
"targetObjectives": "Target objectives",
14011403
"motivation": "Motivation",
14021404
"resources": "Resources",
14031405
"pertinence": "Relevance",
@@ -1439,6 +1441,7 @@
14391441
"attackPath": "Attack path",
14401442
"attackPaths": "Attack paths",
14411443
"selectedAttackPaths": "Selected attack paths",
1444+
"noAttackPathsDefined": "No attack paths defined",
14421445
"currentCriticality": "Current criticality",
14431446
"residualCriticality": "Residual criticality",
14441447
"notSelected": "Not selected",
@@ -2329,6 +2332,7 @@
23292332
"hideAll": "Hide All",
23302333
"required": "required",
23312334
"legendNotes": "Legend & Notes",
2335+
"legend": "Legend",
23322336
"aleTimelineChartDebugInfo": "ALE Timeline Chart Debug Info",
23332337
"scenariosWithCurrentLevel": "Scenarios with current_level:",
23342338
"scenariosWithResidualLevel": "Scenarios with residual_level:",

frontend/messages/fr.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,9 @@
13331333
"ebiosRM": "EBIOS RM",
13341334
"ebiosRMStudies": "Études EBIOS RM",
13351335
"riskOrigin": "Source de risque",
1336+
"riskOrigins": "Sources de risque",
13361337
"targetObjective": "Objectif visé",
1338+
"targetObjectives": "Objectifs visés",
13371339
"motivation": "Motivation",
13381340
"resources": "Ressources",
13391341
"pertinence": "Pertinence",
@@ -1374,6 +1376,7 @@
13741376
"attackPath": "Chemin d'attaque",
13751377
"attackPaths": "Chemins d'attaque",
13761378
"selectedAttackPaths": "Chemins d'attaque sélectionnés",
1379+
"noAttackPathsDefined": "Aucun chemin d'attaque défini",
13771380
"currentCriticality": "Criticité actuelle",
13781381
"residualCriticality": "Criticité résiduelle",
13791382
"notSelected": "Non retenu",
@@ -2295,6 +2298,7 @@
22952298
"hideAll": "Tout masquer",
22962299
"required": "requis",
22972300
"legendNotes": "Légende et notes",
2301+
"legend": "Légende",
22982302
"aleTimelineChartDebugInfo": "Infos de débogage du graphique chronologique ALE",
22992303
"scenariosWithCurrentLevel": "Scénarios avec niveau actuel :",
23002304
"scenariosWithResidualLevel": "Scénarios avec niveau résiduel :",
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<script lang="ts">
2+
import { m } from '$paraglide/messages';
3+
import { safeTranslate } from '$lib/utils/i18n';
4+
5+
type AttackPath = {
6+
id: string;
7+
name?: string;
8+
risk_origin?: string;
9+
target_objective?: string;
10+
stakeholders?: Array<{
11+
id: string;
12+
str: string;
13+
entity?: {
14+
id: string;
15+
name: string;
16+
};
17+
}>;
18+
};
19+
20+
type FearedEvent = {
21+
id: string;
22+
name: string;
23+
};
24+
25+
type FearedEventWithAssets = {
26+
id: string;
27+
name: string;
28+
assets: Array<{
29+
id: string;
30+
str: string;
31+
}>;
32+
};
33+
34+
interface Props {
35+
attackPaths: AttackPath[];
36+
fearedEvents: FearedEvent[];
37+
fearedEventsWithAssets: FearedEventWithAssets[];
38+
}
39+
40+
let { attackPaths, fearedEvents, fearedEventsWithAssets }: Props = $props();
41+
</script>
42+
43+
<!-- Text-based attack path flows -->
44+
<div class="mb-4 space-y-3 bg-white p-4 rounded-lg border border-gray-200">
45+
{#each attackPaths as path}
46+
<div class="text-sm border-l-4 border-primary-500 pl-3 py-2">
47+
{#if path.name}
48+
<div class="font-semibold text-gray-700 mb-2">{path.name}</div>
49+
{/if}
50+
<div class="flex flex-wrap items-center gap-2 font-mono text-xs">
51+
<span class="px-2 py-1 bg-red-100 text-red-800 rounded font-semibold">
52+
{safeTranslate(path.risk_origin) || 'Unknown RO'}
53+
</span>
54+
<i class="fa-solid fa-arrow-right text-gray-400"></i>
55+
56+
<span class="px-2 py-1 bg-purple-100 text-purple-800 rounded font-semibold">
57+
{path.target_objective || 'Unknown TO'}
58+
</span>
59+
<i class="fa-solid fa-arrow-right text-gray-400"></i>
60+
61+
{#if path.stakeholders && path.stakeholders.length > 0}
62+
<div class="flex flex-wrap items-center gap-2">
63+
{#each path.stakeholders as stakeholder}
64+
<span class="px-2 py-1 bg-amber-100 text-amber-800 rounded">
65+
{stakeholder.str}
66+
{#if stakeholder.entity}
67+
<span class="text-amber-600 font-semibold">
68+
({stakeholder.entity.name})
69+
</span>
70+
{/if}
71+
</span>
72+
{#if stakeholder !== path.stakeholders[path.stakeholders.length - 1]}
73+
<span class="text-gray-300">|</span>
74+
{/if}
75+
{/each}
76+
</div>
77+
<i class="fa-solid fa-arrow-right text-gray-400"></i>
78+
{/if}
79+
80+
{#if fearedEvents && fearedEvents.length > 0}
81+
<div class="flex flex-wrap items-center gap-2">
82+
{#each fearedEvents as fe}
83+
<span class="px-2 py-1 bg-orange-100 text-orange-800 rounded">
84+
{fe.name}
85+
</span>
86+
{#if fe !== fearedEvents[fearedEvents.length - 1]}
87+
<span class="text-gray-300">|</span>
88+
{/if}
89+
{/each}
90+
</div>
91+
<i class="fa-solid fa-arrow-right text-gray-400"></i>
92+
{/if}
93+
94+
{#if fearedEventsWithAssets && fearedEventsWithAssets.length > 0}
95+
<div class="flex flex-wrap items-center gap-2">
96+
{#each fearedEventsWithAssets as fe}
97+
{#each fe.assets as asset}
98+
<span class="px-2 py-1 bg-cyan-100 text-cyan-800 rounded text-xs">
99+
{asset.str}
100+
</span>
101+
{/each}
102+
{/each}
103+
</div>
104+
{/if}
105+
</div>
106+
</div>
107+
{/each}
108+
</div>
109+
110+
<!-- Legend -->
111+
<div class="mb-6 bg-white p-3 rounded-lg border border-gray-200">
112+
<h4 class="text-xs font-semibold text-gray-600 mb-2">{m.legend()}:</h4>
113+
<div class="flex flex-wrap gap-3 text-xs">
114+
<span class="px-2 py-1 bg-red-100 text-red-800 rounded font-semibold">{m.riskOrigin()}</span>
115+
<span class="px-2 py-1 bg-purple-100 text-purple-800 rounded font-semibold"
116+
>{m.targetObjective()}</span
117+
>
118+
<span class="px-2 py-1 bg-amber-100 text-amber-800 rounded">{m.stakeholder()}</span>
119+
<span class="px-2 py-1 bg-orange-100 text-orange-800 rounded">{m.fearedEvent()}</span>
120+
<span class="px-2 py-1 bg-cyan-100 text-cyan-800 rounded">{m.asset()}</span>
121+
</div>
122+
</div>

0 commit comments

Comments
 (0)