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} +
+
Refreshing data ..
+
- - - - -
- + -
- - -
- - - - - -
-
- -
- object.color)} + -
- - -
- object.color)} + -
- - - -
-
- {:else if tabSet === 1} -
- {m.statistics()} -
- - + +
+ + + + +
+ +
+ + -
+ - - - +
+
+ +
+ object.color)} + /> +
+ + +
+ object.color)} + /> +
+ + + +
+ + {:catch error} +
+

Error loading metrics

- + {/await} + {:else if tabSet === 1} + {#await data.stream.counters} +
+
Refreshing data ..
+ +
+ {:then counters} +
+ {m.statistics()} +
+ + + + + + +
+
+ {:catch error} +
Data load eror
+ {/await}