diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f26e9382..d990ba0e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ## [Unreleased] +## [0.2.1] - 2023-03-11 + +### Changed + +- Revert previous change: Patients, vehicles, personnel and material inside a simulated region are now deleted, when the simulated region is deleted. For vehicles, personnel, and material, they will only be deleted if all that belong together are in the same simulated region. + +### Fixed + +- Exercises in which simulated regions are deleted no longer crash on import due missing patients in the tick action. + ## [0.2.0] - 2023-03-10 ### Added @@ -76,7 +86,8 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ### Initial unstable release of Digitale FüSim MANV -[Unreleased]: https://github.com/hpi-sam/digital-fuesim-manv/compare/0.2.0...HEAD -[0.2.0]: https://github.com/hpi-sam/digital-fuesim-manv/compare/0.1.0...0.2.0 -[0.1.0]: https://github.com/hpi-sam/digital-fuesim-manv/compare/v0.0.0...0.1.0 +[Unreleased]: https://github.com/hpi-sam/digital-fuesim-manv/compare/v0.2.1...HEAD +[0.2.1]: https://github.com/hpi-sam/digital-fuesim-manv/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/hpi-sam/digital-fuesim-manv/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/hpi-sam/digital-fuesim-manv/compare/v0.0.0...v0.1.0 [0.0.0]: https://github.com/hpi-sam/digital-fuesim-manv/compare/37bd43bc1beb4aa9ad597b1ac763dd71b5709737...v0.0.0 diff --git a/backend/package-lock.json b/backend/package-lock.json index 9ad1ae50d..fdd692754 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", @@ -48,7 +48,7 @@ }, "../shared": { "name": "digital-fuesim-manv-shared", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/backend/package.json b/backend/package.json index f67268e39..b5df44e29 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.2.0", + "version": "0.2.1", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 8bc39c217..1950c3be8 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", @@ -32,7 +32,7 @@ }, "../shared": { "name": "digital-fuesim-manv-shared", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/benchmark/package.json b/benchmark/package.json index 5012c944f..b27c0aa8c 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "0.2.0", + "version": "0.2.1", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index 8a4dab549..68b001e8f 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 0.2.0 + version: 0.2.1 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 834ee2f1e..cb2ba42cc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", @@ -66,7 +66,7 @@ }, "../shared": { "name": "digital-fuesim-manv-shared", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/frontend/package.json b/frontend/package.json index e585d1d70..9577883cb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.2.0", + "version": "0.2.1", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index 876cc70f6..479b94309 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "0.2.0", + "version": "0.2.1", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index b6967417f..92f72cda1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "0.2.0", + "version": "0.2.1", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index de40c1299..75b12bf8b 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "0.2.0", + "version": "0.2.1", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 8edac5b64..f8ff900e4 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.2.0", + "version": "0.2.1", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts index 81e5d38af..0dec676d8 100644 --- a/shared/src/store/action-reducers/simulated-region.ts +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -3,7 +3,6 @@ import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { SimulatedRegion, TransferPoint } from '../../models'; import { isInSpecificSimulatedRegion, - isInSpecificVehicle, MapCoordinates, MapPosition, SimulatedRegionPosition, @@ -22,103 +21,14 @@ import { MaterialAvailableEvent, } from '../../simulation'; import { sendSimulationEvent } from '../../simulation/events/utils'; -import type { ExerciseState } from '../../state'; -import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ExpectedReducerError, ReducerError } from '../reducer-error'; -import { - deleteTransferPoint, - TransferPointActionReducers, -} from './transfer-point'; +import { TransferPointActionReducers } from './transfer-point'; import { isCompletelyLoaded } from './utils/completely-load-vehicle'; import { getElement, getElementByPredicate } from './utils/get-element'; -/** - * This function assumes that every SimulatedRegion holds **ONLY** material,vehicles,patients and personnel - * (in any amount) and **ONE** TransferPoint. - * It only deletes material,vehicles and personnel if they are **ALL** in the SimulatedRegion to be deleted - * If one were to add more things to a SimulatedRegion one would have to change this function accordingly. - * @param draftState: The Draft State from which the SimulatedRegion should be deleted. - * @param simulatedRegionId: The Id of the SimulatedRegion that should be deleted. - */ - -export function deleteSimulatedRegion( - draftState: Mutable, - simulatedRegionId: UUID -) { - // Delete the TransferPoint - - const simulatedRegion = getElement( - draftState, - 'simulatedRegion', - simulatedRegionId - ); - - const transferPointId = getElementByPredicate( - draftState, - 'transferPoint', - (element) => isInSpecificSimulatedRegion(element, simulatedRegion.id) - ).id; - - deleteTransferPoint(draftState, transferPointId); - - // Find related vehicles - - const relatedVehicles = Object.values(draftState.vehicles).filter( - (vehicle) => - isInSpecificSimulatedRegion(vehicle, simulatedRegionId) && - Object.keys(vehicle.materialIds).every((materialId) => { - const material = getElement(draftState, 'material', materialId); - return ( - isInSpecificSimulatedRegion(material, simulatedRegionId) || - isInSpecificVehicle(material, vehicle.id) - ); - }) && - Object.keys(vehicle.personnelIds).every((personnelId) => { - const personnel = getElement( - draftState, - 'personnel', - personnelId - ); - return ( - isInSpecificSimulatedRegion(personnel, simulatedRegionId) || - isInSpecificVehicle(personnel, vehicle.id) - ); - }) - ); - - // Find and delete related materials and personnel - - relatedVehicles.forEach((vehicle) => { - Object.keys(vehicle.materialIds).forEach( - (vehicleId) => delete draftState.materials[vehicleId] - ); - Object.keys(vehicle.personnelIds).forEach( - (personnelId) => delete draftState.personnel[personnelId] - ); - }); - - // Delete related vehicles - - relatedVehicles.forEach( - (vehicle) => delete draftState.vehicles[vehicle.id] - ); - - // Find and delete related patients - - Object.values(draftState.patients) - .filter((patients) => - isInSpecificSimulatedRegion(patients, simulatedRegionId) - ) - .forEach((patients) => delete draftState.patients[patients.id]); - - // Delete the SimulatedRegion - - delete draftState.simulatedRegions[simulatedRegionId]; -} - export class AddSimulatedRegionAction implements Action { @IsValue('[SimulatedRegion] Add simulated region' as const) readonly type = '[SimulatedRegion] Add simulated region'; @@ -236,7 +146,25 @@ export namespace SimulatedRegionActionReducers { { action: RemoveSimulatedRegionAction, reducer: (draftState, { simulatedRegionId }) => { - deleteSimulatedRegion(draftState, simulatedRegionId); + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); + const transferPoint = getElementByPredicate( + draftState, + 'transferPoint', + (element) => + isInSpecificSimulatedRegion(element, simulatedRegion.id) + ); + TransferPointActionReducers.removeTransferPoint.reducer( + draftState, + { + type: '[TransferPoint] Remove TransferPoint', + transferPointId: transferPoint.id, + } + ); + delete draftState.simulatedRegions[simulatedRegionId]; return draftState; }, rights: 'trainer', diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts index b347ed95b..2580777cc 100644 --- a/shared/src/store/action-reducers/transfer-point.ts +++ b/shared/src/store/action-reducers/transfer-point.ts @@ -15,8 +15,6 @@ import { nestedCoordinatesOf, } from '../../models/utils'; import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; -import type { ExerciseState } from '../../state'; -import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; @@ -25,49 +23,6 @@ import { letElementArrive } from './transfer'; import { calculateDistance } from './utils/calculate-distance'; import { getElement } from './utils/get-element'; -export function deleteTransferPoint( - draftState: Mutable, - transferPointId: UUID -) { - // check if transferPoint exists - 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, 'vehicle', vehicleId); - if ( - isInTransfer(vehicle) && - currentTransferOf(vehicle).targetTransferPointId === transferPointId - ) { - letElementArrive(draftState, vehicle.type, vehicleId); - } - } - for (const personnelId of Object.keys(draftState.personnel)) { - const personnel = getElement(draftState, 'personnel', personnelId); - if ( - isInTransfer(personnel) && - currentTransferOf(personnel).targetTransferPointId === - transferPointId - ) { - letElementArrive(draftState, personnel.type, personnelId); - } - } - // TODO: If we can assume that the transfer points are always connected to each other, - // we could just iterate over draftState.transferPoints[transferPointId].reachableTransferPoints - for (const transferPoint of Object.values(draftState.transferPoints)) { - for (const connectedTransferPointId of Object.keys( - transferPoint.reachableTransferPoints - )) { - const connectedTransferPoint = - draftState.transferPoints[connectedTransferPointId]!; - delete connectedTransferPoint.reachableTransferPoints[ - transferPointId - ]; - } - } - delete draftState.transferPoints[transferPointId]; -} - // TODO check: type "TransferPoint" the T is big, in other files, the second word starts with a small letter export class AddTransferPointAction implements Action { @@ -281,7 +236,60 @@ export namespace TransferPointActionReducers { { action: RemoveTransferPointAction, reducer: (draftState, { transferPointId }) => { - deleteTransferPoint(draftState, transferPointId); + // check if transferPoint exists + 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, + 'vehicle', + vehicleId + ); + if ( + isInTransfer(vehicle) && + currentTransferOf(vehicle).targetTransferPointId === + transferPointId + ) { + letElementArrive(draftState, vehicle.type, vehicleId); + } + } + for (const personnelId of Object.keys(draftState.personnel)) { + const personnel = getElement( + draftState, + 'personnel', + personnelId + ); + if ( + isInTransfer(personnel) && + currentTransferOf(personnel).targetTransferPointId === + transferPointId + ) { + letElementArrive( + draftState, + personnel.type, + personnelId + ); + } + } + // TODO: If we can assume that the transfer points are always connected to each other, + // we could just iterate over draftState.transferPoints[transferPointId].reachableTransferPoints + for (const transferPoint of Object.values( + draftState.transferPoints + )) { + for (const connectedTransferPointId of Object.keys( + transferPoint.reachableTransferPoints + )) { + const connectedTransferPoint = + draftState.transferPoints[ + connectedTransferPointId + ]!; + delete connectedTransferPoint.reachableTransferPoints[ + transferPointId + ]; + } + } + delete draftState.transferPoints[transferPointId]; return draftState; }, rights: 'trainer',