summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-07 11:38:42 +0200
committerGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-23 10:05:58 +0200
commite9909159dc5db91eda12437e18c1474cae848af7 (patch)
treef34e0ca56b666f6a4ab1022e58a6dcd84b779725
parentd5a92d3006561fd631279b68b23a1f8075b28bb8 (diff)
Implement first machine slot listing
-rw-r--r--src/actions/interaction-level.js6
-rw-r--r--src/actions/modals/topology.js28
-rw-r--r--src/actions/topology.js63
-rw-r--r--src/components/map/groups/RoomGroup.js2
-rw-r--r--src/components/sidebars/Sidebar.js2
-rw-r--r--src/components/sidebars/Sidebar.sass1
-rw-r--r--src/components/sidebars/topology/TopologySidebarComponent.js4
-rw-r--r--src/components/sidebars/topology/rack/DeleteRackComponent.js11
-rw-r--r--src/components/sidebars/topology/rack/EmptySlotComponent.js16
-rw-r--r--src/components/sidebars/topology/rack/MachineComponent.js28
-rw-r--r--src/components/sidebars/topology/rack/MachineListComponent.js19
-rw-r--r--src/components/sidebars/topology/rack/RackNameComponent.js8
-rw-r--r--src/components/sidebars/topology/rack/RackSidebarComponent.js16
-rw-r--r--src/components/sidebars/topology/room/RackConstructionComponent.js4
-rw-r--r--src/containers/map/TileContainer.js4
-rw-r--r--src/containers/map/layers/ObjectHoverLayer.js2
-rw-r--r--src/containers/modals/DeleteRackModal.js36
-rw-r--r--src/containers/modals/EditRackNameModal.js39
-rw-r--r--src/containers/sidebars/topology/rack/DeleteRackContainer.js16
-rw-r--r--src/containers/sidebars/topology/rack/EmptySlotContainer.js16
-rw-r--r--src/containers/sidebars/topology/rack/MachineContainer.js21
-rw-r--r--src/containers/sidebars/topology/rack/MachineListContainer.js14
-rw-r--r--src/containers/sidebars/topology/rack/RackNameContainer.js22
-rw-r--r--src/containers/sidebars/topology/room/RackConstructionContainer.js8
-rw-r--r--src/pages/App.js4
-rw-r--r--src/reducers/construction.js12
-rw-r--r--src/reducers/interaction-level.js8
-rw-r--r--src/reducers/modals.js6
-rw-r--r--src/sagas/index.js9
-rw-r--r--src/sagas/topology.js86
-rw-r--r--src/util/date-time.js6
31 files changed, 480 insertions, 37 deletions
diff --git a/src/actions/interaction-level.js b/src/actions/interaction-level.js
index 884f1988..5ceff500 100644
--- a/src/actions/interaction-level.js
+++ b/src/actions/interaction-level.js
@@ -1,5 +1,5 @@
export const GO_FROM_BUILDING_TO_ROOM = "GO_FROM_BUILDING_TO_ROOM";
-export const GO_FROM_ROOM_TO_OBJECT = "GO_FROM_ROOM_TO_OBJECT";
+export const GO_FROM_ROOM_TO_RACK = "GO_FROM_ROOM_TO_RACK";
export const GO_DOWN_ONE_INTERACTION_LEVEL = "GO_DOWN_ONE_INTERACTION_LEVEL";
export function goFromBuildingToRoom(roomId) {
@@ -16,14 +16,14 @@ export function goFromBuildingToRoom(roomId) {
};
}
-export function goFromRoomToObject(tileId) {
+export function goFromRoomToRack(tileId) {
return (dispatch, getState) => {
const {interactionLevel} = getState();
if (interactionLevel.mode !== "ROOM") {
return;
}
dispatch({
- type: GO_FROM_ROOM_TO_OBJECT,
+ type: GO_FROM_ROOM_TO_RACK,
tileId
});
};
diff --git a/src/actions/modals/topology.js b/src/actions/modals/topology.js
index ded8771a..507c1de6 100644
--- a/src/actions/modals/topology.js
+++ b/src/actions/modals/topology.js
@@ -2,6 +2,10 @@ 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";
export const CLOSE_DELETE_ROOM_MODAL = "CLOSE_DELETE_ROOM_MODAL";
+export const OPEN_EDIT_RACK_NAME_MODAL = "OPEN_EDIT_RACK_NAME_MODAL";
+export const CLOSE_EDIT_RACK_NAME_MODAL = "CLOSE_EDIT_RACK_NAME_MODAL";
+export const OPEN_DELETE_RACK_MODAL = "OPEN_DELETE_RACK_MODAL";
+export const CLOSE_DELETE_RACK_MODAL = "CLOSE_DELETE_RACK_MODAL";
export function openEditRoomNameModal() {
return {
@@ -26,3 +30,27 @@ export function closeDeleteRoomModal() {
type: CLOSE_DELETE_ROOM_MODAL
};
}
+
+export function openEditRackNameModal() {
+ return {
+ type: OPEN_EDIT_RACK_NAME_MODAL
+ };
+}
+
+export function closeEditRackNameModal() {
+ return {
+ type: CLOSE_EDIT_RACK_NAME_MODAL
+ };
+}
+
+export function openDeleteRackModal() {
+ return {
+ type: OPEN_DELETE_RACK_MODAL
+ };
+}
+
+export function closeDeleteRackModal() {
+ return {
+ type: CLOSE_DELETE_RACK_MODAL
+ };
+}
diff --git a/src/actions/topology.js b/src/actions/topology.js
index ec614c1c..4d9f1e52 100644
--- a/src/actions/topology.js
+++ b/src/actions/topology.js
@@ -16,10 +16,12 @@ export const ADD_TILE = "ADD_TILE";
export const DELETE_TILE = "DELETE_TILE";
export const EDIT_ROOM_NAME = "EDIT_ROOM_NAME";
export const DELETE_ROOM = "DELETE_ROOM";
-export const START_OBJECT_CONSTRUCTION = "START_OBJECT_CONSTRUCTION";
-export const STOP_OBJECT_CONSTRUCTION = "STOP_OBJECT_CONSTRUCTION";
+export const EDIT_RACK_NAME = "EDIT_RACK_NAME";
+export const DELETE_RACK = "DELETE_RACK";
+export const START_RACK_CONSTRUCTION = "START_RACK_CONSTRUCTION";
+export const STOP_RACK_CONSTRUCTION = "STOP_RACK_CONSTRUCTION";
export const ADD_RACK_TO_TILE = "ADD_RACK_TO_TILE";
-export const ADD_RACK_TO_TILE_SUCCEEDED = "ADD_RACK_TO_TILE_SUCCEEDED";
+export const ADD_MACHINE = "ADD_MACHINE";
export function fetchLatestDatacenter() {
return (dispatch, getState) => {
@@ -151,15 +153,15 @@ export function editRoomNameSucceeded(name) {
};
}
-export function startObjectConstruction() {
+export function startRackConstruction() {
return {
- type: START_OBJECT_CONSTRUCTION
+ type: START_RACK_CONSTRUCTION
};
}
-export function stopObjectConstruction() {
+export function stopRackConstruction() {
return {
- type: STOP_OBJECT_CONSTRUCTION
+ type: STOP_RACK_CONSTRUCTION
};
}
@@ -200,3 +202,50 @@ export function deleteRoomSucceeded() {
dispatch(removeIdFromStoreObjectListProp("datacenter", currentDatacenterId, "roomIds", currentRoomId));
};
}
+
+export function editRackName(name) {
+ return {
+ type: EDIT_RACK_NAME,
+ name
+ };
+}
+
+export function editRackNameSucceeded(name) {
+ return (dispatch, getState) => {
+ const {objects, interactionLevel} = getState();
+ dispatch(addPropToStoreObject("rack", objects.tile[interactionLevel.tileId].objectId, {name}));
+ };
+}
+
+export function deleteRack() {
+ return {
+ type: DELETE_RACK
+ };
+}
+
+export function deleteRackSucceeded() {
+ return (dispatch, getState) => {
+ const {interactionLevel} = getState();
+ const currentTileId = interactionLevel.tileId;
+ dispatch(goDownOneInteractionLevel());
+ dispatch(addPropToStoreObject("tile", currentTileId, {objectType: undefined}));
+ dispatch(addPropToStoreObject("tile", currentTileId, {objectId: undefined}));
+ };
+}
+
+export function addMachine(position) {
+ return {
+ type: ADD_MACHINE,
+ position
+ };
+}
+
+export function addMachineSucceeded(machine) {
+ return (dispatch, getState) => {
+ const {objects, interactionLevel} = getState();
+ const rack = objects.rack[objects.tile[interactionLevel.tileId].objectId];
+ const machineIds = [...rack.machineIds];
+ machineIds[machine.position] = machine.id;
+ dispatch(addPropToStoreObject("rack", rack.id, {machineIds}));
+ };
+}
diff --git a/src/components/map/groups/RoomGroup.js b/src/components/map/groups/RoomGroup.js
index 85d3c7c9..1c42106a 100644
--- a/src/components/map/groups/RoomGroup.js
+++ b/src/components/map/groups/RoomGroup.js
@@ -19,7 +19,7 @@ const RoomGroup = ({room, interactionLevel, currentRoomInConstruction, onClick})
return (
<Group onClick={onClick}>
{(() => {
- if (interactionLevel.mode === "OBJECT" && interactionLevel.roomId === room.id) {
+ if (interactionLevel.mode === "RACK" && interactionLevel.roomId === room.id) {
return [
room.tileIds
.filter(tileId => tileId !== interactionLevel.tileId)
diff --git a/src/components/sidebars/Sidebar.js b/src/components/sidebars/Sidebar.js
index be957956..2f4d77a7 100644
--- a/src/components/sidebars/Sidebar.js
+++ b/src/components/sidebars/Sidebar.js
@@ -3,7 +3,7 @@ import React from "react";
import "./Sidebar.css";
const Sidebar = ({isRight, children}) => (
- <div className={classNames("sidebar p-3", {"sidebar-right": isRight})}>
+ <div className={classNames("sidebar p-3 h-100", {"sidebar-right": isRight})}>
{children}
</div>
);
diff --git a/src/components/sidebars/Sidebar.sass b/src/components/sidebars/Sidebar.sass
index 79ea3c27..16a6d48f 100644
--- a/src/components/sidebars/Sidebar.sass
+++ b/src/components/sidebars/Sidebar.sass
@@ -5,7 +5,6 @@
top: 0
left: 0
width: 300px
- height: 100%
z-index: 100
background: white
diff --git a/src/components/sidebars/topology/TopologySidebarComponent.js b/src/components/sidebars/topology/TopologySidebarComponent.js
index dc4dc231..bc23d320 100644
--- a/src/components/sidebars/topology/TopologySidebarComponent.js
+++ b/src/components/sidebars/topology/TopologySidebarComponent.js
@@ -2,6 +2,7 @@ import React from "react";
import BuildingSidebarContainer from "../../../containers/sidebars/topology/building/BuildingSidebarContainer";
import RoomSidebarContainer from "../../../containers/sidebars/topology/room/RoomSidebarContainer";
import Sidebar from "../Sidebar";
+import RackSidebarComponent from "./rack/RackSidebarComponent";
const TopologySidebarComponent = ({interactionLevel}) => {
let sidebarContent;
@@ -13,6 +14,9 @@ const TopologySidebarComponent = ({interactionLevel}) => {
case "ROOM":
sidebarContent = <RoomSidebarContainer/>;
break;
+ case "RACK":
+ sidebarContent = <RackSidebarComponent/>;
+ break;
default:
sidebarContent = "Missing Content";
}
diff --git a/src/components/sidebars/topology/rack/DeleteRackComponent.js b/src/components/sidebars/topology/rack/DeleteRackComponent.js
new file mode 100644
index 00000000..555f6d02
--- /dev/null
+++ b/src/components/sidebars/topology/rack/DeleteRackComponent.js
@@ -0,0 +1,11 @@
+import React from "react";
+
+const DeleteRackComponent = ({onClick}) => {
+ return (
+ <div className="btn btn-danger btn-block" onClick={onClick}>
+ Delete this rack
+ </div>
+ );
+};
+
+export default DeleteRackComponent;
diff --git a/src/components/sidebars/topology/rack/EmptySlotComponent.js b/src/components/sidebars/topology/rack/EmptySlotComponent.js
new file mode 100644
index 00000000..5234ee63
--- /dev/null
+++ b/src/components/sidebars/topology/rack/EmptySlotComponent.js
@@ -0,0 +1,16 @@
+import React from "react";
+import FontAwesome from "react-fontawesome";
+
+const EmptySlotComponent = ({position, onAdd}) => (
+ <li className="list-group-item justify-content-between">
+ <span className="badge badge-default badge-info">
+ {position}
+ </span>
+ Add machine
+ <button className="btn btn-secondary" onClick={onAdd}>
+ <FontAwesome name="plus"/>
+ </button>
+ </li>
+);
+
+export default EmptySlotComponent;
diff --git a/src/components/sidebars/topology/rack/MachineComponent.js b/src/components/sidebars/topology/rack/MachineComponent.js
new file mode 100644
index 00000000..e328951e
--- /dev/null
+++ b/src/components/sidebars/topology/rack/MachineComponent.js
@@ -0,0 +1,28 @@
+import React from "react";
+import Shapes from "../../../../shapes";
+
+const MachineComponent = ({position, machine, onClick}) => (
+ <li className="list-group-item list-group-item-action justify-content-between" onClick={onClick}>
+ <span className="badge badge-default badge-info">
+ {position}
+ </span>
+ <span className="badge badge-primary badge-pill">
+ {machine.cpuIds.length} CPUs
+ </span>
+ <span className="badge badge-warning badge-pill">
+ {machine.gpuIds.length} GPUs
+ </span>
+ <span className="badge badge-success badge-pill">
+ {machine.memoryIds.length} Memories
+ </span>
+ <span className="badge badge-info badge-pill">
+ {machine.storageIds.length} Storages
+ </span>
+ </li>
+);
+
+MachineComponent.propTypes = {
+ machine: Shapes.Machine
+};
+
+export default MachineComponent;
diff --git a/src/components/sidebars/topology/rack/MachineListComponent.js b/src/components/sidebars/topology/rack/MachineListComponent.js
new file mode 100644
index 00000000..d8a31ddc
--- /dev/null
+++ b/src/components/sidebars/topology/rack/MachineListComponent.js
@@ -0,0 +1,19 @@
+import React from "react";
+import EmptySlotContainer from "../../../../containers/sidebars/topology/rack/EmptySlotContainer";
+import MachineContainer from "../../../../containers/sidebars/topology/rack/MachineContainer";
+
+const MachineListComponent = ({machineIds}) => {
+ return (
+ <ul className="list-group">
+ {machineIds.map((machineId, index) => {
+ if (machineId === null) {
+ return <EmptySlotContainer key={index} position={index}/>;
+ } else {
+ return <MachineContainer key={index} position={index} machineId={machineId}/>;
+ }
+ })}
+ </ul>
+ );
+};
+
+export default MachineListComponent;
diff --git a/src/components/sidebars/topology/rack/RackNameComponent.js b/src/components/sidebars/topology/rack/RackNameComponent.js
new file mode 100644
index 00000000..ee8d194b
--- /dev/null
+++ b/src/components/sidebars/topology/rack/RackNameComponent.js
@@ -0,0 +1,8 @@
+import React from "react";
+import NameComponent from "../NameComponent";
+
+const RackNameComponent = ({rackName, onEdit}) => (
+ <NameComponent name={rackName} onEdit={onEdit}/>
+);
+
+export default RackNameComponent;
diff --git a/src/components/sidebars/topology/rack/RackSidebarComponent.js b/src/components/sidebars/topology/rack/RackSidebarComponent.js
new file mode 100644
index 00000000..ddb10387
--- /dev/null
+++ b/src/components/sidebars/topology/rack/RackSidebarComponent.js
@@ -0,0 +1,16 @@
+import React from "react";
+import DeleteRackContainer from "../../../../containers/sidebars/topology/rack/DeleteRackContainer";
+import MachineListContainer from "../../../../containers/sidebars/topology/rack/MachineListContainer";
+import RackNameContainer from "../../../../containers/sidebars/topology/rack/RackNameContainer";
+
+const RackSidebarComponent = () => {
+ return (
+ <div>
+ <RackNameContainer/>
+ <DeleteRackContainer/>
+ <MachineListContainer/>
+ </div>
+ );
+};
+
+export default RackSidebarComponent;
diff --git a/src/components/sidebars/topology/room/RackConstructionComponent.js b/src/components/sidebars/topology/room/RackConstructionComponent.js
index 8298eade..894ffdf7 100644
--- a/src/components/sidebars/topology/room/RackConstructionComponent.js
+++ b/src/components/sidebars/topology/room/RackConstructionComponent.js
@@ -1,7 +1,7 @@
import React from "react";
-const RackConstructionComponent = ({inObjectConstructionMode, onStart, onStop}) => {
- if (inObjectConstructionMode) {
+const RackConstructionComponent = ({inRackConstructionMode, onStart, onStop}) => {
+ if (inRackConstructionMode) {
return (
<div className="btn btn-primary btn-block" onClick={onStop}>
Stop rack construction
diff --git a/src/containers/map/TileContainer.js b/src/containers/map/TileContainer.js
index d00c3611..9e98636a 100644
--- a/src/containers/map/TileContainer.js
+++ b/src/containers/map/TileContainer.js
@@ -1,5 +1,5 @@
import {connect} from "react-redux";
-import {goFromRoomToObject} from "../../actions/interaction-level";
+import {goFromRoomToRack} from "../../actions/interaction-level";
import TileGroup from "../../components/map/groups/TileGroup";
const mapStateToProps = (state, ownProps) => {
@@ -13,7 +13,7 @@ const mapDispatchToProps = dispatch => {
return {
onClick: tile => {
if (tile.objectType) {
- dispatch(goFromRoomToObject(tile.id))
+ dispatch(goFromRoomToRack(tile.id))
}
}
};
diff --git a/src/containers/map/layers/ObjectHoverLayer.js b/src/containers/map/layers/ObjectHoverLayer.js
index e9df0384..138daa2c 100644
--- a/src/containers/map/layers/ObjectHoverLayer.js
+++ b/src/containers/map/layers/ObjectHoverLayer.js
@@ -5,7 +5,7 @@ import {findTileWithPosition} from "../../../util/tile-calculations";
const mapStateToProps = state => {
return {
- isEnabled: () => state.construction.inObjectConstructionMode,
+ isEnabled: () => state.construction.inRackConstructionMode,
isValid: (x, y) => {
if (state.interactionLevel.mode !== "ROOM") {
return false;
diff --git a/src/containers/modals/DeleteRackModal.js b/src/containers/modals/DeleteRackModal.js
new file mode 100644
index 00000000..00dd036c
--- /dev/null
+++ b/src/containers/modals/DeleteRackModal.js
@@ -0,0 +1,36 @@
+import React from "react";
+import {connect} from "react-redux";
+import {closeDeleteRackModal} from "../../actions/modals/topology";
+import {deleteRack} from "../../actions/topology";
+import ConfirmationModal from "../../components/modals/ConfirmationModal";
+
+const DeleteRackModalComponent = ({visible, callback}) => (
+ <ConfirmationModal title="Delete this rack"
+ message="Are you sure you want to delete this rack?"
+ show={visible}
+ callback={callback}/>
+);
+
+const mapStateToProps = state => {
+ return {
+ visible: state.modals.deleteRackModalVisible
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ callback: (isConfirmed) => {
+ if (isConfirmed) {
+ dispatch(deleteRack());
+ }
+ dispatch(closeDeleteRackModal());
+ }
+ };
+};
+
+const DeleteRackModal = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(DeleteRackModalComponent);
+
+export default DeleteRackModal;
diff --git a/src/containers/modals/EditRackNameModal.js b/src/containers/modals/EditRackNameModal.js
new file mode 100644
index 00000000..e793f146
--- /dev/null
+++ b/src/containers/modals/EditRackNameModal.js
@@ -0,0 +1,39 @@
+import React from "react";
+import {connect} from "react-redux";
+import {closeEditRackNameModal} from "../../actions/modals/topology";
+import {editRackName} from "../../actions/topology";
+import TextInputModal from "../../components/modals/TextInputModal";
+
+const EditRackNameModalComponent = ({visible, previousName, callback}) => (
+ <TextInputModal title="Edit rack name"
+ label="Rack name"
+ show={visible}
+ initialValue={previousName}
+ callback={callback}/>
+);
+
+const mapStateToProps = state => {
+ return {
+ visible: state.modals.editRackNameModalVisible,
+ previousName: state.interactionLevel.mode === "RACK" ?
+ state.objects.rack[state.objects.tile[state.interactionLevel.tileId].objectId].name : "",
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ callback: (name) => {
+ if (name) {
+ dispatch(editRackName(name));
+ }
+ dispatch(closeEditRackNameModal());
+ }
+ };
+};
+
+const EditRackNameModal = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(EditRackNameModalComponent);
+
+export default EditRackNameModal;
diff --git a/src/containers/sidebars/topology/rack/DeleteRackContainer.js b/src/containers/sidebars/topology/rack/DeleteRackContainer.js
new file mode 100644
index 00000000..f95c48b8
--- /dev/null
+++ b/src/containers/sidebars/topology/rack/DeleteRackContainer.js
@@ -0,0 +1,16 @@
+import {connect} from "react-redux";
+import {openDeleteRackModal} from "../../../../actions/modals/topology";
+import DeleteRackComponent from "../../../../components/sidebars/topology/rack/DeleteRackComponent";
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onClick: () => dispatch(openDeleteRackModal()),
+ };
+};
+
+const DeleteRackContainer = connect(
+ undefined,
+ mapDispatchToProps
+)(DeleteRackComponent);
+
+export default DeleteRackContainer;
diff --git a/src/containers/sidebars/topology/rack/EmptySlotContainer.js b/src/containers/sidebars/topology/rack/EmptySlotContainer.js
new file mode 100644
index 00000000..01ec6529
--- /dev/null
+++ b/src/containers/sidebars/topology/rack/EmptySlotContainer.js
@@ -0,0 +1,16 @@
+import {connect} from "react-redux";
+import {addMachine} from "../../../../actions/topology";
+import EmptySlotComponent from "../../../../components/sidebars/topology/rack/EmptySlotComponent";
+
+const mapDispatchToProps = (dispatch, ownProps) => {
+ return {
+ onAdd: () => dispatch(addMachine(ownProps.position)),
+ };
+};
+
+const EmptySlotContainer = connect(
+ undefined,
+ mapDispatchToProps
+)(EmptySlotComponent);
+
+export default EmptySlotContainer;
diff --git a/src/containers/sidebars/topology/rack/MachineContainer.js b/src/containers/sidebars/topology/rack/MachineContainer.js
new file mode 100644
index 00000000..74a0bfbc
--- /dev/null
+++ b/src/containers/sidebars/topology/rack/MachineContainer.js
@@ -0,0 +1,21 @@
+import {connect} from "react-redux";
+import MachineComponent from "../../../../components/sidebars/topology/rack/MachineComponent";
+
+const mapStateToProps = (state, ownProps) => {
+ return {
+ machine: state.objects.machine[ownProps.machineId],
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onClick: () => undefined, // TODO implement transition to MACHINE mode
+ };
+};
+
+const MachineContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(MachineComponent);
+
+export default MachineContainer;
diff --git a/src/containers/sidebars/topology/rack/MachineListContainer.js b/src/containers/sidebars/topology/rack/MachineListContainer.js
new file mode 100644
index 00000000..eef2a4e1
--- /dev/null
+++ b/src/containers/sidebars/topology/rack/MachineListContainer.js
@@ -0,0 +1,14 @@
+import {connect} from "react-redux";
+import MachineListComponent from "../../../../components/sidebars/topology/rack/MachineListComponent";
+
+const mapStateToProps = state => {
+ return {
+ machineIds: state.objects.rack[state.objects.tile[state.interactionLevel.tileId].objectId].machineIds,
+ };
+};
+
+const MachineListContainer = connect(
+ mapStateToProps
+)(MachineListComponent);
+
+export default MachineListContainer;
diff --git a/src/containers/sidebars/topology/rack/RackNameContainer.js b/src/containers/sidebars/topology/rack/RackNameContainer.js
new file mode 100644
index 00000000..34416938
--- /dev/null
+++ b/src/containers/sidebars/topology/rack/RackNameContainer.js
@@ -0,0 +1,22 @@
+import {connect} from "react-redux";
+import {openEditRackNameModal} from "../../../../actions/modals/topology";
+import RackNameComponent from "../../../../components/sidebars/topology/rack/RackNameComponent";
+
+const mapStateToProps = state => {
+ return {
+ rackName: state.objects.rack[state.objects.tile[state.interactionLevel.tileId].objectId].name,
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onEdit: () => dispatch(openEditRackNameModal()),
+ };
+};
+
+const RackNameContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(RackNameComponent);
+
+export default RackNameContainer;
diff --git a/src/containers/sidebars/topology/room/RackConstructionContainer.js b/src/containers/sidebars/topology/room/RackConstructionContainer.js
index e1a481e1..47ca43fc 100644
--- a/src/containers/sidebars/topology/room/RackConstructionContainer.js
+++ b/src/containers/sidebars/topology/room/RackConstructionContainer.js
@@ -1,17 +1,17 @@
import {connect} from "react-redux";
-import {startObjectConstruction, stopObjectConstruction} from "../../../../actions/topology";
+import {startRackConstruction, stopRackConstruction} from "../../../../actions/topology";
import RackConstructionComponent from "../../../../components/sidebars/topology/room/RackConstructionComponent";
const mapStateToProps = state => {
return {
- inObjectConstructionMode: state.construction.inObjectConstructionMode,
+ inRackConstructionMode: state.construction.inRackConstructionMode,
};
};
const mapDispatchToProps = dispatch => {
return {
- onStart: () => dispatch(startObjectConstruction()),
- onStop: () => dispatch(stopObjectConstruction()),
+ onStart: () => dispatch(startRackConstruction()),
+ onStop: () => dispatch(stopRackConstruction()),
};
};
diff --git a/src/pages/App.js b/src/pages/App.js
index 001644a2..3aaab454 100644
--- a/src/pages/App.js
+++ b/src/pages/App.js
@@ -6,7 +6,9 @@ import {openSimulationSucceeded} from "../actions/simulations";
import {fetchLatestDatacenter, resetCurrentDatacenter} from "../actions/topology";
import MapStage from "../components/map/MapStage";
import AppNavbar from "../components/navigation/AppNavbar";
+import DeleteRackModal from "../containers/modals/DeleteRackModal";
import DeleteRoomModal from "../containers/modals/DeleteRoomModal";
+import EditRackNameModal from "../containers/modals/EditRackNameModal";
import EditRoomNameModal from "../containers/modals/EditRoomNameModal";
import TopologySidebar from "../containers/sidebars/topology/TopologySidebar";
import KeymapConfiguration from "../shortcuts/keymap";
@@ -43,6 +45,8 @@ class AppContainer extends React.Component {
</div>
<EditRoomNameModal/>
<DeleteRoomModal/>
+ <EditRackNameModal/>
+ <DeleteRackModal/>
</div>
);
}
diff --git a/src/reducers/construction.js b/src/reducers/construction.js
index 33485842..772135ff 100644
--- a/src/reducers/construction.js
+++ b/src/reducers/construction.js
@@ -3,8 +3,8 @@ import {
CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
FINISH_NEW_ROOM_CONSTRUCTION,
START_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
- START_OBJECT_CONSTRUCTION,
- STOP_OBJECT_CONSTRUCTION
+ START_RACK_CONSTRUCTION,
+ STOP_RACK_CONSTRUCTION
} from "../actions/topology";
export function currentRoomInConstruction(state = -1, action) {
@@ -19,11 +19,11 @@ export function currentRoomInConstruction(state = -1, action) {
}
}
-export function inObjectConstructionMode(state = false, action) {
+export function inRackConstructionMode(state = false, action) {
switch (action.type) {
- case START_OBJECT_CONSTRUCTION:
+ case START_RACK_CONSTRUCTION:
return true;
- case STOP_OBJECT_CONSTRUCTION:
+ case STOP_RACK_CONSTRUCTION:
return false;
default:
return state;
@@ -32,5 +32,5 @@ export function inObjectConstructionMode(state = false, action) {
export const construction = combineReducers({
currentRoomInConstruction,
- inObjectConstructionMode,
+ inRackConstructionMode,
});
diff --git a/src/reducers/interaction-level.js b/src/reducers/interaction-level.js
index 5ca917c7..b6287aac 100644
--- a/src/reducers/interaction-level.js
+++ b/src/reducers/interaction-level.js
@@ -1,7 +1,7 @@
import {
GO_DOWN_ONE_INTERACTION_LEVEL,
GO_FROM_BUILDING_TO_ROOM,
- GO_FROM_ROOM_TO_OBJECT
+ GO_FROM_ROOM_TO_RACK
} from "../actions/interaction-level";
export function interactionLevel(state = {mode: "BUILDING"}, action) {
@@ -11,9 +11,9 @@ export function interactionLevel(state = {mode: "BUILDING"}, action) {
mode: "ROOM",
roomId: action.roomId
};
- case GO_FROM_ROOM_TO_OBJECT:
+ case GO_FROM_ROOM_TO_RACK:
return {
- mode: "OBJECT",
+ mode: "RACK",
roomId: state.roomId,
tileId: action.tileId
};
@@ -22,7 +22,7 @@ export function interactionLevel(state = {mode: "BUILDING"}, action) {
return {
mode: "BUILDING"
};
- } else if (state.mode === "OBJECT") {
+ } else if (state.mode === "RACK") {
return {
mode: "ROOM",
roomId: state.roomId
diff --git a/src/reducers/modals.js b/src/reducers/modals.js
index f6d1efea..7a89dae5 100644
--- a/src/reducers/modals.js
+++ b/src/reducers/modals.js
@@ -2,9 +2,13 @@ import {combineReducers} from "redux";
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_DELETE_RACK_MODAL,
CLOSE_DELETE_ROOM_MODAL,
+ CLOSE_EDIT_RACK_NAME_MODAL,
CLOSE_EDIT_ROOM_NAME_MODAL,
+ OPEN_DELETE_RACK_MODAL,
OPEN_DELETE_ROOM_MODAL,
+ OPEN_EDIT_RACK_NAME_MODAL,
OPEN_EDIT_ROOM_NAME_MODAL
} from "../actions/modals/topology";
@@ -26,4 +30,6 @@ export const modals = combineReducers({
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),
});
diff --git a/src/sagas/index.js b/src/sagas/index.js
index 024e40aa..e6c48da4 100644
--- a/src/sagas/index.js
+++ b/src/sagas/index.js
@@ -2,11 +2,14 @@ import {takeEvery} from "redux-saga/effects";
import {LOG_IN} from "../actions/auth";
import {ADD_SIMULATION, DELETE_SIMULATION} from "../actions/simulations";
import {
+ ADD_MACHINE,
ADD_RACK_TO_TILE,
ADD_TILE,
CANCEL_NEW_ROOM_CONSTRUCTION,
+ DELETE_RACK,
DELETE_ROOM,
DELETE_TILE,
+ EDIT_RACK_NAME,
EDIT_ROOM_NAME,
FETCH_LATEST_DATACENTER,
START_NEW_ROOM_CONSTRUCTION
@@ -15,11 +18,14 @@ import {DELETE_CURRENT_USER, FETCH_AUTHORIZATIONS_OF_CURRENT_USER} from "../acti
import {onDeleteCurrentUser} from "./profile";
import {onSimulationAdd, onSimulationDelete} from "./simulations";
import {
+ onAddMachine,
onAddRackToTile,
onAddTile,
onCancelNewRoomConstruction,
+ onDeleteRack,
onDeleteRoom,
onDeleteTile,
+ onEditRackName,
onEditRoomName,
onFetchLatestDatacenter,
onStartNewRoomConstruction
@@ -39,5 +45,8 @@ export default function* rootSaga() {
yield takeEvery(DELETE_TILE, onDeleteTile);
yield takeEvery(EDIT_ROOM_NAME, onEditRoomName);
yield takeEvery(DELETE_ROOM, onDeleteRoom);
+ yield takeEvery(EDIT_RACK_NAME, onEditRackName);
+ yield takeEvery(DELETE_RACK, onDeleteRack);
yield takeEvery(ADD_RACK_TO_TILE, onAddRackToTile);
+ yield takeEvery(ADD_MACHINE, onAddMachine);
}
diff --git a/src/sagas/topology.js b/src/sagas/topology.js
index ab544bbe..2ae31074 100644
--- a/src/sagas/topology.js
+++ b/src/sagas/topology.js
@@ -1,26 +1,40 @@
import {call, put, select} from "redux-saga/effects";
import {addPropToStoreObject, addToStore} from "../actions/objects";
import {
+ addMachineSucceeded,
addRackToTileSucceeded,
addTileSucceeded,
cancelNewRoomConstructionSucceeded,
+ deleteRackSucceeded,
deleteRoomSucceeded,
deleteTileSucceeded,
+ editRackNameSucceeded,
editRoomNameSucceeded,
fetchLatestDatacenterSucceeded,
startNewRoomConstructionSucceeded
} from "../actions/topology";
import {addRoomToDatacenter} from "../api/routes/datacenters";
import {addTileToRoom, deleteRoom, updateRoom} from "../api/routes/rooms";
-import {addRackToTile, deleteTile} from "../api/routes/tiles";
+import {
+ addMachineToRackOnTile,
+ addRackToTile,
+ deleteRackFromTile,
+ deleteTile,
+ updateRackOnTile
+} from "../api/routes/tiles";
import {
fetchAndStoreCoolingItem,
+ fetchAndStoreCPU,
fetchAndStoreDatacenter,
+ fetchAndStoreGPU,
+ fetchAndStoreMachinesOfTile,
+ fetchAndStoreMemory,
fetchAndStorePathsOfSimulation,
fetchAndStorePSU,
fetchAndStoreRackOnTile,
fetchAndStoreRoomsOfDatacenter,
fetchAndStoreSectionsOfPath,
+ fetchAndStoreStorage,
fetchAndStoreTilesOfRoom
} from "./objects";
@@ -69,6 +83,7 @@ function* fetchTile(tile) {
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);
@@ -79,7 +94,30 @@ function* fetchTile(tile) {
yield put(addPropToStoreObject("tile", tile.id, {psuId: psu.id}));
break;
default:
- console.warn("Unknown object type encountered while fetching tile objects");
+ 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] = machine.id);
+
+ yield put(addPropToStoreObject("rack", rack.id, {machineIds}));
+
+ for (let index in machines) {
+ for (let i in machines[index].cpuIds) {
+ yield fetchAndStoreCPU(machines[index].cpuIds[i]);
+ }
+ for (let i in machines[index].gpuIds) {
+ yield fetchAndStoreGPU(machines[index].gpuIds[i]);
+ }
+ for (let i in machines[index].memoryIds) {
+ yield fetchAndStoreMemory(machines[index].memoryIds[i]);
+ }
+ for (let i in machines[index].storageIds) {
+ yield fetchAndStoreStorage(machines[index].storageIds[i]);
+ }
}
}
@@ -155,6 +193,29 @@ 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]));
+ rack.name = action.name;
+ yield call(updateRackOnTile, tileId, rack);
+ yield put(editRackNameSucceeded(action.name));
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+export function* onDeleteRack() {
+ try {
+ const tileId = yield select(state => state.interactionLevel.tileId);
+ yield call(deleteRackFromTile, tileId);
+ yield put(deleteRackSucceeded());
+ } catch (error) {
+ console.log(error);
+ }
+}
+
export function* onAddRackToTile(action) {
try {
const rack = yield call(addRackToTile, action.tileId, {
@@ -170,3 +231,24 @@ export function* onAddRackToTile(action) {
console.log(error);
}
}
+
+export function* onAddMachine(action) {
+ try {
+ const tileId = yield select(state => state.interactionLevel.tileId);
+ const rackId = yield select(state => state.objects.tile[state.interactionLevel.tileId].objectId);
+ const machine = yield call(addMachineToRackOnTile, tileId, {
+ id: -1,
+ rackId,
+ position: action.position,
+ tags: [],
+ cpuIds: [],
+ gpuIds: [],
+ memoryIds: [],
+ storageIds: [],
+ });
+ yield put(addToStore("machine", machine));
+ yield put(addMachineSucceeded(machine));
+ } catch (error) {
+ console.log(error);
+ }
+}
diff --git a/src/util/date-time.js b/src/util/date-time.js
index 0093e846..ef3524db 100644
--- a/src/util/date-time.js
+++ b/src/util/date-time.js
@@ -11,12 +11,12 @@ export function parseAndFormatDateTime(dateTimeString) {
}
/**
- * Parses date-time string representations and returns a parsed object.
+ * Parses date-time string representations and returns a parsed rack.
*
* The format assumed is "YYYY-MM-DDTHH:MM:SS".
*
* @param dateTimeString A string expressing a date and a time, in the above mentioned format.
- * @returns {object} An object with the parsed date and time information as content.
+ * @returns {object} An rack with the parsed date and time information as content.
*/
export function parseDateTime(dateTimeString) {
const output = {
@@ -45,7 +45,7 @@ export function parseDateTime(dateTimeString) {
/**
* Serializes the given date and time value to a human-friendly string.
*
- * @param dateTime An object representation of a date and time.
+ * @param dateTime An rack representation of a date and time.
* @returns {string} A human-friendly string version of that date and time.
*/
export function formatDateTime(dateTime) {