From 31c169169f8ae626ff1b63ea7e6edb55cfcbb916 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 19 Jan 2023 16:44:19 +0100
Subject: [PATCH 01/18] WIP
---
.../create-image-template-modal.component.ts | 1 +
.../send-alarm-group-interface.component.ts | 2 +-
.../transfer-overview-table.component.html | 4 +-
.../transfer-target-input.component.ts | 2 +-
.../transfer-time-input.component.ts | 2 +-
shared/src/models/alarm-group.ts | 4 ++
shared/src/models/client.ts | 5 +-
shared/src/models/eoc-log-entry.ts | 4 ++
shared/src/models/exercise-configuration.ts | 4 ++
shared/src/models/hospital-patient.ts | 5 +-
shared/src/models/hospital.ts | 5 +-
shared/src/models/map-image-template.ts | 4 ++
shared/src/models/map-image.ts | 4 ++
shared/src/models/material-template.ts | 5 +-
shared/src/models/material.ts | 5 +-
shared/src/models/patient-category.ts | 4 ++
shared/src/models/patient-health-state.ts | 4 ++
shared/src/models/patient-template.ts | 5 +-
shared/src/models/patient.ts | 10 +++-
shared/src/models/personnel-template.ts | 5 +-
shared/src/models/personnel.ts | 5 +-
shared/src/models/simulated-region.ts | 4 ++
shared/src/models/transfer-point.ts | 9 +++-
shared/src/models/vehicle-template.ts | 5 +-
shared/src/models/vehicle.ts | 5 +-
shared/src/models/viewport.ts | 4 ++
.../create-vehicle-parameters.ts | 1 +
shared/src/state.ts | 4 +-
.../src/store/action-reducers/alarm-group.ts | 10 ++--
shared/src/store/action-reducers/client.ts | 8 +--
shared/src/store/action-reducers/exercise.ts | 15 ++++--
shared/src/store/action-reducers/hospital.ts | 20 +++-----
.../src/store/action-reducers/map-images.ts | 16 +++---
shared/src/store/action-reducers/material.ts | 2 +-
shared/src/store/action-reducers/patient.ts | 10 ++--
.../store/action-reducers/simulated-region.ts | 8 +--
.../store/action-reducers/transfer-point.ts | 26 +++++-----
shared/src/store/action-reducers/transfer.ts | 14 +++---
.../utils/calculate-treatments.ts | 49 ++++++-------------
.../action-reducers/utils/get-element.ts | 21 +++-----
.../action-reducers/utils/spatial-elements.ts | 18 +++++--
shared/src/store/action-reducers/vehicle.ts | 35 ++++++-------
shared/src/store/action-reducers/viewport.ts | 8 +--
shared/src/utils/type-state-selector-map.ts | 15 ++++++
44 files changed, 234 insertions(+), 162 deletions(-)
create mode 100644 shared/src/utils/type-state-selector-map.ts
diff --git a/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts b/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts
index 11a6aead7..134360443 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts
@@ -35,6 +35,7 @@ export class CreateImageTemplateModalComponent {
type: '[MapImageTemplate] Add mapImageTemplate',
mapImageTemplate: {
id: uuid(),
+ type: 'mapImageTemplate',
image: {
url,
height,
diff --git a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts
index ef6929b26..61cb4b21b 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts
@@ -106,7 +106,7 @@ export class SendAlarmGroupInterfaceComponent implements OnDestroy {
}),
this.exerciseService.proposeAction({
type: '[Transfer] Add to transfer',
- elementType: 'vehicles',
+ elementType: 'vehicle',
elementId: vehicleParameters.vehicle.id,
startPoint: AlarmGroupStartPoint.create(
alarmGroup.name,
diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html
index b17308b0d..4d592c856 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html
+++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html
@@ -42,14 +42,14 @@
|
diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts
index 2bd0ab98f..dd84fa34e 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts
@@ -11,7 +11,7 @@ import { selectTransferPoints } from 'src/app/state/application/selectors/exerci
styleUrls: ['./transfer-target-input.component.scss'],
})
export class TransferTargetInputComponent {
- @Input() elementType!: 'personnel' | 'vehicles';
+ @Input() elementType!: 'personnel' | 'vehicle';
@Input() elementId!: UUID;
@Input() transfer!: Transfer;
diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts
index 011a25963..f01016989 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts
@@ -11,7 +11,7 @@ import { selectCurrentTime } from 'src/app/state/application/selectors/exercise.
styleUrls: ['./transfer-time-input.component.scss'],
})
export class TransferTimeInputComponent {
- @Input() elementType!: 'personnel' | 'vehicles';
+ @Input() elementType!: 'personnel' | 'vehicle';
@Input() elementId!: UUID;
diff --git a/shared/src/models/alarm-group.ts b/shared/src/models/alarm-group.ts
index 3d4d58d72..2d6ed8dc1 100644
--- a/shared/src/models/alarm-group.ts
+++ b/shared/src/models/alarm-group.ts
@@ -1,5 +1,6 @@
import { IsString, IsUUID } from 'class-validator';
import { UUID, uuid, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { IsIdMap } from '../utils/validators/is-id-map';
import { getCreate } from './utils';
import { AlarmGroupVehicle } from './utils/alarm-group-vehicle';
@@ -8,6 +9,9 @@ export class AlarmGroup {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('alarmGroup' as const)
+ public readonly type = 'alarmGroup';
+
@IsString()
public readonly name: string;
diff --git a/shared/src/models/client.ts b/shared/src/models/client.ts
index aac8ec2eb..ae42a3546 100644
--- a/shared/src/models/client.ts
+++ b/shared/src/models/client.ts
@@ -6,7 +6,7 @@ import {
MaxLength,
} from 'class-validator';
import { UUID, uuid, uuidValidationOptions } from '../utils';
-import { IsLiteralUnion } from '../utils/validators';
+import { IsLiteralUnion, IsValue } from '../utils/validators';
import { getCreate, Role } from './utils';
import { roleAllowedValues } from './utils/role';
@@ -14,6 +14,9 @@ export class Client {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('client' as const)
+ public readonly type = 'client';
+
@IsString()
// Required by database
@MaxLength(255)
diff --git a/shared/src/models/eoc-log-entry.ts b/shared/src/models/eoc-log-entry.ts
index f6b7c0113..ed83508e9 100644
--- a/shared/src/models/eoc-log-entry.ts
+++ b/shared/src/models/eoc-log-entry.ts
@@ -1,11 +1,15 @@
import { IsInt, IsString, IsUUID, MaxLength } from 'class-validator';
import { UUID, uuid, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { getCreate } from './utils';
export class EocLogEntry {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('eocLogEntry' as const)
+ public readonly type = 'eocLogEntry';
+
/**
* The time in the exercise
*/
diff --git a/shared/src/models/exercise-configuration.ts b/shared/src/models/exercise-configuration.ts
index 9899cdc3d..dce59e0a9 100644
--- a/shared/src/models/exercise-configuration.ts
+++ b/shared/src/models/exercise-configuration.ts
@@ -1,9 +1,13 @@
import { Type } from 'class-transformer';
import { IsBoolean, ValidateNested } from 'class-validator';
import { defaultTileMapProperties } from '../data';
+import { IsValue } from '../utils/validators';
import { getCreate, TileMapProperties } from './utils';
export class ExerciseConfiguration {
+ @IsValue('exerciseConfiguration' as const)
+ public readonly type = 'exerciseConfiguration';
+
@IsBoolean()
public readonly pretriageEnabled: boolean = true;
@IsBoolean()
diff --git a/shared/src/models/hospital-patient.ts b/shared/src/models/hospital-patient.ts
index b9aa4655f..17a2588ac 100644
--- a/shared/src/models/hospital-patient.ts
+++ b/shared/src/models/hospital-patient.ts
@@ -8,7 +8,7 @@ import {
} from 'class-validator';
import type { Mutable } from '../utils';
import { cloneDeepMutable, UUID, uuidValidationOptions } from '../utils';
-import { IsIdMap, IsLiteralUnion } from '../utils/validators';
+import { IsIdMap, IsLiteralUnion, IsValue } from '../utils/validators';
import {
getCreate,
HealthPoints,
@@ -29,6 +29,9 @@ export class HospitalPatient {
@IsUUID(4, uuidValidationOptions)
public readonly patientId: UUID;
+ @IsValue('hospitalPatient' as const)
+ public readonly type = 'hospitalPatient';
+
/**
* the vehicle that a patient was transported with
*/
diff --git a/shared/src/models/hospital.ts b/shared/src/models/hospital.ts
index 80797693a..528e35c83 100644
--- a/shared/src/models/hospital.ts
+++ b/shared/src/models/hospital.ts
@@ -1,12 +1,15 @@
import { IsNumber, IsString, IsUUID, Min } from 'class-validator';
import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils';
-import { IsUUIDSet } from '../utils/validators';
+import { IsUUIDSet, IsValue } from '../utils/validators';
import { getCreate } from './utils';
export class Hospital {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('hospital' as const)
+ public readonly type = 'hospital';
+
@IsString()
public readonly name: string;
diff --git a/shared/src/models/map-image-template.ts b/shared/src/models/map-image-template.ts
index c701df501..9a2f4ab90 100644
--- a/shared/src/models/map-image-template.ts
+++ b/shared/src/models/map-image-template.ts
@@ -1,12 +1,16 @@
import { Type } from 'class-transformer';
import { IsString, IsUUID, ValidateNested } from 'class-validator';
import { UUID, uuid, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { getCreate, ImageProperties } from './utils';
export class MapImageTemplate {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('mapImageTemplate' as const)
+ public readonly type = 'mapImageTemplate';
+
@IsString()
public readonly name: string;
diff --git a/shared/src/models/map-image.ts b/shared/src/models/map-image.ts
index 6dc0c3e46..ad15022a7 100644
--- a/shared/src/models/map-image.ts
+++ b/shared/src/models/map-image.ts
@@ -1,12 +1,16 @@
import { Type } from 'class-transformer';
import { IsBoolean, IsInt, IsUUID, ValidateNested } from 'class-validator';
import { uuid, UUID, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { Position, getCreate, ImageProperties } from './utils';
export class MapImage {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('mapImage' as const)
+ public readonly type = 'mapImage';
+
@ValidateNested()
@Type(() => Position)
public readonly position: Position;
diff --git a/shared/src/models/material-template.ts b/shared/src/models/material-template.ts
index 95f6ba6ec..39b45da3e 100644
--- a/shared/src/models/material-template.ts
+++ b/shared/src/models/material-template.ts
@@ -1,11 +1,14 @@
import { Type } from 'class-transformer';
import { IsNumber, Max, Min, ValidateNested } from 'class-validator';
import { maxTreatmentRange } from '../state-helpers/max-treatment-range';
-import { IsLiteralUnion } from '../utils/validators';
+import { IsLiteralUnion, IsValue } from '../utils/validators';
import { CanCaterFor, getCreate, ImageProperties } from './utils';
import { MaterialType, materialTypeAllowedValues } from './utils/material-type';
export class MaterialTemplate {
+ @IsValue('materialTemplate' as const)
+ public readonly type = 'materialTemplate';
+
@IsLiteralUnion(materialTypeAllowedValues)
public readonly materialType: MaterialType;
diff --git a/shared/src/models/material.ts b/shared/src/models/material.ts
index e82ab1ed0..5059705b3 100644
--- a/shared/src/models/material.ts
+++ b/shared/src/models/material.ts
@@ -10,7 +10,7 @@ import {
} from 'class-validator';
import { maxTreatmentRange } from '../state-helpers/max-treatment-range';
import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils';
-import { IsUUIDSet } from '../utils/validators';
+import { IsUUIDSet, IsValue } from '../utils/validators';
import type { MaterialTemplate } from './material-template';
import { CanCaterFor, Position, ImageProperties, getCreate } from './utils';
@@ -18,6 +18,9 @@ export class Material {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('material' as const)
+ public readonly type = 'material';
+
@IsUUID(4, uuidValidationOptions)
public readonly vehicleId: UUID;
diff --git a/shared/src/models/patient-category.ts b/shared/src/models/patient-category.ts
index 6b9d8b683..d6161453c 100644
--- a/shared/src/models/patient-category.ts
+++ b/shared/src/models/patient-category.ts
@@ -1,10 +1,14 @@
import { Type } from 'class-transformer';
import { ArrayNotEmpty, IsArray, ValidateNested } from 'class-validator';
+import { IsValue } from '../utils/validators';
import { PatientTemplate } from './patient-template';
import { getCreate, ImageProperties } from './utils';
import { PatientStatusCode } from './utils/patient-status-code';
export class PatientCategory {
+ @IsValue('patientCategory' as const)
+ public readonly type = 'patientCategory';
+
@ValidateNested()
@Type(() => PatientStatusCode)
public readonly name: PatientStatusCode;
diff --git a/shared/src/models/patient-health-state.ts b/shared/src/models/patient-health-state.ts
index 60810920e..9e04c85ea 100644
--- a/shared/src/models/patient-health-state.ts
+++ b/shared/src/models/patient-health-state.ts
@@ -7,6 +7,7 @@ import {
ValidateNested,
} from 'class-validator';
import { uuid, UUID, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { getCreate, HealthPoints, IsValidHealthPoint } from './utils';
/**
@@ -109,6 +110,9 @@ export class PatientHealthState {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('patientHealthState' as const)
+ public readonly type = 'patientHealthState';
+
@Type(() => FunctionParameters)
@ValidateNested()
public readonly functionParameters: FunctionParameters;
diff --git a/shared/src/models/patient-template.ts b/shared/src/models/patient-template.ts
index 65e319f09..63a785757 100644
--- a/shared/src/models/patient-template.ts
+++ b/shared/src/models/patient-template.ts
@@ -1,7 +1,7 @@
import { Type } from 'class-transformer';
import { IsUUID, ValidateNested } from 'class-validator';
import { cloneDeepMutable, UUID, uuid, uuidValidationOptions } from '../utils';
-import { IsIdMap } from '../utils/validators';
+import { IsIdMap, IsValue } from '../utils/validators';
import type { PatientStatusCode } from './utils';
import {
BiometricInformation,
@@ -21,6 +21,9 @@ export class PatientTemplate {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('patientTemplate' as const)
+ public readonly type = 'patientTemplate';
+
@ValidateNested()
@Type(() => BiometricInformation)
public readonly biometricInformation: BiometricInformation;
diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts
index 19423c02d..0e33f4850 100644
--- a/shared/src/models/patient.ts
+++ b/shared/src/models/patient.ts
@@ -12,7 +12,12 @@ import {
isEmpty,
} from 'class-validator';
import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils';
-import { IsLiteralUnion, IsIdMap, IsUUIDSet } from '../utils/validators';
+import {
+ IsLiteralUnion,
+ IsIdMap,
+ IsUUIDSet,
+ IsValue,
+} from '../utils/validators';
import { PatientHealthState } from './patient-health-state';
import {
BiometricInformation,
@@ -32,6 +37,9 @@ export class Patient {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('patient')
+ public readonly type = 'patient';
+
@ValidateNested()
@Type(() => PersonalInformation)
public readonly personalInformation: PersonalInformation;
diff --git a/shared/src/models/personnel-template.ts b/shared/src/models/personnel-template.ts
index ccc06782a..fc3e3c101 100644
--- a/shared/src/models/personnel-template.ts
+++ b/shared/src/models/personnel-template.ts
@@ -1,7 +1,7 @@
import { Type } from 'class-transformer';
import { IsNumber, Max, Min, ValidateNested } from 'class-validator';
import { maxTreatmentRange } from '../state-helpers/max-treatment-range';
-import { IsLiteralUnion } from '../utils/validators';
+import { IsLiteralUnion, IsValue } from '../utils/validators';
import {
PersonnelType,
CanCaterFor,
@@ -12,6 +12,9 @@ import { personnelTypeAllowedValues } from './utils/personnel-type';
// TODO: These are not (yet) saved in the state -> Decide whether they should and if not move this file from the models folder away
export class PersonnelTemplate {
+ @IsValue('personnelTemplate' as const)
+ public readonly type = 'personnelTemplate';
+
@IsLiteralUnion(personnelTypeAllowedValues)
public readonly personnelType: PersonnelType;
diff --git a/shared/src/models/personnel.ts b/shared/src/models/personnel.ts
index afe24d0e4..b5dbd2430 100644
--- a/shared/src/models/personnel.ts
+++ b/shared/src/models/personnel.ts
@@ -10,7 +10,7 @@ import {
} from 'class-validator';
import { maxTreatmentRange } from '../state-helpers/max-treatment-range';
import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils';
-import { IsLiteralUnion, IsUUIDSet } from '../utils/validators';
+import { IsLiteralUnion, IsUUIDSet, IsValue } from '../utils/validators';
import type { PersonnelTemplate } from './personnel-template';
import {
PersonnelType,
@@ -26,6 +26,9 @@ export class Personnel {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('personnel' as const)
+ public readonly type = 'personnel';
+
@IsUUID(4, uuidValidationOptions)
public readonly vehicleId: UUID;
diff --git a/shared/src/models/simulated-region.ts b/shared/src/models/simulated-region.ts
index 6e3db79a4..8d4f47cc4 100644
--- a/shared/src/models/simulated-region.ts
+++ b/shared/src/models/simulated-region.ts
@@ -1,6 +1,7 @@
import { Type } from 'class-transformer';
import { IsString, IsUUID, ValidateNested } from 'class-validator';
import { UUID, uuid, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { getCreate, Position, Size } from './utils';
import type { ImageProperties } from './utils';
@@ -8,6 +9,9 @@ export class SimulatedRegion {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('simulatedRegion' as const)
+ public readonly type = 'simulatedRegion';
+
/**
* top-left position
*/
diff --git a/shared/src/models/transfer-point.ts b/shared/src/models/transfer-point.ts
index b825b36be..5aa895ca5 100644
--- a/shared/src/models/transfer-point.ts
+++ b/shared/src/models/transfer-point.ts
@@ -1,7 +1,11 @@
import { Type } from 'class-transformer';
import { IsString, IsUUID, ValidateNested } from 'class-validator';
import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils';
-import { IsReachableTransferPoints, IsUUIDSet } from '../utils/validators';
+import {
+ IsReachableTransferPoints,
+ IsUUIDSet,
+ IsValue,
+} from '../utils/validators';
import type { ImageProperties } from './utils';
import { getCreate, Position } from './utils';
@@ -9,6 +13,9 @@ export class TransferPoint {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('transferPoint' as const)
+ public readonly type = 'transferPoint';
+
@ValidateNested()
@Type(() => Position)
public readonly position: Position;
diff --git a/shared/src/models/vehicle-template.ts b/shared/src/models/vehicle-template.ts
index f0dd3157b..c2956dd40 100644
--- a/shared/src/models/vehicle-template.ts
+++ b/shared/src/models/vehicle-template.ts
@@ -7,7 +7,7 @@ import {
IsArray,
} from 'class-validator';
import { uuidValidationOptions, UUID, uuid } from '../utils';
-import { IsLiteralUnion } from '../utils/validators';
+import { IsLiteralUnion, IsValue } from '../utils/validators';
import type { PersonnelType } from './utils';
import {
ImageProperties,
@@ -21,6 +21,9 @@ export class VehicleTemplate {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('vehicleTemplate' as const)
+ public readonly type = 'vehicleTemplate';
+
@IsString()
public readonly vehicleType: string;
diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts
index 95141b20b..abad33a37 100644
--- a/shared/src/models/vehicle.ts
+++ b/shared/src/models/vehicle.ts
@@ -7,7 +7,7 @@ import {
ValidateNested,
} from 'class-validator';
import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils';
-import { IsUUIDSet } from '../utils/validators';
+import { IsUUIDSet, IsValue } from '../utils/validators';
import { getCreate, Position, Transfer } from './utils';
import { ImageProperties } from './utils/image-properties';
@@ -15,6 +15,9 @@ export class Vehicle {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('vehicle' as const)
+ public readonly type = 'vehicle';
+
@IsString()
public readonly vehicleType: string;
diff --git a/shared/src/models/viewport.ts b/shared/src/models/viewport.ts
index fc31482b7..4a147e472 100644
--- a/shared/src/models/viewport.ts
+++ b/shared/src/models/viewport.ts
@@ -1,6 +1,7 @@
import { Type } from 'class-transformer';
import { IsString, IsUUID, ValidateNested } from 'class-validator';
import { UUID, uuid, uuidValidationOptions } from '../utils';
+import { IsValue } from '../utils/validators';
import { getCreate, Position, Size } from './utils';
import type { ImageProperties } from './utils';
@@ -8,6 +9,9 @@ export class Viewport {
@IsUUID(4, uuidValidationOptions)
public readonly id: UUID = uuid();
+ @IsValue('viewport' as const)
+ public readonly type = 'viewport';
+
/**
* top-left position
*/
diff --git a/shared/src/state-helpers/create-vehicle-parameters.ts b/shared/src/state-helpers/create-vehicle-parameters.ts
index d4d9951ad..cfda5766d 100644
--- a/shared/src/state-helpers/create-vehicle-parameters.ts
+++ b/shared/src/state-helpers/create-vehicle-parameters.ts
@@ -44,6 +44,7 @@ export function createVehicleParameters(
const vehicle: Vehicle = {
id: vehicleId,
+ type: 'vehicle',
materialIds: arrayToUUIDSet(materials.map((m) => m.id)),
vehicleType: vehicleTemplate.vehicleType,
name: vehicleTemplate.name,
diff --git a/shared/src/state.ts b/shared/src/state.ts
index ab27ab0db..9071494cd 100644
--- a/shared/src/state.ts
+++ b/shared/src/state.ts
@@ -44,7 +44,7 @@ import {
SpatialTree,
} from './models/utils';
import type { MaterialType } from './models/utils/material-type';
-import type { SpatialElementType } from './store/action-reducers/utils/spatial-elements';
+import type { SpatialElementSelector } from './store/action-reducers/utils/spatial-elements';
import type { UUID } from './utils';
import { uuid, uuidValidationOptions } from './utils';
import { IsIdMap, IsLiteralUnion } from './utils/validators';
@@ -123,7 +123,7 @@ export class ExerciseState {
// Mutable` could still have immutable objects in spatialTree
@IsObject()
public readonly spatialTrees: {
- [type in SpatialElementType]: SpatialTree;
+ [type in SpatialElementSelector]: SpatialTree;
} = {
materials: SpatialTree.create(),
patients: SpatialTree.create(),
diff --git a/shared/src/store/action-reducers/alarm-group.ts b/shared/src/store/action-reducers/alarm-group.ts
index 598c30c63..cf4d3cead 100644
--- a/shared/src/store/action-reducers/alarm-group.ts
+++ b/shared/src/store/action-reducers/alarm-group.ts
@@ -96,7 +96,7 @@ export namespace AlarmGroupActionReducers {
reducer: (draftState, { alarmGroupId, name }) => {
const alarmGroup = getElement(
draftState,
- 'alarmGroups',
+ 'alarmGroup',
alarmGroupId
);
alarmGroup.name = name;
@@ -108,7 +108,7 @@ export namespace AlarmGroupActionReducers {
export const removeAlarmGroup: ActionReducer = {
action: RemoveAlarmGroupAction,
reducer: (draftState, { alarmGroupId }) => {
- getElement(draftState, 'alarmGroups', alarmGroupId);
+ getElement(draftState, 'alarmGroup', alarmGroupId);
delete draftState.alarmGroups[alarmGroupId];
return draftState;
},
@@ -121,7 +121,7 @@ export namespace AlarmGroupActionReducers {
reducer: (draftState, { alarmGroupId, alarmGroupVehicle }) => {
const alarmGroup = getElement(
draftState,
- 'alarmGroups',
+ 'alarmGroup',
alarmGroupId
);
alarmGroup.alarmGroupVehicles[alarmGroupVehicle.id] =
@@ -140,7 +140,7 @@ export namespace AlarmGroupActionReducers {
) => {
const alarmGroup = getElement(
draftState,
- 'alarmGroups',
+ 'alarmGroup',
alarmGroupId
);
const alarmGroupVehicle = getAlarmGroupVehicle(
@@ -160,7 +160,7 @@ export namespace AlarmGroupActionReducers {
reducer: (draftState, { alarmGroupId, alarmGroupVehicleId }) => {
const alarmGroup = getElement(
draftState,
- 'alarmGroups',
+ 'alarmGroup',
alarmGroupId
);
getAlarmGroupVehicle(alarmGroup, alarmGroupVehicleId);
diff --git a/shared/src/store/action-reducers/client.ts b/shared/src/store/action-reducers/client.ts
index 5c1438f22..55208470e 100644
--- a/shared/src/store/action-reducers/client.ts
+++ b/shared/src/store/action-reducers/client.ts
@@ -53,7 +53,7 @@ export namespace ClientActionReducers {
export const removeClient: ActionReducer = {
action: RemoveClientAction,
reducer: (draftState, { clientId }) => {
- getElement(draftState, 'clients', clientId);
+ getElement(draftState, 'client', clientId);
delete draftState.clients[clientId];
return draftState;
},
@@ -64,12 +64,12 @@ export namespace ClientActionReducers {
{
action: RestrictViewToViewportAction,
reducer: (draftState, { clientId, viewportId }) => {
- const client = getElement(draftState, 'clients', clientId);
+ const client = getElement(draftState, 'client', clientId);
if (viewportId === undefined) {
client.viewRestrictedToViewportId = viewportId;
return draftState;
}
- getElement(draftState, 'viewports', viewportId);
+ getElement(draftState, 'viewport', viewportId);
client.viewRestrictedToViewportId = viewportId;
return draftState;
},
@@ -79,7 +79,7 @@ export namespace ClientActionReducers {
export const setWaitingRoom: ActionReducer = {
action: SetWaitingRoomAction,
reducer: (draftState, { clientId, shouldBeInWaitingRoom }) => {
- const client = getElement(draftState, 'clients', clientId);
+ const client = getElement(draftState, 'client', clientId);
client.isInWaitingRoom = shouldBeInWaitingRoom;
return draftState;
},
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index 55a1fbba3..b2a7c0918 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -11,6 +11,7 @@ import { Patient } from '../../models';
import { getStatus } from '../../models/utils';
import type { ExerciseState } from '../../state';
import type { Mutable } from '../../utils';
+import { typeSelectorMap } from '../../utils/type-state-selector-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
@@ -122,7 +123,7 @@ export namespace ExerciseActionReducers {
});
// Refresh transfers
- refreshTransfer(draftState, 'vehicles', tickInterval);
+ refreshTransfer(draftState, 'vehicle', tickInterval);
refreshTransfer(draftState, 'personnel', tickInterval);
return draftState;
},
@@ -130,12 +131,18 @@ export namespace ExerciseActionReducers {
};
}
+const transferTypeSelectorMap = {
+ personnel: typeSelectorMap.personnel,
+ vehicle: typeSelectorMap.vehicle,
+} as const;
+type TransferTypeSelectorMap = typeof transferTypeSelectorMap;
+
function refreshTransfer(
draftState: Mutable,
- key: 'personnel' | 'vehicles',
+ type: keyof TransferTypeSelectorMap,
tickInterval: number
): void {
- const elements = draftState[key];
+ const elements = draftState[transferTypeSelectorMap[type]];
Object.values(elements).forEach((element: Mutable) => {
if (!element.transfer) {
return;
@@ -148,6 +155,6 @@ function refreshTransfer(
if (element.transfer.endTimeStamp > draftState.currentTime) {
return;
}
- letElementArrive(draftState, key, element.id);
+ letElementArrive(draftState, type, element.id);
});
}
diff --git a/shared/src/store/action-reducers/hospital.ts b/shared/src/store/action-reducers/hospital.ts
index 0f2214691..b5bb8e559 100644
--- a/shared/src/store/action-reducers/hospital.ts
+++ b/shared/src/store/action-reducers/hospital.ts
@@ -74,11 +74,7 @@ export namespace HospitalActionReducers {
{
action: EditTransportDurationToHospitalAction,
reducer: (draftState, { hospitalId, transportDuration }) => {
- const hospital = getElement(
- draftState,
- 'hospitals',
- hospitalId
- );
+ const hospital = getElement(draftState, 'hospital', hospitalId);
hospital.transportDuration = transportDuration;
return draftState;
},
@@ -88,7 +84,7 @@ export namespace HospitalActionReducers {
export const renameHospital: ActionReducer = {
action: RenameHospitalAction,
reducer: (draftState, { hospitalId, name }) => {
- const hospital = getElement(draftState, 'hospitals', hospitalId);
+ const hospital = getElement(draftState, 'hospital', hospitalId);
hospital.name = name;
return draftState;
},
@@ -98,7 +94,7 @@ export namespace HospitalActionReducers {
export const removeHospital: ActionReducer = {
action: RemoveHospitalAction,
reducer: (draftState, { hospitalId }) => {
- const hospital = getElement(draftState, 'hospitals', hospitalId);
+ const hospital = getElement(draftState, 'hospital', hospitalId);
// TODO: maybe make a hospital undeletable (if at least one patient is in it)
for (const patientId of Object.keys(hospital.patientIds)) {
delete draftState.hospitalPatients[patientId];
@@ -118,17 +114,13 @@ export namespace HospitalActionReducers {
{
action: TransportPatientToHospitalAction,
reducer: (draftState, { hospitalId, vehicleId }) => {
- const hospital = getElement(
- draftState,
- 'hospitals',
- hospitalId
- );
- const vehicle = getElement(draftState, 'vehicles', vehicleId);
+ const hospital = getElement(draftState, 'hospital', hospitalId);
+ const vehicle = getElement(draftState, 'vehicle', vehicleId);
// TODO: Block vehicles whose material and personnel are unloaded
for (const patientId of Object.keys(vehicle.patientIds)) {
const patient = getElement(
draftState,
- 'patients',
+ 'patient',
patientId
);
draftState.hospitalPatients[patientId] =
diff --git a/shared/src/store/action-reducers/map-images.ts b/shared/src/store/action-reducers/map-images.ts
index 26bce6329..7384033ff 100644
--- a/shared/src/store/action-reducers/map-images.ts
+++ b/shared/src/store/action-reducers/map-images.ts
@@ -133,7 +133,7 @@ export namespace MapImagesActionReducers {
export const moveMapImage: ActionReducer = {
action: MoveMapImageAction,
reducer: (draftState, { mapImageId, targetPosition }) => {
- const mapImage = getElement(draftState, 'mapImages', mapImageId);
+ const mapImage = getElement(draftState, 'mapImage', mapImageId);
mapImage.position = cloneDeepMutable(targetPosition);
return draftState;
},
@@ -143,7 +143,7 @@ export namespace MapImagesActionReducers {
export const scaleMapImage: ActionReducer = {
action: ScaleMapImageAction,
reducer: (draftState, { mapImageId, newHeight, newAspectRatio }) => {
- const mapImage = getElement(draftState, 'mapImages', mapImageId);
+ const mapImage = getElement(draftState, 'mapImage', mapImageId);
if (newHeight) {
mapImage.image.height = newHeight;
}
@@ -158,7 +158,7 @@ export namespace MapImagesActionReducers {
export const removeMapImage: ActionReducer = {
action: RemoveMapImageAction,
reducer: (draftState, { mapImageId }) => {
- getElement(draftState, 'mapImages', mapImageId);
+ getElement(draftState, 'mapImage', mapImageId);
delete draftState.mapImages[mapImageId];
return draftState;
},
@@ -169,11 +169,7 @@ export namespace MapImagesActionReducers {
{
action: ReconfigureMapImageUrlAction,
reducer: (draftState, { mapImageId, newUrl }) => {
- const mapImage = getElement(
- draftState,
- 'mapImages',
- mapImageId
- );
+ const mapImage = getElement(draftState, 'mapImage', mapImageId);
mapImage.image.url = newUrl;
return draftState;
},
@@ -183,7 +179,7 @@ export namespace MapImagesActionReducers {
export const setLockedMapImage: ActionReducer = {
action: SetIsLockedMapImageAction,
reducer: (draftState, { mapImageId, newLocked }) => {
- const mapImage = getElement(draftState, 'mapImages', mapImageId);
+ const mapImage = getElement(draftState, 'mapImage', mapImageId);
mapImage.isLocked = newLocked;
return draftState;
},
@@ -193,7 +189,7 @@ export namespace MapImagesActionReducers {
export const changeZIndex: ActionReducer = {
action: ChangeZIndexMapImageAction,
reducer: (draftState, { mapImageId, mode }) => {
- const mapImage = getElement(draftState, 'mapImages', mapImageId);
+ const mapImage = getElement(draftState, 'mapImage', mapImageId);
switch (mode) {
case 'bringToFront':
case 'bringToBack': {
diff --git a/shared/src/store/action-reducers/material.ts b/shared/src/store/action-reducers/material.ts
index a38b201ab..4d1847dc4 100644
--- a/shared/src/store/action-reducers/material.ts
+++ b/shared/src/store/action-reducers/material.ts
@@ -24,7 +24,7 @@ export namespace MaterialActionReducers {
reducer: (draftState, { materialId, targetPosition }) => {
updateElementPosition(
draftState,
- 'materials',
+ 'material',
materialId,
targetPosition
);
diff --git a/shared/src/store/action-reducers/patient.ts b/shared/src/store/action-reducers/patient.ts
index 277ab6e50..613aa7a2d 100644
--- a/shared/src/store/action-reducers/patient.ts
+++ b/shared/src/store/action-reducers/patient.ts
@@ -29,7 +29,7 @@ export function deletePatient(
draftState: Mutable,
patientId: UUID
) {
- removeElementPosition(draftState, 'patients', patientId);
+ removeElementPosition(draftState, 'patient', patientId);
delete draftState.patients[patientId];
}
@@ -120,7 +120,7 @@ export namespace PatientActionReducers {
}
const mutablePatient = cloneDeepMutable(patient);
draftState.patients[mutablePatient.id] = mutablePatient;
- addElementPosition(draftState, 'patients', mutablePatient.id);
+ addElementPosition(draftState, 'patient', mutablePatient.id);
return draftState;
},
rights: 'trainer',
@@ -131,7 +131,7 @@ export namespace PatientActionReducers {
reducer: (draftState, { patientId, targetPosition }) => {
updateElementPosition(
draftState,
- 'patients',
+ 'patient',
patientId,
targetPosition
);
@@ -152,7 +152,7 @@ export namespace PatientActionReducers {
export const setVisibleStatus: ActionReducer = {
action: SetVisibleStatusAction,
reducer: (draftState, { patientId, patientStatus }) => {
- const patient = getElement(draftState, 'patients', patientId);
+ const patient = getElement(draftState, 'patient', patientId);
patient.pretriageStatus = patientStatus;
if (patient.position !== undefined) {
@@ -167,7 +167,7 @@ export namespace PatientActionReducers {
export const setUserTextAction: ActionReducer = {
action: SetUserTextAction,
reducer: (draftState, { patientId, remarks }) => {
- const patient = getElement(draftState, 'patients', patientId);
+ const patient = getElement(draftState, 'patient', patientId);
patient.remarks = remarks;
return draftState;
},
diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts
index 390e0456e..4de91f2ec 100644
--- a/shared/src/store/action-reducers/simulated-region.ts
+++ b/shared/src/store/action-reducers/simulated-region.ts
@@ -71,7 +71,7 @@ export namespace SimulatedRegionActionReducers {
{
action: RemoveSimulatedRegionAction,
reducer: (draftState, { simulatedRegionId }) => {
- getElement(draftState, 'simulatedRegions', simulatedRegionId);
+ getElement(draftState, 'simulatedRegion', simulatedRegionId);
delete draftState.simulatedRegions[simulatedRegionId];
return draftState;
},
@@ -84,7 +84,7 @@ export namespace SimulatedRegionActionReducers {
reducer: (draftState, { simulatedRegionId, targetPosition }) => {
const simulatedRegion = getElement(
draftState,
- 'simulatedRegions',
+ 'simulatedRegion',
simulatedRegionId
);
simulatedRegion.position = cloneDeepMutable(targetPosition);
@@ -102,7 +102,7 @@ export namespace SimulatedRegionActionReducers {
) => {
const simulatedRegion = getElement(
draftState,
- 'simulatedRegions',
+ 'simulatedRegion',
simulatedRegionId
);
simulatedRegion.position = cloneDeepMutable(targetPosition);
@@ -118,7 +118,7 @@ export namespace SimulatedRegionActionReducers {
reducer: (draftState, { simulatedRegionId, newName }) => {
const simulatedRegion = getElement(
draftState,
- 'simulatedRegions',
+ 'simulatedRegion',
simulatedRegionId
);
simulatedRegion.name = newName;
diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts
index dd55cbae0..caad44b2c 100644
--- a/shared/src/store/action-reducers/transfer-point.ts
+++ b/shared/src/store/action-reducers/transfer-point.ts
@@ -124,7 +124,7 @@ export namespace TransferPointActionReducers {
reducer: (draftState, { transferPointId, targetPosition }) => {
const transferPoint = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId
);
transferPoint.position = cloneDeepMutable(targetPosition);
@@ -142,7 +142,7 @@ export namespace TransferPointActionReducers {
) => {
const transferPoint = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId
);
// Empty strings are ignored
@@ -173,12 +173,12 @@ export namespace TransferPointActionReducers {
}
const transferPoint1 = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId1
);
const transferPoint2 = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId2
);
const _duration =
@@ -210,12 +210,12 @@ export namespace TransferPointActionReducers {
}
const transferPoint1 = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId1
);
const transferPoint2 = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId2
);
delete transferPoint1.reachableTransferPoints[transferPointId2];
@@ -230,20 +230,20 @@ export namespace TransferPointActionReducers {
action: RemoveTransferPointAction,
reducer: (draftState, { transferPointId }) => {
// check if transferPoint exists
- getElement(draftState, 'transferPoints', transferPointId);
+ getElement(draftState, 'transferPoint', transferPointId);
// TODO: make it dynamic (if at any time something else is able to transfer this part needs to be changed accordingly)
// Let all vehicles and personnel arrive that are on transfer to this transferPoint before deleting it
for (const vehicleId of Object.keys(draftState.vehicles)) {
const vehicle = getElement(
draftState,
- 'vehicles',
+ 'vehicle',
vehicleId
);
if (
vehicle.transfer?.targetTransferPointId ===
transferPointId
) {
- letElementArrive(draftState, 'vehicles', vehicleId);
+ letElementArrive(draftState, 'vehicle', vehicleId);
}
}
for (const personnelId of Object.keys(draftState.personnel)) {
@@ -286,10 +286,10 @@ export namespace TransferPointActionReducers {
action: ConnectHospitalAction,
reducer: (draftState, { transferPointId, hospitalId }) => {
// Check if hospital with this Id exists
- getElement(draftState, 'hospitals', hospitalId);
+ getElement(draftState, 'hospital', hospitalId);
const transferPoint = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId
);
transferPoint.reachableHospitals[hospitalId] = true;
@@ -302,10 +302,10 @@ export namespace TransferPointActionReducers {
action: DisconnectHospitalAction,
reducer: (draftState, { hospitalId, transferPointId }) => {
// Check if hospital with this Id exists
- getElement(draftState, 'hospitals', hospitalId);
+ getElement(draftState, 'hospital', hospitalId);
const transferPoint = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
transferPointId
);
delete transferPoint.reachableHospitals[hospitalId];
diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts
index cd9f88fa9..1414d478c 100644
--- a/shared/src/store/action-reducers/transfer.ts
+++ b/shared/src/store/action-reducers/transfer.ts
@@ -17,9 +17,9 @@ import {
updateElementPosition,
} from './utils/spatial-elements';
-type TransferableElementType = 'personnel' | 'vehicles';
+type TransferableElementType = 'personnel' | 'vehicle';
const transferableElementTypeAllowedValues: AllowedValues =
- { personnel: true, vehicles: true };
+ { personnel: true, vehicle: true };
/**
* Personnel/Vehicle in transfer will arrive immediately at new targetTransferPoint
@@ -38,7 +38,7 @@ export function letElementArrive(
}
const targetTransferPoint = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
element.transfer.targetTransferPointId
);
const newPosition: Mutable = {
@@ -131,7 +131,7 @@ export namespace TransferActionReducers {
{ elementType, elementId, startPoint, targetTransferPointId }
) => {
// check if transferPoint exists
- getElement(draftState, 'transferPoints', targetTransferPointId);
+ getElement(draftState, 'transferPoint', targetTransferPointId);
const element = getElement(draftState, elementType, elementId);
if (element.transfer) {
throw new ReducerError(
@@ -144,7 +144,7 @@ export namespace TransferActionReducers {
if (startPoint.type === 'transferPoint') {
const transferStartPoint = getElement(
draftState,
- 'transferPoints',
+ 'transferPoint',
startPoint.transferPointId
);
const connection =
@@ -193,7 +193,7 @@ export namespace TransferActionReducers {
}
if (targetTransferPointId) {
// check if transferPoint exists
- getElement(draftState, 'transferPoints', targetTransferPointId);
+ getElement(draftState, 'transferPoint', targetTransferPointId);
element.transfer.targetTransferPointId = targetTransferPointId;
}
if (timeToAdd) {
@@ -215,7 +215,7 @@ export namespace TransferActionReducers {
{ elementType, elementId, targetTransferPointId }
) => {
// check if transferPoint exists
- getElement(draftState, 'transferPoints', targetTransferPointId);
+ getElement(draftState, 'transferPoint', targetTransferPointId);
const element = getElement(draftState, elementType, elementId);
if (!element.transfer) {
throw getNotInTransferError(element.id);
diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts
index fbc9fd9d7..23ebff3b2 100644
--- a/shared/src/store/action-reducers/utils/calculate-treatments.ts
+++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts
@@ -6,6 +6,7 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range';
import type { Mutable, UUID } from '../../../utils';
+import { typeSelectorMap } from '../../../utils/type-state-selector-map';
import { getElement } from './get-element';
// TODO: `caterFor` and `treat` are currently used as synonyms without a clear distinction.
@@ -82,7 +83,7 @@ function tryToCaterFor(
cateringElement.assignedPatientIds[patient.id] = true;
- if (isPersonnel(cateringElement)) {
+ if (cateringElement.type === 'personnel') {
patient.assignedPersonnelIds[cateringElement.id] = true;
} else {
patient.assignedMaterialIds[cateringElement.id] = true;
@@ -92,26 +93,6 @@ function tryToCaterFor(
return true;
}
-// TODO: Instead, give each Element a "type" property -> discriminated union
-function isPatient(
- element: Mutable
-): element is Mutable {
- return (element as Patient).personalInformation !== undefined;
-}
-
-function isPersonnel(
- element: Mutable
-): element is Mutable {
- return (element as Personnel).personnelType !== undefined;
-}
-
-function isMaterial(
- element: Mutable
-): element is Mutable {
- // as Material does not include any distinguishable properties, we will check if it is not of type Personnel or Patient
- return !isPersonnel(element) && !isPatient(element);
-}
-
/**
* @param position of the patient where all elements of {@link elementType} should be recalculated
* @param elementIdsToBeSkipped the elements whose treatment should not be updated
@@ -119,11 +100,11 @@ function isMaterial(
function updateCateringAroundPatient(
state: Mutable,
position: Position,
- elementType: 'materials' | 'personnel',
+ elementType: 'material' | 'personnel',
elementIdsToBeSkipped: Set
) {
const elementsInTreatmentRange = SpatialTree.findAllElementsInCircle(
- state.spatialTrees[elementType],
+ state.spatialTrees[typeSelectorMap[elementType]],
position,
maxTreatmentRange
).filter((elementId) => !elementIdsToBeSkipped.has(elementId));
@@ -140,7 +121,7 @@ function removeTreatmentsOfElement(
// TODO: when elements have their own type saved don't use const patient = getElement(state, 'patients', element.id);
// instead use const patient = element;
// same for personnel and material in the other if statements
- if (isPatient(element)) {
+ if (element.type === 'patient') {
const patient = element;
// Make all personnel stop treating this patient
for (const personnelId of Object.keys(patient.assignedPersonnelIds)) {
@@ -150,23 +131,23 @@ function removeTreatmentsOfElement(
patient.assignedPersonnelIds = {};
// Make all material stop treating this patient
for (const materialId of Object.keys(patient.assignedMaterialIds)) {
- const material = getElement(state, 'materials', materialId);
+ const material = getElement(state, 'material', materialId);
delete material.assignedPatientIds[patient.id];
}
patient.assignedMaterialIds = {};
- } else if (isPersonnel(element)) {
+ } else if (element.type === 'personnel') {
const personnel = element;
// This personnel doesn't treat any patients anymore
for (const patientId of Object.keys(personnel.assignedPatientIds)) {
- const patient = getElement(state, 'patients', patientId);
+ const patient = getElement(state, 'patient', patientId);
delete patient.assignedPersonnelIds[personnel.id];
}
personnel.assignedPatientIds = {};
- } else if (isMaterial(element)) {
+ } else if (element.type === 'material') {
const material = element;
// This material doesn't treat any patients anymore
for (const patientId of Object.keys(material.assignedPatientIds)) {
- const patient = getElement(state, 'patients', patientId);
+ const patient = getElement(state, 'patient', patientId);
delete patient.assignedMaterialIds[material.id];
}
material.assignedPatientIds = {};
@@ -194,7 +175,7 @@ export function updateTreatments(
return;
}
- if (isPersonnel(element) || isMaterial(element)) {
+ if (element.type === 'personnel' || element.type === 'material') {
updateCatering(state, element);
return;
}
@@ -208,7 +189,7 @@ export function updateTreatments(
alreadyUpdatedElementIds.add(personnelId);
}
for (const materialId of Object.keys(element.assignedMaterialIds)) {
- updateCatering(state, getElement(state, 'materials', materialId));
+ updateCatering(state, getElement(state, 'material', materialId));
// Saving materialIds of material that already got calculated - makes small movements of patients more efficient
alreadyUpdatedElementIds.add(materialId);
}
@@ -222,7 +203,7 @@ export function updateTreatments(
updateCateringAroundPatient(
state,
element.position,
- 'materials',
+ 'material',
alreadyUpdatedElementIds
);
// The treatment of the patient has just been updated -> hence the visible status hasn't been changed since the last update
@@ -270,7 +251,7 @@ function updateCatering(
tryToCaterFor(
cateringElement,
catersFor,
- getElement(state, 'patients', patientId),
+ getElement(state, 'patient', patientId),
state.configuration.pretriageEnabled,
state.configuration.bluePatientsEnabled
);
@@ -296,7 +277,7 @@ function updateCatering(
)
// Filter out every patient in the overrideTreatmentRange
.filter((patientId) => !cateredForPatients.has(patientId))
- .map((patientId) => getElement(state, 'patients', patientId));
+ .map((patientId) => getElement(state, 'patient', patientId));
const patientsPerStatus = groupBy(patientsInTreatmentRange, (patient) =>
getCateringStatus(
diff --git a/shared/src/store/action-reducers/utils/get-element.ts b/shared/src/store/action-reducers/utils/get-element.ts
index 721faa5dd..4ed737ed1 100644
--- a/shared/src/store/action-reducers/utils/get-element.ts
+++ b/shared/src/store/action-reducers/utils/get-element.ts
@@ -1,5 +1,7 @@
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
+import type { TypeSelectorMap } from '../../../utils/type-state-selector-map';
+import { typeSelectorMap } from '../../../utils/type-state-selector-map';
import { ReducerError } from '../../reducer-error';
/**
@@ -7,25 +9,16 @@ import { ReducerError } from '../../reducer-error';
* @throws ReducerError if the element does not exist
*/
export function getElement<
- ElementType extends
- | 'alarmGroups'
- | 'clients'
- | 'hospitals'
- | 'mapImages'
- | 'materials'
- | 'patients'
- | 'personnel'
- | 'simulatedRegions'
- | 'transferPoints'
- | 'vehicles'
- | 'viewports',
+ ElementType extends keyof TypeSelectorMap,
State extends ExerciseState | Mutable
>(
state: State,
elementType: ElementType,
elementId: UUID
-): State[ElementType][UUID] {
- const element = state[elementType][elementId] as State[ElementType][UUID];
+): State[TypeSelectorMap[ElementType]][UUID] {
+ const element = state[typeSelectorMap[elementType]][
+ elementId
+ ] as State[TypeSelectorMap[ElementType]][UUID];
if (!element) {
throw new ReducerError(
`Element of type ${elementType} with id ${elementId} does not exist`
diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts
index 49e84c6da..f840adb2c 100644
--- a/shared/src/store/action-reducers/utils/spatial-elements.ts
+++ b/shared/src/store/action-reducers/utils/spatial-elements.ts
@@ -3,6 +3,7 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
import { cloneDeepMutable } from '../../../utils';
+import { typeSelectorMap } from '../../../utils/type-state-selector-map';
import { updateTreatments } from './calculate-treatments';
import { getElement } from './get-element';
@@ -11,7 +12,14 @@ import { getElement } from './get-element';
* The position of the element must be changed via one of the function in this file.
* In addition, the respective functions must be called when an element gets added or removed.
*/
-export type SpatialElementType = 'materials' | 'patients' | 'personnel';
+const spatialTypeSelectorMap = {
+ material: typeSelectorMap.material,
+ patient: typeSelectorMap.patient,
+ personnel: typeSelectorMap.personnel,
+} as const;
+type SpatialTypeSelectorMap = typeof spatialTypeSelectorMap;
+type SpatialElementType = keyof SpatialTypeSelectorMap;
+export type SpatialElementSelector = SpatialTypeSelectorMap[SpatialElementType];
/**
* Adds an element with a position and executes side effects to guarantee the consistency of the state.
@@ -27,7 +35,7 @@ export function addElementPosition(
return;
}
SpatialTree.addElement(
- state.spatialTrees[elementType],
+ state.spatialTrees[spatialTypeSelectorMap[elementType]],
element.id,
element.position
);
@@ -47,14 +55,14 @@ export function updateElementPosition(
const startPosition = element.position;
if (startPosition !== undefined) {
SpatialTree.moveElement(
- state.spatialTrees[elementType],
+ state.spatialTrees[spatialTypeSelectorMap[elementType]],
element.id,
startPosition,
targetPosition
);
} else {
SpatialTree.addElement(
- state.spatialTrees[elementType],
+ state.spatialTrees[spatialTypeSelectorMap[elementType]],
element.id,
targetPosition
);
@@ -77,7 +85,7 @@ export function removeElementPosition(
return;
}
SpatialTree.removeElement(
- state.spatialTrees[elementType],
+ state.spatialTrees[spatialTypeSelectorMap[elementType]],
element.id,
element.position
);
diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts
index 6db4d99bb..5d9778d05 100644
--- a/shared/src/store/action-reducers/vehicle.ts
+++ b/shared/src/store/action-reducers/vehicle.ts
@@ -26,10 +26,10 @@ export function deleteVehicle(
draftState: Mutable,
vehicleId: UUID
) {
- const vehicle = getElement(draftState, 'vehicles', vehicleId);
+ const vehicle = getElement(draftState, 'vehicle', vehicleId);
// Delete related material and personnel
Object.keys(vehicle.materialIds).forEach((materialId) => {
- removeElementPosition(draftState, 'materials', materialId);
+ removeElementPosition(draftState, 'material', materialId);
delete draftState.materials[materialId];
});
Object.keys(vehicle.personnelIds).forEach((personnelId) => {
@@ -151,7 +151,7 @@ export namespace VehicleActionReducers {
draftState.vehicles[vehicle.id] = cloneDeepMutable(vehicle);
for (const material of cloneDeepMutable(materials)) {
draftState.materials[material.id] = material;
- addElementPosition(draftState, 'materials', material.id);
+ addElementPosition(draftState, 'material', material.id);
}
for (const person of cloneDeepMutable(personnel)) {
draftState.personnel[person.id] = person;
@@ -165,7 +165,7 @@ export namespace VehicleActionReducers {
export const moveVehicle: ActionReducer = {
action: MoveVehicleAction,
reducer: (draftState, { vehicleId, targetPosition }) => {
- const vehicle = getElement(draftState, 'vehicles', vehicleId);
+ const vehicle = getElement(draftState, 'vehicle', vehicleId);
vehicle.position = cloneDeepMutable(targetPosition);
return draftState;
},
@@ -175,7 +175,7 @@ export namespace VehicleActionReducers {
export const renameVehicle: ActionReducer = {
action: RenameVehicleAction,
reducer: (draftState, { vehicleId, name }) => {
- const vehicle = getElement(draftState, 'vehicles', vehicleId);
+ const vehicle = getElement(draftState, 'vehicle', vehicleId);
vehicle.name = name;
for (const personnelId of Object.keys(vehicle.personnelIds)) {
draftState.personnel[personnelId]!.vehicleName = name;
@@ -200,7 +200,7 @@ export namespace VehicleActionReducers {
export const unloadVehicle: ActionReducer = {
action: UnloadVehicleAction,
reducer: (draftState, { vehicleId }) => {
- const vehicle = getElement(draftState, 'vehicles', vehicleId);
+ const vehicle = getElement(draftState, 'vehicle', vehicleId);
const unloadPosition = vehicle.position;
if (!unloadPosition) {
throw new ReducerError(
@@ -226,7 +226,7 @@ export namespace VehicleActionReducers {
for (const patientId of patientIds) {
x += space;
- updateElementPosition(draftState, 'patients', patientId, {
+ updateElementPosition(draftState, 'patient', patientId, {
x,
y: unloadPosition.y,
});
@@ -255,13 +255,9 @@ export namespace VehicleActionReducers {
for (const materialId of materialIds) {
x += space;
- const material = getElement(
- draftState,
- 'materials',
- materialId
- );
+ const material = getElement(draftState, 'material', materialId);
if (Material.isInVehicle(material)) {
- updateElementPosition(draftState, 'materials', materialId, {
+ updateElementPosition(draftState, 'material', materialId, {
x,
y: unloadPosition.y,
});
@@ -279,12 +275,12 @@ export namespace VehicleActionReducers {
draftState,
{ vehicleId, elementToBeLoadedId, elementToBeLoadedType }
) => {
- const vehicle = getElement(draftState, 'vehicles', vehicleId);
+ const vehicle = getElement(draftState, 'vehicle', vehicleId);
switch (elementToBeLoadedType) {
case 'materials': {
const material = getElement(
draftState,
- 'materials',
+ 'material',
elementToBeLoadedId
);
if (!vehicle.materialIds[elementToBeLoadedId]) {
@@ -292,7 +288,7 @@ export namespace VehicleActionReducers {
`Material with id ${material.id} is not assignable to the vehicle with id ${vehicle.id}`
);
}
- removeElementPosition(draftState, 'materials', material.id);
+ removeElementPosition(draftState, 'material', material.id);
break;
}
case 'personnel': {
@@ -321,7 +317,7 @@ export namespace VehicleActionReducers {
case 'patients': {
const patient = getElement(
draftState,
- 'patients',
+ 'patient',
elementToBeLoadedId
);
if (
@@ -334,13 +330,14 @@ export namespace VehicleActionReducers {
}
vehicle.patientIds[elementToBeLoadedId] = true;
- removeElementPosition(draftState, 'patients', patient.id);
+ // removeElementPosition(draftState, 'patient', patient.id);
+ removeElementPosition(draftState, patient.type, patient.id);
// Load in all materials
Object.keys(vehicle.materialIds).forEach((materialId) => {
removeElementPosition(
draftState,
- 'materials',
+ 'material',
materialId
);
});
diff --git a/shared/src/store/action-reducers/viewport.ts b/shared/src/store/action-reducers/viewport.ts
index 13c3b1919..f81ee56a3 100644
--- a/shared/src/store/action-reducers/viewport.ts
+++ b/shared/src/store/action-reducers/viewport.ts
@@ -69,7 +69,7 @@ export namespace ViewportActionReducers {
export const removeViewport: ActionReducer = {
action: RemoveViewportAction,
reducer: (draftState, { viewportId }) => {
- getElement(draftState, 'viewports', viewportId);
+ getElement(draftState, 'viewport', viewportId);
delete draftState.viewports[viewportId];
return draftState;
},
@@ -79,7 +79,7 @@ export namespace ViewportActionReducers {
export const moveViewport: ActionReducer = {
action: MoveViewportAction,
reducer: (draftState, { viewportId, targetPosition }) => {
- const viewport = getElement(draftState, 'viewports', viewportId);
+ const viewport = getElement(draftState, 'viewport', viewportId);
viewport.position = cloneDeepMutable(targetPosition);
return draftState;
},
@@ -89,7 +89,7 @@ export namespace ViewportActionReducers {
export const resizeViewport: ActionReducer = {
action: ResizeViewportAction,
reducer: (draftState, { viewportId, targetPosition, newSize }) => {
- const viewport = getElement(draftState, 'viewports', viewportId);
+ const viewport = getElement(draftState, 'viewport', viewportId);
viewport.position = cloneDeepMutable(targetPosition);
viewport.size = cloneDeepMutable(newSize);
return draftState;
@@ -100,7 +100,7 @@ export namespace ViewportActionReducers {
export const renameViewport: ActionReducer = {
action: RenameViewportAction,
reducer: (draftState, { viewportId, newName }) => {
- const viewport = getElement(draftState, 'viewports', viewportId);
+ const viewport = getElement(draftState, 'viewport', viewportId);
viewport.name = newName;
return draftState;
},
diff --git a/shared/src/utils/type-state-selector-map.ts b/shared/src/utils/type-state-selector-map.ts
new file mode 100644
index 000000000..09ab1ac85
--- /dev/null
+++ b/shared/src/utils/type-state-selector-map.ts
@@ -0,0 +1,15 @@
+export const typeSelectorMap = {
+ alarmGroup: 'alarmGroups',
+ client: 'clients',
+ hospital: 'hospitals',
+ mapImage: 'mapImages',
+ material: 'materials',
+ patient: 'patients',
+ personnel: 'personnel',
+ simulatedRegion: 'simulatedRegions',
+ transferPoint: 'transferPoints',
+ vehicle: 'vehicles',
+ viewport: 'viewports',
+} as const;
+
+export type TypeSelectorMap = typeof typeSelectorMap;
From b5a13c860bb9722183b2d3c3731bf1a42c4ebb23 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Tue, 24 Jan 2023 12:22:54 +0100
Subject: [PATCH 02/18] Pick specific selectors from TypeSelectorMap
---
shared/src/store/action-reducers/exercise.ts | 13 ++++++-------
.../action-reducers/utils/spatial-elements.ts | 18 +++++++-----------
2 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index b2a7c0918..a2733c828 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -11,7 +11,10 @@ import { Patient } from '../../models';
import { getStatus } from '../../models/utils';
import type { ExerciseState } from '../../state';
import type { Mutable } from '../../utils';
-import { typeSelectorMap } from '../../utils/type-state-selector-map';
+import {
+ TypeSelectorMap,
+ typeSelectorMap,
+} from '../../utils/type-state-selector-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
@@ -131,18 +134,14 @@ export namespace ExerciseActionReducers {
};
}
-const transferTypeSelectorMap = {
- personnel: typeSelectorMap.personnel,
- vehicle: typeSelectorMap.vehicle,
-} as const;
-type TransferTypeSelectorMap = typeof transferTypeSelectorMap;
+type TransferTypeSelectorMap = Pick;
function refreshTransfer(
draftState: Mutable,
type: keyof TransferTypeSelectorMap,
tickInterval: number
): void {
- const elements = draftState[transferTypeSelectorMap[type]];
+ const elements = draftState[typeSelectorMap[type]];
Object.values(elements).forEach((element: Mutable) => {
if (!element.transfer) {
return;
diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts
index f840adb2c..2458b0568 100644
--- a/shared/src/store/action-reducers/utils/spatial-elements.ts
+++ b/shared/src/store/action-reducers/utils/spatial-elements.ts
@@ -3,6 +3,7 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
import { cloneDeepMutable } from '../../../utils';
+import type { TypeSelectorMap } from '../../../utils/type-state-selector-map';
import { typeSelectorMap } from '../../../utils/type-state-selector-map';
import { updateTreatments } from './calculate-treatments';
import { getElement } from './get-element';
@@ -12,13 +13,8 @@ import { getElement } from './get-element';
* The position of the element must be changed via one of the function in this file.
* In addition, the respective functions must be called when an element gets added or removed.
*/
-const spatialTypeSelectorMap = {
- material: typeSelectorMap.material,
- patient: typeSelectorMap.patient,
- personnel: typeSelectorMap.personnel,
-} as const;
-type SpatialTypeSelectorMap = typeof spatialTypeSelectorMap;
-type SpatialElementType = keyof SpatialTypeSelectorMap;
+type SpatialElementType = 'material' | 'patient' | 'personnel';
+type SpatialTypeSelectorMap = Pick;
export type SpatialElementSelector = SpatialTypeSelectorMap[SpatialElementType];
/**
@@ -35,7 +31,7 @@ export function addElementPosition(
return;
}
SpatialTree.addElement(
- state.spatialTrees[spatialTypeSelectorMap[elementType]],
+ state.spatialTrees[typeSelectorMap[elementType]],
element.id,
element.position
);
@@ -55,14 +51,14 @@ export function updateElementPosition(
const startPosition = element.position;
if (startPosition !== undefined) {
SpatialTree.moveElement(
- state.spatialTrees[spatialTypeSelectorMap[elementType]],
+ state.spatialTrees[typeSelectorMap[elementType]],
element.id,
startPosition,
targetPosition
);
} else {
SpatialTree.addElement(
- state.spatialTrees[spatialTypeSelectorMap[elementType]],
+ state.spatialTrees[typeSelectorMap[elementType]],
element.id,
targetPosition
);
@@ -85,7 +81,7 @@ export function removeElementPosition(
return;
}
SpatialTree.removeElement(
- state.spatialTrees[spatialTypeSelectorMap[elementType]],
+ state.spatialTrees[typeSelectorMap[elementType]],
element.id,
element.position
);
From eff1ca7a750c561201a1532ae50f1b9abc62276a Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Tue, 24 Jan 2023 12:31:23 +0100
Subject: [PATCH 03/18] Fix linter
---
shared/src/store/action-reducers/exercise.ts | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index a2733c828..123cd68b8 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -11,10 +11,8 @@ import { Patient } from '../../models';
import { getStatus } from '../../models/utils';
import type { ExerciseState } from '../../state';
import type { Mutable } from '../../utils';
-import {
- TypeSelectorMap,
- typeSelectorMap,
-} from '../../utils/type-state-selector-map';
+import type { TypeSelectorMap } from '../../utils/type-state-selector-map';
+import { typeSelectorMap } from '../../utils/type-state-selector-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
From 4e67f172b63d22f51b7644c175119fbb57140687 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Tue, 24 Jan 2023 14:52:51 +0100
Subject: [PATCH 04/18] Remove type property from feature
---
.../catering-lines-feature-manager.ts | 1 -
.../element-feature-manager.ts | 8 +-----
.../feature-managers/element-manager.ts | 14 +---------
.../map-images-feature-manager.ts | 8 +++---
.../material-feature-manager.ts | 5 ++--
.../patient-feature-manager.ts | 9 +++----
.../personnel-feature-manager.ts | 5 ++--
.../simulated-region-feature-manager.ts | 7 +++--
.../transfer-lines-feature-manager.ts | 1 -
.../transfer-point-feature-manager.ts | 15 ++++++-----
.../vehicle-feature-manager.ts | 27 ++++++++-----------
.../viewport-feature-manager.ts | 7 +++--
shared/src/store/action-reducers/vehicle.ts | 12 ++++-----
13 files changed, 45 insertions(+), 74 deletions(-)
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts
index 388e360ee..d18292808 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts
@@ -19,7 +19,6 @@ export class CateringLinesFeatureManager
>
implements FeatureManager>
{
- readonly type = 'cateringLines';
readonly unsupportedChangeProperties = new Set(['id'] as const);
private readonly lineStyleHelper = new LineStyleHelper(
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts
index 93c081916..3b3e58cdc 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts
@@ -1,9 +1,4 @@
-import type {
- ExerciseState,
- Position,
- Size,
- UUID,
-} from 'digital-fuesim-manv-shared';
+import type { Position, Size, UUID } from 'digital-fuesim-manv-shared';
import { isArray } from 'lodash-es';
import type { MapBrowserEvent } from 'ol';
import { Feature } from 'ol';
@@ -83,7 +78,6 @@ export abstract class ElementFeatureManager<
>
implements FeatureManager
{
- abstract override readonly type: keyof ExerciseState;
public readonly togglePopup$ = new Subject>();
protected readonly movementAnimator = new MovementAnimator(
this.olMap,
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts
index 4fae9eb95..9e2d5cd07 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts
@@ -19,18 +19,11 @@ export abstract class ElementManager<
UnsupportedChangeProperties
> = Exclude, UnsupportedChangeProperties>
> {
- /**
- * When an element gets (dragged &) dropped, this identifies the type of the dropped element.
- * @example `patients`
- */
- abstract readonly type: string;
-
/**
* This should be called if a new element is added.
*/
public onElementCreated(element: Element) {
const feature = this.createFeature(element);
- feature.set(featureKeys.type, this.type);
feature.set(featureKeys.value, element);
}
@@ -117,10 +110,7 @@ export abstract class ElementManager<
): ElementFeature | undefined;
public getElementFromFeature(feature: Feature) {
- return {
- type: feature.get(featureKeys.type),
- value: feature.get(featureKeys.value),
- };
+ return feature.get(featureKeys.value);
}
private areAllPropertiesSupported(
@@ -140,6 +130,4 @@ export abstract class ElementManager<
*/
const featureKeys = {
value: 'elementValue',
- // TODO: In the future the type should be saved in the element itself
- type: 'elementType',
};
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts
index 43d58bc70..407f3df62 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts
@@ -15,9 +15,8 @@ import { ImageStyleHelper } from '../utility/style-helper/image-style-helper';
import { createPoint, ElementFeatureManager } from './element-feature-manager';
export class MapImageFeatureManager extends ElementFeatureManager {
- readonly type = 'mapImages';
private readonly imageStyleHelper = new ImageStyleHelper(
- (feature) => this.getElementFromFeature(feature)!.value.image
+ (feature) => (this.getElementFromFeature(feature) as MapImage).image
);
private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer);
@@ -45,7 +44,8 @@ export class MapImageFeatureManager extends ElementFeatureManager {
resolution
);
style.setZIndex(
- this.getElementFromFeature(feature as Feature)!.value.zIndex
+ (this.getElementFromFeature(feature as Feature) as MapImage)
+ .zIndex
);
return style;
});
@@ -68,7 +68,7 @@ export class MapImageFeatureManager extends ElementFeatureManager {
}
override isFeatureTranslatable(feature: Feature): boolean {
- const mapImage = this.getElementFromFeature(feature).value as MapImage;
+ const mapImage = this.getElementFromFeature(feature) as MapImage;
return (
selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' &&
!mapImage.isLocked
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts
index b6da79e5a..6fd61a460 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts
@@ -16,13 +16,12 @@ import { createPoint, ElementFeatureManager } from './element-feature-manager';
export class MaterialFeatureManager extends ElementFeatureManager<
WithPosition
> {
- readonly type = 'materials';
private readonly imageStyleHelper = new ImageStyleHelper(
- (feature) => this.getElementFromFeature(feature)!.value.image
+ (feature) => (this.getElementFromFeature(feature) as Material).image
);
private readonly nameStyleHelper = new NameStyleHelper(
(feature) => {
- const material = this.getElementFromFeature(feature)!.value;
+ const material = this.getElementFromFeature(feature) as Material;
return {
name: material.vehicleName,
offsetY: material.image.height / 2 / normalZoom,
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts
index e2ff69fee..dae0854fc 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts
@@ -21,11 +21,10 @@ import { createPoint, ElementFeatureManager } from './element-feature-manager';
export class PatientFeatureManager extends ElementFeatureManager<
WithPosition
> {
- readonly type = 'patients';
private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer);
private readonly imageStyleHelper = new ImageStyleHelper((feature) => {
- const patient = this.getElementFromFeature(feature)!.value;
+ const patient = this.getElementFromFeature(feature) as Patient;
return {
...patient.image,
rotation: patient.pretriageInformation.isWalkable
@@ -36,7 +35,7 @@ export class PatientFeatureManager extends ElementFeatureManager<
private readonly circleStyleHelper = new CircleStyleHelper(
(feature) => {
- const patient = this.getElementFromFeature(feature)!.value;
+ const patient = this.getElementFromFeature(feature) as Patient;
const configuration = selectStateSnapshot(
selectConfiguration,
this.store
@@ -59,8 +58,8 @@ export class PatientFeatureManager extends ElementFeatureManager<
},
0.025,
(feature) =>
- this.getElementFromFeature(feature)!.value.pretriageInformation
- .isWalkable
+ (this.getElementFromFeature(feature) as Patient)
+ .pretriageInformation.isWalkable
? [0, 0.25]
: [-0.25, 0]
);
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts
index 3d42f47ee..9dca667c8 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts
@@ -16,13 +16,12 @@ import { createPoint, ElementFeatureManager } from './element-feature-manager';
export class PersonnelFeatureManager extends ElementFeatureManager<
WithPosition
> {
- readonly type = 'personnel';
private readonly imageStyleHelper = new ImageStyleHelper(
- (feature) => this.getElementFromFeature(feature)!.value.image
+ (feature) => (this.getElementFromFeature(feature) as Personnel).image
);
private readonly nameStyleHelper = new NameStyleHelper(
(feature) => {
- const personnel = this.getElementFromFeature(feature)!.value;
+ const personnel = this.getElementFromFeature(feature) as Personnel;
return {
name: personnel.vehicleName,
offsetY: personnel.image.height / 2 / normalZoom,
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts
index acfa70e1d..fd1c7dd1b 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts
@@ -26,8 +26,6 @@ export class SimulatedRegionFeatureManager
extends ElementFeatureManager
implements FeatureManager>
{
- readonly type = 'simulatedRegions';
-
override unsupportedChangeProperties = new Set(['id'] as const);
constructor(
@@ -63,8 +61,9 @@ export class SimulatedRegionFeatureManager
ResizeRectangleInteraction.onResize(
feature,
({ topLeftCoordinate, scale }) => {
- const currentElement = this.getElementFromFeature(feature)!
- .value as SimulatedRegion;
+ const currentElement = this.getElementFromFeature(
+ feature
+ ) as SimulatedRegion;
this.exerciseService.proposeAction(
{
type: '[SimulatedRegion] Resize simulated region',
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts
index 999de802b..4c5ba8065 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts
@@ -19,7 +19,6 @@ export class TransferLinesFeatureManager
>
implements FeatureManager>
{
- readonly type = 'transferLines';
readonly unsupportedChangeProperties = new Set(['id'] as const);
constructor(public readonly layer: VectorLayer>) {
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts
index 3682c6c10..1122425fe 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts
@@ -19,7 +19,6 @@ import { NameStyleHelper } from '../utility/style-helper/name-style-helper';
import { createPoint, ElementFeatureManager } from './element-feature-manager';
export class TransferPointFeatureManager extends ElementFeatureManager {
- readonly type = 'transferPoints';
private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer);
constructor(
@@ -61,7 +60,8 @@ export class TransferPointFeatureManager extends ElementFeatureManager ({
- name: this.getElementFromFeature(feature)!.value.internalName,
+ name: (this.getElementFromFeature(feature) as TransferPoint)
+ .internalName,
offsetY: 0,
}),
0.2,
@@ -75,14 +75,15 @@ export class TransferPointFeatureManager extends ElementFeatureManager fix getElementFromFeature typings
const droppedElement = this.getElementFromFeature(droppedFeature);
- const droppedOnTransferPoint: TransferPoint =
- this.getElementFromFeature(droppedOnFeature)!.value!;
+ const droppedOnTransferPoint = this.getElementFromFeature(
+ droppedOnFeature
+ ) as TransferPoint;
if (!droppedElement || !droppedOnTransferPoint) {
console.error('Could not find element for the features');
return false;
}
if (
- droppedElement.type !== 'vehicles' &&
+ droppedElement.type !== 'vehicle' &&
droppedElement.type !== 'personnel'
) {
return false;
@@ -106,7 +107,7 @@ export class TransferPointFeatureManager extends ElementFeatureManager
> {
- readonly type = 'vehicles';
-
private readonly imageStyleHelper = new ImageStyleHelper(
- (feature) => this.getElementFromFeature(feature)!.value.image
+ (feature) => (this.getElementFromFeature(feature) as Vehicle).image
);
private readonly nameStyleHelper = new NameStyleHelper(
(feature) => {
- const vehicle = this.getElementFromFeature(feature)!.value;
+ const vehicle = this.getElementFromFeature(feature) as Vehicle;
return {
name: vehicle.name,
offsetY: vehicle.image.height / 2 / normalZoom,
@@ -66,29 +64,26 @@ export class VehicleFeatureManager extends ElementFeatureManager<
const droppedElement = this.getElementFromFeature(droppedFeature);
const droppedOnVehicle = this.getElementFromFeature(
droppedOnFeature
- ) as {
- type: 'vehicles';
- value: Vehicle;
- };
+ ) as Vehicle;
if (!droppedElement || !droppedOnVehicle) {
console.error('Could not find element for the features');
return false;
}
if (
(droppedElement.type === 'personnel' &&
- droppedOnVehicle.value.personnelIds[droppedElement.value.id]) ||
- (droppedElement.type === 'materials' &&
- droppedOnVehicle.value.materialIds[droppedElement.value.id]) ||
- (droppedElement.type === 'patients' &&
- Object.keys(droppedOnVehicle.value.patientIds).length <
- droppedOnVehicle.value.patientCapacity)
+ droppedOnVehicle.personnelIds[droppedElement.id]) ||
+ (droppedElement.type === 'material' &&
+ droppedOnVehicle.materialIds[droppedElement.id]) ||
+ (droppedElement.type === 'patient' &&
+ Object.keys(droppedOnVehicle.patientIds).length <
+ droppedOnVehicle.patientCapacity)
) {
// TODO: user feedback (e.g. toast)
this.exerciseService.proposeAction(
{
type: '[Vehicle] Load vehicle',
- vehicleId: droppedOnVehicle.value.id,
- elementToBeLoadedId: droppedElement.value.id,
+ vehicleId: droppedOnVehicle.id,
+ elementToBeLoadedId: droppedElement.id,
elementToBeLoadedType: droppedElement.type,
},
true
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts
index 5fa0b86d0..efb4d6cd4 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts
@@ -37,8 +37,6 @@ export class ViewportFeatureManager
extends ElementFeatureManager
implements FeatureManager>
{
- readonly type = 'viewports';
-
override unsupportedChangeProperties = new Set(['id'] as const);
constructor(
@@ -74,8 +72,9 @@ export class ViewportFeatureManager
ResizeRectangleInteraction.onResize(
feature,
({ topLeftCoordinate, scale }) => {
- const currentElement = this.getElementFromFeature(feature)!
- .value as Viewport;
+ const currentElement = this.getElementFromFeature(
+ feature
+ ) as Viewport;
this.exerciseService.proposeAction(
{
type: '[Viewport] Resize viewport',
diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts
index 5d9778d05..6a0a1dfc8 100644
--- a/shared/src/store/action-reducers/vehicle.ts
+++ b/shared/src/store/action-reducers/vehicle.ts
@@ -105,13 +105,13 @@ export class LoadVehicleAction implements Action {
public readonly vehicleId!: UUID;
@IsLiteralUnion({
- materials: true,
- patients: true,
+ material: true,
+ patient: true,
personnel: true,
})
public readonly elementToBeLoadedType!:
- | 'materials'
- | 'patients'
+ | 'material'
+ | 'patient'
| 'personnel';
@IsUUID(4, uuidValidationOptions)
@@ -277,7 +277,7 @@ export namespace VehicleActionReducers {
) => {
const vehicle = getElement(draftState, 'vehicle', vehicleId);
switch (elementToBeLoadedType) {
- case 'materials': {
+ case 'material': {
const material = getElement(
draftState,
'material',
@@ -314,7 +314,7 @@ export namespace VehicleActionReducers {
);
break;
}
- case 'patients': {
+ case 'patient': {
const patient = getElement(
draftState,
'patient',
From e577366585d13aef94015820b778fa51ce62998b Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Wed, 25 Jan 2023 12:15:53 +0100
Subject: [PATCH 05/18] Fix bug after merge
---
shared/src/store/action-reducers/vehicle.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts
index 7d9c2e1a0..227586a35 100644
--- a/shared/src/store/action-reducers/vehicle.ts
+++ b/shared/src/store/action-reducers/vehicle.ts
@@ -361,7 +361,7 @@ export namespace VehicleActionReducers {
Object.keys(vehicle.materialIds).forEach((materialId) => {
getElement(
draftState,
- 'materials',
+ 'material',
materialId
).metaPosition = {
type: 'vehicle',
From 9a519a40df7d7167b48e2945532d4e619c1781a1 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Wed, 25 Jan 2023 13:40:07 +0100
Subject: [PATCH 06/18] Rename selector map to plural map and add validation
---
shared/src/models/element.ts | 26 +++++++++++++++++++
shared/src/state.ts | 4 +--
shared/src/store/action-reducers/exercise.ts | 13 ++++++----
.../utils/calculate-treatments.ts | 4 +--
.../action-reducers/utils/get-element.ts | 12 ++++-----
.../action-reducers/utils/spatial-elements.ts | 16 ++++++------
shared/src/utils/type-state-selector-map.ts | 15 ++++++++---
7 files changed, 64 insertions(+), 26 deletions(-)
create mode 100644 shared/src/models/element.ts
diff --git a/shared/src/models/element.ts b/shared/src/models/element.ts
new file mode 100644
index 000000000..7458f0e68
--- /dev/null
+++ b/shared/src/models/element.ts
@@ -0,0 +1,26 @@
+import type { AlarmGroup } from './alarm-group';
+import type { Client } from './client';
+import type { Hospital } from './hospital';
+import type { MapImage } from './map-image';
+import type {
+ Material,
+ Patient,
+ Personnel,
+ SimulatedRegion,
+ TransferPoint,
+ Vehicle,
+ Viewport,
+} from '.';
+
+export type Element =
+ | AlarmGroup
+ | Client
+ | Hospital
+ | MapImage
+ | Material
+ | Patient
+ | Personnel
+ | SimulatedRegion
+ | TransferPoint
+ | Vehicle
+ | Viewport;
diff --git a/shared/src/state.ts b/shared/src/state.ts
index 481294460..3601e4401 100644
--- a/shared/src/state.ts
+++ b/shared/src/state.ts
@@ -44,7 +44,7 @@ import {
SpatialTree,
} from './models/utils';
import type { MaterialType } from './models/utils/material-type';
-import type { SpatialElementSelector } from './store/action-reducers/utils/spatial-elements';
+import type { SpatialElementPlural } from './store/action-reducers/utils/spatial-elements';
import type { UUID } from './utils';
import { uuid, uuidValidationOptions } from './utils';
import { IsIdMap, IsLiteralUnion } from './utils/validators';
@@ -123,7 +123,7 @@ export class ExerciseState {
// Mutable` could still have immutable objects in spatialTree
@IsObject()
public readonly spatialTrees: {
- [type in SpatialElementSelector]: SpatialTree;
+ [type in SpatialElementPlural]: SpatialTree;
} = {
materials: SpatialTree.create(),
patients: SpatialTree.create(),
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index 123cd68b8..c3ac6b555 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -11,8 +11,8 @@ import { Patient } from '../../models';
import { getStatus } from '../../models/utils';
import type { ExerciseState } from '../../state';
import type { Mutable } from '../../utils';
-import type { TypeSelectorMap } from '../../utils/type-state-selector-map';
-import { typeSelectorMap } from '../../utils/type-state-selector-map';
+import type { ElementTypePluralMap } from '../../utils/type-state-selector-map';
+import { elementTypePluralMap } from '../../utils/type-state-selector-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
@@ -132,14 +132,17 @@ export namespace ExerciseActionReducers {
};
}
-type TransferTypeSelectorMap = Pick;
+type TransferTypePluralMap = Pick<
+ ElementTypePluralMap,
+ 'personnel' | 'vehicle'
+>;
function refreshTransfer(
draftState: Mutable,
- type: keyof TransferTypeSelectorMap,
+ type: keyof TransferTypePluralMap,
tickInterval: number
): void {
- const elements = draftState[typeSelectorMap[type]];
+ const elements = draftState[elementTypePluralMap[type]];
Object.values(elements).forEach((element: Mutable) => {
if (!element.transfer) {
return;
diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts
index 23ebff3b2..ce2921232 100644
--- a/shared/src/store/action-reducers/utils/calculate-treatments.ts
+++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts
@@ -6,7 +6,7 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range';
import type { Mutable, UUID } from '../../../utils';
-import { typeSelectorMap } from '../../../utils/type-state-selector-map';
+import { elementTypePluralMap } from '../../../utils/type-state-selector-map';
import { getElement } from './get-element';
// TODO: `caterFor` and `treat` are currently used as synonyms without a clear distinction.
@@ -104,7 +104,7 @@ function updateCateringAroundPatient(
elementIdsToBeSkipped: Set
) {
const elementsInTreatmentRange = SpatialTree.findAllElementsInCircle(
- state.spatialTrees[typeSelectorMap[elementType]],
+ state.spatialTrees[elementTypePluralMap[elementType]],
position,
maxTreatmentRange
).filter((elementId) => !elementIdsToBeSkipped.has(elementId));
diff --git a/shared/src/store/action-reducers/utils/get-element.ts b/shared/src/store/action-reducers/utils/get-element.ts
index 4ed737ed1..8479887be 100644
--- a/shared/src/store/action-reducers/utils/get-element.ts
+++ b/shared/src/store/action-reducers/utils/get-element.ts
@@ -1,7 +1,7 @@
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
-import type { TypeSelectorMap } from '../../../utils/type-state-selector-map';
-import { typeSelectorMap } from '../../../utils/type-state-selector-map';
+import type { ElementTypePluralMap } from '../../../utils/type-state-selector-map';
+import { elementTypePluralMap } from '../../../utils/type-state-selector-map';
import { ReducerError } from '../../reducer-error';
/**
@@ -9,16 +9,16 @@ import { ReducerError } from '../../reducer-error';
* @throws ReducerError if the element does not exist
*/
export function getElement<
- ElementType extends keyof TypeSelectorMap,
+ ElementType extends keyof ElementTypePluralMap,
State extends ExerciseState | Mutable
>(
state: State,
elementType: ElementType,
elementId: UUID
-): State[TypeSelectorMap[ElementType]][UUID] {
- const element = state[typeSelectorMap[elementType]][
+): State[ElementTypePluralMap[ElementType]][UUID] {
+ const element = state[elementTypePluralMap[elementType]][
elementId
- ] as State[TypeSelectorMap[ElementType]][UUID];
+ ] as State[ElementTypePluralMap[ElementType]][UUID];
if (!element) {
throw new ReducerError(
`Element of type ${elementType} with id ${elementId} does not exist`
diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts
index f2d4f59bf..e129ca5ae 100644
--- a/shared/src/store/action-reducers/utils/spatial-elements.ts
+++ b/shared/src/store/action-reducers/utils/spatial-elements.ts
@@ -3,8 +3,8 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
import { cloneDeepMutable } from '../../../utils';
-import type { TypeSelectorMap } from '../../../utils/type-state-selector-map';
-import { typeSelectorMap } from '../../../utils/type-state-selector-map';
+import type { ElementTypePluralMap } from '../../../utils/type-state-selector-map';
+import { elementTypePluralMap } from '../../../utils/type-state-selector-map';
import { updateTreatments } from './calculate-treatments';
import { getElement } from './get-element';
@@ -14,8 +14,8 @@ import { getElement } from './get-element';
* In addition, the respective functions must be called when an element gets added or removed.
*/
type SpatialElementType = 'material' | 'patient' | 'personnel';
-type SpatialTypeSelectorMap = Pick;
-export type SpatialElementSelector = SpatialTypeSelectorMap[SpatialElementType];
+type SpatialTypePluralMap = Pick;
+export type SpatialElementPlural = SpatialTypePluralMap[SpatialElementType];
/**
* Adds an element with a position and executes side effects to guarantee the consistency of the state.
@@ -31,7 +31,7 @@ export function addElementPosition(
return;
}
SpatialTree.addElement(
- state.spatialTrees[typeSelectorMap[elementType]],
+ state.spatialTrees[elementTypePluralMap[elementType]],
element.id,
element.position
);
@@ -51,14 +51,14 @@ export function updateElementPosition(
const startPosition = element.position;
if (startPosition !== undefined) {
SpatialTree.moveElement(
- state.spatialTrees[typeSelectorMap[elementType]],
+ state.spatialTrees[elementTypePluralMap[elementType]],
element.id,
startPosition,
targetPosition
);
} else {
SpatialTree.addElement(
- state.spatialTrees[typeSelectorMap[elementType]],
+ state.spatialTrees[elementTypePluralMap[elementType]],
element.id,
targetPosition
);
@@ -85,7 +85,7 @@ export function removeElementPosition(
return;
}
SpatialTree.removeElement(
- state.spatialTrees[typeSelectorMap[elementType]],
+ state.spatialTrees[elementTypePluralMap[elementType]],
element.id,
element.position
);
diff --git a/shared/src/utils/type-state-selector-map.ts b/shared/src/utils/type-state-selector-map.ts
index 09ab1ac85..443ffbb3c 100644
--- a/shared/src/utils/type-state-selector-map.ts
+++ b/shared/src/utils/type-state-selector-map.ts
@@ -1,4 +1,10 @@
-export const typeSelectorMap = {
+// eslint-disable-next-line @typescript-eslint/no-shadow
+import type { Element } from '../models/element';
+import type { ExerciseState } from '../state';
+
+type ElementType = Element['type'];
+
+export const elementTypePluralMap = {
alarmGroup: 'alarmGroups',
client: 'clients',
hospital: 'hospitals',
@@ -10,6 +16,9 @@ export const typeSelectorMap = {
transferPoint: 'transferPoints',
vehicle: 'vehicles',
viewport: 'viewports',
-} as const;
-export type TypeSelectorMap = typeof typeSelectorMap;
+ // Typescript does not allow literal types for indexes
+ // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
+} as const satisfies Record;
+
+export type ElementTypePluralMap = typeof elementTypePluralMap;
From 8783aac7041617dae8ed43a7913fa79660be54e1 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Wed, 25 Jan 2023 14:15:11 +0100
Subject: [PATCH 07/18] Simplify featureKeys
---
.../exercise-map/feature-managers/element-manager.ts | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts
index 9e2d5cd07..664e37d3c 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts
@@ -24,7 +24,7 @@ export abstract class ElementManager<
*/
public onElementCreated(element: Element) {
const feature = this.createFeature(element);
- feature.set(featureKeys.value, element);
+ feature.set(featureElementKey, element);
}
/**
@@ -62,7 +62,7 @@ export abstract class ElementManager<
this.onElementCreated(newElement);
return;
}
- elementFeature.set(featureKeys.value, newElement);
+ elementFeature.set(featureElementKey, newElement);
this.changeFeature(
oldElement,
newElement,
@@ -110,7 +110,7 @@ export abstract class ElementManager<
): ElementFeature | undefined;
public getElementFromFeature(feature: Feature) {
- return feature.get(featureKeys.value);
+ return feature.get(featureElementKey);
}
private areAllPropertiesSupported(
@@ -128,6 +128,4 @@ export abstract class ElementManager<
/**
* The keys of the feature, where the type and most recent value of the respective element are saved to
*/
-const featureKeys = {
- value: 'elementValue',
-};
+const featureElementKey = 'element';
From 35519dcaea9ea47037617adac992aa2fb37aa1f9 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Wed, 25 Jan 2023 16:08:59 +0100
Subject: [PATCH 08/18] Fix tests by adding type property to demo objects
---
backend/src/fuesim-server.spec.ts | 1 +
.../utils/calculate-treatments.spec.ts | 12 ++++++------
shared/src/store/reduce-exercise-state.spec.ts | 1 +
shared/src/store/validate-exercise-action.spec.ts | 2 ++
4 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/backend/src/fuesim-server.spec.ts b/backend/src/fuesim-server.spec.ts
index 0d4cd3528..ae28339a5 100644
--- a/backend/src/fuesim-server.spec.ts
+++ b/backend/src/fuesim-server.spec.ts
@@ -38,6 +38,7 @@ describe('Exercise saving', () => {
alarmGroup: {
alarmGroupVehicles: {},
id: uuid(),
+ type: 'alarmGroup',
name: 'Alarm Group',
},
},
diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts
index e811becfc..ca0fde55a 100644
--- a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts
+++ b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts
@@ -22,7 +22,7 @@ interface Catering {
* The id of the material or personnel catering
*/
catererId: UUID;
- catererType: 'materials' | 'personnel';
+ catererType: 'material' | 'personnel';
/**
* All patients treated by {@link catererId}
*/
@@ -43,11 +43,11 @@ function assertCatering(
for (const catering of caterings) {
// Update all the patients
const patients = catering.patientIds.map((patientId) =>
- getElement(draftState, 'patients', patientId)
+ getElement(draftState, 'patient', patientId)
);
for (const patient of patients) {
patient[
- catering.catererType === 'materials'
+ catering.catererType === 'material'
? 'assignedMaterialIds'
: 'assignedPersonnelIds'
][catering.catererId] = true;
@@ -288,7 +288,7 @@ describe('calculate treatment', () => {
assertCatering(beforeState, newState, [
{
catererId: ids.material,
- catererType: 'materials',
+ catererType: 'material',
patientIds: [ids.greenPatient],
},
]);
@@ -324,7 +324,7 @@ describe('calculate treatment', () => {
assertCatering(beforeState, newState, [
{
catererId: ids.material,
- catererType: 'materials',
+ catererType: 'material',
patientIds: [ids.redPatient],
},
]);
@@ -392,7 +392,7 @@ describe('calculate treatment', () => {
assertCatering(beforeState, newState, [
{
catererId: ids.material,
- catererType: 'materials',
+ catererType: 'material',
patientIds: [ids.redPatient, ids.greenPatient],
},
]);
diff --git a/shared/src/store/reduce-exercise-state.spec.ts b/shared/src/store/reduce-exercise-state.spec.ts
index 49afadc2d..ac72e6cdd 100644
--- a/shared/src/store/reduce-exercise-state.spec.ts
+++ b/shared/src/store/reduce-exercise-state.spec.ts
@@ -12,6 +12,7 @@ describe('exerciseReducer', () => {
function generateViewport(): Viewport {
return {
id: uuid(),
+ type: 'viewport',
name: 'Test',
size: { width: 100, height: 100 },
position: { x: 0, y: 0 },
diff --git a/shared/src/store/validate-exercise-action.spec.ts b/shared/src/store/validate-exercise-action.spec.ts
index 9bc74a97d..da9aab590 100644
--- a/shared/src/store/validate-exercise-action.spec.ts
+++ b/shared/src/store/validate-exercise-action.spec.ts
@@ -71,6 +71,7 @@ describe('validateExerciseAction', () => {
type: '[Viewport] Add viewport',
viewport: {
id: 'b02c7756-ea52-427f-9fc3-0e163799544d',
+ type: 'viewport',
name: '',
size: {
height: 1,
@@ -112,6 +113,7 @@ describe('validateExerciseAction', () => {
type: '[Viewport] Add viewport',
viewport: {
id: 'b02c7756-ea52-427f-9fc3-0e163799544d',
+ type: 'viewport',
name: '',
size: {
height: 1,
From 7375f1015991575a0a162e658cbaa37a7f5d77b9 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Wed, 25 Jan 2023 18:29:07 +0100
Subject: [PATCH 09/18] WIP: Add migration
---
.../state-migrations/17-add-type-property.ts | 297 ++++++++++++++++++
.../state-migrations/migration-functions.ts | 2 +
shared/src/state.ts | 2 +-
3 files changed, 300 insertions(+), 1 deletion(-)
create mode 100644 shared/src/state-migrations/17-add-type-property.ts
diff --git a/shared/src/state-migrations/17-add-type-property.ts b/shared/src/state-migrations/17-add-type-property.ts
new file mode 100644
index 000000000..76a61f972
--- /dev/null
+++ b/shared/src/state-migrations/17-add-type-property.ts
@@ -0,0 +1,297 @@
+import type { UUID } from '../utils';
+import type { Migration } from './migration-functions';
+
+export const addTypeProperty17: Migration = {
+ actions: (_initialState, actions) => {
+ actions.forEach((action) => {
+ const actionType = (action as { type: string } | null)?.type;
+
+ if (actionType === '[AlarmGroup] Add AlarmGroup') {
+ const typedAction = action as {
+ alarmGroup: {
+ type: 'alarmGroup';
+ };
+ };
+
+ typedAction.alarmGroup.type = 'alarmGroup';
+ }
+
+ if (actionType === '[Client] Add client') {
+ const typedAction = action as {
+ client: {
+ type: 'client';
+ };
+ };
+
+ typedAction.client.type = 'client';
+ }
+
+ if (actionType === '[Hospital] Add hospital') {
+ const typedAction = action as {
+ hospital: {
+ type: 'hospital';
+ };
+ };
+
+ typedAction.hospital.type = 'hospital';
+ }
+
+ if (actionType === '[MapImageTemplate] Add mapImageTemplate') {
+ const typedAction = action as {
+ mapImageTemplate: {
+ type: 'mapImageTemplate';
+ };
+ };
+
+ typedAction.mapImageTemplate.type = 'mapImageTemplate';
+ }
+
+ if (actionType === '[MapImage] Add MapImage') {
+ const typedAction = action as {
+ mapImage: {
+ type: 'mapImage';
+ };
+ };
+
+ typedAction.mapImage.type = 'mapImage';
+ }
+
+ if (actionType === '[Patient] Add patient') {
+ const typedAction = action as {
+ patient: {
+ type: 'patient';
+ healthStates: {
+ [key: UUID]: { type: 'patientHealthState' };
+ };
+ };
+ };
+
+ typedAction.patient.type = 'patient';
+ Object.values(typedAction.patient.healthStates).forEach(
+ (healthState) => {
+ healthState.type = 'patientHealthState';
+ }
+ );
+ }
+
+ if (actionType === '[SimulatedRegion] Add simulated region') {
+ const typedAction = action as {
+ simulatedRegion: {
+ type: 'simulatedRegion';
+ };
+ };
+
+ typedAction.simulatedRegion.type = 'simulatedRegion';
+ }
+
+ if (actionType === '[TransferPoint] Add TransferPoint') {
+ const typedAction = action as {
+ transferPoint: {
+ type: 'transferPoint';
+ };
+ };
+
+ typedAction.transferPoint.type = 'transferPoint';
+ }
+
+ if (actionType === '[Vehicle] Add vehicle') {
+ const typedAction = action as {
+ vehicle: {
+ type: 'vehicle';
+ };
+ materials: { type: 'material' }[];
+ personnel: { type: 'personnel' }[];
+ };
+
+ typedAction.vehicle.type = 'vehicle';
+ typedAction.materials.forEach((material) => {
+ material.type = 'material';
+ });
+ typedAction.personnel.forEach((personnel) => {
+ personnel.type = 'personnel';
+ });
+ }
+
+ if (actionType === '[Viewport] Add viewport') {
+ const typedAction = action as {
+ viewport: {
+ type: 'viewport';
+ };
+ };
+
+ typedAction.viewport.type = 'viewport';
+ }
+ });
+ },
+ state: (state) => {
+ const typedState = state as {
+ alarmGroups: {
+ [key: UUID]: {
+ type: 'alarmGroup';
+ };
+ };
+ clients: {
+ [key: UUID]: {
+ type: 'client';
+ };
+ };
+ eocLog: { type: 'logEntry' }[];
+ configuration: { type: 'exerciseConfiguration' };
+ hospitalPatients: {
+ [key: UUID]: {
+ type: 'hospitalPatient';
+ };
+ };
+ hospitals: {
+ [key: UUID]: {
+ type: 'hospital';
+ };
+ };
+ mapImageTemplates: { type: 'mapImageTemplate' }[];
+ mapImages: {
+ [key: UUID]: {
+ type: 'mapImage';
+ };
+ };
+ materialTemplates: { type: 'materialTemplate' }[];
+ materials: {
+ [key: UUID]: {
+ type: 'material';
+ };
+ };
+ patientCategories: {
+ type: 'patientCategory';
+ patientTemplates: { type: 'patientTemplate' }[];
+ }[];
+ patients: {
+ [key: UUID]: {
+ type: 'patient';
+ healthStates: {
+ [key: UUID]: { type: 'patientHealthState' };
+ };
+ };
+ };
+ personnelTemplates: { type: 'personnelTemplate' }[];
+ personnel: {
+ [key: UUID]: {
+ type: 'personnel';
+ };
+ };
+ simulatedRegions: {
+ [key: UUID]: {
+ type: 'simulatedRegion';
+ };
+ };
+ transferPoints: {
+ [key: UUID]: {
+ type: 'transferPoint';
+ };
+ };
+ vehicleTemplates: { type: 'vehicleTemplate' }[];
+ vehicles: {
+ [key: UUID]: {
+ type: 'vehicle';
+ };
+ };
+ viewports: {
+ [key: UUID]: {
+ type: 'viewport';
+ };
+ };
+ };
+
+ Object.values(typedState.alarmGroups).forEach((alarmGroup) => {
+ alarmGroup.type = 'alarmGroup';
+ });
+
+ Object.values(typedState.clients).forEach((client) => {
+ client.type = 'client';
+ });
+
+ Object.values(typedState.eocLog).forEach((logEntry) => {
+ logEntry.type = 'logEntry';
+ });
+
+ typedState.configuration.type = 'exerciseConfiguration';
+
+ Object.values(typedState.hospitalPatients).forEach(
+ (hospitalPatient) => {
+ hospitalPatient.type = 'hospitalPatient';
+ }
+ );
+
+ Object.values(typedState.hospitals).forEach((hospital) => {
+ hospital.type = 'hospital';
+ });
+
+ Object.values(typedState.mapImageTemplates).forEach(
+ (mapImageTemplate) => {
+ mapImageTemplate.type = 'mapImageTemplate';
+ }
+ );
+
+ Object.values(typedState.mapImages).forEach((mapImage) => {
+ mapImage.type = 'mapImage';
+ });
+
+ Object.values(typedState.materialTemplates).forEach(
+ (materialTemplate) => {
+ materialTemplate.type = 'materialTemplate';
+ }
+ );
+
+ Object.values(typedState.materials).forEach((material) => {
+ material.type = 'material';
+ });
+
+ Object.values(typedState.patientCategories).forEach(
+ (patientCategory) => {
+ patientCategory.type = 'patientCategory';
+ patientCategory.patientTemplates.forEach((patientTemplate) => {
+ patientTemplate.type = 'patientTemplate';
+ });
+ }
+ );
+
+ Object.values(typedState.patients).forEach((patient) => {
+ patient.type = 'patient';
+ Object.values(patient.healthStates).forEach((healthState) => {
+ healthState.type = 'patientHealthState';
+ });
+ });
+
+ Object.values(typedState.personnelTemplates).forEach(
+ (personnelTemplates) => {
+ personnelTemplates.type = 'personnelTemplate';
+ }
+ );
+
+ Object.values(typedState.personnel).forEach((personnel) => {
+ personnel.type = 'personnel';
+ });
+
+ Object.values(typedState.simulatedRegions).forEach(
+ (simulatedRegion) => {
+ simulatedRegion.type = 'simulatedRegion';
+ }
+ );
+
+ Object.values(typedState.transferPoints).forEach((transferPoint) => {
+ transferPoint.type = 'transferPoint';
+ });
+
+ Object.values(typedState.vehicleTemplates).forEach(
+ (vehicleTemplate) => {
+ vehicleTemplate.type = 'vehicleTemplate';
+ }
+ );
+
+ Object.values(typedState.vehicles).forEach((vehicle) => {
+ vehicle.type = 'vehicle';
+ });
+
+ Object.values(typedState.viewports).forEach((viewport) => {
+ viewport.type = 'viewport';
+ });
+ },
+};
diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts
index 8bbed2f7b..965436bb5 100644
--- a/shared/src/state-migrations/migration-functions.ts
+++ b/shared/src/state-migrations/migration-functions.ts
@@ -5,6 +5,7 @@ import { addMapImageZIndex13 } from './13-add-map-image-zindex';
import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state';
import { addSimulatedRegions15 } from './15-add-simulated-regions';
import { addMetaPosition16 } from './16-add-meta-position';
+import { addTypeProperty17 } from './17-add-type-property';
import { updateEocLog3 } from './3-update-eoc-log';
import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action';
import { removeStatistics5 } from './5-remove-statistics';
@@ -55,4 +56,5 @@ export const migrations: {
14: addPersonnelAndMaterialToState14,
15: addSimulatedRegions15,
16: addMetaPosition16,
+ 17: addTypeProperty17,
};
diff --git a/shared/src/state.ts b/shared/src/state.ts
index 3601e4401..de96e2b71 100644
--- a/shared/src/state.ts
+++ b/shared/src/state.ts
@@ -148,5 +148,5 @@ export class ExerciseState {
*
* This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid.
*/
- static readonly currentStateVersion = 16;
+ static readonly currentStateVersion = 17;
}
From 41e0654e03fb26ecc62c145c7232a71546ed02c9 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 09:35:28 +0100
Subject: [PATCH 10/18] Update shared/src/utils/type-state-selector-map.ts
Co-authored-by: Julian Schmidt
---
shared/src/utils/type-state-selector-map.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/shared/src/utils/type-state-selector-map.ts b/shared/src/utils/type-state-selector-map.ts
index 443ffbb3c..4d28070b9 100644
--- a/shared/src/utils/type-state-selector-map.ts
+++ b/shared/src/utils/type-state-selector-map.ts
@@ -17,8 +17,6 @@ export const elementTypePluralMap = {
vehicle: 'vehicles',
viewport: 'viewports',
- // Typescript does not allow literal types for indexes
- // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
-} as const satisfies Record;
+} as const satisfies { [Key in ElementType]: keyof ExerciseState};
export type ElementTypePluralMap = typeof elementTypePluralMap;
From 06b3e37058f1d776b2dcb7c9a1849d25a9bea7ce Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 09:40:37 +0100
Subject: [PATCH 11/18] Rename file to reflect variable name change
---
shared/src/store/action-reducers/exercise.ts | 4 ++--
.../src/store/action-reducers/utils/calculate-treatments.ts | 2 +-
shared/src/store/action-reducers/utils/get-element.ts | 4 ++--
shared/src/store/action-reducers/utils/spatial-elements.ts | 4 ++--
...{type-state-selector-map.ts => element-type-plural-map.ts} | 0
5 files changed, 7 insertions(+), 7 deletions(-)
rename shared/src/utils/{type-state-selector-map.ts => element-type-plural-map.ts} (100%)
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index c3ac6b555..2236e1297 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -11,8 +11,8 @@ import { Patient } from '../../models';
import { getStatus } from '../../models/utils';
import type { ExerciseState } from '../../state';
import type { Mutable } from '../../utils';
-import type { ElementTypePluralMap } from '../../utils/type-state-selector-map';
-import { elementTypePluralMap } from '../../utils/type-state-selector-map';
+import type { ElementTypePluralMap } from '../../utils/element-type-plural-map';
+import { elementTypePluralMap } from '../../utils/element-type-plural-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts
index ce2921232..090729406 100644
--- a/shared/src/store/action-reducers/utils/calculate-treatments.ts
+++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts
@@ -6,7 +6,7 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range';
import type { Mutable, UUID } from '../../../utils';
-import { elementTypePluralMap } from '../../../utils/type-state-selector-map';
+import { elementTypePluralMap } from '../../../utils/element-type-plural-map';
import { getElement } from './get-element';
// TODO: `caterFor` and `treat` are currently used as synonyms without a clear distinction.
diff --git a/shared/src/store/action-reducers/utils/get-element.ts b/shared/src/store/action-reducers/utils/get-element.ts
index 8479887be..653f6087c 100644
--- a/shared/src/store/action-reducers/utils/get-element.ts
+++ b/shared/src/store/action-reducers/utils/get-element.ts
@@ -1,7 +1,7 @@
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
-import type { ElementTypePluralMap } from '../../../utils/type-state-selector-map';
-import { elementTypePluralMap } from '../../../utils/type-state-selector-map';
+import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map';
+import { elementTypePluralMap } from '../../../utils/element-type-plural-map';
import { ReducerError } from '../../reducer-error';
/**
diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts
index e129ca5ae..43fa7a604 100644
--- a/shared/src/store/action-reducers/utils/spatial-elements.ts
+++ b/shared/src/store/action-reducers/utils/spatial-elements.ts
@@ -3,8 +3,8 @@ import { SpatialTree } from '../../../models/utils/spatial-tree';
import type { ExerciseState } from '../../../state';
import type { Mutable, UUID } from '../../../utils';
import { cloneDeepMutable } from '../../../utils';
-import type { ElementTypePluralMap } from '../../../utils/type-state-selector-map';
-import { elementTypePluralMap } from '../../../utils/type-state-selector-map';
+import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map';
+import { elementTypePluralMap } from '../../../utils/element-type-plural-map';
import { updateTreatments } from './calculate-treatments';
import { getElement } from './get-element';
diff --git a/shared/src/utils/type-state-selector-map.ts b/shared/src/utils/element-type-plural-map.ts
similarity index 100%
rename from shared/src/utils/type-state-selector-map.ts
rename to shared/src/utils/element-type-plural-map.ts
From cc7ad9a226d38c95cbe7fdd79f0b32712622c9cc Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 10:21:26 +0100
Subject: [PATCH 12/18] Replace type literals by element property
---
.../send-alarm-group-interface.component.ts | 2 +-
shared/src/store/action-reducers/transfer-point.ts | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts
index 9e7adba02..06755aa93 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts
@@ -112,7 +112,7 @@ export class SendAlarmGroupInterfaceComponent implements OnDestroy {
}),
this.exerciseService.proposeAction({
type: '[Transfer] Add to transfer',
- elementType: 'vehicle',
+ elementType: vehicleParameters.vehicle.type,
elementId: vehicleParameters.vehicle.id,
startPoint: AlarmGroupStartPoint.create(
alarmGroup.name,
diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts
index caad44b2c..f72d916c9 100644
--- a/shared/src/store/action-reducers/transfer-point.ts
+++ b/shared/src/store/action-reducers/transfer-point.ts
@@ -243,7 +243,7 @@ export namespace TransferPointActionReducers {
vehicle.transfer?.targetTransferPointId ===
transferPointId
) {
- letElementArrive(draftState, 'vehicle', vehicleId);
+ letElementArrive(draftState, vehicle.type, vehicleId);
}
}
for (const personnelId of Object.keys(draftState.personnel)) {
@@ -256,7 +256,11 @@ export namespace TransferPointActionReducers {
personnel.transfer?.targetTransferPointId ===
transferPointId
) {
- letElementArrive(draftState, 'personnel', personnelId);
+ letElementArrive(
+ draftState,
+ personnel.type,
+ personnelId
+ );
}
}
// TODO: If we can assume that the transfer points are always connected to each other,
From e759288a1fec8a0b0a980603b6bed651b28af3fc Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 10:23:22 +0100
Subject: [PATCH 13/18] Run prettier
---
shared/src/utils/element-type-plural-map.ts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/shared/src/utils/element-type-plural-map.ts b/shared/src/utils/element-type-plural-map.ts
index 4d28070b9..630dcd7ef 100644
--- a/shared/src/utils/element-type-plural-map.ts
+++ b/shared/src/utils/element-type-plural-map.ts
@@ -16,7 +16,6 @@ export const elementTypePluralMap = {
transferPoint: 'transferPoints',
vehicle: 'vehicles',
viewport: 'viewports',
-
-} as const satisfies { [Key in ElementType]: keyof ExerciseState};
+} as const satisfies { [Key in ElementType]: keyof ExerciseState };
export type ElementTypePluralMap = typeof elementTypePluralMap;
From 366268c98ebb2ca705569f7e3895a87fb03a22eb Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 11:12:53 +0100
Subject: [PATCH 14/18] Finish migration
---
.../state-migrations/17-add-type-property.ts | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/shared/src/state-migrations/17-add-type-property.ts b/shared/src/state-migrations/17-add-type-property.ts
index 76a61f972..d56865040 100644
--- a/shared/src/state-migrations/17-add-type-property.ts
+++ b/shared/src/state-migrations/17-add-type-property.ts
@@ -84,6 +84,21 @@ export const addTypeProperty17: Migration = {
typedAction.simulatedRegion.type = 'simulatedRegion';
}
+ if (
+ actionType === '[Transfer] Add to transfer' ||
+ actionType === '[Transfer] Edit transfer' ||
+ actionType === '[Transfer] Finish transfer' ||
+ actionType === '[Transfer] Toggle pause transfer'
+ ) {
+ const typedAction = action as {
+ elementType: 'personnel' | 'vehicle' | 'vehicles';
+ };
+
+ if (typedAction.elementType === 'vehicles') {
+ typedAction.elementType = 'vehicle';
+ }
+ }
+
if (actionType === '[TransferPoint] Add TransferPoint') {
const typedAction = action as {
transferPoint: {
@@ -112,6 +127,23 @@ export const addTypeProperty17: Migration = {
});
}
+ if (actionType === '[Vehicle] Load vehicle') {
+ const typedAction = action as {
+ elementToBeLoadedType:
+ | 'material'
+ | 'materials'
+ | 'patient'
+ | 'patients'
+ | 'personnel';
+ };
+
+ if (typedAction.elementToBeLoadedType === 'materials') {
+ typedAction.elementToBeLoadedType = 'material';
+ } else if (typedAction.elementToBeLoadedType === 'patients') {
+ typedAction.elementToBeLoadedType = 'patient';
+ }
+ }
+
if (actionType === '[Viewport] Add viewport') {
const typedAction = action as {
viewport: {
From 84b8ed727e274f8e4b26651a64f7c501395bca2e Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 14:49:09 +0100
Subject: [PATCH 15/18] Fix migration to set correct type on EocLogEntry
---
shared/src/state-migrations/17-add-type-property.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/shared/src/state-migrations/17-add-type-property.ts b/shared/src/state-migrations/17-add-type-property.ts
index d56865040..afd36843f 100644
--- a/shared/src/state-migrations/17-add-type-property.ts
+++ b/shared/src/state-migrations/17-add-type-property.ts
@@ -167,7 +167,7 @@ export const addTypeProperty17: Migration = {
type: 'client';
};
};
- eocLog: { type: 'logEntry' }[];
+ eocLog: { type: 'eocLogEntry' }[];
configuration: { type: 'exerciseConfiguration' };
hospitalPatients: {
[key: UUID]: {
@@ -241,7 +241,7 @@ export const addTypeProperty17: Migration = {
});
Object.values(typedState.eocLog).forEach((logEntry) => {
- logEntry.type = 'logEntry';
+ logEntry.type = 'eocLogEntry';
});
typedState.configuration.type = 'exerciseConfiguration';
From fc368d9bd5df3a4487424ae08d37fde955c42904 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 14:51:01 +0100
Subject: [PATCH 16/18] Make imports consistent
---
shared/src/models/element.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/shared/src/models/element.ts b/shared/src/models/element.ts
index 7458f0e68..9aa445366 100644
--- a/shared/src/models/element.ts
+++ b/shared/src/models/element.ts
@@ -1,8 +1,8 @@
-import type { AlarmGroup } from './alarm-group';
-import type { Client } from './client';
-import type { Hospital } from './hospital';
-import type { MapImage } from './map-image';
import type {
+ AlarmGroup,
+ Client,
+ Hospital,
+ MapImage,
Material,
Patient,
Personnel,
From 38e92cac3f86fb1d705c704fef130a67c8218010 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 14:54:53 +0100
Subject: [PATCH 17/18] Reuse literal union from transfer in exercise
---
shared/src/store/action-reducers/exercise.ts | 4 ++--
shared/src/store/action-reducers/transfer.ts | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index 2236e1297..00eaf3a3f 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -16,7 +16,7 @@ import { elementTypePluralMap } from '../../utils/element-type-plural-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
-import { letElementArrive } from './transfer';
+import { letElementArrive, TransferableElementType } from './transfer';
import { updateTreatments } from './utils/calculate-treatments';
import { PatientUpdate } from './utils/patient-updates';
@@ -134,7 +134,7 @@ export namespace ExerciseActionReducers {
type TransferTypePluralMap = Pick<
ElementTypePluralMap,
- 'personnel' | 'vehicle'
+ TransferableElementType
>;
function refreshTransfer(
diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts
index b3ef2ed45..eb0b2f5f1 100644
--- a/shared/src/store/action-reducers/transfer.ts
+++ b/shared/src/store/action-reducers/transfer.ts
@@ -17,7 +17,7 @@ import {
updateElementPosition,
} from './utils/spatial-elements';
-type TransferableElementType = 'personnel' | 'vehicle';
+export type TransferableElementType = 'personnel' | 'vehicle';
const transferableElementTypeAllowedValues: AllowedValues =
{ personnel: true, vehicle: true };
From bab16eaea5a9f06104360397f0dc3655db8bd2e3 Mon Sep 17 00:00:00 2001
From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com>
Date: Thu, 26 Jan 2023 16:55:15 +0100
Subject: [PATCH 18/18] Fix linter
---
.../exercise-map/feature-managers/moveable-feature-manager.ts | 1 -
shared/src/store/action-reducers/exercise.ts | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts
index 162f6a3f4..94034d561 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts
@@ -1,4 +1,3 @@
-import type { ExerciseState } from 'digital-fuesim-manv-shared';
import type { MapBrowserEvent, Feature } from 'ol';
import type Point from 'ol/geom/Point';
import type { TranslateEvent } from 'ol/interaction/Translate';
diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts
index 00eaf3a3f..1fd29a514 100644
--- a/shared/src/store/action-reducers/exercise.ts
+++ b/shared/src/store/action-reducers/exercise.ts
@@ -16,7 +16,8 @@ import { elementTypePluralMap } from '../../utils/element-type-plural-map';
import { IsValue } from '../../utils/validators';
import type { Action, ActionReducer } from '../action-reducer';
import { ReducerError } from '../reducer-error';
-import { letElementArrive, TransferableElementType } from './transfer';
+import type { TransferableElementType } from './transfer';
+import { letElementArrive } from './transfer';
import { updateTreatments } from './utils/calculate-treatments';
import { PatientUpdate } from './utils/patient-updates';
|