Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fill EBIOS RM study summary tile #1243

Merged
merged 2 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/ebios_rm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ def selected_attack_path_count(self):
def operational_scenario_count(self):
return self.operational_scenarios.count()

@property
def applied_control_count(self):
return AppliedControl.objects.filter(stakeholders__ebios_rm_study=self).count()

def update_workshop_step_status(self, workshop: int, step: int, new_status: str):
if workshop < 1 or workshop > 5:
raise ValueError("Workshop must be between 1 and 5")
Expand Down
1 change: 1 addition & 0 deletions backend/ebios_rm/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class EbiosRMStudyReadSerializer(BaseModelSerializer):
selected_roto_count = serializers.IntegerField()
selected_attack_path_count = serializers.IntegerField()
operational_scenario_count = serializers.IntegerField()
applied_control_count = serializers.IntegerField()

class Meta:
model = EbiosRMStudy
Expand Down
3 changes: 3 additions & 0 deletions frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,8 @@
"highlyRelevant": "Highly relevant",
"roTo": "RO/TO",
"roToCouple": "RO/TO couple",
"roToCouples": "RO/TO couples",
"selectedRoToCouples": "Selected RO/TO couples",
"addRoto": "Add RO/TO couple",
"organizedCrime": "Organized crime",
"terrorist": "Terrorist",
Expand All @@ -980,6 +982,7 @@
"addAttackPath": "Add attack path",
"attackPath": "Attack path",
"attackPaths": "Attack paths",
"selectedAttackPaths": "Selected attack paths",
"currentCriticality": "Current criticality",
"residualCriticality": "Residual criticality",
"notSelected": "Not selected",
Expand Down
3 changes: 3 additions & 0 deletions frontend/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,8 @@
"highlyRelevant": "Très pertinent",
"roTo": "SR/OV",
"roToCouple": "Couple SR/OV",
"roToCouples": "Couples SR/OV",
"selectedRoToCouples": "Couples SR/OV sélectionnés",
"addRoto": "Ajouter un couple SR/OV",
"organizedCrime": "Crime organisé",
"terrorist": "Terroriste",
Expand All @@ -980,6 +982,7 @@
"addAttackPath": "Ajouter un chemin d'attaque",
"attackPath": "Chemin d'attaque",
"attackPaths": "Chemins d'attaque",
"selectedAttackPaths": "Chemins d'attaque sélectionnés",
"currentCriticality": "Criticité actuelle",
"residualCriticality": "Criticité résiduelle",
"notSelected": "Non retenu",
Expand Down
51 changes: 36 additions & 15 deletions frontend/src/lib/components/DataViz/Card.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
export let label: string;
export let href: string = '#';
// export let help: string;
export let icon: string;
export let section: string;
export let icon: string = '';
export let section: string = '';
export let emphasis: boolean = false;
let cEmphasis = '';
if (emphasis) {
Expand All @@ -15,20 +15,41 @@
export let customClass: string = '';
</script>

<Anchor
{href}
{label}
class="flex flex-col shadow-lg text-purple-800 p-2 h-28 bg-white hover:bg-violet-50 {cEmphasis} {customClass}"
>
<div class="text-xs">
<span><i class={icon}></i></span>
<span>{section}</span>
{#if href && href !== '#'}
<Anchor
{href}
{label}
class="flex flex-col shadow-lg text-purple-800 p-2 h-28 bg-white hover:bg-violet-50 {cEmphasis} {customClass}"
>
<div class="text-xs">
{#if icon}
<span><i class={icon}></i></span>
{/if}
{#if section}
<span>{section}</span>
{/if}
</div>
<div class="mt-auto">
<p class="text-4xl font-bold text-left">{count}</p>
<div class="text-sm">{label}</div>
</div>
</Anchor>
{:else}
<div class="flex flex-col shadow-lg text-purple-800 p-2 h-28 bg-white {cEmphasis} {customClass}">
<div class="text-xs">
{#if icon}
<span><i class={icon}></i></span>
{/if}
{#if section}
<span>{section}</span>
{/if}
</div>
<div class="mt-auto">
<p class="text-4xl font-bold text-left">{count}</p>
<div class="text-sm">{label}</div>
</div>
</div>
<div class="mt-auto">
<p class="text-4xl font-bold text-left">{count}</p>
<div class="text-sm">{label}</div>
</div>
</Anchor>
{/if}

<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import { getModalStore } from '@skeletonlabs/skeleton';
import type { ActionData, PageData } from './$types';
import Tile from './Tile.svelte';
import Card from '$lib/components/DataViz/Card.svelte';

const modalStore: ModalStore = getModalStore();

Expand Down Expand Up @@ -222,6 +223,39 @@
</button>
</div>
</Tile>
<Tile title={m.summary()} accent_color="bg-purple-800" />
<Tile title={m.summary()} accent_color="bg-purple-800">
<div slot="content">
<Card
count={data.data.roto_count}
label={m.roToCouples()}
section={''}
customClass="col-span-3 lg:col-span-1"
/>
<Card
count={data.data.selected_roto_count}
label={m.selectedRoToCouples()}
section={''}
customClass="col-span-3 lg:col-span-1"
/>
<Card
count={data.data.selected_attack_path_count}
label={m.selectedAttackPaths()}
section={''}
customClass="col-span-3 lg:col-span-1"
/>
<Card
count={data.data.operational_scenario_count}
label={m.operationalScenarios()}
section={''}
customClass="col-span-3 lg:col-span-1"
/>
<Card
count={data.data.applied_control_count}
label={m.appliedControls()}
section={''}
customClass="col-span-3 lg:col-span-1"
/>
</div>
</Tile>
</div>
</div>
176 changes: 90 additions & 86 deletions frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/Tile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,103 +43,107 @@
{/if}
</div>
</div>
{#if meta}
<div class="flex mx-auto">
<div>
<ol class="relative text-gray-500 border-s border-gray-200">
{#each meta as step, i}
<li class="flex flex-row justify-between mb-10 ms-6">
{#if createRiskAnalysis && i == 0}
<slot name="addRiskAnalysis"></slot>
{:else if !step.disabled}
<Anchor
href={step.href}
prefixCrumbs={[{ label: safeTranslate(`ebiosWs${workshop}`) }]}
label={safeTranslate(`ebiosWs${workshop}_${i + 1}`)}
class="hover:text-purple-800"
>
{#if step.status == 'done'}
<span
class="absolute flex items-center justify-center w-8 h-8 bg-success-200 rounded-full -start-4 ring-4 ring-white"
<slot name="content">
{#if meta}
<div class="flex mx-auto">
<div>
<ol class="relative text-gray-500 border-s border-gray-200">
{#each meta as step, i}
<li class="flex flex-row justify-between mb-10 ms-6">
{#if createRiskAnalysis && i == 0}
<slot name="addRiskAnalysis"></slot>
{:else if !step.disabled}
<Anchor
href={step.href}
prefixCrumbs={[{ label: safeTranslate(`ebiosWs${workshop}`) }]}
label={safeTranslate(`ebiosWs${workshop}_${i + 1}`)}
class="hover:text-purple-800"
>
{#if step.status == 'done'}
<span
class="absolute flex items-center justify-center w-8 h-8 bg-success-200 rounded-full -start-4 ring-4 ring-white"
>
<i class="fa-solid fa-check" />
</span>
{:else}
<span
class="absolute flex items-center justify-center w-8 h-8 bg-surface-200 rounded-full -start-4 ring-4 ring-white"
>
<i class="fa-solid fa-clipboard-check" />
</span>
{/if}
<h3 class="font-medium leading-tight">{m.activity()} {i + 1}</h3>
<p class="text-sm">{step.title}</p>
</Anchor>
{:else}
<div class="text-gray-300 [&>*]:pointer-events-none" use:popup={popupHover[i]}>
<div
class="transition card bg-white shadow-lg p-4 z-20 duration-300"
data-popup={'popup' + workshop + i}
>
<i class="fa-solid fa-check" />
</span>
{:else}
<p
data-testid="activity-tooltip"
class="border-l-4 {borderColor} text-gray-500 p-2"
>
{step.tooltip}
</p>
<div class="arrow bg-white" />
</div>
<span
class="absolute flex items-center justify-center w-8 h-8 bg-surface-200 rounded-full -start-4 ring-4 ring-white"
>
<i class="fa-solid fa-clipboard-check" />
</span>
{/if}
<h3 class="font-medium leading-tight">{m.activity()} {i + 1}</h3>
<p class="text-sm">{step.title}</p>
</Anchor>
{:else}
<div class="text-gray-300 [&>*]:pointer-events-none" use:popup={popupHover[i]}>
<h3 class="font-medium leading-tight">{m.activity()} {i + 1}</h3>
<p class="text-sm">{step.title}</p>
</div>
{/if}
{#if !step.disabled}
<button
class="btn bg-initial"
data-testid="sidebar-more-btn"
use:popup={{
event: 'click',
target: `popupStep-${workshop}.${i + 1}`,
placement: 'top'
}}><i class="fa-solid fa-ellipsis-vertical" /></button
>
<div
class="transition card bg-white shadow-lg p-4 z-20 duration-300"
data-popup={'popup' + workshop + i}
class="card whitespace-nowrap bg-white py-2 w-fit shadow-lg space-y-1"
data-testid="sidebar-more-panel"
data-popup="popupStep-{workshop}.{i + 1}"
>
<p
data-testid="activity-tooltip"
class="border-l-4 {borderColor} text-gray-500 p-2"
<form
action="/ebios-rm/{$page.params.id}?/changeStepState"
method="POST"
use:enhance={() => {
return async () => {
if (step.status !== 'done') step.status = 'done';
else step.status = 'in_progress';
};
}}
>
{step.tooltip}
</p>
<div class="arrow bg-white" />
<input type="hidden" name="workshop" value={workshop} />
<input type="hidden" name="step" value={i + 1} />
{#if step.status === 'done'}
<input type="hidden" name="status" value="in_progress" />
<button type="submit" class="btn bg-initial"
>{m.markAsInProgress()}</button
>
{:else}
<input type="hidden" name="status" value="done" />
<button type="submit" class="btn bg-initial">{m.markAsDone()}</button>
{/if}
</form>
</div>
<span
class="absolute flex items-center justify-center w-8 h-8 bg-surface-200 rounded-full -start-4 ring-4 ring-white"
>
<i class="fa-solid fa-clipboard-check" />
</span>
<h3 class="font-medium leading-tight">{m.activity()} {i + 1}</h3>
<p class="text-sm">{step.title}</p>
</div>
{/if}
{#if !step.disabled}
<button
class="btn bg-initial"
data-testid="sidebar-more-btn"
use:popup={{
event: 'click',
target: `popupStep-${workshop}.${i + 1}`,
placement: 'top'
}}><i class="fa-solid fa-ellipsis-vertical" /></button
>
<div
class="card whitespace-nowrap bg-white py-2 w-fit shadow-lg space-y-1"
data-testid="sidebar-more-panel"
data-popup="popupStep-{workshop}.{i + 1}"
>
<form
action="/ebios-rm/{$page.params.id}?/changeStepState"
method="POST"
use:enhance={() => {
return async () => {
if (step.status !== 'done') step.status = 'done';
else step.status = 'in_progress';
};
}}
>
<input type="hidden" name="workshop" value={workshop} />
<input type="hidden" name="step" value={i + 1} />
{#if step.status === 'done'}
<input type="hidden" name="status" value="in_progress" />
<button type="submit" class="btn bg-initial">{m.markAsInProgress()}</button>
{:else}
<input type="hidden" name="status" value="done" />
<button type="submit" class="btn bg-initial">{m.markAsDone()}</button>
{/if}
</form>
</div>
{/if}
</li>
{/each}
</ol>
{/if}
</li>
{/each}
</ol>
</div>
</div>
</div>
{/if}
{/if}
</slot>
<div class="justify-end flex"></div>
</div>
</div>
Loading