From f119fc78dda4d1e828dde04f378a63a93e3a0a7e Mon Sep 17 00:00:00 2001 From: Georgios Andreadis Date: Thu, 2 Jul 2020 18:39:28 +0200 Subject: Add current progress on frontend port --- frontend/.prettierrc.yaml | 1 + frontend/package.json | 150 ++++----- frontend/public/humans.txt | 16 +- frontend/public/img/datacenter-drawing.png | Bin 219576 -> 207909 bytes frontend/public/img/portraits/aiosup.png | Bin 111629 -> 71879 bytes frontend/public/img/portraits/fmastenbroek.png | Bin 135589 -> 121867 bytes frontend/public/img/portraits/gandreadis.png | Bin 118477 -> 76426 bytes frontend/public/img/portraits/jburley.png | Bin 0 -> 328112 bytes frontend/public/img/portraits/loverweel.png | Bin 107768 -> 65866 bytes frontend/src/actions/experiments.js | 3 +- frontend/src/actions/map.js | 17 +- frontend/src/actions/modals/topology.js | 14 + frontend/src/actions/objects.js | 13 +- frontend/src/actions/profile.js | 0 frontend/src/actions/simulation/tick.js | 24 -- frontend/src/actions/topologies.js | 16 + frontend/src/actions/topology/building.js | 14 +- frontend/src/actions/topology/room.js | 2 +- frontend/src/actions/users.js | 10 +- frontend/src/api/index.js | 2 +- frontend/src/api/routes/datacenters.js | 26 -- frontend/src/api/routes/experiments.js | 27 +- frontend/src/api/routes/jobs.js | 5 - frontend/src/api/routes/paths.js | 30 -- frontend/src/api/routes/room-types.js | 9 - frontend/src/api/routes/rooms.js | 46 --- frontend/src/api/routes/sections.js | 5 - frontend/src/api/routes/simulations.js | 14 - frontend/src/api/routes/specifications.js | 57 ---- frontend/src/api/routes/tiles.js | 146 -------- frontend/src/api/routes/topologies.js | 42 +++ frontend/src/api/routes/traces.js | 6 +- frontend/src/api/routes/users.js | 25 +- frontend/src/api/socket.js | 4 +- frontend/src/auth/index.js | 4 +- frontend/src/components/app/map/LoadingScreen.js | 2 +- .../components/app/map/groups/DatacenterGroup.js | 40 --- .../src/components/app/map/groups/RackGroup.js | 4 +- .../src/components/app/map/groups/RoomGroup.js | 6 +- .../src/components/app/map/groups/TileGroup.js | 10 +- .../src/components/app/map/groups/TopologyGroup.js | 40 +++ .../components/app/map/layers/MapLayerComponent.js | 4 +- .../simulation/ExperimentMetadataComponent.js | 4 +- .../simulation/SimulationSidebarComponent.js | 4 - .../app/sidebars/simulation/TaskComponent.js | 58 ---- .../app/sidebars/simulation/TraceComponent.js | 20 -- .../sidebars/topology/machine/UnitAddComponent.js | 4 +- .../app/sidebars/topology/machine/UnitComponent.js | 8 +- .../sidebars/topology/machine/UnitListComponent.js | 4 +- .../app/sidebars/topology/rack/MachineComponent.js | 4 +- .../sidebars/topology/room/RoomSidebarComponent.js | 11 +- .../sidebars/topology/room/RoomTypeComponent.js | 8 - .../app/timeline/TimelineControlsComponent.js | 13 - .../experiments/ExperimentListComponent.js | 4 +- .../experiments/ExperimentRowComponent.js | 10 +- frontend/src/components/home/TeamSection.js | 18 +- .../ChangeTopologyModalComponent.js | 111 +++++++ .../NewExperimentModalComponent.js | 21 +- frontend/src/components/navigation/AppNavbar.js | 76 +++-- .../src/containers/app/map/DatacenterContainer.js | 17 - frontend/src/containers/app/map/MapStage.js | 6 +- frontend/src/containers/app/map/RackContainer.js | 4 +- .../containers/app/map/RackEnergyFillContainer.js | 2 +- .../containers/app/map/RackSpaceFillContainer.js | 2 +- frontend/src/containers/app/map/TileContainer.js | 4 +- .../src/containers/app/map/TopologyContainer.js | 17 + .../containers/app/map/layers/ObjectHoverLayer.js | 2 +- .../containers/app/map/layers/RoomHoverLayer.js | 6 +- .../simulation/ExperimentMetadataContainer.js | 12 +- .../app/sidebars/simulation/TaskContainer.js | 26 -- .../app/sidebars/simulation/TraceContainer.js | 25 -- .../topology/building/BuildingSidebarContainer.js | 3 +- .../topology/machine/MachineSidebarContainer.js | 2 +- .../app/sidebars/topology/machine/UnitContainer.js | 2 +- .../sidebars/topology/machine/UnitListContainer.js | 4 +- .../app/sidebars/topology/rack/MachineContainer.js | 4 +- .../sidebars/topology/rack/MachineListContainer.js | 2 +- .../sidebars/topology/rack/RackNameContainer.js | 2 +- .../sidebars/topology/rack/RackSidebarContainer.js | 2 +- .../sidebars/topology/room/EditRoomContainer.js | 5 +- .../topology/room/RackConstructionContainer.js | 5 +- .../sidebars/topology/room/RoomSidebarContainer.js | 3 +- .../sidebars/topology/room/RoomTypeContainer.js | 12 - .../containers/app/timeline/PlayButtonContainer.js | 5 +- .../containers/app/timeline/TimelineContainer.js | 17 +- .../app/timeline/TimelineControlsContainer.js | 14 - .../experiments/ExperimentRowContainer.js | 2 +- .../src/containers/modals/ChangeTopologyModal.js | 56 ++++ .../src/containers/modals/EditRackNameModal.js | 2 +- .../src/containers/modals/NewExperimentModal.js | 10 +- frontend/src/index.js | 3 - frontend/src/pages/App.js | 66 ++-- frontend/src/pages/Experiments.js | 30 +- frontend/src/pages/Home.js | 22 +- frontend/src/pages/NotFound.js | 2 +- frontend/src/pages/Profile.js | 19 +- frontend/src/pages/Simulations.js | 19 +- frontend/src/reducers/current-ids.js | 10 +- frontend/src/reducers/index.js | 4 +- frontend/src/reducers/interaction-level.js | 4 +- frontend/src/reducers/modals.js | 45 +-- frontend/src/reducers/objects.js | 46 +-- frontend/src/reducers/simulation-list.js | 2 +- frontend/src/reducers/states.js | 3 +- frontend/src/registerServiceWorker.js | 108 ------ frontend/src/routes/index.js | 49 +-- frontend/src/sagas/experiments.js | 98 ++---- frontend/src/sagas/index.js | 15 +- frontend/src/sagas/objects.js | 251 ++++++++------ frontend/src/sagas/simulations.js | 8 +- frontend/src/sagas/topology.js | 370 +++++++-------------- frontend/src/sagas/users.js | 10 +- frontend/src/shapes/index.js | 124 ++----- frontend/src/store/configure-store.js | 5 +- .../src/store/middlewares/viewport-adjustment.js | 16 +- frontend/src/util/date-time.js | 17 +- frontend/src/util/date-time.test.js | 2 +- frontend/src/util/room-types.js | 7 - frontend/src/util/tile-calculations.js | 18 +- frontend/src/util/timeline.js | 14 +- frontend/src/util/unit-specifications.js | 46 +++ frontend/yarn.lock | 18 + 122 files changed, 1086 insertions(+), 1852 deletions(-) create mode 100644 frontend/public/img/portraits/jburley.png delete mode 100644 frontend/src/actions/profile.js create mode 100644 frontend/src/actions/topologies.js delete mode 100644 frontend/src/api/routes/datacenters.js delete mode 100644 frontend/src/api/routes/jobs.js delete mode 100644 frontend/src/api/routes/paths.js delete mode 100644 frontend/src/api/routes/room-types.js delete mode 100644 frontend/src/api/routes/rooms.js delete mode 100644 frontend/src/api/routes/sections.js delete mode 100644 frontend/src/api/routes/specifications.js delete mode 100644 frontend/src/api/routes/tiles.js create mode 100644 frontend/src/api/routes/topologies.js delete mode 100644 frontend/src/components/app/map/groups/DatacenterGroup.js create mode 100644 frontend/src/components/app/map/groups/TopologyGroup.js delete mode 100644 frontend/src/components/app/sidebars/simulation/TaskComponent.js delete mode 100644 frontend/src/components/app/sidebars/simulation/TraceComponent.js delete mode 100644 frontend/src/components/app/sidebars/topology/room/RoomTypeComponent.js create mode 100644 frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js delete mode 100644 frontend/src/containers/app/map/DatacenterContainer.js create mode 100644 frontend/src/containers/app/map/TopologyContainer.js delete mode 100644 frontend/src/containers/app/sidebars/simulation/TaskContainer.js delete mode 100644 frontend/src/containers/app/sidebars/simulation/TraceContainer.js delete mode 100644 frontend/src/containers/app/sidebars/topology/room/RoomTypeContainer.js create mode 100644 frontend/src/containers/modals/ChangeTopologyModal.js delete mode 100644 frontend/src/registerServiceWorker.js delete mode 100644 frontend/src/util/room-types.js create mode 100644 frontend/src/util/unit-specifications.js (limited to 'frontend') diff --git a/frontend/.prettierrc.yaml b/frontend/.prettierrc.yaml index 6e8842f0..9a2b9a95 100644 --- a/frontend/.prettierrc.yaml +++ b/frontend/.prettierrc.yaml @@ -2,3 +2,4 @@ trailingComma: "es5" tabWidth: 4 semi: false singleQuote: true +printWidth: 120 diff --git a/frontend/package.json b/frontend/package.json index cb4f25b4..2180f092 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,77 +1,79 @@ { - "name": "opendc-frontend", - "version": "0.1.0", - "description": "The user-facing component of the OpenDC stack, allowing users to build and interact with their own (virtual) datacenters.", - "keywords": [ - "opendc", - "simulation", - "datacenter", - "frontend" - ], - "homepage": "http://opendc.org", - "bugs": { - "url": "https://github.com/atlarge-research/opendc-frontend/issues", - "email": "opendc@atlarge-research.com" - }, - "author": "Georgios Andreadis (https://gandreadis.com/)", - "license": "MIT", - "private": true, - "proxy": "http://localhost:8081", - "dependencies": { - "approximate-number": "~2.0.0", - "classnames": "~2.2.5", - "husky": "~4.2.5", - "konva": "~6.0.0", - "lint-staged": "~10.2.2", - "node-sass-chokidar": "~1.4.0", - "npm-run-all": "~4.1.2", - "prettier": "~2.0.5", - "prop-types": "~15.7.2", - "react": "~16.13.1", - "react-document-title": "~2.0.3", - "react-dom": "~16.13.1", - "react-fontawesome": "~1.7.1", - "react-google-login": "~5.1.14", - "react-konva": "~16.13.0-2", - "react-redux": "~7.2.0", - "react-router-dom": "~5.1.2", - "react-scripts": "~3.4.1", - "react-shortcuts": "~2.1.0", - "redux": "~4.0.5", - "redux-localstorage": "~0.4.1", - "redux-logger": "~3.0.6", - "redux-saga": "~1.1.3", - "redux-thunk": "~2.3.0", - "socket.io-client": "~2.3.0", - "svgsaver": "~0.9.0", - "victory": "~34.2.1" - }, - "lint-staged": { - "src/**/*.{js,jsx,json}": [ - "prettier --write", - "git add" - ] - }, - "scripts": { - "precommit": "lint-staged", - "build-css": "node-sass-chokidar src/ -o src/", - "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", - "start-js": "react-scripts start", - "start": "npm-run-all -p watch-css start-js", - "build": "npm run build-css && react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" + "name": "opendc-frontend", + "version": "0.1.0", + "description": "The user-facing component of the OpenDC stack, allowing users to build and interact with their own (virtual) datacenters.", + "keywords": [ + "opendc", + "simulation", + "datacenter", + "frontend" ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } + "homepage": "http://opendc.org", + "bugs": { + "url": "https://github.com/atlarge-research/opendc-frontend/issues", + "email": "opendc@atlarge-research.com" + }, + "author": "Georgios Andreadis (https://gandreadis.com/)", + "license": "MIT", + "private": true, + "proxy": "http://localhost:8081", + "dependencies": { + "approximate-number": "~2.0.0", + "classnames": "~2.2.5", + "husky": "~4.2.5", + "konva": "~6.0.0", + "lint-staged": "~10.2.2", + "node-sass-chokidar": "~1.4.0", + "npm-run-all": "~4.1.2", + "prettier": "~2.0.5", + "prop-types": "~15.7.2", + "react": "~16.13.1", + "react-document-title": "~2.0.3", + "react-dom": "~16.13.1", + "react-fontawesome": "~1.7.1", + "react-google-login": "~5.1.14", + "react-konva": "~16.13.0-2", + "react-redux": "~7.2.0", + "react-router-dom": "~5.1.2", + "react-scripts": "~3.4.1", + "react-shortcuts": "~2.1.0", + "redux": "~4.0.5", + "redux-localstorage": "~0.4.1", + "redux-logger": "~3.0.6", + "redux-saga": "~1.1.3", + "redux-thunk": "~2.3.0", + "socket.io-client": "~2.3.0", + "svgsaver": "~0.9.0", + "uuidv4": "^6.1.1", + "victory": "~34.2.1" + }, + "lint-staged": { + "src/**/*.{js,jsx,json}": [ + "prettier --write", + "git add" + ] + }, + "scripts": { + "format": "prettier --write src/**/*.js", + "precommit": "lint-staged", + "build-css": "node-sass-chokidar src/ -o src/", + "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", + "start-js": "react-scripts start", + "start": "npm-run-all -p watch-css start-js", + "build": "npm run build-css && react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } } diff --git a/frontend/public/humans.txt b/frontend/public/humans.txt index d037fcfd..dadcd530 100644 --- a/frontend/public/humans.txt +++ b/frontend/public/humans.txt @@ -4,12 +4,7 @@ Site: http://www.ds.ewi.tudelft.nl/~iosup/ Twitter: aiosup. Location: Delft, Netherlands. -Backend Engineer: Leon Overweel. -Site: http://leonoverweel.com/ -Twitter: layon_overwhale. -Location: Delft, Netherlands. - -Frontend Engineer: Georgios Andreadis. +Full-Stack Engineer: Georgios Andreadis. Site: https://github.com/gandreadis Location: Delft, Netherlands. @@ -17,6 +12,15 @@ Simulation Engineer: Fabian Mastenbroek. Site: https://github.com/fabianishere Location: Delft, Netherlands. +Simulation Engineer: Jacob Burley. +Site: https://github.com/jc0b +Location: Amsterdam, Netherlands. + +Backend Engineer: Leon Overweel. +Site: http://leonoverweel.com/ +Twitter: layon_overwhale. +Location: Delft, Netherlands. + Simulation Engineer: Matthijs Bijman. Site: https://github.com/MDBijman Location: Delft, Netherlands. diff --git a/frontend/public/img/datacenter-drawing.png b/frontend/public/img/datacenter-drawing.png index 401168e3..ec2b7398 100644 Binary files a/frontend/public/img/datacenter-drawing.png and b/frontend/public/img/datacenter-drawing.png differ diff --git a/frontend/public/img/portraits/aiosup.png b/frontend/public/img/portraits/aiosup.png index 30de349c..d2019b4d 100644 Binary files a/frontend/public/img/portraits/aiosup.png and b/frontend/public/img/portraits/aiosup.png differ diff --git a/frontend/public/img/portraits/fmastenbroek.png b/frontend/public/img/portraits/fmastenbroek.png index fd0d9de1..f17ef697 100644 Binary files a/frontend/public/img/portraits/fmastenbroek.png and b/frontend/public/img/portraits/fmastenbroek.png differ diff --git a/frontend/public/img/portraits/gandreadis.png b/frontend/public/img/portraits/gandreadis.png index 403870fa..96a3abda 100644 Binary files a/frontend/public/img/portraits/gandreadis.png and b/frontend/public/img/portraits/gandreadis.png differ diff --git a/frontend/public/img/portraits/jburley.png b/frontend/public/img/portraits/jburley.png new file mode 100644 index 00000000..d2691659 Binary files /dev/null and b/frontend/public/img/portraits/jburley.png differ diff --git a/frontend/public/img/portraits/loverweel.png b/frontend/public/img/portraits/loverweel.png index d12a9e86..85865977 100644 Binary files a/frontend/public/img/portraits/loverweel.png and b/frontend/public/img/portraits/loverweel.png differ diff --git a/frontend/src/actions/experiments.js b/frontend/src/actions/experiments.js index d0eda331..5d384abf 100644 --- a/frontend/src/actions/experiments.js +++ b/frontend/src/actions/experiments.js @@ -1,5 +1,4 @@ -export const FETCH_EXPERIMENTS_OF_SIMULATION = - 'FETCH_EXPERIMENTS_OF_SIMULATION' +export const FETCH_EXPERIMENTS_OF_SIMULATION = 'FETCH_EXPERIMENTS_OF_SIMULATION' export const ADD_EXPERIMENT = 'ADD_EXPERIMENT' export const DELETE_EXPERIMENT = 'DELETE_EXPERIMENT' export const OPEN_EXPERIMENT_SUCCEEDED = 'OPEN_EXPERIMENT_SUCCEEDED' diff --git a/frontend/src/actions/map.js b/frontend/src/actions/map.js index 4ab767f7..0d49d849 100644 --- a/frontend/src/actions/map.js +++ b/frontend/src/actions/map.js @@ -36,13 +36,7 @@ export function zoomInOnCenter(zoomIn) { return (dispatch, getState) => { const state = getState() - dispatch( - zoomInOnPosition( - zoomIn, - state.map.dimensions.width / 2, - state.map.dimensions.height / 2, - ), - ) + dispatch(zoomInOnPosition(zoomIn, state.map.dimensions.width / 2, state.map.dimensions.height / 2)) } } @@ -54,13 +48,8 @@ export function zoomInOnPosition(zoomIn, x, y) { x: x / state.map.scale - state.map.position.x / state.map.scale, y: y / state.map.scale - state.map.position.y / state.map.scale, } - const newScale = zoomIn - ? state.map.scale * MAP_SCALE_PER_EVENT - : state.map.scale / MAP_SCALE_PER_EVENT - const boundedScale = Math.min( - Math.max(MAP_MIN_SCALE, newScale), - MAP_MAX_SCALE, - ) + const newScale = zoomIn ? state.map.scale * MAP_SCALE_PER_EVENT : state.map.scale / MAP_SCALE_PER_EVENT + const boundedScale = Math.min(Math.max(MAP_MIN_SCALE, newScale), MAP_MAX_SCALE) const newX = -(centerPoint.x - x / boundedScale) * boundedScale const newY = -(centerPoint.y - y / boundedScale) * boundedScale diff --git a/frontend/src/actions/modals/topology.js b/frontend/src/actions/modals/topology.js index bc59e579..7b74e820 100644 --- a/frontend/src/actions/modals/topology.js +++ b/frontend/src/actions/modals/topology.js @@ -1,3 +1,5 @@ +export const OPEN_CHANGE_TOPOLOGY_MODAL = 'OPEN_CHANGE_TOPOLOGY_MODAL' +export const CLOSE_CHANGE_TOPOLOGY_MODAL = 'CLOSE_CHANGE_TOPOLOGY_MODAL' export const OPEN_EDIT_ROOM_NAME_MODAL = 'OPEN_EDIT_ROOM_NAME_MODAL' export const CLOSE_EDIT_ROOM_NAME_MODAL = 'CLOSE_EDIT_ROOM_NAME_MODAL' export const OPEN_DELETE_ROOM_MODAL = 'OPEN_DELETE_ROOM_MODAL' @@ -9,6 +11,18 @@ export const CLOSE_DELETE_RACK_MODAL = 'CLOSE_DELETE_RACK_MODAL' export const OPEN_DELETE_MACHINE_MODAL = 'OPEN_DELETE_MACHINE_MODAL' export const CLOSE_DELETE_MACHINE_MODAL = 'CLOSE_DELETE_MACHINE_MODAL' +export function openChangeTopologyModal() { + return { + type: OPEN_CHANGE_TOPOLOGY_MODAL, + } +} + +export function closeChangeTopologyModal() { + return { + type: CLOSE_CHANGE_TOPOLOGY_MODAL, + } +} + export function openEditRoomNameModal() { return { type: OPEN_EDIT_ROOM_NAME_MODAL, diff --git a/frontend/src/actions/objects.js b/frontend/src/actions/objects.js index 2b445c9d..7b648b18 100644 --- a/frontend/src/actions/objects.js +++ b/frontend/src/actions/objects.js @@ -1,9 +1,7 @@ export const ADD_TO_STORE = 'ADD_TO_STORE' export const ADD_PROP_TO_STORE_OBJECT = 'ADD_PROP_TO_STORE_OBJECT' -export const ADD_ID_TO_STORE_OBJECT_LIST_PROP = - 'ADD_ID_TO_STORE_OBJECT_LIST_PROP' -export const REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP = - 'REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP' +export const ADD_ID_TO_STORE_OBJECT_LIST_PROP = 'ADD_ID_TO_STORE_OBJECT_LIST_PROP' +export const REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP = 'REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP' export function addToStore(objectType, object) { return { @@ -32,12 +30,7 @@ export function addIdToStoreObjectListProp(objectType, objectId, propName, id) { } } -export function removeIdFromStoreObjectListProp( - objectType, - objectId, - propName, - id, -) { +export function removeIdFromStoreObjectListProp(objectType, objectId, propName, id) { return { type: REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP, objectType, diff --git a/frontend/src/actions/profile.js b/frontend/src/actions/profile.js deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/src/actions/simulation/tick.js b/frontend/src/actions/simulation/tick.js index 72387d24..ca2027a4 100644 --- a/frontend/src/actions/simulation/tick.js +++ b/frontend/src/actions/simulation/tick.js @@ -1,6 +1,3 @@ -import { getDatacenterIdOfTick } from '../../util/timeline' -import { setCurrentDatacenter } from '../topology/building' - export const GO_TO_TICK = 'GO_TO_TICK' export const SET_LAST_SIMULATED_TICK = 'SET_LAST_SIMULATED_TICK' @@ -13,27 +10,6 @@ export function incrementTick() { export function goToTick(tick) { return (dispatch, getState) => { - const state = getState() - - let sections = [] - if (state.currentExperimentId !== -1) { - const sectionIds = - state.objects.path[ - state.objects.experiment[state.currentExperimentId].pathId - ].sectionIds - - if (sectionIds) { - sections = sectionIds.map( - sectionId => state.objects.section[sectionId], - ) - } - } - - const newDatacenterId = getDatacenterIdOfTick(tick, sections) - if (state.currentDatacenterId !== newDatacenterId) { - dispatch(setCurrentDatacenter(newDatacenterId)) - } - dispatch({ type: GO_TO_TICK, tick, diff --git a/frontend/src/actions/topologies.js b/frontend/src/actions/topologies.js new file mode 100644 index 00000000..c80ef6b2 --- /dev/null +++ b/frontend/src/actions/topologies.js @@ -0,0 +1,16 @@ +export const ADD_TOPOLOGY = 'ADD_TOPOLOGY' +export const DELETE_TOPOLOGY = 'DELETE_TOPOLOGY' + +export function addTopology(topology) { + return { + type: ADD_TOPOLOGY, + topology, + } +} + +export function deleteTopology(id) { + return { + type: DELETE_TOPOLOGY, + id, + } +} diff --git a/frontend/src/actions/topology/building.js b/frontend/src/actions/topology/building.js index 2d4d399c..da2dc311 100644 --- a/frontend/src/actions/topology/building.js +++ b/frontend/src/actions/topology/building.js @@ -1,5 +1,5 @@ -export const SET_CURRENT_DATACENTER = 'SET_CURRENT_DATACENTER' -export const RESET_CURRENT_DATACENTER = 'RESET_CURRENT_DATACENTER' +export const SET_CURRENT_TOPOLOGY = 'SET_CURRENT_TOPOLOGY' +export const RESET_CURRENT_TOPOLOGY = 'RESET_CURRENT_TOPOLOGY' export const START_NEW_ROOM_CONSTRUCTION = 'START_NEW_ROOM_CONSTRUCTION' export const START_NEW_ROOM_CONSTRUCTION_SUCCEEDED = 'START_NEW_ROOM_CONSTRUCTION_SUCCEEDED' @@ -12,16 +12,16 @@ export const FINISH_ROOM_EDIT = 'FINISH_ROOM_EDIT' export const ADD_TILE = 'ADD_TILE' export const DELETE_TILE = 'DELETE_TILE' -export function setCurrentDatacenter(datacenterId) { +export function setCurrentTopology(topologyId) { return { - type: SET_CURRENT_DATACENTER, - datacenterId, + type: SET_CURRENT_TOPOLOGY, + topologyId, } } -export function resetCurrentDatacenter() { +export function resetCurrentTopology() { return { - type: RESET_CURRENT_DATACENTER, + type: RESET_CURRENT_TOPOLOGY, } } diff --git a/frontend/src/actions/topology/room.js b/frontend/src/actions/topology/room.js index 3476f0b6..939b475a 100644 --- a/frontend/src/actions/topology/room.js +++ b/frontend/src/actions/topology/room.js @@ -35,7 +35,7 @@ export function addRackToTile(positionX, positionY) { if (tile !== null) { dispatch({ type: ADD_RACK_TO_TILE, - tileId: tile.id, + tileId: tile._id, }) } } diff --git a/frontend/src/actions/users.js b/frontend/src/actions/users.js index cae7e211..4868ac34 100644 --- a/frontend/src/actions/users.js +++ b/frontend/src/actions/users.js @@ -1,7 +1,5 @@ -export const FETCH_AUTHORIZATIONS_OF_CURRENT_USER = - 'FETCH_AUTHORIZATIONS_OF_CURRENT_USER' -export const FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED = - 'FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED' +export const FETCH_AUTHORIZATIONS_OF_CURRENT_USER = 'FETCH_AUTHORIZATIONS_OF_CURRENT_USER' +export const FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED = 'FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED' export const DELETE_CURRENT_USER = 'DELETE_CURRENT_USER' export const DELETE_CURRENT_USER_SUCCEEDED = 'DELETE_CURRENT_USER_SUCCEEDED' @@ -15,9 +13,7 @@ export function fetchAuthorizationsOfCurrentUser() { } } -export function fetchAuthorizationsOfCurrentUserSucceeded( - authorizationsOfCurrentUser, -) { +export function fetchAuthorizationsOfCurrentUserSucceeded(authorizationsOfCurrentUser) { return { type: FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED, authorizationsOfCurrentUser, diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 6f6c924c..cefcb2c5 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -2,7 +2,7 @@ import { sendSocketRequest } from './socket' export function sendRequest(request) { return new Promise((resolve, reject) => { - sendSocketRequest(request, response => { + sendSocketRequest(request, (response) => { if (response.status.code === 200) { resolve(response.content) } else { diff --git a/frontend/src/api/routes/datacenters.js b/frontend/src/api/routes/datacenters.js deleted file mode 100644 index d041b6ae..00000000 --- a/frontend/src/api/routes/datacenters.js +++ /dev/null @@ -1,26 +0,0 @@ -import { sendRequest } from '../index' -import { getById } from './util' - -export function getDatacenter(datacenterId) { - return getById('/datacenters/{datacenterId}', { datacenterId }) -} - -export function getRoomsOfDatacenter(datacenterId) { - return getById('/datacenters/{datacenterId}/rooms', { datacenterId }) -} - -export function addRoomToDatacenter(room) { - return sendRequest({ - path: '/datacenters/{datacenterId}/rooms', - method: 'POST', - parameters: { - body: { - room, - }, - path: { - datacenterId: room.datacenterId, - }, - query: {}, - }, - }) -} diff --git a/frontend/src/api/routes/experiments.js b/frontend/src/api/routes/experiments.js index 75dab7af..ab85613c 100644 --- a/frontend/src/api/routes/experiments.js +++ b/frontend/src/api/routes/experiments.js @@ -1,4 +1,21 @@ import { deleteById, getById } from './util' +import { sendRequest } from '../index' + +export function addExperiment(simulationId, experiment) { + return sendRequest({ + path: '/simulations/{simulationId}/experiments', + method: 'POST', + parameters: { + body: { + experiment, + }, + path: { + simulationId, + }, + query: {}, + }, + }) +} export function getExperiment(experimentId) { return getById('/experiments/{experimentId}', { experimentId }) @@ -8,12 +25,6 @@ export function deleteExperiment(experimentId) { return deleteById('/experiments/{experimentId}', { experimentId }) } -export function getLastSimulatedTick(experimentId) { - return getById('/experiments/{experimentId}/last-simulated-tick', { - experimentId, - }) -} - export function getAllMachineStates(experimentId) { return getById('/experiments/{experimentId}/machine-states', { experimentId, @@ -27,7 +38,3 @@ export function getAllRackStates(experimentId) { export function getAllRoomStates(experimentId) { return getById('/experiments/{experimentId}/room-states', { experimentId }) } - -export function getAllTaskStates(experimentId) { - return getById('/experiments/{experimentId}/task-states', { experimentId }) -} diff --git a/frontend/src/api/routes/jobs.js b/frontend/src/api/routes/jobs.js deleted file mode 100644 index 205c1777..00000000 --- a/frontend/src/api/routes/jobs.js +++ /dev/null @@ -1,5 +0,0 @@ -import { getById } from './util' - -export function getTasksOfJob(jobId) { - return getById('/jobs/{jobId}/tasks', { jobId }) -} diff --git a/frontend/src/api/routes/paths.js b/frontend/src/api/routes/paths.js deleted file mode 100644 index 74811ab2..00000000 --- a/frontend/src/api/routes/paths.js +++ /dev/null @@ -1,30 +0,0 @@ -import { sendRequest } from '../index' -import { getById } from './util' - -export function getPath(pathId) { - return getById('/paths/{pathId}', { pathId }) -} - -export function getBranchesOfPath(pathId) { - return getById('/paths/{pathId}/branches', { pathId }) -} - -export function branchFromPath(pathId, section) { - return sendRequest({ - path: '/paths/{pathId}/branches', - method: 'POST', - parameters: { - body: { - section, - }, - path: { - pathId, - }, - query: {}, - }, - }) -} - -export function getSectionsOfPath(pathId) { - return getById('/paths/{pathId}/sections', { pathId }) -} diff --git a/frontend/src/api/routes/room-types.js b/frontend/src/api/routes/room-types.js deleted file mode 100644 index 6c964e93..00000000 --- a/frontend/src/api/routes/room-types.js +++ /dev/null @@ -1,9 +0,0 @@ -import { getAll, getById } from './util' - -export function getAvailableRoomTypes() { - return getAll('/room-types') -} - -export function getAllowedObjectsOfRoomType(name) { - return getById('/room-types/{name}/allowed-objects', { name }) -} diff --git a/frontend/src/api/routes/rooms.js b/frontend/src/api/routes/rooms.js deleted file mode 100644 index f87d1298..00000000 --- a/frontend/src/api/routes/rooms.js +++ /dev/null @@ -1,46 +0,0 @@ -import { sendRequest } from '../index' -import { deleteById, getById } from './util' - -export function getRoom(roomId) { - return getById('/rooms/{roomId}', { roomId }) -} - -export function updateRoom(room) { - return sendRequest({ - path: '/rooms/{roomId}', - method: 'PUT', - parameters: { - body: { - room, - }, - path: { - roomId: room.id, - }, - query: {}, - }, - }) -} - -export function deleteRoom(roomId) { - return deleteById('/rooms/{roomId}', { roomId }) -} - -export function getTilesOfRoom(roomId) { - return getById('/rooms/{roomId}/tiles', { roomId }) -} - -export function addTileToRoom(tile) { - return sendRequest({ - path: '/rooms/{roomId}/tiles', - method: 'POST', - parameters: { - body: { - tile, - }, - path: { - roomId: tile.roomId, - }, - query: {}, - }, - }) -} diff --git a/frontend/src/api/routes/sections.js b/frontend/src/api/routes/sections.js deleted file mode 100644 index 1ee8a22a..00000000 --- a/frontend/src/api/routes/sections.js +++ /dev/null @@ -1,5 +0,0 @@ -import { getById } from './util' - -export function getSection(sectionId) { - return getById('/sections/{sectionId}', { sectionId }) -} diff --git a/frontend/src/api/routes/simulations.js b/frontend/src/api/routes/simulations.js index aec89dcc..e22fbc07 100644 --- a/frontend/src/api/routes/simulations.js +++ b/frontend/src/api/routes/simulations.js @@ -39,20 +39,6 @@ export function deleteSimulation(simulationId) { return deleteById('/simulations/{simulationId}', { simulationId }) } -export function getAuthorizationsBySimulation(simulationId) { - return getById('/simulations/{simulationId}/authorizations', { - simulationId, - }) -} - -export function getPathsOfSimulation(simulationId) { - return getById('/simulations/{simulationId}/paths', { simulationId }) -} - -export function getExperimentsOfSimulation(simulationId) { - return getById('/simulations/{simulationId}/experiments', { simulationId }) -} - export function addExperiment(simulationId, experiment) { return sendRequest({ path: '/simulations/{simulationId}/experiments', diff --git a/frontend/src/api/routes/specifications.js b/frontend/src/api/routes/specifications.js deleted file mode 100644 index 167fdce5..00000000 --- a/frontend/src/api/routes/specifications.js +++ /dev/null @@ -1,57 +0,0 @@ -import { getAll, getById } from './util' - -export function getAllCoolingItems() { - return getAll('/specifications/cooling-items') -} - -export function getCoolingItem(id) { - return getById('/specifications/cooling-items/{id}', { id }) -} - -export function getAllCPUs() { - return getAll('/specifications/cpus') -} - -export function getCPU(id) { - return getById('/specifications/cpus/{id}', { id }) -} - -export function getAllFailureModels() { - return getAll('/specifications/failure-models') -} - -export function getFailureModel(id) { - return getById('/specifications/failure-models/{id}', { id }) -} - -export function getAllGPUs() { - return getAll('/specifications/gpus') -} - -export function getGPU(id) { - return getById('/specifications/gpus/{id}', { id }) -} - -export function getAllMemories() { - return getAll('/specifications/memories') -} - -export function getMemory(id) { - return getById('/specifications/memories/{id}', { id }) -} - -export function getAllPSUs() { - return getAll('/specifications/psus') -} - -export function getPSU(id) { - return getById('/specifications/psus/{id}', { id }) -} - -export function getAllStorages() { - return getAll('/specifications/storages') -} - -export function getStorage(id) { - return getById('/specifications/storages/{id}', { id }) -} diff --git a/frontend/src/api/routes/tiles.js b/frontend/src/api/routes/tiles.js deleted file mode 100644 index 170fe462..00000000 --- a/frontend/src/api/routes/tiles.js +++ /dev/null @@ -1,146 +0,0 @@ -import { sendRequest } from '../index' -import { deleteById, getById } from './util' - -export function getTile(tileId) { - return getById('/tiles/{tileId}', { tileId }) -} - -export function deleteTile(tileId) { - return deleteById('/tiles/{tileId}', { tileId }) -} - -export function getRackByTile(tileId) { - return getTileObject(tileId, '/rack') -} - -export function addRackToTile(tileId, rack) { - return addTileObject(tileId, { rack }, '/rack') -} - -export function updateRackOnTile(tileId, rack) { - return updateTileObject(tileId, { rack }, '/rack') -} - -export function deleteRackFromTile(tileId) { - return deleteTileObject(tileId, '/rack') -} - -export function getMachinesOfRackByTile(tileId) { - return getById('/tiles/{tileId}/rack/machines', { tileId }) -} - -export function addMachineToRackOnTile(tileId, machine) { - return sendRequest({ - path: '/tiles/{tileId}/rack/machines', - method: 'POST', - parameters: { - body: { - machine, - }, - path: { - tileId, - }, - query: {}, - }, - }) -} - -export function updateMachineInRackOnTile(tileId, position, machine) { - return sendRequest({ - path: '/tiles/{tileId}/rack/machines/{position}', - method: 'PUT', - parameters: { - body: { - machine, - }, - path: { - tileId, - position, - }, - query: {}, - }, - }) -} - -export function deleteMachineInRackOnTile(tileId, position) { - return sendRequest({ - path: '/tiles/{tileId}/rack/machines/{position}', - method: 'DELETE', - parameters: { - body: {}, - path: { - tileId, - position, - }, - query: {}, - }, - }) -} - -export function getCoolingItemByTile(tileId) { - return getTileObject(tileId, '/cooling-item') -} - -export function addCoolingItemToTile(tileId, coolingItemId) { - return addTileObject(tileId, { coolingItemId }, '/cooling-item') -} - -export function updateCoolingItemOnTile(tileId, coolingItemId) { - return updateTileObject(tileId, { coolingItemId }, '/cooling-item') -} - -export function deleteCoolingItemFromTile(tileId) { - return deleteTileObject(tileId, '/cooling-item') -} - -export function getPSUByTile(tileId) { - return getTileObject(tileId, '/psu') -} - -export function addPSUToTile(tileId, psuId) { - return addTileObject(tileId, { psuId }, '/psu') -} - -export function updatePSUOnTile(tileId, psuId) { - return updateTileObject(tileId, { psuId }, '/psu') -} - -export function deletePSUFromTile(tileId) { - return deleteTileObject(tileId, '/psu') -} - -function getTileObject(tileId, endpoint) { - return getById('/tiles/{tileId}' + endpoint, { tileId }) -} - -function addTileObject(tileId, objectBody, endpoint) { - return sendRequest({ - path: '/tiles/{tileId}' + endpoint, - method: 'POST', - parameters: { - body: objectBody, - path: { - tileId, - }, - query: {}, - }, - }) -} - -function updateTileObject(tileId, objectBody, endpoint) { - return sendRequest({ - path: '/tiles/{tileId}' + endpoint, - method: 'PUT', - parameters: { - body: objectBody, - path: { - tileId, - }, - query: {}, - }, - }) -} - -function deleteTileObject(tileId, endpoint) { - return deleteById('/tiles/{tileId}' + endpoint, { tileId }) -} diff --git a/frontend/src/api/routes/topologies.js b/frontend/src/api/routes/topologies.js new file mode 100644 index 00000000..307ea7ab --- /dev/null +++ b/frontend/src/api/routes/topologies.js @@ -0,0 +1,42 @@ +import { deleteById, getById } from './util' +import { sendRequest } from '../index' + +export function addTopology(topology) { + return sendRequest({ + path: '/simulations/{simulationId}/topologies', + method: 'POST', + parameters: { + body: { + topology, + }, + path: { + simulationId: topology.simulationId, + }, + query: {}, + }, + }) +} + +export function getTopology(topologyId) { + return getById('/topologies/{topologyId}', { topologyId }) +} + +export function updateTopology(topology) { + return sendRequest({ + path: '/topologies/{topologyId}', + method: 'PUT', + parameters: { + body: { + topology, + }, + path: { + topologyId: topology._id, + }, + query: {}, + }, + }) +} + +export function deleteTopology(topologyId) { + return deleteById('/topologies/{topologyId}', { topologyId }) +} diff --git a/frontend/src/api/routes/traces.js b/frontend/src/api/routes/traces.js index 140408b1..67895a87 100644 --- a/frontend/src/api/routes/traces.js +++ b/frontend/src/api/routes/traces.js @@ -1,9 +1,5 @@ -import { getAll, getById } from './util' +import { getAll } from './util' export function getAllTraces() { return getAll('/traces') } - -export function getJobsOfTrace(traceId) { - return getById('/traces/{traceId}/jobs', { traceId }) -} diff --git a/frontend/src/api/routes/users.js b/frontend/src/api/routes/users.js index 4cb194ce..3028f3f7 100644 --- a/frontend/src/api/routes/users.js +++ b/frontend/src/api/routes/users.js @@ -1,5 +1,5 @@ import { sendRequest } from '../index' -import { deleteById, getById } from './util' +import { deleteById } from './util' export function getUserByEmail(email) { return sendRequest({ @@ -43,29 +43,6 @@ export function getUser(userId) { }) } -export function updateUser(userId, user) { - return sendRequest({ - path: '/users/{userId}', - method: 'PUT', - parameters: { - body: { - user: { - givenName: user.givenName, - familyName: user.familyName, - }, - }, - path: { - userId, - }, - query: {}, - }, - }) -} - export function deleteUser(userId) { return deleteById('/users/{userId}', { userId }) } - -export function getAuthorizationsByUser(userId) { - return getById('/users/{userId}/authorizations', { userId }) -} diff --git a/frontend/src/api/socket.js b/frontend/src/api/socket.js index ce5f7587..93ce8fa8 100644 --- a/frontend/src/api/socket.js +++ b/frontend/src/api/socket.js @@ -10,9 +10,7 @@ export function setupSocketConnection(onConnect) { if (process.env.NODE_ENV !== 'production') { port = 8081 } - socket = io.connect( - window.location.protocol + '//' + window.location.hostname + ':' + port, - ) + socket = io.connect(window.location.protocol + '//' + window.location.hostname + ':' + port) socket.on('connect', onConnect) socket.on('response', onSocketResponse) } diff --git a/frontend/src/auth/index.js b/frontend/src/auth/index.js index 7922f567..f93c7141 100644 --- a/frontend/src/auth/index.js +++ b/frontend/src/auth/index.js @@ -29,7 +29,7 @@ export const getAuthToken = () => { return authObj.authToken } -export const saveAuthLocalStorage = payload => { +export const saveAuthLocalStorage = (payload) => { localStorage.setItem('auth', JSON.stringify(payload)) } @@ -37,7 +37,7 @@ export const clearAuthLocalStorage = () => { localStorage.setItem('auth', '') } -export const authRedirectMiddleware = store => next => action => { +export const authRedirectMiddleware = (store) => (next) => (action) => { switch (action.type) { case LOG_IN_SUCCEEDED: saveAuthLocalStorage(action.payload) diff --git a/frontend/src/components/app/map/LoadingScreen.js b/frontend/src/components/app/map/LoadingScreen.js index ca159982..1fd470fc 100644 --- a/frontend/src/components/app/map/LoadingScreen.js +++ b/frontend/src/components/app/map/LoadingScreen.js @@ -4,7 +4,7 @@ import FontAwesome from 'react-fontawesome' const LoadingScreen = () => (
- Loading your datacenter... + Loading your topology...
) diff --git a/frontend/src/components/app/map/groups/DatacenterGroup.js b/frontend/src/components/app/map/groups/DatacenterGroup.js deleted file mode 100644 index 3d3b9702..00000000 --- a/frontend/src/components/app/map/groups/DatacenterGroup.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react' -import { Group } from 'react-konva' -import GrayContainer from '../../../../containers/app/map/GrayContainer' -import RoomContainer from '../../../../containers/app/map/RoomContainer' -import Shapes from '../../../../shapes/index' - -const DatacenterGroup = ({ datacenter, interactionLevel }) => { - if (!datacenter) { - return - } - - if (interactionLevel.mode === 'BUILDING') { - return ( - - {datacenter.roomIds.map(roomId => ( - - ))} - - ) - } - - return ( - - {datacenter.roomIds - .filter(roomId => roomId !== interactionLevel.roomId) - .map(roomId => )} - {interactionLevel.mode === 'ROOM' ? : null} - {datacenter.roomIds - .filter(roomId => roomId === interactionLevel.roomId) - .map(roomId => )} - - ) -} - -DatacenterGroup.propTypes = { - datacenter: Shapes.Datacenter, - interactionLevel: Shapes.InteractionLevel, -} - -export default DatacenterGroup diff --git a/frontend/src/components/app/map/groups/RackGroup.js b/frontend/src/components/app/map/groups/RackGroup.js index 708dcf69..6de939a9 100644 --- a/frontend/src/components/app/map/groups/RackGroup.js +++ b/frontend/src/components/app/map/groups/RackGroup.js @@ -22,12 +22,12 @@ const RackGroup = ({ tile, inSimulation, rackLoad }) => { /> diff --git a/frontend/src/components/app/map/groups/RoomGroup.js b/frontend/src/components/app/map/groups/RoomGroup.js index 230e3c9b..4e3c7410 100644 --- a/frontend/src/components/app/map/groups/RoomGroup.js +++ b/frontend/src/components/app/map/groups/RoomGroup.js @@ -11,7 +11,7 @@ const RoomGroup = ({ currentRoomInConstruction, onClick, }) => { - if (currentRoomInConstruction === room.id) { + if (currentRoomInConstruction === room._id) { return ( {room.tileIds.map(tileId => ( @@ -27,7 +27,7 @@ const RoomGroup = ({ if ( (interactionLevel.mode === 'RACK' || interactionLevel.mode === 'MACHINE') && - interactionLevel.roomId === room.id + interactionLevel.roomId === room._id ) { return [ room.tileIds @@ -44,7 +44,7 @@ const RoomGroup = ({ )) } })()} - + ) } diff --git a/frontend/src/components/app/map/groups/TileGroup.js b/frontend/src/components/app/map/groups/TileGroup.js index 49e2e52b..54f4ae17 100644 --- a/frontend/src/components/app/map/groups/TileGroup.js +++ b/frontend/src/components/app/map/groups/TileGroup.js @@ -9,12 +9,10 @@ import RoomTile from '../elements/RoomTile' const TileGroup = ({ tile, newTile, inSimulation, roomLoad, onClick }) => { let tileObject - switch (tile.objectType) { - case 'RACK': - tileObject = - break - default: - tileObject = null + if (tile.rackId) { + tileObject = + } else { + tileObject = null } let color = ROOM_DEFAULT_COLOR diff --git a/frontend/src/components/app/map/groups/TopologyGroup.js b/frontend/src/components/app/map/groups/TopologyGroup.js new file mode 100644 index 00000000..a40a1d41 --- /dev/null +++ b/frontend/src/components/app/map/groups/TopologyGroup.js @@ -0,0 +1,40 @@ +import React from 'react' +import { Group } from 'react-konva' +import GrayContainer from '../../../../containers/app/map/GrayContainer' +import RoomContainer from '../../../../containers/app/map/RoomContainer' +import Shapes from '../../../../shapes/index' + +const TopologyGroup = ({ topology, interactionLevel }) => { + if (!topology) { + return + } + + if (interactionLevel.mode === 'BUILDING') { + return ( + + {topology.roomIds.map(roomId => ( + + ))} + + ) + } + + return ( + + {topology.roomIds + .filter(roomId => roomId !== interactionLevel.roomId) + .map(roomId => )} + {interactionLevel.mode === 'ROOM' ? : null} + {topology.roomIds + .filter(roomId => roomId === interactionLevel.roomId) + .map(roomId => )} + + ) +} + +TopologyGroup.propTypes = { + topology: Shapes.Topology, + interactionLevel: Shapes.InteractionLevel, +} + +export default TopologyGroup diff --git a/frontend/src/components/app/map/layers/MapLayerComponent.js b/frontend/src/components/app/map/layers/MapLayerComponent.js index 1a31f2b9..940057f9 100644 --- a/frontend/src/components/app/map/layers/MapLayerComponent.js +++ b/frontend/src/components/app/map/layers/MapLayerComponent.js @@ -1,6 +1,6 @@ import React from 'react' import { Group, Layer } from 'react-konva' -import DatacenterContainer from '../../../../containers/app/map/DatacenterContainer' +import TopologyContainer from '../../../../containers/app/map/TopologyContainer' import Backdrop from '../elements/Backdrop' import GridGroup from '../groups/GridGroup' @@ -13,7 +13,7 @@ const MapLayerComponent = ({ mapPosition, mapScale }) => ( scaleY={mapScale} > - + diff --git a/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js b/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js index 54a8b5e9..30990a13 100644 --- a/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js +++ b/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js @@ -2,14 +2,14 @@ import React from 'react' const ExperimentMetadataComponent = ({ experimentName, - pathName, + topologyName, traceName, schedulerName, }) => (

{experimentName}

- Path: {pathName} + Topology: {topologyName}

Trace: {traceName} diff --git a/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js b/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js index 6e89c40e..dba75eb2 100644 --- a/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js +++ b/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js @@ -1,7 +1,6 @@ import React from 'react' import ExperimentMetadataContainer from '../../../../containers/app/sidebars/simulation/ExperimentMetadataContainer' import LoadMetricContainer from '../../../../containers/app/sidebars/simulation/LoadMetricContainer' -import TraceContainer from '../../../../containers/app/sidebars/simulation/TraceContainer' import Sidebar from '../Sidebar' import './SimulationSidebarComponent.css' @@ -11,9 +10,6 @@ const SimulationSidebarComponent = () => {

-
- -
) diff --git a/frontend/src/components/app/sidebars/simulation/TaskComponent.js b/frontend/src/components/app/sidebars/simulation/TaskComponent.js deleted file mode 100644 index 94617086..00000000 --- a/frontend/src/components/app/sidebars/simulation/TaskComponent.js +++ /dev/null @@ -1,58 +0,0 @@ -import approx from 'approximate-number' -import classNames from 'classnames' -import React from 'react' -import { convertSecondsToFormattedTime } from '../../../../util/date-time' - -const TaskComponent = ({ task, flopsLeft }) => { - let icon - let progressBarContent - let percent - let infoTitle - - if (flopsLeft === task.totalFlopCount) { - icon = 'hourglass-half' - progressBarContent = '' - percent = 0 - infoTitle = 'Not submitted yet' - } else if (flopsLeft > 0) { - icon = 'refresh' - progressBarContent = approx(task.totalFlopCount - flopsLeft) + ' FLOP' - percent = 100 * (task.totalFlopCount - flopsLeft) / task.totalFlopCount - infoTitle = - progressBarContent + ' (' + Math.round(percent * 10) / 10 + '%)' - } else { - icon = 'check' - progressBarContent = 'Completed' - percent = 100 - infoTitle = 'Completed' - } - - return ( -
  • -
    -
    {approx(task.totalFlopCount)} FLOP
    - Starts at {convertSecondsToFormattedTime(task.startTick)} -
    -
    - -
    -
    - {progressBarContent} -
    -
    -
    -
  • - ) -} - -export default TaskComponent diff --git a/frontend/src/components/app/sidebars/simulation/TraceComponent.js b/frontend/src/components/app/sidebars/simulation/TraceComponent.js deleted file mode 100644 index 1292219b..00000000 --- a/frontend/src/components/app/sidebars/simulation/TraceComponent.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react' -import TaskContainer from '../../../../containers/app/sidebars/simulation/TaskContainer' - -const TraceComponent = ({ jobs }) => ( -
    -

    Trace

    - {jobs.map(job => ( -
    -

    Job: {job.name}

    -
      - {job.taskIds.map(taskId => ( - - ))} -
    -
    - ))} -
    -) - -export default TraceComponent diff --git a/frontend/src/components/app/sidebars/topology/machine/UnitAddComponent.js b/frontend/src/components/app/sidebars/topology/machine/UnitAddComponent.js index 57e219fd..e8722506 100644 --- a/frontend/src/components/app/sidebars/topology/machine/UnitAddComponent.js +++ b/frontend/src/components/app/sidebars/topology/machine/UnitAddComponent.js @@ -16,7 +16,7 @@ class UnitAddComponent extends React.Component { ref={unitSelect => (this.unitSelect = unitSelect)} > {this.props.units.map(unit => ( -
    )} diff --git a/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js b/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js index 0a1d1065..b4204136 100644 --- a/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js +++ b/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js @@ -61,8 +61,8 @@ const MachineComponent = ({ )} {hasNoUnits ? ( - Machine with no units - + Machine with no units + ) : ( undefined )} diff --git a/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js b/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js index d9865744..d8a805cb 100644 --- a/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js +++ b/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js @@ -6,18 +6,11 @@ import DeleteRoomContainer from '../../../../../containers/app/sidebars/topology import EditRoomContainer from '../../../../../containers/app/sidebars/topology/room/EditRoomContainer' import RackConstructionContainer from '../../../../../containers/app/sidebars/topology/room/RackConstructionContainer' import RoomNameContainer from '../../../../../containers/app/sidebars/topology/room/RoomNameContainer' -import RoomTypeContainer from '../../../../../containers/app/sidebars/topology/room/RoomTypeContainer' - -const RoomSidebarComponent = ({ roomId, roomType, inSimulation }) => { - let allowedObjects - if (!inSimulation && roomType === 'SERVER') { - allowedObjects = - } +const RoomSidebarComponent = ({ roomId, inSimulation }) => { return (
    - {inSimulation ? (
    @@ -26,7 +19,7 @@ const RoomSidebarComponent = ({ roomId, roomType, inSimulation }) => {
    ) : (
    - {allowedObjects} +
    diff --git a/frontend/src/components/app/sidebars/topology/room/RoomTypeComponent.js b/frontend/src/components/app/sidebars/topology/room/RoomTypeComponent.js deleted file mode 100644 index b662307c..00000000 --- a/frontend/src/components/app/sidebars/topology/room/RoomTypeComponent.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react' -import { ROOM_TYPE_TO_NAME_MAP } from '../../../../../util/room-types' - -const RoomTypeComponent = ({ roomType }) => ( -

    {ROOM_TYPE_TO_NAME_MAP[roomType]}

    -) - -export default RoomTypeComponent diff --git a/frontend/src/components/app/timeline/TimelineControlsComponent.js b/frontend/src/components/app/timeline/TimelineControlsComponent.js index 5412b1f5..01911aff 100644 --- a/frontend/src/components/app/timeline/TimelineControlsComponent.js +++ b/frontend/src/components/app/timeline/TimelineControlsComponent.js @@ -27,19 +27,6 @@ class TimelineControlsComponent extends React.Component { ), }} /> - {this.props.sectionTicks.map(sectionTick => ( -
    - ))}
    ) diff --git a/frontend/src/components/experiments/ExperimentListComponent.js b/frontend/src/components/experiments/ExperimentListComponent.js index 55a7ff6d..3c53fc94 100644 --- a/frontend/src/components/experiments/ExperimentListComponent.js +++ b/frontend/src/components/experiments/ExperimentListComponent.js @@ -31,7 +31,7 @@ const ExperimentListComponent = ({ experimentIds, loading }) => { Name - Path + Topology Trace Scheduler @@ -52,7 +52,7 @@ const ExperimentListComponent = ({ experimentIds, loading }) => { } ExperimentListComponent.propTypes = { - experimentIds: PropTypes.arrayOf(PropTypes.number).isRequired, + experimentIds: PropTypes.arrayOf(PropTypes.string).isRequired, loading: PropTypes.bool, } diff --git a/frontend/src/components/experiments/ExperimentRowComponent.js b/frontend/src/components/experiments/ExperimentRowComponent.js index 8a2638a7..880d7e31 100644 --- a/frontend/src/components/experiments/ExperimentRowComponent.js +++ b/frontend/src/components/experiments/ExperimentRowComponent.js @@ -6,16 +6,12 @@ import Shapes from '../../shapes/index' const ExperimentRowComponent = ({ experiment, simulationId, onDelete }) => ( {experiment.name} - - {experiment.path.name - ? experiment.path.name - : 'Path ' + experiment.path.id} - + {experiment.topology.name} {experiment.trace.name} {experiment.scheduler.name} @@ -24,7 +20,7 @@ const ExperimentRowComponent = ({ experiment, simulationId, onDelete }) => (
    onDelete(experiment.id)} + onClick={() => onDelete(experiment._id)} >
    diff --git a/frontend/src/components/home/TeamSection.js b/frontend/src/components/home/TeamSection.js index 2b7bb69d..6823797f 100644 --- a/frontend/src/components/home/TeamSection.js +++ b/frontend/src/components/home/TeamSection.js @@ -2,7 +2,7 @@ import React from 'react' import ContentSection from './ContentSection' const TeamMember = ({ photoId, name, description }) => ( -
    +
    ( name="Prof. dr. ir. Alexandru Iosup" description="Project Lead" /> - ( name="Fabian Mastenbroek" description="Software Engineer responsible for the datacenter simulator" /> + +
    See{' '} diff --git a/frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js b/frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js new file mode 100644 index 00000000..e36bde48 --- /dev/null +++ b/frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js @@ -0,0 +1,111 @@ +import PropTypes from 'prop-types' +import React from 'react' +import Shapes from '../../../shapes' +import Modal from '../Modal' + +class ChangeTopologyModalComponent extends React.Component { + static propTypes = { + show: PropTypes.bool.isRequired, + topologies: PropTypes.arrayOf(Shapes.Topology), + onCreateTopology: PropTypes.func.isRequired, + onDuplicateTopology: PropTypes.func.isRequired, + onDeleteTopology: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + } + + reset() { + this.textInput.value = '' + this.originTopology.selectedIndex = 0 + } + + onSubmit() { + if (this.originTopology.selectedIndex === 0) { + this.onCreate() + } else { + this.onDuplicate() + } + } + + onCreate() { + this.props.onCreateTopology(this.textInput.value) + this.reset() + } + + onDuplicate() { + this.props.onCreateTopology( + this.textInput.value, + this.originTopology.value, + ) + this.reset() + } + + onDelete(id) { + this.props.onDeleteTopology(id) + this.reset() + } + + onCancel() { + this.props.onCancel() + this.reset() + } + + render() { + return ( + +
    + {this.props.topologies.forEach(topology => ( +
    + {topology.name} +
    this.onDelete(topology._id)} + > + Delete +
    +
    + ))} +
    + +
    { + e.preventDefault() + this.onSubmit() + }} + > +
    + + (this.textInput = textInput)} + /> +
    +
    + + +
    +
    +
    + ) + } +} + +export default ChangeTopologyModalComponent diff --git a/frontend/src/components/modals/custom-components/NewExperimentModalComponent.js b/frontend/src/components/modals/custom-components/NewExperimentModalComponent.js index 143109ff..ce685837 100644 --- a/frontend/src/components/modals/custom-components/NewExperimentModalComponent.js +++ b/frontend/src/components/modals/custom-components/NewExperimentModalComponent.js @@ -6,7 +6,7 @@ import Modal from '../Modal' class NewExperimentModalComponent extends React.Component { static propTypes = { show: PropTypes.bool.isRequired, - paths: PropTypes.arrayOf(Shapes.Path), + topologies: PropTypes.arrayOf(Shapes.Topology), schedulers: PropTypes.arrayOf(Shapes.Scheduler), traces: PropTypes.arrayOf(Shapes.Trace), callback: PropTypes.func.isRequired, @@ -14,7 +14,7 @@ class NewExperimentModalComponent extends React.Component { reset() { this.textInput.value = '' - this.pathSelect.selectedIndex = 0 + this.topologySelect.selectedIndex = 0 this.traceSelect.selectedIndex = 0 this.schedulerSelect.selectedIndex = 0 } @@ -22,8 +22,8 @@ class NewExperimentModalComponent extends React.Component { onSubmit() { this.props.callback( this.textInput.value, - parseInt(this.pathSelect.value, 10), - parseInt(this.traceSelect.value, 10), + this.topologySelect.value, + this.traceSelect.value, this.schedulerSelect.value, ) this.reset() @@ -53,18 +53,19 @@ class NewExperimentModalComponent extends React.Component { (this.textInput = textInput)} />
    - + @@ -76,7 +77,7 @@ class NewExperimentModalComponent extends React.Component { ref={traceSelect => (this.traceSelect = traceSelect)} > {this.props.traces.map(trace => ( - ))} diff --git a/frontend/src/components/navigation/AppNavbar.js b/frontend/src/components/navigation/AppNavbar.js index 451bb6a3..da43a330 100644 --- a/frontend/src/components/navigation/AppNavbar.js +++ b/frontend/src/components/navigation/AppNavbar.js @@ -4,52 +4,50 @@ import { Link } from 'react-router-dom' import Navbar, { NavItem } from './Navbar' import './Navbar.css' -const AppNavbar = ({ simulationId, inSimulation, fullWidth }) => ( +const AppNavbar = ({ simulationId, inSimulation, fullWidth, onViewTopologies }) => ( - {inSimulation ? ( - - - - Construction - - - ) : ( - undefined - )} - {inSimulation ? ( - - - - Experiments - - - ) : ( - undefined - )} My Simulations - - - - Support - - + {inSimulation ? ( + <> + + + + Construction + + + + + + Topologies + + + + + + Experiments + + + + ) : ( + undefined + )} ) diff --git a/frontend/src/containers/app/map/DatacenterContainer.js b/frontend/src/containers/app/map/DatacenterContainer.js deleted file mode 100644 index 9ed1d38c..00000000 --- a/frontend/src/containers/app/map/DatacenterContainer.js +++ /dev/null @@ -1,17 +0,0 @@ -import { connect } from 'react-redux' -import DatacenterGroup from '../../../components/app/map/groups/DatacenterGroup' - -const mapStateToProps = state => { - if (state.currentDatacenterId === -1) { - return {} - } - - return { - datacenter: state.objects.datacenter[state.currentDatacenterId], - interactionLevel: state.interactionLevel, - } -} - -const DatacenterContainer = connect(mapStateToProps)(DatacenterGroup) - -export default DatacenterContainer diff --git a/frontend/src/containers/app/map/MapStage.js b/frontend/src/containers/app/map/MapStage.js index e8abb86f..f749e85a 100644 --- a/frontend/src/containers/app/map/MapStage.js +++ b/frontend/src/containers/app/map/MapStage.js @@ -1,9 +1,5 @@ import { connect } from 'react-redux' -import { - setMapDimensions, - setMapPositionWithBoundsCheck, - zoomInOnPosition, -} from '../../../actions/map' +import { setMapDimensions, setMapPositionWithBoundsCheck, zoomInOnPosition } from '../../../actions/map' import MapStageComponent from '../../../components/app/map/MapStageComponent' const mapStateToProps = state => { diff --git a/frontend/src/containers/app/map/RackContainer.js b/frontend/src/containers/app/map/RackContainer.js index 614421b4..362ba2e2 100644 --- a/frontend/src/containers/app/map/RackContainer.js +++ b/frontend/src/containers/app/map/RackContainer.js @@ -9,11 +9,11 @@ const mapStateToProps = (state, ownProps) => { if (inSimulation) { if ( state.states.rack[state.currentTick] && - state.states.rack[state.currentTick][ownProps.tile.objectId] + state.states.rack[state.currentTick][ownProps.tile.rackId] ) { rackLoad = getStateLoad( state.loadMetric, - state.states.rack[state.currentTick][ownProps.tile.objectId], + state.states.rack[state.currentTick][ownProps.tile.rackId], ) } } diff --git a/frontend/src/containers/app/map/RackEnergyFillContainer.js b/frontend/src/containers/app/map/RackEnergyFillContainer.js index e25cd37d..d5989839 100644 --- a/frontend/src/containers/app/map/RackEnergyFillContainer.js +++ b/frontend/src/containers/app/map/RackEnergyFillContainer.js @@ -3,7 +3,7 @@ import RackFillBar from '../../../components/app/map/elements/RackFillBar' const mapStateToProps = (state, ownProps) => { let energyConsumptionTotal = 0 - const rack = state.objects.rack[state.objects.tile[ownProps.tileId].objectId] + const rack = state.objects.rack[state.objects.tile[ownProps.tileId].rackId] const machineIds = rack.machineIds machineIds.forEach(machineId => { if (machineId !== null) { diff --git a/frontend/src/containers/app/map/RackSpaceFillContainer.js b/frontend/src/containers/app/map/RackSpaceFillContainer.js index c43695a9..8110b1fb 100644 --- a/frontend/src/containers/app/map/RackSpaceFillContainer.js +++ b/frontend/src/containers/app/map/RackSpaceFillContainer.js @@ -3,7 +3,7 @@ import RackFillBar from '../../../components/app/map/elements/RackFillBar' const mapStateToProps = (state, ownProps) => { const machineIds = - state.objects.rack[state.objects.tile[ownProps.tileId].objectId].machineIds + state.objects.rack[state.objects.tile[ownProps.tileId].rackId].machineIds return { type: 'space', fillFraction: diff --git a/frontend/src/containers/app/map/TileContainer.js b/frontend/src/containers/app/map/TileContainer.js index 6122be96..7d9f7754 100644 --- a/frontend/src/containers/app/map/TileContainer.js +++ b/frontend/src/containers/app/map/TileContainer.js @@ -31,8 +31,8 @@ const mapStateToProps = (state, ownProps) => { const mapDispatchToProps = dispatch => { return { onClick: tile => { - if (tile.objectType) { - dispatch(goFromRoomToRack(tile.id)) + if (tile.rackId) { + dispatch(goFromRoomToRack(tile._id)) } }, } diff --git a/frontend/src/containers/app/map/TopologyContainer.js b/frontend/src/containers/app/map/TopologyContainer.js new file mode 100644 index 00000000..37cc5a06 --- /dev/null +++ b/frontend/src/containers/app/map/TopologyContainer.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux' +import TopologyGroup from '../../../components/app/map/groups/TopologyGroup' + +const mapStateToProps = state => { + if (state.currentTopologyId === -1) { + return {} + } + + return { + topology: state.objects.topology[state.currentTopologyId], + interactionLevel: state.interactionLevel, + } +} + +const TopologyContainer = connect(mapStateToProps)(TopologyGroup) + +export default TopologyContainer diff --git a/frontend/src/containers/app/map/layers/ObjectHoverLayer.js b/frontend/src/containers/app/map/layers/ObjectHoverLayer.js index dc489e82..4619c0b8 100644 --- a/frontend/src/containers/app/map/layers/ObjectHoverLayer.js +++ b/frontend/src/containers/app/map/layers/ObjectHoverLayer.js @@ -19,7 +19,7 @@ const mapStateToProps = state => { ) const tile = findTileWithPosition(tiles, x, y) - return !(tile === null || tile.objectType) + return !(tile === null || tile.rackId) }, } } diff --git a/frontend/src/containers/app/map/layers/RoomHoverLayer.js b/frontend/src/containers/app/map/layers/RoomHoverLayer.js index b5a891ce..c05627ea 100644 --- a/frontend/src/containers/app/map/layers/RoomHoverLayer.js +++ b/frontend/src/containers/app/map/layers/RoomHoverLayer.js @@ -21,9 +21,9 @@ const mapStateToProps = state => { .map(id => Object.assign({}, state.objects.room[id])) .filter( room => - state.objects.datacenter[state.currentDatacenterId].roomIds.indexOf( - room.id, - ) !== -1 && room.id !== state.construction.currentRoomInConstruction, + state.objects.topology[state.currentTopologyId].roomIds.indexOf( + room._id, + ) !== -1 && room._id !== state.construction.currentRoomInConstruction, ); [...oldRooms, newRoom].forEach(room => { diff --git a/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js b/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js index 06d0b88a..0dc20ea7 100644 --- a/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js +++ b/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js @@ -5,21 +5,21 @@ const mapStateToProps = state => { if (!state.objects.experiment[state.currentExperimentId]) { return { experimentName: 'Loading experiment', - pathName: '', + topologyName: '', traceName: '', schedulerName: '', } } - const path = - state.objects.path[ - state.objects.experiment[state.currentExperimentId].pathId + const topology = + state.objects.topology[ + state.objects.experiment[state.currentExperimentId].topologyId ] - const pathName = path.name ? path.name : 'Path ' + path.id + const topologyName = topology.name return { experimentName: state.objects.experiment[state.currentExperimentId].name, - pathName, + topologyName, traceName: state.objects.trace[ state.objects.experiment[state.currentExperimentId].traceId diff --git a/frontend/src/containers/app/sidebars/simulation/TaskContainer.js b/frontend/src/containers/app/sidebars/simulation/TaskContainer.js deleted file mode 100644 index c4c86284..00000000 --- a/frontend/src/containers/app/sidebars/simulation/TaskContainer.js +++ /dev/null @@ -1,26 +0,0 @@ -import { connect } from 'react-redux' -import TaskComponent from '../../../../components/app/sidebars/simulation/TaskComponent' - -const mapStateToProps = (state, ownProps) => { - let flopsLeft = state.objects.task[ownProps.taskId].totalFlopCount - - if ( - state.states.task[state.currentTick] && - state.states.task[state.currentTick][ownProps.taskId] - ) { - flopsLeft = state.states.task[state.currentTick][ownProps.taskId].flopsLeft - } else if ( - state.objects.task[ownProps.taskId].startTick < state.currentTick - ) { - flopsLeft = 0 - } - - return { - task: state.objects.task[ownProps.taskId], - flopsLeft, - } -} - -const TaskContainer = connect(mapStateToProps)(TaskComponent) - -export default TaskContainer diff --git a/frontend/src/containers/app/sidebars/simulation/TraceContainer.js b/frontend/src/containers/app/sidebars/simulation/TraceContainer.js deleted file mode 100644 index 907c8874..00000000 --- a/frontend/src/containers/app/sidebars/simulation/TraceContainer.js +++ /dev/null @@ -1,25 +0,0 @@ -import { connect } from 'react-redux' -import TraceComponent from '../../../../components/app/sidebars/simulation/TraceComponent' - -const mapStateToProps = state => { - if ( - !state.objects.experiment[state.currentExperimentId] || - !state.objects.trace[ - state.objects.experiment[state.currentExperimentId].traceId - ].jobIds - ) { - return { - jobs: [], - } - } - - return { - jobs: state.objects.trace[ - state.objects.experiment[state.currentExperimentId].traceId - ].jobIds.map(id => state.objects.job[id]), - } -} - -const TraceContainer = connect(mapStateToProps)(TraceComponent) - -export default TraceContainer diff --git a/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js index 711b2b82..1869705a 100644 --- a/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux' -import BuildingSidebarComponent - from '../../../../../components/app/sidebars/topology/building/BuildingSidebarComponent' +import BuildingSidebarComponent from '../../../../../components/app/sidebars/topology/building/BuildingSidebarComponent' const mapStateToProps = state => { return { diff --git a/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js index f5baee44..a39bd2d6 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js @@ -6,7 +6,7 @@ const mapStateToProps = state => { inSimulation: state.currentExperimentId !== -1, machineId: state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].objectId + state.objects.tile[state.interactionLevel.tileId].rackId ].machineIds[state.interactionLevel.position - 1], } } diff --git a/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js b/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js index 1a01cad0..d8e549a7 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js @@ -4,8 +4,8 @@ import UnitComponent from '../../../../../components/app/sidebars/topology/machi const mapStateToProps = (state, ownProps) => { return { - unit: state.objects[ownProps.unitType][ownProps.unitId], inSimulation: state.currentExperimentId !== -1, + unit: state.objects[ownProps.unitType][ownProps.unitId], } } diff --git a/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js b/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js index fce657d4..2f11a22f 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js @@ -3,13 +3,13 @@ import UnitListComponent from '../../../../../components/app/sidebars/topology/m const mapStateToProps = (state, ownProps) => { return { + inSimulation: state.currentExperimentId !== -1, unitIds: state.objects.machine[ state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].objectId + state.objects.tile[state.interactionLevel.tileId].rackId ].machineIds[state.interactionLevel.position - 1] ][ownProps.unitType + 'Ids'], - inSimulation: state.currentExperimentId !== -1, } } diff --git a/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js b/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js index f205257e..89818f1d 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js @@ -11,11 +11,11 @@ const mapStateToProps = (state, ownProps) => { if (inSimulation) { if ( state.states.machine[state.currentTick] && - state.states.machine[state.currentTick][machine.id] + state.states.machine[state.currentTick][machine._id] ) { machineLoad = getStateLoad( state.loadMetric, - state.states.machine[state.currentTick][machine.id], + state.states.machine[state.currentTick][machine._id], ) } } diff --git a/frontend/src/containers/app/sidebars/topology/rack/MachineListContainer.js b/frontend/src/containers/app/sidebars/topology/rack/MachineListContainer.js index 3a797ed5..3898d119 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/MachineListContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/MachineListContainer.js @@ -5,7 +5,7 @@ const mapStateToProps = state => { return { machineIds: state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].objectId + state.objects.tile[state.interactionLevel.tileId].rackId ].machineIds, } } diff --git a/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js b/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js index 11173b82..1eb885fc 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js @@ -6,7 +6,7 @@ const mapStateToProps = state => { return { rackName: state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].objectId + state.objects.tile[state.interactionLevel.tileId].rackId ].name, } } diff --git a/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js index 89382ef0..21745b1d 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js @@ -3,7 +3,7 @@ import RackSidebarComponent from '../../../../../components/app/sidebars/topolog const mapStateToProps = state => { return { - rackId: state.objects.tile[state.interactionLevel.tileId].objectId, + rackId: state.objects.tile[state.interactionLevel.tileId].rackId, inSimulation: state.currentExperimentId !== -1, } } diff --git a/frontend/src/containers/app/sidebars/topology/room/EditRoomContainer.js b/frontend/src/containers/app/sidebars/topology/room/EditRoomContainer.js index 29014022..87470bfe 100644 --- a/frontend/src/containers/app/sidebars/topology/room/EditRoomContainer.js +++ b/frontend/src/containers/app/sidebars/topology/room/EditRoomContainer.js @@ -1,8 +1,5 @@ import { connect } from 'react-redux' -import { - finishRoomEdit, - startRoomEdit, -} from '../../../../../actions/topology/building' +import { finishRoomEdit, startRoomEdit } from '../../../../../actions/topology/building' import EditRoomComponent from '../../../../../components/app/sidebars/topology/room/EditRoomComponent' const mapStateToProps = state => { diff --git a/frontend/src/containers/app/sidebars/topology/room/RackConstructionContainer.js b/frontend/src/containers/app/sidebars/topology/room/RackConstructionContainer.js index fe42647c..30f7a688 100644 --- a/frontend/src/containers/app/sidebars/topology/room/RackConstructionContainer.js +++ b/frontend/src/containers/app/sidebars/topology/room/RackConstructionContainer.js @@ -1,8 +1,5 @@ import { connect } from 'react-redux' -import { - startRackConstruction, - stopRackConstruction, -} from '../../../../../actions/topology/room' +import { startRackConstruction, stopRackConstruction } from '../../../../../actions/topology/room' import RackConstructionComponent from '../../../../../components/app/sidebars/topology/room/RackConstructionComponent' const mapStateToProps = state => { diff --git a/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js index f940b282..443495de 100644 --- a/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js @@ -3,9 +3,8 @@ import RoomSidebarComponent from '../../../../../components/app/sidebars/topolog const mapStateToProps = state => { return { - roomId: state.interactionLevel.roomId, - roomType: state.objects.room[state.interactionLevel.roomId].roomType, inSimulation: state.currentExperimentId !== -1, + roomId: state.interactionLevel.roomId, } } diff --git a/frontend/src/containers/app/sidebars/topology/room/RoomTypeContainer.js b/frontend/src/containers/app/sidebars/topology/room/RoomTypeContainer.js deleted file mode 100644 index de4c8c85..00000000 --- a/frontend/src/containers/app/sidebars/topology/room/RoomTypeContainer.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import RoomTypeComponent from '../../../../../components/app/sidebars/topology/room/RoomTypeComponent' - -const mapStateToProps = state => { - return { - roomType: state.objects.room[state.interactionLevel.roomId].roomType, - } -} - -const RoomNameContainer = connect(mapStateToProps)(RoomTypeComponent) - -export default RoomNameContainer diff --git a/frontend/src/containers/app/timeline/PlayButtonContainer.js b/frontend/src/containers/app/timeline/PlayButtonContainer.js index e332f08b..9662d753 100644 --- a/frontend/src/containers/app/timeline/PlayButtonContainer.js +++ b/frontend/src/containers/app/timeline/PlayButtonContainer.js @@ -1,8 +1,5 @@ import { connect } from 'react-redux' -import { - pauseSimulation, - playSimulation, -} from '../../../actions/simulation/playback' +import { pauseSimulation, playSimulation } from '../../../actions/simulation/playback' import PlayButtonComponent from '../../../components/app/timeline/PlayButtonComponent' const mapStateToProps = state => { diff --git a/frontend/src/containers/app/timeline/TimelineContainer.js b/frontend/src/containers/app/timeline/TimelineContainer.js index 4fcaaaaf..9b196a1b 100644 --- a/frontend/src/containers/app/timeline/TimelineContainer.js +++ b/frontend/src/containers/app/timeline/TimelineContainer.js @@ -1,28 +1,14 @@ import { connect } from 'react-redux' import { pauseSimulation } from '../../../actions/simulation/playback' import { incrementTick } from '../../../actions/simulation/tick' -import { setCurrentDatacenter } from '../../../actions/topology/building' import TimelineComponent from '../../../components/app/timeline/TimelineComponent' const mapStateToProps = state => { - let sections = [] - if (state.currentExperimentId !== -1) { - const sectionIds = - state.objects.path[ - state.objects.experiment[state.currentExperimentId].pathId - ].sectionIds - - if (sectionIds) { - sections = sectionIds.map(sectionId => state.objects.section[sectionId]) - } - } - return { isPlaying: state.isPlaying, currentTick: state.currentTick, lastSimulatedTick: state.lastSimulatedTick, - currentDatacenterId: state.currentDatacenterId, - sections, + currentTopologyId: state.currentTopologyId, } } @@ -30,7 +16,6 @@ const mapDispatchToProps = dispatch => { return { incrementTick: () => dispatch(incrementTick()), pauseSimulation: () => dispatch(pauseSimulation()), - setCurrentDatacenter: id => dispatch(setCurrentDatacenter(id)), } } diff --git a/frontend/src/containers/app/timeline/TimelineControlsContainer.js b/frontend/src/containers/app/timeline/TimelineControlsContainer.js index 92e03e6a..91aba98d 100644 --- a/frontend/src/containers/app/timeline/TimelineControlsContainer.js +++ b/frontend/src/containers/app/timeline/TimelineControlsContainer.js @@ -3,23 +3,9 @@ import { goToTick } from '../../../actions/simulation/tick' import TimelineControlsComponent from '../../../components/app/timeline/TimelineControlsComponent' const mapStateToProps = state => { - let sectionTicks = [] - if (state.currentExperimentId !== -1) { - const sectionIds = - state.objects.path[ - state.objects.experiment[state.currentExperimentId].pathId - ].sectionIds - if (sectionIds) { - sectionTicks = sectionIds - .filter(sectionId => state.objects.section[sectionId].startTick !== 0) - .map(sectionId => state.objects.section[sectionId].startTick) - } - } - return { currentTick: state.currentTick, lastSimulatedTick: state.lastSimulatedTick, - sectionTicks, } } diff --git a/frontend/src/containers/experiments/ExperimentRowContainer.js b/frontend/src/containers/experiments/ExperimentRowContainer.js index bec32617..523c0747 100644 --- a/frontend/src/containers/experiments/ExperimentRowContainer.js +++ b/frontend/src/containers/experiments/ExperimentRowContainer.js @@ -9,7 +9,7 @@ const mapStateToProps = (state, ownProps) => { ) experiment.trace = state.objects.trace[experiment.traceId] experiment.scheduler = state.objects.scheduler[experiment.schedulerName] - experiment.path = state.objects.path[experiment.pathId] + experiment.topology = state.objects.topology[experiment.topologyId] return { experiment, diff --git a/frontend/src/containers/modals/ChangeTopologyModal.js b/frontend/src/containers/modals/ChangeTopologyModal.js new file mode 100644 index 00000000..bd364194 --- /dev/null +++ b/frontend/src/containers/modals/ChangeTopologyModal.js @@ -0,0 +1,56 @@ +import { connect } from 'react-redux' +import ChangeTopologyModalComponent from '../../components/modals/custom-components/ChangeTopologyModalComponent' +import { closeChangeTopologyModal } from '../../actions/modals/topology' +import { addTopology, deleteTopology } from '../../actions/topologies' + +const mapStateToProps = state => { + let topologies = state.objects.simulation[state.currentSimulationId] ? state.objects.simulation[state.currentSimulationId].topologyIds.map(t => ( + state.objects.topology[t] + )) : [] + if (topologies.filter(t => !t).length > 0) { + topologies = [] + } + + return { + show: state.modals.newExperimentModalVisible, + topologies, + } +} + +const mapDispatchToProps = dispatch => { + return { + onCreateTopology: (name) => { + if (name) { + dispatch( + addTopology({name}) + ) + } + dispatch(closeChangeTopologyModal()) + }, + onDuplicateTopology: (name) => { + if (name) { + // TODO different handling here + dispatch( + addTopology({name}) + ) + } + dispatch(closeChangeTopologyModal()) + }, + onDeleteTopology: (id) => { + if (id) { + dispatch( + deleteTopology(id) + ) + } + }, + onCancel: () => { + dispatch(closeChangeTopologyModal()) + }, + } +} + +const ChangeTopologyModal = connect(mapStateToProps, mapDispatchToProps)( + ChangeTopologyModalComponent, +) + +export default ChangeTopologyModal diff --git a/frontend/src/containers/modals/EditRackNameModal.js b/frontend/src/containers/modals/EditRackNameModal.js index e5c87e35..495c107b 100644 --- a/frontend/src/containers/modals/EditRackNameModal.js +++ b/frontend/src/containers/modals/EditRackNameModal.js @@ -20,7 +20,7 @@ const mapStateToProps = state => { previousName: state.interactionLevel.mode === 'RACK' ? state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].objectId + state.objects.tile[state.interactionLevel.tileId].rackId ].name : '', } diff --git a/frontend/src/containers/modals/NewExperimentModal.js b/frontend/src/containers/modals/NewExperimentModal.js index db60f088..2ac5a4b8 100644 --- a/frontend/src/containers/modals/NewExperimentModal.js +++ b/frontend/src/containers/modals/NewExperimentModal.js @@ -6,9 +6,9 @@ import NewExperimentModalComponent from '../../components/modals/custom-componen const mapStateToProps = state => { return { show: state.modals.newExperimentModalVisible, - paths: Object.values(state.objects.path).filter( - path => path.simulationId === state.currentSimulationId, - ), + topologies: state.objects.simulation[state.currentSimulationId].topologyIds.map(t => ( + state.objects.topology[t] + )), traces: Object.values(state.objects.trace), schedulers: Object.values(state.objects.scheduler), } @@ -16,12 +16,12 @@ const mapStateToProps = state => { const mapDispatchToProps = dispatch => { return { - callback: (name, pathId, traceId, schedulerName) => { + callback: (name, topologyId, traceId, schedulerName) => { if (name) { dispatch( addExperiment({ name, - pathId, + topologyId, traceId, schedulerName, }), diff --git a/frontend/src/index.js b/frontend/src/index.js index 940a8dd7..a81a4bc2 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -3,7 +3,6 @@ import ReactDOM from 'react-dom' import { Provider } from 'react-redux' import { setupSocketConnection } from './api/socket' import './index.css' -import registerServiceWorker from './registerServiceWorker' import Routes from './routes' import configureStore from './store/configure-store' @@ -16,6 +15,4 @@ setupSocketConnection(() => { , document.getElementById('root'), ) - - registerServiceWorker() }) diff --git a/frontend/src/pages/App.js b/frontend/src/pages/App.js index c2b9bd51..3034f7ff 100644 --- a/frontend/src/pages/App.js +++ b/frontend/src/pages/App.js @@ -5,7 +5,7 @@ import { connect } from 'react-redux' import { ShortcutManager } from 'react-shortcuts' import { openExperimentSucceeded } from '../actions/experiments' import { openSimulationSucceeded } from '../actions/simulations' -import { resetCurrentDatacenter } from '../actions/topology/building' +import { resetCurrentTopology } from '../actions/topology/building' import ToolPanelComponent from '../components/app/map/controls/ToolPanelComponent' import LoadingScreen from '../components/app/map/LoadingScreen' import SimulationSidebarComponent from '../components/app/sidebars/simulation/SimulationSidebarComponent' @@ -20,6 +20,8 @@ import DeleteRoomModal from '../containers/modals/DeleteRoomModal' import EditRackNameModal from '../containers/modals/EditRackNameModal' import EditRoomNameModal from '../containers/modals/EditRoomNameModal' import KeymapConfiguration from '../shortcuts/keymap' +import ChangeTopologyModal from '../containers/modals/ChangeTopologyModal' +import { openChangeTopologyModal } from '../actions/modals/topology' const shortcutManager = new ShortcutManager(KeymapConfiguration) @@ -29,18 +31,16 @@ class AppComponent extends React.Component { inSimulation: PropTypes.bool, experimentId: PropTypes.number, simulationName: PropTypes.string, + onViewTopologies: PropTypes.func, } static childContextTypes = { shortcuts: PropTypes.object.isRequired, } componentDidMount() { - this.props.resetCurrentDatacenter() + // TODO this.props.resetCurrentTopology() if (this.props.inSimulation) { - this.props.openExperimentSucceeded( - this.props.simulationId, - this.props.experimentId, - ) + this.props.openExperimentSucceeded(this.props.simulationId, this.props.experimentId) return } this.props.openSimulationSucceeded(this.props.simulationId) @@ -55,66 +55,58 @@ class AppComponent extends React.Component { render() { return (
    - {this.props.datacenterIsLoading ? ( + {this.props.topologyIsLoading ? (
    - +
    ) : (
    - - - - - {this.props.inSimulation ? : undefined} - {this.props.inSimulation ? ( - - ) : ( - undefined - )} + + + + + {this.props.inSimulation ? : undefined} + {this.props.inSimulation ? : undefined}
    )} - - - - - + + + + + +
    ) } } -const mapStateToProps = state => { +const mapStateToProps = (state) => { let simulationName = undefined - if ( - state.currentSimulationId !== -1 && - state.objects.simulation[state.currentSimulationId] - ) { + if (state.currentSimulationId !== -1 && state.objects.simulation[state.currentSimulationId]) { simulationName = state.objects.simulation[state.currentSimulationId].name } return { - datacenterIsLoading: state.currentDatacenterId === -1, + topologyIsLoading: state.currentTopologyId === -1, simulationName, } } -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch) => { return { - resetCurrentDatacenter: () => dispatch(resetCurrentDatacenter()), - openSimulationSucceeded: id => dispatch(openSimulationSucceeded(id)), + resetCurrentTopology: () => dispatch(resetCurrentTopology()), + openSimulationSucceeded: (id) => dispatch(openSimulationSucceeded(id)), + onViewTopologies: () => dispatch(openChangeTopologyModal()), openExperimentSucceeded: (simulationId, experimentId) => dispatch(openExperimentSucceeded(simulationId, experimentId)), } diff --git a/frontend/src/pages/Experiments.js b/frontend/src/pages/Experiments.js index 67e3fd77..97e63f44 100644 --- a/frontend/src/pages/Experiments.js +++ b/frontend/src/pages/Experiments.js @@ -30,28 +30,21 @@ class ExperimentsComponent extends React.Component { } >
    - +
    - - + +
    - +
    ) } } -const mapStateToProps = state => { +const mapStateToProps = (state) => { let simulationName = undefined - if ( - state.currentSimulationId !== -1 && - state.objects.simulation[state.currentSimulationId] - ) { + if (state.currentSimulationId !== -1 && state.objects.simulation[state.currentSimulationId]) { simulationName = state.objects.simulation[state.currentSimulationId].name } @@ -60,16 +53,13 @@ const mapStateToProps = state => { } } -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch) => { return { - storeSimulationId: id => dispatch(openSimulationSucceeded(id)), - fetchExperimentsOfSimulation: id => - dispatch(fetchExperimentsOfSimulation(id)), + storeSimulationId: (id) => dispatch(openSimulationSucceeded(id)), + fetchExperimentsOfSimulation: (id) => dispatch(fetchExperimentsOfSimulation(id)), } } -const Experiments = connect(mapStateToProps, mapDispatchToProps)( - ExperimentsComponent, -) +const Experiments = connect(mapStateToProps, mapDispatchToProps)(ExperimentsComponent) export default Experiments diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js index e69c2049..1bdfc5c7 100644 --- a/frontend/src/pages/Home.js +++ b/frontend/src/pages/Home.js @@ -21,7 +21,7 @@ class Home extends React.Component { const scrollOffset = 60 jQuery('#navbar') .find('li a') - .click(function(e) { + .click(function (e) { if (jQuery(e.target).parents('.auth-links').length > 0) { return } @@ -42,17 +42,17 @@ class Home extends React.Component { render() { return (
    - +
    - - - - - - - - - + + + + + + + + +
    ) diff --git a/frontend/src/pages/NotFound.js b/frontend/src/pages/NotFound.js index 959cceec..f72c7d01 100644 --- a/frontend/src/pages/NotFound.js +++ b/frontend/src/pages/NotFound.js @@ -6,7 +6,7 @@ import './NotFound.css' const NotFound = () => (
    - +
    ) diff --git a/frontend/src/pages/Profile.js b/frontend/src/pages/Profile.js index e6d2aa7b..45b48247 100644 --- a/frontend/src/pages/Profile.js +++ b/frontend/src/pages/Profile.js @@ -8,28 +8,23 @@ import DeleteProfileModal from '../containers/modals/DeleteProfileModal' const ProfileContainer = ({ onDelete }) => (
    - +
    -

    - This does not delete your Google account, but simply disconnects it - from the OpenDC platform and deletes any simulation info that is - associated with you (simulations you own and any authorizations you - may have on other projects). + This does not delete your Google account, but simply disconnects it from the OpenDC platform and + deletes any simulation info that is associated with you (simulations you own and any authorizations + you may have on other projects).

    - +
    ) -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch) => { return { onDelete: () => dispatch(openDeleteProfileModal()), } diff --git a/frontend/src/pages/Simulations.js b/frontend/src/pages/Simulations.js index 116eb1b2..ce2386fd 100644 --- a/frontend/src/pages/Simulations.js +++ b/frontend/src/pages/Simulations.js @@ -18,29 +18,26 @@ class SimulationsContainer extends React.Component { return (
    - +
    - - - + + +
    - +
    ) } } -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch) => { return { - fetchAuthorizationsOfCurrentUser: () => - dispatch(fetchAuthorizationsOfCurrentUser()), + fetchAuthorizationsOfCurrentUser: () => dispatch(fetchAuthorizationsOfCurrentUser()), openNewSimulationModal: () => dispatch(openNewSimulationModal()), } } -const Simulations = connect(undefined, mapDispatchToProps)( - SimulationsContainer, -) +const Simulations = connect(undefined, mapDispatchToProps)(SimulationsContainer) export default Simulations diff --git a/frontend/src/reducers/current-ids.js b/frontend/src/reducers/current-ids.js index 6a605d9f..76ae67c7 100644 --- a/frontend/src/reducers/current-ids.js +++ b/frontend/src/reducers/current-ids.js @@ -1,12 +1,12 @@ import { OPEN_EXPERIMENT_SUCCEEDED } from '../actions/experiments' import { OPEN_SIMULATION_SUCCEEDED } from '../actions/simulations' -import { RESET_CURRENT_DATACENTER, SET_CURRENT_DATACENTER } from '../actions/topology/building' +import { RESET_CURRENT_TOPOLOGY, SET_CURRENT_TOPOLOGY } from '../actions/topology/building' -export function currentDatacenterId(state = -1, action) { +export function currentTopologyId(state = -1, action) { switch (action.type) { - case SET_CURRENT_DATACENTER: - return action.datacenterId - case RESET_CURRENT_DATACENTER: + case SET_CURRENT_TOPOLOGY: + return action.topologyId + case RESET_CURRENT_TOPOLOGY: return -1 default: return state diff --git a/frontend/src/reducers/index.js b/frontend/src/reducers/index.js index a5b14f4a..1c3ee145 100644 --- a/frontend/src/reducers/index.js +++ b/frontend/src/reducers/index.js @@ -1,7 +1,7 @@ import { combineReducers } from 'redux' import { auth } from './auth' import { construction } from './construction-mode' -import { currentDatacenterId, currentSimulationId } from './current-ids' +import { currentTopologyId, currentSimulationId } from './current-ids' import { interactionLevel } from './interaction-level' import { map } from './map' import { modals } from './modals' @@ -18,7 +18,7 @@ const rootReducer = combineReducers({ construction, map, currentSimulationId, - currentDatacenterId, + currentTopologyId, currentExperimentId, currentTick, lastSimulatedTick, diff --git a/frontend/src/reducers/interaction-level.js b/frontend/src/reducers/interaction-level.js index 12d5d70e..88c3b30e 100644 --- a/frontend/src/reducers/interaction-level.js +++ b/frontend/src/reducers/interaction-level.js @@ -6,13 +6,13 @@ import { GO_FROM_ROOM_TO_RACK, } from '../actions/interaction-level' import { OPEN_SIMULATION_SUCCEEDED } from '../actions/simulations' -import { SET_CURRENT_DATACENTER } from '../actions/topology/building' +import { SET_CURRENT_TOPOLOGY } from '../actions/topology/building' export function interactionLevel(state = { mode: 'BUILDING' }, action) { switch (action.type) { case OPEN_EXPERIMENT_SUCCEEDED: case OPEN_SIMULATION_SUCCEEDED: - case SET_CURRENT_DATACENTER: + case SET_CURRENT_TOPOLOGY: return { mode: 'BUILDING', } diff --git a/frontend/src/reducers/modals.js b/frontend/src/reducers/modals.js index 04e9ab49..81a0660e 100644 --- a/frontend/src/reducers/modals.js +++ b/frontend/src/reducers/modals.js @@ -4,11 +4,13 @@ import { CLOSE_NEW_EXPERIMENT_MODAL, OPEN_NEW_EXPERIMENT_MODAL } from '../action import { CLOSE_DELETE_PROFILE_MODAL, OPEN_DELETE_PROFILE_MODAL } from '../actions/modals/profile' import { CLOSE_NEW_SIMULATION_MODAL, OPEN_NEW_SIMULATION_MODAL } from '../actions/modals/simulations' import { + CLOSE_CHANGE_TOPOLOGY_MODAL, CLOSE_DELETE_MACHINE_MODAL, CLOSE_DELETE_RACK_MODAL, CLOSE_DELETE_ROOM_MODAL, CLOSE_EDIT_RACK_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL, + OPEN_CHANGE_TOPOLOGY_MODAL, OPEN_DELETE_MACHINE_MODAL, OPEN_DELETE_RACK_MODAL, OPEN_DELETE_ROOM_MODAL, @@ -17,7 +19,7 @@ import { } from '../actions/modals/topology' function modal(openAction, closeAction) { - return function(state = false, action) { + return function (state = false, action) { switch (action.type) { case openAction: return true @@ -31,36 +33,13 @@ function modal(openAction, closeAction) { } export const modals = combineReducers({ - newSimulationModalVisible: modal( - OPEN_NEW_SIMULATION_MODAL, - CLOSE_NEW_SIMULATION_MODAL, - ), - deleteProfileModalVisible: modal( - OPEN_DELETE_PROFILE_MODAL, - CLOSE_DELETE_PROFILE_MODAL, - ), - editRoomNameModalVisible: modal( - OPEN_EDIT_ROOM_NAME_MODAL, - CLOSE_EDIT_ROOM_NAME_MODAL, - ), - deleteRoomModalVisible: modal( - OPEN_DELETE_ROOM_MODAL, - CLOSE_DELETE_ROOM_MODAL, - ), - editRackNameModalVisible: modal( - OPEN_EDIT_RACK_NAME_MODAL, - CLOSE_EDIT_RACK_NAME_MODAL, - ), - deleteRackModalVisible: modal( - OPEN_DELETE_RACK_MODAL, - CLOSE_DELETE_RACK_MODAL, - ), - deleteMachineModalVisible: modal( - OPEN_DELETE_MACHINE_MODAL, - CLOSE_DELETE_MACHINE_MODAL, - ), - newExperimentModalVisible: modal( - OPEN_NEW_EXPERIMENT_MODAL, - CLOSE_NEW_EXPERIMENT_MODAL, - ), + newSimulationModalVisible: modal(OPEN_NEW_SIMULATION_MODAL, CLOSE_NEW_SIMULATION_MODAL), + deleteProfileModalVisible: modal(OPEN_DELETE_PROFILE_MODAL, CLOSE_DELETE_PROFILE_MODAL), + changeTopologyModalVisible: modal(OPEN_CHANGE_TOPOLOGY_MODAL, CLOSE_CHANGE_TOPOLOGY_MODAL), + editRoomNameModalVisible: modal(OPEN_EDIT_ROOM_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL), + deleteRoomModalVisible: modal(OPEN_DELETE_ROOM_MODAL, CLOSE_DELETE_ROOM_MODAL), + editRackNameModalVisible: modal(OPEN_EDIT_RACK_NAME_MODAL, CLOSE_EDIT_RACK_NAME_MODAL), + deleteRackModalVisible: modal(OPEN_DELETE_RACK_MODAL, CLOSE_DELETE_RACK_MODAL), + deleteMachineModalVisible: modal(OPEN_DELETE_MACHINE_MODAL, CLOSE_DELETE_MACHINE_MODAL), + newExperimentModalVisible: modal(OPEN_NEW_EXPERIMENT_MODAL, CLOSE_NEW_EXPERIMENT_MODAL), }) diff --git a/frontend/src/reducers/objects.js b/frontend/src/reducers/objects.js index 1dc1e7e8..f52ca369 100644 --- a/frontend/src/reducers/objects.js +++ b/frontend/src/reducers/objects.js @@ -5,41 +5,32 @@ import { ADD_TO_STORE, REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP, } from '../actions/objects' +import { CPU_UNITS, GPU_UNITS, MEMORY_UNITS, STORAGE_UNITS } from '../util/unit-specifications' export const objects = combineReducers({ simulation: object('simulation'), user: object('user'), - authorization: objectWithId('authorization', object => [ - object.userId, - object.simulationId, - ]), - failureModel: object('failureModel'), - cpu: object('cpu'), - gpu: object('gpu'), - memory: object('memory'), - storage: object('storage'), + authorization: objectWithId('authorization', (object) => [object.userId, object.simulationId]), + cpu: object('cpu', CPU_UNITS), + gpu: object('gpu', GPU_UNITS), + memory: object('memory', MEMORY_UNITS), + storage: object('storage', STORAGE_UNITS), machine: object('machine'), rack: object('rack'), - coolingItem: object('coolingItem'), - psu: object('psu'), tile: object('tile'), room: object('room'), - datacenter: object('datacenter'), - section: object('section'), - path: object('path'), - task: object('task'), - job: object('job'), + topology: object('topology'), trace: object('trace'), scheduler: object('scheduler'), experiment: object('experiment'), }) -function object(type) { - return objectWithId(type, object => object._id) +function object(type, defaultState = {}) { + return objectWithId(type, (object) => object._id, defaultState) } -function objectWithId(type, getId) { - return (state = {}, action) => { +function objectWithId(type, getId, defaultState = {}) { + return (state = defaultState, action) => { if (action.objectType !== type) { return state } @@ -50,27 +41,18 @@ function objectWithId(type, getId) { }) } else if (action.type === ADD_PROP_TO_STORE_OBJECT) { return Object.assign({}, state, { - [action.objectId]: Object.assign( - {}, - state[action.objectId], - action.propObject, - ), + [action.objectId]: Object.assign({}, state[action.objectId], action.propObject), }) } else if (action.type === ADD_ID_TO_STORE_OBJECT_LIST_PROP) { return Object.assign({}, state, { [action.objectId]: Object.assign({}, state[action.objectId], { - [action.propName]: [ - ...state[action.objectId][action.propName], - action.id, - ], + [action.propName]: [...state[action.objectId][action.propName], action.id], }), }) } else if (action.type === REMOVE_ID_FROM_STORE_OBJECT_LIST_PROP) { return Object.assign({}, state, { [action.objectId]: Object.assign({}, state[action.objectId], { - [action.propName]: state[action.objectId][action.propName].filter( - id => id !== action.id, - ), + [action.propName]: state[action.objectId][action.propName].filter((id) => id !== action.id), }), }) } diff --git a/frontend/src/reducers/simulation-list.js b/frontend/src/reducers/simulation-list.js index 78f3c4fe..383f4b35 100644 --- a/frontend/src/reducers/simulation-list.js +++ b/frontend/src/reducers/simulation-list.js @@ -13,7 +13,7 @@ export function authorizationsOfCurrentUser(state = [], action) { case ADD_SIMULATION_SUCCEEDED: return [...state, action.authorization] case DELETE_SIMULATION_SUCCEEDED: - return state.filter(authorization => authorization[1] !== action.id) + return state.filter((authorization) => authorization[1] !== action.id) default: return state } diff --git a/frontend/src/reducers/states.js b/frontend/src/reducers/states.js index e4c2fd19..c9bb4158 100644 --- a/frontend/src/reducers/states.js +++ b/frontend/src/reducers/states.js @@ -2,7 +2,6 @@ import { combineReducers } from 'redux' import { ADD_BATCH_TO_STATES } from '../actions/states' export const states = combineReducers({ - task: objectStates('task'), room: objectStates('room'), rack: objectStates('rack'), machine: objectStates('machine'), @@ -21,7 +20,7 @@ function objectStates(type) { {}, state[action.objects[i].tick], batch[action.objects[i].tick], - { [action.objects[i][action.objectType + 'Id']]: action.objects[i] }, + { [action.objects[i][action.objectType + 'Id']]: action.objects[i] } ) } diff --git a/frontend/src/registerServiceWorker.js b/frontend/src/registerServiceWorker.js deleted file mode 100644 index 32a116a6..00000000 --- a/frontend/src/registerServiceWorker.js +++ /dev/null @@ -1,108 +0,0 @@ -// In production, we register a service worker to serve assets from local cache. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on the "N+1" visit to a page, since previously -// cached resources are updated in the background. - -// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. -// This link also includes instructions on opting out of this behavior. - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/, - ), -) - -export default function register() { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location) - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 - return - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` - - if (!isLocalhost) { - // Is not local host. Just register service worker - registerValidSW(swUrl) - } else { - // This is running on localhost. Lets check if a service worker still exists or not. - checkValidServiceWorker(swUrl) - } - }) - } -} - -function registerValidSW(swUrl) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing - installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { - if (navigator.serviceWorker.controller) { - // At this point, the old content will have been purged and - // the fresh content will have been added to the cache. - // It's the perfect time to display a "New content is - // available; please refresh." message in your web app. - console.log('New content is available; please refresh.') - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log('Content is cached for offline use.') - } - } - } - } - }) - .catch(error => { - console.error('Error during service worker registration:', error) - }) -} - -function checkValidServiceWorker(swUrl) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - if ( - response.status === 404 || - response.headers.get('content-type').indexOf('javascript') === -1 - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload() - }) - }) - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl) - } - }) - .catch(() => { - console.log( - 'No internet connection found. App is running in offline mode.', - ) - }) -} - -export function unregister() { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready.then(registration => { - registration.unregister() - }) - } -} diff --git a/frontend/src/routes/index.js b/frontend/src/routes/index.js index 119cdb54..ea703567 100644 --- a/frontend/src/routes/index.js +++ b/frontend/src/routes/index.js @@ -8,55 +8,30 @@ import NotFound from '../pages/NotFound' import Profile from '../pages/Profile' import Simulations from '../pages/Simulations' -const ProtectedComponent = component => () => - userIsLoggedIn() ? component : +const ProtectedComponent = (component) => () => (userIsLoggedIn() ? component : ) const AppComponent = ({ match }) => - userIsLoggedIn() ? ( - - ) : ( - - ) + userIsLoggedIn() ? : const ExperimentsComponent = ({ match }) => - userIsLoggedIn() ? ( - - ) : ( - - ) + userIsLoggedIn() ? : const SimulationComponent = ({ match }) => userIsLoggedIn() ? ( - + ) : ( - + ) const Routes = () => ( - - )} - /> - - - - )}/> - + + )} /> + + + + )} /> + ) diff --git a/frontend/src/sagas/experiments.js b/frontend/src/sagas/experiments.js index a361759b..b9106fdc 100644 --- a/frontend/src/sagas/experiments.js +++ b/frontend/src/sagas/experiments.js @@ -7,15 +7,11 @@ import { 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' +import { addExperiment, getSimulation } from '../api/routes/simulations' +import { fetchAndStoreAllSchedulers, fetchAndStoreAllTraces } from './objects' +import { fetchAndStoreAllTopologiesOfSimulation, fetchTopologyOfExperiment } from './topology' export function* onOpenExperimentSucceeded(action) { try { @@ -26,9 +22,8 @@ export function* onOpenExperimentSucceeded(action) { yield put(addToStore('experiment', experiment)) yield fetchExperimentSpecifications() - yield fetchWorkloadOfTrace(experiment.traceId) - yield fetchAllDatacentersOfExperiment(experiment) + yield fetchTopologyOfExperiment(experiment) yield startStateFetchLoop(action.experimentId) } catch (error) { console.error(error) @@ -37,20 +32,15 @@ export function* onOpenExperimentSucceeded(action) { 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)) - ) { + while ((yield select((state) => state.currentExperimentId)) !== -1) { + const lastSimulatedTick = (yield call(getExperiment, 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)) @@ -67,23 +57,15 @@ function* startStateFetchLoop(experimentId) { export function* onFetchExperimentsOfSimulation() { try { - const currentSimulationId = yield select( - state => state.currentSimulationId, - ) + const currentSimulationId = yield select((state) => state.currentSimulationId) + const currentSimulation = yield select((state) => state.object.simulation[currentSimulationId]) yield fetchExperimentSpecifications() - const experiments = yield call( - getExperimentsOfSimulation, - currentSimulationId, - ) - for (let i in experiments) { - yield put(addToStore('experiment', experiments[i])) + + for (let i in currentSimulation.experimentIds) { + const experiment = yield call(getExperiment, currentSimulation.experimentIds[i]) + yield put(addToStore('experiment', experiment)) } - yield put( - addPropToStoreObject('simulation', currentSimulationId, { - experimentIds: experiments.map(experiment => experiment.id), - }), - ) } catch (error) { console.error(error) } @@ -91,10 +73,8 @@ export function* onFetchExperimentsOfSimulation() { function* fetchExperimentSpecifications() { try { - const currentSimulationId = yield select( - state => state.currentSimulationId, - ) - yield fetchAndStorePathsOfSimulation(currentSimulationId) + const currentSimulationId = yield select((state) => state.currentSimulationId) + yield fetchAndStoreAllTopologiesOfSimulation(currentSimulationId) yield fetchAndStoreAllTraces() yield fetchAndStoreAllSchedulers() } catch (error) { @@ -102,33 +82,9 @@ function* fetchExperimentSpecifications() { } } -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 currentSimulationId = yield select((state) => state.currentSimulationId) const experiment = yield call( addExperiment, @@ -136,17 +92,15 @@ export function* onAddExperiment(action) { Object.assign({}, action.experiment, { id: -1, simulationId: currentSimulationId, - }), + }) ) yield put(addToStore('experiment', experiment)) - const experimentIds = yield select( - state => state.objects.simulation[currentSimulationId].experimentIds, - ) + const experimentIds = yield select((state) => state.objects.simulation[currentSimulationId].experimentIds) yield put( addPropToStoreObject('simulation', currentSimulationId, { - experimentIds: experimentIds.concat([experiment.id]), - }), + experimentIds: experimentIds.concat([experiment._id]), + }) ) } catch (error) { console.error(error) @@ -157,17 +111,13 @@ 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, - ) + 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), - }), + 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 index d1de906f..0947befc 100644 --- a/frontend/src/sagas/index.js +++ b/frontend/src/sagas/index.js @@ -29,26 +29,26 @@ import { onAddMachine, onAddRackToTile, onAddTile, + onAddTopology, onAddUnit, onCancelNewRoomConstruction, onDeleteMachine, onDeleteRack, onDeleteRoom, onDeleteTile, + onDeleteTopology, onDeleteUnit, onEditRackName, onEditRoomName, onStartNewRoomConstruction, } from './topology' import { onFetchAuthorizationsOfCurrentUser, onFetchLoggedInUser } from './users' +import { ADD_TOPOLOGY, DELETE_TOPOLOGY } from '../actions/topologies' export default function* rootSaga() { yield takeEvery(LOG_IN, onFetchLoggedInUser) - yield takeEvery( - FETCH_AUTHORIZATIONS_OF_CURRENT_USER, - onFetchAuthorizationsOfCurrentUser, - ) + yield takeEvery(FETCH_AUTHORIZATIONS_OF_CURRENT_USER, onFetchAuthorizationsOfCurrentUser) yield takeEvery(ADD_SIMULATION, onSimulationAdd) yield takeEvery(DELETE_SIMULATION, onSimulationDelete) @@ -57,6 +57,8 @@ export default function* rootSaga() { yield takeEvery(OPEN_SIMULATION_SUCCEEDED, onOpenSimulationSucceeded) yield takeEvery(OPEN_EXPERIMENT_SUCCEEDED, onOpenExperimentSucceeded) + yield takeEvery(ADD_TOPOLOGY, onAddTopology) + yield takeEvery(DELETE_TOPOLOGY, onDeleteTopology) yield takeEvery(START_NEW_ROOM_CONSTRUCTION, onStartNewRoomConstruction) yield takeEvery(CANCEL_NEW_ROOM_CONSTRUCTION, onCancelNewRoomConstruction) yield takeEvery(ADD_TILE, onAddTile) @@ -71,10 +73,7 @@ export default function* rootSaga() { yield takeEvery(ADD_UNIT, onAddUnit) yield takeEvery(DELETE_UNIT, onDeleteUnit) - yield takeEvery( - FETCH_EXPERIMENTS_OF_SIMULATION, - onFetchExperimentsOfSimulation, - ) + 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 index faa75be2..174f9c3e 100644 --- a/frontend/src/sagas/objects.js +++ b/frontend/src/sagas/objects.js @@ -1,46 +1,25 @@ 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 { getSimulation } from '../api/routes/simulations' import { getAllTraces } from '../api/routes/traces' import { getUser } from '../api/routes/users' +import { getTopology, updateTopology } from '../api/routes/topologies' +import { uuid } from 'uuidv4' 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, + simulation: (state) => state.objects.simulation, + user: (state) => state.objects.user, + authorization: (state) => state.objects.authorization, + 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, + tile: (state) => state.objects.tile, + room: (state) => state.objects.room, + topology: (state) => state.objects.topology, } function* fetchAndStoreObject(objectType, id, apiCall) { @@ -61,79 +40,151 @@ function* fetchAndStoreObjects(objectType, apiCall) { 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 fetchAndStoreSimulation = (id) => fetchAndStoreObject('simulation', id, call(getSimulation, id)) + +export const fetchAndStoreUser = (id) => fetchAndStoreObject('user', id, call(getUser, id)) + +export const fetchAndStoreTopology = function* (id) { + const topologyStore = yield select(OBJECT_SELECTORS['topology']) + const roomStore = yield select(OBJECT_SELECTORS['room']) + const tileStore = yield select(OBJECT_SELECTORS['tile']) + const rackStore = yield select(OBJECT_SELECTORS['rack']) + const machineStore = yield select(OBJECT_SELECTORS['machine']) + + let topology = topologyStore[id] + if (!topology) { + const fullTopology = yield call(getTopology, id) + + for (let roomIdx in fullTopology.rooms) { + const fullRoom = fullTopology.rooms[roomIdx] + + generateIdIfNotPresent(fullRoom) + + if (!roomStore[fullRoom._id]) { + for (let tileIdx in fullRoom.tiles) { + const fullTile = fullRoom.tiles[tileIdx] + + generateIdIfNotPresent(fullTile) + + if (!tileStore[fullTile._id]) { + if (fullTile.rack) { + const fullRack = fullTile.rack + + generateIdIfNotPresent(fullTile) + + if (!rackStore[fullRack._id]) { + for (let machineIdx in fullRack.machines) { + const fullMachine = fullRoom.machines[machineIdx] + + generateIdIfNotPresent(fullMachine) + + if (!machineStore[fullMachine._id]) { + let machine = (({ _id, position, cpuIds, gpuIds, memoryIds, storageIds }) => ({ + _id, + rackId: fullRack._id, + position, + cpuIds, + gpuIds, + memoryIds, + storageIds, + }))(fullMachine) + yield put(addToStore('machine', machine)) + } + } + + const filledSlots = new Array(fullRack.capacity).fill(null) + fullRack.machines.forEach( + (machine) => (filledSlots[machine.position - 1] = machine._id) + ) + let rack = (({ _id, capacity, powerCapacityW }) => ({ + _id, + capacity, + powerCapacityW, + machineIds: filledSlots, + }))(fullRack) + yield put(addToStore('rack', rack)) + } + } + + let tile = (({ _id, positionX, positionY, rack }) => ({ + _id, + roomId: fullRoom._id, + positionX, + positionY, + rackId: rack ? rack._id : undefined, + }))(fullTile) + yield put(addToStore('tile', tile)) + } + } + + let room = (({ _id, name, tiles }) => ({ _id, name, tileIds: tiles.map((t) => t._id) }))(fullRoom) + yield put(addToStore('room', room)) + } + } + + topology = (({ _id, name, rooms }) => ({ _id, name, roomIds: rooms.map((r) => r._id) }))(fullTopology) + yield put(addToStore('topology', topology)) + + console.log('Full topology after insertion', fullTopology) + // TODO consider pushing the IDs + } -export const fetchAndStoreSection = id => - fetchAndStoreObject('section', id, call(getSection, id)) + return topology +} -export const fetchAndStoreSectionsOfPath = pathId => - fetchAndStoreObjects('section', call(getSectionsOfPath, pathId)) +const generateIdIfNotPresent = (obj) => { + if (!obj._id) { + obj._id = uuid() + } +} -export const fetchAndStorePath = id => - fetchAndStoreObject('path', id, call(getPath, id)) +export const updateTopologyOnServer = function* (id) { + const topologyStore = yield select(OBJECT_SELECTORS['topology']) + const roomStore = yield select(OBJECT_SELECTORS['room']) + const tileStore = yield select(OBJECT_SELECTORS['tile']) + const rackStore = yield select(OBJECT_SELECTORS['rack']) + const machineStore = yield select(OBJECT_SELECTORS['machine']) + + const topology = { + _id: id, + name: topologyStore[id].name, + rooms: topologyStore[id].roomIds.map((roomId) => ({ + _id: roomId, + name: roomStore[roomId].name, + tiles: roomStore[roomId].tileIds.map((tileId) => ({ + _id: tileId, + positionX: tileStore[tileId].positionX, + positionY: tileStore[tileId].positionY, + rack: !tileStore[tileId].rackId + ? undefined + : { + _id: rackStore[tileStore[tileId].rackId]._id, + capacity: rackStore[tileStore[tileId].rackId].capacity, + powerCapacityW: rackStore[tileStore[tileId].rackId].powerCapacityW, + machines: rackStore[tileStore[tileId].rackId].machineIds + .filter((m) => m !== null) + .map((machineId) => ({ + _id: machineId, + position: machineStore[machineId].position, + cpuIds: machineStore[machineId].cpuIds, + gpuIds: machineStore[machineId].gpuIds, + memoryIds: machineStore[machineId].memoryIds, + storageIds: machineStore[machineId].storageIds, + })), + }, + })), + })), + } -export const fetchAndStorePathsOfSimulation = simulationId => - fetchAndStoreObjects('path', call(getPathsOfSimulation, simulationId)) + yield call(updateTopology, topology) +} -export const fetchAndStoreAllTraces = () => - fetchAndStoreObjects('trace', call(getAllTraces)) +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 + objects[index]._id = objects[index].name yield put(addToStore('scheduler', objects[index])) } return objects diff --git a/frontend/src/sagas/simulations.js b/frontend/src/sagas/simulations.js index b57fac95..be69fedd 100644 --- a/frontend/src/sagas/simulations.js +++ b/frontend/src/sagas/simulations.js @@ -2,14 +2,14 @@ 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' +import { fetchAndStoreAllTopologiesOfSimulation } from './topology' export function* onOpenSimulationSucceeded(action) { try { const simulation = yield call(getSimulation, action.id) yield put(addToStore('simulation', simulation)) - yield fetchLatestDatacenter(action.id) + yield fetchAndStoreAllTopologiesOfSimulation(action.id) } catch (error) { console.error(error) } @@ -27,9 +27,7 @@ export function* onSimulationAdd(action) { simulation, } yield put(addToStore('authorization', authorization)) - yield put( - addSimulationSucceeded([authorization.userId, authorization.simulationId]), - ) + yield put(addSimulationSucceeded([authorization.userId, authorization.simulationId])) } catch (error) { console.error(error) } diff --git a/frontend/src/sagas/topology.js b/frontend/src/sagas/topology.js index b38358a4..0be619a9 100644 --- a/frontend/src/sagas/topology.js +++ b/frontend/src/sagas/topology.js @@ -8,181 +8,95 @@ import { } from '../actions/objects' import { cancelNewRoomConstructionSucceeded, - setCurrentDatacenter, + setCurrentTopology, 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' +import { fetchAndStoreTopology, updateTopologyOnServer } from './objects' +import { uuid } from 'uuidv4' +import { addTopology, deleteTopology } from '../api/routes/topologies' -export function* fetchLatestDatacenter(simulationId) { +export function* fetchTopologyOfExperiment(experiment) { 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)) + yield fetchAndStoreTopology(experiment.topologyId) + yield put(setCurrentTopology(experiment.topologyId)) } catch (error) { console.error(error) } } -export function* fetchAllDatacentersOfExperiment(experiment) { +export function* fetchAndStoreAllTopologiesOfSimulation(simulationId) { try { - const path = yield fetchAndStorePath(experiment.pathId) - const sections = yield fetchAndStoreSectionsOfPath(path.id) - path.sectionIds = sections.map(section => section.id) - yield fetchAllUnitSpecifications() + const simulation = yield select((state) => state.objects.simulation[simulationId]) - for (let i in sections) { - yield fetchDatacenter(sections[i].datacenterId) + for (let i in simulation.topologyIds) { + yield fetchAndStoreTopology(simulation.topologyIds[i]) } - yield put(setCurrentDatacenter(sections[0].datacenterId)) + + yield put(setCurrentTopology(simulation.topologyIds[0])) } catch (error) { console.error(error) } } -function* fetchDatacenter(datacenterId) { +export function* onAddTopology(action) { try { - yield fetchAndStoreDatacenter(datacenterId) - const rooms = yield fetchAndStoreRoomsOfDatacenter(datacenterId) - yield put( - addPropToStoreObject('datacenter', datacenterId, { - roomIds: rooms.map(room => room.id), - }), + const currentSimulationId = yield select((state) => state.currentSimulationId) + + const topology = yield call( + addTopology, + Object.assign({}, action.topology, { + _id: -1, + simulationId: currentSimulationId, + }) ) + yield put(addToStore('topology', topology)) - for (let index in rooms) { - yield fetchRoom(rooms[index].id) - } + const topologyIds = yield select((state) => state.objects.simulation[currentSimulationId].topologyIds) + yield put( + addPropToStoreObject('simulation', currentSimulationId, { + topologyIds: topologyIds.concat([topology._id]), + }) + ) } catch (error) { console.error(error) } } -function* fetchAllUnitSpecifications() { +export function* onDeleteTopology(action) { 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 call(deleteTopology, action.id) - yield put(addPropToStoreObject('rack', rack.id, { machineIds })) + const currentSimulationId = yield select((state) => state.currentSimulationId) + const topologyIds = yield select((state) => state.objects.simulation[currentSimulationId].topologyIds) - 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]) - } + yield put( + addPropToStoreObject('simulation', currentSimulationId, { + topologyIds: topologyIds.filter((id) => id !== action.id), + }) + ) + } catch (error) { + console.error(error) } } 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)) + const topologyId = yield select((state) => state.currentTopologyId) + const room = { + _id: uuid(), + name: 'Room', + topologyId, + tileIds: [], + } + yield put(addToStore('room', room)) + yield put(addIdToStoreObjectListProp('topology', topologyId, 'roomIds', room._id)) + yield updateTopologyOnServer(topologyId) + yield put(startNewRoomConstructionSucceeded(room._id)) } catch (error) { console.error(error) } @@ -190,19 +104,11 @@ export function* onStartNewRoomConstruction() { 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, - ), - ) + const topologyId = yield select((state) => state.currentTopologyId) + const roomId = yield select((state) => state.construction.currentRoomInConstruction) + yield put(removeIdFromStoreObjectListProp('topology', topologyId, 'roomIds', roomId)) + // TODO remove room from store, too + yield updateTopologyOnServer(topologyId) yield put(cancelNewRoomConstructionSucceeded()) } catch (error) { console.error(error) @@ -211,16 +117,17 @@ export function* onCancelNewRoomConstruction() { export function* onAddTile(action) { try { - const roomId = yield select( - state => state.construction.currentRoomInConstruction, - ) - const tile = yield call(addTileToRoom, { + const topologyId = yield select((state) => state.currentTopologyId) + const roomId = yield select((state) => state.construction.currentRoomInConstruction) + const tile = { + _id: uuid(), roomId, positionX: action.positionX, positionY: action.positionY, - }) + } yield put(addToStore('tile', tile)) - yield put(addIdToStoreObjectListProp('room', roomId, 'tileIds', tile.id)) + yield put(addIdToStoreObjectListProp('room', roomId, 'tileIds', tile._id)) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -228,13 +135,10 @@ export function* onAddTile(action) { 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), - ) + const topologyId = yield select((state) => state.currentTopologyId) + const roomId = yield select((state) => state.construction.currentRoomInConstruction) + yield put(removeIdFromStoreObjectListProp('room', roomId, 'tileIds', action.tileId)) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -242,14 +146,12 @@ export function* onDeleteTile(action) { export function* onEditRoomName(action) { try { - const roomId = yield select(state => state.interactionLevel.roomId) - const room = Object.assign( - {}, - yield select(state => state.objects.room[roomId]), - ) + const topologyId = yield select((state) => state.currentTopologyId) + 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 })) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -257,18 +159,11 @@ export function* onEditRoomName(action) { export function* onDeleteRoom() { try { - const datacenterId = yield select(state => state.currentDatacenterId) - const roomId = yield select(state => state.interactionLevel.roomId) - yield call(deleteRoom, roomId) + const topologyId = yield select((state) => state.currentTopologyId) + const roomId = yield select((state) => state.interactionLevel.roomId) yield put(goDownOneInteractionLevel()) - yield put( - removeIdFromStoreObjectListProp( - 'datacenter', - datacenterId, - 'roomIds', - roomId, - ), - ) + yield put(removeIdFromStoreObjectListProp('topology', topologyId, 'roomIds', roomId)) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -276,17 +171,12 @@ export function* onDeleteRoom() { 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]), - ) + const topologyId = yield select((state) => state.currentTopologyId) + const rackId = yield select((state) => state.objects.tile[state.interactionLevel.tileId].rackId) + 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 })) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -294,11 +184,11 @@ export function* onEditRackName(action) { export function* onDeleteRack() { try { - const tileId = yield select(state => state.interactionLevel.tileId) - yield call(deleteRackFromTile, tileId) + const topologyId = yield select((state) => state.currentTopologyId) + const tileId = yield select((state) => state.interactionLevel.tileId) yield put(goDownOneInteractionLevel()) - yield put(addPropToStoreObject('tile', tileId, { objectType: undefined })) - yield put(addPropToStoreObject('tile', tileId, { objectId: undefined })) + yield put(addPropToStoreObject('tile', tileId, { rackId: undefined })) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -306,20 +196,16 @@ export function* onDeleteRack() { export function* onAddRackToTile(action) { try { - const rack = yield call(addRackToTile, action.tileId, { - id: -1, - name: 'Rack', + const topologyId = yield select((state) => state.currentTopologyId) + const rack = { + _id: uuid(), 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' }), - ) + yield put(addPropToStoreObject('tile', action.tileId, { rackId: rack._id })) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -327,27 +213,24 @@ export function* onAddRackToTile(action) { 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 topologyId = yield select((state) => state.currentTopologyId) + const rackId = yield select((state) => state.objects.tile[state.interactionLevel.tileId].rackId) + const rack = yield select((state) => state.objects.rack[rackId]) - const machine = yield call(addMachineToRackOnTile, tileId, { - id: -1, - rackId, + const machine = { + _id: -1, position: action.position, - tags: [], cpuIds: [], gpuIds: [], memoryIds: [], storageIds: [], - }) + } yield put(addToStore('machine', machine)) const machineIds = [...rack.machineIds] - machineIds[machine.position - 1] = machine.id + machineIds[machine.position - 1] = machine._id yield put(addPropToStoreObject('rack', rackId, { machineIds })) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -355,16 +238,15 @@ export function* onAddMachine(action) { 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 topologyId = yield select((state) => state.currentTopologyId) + 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].rackId]) const machineIds = [...rack.machineIds] machineIds[position - 1] = null yield put(goDownOneInteractionLevel()) - yield put(addPropToStoreObject('rack', rack.id, { machineIds })) + yield put(addPropToStoreObject('rack', rack._id, { machineIds })) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -372,15 +254,12 @@ export function* onDeleteMachine() { export function* onAddUnit(action) { try { - const tileId = yield select(state => state.interactionLevel.tileId) - const position = yield select(state => state.interactionLevel.position) + const topologyId = yield select((state) => state.currentTopologyId) + 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 - ] - ], + (state) => + state.objects.machine[state.objects.rack[state.objects.tile[tileId].rackId].machineIds[position - 1]] ) if (machine[action.unitType + 'Ids'].length >= MAX_NUM_UNITS_PER_MACHINE) { @@ -388,17 +267,12 @@ export function* onAddUnit(action) { } 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, { + addPropToStoreObject('machine', machine._id, { [action.unitType + 'Ids']: units, - }), + }) ) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } @@ -406,28 +280,22 @@ export function* onAddUnit(action) { export function* onDeleteUnit(action) { try { - const tileId = yield select(state => state.interactionLevel.tileId) - const position = yield select(state => state.interactionLevel.position) + const topologyId = yield select((state) => state.currentTopologyId) + 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 - ] - ], + (state) => + state.objects.machine[state.objects.rack[state.objects.tile[tileId].rackId].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, { + addPropToStoreObject('machine', machine._id, { [action.unitType + 'Ids']: unitIds, - }), + }) ) + yield updateTopologyOnServer(topologyId) } catch (error) { console.error(error) } diff --git a/frontend/src/sagas/users.js b/frontend/src/sagas/users.js index a10887a0..a95893d2 100644 --- a/frontend/src/sagas/users.js +++ b/frontend/src/sagas/users.js @@ -9,10 +9,7 @@ import { fetchAndStoreSimulation, fetchAndStoreUser } from './objects' export function* onFetchLoggedInUser(action) { try { - const tokenResponse = yield call( - performTokenSignIn, - action.payload.authToken, - ) + const tokenResponse = yield call(performTokenSignIn, action.payload.authToken) let userId = tokenResponse.userId @@ -38,10 +35,7 @@ export function* onFetchAuthorizationsOfCurrentUser(action) { yield fetchAndStoreSimulation(authorization.simulationId) } - const authorizationIds = user.authorizations.map(authorization => [ - action.userId, - authorization.simulationId, - ]) + const authorizationIds = user.authorizations.map((authorization) => [action.userId, authorization.simulationId]) yield put(fetchAuthorizationsOfCurrentUserSucceeded(authorizationIds)) } catch (error) { diff --git a/frontend/src/shapes/index.js b/frontend/src/shapes/index.js index 4c63fdfe..d43496d9 100644 --- a/frontend/src/shapes/index.js +++ b/frontend/src/shapes/index.js @@ -8,6 +8,7 @@ Shapes.User = PropTypes.shape({ email: PropTypes.string.isRequired, givenName: PropTypes.string.isRequired, familyName: PropTypes.string.isRequired, + authorizations: PropTypes.array.isRequired, }) Shapes.Simulation = PropTypes.shape({ @@ -15,6 +16,8 @@ Shapes.Simulation = PropTypes.shape({ name: PropTypes.string.isRequired, datetimeCreated: PropTypes.string.isRequired, datetimeLastEdited: PropTypes.string.isRequired, + topologyIds: PropTypes.array.isRequired, + experimentIds: PropTypes.array.isRequired, }) Shapes.Authorization = PropTypes.shape({ @@ -25,148 +28,81 @@ Shapes.Authorization = PropTypes.shape({ authorizationLevel: PropTypes.string.isRequired, }) -Shapes.FailureModel = PropTypes.shape({ - id: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, - rate: PropTypes.number.isRequired, -}) - Shapes.ProcessingUnit = PropTypes.shape({ - id: PropTypes.number.isRequired, - manufacturer: PropTypes.string.isRequired, - family: PropTypes.string.isRequired, - generation: PropTypes.string.isRequired, - model: PropTypes.string.isRequired, + _id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, clockRateMhz: PropTypes.number.isRequired, numberOfCores: PropTypes.number.isRequired, energyConsumptionW: PropTypes.number.isRequired, - failureModelId: PropTypes.number.isRequired, - failureModel: Shapes.FailureModel, }) Shapes.StorageUnit = PropTypes.shape({ - id: PropTypes.number.isRequired, - manufacturer: PropTypes.string.isRequired, - family: PropTypes.string.isRequired, - generation: PropTypes.string.isRequired, - model: PropTypes.string.isRequired, + _id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, speedMbPerS: PropTypes.number.isRequired, sizeMb: PropTypes.number.isRequired, energyConsumptionW: PropTypes.number.isRequired, - failureModelId: PropTypes.number.isRequired, - failureModel: Shapes.FailureModel, }) Shapes.Machine = PropTypes.shape({ - id: PropTypes.number.isRequired, - rackId: PropTypes.number.isRequired, + _id: PropTypes.string.isRequired, + rackId: PropTypes.string.isRequired, position: PropTypes.number.isRequired, - cpuIds: PropTypes.arrayOf(PropTypes.number.isRequired), + cpuIds: PropTypes.arrayOf(PropTypes.string.isRequired), cpus: PropTypes.arrayOf(Shapes.ProcessingUnit), - gpuIds: PropTypes.arrayOf(PropTypes.number.isRequired), + gpuIds: PropTypes.arrayOf(PropTypes.string.isRequired), gpus: PropTypes.arrayOf(Shapes.ProcessingUnit), - memoryIds: PropTypes.arrayOf(PropTypes.number.isRequired), + memoryIds: PropTypes.arrayOf(PropTypes.string.isRequired), memories: PropTypes.arrayOf(Shapes.StorageUnit), - storageIds: PropTypes.arrayOf(PropTypes.number.isRequired), + storageIds: PropTypes.arrayOf(PropTypes.string.isRequired), storages: PropTypes.arrayOf(Shapes.StorageUnit), }) Shapes.Rack = PropTypes.shape({ - id: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, + _id: PropTypes.string.isRequired, capacity: PropTypes.number.isRequired, powerCapacityW: PropTypes.number.isRequired, machines: PropTypes.arrayOf(Shapes.Machine), }) -Shapes.CoolingItem = PropTypes.shape({ - id: PropTypes.number.isRequired, - energyConsumptionW: PropTypes.number.isRequired, - type: PropTypes.string.isRequired, - failureModelId: PropTypes.number.isRequired, - failureModel: Shapes.FailureModel, -}) - -Shapes.PSU = PropTypes.shape({ - id: PropTypes.number.isRequired, - energyKwh: PropTypes.number.isRequired, - type: PropTypes.string.isRequired, - failureModelId: PropTypes.number.isRequired, - failureModel: Shapes.FailureModel, -}) - Shapes.Tile = PropTypes.shape({ - id: PropTypes.number.isRequired, - roomId: PropTypes.number.isRequired, + _id: PropTypes.string.isRequired, + roomId: PropTypes.string.isRequired, positionX: PropTypes.number.isRequired, positionY: PropTypes.number.isRequired, - objectId: PropTypes.number, - objectType: PropTypes.string, + rackId: PropTypes.string, rack: Shapes.Rack, - coolingItem: Shapes.CoolingItem, - psu: Shapes.PSU, }) Shapes.Room = PropTypes.shape({ - id: PropTypes.number.isRequired, - datacenterId: PropTypes.number.isRequired, + _id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, - roomType: PropTypes.string.isRequired, tiles: PropTypes.arrayOf(Shapes.Tile), }) -Shapes.Datacenter = PropTypes.shape({ - id: PropTypes.number.isRequired, +Shapes.Topology = PropTypes.shape({ + _id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, rooms: PropTypes.arrayOf(Shapes.Room), }) -Shapes.Section = PropTypes.shape({ - id: PropTypes.number.isRequired, - pathId: PropTypes.number.isRequired, - startTick: PropTypes.number.isRequired, - datacenterId: PropTypes.number.isRequired, - datacenter: Shapes.Datacenter, -}) - -Shapes.Path = PropTypes.shape({ - id: PropTypes.number.isRequired, - simulationId: PropTypes.number.isRequired, - name: PropTypes.string, - datetimeCreated: PropTypes.string.isRequired, - sections: PropTypes.arrayOf(Shapes.Section), -}) - Shapes.Scheduler = PropTypes.shape({ name: PropTypes.string.isRequired, }) -Shapes.Task = PropTypes.shape({ - id: PropTypes.number.isRequired, - jobId: PropTypes.number.isRequired, - startTick: PropTypes.number.isRequired, - totalFlopCount: PropTypes.number.isRequired, -}) - -Shapes.Job = PropTypes.shape({ - id: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, - traceId: PropTypes.number.isRequired, - taskIds: PropTypes.arrayOf(PropTypes.number), -}) - Shapes.Trace = PropTypes.shape({ - id: PropTypes.number.isRequired, + _id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, - jobIds: PropTypes.arrayOf(PropTypes.number), + type: PropTypes.string.isRequired, }) Shapes.Experiment = PropTypes.shape({ - id: PropTypes.number.isRequired, - simulationId: PropTypes.number.isRequired, - traceId: PropTypes.number.isRequired, + _id: PropTypes.string.isRequired, + simulationId: PropTypes.string.isRequired, + topologyId: PropTypes.string.isRequired, + topology: Shapes.Topology, + traceId: PropTypes.string.isRequired, trace: Shapes.Trace, - pathId: PropTypes.number.isRequired, - path: Shapes.Path, schedulerName: PropTypes.string.isRequired, scheduler: Shapes.Scheduler, name: PropTypes.string.isRequired, @@ -181,8 +117,8 @@ Shapes.WallSegment = PropTypes.shape({ Shapes.InteractionLevel = PropTypes.shape({ mode: PropTypes.string.isRequired, - roomId: PropTypes.number, - rackId: PropTypes.bool, + roomId: PropTypes.string, + rackId: PropTypes.string, }) export default Shapes diff --git a/frontend/src/store/configure-store.js b/frontend/src/store/configure-store.js index f01b61bb..d8f343ed 100644 --- a/frontend/src/store/configure-store.js +++ b/frontend/src/store/configure-store.js @@ -27,10 +27,7 @@ const middlewares = [ export let store = undefined export default function configureStore() { - const configuredStore = createStore( - rootReducer, - compose(persistState('auth'), applyMiddleware(...middlewares)), - ) + const configuredStore = createStore(rootReducer, compose(persistState('auth'), applyMiddleware(...middlewares))) sagaMiddleware.run(rootSaga) store = configuredStore diff --git a/frontend/src/store/middlewares/viewport-adjustment.js b/frontend/src/store/middlewares/viewport-adjustment.js index 0a074f61..ae8f032a 100644 --- a/frontend/src/store/middlewares/viewport-adjustment.js +++ b/frontend/src/store/middlewares/viewport-adjustment.js @@ -1,5 +1,5 @@ import { SET_MAP_DIMENSIONS, setMapPosition, setMapScale } from '../../actions/map' -import { SET_CURRENT_DATACENTER } from '../../actions/topology/building' +import { SET_CURRENT_TOPOLOGY } from '../../actions/topology/building' import { MAP_MAX_SCALE, MAP_MIN_SCALE, @@ -12,21 +12,21 @@ import { calculateRoomListBounds } from '../../util/tile-calculations' export const viewportAdjustmentMiddleware = store => next => action => { const state = store.getState() - let datacenterId = -1 + let topologyId = -1 let mapDimensions = {} - if (action.type === SET_CURRENT_DATACENTER && action.datacenterId !== -1) { - datacenterId = action.datacenterId + if (action.type === SET_CURRENT_TOPOLOGY && action.topologyId !== -1) { + topologyId = action.topologyId mapDimensions = state.map.dimensions } else if ( action.type === SET_MAP_DIMENSIONS && - state.currentDatacenterId !== -1 + state.currentTopologyId !== -1 ) { - datacenterId = state.currentDatacenterId + topologyId = state.currentTopologyId mapDimensions = { width: action.width, height: action.height } } - if (datacenterId !== -1) { - const roomIds = state.objects.datacenter[datacenterId].roomIds + if (topologyId !== -1) { + const roomIds = state.objects.topology[topologyId].roomIds const rooms = roomIds.map(id => Object.assign({}, state.objects.room[id])) rooms.forEach( room => diff --git a/frontend/src/util/date-time.js b/frontend/src/util/date-time.js index d176ebef..66efdf5b 100644 --- a/frontend/src/util/date-time.js +++ b/frontend/src/util/date-time.js @@ -39,10 +39,7 @@ export function formatDateTime(dateTime) { '/' + addPaddingToTwo(dateTime.getFullYear()) - if ( - dateTime.getFullYear() === currentDate.getFullYear() && - dateTime.getMonth() === currentDate.getMonth() - ) { + if (dateTime.getFullYear() === currentDate.getFullYear() && dateTime.getMonth() === currentDate.getMonth()) { if (dateTime.getDate() === currentDate.getDate()) { date = 'Today' } else if (dateTime.getDate() === currentDate.getDate() - 1) { @@ -50,13 +47,7 @@ export function formatDateTime(dateTime) { } } - return ( - date + - ', ' + - addPaddingToTwo(dateTime.getHours()) + - ':' + - addPaddingToTwo(dateTime.getMinutes()) - ) + return date + ', ' + addPaddingToTwo(dateTime.getHours()) + ':' + addPaddingToTwo(dateTime.getMinutes()) } /** @@ -83,9 +74,7 @@ export function convertSecondsToFormattedTime(seconds) { } else if (hour === 0) { return minute + 'm' + addPaddingToTwo(second) + 's' } else { - return ( - hour + 'h' + addPaddingToTwo(minute) + 'm' + addPaddingToTwo(second) + 's' - ) + return hour + 'h' + addPaddingToTwo(minute) + 'm' + addPaddingToTwo(second) + 's' } } diff --git a/frontend/src/util/date-time.test.js b/frontend/src/util/date-time.test.js index 9274d4b7..3d95eba6 100644 --- a/frontend/src/util/date-time.test.js +++ b/frontend/src/util/date-time.test.js @@ -15,7 +15,7 @@ describe('date-time parsing', () => { }) describe('tick formatting', () => { - it('returns \'0s\' for numbers <= 0', () => { + it("returns '0s' for numbers <= 0", () => { expect(convertSecondsToFormattedTime(-1)).toEqual('0s') expect(convertSecondsToFormattedTime(0)).toEqual('0s') }) diff --git a/frontend/src/util/room-types.js b/frontend/src/util/room-types.js deleted file mode 100644 index ff69d013..00000000 --- a/frontend/src/util/room-types.js +++ /dev/null @@ -1,7 +0,0 @@ -export const ROOM_TYPE_TO_NAME_MAP = { - SERVER: 'Server room', - HALLWAY: 'Hallway', - OFFICE: 'Office', - POWER: 'Power room', - COOLING: 'Cooling room', -} diff --git a/frontend/src/util/tile-calculations.js b/frontend/src/util/tile-calculations.js index 3ef1cff6..764ae6ac 100644 --- a/frontend/src/util/tile-calculations.js +++ b/frontend/src/util/tile-calculations.js @@ -7,7 +7,7 @@ function getWallSegments(tiles) { const verticalWalls = {} const horizontalWalls = {} - tiles.forEach(tile => { + tiles.forEach((tile) => { const x = tile.positionX, y = tile.positionY @@ -19,10 +19,7 @@ function getWallSegments(tiles) { let doInsert = true for (let tileIndex in tiles) { - if ( - tiles[tileIndex].positionX === x + dX && - tiles[tileIndex].positionY === y + dY - ) { + if (tiles[tileIndex].positionX === x + dX && tiles[tileIndex].positionY === y + dY) { doInsert = false break } @@ -143,7 +140,7 @@ export function deriveValidNextTilePositions(rooms, selectedTiles) { newPosition = { x: 0, y: 0 } let isSurroundingTile - selectedTiles.forEach(tile => { + selectedTiles.forEach((tile) => { const x = tile.positionX const y = tile.positionY result.push({ x, y }) @@ -168,10 +165,7 @@ export function deriveValidNextTilePositions(rooms, selectedTiles) { } } - if ( - isSurroundingTile && - findPositionInRooms(rooms, newPosition.x, newPosition.y) === -1 - ) { + if (isSurroundingTile && findPositionInRooms(rooms, newPosition.x, newPosition.y) === -1) { result.push({ x: newPosition.x, y: newPosition.y }) } } @@ -231,8 +225,8 @@ export function calculateRoomListBounds(rooms) { const min = { x: Number.MAX_VALUE, y: Number.MAX_VALUE } const max = { x: -1, y: -1 } - rooms.forEach(room => { - room.tiles.forEach(tile => { + rooms.forEach((room) => { + room.tiles.forEach((tile) => { if (tile.positionX < min.x) { min.x = tile.positionX } diff --git a/frontend/src/util/timeline.js b/frontend/src/util/timeline.js index 21258e23..7c8a3ef0 100644 --- a/frontend/src/util/timeline.js +++ b/frontend/src/util/timeline.js @@ -2,18 +2,8 @@ export function convertTickToPercentage(tick, maxTick) { if (maxTick === 0) { return '0%' } else if (tick > maxTick) { - return maxTick / (maxTick + 1) * 100 + '%' + return (maxTick / (maxTick + 1)) * 100 + '%' } - return tick / (maxTick + 1) * 100 + '%' -} - -export function getDatacenterIdOfTick(tick, sections) { - for (let i in sections.reverse()) { - if (tick >= sections[i].startTick) { - return sections[i].datacenterId - } - } - - return -1 + return (tick / (maxTick + 1)) * 100 + '%' } diff --git a/frontend/src/util/unit-specifications.js b/frontend/src/util/unit-specifications.js new file mode 100644 index 00000000..43c45b7e --- /dev/null +++ b/frontend/src/util/unit-specifications.js @@ -0,0 +1,46 @@ +export const CPU_UNITS = { + 'cpu-1': { + _id: 'cpu-1', + name: 'Intel i7 v6 6700k', + clockRateMhz: 4100, + numberOfCores: 4, + energyConsumptionW: 70, + }, + 'cpu-2': { + _id: 'cpu-2', + name: 'Intel i5 v6 6700k', + clockRateMhz: 3500, + numberOfCores: 2, + energyConsumptionW: 50, + }, +} + +export const GPU_UNITS = { + 'gpu-1': { + _id: 'gpu-1', + name: 'NVIDIA GTX 4 1080', + clockRateMhz: 1200, + numberOfCores: 200, + energyConsumptionW: 250, + }, +} + +export const MEMORY_UNITS = { + 'memory-1': { + _id: 'memory-1', + name: 'Samsung PC DRAM K4A4G045WD', + speedMbPerS: 16000, + sizeMb: 4000, + energyConsumptionW: 10, + }, +} + +export const STORAGE_UNITS = { + 'storage-1': { + _id: 'storage-1', + name: 'Samsung EVO 2016 SATA III', + speedMbPerS: 6000, + sizeMb: 250000, + energyConsumptionW: 10, + }, +} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 2956bd46..00c6e441 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1581,6 +1581,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/uuid@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0" + integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw== + "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" @@ -11512,11 +11517,24 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.2.0.tgz#cb10dd6b118e2dada7d0cd9730ba7417c93d920e" + integrity sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q== + uuid@^3.0.1, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuidv4@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.1.1.tgz#6565b4f2be7d6f841c14106f420fdb701eae5c81" + integrity sha512-ZplGb1SHFMVH3l7PUQl2Uwo+FpJQV6IPOoU+MjjbqrNYQolqbGwv+/sn9F+AGMsMOgGz3r9JN3ztGUi0VzMxmw== + dependencies: + "@types/uuid" "8.0.0" + uuid "8.2.0" + v8-compile-cache@^2.0.3: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" -- cgit v1.2.3