From 42778e8be409b97059fa519b53c303cdba502e01 Mon Sep 17 00:00:00 2001 From: Georgios Andreadis Date: Tue, 5 Sep 2017 09:30:42 +0200 Subject: Implement rack creation --- src/actions/topology.js | 60 ++++++++++++++++++---- src/components/map/MapStage.js | 11 +++- src/components/map/elements/TilePlusIcon.js | 29 ++++++----- src/components/map/layers/HoverLayerComponent.js | 59 +++++++++++++++++++++ .../map/layers/HoverTileLayerComponent.js | 57 -------------------- .../map/layers/ObjectHoverLayerComponent.js | 11 ++++ .../map/layers/RoomHoverLayerComponent.js | 8 +++ .../topology/room/RackConstructionComponent.js | 19 +++++++ .../sidebars/topology/room/RoomSidebarComponent.js | 3 +- src/containers/map/RoomContainer.js | 2 +- src/containers/map/layers/HoverTileLayer.js | 43 ---------------- src/containers/map/layers/ObjectHoverLayer.js | 35 +++++++++++++ src/containers/map/layers/RoomHoverLayer.js | 48 +++++++++++++++++ .../topology/building/BuildingSidebarContainer.js | 2 +- .../topology/room/RackConstructionContainer.js | 23 +++++++++ src/reducers/construction.js | 36 +++++++++++++ src/reducers/index.js | 5 +- src/reducers/topology.js | 19 +------ src/sagas/index.js | 3 ++ src/sagas/topology.js | 25 +++++++-- src/util/tile-calculations.js | 24 +++++---- 21 files changed, 360 insertions(+), 162 deletions(-) create mode 100644 src/components/map/layers/HoverLayerComponent.js delete mode 100644 src/components/map/layers/HoverTileLayerComponent.js create mode 100644 src/components/map/layers/ObjectHoverLayerComponent.js create mode 100644 src/components/map/layers/RoomHoverLayerComponent.js create mode 100644 src/components/sidebars/topology/room/RackConstructionComponent.js delete mode 100644 src/containers/map/layers/HoverTileLayer.js create mode 100644 src/containers/map/layers/ObjectHoverLayer.js create mode 100644 src/containers/map/layers/RoomHoverLayer.js create mode 100644 src/containers/sidebars/topology/room/RackConstructionContainer.js create mode 100644 src/reducers/construction.js diff --git a/src/actions/topology.js b/src/actions/topology.js index 79f1bfb5..3f60386b 100644 --- a/src/actions/topology.js +++ b/src/actions/topology.js @@ -1,3 +1,4 @@ +import {findTileWithPosition} from "../util/tile-calculations"; import {addIdToStoreObjectListProp, addPropToStoreObject, removeIdFromStoreObjectListProp} from "./objects"; export const FETCH_TOPOLOGY_OF_DATACENTER = "FETCH_TOPOLOGY_OF_DATACENTER"; @@ -12,6 +13,10 @@ export const CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED = "CANCEL_NEW_ROOM_CONSTRUCT export const ADD_TILE = "ADD_TILE"; export const DELETE_TILE = "DELETE_TILE"; export const EDIT_ROOM_NAME = "EDIT_ROOM_NAME"; +export const START_OBJECT_CONSTRUCTION = "START_OBJECT_CONSTRUCTION"; +export const STOP_OBJECT_CONSTRUCTION = "STOP_OBJECT_CONSTRUCTION"; +export const ADD_RACK_TO_TILE = "ADD_RACK_TO_TILE"; +export const ADD_RACK_TO_TILE_SUCCEEDED = "ADD_RACK_TO_TILE_SUCCEEDED"; export function fetchLatestDatacenter() { return (dispatch, getState) => { @@ -49,8 +54,8 @@ export function startNewRoomConstructionSucceeded(roomId) { export function finishNewRoomConstruction() { return (dispatch, getState) => { - const {objects, currentRoomInConstruction} = getState(); - if (objects.room[currentRoomInConstruction].tileIds.length === 0) { + const {objects, construction} = getState(); + if (objects.room[construction.currentRoomInConstruction].tileIds.length === 0) { dispatch(cancelNewRoomConstruction()); return; } @@ -69,9 +74,9 @@ export function cancelNewRoomConstruction() { export function cancelNewRoomConstructionSucceeded() { return (dispatch, getState) => { - const {currentDatacenterId, currentRoomInConstruction} = getState(); + const {currentDatacenterId, construction} = getState(); dispatch(removeIdFromStoreObjectListProp("datacenter", currentDatacenterId, "roomIds", - currentRoomInConstruction)); + construction.currentRoomInConstruction)); dispatch({ type: CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED }); @@ -80,9 +85,9 @@ export function cancelNewRoomConstructionSucceeded() { export function toggleTileAtLocation(positionX, positionY) { return (dispatch, getState) => { - const {objects, currentRoomInConstruction} = getState(); + const {objects, construction} = getState(); - const tileIds = objects.room[currentRoomInConstruction].tileIds; + const tileIds = objects.room[construction.currentRoomInConstruction].tileIds; for (let index in tileIds) { if (objects.tile[tileIds[index]].positionX === positionX && objects.tile[tileIds[index]].positionY === positionY) { @@ -104,8 +109,8 @@ export function addTile(positionX, positionY) { export function addTileSucceeded(tileId) { return (dispatch, getState) => { - const {currentRoomInConstruction} = getState(); - dispatch(addIdToStoreObjectListProp("room", currentRoomInConstruction, "tileIds", tileId)); + const {construction} = getState(); + dispatch(addIdToStoreObjectListProp("room", construction.currentRoomInConstruction, "tileIds", tileId)); }; } @@ -118,8 +123,8 @@ export function deleteTile(tileId) { export function deleteTileSucceeded(tileId) { return (dispatch, getState) => { - const {currentRoomInConstruction} = getState(); - dispatch(removeIdFromStoreObjectListProp("room", currentRoomInConstruction, "tileIds", tileId)); + const {construction} = getState(); + dispatch(removeIdFromStoreObjectListProp("room", construction.currentRoomInConstruction, "tileIds", tileId)); }; } @@ -136,3 +141,38 @@ export function editRoomNameSucceeded(name) { dispatch(addPropToStoreObject("room", interactionLevel.roomId, {name})); }; } + +export function startObjectConstruction() { + return { + type: START_OBJECT_CONSTRUCTION + }; +} + +export function stopObjectConstruction() { + return { + type: STOP_OBJECT_CONSTRUCTION + }; +} + +export function addRackToTile(positionX, positionY) { + return (dispatch, getState) => { + const {objects, interactionLevel} = getState(); + const currentRoom = objects.room[interactionLevel.roomId]; + const tiles = currentRoom.tileIds.map(tileId => objects.tile[tileId]); + const tile = findTileWithPosition(tiles, positionX, positionY); + + if (tile !== null) { + dispatch({ + type: ADD_RACK_TO_TILE, + tileId: tile.id + }); + } + }; +} + +export function addRackToTileSucceeded(tileId, rackId) { + return dispatch => { + dispatch(addPropToStoreObject("tile", tileId, {objectType: "RACK"})); + dispatch(addPropToStoreObject("tile", tileId, {objectId: rackId})); + }; +} diff --git a/src/components/map/MapStage.js b/src/components/map/MapStage.js index f3f38917..c4579965 100644 --- a/src/components/map/MapStage.js +++ b/src/components/map/MapStage.js @@ -2,7 +2,8 @@ import React from "react"; import {Group, Layer, Stage} from "react-konva"; import {Shortcuts} from "react-shortcuts"; import DatacenterContainer from "../../containers/map/DatacenterContainer"; -import HoverTileLayer from "../../containers/map/layers/HoverTileLayer"; +import ObjectHoverLayer from "../../containers/map/layers/ObjectHoverLayer"; +import RoomHoverLayer from "../../containers/map/layers/RoomHoverLayer"; import jQuery from "../../util/jquery"; import {NAVBAR_HEIGHT} from "../navigation/Navbar"; import Backdrop from "./elements/Backdrop"; @@ -90,7 +91,13 @@ class MapStage extends React.Component { - + { +const TilePlusIcon = ({pixelX, pixelY}) => { const linePoints = [ [ - (positionX + 0.5) * TILE_SIZE_IN_PIXELS, - positionY * TILE_SIZE_IN_PIXELS + OBJECT_MARGIN_IN_PIXELS, - (positionX + 0.5) * TILE_SIZE_IN_PIXELS, - (positionY + 1) * TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS, + pixelX + 0.5 * TILE_SIZE_IN_PIXELS, + pixelY + OBJECT_MARGIN_IN_PIXELS, + pixelX + 0.5 * TILE_SIZE_IN_PIXELS, + pixelY + TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS, ], [ - positionX * TILE_SIZE_IN_PIXELS + OBJECT_MARGIN_IN_PIXELS, - (positionY + 0.5) * TILE_SIZE_IN_PIXELS, - (positionX + 1) * TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS, - (positionY + 0.5) * TILE_SIZE_IN_PIXELS, + pixelX + OBJECT_MARGIN_IN_PIXELS, + pixelY + 0.5 * TILE_SIZE_IN_PIXELS, + pixelX + TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS, + pixelY + 0.5 * TILE_SIZE_IN_PIXELS, ], ]; return ( - {linePoints.map(points => ( + {linePoints.map((points, index) => ( ))} @@ -34,7 +36,8 @@ const TilePlusIcon = ({positionX, positionY}) => { }; TilePlusIcon.propTypes = { - wallSegment: Shapes.WallSegment, + pixelX: PropTypes.number, + pixelY: PropTypes.number, }; export default TilePlusIcon; diff --git a/src/components/map/layers/HoverLayerComponent.js b/src/components/map/layers/HoverLayerComponent.js new file mode 100644 index 00000000..861d2b9a --- /dev/null +++ b/src/components/map/layers/HoverLayerComponent.js @@ -0,0 +1,59 @@ +import PropTypes from "prop-types"; +import React from 'react'; +import {Layer} from "react-konva"; +import HoverTile from "../elements/HoverTile"; +import {TILE_SIZE_IN_PIXELS} from "../MapConstants"; + +class HoverLayerComponent extends React.Component { + static propTypes = { + mouseX: PropTypes.number.isRequired, + mouseY: PropTypes.number.isRequired, + mainGroupX: PropTypes.number.isRequired, + mainGroupY: PropTypes.number.isRequired, + isEnabled: PropTypes.func.isRequired, + onClick: PropTypes.func.isRequired, + }; + + state = { + positionX: -1, + positionY: -1, + validity: false, + }; + + componentDidUpdate() { + if (!this.props.isEnabled()) { + return; + } + + const positionX = Math.floor((this.props.mouseX - this.props.mainGroupX) / TILE_SIZE_IN_PIXELS); + const positionY = Math.floor((this.props.mouseY - this.props.mainGroupY) / TILE_SIZE_IN_PIXELS); + + if (positionX !== this.state.positionX || positionY !== this.state.positionY) { + this.setState({positionX, positionY, validity: this.props.isValid(positionX, positionY)}); + } + } + + render() { + if (!this.props.isEnabled()) { + return ; + } + + const positionX = Math.floor((this.props.mouseX - this.props.mainGroupX) / TILE_SIZE_IN_PIXELS); + const positionY = Math.floor((this.props.mouseY - this.props.mainGroupY) / TILE_SIZE_IN_PIXELS); + const pixelX = positionX * TILE_SIZE_IN_PIXELS + this.props.mainGroupX; + const pixelY = positionY * TILE_SIZE_IN_PIXELS + this.props.mainGroupY; + + return ( + + this.state.validity ? this.props.onClick(positionX, positionY) : undefined} + /> + {this.props.children ? React.cloneElement(this.props.children, {pixelX, pixelY}) : undefined} + + ); + } +} + +export default HoverLayerComponent; diff --git a/src/components/map/layers/HoverTileLayerComponent.js b/src/components/map/layers/HoverTileLayerComponent.js deleted file mode 100644 index bd07596a..00000000 --- a/src/components/map/layers/HoverTileLayerComponent.js +++ /dev/null @@ -1,57 +0,0 @@ -import PropTypes from "prop-types"; -import React from 'react'; -import {Layer} from "react-konva"; -import HoverTile from "../elements/HoverTile"; -import {TILE_SIZE_IN_PIXELS} from "../MapConstants"; - -class HoverTileLayerComponent extends React.Component { - static propTypes = { - mouseX: PropTypes.number.isRequired, - mouseY: PropTypes.number.isRequired, - mainGroupX: PropTypes.number.isRequired, - mainGroupY: PropTypes.number.isRequired, - onClick: PropTypes.func.isRequired, - containsRack: PropTypes.bool, - }; - - state = { - positionX: -1, - positionY: -1, - validity: false, - }; - - componentDidUpdate() { - if (this.props.currentRoomInConstruction === -1) { - return; - } - - const positionX = Math.floor((this.props.mouseX - this.props.mainGroupX) / TILE_SIZE_IN_PIXELS); - const positionY = Math.floor((this.props.mouseY - this.props.mainGroupY) / TILE_SIZE_IN_PIXELS); - - if (positionX !== this.state.positionX || positionY !== this.state.positionY) { - this.setState({positionX, positionY, validity: this.props.isValid(positionX, positionY)}); - } - } - - render() { - if (this.props.currentRoomInConstruction === -1) { - return ; - } - - const positionX = Math.floor((this.props.mouseX - this.props.mainGroupX) / TILE_SIZE_IN_PIXELS); - const positionY = Math.floor((this.props.mouseY - this.props.mainGroupY) / TILE_SIZE_IN_PIXELS); - const pixelX = positionX * TILE_SIZE_IN_PIXELS + this.props.mainGroupX; - const pixelY = positionY * TILE_SIZE_IN_PIXELS + this.props.mainGroupY; - - return ( - - this.props.onClick(positionX, positionY)} - /> - - ); - } -} - -export default HoverTileLayerComponent; diff --git a/src/components/map/layers/ObjectHoverLayerComponent.js b/src/components/map/layers/ObjectHoverLayerComponent.js new file mode 100644 index 00000000..91757cb3 --- /dev/null +++ b/src/components/map/layers/ObjectHoverLayerComponent.js @@ -0,0 +1,11 @@ +import React from 'react'; +import TilePlusIcon from "../elements/TilePlusIcon"; +import HoverLayerComponent from "./HoverLayerComponent"; + +const ObjectHoverLayerComponent = (props) => ( + + + +); + +export default ObjectHoverLayerComponent; diff --git a/src/components/map/layers/RoomHoverLayerComponent.js b/src/components/map/layers/RoomHoverLayerComponent.js new file mode 100644 index 00000000..2133c8d8 --- /dev/null +++ b/src/components/map/layers/RoomHoverLayerComponent.js @@ -0,0 +1,8 @@ +import React from 'react'; +import HoverLayerComponent from "./HoverLayerComponent"; + +const RoomHoverLayerComponent = (props) => ( + +); + +export default RoomHoverLayerComponent; diff --git a/src/components/sidebars/topology/room/RackConstructionComponent.js b/src/components/sidebars/topology/room/RackConstructionComponent.js new file mode 100644 index 00000000..8298eade --- /dev/null +++ b/src/components/sidebars/topology/room/RackConstructionComponent.js @@ -0,0 +1,19 @@ +import React from "react"; + +const RackConstructionComponent = ({inObjectConstructionMode, onStart, onStop}) => { + if (inObjectConstructionMode) { + return ( +
+ Stop rack construction +
+ ); + } + + return ( +
+ Start rack construction +
+ ); +}; + +export default RackConstructionComponent; diff --git a/src/components/sidebars/topology/room/RoomSidebarComponent.js b/src/components/sidebars/topology/room/RoomSidebarComponent.js index dc01a301..4c1200c1 100644 --- a/src/components/sidebars/topology/room/RoomSidebarComponent.js +++ b/src/components/sidebars/topology/room/RoomSidebarComponent.js @@ -1,11 +1,12 @@ import React from "react"; +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}) => { let allowedObjects; if (roomType === "SERVER") { - allowedObjects = "test"; + allowedObjects = ; } return ( diff --git a/src/containers/map/RoomContainer.js b/src/containers/map/RoomContainer.js index 2d078e09..9edcb096 100644 --- a/src/containers/map/RoomContainer.js +++ b/src/containers/map/RoomContainer.js @@ -5,7 +5,7 @@ import RoomGroup from "../../components/map/groups/RoomGroup"; const mapStateToProps = (state, ownProps) => { return { interactionLevel: state.interactionLevel, - currentRoomInConstruction: state.currentRoomInConstruction, + currentRoomInConstruction: state.construction.currentRoomInConstruction, room: state.objects.room[ownProps.roomId], }; }; diff --git a/src/containers/map/layers/HoverTileLayer.js b/src/containers/map/layers/HoverTileLayer.js deleted file mode 100644 index d8a1d983..00000000 --- a/src/containers/map/layers/HoverTileLayer.js +++ /dev/null @@ -1,43 +0,0 @@ -import {connect} from "react-redux"; -import {toggleTileAtLocation} from "../../../actions/topology"; -import HoverTileLayerComponent from "../../../components/map/layers/HoverTileLayerComponent"; -import { - deriveValidNextTilePositions, - findPositionInPositions, - findPositionInRooms -} from "../../../util/tile-calculations"; - -const mapStateToProps = state => { - return { - currentRoomInConstruction: state.currentRoomInConstruction, - isValid: (x, y) => { - const newRoom = Object.assign({}, state.objects.room[state.currentRoomInConstruction]); - const oldRooms = Object.keys(state.objects.room) - .map(id => Object.assign({}, state.objects.room[id])) - .filter(room => room.id !== state.currentRoomInConstruction); - - [...oldRooms, newRoom].forEach(room => { - room.tiles = room.tileIds.map(tileId => state.objects.tile[tileId]); - }); - if (newRoom.tileIds.length === 0) { - return findPositionInRooms(oldRooms, x, y) === -1; - } - - const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles); - return findPositionInPositions(validNextPositions, x, y) !== -1; - }, - }; -}; - -const mapDispatchToProps = dispatch => { - return { - onClick: (x, y) => dispatch(toggleTileAtLocation(x, y)), - }; -}; - -const HoverTileLayer = connect( - mapStateToProps, - mapDispatchToProps -)(HoverTileLayerComponent); - -export default HoverTileLayer; diff --git a/src/containers/map/layers/ObjectHoverLayer.js b/src/containers/map/layers/ObjectHoverLayer.js new file mode 100644 index 00000000..e9df0384 --- /dev/null +++ b/src/containers/map/layers/ObjectHoverLayer.js @@ -0,0 +1,35 @@ +import {connect} from "react-redux"; +import {addRackToTile} from "../../../actions/topology"; +import ObjectHoverLayerComponent from "../../../components/map/layers/ObjectHoverLayerComponent"; +import {findTileWithPosition} from "../../../util/tile-calculations"; + +const mapStateToProps = state => { + return { + isEnabled: () => state.construction.inObjectConstructionMode, + isValid: (x, y) => { + if (state.interactionLevel.mode !== "ROOM") { + return false; + } + + const currentRoom = state.objects.room[state.interactionLevel.roomId]; + const tiles = currentRoom.tileIds.map(tileId => state.objects.tile[tileId]); + const tile = findTileWithPosition(tiles, x, y); + + return !(tile === null || tile.objectType); + + }, + }; +}; + +const mapDispatchToProps = dispatch => { + return { + onClick: (x, y) => dispatch(addRackToTile(x, y)), + }; +}; + +const ObjectHoverLayer = connect( + mapStateToProps, + mapDispatchToProps +)(ObjectHoverLayerComponent); + +export default ObjectHoverLayer; diff --git a/src/containers/map/layers/RoomHoverLayer.js b/src/containers/map/layers/RoomHoverLayer.js new file mode 100644 index 00000000..188ee51a --- /dev/null +++ b/src/containers/map/layers/RoomHoverLayer.js @@ -0,0 +1,48 @@ +import {connect} from "react-redux"; +import {toggleTileAtLocation} from "../../../actions/topology"; +import RoomHoverLayerComponent from "../../../components/map/layers/RoomHoverLayerComponent"; +import { + deriveValidNextTilePositions, + findPositionInPositions, + findPositionInRooms +} from "../../../util/tile-calculations"; + +const mapStateToProps = state => { + return { + isEnabled: () => state.construction.currentRoomInConstruction !== -1, + isValid: (x, y) => { + if (state.interactionLevel.mode !== "BUILDING") { + return false; + } + + const newRoom = Object.assign({}, state.objects.room[state.construction.currentRoomInConstruction]); + const oldRooms = Object.keys(state.objects.room) + .map(id => Object.assign({}, state.objects.room[id])) + .filter(room => room.datacenterId === state.currentDatacenterId + && room.id !== state.construction.currentRoomInConstruction); + + [...oldRooms, newRoom].forEach(room => { + room.tiles = room.tileIds.map(tileId => state.objects.tile[tileId]); + }); + if (newRoom.tileIds.length === 0) { + return findPositionInRooms(oldRooms, x, y) === -1; + } + + const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles); + return findPositionInPositions(validNextPositions, x, y) !== -1; + }, + }; +}; + +const mapDispatchToProps = dispatch => { + return { + onClick: (x, y) => dispatch(toggleTileAtLocation(x, y)), + }; +}; + +const RoomHoverLayer = connect( + mapStateToProps, + mapDispatchToProps +)(RoomHoverLayerComponent); + +export default RoomHoverLayer; diff --git a/src/containers/sidebars/topology/building/BuildingSidebarContainer.js b/src/containers/sidebars/topology/building/BuildingSidebarContainer.js index e543d65c..a91ad5ef 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.currentRoomInConstruction + currentRoomInConstruction: state.construction.currentRoomInConstruction }; }; diff --git a/src/containers/sidebars/topology/room/RackConstructionContainer.js b/src/containers/sidebars/topology/room/RackConstructionContainer.js new file mode 100644 index 00000000..e1a481e1 --- /dev/null +++ b/src/containers/sidebars/topology/room/RackConstructionContainer.js @@ -0,0 +1,23 @@ +import {connect} from "react-redux"; +import {startObjectConstruction, stopObjectConstruction} from "../../../../actions/topology"; +import RackConstructionComponent from "../../../../components/sidebars/topology/room/RackConstructionComponent"; + +const mapStateToProps = state => { + return { + inObjectConstructionMode: state.construction.inObjectConstructionMode, + }; +}; + +const mapDispatchToProps = dispatch => { + return { + onStart: () => dispatch(startObjectConstruction()), + onStop: () => dispatch(stopObjectConstruction()), + }; +}; + +const RackConstructionContainer = connect( + mapStateToProps, + mapDispatchToProps +)(RackConstructionComponent); + +export default RackConstructionContainer; diff --git a/src/reducers/construction.js b/src/reducers/construction.js new file mode 100644 index 00000000..33485842 --- /dev/null +++ b/src/reducers/construction.js @@ -0,0 +1,36 @@ +import {combineReducers} from "redux"; +import { + CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED, + FINISH_NEW_ROOM_CONSTRUCTION, + START_NEW_ROOM_CONSTRUCTION_SUCCEEDED, + START_OBJECT_CONSTRUCTION, + STOP_OBJECT_CONSTRUCTION +} from "../actions/topology"; + +export function currentRoomInConstruction(state = -1, action) { + switch (action.type) { + case START_NEW_ROOM_CONSTRUCTION_SUCCEEDED: + return action.roomId; + case CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED: + case FINISH_NEW_ROOM_CONSTRUCTION: + return -1; + default: + return state; + } +} + +export function inObjectConstructionMode(state = false, action) { + switch (action.type) { + case START_OBJECT_CONSTRUCTION: + return true; + case STOP_OBJECT_CONSTRUCTION: + return false; + default: + return state; + } +} + +export const construction = combineReducers({ + currentRoomInConstruction, + inObjectConstructionMode, +}); diff --git a/src/reducers/index.js b/src/reducers/index.js index d3ace393..2dc6b8af 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,10 +1,11 @@ import {combineReducers} from "redux"; import {auth} from "./auth"; +import {construction} from "./construction"; import {interactionLevel} from "./interaction-level"; import {modals} from "./modals"; import {objects} from "./objects"; import {authorizationsOfCurrentUser, authVisibilityFilter, currentSimulationId} from "./simulations"; -import {currentDatacenterId, currentRoomInConstruction} from "./topology"; +import {currentDatacenterId} from "./topology"; const rootReducer = combineReducers({ auth, @@ -15,7 +16,7 @@ const rootReducer = combineReducers({ currentSimulationId, currentDatacenterId, interactionLevel, - currentRoomInConstruction, + construction, }); export default rootReducer; diff --git a/src/reducers/topology.js b/src/reducers/topology.js index c8690816..caafb7c1 100644 --- a/src/reducers/topology.js +++ b/src/reducers/topology.js @@ -1,9 +1,4 @@ -import { - CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED, - FETCH_LATEST_DATACENTER_SUCCEEDED, - FINISH_NEW_ROOM_CONSTRUCTION, - START_NEW_ROOM_CONSTRUCTION_SUCCEEDED -} from "../actions/topology"; +import {FETCH_LATEST_DATACENTER_SUCCEEDED} from "../actions/topology"; export function currentDatacenterId(state = -1, action) { switch (action.type) { @@ -13,15 +8,3 @@ export function currentDatacenterId(state = -1, action) { return state; } } - -export function currentRoomInConstruction(state = -1, action) { - switch (action.type) { - case START_NEW_ROOM_CONSTRUCTION_SUCCEEDED: - return action.roomId; - case CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED: - case FINISH_NEW_ROOM_CONSTRUCTION: - return -1; - default: - return state; - } -} diff --git a/src/sagas/index.js b/src/sagas/index.js index a076736c..e58c966f 100644 --- a/src/sagas/index.js +++ b/src/sagas/index.js @@ -2,6 +2,7 @@ import {takeEvery} from "redux-saga/effects"; import {LOG_IN} from "../actions/auth"; import {ADD_SIMULATION, DELETE_SIMULATION} from "../actions/simulations"; import { + ADD_RACK_TO_TILE, ADD_TILE, CANCEL_NEW_ROOM_CONSTRUCTION, DELETE_TILE, @@ -13,6 +14,7 @@ import {DELETE_CURRENT_USER, FETCH_AUTHORIZATIONS_OF_CURRENT_USER} from "../acti import {onDeleteCurrentUser} from "./profile"; import {onSimulationAdd, onSimulationDelete} from "./simulations"; import { + onAddRackToTile, onAddTile, onCancelNewRoomConstruction, onDeleteTile, @@ -34,4 +36,5 @@ export default function* rootSaga() { yield takeEvery(ADD_TILE, onAddTile); yield takeEvery(DELETE_TILE, onDeleteTile); yield takeEvery(EDIT_ROOM_NAME, onEditRoomName); + yield takeEvery(ADD_RACK_TO_TILE, onAddRackToTile); } diff --git a/src/sagas/topology.js b/src/sagas/topology.js index c029c861..22f70f25 100644 --- a/src/sagas/topology.js +++ b/src/sagas/topology.js @@ -1,6 +1,7 @@ import {call, put, select} from "redux-saga/effects"; import {addPropToStoreObject, addToStore} from "../actions/objects"; import { + addRackToTileSucceeded, addTileSucceeded, cancelNewRoomConstructionSucceeded, deleteTileSucceeded, @@ -10,7 +11,7 @@ import { } from "../actions/topology"; import {addRoomToDatacenter} from "../api/routes/datacenters"; import {addTileToRoom, deleteRoom, updateRoom} from "../api/routes/rooms"; -import {deleteTile} from "../api/routes/tiles"; +import {addRackToTile, deleteTile} from "../api/routes/tiles"; import { fetchAndStoreCoolingItem, fetchAndStoreDatacenter, @@ -89,7 +90,7 @@ export function* onStartNewRoomConstruction() { datacenterId, roomType: "SERVER" }); - const roomWithEmptyTileList = Object.assign(room, {tileIds: []}); + const roomWithEmptyTileList = Object.assign({}, room, {tileIds: []}); yield put(addToStore("room", roomWithEmptyTileList)); yield put(startNewRoomConstructionSucceeded(room.id)); } catch (error) { @@ -99,7 +100,7 @@ export function* onStartNewRoomConstruction() { export function* onCancelNewRoomConstruction() { try { - const roomId = yield select(state => state.currentRoomInConstruction); + const roomId = yield select(state => state.construction.currentRoomInConstruction); yield call(deleteRoom, roomId); yield put(cancelNewRoomConstructionSucceeded()); } catch (error) { @@ -109,7 +110,7 @@ export function* onCancelNewRoomConstruction() { export function* onAddTile(action) { try { - const roomId = yield select(state => state.currentRoomInConstruction); + const roomId = yield select(state => state.construction.currentRoomInConstruction); const tile = yield call(addTileToRoom, { roomId, positionX: action.positionX, @@ -142,3 +143,19 @@ export function* onEditRoomName(action) { console.log(error); } } + +export function* onAddRackToTile(action) { + try { + const rack = yield call(addRackToTile, action.tileId, { + id: -1, + name: "Rack", + capacity: 5, + powerCapacityW: 100, + machines: 20 + }); + yield put(addToStore("rack", rack)); + yield put(addRackToTileSucceeded(action.tileId, rack.id)); + } catch (error) { + console.log(error); + } +} diff --git a/src/util/tile-calculations.js b/src/util/tile-calculations.js index 4d81dd31..71442941 100644 --- a/src/util/tile-calculations.js +++ b/src/util/tile-calculations.js @@ -164,31 +164,25 @@ export function deriveValidNextTilePositions(rooms, selectedTiles) { } export function findPositionInPositions(positions, positionX, positionY) { - let index = -1; - for (let i = 0; i < positions.length; i++) { const position = positions[i]; if (positionX === position.x && positionY === position.y) { - index = i; - break; + return i; } } - return index; + return -1; } export function findPositionInRooms(rooms, positionX, positionY) { - let index = -1; - for (let i = 0; i < rooms.length; i++) { const room = rooms[i]; if (findPositionInTiles(room.tiles, positionX, positionY) !== -1) { - index = i; - break; + return i; } } - return index; + return -1; } function findPositionInTiles(tiles, positionX, positionY) { @@ -204,3 +198,13 @@ function findPositionInTiles(tiles, positionX, positionY) { return index; } + +export function findTileWithPosition(tiles, positionX, positionY) { + for (let i = 0; i < tiles.length; i++) { + if (tiles[i].positionX === positionX && tiles[i].positionY === positionY) { + return tiles[i]; + } + } + + return null; +} -- cgit v1.2.3