diff options
Diffstat (limited to 'frontend/src/sagas')
| -rw-r--r-- | frontend/src/sagas/experiments.js | 183 | ||||
| -rw-r--r-- | frontend/src/sagas/index.js | 106 | ||||
| -rw-r--r-- | frontend/src/sagas/objects.js | 140 | ||||
| -rw-r--r-- | frontend/src/sagas/profile.js | 12 | ||||
| -rw-r--r-- | frontend/src/sagas/simulations.js | 51 | ||||
| -rw-r--r-- | frontend/src/sagas/topology.js | 434 | ||||
| -rw-r--r-- | frontend/src/sagas/users.js | 50 |
7 files changed, 976 insertions, 0 deletions
diff --git a/frontend/src/sagas/experiments.js b/frontend/src/sagas/experiments.js new file mode 100644 index 00000000..d9c410f7 --- /dev/null +++ b/frontend/src/sagas/experiments.js @@ -0,0 +1,183 @@ +import { call, put, select, delay } from "redux-saga/effects"; +import { addPropToStoreObject, addToStore } from "../actions/objects"; +import { setLastSimulatedTick } from "../actions/simulation/tick"; +import { addBatchToStates } from "../actions/states"; +import { + deleteExperiment, + getAllMachineStates, + getAllRackStates, + getAllRoomStates, + getAllTaskStates, + getExperiment, + getLastSimulatedTick +} from "../api/routes/experiments"; +import { getTasksOfJob } from "../api/routes/jobs"; +import { + addExperiment, + getExperimentsOfSimulation, + getSimulation +} from "../api/routes/simulations"; +import { getJobsOfTrace } from "../api/routes/traces"; +import { + fetchAndStoreAllSchedulers, + fetchAndStoreAllTraces, + fetchAndStorePathsOfSimulation +} from "./objects"; +import { fetchAllDatacentersOfExperiment } from "./topology"; + +export function* onOpenExperimentSucceeded(action) { + try { + const simulation = yield call(getSimulation, action.simulationId); + yield put(addToStore("simulation", simulation)); + + const experiment = yield call(getExperiment, action.experimentId); + yield put(addToStore("experiment", experiment)); + + yield fetchExperimentSpecifications(); + yield fetchWorkloadOfTrace(experiment.traceId); + + yield fetchAllDatacentersOfExperiment(experiment); + yield startStateFetchLoop(action.experimentId); + } catch (error) { + console.error(error); + } +} + +function* startStateFetchLoop(experimentId) { + try { + while ((yield select(state => state.currentExperimentId)) !== -1) { + const lastSimulatedTick = (yield call(getLastSimulatedTick, experimentId)) + .lastSimulatedTick; + if ( + lastSimulatedTick !== (yield select(state => state.lastSimulatedTick)) + ) { + yield put(setLastSimulatedTick(lastSimulatedTick)); + + const taskStates = yield call(getAllTaskStates, experimentId); + const machineStates = yield call(getAllMachineStates, experimentId); + const rackStates = yield call(getAllRackStates, experimentId); + const roomStates = yield call(getAllRoomStates, experimentId); + + yield put(addBatchToStates("task", taskStates)); + yield put(addBatchToStates("machine", machineStates)); + yield put(addBatchToStates("rack", rackStates)); + yield put(addBatchToStates("room", roomStates)); + + yield delay(5000); + } else { + yield delay(10000); + } + } + } catch (error) { + console.error(error); + } +} + +export function* onFetchExperimentsOfSimulation() { + try { + const currentSimulationId = yield select( + state => state.currentSimulationId + ); + + yield fetchExperimentSpecifications(); + const experiments = yield call( + getExperimentsOfSimulation, + currentSimulationId + ); + for (let i in experiments) { + yield put(addToStore("experiment", experiments[i])); + } + yield put( + addPropToStoreObject("simulation", currentSimulationId, { + experimentIds: experiments.map(experiment => experiment.id) + }) + ); + } catch (error) { + console.error(error); + } +} + +function* fetchExperimentSpecifications() { + try { + const currentSimulationId = yield select( + state => state.currentSimulationId + ); + yield fetchAndStorePathsOfSimulation(currentSimulationId); + yield fetchAndStoreAllTraces(); + yield fetchAndStoreAllSchedulers(); + } catch (error) { + console.error(error); + } +} + +function* fetchWorkloadOfTrace(traceId) { + try { + const jobs = yield call(getJobsOfTrace, traceId); + for (let i in jobs) { + const job = jobs[i]; + const tasks = yield call(getTasksOfJob, job.id); + job.taskIds = tasks.map(task => task.id); + for (let j in tasks) { + yield put(addToStore("task", tasks[j])); + } + yield put(addToStore("job", job)); + } + yield put( + addPropToStoreObject("trace", traceId, { + jobIds: jobs.map(job => job.id) + }) + ); + } catch (error) { + console.error(error); + } +} + +export function* onAddExperiment(action) { + try { + const currentSimulationId = yield select( + state => state.currentSimulationId + ); + + const experiment = yield call( + addExperiment, + currentSimulationId, + Object.assign({}, action.experiment, { + id: -1, + simulationId: currentSimulationId + }) + ); + yield put(addToStore("experiment", experiment)); + + const experimentIds = yield select( + state => state.objects.simulation[currentSimulationId].experimentIds + ); + yield put( + addPropToStoreObject("simulation", currentSimulationId, { + experimentIds: experimentIds.concat([experiment.id]) + }) + ); + } catch (error) { + console.error(error); + } +} + +export function* onDeleteExperiment(action) { + try { + yield call(deleteExperiment, action.id); + + const currentSimulationId = yield select( + state => state.currentSimulationId + ); + const experimentIds = yield select( + state => state.objects.simulation[currentSimulationId].experimentIds + ); + + yield put( + addPropToStoreObject("simulation", currentSimulationId, { + experimentIds: experimentIds.filter(id => id !== action.id) + }) + ); + } catch (error) { + console.error(error); + } +} diff --git a/frontend/src/sagas/index.js b/frontend/src/sagas/index.js new file mode 100644 index 00000000..56c8f09b --- /dev/null +++ b/frontend/src/sagas/index.js @@ -0,0 +1,106 @@ +import { takeEvery } from "redux-saga/effects"; +import { LOG_IN } from "../actions/auth"; +import { + ADD_EXPERIMENT, + DELETE_EXPERIMENT, + FETCH_EXPERIMENTS_OF_SIMULATION, + OPEN_EXPERIMENT_SUCCEEDED +} from "../actions/experiments"; +import { + ADD_SIMULATION, + DELETE_SIMULATION, + OPEN_SIMULATION_SUCCEEDED +} from "../actions/simulations"; +import { + ADD_TILE, + CANCEL_NEW_ROOM_CONSTRUCTION, + DELETE_TILE, + START_NEW_ROOM_CONSTRUCTION +} from "../actions/topology/building"; +import { + ADD_UNIT, + DELETE_MACHINE, + DELETE_UNIT +} from "../actions/topology/machine"; +import { + ADD_MACHINE, + DELETE_RACK, + EDIT_RACK_NAME +} from "../actions/topology/rack"; +import { + ADD_RACK_TO_TILE, + DELETE_ROOM, + EDIT_ROOM_NAME +} from "../actions/topology/room"; +import { + DELETE_CURRENT_USER, + FETCH_AUTHORIZATIONS_OF_CURRENT_USER +} from "../actions/users"; +import { + onAddExperiment, + onDeleteExperiment, + onFetchExperimentsOfSimulation, + onOpenExperimentSucceeded +} from "./experiments"; +import { onDeleteCurrentUser } from "./profile"; +import { + onOpenSimulationSucceeded, + onSimulationAdd, + onSimulationDelete +} from "./simulations"; +import { + onAddMachine, + onAddRackToTile, + onAddTile, + onAddUnit, + onCancelNewRoomConstruction, + onDeleteMachine, + onDeleteRack, + onDeleteRoom, + onDeleteTile, + onDeleteUnit, + onEditRackName, + onEditRoomName, + onStartNewRoomConstruction +} from "./topology"; +import { + onFetchAuthorizationsOfCurrentUser, + onFetchLoggedInUser +} from "./users"; + +export default function* rootSaga() { + yield takeEvery(LOG_IN, onFetchLoggedInUser); + + yield takeEvery( + FETCH_AUTHORIZATIONS_OF_CURRENT_USER, + onFetchAuthorizationsOfCurrentUser + ); + yield takeEvery(ADD_SIMULATION, onSimulationAdd); + yield takeEvery(DELETE_SIMULATION, onSimulationDelete); + + yield takeEvery(DELETE_CURRENT_USER, onDeleteCurrentUser); + + yield takeEvery(OPEN_SIMULATION_SUCCEEDED, onOpenSimulationSucceeded); + yield takeEvery(OPEN_EXPERIMENT_SUCCEEDED, onOpenExperimentSucceeded); + + yield takeEvery(START_NEW_ROOM_CONSTRUCTION, onStartNewRoomConstruction); + yield takeEvery(CANCEL_NEW_ROOM_CONSTRUCTION, onCancelNewRoomConstruction); + yield takeEvery(ADD_TILE, onAddTile); + yield takeEvery(DELETE_TILE, onDeleteTile); + yield takeEvery(EDIT_ROOM_NAME, onEditRoomName); + yield takeEvery(DELETE_ROOM, onDeleteRoom); + yield takeEvery(EDIT_RACK_NAME, onEditRackName); + yield takeEvery(DELETE_RACK, onDeleteRack); + yield takeEvery(ADD_RACK_TO_TILE, onAddRackToTile); + yield takeEvery(ADD_MACHINE, onAddMachine); + yield takeEvery(DELETE_MACHINE, onDeleteMachine); + yield takeEvery(ADD_UNIT, onAddUnit); + yield takeEvery(DELETE_UNIT, onDeleteUnit); + + yield takeEvery( + FETCH_EXPERIMENTS_OF_SIMULATION, + onFetchExperimentsOfSimulation + ); + yield takeEvery(ADD_EXPERIMENT, onAddExperiment); + yield takeEvery(DELETE_EXPERIMENT, onDeleteExperiment); +} diff --git a/frontend/src/sagas/objects.js b/frontend/src/sagas/objects.js new file mode 100644 index 00000000..3cfd43a6 --- /dev/null +++ b/frontend/src/sagas/objects.js @@ -0,0 +1,140 @@ +import { call, put, select } from "redux-saga/effects"; +import { addToStore } from "../actions/objects"; +import { getDatacenter, getRoomsOfDatacenter } from "../api/routes/datacenters"; +import { getPath, getSectionsOfPath } from "../api/routes/paths"; +import { getTilesOfRoom } from "../api/routes/rooms"; +import { getAllSchedulers } from "../api/routes/schedulers"; +import { getSection } from "../api/routes/sections"; +import { getPathsOfSimulation, getSimulation } from "../api/routes/simulations"; +import { + getAllCPUs, + getAllGPUs, + getAllMemories, + getAllStorages, + getCoolingItem, + getCPU, + getFailureModel, + getGPU, + getMemory, + getPSU, + getStorage +} from "../api/routes/specifications"; +import { getMachinesOfRackByTile, getRackByTile } from "../api/routes/tiles"; +import { getAllTraces } from "../api/routes/traces"; +import { getUser } from "../api/routes/users"; + +export const OBJECT_SELECTORS = { + simulation: state => state.objects.simulation, + user: state => state.objects.user, + authorization: state => state.objects.authorization, + failureModel: state => state.objects.failureModel, + cpu: state => state.objects.cpu, + gpu: state => state.objects.gpu, + memory: state => state.objects.memory, + storage: state => state.objects.storage, + machine: state => state.objects.machine, + rack: state => state.objects.rack, + coolingItem: state => state.objects.coolingItem, + psu: state => state.objects.psu, + tile: state => state.objects.tile, + room: state => state.objects.room, + datacenter: state => state.objects.datacenter, + section: state => state.objects.section, + path: state => state.objects.path +}; + +function* fetchAndStoreObject(objectType, id, apiCall) { + const objectStore = yield select(OBJECT_SELECTORS[objectType]); + let object = objectStore[id]; + if (!object) { + object = yield apiCall; + yield put(addToStore(objectType, object)); + } + return object; +} + +function* fetchAndStoreObjects(objectType, apiCall) { + const objects = yield apiCall; + for (let index in objects) { + yield put(addToStore(objectType, objects[index])); + } + return objects; +} + +export const fetchAndStoreSimulation = id => + fetchAndStoreObject("simulation", id, call(getSimulation, id)); + +export const fetchAndStoreUser = id => + fetchAndStoreObject("user", id, call(getUser, id)); + +export const fetchAndStoreFailureModel = id => + fetchAndStoreObject("failureModel", id, call(getFailureModel, id)); + +export const fetchAndStoreAllCPUs = () => + fetchAndStoreObjects("cpu", call(getAllCPUs)); + +export const fetchAndStoreCPU = id => + fetchAndStoreObject("cpu", id, call(getCPU, id)); + +export const fetchAndStoreAllGPUs = () => + fetchAndStoreObjects("gpu", call(getAllGPUs)); + +export const fetchAndStoreGPU = id => + fetchAndStoreObject("gpu", id, call(getGPU, id)); + +export const fetchAndStoreAllMemories = () => + fetchAndStoreObjects("memory", call(getAllMemories)); + +export const fetchAndStoreMemory = id => + fetchAndStoreObject("memory", id, call(getMemory, id)); + +export const fetchAndStoreAllStorages = () => + fetchAndStoreObjects("storage", call(getAllStorages)); + +export const fetchAndStoreStorage = id => + fetchAndStoreObject("storage", id, call(getStorage, id)); + +export const fetchAndStoreMachinesOfTile = tileId => + fetchAndStoreObjects("machine", call(getMachinesOfRackByTile, tileId)); + +export const fetchAndStoreRackOnTile = (id, tileId) => + fetchAndStoreObject("rack", id, call(getRackByTile, tileId)); + +export const fetchAndStoreCoolingItem = id => + fetchAndStoreObject("coolingItem", id, call(getCoolingItem, id)); + +export const fetchAndStorePSU = id => + fetchAndStoreObject("psu", id, call(getPSU, id)); + +export const fetchAndStoreTilesOfRoom = roomId => + fetchAndStoreObjects("tile", call(getTilesOfRoom, roomId)); + +export const fetchAndStoreRoomsOfDatacenter = datacenterId => + fetchAndStoreObjects("room", call(getRoomsOfDatacenter, datacenterId)); + +export const fetchAndStoreDatacenter = id => + fetchAndStoreObject("datacenter", id, call(getDatacenter, id)); + +export const fetchAndStoreSection = id => + fetchAndStoreObject("section", id, call(getSection, id)); + +export const fetchAndStoreSectionsOfPath = pathId => + fetchAndStoreObjects("section", call(getSectionsOfPath, pathId)); + +export const fetchAndStorePath = id => + fetchAndStoreObject("path", id, call(getPath, id)); + +export const fetchAndStorePathsOfSimulation = simulationId => + fetchAndStoreObjects("path", call(getPathsOfSimulation, simulationId)); + +export const fetchAndStoreAllTraces = () => + fetchAndStoreObjects("trace", call(getAllTraces)); + +export const fetchAndStoreAllSchedulers = function*() { + const objects = yield call(getAllSchedulers); + for (let index in objects) { + objects[index].id = objects[index].name; + yield put(addToStore("scheduler", objects[index])); + } + return objects; +}; diff --git a/frontend/src/sagas/profile.js b/frontend/src/sagas/profile.js new file mode 100644 index 00000000..31d4dd4f --- /dev/null +++ b/frontend/src/sagas/profile.js @@ -0,0 +1,12 @@ +import { call, put } from "redux-saga/effects"; +import { deleteCurrentUserSucceeded } from "../actions/users"; +import { deleteUser } from "../api/routes/users"; + +export function* onDeleteCurrentUser(action) { + try { + yield call(deleteUser, action.userId); + yield put(deleteCurrentUserSucceeded()); + } catch (error) { + console.error(error); + } +} diff --git a/frontend/src/sagas/simulations.js b/frontend/src/sagas/simulations.js new file mode 100644 index 00000000..9df4e4b5 --- /dev/null +++ b/frontend/src/sagas/simulations.js @@ -0,0 +1,51 @@ +import { call, put } from "redux-saga/effects"; +import { addToStore } from "../actions/objects"; +import { + addSimulationSucceeded, + deleteSimulationSucceeded +} from "../actions/simulations"; +import { + addSimulation, + deleteSimulation, + getSimulation +} from "../api/routes/simulations"; +import { fetchLatestDatacenter } from "./topology"; + +export function* onOpenSimulationSucceeded(action) { + try { + const simulation = yield call(getSimulation, action.id); + yield put(addToStore("simulation", simulation)); + + yield fetchLatestDatacenter(action.id); + } catch (error) { + console.error(error); + } +} + +export function* onSimulationAdd(action) { + try { + const simulation = yield call(addSimulation, { name: action.name }); + yield put(addToStore("simulation", simulation)); + + const authorization = { + simulationId: simulation.id, + userId: action.userId, + authorizationLevel: "OWN" + }; + yield put(addToStore("authorization", authorization)); + yield put( + addSimulationSucceeded([authorization.userId, authorization.simulationId]) + ); + } catch (error) { + console.error(error); + } +} + +export function* onSimulationDelete(action) { + try { + yield call(deleteSimulation, action.id); + yield put(deleteSimulationSucceeded(action.id)); + } catch (error) { + console.error(error); + } +} diff --git a/frontend/src/sagas/topology.js b/frontend/src/sagas/topology.js new file mode 100644 index 00000000..13b4ed17 --- /dev/null +++ b/frontend/src/sagas/topology.js @@ -0,0 +1,434 @@ +import { call, put, select } from "redux-saga/effects"; +import { goDownOneInteractionLevel } from "../actions/interaction-level"; +import { + addIdToStoreObjectListProp, + addPropToStoreObject, + addToStore, + removeIdFromStoreObjectListProp +} from "../actions/objects"; +import { + cancelNewRoomConstructionSucceeded, + setCurrentDatacenter, + startNewRoomConstructionSucceeded +} from "../actions/topology/building"; +import { addRoomToDatacenter } from "../api/routes/datacenters"; +import { addTileToRoom, deleteRoom, updateRoom } from "../api/routes/rooms"; +import { + addMachineToRackOnTile, + addRackToTile, + deleteMachineInRackOnTile, + deleteRackFromTile, + deleteTile, + updateMachineInRackOnTile, + updateRackOnTile +} from "../api/routes/tiles"; +import { + DEFAULT_RACK_POWER_CAPACITY, + DEFAULT_RACK_SLOT_CAPACITY, + MAX_NUM_UNITS_PER_MACHINE +} from "../components/app/map/MapConstants"; +import { + fetchAndStoreAllCPUs, + fetchAndStoreAllGPUs, + fetchAndStoreAllMemories, + fetchAndStoreAllStorages, + fetchAndStoreCoolingItem, + fetchAndStoreCPU, + fetchAndStoreDatacenter, + fetchAndStoreGPU, + fetchAndStoreMachinesOfTile, + fetchAndStoreMemory, + fetchAndStorePath, + fetchAndStorePathsOfSimulation, + fetchAndStorePSU, + fetchAndStoreRackOnTile, + fetchAndStoreRoomsOfDatacenter, + fetchAndStoreSectionsOfPath, + fetchAndStoreStorage, + fetchAndStoreTilesOfRoom +} from "./objects"; + +export function* fetchLatestDatacenter(simulationId) { + try { + const paths = yield fetchAndStorePathsOfSimulation(simulationId); + const latestPath = paths[paths.length - 1]; + const sections = yield fetchAndStoreSectionsOfPath(latestPath.id); + const latestSection = sections[sections.length - 1]; + yield fetchAllUnitSpecifications(); + yield fetchDatacenter(latestSection.datacenterId); + yield put(setCurrentDatacenter(latestSection.datacenterId)); + } catch (error) { + console.error(error); + } +} + +export function* fetchAllDatacentersOfExperiment(experiment) { + try { + const path = yield fetchAndStorePath(experiment.pathId); + const sections = yield fetchAndStoreSectionsOfPath(path.id); + path.sectionIds = sections.map(section => section.id); + yield fetchAllUnitSpecifications(); + + for (let i in sections) { + yield fetchDatacenter(sections[i].datacenterId); + } + yield put(setCurrentDatacenter(sections[0].datacenterId)); + } catch (error) { + console.error(error); + } +} + +function* fetchDatacenter(datacenterId) { + try { + yield fetchAndStoreDatacenter(datacenterId); + const rooms = yield fetchAndStoreRoomsOfDatacenter(datacenterId); + yield put( + addPropToStoreObject("datacenter", datacenterId, { + roomIds: rooms.map(room => room.id) + }) + ); + + for (let index in rooms) { + yield fetchRoom(rooms[index].id); + } + } catch (error) { + console.error(error); + } +} + +function* fetchAllUnitSpecifications() { + try { + yield fetchAndStoreAllCPUs(); + yield fetchAndStoreAllGPUs(); + yield fetchAndStoreAllMemories(); + yield fetchAndStoreAllStorages(); + } catch (error) { + console.error(error); + } +} + +function* fetchRoom(roomId) { + const tiles = yield fetchAndStoreTilesOfRoom(roomId); + yield put( + addPropToStoreObject("room", roomId, { + tileIds: tiles.map(tile => tile.id) + }) + ); + + for (let index in tiles) { + yield fetchTile(tiles[index]); + } +} + +function* fetchTile(tile) { + if (!tile.objectType) { + return; + } + + switch (tile.objectType) { + case "RACK": + const rack = yield fetchAndStoreRackOnTile(tile.objectId, tile.id); + yield put(addPropToStoreObject("tile", tile.id, { rackId: rack.id })); + yield fetchMachinesOfRack(tile.id, rack); + break; + case "COOLING_ITEM": + const coolingItem = yield fetchAndStoreCoolingItem(tile.objectId); + yield put( + addPropToStoreObject("tile", tile.id, { coolingItemId: coolingItem.id }) + ); + break; + case "PSU": + const psu = yield fetchAndStorePSU(tile.objectId); + yield put(addPropToStoreObject("tile", tile.id, { psuId: psu.id })); + break; + default: + console.warn("Unknown rack type encountered while fetching tile objects"); + } +} + +function* fetchMachinesOfRack(tileId, rack) { + const machines = yield fetchAndStoreMachinesOfTile(tileId); + const machineIds = new Array(rack.capacity).fill(null); + machines.forEach(machine => (machineIds[machine.position - 1] = machine.id)); + + yield put(addPropToStoreObject("rack", rack.id, { machineIds })); + + for (let index in machines) { + for (let i in machines[index].cpuIds) { + yield fetchAndStoreCPU(machines[index].cpuIds[i]); + } + for (let i in machines[index].gpuIds) { + yield fetchAndStoreGPU(machines[index].gpuIds[i]); + } + for (let i in machines[index].memoryIds) { + yield fetchAndStoreMemory(machines[index].memoryIds[i]); + } + for (let i in machines[index].storageIds) { + yield fetchAndStoreStorage(machines[index].storageIds[i]); + } + } +} + +export function* onStartNewRoomConstruction() { + try { + const datacenterId = yield select(state => state.currentDatacenterId); + const room = yield call(addRoomToDatacenter, { + id: -1, + datacenterId, + roomType: "SERVER" + }); + const roomWithEmptyTileList = Object.assign({}, room, { tileIds: [] }); + yield put(addToStore("room", roomWithEmptyTileList)); + yield put( + addIdToStoreObjectListProp("datacenter", datacenterId, "roomIds", room.id) + ); + yield put(startNewRoomConstructionSucceeded(room.id)); + } catch (error) { + console.error(error); + } +} + +export function* onCancelNewRoomConstruction() { + try { + const datacenterId = yield select(state => state.currentDatacenterId); + const roomId = yield select( + state => state.construction.currentRoomInConstruction + ); + yield call(deleteRoom, roomId); + yield put( + removeIdFromStoreObjectListProp( + "datacenter", + datacenterId, + "roomIds", + roomId + ) + ); + yield put(cancelNewRoomConstructionSucceeded()); + } catch (error) { + console.error(error); + } +} + +export function* onAddTile(action) { + try { + const roomId = yield select( + state => state.construction.currentRoomInConstruction + ); + const tile = yield call(addTileToRoom, { + roomId, + positionX: action.positionX, + positionY: action.positionY + }); + yield put(addToStore("tile", tile)); + yield put(addIdToStoreObjectListProp("room", roomId, "tileIds", tile.id)); + } catch (error) { + console.error(error); + } +} + +export function* onDeleteTile(action) { + try { + const roomId = yield select( + state => state.construction.currentRoomInConstruction + ); + yield call(deleteTile, action.tileId); + yield put( + removeIdFromStoreObjectListProp("room", roomId, "tileIds", action.tileId) + ); + } catch (error) { + console.error(error); + } +} + +export function* onEditRoomName(action) { + try { + const roomId = yield select(state => state.interactionLevel.roomId); + const room = Object.assign( + {}, + yield select(state => state.objects.room[roomId]) + ); + room.name = action.name; + yield call(updateRoom, room); + yield put(addPropToStoreObject("room", roomId, { name: action.name })); + } catch (error) { + console.error(error); + } +} + +export function* onDeleteRoom() { + try { + const datacenterId = yield select(state => state.currentDatacenterId); + const roomId = yield select(state => state.interactionLevel.roomId); + yield call(deleteRoom, roomId); + yield put(goDownOneInteractionLevel()); + yield put( + removeIdFromStoreObjectListProp( + "datacenter", + datacenterId, + "roomIds", + roomId + ) + ); + } catch (error) { + console.error(error); + } +} + +export function* onEditRackName(action) { + try { + const tileId = yield select(state => state.interactionLevel.tileId); + const rackId = yield select( + state => state.objects.tile[state.interactionLevel.tileId].objectId + ); + const rack = Object.assign( + {}, + yield select(state => state.objects.rack[rackId]) + ); + rack.name = action.name; + yield call(updateRackOnTile, tileId, rack); + yield put(addPropToStoreObject("rack", rackId, { name: action.name })); + } catch (error) { + console.error(error); + } +} + +export function* onDeleteRack() { + try { + const tileId = yield select(state => state.interactionLevel.tileId); + yield call(deleteRackFromTile, tileId); + yield put(goDownOneInteractionLevel()); + yield put(addPropToStoreObject("tile", tileId, { objectType: undefined })); + yield put(addPropToStoreObject("tile", tileId, { objectId: undefined })); + } catch (error) { + console.error(error); + } +} + +export function* onAddRackToTile(action) { + try { + const rack = yield call(addRackToTile, action.tileId, { + id: -1, + name: "Rack", + capacity: DEFAULT_RACK_SLOT_CAPACITY, + powerCapacityW: DEFAULT_RACK_POWER_CAPACITY + }); + rack.machineIds = new Array(rack.capacity).fill(null); + yield put(addToStore("rack", rack)); + yield put( + addPropToStoreObject("tile", action.tileId, { objectId: rack.id }) + ); + yield put( + addPropToStoreObject("tile", action.tileId, { objectType: "RACK" }) + ); + } catch (error) { + console.error(error); + } +} + +export function* onAddMachine(action) { + try { + const tileId = yield select(state => state.interactionLevel.tileId); + const rackId = yield select( + state => state.objects.tile[state.interactionLevel.tileId].objectId + ); + const rack = yield select(state => state.objects.rack[rackId]); + + const machine = yield call(addMachineToRackOnTile, tileId, { + id: -1, + rackId, + position: action.position, + tags: [], + cpuIds: [], + gpuIds: [], + memoryIds: [], + storageIds: [] + }); + yield put(addToStore("machine", machine)); + + const machineIds = [...rack.machineIds]; + machineIds[machine.position - 1] = machine.id; + yield put(addPropToStoreObject("rack", rackId, { machineIds })); + } catch (error) { + console.error(error); + } +} + +export function* onDeleteMachine() { + try { + const tileId = yield select(state => state.interactionLevel.tileId); + const position = yield select(state => state.interactionLevel.position); + const rack = yield select( + state => state.objects.rack[state.objects.tile[tileId].objectId] + ); + yield call(deleteMachineInRackOnTile, tileId, position); + const machineIds = [...rack.machineIds]; + machineIds[position - 1] = null; + yield put(goDownOneInteractionLevel()); + yield put(addPropToStoreObject("rack", rack.id, { machineIds })); + } catch (error) { + console.error(error); + } +} + +export function* onAddUnit(action) { + try { + const tileId = yield select(state => state.interactionLevel.tileId); + const position = yield select(state => state.interactionLevel.position); + const machine = yield select( + state => + state.objects.machine[ + state.objects.rack[state.objects.tile[tileId].objectId].machineIds[ + position - 1 + ] + ] + ); + + if (machine[action.unitType + "Ids"].length >= MAX_NUM_UNITS_PER_MACHINE) { + return; + } + + const units = [...machine[action.unitType + "Ids"], action.id]; + const updatedMachine = Object.assign({}, machine, { + [action.unitType + "Ids"]: units + }); + + yield call(updateMachineInRackOnTile, tileId, position, updatedMachine); + + yield put( + addPropToStoreObject("machine", machine.id, { + [action.unitType + "Ids"]: units + }) + ); + } catch (error) { + console.error(error); + } +} + +export function* onDeleteUnit(action) { + try { + const tileId = yield select(state => state.interactionLevel.tileId); + const position = yield select(state => state.interactionLevel.position); + const machine = yield select( + state => + state.objects.machine[ + state.objects.rack[state.objects.tile[tileId].objectId].machineIds[ + position - 1 + ] + ] + ); + const unitIds = machine[action.unitType + "Ids"].slice(); + unitIds.splice(action.index, 1); + const updatedMachine = Object.assign({}, machine, { + [action.unitType + "Ids"]: unitIds + }); + + yield call(updateMachineInRackOnTile, tileId, position, updatedMachine); + yield put( + addPropToStoreObject("machine", machine.id, { + [action.unitType + "Ids"]: unitIds + }) + ); + } catch (error) { + console.error(error); + } +} diff --git a/frontend/src/sagas/users.js b/frontend/src/sagas/users.js new file mode 100644 index 00000000..3825443a --- /dev/null +++ b/frontend/src/sagas/users.js @@ -0,0 +1,50 @@ +import { call, put } from "redux-saga/effects"; +import { logInSucceeded } from "../actions/auth"; +import { addToStore } from "../actions/objects"; +import { fetchAuthorizationsOfCurrentUserSucceeded } from "../actions/users"; +import { performTokenSignIn } from "../api/routes/token-signin"; +import { addUser, getAuthorizationsByUser } from "../api/routes/users"; +import { saveAuthLocalStorage } from "../auth/index"; +import { fetchAndStoreSimulation, fetchAndStoreUser } from "./objects"; + +export function* onFetchLoggedInUser(action) { + try { + const tokenResponse = yield call( + performTokenSignIn, + action.payload.authToken + ); + let userId = tokenResponse.userId; + + if (tokenResponse.isNewUser) { + saveAuthLocalStorage({ authToken: action.payload.authToken }); + const newUser = yield call(addUser, action.payload); + userId = newUser.id; + } + + yield put(logInSucceeded(Object.assign({ userId }, action.payload))); + } catch (error) { + console.error(error); + } +} + +export function* onFetchAuthorizationsOfCurrentUser(action) { + try { + const authorizations = yield call(getAuthorizationsByUser, action.userId); + + for (const authorization of authorizations) { + yield put(addToStore("authorization", authorization)); + + yield fetchAndStoreSimulation(authorization.simulationId); + yield fetchAndStoreUser(authorization.userId); + } + + const authorizationIds = authorizations.map(authorization => [ + authorization.userId, + authorization.simulationId + ]); + + yield put(fetchAuthorizationsOfCurrentUserSucceeded(authorizationIds)); + } catch (error) { + console.error(error); + } +} |
