diff --git a/backend/core/serializers.py b/backend/core/serializers.py
index 1b2661a14..f61807a06 100644
--- a/backend/core/serializers.py
+++ b/backend/core/serializers.py
@@ -705,3 +705,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 833cff177..63d952859 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 d0aa4054d..a1a1ab108 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 be431f545..334d74198 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -359,7 +359,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")
@@ -1950,6 +1956,15 @@ 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.
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..f51d4fc8b 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,
diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py
index 3507bf69f..39dfdd6f7 100644
--- a/backend/ebios_rm/serializers.py
+++ b/backend/ebios_rm/serializers.py
@@ -65,8 +65,8 @@ class Meta:
class FearedEventReadSerializer(BaseModelSerializer):
- str = serializers.CharField(source="__str__")
ebios_rm_study = FieldsRelatedField()
+ qualifications = FieldsRelatedField(["name"], many=True)
folder = FieldsRelatedField()
class Meta:
diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py
index 69676bf77..7bdfa29f3 100644
--- a/backend/ebios_rm/views.py
+++ b/backend/ebios_rm/views.py
@@ -27,3 +27,7 @@ def status(self, request):
class FearedEventViewSet(BaseModelViewSet):
model = FearedEvent
+
+ filterset_fields = [
+ "ebios_rm_study",
+ ]
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 8be7b78d0..d16cc46f7 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -919,5 +919,11 @@
"ebiosWs5_3": "Define security measures",
"ebiosWs5_4": "Assess and document residual risks",
"ebiosWs5_5": "Establish risk monitoring framework",
- "activity": "Activity"
+ "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"
}
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 2a331686a..054b51a71 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';
@@ -254,6 +256,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/EbiosRmForm.svelte b/frontend/src/lib/components/Forms/ModelForm/EbiosRmForm.svelte
new file mode 100644
index 000000000..20ba8c544
--- /dev/null
+++ b/frontend/src/lib/components/Forms/ModelForm/EbiosRmForm.svelte
@@ -0,0 +1,110 @@
+
+
+{#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..d3548da56
--- /dev/null
+++ b/frontend/src/lib/components/Forms/ModelForm/FearedEventForm.svelte
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
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 52a7e0830..4c482149f 100644
--- a/frontend/src/lib/utils/crud.ts
+++ b/frontend/src/lib/utils/crud.ts
@@ -131,6 +131,7 @@ export interface ModelMapEntry {
fileFields?: string[];
filters?: SelectField[];
path?: string;
+ endpointUrl?: string;
}
type ModelMap = {
@@ -574,6 +575,41 @@ 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' }
+ ]
}
};
diff --git a/frontend/src/lib/utils/load.ts b/frontend/src/lib/utils/load.ts
index 165d2a64c..596570cb9 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();
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index 42a10b1a6..102742df6 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -370,6 +370,27 @@ export const vulnerabilitySchema = baseNamedObject({
filtering_labels: z.string().optional().array().optional()
});
+export const ebiosRMSchema = baseNamedObject({
+ version: z.string().optional().default('0.1'),
+ ref_id: z.string().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 = baseNamedObject({
+ ref_id: z.string().optional(),
+ gravity: z.number().optional(),
+ 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,
@@ -394,7 +415,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 012b8268c..c4623fa3b 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -527,5 +527,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 8d11ac1d0..d0c365d1c 100644
--- a/frontend/src/lib/utils/types.ts
+++ b/frontend/src/lib/utils/types.ts
@@ -52,7 +52,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]/[id=uuid]/edit/+layout.server.ts b/frontend/src/routes/(app)/(internal)/[model=urlmodel]/[id=uuid]/edit/+layout.server.ts
index 8639fad8d..a6d843e1e 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);
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..1c395758c
--- /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: 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..225dbbaba 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,11 +2,31 @@
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_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: '#' }
],
ws2: [
@@ -33,15 +53,15 @@
};
-
+
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..e28cc52ea
--- /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: 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..bb8c37006
--- /dev/null
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/feared-events/+page.server.ts
@@ -0,0 +1,84 @@
+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 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']}
/>
-