summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/containers
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui/src/containers')
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/App.js111
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/RackEnergyFillContainer.js12
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/RackSpaceFillContainer.js2
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/RoomContainer.js5
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js2
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/WallContainer.js2
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/layers/ObjectHoverLayer.js4
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/map/layers/RoomHoverLayer.js6
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/results/PortfolioResultsContainer.js29
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/project/PortfolioListContainer.js35
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/project/ScenarioListContainer.js63
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/project/TopologyListContainer.js24
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js2
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitContainer.js14
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitListContainer.js33
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js12
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineContainer.js14
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineListContainer.js27
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackNameContainer.js2
-rw-r--r--opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js2
-rw-r--r--opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js5
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js7
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js7
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/ProjectListContainer.js4
24 files changed, 140 insertions, 284 deletions
diff --git a/opendc-web/opendc-web-ui/src/containers/app/App.js b/opendc-web/opendc-web-ui/src/containers/app/App.js
deleted file mode 100644
index ec9714ce..00000000
--- a/opendc-web/opendc-web-ui/src/containers/app/App.js
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React, { useEffect } from 'react'
-import Head from 'next/head'
-import { HotKeys } from 'react-hotkeys'
-import { useDispatch, useSelector } from 'react-redux'
-import { openPortfolioSucceeded } from '../../redux/actions/portfolios'
-import { openProjectSucceeded } from '../../redux/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 AppNavbarContainer from '../../containers/navigation/AppNavbarContainer'
-import ProjectSidebarContainer from '../../containers/app/sidebars/project/ProjectSidebarContainer'
-import { openScenarioSucceeded } from '../../redux/actions/scenarios'
-import PortfolioResultsContainer from '../../containers/app/results/PortfolioResultsContainer'
-import { KeymapConfiguration } from '../../hotkeys'
-import { useRequireAuth } from '../../auth'
-import { useActiveProject } from '../../data/project'
-
-const App = ({ projectId, portfolioId, scenarioId }) => {
- useRequireAuth()
-
- const projectName = useActiveProject()?.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 ? (
- <div className="full-height d-flex align-items-center justify-content-center">
- <LoadingScreen />
- </div>
- ) : (
- <div className="full-height">
- <MapStage />
- <ScaleIndicatorContainer />
- <ToolPanelComponent />
- <ProjectSidebarContainer />
- <TopologySidebarContainer />
- </div>
- )
-
- const portfolioElements = (
- <div className="full-height app-page-container">
- <ProjectSidebarContainer />
- <div className="container-fluid full-height">
- <PortfolioResultsContainer />
- </div>
- </div>
- )
-
- const scenarioElements = (
- <div className="full-height app-page-container">
- <ProjectSidebarContainer />
- <div className="container-fluid full-height">
- <h2>Scenario loading</h2>
- </div>
- </div>
- )
-
- const title = projectName ? projectName + ' - OpenDC' : 'Simulation - OpenDC'
-
- return (
- <HotKeys keyMap={KeymapConfiguration} allowChanges={true} className="page-container full-height">
- <Head>
- <title>{title}</title>
- </Head>
- <AppNavbarContainer fullWidth={true} />
- {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements}
- </HotKeys>
- )
-}
-
-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/RackEnergyFillContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/RackEnergyFillContainer.js
index 00d3152f..d22317a5 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
@@ -5,17 +5,17 @@ import RackFillBar from '../../../components/app/map/elements/RackFillBar'
const RackSpaceFillContainer = (props) => {
const state = useSelector((state) => {
let energyConsumptionTotal = 0
- const rack = state.objects.rack[state.objects.tile[props.tileId].rackId]
- const machineIds = rack.machineIds
+ const rack = state.objects.rack[state.objects.tile[props.tileId].rack]
+ const machineIds = rack.machines
machineIds.forEach((machineId) => {
if (machineId !== null) {
const machine = state.objects.machine[machineId]
- machine.cpuIds.forEach((id) => (energyConsumptionTotal += state.objects.cpu[id].energyConsumptionW))
- machine.gpuIds.forEach((id) => (energyConsumptionTotal += state.objects.gpu[id].energyConsumptionW))
- machine.memoryIds.forEach(
+ machine.cpus.forEach((id) => (energyConsumptionTotal += state.objects.cpu[id].energyConsumptionW))
+ machine.gpus.forEach((id) => (energyConsumptionTotal += state.objects.gpu[id].energyConsumptionW))
+ machine.memories.forEach(
(id) => (energyConsumptionTotal += state.objects.memory[id].energyConsumptionW)
)
- machine.storageIds.forEach(
+ machine.storages.forEach(
(id) => (energyConsumptionTotal += state.objects.storage[id].energyConsumptionW)
)
}
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 dc5119fd..8d6f61e0 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
@@ -4,7 +4,7 @@ import RackFillBar from '../../../components/app/map/elements/RackFillBar'
const RackSpaceFillContainer = (props) => {
const state = useSelector((state) => {
- const machineIds = state.objects.rack[state.objects.tile[props.tileId].rackId].machineIds
+ const machineIds = state.objects.rack[state.objects.tile[props.tileId].rack].machines
return {
type: 'space',
fillFraction: machineIds.filter((id) => id !== null).length / machineIds.length,
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 52d48317..0a9e1503 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,3 +1,4 @@
+import PropTypes from 'prop-types'
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { goFromBuildingToRoom } from '../../../redux/actions/interaction-level'
@@ -15,4 +16,8 @@ const RoomContainer = (props) => {
return <RoomGroup {...props} {...state} onClick={() => dispatch(goFromBuildingToRoom(props.roomId))} />
}
+RoomContainer.propTypes = {
+ roomId: PropTypes.string,
+}
+
export default RoomContainer
diff --git a/opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js b/opendc-web/opendc-web-ui/src/containers/app/map/TileContainer.js
index f97e89a1..50a2abfd 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
@@ -9,7 +9,7 @@ const TileContainer = (props) => {
const dispatch = useDispatch()
const onClick = (tile) => {
- if (tile.rackId) {
+ if (tile.rack) {
dispatch(goFromRoomToRack(tile._id))
}
}
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 2a469860..67f36396 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
@@ -4,7 +4,7 @@ import WallGroup from '../../../components/app/map/groups/WallGroup'
const WallContainer = (props) => {
const tiles = useSelector((state) =>
- state.objects.room[props.roomId].tileIds.map((tileId) => state.objects.tile[tileId])
+ state.objects.room[props.roomId].tiles.map((tileId) => state.objects.tile[tileId])
)
return <WallGroup {...props} tiles={tiles} />
}
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 8e934a01..e9a64545 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
@@ -16,10 +16,10 @@ const ObjectHoverLayer = (props) => {
}
const currentRoom = state.objects.room[state.interactionLevel.roomId]
- const tiles = currentRoom.tileIds.map((tileId) => state.objects.tile[tileId])
+ const tiles = currentRoom.tiles.map((tileId) => state.objects.tile[tileId])
const tile = findTileWithPosition(tiles, x, y)
- return !(tile === null || tile.rackId)
+ return !(tile === null || tile.rack)
},
}
})
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 1bfadb6d..4070c766 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
@@ -23,14 +23,14 @@ const RoomHoverLayer = (props) => {
.map((id) => Object.assign({}, state.objects.room[id]))
.filter(
(room) =>
- state.objects.topology[state.currentTopologyId].roomIds.indexOf(room._id) !== -1 &&
+ state.objects.topology[state.currentTopologyId].rooms.indexOf(room._id) !== -1 &&
room._id !== state.construction.currentRoomInConstruction
)
;[...oldRooms, newRoom].forEach((room) => {
- room.tiles = room.tileIds.map((tileId) => state.objects.tile[tileId])
+ room.tiles = room.tiles.map((tileId) => state.objects.tile[tileId])
})
- if (newRoom.tileIds.length === 0) {
+ if (newRoom.tiles.length === 0) {
return findPositionInRooms(oldRooms, x, y) === -1
}
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 e60abe18..a75f15ae 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,30 +1,13 @@
import React from 'react'
-import { useSelector } from 'react-redux'
import PortfolioResultsComponent from '../../../components/app/results/PortfolioResultsComponent'
+import { useRouter } from 'next/router'
+import { usePortfolio, usePortfolioScenarios } from '../../../data/project'
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: state.objects.portfolio[state.currentPortfolioId],
- scenarios: state.objects.portfolio[state.currentPortfolioId].scenarioIds.map(
- (scenarioId) => state.objects.scenario[scenarioId]
- ),
- }
- })
-
+ const router = useRouter()
+ const { portfolio: currentPortfolioId } = router.query
+ const { data: portfolio } = usePortfolio(currentPortfolioId)
+ const scenarios = usePortfolioScenarios(currentPortfolioId).data ?? []
return <PortfolioResultsComponent {...props} scenarios={scenarios} portfolio={portfolio} />
}
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 a36997ff..60ac666c 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,43 +1,34 @@
import React, { useState } from 'react'
-import { useDispatch } from 'react-redux'
import { useRouter } from 'next/router'
import PortfolioListComponent from '../../../../components/app/sidebars/project/PortfolioListComponent'
-import { addPortfolio, deletePortfolio, setCurrentPortfolio } from '../../../../redux/actions/portfolios'
-import { getState } from '../../../../util/state-utils'
-import { setCurrentTopology } from '../../../../redux/actions/topology/building'
import NewPortfolioModalComponent from '../../../../components/modals/custom-components/NewPortfolioModalComponent'
-import { useActivePortfolio, useActiveProject, usePortfolios } from '../../../../data/project'
+import { useProjectPortfolios } from '../../../../data/project'
+import { useMutation } from 'react-query'
const PortfolioListContainer = () => {
- const currentProjectId = useActiveProject()?._id
- const currentPortfolioId = useActivePortfolio()?._id
- const portfolios = usePortfolios(currentProjectId)
+ const router = useRouter()
+ const { project: currentProjectId, portfolio: currentPortfolioId } = router.query
+ const portfolios = useProjectPortfolios(currentProjectId).data ?? []
+
+ const { mutate: addPortfolio } = useMutation('addPortfolio')
+ const { mutateAsync: deletePortfolio } = useMutation('deletePortfolio')
- const dispatch = useDispatch()
const [isVisible, setVisible] = useState(false)
- const router = useRouter()
const actions = {
onNewPortfolio: () => setVisible(true),
- onChoosePortfolio: (portfolioId) => {
- dispatch(setCurrentPortfolio(portfolioId))
+ onChoosePortfolio: async (portfolioId) => {
+ await router.push(`/projects/${currentProjectId}/portfolios/${portfolioId}`)
},
onDeletePortfolio: async (id) => {
if (id) {
- const state = await getState(dispatch)
- dispatch(deletePortfolio(id))
- dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0]))
- router.push(`/projects/${state.currentProjectId}`)
+ await deletePortfolio(id)
+ await router.push(`/projects/${currentProjectId}`)
}
},
}
const callback = (name, targets) => {
if (name) {
- dispatch(
- addPortfolio({
- name,
- targets,
- })
- )
+ addPortfolio({ projectId: currentProjectId, name, targets })
}
setVisible(false)
}
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 e1be51dc..3b68df38 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,47 +1,39 @@
+import PropTypes from 'prop-types'
import React, { useState } from 'react'
-import { useDispatch } from 'react-redux'
import ScenarioListComponent from '../../../../components/app/sidebars/project/ScenarioListComponent'
-import { addScenario, deleteScenario, setCurrentScenario } from '../../../../redux/actions/scenarios'
-import { setCurrentPortfolio } from '../../../../redux/actions/portfolios'
import NewScenarioModalComponent from '../../../../components/modals/custom-components/NewScenarioModalComponent'
import { useProjectTopologies } from '../../../../data/topology'
-import { useActiveScenario, useActiveProject, useScenarios } from '../../../../data/project'
+import { usePortfolio, usePortfolioScenarios } from '../../../../data/project'
import { useSchedulers, useTraces } from '../../../../data/experiments'
+import { useMutation } from 'react-query'
const ScenarioListContainer = ({ portfolioId }) => {
- const currentProjectId = useActiveProject()?._id
- const currentScenarioId = useActiveScenario()?._id
- const scenarios = useScenarios(portfolioId)
- const topologies = useProjectTopologies()
- const traces = useTraces()
- const schedulers = useSchedulers()
+ const { data: portfolio } = usePortfolio(portfolioId)
+ const scenarios = usePortfolioScenarios(portfolioId).data ?? []
+ const topologies =
+ useProjectTopologies(portfolio?.projectId).data?.map((topology) => ({
+ _id: topology._id,
+ name: topology.name,
+ })) ?? []
+ const traces = useTraces().data ?? []
+ const schedulers = useSchedulers().data ?? []
+
+ const { mutate: addScenario } = useMutation('addScenario')
+ const { mutate: deleteScenario } = useMutation('deleteScenario')
- const dispatch = useDispatch()
const [isVisible, setVisible] = useState(false)
- const onNewScenario = (currentPortfolioId) => {
- dispatch(setCurrentPortfolio(currentPortfolioId))
- setVisible(true)
- }
- const onChooseScenario = (portfolioId, scenarioId) => {
- dispatch(setCurrentScenario(portfolioId, scenarioId))
- }
- const onDeleteScenario = (id) => {
- if (id) {
- dispatch(deleteScenario(id))
- }
- }
+ const onNewScenario = () => setVisible(true)
+ const onDeleteScenario = (id) => id && deleteScenario(id)
const callback = (name, portfolioId, trace, topology, operational) => {
if (name) {
- dispatch(
- addScenario({
- portfolioId,
- name,
- trace,
- topology,
- operational,
- })
- )
+ addScenario({
+ portfolioId,
+ name,
+ trace,
+ topology,
+ operational,
+ })
}
setVisible(false)
@@ -51,11 +43,8 @@ const ScenarioListContainer = ({ portfolioId }) => {
<>
<ScenarioListComponent
portfolioId={portfolioId}
- currentProjectId={currentProjectId}
- currentScenarioId={currentScenarioId}
scenarios={scenarios}
onNewScenario={onNewScenario}
- onChooseScenario={onChooseScenario}
onDeleteScenario={onDeleteScenario}
/>
<NewScenarioModalComponent
@@ -71,4 +60,8 @@ const ScenarioListContainer = ({ portfolioId }) => {
)
}
+ScenarioListContainer.propTypes = {
+ portfolioId: PropTypes.string,
+}
+
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 266ca495..a2244a30 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,40 +3,42 @@ import { useDispatch } from 'react-redux'
import TopologyListComponent from '../../../../components/app/sidebars/project/TopologyListComponent'
import { setCurrentTopology } from '../../../../redux/actions/topology/building'
import { useRouter } from 'next/router'
-import { getState } from '../../../../util/state-utils'
-import { addTopology, deleteTopology } from '../../../../redux/actions/topologies'
+import { addTopology } from '../../../../redux/actions/topologies'
import NewTopologyModalComponent from '../../../../components/modals/custom-components/NewTopologyModalComponent'
import { useActiveTopology, useProjectTopologies } from '../../../../data/topology'
+import { useMutation } from 'react-query'
const TopologyListContainer = () => {
const dispatch = useDispatch()
const router = useRouter()
- const topologies = useProjectTopologies()
+ const { project: currentProjectId } = router.query
+ const topologies =
+ useProjectTopologies(currentProjectId).data?.map((topology) => ({ _id: topology._id, name: topology.name })) ??
+ []
const currentTopologyId = useActiveTopology()?._id
const [isVisible, setVisible] = useState(false)
+ const { mutate: deleteTopology } = useMutation('deleteTopology')
+
const onChooseTopology = async (id) => {
dispatch(setCurrentTopology(id))
- const state = await getState(dispatch)
- router.push(`/projects/${state.currentProjectId}`)
+ await router.push(`/projects/${currentProjectId}/topologies/${id}`)
}
const onDeleteTopology = async (id) => {
if (id) {
- const state = await getState(dispatch)
- dispatch(deleteTopology(id))
- dispatch(setCurrentTopology(state.objects.project[state.currentProjectId].topologyIds[0]))
- router.push(`/projects/${state.currentProjectId}`)
+ deleteTopology(id)
+ await router.push(`/projects/${currentProjectId}`)
}
}
const onCreateTopology = (name) => {
if (name) {
- dispatch(addTopology(name, undefined))
+ dispatch(addTopology(currentProjectId, name, undefined))
}
setVisible(false)
}
const onDuplicateTopology = (name, id) => {
if (name) {
- dispatch(addTopology(name, id))
+ dispatch(addTopology(currentProjectId, name, id))
}
setVisible(false)
}
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 cb7ec8f9..7553c2fe 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
@@ -5,7 +5,7 @@ import MachineSidebarComponent from '../../../../../components/app/sidebars/topo
const MachineSidebarContainer = (props) => {
const machineId = useSelector(
(state) =>
- state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds[
+ state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rack].machines[
state.interactionLevel.position - 1
]
)
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
deleted file mode 100644
index acb16a21..00000000
--- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/machine/UnitContainer.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { deleteUnit } from '../../../../../redux/actions/topology/machine'
-import UnitComponent from '../../../../../components/app/sidebars/topology/machine/UnitComponent'
-
-const UnitContainer = ({ unitId, unitType }) => {
- const dispatch = useDispatch()
- const unit = useSelector((state) => state.objects[unitType][unitId])
- const onDelete = () => dispatch(deleteUnit(unitType, unitId))
-
- return <UnitComponent index={unitId} unit={unit} unitType={unitType} onDelete={onDelete} />
-}
-
-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 c5c9444d..cdd7e268 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,34 @@
+import PropTypes from 'prop-types'
import React from 'react'
-import { useSelector } from 'react-redux'
+import { useDispatch, useSelector } from 'react-redux'
import UnitListComponent from '../../../../../components/app/sidebars/topology/machine/UnitListComponent'
+import { deleteUnit } from '../../../../../redux/actions/topology/machine'
-const UnitListContainer = (props) => {
- const unitIds = useSelector(
- (state) =>
+const unitMapping = {
+ cpu: 'cpus',
+ gpu: 'gpus',
+ memory: 'memories',
+ storage: 'storages',
+}
+
+const UnitListContainer = ({ unitType, ...props }) => {
+ const dispatch = useDispatch()
+ const units = useSelector((state) => {
+ const machine =
state.objects.machine[
- state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds[
+ state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rack].machines[
state.interactionLevel.position - 1
]
- ][props.unitType + 'Ids']
- )
- return <UnitListComponent {...props} unitIds={unitIds} />
+ ]
+ return machine[unitMapping[unitType]].map((id) => state.objects[unitType][id])
+ })
+ const onDelete = (unit, unitType) => dispatch(deleteUnit(unitType, unit._id))
+
+ return <UnitListComponent {...props} units={units} unitType={unitType} onDelete={onDelete} />
+}
+
+UnitListContainer.propTypes = {
+ unitType: PropTypes.string.isRequired,
}
export default UnitListContainer
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
deleted file mode 100644
index 2134e411..00000000
--- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react'
-import { useDispatch } from 'react-redux'
-import { addMachine } from '../../../../../redux/actions/topology/rack'
-import EmptySlotComponent from '../../../../../components/app/sidebars/topology/rack/EmptySlotComponent'
-
-const EmptySlotContainer = (props) => {
- const dispatch = useDispatch()
- const onAdd = () => dispatch(addMachine(props.position))
- return <EmptySlotComponent {...props} onAdd={onAdd} />
-}
-
-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
deleted file mode 100644
index 7d8e32c1..00000000
--- a/opendc-web/opendc-web-ui/src/containers/app/sidebars/topology/rack/MachineContainer.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { goFromRackToMachine } from '../../../../../redux/actions/interaction-level'
-import MachineComponent from '../../../../../components/app/sidebars/topology/rack/MachineComponent'
-
-const MachineContainer = (props) => {
- const machine = useSelector((state) => state.objects.machine[props.machineId])
- const dispatch = useDispatch()
- return (
- <MachineComponent {...props} onClick={() => dispatch(goFromRackToMachine(props.position))} machine={machine} />
- )
-}
-
-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 b45300fc..2118d915 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,29 @@
-import React from 'react'
-import { useSelector } from 'react-redux'
+import React, { useMemo } from 'react'
+import { useDispatch, useSelector } from 'react-redux'
import MachineListComponent from '../../../../../components/app/sidebars/topology/rack/MachineListComponent'
+import { goFromRackToMachine } from '../../../../../redux/actions/interaction-level'
+import { addMachine } from '../../../../../redux/actions/topology/rack'
const MachineListContainer = (props) => {
- const machineIds = useSelector(
- (state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].machineIds
+ const rack = useSelector((state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rack])
+ const machines = useSelector((state) => rack.machines.map((id) => state.objects.machine[id]))
+ const machinesNull = useMemo(() => {
+ const res = Array(rack.capacity).fill(null)
+ for (const machine of machines) {
+ res[machine.position - 1] = machine
+ }
+ return res
+ }, [rack, machines])
+ const dispatch = useDispatch()
+
+ return (
+ <MachineListComponent
+ {...props}
+ machines={machinesNull}
+ onAdd={(index) => dispatch(addMachine(index))}
+ onSelect={(index) => dispatch(goFromRackToMachine(index))}
+ />
)
- return <MachineListComponent {...props} machineIds={machineIds} />
}
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 eaa1e78e..2c39cf9f 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
@@ -7,7 +7,7 @@ import { editRackName } from '../../../../../redux/actions/topology/rack'
const RackNameContainer = () => {
const [isVisible, setVisible] = useState(false)
const rackName = useSelector(
- (state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rackId].name
+ (state) => state.objects.rack[state.objects.tile[state.interactionLevel.tileId].rack].name
)
const dispatch = useDispatch()
const callback = (name) => {
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 b8fc3bfb..34777125 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
@@ -3,7 +3,7 @@ import { useSelector } from 'react-redux'
import RackSidebarComponent from '../../../../../components/app/sidebars/topology/rack/RackSidebarComponent'
const RackSidebarContainer = (props) => {
- const rackId = useSelector((state) => state.objects.tile[state.interactionLevel.tileId].rackId)
+ const rackId = useSelector((state) => state.objects.tile[state.interactionLevel.tileId].rack)
return <RackSidebarComponent {...props} rackId={rackId} />
}
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 6742bc26..ff9f9fe7 100644
--- a/opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js
+++ b/opendc-web/opendc-web-ui/src/containers/navigation/AppNavbarContainer.js
@@ -1,9 +1,10 @@
import React from 'react'
import AppNavbarComponent from '../../components/navigation/AppNavbarComponent'
-import { useActiveProject } from '../../data/project'
+import { useActiveProjectId, useProject } from '../../data/project'
const AppNavbarContainer = (props) => {
- const project = useActiveProject()
+ const projectId = useActiveProjectId()
+ const { data: project } = useProject(projectId)
return <AppNavbarComponent {...props} project={project} />
}
diff --git a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js
index e03b5c07..ac0edae4 100644
--- a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js
+++ b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js
@@ -1,20 +1,19 @@
import React, { useState } from 'react'
-import { useDispatch } from 'react-redux'
-import { addProject } from '../../redux/actions/projects'
import TextInputModal from '../../components/modals/TextInputModal'
import { Button } from 'reactstrap'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'
+import { useMutation } from 'react-query'
/**
* A container for creating a new project.
*/
const NewProjectContainer = () => {
const [isVisible, setVisible] = useState(false)
- const dispatch = useDispatch()
+ const { mutate: addProject } = useMutation('addProject')
const callback = (text) => {
if (text) {
- dispatch(addProject(text))
+ addProject({ name: text })
}
setVisible(false)
}
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 bdb422dc..62985742 100644
--- a/opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js
+++ b/opendc-web/opendc-web-ui/src/containers/projects/ProjectActions.js
@@ -1,13 +1,12 @@
import React from 'react'
-import { useDispatch } from 'react-redux'
-import { deleteProject } from '../../redux/actions/projects'
import ProjectActionButtons from '../../components/projects/ProjectActionButtons'
+import { useMutation } from 'react-query'
const ProjectActions = (props) => {
- const dispatch = useDispatch()
+ const { mutate: deleteProject } = useMutation('deleteProject')
const actions = {
onViewUsers: (id) => {}, // TODO implement user viewing
- onDelete: (id) => dispatch(deleteProject(id)),
+ onDelete: (id) => deleteProject(id),
}
return <ProjectActionButtons {...props} {...actions} />
}
diff --git a/opendc-web/opendc-web-ui/src/containers/projects/ProjectListContainer.js b/opendc-web/opendc-web-ui/src/containers/projects/ProjectListContainer.js
index 6632a8b5..b5c5dd68 100644
--- a/opendc-web/opendc-web-ui/src/containers/projects/ProjectListContainer.js
+++ b/opendc-web/opendc-web-ui/src/containers/projects/ProjectListContainer.js
@@ -23,8 +23,8 @@ const getVisibleProjects = (projects, filter, userId) => {
const ProjectListContainer = ({ filter }) => {
const { user } = useAuth()
- const projects = useProjects()
- return <ProjectList projects={getVisibleProjects(projects, filter, user?.sub)} />
+ const { data: projects } = useProjects()
+ return <ProjectList projects={getVisibleProjects(projects ?? [], filter, user?.sub)} />
}
ProjectListContainer.propTypes = {