summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-17 17:55:04 +0200
committerGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-23 10:06:03 +0200
commiteb208a7e2fd020ab5d07d11cc6d52d1e3dcfcc7c (patch)
treed2ec8a20408b7b2880e62feaa70fe95a78c484dd /src
parent326b74fc39f63f47c71359276601ea93f7345dc6 (diff)
Add simulation mode framework
Includes object states in the store (by tick), charting, and progress bars.
Diffstat (limited to 'src')
-rw-r--r--src/actions/experiments.js8
-rw-r--r--src/actions/simulation/load-metric.js8
-rw-r--r--src/actions/simulation/playback.js15
-rw-r--r--src/actions/simulation/tick.js23
-rw-r--r--src/actions/states.js10
-rw-r--r--src/api/routes/experiments.js22
-rw-r--r--src/components/map/elements/RoomTile.js5
-rw-r--r--src/components/map/groups/RackGroup.js27
-rw-r--r--src/components/map/groups/TileGroup.js17
-rw-r--r--src/components/sidebars/Sidebar.js5
-rw-r--r--src/components/sidebars/elements/LoadBarComponent.js19
-rw-r--r--src/components/sidebars/elements/LoadChartComponent.js16
-rw-r--r--src/components/sidebars/topology/TopologySidebarComponent.js8
-rw-r--r--src/components/sidebars/topology/building/BuildingSidebarComponent.js15
-rw-r--r--src/components/sidebars/topology/building/CancelNewRoomConstructionComponent.js9
-rw-r--r--src/components/sidebars/topology/building/FinishNewRoomConstructionComponent.js9
-rw-r--r--src/components/sidebars/topology/building/NewRoomConstructionComponent.js24
-rw-r--r--src/components/sidebars/topology/building/StartNewRoomConstructionComponent.js9
-rw-r--r--src/components/sidebars/topology/machine/MachineSidebarComponent.js12
-rw-r--r--src/components/sidebars/topology/rack/MachineComponent.js80
-rw-r--r--src/components/sidebars/topology/rack/RackSidebarComponent.js14
-rw-r--r--src/components/sidebars/topology/room/RoomSidebarComponent.js18
-rw-r--r--src/components/simulations/FilterButton.js8
-rw-r--r--src/containers/map/DatacenterContainer.js2
-rw-r--r--src/containers/map/RackContainer.js26
-rw-r--r--src/containers/map/TileContainer.js15
-rw-r--r--src/containers/sidebars/elements/LoadBarContainer.js25
-rw-r--r--src/containers/sidebars/elements/LoadChartContainer.js26
-rw-r--r--src/containers/sidebars/topology/building/BuildingSidebarContainer.js2
-rw-r--r--src/containers/sidebars/topology/building/CancelNewRoomConstructionButton.js16
-rw-r--r--src/containers/sidebars/topology/building/FinishNewRoomConstructionButton.js16
-rw-r--r--src/containers/sidebars/topology/building/NewRoomConstructionContainer.js28
-rw-r--r--src/containers/sidebars/topology/building/StartNewRoomConstructionButton.js16
-rw-r--r--src/containers/sidebars/topology/machine/MachineSidebarContainer.js15
-rw-r--r--src/containers/sidebars/topology/rack/MachineContainer.js15
-rw-r--r--src/containers/sidebars/topology/rack/RackSidebarContainer.js15
-rw-r--r--src/containers/sidebars/topology/room/RoomSidebarContainer.js2
-rw-r--r--src/reducers/construction-mode.js (renamed from src/reducers/construction.js)0
-rw-r--r--src/reducers/current-ids.js (renamed from src/reducers/topology.js)11
-rw-r--r--src/reducers/index.js18
-rw-r--r--src/reducers/simulation-mode.js50
-rw-r--r--src/reducers/simulations.js10
-rw-r--r--src/reducers/states.js33
-rw-r--r--src/util/simulation-load.js26
44 files changed, 576 insertions, 172 deletions
diff --git a/src/actions/experiments.js b/src/actions/experiments.js
index b067f5d9..c7cc7e24 100644
--- a/src/actions/experiments.js
+++ b/src/actions/experiments.js
@@ -1,6 +1,7 @@
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";
export function fetchExperimentsOfSimulation(simulationId) {
return {
@@ -22,3 +23,10 @@ export function deleteExperiment(id) {
id
};
}
+
+export function openExperimentSucceeded(id) {
+ return {
+ type: OPEN_EXPERIMENT_SUCCEEDED,
+ id
+ }
+}
diff --git a/src/actions/simulation/load-metric.js b/src/actions/simulation/load-metric.js
new file mode 100644
index 00000000..e426a7d2
--- /dev/null
+++ b/src/actions/simulation/load-metric.js
@@ -0,0 +1,8 @@
+export const CHANGE_LOAD_METRIC = "CHANGE_LOAD_METRIC";
+
+export function changeLoadMetric(metric) {
+ return {
+ type: CHANGE_LOAD_METRIC,
+ metric
+ };
+}
diff --git a/src/actions/simulation/playback.js b/src/actions/simulation/playback.js
new file mode 100644
index 00000000..bddb9a0a
--- /dev/null
+++ b/src/actions/simulation/playback.js
@@ -0,0 +1,15 @@
+export const SET_PLAYING = "SET_PLAYING";
+
+export function playSimulation() {
+ return {
+ type: SET_PLAYING,
+ playing: true
+ }
+}
+
+export function pauseSimulation() {
+ return {
+ type: SET_PLAYING,
+ playing: false
+ }
+}
diff --git a/src/actions/simulation/tick.js b/src/actions/simulation/tick.js
new file mode 100644
index 00000000..68f226d7
--- /dev/null
+++ b/src/actions/simulation/tick.js
@@ -0,0 +1,23 @@
+export const GO_TO_TICK = "GO_TO_TICK";
+export const SET_LAST_SIMULATED_TICK = "SET_LAST_SIMULATED_TICK";
+
+export function incrementTick() {
+ return (dispatch, getState) => {
+ const {currentTick} = getState();
+ dispatch(goToTick(currentTick + 1));
+ }
+}
+
+export function goToTick(tick) {
+ return {
+ type: GO_TO_TICK,
+ tick
+ }
+}
+
+export function setLastSimulatedTick(tick) {
+ return {
+ type: SET_LAST_SIMULATED_TICK,
+ tick
+ }
+}
diff --git a/src/actions/states.js b/src/actions/states.js
new file mode 100644
index 00000000..6887a1b3
--- /dev/null
+++ b/src/actions/states.js
@@ -0,0 +1,10 @@
+export const ADD_TO_STATES = "ADD_TO_STATES";
+
+export function addToStates(objectType, tick, object) {
+ return {
+ type: ADD_TO_STATES,
+ objectType,
+ tick,
+ object
+ };
+}
diff --git a/src/api/routes/experiments.js b/src/api/routes/experiments.js
index 8e9cfd2f..e2306059 100644
--- a/src/api/routes/experiments.js
+++ b/src/api/routes/experiments.js
@@ -1,5 +1,25 @@
-import {deleteById} from "./util";
+import {deleteById, getById} from "./util";
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});
+}
+
+export function getAllRackStates(experimentId) {
+ return getById("/experiments/{experimentId}/rack-states", {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/src/components/map/elements/RoomTile.js b/src/components/map/elements/RoomTile.js
index 4d5e50fc..87dd2f03 100644
--- a/src/components/map/elements/RoomTile.js
+++ b/src/components/map/elements/RoomTile.js
@@ -1,16 +1,15 @@
import React from "react";
import {Rect} from "react-konva";
-import {ROOM_DEFAULT_COLOR, ROOM_IN_CONSTRUCTION_COLOR} from "../../../colors/index";
import Shapes from "../../../shapes/index";
import {TILE_SIZE_IN_PIXELS} from "../MapConstants";
-const RoomTile = ({tile, newTile}) => (
+const RoomTile = ({tile, color}) => (
<Rect
x={tile.positionX * TILE_SIZE_IN_PIXELS}
y={tile.positionY * TILE_SIZE_IN_PIXELS}
width={TILE_SIZE_IN_PIXELS}
height={TILE_SIZE_IN_PIXELS}
- fill={newTile ? ROOM_IN_CONSTRUCTION_COLOR : ROOM_DEFAULT_COLOR}
+ fill={color}
/>
);
diff --git a/src/components/map/groups/RackGroup.js b/src/components/map/groups/RackGroup.js
index 5dd470de..648c74d7 100644
--- a/src/components/map/groups/RackGroup.js
+++ b/src/components/map/groups/RackGroup.js
@@ -4,15 +4,28 @@ import {RACK_BACKGROUND_COLOR} from "../../../colors/index";
import RackEnergyFillContainer from "../../../containers/map/RackEnergyFillContainer";
import RackSpaceFillContainer from "../../../containers/map/RackSpaceFillContainer";
import Shapes from "../../../shapes/index";
+import {convertLoadToSimulationColor} from "../../../util/simulation-load";
import TileObject from "../elements/TileObject";
-const RackGroup = ({tile}) => (
- <Group>
- <TileObject positionX={tile.positionX} positionY={tile.positionY} color={RACK_BACKGROUND_COLOR}/>
- <RackSpaceFillContainer tileId={tile.id} positionX={tile.positionX} positionY={tile.positionY}/>
- <RackEnergyFillContainer tileId={tile.id} positionX={tile.positionX} positionY={tile.positionY}/>
- </Group>
-);
+const RackGroup = ({tile, inSimulation, rackLoad}) => {
+ let color = RACK_BACKGROUND_COLOR;
+ if (inSimulation) {
+ color = convertLoadToSimulationColor(rackLoad);
+ }
+
+ return (
+ <Group>
+ <TileObject positionX={tile.positionX} positionY={tile.positionY} color={color}/>
+ {inSimulation ?
+ undefined :
+ <Group>
+ <RackSpaceFillContainer tileId={tile.id} positionX={tile.positionX} positionY={tile.positionY}/>
+ <RackEnergyFillContainer tileId={tile.id} positionX={tile.positionX} positionY={tile.positionY}/>
+ </Group>
+ }
+ </Group>
+ );
+};
RackGroup.propTypes = {
tile: Shapes.Tile,
diff --git a/src/components/map/groups/TileGroup.js b/src/components/map/groups/TileGroup.js
index 8fbdeb31..3de712d1 100644
--- a/src/components/map/groups/TileGroup.js
+++ b/src/components/map/groups/TileGroup.js
@@ -1,25 +1,34 @@
import PropTypes from "prop-types";
import React from "react";
import {Group} from "react-konva";
+import {ROOM_DEFAULT_COLOR, ROOM_IN_CONSTRUCTION_COLOR} from "../../../colors/index";
+import RackContainer from "../../../containers/map/RackContainer";
import Shapes from "../../../shapes/index";
+import {convertLoadToSimulationColor} from "../../../util/simulation-load";
import RoomTile from "../elements/RoomTile";
-import RackGroup from "./RackGroup";
-const TileGroup = ({tile, newTile, onClick}) => {
+const TileGroup = ({tile, newTile, inSimulation, roomLoad, onClick}) => {
let tileObject;
switch (tile.objectType) {
case "RACK":
- tileObject = <RackGroup tile={tile}/>;
+ tileObject = <RackContainer tile={tile}/>;
break;
default:
tileObject = null;
}
+ let color = ROOM_DEFAULT_COLOR;
+ if (newTile) {
+ color = ROOM_IN_CONSTRUCTION_COLOR;
+ } else if (inSimulation) {
+ color = convertLoadToSimulationColor(roomLoad);
+ }
+
return (
<Group
onClick={() => onClick(tile)}
>
- <RoomTile tile={tile} newTile={newTile}/>
+ <RoomTile tile={tile} color={color}/>
{tileObject}
</Group>
);
diff --git a/src/components/sidebars/Sidebar.js b/src/components/sidebars/Sidebar.js
index 2f4d77a7..ce743b17 100644
--- a/src/components/sidebars/Sidebar.js
+++ b/src/components/sidebars/Sidebar.js
@@ -3,7 +3,10 @@ import React from "react";
import "./Sidebar.css";
const Sidebar = ({isRight, children}) => (
- <div className={classNames("sidebar p-3 h-100", {"sidebar-right": isRight})}>
+ <div
+ className={classNames("sidebar p-3 h-100", {"sidebar-right": isRight})}
+ onWheel={e => e.stopPropagation()}
+ >
{children}
</div>
);
diff --git a/src/components/sidebars/elements/LoadBarComponent.js b/src/components/sidebars/elements/LoadBarComponent.js
new file mode 100644
index 00000000..5a39b188
--- /dev/null
+++ b/src/components/sidebars/elements/LoadBarComponent.js
@@ -0,0 +1,19 @@
+import classNames from "classnames";
+import React from "react";
+
+const LoadBarComponent = ({percent, disabled}) => (
+ <div className={classNames("progress", {disabled})}>
+ <div
+ className="progress-bar progress-bar-striped"
+ role="progressbar"
+ aria-valuenow={percent}
+ aria-valuemin="0"
+ aria-valuemax="100"
+ style={{width: percent + "%"}}
+ >
+ {percent}%
+ </div>
+ </div>
+);
+
+export default LoadBarComponent;
diff --git a/src/components/sidebars/elements/LoadChartComponent.js b/src/components/sidebars/elements/LoadChartComponent.js
new file mode 100644
index 00000000..54a20116
--- /dev/null
+++ b/src/components/sidebars/elements/LoadChartComponent.js
@@ -0,0 +1,16 @@
+import React from "react";
+import {VictoryChart, VictoryLine, VictoryScatter} from "victory";
+
+const LoadChartComponent = ({data, tick}) => (
+ <VictoryChart height={300}>
+ <VictoryLine
+ data={data}
+ />
+ <VictoryScatter
+ data={data}
+ size={5}
+ />
+ </VictoryChart>
+);
+
+export default LoadChartComponent;
diff --git a/src/components/sidebars/topology/TopologySidebarComponent.js b/src/components/sidebars/topology/TopologySidebarComponent.js
index 36f2ecc1..b61c7e3c 100644
--- a/src/components/sidebars/topology/TopologySidebarComponent.js
+++ b/src/components/sidebars/topology/TopologySidebarComponent.js
@@ -1,9 +1,9 @@
import React from "react";
import BuildingSidebarContainer from "../../../containers/sidebars/topology/building/BuildingSidebarContainer";
+import MachineSidebarContainer from "../../../containers/sidebars/topology/machine/MachineSidebarContainer";
+import RackSidebarContainer from "../../../containers/sidebars/topology/rack/RackSidebarContainer";
import RoomSidebarContainer from "../../../containers/sidebars/topology/room/RoomSidebarContainer";
import Sidebar from "../Sidebar";
-import MachineSidebarComponent from "./machine/MachineSidebarComponent";
-import RackSidebarComponent from "./rack/RackSidebarComponent";
const TopologySidebarComponent = ({interactionLevel}) => {
let sidebarContent;
@@ -16,10 +16,10 @@ const TopologySidebarComponent = ({interactionLevel}) => {
sidebarContent = <RoomSidebarContainer/>;
break;
case "RACK":
- sidebarContent = <RackSidebarComponent/>;
+ sidebarContent = <RackSidebarContainer/>;
break;
case "MACHINE":
- sidebarContent = <MachineSidebarComponent/>;
+ sidebarContent = <MachineSidebarContainer/>;
break;
default:
sidebarContent = "Missing Content";
diff --git a/src/components/sidebars/topology/building/BuildingSidebarComponent.js b/src/components/sidebars/topology/building/BuildingSidebarComponent.js
index 002184ae..835943f2 100644
--- a/src/components/sidebars/topology/building/BuildingSidebarComponent.js
+++ b/src/components/sidebars/topology/building/BuildingSidebarComponent.js
@@ -1,18 +1,13 @@
import React from "react";
-import CancelNewRoomConstructionButton from "../../../../containers/sidebars/topology/building/CancelNewRoomConstructionButton";
-import FinishNewRoomConstructionButton from "../../../../containers/sidebars/topology/building/FinishNewRoomConstructionButton";
-import StartNewRoomConstructionButton from "../../../../containers/sidebars/topology/building/StartNewRoomConstructionButton";
+import NewRoomConstructionContainer from "../../../../containers/sidebars/topology/building/NewRoomConstructionContainer";
-const BuildingSidebarComponent = ({currentRoomInConstruction}) => {
+const BuildingSidebarComponent = ({inSimulation}) => {
return (
<div>
<h2>Building</h2>
- {currentRoomInConstruction === -1 ?
- <StartNewRoomConstructionButton/> :
- <div>
- <FinishNewRoomConstructionButton/>
- <CancelNewRoomConstructionButton/>
- </div>
+ {inSimulation ?
+ undefined :
+ <NewRoomConstructionContainer/>
}
</div>
);
diff --git a/src/components/sidebars/topology/building/CancelNewRoomConstructionComponent.js b/src/components/sidebars/topology/building/CancelNewRoomConstructionComponent.js
deleted file mode 100644
index 15f199a6..00000000
--- a/src/components/sidebars/topology/building/CancelNewRoomConstructionComponent.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from "react";
-
-const CancelNewRoomConstructionComponent = ({onClick}) => (
- <div className="btn btn-default btn-block" onClick={onClick}>
- Cancel construction
- </div>
-);
-
-export default CancelNewRoomConstructionComponent;
diff --git a/src/components/sidebars/topology/building/FinishNewRoomConstructionComponent.js b/src/components/sidebars/topology/building/FinishNewRoomConstructionComponent.js
deleted file mode 100644
index d9edbb61..00000000
--- a/src/components/sidebars/topology/building/FinishNewRoomConstructionComponent.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from "react";
-
-const FinishNewRoomConstructionComponent = ({onClick}) => (
- <div className="btn btn-primary btn-block" onClick={onClick}>
- Finalize new room
- </div>
-);
-
-export default FinishNewRoomConstructionComponent;
diff --git a/src/components/sidebars/topology/building/NewRoomConstructionComponent.js b/src/components/sidebars/topology/building/NewRoomConstructionComponent.js
new file mode 100644
index 00000000..581330ab
--- /dev/null
+++ b/src/components/sidebars/topology/building/NewRoomConstructionComponent.js
@@ -0,0 +1,24 @@
+import React from "react";
+
+const NewRoomConstructionComponent = ({onStart, onFinish, onCancel, currentRoomInConstruction}) => {
+ if (currentRoomInConstruction === -1) {
+ return (
+ <div className="btn btn-primary btn-block" onClick={onStart}>
+ Construct a new room
+ </div>
+ );
+ }
+ return (
+ <div>
+ <div className="btn btn-primary btn-block" onClick={onFinish}>
+ Finalize new room
+ </div>
+ <div className="btn btn-default btn-block" onClick={onCancel}>
+ Cancel construction
+ </div>
+ </div>
+ );
+
+};
+
+export default NewRoomConstructionComponent;
diff --git a/src/components/sidebars/topology/building/StartNewRoomConstructionComponent.js b/src/components/sidebars/topology/building/StartNewRoomConstructionComponent.js
deleted file mode 100644
index 60573532..00000000
--- a/src/components/sidebars/topology/building/StartNewRoomConstructionComponent.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from "react";
-
-const StartNewRoomConstructionComponent = ({onClick}) => (
- <div className="btn btn-primary btn-block" onClick={onClick}>
- Construct a new room
- </div>
-);
-
-export default StartNewRoomConstructionComponent;
diff --git a/src/components/sidebars/topology/machine/MachineSidebarComponent.js b/src/components/sidebars/topology/machine/MachineSidebarComponent.js
index 218e4f41..0f85f0f9 100644
--- a/src/components/sidebars/topology/machine/MachineSidebarComponent.js
+++ b/src/components/sidebars/topology/machine/MachineSidebarComponent.js
@@ -1,15 +1,23 @@
import React from "react";
+import LoadBarContainer from "../../../../containers/sidebars/elements/LoadBarContainer";
+import LoadChartContainer from "../../../../containers/sidebars/elements/LoadChartContainer";
import BackToRackContainer from "../../../../containers/sidebars/topology/machine/BackToRackContainer";
import DeleteMachineContainer from "../../../../containers/sidebars/topology/machine/DeleteMachineContainer";
import MachineNameContainer from "../../../../containers/sidebars/topology/machine/MachineNameContainer";
import UnitTabsComponent from "./UnitTabsComponent";
-const MachineSidebarComponent = () => {
+const MachineSidebarComponent = ({inSimulation, machineId}) => {
return (
<div>
<MachineNameContainer/>
<BackToRackContainer/>
- <DeleteMachineContainer/>
+ {inSimulation ?
+ <div>
+ <LoadBarContainer objectType="machine" objectId={machineId}/>
+ <LoadChartContainer objectType="machine" objectId={machineId}/>
+ </div> :
+ <DeleteMachineContainer/>
+ }
<UnitTabsComponent/>
</div>
);
diff --git a/src/components/sidebars/topology/rack/MachineComponent.js b/src/components/sidebars/topology/rack/MachineComponent.js
index 4854456c..b6e9791d 100644
--- a/src/components/sidebars/topology/rack/MachineComponent.js
+++ b/src/components/sidebars/topology/rack/MachineComponent.js
@@ -1,5 +1,6 @@
import React from "react";
import Shapes from "../../../../shapes";
+import {convertLoadToSimulationColor} from "../../../../util/simulation-load";
const UnitIcon = ({id, type}) => (
<div>
@@ -12,41 +13,50 @@ const UnitIcon = ({id, type}) => (
</div>
);
-const MachineComponent = ({position, machine, onClick}) => (
- <li
- className="d-flex list-group-item list-group-item-action justify-content-between align-items-center"
- onClick={onClick}
- >
- <span className="badge badge-default badge-info mr-1">
- {position}
- </span>
- <div className="d-inline-flex">
- {machine.cpuIds.length > 0 ?
- <UnitIcon id="cpu" type="CPU"/> :
- undefined
- }
- {machine.gpuIds.length > 0 ?
- <UnitIcon id="gpu" type="GPU"/> :
- undefined
- }
- {machine.memoryIds.length > 0 ?
- <UnitIcon id="memory" type="memory"/> :
- undefined
- }
- {machine.storageIds.length > 0 ?
- <UnitIcon id="storage" type="storage"/> :
- undefined
- }
- {machine.cpuIds.length + machine.gpuIds.length + machine.memoryIds.length
- + machine.storageIds.length === 0 ?
- <span className="badge badge-default badge-warning">
- Machine with no units
- </span> :
- undefined
- }
- </div>
- </li>
-);
+const MachineComponent = ({position, machine, inSimulation, machineLoad, onClick}) => {
+ let color = "white";
+ if (inSimulation) {
+ color = convertLoadToSimulationColor(machineLoad);
+ }
+ const hasNoUnits = machine.cpuIds.length + machine.gpuIds.length + machine.memoryIds.length
+ + machine.storageIds.length === 0;
+
+ return (
+ <li
+ className="d-flex list-group-item list-group-item-action justify-content-between align-items-center"
+ onClick={onClick}
+ style={{backgroundColor: color}}
+ >
+ <span className="badge badge-default badge-info mr-1">
+ {position}
+ </span>
+ <div className="d-inline-flex">
+ {machine.cpuIds.length > 0 ?
+ <UnitIcon id="cpu" type="CPU"/> :
+ undefined
+ }
+ {machine.gpuIds.length > 0 ?
+ <UnitIcon id="gpu" type="GPU"/> :
+ undefined
+ }
+ {machine.memoryIds.length > 0 ?
+ <UnitIcon id="memory" type="memory"/> :
+ undefined
+ }
+ {machine.storageIds.length > 0 ?
+ <UnitIcon id="storage" type="storage"/> :
+ undefined
+ }
+ {hasNoUnits ?
+ <span className="badge badge-default badge-warning">
+ Machine with no units
+ </span> :
+ undefined
+ }
+ </div>
+ </li>
+ );
+};
MachineComponent.propTypes = {
machine: Shapes.Machine
diff --git a/src/components/sidebars/topology/rack/RackSidebarComponent.js b/src/components/sidebars/topology/rack/RackSidebarComponent.js
index 007add6e..bfcc7e32 100644
--- a/src/components/sidebars/topology/rack/RackSidebarComponent.js
+++ b/src/components/sidebars/topology/rack/RackSidebarComponent.js
@@ -1,14 +1,24 @@
import React from "react";
+import LoadBarContainer from "../../../../containers/sidebars/elements/LoadBarContainer";
+import LoadChartContainer from "../../../../containers/sidebars/elements/LoadChartContainer";
import DeleteRackContainer from "../../../../containers/sidebars/topology/rack/DeleteRackContainer";
import MachineListContainer from "../../../../containers/sidebars/topology/rack/MachineListContainer";
import RackNameContainer from "../../../../containers/sidebars/topology/rack/RackNameContainer";
import "./RackSidebarComponent.css";
-const RackSidebarComponent = () => {
+const RackSidebarComponent = ({inSimulation, rackId}) => {
return (
<div className="rack-sidebar-container flex-column">
<RackNameContainer/>
- <DeleteRackContainer/>
+ {inSimulation ?
+ <div>
+ <LoadBarContainer objectType="rack" objectId={rackId}/>
+ <LoadChartContainer objectType="rack" objectId={rackId}/>
+ </div> :
+ <div>
+ <DeleteRackContainer/>
+ </div>
+ }
<div className="machine-list-container mt-2">
<MachineListContainer/>
</div>
diff --git a/src/components/sidebars/topology/room/RoomSidebarComponent.js b/src/components/sidebars/topology/room/RoomSidebarComponent.js
index a15351f9..59c5fc8f 100644
--- a/src/components/sidebars/topology/room/RoomSidebarComponent.js
+++ b/src/components/sidebars/topology/room/RoomSidebarComponent.js
@@ -1,12 +1,14 @@
import React from "react";
+import LoadBarContainer from "../../../../containers/sidebars/elements/LoadBarContainer";
+import LoadChartContainer from "../../../../containers/sidebars/elements/LoadChartContainer";
import DeleteRoomContainer from "../../../../containers/sidebars/topology/room/DeleteRoomContainer";
import RackConstructionContainer from "../../../../containers/sidebars/topology/room/RackConstructionContainer";
import RoomNameContainer from "../../../../containers/sidebars/topology/room/RoomNameContainer";
import RoomTypeContainer from "../../../../containers/sidebars/topology/room/RoomTypeContainer";
-const RoomSidebarComponent = ({roomType}) => {
+const RoomSidebarComponent = ({roomId, roomType, inSimulation}) => {
let allowedObjects;
- if (roomType === "SERVER") {
+ if (!inSimulation && roomType === "SERVER") {
allowedObjects = <RackConstructionContainer/>;
}
@@ -14,8 +16,16 @@ const RoomSidebarComponent = ({roomType}) => {
<div>
<RoomNameContainer/>
<RoomTypeContainer/>
- {allowedObjects}
- <DeleteRoomContainer/>
+ {inSimulation ?
+ <div>
+ <LoadBarContainer objectType="room" objectId={roomId}/>
+ <LoadChartContainer objectType="room" objectId={roomId}/>
+ </div> :
+ <div>
+ {allowedObjects}
+ <DeleteRoomContainer/>
+ </div>
+ }
</div>
);
};
diff --git a/src/components/simulations/FilterButton.js b/src/components/simulations/FilterButton.js
index f95c35fa..b26dd231 100644
--- a/src/components/simulations/FilterButton.js
+++ b/src/components/simulations/FilterButton.js
@@ -5,10 +5,10 @@ import React from 'react';
const FilterButton = ({active, children, onClick}) => (
<button className={classNames("btn btn-secondary", {"active": active})}
onClick={() => {
- if (!active) {
- onClick();
- }
- }}>
+ if (!active) {
+ onClick();
+ }
+ }}>
{children}
</button>
);
diff --git a/src/containers/map/DatacenterContainer.js b/src/containers/map/DatacenterContainer.js
index 8c80146d..b56adbac 100644
--- a/src/containers/map/DatacenterContainer.js
+++ b/src/containers/map/DatacenterContainer.js
@@ -8,7 +8,7 @@ const mapStateToProps = state => {
return {
datacenter: state.objects.datacenter[state.currentDatacenterId],
- interactionLevel: state.interactionLevel
+ interactionLevel: state.interactionLevel,
};
};
diff --git a/src/containers/map/RackContainer.js b/src/containers/map/RackContainer.js
new file mode 100644
index 00000000..60df9aaf
--- /dev/null
+++ b/src/containers/map/RackContainer.js
@@ -0,0 +1,26 @@
+import {connect} from "react-redux";
+import RackGroup from "../../components/map/groups/RackGroup";
+import {getStateLoad} from "../../util/simulation-load";
+
+const mapStateToProps = (state, ownProps) => {
+ const inSimulation = state.currentExperimentId !== -1;
+
+ let rackLoad = undefined;
+ if (inSimulation) {
+ if (state.states.rack[state.currentTick] && state.states.rack[state.currentTick][ownProps.tile.objectId]) {
+ rackLoad = getStateLoad(state.loadMetric, state.states.rack[state.currentTick][ownProps.tile.objectId]);
+ }
+ }
+
+ return {
+ interactionLevel: state.interactionLevel,
+ inSimulation,
+ rackLoad,
+ };
+};
+
+const RackContainer = connect(
+ mapStateToProps
+)(RackGroup);
+
+export default RackContainer;
diff --git a/src/containers/map/TileContainer.js b/src/containers/map/TileContainer.js
index 9e98636a..75fac5ad 100644
--- a/src/containers/map/TileContainer.js
+++ b/src/containers/map/TileContainer.js
@@ -1,11 +1,24 @@
import {connect} from "react-redux";
import {goFromRoomToRack} from "../../actions/interaction-level";
import TileGroup from "../../components/map/groups/TileGroup";
+import {getStateLoad} from "../../util/simulation-load";
const mapStateToProps = (state, ownProps) => {
+ const tile = state.objects.tile[ownProps.tileId];
+ const inSimulation = state.currentExperimentId !== -1;
+
+ let roomLoad = undefined;
+ if (inSimulation) {
+ if (state.states.room[state.currentTick] && state.states.room[state.currentTick][tile.roomId]) {
+ roomLoad = getStateLoad(state.loadMetric, state.states.room[state.currentTick][tile.roomId]);
+ }
+ }
+
return {
interactionLevel: state.interactionLevel,
- tile: state.objects.tile[ownProps.tileId],
+ tile,
+ inSimulation,
+ roomLoad,
};
};
diff --git a/src/containers/sidebars/elements/LoadBarContainer.js b/src/containers/sidebars/elements/LoadBarContainer.js
new file mode 100644
index 00000000..08aec93c
--- /dev/null
+++ b/src/containers/sidebars/elements/LoadBarContainer.js
@@ -0,0 +1,25 @@
+import {connect} from "react-redux";
+import LoadBarComponent from "../../../components/sidebars/elements/LoadBarComponent";
+import {getStateLoad} from "../../../util/simulation-load";
+
+const mapStateToProps = (state, ownProps) => {
+ let percent = 0;
+ let enabled = false;
+
+ const objectStates = state.states[ownProps.objectType];
+ if (objectStates[state.currentTick] && objectStates[state.currentTick][ownProps.objectId]) {
+ percent = Math.floor(100 * getStateLoad(state.loadMetric, objectStates[state.currentTick][ownProps.objectId]));
+ enabled = true;
+ }
+
+ return {
+ percent,
+ enabled
+ };
+};
+
+const LoadBarContainer = connect(
+ mapStateToProps
+)(LoadBarComponent);
+
+export default LoadBarContainer;
diff --git a/src/containers/sidebars/elements/LoadChartContainer.js b/src/containers/sidebars/elements/LoadChartContainer.js
new file mode 100644
index 00000000..7d8b10e5
--- /dev/null
+++ b/src/containers/sidebars/elements/LoadChartContainer.js
@@ -0,0 +1,26 @@
+import {connect} from "react-redux";
+import LoadChartComponent from "../../../components/sidebars/elements/LoadChartComponent";
+import {getStateLoad} from "../../../util/simulation-load";
+
+const mapStateToProps = (state, ownProps) => {
+ const data = [];
+
+ if (state.lastSimulatedTick !== -1) {
+ const objectStates = state.states[ownProps.objectType];
+ Object.keys(objectStates).forEach(tick => {
+ if (objectStates[tick][ownProps.objectId]) {
+ data.push({x: tick, y: getStateLoad(state.loadMetric, objectStates[tick][ownProps.objectId])});
+ }
+ });
+ }
+
+ return {
+ data
+ };
+};
+
+const LoadChartContainer = connect(
+ mapStateToProps
+)(LoadChartComponent);
+
+export default LoadChartContainer;
diff --git a/src/containers/sidebars/topology/building/BuildingSidebarContainer.js b/src/containers/sidebars/topology/building/BuildingSidebarContainer.js
index a91ad5ef..a3e09149 100644
--- a/src/containers/sidebars/topology/building/BuildingSidebarContainer.js
+++ b/src/containers/sidebars/topology/building/BuildingSidebarContainer.js
@@ -3,7 +3,7 @@ import BuildingSidebarComponent from "../../../../components/sidebars/topology/b
const mapStateToProps = state => {
return {
- currentRoomInConstruction: state.construction.currentRoomInConstruction
+ inSimulation: state.construction.currentExperimentId !== -1
};
};
diff --git a/src/containers/sidebars/topology/building/CancelNewRoomConstructionButton.js b/src/containers/sidebars/topology/building/CancelNewRoomConstructionButton.js
deleted file mode 100644
index 399c7a0d..00000000
--- a/src/containers/sidebars/topology/building/CancelNewRoomConstructionButton.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import {connect} from "react-redux";
-import {cancelNewRoomConstruction} from "../../../../actions/topology/building";
-import CancelNewRoomConstructionComponent from "../../../../components/sidebars/topology/building/CancelNewRoomConstructionComponent";
-
-const mapDispatchToProps = dispatch => {
- return {
- onClick: () => dispatch(cancelNewRoomConstruction()),
- };
-};
-
-const CancelNewRoomConstructionButton = connect(
- null,
- mapDispatchToProps
-)(CancelNewRoomConstructionComponent);
-
-export default CancelNewRoomConstructionButton;
diff --git a/src/containers/sidebars/topology/building/FinishNewRoomConstructionButton.js b/src/containers/sidebars/topology/building/FinishNewRoomConstructionButton.js
deleted file mode 100644
index 8fc192e0..00000000
--- a/src/containers/sidebars/topology/building/FinishNewRoomConstructionButton.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import {connect} from "react-redux";
-import {finishNewRoomConstruction} from "../../../../actions/topology/building";
-import FinishNewRoomConstructionComponent from "../../../../components/sidebars/topology/building/FinishNewRoomConstructionComponent";
-
-const mapDispatchToProps = dispatch => {
- return {
- onClick: () => dispatch(finishNewRoomConstruction()),
- };
-};
-
-const FinishNewRoomConstructionButton = connect(
- null,
- mapDispatchToProps
-)(FinishNewRoomConstructionComponent);
-
-export default FinishNewRoomConstructionButton;
diff --git a/src/containers/sidebars/topology/building/NewRoomConstructionContainer.js b/src/containers/sidebars/topology/building/NewRoomConstructionContainer.js
new file mode 100644
index 00000000..0236522d
--- /dev/null
+++ b/src/containers/sidebars/topology/building/NewRoomConstructionContainer.js
@@ -0,0 +1,28 @@
+import {connect} from "react-redux";
+import {
+ cancelNewRoomConstruction,
+ finishNewRoomConstruction,
+ startNewRoomConstruction
+} from "../../../../actions/topology/building";
+import StartNewRoomConstructionComponent from "../../../../components/sidebars/topology/building/NewRoomConstructionComponent";
+
+const mapStateToProps = state => {
+ return {
+ currentRoomInConstruction: state.construction.currentRoomInConstruction
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onStart: () => dispatch(startNewRoomConstruction()),
+ onFinish: () => dispatch(finishNewRoomConstruction()),
+ onCancel: () => dispatch(cancelNewRoomConstruction()),
+ };
+};
+
+const NewRoomConstructionButton = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(StartNewRoomConstructionComponent);
+
+export default NewRoomConstructionButton;
diff --git a/src/containers/sidebars/topology/building/StartNewRoomConstructionButton.js b/src/containers/sidebars/topology/building/StartNewRoomConstructionButton.js
deleted file mode 100644
index c2c9808a..00000000
--- a/src/containers/sidebars/topology/building/StartNewRoomConstructionButton.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import {connect} from "react-redux";
-import {startNewRoomConstruction} from "../../../../actions/topology/building";
-import StartNewRoomConstructionComponent from "../../../../components/sidebars/topology/building/StartNewRoomConstructionComponent";
-
-const mapDispatchToProps = dispatch => {
- return {
- onClick: () => dispatch(startNewRoomConstruction()),
- };
-};
-
-const StartNewRoomConstructionButton = connect(
- null,
- mapDispatchToProps
-)(StartNewRoomConstructionComponent);
-
-export default StartNewRoomConstructionButton;
diff --git a/src/containers/sidebars/topology/machine/MachineSidebarContainer.js b/src/containers/sidebars/topology/machine/MachineSidebarContainer.js
new file mode 100644
index 00000000..b0d5eed9
--- /dev/null
+++ b/src/containers/sidebars/topology/machine/MachineSidebarContainer.js
@@ -0,0 +1,15 @@
+import {connect} from "react-redux";
+import MachineSidebarComponent from "../../../../components/sidebars/topology/machine/MachineSidebarComponent";
+
+const mapStateToProps = state => {
+ return {
+ machineId: state.interactionLevel.machineId,
+ inSimulation: state.currentExperimentId !== -1,
+ };
+};
+
+const MachineSidebarContainer = connect(
+ mapStateToProps
+)(MachineSidebarComponent);
+
+export default MachineSidebarContainer;
diff --git a/src/containers/sidebars/topology/rack/MachineContainer.js b/src/containers/sidebars/topology/rack/MachineContainer.js
index 21ab06c4..7406d191 100644
--- a/src/containers/sidebars/topology/rack/MachineContainer.js
+++ b/src/containers/sidebars/topology/rack/MachineContainer.js
@@ -1,10 +1,23 @@
import {connect} from "react-redux";
import {goFromRackToMachine} from "../../../../actions/interaction-level";
import MachineComponent from "../../../../components/sidebars/topology/rack/MachineComponent";
+import {getStateLoad} from "../../../../util/simulation-load";
const mapStateToProps = (state, ownProps) => {
+ const machine = state.objects.machine[ownProps.machineId];
+ const inSimulation = state.currentExperimentId !== -1;
+
+ let machineLoad = undefined;
+ if (inSimulation) {
+ if (state.states.machine[state.currentTick] && state.states.machine[state.currentTick][machine.id]) {
+ machineLoad = getStateLoad(state.loadMetric, state.states.machine[state.currentTick][machine.id]);
+ }
+ }
+
return {
- machine: state.objects.machine[ownProps.machineId],
+ machine,
+ inSimulation,
+ machineLoad
};
};
diff --git a/src/containers/sidebars/topology/rack/RackSidebarContainer.js b/src/containers/sidebars/topology/rack/RackSidebarContainer.js
new file mode 100644
index 00000000..4652b968
--- /dev/null
+++ b/src/containers/sidebars/topology/rack/RackSidebarContainer.js
@@ -0,0 +1,15 @@
+import {connect} from "react-redux";
+import RackSidebarComponent from "../../../../components/sidebars/topology/rack/RackSidebarComponent";
+
+const mapStateToProps = state => {
+ return {
+ rackId: state.objects.tile[state.interactionLevel.tileId].objectId,
+ inSimulation: state.currentExperimentId !== -1,
+ };
+};
+
+const RackSidebarContainer = connect(
+ mapStateToProps
+)(RackSidebarComponent);
+
+export default RackSidebarContainer;
diff --git a/src/containers/sidebars/topology/room/RoomSidebarContainer.js b/src/containers/sidebars/topology/room/RoomSidebarContainer.js
index b7ded316..6dded3e7 100644
--- a/src/containers/sidebars/topology/room/RoomSidebarContainer.js
+++ b/src/containers/sidebars/topology/room/RoomSidebarContainer.js
@@ -3,7 +3,9 @@ import RoomSidebarComponent from "../../../../components/sidebars/topology/room/
const mapStateToProps = state => {
return {
+ roomId: state.interactionLevel.roomId,
roomType: state.objects.room[state.interactionLevel.roomId].roomType,
+ inSimulation: state.currentExperimentId !== -1,
};
};
diff --git a/src/reducers/construction.js b/src/reducers/construction-mode.js
index 3e0b7542..3e0b7542 100644
--- a/src/reducers/construction.js
+++ b/src/reducers/construction-mode.js
diff --git a/src/reducers/topology.js b/src/reducers/current-ids.js
index f98b50e7..c94d7861 100644
--- a/src/reducers/topology.js
+++ b/src/reducers/current-ids.js
@@ -1,3 +1,4 @@
+import {OPEN_SIMULATION_SUCCEEDED} from "../actions/simulations";
import {FETCH_LATEST_DATACENTER_SUCCEEDED, RESET_CURRENT_DATACENTER} from "../actions/topology/building";
export function currentDatacenterId(state = -1, action) {
@@ -10,3 +11,13 @@ export function currentDatacenterId(state = -1, action) {
return state;
}
}
+
+export function currentSimulationId(state = -1, action) {
+ switch (action.type) {
+ case OPEN_SIMULATION_SUCCEEDED:
+ return action.id;
+ default:
+ return state;
+ }
+}
+
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 1f3aa8f2..a9b6bf34 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -1,24 +1,30 @@
import {combineReducers} from "redux";
import {auth} from "./auth";
-import {construction} from "./construction";
+import {construction} from "./construction-mode";
+import {currentDatacenterId, currentSimulationId} from "./current-ids";
import {interactionLevel} from "./interaction-level";
import {map} from "./map";
import {modals} from "./modals";
import {objects} from "./objects";
import {simulationList} from "./simulation-list";
-import {currentSimulationId} from "./simulations";
-import {currentDatacenterId} from "./topology";
+import {currentExperimentId, currentTick, isPlaying, loadMetric} from "./simulation-mode";
+import {states} from "./states";
const rootReducer = combineReducers({
- auth,
objects,
+ states,
modals,
simulationList,
+ construction,
+ map,
currentSimulationId,
currentDatacenterId,
+ currentExperimentId,
+ currentTick,
+ loadMetric,
+ isPlaying,
interactionLevel,
- construction,
- map,
+ auth,
});
export default rootReducer;
diff --git a/src/reducers/simulation-mode.js b/src/reducers/simulation-mode.js
new file mode 100644
index 00000000..da6aa94a
--- /dev/null
+++ b/src/reducers/simulation-mode.js
@@ -0,0 +1,50 @@
+import {OPEN_EXPERIMENT_SUCCEEDED} from "../actions/experiments";
+import {CHANGE_LOAD_METRIC} from "../actions/simulation/load-metric";
+import {SET_PLAYING} from "../actions/simulation/playback";
+import {GO_TO_TICK, SET_LAST_SIMULATED_TICK} from "../actions/simulation/tick";
+
+export function currentExperimentId(state = -1, action) {
+ switch (action.type) {
+ case OPEN_EXPERIMENT_SUCCEEDED:
+ return action.id;
+ default:
+ return state;
+ }
+}
+
+export function currentTick(state = 0, action) {
+ switch (action.type) {
+ case GO_TO_TICK:
+ return action.tick;
+ default:
+ return state;
+ }
+}
+
+export function loadMetric(state = "LOAD", action) {
+ switch (action.type) {
+ case CHANGE_LOAD_METRIC:
+ return action.metric;
+ default:
+ return state;
+ }
+}
+
+export function isPlaying(state = false, action) {
+ switch (action.type) {
+ case SET_PLAYING:
+ return action.playing;
+ default:
+ return state;
+ }
+}
+
+export function lastSimulatedTick(state = -1, action) {
+ switch (action.type) {
+ case SET_LAST_SIMULATED_TICK:
+ return action.tick;
+ default:
+ return state;
+ }
+}
+
diff --git a/src/reducers/simulations.js b/src/reducers/simulations.js
deleted file mode 100644
index e15c2d21..00000000
--- a/src/reducers/simulations.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import {OPEN_SIMULATION_SUCCEEDED} from "../actions/simulations";
-
-export function currentSimulationId(state = -1, action) {
- switch (action.type) {
- case OPEN_SIMULATION_SUCCEEDED:
- return action.id;
- default:
- return state;
- }
-}
diff --git a/src/reducers/states.js b/src/reducers/states.js
new file mode 100644
index 00000000..a9eb4ce8
--- /dev/null
+++ b/src/reducers/states.js
@@ -0,0 +1,33 @@
+import {combineReducers} from "redux";
+import {ADD_TO_STATES} from "../actions/states";
+
+export const states = combineReducers({
+ task: objectStates("task"),
+ room: objectStates("room"),
+ rack: objectStates("rack"),
+ machine: objectStates("machine"),
+});
+
+function objectStates(type) {
+ return (state = {}, action) => {
+ if (action.objectType !== type) {
+ return state;
+ }
+
+ if (action.type === ADD_TO_STATES) {
+ return Object.assign(
+ {},
+ state,
+ {
+ [action.tick]: Object.assign(
+ {},
+ state[action.tick],
+ {[action.object.id]: action.object}
+ )
+ }
+ );
+ }
+
+ return state;
+ };
+}
diff --git a/src/util/simulation-load.js b/src/util/simulation-load.js
new file mode 100644
index 00000000..224dc6f4
--- /dev/null
+++ b/src/util/simulation-load.js
@@ -0,0 +1,26 @@
+import {SIM_HIGH_COLOR, SIM_LOW_COLOR, SIM_MID_HIGH_COLOR, SIM_MID_LOW_COLOR} from "../colors/index";
+
+export function convertLoadToSimulationColor(load) {
+ if (load <= 0.25) {
+ return SIM_LOW_COLOR;
+ } else if (load <= 0.5) {
+ return SIM_MID_LOW_COLOR;
+ } else if (load <= 0.75) {
+ return SIM_MID_HIGH_COLOR;
+ } else {
+ return SIM_HIGH_COLOR;
+ }
+}
+
+export function getStateLoad(loadMetric, state) {
+ switch (loadMetric) {
+ case "LOAD":
+ return state.loadFraction;
+ case "TEMPERATURE":
+ return state.temperatureC / 100.0;
+ case "MEMORY":
+ return state.inUseMemoryMb / 10000.0;
+ default:
+ return 0;
+ }
+}