From 4707c6c69db573a7b73496ee03a0ddaafe82f020 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Mon, 12 Feb 2024 15:28:30 +0100 Subject: [PATCH] feat: add security measures and requirement assessments nested tables in evidence view --- backend/core/serializers.py | 2 + backend/core/views.py | 3 +- .../src/lib/components/Forms/ModelForm.svelte | 14 ------- frontend/src/lib/utils/crud.ts | 3 +- frontend/src/lib/utils/table.ts | 4 ++ .../(app)/evidences/[id=uuid]/+page.server.ts | 25 ++++++++++- .../(app)/evidences/[id=uuid]/+page.svelte | 41 +++++++++++++++++-- 7 files changed, 72 insertions(+), 20 deletions(-) diff --git a/backend/core/serializers.py b/backend/core/serializers.py index 6a283edd4..1ef5af2d7 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -395,6 +395,8 @@ class Meta: class RequirementAssessmentReadSerializer(BaseModelSerializer): name = serializers.CharField(source="__str__") + compliance_assessment = FieldsRelatedField() + class Meta: model = RequirementAssessment diff --git a/backend/core/views.py b/backend/core/views.py index 2706cd9c4..cf1128710 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -502,6 +502,7 @@ class SecurityMeasureViewSet(BaseModelViewSet): "effort", "risk_scenarios", "requirement_assessments", + "evidences" ] search_fields = ["name", "description", "risk_scenarios", "requirement_assessments"] @@ -1161,7 +1162,7 @@ class RequirementAssessmentViewSet(BaseModelViewSet): """ model = RequirementAssessment - filterset_fields = ["folder"] + filterset_fields = ["folder", "evidences"] search_fields = ["name", "description"] @action(detail=False, name="Get updatable measures") diff --git a/frontend/src/lib/components/Forms/ModelForm.svelte b/frontend/src/lib/components/Forms/ModelForm.svelte index ac2d13af6..d28a68a18 100644 --- a/frontend/src/lib/components/Forms/ModelForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm.svelte @@ -248,20 +248,6 @@ label="Domain" hide={initialData.security_measures || initialData.requirement_assessments} /> - - { const URLModel = 'evidences'; @@ -14,7 +17,27 @@ export const load: PageServerLoad = (async ({ fetch, params }) => { const object = await fetch(`${endpoint}object/`).then((res) => res.json()); - return { URLModel, evidence, object }; + const tables: Record = {}; + + for (const key of ['security-measures', 'requirement-assessments'] as urlModel[]) { + const keyEndpoint = `${BASE_API_URL}/${key}/?evidences=${params.id}`; + const response = await fetch(keyEndpoint); + if (response.ok) { + const data = await response.json().then((data) => data.results); + const bodyData = tableSourceMapper(data, listViewFields[key].body); + + const table: TableSource = { + head: listViewFields[key].head, + body: bodyData, + meta: data + }; + tables[key] = table; + } else { + console.error(`Failed to fetch data for ${key}: ${response.statusText}`); + } + } + + return { URLModel, evidence, object, tables }; }) export const actions: Actions = { diff --git a/frontend/src/routes/(app)/evidences/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/evidences/[id=uuid]/+page.svelte index 4396d4c3d..fa13cc424 100644 --- a/frontend/src/routes/(app)/evidences/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/evidences/[id=uuid]/+page.svelte @@ -5,10 +5,11 @@ import { breadcrumbObject } from '$lib/utils/stores'; import { URL_MODEL_MAP } from '$lib/utils/crud'; import ConfirmModal from '$lib/components/Modals/ConfirmModal.svelte'; - import type { ModalSettings, ModalComponent, ModalStore } from '@skeletonlabs/skeleton'; - import { getModalStore } from '@skeletonlabs/skeleton'; + import type { ModalSettings, ModalComponent, ModalStore, ToastStore } from '@skeletonlabs/skeleton'; + import { getModalStore, TabGroup, Tab, getToastStore } from '@skeletonlabs/skeleton'; import { isURL } from '$lib/utils/helpers'; import { getModelInfo } from '$lib/utils/crud.js'; + import ModelTable from '$lib/components/ModelTable/ModelTable.svelte'; export let data: PageData; breadcrumbObject.set(data.evidence); @@ -21,6 +22,7 @@ let attachment: Attachment | undefined = undefined; const modalStore: ModalStore = getModalStore(); + const toastStore: ToastStore = getToastStore(); function modalConfirm(id: string, name: string, action: string): void { const modalComponent: ModalComponent = { @@ -55,12 +57,14 @@ const user = $page.data.user; const model = URL_MODEL_MAP['evidences']; const canEditObject: boolean = Object.hasOwn(user.permissions, `change_${model.name}`); + + let tabSet = 0;
- {#each Object.entries(data.evidence).filter( ([key, _]) => ['name', 'description', 'folder', 'security_measures', 'requirement_assessments', 'attachment', 'link', 'comment'].includes(key) ) as [key, value]} + {#each Object.entries(data.evidence).filter( ([key, _]) => ['name', 'description', 'folder', 'attachment', 'link', 'comment'].includes(key) ) as [key, value]}
{#if key === 'urn'} @@ -123,6 +127,37 @@ {/if}
+
+ + + Security measures + + + Requirement assessments + + + {#if tabSet === 0} +
+ +
+ {/if} + {#if tabSet === 1} +
+ +
+ {/if} +
+
+
{#if data.evidence.attachment}