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

UI/compliance assessment detail #41

Merged
merged 5 commits into from
Feb 13, 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
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import DonutChart from '$lib/components/Chart/DonutChart.svelte';
import { URL_MODEL_MAP } from '$lib/utils/crud';
import type { Node } from './types';

export let data: PageData;
breadcrumbObject.set(data.compliance_assessment);
Expand All @@ -27,18 +28,6 @@
`change_${requirementAssessmentModel.name}`
);

interface Node {
urn: string;
parent_urn: string | null;
name: string;
node_content: string;
assessable: boolean;
style: string;
description: string | null;
children?: Record<string, Node>;
status?: string; // Assuming that the status field exists in nodes similar to leaves
}

const countStatus = (
node: Node,
statusCounts: Record<string, number> = {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
<script lang="ts">
import { complianceColorMap } from './utils';
import { page } from '$app/stores';
import type { z } from 'zod';
import type { SecurityFunctionSchema, ThreatSchema } from '$lib/utils/schemas';

export let name: string;
export let description: string;
export let ra_id: string | undefined = undefined;
export let leaf_content: string;
export let threats: Record<string, any>[] | undefined = undefined;
export let security_functions: Record<string, any>[] | undefined = undefined;
export let threats: z.infer<typeof ThreatSchema>[] | undefined = undefined;
export let security_functions: z.infer<typeof SecurityFunctionSchema>[] | undefined = undefined;
export let children: Record<string, Record<string, unknown>> | undefined = undefined;
export let canEditRequirementAssessment: boolean;
// export let status: string | undefined = undefined;
export let status: string | undefined = undefined;
export let statusCounts: Record<string, number> | undefined;
export let assessable: boolean;

const node = {
name,
description,
ra_id,
leaf_content,
threats,
security_functions,
children,
canEditRequirementAssessment,
status,
statusCounts,
assessable
} as const;

type TreeViewItemNode = typeof node;

$: hasChildren = children && Object.keys(children).length > 0;

Expand All @@ -23,19 +42,20 @@

let showInfo = false;

const getLeaves = (children: Record<string, any>[] | undefined, leaves: any = []) => {
if (children?.length === 0) return leaves;
for (const value of Object.values(children)) {
if (value.children && Object.keys(value.children).length > 0) {
getLeaves(value.children, leaves);
} else {
leaves.push(value);
const getAssessableNodes = (
startNode: TreeViewItemNode,
assessableNodes: TreeViewItemNode[] = []
) => {
if (startNode.assessable) assessableNodes.push(startNode);
if (startNode.children) {
for (const value of Object.values(startNode.children) as TreeViewItemNode[]) {
getAssessableNodes(value, assessableNodes);
}
}
return leaves;
return assessableNodes;
};

const leaves = getLeaves(children) ?? [];
const assessableNodes = getAssessableNodes(node);

const REQUIREMENT_ASSESSMENT_STATUS = [
'compliant',
Expand All @@ -58,7 +78,7 @@
(status) => {
if (!statusCounts) return { status, percentage: { value: 0, display: '0' } };
const value = statusCounts[status] || 0;
const percentValue: number = (value / leaves.length) * 100;
const percentValue: number = (value / assessableNodes.length) * 100;
const percentage = {
value: percentValue,
display: percentValue.toFixed(0)
Expand All @@ -69,13 +89,14 @@

$: classesShowInfo = (show: boolean) => (!show ? 'hidden' : '');
$: classesShowInfoText = (show: boolean) => (show ? 'text-primary-500' : '');
$: classesPercentText = (statusColor: string) => (statusColor === '#000000' ? 'text-white' : '');
</script>

<div class="flex flex-row justify-between">
<div class="flex flex-col w-1/2">
<div class="flex flex-row justify-between space-x-8">
<div class="flex flex-1 max-w-[65ch] flex-col">
<span style="font-weight: {hasChildren ? 600 : 300};">
{#if !hasChildren && canEditRequirementAssessment}
<span class="w-full h-full flex p-4 rounded-token hover:text-primary-500">
{#if assessable && canEditRequirementAssessment}
<span class="w-full h-full flex rounded-token hover:text-primary-500">
<a href="/requirement-assessments/{ra_id}?next={$page.url.pathname}">
{content}
</a>
Expand All @@ -84,13 +105,21 @@
{content}
{/if}
</span>
{#if threats || security_functions}
{#if (threats && threats.length > 0) || (security_functions && security_functions.length > 0)}
<div
role="button"
tabindex="0"
class="underline text-sm hover:text-primary-400 {classesShowInfoText(showInfo)}"
on:click={(_) => (showInfo = !showInfo)}
on:keydown={(_) => (showInfo = !showInfo)}
class="select-none text-sm hover:text-primary-400 {classesShowInfoText(showInfo)}"
on:click={(e) => {
e.preventDefault();
showInfo = !showInfo;
}}
on:keydown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
showInfo = !showInfo;
}
}}
>
<i class="text-xs fa-solid fa-info-circle" /> Learn more
</div>
Expand Down Expand Up @@ -152,24 +181,16 @@
{/if}
</div>
{#if hasChildren}
<div class="flex flex-1 bg-gray-200 rounded-full overflow-hidden h-4 shrink">
<div class="flex max-w-96 grow bg-gray-200 rounded-full overflow-hidden h-4 shrink self-center">
{#each orderedStatusPercentages as sp}
{#if complianceColorMap[sp.status] === '#000000'}
<div
class="flex flex-col justify-center overflow-hidden text-white text-xs text-center bg-yellow-500"
style="width: {sp.percentage.value}%; background-color: {complianceColorMap[sp.status]}"
>
{sp.percentage.display}%
</div>
{:else}
<div
class="flex flex-col justify-center overflow-hidden text-black text-xs text-center bg-yellow-500"
style="width: {sp.percentage.value}%; background-color: {complianceColorMap[sp.status]}"
>
{sp.percentage.display}%
<!-- {sp.percentage?.display}% -->
</div>
{/if}
<div
class="flex flex-col justify-center overflow-hidden text-xs text-center {classesPercentText(
complianceColorMap[sp.status]
)}"
style="width: {sp.percentage.value}%; background-color: {complianceColorMap[sp.status]}"
>
{sp.percentage.display}%
</div>
{/each}
</div>
{/if}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
// export let status: string;
export let statusDisplay: string;
export let statusColor: string;
export let assessable: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface Node {
name: string;
description?: string;
urn: string;
parent_urn?: string;
node_content: string;
assessable: boolean;
style: string;
children?: Record<string, Node>;
status?: string; // Assuming that the status field exists in nodes similar to leaves
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@
}

const title =
data.compliance_assessment.name +
' - ' +
data.parent.display_short +
': ' +
(data.parent.display_short ? data.parent.display_short + ': ' : '') +
data.requirement.display_short;
breadcrumbObject.set({ id: data.requirementAssessment.id, name: title, email: '' });
breadcrumbObject.set({
id: data.requirementAssessment.id,
name: title ?? 'Requirement assessment',
email: ''
});

const schema = RequirementAssessmentSchema;

Expand Down
Loading