diff --git a/frontend/src/lib/components/utils/LoadingSpinner.svelte b/frontend/src/lib/components/utils/LoadingSpinner.svelte
new file mode 100644
index 000000000..6a20985a5
--- /dev/null
+++ b/frontend/src/lib/components/utils/LoadingSpinner.svelte
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/routes/(app)/(internal)/analytics/+page.server.ts b/frontend/src/routes/(app)/(internal)/analytics/+page.server.ts
index f4100ed1c..bbf5223d0 100644
--- a/frontend/src/routes/(app)/(internal)/analytics/+page.server.ts
+++ b/frontend/src/routes/(app)/(internal)/analytics/+page.server.ts
@@ -3,38 +3,9 @@ import { composerSchema } from '$lib/utils/schemas';
import { superValidate } from 'sveltekit-superforms';
import { zod } from 'sveltekit-superforms/adapters';
import type { PageServerLoad } from './$types';
-import type { Project } from '$lib/utils/types';
import { TODAY } from '$lib/utils/constants';
import * as m from '$paraglide/messages';
-const REQUIREMENT_ASSESSMENT_STATUS = [
- 'compliant',
- 'partially_compliant',
- 'in_progress',
- 'non_compliant',
- 'not_applicable',
- 'to_do'
-] as const;
-
-interface DonutItem {
- name: string;
- localName?: string;
- value: number;
- itemStyle: Record;
-}
-
-interface RequirementAssessmentDonutItem extends Omit {
- name: (typeof REQUIREMENT_ASSESSMENT_STATUS)[number];
- percentage: string;
-}
-
-interface ProjectAnalytics extends Project {
- overallCompliance: {
- values: RequirementAssessmentDonutItem[];
- total: number;
- };
-}
-
export const load: PageServerLoad = async ({ locals, fetch }) => {
const req_applied_control_status = await fetch(`${BASE_API_URL}/applied-controls/per_status/`);
const applied_control_status = await req_applied_control_status.json();
@@ -69,11 +40,26 @@ export const load: PageServerLoad = async ({ locals, fetch }) => {
applied_control.state = timeState(applied_control.eta);
}
- const req_get_counters = await fetch(`${BASE_API_URL}/get_counters/`);
- const counters = await req_get_counters.json();
-
- const req_get_metrics = await fetch(`${BASE_API_URL}/get_metrics/`);
- const metrics = await req_get_metrics.json();
+ const getCounters = async () => {
+ try {
+ const response = await fetch(`${BASE_API_URL}/get_counters/`);
+ const data = await response.json();
+ return data.results;
+ } catch (error) {
+ console.error('failed to fetch or parse counters:', error);
+ return null;
+ }
+ };
+ const getMetrics = async () => {
+ try {
+ const response = await fetch(`${BASE_API_URL}/get_metrics/`);
+ const data = await response.json();
+ return data.results;
+ } catch (error) {
+ console.error('Failed to fetch or parse metrics:', error);
+ return null;
+ }
+ };
const usedRiskMatrices: { id: string; name: string; risk_assessments_count: number }[] =
await fetch(`${BASE_API_URL}/risk-matrices/used/`)
@@ -126,11 +112,13 @@ export const load: PageServerLoad = async ({ locals, fetch }) => {
measures_to_review: measures_to_review.results,
acceptances_to_review: acceptances_to_review.results,
risk_assessments: risk_assessments.results,
- get_counters: counters.results,
measures: ord_applied_controls.results,
applied_control_status: applied_control_status.results,
user: locals.user,
- metrics: metrics.results,
- title: m.analytics()
+ title: m.analytics(),
+ stream: {
+ metrics: getMetrics(),
+ counters: getCounters()
+ }
};
};
diff --git a/frontend/src/routes/(app)/(internal)/analytics/+page.svelte b/frontend/src/routes/(app)/(internal)/analytics/+page.svelte
index 029203404..7c717f9fd 100644
--- a/frontend/src/routes/(app)/(internal)/analytics/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/analytics/+page.svelte
@@ -17,20 +17,10 @@
import CounterCard from './CounterCard.svelte';
import type { PageData } from './$types';
import StackedBarsNormalized from '$lib/components/Chart/StackedBarsNormalized.svelte';
-
- interface Counters {
- domains: number;
- projects: number;
- applied_controls: number;
- risk_assessments: number;
- compliance_assessments: number;
- policies: number;
- }
+ import LoadingSpinner from '$lib/components/utils/LoadingSpinner.svelte';
export let data: PageData;
- const counters: Counters = data.get_counters;
- const metrics = data.metrics;
const risk_assessments = data.risk_assessments;
const cur_rsk_label = m.currentRisk();
@@ -108,15 +98,6 @@
$page.url.searchParams.set('tab', index.toString());
goto($page.url);
}
-
- const REQUIREMENT_ASSESSMENT_STATUS = [
- 'compliant',
- 'partially_compliant',
- 'in_progress',
- 'non_compliant',
- 'not_applicable',
- 'to_do'
- ] as const;
@@ -137,228 +118,248 @@
{#if tabSet === 0}
-
-
-
-
-
-
-
+ {#await data.stream.metrics}
+
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- object.color)}
+
-
-
-
-
- object.color)}
+
-
-
-
-
-
-
- {:else if tabSet === 1}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+ object.color)}
+ />
+
+
+
+
+ object.color)}
+ />
+
+
+
+
+
+
+ {:catch error}
+
-
+ {/await}
+ {:else if tabSet === 1}
+ {#await data.stream.counters}
+
+ {:then counters}
+
+ {:catch error}
+
Data load eror
+ {/await}