summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/components/app
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/app')
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js5
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js118
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ExportCanvasComponent.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.module.scss10
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.sass9
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.js4
-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/ToolPanelComponent.sass5
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/controls/ZoomControlComponent.js6
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/elements/ImageComponent.js54
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/elements/RoomTile.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/elements/WallSegment.js4
-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.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js6
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/groups/WallGroup.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js104
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/results/PortfolioResultsComponent.js6
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.js80
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.module.scss57
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.sass50
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/project/PortfolioListComponent.js119
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/project/ProjectSidebarComponent.js5
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/project/ScenarioListComponent.js124
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/project/TopologyListComponent.js100
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/NameComponent.js5
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/building/NewRoomConstructionComponent.js17
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/BackToRackComponent.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/DeleteMachineComponent.js10
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/MachineNameComponent.js5
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitAddComponent.js57
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js10
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitTabsComponent.js28
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/AddPrefabComponent.js9
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/BackToRoomComponent.js9
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/DeleteRackComponent.js10
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/EmptySlotComponent.js17
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js30
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.module.scss3
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.sass2
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackNameComponent.js6
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.js8
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.module.scss14
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.sass11
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/BackToBuildingComponent.js4
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/DeleteRoomComponent.js9
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/EditRoomComponent.js22
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RackConstructionComponent.js23
-rw-r--r--opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RoomNameComponent.js6
52 files changed, 600 insertions, 623 deletions
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
index 7efea9b0..ddb94990 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/LoadingScreen.js
@@ -1,9 +1,10 @@
import React from 'react'
-import FontAwesome from 'react-fontawesome'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faSpinner } from '@fortawesome/free-solid-svg-icons'
const LoadingScreen = () => (
<div className="display-4">
- <FontAwesome name="refresh" className="mr-4" spin />
+ <FontAwesomeIcon icon={faSpinner} spin className="mr-4" />
Loading your project...
</div>
)
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
index 7ca10792..7c97f3e4 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js
@@ -1,4 +1,4 @@
-import React from 'react'
+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'
@@ -6,85 +6,75 @@ import ObjectHoverLayer from '../../../containers/app/map/layers/ObjectHoverLaye
import RoomHoverLayer from '../../../containers/app/map/layers/RoomHoverLayer'
import { NAVBAR_HEIGHT } from '../../navigation/Navbar'
import { MAP_MOVE_PIXELS_PER_EVENT } from './MapConstants'
-import { Provider } from 'react-redux'
-import { store } from '../../../store/configure-store'
+import { Provider, useStore } from 'react-redux'
-class MapStageComponent extends React.Component {
- state = {
- mouseX: 0,
- mouseY: 0,
+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),
}
- constructor(props) {
- super(props)
+ const moveWithDelta = (deltaX, deltaY) =>
+ setMapPositionWithBoundsCheck(mapPosition.x + deltaX, mapPosition.y + deltaY)
+ const updateMousePosition = () => {
+ if (!stage.current) {
+ return
+ }
- this.updateDimensions = this.updateDimensions.bind(this)
- this.updateScale = this.updateScale.bind(this)
+ 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)
- componentDidMount() {
- this.updateDimensions()
+ useEffect(() => {
+ updateDimensions()
- window.addEventListener('resize', this.updateDimensions)
- window.addEventListener('wheel', this.updateScale)
+ window.addEventListener('resize', updateDimensions)
+ window.addEventListener('wheel', updateScale)
window['exportCanvasToImage'] = () => {
const download = document.createElement('a')
- download.href = this.stage.getStage().toDataURL()
+ download.href = stage.current.getStage().toDataURL()
download.download = 'opendc-canvas-export-' + Date.now() + '.png'
download.click()
}
- }
-
- componentWillUnmount() {
- window.removeEventListener('resize', this.updateDimensions)
- window.removeEventListener('wheel', this.updateScale)
- }
-
- updateDimensions() {
- this.props.setMapDimensions(window.innerWidth, window.innerHeight - NAVBAR_HEIGHT)
- }
-
- updateScale(e) {
- this.props.zoomInOnPosition(e.deltaY < 0, this.state.mouseX, this.state.mouseY)
- }
-
- updateMousePosition() {
- const mousePos = this.stage.getStage().getPointerPosition()
- this.setState({ mouseX: mousePos.x, mouseY: mousePos.y })
- }
- handlers = {
- MOVE_LEFT: () => this.moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0),
- MOVE_RIGHT: () => this.moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0),
- MOVE_UP: () => this.moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT),
- MOVE_DOWN: () => this.moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT),
- }
+ return () => {
+ window.removeEventListener('resize', updateDimensions)
+ window.removeEventListener('wheel', updateScale)
+ }
+ }, [])
- moveWithDelta(deltaX, deltaY) {
- this.props.setMapPositionWithBoundsCheck(this.props.mapPosition.x + deltaX, this.props.mapPosition.y + deltaY)
- }
+ const store = useStore()
- render() {
- return (
- <HotKeys handlers={this.handlers}>
- <Stage
- ref={(stage) => {
- this.stage = stage
- }}
- width={this.props.mapDimensions.width}
- height={this.props.mapDimensions.height}
- onMouseMove={this.updateMousePosition.bind(this)}
- >
- <Provider store={store}>
- <MapLayer />
- <RoomHoverLayer mouseX={this.state.mouseX} mouseY={this.state.mouseY} />
- <ObjectHoverLayer mouseX={this.state.mouseX} mouseY={this.state.mouseY} />
- </Provider>
- </Stage>
- </HotKeys>
- )
- }
+ 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>
+ )
}
export default MapStageComponent
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
index 8487f47b..9e8cb36a 100644
--- 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
@@ -1,4 +1,6 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faCamera } from '@fortawesome/free-solid-svg-icons'
const ExportCanvasComponent = () => (
<button
@@ -6,7 +8,7 @@ const ExportCanvasComponent = () => (
title="Export Canvas to PNG Image"
onClick={() => window['exportCanvasToImage']()}
>
- <span className="fa fa-camera" />
+ <FontAwesomeIcon icon={faCamera} />
</button>
)
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/ScaleIndicatorComponent.js
index 7cbb45c0..13226602 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/ScaleIndicatorComponent.js
@@ -1,9 +1,9 @@
import React from 'react'
import { TILE_SIZE_IN_METERS, TILE_SIZE_IN_PIXELS } from '../MapConstants'
-import './ScaleIndicatorComponent.sass'
+import { scaleIndicator } from './ScaleIndicatorComponent.module.scss'
const ScaleIndicatorComponent = ({ scale }) => (
- <div className="scale-indicator" style={{ width: TILE_SIZE_IN_PIXELS * scale }}>
+ <div className={scaleIndicator} style={{ width: TILE_SIZE_IN_PIXELS * scale }}>
{TILE_SIZE_IN_METERS}m
</div>
)
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/ScaleIndicatorComponent.module.scss
new file mode 100644
index 00000000..f19e0ff2
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.module.scss
@@ -0,0 +1,10 @@
+.scaleIndicator {
+ position: absolute;
+ right: 10px;
+ bottom: 10px;
+ z-index: 50;
+
+ border: solid 2px #212529;
+ border-top: none;
+ border-left: none;
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.sass b/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.sass
deleted file mode 100644
index 03a72c99..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.sass
+++ /dev/null
@@ -1,9 +0,0 @@
-.scale-indicator
- position: absolute
- right: 10px
- bottom: 10px
- z-index: 50
-
- border: solid 2px #212529
- border-top: none
- border-left: none
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
index f372734d..d2f70953 100644
--- 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
@@ -1,10 +1,10 @@
import React from 'react'
import ZoomControlContainer from '../../../../containers/app/map/controls/ZoomControlContainer'
import ExportCanvasComponent from './ExportCanvasComponent'
-import './ToolPanelComponent.sass'
+import { toolPanel } from './ToolPanelComponent.module.scss'
const ToolPanelComponent = () => (
- <div className="tool-panel">
+ <div className={toolPanel}>
<ZoomControlContainer />
<ExportCanvasComponent />
</div>
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
new file mode 100644
index 00000000..970b1ce2
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.module.scss
@@ -0,0 +1,6 @@
+.toolPanel {
+ position: absolute;
+ left: 10px;
+ bottom: 10px;
+ z-index: 50;
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.sass b/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.sass
deleted file mode 100644
index 8b27d24a..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.sass
+++ /dev/null
@@ -1,5 +0,0 @@
-.tool-panel
- position: absolute
- left: 10px
- bottom: 10px
- z-index: 50
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
index 65944bea..6bae792c 100644
--- 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
@@ -1,4 +1,6 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'
const ZoomControlComponent = ({ zoomInOnCenter }) => {
return (
@@ -8,14 +10,14 @@ const ZoomControlComponent = ({ zoomInOnCenter }) => {
title="Zoom in"
onClick={() => zoomInOnCenter(true)}
>
- <span className="fa fa-plus" />
+ <FontAwesomeIcon icon={faPlus} />
</button>
<button
className="btn btn-default btn-circle btn-sm mr-1"
title="Zoom out"
onClick={() => zoomInOnCenter(false)}
>
- <span className="fa fa-minus" />
+ <FontAwesomeIcon icon={faMinus} />
</button>
</span>
)
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/elements/ImageComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/elements/ImageComponent.js
index 2b5c569f..7d304b6b 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/elements/ImageComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/elements/ImageComponent.js
@@ -1,48 +1,36 @@
import PropTypes from 'prop-types'
-import React from 'react'
+import React, { useEffect, useState } from 'react'
import { Image } from 'react-konva'
-class ImageComponent extends React.Component {
- static imageCaches = {}
- static propTypes = {
- src: PropTypes.string.isRequired,
- x: PropTypes.number.isRequired,
- y: PropTypes.number.isRequired,
- width: PropTypes.number.isRequired,
- height: PropTypes.number.isRequired,
- opacity: PropTypes.number.isRequired,
- }
+const imageCaches = {}
- state = {
- image: null,
- }
+function ImageComponent({ src, x, y, width, height, opacity }) {
+ const [image, setImage] = useState(null)
- componentDidMount() {
- if (ImageComponent.imageCaches[this.props.src]) {
- this.setState({ image: ImageComponent.imageCaches[this.props.src] })
+ useEffect(() => {
+ if (imageCaches[src]) {
+ setImage(imageCaches[src])
return
}
const image = new window.Image()
- image.src = this.props.src
+ image.src = src
image.onload = () => {
- this.setState({ image })
- ImageComponent.imageCaches[this.props.src] = image
+ setImage(image)
+ imageCaches[src] = image
}
- }
+ }, [src])
- render() {
- return (
- <Image
- image={this.state.image}
- x={this.props.x}
- y={this.props.y}
- width={this.props.width}
- height={this.props.height}
- opacity={this.props.opacity}
- />
- )
- }
+ return <Image image={image} x={x} y={y} width={width} height={height} opacity={opacity} />
+}
+
+ImageComponent.propTypes = {
+ src: PropTypes.string.isRequired,
+ x: PropTypes.number.isRequired,
+ y: PropTypes.number.isRequired,
+ width: PropTypes.number.isRequired,
+ height: PropTypes.number.isRequired,
+ opacity: PropTypes.number.isRequired,
}
export default ImageComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/elements/RoomTile.js b/opendc-web/opendc-web-ui/src/components/app/map/elements/RoomTile.js
index 43bf918e..b2cc1273 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/elements/RoomTile.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/elements/RoomTile.js
@@ -1,6 +1,6 @@
import React from 'react'
import { Rect } from 'react-konva'
-import Shapes from '../../../../shapes/index'
+import { Tile } from '../../../../shapes'
import { TILE_SIZE_IN_PIXELS } from '../MapConstants'
const RoomTile = ({ tile, color }) => (
@@ -14,7 +14,7 @@ const RoomTile = ({ tile, color }) => (
)
RoomTile.propTypes = {
- tile: Shapes.Tile,
+ tile: Tile,
}
export default RoomTile
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/elements/WallSegment.js b/opendc-web/opendc-web-ui/src/components/app/map/elements/WallSegment.js
index 8aa2aebf..ad6412c3 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/elements/WallSegment.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/elements/WallSegment.js
@@ -1,6 +1,6 @@
import React from 'react'
import { Line } from 'react-konva'
-import Shapes from '../../../../shapes/index'
+import { WallSegment as WallSegmentShape } from '../../../../shapes'
import { WALL_COLOR } from '../../../../util/colors'
import { TILE_SIZE_IN_PIXELS, WALL_WIDTH_IN_PIXELS } from '../MapConstants'
@@ -26,7 +26,7 @@ const WallSegment = ({ wallSegment }) => {
}
WallSegment.propTypes = {
- wallSegment: Shapes.WallSegment,
+ wallSegment: WallSegmentShape,
}
export default WallSegment
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 eb6dc24a..40e28f01 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
@@ -2,7 +2,7 @@ import React from 'react'
import { Group } from 'react-konva'
import RackEnergyFillContainer from '../../../../containers/app/map/RackEnergyFillContainer'
import RackSpaceFillContainer from '../../../../containers/app/map/RackSpaceFillContainer'
-import Shapes from '../../../../shapes/index'
+import { Tile } from '../../../../shapes'
import { RACK_BACKGROUND_COLOR } from '../../../../util/colors'
import TileObject from '../elements/TileObject'
@@ -19,7 +19,7 @@ const RackGroup = ({ tile }) => {
}
RackGroup.propTypes = {
- tile: Shapes.Tile,
+ tile: Tile,
}
export default RackGroup
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 1fd54687..d7c207ca 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
@@ -3,7 +3,7 @@ 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 Shapes from '../../../../shapes/index'
+import { Room } from '../../../../shapes'
const RoomGroup = ({ room, interactionLevel, currentRoomInConstruction, onClick }) => {
if (currentRoomInConstruction === room._id) {
@@ -42,7 +42,7 @@ const RoomGroup = ({ room, interactionLevel, currentRoomInConstruction, onClick
}
RoomGroup.propTypes = {
- room: Shapes.Room,
+ room: Room,
}
export default RoomGroup
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 1e106823..ff6ec7ec 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
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types'
import React from 'react'
import { Group } from 'react-konva'
import RackContainer from '../../../../containers/app/map/RackContainer'
-import Shapes from '../../../../shapes/index'
+import { Tile } from '../../../../shapes'
import { ROOM_DEFAULT_COLOR, ROOM_IN_CONSTRUCTION_COLOR } from '../../../../util/colors'
import RoomTile from '../elements/RoomTile'
@@ -28,7 +28,7 @@ const TileGroup = ({ tile, newTile, roomLoad, onClick }) => {
}
TileGroup.propTypes = {
- tile: Shapes.Tile,
+ tile: Tile,
newTile: PropTypes.bool,
}
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 6096fc8b..57107768 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
@@ -2,7 +2,7 @@ import React from 'react'
import { Group } from 'react-konva'
import GrayContainer from '../../../../containers/app/map/GrayContainer'
import RoomContainer from '../../../../containers/app/map/RoomContainer'
-import Shapes from '../../../../shapes/index'
+import { InteractionLevel, Topology } from '../../../../shapes'
const TopologyGroup = ({ topology, interactionLevel }) => {
if (!topology) {
@@ -37,8 +37,8 @@ const TopologyGroup = ({ topology, interactionLevel }) => {
}
TopologyGroup.propTypes = {
- topology: Shapes.Topology,
- interactionLevel: Shapes.InteractionLevel,
+ topology: Topology,
+ interactionLevel: InteractionLevel,
}
export default TopologyGroup
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/WallGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/WallGroup.js
index 7b0f5ca0..c73a95a7 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/groups/WallGroup.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/WallGroup.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Group } from 'react-konva'
-import Shapes from '../../../../shapes/index'
+import { Tile } from '../../../../shapes'
import { deriveWallLocations } from '../../../../util/tile-calculations'
import WallSegment from '../elements/WallSegment'
@@ -16,7 +16,7 @@ const WallGroup = ({ tiles }) => {
}
WallGroup.propTypes = {
- tiles: PropTypes.arrayOf(Shapes.Tile).isRequired,
+ tiles: PropTypes.arrayOf(Tile).isRequired,
}
export default WallGroup
diff --git a/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js b/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js
index bead87de..08d31dac 100644
--- a/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/map/layers/HoverLayerComponent.js
@@ -1,75 +1,63 @@
import PropTypes from 'prop-types'
-import React from 'react'
+import React, { useEffect, useState } 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,
- mapPosition: PropTypes.object.isRequired,
- mapScale: PropTypes.number.isRequired,
- isEnabled: PropTypes.func.isRequired,
- onClick: PropTypes.func.isRequired,
- }
-
- state = {
- positionX: -1,
- positionY: -1,
- validity: false,
- }
+function HoverLayerComponent({ mouseX, mouseY, mapPosition, mapScale, isEnabled, isValid, onClick, children }) {
+ const [pos, setPos] = useState([-1, -1])
+ const [x, y] = pos
+ const [valid, setValid] = useState(false)
- componentDidUpdate() {
- if (!this.props.isEnabled()) {
+ useEffect(() => {
+ if (!isEnabled()) {
return
}
- const positionX = Math.floor(
- (this.props.mouseX - this.props.mapPosition.x) / (this.props.mapScale * TILE_SIZE_IN_PIXELS)
- )
- const positionY = Math.floor(
- (this.props.mouseY - this.props.mapPosition.y) / (this.props.mapScale * TILE_SIZE_IN_PIXELS)
- )
+ const positionX = Math.floor((mouseX - mapPosition.x) / (mapScale * TILE_SIZE_IN_PIXELS))
+ const positionY = Math.floor((mouseY - mapPosition.y) / (mapScale * TILE_SIZE_IN_PIXELS))
- if (positionX !== this.state.positionX || positionY !== this.state.positionY) {
- this.setState({
- positionX,
- positionY,
- validity: this.props.isValid(positionX, positionY),
- })
+ if (positionX !== x || positionY !== y) {
+ setPos([positionX, positionY])
+ setValid(isValid(positionX, positionY))
}
- }
+ }, [mouseX, mouseY, mapPosition, mapScale])
- render() {
- if (!this.props.isEnabled()) {
- return <Layer />
- }
+ if (!isEnabled()) {
+ return <Layer />
+ }
- const pixelX = this.props.mapScale * this.state.positionX * TILE_SIZE_IN_PIXELS + this.props.mapPosition.x
- const pixelY = this.props.mapScale * this.state.positionY * TILE_SIZE_IN_PIXELS + this.props.mapPosition.y
+ const pixelX = mapScale * x * TILE_SIZE_IN_PIXELS + mapPosition.x
+ const pixelY = mapScale * y * TILE_SIZE_IN_PIXELS + mapPosition.y
+
+ return (
+ <Layer opacity={0.6}>
+ <HoverTile
+ pixelX={pixelX}
+ pixelY={pixelY}
+ scale={mapScale}
+ isValid={valid}
+ onClick={() => (valid ? onClick(x, y) : undefined)}
+ />
+ {children
+ ? React.cloneElement(children, {
+ pixelX,
+ pixelY,
+ scale: mapScale,
+ })
+ : undefined}
+ </Layer>
+ )
+}
- return (
- <Layer opacity={0.6}>
- <HoverTile
- pixelX={pixelX}
- pixelY={pixelY}
- scale={this.props.mapScale}
- isValid={this.state.validity}
- onClick={() =>
- this.state.validity ? this.props.onClick(this.state.positionX, this.state.positionY) : undefined
- }
- />
- {this.props.children
- ? React.cloneElement(this.props.children, {
- pixelX,
- pixelY,
- scale: this.props.mapScale,
- })
- : undefined}
- </Layer>
- )
- }
+HoverLayerComponent.propTypes = {
+ mouseX: PropTypes.number.isRequired,
+ mouseY: PropTypes.number.isRequired,
+ mapPosition: PropTypes.object.isRequired,
+ mapScale: PropTypes.number.isRequired,
+ isEnabled: PropTypes.func.isRequired,
+ isValid: PropTypes.func.isRequired,
+ onClick: PropTypes.func.isRequired,
}
export default HoverLayerComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/results/PortfolioResultsComponent.js b/opendc-web/opendc-web-ui/src/components/app/results/PortfolioResultsComponent.js
index 759acd57..983a5c1d 100644
--- a/opendc-web/opendc-web-ui/src/components/app/results/PortfolioResultsComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/results/PortfolioResultsComponent.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import { Bar, CartesianGrid, ComposedChart, ErrorBar, ResponsiveContainer, Scatter, XAxis, YAxis } from 'recharts'
import { AVAILABLE_METRICS, METRIC_NAMES_SHORT, METRIC_UNITS } from '../../../util/available-metrics'
import { mean, std } from 'mathjs'
-import Shapes from '../../../shapes/index'
+import { Portfolio, Scenario } from '../../../shapes'
import approx from 'approximate-number'
const PortfolioResultsComponent = ({ portfolio, scenarios }) => {
@@ -86,8 +86,8 @@ const PortfolioResultsComponent = ({ portfolio, scenarios }) => {
}
PortfolioResultsComponent.propTypes = {
- portfolio: Shapes.Portfolio,
- scenarios: PropTypes.arrayOf(Shapes.Scenario),
+ portfolio: Portfolio,
+ scenarios: PropTypes.arrayOf(Scenario),
}
export default PortfolioResultsComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.js
index f7368f54..ccaa4144 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.js
@@ -1,53 +1,47 @@
import PropTypes from 'prop-types'
import classNames from 'classnames'
-import React from 'react'
-import './Sidebar.sass'
+import React, { useState } from 'react'
+import { collapseButton, collapseButtonRight, sidebar, sidebarRight } from './Sidebar.module.scss'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
-class Sidebar extends React.Component {
- static propTypes = {
- isRight: PropTypes.bool.isRequired,
- collapsible: PropTypes.bool,
- }
+function Sidebar({ isRight, collapsible = true, children }) {
+ const [isCollapsed, setCollapsed] = useState(false)
- static defaultProps = {
- collapsible: true,
- }
+ const button = (
+ <div
+ className={classNames(collapseButton, {
+ [collapseButtonRight]: isRight,
+ })}
+ onClick={() => setCollapsed(!isCollapsed)}
+ >
+ {(isCollapsed && isRight) || (!isCollapsed && !isRight) ? (
+ <FontAwesomeIcon icon={faAngleLeft} title={isRight ? 'Expand' : 'Collapse'} />
+ ) : (
+ <FontAwesomeIcon icon={faAngleRight} title={isRight ? 'Collapse' : 'Expand'} />
+ )}
+ </div>
+ )
- state = {
- collapsed: false,
+ if (isCollapsed) {
+ return button
}
+ return (
+ <div
+ className={classNames(`${sidebar} p-3 h-100`, {
+ [sidebarRight]: isRight,
+ })}
+ onWheel={(e) => e.stopPropagation()}
+ >
+ {children}
+ {collapsible && button}
+ </div>
+ )
+}
- render() {
- const collapseButton = (
- <div
- className={classNames('sidebar-collapse-button', {
- 'sidebar-collapse-button-right': this.props.isRight,
- })}
- onClick={() => this.setState({ collapsed: !this.state.collapsed })}
- >
- {(this.state.collapsed && this.props.isRight) || (!this.state.collapsed && !this.props.isRight) ? (
- <span className="fa fa-angle-left" title={this.props.isRight ? 'Expand' : 'Collapse'} />
- ) : (
- <span className="fa fa-angle-right" title={this.props.isRight ? 'Collapse' : 'Expand'} />
- )}
- </div>
- )
-
- if (this.state.collapsed) {
- return collapseButton
- }
- return (
- <div
- className={classNames('sidebar p-3 h-100', {
- 'sidebar-right': this.props.isRight,
- })}
- onWheel={(e) => e.stopPropagation()}
- >
- {this.props.children}
- {this.props.collapsible && collapseButton}
- </div>
- )
- }
+Sidebar.propTypes = {
+ isRight: PropTypes.bool.isRequired,
+ collapsible: PropTypes.bool,
}
export default Sidebar
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.module.scss b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.module.scss
new file mode 100644
index 00000000..19c6a97f
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.module.scss
@@ -0,0 +1,57 @@
+@import 'src/style/_variables.scss';
+@import 'src/style/_mixins.scss';
+
+.collapseButton {
+ position: absolute;
+ left: 5px;
+ top: 5px;
+ padding: 5px 7px;
+
+ background: white;
+ border: solid 1px $gray-semi-light;
+ z-index: 99;
+
+ @include clickable;
+ border-radius: 5px;
+ transition: background 200ms;
+
+ &.collapseButtonRight {
+ left: auto;
+ right: 5px;
+ top: 5px;
+ }
+
+ &:hover {
+ background: #eeeeee;
+ }
+}
+
+.sidebar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: $side-bar-width;
+
+ z-index: 100;
+ background: white;
+
+ border-right: $gray-semi-dark 1px solid;
+
+ .collapseButton {
+ left: auto;
+ right: -25px;
+ }
+}
+
+.sidebarRight {
+ left: auto;
+ right: 0;
+
+ border-left: $gray-semi-dark 1px solid;
+ border-right: none;
+
+ .collapseButtonRight {
+ left: -25px;
+ right: auto;
+ }
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.sass b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.sass
deleted file mode 100644
index b8e15716..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.sass
+++ /dev/null
@@ -1,50 +0,0 @@
-@import ../../../style-globals/_variables.sass
-@import ../../../style-globals/_mixins.sass
-
-.sidebar-collapse-button
- position: absolute
- left: 5px
- top: 5px
- padding: 5px 7px
-
- background: white
- border: solid 1px $gray-semi-light
- z-index: 99
-
- +clickable
- +border-radius(5px)
- +transition(background, 200ms)
-
- &.sidebar-collapse-button-right
- left: auto
- right: 5px
- top: 5px
-
- &:hover
- background: #eeeeee
-
-.sidebar
- position: absolute
- top: 0
- left: 0
- width: $side-bar-width
-
- z-index: 100
- background: white
-
- border-right: $gray-semi-dark 1px solid
-
- .sidebar-collapse-button
- left: auto
- right: -25px
-
-.sidebar-right
- left: auto
- right: 0
-
- border-left: $gray-semi-dark 1px solid
- border-right: none
-
- .sidebar-collapse-button-right
- left: -25px
- right: auto
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/PortfolioListComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/PortfolioListComponent.js
index b000b9e2..9dd36d5e 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/PortfolioListComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/PortfolioListComponent.js
@@ -1,66 +1,71 @@
import PropTypes from 'prop-types'
import React from 'react'
-import Shapes from '../../../../shapes'
-import { Link } from 'react-router-dom'
-import FontAwesome from 'react-fontawesome'
+import { Portfolio } from '../../../../shapes'
+import Link from 'next/link'
import ScenarioListContainer from '../../../../containers/app/sidebars/project/ScenarioListContainer'
+import { Button, Col, Row } from 'reactstrap'
+import classNames from 'classnames'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus, faPlay, faTrash } from '@fortawesome/free-solid-svg-icons'
-class PortfolioListComponent extends React.Component {
- static propTypes = {
- portfolios: PropTypes.arrayOf(Shapes.Portfolio),
- currentProjectId: PropTypes.string.isRequired,
- currentPortfolioId: PropTypes.string,
- onNewPortfolio: PropTypes.func.isRequired,
- onChoosePortfolio: PropTypes.func.isRequired,
- onDeletePortfolio: PropTypes.func.isRequired,
- }
+function PortfolioListComponent({
+ portfolios,
+ currentProjectId,
+ currentPortfolioId,
+ onNewPortfolio,
+ onChoosePortfolio,
+ onDeletePortfolio,
+}) {
+ return (
+ <div className="pb-3">
+ <h2>
+ Portfolios
+ <Button color="primary" outline className="float-right" onClick={(e) => onNewPortfolio(e)}>
+ <FontAwesomeIcon icon={faPlus} />
+ </Button>
+ </h2>
- onDelete(id) {
- this.props.onDeletePortfolio(id)
- }
-
- render() {
- return (
- <div className="pb-3">
- <h2>
- Portfolios
- <button
- className="btn btn-outline-primary float-right"
- onClick={this.props.onNewPortfolio.bind(this)}
- >
- <FontAwesome name="plus" />
- </button>
- </h2>
+ {portfolios.map((portfolio, idx) => (
+ <div key={portfolio._id}>
+ <Row className="row mb-1">
+ <Col
+ xs="7"
+ className={classNames('align-self-center', {
+ 'font-weight-bold': portfolio._id === currentPortfolioId,
+ })}
+ >
+ {portfolio.name}
+ </Col>
+ <Col xs="5" className="text-right">
+ <Link href={`/projects/${currentProjectId}/portfolios/${portfolio._id}`}>
+ <Button
+ color="primary"
+ outline
+ className="mr-1"
+ onClick={() => onChoosePortfolio(portfolio._id)}
+ >
+ <FontAwesomeIcon icon={faPlay} />
+ </Button>
+ </Link>
+ <Button color="danger" outline onClick={() => onDeletePortfolio(portfolio._id)}>
+ <FontAwesomeIcon icon={faTrash} />
+ </Button>
+ </Col>
+ </Row>
+ <ScenarioListContainer portfolioId={portfolio._id} />
+ </div>
+ ))}
+ </div>
+ )
+}
- {this.props.portfolios.map((portfolio, idx) => (
- <div key={portfolio._id}>
- <div className="row mb-1">
- <div
- className={
- 'col-7 align-self-center ' +
- (portfolio._id === this.props.currentPortfolioId ? 'font-weight-bold' : '')
- }
- >
- {portfolio.name}
- </div>
- <div className="col-5 text-right">
- <Link
- className="btn btn-outline-primary mr-1 fa fa-play"
- to={`/projects/${this.props.currentProjectId}/portfolios/${portfolio._id}`}
- onClick={() => this.props.onChoosePortfolio(portfolio._id)}
- />
- <span
- className="btn btn-outline-danger fa fa-trash"
- onClick={() => this.onDelete(portfolio._id)}
- />
- </div>
- </div>
- <ScenarioListContainer portfolioId={portfolio._id} />
- </div>
- ))}
- </div>
- )
- }
+PortfolioListComponent.propTypes = {
+ portfolios: PropTypes.arrayOf(Portfolio),
+ currentProjectId: PropTypes.string.isRequired,
+ currentPortfolioId: PropTypes.string,
+ onNewPortfolio: PropTypes.func.isRequired,
+ onChoosePortfolio: PropTypes.func.isRequired,
+ onDeletePortfolio: PropTypes.func.isRequired,
}
export default PortfolioListComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ProjectSidebarComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ProjectSidebarComponent.js
index 4789315e..7dd13663 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ProjectSidebarComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ProjectSidebarComponent.js
@@ -2,13 +2,14 @@ import React from 'react'
import Sidebar from '../Sidebar'
import TopologyListContainer from '../../../../containers/app/sidebars/project/TopologyListContainer'
import PortfolioListContainer from '../../../../containers/app/sidebars/project/PortfolioListContainer'
+import { Container } from 'reactstrap'
const ProjectSidebarComponent = ({ collapsible }) => (
<Sidebar isRight={false} collapsible={collapsible}>
- <div className="h-100 overflow-auto container-fluid">
+ <Container fluid className="h-100 overflow-auto">
<TopologyListContainer />
<PortfolioListContainer />
- </div>
+ </Container>
</Sidebar>
)
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ScenarioListComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ScenarioListComponent.js
index e775a663..131a00b5 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ScenarioListComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/ScenarioListComponent.js
@@ -1,62 +1,76 @@
import PropTypes from 'prop-types'
import React from 'react'
-import Shapes from '../../../../shapes'
-import { Link } from 'react-router-dom'
-import FontAwesome from 'react-fontawesome'
+import { Scenario } from '../../../../shapes'
+import Link from 'next/link'
+import { Button, Col, Row } from 'reactstrap'
+import classNames from 'classnames'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus, faPlay, faTrash } from '@fortawesome/free-solid-svg-icons'
-class ScenarioListComponent extends React.Component {
- static propTypes = {
- scenarios: PropTypes.arrayOf(Shapes.Scenario),
- portfolioId: PropTypes.string,
- currentProjectId: PropTypes.string.isRequired,
- currentScenarioId: PropTypes.string,
- onNewScenario: PropTypes.func.isRequired,
- onChooseScenario: PropTypes.func.isRequired,
- onDeleteScenario: PropTypes.func.isRequired,
- }
-
- onDelete(id) {
- this.props.onDeleteScenario(id)
- }
-
- render() {
- return (
- <>
- {this.props.scenarios.map((scenario, idx) => (
- <div key={scenario._id} className="row mb-1">
- <div
- className={
- 'col-7 pl-5 align-self-center ' +
- (scenario._id === this.props.currentScenarioId ? 'font-weight-bold' : '')
- }
- >
- {scenario.name}
- </div>
- <div className="col-5 text-right">
- <Link
- className="btn btn-outline-primary mr-1 fa fa-play disabled"
- to={`/projects/${this.props.currentProjectId}/portfolios/${scenario.portfolioId}/scenarios/${scenario._id}`}
- onClick={() => this.props.onChooseScenario(scenario.portfolioId, scenario._id)}
- />
- <span
- className={'btn btn-outline-danger fa fa-trash ' + (idx === 0 ? 'disabled' : '')}
- onClick={() => (idx !== 0 ? this.onDelete(scenario._id) : undefined)}
- />
- </div>
- </div>
- ))}
- <div className="pl-4 mb-2">
- <div
- className="btn btn-outline-primary"
- onClick={() => this.props.onNewScenario(this.props.portfolioId)}
+function ScenarioListComponent({
+ scenarios,
+ portfolioId,
+ currentProjectId,
+ currentScenarioId,
+ onNewScenario,
+ onChooseScenario,
+ onDeleteScenario,
+}) {
+ return (
+ <>
+ {scenarios.map((scenario, idx) => (
+ <Row key={scenario._id} className="mb-1">
+ <Col
+ xs="7"
+ className={classNames('pl-5 align-self-center', {
+ 'font-weight-bold': scenario._id === currentScenarioId,
+ })}
>
- <FontAwesome name="plus" className="mr-1" />
- New scenario
- </div>
- </div>
- </>
- )
- }
+ {scenario.name}
+ </Col>
+ <Col xs="5" className="text-right">
+ <Link
+ href={`/projects/${currentProjectId}/portfolios/${scenario.portfolioId}/scenarios/${scenario._id}`}
+ >
+ <Button
+ color="primary"
+ outline
+ disabled
+ className="mr-1"
+ onClick={() => onChooseScenario(scenario.portfolioId, scenario._id)}
+ >
+ <FontAwesomeIcon icon={faPlay} />
+ </Button>
+ </Link>
+ <Button
+ color="danger"
+ outline
+ disabled={idx === 0}
+ onClick={() => (idx !== 0 ? onDeleteScenario(scenario._id) : undefined)}
+ >
+ <FontAwesomeIcon icon={faTrash} />
+ </Button>
+ </Col>
+ </Row>
+ ))}
+ <div className="pl-4 mb-2">
+ <Button color="primary" outline onClick={() => onNewScenario(portfolioId)}>
+ <FontAwesomeIcon icon={faPlus} className="mr-1" />
+ New scenario
+ </Button>
+ </div>
+ </>
+ )
+}
+
+ScenarioListComponent.propTypes = {
+ scenarios: PropTypes.arrayOf(Scenario),
+ portfolioId: PropTypes.string,
+ currentProjectId: PropTypes.string.isRequired,
+ currentScenarioId: PropTypes.string,
+ onNewScenario: PropTypes.func.isRequired,
+ onChooseScenario: PropTypes.func.isRequired,
+ onDeleteScenario: PropTypes.func.isRequired,
}
export default ScenarioListComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/TopologyListComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/TopologyListComponent.js
index 2f42f7e4..ac58669b 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/project/TopologyListComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/project/TopologyListComponent.js
@@ -1,60 +1,56 @@
import PropTypes from 'prop-types'
import React from 'react'
-import Shapes from '../../../../shapes'
-import FontAwesome from 'react-fontawesome'
+import { Topology } from '../../../../shapes'
+import { Button, Col, Row } from 'reactstrap'
+import classNames from 'classnames'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus, faPlay, faTrash } from '@fortawesome/free-solid-svg-icons'
-class TopologyListComponent extends React.Component {
- static propTypes = {
- topologies: PropTypes.arrayOf(Shapes.Topology),
- currentTopologyId: PropTypes.string,
- onChooseTopology: PropTypes.func.isRequired,
- onNewTopology: PropTypes.func.isRequired,
- onDeleteTopology: PropTypes.func.isRequired,
- }
+function TopologyListComponent({ topologies, currentTopologyId, onChooseTopology, onNewTopology, onDeleteTopology }) {
+ return (
+ <div className="pb-3">
+ <h2>
+ Topologies
+ <Button color="primary" outline className="float-right" onClick={onNewTopology}>
+ <FontAwesomeIcon icon={faPlus} />
+ </Button>
+ </h2>
- onChoose(id) {
- this.props.onChooseTopology(id)
- }
-
- onDelete(id) {
- this.props.onDeleteTopology(id)
- }
-
- render() {
- return (
- <div className="pb-3">
- <h2>
- Topologies
- <button className="btn btn-outline-primary float-right" onClick={this.props.onNewTopology}>
- <FontAwesome name="plus" />
- </button>
- </h2>
-
- {this.props.topologies.map((topology, idx) => (
- <div key={topology._id} className="row mb-1">
- <div
- className={
- 'col-7 align-self-center ' +
- (topology._id === this.props.currentTopologyId ? 'font-weight-bold' : '')
- }
+ {topologies.map((topology, idx) => (
+ <Row key={topology._id} className="mb-1">
+ <Col
+ xs="7"
+ className={classNames('align-self-center', {
+ 'font-weight-bold': topology._id === currentTopologyId,
+ })}
+ >
+ {topology.name}
+ </Col>
+ <Col xs="5" className="text-right">
+ <Button color="primary" outline className="mr-1" onClick={() => onChooseTopology(topology._id)}>
+ <FontAwesomeIcon icon={faPlay} />
+ </Button>
+ <Button
+ color="danger"
+ outline
+ disabled={idx === 0}
+ onClick={() => (idx !== 0 ? onDeleteTopology(topology._id) : undefined)}
>
- {topology.name}
- </div>
- <div className="col-5 text-right">
- <span
- className="btn btn-outline-primary mr-1 fa fa-play"
- onClick={() => this.onChoose(topology._id)}
- />
- <span
- className={'btn btn-outline-danger fa fa-trash ' + (idx === 0 ? 'disabled' : '')}
- onClick={() => (idx !== 0 ? this.onDelete(topology._id) : undefined)}
- />
- </div>
- </div>
- ))}
- </div>
- )
- }
+ <FontAwesomeIcon icon={faTrash} />
+ </Button>
+ </Col>
+ </Row>
+ ))}
+ </div>
+ )
+}
+
+TopologyListComponent.propTypes = {
+ topologies: PropTypes.arrayOf(Topology),
+ currentTopologyId: PropTypes.string,
+ onChooseTopology: PropTypes.func.isRequired,
+ onNewTopology: PropTypes.func.isRequired,
+ onDeleteTopology: PropTypes.func.isRequired,
}
export default TopologyListComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/NameComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/NameComponent.js
index 5fb0dc55..b4cbc78f 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/NameComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/NameComponent.js
@@ -1,11 +1,12 @@
import React from 'react'
-import FontAwesome from 'react-fontawesome'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPencilAlt } from '@fortawesome/free-solid-svg-icons'
const NameComponent = ({ name, onEdit }) => (
<h2>
{name}
<button className="btn btn-outline-secondary float-right" onClick={onEdit}>
- <FontAwesome name="pencil" />
+ <FontAwesomeIcon icon={faPencilAlt} />
</button>
</h2>
)
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/building/NewRoomConstructionComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/building/NewRoomConstructionComponent.js
index fd552c1e..b1461743 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/building/NewRoomConstructionComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/building/NewRoomConstructionComponent.js
@@ -1,24 +1,27 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus, faCheck, faTimes } from '@fortawesome/free-solid-svg-icons'
+import { Button } from 'reactstrap'
const NewRoomConstructionComponent = ({ onStart, onFinish, onCancel, currentRoomInConstruction }) => {
if (currentRoomInConstruction === '-1') {
return (
<div className="btn btn-outline-primary btn-block" onClick={onStart}>
- <span className="fa fa-plus mr-2" />
+ <FontAwesomeIcon icon={faPlus} className="mr-2" />
Construct a new room
</div>
)
}
return (
<div>
- <div className="btn btn-primary btn-block" onClick={onFinish}>
- <span className="fa fa-check mr-2" />
+ <Button color="primary" block onClick={onFinish}>
+ <FontAwesomeIcon icon={faCheck} className="mr-2" />
Finalize new room
- </div>
- <div className="btn btn-default btn-block" onClick={onCancel}>
- <span className="fa fa-times mr-2" />
+ </Button>
+ <Button color="default" block onClick={onCancel}>
+ <FontAwesomeIcon icon={faTimes} className="mr-2" />
Cancel construction
- </div>
+ </Button>
</div>
)
}
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/BackToRackComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/BackToRackComponent.js
index 70d522b2..eac99643 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/BackToRackComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/BackToRackComponent.js
@@ -1,8 +1,10 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faAngleLeft } from '@fortawesome/free-solid-svg-icons'
const BackToRackComponent = ({ onClick }) => (
<div className="btn btn-secondary btn-block" onClick={onClick}>
- <span className="fa fa-angle-left mr-2" />
+ <FontAwesomeIcon icon={faAngleLeft} className="mr-2" />
Back to rack
</div>
)
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/DeleteMachineComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/DeleteMachineComponent.js
deleted file mode 100644
index 37820316..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/DeleteMachineComponent.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react'
-
-const DeleteMachineComponent = ({ onClick }) => (
- <div className="btn btn-outline-danger btn-block" onClick={onClick}>
- <span className="fa fa-trash mr-2" />
- Delete this machine
- </div>
-)
-
-export default DeleteMachineComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/MachineNameComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/MachineNameComponent.js
deleted file mode 100644
index 992383c4..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/MachineNameComponent.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react'
-
-const MachineNameComponent = ({ position }) => <h2>Machine at slot {position}</h2>
-
-export default MachineNameComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitAddComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitAddComponent.js
index 4e9dbc7e..532add37 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitAddComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitAddComponent.js
@@ -1,35 +1,34 @@
import PropTypes from 'prop-types'
-import React from 'react'
+import React, { useRef } from 'react'
+import { Button, Form, FormGroup, Input } from 'reactstrap'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus } from '@fortawesome/free-solid-svg-icons'
-class UnitAddComponent extends React.Component {
- static propTypes = {
- units: PropTypes.array.isRequired,
- onAdd: PropTypes.func.isRequired,
- }
+function UnitAddComponent({ units, onAdd }) {
+ const unitSelect = useRef(null)
- render() {
- return (
- <div className="form-inline">
- <div className="form-group w-100">
- <select className="form-control w-70 mr-1" ref={(unitSelect) => (this.unitSelect = unitSelect)}>
- {this.props.units.map((unit) => (
- <option value={unit._id} key={unit._id}>
- {unit.name}
- </option>
- ))}
- </select>
- <button
- type="submit"
- className="btn btn-outline-primary"
- onClick={() => this.props.onAdd(this.unitSelect.value)}
- >
- <span className="fa fa-plus mr-2" />
- Add
- </button>
- </div>
- </div>
- )
- }
+ return (
+ <Form inline>
+ <FormGroup className="w-100">
+ <Input type="select" className="w-70 mr-1" innerRef={unitSelect}>
+ {units.map((unit) => (
+ <option value={unit._id} key={unit._id}>
+ {unit.name}
+ </option>
+ ))}
+ </Input>
+ <Button color="primary" outline onClick={() => onAdd(unitSelect.current.value)}>
+ <FontAwesomeIcon icon={faPlus} className="mr-2" />
+ Add
+ </Button>
+ </FormGroup>
+ </Form>
+ )
+}
+
+UnitAddComponent.propTypes = {
+ units: PropTypes.array.isRequired,
+ onAdd: PropTypes.func.isRequired,
}
export default UnitAddComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js
index de55e506..aa473f91 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js
@@ -1,5 +1,7 @@
import React from 'react'
import { UncontrolledPopover, PopoverHeader, PopoverBody, Button } from 'reactstrap'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faTrash, faInfoCircle } from '@fortawesome/free-solid-svg-icons'
function UnitComponent({ index, unitType, unit, onDelete }) {
let unitInfo
@@ -37,13 +39,17 @@ function UnitComponent({ index, unitType, unit, onDelete }) {
<li className="d-flex list-group-item justify-content-between align-items-center">
<span style={{ maxWidth: '60%' }}>{unit.name}</span>
<span>
- <Button outline={true} color="info" className="mr-1 fa fa-info-circle" id={`unit-${index}`} />
+ <Button outline={true} color="info" className="mr-1" id={`unit-${index}`}>
+ <FontAwesomeIcon icon={faInfoCircle} />
+ </Button>
<UncontrolledPopover trigger="focus" placement="left" target={`unit-${index}`}>
<PopoverHeader>Unit Information</PopoverHeader>
<PopoverBody>{unitInfo}</PopoverBody>
</UncontrolledPopover>
- <span className="btn btn-outline-danger fa fa-trash" onClick={onDelete} />
+ <Button outline color="danger" onClick={onDelete}>
+ <FontAwesomeIcon icon={faTrash} />
+ </Button>
</span>
</li>
)
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitTabsComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitTabsComponent.js
index 6599fefd..ebb5f479 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitTabsComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitTabsComponent.js
@@ -1,5 +1,5 @@
import React, { useState } from 'react'
-import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'
+import { Nav, NavItem, NavLink, Row, TabContent, TabPane } from 'reactstrap'
import UnitAddContainer from '../../../../../containers/app/sidebars/topology/machine/UnitAddContainer'
import UnitListContainer from '../../../../../containers/app/sidebars/topology/machine/UnitListContainer'
@@ -10,7 +10,7 @@ const UnitTabsComponent = () => {
}
return (
- <div>
+ <div className="mt-2">
<Nav tabs>
<NavItem>
<NavLink
@@ -55,20 +55,28 @@ const UnitTabsComponent = () => {
</Nav>
<TabContent activeTab={activeTab}>
<TabPane tabId="cpu-units">
- <UnitAddContainer unitType="cpu" />
- <UnitListContainer unitType="cpu" />
+ <div className="py-2">
+ <UnitAddContainer unitType="cpu" />
+ <UnitListContainer unitType="cpu" />
+ </div>
</TabPane>
<TabPane tabId="gpu-units">
- <UnitAddContainer unitType="gpu" />
- <UnitListContainer unitType="gpu" />
+ <div className="py-2">
+ <UnitAddContainer unitType="gpu" />
+ <UnitListContainer unitType="gpu" />
+ </div>
</TabPane>
<TabPane tabId="memory-units">
- <UnitAddContainer unitType="memory" />
- <UnitListContainer unitType="memory" />
+ <div className="py-2">
+ <UnitAddContainer unitType="memory" />
+ <UnitListContainer unitType="memory" />
+ </div>
</TabPane>
<TabPane tabId="storage-units">
- <UnitAddContainer unitType="storage" />
- <UnitListContainer unitType="storage" />
+ <div className="py-2">
+ <UnitAddContainer unitType="storage" />
+ <UnitListContainer unitType="storage" />
+ </div>
</TabPane>
</TabContent>
</div>
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/AddPrefabComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/AddPrefabComponent.js
index 75418f9d..d0218f38 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/AddPrefabComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/AddPrefabComponent.js
@@ -1,10 +1,13 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faSave } from '@fortawesome/free-solid-svg-icons'
+import { Button } from 'reactstrap'
const AddPrefabComponent = ({ onClick }) => (
- <div className="btn btn-primary btn-block" onClick={onClick}>
- <span className="fa fa-floppy-o mr-2" />
+ <Button color="primary" block onClick={onClick}>
+ <FontAwesomeIcon icon={faSave} className="mr-2" />
Save this rack to a prefab
- </div>
+ </Button>
)
export default AddPrefabComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/BackToRoomComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/BackToRoomComponent.js
index c14775bf..f6a6f79b 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/BackToRoomComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/BackToRoomComponent.js
@@ -1,10 +1,13 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faAngleLeft } from '@fortawesome/free-solid-svg-icons'
+import { Button } from 'reactstrap'
const BackToRoomComponent = ({ onClick }) => (
- <div className="btn btn-secondary btn-block mb-2" onClick={onClick}>
- <span className="fa fa-angle-left mr-2" />
+ <Button color="secondary" block className="mb-2" onClick={onClick}>
+ <FontAwesomeIcon icon={faAngleLeft} className="mr-2" />
Back to room
- </div>
+ </Button>
)
export default BackToRoomComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/DeleteRackComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/DeleteRackComponent.js
deleted file mode 100644
index 23b0daac..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/DeleteRackComponent.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react'
-
-const DeleteRackComponent = ({ onClick }) => (
- <div className="btn btn-outline-danger btn-block" onClick={onClick}>
- <span className="fa fa-trash mr-2" />
- Delete this rack
- </div>
-)
-
-export default DeleteRackComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/EmptySlotComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/EmptySlotComponent.js
index d7e30f1d..d6fa9dc9 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/EmptySlotComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/EmptySlotComponent.js
@@ -1,13 +1,18 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faPlus } from '@fortawesome/free-solid-svg-icons'
+import { ListGroupItem, Badge, Button } from 'reactstrap'
const EmptySlotComponent = ({ position, onAdd }) => (
- <li className="list-group-item d-flex justify-content-between align-items-center">
- <span className="badge badge-default badge-info mr-1 disabled">{position}</span>
- <button className="btn btn-outline-primary" onClick={onAdd}>
- <span className="fa fa-plus mr-2" />
+ <ListGroupItem className="d-flex justify-content-between align-items-center">
+ <Badge color="info" className="mr-1">
+ {position}
+ </Badge>
+ <Button color="primary" outline onClick={onAdd}>
+ <FontAwesomeIcon icon={faPlus} className="mr-2" />
Add machine
- </button>
- </li>
+ </Button>
+ </ListGroupItem>
)
export default EmptySlotComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js
index caa3dc04..36b15c71 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js
@@ -1,13 +1,16 @@
import React from 'react'
-import Shapes from '../../../../../shapes'
+import Image from 'next/image'
+import { Machine } from '../../../../../shapes'
+import { Badge, ListGroupItem } from 'reactstrap'
const UnitIcon = ({ id, type }) => (
- <div>
- <img
+ <div className="ml-1">
+ <Image
src={'/img/topology/' + id + '-icon.png'}
alt={'Machine contains ' + type + ' units'}
- className="img-fluid ml-1"
- style={{ maxHeight: '35px' }}
+ layout="intrinsic"
+ height={35}
+ width={35}
/>
</div>
)
@@ -17,27 +20,28 @@ const MachineComponent = ({ position, machine, onClick }) => {
machine.cpuIds.length + machine.gpuIds.length + machine.memoryIds.length + machine.storageIds.length === 0
return (
- <li
- className="d-flex list-group-item list-group-item-action justify-content-between align-items-center"
+ <ListGroupItem
+ action
+ className="d-flex justify-content-between align-items-center"
onClick={onClick}
style={{ backgroundColor: 'white' }}
>
- <span className="badge badge-default badge-info mr-1">{position}</span>
+ <Badge color="info" className="mr-1">
+ {position}
+ </Badge>
<div className="d-inline-flex">
{machine.cpuIds.length > 0 ? <UnitIcon id="cpu" type="CPU" /> : undefined}
{machine.gpuIds.length > 0 ? <UnitIcon id="gpu" type="GPU" /> : undefined}
{machine.memoryIds.length > 0 ? <UnitIcon id="memory" type="memory" /> : undefined}
{machine.storageIds.length > 0 ? <UnitIcon id="storage" type="storage" /> : undefined}
- {hasNoUnits ? (
- <span className="badge badge-default badge-warning">Machine with no units</span>
- ) : undefined}
+ {hasNoUnits ? <Badge color="warning">Machine with no units</Badge> : undefined}
</div>
- </li>
+ </ListGroupItem>
)
}
MachineComponent.propTypes = {
- machine: Shapes.Machine,
+ machine: Machine,
}
export default MachineComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.js
index 12be26bd..1c07d237 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.js
@@ -1,11 +1,11 @@
import React from 'react'
import EmptySlotContainer from '../../../../../containers/app/sidebars/topology/rack/EmptySlotContainer'
import MachineContainer from '../../../../../containers/app/sidebars/topology/rack/MachineContainer'
-import './MachineListComponent.sass'
+import { machineList } from './MachineListComponent.module.scss'
const MachineListComponent = ({ machineIds }) => {
return (
- <ul className="list-group machine-list">
+ <ul className={`list-group ${machineList}`}>
{machineIds.map((machineId, index) => {
if (machineId === null) {
return <EmptySlotContainer key={index} position={index + 1} />
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.module.scss b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.module.scss
new file mode 100644
index 00000000..f075aac9
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.module.scss
@@ -0,0 +1,3 @@
+.machineList li {
+ min-height: 64px;
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.sass b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.sass
deleted file mode 100644
index 11b82c93..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.sass
+++ /dev/null
@@ -1,2 +0,0 @@
-.machine-list li
- min-height: 64px
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackNameComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackNameComponent.js
deleted file mode 100644
index b701909a..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackNameComponent.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from 'react'
-import NameComponent from '../NameComponent'
-
-const RackNameComponent = ({ rackName, onEdit }) => <NameComponent name={rackName} onEdit={onEdit} />
-
-export default RackNameComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.js
index ca41bf57..74313bf7 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.js
@@ -3,19 +3,19 @@ import BackToRoomContainer from '../../../../../containers/app/sidebars/topology
import DeleteRackContainer from '../../../../../containers/app/sidebars/topology/rack/DeleteRackContainer'
import MachineListContainer from '../../../../../containers/app/sidebars/topology/rack/MachineListContainer'
import RackNameContainer from '../../../../../containers/app/sidebars/topology/rack/RackNameContainer'
-import './RackSidebarComponent.sass'
+import { sidebarContainer, sidebarHeaderContainer, machineListContainer } from './RackSidebarComponent.module.scss'
import AddPrefabContainer from '../../../../../containers/app/sidebars/topology/rack/AddPrefabContainer'
const RackSidebarComponent = () => {
return (
- <div className="rack-sidebar-container flex-column">
- <div className="rack-sidebar-header-container">
+ <div className={`${sidebarContainer} flex-column`}>
+ <div className={sidebarHeaderContainer}>
<RackNameContainer />
<BackToRoomContainer />
<AddPrefabContainer />
<DeleteRackContainer />
</div>
- <div className="machine-list-container mt-2">
+ <div className={`${machineListContainer} mt-2`}>
<MachineListContainer />
</div>
</div>
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.module.scss b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.module.scss
new file mode 100644
index 00000000..8ce3836a
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.module.scss
@@ -0,0 +1,14 @@
+.sidebarContainer {
+ display: flex;
+ height: 100%;
+ max-height: 100%;
+}
+
+.sidebarHeaderContainer {
+ flex: 0;
+}
+
+.machineListContainer {
+ flex: 1;
+ overflow-y: scroll;
+}
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.sass b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.sass
deleted file mode 100644
index 29fec02a..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.sass
+++ /dev/null
@@ -1,11 +0,0 @@
-.rack-sidebar-container
- display: flex
- height: 100%
- max-height: 100%
-
-.rack-sidebar-header-container
- flex: 0
-
-.machine-list-container
- flex: 1
- overflow-y: scroll
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/BackToBuildingComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/BackToBuildingComponent.js
index 64c0a1f6..696b345b 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/BackToBuildingComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/BackToBuildingComponent.js
@@ -1,8 +1,10 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faAngleLeft } from '@fortawesome/free-solid-svg-icons'
const BackToBuildingComponent = ({ onClick }) => (
<div className="btn btn-secondary btn-block mb-2" onClick={onClick}>
- <span className="fa fa-angle-left mr-2" />
+ <FontAwesomeIcon icon={faAngleLeft} className="mr-2" />
Back to building
</div>
)
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/DeleteRoomComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/DeleteRoomComponent.js
index 78417359..242f7a2b 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/DeleteRoomComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/DeleteRoomComponent.js
@@ -1,10 +1,13 @@
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faTrash } from '@fortawesome/free-solid-svg-icons'
+import { Button } from 'reactstrap'
const DeleteRoomComponent = ({ onClick }) => (
- <div className="btn btn-outline-danger btn-block" onClick={onClick}>
- <span className="fa fa-trash mr-2" />
+ <Button color="danger" outline block onClick={onClick}>
+ <FontAwesomeIcon icon={faTrash} className="mr-2" />
Delete this room
- </div>
+ </Button>
)
export default DeleteRoomComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/EditRoomComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/EditRoomComponent.js
deleted file mode 100644
index 857a646f..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/EditRoomComponent.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import classNames from 'classnames'
-import React from 'react'
-
-const EditRoomComponent = ({ onEdit, onFinish, isEditing, isInRackConstructionMode }) =>
- isEditing ? (
- <div className="btn btn-info btn-block" onClick={onFinish}>
- <span className="fa fa-check mr-2" />
- Finish editing room
- </div>
- ) : (
- <div
- className={classNames('btn btn-outline-info btn-block', {
- disabled: isInRackConstructionMode,
- })}
- onClick={() => (isInRackConstructionMode ? undefined : onEdit())}
- >
- <span className="fa fa-pencil mr-2" />
- Edit the tiles of this room
- </div>
- )
-
-export default EditRoomComponent
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RackConstructionComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RackConstructionComponent.js
index 44566f61..19d6b309 100644
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RackConstructionComponent.js
+++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RackConstructionComponent.js
@@ -1,26 +1,29 @@
-import classNames from 'classnames'
import React from 'react'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faTimes, faPlus } from '@fortawesome/free-solid-svg-icons'
+import { Button } from 'reactstrap'
const RackConstructionComponent = ({ onStart, onStop, inRackConstructionMode, isEditingRoom }) => {
if (inRackConstructionMode) {
return (
- <div className="btn btn-primary btn-block" onClick={onStop}>
- <span className="fa fa-times mr-2" />
+ <Button color="primary" block onClick={onStop}>
+ <FontAwesomeIcon icon={faTimes} className="mr-2" />
Stop rack construction
- </div>
+ </Button>
)
}
return (
- <div
- className={classNames('btn btn-outline-primary btn-block', {
- disabled: isEditingRoom,
- })}
+ <Button
+ color="primary"
+ outline
+ block
+ disabled={isEditingRoom}
onClick={() => (isEditingRoom ? undefined : onStart())}
>
- <span className="fa fa-plus mr-2" />
+ <FontAwesomeIcon icon={faPlus} className="mr-2" />
Start rack construction
- </div>
+ </Button>
)
}
diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RoomNameComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RoomNameComponent.js
deleted file mode 100644
index d637828e..00000000
--- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/room/RoomNameComponent.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from 'react'
-import NameComponent from '../NameComponent'
-
-const RoomNameComponent = ({ roomName, onEdit }) => <NameComponent name={roomName} onEdit={onEdit} />
-
-export default RoomNameComponent