Skip to content

Commit

Permalink
feat: add security measures and requirement assessments nested tables…
Browse files Browse the repository at this point in the history
… in evidence view
  • Loading branch information
Mohamed-Hacene committed Feb 12, 2024
1 parent 88888a3 commit 4707c6c
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 20 deletions.
2 changes: 2 additions & 0 deletions backend/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ class Meta:

class RequirementAssessmentReadSerializer(BaseModelSerializer):
name = serializers.CharField(source="__str__")
compliance_assessment = FieldsRelatedField()


class Meta:
model = RequirementAssessment
Expand Down
3 changes: 2 additions & 1 deletion backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ class SecurityMeasureViewSet(BaseModelViewSet):
"effort",
"risk_scenarios",
"requirement_assessments",
"evidences"
]
search_fields = ["name", "description", "risk_scenarios", "requirement_assessments"]

Expand Down Expand Up @@ -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")
Expand Down
14 changes: 0 additions & 14 deletions frontend/src/lib/components/Forms/ModelForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -248,20 +248,6 @@
label="Domain"
hide={initialData.security_measures || initialData.requirement_assessments}
/>
<AutocompleteSelect
{form}
multiple
options={getOptions({ objects: model.foreignKeys['security_measures'] })}
field="security_measures"
label="Security measures"
/>
<AutocompleteSelect
{form}
multiple
options={getOptions({ objects: model.foreignKeys['requirement_assessments'] })}
field="requirement_assessments"
label="Requirement assessments"
/>
<TextField
{form}
field="link"
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/utils/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ export const URL_MODEL_MAP: ModelMap = {
selectFields: [{ field: 'status' }],
foreignKeyFields: [
{ field: 'security_measures', urlModel: 'security-measures' },
{ field: 'evidences', urlModel: 'evidences' }
{ field: 'evidences', urlModel: 'evidences' },
{ field: 'compliance_assessment', urlModel: 'compliance-assessments'}
]
},
libraries: {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/lib/utils/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export const listViewFields = {
head: ['Name', 'Framework', 'Description', 'Project'],
body: ['name', 'framework', 'description', 'project']
},
'requirement-assessments': {
head: ['Name', 'Description', 'Compliance Assessment'],
body: ['name', 'description', 'compliance_assessment'],
},
evidences: {
head: ['Name', 'File', 'Description'],
body: ['name', 'attachment', 'description']
Expand Down
25 changes: 24 additions & 1 deletion frontend/src/routes/(app)/evidences/[id=uuid]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { z } from 'zod';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { setFlash } from 'sveltekit-flash-message/server';
import type { PageServerLoad } from './$types';
import type { urlModel } from '$lib/utils/types';
import { listViewFields } from '$lib/utils/table';
import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton';

export const load: PageServerLoad = (async ({ fetch, params }) => {
const URLModel = 'evidences';
Expand All @@ -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<string, any> = {};

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 = {
Expand Down
41 changes: 38 additions & 3 deletions frontend/src/routes/(app)/evidences/[id=uuid]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 = {
Expand Down Expand Up @@ -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;
</script>

<div class="flex flex-col space-y-4">
<div class="card px-6 py-4 bg-white flex flex-row justify-between shadow-lg">
<div class="flex flex-col space-y-2">
{#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]}
<div class="flex flex-col">
<div class="text-sm font-medium text-gray-800 capitalize-first">
{#if key === 'urn'}
Expand Down Expand Up @@ -123,6 +127,37 @@
{/if}
</span>
</div>
<div class="card px-6 py-4 bg-white flex flex-col shadow-lg space-y-4">
<TabGroup>
<Tab bind:group={tabSet} name="compliance_assessments_tab" value={0}>
Security measures
</Tab>
<Tab bind:group={tabSet} name="risk_assessments_tab" value={1}>
Requirement assessments
</Tab>
<svelte:fragment slot="panel">
{#if tabSet === 0}
<div
class="h-full flex flex-col space-y-2 variant-outline-surface rounded-container-token p-4"
>
<ModelTable
source={data.tables['security-measures']}
URLModel="security-measures"
/>
</div>
{/if}
{#if tabSet === 1}
<div
class="h-full flex flex-col space-y-2 variant-outline-surface rounded-container-token p-4"
>
<ModelTable source={data.tables['requirement-assessments']}
URLModel="requirement-assessments"
/>
</div>
{/if}
</svelte:fragment>
</TabGroup>
</div>
{#if data.evidence.attachment}
<div class="card px-6 py-4 bg-white flex flex-col shadow-lg space-y-4">
<div class="flex flex-row justify-between">
Expand Down

0 comments on commit 4707c6c

Please sign in to comment.