summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-08-25 17:48:12 +0200
committerGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-23 10:05:44 +0200
commitc47a27b826f7d76410308a4151611a366f9eaf46 (patch)
treec1ca374204714cedabcacb8620848b903a0bf8d6
parent1ddbbd3563af77a218020021ea50a8832900b4db (diff)
Fetch and display datacenter topology
-rw-r--r--package.json1
-rw-r--r--src/actions/objects.js10
-rw-r--r--src/actions/topology.js21
-rw-r--r--src/api/routes/rooms.js1
-rw-r--r--src/api/sagas/objects.js24
-rw-r--r--src/components/map/MapStage.js8
-rw-r--r--src/components/map/elements/RoomTile.js1
-rw-r--r--src/components/map/elements/TileObject.js2
-rw-r--r--src/components/map/groups/DatacenterGroup.js20
-rw-r--r--src/components/map/groups/GridGroup.js3
-rw-r--r--src/components/map/groups/RoomGroup.js3
-rw-r--r--src/containers/map/DatacenterContainer.js22
-rw-r--r--src/pages/App.js6
-rw-r--r--src/pages/Simulations.js4
-rw-r--r--src/reducers/index.js5
-rw-r--r--src/reducers/objects.js24
-rw-r--r--src/reducers/topology.js10
-rw-r--r--src/sagas/index.js (renamed from src/api/sagas/index.js)9
-rw-r--r--src/sagas/objects.js109
-rw-r--r--src/sagas/profile.js (renamed from src/api/sagas/profile.js)4
-rw-r--r--src/sagas/simulations.js (renamed from src/api/sagas/simulations.js)6
-rw-r--r--src/sagas/topology.js71
-rw-r--r--src/sagas/users.js (renamed from src/api/sagas/users.js)14
-rw-r--r--src/shapes/index.js3
-rw-r--r--src/store/configureStore.js2
-rw-r--r--src/store/denormalizer.js20
26 files changed, 328 insertions, 75 deletions
diff --git a/package.json b/package.json
index 10f9fa7c..25d27b02 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,6 @@
"isomorphic-fetch": "^2.2.1",
"konva": "^1.6.7",
"node-sass-chokidar": "^0.0.3",
- "normalizr": "^3.2.3",
"npm-run-all": "^4.0.2",
"prop-types": "^15.5.10",
"react": "^15.6.1",
diff --git a/src/actions/objects.js b/src/actions/objects.js
index 0a0e3046..6fdb83cd 100644
--- a/src/actions/objects.js
+++ b/src/actions/objects.js
@@ -1,4 +1,5 @@
export const ADD_TO_STORE = "ADD_TO_STORE";
+export const ADD_PROP_TO_STORE_OBJECT = "ADD_PROP_TO_STORE_OBJECT";
export function addToStore(objectType, object) {
return {
@@ -7,3 +8,12 @@ export function addToStore(objectType, object) {
object
};
}
+
+export function addPropToStoreObject(objectType, objectId, propObject) {
+ return {
+ type: ADD_PROP_TO_STORE_OBJECT,
+ objectType,
+ objectId,
+ propObject
+ };
+}
diff --git a/src/actions/topology.js b/src/actions/topology.js
new file mode 100644
index 00000000..de742bb1
--- /dev/null
+++ b/src/actions/topology.js
@@ -0,0 +1,21 @@
+export const FETCH_TOPOLOGY_OF_DATACENTER = "FETCH_TOPOLOGY_OF_DATACENTER";
+export const FETCH_TOPOLOGY_OF_DATACENTER_SUCCEEDED = "FETCH_TOPOLOGY_OF_DATACENTER_SUCCEEDED";
+export const FETCH_LATEST_DATACENTER = "FETCH_LATEST_DATACENTER";
+export const FETCH_LATEST_DATACENTER_SUCCEEDED = "FETCH_LATEST_DATACENTER_SUCCEEDED";
+
+export function fetchLatestDatacenter() {
+ return (dispatch, getState) => {
+ const {currentSimulationId} = getState();
+ dispatch({
+ type: FETCH_LATEST_DATACENTER,
+ currentSimulationId
+ });
+ };
+}
+
+export function fetchLatestDatacenterSucceeded(datacenterId) {
+ return {
+ type: FETCH_LATEST_DATACENTER_SUCCEEDED,
+ datacenterId
+ };
+}
diff --git a/src/api/routes/rooms.js b/src/api/routes/rooms.js
index e08cc6e7..1a7a7453 100644
--- a/src/api/routes/rooms.js
+++ b/src/api/routes/rooms.js
@@ -1,4 +1,5 @@
import {sendRequest} from "../index";
+import {deleteById, getById} from "./util";
export function getRoom(roomId) {
return getById("/rooms/{roomId}", {roomId});
diff --git a/src/api/sagas/objects.js b/src/api/sagas/objects.js
deleted file mode 100644
index 98c766ec..00000000
--- a/src/api/sagas/objects.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import {call, put, select} from "redux-saga/effects";
-import {addToStore} from "../../actions/objects";
-import {getSimulation} from "../routes/simulations";
-import {getUser} from "../routes/users";
-
-const selectors = {
- simulation: state => state.objects.simulation,
- user: state => state.objects.user,
- authorization: state => state.objects.authorization,
-};
-
-function* fetchAndStoreObject(objectType, id, apiCall) {
- const objectStore = yield select(selectors[objectType]);
- if (!objectStore[id]) {
- const object = yield apiCall;
- yield put(addToStore(objectType, object));
- }
-}
-
-export const fetchAndStoreSimulation = (id) =>
- fetchAndStoreObject("simulation", id, call(getSimulation, id));
-
-export const fetchAndStoreUser = (id) =>
- fetchAndStoreObject("user", id, call(getUser, id),);
diff --git a/src/components/map/MapStage.js b/src/components/map/MapStage.js
index 0950d5bd..879c7c39 100644
--- a/src/components/map/MapStage.js
+++ b/src/components/map/MapStage.js
@@ -1,8 +1,8 @@
import React from "react";
import {Group, Layer, Stage} from "react-konva";
+import DatacenterContainer from "../../containers/map/DatacenterContainer";
import jQuery from "../../util/jquery";
import Backdrop from "./elements/Backdrop";
-import DatacenterGroup from "./groups/DatacenterGroup";
import GridGroup from "./groups/GridGroup";
import {MAP_SIZE_IN_PIXELS} from "./MapConstants";
@@ -28,7 +28,7 @@ class MapStage extends React.Component {
this.setState({width: jQuery(window).width(), height: jQuery(window).height()});
}
- dragBoundHandler(pos) {
+ dragBoundFunc(pos) {
return {
x: pos.x > 0 ? 0 :
(pos.x < -MAP_SIZE_IN_PIXELS + this.state.width ? -MAP_SIZE_IN_PIXELS + this.state.width : pos.x),
@@ -41,9 +41,9 @@ class MapStage extends React.Component {
return (
<Stage width={this.state.width} height={this.state.height}>
<Layer>
- <Group draggable={true} dragBoundFunc={this.dragBoundHandler.bind(this)}>
+ <Group draggable={true} dragBoundFunc={this.dragBoundFunc.bind(this)}>
<Backdrop/>
- <DatacenterGroup/>
+ <DatacenterContainer/>
<GridGroup/>
</Group>
</Layer>
diff --git a/src/components/map/elements/RoomTile.js b/src/components/map/elements/RoomTile.js
index aa837def..759dcf35 100644
--- a/src/components/map/elements/RoomTile.js
+++ b/src/components/map/elements/RoomTile.js
@@ -2,6 +2,7 @@ import React from "react";
import {Rect} from "react-konva";
import {ROOM_DEFAULT_COLOR} from "../../../colors/index";
import Shapes from "../../../shapes/index";
+import {TILE_SIZE_IN_PIXELS} from "../MapConstants";
const RoomTile = ({tile}) => (
<Rect
diff --git a/src/components/map/elements/TileObject.js b/src/components/map/elements/TileObject.js
index 8703011c..1517ef97 100644
--- a/src/components/map/elements/TileObject.js
+++ b/src/components/map/elements/TileObject.js
@@ -3,7 +3,7 @@ import React from "react";
import {Rect} from "react-konva";
import {OBJECT_BORDER_COLOR, ROOM_DEFAULT_COLOR} from "../../../colors/index";
import Shapes from "../../../shapes/index";
-import {OBJECT_BORDER_WIDTH_IN_PIXELS, OBJECT_MARGIN_IN_PIXELS} from "../MapConstants";
+import {OBJECT_BORDER_WIDTH_IN_PIXELS, OBJECT_MARGIN_IN_PIXELS, TILE_SIZE_IN_PIXELS} from "../MapConstants";
const TileObject = ({tile, color}) => (
<Rect
diff --git a/src/components/map/groups/DatacenterGroup.js b/src/components/map/groups/DatacenterGroup.js
index 3b7a086b..d7e349be 100644
--- a/src/components/map/groups/DatacenterGroup.js
+++ b/src/components/map/groups/DatacenterGroup.js
@@ -1,14 +1,20 @@
import React from "react";
import {Group} from "react-konva";
+import Shapes from "../../../shapes/index";
import RoomGroup from "./RoomGroup";
-const DatacenterGroup = ({datacenter}) => (
- <Group>
- {datacenter.rooms.map(room => (
- <RoomGroup room={room}/>
- ))}
- </Group>
-);
+const DatacenterGroup = ({datacenter}) => {
+ if (!datacenter) {
+ return <Group/>;
+ }
+ return (
+ <Group>
+ {datacenter.rooms.map(room => (
+ <RoomGroup key={room.id} room={room}/>
+ ))}
+ </Group>
+ );
+};
DatacenterGroup.propTypes = {
datacenter: Shapes.Datacenter,
diff --git a/src/components/map/groups/GridGroup.js b/src/components/map/groups/GridGroup.js
index 2651bf19..f50482ce 100644
--- a/src/components/map/groups/GridGroup.js
+++ b/src/components/map/groups/GridGroup.js
@@ -15,11 +15,12 @@ const VERTICAL_POINT_PAIRS = MAP_COORDINATE_ENTRIES.map(index => [
const GridGroup = () => (
<Group>
- {HORIZONTAL_POINT_PAIRS.concat(VERTICAL_POINT_PAIRS).map(points => (
+ {HORIZONTAL_POINT_PAIRS.concat(VERTICAL_POINT_PAIRS).map((points, index) => (
<Line
points={points}
stroke={GRID_COLOR}
strokeWidth={GRID_LINE_WIDTH_IN_PIXELS}
+ key={index}
/>
))}
</Group>
diff --git a/src/components/map/groups/RoomGroup.js b/src/components/map/groups/RoomGroup.js
index 90a58767..28240d77 100644
--- a/src/components/map/groups/RoomGroup.js
+++ b/src/components/map/groups/RoomGroup.js
@@ -1,11 +1,12 @@
import React from "react";
import {Group} from "react-konva";
+import Shapes from "../../../shapes/index";
import TileGroup from "./TileGroup";
const RoomGroup = ({room}) => (
<Group>
{room.tiles.map(tile => (
- <TileGroup tile={tile}/>
+ <TileGroup key={tile.id} tile={tile}/>
))}
</Group>
);
diff --git a/src/containers/map/DatacenterContainer.js b/src/containers/map/DatacenterContainer.js
new file mode 100644
index 00000000..1716f22d
--- /dev/null
+++ b/src/containers/map/DatacenterContainer.js
@@ -0,0 +1,22 @@
+import {connect} from "react-redux";
+import DatacenterGroup from "../../components/map/groups/DatacenterGroup";
+import {denormalize} from "../../store/denormalizer";
+
+const mapStateToProps = state => {
+ if (state.currentDatacenterId === -1) {
+ return {};
+ }
+
+ const datacenter = denormalize(state, "datacenter", state.currentDatacenterId);
+ console.log(datacenter);
+
+ return {
+ datacenter
+ };
+};
+
+const DatacenterContainer = connect(
+ mapStateToProps
+)(DatacenterGroup);
+
+export default DatacenterContainer;
diff --git a/src/pages/App.js b/src/pages/App.js
index a2a1050b..f34c03cd 100644
--- a/src/pages/App.js
+++ b/src/pages/App.js
@@ -2,7 +2,7 @@ import PropTypes from "prop-types";
import React from 'react';
import {connect} from "react-redux";
import {openSimulationSucceeded} from "../actions/simulations";
-import {fetchAuthorizationsOfCurrentUser} from "../actions/users";
+import {fetchLatestDatacenter} from "../actions/topology";
import MapStage from "../components/map/MapStage";
import Navbar from "../components/navigation/Navbar";
import Login from "../containers/auth/Login";
@@ -14,7 +14,7 @@ class AppContainer extends React.Component {
componentDidMount() {
this.props.storeSimulationId(this.props.simulationId);
- this.props.fetchAuthorizationsOfCurrentUser();
+ this.props.fetchLatestDatacenter();
}
render() {
@@ -33,7 +33,7 @@ class AppContainer extends React.Component {
const mapDispatchToProps = dispatch => {
return {
storeSimulationId: id => dispatch(openSimulationSucceeded(id)),
- fetchAuthorizationsOfCurrentUser: () => dispatch(fetchAuthorizationsOfCurrentUser()),
+ fetchLatestDatacenter: () => dispatch(fetchLatestDatacenter()),
};
};
diff --git a/src/pages/Simulations.js b/src/pages/Simulations.js
index c46cb621..8218b1a4 100644
--- a/src/pages/Simulations.js
+++ b/src/pages/Simulations.js
@@ -15,10 +15,6 @@ class SimulationsContainer extends React.Component {
this.props.fetchAuthorizationsOfCurrentUser();
}
- onInputSubmission(text) {
- this.props.addSimulation(text);
- }
-
render() {
return (
<div className="full-height">
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 40a51a04..287a9762 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -2,7 +2,8 @@ import {combineReducers} from "redux";
import {auth} from "./auth";
import {modals} from "./modals";
import {objects} from "./objects";
-import {authorizationsOfCurrentUser, authVisibilityFilter} from "./simulations";
+import {authorizationsOfCurrentUser, authVisibilityFilter, currentSimulationId} from "./simulations";
+import {currentDatacenterId} from "./topology";
const rootReducer = combineReducers({
auth,
@@ -10,6 +11,8 @@ const rootReducer = combineReducers({
modals,
authorizationsOfCurrentUser,
authVisibilityFilter,
+ currentSimulationId,
+ currentDatacenterId,
});
export default rootReducer;
diff --git a/src/reducers/objects.js b/src/reducers/objects.js
index 60cd2711..4fbffea6 100644
--- a/src/reducers/objects.js
+++ b/src/reducers/objects.js
@@ -1,5 +1,5 @@
import {combineReducers} from "redux";
-import {ADD_TO_STORE} from "../actions/objects";
+import {ADD_PROP_TO_STORE_OBJECT, ADD_TO_STORE} from "../actions/objects";
export const objects = combineReducers({
simulation: object("simulation"),
@@ -27,14 +27,22 @@ function object(type) {
function objectWithId(type, getId) {
return (state = {}, action) => {
- if (action.type === ADD_TO_STORE) {
- if (action.objectType === type) {
- return Object.assign(
- state,
- {[getId(action.object)]: action.object}
- );
- }
+ if (action.objectType !== type) {
return state;
}
+
+ if (action.type === ADD_TO_STORE) {
+ return Object.assign(
+ state,
+ {[getId(action.object)]: action.object}
+ );
+ } else if (action.type === ADD_PROP_TO_STORE_OBJECT) {
+ return Object.assign(
+ state,
+ {[action.objectId]: Object.assign(state[action.objectId], action.propObject)}
+ );
+ }
+
+ return state;
};
}
diff --git a/src/reducers/topology.js b/src/reducers/topology.js
new file mode 100644
index 00000000..caafb7c1
--- /dev/null
+++ b/src/reducers/topology.js
@@ -0,0 +1,10 @@
+import {FETCH_LATEST_DATACENTER_SUCCEEDED} from "../actions/topology";
+
+export function currentDatacenterId(state = -1, action) {
+ switch (action.type) {
+ case FETCH_LATEST_DATACENTER_SUCCEEDED:
+ return action.datacenterId;
+ default:
+ return state;
+ }
+}
diff --git a/src/api/sagas/index.js b/src/sagas/index.js
index 7fe57453..c6177cd4 100644
--- a/src/api/sagas/index.js
+++ b/src/sagas/index.js
@@ -1,9 +1,11 @@
import {takeEvery} from "redux-saga/effects";
-import {LOG_IN} from "../../actions/auth";
-import {ADD_SIMULATION, DELETE_SIMULATION} from "../../actions/simulations";
-import {DELETE_CURRENT_USER, FETCH_AUTHORIZATIONS_OF_CURRENT_USER} from "../../actions/users";
+import {LOG_IN} from "../actions/auth";
+import {ADD_SIMULATION, DELETE_SIMULATION} from "../actions/simulations";
+import {FETCH_LATEST_DATACENTER} from "../actions/topology";
+import {DELETE_CURRENT_USER, FETCH_AUTHORIZATIONS_OF_CURRENT_USER} from "../actions/users";
import {onDeleteCurrentUser} from "./profile";
import {onSimulationAdd, onSimulationDelete} from "./simulations";
+import {onFetchLatestDatacenter} from "./topology";
import {onFetchAuthorizationsOfCurrentUser, onFetchLoggedInUser} from "./users";
export default function* rootSaga() {
@@ -12,4 +14,5 @@ export default function* rootSaga() {
yield takeEvery(ADD_SIMULATION, onSimulationAdd);
yield takeEvery(DELETE_SIMULATION, onSimulationDelete);
yield takeEvery(DELETE_CURRENT_USER, onDeleteCurrentUser);
+ yield takeEvery(FETCH_LATEST_DATACENTER, onFetchLatestDatacenter);
}
diff --git a/src/sagas/objects.js b/src/sagas/objects.js
new file mode 100644
index 00000000..5fac6c3e
--- /dev/null
+++ b/src/sagas/objects.js
@@ -0,0 +1,109 @@
+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 {getSection} from "../api/routes/sections";
+import {getPathsOfSimulation, getSimulation} from "../api/routes/simulations";
+import {
+ getCoolingItem,
+ getCPU,
+ getFailureModel,
+ getGPU,
+ getMemory,
+ getPSU,
+ getStorage
+} from "../api/routes/specifications";
+import {getMachinesOfRackByTile, getRackByTile} from "../api/routes/tiles";
+import {getUser} from "../api/routes/users";
+
+export const OBJECT_SELECTORS = {
+ simulation: state => state.objects.simulation,
+ user: state => state.objects.user,
+ authorization: state => state.objects.authorization,
+ failureModel: state => state.objects.failureModel,
+ cpu: state => state.objects.cpu,
+ gpu: state => state.objects.gpu,
+ memory: state => state.objects.memory,
+ storage: state => state.objects.storage,
+ machine: state => state.objects.machine,
+ rack: state => state.objects.rack,
+ coolingItem: state => state.objects.coolingItem,
+ psu: state => state.objects.psu,
+ tile: state => state.objects.tile,
+ room: state => state.objects.room,
+ datacenter: state => state.objects.datacenter,
+ section: state => state.objects.section,
+ path: state => state.objects.path,
+};
+
+function* fetchAndStoreObject(objectType, id, apiCall) {
+ const objectStore = yield select(OBJECT_SELECTORS[objectType]);
+ if (!objectStore[id]) {
+ const object = yield apiCall;
+ yield put(addToStore(objectType, object));
+ }
+ return objectStore[id];
+}
+
+function* fetchAndStoreObjects(objectType, apiCall) {
+ const objects = yield apiCall;
+ for (let index in objects) {
+ yield put(addToStore(objectType, objects[index]));
+ }
+ return objects;
+}
+
+export const fetchAndStoreSimulation = (id) =>
+ fetchAndStoreObject("simulation", id, call(getSimulation, id));
+
+export const fetchAndStoreUser = (id) =>
+ fetchAndStoreObject("user", id, call(getUser, id));
+
+export const fetchAndStoreFailureModel = (id) =>
+ fetchAndStoreObject("failureModel", id, call(getFailureModel, id));
+
+export const fetchAndStoreCPU = (id) =>
+ fetchAndStoreObject("cpu", id, call(getCPU, id));
+
+export const fetchAndStoreGPU = (id) =>
+ fetchAndStoreObject("gpu", id, call(getGPU, id));
+
+export const fetchAndStoreMemory = (id) =>
+ fetchAndStoreObject("memory", id, call(getMemory, id));
+
+export const fetchAndStoreStorage = (id) =>
+ fetchAndStoreObject("storage", id, call(getStorage, id));
+
+export const fetchAndStoreMachinesOfTile = (tileId) =>
+ fetchAndStoreObjects("machine", call(getMachinesOfRackByTile, tileId));
+
+export const fetchAndStoreRackOnTile = (id, tileId) =>
+ fetchAndStoreObject("rack", id, call(getRackByTile, tileId));
+
+export const fetchAndStoreCoolingItem = (id) =>
+ fetchAndStoreObject("coolingItem", id, call(getCoolingItem, id));
+
+export const fetchAndStorePSU = (id) =>
+ fetchAndStoreObject("psu", id, call(getPSU, id));
+
+export const fetchAndStoreTilesOfRoom = (roomId) =>
+ fetchAndStoreObjects("tile", call(getTilesOfRoom, roomId));
+
+export const fetchAndStoreRoomsOfDatacenter = (datacenterId) =>
+ fetchAndStoreObjects("room", call(getRoomsOfDatacenter, datacenterId));
+
+export const fetchAndStoreDatacenter = (id) =>
+ fetchAndStoreObject("datacenter", id, call(getDatacenter, id));
+
+export const fetchAndStoreSection = (id) =>
+ fetchAndStoreObject("section", id, call(getSection, id));
+
+export const fetchAndStoreSectionsOfPath = (pathId) =>
+ fetchAndStoreObjects("section", call(getSectionsOfPath, pathId));
+
+export const fetchAndStorePath = (id) =>
+ fetchAndStoreObject("path", id, call(getPath, id));
+
+export const fetchAndStorePathsOfSimulation = (simulationId) =>
+ fetchAndStoreObjects("path", call(getPathsOfSimulation, simulationId));
diff --git a/src/api/sagas/profile.js b/src/sagas/profile.js
index 3c4e1825..6a72e7c2 100644
--- a/src/api/sagas/profile.js
+++ b/src/sagas/profile.js
@@ -1,6 +1,6 @@
import {call, put} from "redux-saga/effects";
-import {deleteCurrentUserSucceeded} from "../../actions/users";
-import {deleteUser} from "../routes/users";
+import {deleteCurrentUserSucceeded} from "../actions/users";
+import {deleteUser} from "../api/routes/users";
export function* onDeleteCurrentUser(action) {
try {
diff --git a/src/api/sagas/simulations.js b/src/sagas/simulations.js
index 6b7471c0..b699002e 100644
--- a/src/api/sagas/simulations.js
+++ b/src/sagas/simulations.js
@@ -1,7 +1,7 @@
import {call, put} from "redux-saga/effects";
-import {addToStore} from "../../actions/objects";
-import {addSimulationSucceeded, deleteSimulationSucceeded} from "../../actions/simulations";
-import {addSimulation, deleteSimulation} from "../routes/simulations";
+import {addToStore} from "../actions/objects";
+import {addSimulationSucceeded, deleteSimulationSucceeded} from "../actions/simulations";
+import {addSimulation, deleteSimulation} from "../api/routes/simulations";
export function* onSimulationAdd(action) {
try {
diff --git a/src/sagas/topology.js b/src/sagas/topology.js
new file mode 100644
index 00000000..6d359534
--- /dev/null
+++ b/src/sagas/topology.js
@@ -0,0 +1,71 @@
+import {put} from "redux-saga/effects";
+import {addPropToStoreObject} from "../actions/objects";
+import {fetchLatestDatacenterSucceeded} from "../actions/topology";
+import {
+ fetchAndStoreCoolingItem,
+ fetchAndStoreDatacenter,
+ fetchAndStorePathsOfSimulation,
+ fetchAndStorePSU,
+ fetchAndStoreRackOnTile,
+ fetchAndStoreRoomsOfDatacenter,
+ fetchAndStoreSectionsOfPath,
+ fetchAndStoreTilesOfRoom
+} from "./objects";
+
+export function* onFetchLatestDatacenter(action) {
+ try {
+ const paths = yield fetchAndStorePathsOfSimulation(action.currentSimulationId);
+ const latestPath = paths[paths.length - 1];
+ const sections = yield fetchAndStoreSectionsOfPath(latestPath.id);
+ const latestSection = sections[sections.length - 1];
+ yield fetchDatacenter(latestSection.datacenterId);
+ yield put(fetchLatestDatacenterSucceeded(latestSection.datacenterId));
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+export function* fetchDatacenter(datacenterId) {
+ try {
+ const datacenter = yield fetchAndStoreDatacenter(datacenterId);
+ datacenter.roomIds = (yield fetchAndStoreRoomsOfDatacenter(datacenterId)).map(room => room.id);
+
+ for (let index in datacenter.roomIds) {
+ yield fetchRoom(datacenter.roomIds[index]);
+ }
+ } catch (error) {
+ console.log(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;
+ }
+ console.log(tile);
+ switch (tile.objectType) {
+ case "RACK":
+ const rack = yield fetchAndStoreRackOnTile(tile.objectId, tile.id);
+ yield put(addPropToStoreObject("tile", tile.id, {rackId: rack.id}));
+ 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 object type encountered while fetching tile objects");
+ }
+}
diff --git a/src/api/sagas/users.js b/src/sagas/users.js
index d3bc3f5f..5f9bffa1 100644
--- a/src/api/sagas/users.js
+++ b/src/sagas/users.js
@@ -1,10 +1,10 @@
import {call, put} from "redux-saga/effects";
-import {logInSucceeded} from "../../actions/auth";
-import {addToAuthorizationStore} from "../../actions/objects";
-import {fetchAuthorizationsOfCurrentUserSucceeded} from "../../actions/users";
-import {saveAuthLocalStorage} from "../../auth/index";
-import {performTokenSignIn} from "../routes/token-signin";
-import {addUser, getAuthorizationsByUser} from "../routes/users";
+import {logInSucceeded} from "../actions/auth";
+import {addToStore} from "../actions/objects";
+import {fetchAuthorizationsOfCurrentUserSucceeded} from "../actions/users";
+import {performTokenSignIn} from "../api/routes/token-signin";
+import {addUser, getAuthorizationsByUser} from "../api/routes/users";
+import {saveAuthLocalStorage} from "../auth/index";
import {fetchAndStoreSimulation, fetchAndStoreUser} from "./objects";
export function* onFetchLoggedInUser(action) {
@@ -29,7 +29,7 @@ export function* onFetchAuthorizationsOfCurrentUser(action) {
const authorizations = yield call(getAuthorizationsByUser, action.userId);
for (const authorization of authorizations) {
- yield put(addToAuthorizationStore(authorization));
+ yield put(addToStore("authorization", authorization));
yield fetchAndStoreSimulation(authorization.simulationId);
yield fetchAndStoreUser(authorization.userId);
diff --git a/src/shapes/index.js b/src/shapes/index.js
index 1938032e..bea0f1aa 100644
--- a/src/shapes/index.js
+++ b/src/shapes/index.js
@@ -101,7 +101,7 @@ Shapes.Tile = PropTypes.shape({
positionX: PropTypes.number.isRequired,
positionY: PropTypes.number.isRequired,
objectId: PropTypes.number,
- objectType: PropTypes.number,
+ objectType: PropTypes.string,
rack: Shapes.Rack,
coolingItem: Shapes.CoolingItem,
psu: Shapes.PSU,
@@ -123,6 +123,7 @@ Shapes.Datacenter = PropTypes.shape({
Shapes.Section = PropTypes.shape({
id: PropTypes.number.isRequired,
pathId: PropTypes.number.isRequired,
+ startTick: PropTypes.number.isRequired,
datacenterId: PropTypes.number.isRequired,
datacenter: Shapes.Datacenter,
});
diff --git a/src/store/configureStore.js b/src/store/configureStore.js
index ecd804a2..5bbaf811 100644
--- a/src/store/configureStore.js
+++ b/src/store/configureStore.js
@@ -3,9 +3,9 @@ import persistState from "redux-localstorage";
import {createLogger} from "redux-logger";
import createSagaMiddleware from 'redux-saga';
import thunk from "redux-thunk";
-import rootSaga from "../api/sagas/index";
import {authRedirectMiddleware} from "../auth/index";
import rootReducer from "../reducers/index";
+import rootSaga from "../sagas/index";
const sagaMiddleware = createSagaMiddleware();
const logger = createLogger();
diff --git a/src/store/denormalizer.js b/src/store/denormalizer.js
index fbf15430..e6583ae7 100644
--- a/src/store/denormalizer.js
+++ b/src/store/denormalizer.js
@@ -1,14 +1,28 @@
+const EXCLUDED_IDENTIFIERS = [
+ "objectId",
+ "googleId",
+];
+
export function denormalize(state, objectType, id) {
+ return denormalizeWithRecursionCheck(state, objectType, id, undefined);
+}
+
+function denormalizeWithRecursionCheck(state, objectType, id, previousType) {
const object = Object.assign({}, state.objects[objectType][id]);
for (let prop in object) {
- if (!object.hasOwnProperty(prop)) {
+ if (prop.indexOf(previousType) !== -1) {
continue;
}
- if (prop.endsWith("Id")) {
+ if (prop.endsWith("Id") && EXCLUDED_IDENTIFIERS.indexOf(prop) === -1) {
const propType = prop.replace("Id", "");
- object[propType] = state.objects[propType][object[prop]];
+ object[propType] = denormalizeWithRecursionCheck(state, propType, object[prop], objectType);
+ }
+
+ if (prop.endsWith("Ids")) {
+ const propType = prop.replace("Ids", "");
+ object[propType + "s"] = object[prop].map(id => denormalizeWithRecursionCheck(state, propType, id, objectType));
}
}