From 6d5a2eebb609da67239ea37d12d6b2d3bbfef76e Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 28 Oct 2020 16:41:53 +0100 Subject: ui: Do not clutter component tree with Redux connects This change refactors the frontend to use hooks for obtaining state within the Redux store as opposed to using Higher-Order Components (HOCs). This eliminates a lot of clutter in the components. --- .../src/components/app/map/MapStageComponent.js | 28 +--- .../src/containers/app/map/GrayContainer.js | 13 +- .../src/containers/app/map/MapStage.js | 33 ++-- .../src/containers/app/map/RackContainer.js | 12 +- .../containers/app/map/RackEnergyFillContainer.js | 44 +++--- .../containers/app/map/RackSpaceFillContainer.js | 20 +-- .../src/containers/app/map/RoomContainer.js | 27 ++-- .../src/containers/app/map/TileContainer.js | 29 ++-- .../src/containers/app/map/TopologyContainer.js | 19 +-- .../src/containers/app/map/WallContainer.js | 14 +- .../app/map/controls/ScaleIndicatorContainer.js | 12 +- .../app/map/controls/ZoomControlContainer.js | 19 +-- .../src/containers/app/map/layers/MapLayer.js | 13 +- .../containers/app/map/layers/ObjectHoverLayer.js | 45 +++--- .../containers/app/map/layers/RoomHoverLayer.js | 63 ++++---- .../app/results/PortfolioResultsContainer.js | 43 +++--- .../app/sidebars/project/PortfolioListContainer.js | 42 +++--- .../sidebars/project/ProjectSidebarContainer.js | 9 +- .../app/sidebars/project/ScenarioListContainer.js | 68 +++++---- .../app/sidebars/project/TopologyListContainer.js | 74 +++++---- .../sidebars/topology/TopologySidebarContainer.js | 12 +- .../building/NewRoomConstructionContainer.js | 23 +-- .../topology/machine/BackToRackContainer.js | 12 +- .../topology/machine/DeleteMachineContainer.js | 12 +- .../topology/machine/MachineNameContainer.js | 12 +- .../topology/machine/MachineSidebarContainer.js | 16 +- .../sidebars/topology/machine/UnitAddContainer.js | 20 +-- .../app/sidebars/topology/machine/UnitContainer.js | 20 +-- .../sidebars/topology/machine/UnitListContainer.js | 16 +- .../sidebars/topology/rack/AddPrefabContainer.js | 12 +- .../sidebars/topology/rack/BackToRoomContainer.js | 12 +- .../sidebars/topology/rack/DeleteRackContainer.js | 12 +- .../sidebars/topology/rack/EmptySlotContainer.js | 13 +- .../app/sidebars/topology/rack/MachineContainer.js | 21 +-- .../sidebars/topology/rack/MachineListContainer.js | 14 +- .../sidebars/topology/rack/RackNameContainer.js | 21 +-- .../sidebars/topology/rack/RackSidebarContainer.js | 12 +- .../topology/room/BackToBuildingContainer.js | 13 +- .../sidebars/topology/room/DeleteRoomContainer.js | 13 +- .../sidebars/topology/room/EditRoomContainer.js | 32 ++-- .../topology/room/RackConstructionContainer.js | 31 ++-- .../sidebars/topology/room/RoomNameContainer.js | 20 +-- .../sidebars/topology/room/RoomSidebarContainer.js | 12 +- .../opendc-web-ui/src/containers/auth/Login.js | 64 +++----- .../opendc-web-ui/src/containers/auth/Logout.js | 12 +- .../src/containers/auth/ProfileName.js | 13 +- .../src/containers/modals/DeleteMachineModal.js | 43 +++--- .../src/containers/modals/DeleteProfileModal.js | 42 +++--- .../src/containers/modals/DeleteRackModal.js | 44 +++--- .../src/containers/modals/DeleteRoomModal.js | 43 +++--- .../src/containers/modals/EditRackNameModal.js | 57 ++++--- .../src/containers/modals/EditRoomNameModal.js | 51 +++---- .../src/containers/modals/NewPortfolioModal.js | 40 +++-- .../src/containers/modals/NewProjectModal.js | 31 ++-- .../src/containers/modals/NewScenarioModal.js | 78 +++++----- .../src/containers/modals/NewTopologyModal.js | 70 +++++---- .../containers/navigation/AppNavbarContainer.js | 14 +- .../src/containers/projects/FilterLink.js | 18 +-- .../projects/NewProjectButtonContainer.js | 12 +- .../src/containers/projects/ProjectActions.js | 17 +-- .../containers/projects/VisibleProjectAuthList.js | 26 ++-- opendc-web/opendc-web-ui/src/pages/App.js | 168 ++++++++------------- opendc-web/opendc-web-ui/src/pages/Profile.js | 51 ++++--- opendc-web/opendc-web-ui/src/pages/Projects.js | 48 +++--- opendc-web/opendc-web-ui/src/shortcuts/keymap.js | 10 +- 65 files changed, 886 insertions(+), 1074 deletions(-) (limited to 'opendc-web/opendc-web-ui/src') 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 2cd0ed6e..60bf3104 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,6 +1,6 @@ import React from 'react' +import { HotKeys } from 'react-hotkeys' import { Stage } from 'react-konva' -import { Shortcuts } from 'react-shortcuts' import MapLayer from '../../../containers/app/map/layers/MapLayer' import ObjectHoverLayer from '../../../containers/app/map/layers/ObjectHoverLayer' import RoomHoverLayer from '../../../containers/app/map/layers/RoomHoverLayer' @@ -55,23 +55,11 @@ class MapStageComponent extends React.Component { this.setState({ mouseX: mousePos.x, mouseY: mousePos.y }) } - handleShortcuts(action) { - switch (action) { - case 'MOVE_LEFT': - this.moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0) - break - case 'MOVE_RIGHT': - this.moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0) - break - case 'MOVE_UP': - this.moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT) - break - case 'MOVE_DOWN': - this.moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT) - break - default: - break - } + 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), } moveWithDelta(deltaX, deltaY) { @@ -80,7 +68,7 @@ class MapStageComponent extends React.Component { render() { return ( - + { this.stage = stage @@ -95,7 +83,7 @@ class MapStageComponent extends React.Component { - + ) } } diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/GrayContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/GrayContainer.js index 9e4a6969..651b3459 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/GrayContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/GrayContainer.js @@ -1,13 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { goDownOneInteractionLevel } from '../../../actions/interaction-level' import GrayLayer from '../../../components/app/map/elements/GrayLayer' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(goDownOneInteractionLevel()), - } +const GrayContainer = () => { + const dispatch = useDispatch() + const onClick = () => dispatch(goDownOneInteractionLevel()) + return } -const GrayContainer = connect(undefined, mapDispatchToProps)(GrayLayer) - export default GrayContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js b/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js index 23c920b6..61d123e8 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js @@ -1,22 +1,23 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { setMapDimensions, setMapPositionWithBoundsCheck, zoomInOnPosition } from '../../../actions/map' import MapStageComponent from '../../../components/app/map/MapStageComponent' -const mapStateToProps = (state) => { - return { - mapPosition: state.map.position, - mapDimensions: state.map.dimensions, - } +const MapStage = () => { + const { position, dimensions } = useSelector((state) => state.map) + const dispatch = useDispatch() + const zoomInOnPositionA = (zoomIn, x, y) => dispatch(zoomInOnPosition(zoomIn, x, y)) + const setMapPositionWithBoundsCheckA = (x, y) => dispatch(setMapPositionWithBoundsCheck(x, y)) + const setMapDimensionsA = (width, height) => dispatch(setMapDimensions(width, height)) + return ( + + ) } -const mapDispatchToProps = (dispatch) => { - return { - zoomInOnPosition: (zoomIn, x, y) => dispatch(zoomInOnPosition(zoomIn, x, y)), - setMapPositionWithBoundsCheck: (x, y) => dispatch(setMapPositionWithBoundsCheck(x, y)), - setMapDimensions: (width, height) => dispatch(setMapDimensions(width, height)), - } -} - -const MapStage = connect(mapStateToProps, mapDispatchToProps)(MapStageComponent) - export default MapStage diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/RackContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/RackContainer.js index 40077608..e5af5117 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/RackContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/RackContainer.js @@ -1,12 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import RackGroup from '../../../components/app/map/groups/RackGroup' -const mapStateToProps = (state) => { - return { - interactionLevel: state.interactionLevel, - } +const RackContainer = ({ tile }) => { + const interactionLevel = useSelector((state) => state.interactionLevel) + return } -const RackContainer = connect(mapStateToProps)(RackGroup) - export default RackContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/RackEnergyFillContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/RackEnergyFillContainer.js index 53746271..00d3152f 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/RackEnergyFillContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/RackEnergyFillContainer.js @@ -1,26 +1,32 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import RackFillBar from '../../../components/app/map/elements/RackFillBar' -const mapStateToProps = (state, ownProps) => { - let energyConsumptionTotal = 0 - const rack = state.objects.rack[state.objects.tile[ownProps.tileId].rackId] - const machineIds = rack.machineIds - machineIds.forEach((machineId) => { - if (machineId !== null) { - const machine = state.objects.machine[machineId] - machine.cpuIds.forEach((id) => (energyConsumptionTotal += state.objects.cpu[id].energyConsumptionW)) - machine.gpuIds.forEach((id) => (energyConsumptionTotal += state.objects.gpu[id].energyConsumptionW)) - machine.memoryIds.forEach((id) => (energyConsumptionTotal += state.objects.memory[id].energyConsumptionW)) - machine.storageIds.forEach((id) => (energyConsumptionTotal += state.objects.storage[id].energyConsumptionW)) +const RackSpaceFillContainer = (props) => { + const state = useSelector((state) => { + let energyConsumptionTotal = 0 + const rack = state.objects.rack[state.objects.tile[props.tileId].rackId] + const machineIds = rack.machineIds + machineIds.forEach((machineId) => { + if (machineId !== null) { + const machine = state.objects.machine[machineId] + machine.cpuIds.forEach((id) => (energyConsumptionTotal += state.objects.cpu[id].energyConsumptionW)) + machine.gpuIds.forEach((id) => (energyConsumptionTotal += state.objects.gpu[id].energyConsumptionW)) + machine.memoryIds.forEach( + (id) => (energyConsumptionTotal += state.objects.memory[id].energyConsumptionW) + ) + machine.storageIds.forEach( + (id) => (energyConsumptionTotal += state.objects.storage[id].energyConsumptionW) + ) + } + }) + + return { + type: 'energy', + fillFraction: Math.min(1, energyConsumptionTotal / rack.powerCapacityW), } }) - - return { - type: 'energy', - fillFraction: Math.min(1, energyConsumptionTotal / rack.powerCapacityW), - } + return } -const RackSpaceFillContainer = connect(mapStateToProps)(RackFillBar) - export default RackSpaceFillContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/RackSpaceFillContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/RackSpaceFillContainer.js index 0509a5a5..dc5119fd 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/RackSpaceFillContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/RackSpaceFillContainer.js @@ -1,14 +1,16 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import RackFillBar from '../../../components/app/map/elements/RackFillBar' -const mapStateToProps = (state, ownProps) => { - const machineIds = state.objects.rack[state.objects.tile[ownProps.tileId].rackId].machineIds - return { - type: 'space', - fillFraction: machineIds.filter((id) => id !== null).length / machineIds.length, - } +const RackSpaceFillContainer = (props) => { + const state = useSelector((state) => { + const machineIds = state.objects.rack[state.objects.tile[props.tileId].rackId].machineIds + return { + type: 'space', + fillFraction: machineIds.filter((id) => id !== null).length / machineIds.length, + } + }) + return } -const RackSpaceFillContainer = connect(mapStateToProps)(RackFillBar) - export default RackSpaceFillContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/RoomContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/RoomContainer.js index 91bf4e5d..877233fc 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/RoomContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/RoomContainer.js @@ -1,21 +1,18 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { goFromBuildingToRoom } from '../../../actions/interaction-level' import RoomGroup from '../../../components/app/map/groups/RoomGroup' -const mapStateToProps = (state, ownProps) => { - return { - interactionLevel: state.interactionLevel, - currentRoomInConstruction: state.construction.currentRoomInConstruction, - room: state.objects.room[ownProps.roomId], - } +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 dispatch(goFromBuildingToRoom(props.roomId))} /> } -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onClick: () => dispatch(goFromBuildingToRoom(ownProps.roomId)), - } -} - -const RoomContainer = connect(mapStateToProps, mapDispatchToProps)(RoomGroup) - export default RoomContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js index 04d6c8d6..ad7301a7 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js @@ -1,26 +1,19 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { goFromRoomToRack } from '../../../actions/interaction-level' import TileGroup from '../../../components/app/map/groups/TileGroup' -const mapStateToProps = (state, ownProps) => { - const tile = state.objects.tile[ownProps.tileId] +const TileContainer = (props) => { + const interactionLevel = useSelector((state) => state.interactionLevel) + const tile = useSelector((state) => state.objects.tile[props.tileId]) - return { - interactionLevel: state.interactionLevel, - tile, + const dispatch = useDispatch() + const onClick = (tile) => { + if (tile.rackId) { + dispatch(goFromRoomToRack(tile._id)) + } } + return } -const mapDispatchToProps = (dispatch) => { - return { - onClick: (tile) => { - if (tile.rackId) { - dispatch(goFromRoomToRack(tile._id)) - } - }, - } -} - -const TileContainer = connect(mapStateToProps, mapDispatchToProps)(TileGroup) - export default TileContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/TopologyContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/TopologyContainer.js index de43a151..612ca41c 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/TopologyContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/TopologyContainer.js @@ -1,17 +1,14 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import TopologyGroup from '../../../components/app/map/groups/TopologyGroup' -const mapStateToProps = (state) => { - if (state.currentTopologyId === '-1') { - return {} - } +const TopologyContainer = () => { + const topology = useSelector( + (state) => state.currentTopologyId !== '-1' && state.objects.topology[state.currentTopologyId] + ) + const interactionLevel = useSelector((state) => state.interactionLevel) - return { - topology: state.objects.topology[state.currentTopologyId], - interactionLevel: state.interactionLevel, - } + return } -const TopologyContainer = connect(mapStateToProps)(TopologyGroup) - export default TopologyContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/WallContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/WallContainer.js index 67f8a242..2a469860 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/WallContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/WallContainer.js @@ -1,12 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import WallGroup from '../../../components/app/map/groups/WallGroup' -const mapStateToProps = (state, ownProps) => { - return { - tiles: state.objects.room[ownProps.roomId].tileIds.map((tileId) => state.objects.tile[tileId]), - } +const WallContainer = (props) => { + const tiles = useSelector((state) => + state.objects.room[props.roomId].tileIds.map((tileId) => state.objects.tile[tileId]) + ) + return } -const WallContainer = connect(mapStateToProps)(WallGroup) - export default WallContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/controls/ScaleIndicatorContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/controls/ScaleIndicatorContainer.js index fa3b9d22..e9d58b9f 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/controls/ScaleIndicatorContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/controls/ScaleIndicatorContainer.js @@ -1,12 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import ScaleIndicatorComponent from '../../../../components/app/map/controls/ScaleIndicatorComponent' -const mapStateToProps = (state) => { - return { - scale: state.map.scale, - } +const ScaleIndicatorContainer = (props) => { + const scale = useSelector((state) => state.map.scale) + return } -const ScaleIndicatorContainer = connect(mapStateToProps)(ScaleIndicatorComponent) - export default ScaleIndicatorContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/controls/ZoomControlContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/controls/ZoomControlContainer.js index ddc68cc7..a18dfd5b 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/controls/ZoomControlContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/controls/ZoomControlContainer.js @@ -1,19 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { zoomInOnCenter } from '../../../../actions/map' import ZoomControlComponent from '../../../../components/app/map/controls/ZoomControlComponent' -const mapStateToProps = (state) => { - return { - mapScale: state.map.scale, - } +const ZoomControlContainer = () => { + const dispatch = useDispatch() + const scale = useSelector((state) => state.map.scale) + return dispatch(zoomInOnCenter(zoomIn))} /> } -const mapDispatchToProps = (dispatch) => { - return { - zoomInOnCenter: (zoomIn) => dispatch(zoomInOnCenter(zoomIn)), - } -} - -const ZoomControlContainer = connect(mapStateToProps, mapDispatchToProps)(ZoomControlComponent) - export default ZoomControlContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/layers/MapLayer.js b/opendc-web/opendc-web-ui/src/containers/app/map/layers/MapLayer.js index 8596cb9c..5f701b4b 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/layers/MapLayer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/layers/MapLayer.js @@ -1,13 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import MapLayerComponent from '../../../../components/app/map/layers/MapLayerComponent' -const mapStateToProps = (state) => { - return { - mapPosition: state.map.position, - mapScale: state.map.scale, - } +const MapLayer = (props) => { + const { position, scale } = useSelector((state) => state.map) + return } -const MapLayer = connect(mapStateToProps)(MapLayerComponent) - export default MapLayer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/layers/ObjectHoverLayer.js b/opendc-web/opendc-web-ui/src/containers/app/map/layers/ObjectHoverLayer.js index a4927862..cefdf35c 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/layers/ObjectHoverLayer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/layers/ObjectHoverLayer.js @@ -1,33 +1,32 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { addRackToTile } from '../../../../actions/topology/room' import ObjectHoverLayerComponent from '../../../../components/app/map/layers/ObjectHoverLayerComponent' import { findTileWithPosition } from '../../../../util/tile-calculations' -const mapStateToProps = (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 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.tileIds.map((tileId) => state.objects.tile[tileId]) - const tile = findTileWithPosition(tiles, x, y) + const currentRoom = state.objects.room[state.interactionLevel.roomId] + const tiles = currentRoom.tileIds.map((tileId) => state.objects.tile[tileId]) + const tile = findTileWithPosition(tiles, x, y) - return !(tile === null || tile.rackId) - }, - } -} + return !(tile === null || tile.rackId) + }, + } + }) -const mapDispatchToProps = (dispatch) => { - return { - onClick: (x, y) => dispatch(addRackToTile(x, y)), - } + const dispatch = useDispatch() + const onClick = (x, y) => dispatch(addRackToTile(x, y)) + return } -const ObjectHoverLayer = connect(mapStateToProps, mapDispatchToProps)(ObjectHoverLayerComponent) - export default ObjectHoverLayer diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/layers/RoomHoverLayer.js b/opendc-web/opendc-web-ui/src/containers/app/map/layers/RoomHoverLayer.js index 66404f9e..2717d890 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/layers/RoomHoverLayer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/layers/RoomHoverLayer.js @@ -1,4 +1,5 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { toggleTileAtLocation } from '../../../../actions/topology/building' import RoomHoverLayerComponent from '../../../../components/app/map/layers/RoomHoverLayerComponent' import { @@ -7,40 +8,38 @@ import { findPositionInRooms, } from '../../../../util/tile-calculations' -const mapStateToProps = (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].roomIds.indexOf(room._id) !== -1 && - room._id !== state.construction.currentRoomInConstruction - ) +const RoomHoverLayer = (props) => { + const dispatch = useDispatch() + const onClick = (x, y) => dispatch(toggleTileAtLocation(x, y)) - ;[...oldRooms, newRoom].forEach((room) => { - room.tiles = room.tileIds.map((tileId) => state.objects.tile[tileId]) - }) - if (newRoom.tileIds.length === 0) { - return findPositionInRooms(oldRooms, x, y) === -1 - } + const 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].roomIds.indexOf(room._id) !== -1 && + room._id !== state.construction.currentRoomInConstruction + ) - const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles) - return findPositionInPositions(validNextPositions, x, y) !== -1 - }, - } -} + ;[...oldRooms, newRoom].forEach((room) => { + room.tiles = room.tileIds.map((tileId) => state.objects.tile[tileId]) + }) + if (newRoom.tileIds.length === 0) { + return findPositionInRooms(oldRooms, x, y) === -1 + } -const mapDispatchToProps = (dispatch) => { - return { - onClick: (x, y) => dispatch(toggleTileAtLocation(x, y)), - } + const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles) + return findPositionInPositions(validNextPositions, x, y) !== -1 + }, + } + }) + return } -const RoomHoverLayer = connect(mapStateToProps, mapDispatchToProps)(RoomHoverLayerComponent) - export default RoomHoverLayer diff --git a/opendc-web/opendc-web-ui/src/containers/app/results/PortfolioResultsContainer.js b/opendc-web/opendc-web-ui/src/containers/app/results/PortfolioResultsContainer.js index 4b430e54..e60abe18 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/results/PortfolioResultsContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/results/PortfolioResultsContainer.js @@ -1,28 +1,31 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import PortfolioResultsComponent from '../../../components/app/results/PortfolioResultsComponent' -const mapStateToProps = (state) => { - if ( - state.currentPortfolioId === '-1' || - !state.objects.portfolio[state.currentPortfolioId] || - state.objects.portfolio[state.currentPortfolioId].scenarioIds - .map((scenarioId) => state.objects.scenario[scenarioId]) - .some((s) => s === undefined) - ) { +const PortfolioResultsContainer = (props) => { + const { scenarios, portfolio } = useSelector((state) => { + if ( + state.currentPortfolioId === '-1' || + !state.objects.portfolio[state.currentPortfolioId] || + state.objects.portfolio[state.currentPortfolioId].scenarioIds + .map((scenarioId) => state.objects.scenario[scenarioId]) + .some((s) => s === undefined) + ) { + return { + portfolio: undefined, + scenarios: [], + } + } + return { - portfolio: undefined, - scenarios: [], + portfolio: state.objects.portfolio[state.currentPortfolioId], + scenarios: state.objects.portfolio[state.currentPortfolioId].scenarioIds.map( + (scenarioId) => state.objects.scenario[scenarioId] + ), } - } + }) - return { - portfolio: state.objects.portfolio[state.currentPortfolioId], - scenarios: state.objects.portfolio[state.currentPortfolioId].scenarioIds.map( - (scenarioId) => state.objects.scenario[scenarioId] - ), - } + return } -const PortfolioResultsContainer = connect(mapStateToProps)(PortfolioResultsComponent) - export default PortfolioResultsContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/PortfolioListContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/PortfolioListContainer.js index b32c8b1d..86f465b6 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/PortfolioListContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/PortfolioListContainer.js @@ -1,28 +1,31 @@ -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { useHistory } from 'react-router-dom' import PortfolioListComponent from '../../../../components/app/sidebars/project/PortfolioListComponent' import { deletePortfolio, setCurrentPortfolio } from '../../../../actions/portfolios' import { openNewPortfolioModal } from '../../../../actions/modals/portfolios' import { getState } from '../../../../util/state-utils' import { setCurrentTopology } from '../../../../actions/topology/building' -const mapStateToProps = (state) => { - let portfolios = state.objects.project[state.currentProjectId] - ? state.objects.project[state.currentProjectId].portfolioIds.map((t) => state.objects.portfolio[t]) - : [] - if (portfolios.filter((t) => !t).length > 0) { - portfolios = [] - } +const PortfolioListContainer = (props) => { + const state = useSelector((state) => { + let portfolios = state.objects.project[state.currentProjectId] + ? state.objects.project[state.currentProjectId].portfolioIds.map((t) => state.objects.portfolio[t]) + : [] + if (portfolios.filter((t) => !t).length > 0) { + portfolios = [] + } - return { - currentProjectId: state.currentProjectId, - currentPortfolioId: state.currentPortfolioId, - portfolios, - } -} + return { + currentProjectId: state.currentProjectId, + currentPortfolioId: state.currentPortfolioId, + portfolios, + } + }) -const mapDispatchToProps = (dispatch, ownProps) => { - return { + const dispatch = useDispatch() + const history = useHistory() + const actions = { onNewPortfolio: () => { dispatch(openNewPortfolioModal()) }, @@ -34,12 +37,11 @@ const mapDispatchToProps = (dispatch, ownProps) => { const state = await getState(dispatch) dispatch(deletePortfolio(id)) dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0])) - ownProps.history.push(`/projects/${state.currentProjectId}`) + history.push(`/projects/${state.currentProjectId}`) } }, } + return } -const PortfolioListContainer = withRouter(connect(mapStateToProps, mapDispatchToProps)(PortfolioListComponent)) - export default PortfolioListContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js index 49001099..35e6c52b 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js @@ -1,10 +1,11 @@ import React from 'react' -import { withRouter } from 'react-router-dom' +import { useLocation } from 'react-router-dom' import ProjectSidebarComponent from '../../../../components/app/sidebars/project/ProjectSidebarComponent' import { isCollapsible } from '../../../../util/sidebar-space' -const ProjectSidebarContainer = withRouter(({ location, ...props }) => ( - -)) +const ProjectSidebarContainer = (props) => { + const location = useLocation() + return +} export default ProjectSidebarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ScenarioListContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ScenarioListContainer.js index 415e2792..18d0735e 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ScenarioListContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ScenarioListContainer.js @@ -1,41 +1,49 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import ScenarioListComponent from '../../../../components/app/sidebars/project/ScenarioListComponent' import { openNewScenarioModal } from '../../../../actions/modals/scenarios' import { deleteScenario, setCurrentScenario } from '../../../../actions/scenarios' import { setCurrentPortfolio } from '../../../../actions/portfolios' -const mapStateToProps = (state, ownProps) => { - let scenarios = state.objects.portfolio[ownProps.portfolioId] - ? state.objects.portfolio[ownProps.portfolioId].scenarioIds.map((t) => state.objects.scenario[t]) - : [] - if (scenarios.filter((t) => !t).length > 0) { - scenarios = [] - } +const ScenarioListContainer = ({ portfolioId, children }) => { + const currentProjectId = useSelector((state) => state.currentProjectId) + const currentScenarioId = useSelector((state) => state.currentScenarioId) + const scenarios = useSelector((state) => { + let scenarios = state.objects.portfolio[portfolioId] + ? state.objects.portfolio[portfolioId].scenarioIds.map((t) => state.objects.scenario[t]) + : [] + if (scenarios.filter((t) => !t).length > 0) { + scenarios = [] + } - return { - currentProjectId: state.currentProjectId, - currentScenarioId: state.currentScenarioId, - scenarios, - } -} + return scenarios + }) -const mapDispatchToProps = (dispatch) => { - return { - onNewScenario: (currentPortfolioId) => { - dispatch(setCurrentPortfolio(currentPortfolioId)) - dispatch(openNewScenarioModal()) - }, - onChooseScenario: (portfolioId, scenarioId) => { - dispatch(setCurrentScenario(portfolioId, scenarioId)) - }, - onDeleteScenario: (id) => { - if (id) { - dispatch(deleteScenario(id)) - } - }, + const dispatch = useDispatch() + const onNewScenario = (currentPortfolioId) => { + dispatch(setCurrentPortfolio(currentPortfolioId)) + dispatch(openNewScenarioModal()) + } + const onChooseScenario = (portfolioId, scenarioId) => { + dispatch(setCurrentScenario(portfolioId, scenarioId)) + } + const onDeleteScenario = (id) => { + if (id) { + dispatch(deleteScenario(id)) + } } -} -const ScenarioListContainer = connect(mapStateToProps, mapDispatchToProps)(ScenarioListComponent) + return ( + + ) +} export default ScenarioListContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js index e1de18f9..954284a6 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js @@ -1,46 +1,54 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import TopologyListComponent from '../../../../components/app/sidebars/project/TopologyListComponent' import { setCurrentTopology } from '../../../../actions/topology/building' import { openNewTopologyModal } from '../../../../actions/modals/topology' -import { withRouter } from 'react-router-dom' +import { useHistory } from 'react-router-dom' import { getState } from '../../../../util/state-utils' import { deleteTopology } from '../../../../actions/topologies' -const mapStateToProps = (state) => { - let topologies = state.objects.project[state.currentProjectId] - ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) - : [] - if (topologies.filter((t) => !t).length > 0) { - topologies = [] - } +const TopologyListContainer = () => { + const dispatch = useDispatch() + const history = useHistory() - return { - currentTopologyId: state.currentTopologyId, - topologies, - } -} + const topologies = useSelector((state) => { + let topologies = state.objects.project[state.currentProjectId] + ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) + : [] + if (topologies.filter((t) => !t).length > 0) { + topologies = [] + } + + return topologies + }) + const currentTopologyId = useSelector((state) => state.currentTopologyId) -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onChooseTopology: async (id) => { - dispatch(setCurrentTopology(id)) + const onChooseTopology = async (id) => { + dispatch(setCurrentTopology(id)) + const state = await getState(dispatch) + history.push(`/projects/${state.currentProjectId}`) + } + const onNewTopology = () => { + dispatch(openNewTopologyModal()) + } + const onDeleteTopology = async (id) => { + if (id) { const state = await getState(dispatch) - ownProps.history.push(`/projects/${state.currentProjectId}`) - }, - onNewTopology: () => { - dispatch(openNewTopologyModal()) - }, - onDeleteTopology: async (id) => { - if (id) { - const state = await getState(dispatch) - dispatch(deleteTopology(id)) - dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0])) - ownProps.history.push(`/projects/${state.currentProjectId}`) - } - }, + dispatch(deleteTopology(id)) + dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0])) + history.push(`/projects/${state.currentProjectId}`) + } } -} -const TopologyListContainer = withRouter(connect(mapStateToProps, mapDispatchToProps)(TopologyListComponent)) + return ( + + ) +} export default TopologyListContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/TopologySidebarContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/TopologySidebarContainer.js index fe7c02fd..42c81c65 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/TopologySidebarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/TopologySidebarContainer.js @@ -1,12 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import TopologySidebarComponent from '../../../../components/app/sidebars/topology/TopologySidebarComponent' -const mapStateToProps = (state) => { - return { - interactionLevel: state.interactionLevel, - } +const TopologySidebarContainer = (props) => { + const interactionLevel = useSelector((state) => state.interactionLevel) + return } -const TopologySidebarContainer = connect(mapStateToProps)(TopologySidebarComponent) - export default TopologySidebarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/building/NewRoomConstructionContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/building/NewRoomConstructionContainer.js index ea9e9e60..ea36539c 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/building/NewRoomConstructionContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/building/NewRoomConstructionContainer.js @@ -1,4 +1,5 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { cancelNewRoomConstruction, finishNewRoomConstruction, @@ -6,20 +7,22 @@ import { } from '../../../../../actions/topology/building' import StartNewRoomConstructionComponent from '../../../../../components/app/sidebars/topology/building/NewRoomConstructionComponent' -const mapStateToProps = (state) => { - return { - currentRoomInConstruction: state.construction.currentRoomInConstruction, - } -} +const NewRoomConstructionButton = (props) => { + const currentRoomInConstruction = useSelector((state) => state.construction.currentRoomInConstruction) -const mapDispatchToProps = (dispatch) => { - return { + const dispatch = useDispatch() + const actions = { onStart: () => dispatch(startNewRoomConstruction()), onFinish: () => dispatch(finishNewRoomConstruction()), onCancel: () => dispatch(cancelNewRoomConstruction()), } + return ( + + ) } -const NewRoomConstructionButton = connect(mapStateToProps, mapDispatchToProps)(StartNewRoomConstructionComponent) - export default NewRoomConstructionButton diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/BackToRackContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/BackToRackContainer.js index 24287ab0..46862472 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/BackToRackContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/BackToRackContainer.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { goDownOneInteractionLevel } from '../../../../../actions/interaction-level' import BackToRackComponent from '../../../../../components/app/sidebars/topology/machine/BackToRackComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(goDownOneInteractionLevel()), - } +const BackToRackContainer = (props) => { + const dispatch = useDispatch() + return dispatch(goDownOneInteractionLevel())} /> } -const BackToRackContainer = connect(undefined, mapDispatchToProps)(BackToRackComponent) - export default BackToRackContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/DeleteMachineContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/DeleteMachineContainer.js index 65e683e6..1510a436 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/DeleteMachineContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/DeleteMachineContainer.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { openDeleteMachineModal } from '../../../../../actions/modals/topology' import DeleteMachineComponent from '../../../../../components/app/sidebars/topology/machine/DeleteMachineComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(openDeleteMachineModal()), - } +const DeleteMachineContainer = (props) => { + const dispatch = useDispatch() + return dispatch(openDeleteMachineModal())} /> } -const DeleteMachineContainer = connect(undefined, mapDispatchToProps)(DeleteMachineComponent) - export default DeleteMachineContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineNameContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineNameContainer.js index 1cf35b05..6f4285b2 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineNameContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineNameContainer.js @@ -1,12 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import MachineNameComponent from '../../../../../components/app/sidebars/topology/machine/MachineNameComponent' -const mapStateToProps = (state) => { - return { - position: state.interactionLevel.position, - } +const MachineNameContainer = (props) => { + const position = useSelector((state) => state.interactionLevel.position) + return } -const MachineNameContainer = connect(mapStateToProps)(MachineNameComponent) - export default MachineNameContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js index b04e3118..cb7ec8f9 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js @@ -1,15 +1,15 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import MachineSidebarComponent from '../../../../../components/app/sidebars/topology/machine/MachineSidebarComponent' -const mapStateToProps = (state) => { - return { - machineId: +const MachineSidebarContainer = (props) => { + const machineId = useSelector( + (state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds[ state.interactionLevel.position - 1 - ], - } + ] + ) + return } -const MachineSidebarContainer = connect(mapStateToProps)(MachineSidebarComponent) - export default MachineSidebarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitAddContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitAddContainer.js index 29e48016..3795cdff 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitAddContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitAddContainer.js @@ -1,19 +1,15 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { addUnit } from '../../../../../actions/topology/machine' import UnitAddComponent from '../../../../../components/app/sidebars/topology/machine/UnitAddComponent' -const mapStateToProps = (state, ownProps) => { - return { - units: Object.values(state.objects[ownProps.unitType]), - } -} +const UnitAddContainer = (props) => { + const units = useSelector((state) => Object.values(state.objects[props.unitType])) + const dispatch = useDispatch() -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onAdd: (id) => dispatch(addUnit(ownProps.unitType, id)), - } -} + const onAdd = (id) => dispatch(addUnit(props.unitType, id)) -const UnitAddContainer = connect(mapStateToProps, mapDispatchToProps)(UnitAddComponent) + return +} export default UnitAddContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitContainer.js index f334f9f2..3d24859e 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitContainer.js @@ -1,20 +1,14 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { deleteUnit } from '../../../../../actions/topology/machine' import UnitComponent from '../../../../../components/app/sidebars/topology/machine/UnitComponent' -const mapStateToProps = (state, ownProps) => { - return { - unit: state.objects[ownProps.unitType][ownProps.unitId], - index: ownProps.unitId, - } -} +const UnitContainer = ({ unitId, unitType }) => { + const dispatch = useDispatch() + const unit = useSelector((state) => state.objects[unitType][unitId]) + const onDelete = () => dispatch(deleteUnit(unitType, unitId)) -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onDelete: () => dispatch(deleteUnit(ownProps.unitType, ownProps.index)), - } + return } -const UnitContainer = connect(mapStateToProps, mapDispatchToProps)(UnitComponent) - export default UnitContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitListContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitListContainer.js index f382ff74..c5c9444d 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitListContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitListContainer.js @@ -1,17 +1,17 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import UnitListComponent from '../../../../../components/app/sidebars/topology/machine/UnitListComponent' -const mapStateToProps = (state, ownProps) => { - return { - unitIds: +const UnitListContainer = (props) => { + const unitIds = useSelector( + (state) => state.objects.machine[ state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds[ state.interactionLevel.position - 1 ] - ][ownProps.unitType + 'Ids'], - } + ][props.unitType + 'Ids'] + ) + return } -const UnitListContainer = connect(mapStateToProps)(UnitListComponent) - export default UnitListContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/AddPrefabContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/AddPrefabContainer.js index c941e745..3708e33e 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/AddPrefabContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/AddPrefabContainer.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { addPrefab } from '../../../../../actions/prefabs' import AddPrefabComponent from '../../../../../components/app/sidebars/topology/rack/AddPrefabComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(addPrefab('name')), - } +const AddPrefabContainer = (props) => { + const dispatch = useDispatch() + return dispatch(addPrefab('name'))} /> } -const AddPrefabContainer = connect(undefined, mapDispatchToProps)(AddPrefabComponent) - export default AddPrefabContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/BackToRoomContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/BackToRoomContainer.js index 58c3b082..93bb749f 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/BackToRoomContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/BackToRoomContainer.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { goDownOneInteractionLevel } from '../../../../../actions/interaction-level' import BackToRoomComponent from '../../../../../components/app/sidebars/topology/rack/BackToRoomComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(goDownOneInteractionLevel()), - } +const BackToRoomContainer = (props) => { + const dispatch = useDispatch() + return dispatch(goDownOneInteractionLevel())} /> } -const BackToRoomContainer = connect(undefined, mapDispatchToProps)(BackToRoomComponent) - export default BackToRoomContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/DeleteRackContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/DeleteRackContainer.js index 8229a359..de46e491 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/DeleteRackContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/DeleteRackContainer.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { openDeleteRackModal } from '../../../../../actions/modals/topology' import DeleteRackComponent from '../../../../../components/app/sidebars/topology/rack/DeleteRackComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(openDeleteRackModal()), - } +const DeleteRackContainer = (props) => { + const dispatch = useDispatch() + return dispatch(openDeleteRackModal())} /> } -const DeleteRackContainer = connect(undefined, mapDispatchToProps)(DeleteRackComponent) - export default DeleteRackContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js index cf341da9..5bb2c784 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js @@ -1,13 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { addMachine } from '../../../../../actions/topology/rack' import EmptySlotComponent from '../../../../../components/app/sidebars/topology/rack/EmptySlotComponent' -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onAdd: () => dispatch(addMachine(ownProps.position)), - } +const EmptySlotContainer = (props) => { + const dispatch = useDispatch() + const onAdd = () => dispatch(addMachine(props.position)) + return } -const EmptySlotContainer = connect(undefined, mapDispatchToProps)(EmptySlotComponent) - export default EmptySlotContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineContainer.js index fe12827d..149b4d18 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineContainer.js @@ -1,19 +1,14 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { goFromRackToMachine } from '../../../../../actions/interaction-level' import MachineComponent from '../../../../../components/app/sidebars/topology/rack/MachineComponent' -const mapStateToProps = (state, ownProps) => { - return { - machine: state.objects.machine[ownProps.machineId], - } +const MachineContainer = (props) => { + const machine = useSelector((state) => state.objects.machine[props.machineId]) + const dispatch = useDispatch() + return ( + dispatch(goFromRackToMachine(props.position))} machine={machine} /> + ) } -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onClick: () => dispatch(goFromRackToMachine(ownProps.position)), - } -} - -const MachineContainer = connect(mapStateToProps, mapDispatchToProps)(MachineComponent) - export default MachineContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineListContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineListContainer.js index bc5a285a..b45300fc 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineListContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineListContainer.js @@ -1,12 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import MachineListComponent from '../../../../../components/app/sidebars/topology/rack/MachineListComponent' -const mapStateToProps = (state) => { - return { - machineIds: state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds, - } +const MachineListContainer = (props) => { + const machineIds = useSelector( + (state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds + ) + return } -const MachineListContainer = connect(mapStateToProps)(MachineListComponent) - export default MachineListContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackNameContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackNameContainer.js index 504dbc61..7dfdb473 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackNameContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackNameContainer.js @@ -1,19 +1,14 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { openEditRackNameModal } from '../../../../../actions/modals/topology' import RackNameComponent from '../../../../../components/app/sidebars/topology/rack/RackNameComponent' -const mapStateToProps = (state) => { - return { - rackName: state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].name, - } +const RackNameContainer = (props) => { + const rackName = useSelector( + (state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].name + ) + const dispatch = useDispatch() + return dispatch(openEditRackNameModal())} /> } -const mapDispatchToProps = (dispatch) => { - return { - onEdit: () => dispatch(openEditRackNameModal()), - } -} - -const RackNameContainer = connect(mapStateToProps, mapDispatchToProps)(RackNameComponent) - export default RackNameContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js index 453d7e41..b8fc3bfb 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js @@ -1,12 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import RackSidebarComponent from '../../../../../components/app/sidebars/topology/rack/RackSidebarComponent' -const mapStateToProps = (state) => { - return { - rackId: state.objects.tile[state.interactionLevel.tileId].rackId, - } +const RackSidebarContainer = (props) => { + const rackId = useSelector((state) => state.objects.tile[state.interactionLevel.tileId].rackId) + return } -const RackSidebarContainer = connect(mapStateToProps)(RackSidebarComponent) - export default RackSidebarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/BackToBuildingContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/BackToBuildingContainer.js index 4c1ab99d..a48bf0a7 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/BackToBuildingContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/BackToBuildingContainer.js @@ -1,13 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { goDownOneInteractionLevel } from '../../../../../actions/interaction-level' import BackToBuildingComponent from '../../../../../components/app/sidebars/topology/room/BackToBuildingComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(goDownOneInteractionLevel()), - } +const BackToBuildingContainer = () => { + const dispatch = useDispatch() + const onClick = () => dispatch(goDownOneInteractionLevel()) + return } -const BackToBuildingContainer = connect(undefined, mapDispatchToProps)(BackToBuildingComponent) - export default BackToBuildingContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/DeleteRoomContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/DeleteRoomContainer.js index 636fa5c5..6a80e9b0 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/DeleteRoomContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/DeleteRoomContainer.js @@ -1,13 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { openDeleteRoomModal } from '../../../../../actions/modals/topology' import DeleteRoomComponent from '../../../../../components/app/sidebars/topology/room/DeleteRoomComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(openDeleteRoomModal()), - } +const DeleteRoomContainer = (props) => { + const dispatch = useDispatch() + const onClick = () => dispatch(openDeleteRoomModal()) + return } -const DeleteRoomContainer = connect(undefined, mapDispatchToProps)(DeleteRoomComponent) - export default DeleteRoomContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/EditRoomContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/EditRoomContainer.js index d17a45d1..37027fc5 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/EditRoomContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/EditRoomContainer.js @@ -1,21 +1,25 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { finishRoomEdit, startRoomEdit } from '../../../../../actions/topology/building' import EditRoomComponent from '../../../../../components/app/sidebars/topology/room/EditRoomComponent' -const mapStateToProps = (state) => { - return { - isEditing: state.construction.currentRoomInConstruction !== '-1', - isInRackConstructionMode: state.construction.inRackConstructionMode, - } -} +const EditRoomContainer = (props) => { + const isEditing = useSelector((state) => state.construction.currentRoomInConstruction !== '-1') + const isInRackConstructionMode = useSelector((state) => state.construction.inRackConstructionMode) -const mapDispatchToProps = (dispatch) => { - return { - onEdit: () => dispatch(startRoomEdit()), - onFinish: () => dispatch(finishRoomEdit()), - } -} + const dispatch = useDispatch() + const onEdit = () => dispatch(startRoomEdit()) + const onFinish = () => dispatch(finishRoomEdit()) -const EditRoomContainer = connect(mapStateToProps, mapDispatchToProps)(EditRoomComponent) + return ( + + ) +} export default EditRoomContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RackConstructionContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RackConstructionContainer.js index cd8319de..726e9d37 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RackConstructionContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RackConstructionContainer.js @@ -1,21 +1,24 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { startRackConstruction, stopRackConstruction } from '../../../../../actions/topology/room' import RackConstructionComponent from '../../../../../components/app/sidebars/topology/room/RackConstructionComponent' -const mapStateToProps = (state) => { - return { - inRackConstructionMode: state.construction.inRackConstructionMode, - isEditingRoom: state.construction.currentRoomInConstruction !== '-1', - } -} +const RackConstructionContainer = (props) => { + const isRackConstructionMode = useSelector((state) => state.construction.inRackConstructionMode) + const isEditingRoom = useSelector((state) => state.construction.currentRoomInConstruction !== '-1') -const mapDispatchToProps = (dispatch) => { - return { - onStart: () => dispatch(startRackConstruction()), - onStop: () => dispatch(stopRackConstruction()), - } + const dispatch = useDispatch() + const onStart = () => dispatch(startRackConstruction()) + const onStop = () => dispatch(stopRackConstruction()) + return ( + + ) } -const RackConstructionContainer = connect(mapStateToProps, mapDispatchToProps)(RackConstructionComponent) - export default RackConstructionContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomNameContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomNameContainer.js index cab16016..1f53aeb6 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomNameContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomNameContainer.js @@ -1,19 +1,13 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { openEditRoomNameModal } from '../../../../../actions/modals/topology' import RoomNameComponent from '../../../../../components/app/sidebars/topology/room/RoomNameComponent' -const mapStateToProps = (state) => { - return { - roomName: state.objects.room[state.interactionLevel.roomId].name, - } +const RoomNameContainer = (props) => { + const roomName = useSelector((state) => state.objects.room[state.interactionLevel.roomId].name) + const dispatch = useDispatch() + const onEdit = () => dispatch(openEditRoomNameModal()) + return } -const mapDispatchToProps = (dispatch) => { - return { - onEdit: () => dispatch(openEditRoomNameModal()), - } -} - -const RoomNameContainer = connect(mapStateToProps, mapDispatchToProps)(RoomNameComponent) - export default RoomNameContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js index 8c3ca8ab..252881a0 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js @@ -1,12 +1,10 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import RoomSidebarComponent from '../../../../../components/app/sidebars/topology/room/RoomSidebarComponent' -const mapStateToProps = (state) => { - return { - roomId: state.interactionLevel.roomId, - } +const RoomSidebarContainer = (props) => { + const roomId = useSelector((state) => state.interactionLevel.roomId) + return } -const RoomSidebarContainer = connect(mapStateToProps)(RoomSidebarComponent) - export default RoomSidebarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/auth/Login.js b/opendc-web/opendc-web-ui/src/containers/auth/Login.js index bebe015c..54605775 100644 --- a/opendc-web/opendc-web-ui/src/containers/auth/Login.js +++ b/opendc-web/opendc-web-ui/src/containers/auth/Login.js @@ -1,18 +1,16 @@ -import PropTypes from 'prop-types' import React from 'react' import GoogleLogin from 'react-google-login' -import { connect } from 'react-redux' +import { useDispatch } from 'react-redux' import { logIn } from '../../actions/auth' import config from '../../config' -class LoginContainer extends React.Component { - static propTypes = { - visible: PropTypes.bool.isRequired, - onLogin: PropTypes.func.isRequired, - } +const Login = (props) => { + const { visible } = props + const dispatch = useDispatch() - onAuthResponse(response) { - this.props.onLogin({ + const onLogin = (payload) => dispatch(logIn(payload)) + const onAuthResponse = (response) => { + onLogin({ email: response.getBasicProfile().getEmail(), givenName: response.getBasicProfile().getGivenName(), familyName: response.getBasicProfile().getFamilyName(), @@ -21,43 +19,27 @@ class LoginContainer extends React.Component { expiresAt: response.getAuthResponse().expires_at, }) } - - onAuthFailure(error) { + const onAuthFailure = (error) => { + // TODO Show error alert console.error(error) } - render() { - if (!this.props.visible) { - return - } - - return ( - ( - - Login with Google - - )} - /> - ) + if (!visible) { + return } -} -const mapStateToProps = (state, ownProps) => { - return { - visible: ownProps.visible, - } + return ( + ( + + Login with Google + + )} + /> + ) } -const mapDispatchToProps = (dispatch) => { - return { - onLogin: (payload) => dispatch(logIn(payload)), - } -} - -const Login = connect(mapStateToProps, mapDispatchToProps)(LoginContainer) - export default Login diff --git a/opendc-web/opendc-web-ui/src/containers/auth/Logout.js b/opendc-web/opendc-web-ui/src/containers/auth/Logout.js index 22400381..66f0f6db 100644 --- a/opendc-web/opendc-web-ui/src/containers/auth/Logout.js +++ b/opendc-web/opendc-web-ui/src/containers/auth/Logout.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { logOut } from '../../actions/auth' import LogoutButton from '../../components/navigation/LogoutButton' -const mapDispatchToProps = (dispatch) => { - return { - onLogout: () => dispatch(logOut()), - } +const Logout = (props) => { + const dispatch = useDispatch() + return dispatch(logOut())} /> } -const Logout = connect(undefined, mapDispatchToProps)(LogoutButton) - export default Logout diff --git a/opendc-web/opendc-web-ui/src/containers/auth/ProfileName.js b/opendc-web/opendc-web-ui/src/containers/auth/ProfileName.js index 06da75ab..291c0068 100644 --- a/opendc-web/opendc-web-ui/src/containers/auth/ProfileName.js +++ b/opendc-web/opendc-web-ui/src/containers/auth/ProfileName.js @@ -1,14 +1,9 @@ import React from 'react' -import { connect } from 'react-redux' +import { useSelector } from 'react-redux' -const mapStateToProps = (state) => { - return { - text: state.auth.givenName + ' ' + state.auth.familyName, - } +function ProfileName() { + const name = useSelector((state) => `${state.auth.givenName} ${state.auth.familyName}`) + return {name} } -const SpanElement = ({ text }) => {text} - -const ProfileName = connect(mapStateToProps)(SpanElement) - export default ProfileName diff --git a/opendc-web/opendc-web-ui/src/containers/modals/DeleteMachineModal.js b/opendc-web/opendc-web-ui/src/containers/modals/DeleteMachineModal.js index f30febdb..33b2612f 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/DeleteMachineModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/DeleteMachineModal.js @@ -1,35 +1,26 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeDeleteMachineModal } from '../../actions/modals/topology' import { deleteMachine } from '../../actions/topology/machine' import ConfirmationModal from '../../components/modals/ConfirmationModal' -const DeleteMachineModalComponent = ({ visible, callback }) => ( - -) - -const mapStateToProps = (state) => { - return { - visible: state.modals.deleteMachineModalVisible, +const DeleteMachineModal = () => { + const dispatch = useDispatch() + const callback = (isConfirmed) => { + if (isConfirmed) { + dispatch(deleteMachine()) + } + dispatch(closeDeleteMachineModal()) } + const visible = useSelector((state) => state.modals.deleteMachineModalVisible) + return ( + + ) } -const mapDispatchToProps = (dispatch) => { - return { - callback: (isConfirmed) => { - if (isConfirmed) { - dispatch(deleteMachine()) - } - dispatch(closeDeleteMachineModal()) - }, - } -} - -const DeleteMachineModal = connect(mapStateToProps, mapDispatchToProps)(DeleteMachineModalComponent) - export default DeleteMachineModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js b/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js index e7c4014d..93a38642 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js @@ -1,35 +1,27 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeDeleteProfileModal } from '../../actions/modals/profile' import { deleteCurrentUser } from '../../actions/users' import ConfirmationModal from '../../components/modals/ConfirmationModal' -const DeleteProfileModalComponent = ({ visible, callback }) => ( - -) +const DeleteProfileModal = () => { + const visible = useSelector((state) => state.modals.deleteProfileModalVisible) -const mapStateToProps = (state) => { - return { - visible: state.modals.deleteProfileModalVisible, + const dispatch = useDispatch() + const callback = (isConfirmed) => { + if (isConfirmed) { + dispatch(deleteCurrentUser()) + } + dispatch(closeDeleteProfileModal()) } + return ( + + ) } -const mapDispatchToProps = (dispatch) => { - return { - callback: (isConfirmed) => { - if (isConfirmed) { - dispatch(deleteCurrentUser()) - } - dispatch(closeDeleteProfileModal()) - }, - } -} - -const DeleteProfileModal = connect(mapStateToProps, mapDispatchToProps)(DeleteProfileModalComponent) - export default DeleteProfileModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/DeleteRackModal.js b/opendc-web/opendc-web-ui/src/containers/modals/DeleteRackModal.js index 0cb22a7e..ca76fd04 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/DeleteRackModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/DeleteRackModal.js @@ -1,35 +1,27 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeDeleteRackModal } from '../../actions/modals/topology' import { deleteRack } from '../../actions/topology/rack' import ConfirmationModal from '../../components/modals/ConfirmationModal' -const DeleteRackModalComponent = ({ visible, callback }) => ( - -) - -const mapStateToProps = (state) => { - return { - visible: state.modals.deleteRackModalVisible, +const DeleteRackModal = (props) => { + const visible = useSelector((state) => state.modals.deleteRackModalVisible) + const dispatch = useDispatch() + const callback = (isConfirmed) => { + if (isConfirmed) { + dispatch(deleteRack()) + } + dispatch(closeDeleteRackModal()) } + return ( + + ) } -const mapDispatchToProps = (dispatch) => { - return { - callback: (isConfirmed) => { - if (isConfirmed) { - dispatch(deleteRack()) - } - dispatch(closeDeleteRackModal()) - }, - } -} - -const DeleteRackModal = connect(mapStateToProps, mapDispatchToProps)(DeleteRackModalComponent) - export default DeleteRackModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/DeleteRoomModal.js b/opendc-web/opendc-web-ui/src/containers/modals/DeleteRoomModal.js index 1f6eef92..9a7be6a6 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/DeleteRoomModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/DeleteRoomModal.js @@ -1,35 +1,28 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeDeleteRoomModal } from '../../actions/modals/topology' import { deleteRoom } from '../../actions/topology/room' import ConfirmationModal from '../../components/modals/ConfirmationModal' -const DeleteRoomModalComponent = ({ visible, callback }) => ( - -) +const DeleteRoomModal = (props) => { + const visible = useSelector((state) => state.modals.deleteRoomModalVisible) -const mapStateToProps = (state) => { - return { - visible: state.modals.deleteRoomModalVisible, + const dispatch = useDispatch() + const callback = (isConfirmed) => { + if (isConfirmed) { + dispatch(deleteRoom()) + } + dispatch(closeDeleteRoomModal()) } + return ( + + ) } -const mapDispatchToProps = (dispatch) => { - return { - callback: (isConfirmed) => { - if (isConfirmed) { - dispatch(deleteRoom()) - } - dispatch(closeDeleteRoomModal()) - }, - } -} - -const DeleteRoomModal = connect(mapStateToProps, mapDispatchToProps)(DeleteRoomModalComponent) - export default DeleteRoomModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/EditRackNameModal.js b/opendc-web/opendc-web-ui/src/containers/modals/EditRackNameModal.js index 9128f449..edb57217 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/EditRackNameModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/EditRackNameModal.js @@ -1,40 +1,37 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeEditRackNameModal } from '../../actions/modals/topology' import { editRackName } from '../../actions/topology/rack' import TextInputModal from '../../components/modals/TextInputModal' -const EditRackNameModalComponent = ({ visible, previousName, callback }) => ( - -) +const EditRackNameModal = (props) => { + const { visible, previousName } = useSelector((state) => { + return { + visible: state.modals.editRackNameModalVisible, + previousName: + state.interactionLevel.mode === 'RACK' + ? state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].name + : '', + } + }) -const mapStateToProps = (state) => { - return { - visible: state.modals.editRackNameModalVisible, - previousName: - state.interactionLevel.mode === 'RACK' - ? state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].name - : '', + const dispatch = useDispatch() + const callback = (name) => { + if (name) { + dispatch(editRackName(name)) + } + dispatch(closeEditRackNameModal()) } + return ( + + ) } -const mapDispatchToProps = (dispatch) => { - return { - callback: (name) => { - if (name) { - dispatch(editRackName(name)) - } - dispatch(closeEditRackNameModal()) - }, - } -} - -const EditRackNameModal = connect(mapStateToProps, mapDispatchToProps)(EditRackNameModalComponent) - export default EditRackNameModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/EditRoomNameModal.js b/opendc-web/opendc-web-ui/src/containers/modals/EditRoomNameModal.js index 8032a5d1..a804c0b0 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/EditRoomNameModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/EditRoomNameModal.js @@ -1,38 +1,31 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeEditRoomNameModal } from '../../actions/modals/topology' import { editRoomName } from '../../actions/topology/room' import TextInputModal from '../../components/modals/TextInputModal' -const EditRoomNameModalComponent = ({ visible, previousName, callback }) => ( - -) +const EditRoomNameModal = (props) => { + const visible = useSelector((state) => state.modals.editRoomNameModalVisible) + const previousName = useSelector((state) => + state.interactionLevel.mode === 'ROOM' ? state.objects.room[state.interactionLevel.roomId].name : '' + ) -const mapStateToProps = (state) => { - return { - visible: state.modals.editRoomNameModalVisible, - previousName: - state.interactionLevel.mode === 'ROOM' ? state.objects.room[state.interactionLevel.roomId].name : '', + const dispatch = useDispatch() + const callback = (name) => { + if (name) { + dispatch(editRoomName(name)) + } + dispatch(closeEditRoomNameModal()) } + return ( + + ) } - -const mapDispatchToProps = (dispatch) => { - return { - callback: (name) => { - if (name) { - dispatch(editRoomName(name)) - } - dispatch(closeEditRoomNameModal()) - }, - } -} - -const EditRoomNameModal = connect(mapStateToProps, mapDispatchToProps)(EditRoomNameModalComponent) - export default EditRoomNameModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewPortfolioModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewPortfolioModal.js index 6cf12d8e..b364ed4c 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/NewPortfolioModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/NewPortfolioModal.js @@ -1,30 +1,24 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { closeNewPortfolioModal } from '../../actions/modals/portfolios' import NewPortfolioModalComponent from '../../components/modals/custom-components/NewPortfolioModalComponent' import { addPortfolio } from '../../actions/portfolios' -import { closeNewPortfolioModal } from '../../actions/modals/portfolios' - -const mapStateToProps = (state) => { - return { - show: state.modals.newPortfolioModalVisible, - } -} -const mapDispatchToProps = (dispatch) => { - return { - callback: (name, targets) => { - if (name) { - dispatch( - addPortfolio({ - name, - targets, - }) - ) - } - dispatch(closeNewPortfolioModal()) - }, +const NewPortfolioModal = (props) => { + const show = useSelector((state) => state.modals.newPortfolioModalVisible) + const dispatch = useDispatch() + const callback = (name, targets) => { + if (name) { + dispatch( + addPortfolio({ + name, + targets, + }) + ) + } + dispatch(closeNewPortfolioModal()) } + return } -const NewPortfolioModal = connect(mapStateToProps, mapDispatchToProps)(NewPortfolioModalComponent) - export default NewPortfolioModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js index d306dc45..e63ba76b 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js @@ -1,30 +1,19 @@ import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { closeNewProjectModal } from '../../actions/modals/projects' import { addProject } from '../../actions/projects' import TextInputModal from '../../components/modals/TextInputModal' -const NewProjectModalComponent = ({ visible, callback }) => ( - -) - -const mapStateToProps = (state) => { - return { - visible: state.modals.newProjectModalVisible, +const NewProjectModal = (props) => { + const visible = useSelector((state) => state.modals.newProjectModalVisible) + const dispatch = useDispatch() + const callback = (text) => { + if (text) { + dispatch(addProject(text)) + } + dispatch(closeNewProjectModal()) } + return } -const mapDispatchToProps = (dispatch) => { - return { - callback: (text) => { - if (text) { - dispatch(addProject(text)) - } - dispatch(closeNewProjectModal()) - }, - } -} - -const NewProjectModal = connect(mapStateToProps, mapDispatchToProps)(NewProjectModalComponent) - export default NewProjectModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js index 7d774fa4..1de838e4 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js @@ -1,50 +1,48 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import NewScenarioModalComponent from '../../components/modals/custom-components/NewScenarioModalComponent' import { addScenario } from '../../actions/scenarios' import { closeNewScenarioModal } from '../../actions/modals/scenarios' -const mapStateToProps = (state) => { - let topologies = - state.currentProjectId !== '-1' - ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) - : [] - if (topologies.filter((t) => !t).length > 0) { - topologies = [] - } +const NewScenarioModal = (props) => { + const state = useSelector((state) => { + let topologies = + state.currentProjectId !== '-1' + ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) + : [] + if (topologies.filter((t) => !t).length > 0) { + topologies = [] + } - return { - show: state.modals.newScenarioModalVisible, - currentPortfolioId: state.currentPortfolioId, - currentPortfolioScenarioIds: - state.currentPortfolioId !== '-1' && state.objects.portfolio[state.currentPortfolioId] - ? state.objects.portfolio[state.currentPortfolioId].scenarioIds - : [], - traces: Object.values(state.objects.trace), - topologies, - schedulers: Object.values(state.objects.scheduler), - } -} + return { + show: state.modals.newScenarioModalVisible, + currentPortfolioId: state.currentPortfolioId, + currentPortfolioScenarioIds: + state.currentPortfolioId !== '-1' && state.objects.portfolio[state.currentPortfolioId] + ? state.objects.portfolio[state.currentPortfolioId].scenarioIds + : [], + traces: Object.values(state.objects.trace), + topologies, + schedulers: Object.values(state.objects.scheduler), + } + }) -const mapDispatchToProps = (dispatch) => { - return { - callback: (name, portfolioId, trace, topology, operational) => { - if (name) { - dispatch( - addScenario({ - portfolioId, - name, - trace, - topology, - operational, - }) - ) - } - - dispatch(closeNewScenarioModal()) - }, + const dispatch = useDispatch() + const callback = (name, portfolioId, trace, topology, operational) => { + if (name) { + dispatch( + addScenario({ + portfolioId, + name, + trace, + topology, + operational, + }) + ) + } + dispatch(closeNewScenarioModal()) } + return } -const NewScenarioModal = connect(mapStateToProps, mapDispatchToProps)(NewScenarioModalComponent) - export default NewScenarioModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewTopologyModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewTopologyModal.js index 0acf6cf2..2f81706e 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/NewTopologyModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/NewTopologyModal.js @@ -1,42 +1,48 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import NewTopologyModalComponent from '../../components/modals/custom-components/NewTopologyModalComponent' import { closeNewTopologyModal } from '../../actions/modals/topology' import { addTopology } from '../../actions/topologies' -const mapStateToProps = (state) => { - let topologies = state.objects.project[state.currentProjectId] - ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) - : [] - if (topologies.filter((t) => !t).length > 0) { - topologies = [] - } +const NewTopologyModal = () => { + const show = useSelector((state) => state.modals.changeTopologyModalVisible) + const topologies = useSelector((state) => { + let topologies = state.objects.project[state.currentProjectId] + ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) + : [] + if (topologies.filter((t) => !t).length > 0) { + topologies = [] + } - return { - show: state.modals.changeTopologyModalVisible, - topologies, - } -} + return topologies + }) -const mapDispatchToProps = (dispatch) => { - return { - onCreateTopology: (name) => { - if (name) { - dispatch(addTopology(name, undefined)) - } - dispatch(closeNewTopologyModal()) - }, - onDuplicateTopology: (name, id) => { - if (name) { - dispatch(addTopology(name, id)) - } - dispatch(closeNewTopologyModal()) - }, - onCancel: () => { - dispatch(closeNewTopologyModal()) - }, + const dispatch = useDispatch() + const onCreateTopology = (name) => { + if (name) { + dispatch(addTopology(name, undefined)) + } + dispatch(closeNewTopologyModal()) + } + const onDuplicateTopology = (name, id) => { + if (name) { + dispatch(addTopology(name, id)) + } + dispatch(closeNewTopologyModal()) + } + const onCancel = () => { + dispatch(closeNewTopologyModal()) } -} -const NewTopologyModal = connect(mapStateToProps, mapDispatchToProps)(NewTopologyModalComponent) + return ( + + ) +} export default NewTopologyModal diff --git a/opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js b/opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js index 845d54e1..42a44345 100644 --- a/opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js @@ -1,12 +1,12 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import AppNavbarComponent from '../../components/navigation/AppNavbarComponent' -const mapStateToProps = (state) => { - return { - project: state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined, - } +const AppNavbarContainer = (props) => { + const project = useSelector((state) => + state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined + ) + return } -const AppNavbarContainer = connect(mapStateToProps)(AppNavbarComponent) - export default AppNavbarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js b/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js index dfd6affe..26f95c55 100644 --- a/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js +++ b/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js @@ -1,19 +1,13 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' import { setAuthVisibilityFilter } from '../../actions/projects' import FilterButton from '../../components/projects/FilterButton' -const mapStateToProps = (state, ownProps) => { - return { - active: state.projectList.authVisibilityFilter === ownProps.filter, - } -} +const FilterLink = (props) => { + const active = useSelector((state) => state.projectList.authVisibilityFilter === props.filter) + const dispatch = useDispatch() -const mapDispatchToProps = (dispatch, ownProps) => { - return { - onClick: () => dispatch(setAuthVisibilityFilter(ownProps.filter)), - } + return dispatch(setAuthVisibilityFilter(props.filter))} active={active} /> } -const FilterLink = connect(mapStateToProps, mapDispatchToProps)(FilterButton) - export default FilterLink diff --git a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js index ffd4a4a3..b8f6fef5 100644 --- a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js @@ -1,13 +1,11 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { openNewProjectModal } from '../../actions/modals/projects' import NewProjectButtonComponent from '../../components/projects/NewProjectButtonComponent' -const mapDispatchToProps = (dispatch) => { - return { - onClick: () => dispatch(openNewProjectModal()), - } +const NewProjectButtonContainer = (props) => { + const dispatch = useDispatch() + return dispatch(openNewProjectModal())} /> } -const NewProjectButtonContainer = connect(undefined, mapDispatchToProps)(NewProjectButtonComponent) - export default NewProjectButtonContainer diff --git a/opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js b/opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js index 8bcbb7fd..a13034e9 100644 --- a/opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js +++ b/opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js @@ -1,20 +1,15 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useDispatch } from 'react-redux' import { deleteProject } from '../../actions/projects' import ProjectActionButtons from '../../components/projects/ProjectActionButtons' -const mapStateToProps = (state, ownProps) => { - return { - projectId: ownProps.projectId, - } -} - -const mapDispatchToProps = (dispatch) => { - return { +const ProjectActions = (props) => { + const dispatch = useDispatch() + const actions = { onViewUsers: (id) => {}, // TODO implement user viewing onDelete: (id) => dispatch(deleteProject(id)), } + return } -const ProjectActions = connect(mapStateToProps, mapDispatchToProps)(ProjectActionButtons) - export default ProjectActions diff --git a/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js b/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js index f0010540..b869775c 100644 --- a/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js +++ b/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js @@ -1,4 +1,5 @@ -import { connect } from 'react-redux' +import React from 'react' +import { useSelector } from 'react-redux' import ProjectList from '../../components/projects/ProjectAuthList' const getVisibleProjectAuths = (projectAuths, filter) => { @@ -14,19 +15,18 @@ const getVisibleProjectAuths = (projectAuths, filter) => { } } -const mapStateToProps = (state) => { - const denormalizedAuthorizations = state.projectList.authorizationsOfCurrentUser.map((authorizationIds) => { - const authorization = state.objects.authorization[authorizationIds] - authorization.user = state.objects.user[authorization.userId] - authorization.project = state.objects.project[authorization.projectId] - return authorization - }) +const VisibleProjectAuthList = (props) => { + const authorizations = useSelector((state) => { + const denormalizedAuthorizations = state.projectList.authorizationsOfCurrentUser.map((authorizationIds) => { + const authorization = state.objects.authorization[authorizationIds] + authorization.user = state.objects.user[authorization.userId] + authorization.project = state.objects.project[authorization.projectId] + return authorization + }) - return { - authorizations: getVisibleProjectAuths(denormalizedAuthorizations, state.projectList.authVisibilityFilter), - } + return getVisibleProjectAuths(denormalizedAuthorizations, state.projectList.authVisibilityFilter) + }) + return } -const VisibleProjectAuthList = connect(mapStateToProps)(ProjectList) - export default VisibleProjectAuthList diff --git a/opendc-web/opendc-web-ui/src/pages/App.js b/opendc-web/opendc-web-ui/src/pages/App.js index cbc805b8..03e21cc2 100644 --- a/opendc-web/opendc-web-ui/src/pages/App.js +++ b/opendc-web/opendc-web-ui/src/pages/App.js @@ -1,8 +1,8 @@ import PropTypes from 'prop-types' -import React from 'react' +import React, { useEffect } from 'react' import DocumentTitle from 'react-document-title' -import { connect } from 'react-redux' -import { ShortcutManager } from 'react-shortcuts' +import { HotKeys } from 'react-hotkeys' +import { useDispatch, useSelector } from 'react-redux' import { openPortfolioSucceeded } from '../actions/portfolios' import { openProjectSucceeded } from '../actions/projects' import ToolPanelComponent from '../components/app/map/controls/ToolPanelComponent' @@ -15,7 +15,6 @@ import DeleteRackModal from '../containers/modals/DeleteRackModal' import DeleteRoomModal from '../containers/modals/DeleteRoomModal' import EditRackNameModal from '../containers/modals/EditRackNameModal' import EditRoomNameModal from '../containers/modals/EditRoomNameModal' -import KeymapConfiguration from '../shortcuts/keymap' import NewTopologyModal from '../containers/modals/NewTopologyModal' import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' import ProjectSidebarContainer from '../containers/app/sidebars/project/ProjectSidebarContainer' @@ -23,115 +22,82 @@ import { openScenarioSucceeded } from '../actions/scenarios' import NewPortfolioModal from '../containers/modals/NewPortfolioModal' import NewScenarioModal from '../containers/modals/NewScenarioModal' import PortfolioResultsContainer from '../containers/app/results/PortfolioResultsContainer' +import KeymapConfiguration from '../shortcuts/keymap' -const shortcutManager = new ShortcutManager(KeymapConfiguration) - -class AppComponent extends React.Component { - static propTypes = { - projectId: PropTypes.string.isRequired, - portfolioId: PropTypes.string, - scenarioId: PropTypes.string, - projectName: PropTypes.string, - } - static childContextTypes = { - shortcuts: PropTypes.object.isRequired, - } +const App = ({ projectId, portfolioId, scenarioId }) => { + const projectName = useSelector( + (state) => + state.currentProjectId !== '-1' && + state.objects.project[state.currentProjectId] && + state.objects.project[state.currentProjectId].name + ) + const topologyIsLoading = useSelector((state) => state.currentTopologyId === '-1') - componentDidMount() { - if (this.props.scenarioId) { - this.props.openScenarioSucceeded(this.props.projectId, this.props.portfolioId, this.props.scenarioId) - } else if (this.props.portfolioId) { - this.props.openPortfolioSucceeded(this.props.projectId, this.props.portfolioId) + const dispatch = useDispatch() + useEffect(() => { + if (scenarioId) { + dispatch(openScenarioSucceeded(projectId, portfolioId, scenarioId)) + } else if (portfolioId) { + dispatch(openPortfolioSucceeded(projectId, portfolioId)) } else { - this.props.openProjectSucceeded(this.props.projectId) + dispatch(openProjectSucceeded(projectId)) } - } + }, [projectId, portfolioId, scenarioId, dispatch]) - getChildContext() { - return { - shortcuts: shortcutManager, - } - } + const constructionElements = topologyIsLoading ? ( +
+ +
+ ) : ( +
+ + + + + +
+ ) - render() { - const constructionElements = this.props.topologyIsLoading ? ( -
- -
- ) : ( -
- - - - - + const portfolioElements = ( +
+ +
+
- ) +
+ ) - const portfolioElements = ( -
- -
- -
+ const scenarioElements = ( +
+ +
+

Scenario loading

- ) +
+ ) - const scenarioElements = ( -
- -
-

Scenario loading

-
-
- ) - - return ( - -
- - {this.props.scenarioId - ? scenarioElements - : this.props.portfolioId - ? portfolioElements - : constructionElements} - - - - - - - - -
-
- ) - } + return ( + + + + {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements} + + + + + + + + + + + ) } -const mapStateToProps = (state) => { - let projectName = undefined - if (state.currentProjectId !== '-1' && state.objects.project[state.currentProjectId]) { - projectName = state.objects.project[state.currentProjectId].name - } - - return { - topologyIsLoading: state.currentTopologyId === '-1', - projectName, - } +App.propTypes = { + projectId: PropTypes.string.isRequired, + portfolioId: PropTypes.string, + scenarioId: PropTypes.string, } -const mapDispatchToProps = (dispatch) => { - return { - openProjectSucceeded: (projectId) => dispatch(openProjectSucceeded(projectId)), - openPortfolioSucceeded: (projectId, portfolioId) => dispatch(openPortfolioSucceeded(projectId, portfolioId)), - openScenarioSucceeded: (projectId, portfolioId, scenarioId) => - dispatch(openScenarioSucceeded(projectId, portfolioId, scenarioId)), - } -} - -const App = connect(mapStateToProps, mapDispatchToProps)(AppComponent) - export default App diff --git a/opendc-web/opendc-web-ui/src/pages/Profile.js b/opendc-web/opendc-web-ui/src/pages/Profile.js index 0d94b519..1e817037 100644 --- a/opendc-web/opendc-web-ui/src/pages/Profile.js +++ b/opendc-web/opendc-web-ui/src/pages/Profile.js @@ -1,35 +1,36 @@ import React from 'react' import DocumentTitle from 'react-document-title' -import { connect } from 'react-redux' +import { useDispatch } from 'react-redux' import { openDeleteProfileModal } from '../actions/modals/profile' import DeleteProfileModal from '../containers/modals/DeleteProfileModal' import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -const ProfileContainer = ({ onDelete }) => ( - -
- -
- -

- This does not delete your Google account, but simply disconnects it from the OpenDC platform and - deletes any project info that is associated with you (projects you own and any authorizations you - may have on other projects). -

-
- -
-
-) +const Profile = () => { + const dispatch = useDispatch() + const onDelete = () => dispatch(openDeleteProfileModal()) -const mapDispatchToProps = (dispatch) => { - return { - onDelete: () => dispatch(openDeleteProfileModal()), - } + return ( + +
+ +
+ +

+ This does not delete your Google account, but simply disconnects it from the OpenDC platform and + deletes any project info that is associated with you (projects you own and any authorizations + you may have on other projects). +

+
+ +
+
+ ) } -const Profile = connect(undefined, mapDispatchToProps)(ProfileContainer) - export default Profile diff --git a/opendc-web/opendc-web-ui/src/pages/Projects.js b/opendc-web/opendc-web-ui/src/pages/Projects.js index bb54aaa5..f759073f 100644 --- a/opendc-web/opendc-web-ui/src/pages/Projects.js +++ b/opendc-web/opendc-web-ui/src/pages/Projects.js @@ -1,7 +1,6 @@ -import React from 'react' +import React, { useEffect } from 'react' import DocumentTitle from 'react-document-title' -import { connect } from 'react-redux' -import { openNewProjectModal } from '../actions/modals/projects' +import { useDispatch } from 'react-redux' import { fetchAuthorizationsOfCurrentUser } from '../actions/users' import ProjectFilterPanel from '../components/projects/FilterPanel' import NewProjectModal from '../containers/modals/NewProjectModal' @@ -9,35 +8,24 @@ import NewProjectButtonContainer from '../containers/projects/NewProjectButtonCo import VisibleProjectList from '../containers/projects/VisibleProjectAuthList' import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -class ProjectsContainer extends React.Component { - componentDidMount() { - this.props.fetchAuthorizationsOfCurrentUser() - } +function Projects() { + const dispatch = useDispatch() - render() { - return ( - -
- -
- - - -
- -
-
- ) - } -} + useEffect(() => dispatch(fetchAuthorizationsOfCurrentUser())) -const mapDispatchToProps = (dispatch) => { - return { - fetchAuthorizationsOfCurrentUser: () => dispatch(fetchAuthorizationsOfCurrentUser()), - openNewProjectModal: () => dispatch(openNewProjectModal()), - } + return ( + +
+ +
+ + + +
+ +
+
+ ) } -const Projects = connect(undefined, mapDispatchToProps)(ProjectsContainer) - export default Projects diff --git a/opendc-web/opendc-web-ui/src/shortcuts/keymap.js b/opendc-web/opendc-web-ui/src/shortcuts/keymap.js index 797340d7..8260ace2 100644 --- a/opendc-web/opendc-web-ui/src/shortcuts/keymap.js +++ b/opendc-web/opendc-web-ui/src/shortcuts/keymap.js @@ -1,10 +1,8 @@ const KeymapConfiguration = { - MAP: { - MOVE_LEFT: ['a', 'left'], - MOVE_RIGHT: ['d', 'right'], - MOVE_UP: ['w', 'up'], - MOVE_DOWN: ['s', 'down'], - }, + MOVE_LEFT: ['a', 'left'], + MOVE_RIGHT: ['d', 'right'], + MOVE_UP: ['w', 'up'], + MOVE_DOWN: ['s', 'down'], } export default KeymapConfiguration -- cgit v1.2.3 From 00c8d0086631a249f7d9dcee022e013bbc683616 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 28 Oct 2020 16:42:43 +0100 Subject: ui: Do not prevent default on mouse scroll This change removes the prevent default from the mouse scroll since Chrome does not allow it anymore. --- opendc-web/opendc-web-ui/src/components/app/map/MapStageComponent.js | 1 - 1 file changed, 1 deletion(-) (limited to 'opendc-web/opendc-web-ui/src') 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 60bf3104..7ca10792 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 @@ -46,7 +46,6 @@ class MapStageComponent extends React.Component { } updateScale(e) { - e.preventDefault() this.props.zoomInOnPosition(e.deltaY < 0, this.state.mouseX, this.state.mouseY) } -- cgit v1.2.3 From 4d4fb1bb19c045e78c74e57816ebee251e1d7d08 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 28 Oct 2020 23:41:16 +0100 Subject: ui: Fix undefined project in NewScenarioModal --- .../src/containers/modals/NewScenarioModal.js | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js index 1de838e4..b588b4bc 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js @@ -5,15 +5,22 @@ import { addScenario } from '../../actions/scenarios' import { closeNewScenarioModal } from '../../actions/modals/scenarios' const NewScenarioModal = (props) => { - const state = useSelector((state) => { - let topologies = - state.currentProjectId !== '-1' - ? state.objects.project[state.currentProjectId].topologyIds.map((t) => state.objects.topology[t]) - : [] + const topologies = useSelector(({ currentProjectId, objects }) => { + console.log(currentProjectId, objects) + + if (currentProjectId === '-1' || !objects.project[currentProjectId]) { + return [] + } + + const topologies = objects.project[currentProjectId].topologyIds.map((t) => objects.topology[t]) + if (topologies.filter((t) => !t).length > 0) { - topologies = [] + return [] } + return topologies + }) + const state = useSelector((state) => { return { show: state.modals.newScenarioModalVisible, currentPortfolioId: state.currentPortfolioId, @@ -22,7 +29,6 @@ const NewScenarioModal = (props) => { ? state.objects.portfolio[state.currentPortfolioId].scenarioIds : [], traces: Object.values(state.objects.trace), - topologies, schedulers: Object.values(state.objects.scheduler), } }) @@ -42,7 +48,8 @@ const NewScenarioModal = (props) => { } dispatch(closeNewScenarioModal()) } - return + + return } export default NewScenarioModal -- cgit v1.2.3 From 6e6f14db8986f5de6491b51117de0e1b0438b341 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Thu, 29 Oct 2020 00:53:52 +0100 Subject: ui: Adapt home components to Reactstrap --- .../src/components/home/ContactSection.js | 44 +++++++++++----------- .../src/components/home/ContentSection.js | 13 ++++--- .../src/components/home/IntroSection.js | 21 ++++++----- .../src/components/home/ScreenshotSection.js | 13 +------ .../src/components/home/StakeholderSection.js | 18 ++++++--- .../src/components/home/TechnologiesSection.js | 21 ++++++----- 6 files changed, 66 insertions(+), 64 deletions(-) (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/components/home/ContactSection.js b/opendc-web/opendc-web-ui/src/components/home/ContactSection.js index d5c6e55f..d25a1bc4 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ContactSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ContactSection.js @@ -1,42 +1,44 @@ import React from 'react' import FontAwesome from 'react-fontawesome' -import './ContactSection.sass' +import { Row, Col } from 'reactstrap' import ContentSection from './ContentSection' +import './ContactSection.sass' + const ContactSection = () => ( - -
-
+ + + - -
-
- TU Delft -
-
-
-
+ + + + + TU Delft + + + + A project by the   @Large Research Group . -
-
-
-
+ + + +
Disclaimer: @@ -47,8 +49,8 @@ const ContactSection = () => ( license ). Sorry for the inconvenience. -
-
+ +
) diff --git a/opendc-web/opendc-web-ui/src/components/home/ContentSection.js b/opendc-web/opendc-web-ui/src/components/home/ContentSection.js index 9d4832d9..3a8960d9 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ContentSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ContentSection.js @@ -1,15 +1,16 @@ +import React from 'react' import classNames from 'classnames' +import { Container } from 'reactstrap' import PropTypes from 'prop-types' -import React from 'react' import './ContentSection.sass' -const ContentSection = ({ name, title, children }) => ( -
-
+const ContentSection = ({ name, title, children, className }) => ( +
+

{title}

{children} -
-
+ + ) ContentSection.propTypes = { diff --git a/opendc-web/opendc-web-ui/src/components/home/IntroSection.js b/opendc-web/opendc-web-ui/src/components/home/IntroSection.js index a799272a..bc6ee83b 100644 --- a/opendc-web/opendc-web-ui/src/components/home/IntroSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/IntroSection.js @@ -1,18 +1,19 @@ import React from 'react' +import { Container, Row, Col } from 'reactstrap' const IntroSection = () => (
-
-
-
+ + +

The datacenter (DC) industry...

  • Is worth over $15 bn, and growing
  • Has many hard-to-grasp concepts
  • Needs to become accessible to many
-
-
+ + ( Image source

-
-
+ +

OpenDC provides...

  • Collaborative online DC modeling
  • Diverse and effective DC simulation
  • Exploratory DC performance feedback
-
-
-
+ + +
) diff --git a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js index 263590d5..33aab17f 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js @@ -1,4 +1,3 @@ -import classNames from 'classnames' import React from 'react' import { Row, Col } from 'reactstrap' import ContentSection from './ContentSection' @@ -7,20 +6,12 @@ import './ScreenshotSection.sass' const ScreenshotSection = ({ name, title, imageUrl, caption, imageIsRight, children }) => ( - + {children} {caption} - {caption} +
{caption}
diff --git a/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js b/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js index e5ed9683..1624b4d2 100644 --- a/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js @@ -1,29 +1,35 @@ import React from 'react' +import { Row, Col } from 'reactstrap' import ContentSection from './ContentSection' const Stakeholder = ({ name, title, subtitle }) => ( -
- +

{title}

{subtitle}

-
+ ) const StakeholderSection = () => ( -
+ -
+
) diff --git a/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js b/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js index c6013c71..efd77edf 100644 --- a/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js @@ -1,39 +1,40 @@ import React from 'react' import FontAwesome from 'react-fontawesome' +import { ListGroup, ListGroupItem } from 'reactstrap' import ContentSection from './ContentSection' const TechnologiesSection = () => ( -
    -
  • + + Browser JavaScript, React, Redux, Konva -
  • -
  • + + Server Python, Flask, FlaskSocketIO, OpenAPI -
  • -
  • + + Database MongoDB -
  • -
  • + + Simulator Kotlin -
  • -
+ +
) -- cgit v1.2.3 From c2c5dfe0119546935118ce5ae1803bf87f0b787c Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 10 May 2021 17:31:43 +0200 Subject: ui: Update React dependencies This change updates the React dependencies to version 17, in order to keep up to date with React. --- opendc-web/opendc-web-ui/src/pages/App.js | 30 +++++++++++----------- opendc-web/opendc-web-ui/src/pages/Home.js | 4 +-- opendc-web/opendc-web-ui/src/pages/NotFound.js | 11 ++++---- opendc-web/opendc-web-ui/src/pages/Profile.js | 35 +++++++++++--------------- opendc-web/opendc-web-ui/src/pages/Projects.js | 21 ++++++++-------- opendc-web/opendc-web-ui/src/util/hooks.js | 29 +++++++++++++++++++++ 6 files changed, 77 insertions(+), 53 deletions(-) create mode 100644 opendc-web/opendc-web-ui/src/util/hooks.js (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/pages/App.js b/opendc-web/opendc-web-ui/src/pages/App.js index 03e21cc2..ea62e8dc 100644 --- a/opendc-web/opendc-web-ui/src/pages/App.js +++ b/opendc-web/opendc-web-ui/src/pages/App.js @@ -1,6 +1,5 @@ import PropTypes from 'prop-types' import React, { useEffect } from 'react' -import DocumentTitle from 'react-document-title' import { HotKeys } from 'react-hotkeys' import { useDispatch, useSelector } from 'react-redux' import { openPortfolioSucceeded } from '../actions/portfolios' @@ -23,6 +22,7 @@ import NewPortfolioModal from '../containers/modals/NewPortfolioModal' import NewScenarioModal from '../containers/modals/NewScenarioModal' import PortfolioResultsContainer from '../containers/app/results/PortfolioResultsContainer' import KeymapConfiguration from '../shortcuts/keymap' +import { useDocumentTitle } from '../util/hooks' const App = ({ projectId, portfolioId, scenarioId }) => { const projectName = useSelector( @@ -76,21 +76,21 @@ const App = ({ projectId, portfolioId, scenarioId }) => {
) + useDocumentTitle(projectName ? projectName + ' - OpenDC' : 'Simulation - OpenDC') + return ( - - - - {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements} - - - - - - - - - - + + + {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements} + + + + + + + + + ) } diff --git a/opendc-web/opendc-web-ui/src/pages/Home.js b/opendc-web/opendc-web-ui/src/pages/Home.js index 6fc940c0..fb383426 100644 --- a/opendc-web/opendc-web-ui/src/pages/Home.js +++ b/opendc-web/opendc-web-ui/src/pages/Home.js @@ -1,5 +1,4 @@ import React from 'react' -import DocumentTitle from 'react-document-title' import ContactSection from '../components/home/ContactSection' import IntroSection from '../components/home/IntroSection' import JumbotronHeader from '../components/home/JumbotronHeader' @@ -10,8 +9,10 @@ import TeamSection from '../components/home/TeamSection' import TechnologiesSection from '../components/home/TechnologiesSection' import HomeNavbar from '../components/navigation/HomeNavbar' import './Home.sass' +import { useDocumentTitle } from '../util/hooks' function Home() { + useDocumentTitle('OpenDC') return (
@@ -24,7 +25,6 @@ function Home() { -
) diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.js b/opendc-web/opendc-web-ui/src/pages/NotFound.js index 72be7342..b933ffa5 100644 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.js +++ b/opendc-web/opendc-web-ui/src/pages/NotFound.js @@ -1,14 +1,15 @@ import React from 'react' -import DocumentTitle from 'react-document-title' import TerminalWindow from '../components/not-found/TerminalWindow' import './NotFound.sass' +import { useDocumentTitle } from '../util/hooks' -const NotFound = () => ( - +const NotFound = () => { + useDocumentTitle('Page Not Found - OpenDC') + return (
-
-) + ) +} export default NotFound diff --git a/opendc-web/opendc-web-ui/src/pages/Profile.js b/opendc-web/opendc-web-ui/src/pages/Profile.js index 1e817037..ea781686 100644 --- a/opendc-web/opendc-web-ui/src/pages/Profile.js +++ b/opendc-web/opendc-web-ui/src/pages/Profile.js @@ -1,35 +1,30 @@ import React from 'react' -import DocumentTitle from 'react-document-title' import { useDispatch } from 'react-redux' import { openDeleteProfileModal } from '../actions/modals/profile' import DeleteProfileModal from '../containers/modals/DeleteProfileModal' import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' +import { useDocumentTitle } from '../util/hooks' const Profile = () => { const dispatch = useDispatch() const onDelete = () => dispatch(openDeleteProfileModal()) + useDocumentTitle('My Profile - OpenDC') return ( - -
- -
- -

- This does not delete your Google account, but simply disconnects it from the OpenDC platform and - deletes any project info that is associated with you (projects you own and any authorizations - you may have on other projects). -

-
- +
+ +
+ +

+ This does not delete your Google account, but simply disconnects it from the OpenDC platform and + deletes any project info that is associated with you (projects you own and any authorizations you + may have on other projects). +

- + +
) } diff --git a/opendc-web/opendc-web-ui/src/pages/Projects.js b/opendc-web/opendc-web-ui/src/pages/Projects.js index f759073f..5e642a03 100644 --- a/opendc-web/opendc-web-ui/src/pages/Projects.js +++ b/opendc-web/opendc-web-ui/src/pages/Projects.js @@ -1,5 +1,4 @@ import React, { useEffect } from 'react' -import DocumentTitle from 'react-document-title' import { useDispatch } from 'react-redux' import { fetchAuthorizationsOfCurrentUser } from '../actions/users' import ProjectFilterPanel from '../components/projects/FilterPanel' @@ -7,24 +6,24 @@ import NewProjectModal from '../containers/modals/NewProjectModal' import NewProjectButtonContainer from '../containers/projects/NewProjectButtonContainer' import VisibleProjectList from '../containers/projects/VisibleProjectAuthList' import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' +import { useDocumentTitle } from '../util/hooks' function Projects() { const dispatch = useDispatch() useEffect(() => dispatch(fetchAuthorizationsOfCurrentUser())) + useDocumentTitle('My Projects - OpenDC') return ( - -
- -
- - - -
- +
+ +
+ + +
- + +
) } diff --git a/opendc-web/opendc-web-ui/src/util/hooks.js b/opendc-web/opendc-web-ui/src/util/hooks.js new file mode 100644 index 00000000..7780a778 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/util/hooks.js @@ -0,0 +1,29 @@ +/* + * 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 { useEffect } from 'react' + +export function useDocumentTitle(title) { + useEffect(() => { + document.title = title + }, [title]) +} -- cgit v1.2.3 From 873ddacf5abafe43fbc2b6c1033e473c3366dc62 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Tue, 11 May 2021 15:40:11 +0200 Subject: ui: Move component styling into CSS modules This change updates the frontend codebase by moving the component styling into CSS module files as opposed to the global styles which we used before. In addition, I have changed the syntax to the newer SCSS syntax, which is more similar to CSS. These changes reduces the styling conflicts that can occur between components and allows us to migrate to systems that do not support importing global styles in components. Moreover, we can benefit from treeshaking using CSS modules. --- .../app/map/controls/ScaleIndicatorComponent.js | 4 +- .../controls/ScaleIndicatorComponent.module.scss | 10 +++ .../app/map/controls/ScaleIndicatorComponent.sass | 9 --- .../app/map/controls/ToolPanelComponent.js | 4 +- .../map/controls/ToolPanelComponent.module.scss | 6 ++ .../app/map/controls/ToolPanelComponent.sass | 5 -- .../src/components/app/sidebars/Sidebar.js | 78 ++++++++++------------ .../components/app/sidebars/Sidebar.module.scss | 57 ++++++++++++++++ .../src/components/app/sidebars/Sidebar.sass | 50 -------------- .../sidebars/topology/rack/MachineListComponent.js | 4 +- .../topology/rack/MachineListComponent.module.scss | 3 + .../topology/rack/MachineListComponent.sass | 2 - .../sidebars/topology/rack/RackSidebarComponent.js | 8 +-- .../topology/rack/RackSidebarComponent.module.scss | 14 ++++ .../topology/rack/RackSidebarComponent.sass | 11 --- .../src/components/home/ContactSection.js | 6 +- .../src/components/home/ContactSection.module.scss | 20 ++++++ .../src/components/home/ContactSection.sass | 15 ----- .../src/components/home/ContentSection.js | 4 +- .../src/components/home/ContentSection.module.scss | 11 +++ .../src/components/home/ContentSection.sass | 9 --- .../src/components/home/IntroSection.js | 4 +- .../src/components/home/JumbotronHeader.js | 8 +-- .../components/home/JumbotronHeader.module.scss | 31 +++++++++ .../src/components/home/JumbotronHeader.sass | 24 ------- .../src/components/home/ModelingSection.js | 3 +- .../src/components/home/ScreenshotSection.js | 8 +-- .../components/home/ScreenshotSection.module.scss | 5 ++ .../src/components/home/ScreenshotSection.sass | 4 -- .../src/components/home/SimulationSection.js | 4 +- .../src/components/home/StakeholderSection.js | 4 +- .../src/components/home/TeamSection.js | 4 +- .../src/components/home/TechnologiesSection.js | 4 +- .../components/navigation/AppNavbarComponent.js | 2 +- .../src/components/navigation/HomeNavbar.js | 2 +- .../src/components/navigation/Navbar.js | 8 +-- .../src/components/navigation/Navbar.module.scss | 36 ++++++++++ .../src/components/navigation/Navbar.sass | 30 --------- .../src/components/not-found/BlinkingCursor.js | 4 +- .../not-found/BlinkingCursor.module.scss | 13 ++++ .../src/components/not-found/BlinkingCursor.sass | 35 ---------- .../src/components/not-found/CodeBlock.js | 4 +- .../src/components/not-found/CodeBlock.module.scss | 4 ++ .../src/components/not-found/CodeBlock.sass | 3 - .../src/components/not-found/TerminalWindow.js | 14 ++-- .../not-found/TerminalWindow.module.scss | 61 +++++++++++++++++ .../src/components/not-found/TerminalWindow.sass | 70 ------------------- .../src/components/projects/FilterPanel.js | 4 +- .../components/projects/FilterPanel.module.scss | 7 ++ .../src/components/projects/FilterPanel.sass | 5 -- .../opendc-web-ui/src/containers/auth/Login.js | 8 +-- opendc-web/opendc-web-ui/src/index.js | 2 +- opendc-web/opendc-web-ui/src/index.sass | 52 --------------- opendc-web/opendc-web-ui/src/index.scss | 68 +++++++++++++++++++ opendc-web/opendc-web-ui/src/pages/Home.js | 21 ++++-- .../opendc-web-ui/src/pages/Home.module.scss | 16 +++++ opendc-web/opendc-web-ui/src/pages/Home.sass | 9 --- opendc-web/opendc-web-ui/src/pages/NotFound.js | 4 +- .../opendc-web-ui/src/pages/NotFound.module.scss | 8 +++ opendc-web/opendc-web-ui/src/pages/NotFound.sass | 11 --- .../opendc-web-ui/src/style-globals/_mixins.sass | 21 ------ .../opendc-web-ui/src/style-globals/_mixins.scss | 5 ++ .../src/style-globals/_variables.sass | 31 --------- .../src/style-globals/_variables.scss | 31 +++++++++ 64 files changed, 516 insertions(+), 506 deletions(-) create mode 100644 opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/app/map/controls/ScaleIndicatorComponent.sass create mode 100644 opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/app/map/controls/ToolPanelComponent.sass create mode 100644 opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.sass create mode 100644 opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineListComponent.sass create mode 100644 opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/RackSidebarComponent.sass create mode 100644 opendc-web/opendc-web-ui/src/components/home/ContactSection.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/home/ContactSection.sass create mode 100644 opendc-web/opendc-web-ui/src/components/home/ContentSection.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/home/ContentSection.sass create mode 100644 opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.sass create mode 100644 opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.sass create mode 100644 opendc-web/opendc-web-ui/src/components/navigation/Navbar.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/navigation/Navbar.sass create mode 100644 opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.sass create mode 100644 opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.sass create mode 100644 opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.sass create mode 100644 opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/components/projects/FilterPanel.sass delete mode 100644 opendc-web/opendc-web-ui/src/index.sass create mode 100644 opendc-web/opendc-web-ui/src/index.scss create mode 100644 opendc-web/opendc-web-ui/src/pages/Home.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/pages/Home.sass create mode 100644 opendc-web/opendc-web-ui/src/pages/NotFound.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/pages/NotFound.sass delete mode 100644 opendc-web/opendc-web-ui/src/style-globals/_mixins.sass create mode 100644 opendc-web/opendc-web-ui/src/style-globals/_mixins.scss delete mode 100644 opendc-web/opendc-web-ui/src/style-globals/_variables.sass create mode 100644 opendc-web/opendc-web-ui/src/style-globals/_variables.scss (limited to 'opendc-web/opendc-web-ui/src') 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 }) => ( -
+
{TILE_SIZE_IN_METERS}m
) 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 = () => ( -
+
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/sidebars/Sidebar.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.js index f7368f54..64e95014 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,45 @@ 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' -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 = ( +
setCollapsed(!isCollapsed)} + > + {(isCollapsed && isRight) || (!isCollapsed && !isRight) ? ( + + ) : ( + + )} +
+ ) - state = { - collapsed: false, + if (isCollapsed) { + return button } + return ( +
e.stopPropagation()} + > + {children} + {collapsible && button} +
+ ) +} - render() { - const collapseButton = ( -
this.setState({ collapsed: !this.state.collapsed })} - > - {(this.state.collapsed && this.props.isRight) || (!this.state.collapsed && !this.props.isRight) ? ( - - ) : ( - - )} -
- ) - - if (this.state.collapsed) { - return collapseButton - } - return ( -
e.stopPropagation()} - > - {this.props.children} - {this.props.collapsible && collapseButton} -
- ) - } +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..d6be4d9b --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/Sidebar.module.scss @@ -0,0 +1,57 @@ +@import '../../../style-globals/_variables.scss'; +@import '../../../style-globals/_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/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 ( -
    +
      {machineIds.map((machineId, index) => { if (machineId === null) { return 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/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 ( -
      -
      +
      +
      -
      +
      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/home/ContactSection.js b/opendc-web/opendc-web-ui/src/components/home/ContactSection.js index d25a1bc4..25daaccf 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ContactSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ContactSection.js @@ -3,10 +3,10 @@ import FontAwesome from 'react-fontawesome' import { Row, Col } from 'reactstrap' import ContentSection from './ContentSection' -import './ContactSection.sass' +import { contactSection, tudelftIcon } from './ContactSection.module.scss' const ContactSection = () => ( - + @@ -25,7 +25,7 @@ const ContactSection = () => ( - TU Delft + TU Delft diff --git a/opendc-web/opendc-web-ui/src/components/home/ContactSection.module.scss b/opendc-web/opendc-web-ui/src/components/home/ContactSection.module.scss new file mode 100644 index 00000000..9ab4fcb1 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/home/ContactSection.module.scss @@ -0,0 +1,20 @@ +.contactSection { + background-color: #444; + color: #ddd; + + a { + color: #ddd; + + &:hover { + color: #fff; + } + } + + .tudelftIcon { + height: 100px; + } + + .disclaimer { + color: #cccccc; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/home/ContactSection.sass b/opendc-web/opendc-web-ui/src/components/home/ContactSection.sass deleted file mode 100644 index 997f8d98..00000000 --- a/opendc-web/opendc-web-ui/src/components/home/ContactSection.sass +++ /dev/null @@ -1,15 +0,0 @@ -.contact-section - background-color: #444 - color: #ddd - - a - color: #ddd - - a:hover - color: #fff - - .tudelft-icon - height: 100px - - .disclaimer - color: #cccccc diff --git a/opendc-web/opendc-web-ui/src/components/home/ContentSection.js b/opendc-web/opendc-web-ui/src/components/home/ContentSection.js index 3a8960d9..3e9ad50a 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ContentSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ContentSection.js @@ -2,10 +2,10 @@ import React from 'react' import classNames from 'classnames' import { Container } from 'reactstrap' import PropTypes from 'prop-types' -import './ContentSection.sass' +import { contentSection } from './ContentSection.module.scss' const ContentSection = ({ name, title, children, className }) => ( -
      +

      {title}

      {children} diff --git a/opendc-web/opendc-web-ui/src/components/home/ContentSection.module.scss b/opendc-web/opendc-web-ui/src/components/home/ContentSection.module.scss new file mode 100644 index 00000000..3d150c93 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/home/ContentSection.module.scss @@ -0,0 +1,11 @@ +@import '../../style-globals/_variables.scss'; + +.contentSection { + padding-top: 50px; + padding-bottom: 50px; + text-align: center; + + h1 { + margin-bottom: 30px; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/home/ContentSection.sass b/opendc-web/opendc-web-ui/src/components/home/ContentSection.sass deleted file mode 100644 index a4c8bd66..00000000 --- a/opendc-web/opendc-web-ui/src/components/home/ContentSection.sass +++ /dev/null @@ -1,9 +0,0 @@ -@import ../../style-globals/_variables.sass - -.content-section - padding-top: 50px - padding-bottom: 150px - text-align: center - - h1 - margin-bottom: 30px diff --git a/opendc-web/opendc-web-ui/src/components/home/IntroSection.js b/opendc-web/opendc-web-ui/src/components/home/IntroSection.js index bc6ee83b..7b467889 100644 --- a/opendc-web/opendc-web-ui/src/components/home/IntroSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/IntroSection.js @@ -1,8 +1,8 @@ import React from 'react' import { Container, Row, Col } from 'reactstrap' -const IntroSection = () => ( -
      +const IntroSection = ({ className }) => ( +
      diff --git a/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.js b/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.js index 6a9ea00c..0d3217f9 100644 --- a/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.js +++ b/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.js @@ -1,13 +1,13 @@ import React from 'react' import { Container, Jumbotron, Button } from 'reactstrap' -import './JumbotronHeader.sass' +import { jumbotronHeader, jumbotron, dc } from './JumbotronHeader.module.scss' const JumbotronHeader = () => ( -
      +
      - +

      - OpenDC + OpenDC

      Collaborative Datacenter Simulation and Exploration for Everybody

      OpenDC diff --git a/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.module.scss b/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.module.scss new file mode 100644 index 00000000..567b3e73 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.module.scss @@ -0,0 +1,31 @@ +.jumbotronHeader { + background: #00a6d6; +} + +.jumbotron { + background-color: inherit; + margin-bottom: 0; + text-align: center; + + padding-top: 120px; + padding-bottom: 120px; + + img { + max-width: 110px; + } + + h1 { + color: #fff; + font-size: 4.5em; + + .dc { + color: #fff; + font-weight: bold; + } + } + + :global(.lead) { + color: #fff; + font-size: 1.4em; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.sass b/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.sass deleted file mode 100644 index 1b6a89fd..00000000 --- a/opendc-web/opendc-web-ui/src/components/home/JumbotronHeader.sass +++ /dev/null @@ -1,24 +0,0 @@ -.jumbotron-header - background: #00A6D6 - -.jumbotron - background-color: inherit - margin-bottom: 0 - - padding-top: 120px - padding-bottom: 120px - - img - max-width: 110px - - h1 - color: #fff - font-size: 4.5em - - .dc - color: #fff - font-weight: bold - - .lead - color: #fff - font-size: 1.4em diff --git a/opendc-web/opendc-web-ui/src/components/home/ModelingSection.js b/opendc-web/opendc-web-ui/src/components/home/ModelingSection.js index 643dca65..af36aa45 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ModelingSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ModelingSection.js @@ -1,13 +1,14 @@ import React from 'react' import ScreenshotSection from './ScreenshotSection' -const ModelingSection = () => ( +const ModelingSection = ({ className }) => (

      Collaboratively...

        diff --git a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js index 33aab17f..4f634b28 100644 --- a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.js @@ -1,16 +1,16 @@ import React from 'react' import { Row, Col } from 'reactstrap' import ContentSection from './ContentSection' -import './ScreenshotSection.sass' +import { screenshot } from './ScreenshotSection.module.scss' -const ScreenshotSection = ({ name, title, imageUrl, caption, imageIsRight, children }) => ( - +const ScreenshotSection = ({ className, name, title, imageUrl, caption, imageIsRight, children }) => ( + {children} - {caption} + {caption}
        {caption}
        diff --git a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.module.scss b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.module.scss new file mode 100644 index 00000000..7e22de32 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.module.scss @@ -0,0 +1,5 @@ +.screenshot { + padding-left: 0; + padding-right: 0; + margin-bottom: 5px; +} diff --git a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.sass b/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.sass deleted file mode 100644 index 6b1a6ec4..00000000 --- a/opendc-web/opendc-web-ui/src/components/home/ScreenshotSection.sass +++ /dev/null @@ -1,4 +0,0 @@ -.screenshot - padding-left: 0 - padding-right: 0 - margin-bottom: 5px diff --git a/opendc-web/opendc-web-ui/src/components/home/SimulationSection.js b/opendc-web/opendc-web-ui/src/components/home/SimulationSection.js index 8e98717a..44ce905b 100644 --- a/opendc-web/opendc-web-ui/src/components/home/SimulationSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/SimulationSection.js @@ -2,9 +2,9 @@ import React from 'react' import { Col, Row } from 'reactstrap' import ContentSection from './ContentSection' -const SimulationSection = () => { +const SimulationSection = ({ className }) => { return ( - +

        Working with OpenDC:

        diff --git a/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js b/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js index 1624b4d2..9a4892ed 100644 --- a/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/StakeholderSection.js @@ -21,8 +21,8 @@ const Stakeholder = ({ name, title, subtitle }) => ( ) -const StakeholderSection = () => ( - +const StakeholderSection = ({ className }) => ( + diff --git a/opendc-web/opendc-web-ui/src/components/home/TeamSection.js b/opendc-web/opendc-web-ui/src/components/home/TeamSection.js index 1ee1cbf5..4e8a3906 100644 --- a/opendc-web/opendc-web-ui/src/components/home/TeamSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/TeamSection.js @@ -41,8 +41,8 @@ const TeamMember = ({ photoId, name }) => ( ) -const TeamSection = () => ( - +const TeamSection = ({ className }) => ( + diff --git a/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js b/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js index efd77edf..6fdf4e5c 100644 --- a/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js +++ b/opendc-web/opendc-web-ui/src/components/home/TechnologiesSection.js @@ -3,8 +3,8 @@ import FontAwesome from 'react-fontawesome' import { ListGroup, ListGroupItem } from 'reactstrap' import ContentSection from './ContentSection' -const TechnologiesSection = () => ( - +const TechnologiesSection = ({ className }) => ( + diff --git a/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js b/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js index c5de3d0b..8c28c542 100644 --- a/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js +++ b/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js @@ -3,7 +3,7 @@ import FontAwesome from 'react-fontawesome' import { Link } from 'react-router-dom' import { NavLink } from 'reactstrap' import Navbar, { NavItem } from './Navbar' -import './Navbar.sass' +import {} from './Navbar.module.scss' const AppNavbarComponent = ({ project, fullWidth }) => ( diff --git a/opendc-web/opendc-web-ui/src/components/navigation/HomeNavbar.js b/opendc-web/opendc-web-ui/src/components/navigation/HomeNavbar.js index 08d222ea..46d01a25 100644 --- a/opendc-web/opendc-web-ui/src/components/navigation/HomeNavbar.js +++ b/opendc-web/opendc-web-ui/src/components/navigation/HomeNavbar.js @@ -1,7 +1,7 @@ import React from 'react' import { NavItem, NavLink } from 'reactstrap' import Navbar from './Navbar' -import './Navbar.sass' +import {} from './Navbar.module.scss' const ScrollNavItem = ({ id, name }) => ( diff --git a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js index 55f98900..bf18f1c4 100644 --- a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js +++ b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js @@ -14,7 +14,7 @@ import { userIsLoggedIn } from '../../auth/index' import Login from '../../containers/auth/Login' import Logout from '../../containers/auth/Logout' import ProfileName from '../../containers/auth/ProfileName' -import './Navbar.sass' +import { login, navbar, opendcBrand } from './Navbar.module.scss' export const NAVBAR_HEIGHT = 60 @@ -59,7 +59,7 @@ export const LoggedInSection = () => { ) : ( - + )} @@ -71,10 +71,10 @@ const Navbar = ({ fullWidth, children }) => { const toggle = () => setIsOpen(!isOpen) return ( - + - + OpenDC diff --git a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.module.scss b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.module.scss new file mode 100644 index 00000000..2ea59a0f --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.module.scss @@ -0,0 +1,36 @@ +@import '../../style-globals/_mixins.scss'; +@import '../../style-globals/_variables.scss'; + +.navbar { + border-top: $blue 3px solid; + border-bottom: $gray-semi-dark 1px solid; + color: $gray-very-dark; + background: #fafafb; +} + +.opendcBrand { + display: inline-block; + color: $gray-very-dark; + + transition: background $transition-length; + + img { + position: relative; + bottom: 3px; + display: inline-block; + width: 30px; + } +} + +.login { + height: 40px; + background: $blue; + border: none; + padding-top: 10px; + + @include clickable; + + &:hover { + background: $blue-dark; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.sass b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.sass deleted file mode 100644 index c9d2aad2..00000000 --- a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.sass +++ /dev/null @@ -1,30 +0,0 @@ -@import ../../style-globals/_mixins.sass -@import ../../style-globals/_variables.sass - -.navbar - border-top: $blue 3px solid - border-bottom: $gray-semi-dark 1px solid - color: $gray-very-dark - background: #fafafb - -.opendc-brand - display: inline-block - color: $gray-very-dark - - +transition(background, $transition-length) - - img - position: relative - bottom: 3px - display: inline-block - width: 30px - -.login - height: 40px - background: $blue - border: none - padding-top: 10px - +clickable - - &:hover - background: $blue-dark diff --git a/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.js b/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.js index dbdba212..03a4894b 100644 --- a/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.js +++ b/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.js @@ -1,6 +1,6 @@ import React from 'react' -import './BlinkingCursor.sass' +import { blinkingCursor } from './BlinkingCursor.module.scss' -const BlinkingCursor = () => _ +const BlinkingCursor = () => _ export default BlinkingCursor diff --git a/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.module.scss b/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.module.scss new file mode 100644 index 00000000..aba0c604 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.module.scss @@ -0,0 +1,13 @@ +.blinkingCursor { + animation: blink 1s step-end infinite; +} + +@keyframes blink { + from, + to { + color: #eeeeee; + } + 50% { + color: #333333; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.sass b/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.sass deleted file mode 100644 index ad91df85..00000000 --- a/opendc-web/opendc-web-ui/src/components/not-found/BlinkingCursor.sass +++ /dev/null @@ -1,35 +0,0 @@ -.blinking-cursor - -webkit-animation: 1s blink step-end infinite - -moz-animation: 1s blink step-end infinite - -o-animation: 1s blink step-end infinite - animation: 1s blink step-end infinite - -@keyframes blink - from, to - color: #eeeeee - 50% - color: #333333 - -@-moz-keyframes blink - from, to - color: #eeeeee - 50% - color: #333333 - -@-webkit-keyframes blink - from, to - color: #eeeeee - 50% - color: #333333 - -@-ms-keyframes blink - from, to - color: #eeeeee - 50% - color: #333333 - -@-o-keyframes blink - from, to - color: #eeeeee - 50% - color: #333333 diff --git a/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.js b/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.js index bcc522c9..6ded4350 100644 --- a/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.js +++ b/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.js @@ -1,5 +1,5 @@ import React from 'react' -import './CodeBlock.sass' +import { codeBlock } from './CodeBlock.module.scss' const CodeBlock = () => { const textBlock = @@ -22,7 +22,7 @@ const CodeBlock = () => { } } - return
        + return
        } export default CodeBlock diff --git a/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.module.scss b/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.module.scss new file mode 100644 index 00000000..8af3ee6d --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.module.scss @@ -0,0 +1,4 @@ +.codeBlock { + white-space: pre-wrap; + margin-top: 60px; +} diff --git a/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.sass b/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.sass deleted file mode 100644 index e452f917..00000000 --- a/opendc-web/opendc-web-ui/src/components/not-found/CodeBlock.sass +++ /dev/null @@ -1,3 +0,0 @@ -.code-block - white-space: pre-wrap - margin-top: 60px diff --git a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js index a25e558a..b38fc183 100644 --- a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js +++ b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js @@ -2,13 +2,13 @@ import React from 'react' import { Link } from 'react-router-dom' import BlinkingCursor from './BlinkingCursor' import CodeBlock from './CodeBlock' -import './TerminalWindow.sass' +import { terminalWindow, terminalHeader, terminalBody, segfault, subTitle, homeBtn } from './TerminalWindow.module.scss' const TerminalWindow = () => ( -
        -
        Terminal -- bash
        -
        -
        +
        +
        Terminal -- bash
        +
        +
        $ status
        opendc[4264]: segfault at 0000051497be459d1 err 12 in libopendc.9.0.4 @@ -19,11 +19,11 @@ const TerminalWindow = () => (
        -
        +
        Got lost?
        - + GET ME BACK TO OPENDC
        diff --git a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.module.scss b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.module.scss new file mode 100644 index 00000000..614852d3 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.module.scss @@ -0,0 +1,61 @@ +.terminalWindow { + display: block; + align-self: center; + + margin: auto; + + user-select: none; + cursor: default; + + overflow: hidden; + + box-shadow: 5px 5px 20px #444444; +} + +.terminalHeader { + font-family: monospace; + background: #cccccc; + color: #444444; + height: 30px; + line-height: 30px; + padding-left: 10px; + + border-top-left-radius: 7px; + border-top-right-radius: 7px; +} + +.terminalBody { + font-family: monospace; + text-align: center; + background-color: #333333; + color: #eeeeee; + padding: 10px; + + height: 100%; +} + +.segfault { + text-align: left; +} + +.subTitle { + margin-top: 20px; +} + +.homeBtn { + margin-top: 10px; + padding: 5px; + display: inline-block; + border: 1px solid #eeeeee; + color: #eeeeee; + text-decoration: none; + cursor: pointer; + + transition: all 200ms; + + &:hover, + &:active { + background: #eeeeee; + color: #333333; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.sass b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.sass deleted file mode 100644 index 7f05335a..00000000 --- a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.sass +++ /dev/null @@ -1,70 +0,0 @@ -.terminal-window - width: 600px - height: 400px - display: block - - position: absolute - top: 0 - bottom: 0 - left: 0 - right: 0 - - margin: auto - - -webkit-user-select: none - -moz-user-select: none - -ms-user-select: none - user-select: none - cursor: default - - overflow: hidden - - box-shadow: 5px 5px 20px #444444 - -.terminal-header - font-family: monospace - background: #cccccc - color: #444444 - height: 30px - line-height: 30px - padding-left: 10px - - border-top-left-radius: 7px - border-top-right-radius: 7px - -.terminal-body - font-family: monospace - text-align: center - background-color: #333333 - color: #eeeeee - padding: 10px - - height: 100% - -.segfault - text-align: left - -.sub-title - margin-top: 20px - -.home-btn - margin-top: 10px - padding: 5px - display: inline-block - border: 1px solid #eeeeee - color: #eeeeee - text-decoration: none - cursor: pointer - - -webkit-transition: all 200ms - -moz-transition: all 200ms - -o-transition: all 200ms - transition: all 200ms - -.home-btn:hover - background: #eeeeee - color: #333333 - -.home-btn:active - background: #333333 - color: #eeeeee diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js index 2b9795d0..89b483fb 100644 --- a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js +++ b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js @@ -1,9 +1,9 @@ import React from 'react' import FilterLink from '../../containers/projects/FilterLink' -import './FilterPanel.sass' +import { filterPanel } from './FilterPanel.module.scss' const FilterPanel = () => ( -
        +
        All Projects My Projects Shared with me diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.scss b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.scss new file mode 100644 index 00000000..79cdf81a --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.scss @@ -0,0 +1,7 @@ +.filterPanel { + display: flex; + + button { + flex: 1 !important; + } +} diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.sass b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.sass deleted file mode 100644 index f71cf6c8..00000000 --- a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.sass +++ /dev/null @@ -1,5 +0,0 @@ -.filter-panel - display: flex - - button - flex: 1 !important diff --git a/opendc-web/opendc-web-ui/src/containers/auth/Login.js b/opendc-web/opendc-web-ui/src/containers/auth/Login.js index 54605775..f652429d 100644 --- a/opendc-web/opendc-web-ui/src/containers/auth/Login.js +++ b/opendc-web/opendc-web-ui/src/containers/auth/Login.js @@ -2,10 +2,10 @@ import React from 'react' import GoogleLogin from 'react-google-login' import { useDispatch } from 'react-redux' import { logIn } from '../../actions/auth' +import { Button } from 'reactstrap' import config from '../../config' -const Login = (props) => { - const { visible } = props +function Login({ visible, className }) { const dispatch = useDispatch() const onLogin = (payload) => dispatch(logIn(payload)) @@ -34,9 +34,9 @@ const Login = (props) => { onSuccess={onAuthResponse} onFailure={onAuthFailure} render={(renderProps) => ( - + )} /> ) diff --git a/opendc-web/opendc-web-ui/src/index.js b/opendc-web/opendc-web-ui/src/index.js index ae3a5ddc..d40d17a2 100644 --- a/opendc-web/opendc-web-ui/src/index.js +++ b/opendc-web/opendc-web-ui/src/index.js @@ -4,7 +4,7 @@ import * as Sentry from '@sentry/react' import { Integrations } from '@sentry/tracing' import { Provider } from 'react-redux' import { setupSocketConnection } from './api/socket' -import './index.sass' +import './index.scss' import Routes from './routes' import config from './config' import configureStore from './store/configure-store' diff --git a/opendc-web/opendc-web-ui/src/index.sass b/opendc-web/opendc-web-ui/src/index.sass deleted file mode 100644 index a78f7a19..00000000 --- a/opendc-web/opendc-web-ui/src/index.sass +++ /dev/null @@ -1,52 +0,0 @@ -@import "~bootstrap/scss/bootstrap" - -@import ./style-globals/_mixins.sass -@import ./style-globals/_variables.sass - -html, body, #root - margin: 0 - padding: 0 - width: 100% - height: 100% - - font-family: Roboto, Helvetica, Verdana, sans-serif - background: #eee - - // Scroll padding for top navbar - scroll-padding-top: 60px - -.full-height - position: relative - height: 100% !important - -.page-container - padding-top: 60px - -.text-page-container - padding-top: 80px - display: flex - flex-flow: column - -.vertically-expanding-container - flex: 1 1 auto - overflow-y: auto - -.bottom-btn-container - flex: 0 1 auto - padding: 20px 0 - -.btn, .list-group-item-action, .clickable - +clickable - -.btn-circle - +border-radius(50%) - -a, a:hover - text-decoration: none - -.app-page-container - padding-left: $side-bar-width - padding-top: 15px - -.w-70 - width: 70% !important diff --git a/opendc-web/opendc-web-ui/src/index.scss b/opendc-web/opendc-web-ui/src/index.scss new file mode 100644 index 00000000..0c1ddff4 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/index.scss @@ -0,0 +1,68 @@ +@import '~bootstrap/scss/bootstrap'; + +@import './style-globals/_mixins.scss'; +@import './style-globals/_variables.scss'; + +html, +body, +#root { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + + font-family: Roboto, Helvetica, Verdana, sans-serif; + background: #eee; + + // Scroll padding for top navbar + scroll-padding-top: 60px; +} + +.full-height { + position: relative; + height: 100% !important; +} + +.page-container { + padding-top: 60px; +} + +.text-page-container { + padding-top: 80px; + display: flex; + flex-flow: column; +} + +.vertically-expanding-container { + flex: 1 1 auto; + overflow-y: auto; +} + +.bottom-btn-container { + flex: 0 1 auto; + padding: 20px 0; +} + +.btn, +.list-group-item-action, +.clickable { + @include clickable; +} + +.btn-circle { + border-radius: 50%; +} + +a, +a:hover { + text-decoration: none; +} + +.app-page-container { + padding-left: $side-bar-width; + padding-top: 15px; +} + +.w-70 { + width: 70% !important; +} diff --git a/opendc-web/opendc-web-ui/src/pages/Home.js b/opendc-web/opendc-web-ui/src/pages/Home.js index fb383426..ee930fbe 100644 --- a/opendc-web/opendc-web-ui/src/pages/Home.js +++ b/opendc-web/opendc-web-ui/src/pages/Home.js @@ -8,7 +8,14 @@ import StakeholderSection from '../components/home/StakeholderSection' import TeamSection from '../components/home/TeamSection' import TechnologiesSection from '../components/home/TechnologiesSection' import HomeNavbar from '../components/navigation/HomeNavbar' -import './Home.sass' +import { + introSection, + stakeholderSection, + modelingSection, + simulationSection, + technologiesSection, + teamSection, +} from './Home.module.scss' import { useDocumentTitle } from '../util/hooks' function Home() { @@ -18,12 +25,12 @@ function Home() {
        - - - - - - + + + + + +
        diff --git a/opendc-web/opendc-web-ui/src/pages/Home.module.scss b/opendc-web/opendc-web-ui/src/pages/Home.module.scss new file mode 100644 index 00000000..aed1d88f --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/Home.module.scss @@ -0,0 +1,16 @@ +.bodyWrapper { + position: relative; + overflow-y: hidden; +} + +.introSection, +.modelingSection, +.technologiesSection { + background-color: #fff; +} + +.stakeholderSection, +.simulationSection, +.teamSection { + background-color: #f2f2f2; +} diff --git a/opendc-web/opendc-web-ui/src/pages/Home.sass b/opendc-web/opendc-web-ui/src/pages/Home.sass deleted file mode 100644 index 79cb9698..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Home.sass +++ /dev/null @@ -1,9 +0,0 @@ -.body-wrapper - position: relative - overflow-y: hidden - -.intro-section, .modeling-section, .technologies-section - background-color: #fff - -.stakeholder-section, .simulation-section, .team-section - background-color: #f2f2f2 diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.js b/opendc-web/opendc-web-ui/src/pages/NotFound.js index b933ffa5..409ffa0e 100644 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.js +++ b/opendc-web/opendc-web-ui/src/pages/NotFound.js @@ -1,12 +1,12 @@ import React from 'react' import TerminalWindow from '../components/not-found/TerminalWindow' -import './NotFound.sass' +import style from './NotFound.module.scss' import { useDocumentTitle } from '../util/hooks' const NotFound = () => { useDocumentTitle('Page Not Found - OpenDC') return ( -
        +
        ) diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.module.scss b/opendc-web/opendc-web-ui/src/pages/NotFound.module.scss new file mode 100644 index 00000000..e91c2780 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/NotFound.module.scss @@ -0,0 +1,8 @@ +.not-found-backdrop { + display: flex; + + width: 100%; + height: 100%; + + background-image: linear-gradient(135deg, #00678a, #008fbf, #00a6d6); +} diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.sass b/opendc-web/opendc-web-ui/src/pages/NotFound.sass deleted file mode 100644 index 59231f7a..00000000 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.sass +++ /dev/null @@ -1,11 +0,0 @@ -.not-found-backdrop - position: absolute - left: 0 - top: 0 - - margin: 0 - padding: 0 - width: 100% - height: 100% - - background-image: linear-gradient(135deg, #00678a, #008fbf, #00A6D6) diff --git a/opendc-web/opendc-web-ui/src/style-globals/_mixins.sass b/opendc-web/opendc-web-ui/src/style-globals/_mixins.sass deleted file mode 100644 index d0a8d1ac..00000000 --- a/opendc-web/opendc-web-ui/src/style-globals/_mixins.sass +++ /dev/null @@ -1,21 +0,0 @@ -=transition($property, $time) - -webkit-transition: $property $time - -moz-transition: $property $time - -o-transition: $property $time - transition: $property $time - -=user-select - -webkit-user-select: none - -moz-user-select: none - -ms-user-select: none - user-select: none - -=border-radius($length) - -webkit-border-radius: $length - -moz-border-radius: $length - border-radius: $length - -/* General Button Abstractions */ -=clickable - cursor: pointer - +user-select diff --git a/opendc-web/opendc-web-ui/src/style-globals/_mixins.scss b/opendc-web/opendc-web-ui/src/style-globals/_mixins.scss new file mode 100644 index 00000000..5f103cd7 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/style-globals/_mixins.scss @@ -0,0 +1,5 @@ +/* General Button Abstractions */ +@mixin clickable { + cursor: pointer; + user-select: none; +} diff --git a/opendc-web/opendc-web-ui/src/style-globals/_variables.sass b/opendc-web/opendc-web-ui/src/style-globals/_variables.sass deleted file mode 100644 index 7553caa0..00000000 --- a/opendc-web/opendc-web-ui/src/style-globals/_variables.sass +++ /dev/null @@ -1,31 +0,0 @@ -// Sizes and Margins -$document-padding: 20px -$inter-element-margin: 5px -$standard-border-radius: 5px -$side-menu-width: 350px -$color-indicator-width: 140px - -$global-padding: 30px -$side-bar-width: 350px -$navbar-height: 50px -$navbar-padding: 10px - -// Durations -$transition-length: 150ms - -// Colors -$gray-very-dark: #5c5c5c -$gray-dark: #aaa -$gray-semi-dark: #bbb -$gray-semi-light: #ccc -$gray-light: #ddd -$gray-very-light: #eee -$blue: #00A6D6 -$blue-dark: #0087b5 -$blue-very-dark: #006182 -$blue-light: #deebf7 - -// Media queries -$screen-sm: 768px -$screen-md: 992px -$screen-lg: 1200px diff --git a/opendc-web/opendc-web-ui/src/style-globals/_variables.scss b/opendc-web/opendc-web-ui/src/style-globals/_variables.scss new file mode 100644 index 00000000..e3df6cbd --- /dev/null +++ b/opendc-web/opendc-web-ui/src/style-globals/_variables.scss @@ -0,0 +1,31 @@ +// Sizes and Margins +$document-padding: 20px; +$inter-element-margin: 5px; +$standard-border-radius: 5px; +$side-menu-width: 350px; +$color-indicator-width: 140px; + +$global-padding: 30px; +$side-bar-width: 350px; +$navbar-height: 50px; +$navbar-padding: 10px; + +// Durations +$transition-length: 150ms; + +// Colors +$gray-very-dark: #5c5c5c; +$gray-dark: #aaa; +$gray-semi-dark: #bbb; +$gray-semi-light: #ccc; +$gray-light: #ddd; +$gray-very-light: #eee; +$blue: #00a6d6; +$blue-dark: #0087b5; +$blue-very-dark: #006182; +$blue-light: #deebf7; + +// Media queries +$screen-sm: 768px; +$screen-md: 992px; +$screen-lg: 1200px; -- cgit v1.2.3 From 2dbb06f433964ccac13fd64ef512ed03142ed97b Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Tue, 11 May 2021 16:34:25 +0200 Subject: ui: Move communication to REST API This change removes the socket.io websocket connection/client in favour of the OpenDC REST API. The socket.io websocket implementation was intended to be used for interactive and collaborative datacenter design and exploration. However, we do not support this functionality at the moment (collaborative design and exploration) and having the entire API run over this websocket connection is fragile and not standard practice. To improve maintainability, we therefore remove the websocket implementation in favour of the OpenDC REST API implementation using the fetch API. If we want to implement collaboration in the future, we will develop appropriate extensions in conjuction with the existing REST API. For this, we should look for standard and existing implementation of this functionality. --- opendc-web/opendc-web-ui/src/api/index.js | 31 +++++++++----- .../opendc-web-ui/src/api/routes/portfolios.js | 35 +++------------ opendc-web/opendc-web-ui/src/api/routes/prefabs.js | 33 +++----------- .../opendc-web-ui/src/api/routes/projects.js | 33 +++----------- .../opendc-web-ui/src/api/routes/scenarios.js | 35 +++------------ .../opendc-web-ui/src/api/routes/schedulers.js | 4 +- .../opendc-web-ui/src/api/routes/topologies.js | 35 +++------------ opendc-web/opendc-web-ui/src/api/routes/traces.js | 4 +- opendc-web/opendc-web-ui/src/api/routes/users.js | 41 +++--------------- opendc-web/opendc-web-ui/src/api/routes/util.js | 37 ---------------- opendc-web/opendc-web-ui/src/api/socket.js | 50 ---------------------- opendc-web/opendc-web-ui/src/index.js | 37 ++++++++-------- 12 files changed, 71 insertions(+), 304 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/api/routes/util.js delete mode 100644 opendc-web/opendc-web-ui/src/api/socket.js (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/api/index.js b/opendc-web/opendc-web-ui/src/api/index.js index cefcb2c5..e6528fd9 100644 --- a/opendc-web/opendc-web-ui/src/api/index.js +++ b/opendc-web/opendc-web-ui/src/api/index.js @@ -1,13 +1,22 @@ -import { sendSocketRequest } from './socket' - -export function sendRequest(request) { - return new Promise((resolve, reject) => { - sendSocketRequest(request, (response) => { - if (response.status.code === 200) { - resolve(response.content) - } else { - reject(response) - } - }) +import config from '../config' +import { getAuthToken } from '../auth' + +const apiUrl = config['API_BASE_URL'] + +export async function request(path, method = 'GET', body) { + const res = await fetch(`${apiUrl}/v2/${path}`, { + method: method, + headers: { + 'auth-token': getAuthToken(), + 'Content-Type': 'application/json', + }, + body: body && JSON.stringify(body), }) + const { status, content } = await res.json() + + if (status.code !== 200) { + throw status + } + + return content } diff --git a/opendc-web/opendc-web-ui/src/api/routes/portfolios.js b/opendc-web/opendc-web-ui/src/api/routes/portfolios.js index 7c9ea02a..ba15e828 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/portfolios.js +++ b/opendc-web/opendc-web-ui/src/api/routes/portfolios.js @@ -1,42 +1,17 @@ -import { deleteById, getById } from './util' -import { sendRequest } from '../index' +import { request } from '../index' export function addPortfolio(projectId, portfolio) { - return sendRequest({ - path: '/projects/{projectId}/portfolios', - method: 'POST', - parameters: { - body: { - portfolio, - }, - path: { - projectId, - }, - query: {}, - }, - }) + return request(`projects/${projectId}/portfolios`, 'POST', { portfolio }) } export function getPortfolio(portfolioId) { - return getById('/portfolios/{portfolioId}', { portfolioId }) + return request(`portfolios/${portfolioId}`) } export function updatePortfolio(portfolioId, portfolio) { - return sendRequest({ - path: '/portfolios/{projectId}', - method: 'POST', - parameters: { - body: { - portfolio, - }, - path: { - portfolioId, - }, - query: {}, - }, - }) + return request(`portfolios/${portfolioId}`, 'PUT', { portfolio }) } export function deletePortfolio(portfolioId) { - return deleteById('/portfolios/{portfolioId}', { portfolioId }) + return request(`portfolios/${portfolioId}`, 'DELETE') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/prefabs.js b/opendc-web/opendc-web-ui/src/api/routes/prefabs.js index 8a1debfa..032e12bc 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/prefabs.js +++ b/opendc-web/opendc-web-ui/src/api/routes/prefabs.js @@ -1,40 +1,17 @@ -import { sendRequest } from '../index' -import { deleteById, getById } from './util' +import { request } from '../index' export function getPrefab(prefabId) { - return getById('/prefabs/{prefabId}', { prefabId }) + return request(`prefabs/${prefabId}`) } export function addPrefab(prefab) { - return sendRequest({ - path: '/prefabs', - method: 'POST', - parameters: { - body: { - prefab, - }, - path: {}, - query: {}, - }, - }) + return request('prefabs', 'POST', { prefab }) } export function updatePrefab(prefab) { - return sendRequest({ - path: '/prefabs/{prefabId}', - method: 'PUT', - parameters: { - body: { - prefab, - }, - path: { - prefabId: prefab._id, - }, - query: {}, - }, - }) + return request(`prefabs/${prefab._id}`, 'PUT', { prefab }) } export function deletePrefab(prefabId) { - return deleteById('/prefabs/{prefabId}', { prefabId }) + return request(`prefabs/${prefabId}`, 'DELETE') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/projects.js b/opendc-web/opendc-web-ui/src/api/routes/projects.js index 4109079c..cd46036f 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/projects.js +++ b/opendc-web/opendc-web-ui/src/api/routes/projects.js @@ -1,40 +1,17 @@ -import { sendRequest } from '../index' -import { deleteById, getById } from './util' +import { request } from '../index' export function getProject(projectId) { - return getById('/projects/{projectId}', { projectId }) + return request(`projects/${projectId}`) } export function addProject(project) { - return sendRequest({ - path: '/projects', - method: 'POST', - parameters: { - body: { - project, - }, - path: {}, - query: {}, - }, - }) + return request('projects', 'POST', { project }) } export function updateProject(project) { - return sendRequest({ - path: '/projects/{projectId}', - method: 'PUT', - parameters: { - body: { - project, - }, - path: { - projectId: project._id, - }, - query: {}, - }, - }) + return request(`projects/${project._id}`, 'PUT', { project }) } export function deleteProject(projectId) { - return deleteById('/projects/{projectId}', { projectId }) + return request(`projects/${projectId}`, 'DELETE') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/scenarios.js b/opendc-web/opendc-web-ui/src/api/routes/scenarios.js index ab2e8b86..00cc1eb0 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/scenarios.js +++ b/opendc-web/opendc-web-ui/src/api/routes/scenarios.js @@ -1,42 +1,17 @@ -import { deleteById, getById } from './util' -import { sendRequest } from '../index' +import { request } from '../index' export function addScenario(portfolioId, scenario) { - return sendRequest({ - path: '/portfolios/{portfolioId}/scenarios', - method: 'POST', - parameters: { - body: { - scenario, - }, - path: { - portfolioId, - }, - query: {}, - }, - }) + return request(`portfolios/${portfolioId}/scenarios`, 'POST', { scenario }) } export function getScenario(scenarioId) { - return getById('/scenarios/{scenarioId}', { scenarioId }) + return request(`scenarios/${scenarioId}`) } export function updateScenario(scenarioId, scenario) { - return sendRequest({ - path: '/scenarios/{projectId}', - method: 'POST', - parameters: { - body: { - scenario, - }, - path: { - scenarioId, - }, - query: {}, - }, - }) + return request(`scenarios/${scenarioId}`, 'PUT', { scenario }) } export function deleteScenario(scenarioId) { - return deleteById('/scenarios/{scenarioId}', { scenarioId }) + return request(`scenarios/${scenarioId}`, 'DELETE') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/schedulers.js b/opendc-web/opendc-web-ui/src/api/routes/schedulers.js index 4481fb2a..5e129d33 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/schedulers.js +++ b/opendc-web/opendc-web-ui/src/api/routes/schedulers.js @@ -1,5 +1,5 @@ -import { getAll } from './util' +import { request } from '../index' export function getAllSchedulers() { - return getAll('/schedulers') + return request('schedulers') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/topologies.js b/opendc-web/opendc-web-ui/src/api/routes/topologies.js index a8f0d6b1..076895ff 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/topologies.js +++ b/opendc-web/opendc-web-ui/src/api/routes/topologies.js @@ -1,42 +1,17 @@ -import { deleteById, getById } from './util' -import { sendRequest } from '../index' +import { request } from '../index' export function addTopology(topology) { - return sendRequest({ - path: '/projects/{projectId}/topologies', - method: 'POST', - parameters: { - body: { - topology, - }, - path: { - projectId: topology.projectId, - }, - query: {}, - }, - }) + return request(`projects/${topology.projectId}/topologies`, 'POST', { topology }) } export function getTopology(topologyId) { - return getById('/topologies/{topologyId}', { topologyId }) + return request(`topologies/${topologyId}`) } export function updateTopology(topology) { - return sendRequest({ - path: '/topologies/{topologyId}', - method: 'PUT', - parameters: { - body: { - topology, - }, - path: { - topologyId: topology._id, - }, - query: {}, - }, - }) + return request(`topologies/${topology._id}`, 'PUT', { topology }) } export function deleteTopology(topologyId) { - return deleteById('/topologies/{topologyId}', { topologyId }) + return request(`topologies/${topologyId}`, 'DELETE') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/traces.js b/opendc-web/opendc-web-ui/src/api/routes/traces.js index 67895a87..eb2526ee 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/traces.js +++ b/opendc-web/opendc-web-ui/src/api/routes/traces.js @@ -1,5 +1,5 @@ -import { getAll } from './util' +import { request } from '../index' export function getAllTraces() { - return getAll('/traces') + return request('traces') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/users.js b/opendc-web/opendc-web-ui/src/api/routes/users.js index 3028f3f7..619aec1f 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/users.js +++ b/opendc-web/opendc-web-ui/src/api/routes/users.js @@ -1,48 +1,17 @@ -import { sendRequest } from '../index' -import { deleteById } from './util' +import { request } from '../index' export function getUserByEmail(email) { - return sendRequest({ - path: '/users', - method: 'GET', - parameters: { - body: {}, - path: {}, - query: { - email, - }, - }, - }) + return request(`users` + new URLSearchParams({ email })) } export function addUser(user) { - return sendRequest({ - path: '/users', - method: 'POST', - parameters: { - body: { - user, - }, - path: {}, - query: {}, - }, - }) + return request('users', 'POST', { user }) } export function getUser(userId) { - return sendRequest({ - path: '/users/{userId}', - method: 'GET', - parameters: { - body: {}, - path: { - userId, - }, - query: {}, - }, - }) + return request(`users/${userId}`) } export function deleteUser(userId) { - return deleteById('/users/{userId}', { userId }) + return request(`users/${userId}`, 'DELETE') } diff --git a/opendc-web/opendc-web-ui/src/api/routes/util.js b/opendc-web/opendc-web-ui/src/api/routes/util.js deleted file mode 100644 index 67e7173b..00000000 --- a/opendc-web/opendc-web-ui/src/api/routes/util.js +++ /dev/null @@ -1,37 +0,0 @@ -import { sendRequest } from '../index' - -export function getAll(path) { - return sendRequest({ - path, - method: 'GET', - parameters: { - body: {}, - path: {}, - query: {}, - }, - }) -} - -export function getById(path, pathObject) { - return sendRequest({ - path, - method: 'GET', - parameters: { - body: {}, - path: pathObject, - query: {}, - }, - }) -} - -export function deleteById(path, pathObject) { - return sendRequest({ - path, - method: 'DELETE', - parameters: { - body: {}, - path: pathObject, - query: {}, - }, - }) -} diff --git a/opendc-web/opendc-web-ui/src/api/socket.js b/opendc-web/opendc-web-ui/src/api/socket.js deleted file mode 100644 index 87facda8..00000000 --- a/opendc-web/opendc-web-ui/src/api/socket.js +++ /dev/null @@ -1,50 +0,0 @@ -import io from 'socket.io-client' -import { getAuthToken } from '../auth/index' -import config from '../config' - -let socket -let requestIdCounter = 0 -const callbacks = {} - -export function setupSocketConnection(onConnect) { - const apiUrl = - config['API_BASE_URL'] || `${window.location.protocol}//${window.location.hostname}:${window.location.port}` - - socket = io.connect(apiUrl) - socket.on('connect', onConnect) - socket.on('response', onSocketResponse) -} - -export function sendSocketRequest(request, callback) { - if (!socket.connected) { - console.error('Attempted to send request over unconnected socket') - return - } - - const newId = requestIdCounter++ - callbacks[newId] = callback - - request.id = newId - request.token = getAuthToken() - - if (!request.isRootRoute) { - request.path = '/v2' + request.path - } - - socket.emit('request', request) - - if (process.env.NODE_ENV !== 'production') { - console.log('Sent socket request:', request) - } -} - -function onSocketResponse(json) { - const response = JSON.parse(json) - - if (process.env.NODE_ENV !== 'production') { - console.log('Received socket response:', response) - } - - callbacks[response.id](response) - delete callbacks[response.id] -} diff --git a/opendc-web/opendc-web-ui/src/index.js b/opendc-web/opendc-web-ui/src/index.js index d40d17a2..fdfec24b 100644 --- a/opendc-web/opendc-web-ui/src/index.js +++ b/opendc-web/opendc-web-ui/src/index.js @@ -3,30 +3,27 @@ import ReactDOM from 'react-dom' import * as Sentry from '@sentry/react' import { Integrations } from '@sentry/tracing' import { Provider } from 'react-redux' -import { setupSocketConnection } from './api/socket' import './index.scss' import Routes from './routes' import config from './config' import configureStore from './store/configure-store' -setupSocketConnection(() => { - const store = configureStore() +const store = configureStore() - // Initialize Sentry if the user has configured a DSN - const dsn = config['SENTRY_DSN'] - if (dsn) { - Sentry.init({ - environment: process.env.NODE_ENV, - dsn: dsn, - integrations: [new Integrations.BrowserTracing()], - tracesSampleRate: 0.1, - }) - } +// Initialize Sentry if the user has configured a DSN +const dsn = config['SENTRY_DSN'] +if (dsn) { + Sentry.init({ + environment: process.env.NODE_ENV, + dsn: dsn, + integrations: [new Integrations.BrowserTracing()], + tracesSampleRate: 0.1, + }) +} - ReactDOM.render( - - - , - document.getElementById('root') - ) -}) +ReactDOM.render( + + + , + document.getElementById('root') +) -- cgit v1.2.3 From d21606bd238702645690586df5ad5b5075ca09c9 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Tue, 11 May 2021 16:45:23 +0200 Subject: ui: Ensure Redux logger is last in middleware chain This change updates the Redux store initialization to ensure that the Redux logger is last in the middleware change. If we do not do this, Redux Logger might log thunds and promises, but not actual actions. See https://github.com/LogRocket/redux-logger/issues/20 --- opendc-web/opendc-web-ui/src/store/configure-store.js | 14 +++----------- .../src/store/middlewares/dummy-middleware.js | 3 --- 2 files changed, 3 insertions(+), 14 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/store/configure-store.js b/opendc-web/opendc-web-ui/src/store/configure-store.js index d8f343ed..13bcd69e 100644 --- a/opendc-web/opendc-web-ui/src/store/configure-store.js +++ b/opendc-web/opendc-web-ui/src/store/configure-store.js @@ -6,24 +6,16 @@ import thunk from 'redux-thunk' import { authRedirectMiddleware } from '../auth/index' import rootReducer from '../reducers/index' import rootSaga from '../sagas/index' -import { dummyMiddleware } from './middlewares/dummy-middleware' import { viewportAdjustmentMiddleware } from './middlewares/viewport-adjustment' const sagaMiddleware = createSagaMiddleware() -let logger +const middlewares = [thunk, sagaMiddleware, authRedirectMiddleware, viewportAdjustmentMiddleware] + if (process.env.NODE_ENV !== 'production') { - logger = createLogger() + middlewares.push(createLogger()) } -const middlewares = [ - process.env.NODE_ENV === 'production' ? dummyMiddleware : logger, - thunk, - sagaMiddleware, - authRedirectMiddleware, - viewportAdjustmentMiddleware, -] - export let store = undefined export default function configureStore() { diff --git a/opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js b/opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js deleted file mode 100644 index 5ba35691..00000000 --- a/opendc-web/opendc-web-ui/src/store/middlewares/dummy-middleware.js +++ /dev/null @@ -1,3 +0,0 @@ -export const dummyMiddleware = (store) => (next) => (action) => { - next(action) -} -- cgit v1.2.3 From 4397a959e806bf476be4c81bc804616adf58b969 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 12 May 2021 22:42:12 +0200 Subject: ui: Migrate from CRA to Next.js This change updates the web frontend to use Next.js instead of Create React App (CRA). Next.js enables the possibility of rendering pages on the server side (which reduces the time to first frame) and overall provides a better development experience. Future commits will try to futher optimize the implementation for Next.js. --- opendc-web/opendc-web-ui/src/actions/map.js | 1 + .../opendc-web-ui/src/actions/modals/profile.js | 14 --- opendc-web/opendc-web-ui/src/api/index.js | 31 ++++- .../opendc-web-ui/src/api/routes/token-signin.js | 4 +- opendc-web/opendc-web-ui/src/auth/hook.js | 44 +++++++ opendc-web/opendc-web-ui/src/auth/index.js | 2 +- .../src/components/app/map/MapStageComponent.js | 118 +++++++++--------- .../app/sidebars/project/PortfolioListComponent.js | 13 +- .../app/sidebars/project/ScenarioListComponent.js | 13 +- .../src/components/modals/ConfirmationModal.js | 48 +++----- .../components/navigation/AppNavbarComponent.js | 20 ++-- .../src/components/navigation/LogoutButton.js | 3 +- .../src/components/navigation/Navbar.js | 47 +++++--- .../src/components/not-found/TerminalWindow.js | 8 +- .../components/projects/ProjectActionButtons.js | 8 +- opendc-web/opendc-web-ui/src/config.js | 40 ------- opendc-web/opendc-web-ui/src/containers/app/App.js | 132 +++++++++++++++++++++ .../src/containers/app/map/MapStage.js | 4 +- .../app/sidebars/project/PortfolioListContainer.js | 6 +- .../sidebars/project/ProjectSidebarContainer.js | 6 +- .../app/sidebars/project/TopologyListContainer.js | 8 +- .../opendc-web-ui/src/containers/auth/Login.js | 5 +- .../src/containers/modals/DeleteProfileModal.js | 27 ----- .../src/containers/modals/NewScenarioModal.js | 2 - opendc-web/opendc-web-ui/src/index.js | 29 ----- opendc-web/opendc-web-ui/src/index.scss | 2 +- opendc-web/opendc-web-ui/src/pages/404.js | 19 +++ opendc-web/opendc-web-ui/src/pages/404.module.scss | 8 ++ opendc-web/opendc-web-ui/src/pages/App.js | 103 ---------------- opendc-web/opendc-web-ui/src/pages/Home.js | 40 ------- .../opendc-web-ui/src/pages/Home.module.scss | 16 --- opendc-web/opendc-web-ui/src/pages/NotFound.js | 15 --- .../opendc-web-ui/src/pages/NotFound.module.scss | 8 -- opendc-web/opendc-web-ui/src/pages/Profile.js | 31 ----- opendc-web/opendc-web-ui/src/pages/Projects.js | 30 ----- opendc-web/opendc-web-ui/src/pages/_app.js | 42 +++++++ opendc-web/opendc-web-ui/src/pages/_document.js | 96 +++++++++++++++ opendc-web/opendc-web-ui/src/pages/index.js | 42 +++++++ .../opendc-web-ui/src/pages/index.module.scss | 16 +++ opendc-web/opendc-web-ui/src/pages/profile.js | 54 +++++++++ .../src/pages/projects/[project]/index.js | 37 ++++++ .../projects/[project]/portfolios/[portfolio].js | 37 ++++++ .../opendc-web-ui/src/pages/projects/index.js | 36 ++++++ opendc-web/opendc-web-ui/src/reducers/modals.js | 2 - opendc-web/opendc-web-ui/src/routes/index.js | 40 ------- .../opendc-web-ui/src/store/configure-store.js | 51 ++++++-- opendc-web/opendc-web-ui/src/util/hooks.js | 29 ----- opendc-web/opendc-web-ui/src/util/sidebar-space.js | 4 +- 48 files changed, 797 insertions(+), 594 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/actions/modals/profile.js create mode 100644 opendc-web/opendc-web-ui/src/auth/hook.js delete mode 100644 opendc-web/opendc-web-ui/src/config.js create mode 100644 opendc-web/opendc-web-ui/src/containers/app/App.js delete mode 100644 opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js delete mode 100644 opendc-web/opendc-web-ui/src/index.js create mode 100644 opendc-web/opendc-web-ui/src/pages/404.js create mode 100644 opendc-web/opendc-web-ui/src/pages/404.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/pages/App.js delete mode 100644 opendc-web/opendc-web-ui/src/pages/Home.js delete mode 100644 opendc-web/opendc-web-ui/src/pages/Home.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/pages/NotFound.js delete mode 100644 opendc-web/opendc-web-ui/src/pages/NotFound.module.scss delete mode 100644 opendc-web/opendc-web-ui/src/pages/Profile.js delete mode 100644 opendc-web/opendc-web-ui/src/pages/Projects.js create mode 100644 opendc-web/opendc-web-ui/src/pages/_app.js create mode 100644 opendc-web/opendc-web-ui/src/pages/_document.js create mode 100644 opendc-web/opendc-web-ui/src/pages/index.js create mode 100644 opendc-web/opendc-web-ui/src/pages/index.module.scss create mode 100644 opendc-web/opendc-web-ui/src/pages/profile.js create mode 100644 opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js create mode 100644 opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js create mode 100644 opendc-web/opendc-web-ui/src/pages/projects/index.js delete mode 100644 opendc-web/opendc-web-ui/src/routes/index.js delete mode 100644 opendc-web/opendc-web-ui/src/util/hooks.js (limited to 'opendc-web/opendc-web-ui/src') diff --git a/opendc-web/opendc-web-ui/src/actions/map.js b/opendc-web/opendc-web-ui/src/actions/map.js index 0d49d849..09196dca 100644 --- a/opendc-web/opendc-web-ui/src/actions/map.js +++ b/opendc-web/opendc-web-ui/src/actions/map.js @@ -64,6 +64,7 @@ export function setMapPositionWithBoundsCheck(x, y) { const state = getState() const scaledMapSize = MAP_SIZE_IN_PIXELS * state.map.scale + const updatedX = x > 0 ? 0 diff --git a/opendc-web/opendc-web-ui/src/actions/modals/profile.js b/opendc-web/opendc-web-ui/src/actions/modals/profile.js deleted file mode 100644 index 39c72c03..00000000 --- a/opendc-web/opendc-web-ui/src/actions/modals/profile.js +++ /dev/null @@ -1,14 +0,0 @@ -export const OPEN_DELETE_PROFILE_MODAL = 'OPEN_DELETE_PROFILE_MODAL' -export const CLOSE_DELETE_PROFILE_MODAL = 'CLOSE_DELETE_PROFILE_MODAL' - -export function openDeleteProfileModal() { - return { - type: OPEN_DELETE_PROFILE_MODAL, - } -} - -export function closeDeleteProfileModal() { - return { - type: CLOSE_DELETE_PROFILE_MODAL, - } -} diff --git a/opendc-web/opendc-web-ui/src/api/index.js b/opendc-web/opendc-web-ui/src/api/index.js index e6528fd9..65358745 100644 --- a/opendc-web/opendc-web-ui/src/api/index.js +++ b/opendc-web/opendc-web-ui/src/api/index.js @@ -1,8 +1,35 @@ -import config from '../config' +/* + * 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 { getAuthToken } from '../auth' -const apiUrl = config['API_BASE_URL'] +const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL +/** + * Send the specified request to the OpenDC API. + * @param path Relative path for the API. + * @param method The method to use for the request. + * @param body The body of the request. + */ export async function request(path, method = 'GET', body) { const res = await fetch(`${apiUrl}/v2/${path}`, { method: method, diff --git a/opendc-web/opendc-web-ui/src/api/routes/token-signin.js b/opendc-web/opendc-web-ui/src/api/routes/token-signin.js index ced5d2e0..1c285bdb 100644 --- a/opendc-web/opendc-web-ui/src/api/routes/token-signin.js +++ b/opendc-web/opendc-web-ui/src/api/routes/token-signin.js @@ -1,7 +1,5 @@ -import config from '../../config' - export function performTokenSignIn(token) { - const apiUrl = config['API_BASE_URL'] + const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL return fetch(`${apiUrl}/tokensignin`, { method: 'POST', diff --git a/opendc-web/opendc-web-ui/src/auth/hook.js b/opendc-web/opendc-web-ui/src/auth/hook.js new file mode 100644 index 00000000..ddaf53ed --- /dev/null +++ b/opendc-web/opendc-web-ui/src/auth/hook.js @@ -0,0 +1,44 @@ +/* + * 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 { useEffect, useState } from 'react' +import { userIsLoggedIn } from './index' +import { useRouter } from 'next/router' + +export function useAuth() { + const [isLoggedIn, setLoggedIn] = useState(false) + + useEffect(() => { + setLoggedIn(userIsLoggedIn()) + }, []) + + return isLoggedIn +} + +export function useRequireAuth() { + const router = useRouter() + useEffect(() => { + if (!userIsLoggedIn()) { + router.replace('/') + } + }) +} diff --git a/opendc-web/opendc-web-ui/src/auth/index.js b/opendc-web/opendc-web-ui/src/auth/index.js index b5953990..148e2e13 100644 --- a/opendc-web/opendc-web-ui/src/auth/index.js +++ b/opendc-web/opendc-web-ui/src/auth/index.js @@ -2,7 +2,7 @@ import { LOG_IN_SUCCEEDED, LOG_OUT } from '../actions/auth' import { DELETE_CURRENT_USER_SUCCEEDED } from '../actions/users' const getAuthObject = () => { - const authItem = localStorage.getItem('auth') + const authItem = global.localStorage && localStorage.getItem('auth') if (!authItem || authItem === '{}') { return undefined } 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..dd32927f 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, useMemo, 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 ( - - { - this.stage = stage - }} - width={this.props.mapDimensions.width} - height={this.props.mapDimensions.height} - onMouseMove={this.updateMousePosition.bind(this)} - > - - - - - - - - ) - } + return ( + + + + + + + + + + ) } export default MapStageComponent 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..b714a7d2 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,7 +1,7 @@ import PropTypes from 'prop-types' import React from 'react' import Shapes from '../../../../shapes' -import { Link } from 'react-router-dom' +import Link from 'next/link' import FontAwesome from 'react-fontawesome' import ScenarioListContainer from '../../../../containers/app/sidebars/project/ScenarioListContainer' @@ -44,11 +44,12 @@ class PortfolioListComponent extends React.Component { {portfolio.name}
        - this.props.onChoosePortfolio(portfolio._id)} - /> + + this.props.onChoosePortfolio(portfolio._id)} + /> + this.onDelete(portfolio._id)} 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..4efa99ef 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,7 +1,7 @@ import PropTypes from 'prop-types' import React from 'react' import Shapes from '../../../../shapes' -import { Link } from 'react-router-dom' +import Link from 'next/link' import FontAwesome from 'react-fontawesome' class ScenarioListComponent extends React.Component { @@ -34,10 +34,13 @@ class ScenarioListComponent extends React.Component {
        this.props.onChooseScenario(scenario.portfolioId, scenario._id)} - /> + href={`/projects/${this.props.currentProjectId}/portfolios/${scenario.portfolioId}/scenarios/${scenario._id}`} + > + this.props.onChooseScenario(scenario.portfolioId, scenario._id)} + /> + (idx !== 0 ? this.onDelete(scenario._id) : undefined)} diff --git a/opendc-web/opendc-web-ui/src/components/modals/ConfirmationModal.js b/opendc-web/opendc-web-ui/src/components/modals/ConfirmationModal.js index 589047dc..5a95810a 100644 --- a/opendc-web/opendc-web-ui/src/components/modals/ConfirmationModal.js +++ b/opendc-web/opendc-web-ui/src/components/modals/ConfirmationModal.js @@ -2,36 +2,26 @@ import PropTypes from 'prop-types' import React from 'react' import Modal from './Modal' -class ConfirmationModal extends React.Component { - static propTypes = { - title: PropTypes.string.isRequired, - message: PropTypes.string.isRequired, - show: PropTypes.bool.isRequired, - callback: PropTypes.func.isRequired, - } - - onConfirm() { - this.props.callback(true) - } - - onCancel() { - this.props.callback(false) - } +function ConfirmationModal({ title, message, show, callback }) { + return ( + callback(true)} + onCancel={() => callback(false)} + submitButtonType="danger" + submitButtonText="Confirm" + > + {message} + + ) +} - render() { - return ( - - {this.props.message} - - ) - } +ConfirmationModal.propTypes = { + title: PropTypes.string.isRequired, + message: PropTypes.string.isRequired, + show: PropTypes.bool.isRequired, + callback: PropTypes.func.isRequired, } export default ConfirmationModal diff --git a/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js b/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js index 8c28c542..7b1eaae2 100644 --- a/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js +++ b/opendc-web/opendc-web-ui/src/components/navigation/AppNavbarComponent.js @@ -1,6 +1,6 @@ import React from 'react' import FontAwesome from 'react-fontawesome' -import { Link } from 'react-router-dom' +import Link from 'next/link' import { NavLink } from 'reactstrap' import Navbar, { NavItem } from './Navbar' import {} from './Navbar.module.scss' @@ -8,16 +8,20 @@ import {} from './Navbar.module.scss' const AppNavbarComponent = ({ project, fullWidth }) => ( - - - My Projects - + + + + My Projects + + {project ? ( - - {project.name} - + + + {project.name} + + ) : undefined} diff --git a/opendc-web/opendc-web-ui/src/components/navigation/LogoutButton.js b/opendc-web/opendc-web-ui/src/components/navigation/LogoutButton.js index 78b02b44..0c0feeb1 100644 --- a/opendc-web/opendc-web-ui/src/components/navigation/LogoutButton.js +++ b/opendc-web/opendc-web-ui/src/components/navigation/LogoutButton.js @@ -1,11 +1,10 @@ import PropTypes from 'prop-types' import React from 'react' import FontAwesome from 'react-fontawesome' -import { Link } from 'react-router-dom' import { NavLink } from 'reactstrap' const LogoutButton = ({ onLogout }) => ( - + ) diff --git a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js index bf18f1c4..90f55665 100644 --- a/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js +++ b/opendc-web/opendc-web-ui/src/components/navigation/Navbar.js @@ -1,5 +1,6 @@ import React, { useState } from 'react' -import { Link, useLocation } from 'react-router-dom' +import Link from 'next/link' +import { useRouter } from 'next/router' import { Navbar as RNavbar, NavItem as RNavItem, @@ -15,6 +16,7 @@ import Login from '../../containers/auth/Login' import Logout from '../../containers/auth/Logout' import ProfileName from '../../containers/auth/ProfileName' import { login, navbar, opendcBrand } from './Navbar.module.scss' +import { useAuth } from '../../auth/hook' export const NAVBAR_HEIGHT = 60 @@ -24,32 +26,45 @@ const GitHubLink = () => ( className="ml-2 mr-3 text-dark" style={{ position: 'relative', top: 7 }} > - + ) export const NavItem = ({ route, children }) => { - const location = useLocation() - return {children} + const router = useRouter() + const handleClick = (e) => { + e.preventDefault() + router.push(route) + } + return ( + + {children} + + ) } export const LoggedInSection = () => { - const location = useLocation() + const router = useRouter() + const isLoggedIn = useAuth() return ( ) @@ -74,7 +89,7 @@ const Navbar = ({ fullWidth, children }) => { - + OpenDC diff --git a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js index b38fc183..28fd81e9 100644 --- a/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js +++ b/opendc-web/opendc-web-ui/src/components/not-found/TerminalWindow.js @@ -1,5 +1,5 @@ import React from 'react' -import { Link } from 'react-router-dom' +import Link from 'next/link' import BlinkingCursor from './BlinkingCursor' import CodeBlock from './CodeBlock' import { terminalWindow, terminalHeader, terminalBody, segfault, subTitle, homeBtn } from './TerminalWindow.module.scss' @@ -23,8 +23,10 @@ const TerminalWindow = () => ( Got lost?
        - - GET ME BACK TO OPENDC + +
        + GET ME BACK TO OPENDC +
        diff --git a/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js b/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js index 1c76cc7f..48cce019 100644 --- a/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js +++ b/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js @@ -1,11 +1,13 @@ import PropTypes from 'prop-types' import React from 'react' -import { Link } from 'react-router-dom' +import Link from 'next/link' const ProjectActionButtons = ({ projectId, onViewUsers, onDelete }) => ( - - + + + +
        { + useRequireAuth() + + const projectName = useSelector( + (state) => + state.currentProjectId !== '-1' && + state.objects.project[state.currentProjectId] && + state.objects.project[state.currentProjectId].name + ) + const topologyIsLoading = useSelector((state) => state.currentTopologyIdd === '-1') + + const dispatch = useDispatch() + useEffect(() => { + if (scenarioId) { + dispatch(openScenarioSucceeded(projectId, portfolioId, scenarioId)) + } else if (portfolioId) { + dispatch(openPortfolioSucceeded(projectId, portfolioId)) + } else { + dispatch(openProjectSucceeded(projectId)) + } + }, [projectId, portfolioId, scenarioId, dispatch]) + + const constructionElements = topologyIsLoading ? ( +
        + +
        + ) : ( +
        + + + + + +
        + ) + + const portfolioElements = ( +
        + +
        + +
        +
        + ) + + const scenarioElements = ( +
        + +
        +

        Scenario loading

        +
        +
        + ) + + const title = projectName ? projectName + ' - OpenDC' : 'Simulation - OpenDC' + + return ( + + + {title} + + + {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements} + + + + + + + + + + ) +} + +App.propTypes = { + projectId: PropTypes.string.isRequired, + portfolioId: PropTypes.string, + scenarioId: PropTypes.string, +} + +export default App diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js b/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js index 61d123e8..9394238d 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js +++ b/opendc-web/opendc-web-ui/src/containers/app/map/MapStage.js @@ -4,11 +4,13 @@ import { setMapDimensions, setMapPositionWithBoundsCheck, zoomInOnPosition } fro import MapStageComponent from '../../../components/app/map/MapStageComponent' const MapStage = () => { - const { position, dimensions } = useSelector((state) => state.map) + const position = useSelector((state) => state.map.position) + const dimensions = useSelector((state) => state.map.dimensions) const dispatch = useDispatch() const zoomInOnPositionA = (zoomIn, x, y) => dispatch(zoomInOnPosition(zoomIn, x, y)) const setMapPositionWithBoundsCheckA = (x, y) => dispatch(setMapPositionWithBoundsCheck(x, y)) const setMapDimensionsA = (width, height) => dispatch(setMapDimensions(width, height)) + return ( { }) const dispatch = useDispatch() - const history = useHistory() + const router = useRouter() const actions = { onNewPortfolio: () => { dispatch(openNewPortfolioModal()) @@ -37,7 +37,7 @@ const PortfolioListContainer = (props) => { const state = await getState(dispatch) dispatch(deletePortfolio(id)) dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0])) - history.push(`/projects/${state.currentProjectId}`) + router.push(`/projects/${state.currentProjectId}`) } }, } diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js index 35e6c52b..06c7f0f7 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ProjectSidebarContainer.js @@ -1,11 +1,11 @@ import React from 'react' -import { useLocation } from 'react-router-dom' +import { useRouter } from 'next/router' import ProjectSidebarComponent from '../../../../components/app/sidebars/project/ProjectSidebarComponent' import { isCollapsible } from '../../../../util/sidebar-space' const ProjectSidebarContainer = (props) => { - const location = useLocation() - return + const router = useRouter() + return } export default ProjectSidebarContainer diff --git a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js index 954284a6..e9c05f17 100644 --- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js +++ b/opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js @@ -3,13 +3,13 @@ import { useDispatch, useSelector } from 'react-redux' import TopologyListComponent from '../../../../components/app/sidebars/project/TopologyListComponent' import { setCurrentTopology } from '../../../../actions/topology/building' import { openNewTopologyModal } from '../../../../actions/modals/topology' -import { useHistory } from 'react-router-dom' +import { useRouter } from 'next/router' import { getState } from '../../../../util/state-utils' import { deleteTopology } from '../../../../actions/topologies' const TopologyListContainer = () => { const dispatch = useDispatch() - const history = useHistory() + const router = useRouter() const topologies = useSelector((state) => { let topologies = state.objects.project[state.currentProjectId] @@ -26,7 +26,7 @@ const TopologyListContainer = () => { const onChooseTopology = async (id) => { dispatch(setCurrentTopology(id)) const state = await getState(dispatch) - history.push(`/projects/${state.currentProjectId}`) + router.push(`/projects/${state.currentProjectId}`) } const onNewTopology = () => { dispatch(openNewTopologyModal()) @@ -36,7 +36,7 @@ const TopologyListContainer = () => { const state = await getState(dispatch) dispatch(deleteTopology(id)) dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0])) - history.push(`/projects/${state.currentProjectId}`) + router.push(`/projects/${state.currentProjectId}`) } } diff --git a/opendc-web/opendc-web-ui/src/containers/auth/Login.js b/opendc-web/opendc-web-ui/src/containers/auth/Login.js index f652429d..178f269e 100644 --- a/opendc-web/opendc-web-ui/src/containers/auth/Login.js +++ b/opendc-web/opendc-web-ui/src/containers/auth/Login.js @@ -3,7 +3,6 @@ import GoogleLogin from 'react-google-login' import { useDispatch } from 'react-redux' import { logIn } from '../../actions/auth' import { Button } from 'reactstrap' -import config from '../../config' function Login({ visible, className }) { const dispatch = useDispatch() @@ -30,12 +29,12 @@ function Login({ visible, className }) { return ( ( )} /> diff --git a/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js b/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js deleted file mode 100644 index 93a38642..00000000 --- a/opendc-web/opendc-web-ui/src/containers/modals/DeleteProfileModal.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { closeDeleteProfileModal } from '../../actions/modals/profile' -import { deleteCurrentUser } from '../../actions/users' -import ConfirmationModal from '../../components/modals/ConfirmationModal' - -const DeleteProfileModal = () => { - const visible = useSelector((state) => state.modals.deleteProfileModalVisible) - - const dispatch = useDispatch() - const callback = (isConfirmed) => { - if (isConfirmed) { - dispatch(deleteCurrentUser()) - } - dispatch(closeDeleteProfileModal()) - } - return ( - - ) -} - -export default DeleteProfileModal diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js index b588b4bc..18ad65f9 100644 --- a/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js +++ b/opendc-web/opendc-web-ui/src/containers/modals/NewScenarioModal.js @@ -6,8 +6,6 @@ import { closeNewScenarioModal } from '../../actions/modals/scenarios' const NewScenarioModal = (props) => { const topologies = useSelector(({ currentProjectId, objects }) => { - console.log(currentProjectId, objects) - if (currentProjectId === '-1' || !objects.project[currentProjectId]) { return [] } diff --git a/opendc-web/opendc-web-ui/src/index.js b/opendc-web/opendc-web-ui/src/index.js deleted file mode 100644 index fdfec24b..00000000 --- a/opendc-web/opendc-web-ui/src/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom' -import * as Sentry from '@sentry/react' -import { Integrations } from '@sentry/tracing' -import { Provider } from 'react-redux' -import './index.scss' -import Routes from './routes' -import config from './config' -import configureStore from './store/configure-store' - -const store = configureStore() - -// Initialize Sentry if the user has configured a DSN -const dsn = config['SENTRY_DSN'] -if (dsn) { - Sentry.init({ - environment: process.env.NODE_ENV, - dsn: dsn, - integrations: [new Integrations.BrowserTracing()], - tracesSampleRate: 0.1, - }) -} - -ReactDOM.render( - - - , - document.getElementById('root') -) diff --git a/opendc-web/opendc-web-ui/src/index.scss b/opendc-web/opendc-web-ui/src/index.scss index 0c1ddff4..1a4d1303 100644 --- a/opendc-web/opendc-web-ui/src/index.scss +++ b/opendc-web/opendc-web-ui/src/index.scss @@ -5,7 +5,7 @@ html, body, -#root { +#__next { margin: 0; padding: 0; width: 100%; diff --git a/opendc-web/opendc-web-ui/src/pages/404.js b/opendc-web/opendc-web-ui/src/pages/404.js new file mode 100644 index 00000000..cc9281fc --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/404.js @@ -0,0 +1,19 @@ +import React from 'react' +import Head from 'next/head' +import TerminalWindow from '../components/not-found/TerminalWindow' +import style from './404.module.scss' + +const NotFound = () => { + return ( + <> + + Page Not Found - OpenDC + +
        + +
        + + ) +} + +export default NotFound diff --git a/opendc-web/opendc-web-ui/src/pages/404.module.scss b/opendc-web/opendc-web-ui/src/pages/404.module.scss new file mode 100644 index 00000000..e91c2780 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/404.module.scss @@ -0,0 +1,8 @@ +.not-found-backdrop { + display: flex; + + width: 100%; + height: 100%; + + background-image: linear-gradient(135deg, #00678a, #008fbf, #00a6d6); +} diff --git a/opendc-web/opendc-web-ui/src/pages/App.js b/opendc-web/opendc-web-ui/src/pages/App.js deleted file mode 100644 index ea62e8dc..00000000 --- a/opendc-web/opendc-web-ui/src/pages/App.js +++ /dev/null @@ -1,103 +0,0 @@ -import PropTypes from 'prop-types' -import React, { useEffect } from 'react' -import { HotKeys } from 'react-hotkeys' -import { useDispatch, useSelector } from 'react-redux' -import { openPortfolioSucceeded } from '../actions/portfolios' -import { openProjectSucceeded } from '../actions/projects' -import ToolPanelComponent from '../components/app/map/controls/ToolPanelComponent' -import LoadingScreen from '../components/app/map/LoadingScreen' -import ScaleIndicatorContainer from '../containers/app/map/controls/ScaleIndicatorContainer' -import MapStage from '../containers/app/map/MapStage' -import TopologySidebarContainer from '../containers/app/sidebars/topology/TopologySidebarContainer' -import DeleteMachineModal from '../containers/modals/DeleteMachineModal' -import DeleteRackModal from '../containers/modals/DeleteRackModal' -import DeleteRoomModal from '../containers/modals/DeleteRoomModal' -import EditRackNameModal from '../containers/modals/EditRackNameModal' -import EditRoomNameModal from '../containers/modals/EditRoomNameModal' -import NewTopologyModal from '../containers/modals/NewTopologyModal' -import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -import ProjectSidebarContainer from '../containers/app/sidebars/project/ProjectSidebarContainer' -import { openScenarioSucceeded } from '../actions/scenarios' -import NewPortfolioModal from '../containers/modals/NewPortfolioModal' -import NewScenarioModal from '../containers/modals/NewScenarioModal' -import PortfolioResultsContainer from '../containers/app/results/PortfolioResultsContainer' -import KeymapConfiguration from '../shortcuts/keymap' -import { useDocumentTitle } from '../util/hooks' - -const App = ({ projectId, portfolioId, scenarioId }) => { - const projectName = useSelector( - (state) => - state.currentProjectId !== '-1' && - state.objects.project[state.currentProjectId] && - state.objects.project[state.currentProjectId].name - ) - const topologyIsLoading = useSelector((state) => state.currentTopologyId === '-1') - - const dispatch = useDispatch() - useEffect(() => { - if (scenarioId) { - dispatch(openScenarioSucceeded(projectId, portfolioId, scenarioId)) - } else if (portfolioId) { - dispatch(openPortfolioSucceeded(projectId, portfolioId)) - } else { - dispatch(openProjectSucceeded(projectId)) - } - }, [projectId, portfolioId, scenarioId, dispatch]) - - const constructionElements = topologyIsLoading ? ( -
        - -
        - ) : ( -
        - - - - - -
        - ) - - const portfolioElements = ( -
        - -
        - -
        -
        - ) - - const scenarioElements = ( -
        - -
        -

        Scenario loading

        -
        -
        - ) - - useDocumentTitle(projectName ? projectName + ' - OpenDC' : 'Simulation - OpenDC') - - return ( - - - {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements} - - - - - - - - - - ) -} - -App.propTypes = { - projectId: PropTypes.string.isRequired, - portfolioId: PropTypes.string, - scenarioId: PropTypes.string, -} - -export default App diff --git a/opendc-web/opendc-web-ui/src/pages/Home.js b/opendc-web/opendc-web-ui/src/pages/Home.js deleted file mode 100644 index ee930fbe..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Home.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react' -import ContactSection from '../components/home/ContactSection' -import IntroSection from '../components/home/IntroSection' -import JumbotronHeader from '../components/home/JumbotronHeader' -import ModelingSection from '../components/home/ModelingSection' -import SimulationSection from '../components/home/SimulationSection' -import StakeholderSection from '../components/home/StakeholderSection' -import TeamSection from '../components/home/TeamSection' -import TechnologiesSection from '../components/home/TechnologiesSection' -import HomeNavbar from '../components/navigation/HomeNavbar' -import { - introSection, - stakeholderSection, - modelingSection, - simulationSection, - technologiesSection, - teamSection, -} from './Home.module.scss' -import { useDocumentTitle } from '../util/hooks' - -function Home() { - useDocumentTitle('OpenDC') - return ( -
        - -
        - - - - - - - - -
        -
        - ) -} - -export default Home diff --git a/opendc-web/opendc-web-ui/src/pages/Home.module.scss b/opendc-web/opendc-web-ui/src/pages/Home.module.scss deleted file mode 100644 index aed1d88f..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Home.module.scss +++ /dev/null @@ -1,16 +0,0 @@ -.bodyWrapper { - position: relative; - overflow-y: hidden; -} - -.introSection, -.modelingSection, -.technologiesSection { - background-color: #fff; -} - -.stakeholderSection, -.simulationSection, -.teamSection { - background-color: #f2f2f2; -} diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.js b/opendc-web/opendc-web-ui/src/pages/NotFound.js deleted file mode 100644 index 409ffa0e..00000000 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import TerminalWindow from '../components/not-found/TerminalWindow' -import style from './NotFound.module.scss' -import { useDocumentTitle } from '../util/hooks' - -const NotFound = () => { - useDocumentTitle('Page Not Found - OpenDC') - return ( -
        - -
        - ) -} - -export default NotFound diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.module.scss b/opendc-web/opendc-web-ui/src/pages/NotFound.module.scss deleted file mode 100644 index e91c2780..00000000 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.not-found-backdrop { - display: flex; - - width: 100%; - height: 100%; - - background-image: linear-gradient(135deg, #00678a, #008fbf, #00a6d6); -} diff --git a/opendc-web/opendc-web-ui/src/pages/Profile.js b/opendc-web/opendc-web-ui/src/pages/Profile.js deleted file mode 100644 index ea781686..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Profile.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' -import { useDispatch } from 'react-redux' -import { openDeleteProfileModal } from '../actions/modals/profile' -import DeleteProfileModal from '../containers/modals/DeleteProfileModal' -import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -import { useDocumentTitle } from '../util/hooks' - -const Profile = () => { - const dispatch = useDispatch() - const onDelete = () => dispatch(openDeleteProfileModal()) - - useDocumentTitle('My Profile - OpenDC') - return ( -
        - -
        - -

        - This does not delete your Google account, but simply disconnects it from the OpenDC platform and - deletes any project info that is associated with you (projects you own and any authorizations you - may have on other projects). -

        -
        - -
        - ) -} - -export default Profile diff --git a/opendc-web/opendc-web-ui/src/pages/Projects.js b/opendc-web/opendc-web-ui/src/pages/Projects.js deleted file mode 100644 index 5e642a03..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Projects.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useEffect } from 'react' -import { useDispatch } from 'react-redux' -import { fetchAuthorizationsOfCurrentUser } from '../actions/users' -import ProjectFilterPanel from '../components/projects/FilterPanel' -import NewProjectModal from '../containers/modals/NewProjectModal' -import NewProjectButtonContainer from '../containers/projects/NewProjectButtonContainer' -import VisibleProjectList from '../containers/projects/VisibleProjectAuthList' -import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -import { useDocumentTitle } from '../util/hooks' - -function Projects() { - const dispatch = useDispatch() - - useEffect(() => dispatch(fetchAuthorizationsOfCurrentUser())) - useDocumentTitle('My Projects - OpenDC') - - return ( -
        - -
        - - - -
        - -
        - ) -} - -export default Projects diff --git a/opendc-web/opendc-web-ui/src/pages/_app.js b/opendc-web/opendc-web-ui/src/pages/_app.js new file mode 100644 index 00000000..77ffa698 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/_app.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 Head from 'next/head' +import { Provider } from 'react-redux' +import { useStore } from '../store/configure-store' +import '../index.scss' + +export default function App({ Component, pageProps }) { + const store = useStore(pageProps.initialReduxState) + + return ( + <> + + + + + + + + + ) +} diff --git a/opendc-web/opendc-web-ui/src/pages/_document.js b/opendc-web/opendc-web-ui/src/pages/_document.js new file mode 100644 index 00000000..943ae395 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/_document.js @@ -0,0 +1,96 @@ +/* + * 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 Document, { Html, Head, Main, NextScript } from 'next/document' + +class OpenDCDocument extends Document { + render() { + return ( + + + + + + + + + + + {/* Twitter Card data */} + + + + + + + + {/* OpenGraph meta tags */} + + + + + + + + + {/* CDN Dependencies */} + +