Skip to content

Commit

Permalink
Adjusted creation of manual evalaution results to new API (#45)
Browse files Browse the repository at this point in the history
Validity is now mandatory and now set to 1 month (not changeable for now). It is also possible to set non-compliant manual results.
  • Loading branch information
oxisto authored Oct 24, 2023
1 parent 64b6cad commit 58fe795
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 23 deletions.
4 changes: 3 additions & 1 deletion src/lib/api/evaluation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ComplianceStatus =
| 'EVALUATION_STATUS_NOT_COMPLIANT'
| 'EVALUATION_STATUS_COMPLIANT'
| 'EVALUATION_STATUS_COMPLIANT_MANUALLY'
| 'EVALUATION_STATUS_NOT_COMPLIANT_MANUALLY'
| 'EVALUATION_STATUS_PENDING'
| 'EVALUATION_STATUS_DELEGATED'
;
Expand All @@ -28,7 +29,8 @@ export interface EvaluationResult {
parentControlId?: string
timestamp: string,
failingAssessmentResultIds: string[]
comment?: string
comment?: string,
validUntil?: string
}

export async function startEvaluation(toe: TargetOfEvaluation): Promise<StartEvaluationResponse> {
Expand Down
67 changes: 52 additions & 15 deletions src/lib/components/AddEvaluationResultDialog.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
<script lang="ts" context="module">
export interface AddEvaluationResultEvent {
name: string;
comment: string;
validUntil: Date;
status: ComplianceStatus;
}
</script>

<script lang="ts">
import type { ComplianceStatus } from '$lib/api/evaluation';
import {
Dialog,
DialogOverlay,
Expand All @@ -7,16 +17,27 @@
TransitionRoot
} from '@rgossiaux/svelte-headlessui';
import { createEventDispatcher } from 'svelte';
import ComplianceStatusSelect from './ComplianceStatusSelect.svelte';
export let open = false;
let name: string;
let comment: string;
const dispatch = createEventDispatcher<{ addResult: { name: string; comment: string } }>();
const dispatch = createEventDispatcher<{
addResult: AddEvaluationResultEvent;
}>();
interface $$Events {
addResult: CustomEvent<AddEvaluationResultEvent>;
}
function submit() {
dispatch('addResult', { comment: comment, name: name });
let date = new Date();
date.setDate(date.getDate() + 30);
dispatch('addResult', { comment: comment, name: name, validUntil: date, status: status });
open = false;
}
let status: ComplianceStatus = 'EVALUATION_STATUS_COMPLIANT_MANUALLY';
</script>

<TransitionRoot show={open}>
Expand Down Expand Up @@ -52,31 +73,29 @@
</DialogTitle>
<p class="mt-1 text-sm leading-6 text-gray-600">
Using this form, you can provide a manual evaluation result that will be
considered as <b>compliant</b>.
considered as <ComplianceStatusSelect bind:status />
</p>

<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="mt-2 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-4">
<label
for="username"
class="block text-sm font-medium leading-6 text-gray-900">Name</label
>
<label for="name" class="block text-sm font-medium leading-6 text-gray-900">
Name
</label>
<div class="mt-2">
<input
type="text"
name="first-name"
id="first-name"
autocomplete="given-name"
name="name"
id="name"
autocomplete="name"
class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-clouditor sm:text-sm sm:leading-6"
bind:value={name}
/>
</div>
</div>

<div class="col-span-full">
<label for="about" class="block text-sm font-medium leading-6 text-gray-900"
>Comment</label
>
<label for="about" class="block text-sm font-medium leading-6 text-gray-900">
Comment
</label>
<div class="mt-2">
<textarea
id="about"
Expand All @@ -91,6 +110,24 @@
based on your comment.
</p>
</div>

<div class="sm:col-span-4">
<label
for="validity"
class="block text-sm font-medium leading-6 text-gray-900">Validity</label
>
<div class="mt-2">
<input
type="text"
name="first-name"
id="first-name"
autocomplete="given-name"
class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-clouditor sm:text-sm sm:leading-6"
value="1 month"
disabled
/>
</div>
</div>
</div>
<div class="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
<button
Expand Down
13 changes: 11 additions & 2 deletions src/lib/components/ComplianceChart.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,23 @@
export let toe: TargetOfEvaluation;
const data = {
labels: ['Non Compliant', 'Compliant', 'Manually set to Compliant', 'Waiting for Data'],
labels: [
'Non Compliant',
'Manually set to Non Compliant',
'Compliant',
'Manually set to Compliant',
'Waiting for Data'
],
datasets: [
{
label: toe.catalogId,
data: [
Array.from(compliance.values()).filter(
(value) => value == 'EVALUATION_STATUS_NOT_COMPLIANT'
).length,
Array.from(compliance.values()).filter(
(value) => value == 'EVALUATION_STATUS_NOT_COMPLIANT_MANUALLY'
).length,
Array.from(compliance.values()).filter((value) => value == 'EVALUATION_STATUS_COMPLIANT')
.length,
Array.from(compliance.values()).filter(
Expand All @@ -26,7 +35,7 @@
Array.from(compliance.values()).filter((value) => value == 'EVALUATION_STATUS_PENDING')
.length
],
backgroundColor: ['#991b1b', '#166534', '#007fc3', '#d4d4d4'],
backgroundColor: ['#991b1b', '#991b1b', '#166534', '#166534', '#d4d4d4'],
hoverOffset: 4
}
]
Expand Down
87 changes: 87 additions & 0 deletions src/lib/components/ComplianceStatusSelect.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<script lang="ts">
import type { ComplianceStatus } from '$lib/api/evaluation';
import {
Listbox,
ListboxButton,
ListboxLabel,
ListboxOption,
ListboxOptions,
Transition
} from '@rgossiaux/svelte-headlessui';
import { Check, ChevronDown } from '@steeze-ui/heroicons';
import { Icon } from '@steeze-ui/svelte-icon';
const publishingOptions = [
{
name: 'Compliant',
description: 'This job posting can be viewed by anyone who has the link.',
bgColor: 'bg-green-800',
hoverColor: 'hover:bg-green-900 focus:ring-green-800',
divideColor: 'divide-green-900',
status: 'EVALUATION_STATUS_COMPLIANT_MANUALLY'
},
{
name: 'Non-Compliant',
description: 'This job posting will no longer be publicly accessible.',
bgColor: 'bg-red-800',
hoverColor: 'hover:bg-red-900 focus:ring-red-900',
divideColor: 'divide-red-900',
status: 'EVALUATION_STATUS_NOT_COMPLIANT_MANUALLY'
}
];
export let status: ComplianceStatus = 'EVALUATION_STATUS_COMPLIANT_MANUALLY';
$: selected =
status == 'EVALUATION_STATUS_COMPLIANT_MANUALLY' ? publishingOptions[0] : publishingOptions[1];
</script>

<Listbox bind:value={status}>
<ListboxLabel class="sr-only">Change published status</ListboxLabel>
<div class="relative">
<div class="inline-flex divide-x {selected.divideColor} rounded-md shadow-sm">
<div
class="inline-flex items-center gap-x-1.5 rounded-l-md px-3 py-2 text-white shadow-sm {selected.bgColor}"
>
<Icon src={Check} class="-ml-0.5 h-5 w-5" aria-hidden="true" />
<p class="text-sm font-semibold">{selected.name}</p>
</div>
<ListboxButton
class="inline-flex items-center rounded-l-none rounded-r-md {selected.bgColor} {selected.hoverColor} p-2 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-50"
>
<span class="sr-only">Change published status</span>
<Icon src={ChevronDown} class="h-5 w-5 text-white" aria-hidden="true" />
</ListboxButton>
</div>

<Transition leave="transition ease-in duration-100" leaveFrom="opacity-100" leaveTo="opacity-0">
<ListboxOptions
class="absolute right-0 z-10 mt-2 w-72 origin-top-right divide-y divide-gray-200 overflow-hidden rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
>
{#each publishingOptions as option (option.name)}
<ListboxOption value={option.status} let:active let:selected>
<li
class="{active
? 'bg-clouditor text-white'
: 'text-gray-900'} cursor-default select-none p-4 text-sm"
>
<div class="flex flex-col">
<div class="flex justify-between">
<p class={selected ? 'font-semibold' : 'font-normal'}>{option.name}</p>
{#if selected}
<span class="active ? 'text-white' : 'text-clouditor'">
<Icon src={Check} class="h-5 w-5" aria-hidden="true" />
</span>
{/if}
</div>
<p class="{active ? 'text-indigo-200' : 'text-gray-500'} mt-2">
{option.description}
</p>
</div>
</li>
</ListboxOption>
{/each}
</ListboxOptions>
</Transition>
</div>
</Listbox>
4 changes: 3 additions & 1 deletion src/lib/components/ControlComplianceItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
{#if result.status == 'EVALUATION_STATUS_COMPLIANT'}
<Icon src={CheckCircle} theme="solid" class="w-8 h-8 text-green-800" />
{:else if result.status == 'EVALUATION_STATUS_COMPLIANT_MANUALLY'}
<Icon src={CheckCircle} theme="solid" class="w-8 h-8 text-clouditor" />
<Icon src={CheckCircle} theme="solid" class="w-8 h-8 text-green-800" />
{:else if result.status == 'EVALUATION_STATUS_NOT_COMPLIANT_MANUALLY'}
<Icon src={XCircle} theme="solid" class="w-8 h-8 text-red-800" />
{:else if result.status == 'EVALUATION_STATUS_PENDING'}
<button on:click={addResult}>
<Icon src={EllipsisHorizontalCircle} theme="solid" class="w-8 h-8 text-gray-400" />
Expand Down
14 changes: 10 additions & 4 deletions src/routes/(app)/cloud/[id]/compliance/[catalogId]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { createEvaluationResult, type EvaluationResult } from '$lib/api/evaluation';
import type { Control } from '$lib/api/orchestrator';
import type { AddEvaluationResultEvent } from '$lib/components/AddEvaluationResultDialog.svelte';
import ControlComplianceItem from '$lib/components/ControlComplianceItem.svelte';
import { Disclosure, DisclosureButton, DisclosurePanel } from '@rgossiaux/svelte-headlessui';
import { Minus, Plus } from '@steeze-ui/heroicons';
import { Icon } from '@steeze-ui/svelte-icon';
import type { PageData } from './$types';
import { invalidate } from '$app/navigation';
export let data: PageData;
Expand Down Expand Up @@ -64,18 +65,23 @@
return tree;
}
async function addResult(e: CustomEvent<{ name: string; comment: string }>, control: Control) {
async function addResult(e: CustomEvent<AddEvaluationResultEvent>, control?: Control) {
if (control == undefined) {
return;
}
let result: EvaluationResult = {
id: '',
controlId: control.id,
cloudServiceId: data.service.id,
controlCategoryName: control.categoryName,
controlCatalogId: data.catalog.id,
parentControlId: control.parentControlId,
status: 'EVALUATION_STATUS_COMPLIANT_MANUALLY',
status: e.detail.status,
timestamp: new Date().toISOString(),
failingAssessmentResultIds: [],
comment: e.detail.comment
comment: e.detail.comment,
validUntil: e.detail.validUntil.toISOString()
};
result = await createEvaluationResult(result);
Expand Down

0 comments on commit 58fe795

Please sign in to comment.