summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/components/app/map
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/app/map')
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/GrayContainer.js34
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js12
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/MapStage.js66
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/MapStage.module.scss31
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js97
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/RackContainer.js37
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js37
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js43
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/RoomContainer.js45
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/TileContainer.js46
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/TopologyContainer.js35
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/WallContainer.js39
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.js42
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.module.scss55
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ExportCanvasComponent.js15
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicator.js (renamed from opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.js)8
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicator.module.scss (renamed from opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.module.scss)0
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.js13
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.module.scss6
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.js28
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.module.scss29
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ZoomControlComponent.js31
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/RackGroup.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js6
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js2
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js33
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js2
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js54
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js67
31 files changed, 736 insertions, 189 deletions
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/GrayContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/GrayContainer.js
new file mode 100644
index 00000000..4791940f
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/GrayContainer.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useDispatch } from 'react-redux'
+import { goDownOneInteractionLevel } from '../../../redux/actions/interaction-level'
+import GrayLayer from '../../../components/app/map/elements/GrayLayer'
+
+const GrayContainer = () => {
+ const dispatch = useDispatch()
+ const onClick = () => dispatch(goDownOneInteractionLevel())
+ return <GrayLayer onClick={onClick} />
+}
+
+export default GrayContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js b/opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js
deleted file mode 100644
index ddb94990..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
-import { faSpinner } from '@fortawesome/free-solid-svg-icons'
-
-const LoadingScreen = () => (
- <div className="display-4">
- <FontAwesomeIcon icon={faSpinner} spin className="mr-4" />
- Loading your project...
- </div>
-)
-
-export default LoadingScreen
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js b/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js
index d6ea1f84..45799f70 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/MapConstants.js
@@ -8,8 +8,8 @@ export const TILE_PLUS_MARGIN_IN_PIXELS = TILE_SIZE_IN_PIXELS / 3
export const OBJECT_SIZE_IN_PIXELS = TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS * 2
export const GRID_LINE_WIDTH_IN_PIXELS = 2
-export const WALL_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 8
-export const OBJECT_BORDER_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 12
+export const WALL_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 16
+export const OBJECT_BORDER_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 16
export const TILE_PLUS_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 10
export const SIDEBAR_WIDTH = 350
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js b/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js
new file mode 100644
index 00000000..73accf3f
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/MapStage.js
@@ -0,0 +1,66 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { HotKeys } from 'react-hotkeys'
+import { Stage } from 'react-konva'
+import { MAP_MOVE_PIXELS_PER_EVENT } from './MapConstants'
+import { Provider, useDispatch, useStore } from 'react-redux'
+import useResizeObserver from 'use-resize-observer'
+import { mapContainer } from './MapStage.module.scss'
+import { useMapPosition } from '../../../data/map'
+import { setMapDimensions, setMapPositionWithBoundsCheck, zoomInOnPosition } from '../../../redux/actions/map'
+import MapLayer from './layers/MapLayer'
+import RoomHoverLayer from './layers/RoomHoverLayer'
+import ObjectHoverLayer from './layers/ObjectHoverLayer'
+
+function MapStage() {
+ const store = useStore()
+ const dispatch = useDispatch()
+
+ const stage = useRef(null)
+ const [pos, setPos] = useState([0, 0])
+ const [x, y] = pos
+ const handlers = {
+ MOVE_LEFT: () => moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0),
+ MOVE_RIGHT: () => moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0),
+ MOVE_UP: () => moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT),
+ MOVE_DOWN: () => moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT),
+ }
+ const mapPosition = useMapPosition()
+ const { ref, width = 100, height = 100 } = useResizeObserver()
+
+ const moveWithDelta = (deltaX, deltaY) =>
+ dispatch(setMapPositionWithBoundsCheck(mapPosition.x + deltaX, mapPosition.y + deltaY))
+ const updateMousePosition = () => {
+ if (!stage.current) {
+ return
+ }
+
+ const mousePos = stage.current.getStage().getPointerPosition()
+ setPos([mousePos.x, mousePos.y])
+ }
+ const updateScale = ({ evt }) => dispatch(zoomInOnPosition(evt.deltaY < 0, x, y))
+
+ useEffect(() => {
+ window['exportCanvasToImage'] = () => {
+ const download = document.createElement('a')
+ download.href = stage.current.getStage().toDataURL()
+ download.download = 'opendc-canvas-export-' + Date.now() + '.png'
+ download.click()
+ }
+ }, [stage])
+
+ useEffect(() => dispatch(setMapDimensions(width, height)), [width, height]) // eslint-disable-line react-hooks/exhaustive-deps
+
+ return (
+ <HotKeys handlers={handlers} allowChanges={true} innerRef={ref} className={mapContainer}>
+ <Stage ref={stage} width={width} height={height} onMouseMove={updateMousePosition} onWheel={updateScale}>
+ <Provider store={store}>
+ <MapLayer />
+ <RoomHoverLayer mouseX={x} mouseY={y} />
+ <ObjectHoverLayer mouseX={x} mouseY={y} />
+ </Provider>
+ </Stage>
+ </HotKeys>
+ )
+}
+
+export default MapStage
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/MapStage.module.scss b/opendc-web/opendc-web-ui/src/components/app/map/MapStage.module.scss
new file mode 100644
index 00000000..d879b4c8
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/MapStage.module.scss
@@ -0,0 +1,31 @@
+/*!
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+.mapContainer {
+ background-color: var(--pf-global--Color--light-200);
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js
deleted file mode 100644
index c3177fe1..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useEffect, useRef, useState } from 'react'
-import { HotKeys } from 'react-hotkeys'
-import { Stage } from 'react-konva'
-import MapLayer from '../../../containers/app/map/layers/MapLayer'
-import ObjectHoverLayer from '../../../containers/app/map/layers/ObjectHoverLayer'
-import RoomHoverLayer from '../../../containers/app/map/layers/RoomHoverLayer'
-import { NAVBAR_HEIGHT } from '../../navigation/Navbar'
-import { MAP_MOVE_PIXELS_PER_EVENT } from './MapConstants'
-import { Provider, useStore } from 'react-redux'
-
-function MapStageComponent({
- mapDimensions,
- mapPosition,
- setMapDimensions,
- setMapPositionWithBoundsCheck,
- zoomInOnPosition,
-}) {
- const [pos, setPos] = useState([0, 0])
- const stage = useRef(null)
- const [x, y] = pos
- const handlers = {
- MOVE_LEFT: () => moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0),
- MOVE_RIGHT: () => moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0),
- MOVE_UP: () => moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT),
- MOVE_DOWN: () => moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT),
- }
-
- const moveWithDelta = (deltaX, deltaY) =>
- setMapPositionWithBoundsCheck(mapPosition.x + deltaX, mapPosition.y + deltaY)
- const updateMousePosition = () => {
- if (!stage.current) {
- return
- }
-
- const mousePos = stage.current.getStage().getPointerPosition()
- setPos([mousePos.x, mousePos.y])
- }
-
- const updateDimensions = () => setMapDimensions(window.innerWidth, window.innerHeight - NAVBAR_HEIGHT)
- const updateScale = (e) => zoomInOnPosition(e.deltaY < 0, x, y)
-
- // We explicitly do not specify any dependencies to prevent infinitely dispatching updateDimensions commands
- useEffect(() => {
- updateDimensions()
-
- window.addEventListener('resize', updateDimensions)
- window.addEventListener('wheel', updateScale)
-
- window['exportCanvasToImage'] = () => {
- const download = document.createElement('a')
- download.href = stage.current.getStage().toDataURL()
- download.download = 'opendc-canvas-export-' + Date.now() + '.png'
- download.click()
- }
-
- return () => {
- window.removeEventListener('resize', updateDimensions)
- window.removeEventListener('wheel', updateScale)
- }
- }, []) // eslint-disable-line react-hooks/exhaustive-deps
-
- const store = useStore()
-
- return (
- <HotKeys handlers={handlers} allowChanges={true}>
- <Stage
- ref={stage}
- width={mapDimensions.width}
- height={mapDimensions.height}
- onMouseMove={updateMousePosition}
- >
- <Provider store={store}>
- <MapLayer />
- <RoomHoverLayer mouseX={x} mouseY={y} />
- <ObjectHoverLayer mouseX={x} mouseY={y} />
- </Provider>
- </Stage>
- </HotKeys>
- )
-}
-
-MapStageComponent.propTypes = {
- mapDimensions: PropTypes.shape({
- width: PropTypes.number.isRequired,
- height: PropTypes.number.isRequired,
- }).isRequired,
- mapPosition: PropTypes.shape({
- x: PropTypes.number.isRequired,
- y: PropTypes.number.isRequired,
- }).isRequired,
- setMapDimensions: PropTypes.func,
- setMapPositionWithBoundsCheck: PropTypes.func,
- zoomInOnPosition: PropTypes.func,
-}
-
-export default MapStageComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/RackContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/RackContainer.js
new file mode 100644
index 00000000..3c75d3a7
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/RackContainer.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useSelector } from 'react-redux'
+import RackGroup from '../../../components/app/map/groups/RackGroup'
+import { Tile } from '../../../shapes'
+
+const RackContainer = ({ tile }) => {
+ const interactionLevel = useSelector((state) => state.interactionLevel)
+ return <RackGroup interactionLevel={interactionLevel} tile={tile} />
+}
+
+RackContainer.propTypes = {
+ tile: Tile,
+}
+
+export default RackContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js
new file mode 100644
index 00000000..838aea5a
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/RackEnergyFillContainer.js
@@ -0,0 +1,37 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { useSelector } from 'react-redux'
+import RackFillBar from '../../../components/app/map/elements/RackFillBar'
+
+const RackSpaceFillContainer = (props) => {
+ const state = useSelector((state) => {
+ let energyConsumptionTotal = 0
+ const rack = state.objects.rack[state.objects.tile[props.tileId].rack]
+ const machineIds = rack.machines
+ machineIds.forEach((machineId) => {
+ if (machineId !== null) {
+ const machine = state.objects.machine[machineId]
+ machine.cpus.forEach((id) => (energyConsumptionTotal += state.objects.cpu[id].energyConsumptionW))
+ machine.gpus.forEach((id) => (energyConsumptionTotal += state.objects.gpu[id].energyConsumptionW))
+ machine.memories.forEach(
+ (id) => (energyConsumptionTotal += state.objects.memory[id].energyConsumptionW)
+ )
+ machine.storages.forEach(
+ (id) => (energyConsumptionTotal += state.objects.storage[id].energyConsumptionW)
+ )
+ }
+ })
+
+ return {
+ type: 'energy',
+ fillFraction: Math.min(1, energyConsumptionTotal / rack.powerCapacityW),
+ }
+ })
+ return <RackFillBar {...props} {...state} />
+}
+
+RackSpaceFillContainer.propTypes = {
+ tileId: PropTypes.string.isRequired,
+}
+
+export default RackSpaceFillContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js
new file mode 100644
index 00000000..6791120e
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/RackSpaceFillContainer.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import PropTypes from 'prop-types'
+import { useSelector } from 'react-redux'
+import RackFillBar from '../../../components/app/map/elements/RackFillBar'
+
+const RackSpaceFillContainer = (props) => {
+ const state = useSelector((state) => {
+ const machineIds = state.objects.rack[state.objects.tile[props.tileId].rack].machines
+ return {
+ type: 'space',
+ fillFraction: machineIds.filter((id) => id !== null).length / machineIds.length,
+ }
+ })
+ return <RackFillBar {...props} {...state} />
+}
+
+RackSpaceFillContainer.propTypes = {
+ tileId: PropTypes.string.isRequired,
+}
+
+export default RackSpaceFillContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/RoomContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/RoomContainer.js
new file mode 100644
index 00000000..26fbcd7a
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/RoomContainer.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import PropTypes from 'prop-types'
+import React from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import { goFromBuildingToRoom } from '../../../redux/actions/interaction-level'
+import RoomGroup from '../../../components/app/map/groups/RoomGroup'
+
+const RoomContainer = (props) => {
+ const state = useSelector((state) => {
+ return {
+ interactionLevel: state.interactionLevel,
+ currentRoomInConstruction: state.construction.currentRoomInConstruction,
+ room: state.objects.room[props.roomId],
+ }
+ })
+ const dispatch = useDispatch()
+ return <RoomGroup {...props} {...state} onClick={() => dispatch(goFromBuildingToRoom(props.roomId))} />
+}
+
+RoomContainer.propTypes = {
+ roomId: PropTypes.string,
+}
+
+export default RoomContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/TileContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/TileContainer.js
new file mode 100644
index 00000000..bfcbf735
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/TileContainer.js
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import PropTypes from 'prop-types'
+import { useDispatch, useSelector } from 'react-redux'
+import { goFromRoomToRack } from '../../../redux/actions/interaction-level'
+import TileGroup from '../../../components/app/map/groups/TileGroup'
+
+const TileContainer = (props) => {
+ const interactionLevel = useSelector((state) => state.interactionLevel)
+ const tile = useSelector((state) => state.objects.tile[props.tileId])
+
+ const dispatch = useDispatch()
+ const onClick = (tile) => {
+ if (tile.rack) {
+ dispatch(goFromRoomToRack(tile._id))
+ }
+ }
+ return <TileGroup {...props} onClick={onClick} tile={tile} interactionLevel={interactionLevel} />
+}
+
+TileContainer.propTypes = {
+ tileId: PropTypes.string.isRequired,
+}
+
+export default TileContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/TopologyContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/TopologyContainer.js
new file mode 100644
index 00000000..78e75d0f
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/TopologyContainer.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useSelector } from 'react-redux'
+import TopologyGroup from '../../../components/app/map/groups/TopologyGroup'
+import { useActiveTopology } from '../../../data/topology'
+
+const TopologyContainer = () => {
+ const topology = useActiveTopology()
+ const interactionLevel = useSelector((state) => state.interactionLevel)
+
+ return <TopologyGroup topology={topology} interactionLevel={interactionLevel} />
+}
+
+export default TopologyContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/WallContainer.js b/opendc-web/opendc-web-ui/src/components/app/map/WallContainer.js
new file mode 100644
index 00000000..51dffe4b
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/WallContainer.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import PropTypes from 'prop-types'
+import { useSelector } from 'react-redux'
+import WallGroup from '../../../components/app/map/groups/WallGroup'
+
+const WallContainer = (props) => {
+ const tiles = useSelector((state) =>
+ state.objects.room[props.roomId].tiles.map((tileId) => state.objects.tile[tileId])
+ )
+ return <WallGroup {...props} tiles={tiles} />
+}
+
+WallContainer.propTypes = {
+ roomId: PropTypes.string.isRequired,
+}
+
+export default WallContainer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.js b/opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.js
new file mode 100644
index 00000000..f54b7c84
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import PropTypes from 'prop-types'
+import { ChevronLeftIcon } from '@patternfly/react-icons'
+import { collapseContainer } from './Collapse.module.scss'
+import { Button } from '@patternfly/react-core'
+
+function Collapse({ onClick }) {
+ return (
+ <div className={collapseContainer}>
+ <Button variant="tertiary" onClick={onClick}>
+ <ChevronLeftIcon />
+ </Button>
+ </div>
+ )
+}
+
+Collapse.propTypes = {
+ onClick: PropTypes.func,
+}
+
+export default Collapse
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.module.scss b/opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.module.scss
new file mode 100644
index 00000000..0c1fac94
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/Collapse.module.scss
@@ -0,0 +1,55 @@
+/*!
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+.collapseContainer {
+ position: absolute;
+ right: var(--pf-global--spacer--xs);
+ top: 0;
+ bottom: 10%;
+ margin: auto 0;
+ height: 50px;
+
+ button:global(.pf-m-tertiary) {
+ height: 100%;
+ padding: 2px;
+
+ margin-right: var(--pf-global--spacer--xs);
+ margin-top: var(--pf-global--spacer--xs);
+ background-color: var(--pf-global--BackgroundColor--100);
+ border: none;
+ border-radius: var(--pf-global--BorderRadius--sm);
+ box-shadow: var(--pf-global--BoxShadow--sm);
+
+ &:not(:global(.pf-m-disabled)) {
+ background-color: var(--pf-global--BackgroundColor--100);
+ }
+
+ &:after {
+ display: none;
+ }
+
+ &:hover {
+ border: none;
+ box-shadow: var(--pf-global--BoxShadow--md);
+ }
+ }
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ExportCanvasComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/controls/ExportCanvasComponent.js
deleted file mode 100644
index 9e8cb36a..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ExportCanvasComponent.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
-import { faCamera } from '@fortawesome/free-solid-svg-icons'
-
-const ExportCanvasComponent = () => (
- <button
- className="btn btn-success btn-circle btn-sm"
- title="Export Canvas to PNG Image"
- onClick={() => window['exportCanvasToImage']()}
- >
- <FontAwesomeIcon icon={faCamera} />
- </button>
-)
-
-export default ExportCanvasComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicator.js
index ef633764..11c2f2d3 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicator.js
@@ -1,16 +1,16 @@
import PropTypes from 'prop-types'
import React from 'react'
import { TILE_SIZE_IN_METERS, TILE_SIZE_IN_PIXELS } from '../MapConstants'
-import { scaleIndicator } from './ScaleIndicatorComponent.module.scss'
+import { scaleIndicator } from './ScaleIndicator.module.scss'
-const ScaleIndicatorComponent = ({ scale }) => (
+const ScaleIndicator = ({ scale }) => (
<div className={scaleIndicator} style={{ width: TILE_SIZE_IN_PIXELS * scale }}>
{TILE_SIZE_IN_METERS}m
</div>
)
-ScaleIndicatorComponent.propTypes = {
+ScaleIndicator.propTypes = {
scale: PropTypes.number.isRequired,
}
-export default ScaleIndicatorComponent
+export default ScaleIndicator
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.module.scss b/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicator.module.scss
index f19e0ff2..f19e0ff2 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.module.scss
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicator.module.scss
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.js
deleted file mode 100644
index d2f70953..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react'
-import ZoomControlContainer from '../../../../containers/app/map/controls/ZoomControlContainer'
-import ExportCanvasComponent from './ExportCanvasComponent'
-import { toolPanel } from './ToolPanelComponent.module.scss'
-
-const ToolPanelComponent = () => (
- <div className={toolPanel}>
- <ZoomControlContainer />
- <ExportCanvasComponent />
- </div>
-)
-
-export default ToolPanelComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.module.scss b/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.module.scss
deleted file mode 100644
index 970b1ce2..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.module.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-.toolPanel {
- position: absolute;
- left: 10px;
- bottom: 10px;
- z-index: 50;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.js b/opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.js
new file mode 100644
index 00000000..4c60bfb2
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.js
@@ -0,0 +1,28 @@
+import PropTypes from 'prop-types'
+import React from 'react'
+import { control, toolBar } from './Toolbar.module.scss'
+import { Button } from '@patternfly/react-core'
+import { SearchPlusIcon, SearchMinusIcon } from '@patternfly/react-icons'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faCamera } from '@fortawesome/free-solid-svg-icons'
+
+const Toolbar = ({ onZoom, onExport }) => (
+ <div className={toolBar}>
+ <Button variant="tertiary" title="Zoom in" onClick={() => onZoom(true)} className={control}>
+ <SearchPlusIcon />
+ </Button>
+ <Button variant="tertiary" title="Zoom out" onClick={() => onZoom(false)} className={control}>
+ <SearchMinusIcon />
+ </Button>
+ <Button variant="tertiary" title="Export Canvas to PNG Image" onClick={() => onExport()} className={control}>
+ <FontAwesomeIcon icon={faCamera} />
+ </Button>
+ </div>
+)
+
+Toolbar.propTypes = {
+ onZoom: PropTypes.func,
+ onExport: PropTypes.func,
+}
+
+export default Toolbar
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.module.scss b/opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.module.scss
new file mode 100644
index 00000000..0d505acc
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/Toolbar.module.scss
@@ -0,0 +1,29 @@
+.toolBar {
+ position: absolute;
+ bottom: var(--pf-global--spacer--md);
+ left: var(--pf-global--spacer--xl);
+}
+
+.control {
+ &:global(.pf-m-tertiary) {
+ margin-right: var(--pf-global--spacer--xs);
+ margin-top: var(--pf-global--spacer--xs);
+ background-color: var(--pf-global--BackgroundColor--100);
+ border: none;
+ border-radius: var(--pf-global--BorderRadius--sm);
+ box-shadow: var(--pf-global--BoxShadow--sm);
+
+ &:not(:global(.pf-m-disabled)) {
+ background-color: var(--pf-global--BackgroundColor--100);
+ }
+
+ &:after {
+ display: none;
+ }
+
+ &:hover {
+ border: none;
+ box-shadow: var(--pf-global--BoxShadow--md);
+ }
+ }
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ZoomControlComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/controls/ZoomControlComponent.js
deleted file mode 100644
index 6c3c6cb7..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ZoomControlComponent.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
-import { faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'
-
-const ZoomControlComponent = ({ zoomInOnCenter }) => {
- return (
- <span>
- <button
- className="btn btn-default btn-circle btn-sm mr-1"
- title="Zoom in"
- onClick={() => zoomInOnCenter(true)}
- >
- <FontAwesomeIcon icon={faPlus} />
- </button>
- <button
- className="btn btn-default btn-circle btn-sm mr-1"
- title="Zoom out"
- onClick={() => zoomInOnCenter(false)}
- >
- <FontAwesomeIcon icon={faMinus} />
- </button>
- </span>
- )
-}
-
-ZoomControlComponent.propTypes = {
- zoomInOnCenter: PropTypes.func.isRequired,
-}
-
-export default ZoomControlComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/RackGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/RackGroup.js
index 40e28f01..9c4abc4a 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/groups/RackGroup.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/RackGroup.js
@@ -1,10 +1,10 @@
import React from 'react'
import { Group } from 'react-konva'
-import RackEnergyFillContainer from '../../../../containers/app/map/RackEnergyFillContainer'
-import RackSpaceFillContainer from '../../../../containers/app/map/RackSpaceFillContainer'
import { Tile } from '../../../../shapes'
import { RACK_BACKGROUND_COLOR } from '../../../../util/colors'
import TileObject from '../elements/TileObject'
+import RackSpaceFillContainer from '../RackSpaceFillContainer'
+import RackEnergyFillContainer from '../RackEnergyFillContainer'
const RackGroup = ({ tile }) => {
return (
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js
index 42d20ff1..a14f3676 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js
@@ -1,10 +1,10 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Group } from 'react-konva'
-import GrayContainer from '../../../../containers/app/map/GrayContainer'
-import TileContainer from '../../../../containers/app/map/TileContainer'
-import WallContainer from '../../../../containers/app/map/WallContainer'
import { InteractionLevel, Room } from '../../../../shapes'
+import GrayContainer from '../GrayContainer'
+import TileContainer from '../TileContainer'
+import WallContainer from '../WallContainer'
const RoomGroup = ({ room, interactionLevel, currentRoomInConstruction, onClick }) => {
if (currentRoomInConstruction === room._id) {
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js
index ce5e4a6b..cd36c7e5 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js
@@ -1,10 +1,10 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Group } from 'react-konva'
-import RackContainer from '../../../../containers/app/map/RackContainer'
import { Tile } from '../../../../shapes'
import { ROOM_DEFAULT_COLOR, ROOM_IN_CONSTRUCTION_COLOR } from '../../../../util/colors'
import RoomTile from '../elements/RoomTile'
+import RackContainer from '../RackContainer'
const TileGroup = ({ tile, newTile, onClick }) => {
let tileObject
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js
index d4c6db7d..d3bcb279 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js
@@ -1,8 +1,8 @@
import React from 'react'
import { Group } from 'react-konva'
-import GrayContainer from '../../../../containers/app/map/GrayContainer'
-import RoomContainer from '../../../../containers/app/map/RoomContainer'
import { InteractionLevel, Topology } from '../../../../shapes'
+import RoomContainer from '../RoomContainer'
+import GrayContainer from '../GrayContainer'
const TopologyGroup = ({ topology, interactionLevel }) => {
if (!topology) {
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js
new file mode 100644
index 00000000..badb9f68
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayer.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import MapLayerComponent from '../../../../components/app/map/layers/MapLayerComponent'
+import { useMapPosition, useMapScale } from '../../../../data/map'
+
+const MapLayer = (props) => {
+ const position = useMapPosition()
+ const scale = useMapScale()
+ return <MapLayerComponent {...props} mapPosition={position} mapScale={scale} />
+}
+
+export default MapLayer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js
index 96e6867c..efe5b4e5 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/MapLayerComponent.js
@@ -1,9 +1,9 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Group, Layer } from 'react-konva'
-import TopologyContainer from '../../../../containers/app/map/TopologyContainer'
import Backdrop from '../elements/Backdrop'
import GridGroup from '../groups/GridGroup'
+import TopologyContainer from '../TopologyContainer'
const MapLayerComponent = ({ mapPosition, mapScale }) => (
<Layer>
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js
new file mode 100644
index 00000000..9a087bd5
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/ObjectHoverLayer.js
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import { addRackToTile } from '../../../../redux/actions/topology/room'
+import ObjectHoverLayerComponent from '../../../../components/app/map/layers/ObjectHoverLayerComponent'
+import { findTileWithPosition } from '../../../../util/tile-calculations'
+
+const ObjectHoverLayer = (props) => {
+ const state = useSelector((state) => {
+ return {
+ mapPosition: state.map.position,
+ mapScale: state.map.scale,
+ isEnabled: () => state.construction.inRackConstructionMode,
+ isValid: (x, y) => {
+ if (state.interactionLevel.mode !== 'ROOM') {
+ return false
+ }
+
+ const currentRoom = state.objects.room[state.interactionLevel.roomId]
+ const tiles = currentRoom.tiles.map((tileId) => state.objects.tile[tileId])
+ const tile = findTileWithPosition(tiles, x, y)
+
+ return !(tile === null || tile.rack)
+ },
+ }
+ })
+
+ const dispatch = useDispatch()
+ const onClick = (x, y) => dispatch(addRackToTile(x, y))
+ return <ObjectHoverLayerComponent {...props} {...state} onClick={onClick} />
+}
+
+export default ObjectHoverLayer
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js
new file mode 100644
index 00000000..87240813
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/RoomHoverLayer.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from 'react'
+import { useDispatch, useSelector } from 'react-redux'
+import { toggleTileAtLocation } from '../../../../redux/actions/topology/building'
+import RoomHoverLayerComponent from '../../../../components/app/map/layers/RoomHoverLayerComponent'
+import {
+ deriveValidNextTilePositions,
+ findPositionInPositions,
+ findPositionInRooms,
+} from '../../../../util/tile-calculations'
+
+const RoomHoverLayer = (props) => {
+ const dispatch = useDispatch()
+ const onClick = (x, y) => dispatch(toggleTileAtLocation(x, y))
+
+ const state = useSelector((state) => {
+ return {
+ mapPosition: state.map.position,
+ mapScale: state.map.scale,
+ isEnabled: () => state.construction.currentRoomInConstruction !== '-1',
+ isValid: (x, y) => {
+ 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) =>
+ state.objects.topology[state.currentTopologyId].rooms.indexOf(room._id) !== -1 &&
+ room._id !== state.construction.currentRoomInConstruction
+ )
+
+ ;[...oldRooms, newRoom].forEach((room) => {
+ room.tiles = room.tiles.map((tileId) => state.objects.tile[tileId])
+ })
+ if (newRoom.tiles.length === 0) {
+ return findPositionInRooms(oldRooms, x, y) === -1
+ }
+
+ const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles)
+ return findPositionInPositions(validNextPositions, x, y) !== -1
+ },
+ }
+ })
+ return <RoomHoverLayerComponent onClick={onClick} {...props} {...state} />
+}
+
+export default RoomHoverLayer