diff --git a/backend/ciso_assistant/settings.py b/backend/ciso_assistant/settings.py
index bff8abcd7..61f3528bf 100644
--- a/backend/ciso_assistant/settings.py
+++ b/backend/ciso_assistant/settings.py
@@ -138,9 +138,9 @@ def set_ciso_assistant_url(_, __, event_dict):
"tailwind",
"iam",
"global_settings",
+ "ebios_rm",
"tprm",
"core",
- "ebios_rm",
"cal",
"django_filters",
"library",
diff --git a/backend/core/serializers.py b/backend/core/serializers.py
index c8490d807..e55df2c53 100644
--- a/backend/core/serializers.py
+++ b/backend/core/serializers.py
@@ -5,6 +5,7 @@
from core.models import *
from iam.models import *
+from ebios_rm.models import EbiosRMStudy
from rest_framework import serializers
from rest_framework.exceptions import PermissionDenied
@@ -600,6 +601,13 @@ class ComplianceAssessmentWriteSerializer(BaseModelSerializer):
required=False,
allow_null=True,
)
+ ebios_rm_studies = serializers.PrimaryKeyRelatedField(
+ many=True,
+ queryset=EbiosRMStudy.objects.all(),
+ required=False,
+ allow_null=True,
+ write_only=True,
+ )
create_applied_controls_from_suggestions = serializers.BooleanField(
write_only=True, required=False, default=False
)
@@ -712,3 +720,13 @@ class FilteringLabelWriteSerializer(BaseModelSerializer):
class Meta:
model = FilteringLabel
exclude = ["folder", "is_published"]
+
+
+class QualificationReadSerializer(ReferentialSerializer):
+ class Meta:
+ model = Qualification
+ exclude = ["translations"]
+
+
+class QualificationWriteSerializer(QualificationReadSerializer):
+ pass
diff --git a/backend/core/startup.py b/backend/core/startup.py
index 37c06a1e5..3196379e2 100644
--- a/backend/core/startup.py
+++ b/backend/core/startup.py
@@ -363,6 +363,10 @@
"view_operationalscenario",
"change_operationalscenario",
"delete_operationalscenario",
+ "view_qualification",
+ "add_qualification",
+ "change_qualification",
+ "delete_qualification",
]
THIRD_PARTY_RESPONDENT_PERMISSIONS_LIST = [
diff --git a/backend/core/urls.py b/backend/core/urls.py
index 57b55901e..0b79a6c3c 100644
--- a/backend/core/urls.py
+++ b/backend/core/urls.py
@@ -66,6 +66,11 @@
FilteringLabelViewSet,
basename="filtering-labels",
)
+router.register(
+ r"qualifications",
+ QualificationViewSet,
+ basename="qualifications",
+)
ROUTES = settings.ROUTES
MODULES = settings.MODULES.values()
diff --git a/backend/core/views.py b/backend/core/views.py
index d7c825dd7..858cf7118 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -358,7 +358,13 @@ class AssetViewSet(BaseModelViewSet):
"""
model = Asset
- filterset_fields = ["folder", "parent_assets", "type", "risk_scenarios"]
+ filterset_fields = [
+ "folder",
+ "parent_assets",
+ "type",
+ "risk_scenarios",
+ "ebios_rm_studies",
+ ]
search_fields = ["name", "description", "business_value"]
@action(detail=False, name="Get type choices")
@@ -2025,13 +2031,22 @@ def post(self, request, *args, **kwargs):
return Response(status=status.HTTP_400_BAD_REQUEST)
+class QualificationViewSet(BaseModelViewSet):
+ """
+ API endpoint that allows qualifications to be viewed or edited.
+ """
+
+ model = Qualification
+ search_fields = ["name"]
+
+
class ComplianceAssessmentViewSet(BaseModelViewSet):
"""
API endpoint that allows compliance assessments to be viewed or edited.
"""
model = ComplianceAssessment
- filterset_fields = ["framework", "project", "status"]
+ filterset_fields = ["framework", "project", "status", "ebios_rm_studies"]
search_fields = ["name", "description", "ref_id"]
ordering_fields = ["name", "description"]
diff --git a/backend/ebios_rm/migrations/0001_initial.py b/backend/ebios_rm/migrations/0001_initial.py
index 66af48c5f..8980b23f0 100644
--- a/backend/ebios_rm/migrations/0001_initial.py
+++ b/backend/ebios_rm/migrations/0001_initial.py
@@ -163,6 +163,7 @@ class Migration(migrations.Migration):
related_name="ebios_rm_studies",
to="core.riskmatrix",
verbose_name="Risk matrix",
+ blank=True,
),
),
],
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 99104508d..30543cba9 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -31,6 +31,7 @@ class Status(models.TextChoices):
help_text=_(
"Risk matrix used as a reference for the study. Defaults to `urn:intuitem:risk:library:risk-matrix-4x4-ebios-rm`"
),
+ blank=True,
)
assets = models.ManyToManyField(
Asset,
@@ -100,6 +101,10 @@ class Meta:
verbose_name_plural = _("Ebios RM Studies")
ordering = ["created_at"]
+ @property
+ def parsed_matrix(self):
+ return self.risk_matrix.parse_json_translated()
+
class FearedEvent(NameDescriptionMixin, FolderMixin):
ebios_rm_study = models.ForeignKey(
@@ -136,6 +141,28 @@ def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
+ @property
+ def risk_matrix(self):
+ return self.ebios_rm_study.risk_matrix
+
+ @property
+ def parsed_matrix(self):
+ return self.risk_matrix.parse_json_translated()
+
+ def get_gravity_display(self):
+ if self.gravity < 0:
+ return {
+ "abbreviation": "--",
+ "name": "--",
+ "description": "not rated",
+ "value": -1,
+ }
+ risk_matrix = self.parsed_matrix
+ return {
+ **risk_matrix["impact"][self.gravity],
+ "value": self.gravity,
+ }
+
class RoTo(AbstractBaseModel, FolderMixin):
class RiskOrigin(models.TextChoices):
diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py
index e77c5c153..15da633fc 100644
--- a/backend/ebios_rm/serializers.py
+++ b/backend/ebios_rm/serializers.py
@@ -71,8 +71,10 @@ class Meta:
class FearedEventReadSerializer(BaseModelSerializer):
- str = serializers.CharField(source="__str__")
ebios_rm_study = FieldsRelatedField()
+ qualifications = FieldsRelatedField(["name"], many=True)
+ assets = FieldsRelatedField(many=True)
+ gravity = serializers.JSONField(source="get_gravity_display")
folder = FieldsRelatedField()
class Meta:
diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py
index ca0d048dd..af0360603 100644
--- a/backend/ebios_rm/views.py
+++ b/backend/ebios_rm/views.py
@@ -1,3 +1,4 @@
+from core.serializers import RiskMatrixReadSerializer
from core.views import BaseModelViewSet as AbstractBaseModelViewSet
from .models import (
EbiosRMStudy,
@@ -31,10 +32,47 @@ class EbiosRMStudyViewSet(BaseModelViewSet):
def status(self, request):
return Response(dict(EbiosRMStudy.Status.choices))
+ @method_decorator(cache_page(60 * LONG_CACHE_TTL))
+ @action(detail=True, name="Get gravity choices")
+ def gravity(self, request, pk):
+ study: EbiosRMStudy = self.get_object()
+ undefined = dict([(-1, "--")])
+ _choices = dict(
+ zip(
+ list(range(0, 64)),
+ [x["name"] for x in study.parsed_matrix["impact"]],
+ )
+ )
+ choices = undefined | _choices
+ return Response(choices)
+
class FearedEventViewSet(BaseModelViewSet):
model = FearedEvent
+ filterset_fields = [
+ "ebios_rm_study",
+ ]
+
+ @action(detail=True, name="Get risk matrix", url_path="risk-matrix")
+ def risk_matrix(self, request, pk=None):
+ feared_event = self.get_object()
+ return Response(RiskMatrixReadSerializer(feared_event.risk_matrix).data)
+
+ @method_decorator(cache_page(60 * LONG_CACHE_TTL))
+ @action(detail=True, name="Get gravity choices")
+ def gravity(self, request, pk):
+ feared_event: FearedEvent = self.get_object()
+ undefined = dict([(-1, "--")])
+ _choices = dict(
+ zip(
+ list(range(0, 64)),
+ [x["name"] for x in feared_event.parsed_matrix["impact"]],
+ )
+ )
+ choices = undefined | _choices
+ return Response(choices)
+
class RoToViewSet(BaseModelViewSet):
model = RoTo
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 51665084a..11b1f8bf3 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -921,9 +921,21 @@
"ebiosWs5_4": "Assess and document residual risks",
"ebiosWs5_5": "Establish risk monitoring framework",
"activity": "Activity",
+ "ebiosRmMatrixHelpText": "Risk matrix used as a reference for the study. Defaults to `urn:intuitem:risk:library:risk-matrix-4x4-ebios-rm`",
+ "activityOne": "Activity 1",
+ "activityTwo": "Activity 2",
+ "ebiosRmStudy": "Ebios RM study",
+ "qualifications": "Qualifications",
+ "impacts": "Impacts",
+ "ebiosRmStudies": "Ebios RM studies",
"bringTheEvidences": "Bring the evidences",
"bringTheEvidencesHelpText": "If disabled, the object will be duplicated without its evidences",
+ "gravity": "Gravity",
"existingControlsHelper": "What do you currently have to manage this risk",
"extraControlsHelper": "What will you do to mitigate this risk",
- "existingContextHelper": "Description of the existing mitigations (this field will be deprecated soon)"
+ "existingContextHelper": "Description of the existing mitigations (this field will be deprecated soon)",
+ "fearedEvent": "Feared event",
+ "fearedEvents": "Feared events",
+ "isSelected": "Is selected",
+ "ebiosRM": "Ebios RM"
}
diff --git a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
index 7ceac4475..ff92026a7 100644
--- a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
+++ b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte
@@ -17,7 +17,7 @@
let tokenPath = '';
crumbs = tokens.map((t) => {
tokenPath += '/' + t;
- if (t === $breadcrumbObject.id) {
+ if (t === $breadcrumbObject?.id) {
if ($breadcrumbObject.name) {
t = $breadcrumbObject.name;
} else if ($breadcrumbObject.first_name && $breadcrumbObject.last_name) {
diff --git a/frontend/src/lib/components/Forms/ModelForm.svelte b/frontend/src/lib/components/Forms/ModelForm.svelte
index da9c227a7..7f30a2a71 100644
--- a/frontend/src/lib/components/Forms/ModelForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm.svelte
@@ -26,6 +26,8 @@
import SsoSettingsForm from './ModelForm/SsoSettingForm.svelte';
import FolderForm from './ModelForm/FolderForm.svelte';
import GeneralSettingsForm from './ModelForm/GeneralSettingForm.svelte';
+ import EbiosRmForm from './ModelForm/EbiosRmForm.svelte';
+ import FearedEventForm from './ModelForm/FearedEventForm.svelte';
import AutocompleteSelect from './AutocompleteSelect.svelte';
@@ -255,6 +257,10 @@
{:else if URLModel === 'filtering-labels'}
+ {:else if URLModel === 'ebios-rm'}
+
+ {:else if URLModel === 'feared-events'}
+
{/if}
{#if closeModal}
diff --git a/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte b/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte
index c53338fa0..0bba0a55c 100644
--- a/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/ComplianceAssessmentForm.svelte
@@ -38,6 +38,18 @@
options={getOptions({ objects: model.foreignKeys['baseline'] })}
/>
{/if}
+{#if initialData.ebios_rm_studies}
+
+{/if}
+ import type { SuperValidated } from 'sveltekit-superforms';
+ import type { ModelInfo, CacheLock } from '$lib/utils/types';
+ import TextField from '$lib/components/Forms/TextField.svelte';
+ import AutocompleteSelect from '$lib/components/Forms/AutocompleteSelect.svelte';
+ import Select from '$lib/components/Forms/Select.svelte';
+ import * as m from '$paraglide/messages.js';
+ import { getOptions } from '$lib/utils/crud';
+ import TextArea from '../TextArea.svelte';
+
+ export let form: SuperValidated;
+ export let model: ModelInfo;
+ export let cacheLocks: Record = {};
+ export let formDataCache: Record = {};
+ export let initialData: Record = {};
+ export let context: string;
+
+
+{#if context !== 'ebiosRmStudy'}
+
+
+
+
+{:else if context === 'ebiosRmStudy'}
+
+
{m.activityOne()}
+
+
+
+
+
+
+
+{/if}
diff --git a/frontend/src/lib/components/Forms/ModelForm/FearedEventForm.svelte b/frontend/src/lib/components/Forms/ModelForm/FearedEventForm.svelte
new file mode 100644
index 000000000..9580233a3
--- /dev/null
+++ b/frontend/src/lib/components/Forms/ModelForm/FearedEventForm.svelte
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
diff --git a/frontend/src/lib/utils/actions.ts b/frontend/src/lib/utils/actions.ts
index f85adeeed..c869da8fa 100644
--- a/frontend/src/lib/utils/actions.ts
+++ b/frontend/src/lib/utils/actions.ts
@@ -48,11 +48,16 @@ function getEndpoint({
urlModel: string;
event: RequestEvent;
}) {
+ const model = getModelInfo(urlModel);
if (action === 'create') {
- return `${BASE_API_URL}/${urlModel}/`;
+ return model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/`
+ : `${BASE_API_URL}/${urlModel}/`;
}
const id = event.params.id;
- return `${BASE_API_URL}/${urlModel}/${id}/`;
+ return model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${id}/`
+ : `${BASE_API_URL}/${urlModel}/${id}/`;
}
export async function handleErrorResponse({
@@ -199,9 +204,12 @@ export async function defaultDeleteFormAction({
const formData = await event.request.formData();
const schema = z.object({ id: z.string().uuid() });
const deleteForm = await superValidate(formData, zod(schema));
+ const model = getModelInfo(urlModel);
const id = deleteForm.data.id;
- const endpoint = `${BASE_API_URL}/${urlModel}/${id}/`;
+ const endpoint = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${id}/`
+ : `${BASE_API_URL}/${model.urlModel}/${id}/`;
if (!deleteForm.valid) {
console.error(deleteForm.errors);
diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts
index 20573da0b..49f30e7ab 100644
--- a/frontend/src/lib/utils/crud.ts
+++ b/frontend/src/lib/utils/crud.ts
@@ -114,6 +114,7 @@ interface Field {
interface SelectField {
field: string;
detail?: boolean;
+ valueType?: 'string' | 'number';
}
export interface ModelMapEntry {
@@ -131,6 +132,7 @@ export interface ModelMapEntry {
fileFields?: string[];
filters?: SelectField[];
path?: string;
+ endpointUrl?: string;
}
type ModelMap = {
@@ -460,7 +462,8 @@ export const URL_MODEL_MAP: ModelMap = {
{ field: 'framework', urlModel: 'frameworks' },
{ field: 'authors', urlModel: 'users' },
{ field: 'reviewers', urlModel: 'users', urlParams: 'is_third_party=false' },
- { field: 'baseline', urlModel: 'compliance-assessments' }
+ { field: 'baseline', urlModel: 'compliance-assessments' },
+ { field: 'ebios_rm_studies', urlModel: 'ebios-rm' }
],
selectFields: [{ field: 'status' }],
filters: [{ field: 'status' }]
@@ -584,6 +587,42 @@ export const URL_MODEL_MAP: ModelMap = {
{ field: 'entity', urlModel: 'entities' },
{ field: 'user', urlModel: 'users' }
]
+ },
+ qualifications: {
+ name: 'qualification',
+ localName: 'qualification',
+ localNamePlural: 'qualifications',
+ verboseName: 'Qualification',
+ verboseNamePlural: 'Qualifications'
+ },
+ 'ebios-rm': {
+ endpointUrl: 'ebios-rm/studies',
+ name: 'ebiosrmstudy',
+ localName: 'ebiosRMstudy',
+ localNamePlural: 'ebiosRMstudy',
+ verboseName: 'Ebios RMstudy',
+ verboseNamePlural: 'Ebios RMstudy',
+ foreignKeyFields: [
+ { field: 'risk_matrix', urlModel: 'risk-matrices' },
+ { field: 'assets', urlModel: 'assets' },
+ { field: 'authors', urlModel: 'users', urlParams: 'is_third_party=false' },
+ { field: 'reviewers', urlModel: 'users', urlParams: 'is_third_party=false' },
+ { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' }
+ ]
+ },
+ 'feared-events': {
+ endpointUrl: 'ebios-rm/feared-events',
+ name: 'fearedevent',
+ localName: 'fearedEvent',
+ localNamePlural: 'fearedEvents',
+ verboseName: 'Feared event',
+ verboseNamePlural: 'Feared events',
+ foreignKeyFields: [
+ { field: 'ebios_rm_study', urlModel: 'ebios-rm' },
+ { field: 'assets', urlModel: 'assets' },
+ { field: 'qualifications', urlModel: 'qualifications' }
+ ],
+ selectFields: [{ field: 'gravity', valueType: 'number', detail: true }]
}
};
diff --git a/frontend/src/lib/utils/load.ts b/frontend/src/lib/utils/load.ts
index 08a762273..b4a42ec11 100644
--- a/frontend/src/lib/utils/load.ts
+++ b/frontend/src/lib/utils/load.ts
@@ -11,7 +11,9 @@ import { zod } from 'sveltekit-superforms/adapters';
import { z, type AnyZodObject } from 'zod';
export const loadDetail = async ({ event, model, id }) => {
- const endpoint = `${BASE_API_URL}/${model.urlModel}/${id}/`;
+ const endpoint = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${id}/`
+ : `${BASE_API_URL}/${model.urlModel}/${id}/`;
const res = await event.fetch(endpoint);
const data = await res.json();
@@ -107,7 +109,7 @@ export const loadDetail = async ({ event, model, id }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index bc96c4bb0..413d7c45c 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -268,7 +268,8 @@ export const ComplianceAssessmentSchema = z.object({
reviewers: z.array(z.string().optional()).optional(),
baseline: z.string().optional().nullable(),
create_applied_controls_from_suggestions: z.boolean().optional().default(false),
- observation: z.string().optional().nullable()
+ observation: z.string().optional().nullable(),
+ ebios_rm_studies: z.string().uuid().optional().array().optional()
});
export const EvidenceSchema = z.object({
@@ -389,6 +390,29 @@ export const vulnerabilitySchema = z.object({
filtering_labels: z.string().optional().array().optional()
});
+export const ebiosRMSchema = z.object({
+ ...NameDescriptionMixin,
+ version: z.string().optional().default('0.1'),
+ ref_id: z.string().optional().default(''),
+ risk_matrix: z.string().optional(),
+ authors: z.array(z.string().optional()).optional(),
+ reviewers: z.array(z.string().optional()).optional(),
+ observation: z.string().optional().nullable(),
+ assets: z.string().uuid().optional().array().optional(),
+ folder: z.string()
+});
+
+export const fearedEventsSchema = z.object({
+ ...NameDescriptionMixin,
+ ref_id: z.string().optional(),
+ gravity: z.number().optional().default(-1),
+ is_selected: z.boolean().optional(),
+ justification: z.string().optional(),
+ ebios_rm_study: z.string(),
+ assets: z.string().uuid().optional().array().optional(),
+ qualifications: z.string().optional().array().optional()
+});
+
const SCHEMA_MAP: Record = {
folders: FolderSchema,
projects: ProjectSchema,
@@ -413,7 +437,9 @@ const SCHEMA_MAP: Record = {
representatives: representativeSchema,
solutions: solutionSchema,
vulnerabilities: vulnerabilitySchema,
- 'filtering-labels': FilteringLabelSchema
+ 'filtering-labels': FilteringLabelSchema,
+ 'ebios-rm': ebiosRMSchema,
+ 'feared-events': fearedEventsSchema
};
export const modelSchema = (model: string) => {
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index ce68ba165..a02b1c270 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -547,5 +547,13 @@ export const listViewFields: ListViewFieldsConfig = {
representatives: {
head: ['email', 'entity', 'role'],
body: ['email', 'entity', 'role']
+ },
+ 'ebios-rm': {
+ head: ['name', 'description'],
+ body: ['name', 'description']
+ },
+ 'feared-events': {
+ head: ['selected', 'assets', 'fearedEvent', 'qualifications', 'gravity'],
+ body: ['is_selected', 'assets', 'description', 'qualifications', 'gravity']
}
};
diff --git a/frontend/src/lib/utils/types.ts b/frontend/src/lib/utils/types.ts
index edff27b87..14c7c0356 100644
--- a/frontend/src/lib/utils/types.ts
+++ b/frontend/src/lib/utils/types.ts
@@ -51,7 +51,9 @@ export const URL_MODEL = [
'solutions',
'representatives',
'vulnerabilities',
- 'filtering-labels'
+ 'filtering-labels',
+ 'feared-events'
+ // 'ebios-rm',
] as const;
export const THIRD_PARTY_URL_MODEL = ['compliance-assessments', 'evidences'] as const;
diff --git a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+layout.server.ts b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+layout.server.ts
index 128452015..45ce69a1f 100644
--- a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+layout.server.ts
+++ b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+layout.server.ts
@@ -14,7 +14,9 @@ export const load = (async ({ fetch, params }) => {
const fetch_function = CUSTOM_MODEL_FETCH_MAP[params.model];
data = await fetch_function({ fetch, params }, languageTag());
} else {
- const endpoint = `${BASE_API_URL}/${params.model}/${model.listViewUrlParams || ''}`;
+ const endpoint = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${model.listViewUrlParams || ''}`
+ : `${BASE_API_URL}/${params.model}/${model.listViewUrlParams || ''}`;
const res = await fetch(endpoint);
data = await res.json().then((res) => res.results);
}
diff --git a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+page.server.ts b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+page.server.ts
index 61f425852..fe10f5bf2 100644
--- a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+page.server.ts
+++ b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/+page.server.ts
@@ -48,7 +48,7 @@ export const load: PageServerLoad = async ({ params, fetch }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts
index 8639fad8d..918df2f18 100644
--- a/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts
+++ b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts
@@ -12,11 +12,13 @@ import { zod } from 'sveltekit-superforms/adapters';
export const load: LayoutServerLoad = async (event) => {
const URLModel = event.params.model!;
const schema = modelSchema(event.params.model);
- const objectEndpoint = `${BASE_API_URL}/${event.params.model}/${event.params.id}/object/`;
+ const model = getModelInfo(event.params.model!);
+ const objectEndpoint = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${event.params.id}/object/`
+ : `${BASE_API_URL}/${event.params.model}/${event.params.id}/object/`;
const object = await event.fetch(objectEndpoint).then((res) => res.json());
const form = await superValidate(object, zod(schema), { errors: false });
- const model = getModelInfo(event.params.model!);
const foreignKeyFields = model.foreignKeyFields;
const selectFields = model.selectFields;
@@ -46,7 +48,10 @@ export const load: LayoutServerLoad = async (event) => {
if (foreignKeyFields) {
for (const keyField of foreignKeyFields) {
const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
- const url = `${BASE_API_URL}/${keyField.urlModel}/${queryParams}`;
+ const keyModel = getModelInfo(keyField.urlModel);
+ const url = keyModel.endpointUrl
+ ? `${BASE_API_URL}/${keyModel.endpointUrl}/${queryParams}`
+ : `${BASE_API_URL}/${keyModel.urlModel}/${queryParams}`;
const response = await event.fetch(url);
if (response.ok) {
foreignKeys[keyField.field] = await response.json().then((data) => data.results);
@@ -60,7 +65,7 @@ export const load: LayoutServerLoad = async (event) => {
if (selectFields) {
for (const selectField of selectFields) {
- const url = `${BASE_API_URL}/${event.params.model}/${
+ const url = `${BASE_API_URL}/${model.endpointUrl ?? event.params.model}/${
selectField.detail ? event.params.id + '/' : ''
}${selectField.field}/`;
const response = await event.fetch(url);
@@ -68,7 +73,7 @@ export const load: LayoutServerLoad = async (event) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/+page.server.ts
new file mode 100644
index 000000000..809ca81b9
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/+page.server.ts
@@ -0,0 +1,99 @@
+import { defaultDeleteFormAction, defaultWriteFormAction } from '$lib/utils/actions';
+import { BASE_API_URL } from '$lib/utils/constants';
+import {
+ getModelInfo,
+ urlParamModelForeignKeyFields,
+ urlParamModelSelectFields
+} from '$lib/utils/crud';
+import { modelSchema } from '$lib/utils/schemas';
+import type { ModelInfo, urlModel } from '$lib/utils/types';
+import { type Actions } from '@sveltejs/kit';
+import { superValidate } from 'sveltekit-superforms';
+import { zod } from 'sveltekit-superforms/adapters';
+import { z } from 'zod';
+import type { PageServerLoad } from './$types';
+import { listViewFields } from '$lib/utils/table';
+import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton';
+
+export const load: PageServerLoad = async ({ params, fetch }) => {
+ const schema = z.object({ id: z.string().uuid() });
+ const deleteForm = await superValidate(zod(schema));
+ const URLModel = 'ebios-rm';
+ const createSchema = modelSchema(URLModel);
+ const createForm = await superValidate(zod(createSchema));
+ const model: ModelInfo = getModelInfo(URLModel);
+ const foreignKeyFields = urlParamModelForeignKeyFields(URLModel);
+ const selectFields = urlParamModelSelectFields(URLModel);
+
+ const foreignKeys: Record = {};
+
+ for (const keyField of foreignKeyFields) {
+ const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
+ const url = `${BASE_API_URL}/${keyField.urlModel}/${queryParams}`;
+ const response = await fetch(url);
+ if (response.ok) {
+ foreignKeys[keyField.field] = await response.json().then((data) => data.results);
+ } else {
+ console.error(`Failed to fetch data for ${keyField.field}: ${response.statusText}`);
+ }
+ }
+
+ model['foreignKeys'] = foreignKeys;
+
+ const selectOptions: Record = {};
+
+ for (const selectField of selectFields) {
+ if (selectField.detail) continue;
+ const url = `${BASE_API_URL}/${URLModel}/${selectField.field}/`;
+ const response = await fetch(url);
+ if (response.ok) {
+ selectOptions[selectField.field] = await response.json().then((data) =>
+ Object.entries(data).map(([key, value]) => ({
+ label: value,
+ value: selectField.valueType === 'number' ? parseInt(key) : key
+ }))
+ );
+ } else {
+ console.error(`Failed to fetch data for ${selectField.field}: ${response.statusText}`);
+ }
+ }
+
+ model['selectOptions'] = selectOptions;
+
+ const endpoint = `${BASE_API_URL}/${model.endpointUrl}`;
+ const res = await fetch(endpoint);
+ const data = await res.json().then((res) => res.results);
+
+ const bodyData = tableSourceMapper(data, listViewFields[URLModel as urlModel].body);
+
+ const headData: Record = listViewFields[URLModel as urlModel].body.reduce(
+ (obj, key, index) => {
+ obj[key] = listViewFields[URLModel as urlModel].head[index];
+ return obj;
+ },
+ {}
+ );
+
+ const table: TableSource = {
+ head: headData,
+ body: bodyData,
+ meta: data // metaData
+ };
+
+ return { createForm, deleteForm, model, URLModel, table };
+};
+
+export const actions: Actions = {
+ create: async (event) => {
+ // const redirectToWrittenObject = Boolean(event.params.model === 'entity-assessments');
+ return defaultWriteFormAction({
+ event,
+ urlModel: 'ebios-rm',
+ action: 'create'
+ // redirectToWrittenObject: redirectToWrittenObject
+ });
+ },
+ delete: async (event) => {
+ return defaultDeleteFormAction({ event, urlModel: 'ebios-rm' });
+ }
+};
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/+page.svelte
new file mode 100644
index 000000000..4d1ae36d4
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/+page.svelte
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts
new file mode 100644
index 000000000..cb361f306
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.server.ts
@@ -0,0 +1,7 @@
+import { loadDetail } from '$lib/utils/load';
+import type { PageServerLoad } from './$types';
+import { getModelInfo } from '$lib/utils/crud';
+
+export const load: PageServerLoad = async (event) => {
+ return await loadDetail({ event, model: getModelInfo('ebios-rm'), id: event.params.id });
+};
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte
index 33000896f..21df4f60f 100644
--- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte
@@ -2,12 +2,36 @@
import * as m from '$paraglide/messages';
import { safeTranslate } from '$lib/utils/i18n';
import Tile from './Tile.svelte';
- const data = {
+ import { page } from '$app/stores';
+ import type { PageData } from './$types';
+ import { breadcrumbObject } from '$lib/utils/stores';
+
+ export let data: PageData;
+
+ $: breadcrumbObject.set(data.data);
+
+ const dummydata = {
ws1: [
- { title: safeTranslate(m.ebiosWs1_1()), status: 'done', href: '#' },
- { title: safeTranslate(m.ebiosWs1_2()), status: 'done', href: '#' },
- { title: safeTranslate(m.ebiosWs1_3()), status: 'to_do', href: '#' },
- { title: safeTranslate(m.ebiosWs1_4()), status: 'to_do', href: '#' }
+ {
+ title: safeTranslate(m.ebiosWs1_1()),
+ status: 'done',
+ href: `${$page.url.pathname}/workshop-one/ebios-rm-study?next=${$page.url.pathname}`
+ },
+ {
+ title: safeTranslate(m.ebiosWs1_2()),
+ status: 'done',
+ href: `${$page.url.pathname}/workshop-one/ebios-rm-study?next=${$page.url.pathname}`
+ },
+ {
+ title: safeTranslate(m.ebiosWs1_3()),
+ status: 'to_do',
+ href: `${$page.url.pathname}/workshop-one/feared-events?next=${$page.url.pathname}`
+ },
+ {
+ title: safeTranslate(m.ebiosWs1_4()),
+ status: 'to_do',
+ href: `${$page.url.pathname}/workshop-one/baseline?next=${$page.url.pathname}`
+ }
],
ws2: [
{ title: safeTranslate(m.ebiosWs2_1()), status: 'to_do', href: '#' },
@@ -33,15 +57,15 @@
};
-
+
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/baseline/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/baseline/+page.server.ts
new file mode 100644
index 000000000..2d907c25f
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/baseline/+page.server.ts
@@ -0,0 +1,110 @@
+import { defaultDeleteFormAction, defaultWriteFormAction } from '$lib/utils/actions';
+import { BASE_API_URL } from '$lib/utils/constants';
+import {
+ getModelInfo,
+ urlParamModelForeignKeyFields,
+ urlParamModelSelectFields
+} from '$lib/utils/crud';
+import { modelSchema } from '$lib/utils/schemas';
+import type { ModelInfo, urlModel } from '$lib/utils/types';
+import { type Actions } from '@sveltejs/kit';
+import { superValidate } from 'sveltekit-superforms';
+import { zod } from 'sveltekit-superforms/adapters';
+import { z } from 'zod';
+import type { PageServerLoad } from './$types';
+import { listViewFields } from '$lib/utils/table';
+import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton';
+
+export const load: PageServerLoad = async ({ params, fetch }) => {
+ const schema = z.object({ id: z.string().uuid() });
+ const deleteForm = await superValidate(zod(schema));
+ const URLModel = 'compliance-assessments';
+ const createSchema = modelSchema(URLModel);
+ const initialData = {
+ ebios_rm_studies: [params.id]
+ };
+ const createForm = await superValidate(initialData, zod(createSchema), { errors: false });
+ const model: ModelInfo = getModelInfo(URLModel);
+ const foreignKeyFields = urlParamModelForeignKeyFields(URLModel);
+ const selectFields = model.selectFields;
+
+ const foreignKeys: Record
= {};
+
+ for (const keyField of foreignKeyFields) {
+ const model = getModelInfo(keyField.urlModel);
+ const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
+ const url = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${queryParams}`
+ : `${BASE_API_URL}/${model.urlModel}/${queryParams}`;
+ const response = await fetch(url);
+ if (response.ok) {
+ foreignKeys[keyField.field] = await response.json().then((data) => data.results);
+ } else {
+ console.error(`Failed to fetch data for ${keyField.field}: ${response.statusText}`);
+ }
+ }
+
+ model['foreignKeys'] = foreignKeys;
+
+ const selectOptions: Record = {};
+
+ if (selectFields) {
+ for (const selectField of selectFields) {
+ const url = `${BASE_API_URL}/${URLModel}/${
+ selectField.detail ? params.id + '/' : ''
+ }${selectField.field}/`;
+ const response = await fetch(url);
+ if (response.ok) {
+ selectOptions[selectField.field] = await response.json().then((data) =>
+ Object.entries(data).map(([key, value]) => ({
+ label: value,
+ value: selectField.valueType === 'number' ? parseInt(key) : key
+ }))
+ );
+ } else {
+ console.error(`Failed to fetch data for ${selectField.field}: ${response.statusText}`);
+ }
+ }
+ }
+
+ model['selectOptions'] = selectOptions;
+
+ const endpoint = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}?ebios_rm_studies=${params.id}`
+ : `${BASE_API_URL}/${model.urlModel}?ebios_rm_studies=${params.id}`;
+ const res = await fetch(endpoint);
+ const data = await res.json().then((res) => res.results);
+
+ const bodyData = tableSourceMapper(data, listViewFields[URLModel as urlModel].body);
+
+ const headData: Record = listViewFields[URLModel as urlModel].body.reduce(
+ (obj, key, index) => {
+ obj[key] = listViewFields[URLModel as urlModel].head[index];
+ return obj;
+ },
+ {}
+ );
+
+ const table: TableSource = {
+ head: headData,
+ body: bodyData,
+ meta: data // metaData
+ };
+
+ return { createForm, deleteForm, model, URLModel, table };
+};
+
+export const actions: Actions = {
+ create: async (event) => {
+ // const redirectToWrittenObject = Boolean(event.params.model === 'entity-assessments');
+ return defaultWriteFormAction({
+ event,
+ urlModel: 'compliance-assessments',
+ action: 'create'
+ // redirectToWrittenObject: redirectToWrittenObject
+ });
+ },
+ delete: async (event) => {
+ return defaultDeleteFormAction({ event, urlModel: 'compliance-assessments' });
+ }
+};
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/baseline/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/baseline/+page.svelte
new file mode 100644
index 000000000..08ebedae8
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/baseline/+page.svelte
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.server.ts
new file mode 100644
index 000000000..346bfdee2
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.server.ts
@@ -0,0 +1,65 @@
+import { BASE_API_URL } from '$lib/utils/constants';
+import { getModelInfo } from '$lib/utils/crud';
+import { modelSchema } from '$lib/utils/schemas';
+import { superValidate } from 'sveltekit-superforms';
+import { zod } from 'sveltekit-superforms/adapters';
+import type { PageServerLoad, Actions } from './$types';
+import { defaultWriteFormAction } from '$lib/utils/actions';
+
+export const load: PageServerLoad = async (event) => {
+ const URLModel = 'ebios-rm';
+ const model = getModelInfo(URLModel);
+ const schema = modelSchema(URLModel);
+ const objectEndpoint = `${BASE_API_URL}/${model.endpointUrl}/${event.params.id}/object/`;
+ const objectResponse = await event.fetch(objectEndpoint);
+ const object = await objectResponse.json();
+
+ const form = await superValidate(object, zod(schema), { errors: false });
+ const foreignKeyFields = model.foreignKeyFields;
+ const selectFields = model.selectFields;
+
+ const foreignKeys: Record = {};
+
+ if (foreignKeyFields) {
+ for (const keyField of foreignKeyFields) {
+ const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
+ const url = `${BASE_API_URL}/${keyField.urlModel}/${queryParams}`;
+ const response = await event.fetch(url);
+ if (response.ok) {
+ foreignKeys[keyField.field] = await response.json().then((data) => data.results);
+ } else {
+ console.error(`Failed to fetch data for ${keyField.field}: ${response.statusText}`);
+ }
+ }
+ }
+
+ const selectOptions: Record = {};
+
+ if (selectFields) {
+ for (const selectField of selectFields) {
+ const url = `${BASE_API_URL}/${URLModel}/${
+ selectField.detail ? event.params.id + '/' : ''
+ }${selectField.field}/`;
+ const response = await event.fetch(url);
+ if (response.ok) {
+ selectOptions[selectField.field] = await response.json().then((data) =>
+ Object.entries(data).map(([key, value]) => ({
+ label: value,
+ value: selectField.valueType === 'number' ? parseInt(key) : key
+ }))
+ );
+ } else {
+ console.error(`Failed to fetch data for ${selectField.field}: ${response.statusText}`);
+ }
+ }
+ }
+ model.foreignKeys = foreignKeys;
+ model.selectOptions = selectOptions;
+ return { form, model, object, foreignKeys, selectOptions, URLModel };
+};
+
+export const actions: Actions = {
+ default: async (event) => {
+ return defaultWriteFormAction({ event, urlModel: 'ebios-rm', action: 'edit' });
+ }
+};
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte
new file mode 100644
index 000000000..beafb4be4
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.server.ts
new file mode 100644
index 000000000..852754409
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.server.ts
@@ -0,0 +1,102 @@
+import { defaultDeleteFormAction, defaultWriteFormAction } from '$lib/utils/actions';
+import { BASE_API_URL } from '$lib/utils/constants';
+import {
+ getModelInfo,
+ urlParamModelForeignKeyFields,
+ urlParamModelSelectFields
+} from '$lib/utils/crud';
+import { modelSchema } from '$lib/utils/schemas';
+import type { ModelInfo, urlModel } from '$lib/utils/types';
+import { type Actions } from '@sveltejs/kit';
+import { superValidate } from 'sveltekit-superforms';
+import { zod } from 'sveltekit-superforms/adapters';
+import { z } from 'zod';
+import type { PageServerLoad } from './$types';
+import { listViewFields } from '$lib/utils/table';
+import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton';
+
+export const load: PageServerLoad = async ({ params, fetch }) => {
+ const schema = z.object({ id: z.string().uuid() });
+ const deleteForm = await superValidate(zod(schema));
+ const URLModel = 'feared-events';
+ const createSchema = modelSchema(URLModel);
+ const initialData = {
+ ebios_rm_study: params.id
+ };
+ const createForm = await superValidate(initialData, zod(createSchema), { errors: false });
+ const model: ModelInfo = getModelInfo(URLModel);
+ const foreignKeyFields = urlParamModelForeignKeyFields(URLModel);
+
+ const selectOptions: Record = {};
+
+ const gravityChoicesEndpoint = `${BASE_API_URL}/ebios-rm/studies/${params.id}/gravity/`;
+ const gravityChoicesResponse = await fetch(gravityChoicesEndpoint);
+
+ if (gravityChoicesResponse.ok) {
+ selectOptions['gravity'] = await gravityChoicesResponse.json().then((data) =>
+ Object.entries(data).map(([key, value]) => ({
+ label: value,
+ value: parseInt(key)
+ }))
+ );
+ } else {
+ console.error(`Failed to fetch data for gravity: ${gravityChoicesResponse.statusText}`);
+ }
+
+ model['selectOptions'] = selectOptions;
+
+ const foreignKeys: Record = {};
+
+ for (const keyField of foreignKeyFields) {
+ const model = getModelInfo(keyField.urlModel);
+ const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
+ const url = model.endpointUrl
+ ? `${BASE_API_URL}/${model.endpointUrl}/${queryParams}`
+ : `${BASE_API_URL}/${model.urlModel}/${queryParams}`;
+ const response = await fetch(url);
+ if (response.ok) {
+ foreignKeys[keyField.field] = await response.json().then((data) => data.results);
+ } else {
+ console.error(`Failed to fetch data for ${keyField.field}: ${response.statusText}`);
+ }
+ }
+
+ model['foreignKeys'] = foreignKeys;
+
+ const endpoint = `${BASE_API_URL}/${model.endpointUrl}?ebios_rm_study=${params.id}`;
+ const res = await fetch(endpoint);
+ const data = await res.json().then((res) => res.results);
+
+ const bodyData = tableSourceMapper(data, listViewFields[URLModel as urlModel].body);
+
+ const headData: Record = listViewFields[URLModel as urlModel].body.reduce(
+ (obj, key, index) => {
+ obj[key] = listViewFields[URLModel as urlModel].head[index];
+ return obj;
+ },
+ {}
+ );
+
+ const table: TableSource = {
+ head: headData,
+ body: bodyData,
+ meta: data // metaData
+ };
+
+ return { createForm, deleteForm, model, URLModel, table };
+};
+
+export const actions: Actions = {
+ create: async (event) => {
+ // const redirectToWrittenObject = Boolean(event.params.model === 'entity-assessments');
+ return defaultWriteFormAction({
+ event,
+ urlModel: 'feared-events',
+ action: 'create'
+ // redirectToWrittenObject: redirectToWrittenObject
+ });
+ },
+ delete: async (event) => {
+ return defaultDeleteFormAction({ event, urlModel: 'feared-events' });
+ }
+};
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.svelte
new file mode 100644
index 000000000..08ebedae8
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.svelte
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/(app)/(internal)/experimental/+page.svelte b/frontend/src/routes/(app)/(internal)/experimental/+page.svelte
index d9a1f5d98..7964bcdf6 100644
--- a/frontend/src/routes/(app)/(internal)/experimental/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/experimental/+page.svelte
@@ -27,10 +27,4 @@
link="assets/graph"
tags={['analysis', 'assets']}
/>
-
diff --git a/frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+layout.server.ts b/frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+layout.server.ts
index f1d747965..80f149cec 100644
--- a/frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+layout.server.ts
+++ b/frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+layout.server.ts
@@ -94,7 +94,7 @@ export const load: LayoutServerLoad = async ({ fetch, params }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(internal)/risk-matrices/[id=uuid]/+layout.server.ts b/frontend/src/routes/(app)/(internal)/risk-matrices/[id=uuid]/+layout.server.ts
index bfc57593b..36d5cfa30 100644
--- a/frontend/src/routes/(app)/(internal)/risk-matrices/[id=uuid]/+layout.server.ts
+++ b/frontend/src/routes/(app)/(internal)/risk-matrices/[id=uuid]/+layout.server.ts
@@ -69,7 +69,7 @@ export const load: LayoutServerLoad = async ({ fetch, params }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.server.ts
index 1f9f71221..3e79e183a 100644
--- a/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.server.ts
+++ b/frontend/src/routes/(app)/(internal)/risk-scenarios/[id=uuid]/edit/+page.server.ts
@@ -79,7 +79,7 @@ export const load: PageServerLoad = async ({ params, fetch }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
@@ -152,7 +152,7 @@ export const load: PageServerLoad = async ({ params, fetch }) => {
measureSelectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(internal)/settings/+page.server.ts b/frontend/src/routes/(app)/(internal)/settings/+page.server.ts
index 450eab6b2..cc2dba5b9 100644
--- a/frontend/src/routes/(app)/(internal)/settings/+page.server.ts
+++ b/frontend/src/routes/(app)/(internal)/settings/+page.server.ts
@@ -28,7 +28,7 @@ export const load: PageServerLoad = async ({ fetch }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
@@ -47,7 +47,7 @@ export const load: PageServerLoad = async ({ fetch }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/+page.server.ts b/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/+page.server.ts
index e1a02c463..ce9f05aab 100644
--- a/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/+page.server.ts
+++ b/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/+page.server.ts
@@ -51,7 +51,7 @@ export const load: PageServerLoad = async ({ params, fetch }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/[id=uuid]/edit/+layout.server.ts b/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/[id=uuid]/edit/+layout.server.ts
index 5b0ef3913..c152b8703 100644
--- a/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/[id=uuid]/edit/+layout.server.ts
+++ b/frontend/src/routes/(app)/(third-party)/[model=thirdparty_urlmodels]/[id=uuid]/edit/+layout.server.ts
@@ -67,7 +67,7 @@ export const load: LayoutServerLoad = async (event) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.server.ts b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.server.ts
index 6ee0140c1..983c9c84a 100644
--- a/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.server.ts
+++ b/frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/+page.server.ts
@@ -71,7 +71,7 @@ export const load = (async ({ fetch, params }) => {
selectOptions[selectField.field] = await response.json().then((data) =>
Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}))
);
} else {
diff --git a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts
index 08e68fed1..9670f9657 100644
--- a/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts
+++ b/frontend/src/routes/(app)/(third-party)/requirement-assessments/[id=uuid]/edit/+page.server.ts
@@ -72,7 +72,7 @@ export const load = (async ({ fetch, params }) => {
if (data) {
selectOptions[selectField.field] = Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}));
}
})
@@ -98,7 +98,7 @@ export const load = (async ({ fetch, params }) => {
if (data) {
measureSelectOptions[selectField.field] = Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}));
} else {
console.error(`Failed to fetch data for ${selectField.field}: ${response.statusText}`);
@@ -169,7 +169,7 @@ export const load = (async ({ fetch, params }) => {
if (data) {
evidenceSelectOptions[selectField.field] = Object.entries(data).map(([key, value]) => ({
label: value,
- value: key
+ value: selectField.valueType === 'number' ? parseInt(key) : key
}));
}
})