Skip to content

Commit

Permalink
🎉 First version of user created scenarios.
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasGilg committed Dec 19, 2024
1 parent 0b6da69 commit 40fc16e
Show file tree
Hide file tree
Showing 21 changed files with 562 additions and 598 deletions.
12 changes: 12 additions & 0 deletions frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,17 @@ module.exports = {
],
},
],
'@typescript-eslint/no-unused-vars': [
"error",
{
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "all",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
]
},
};
3 changes: 2 additions & 1 deletion frontend/locales/de-backend.json5
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,15 @@
description: 'Mittlere Zeitspanne bevor angesteckte Personen infektiös werden',
unit: 'Tage',
},
TimeInfectedNoSymptoms: {
TimeInfectedNoSymptom: {
symbol: 'T_C',
description: 'Mittlere Zeitspanne der Infektiösität ohne Symptome',
unit: 'Tage',
},
},
'scenario-names': {
caseData: 'Geschätzte Fälle',
casedata: 'Geschätzte Fälle',
baseline: 'Basisszenario',
closed_schools: 'Geschlossene Schulen',
remote_work: 'Homeoffice',
Expand Down
24 changes: 24 additions & 0 deletions frontend/locales/de-global.json5
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
more: 'Mehr Eigenschaften',
activate: 'Scenario aktivieren',
deactivate: 'Scenario deaktivieren',
hide: 'In die Bibliothek verschieben',
'manage-groups': 'Filter',
'reference-day': 'Referenztag',
},
Expand Down Expand Up @@ -77,6 +78,29 @@
parameters: {
'no-parameters': 'Für das ausgewählte Szenario existieren keine Parameter.',
},
'scenario-library': {
'title': 'Szenarienbibliothek',
'add': 'Hinzufügen',
'no-scenarios': 'Keine weiteren Szenarien verfügbar.',
'new-scenario': 'Szenario Erstellen',
'new': {
'title': 'Neues Szenario Erstellen',
'name': 'Name',
'description': 'Beschreibung',
'start-date': 'Start',
'end-date': 'Ende',
'interventions': 'Interventionen',
'model': 'Simulationsmodell',
'node-list': 'Regionen',
'create': 'Szenario Erstellen',
'cancel': 'Abbrechen',

'name-required': 'Der Name muss gesetzt werden!',
'model-required': 'Ein Modell muss ausgewählt werden!',
'node-required': 'Eine Region muss ausgewählt werden!',
'date-order': 'Das Startdatum muss vor dem Enddatum liegen!',
},
},
today: 'Heute',
more: 'Mehr',
less: 'Weniger',
Expand Down
3 changes: 2 additions & 1 deletion frontend/locales/en-backend.json5
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,15 @@
description: 'Average time span before exposed individuals become infectious',
unit: 'days',
},
TimeInfectedNoSymptoms: {
TimeInfectedNoSymptom: {
symbol: 'T_C',
description: 'Average time span of infectiousness without symptoms',
unit: 'days',
},
},
'scenario-names': {
caseData: 'Estimated Cases',
casedata: 'Estimated Cases',
baseline: 'Baseline Scenario',
closed_schools: 'Schools Closed',
remote_work: 'Home Office',
Expand Down
24 changes: 24 additions & 0 deletions frontend/locales/en-global.json5
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
more: 'More properties',
activate: 'Activate scenario',
deactivate: 'Deactivate scenario',
hide: 'Move to the library',
'manage-groups': 'Filters',
'reference-day': 'Reference Day',
},
Expand Down Expand Up @@ -86,6 +87,29 @@
parameters: {
'no-parameters': 'No parameters available for the selected scenario.',
},
'scenario-library': {
'title': 'Scenario Library',
'add': 'Add',
'no-scenarios': 'No further scenarios available.',
'new-scenario': 'Create Scenario',
'new': {
'title': 'Create new Scenario',
'name': 'Name',
'description': 'Description',
'start-date': 'Start',
'end-date': 'End',
'interventions': 'Interventions',
'model': 'Simulation Model',
'node-list': 'Regions',
'create': 'Create Scenario',
'cancel': 'Cancel',

'name-required': 'A name is required!',
'model-required': 'A model needs to be selected!',
'node-required': 'A region needs to be selected!',
'date-order': 'The start date needs to be before the end date!',
}
},
today: 'Today',
more: 'More',
less: 'Less',
Expand Down
55 changes: 46 additions & 9 deletions frontend/src/DataContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
useGetGroupCategoriesQuery,
useGetModelQuery,
useGetMultiParameterDefinitionsQuery,
useGetInterventionTemplatesQuery,
useGetNodeListsQuery,
} from 'store/services/scenarioApi';
import data from '../assets/lk_germany_reduced.geojson?url';
import {GeoJSON, GeoJsonProperties} from 'geojson';
Expand All @@ -26,21 +28,26 @@ import {
Groups,
InfectionData,
InfectionDataParameters,
InterventionTemplates,
Model,
Models,
NodeLists,
ParameterDefinition,
Scenario,
ScenarioPreview,
Scenarios,
} from './store/services/APITypes';
import {
addScenario,
removeScenario,
selectCompartment,
selectDate,
selectScenario,
setActiveScenario,
setMinMaxDates,
setScenarioColors,
setStartDate,
showScenario,
} from './store/DataSelectionSlice';
import theme from './util/Theme';
import {AuthContext} from 'react-oauth2-code-pkce';
Expand All @@ -63,6 +70,8 @@ export const DataContext = createContext<{
selectedSimulationModel: Model | undefined;
parameterDefinitions: Record<string, ParameterDefinition> | undefined;
compartments: Compartments | undefined;
npis: InterventionTemplates | undefined;
nodeLists: NodeLists | undefined;
}>({
geoData: undefined,
mapData: undefined,
Expand All @@ -79,6 +88,8 @@ export const DataContext = createContext<{
selectedSimulationModel: undefined,
parameterDefinitions: undefined,
compartments: undefined,
npis: undefined,
nodeLists: undefined,
});

// Create a provider component
Expand All @@ -105,8 +116,26 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => {

const {data: scenarios} = useGetScenariosQuery();
const {data: compartments} = useGetCompartmentsQuery();
const {data: npis} = useGetInterventionTemplatesQuery();
const {data: nodeLists} = useGetNodeListsQuery();

const caseDataId = scenarios?.find((scenario) => scenario.name === 'caseData')?.id;
useEffect(() => {
if (scenarios) {
for (const [id, _] of Object.entries(scenariosState)) {
if (!scenarios.find((s) => s.id === id)) {
dispatch(removeScenario(id));
}
}

for (const scenario of scenarios) {
if (!scenariosState[scenario.id]) {
dispatch(addScenario({id: scenario.id, state: {shown: false, active: false, colors: []}}));
}
}
}
}, [dispatch, scenarios, scenariosState]);

const caseDataId = scenarios?.find((scenario) => scenario.name === 'casedata')?.id;
const {data: caseDataScenario} = useGetScenarioQuery(caseDataId!, {skip: !caseDataId});

const {data: referenceDateValues} = useGetScenarioInfectionDataQuery(
Expand Down Expand Up @@ -181,15 +210,18 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => {
}
);

const {data: mapData} = useGetScenarioInfectionDataQuery({
path: {scenarioId: selectedScenario!},
query: {
startDate: selectedDate!,
endDate: selectedDate!,
percentiles: ['50'],
compartments: [selectedCompartment!],
const {data: mapData} = useGetScenarioInfectionDataQuery(
{
path: {scenarioId: selectedScenario!},
query: {
startDate: selectedDate!,
endDate: selectedDate!,
percentiles: ['50'],
compartments: [selectedCompartment!],
},
},
});
{skip: !selectedScenario || !selectedDate || !selectedCompartment}
);

const {data: selectedScenarioData} = useGetScenarioQuery(selectedScenario!, {skip: !selectedScenario});
const {data: simulationModels} = useGetModelsQuery();
Expand All @@ -206,6 +238,7 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => {
// Try to set at least one active scenario.
useEffect(() => {
if (activeScenarios?.length === 0 && caseDataScenario) {
dispatch(showScenario(caseDataScenario.id));
dispatch(setActiveScenario({id: caseDataScenario.id, state: true}));
}
}, [activeScenarios, caseDataScenario, dispatch]);
Expand Down Expand Up @@ -340,6 +373,8 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => {
selectedSimulationModel,
parameterDefinitions,
compartments,
npis,
nodeLists,
}),
[
geoData,
Expand All @@ -357,6 +392,8 @@ export const DataProvider = ({children}: {children: React.ReactNode}) => {
selectedSimulationModel,
parameterDefinitions,
compartments,
npis,
nodeLists,
]
)}
>
Expand Down
8 changes: 3 additions & 5 deletions frontend/src/components/ParameterEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2024 German Aerospace Center (DLR)
// SPDX-License-Identifier: Apache-2.0

import React, {useCallback, useContext, useMemo, useState} from 'react';
import React, {useCallback, useContext, useMemo} from 'react';
import TableContainer from '@mui/material/TableContainer';
import Table from '@mui/material/Table';
import TableHead from '@mui/material/TableHead';
Expand Down Expand Up @@ -36,8 +36,6 @@ export default function ParameterEditor() {
const {t: tBackend} = useTranslation('backend');
const theme = useTheme();

const [scenarioId] = useState<number | null>(null);

const {selectedSimulationModel, selectedScenarioData, groups, parameterDefinitions} = useContext(DataContext);

const parameters: Array<ParameterData> = useMemo(() => {
Expand Down Expand Up @@ -84,15 +82,15 @@ export default function ParameterEditor() {
if (group) {
return {
id: groupId,
name: tBackend(`groups.${group.name}`),
name: tBackend(`group-filters.groups.${group.name}`),
};
}
return [];
}) ?? []
);
}, [groups, selectedSimulationModel?.groups, tBackend]);

if (scenarioId !== null) {
if (parameters.length > 0) {
return (
<TableContainer sx={{background: theme.palette.background.paper, height: '100%'}} id='table-container'>
<Table stickyHeader size='small' sx={{position: 'relative'}}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface CardContainerProps {

/** A dictionary of card values. Each value is an object containing 'startValues', a dictionary used for rate calculation, and 'compartmentValues' for each card.
*'startValues' help determine whether the values have increased, decreased, or remained the same. */
cardValues: Record<string, Record<string, number>> | undefined;
cardValues: Record<string, Record<string, number | null>> | undefined;

referenceValues: Record<string, number> | undefined;

Expand All @@ -26,10 +26,7 @@ interface CardContainerProps {
selectedCompartmentId: string | null;

/** An array of scenarios. */
scenarios: Array<{id: string; name: string; color: string}>;

/** An array of active scenarios. */
activeScenarios: string[];
scenarios: Array<{id: string; name: string; color: string; active: boolean}>;

/** A function to set the active scenarios. */
setActiveScenario: Dispatch<{id: string; state: boolean}>;
Expand All @@ -40,6 +37,8 @@ interface CardContainerProps {
/** A function to set the selected scenario. */
setSelectedScenario: Dispatch<{id: string; state: boolean}>;

hide: Dispatch<string>;

/** The minimum number of compartment rows. */
minCompartmentsRows: number;

Expand All @@ -65,12 +64,12 @@ export default function CardContainer({
filterValues,
selectedCompartmentId,
scenarios,
activeScenarios,
cardValues,
referenceValues,
minCompartmentsRows,
maxCompartmentsRows,
setActiveScenario,
hide,
localization = {
formatNumber: (value: number) => value.toString(),
customLang: 'global',
Expand Down Expand Up @@ -112,9 +111,10 @@ export default function CardContainer({
selectedCompartmentId={selectedCompartmentId}
filterValues={filterValues}
isSelected={selectedScenario === scenario.id}
isActive={activeScenarios.includes(scenario.id)}
isActive={scenario.active}
setSelected={setSelectedScenario}
setActive={setActiveScenario}
hide={hide}
minCompartmentsRows={minCompartmentsRows}
maxCompartmentsRows={maxCompartmentsRows}
localization={localization}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface DataCardProps {
id: string;

/** A dictionary of compartment values associated with the card.*/
compartmentValues: Record<string, number> | null;
compartmentValues: Record<string, number | null> | null;

/** A dictionary of start values used for calculating the rate. This determines whether the values have increased, decreased, or remained the same. */
referenceValues: Record<string, number> | null;
Expand Down Expand Up @@ -47,6 +47,8 @@ interface DataCardProps {
/** A function to set the active scenario.*/
setActive: Dispatch<{id: string; state: boolean}>;

hide: Dispatch<string>;

/** The minimum number of compartment rows.*/
minCompartmentsRows: number;

Expand Down Expand Up @@ -83,6 +85,7 @@ export default function DataCard({
maxCompartmentsRows,
setSelected,
setActive,
hide,
localization = {
formatNumber: (value: number) => value.toString(),
customLang: 'global',
Expand Down Expand Up @@ -149,6 +152,7 @@ export default function DataCard({
isActive={isActive}
setSelected={setSelected}
setActive={setActive}
hide={hide}
minCompartmentsRows={minCompartmentsRows}
maxCompartmentsRows={maxCompartmentsRows}
localization={localization}
Expand Down
Loading

0 comments on commit 40fc16e

Please sign in to comment.