diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-07-08 16:08:02 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-08 16:08:02 +0200 |
| commit | 1a2416043f0b877f570e89da74e0d0a4aff1d8ae (patch) | |
| tree | 1bed18bb62d223be954faca87b0736d2a571b443 /opendc-web/opendc-web-ui/src/components | |
| parent | dfd2ded56780995cec6d91af37443b710d4ddb3b (diff) | |
| parent | 2c8d675c2cf140eac05988065a9d20fd2773399a (diff) | |
ui: Simplify data fetching in frontend
This pull request aims to simplify the data fetching logic in the OpenDC frontend.
Previously, the frontend used Redux extensively to sync the server state with the
client state, which introduced a lot of unnecessary complexity.
With this pull request, we move most of the data fetching logic out of Redux and
instead use React Query to perform the logic for fetching and caching API requests.
* Move all server data except topologies outside Redux
* Use React Query for fetching server data
* (De)normalize topology using Normalizr
* Remove current ids state from Redux
* Combine fetching of project relations
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components')
10 files changed, 50 insertions, 70 deletions
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 07b2d8f0..c3177fe1 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 @@ -37,10 +37,11 @@ function MapStageComponent({ setPos([mousePos.x, mousePos.y]) } - useEffect(() => { - const updateDimensions = () => setMapDimensions(window.innerWidth, window.innerHeight - NAVBAR_HEIGHT) - const updateScale = (e) => zoomInOnPosition(e.deltaY < 0, x, y) + const updateDimensions = () => setMapDimensions(window.innerWidth, window.innerHeight - NAVBAR_HEIGHT) + const updateScale = (e) => zoomInOnPosition(e.deltaY < 0, x, y) + // We explicitly do not specify any dependencies to prevent infinitely dispatching updateDimensions commands + useEffect(() => { updateDimensions() window.addEventListener('resize', updateDimensions) @@ -57,7 +58,7 @@ function MapStageComponent({ window.removeEventListener('resize', updateDimensions) window.removeEventListener('wheel', updateScale) } - }, [x, y, setMapDimensions, zoomInOnPosition]) + }, []) // eslint-disable-line react-hooks/exhaustive-deps const store = useStore() diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js index e67d54fc..42d20ff1 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/RoomGroup.js @@ -10,7 +10,7 @@ const RoomGroup = ({ room, interactionLevel, currentRoomInConstruction, onClick if (currentRoomInConstruction === room._id) { return ( <Group onClick={onClick}> - {room.tileIds.map((tileId) => ( + {room.tiles.map((tileId) => ( <TileContainer key={tileId} tileId={tileId} newTile={true} /> ))} </Group> @@ -25,16 +25,16 @@ const RoomGroup = ({ room, interactionLevel, currentRoomInConstruction, onClick interactionLevel.roomId === room._id ) { return [ - room.tileIds + room.tiles .filter((tileId) => tileId !== interactionLevel.tileId) .map((tileId) => <TileContainer key={tileId} tileId={tileId} />), <GrayContainer key={-1} />, - room.tileIds + room.tiles .filter((tileId) => tileId === interactionLevel.tileId) .map((tileId) => <TileContainer key={tileId} tileId={tileId} />), ] } else { - return room.tileIds.map((tileId) => <TileContainer key={tileId} tileId={tileId} />) + return room.tiles.map((tileId) => <TileContainer key={tileId} tileId={tileId} />) } })()} <WallContainer roomId={room._id} /> diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js index 2a108b93..ce5e4a6b 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/TileGroup.js @@ -8,7 +8,7 @@ import RoomTile from '../elements/RoomTile' const TileGroup = ({ tile, newTile, onClick }) => { let tileObject - if (tile.rackId) { + if (tile.rack) { tileObject = <RackContainer tile={tile} /> } else { tileObject = null diff --git a/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js b/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js index 57107768..d4c6db7d 100644 --- a/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js +++ b/opendc-web/opendc-web-ui/src/components/app/map/groups/TopologyGroup.js @@ -12,7 +12,7 @@ const TopologyGroup = ({ topology, interactionLevel }) => { if (interactionLevel.mode === 'BUILDING') { return ( <Group> - {topology.roomIds.map((roomId) => ( + {topology.rooms.map((roomId) => ( <RoomContainer key={roomId} roomId={roomId} /> ))} </Group> @@ -21,13 +21,13 @@ const TopologyGroup = ({ topology, interactionLevel }) => { return ( <Group> - {topology.roomIds + {topology.rooms .filter((roomId) => roomId !== interactionLevel.roomId) .map((roomId) => ( <RoomContainer key={roomId} roomId={roomId} /> ))} {interactionLevel.mode === 'ROOM' ? <GrayContainer /> : null} - {topology.roomIds + {topology.rooms .filter((roomId) => roomId === interactionLevel.roomId) .map((roomId) => ( <RoomContainer key={roomId} roomId={roomId} /> 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 ce271819..d61ff24e 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 @@ -25,7 +25,7 @@ function PortfolioListComponent({ </Button> </h2> - {portfolios.map((portfolio, idx) => ( + {portfolios.map((portfolio) => ( <div key={portfolio._id}> <Row className="row mb-1"> <Col @@ -61,7 +61,7 @@ function PortfolioListComponent({ PortfolioListComponent.propTypes = { portfolios: PropTypes.arrayOf(Portfolio), - currentProjectId: PropTypes.string.isRequired, + currentProjectId: PropTypes.string, currentPortfolioId: PropTypes.string, onNewPortfolio: PropTypes.func.isRequired, onChoosePortfolio: PropTypes.func.isRequired, 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 f990dfcb..e81d2b78 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,48 +1,19 @@ import PropTypes from 'prop-types' import React from 'react' import { Scenario } from '../../../../shapes' -import Link from 'next/link' import { Button, Col, Row } from 'reactstrap' -import classNames from 'classnames' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faPlus, faPlay, faTrash } from '@fortawesome/free-solid-svg-icons' +import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons' -function ScenarioListComponent({ - scenarios, - portfolioId, - currentProjectId, - currentScenarioId, - onNewScenario, - onChooseScenario, - onDeleteScenario, -}) { +function ScenarioListComponent({ scenarios, portfolioId, onNewScenario, onDeleteScenario }) { return ( <> {scenarios.map((scenario, idx) => ( <Row key={scenario._id} className="mb-1"> - <Col - xs="7" - className={classNames('pl-5 align-self-center', { - 'font-weight-bold': scenario._id === currentScenarioId, - })} - > + <Col xs="7" className="pl-5 align-self-center"> {scenario.name} </Col> <Col xs="5" className="text-right"> - <Link - passHref - href={`/projects/${currentProjectId}/portfolios/${scenario.portfolioId}/scenarios/${scenario._id}`} - > - <Button - color="primary" - outline - disabled - className="mr-1" - onClick={() => onChooseScenario(scenario.portfolioId, scenario._id)} - > - <FontAwesomeIcon icon={faPlay} /> - </Button> - </Link> <Button color="danger" outline @@ -67,10 +38,7 @@ function ScenarioListComponent({ ScenarioListComponent.propTypes = { scenarios: PropTypes.arrayOf(Scenario), portfolioId: PropTypes.string, - currentProjectId: PropTypes.string.isRequired, - currentScenarioId: PropTypes.string, onNewScenario: PropTypes.func.isRequired, - onChooseScenario: PropTypes.func.isRequired, onDeleteScenario: PropTypes.func.isRequired, } diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js index 03b92459..46c639bd 100644 --- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js +++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitComponent.js @@ -60,7 +60,7 @@ function UnitComponent({ index, unitType, unit, onDelete }) { UnitComponent.propTypes = { index: PropTypes.number, unitType: PropTypes.string, - unit: PropTypes.oneOf([ProcessingUnit, StorageUnit]), + unit: PropTypes.oneOfType([ProcessingUnit, StorageUnit]), onDelete: PropTypes.func, } diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitListComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitListComponent.js index b7da74a1..54c1a6cc 100644 --- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitListComponent.js +++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/machine/UnitListComponent.js @@ -1,12 +1,19 @@ import PropTypes from 'prop-types' import React from 'react' -import UnitContainer from '../../../../../containers/app/sidebars/topology/machine/UnitContainer' +import { ProcessingUnit, StorageUnit } from '../../../../../shapes' +import UnitComponent from './UnitComponent' -const UnitListComponent = ({ unitType, unitIds }) => ( +const UnitListComponent = ({ unitType, units, onDelete }) => ( <ul className="list-group mt-1"> - {unitIds.length !== 0 ? ( - unitIds.map((unitId, index) => ( - <UnitContainer unitType={unitType} unitId={unitId} index={index} key={index} /> + {units.length !== 0 ? ( + units.map((unit, index) => ( + <UnitComponent + unitType={unitType} + unit={unit} + onDelete={() => onDelete(unit, unitType)} + index={index} + key={index} + /> )) ) : ( <div className="alert alert-info"> @@ -19,8 +26,9 @@ const UnitListComponent = ({ unitType, unitIds }) => ( ) UnitListComponent.propTypes = { - unitType: PropTypes.string, - unitIds: PropTypes.array, + unitType: PropTypes.string.isRequired, + units: PropTypes.arrayOf(PropTypes.oneOfType([ProcessingUnit, StorageUnit])).isRequired, + onDelete: PropTypes.func, } export default UnitListComponent diff --git a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js index f91202ba..b71918da 100644 --- a/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js +++ b/opendc-web/opendc-web-ui/src/components/app/sidebars/topology/rack/MachineComponent.js @@ -23,7 +23,7 @@ UnitIcon.propTypes = { const MachineComponent = ({ position, machine, onClick }) => { const hasNoUnits = - machine.cpuIds.length + machine.gpuIds.length + machine.memoryIds.length + machine.storageIds.length === 0 + machine.cpus.length + machine.gpus.length + machine.memories.length + machine.storages.length === 0 return ( <ListGroupItem @@ -36,10 +36,10 @@ const MachineComponent = ({ position, machine, onClick }) => { {position} </Badge> <div className="d-inline-flex"> - {machine.cpuIds.length > 0 ? <UnitIcon id="cpu" type="CPU" /> : undefined} - {machine.gpuIds.length > 0 ? <UnitIcon id="gpu" type="GPU" /> : undefined} - {machine.memoryIds.length > 0 ? <UnitIcon id="memory" type="memory" /> : undefined} - {machine.storageIds.length > 0 ? <UnitIcon id="storage" type="storage" /> : undefined} + {machine.cpus.length > 0 ? <UnitIcon id="cpu" type="CPU" /> : undefined} + {machine.gpus.length > 0 ? <UnitIcon id="gpu" type="GPU" /> : undefined} + {machine.memories.length > 0 ? <UnitIcon id="memory" type="memory" /> : undefined} + {machine.storages.length > 0 ? <UnitIcon id="storage" type="storage" /> : undefined} {hasNoUnits ? <Badge color="warning">Machine with no units</Badge> : undefined} </div> </ListGroupItem> 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 d0958c28..e024a417 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,17 +1,18 @@ import PropTypes from 'prop-types' import React from 'react' -import EmptySlotContainer from '../../../../../containers/app/sidebars/topology/rack/EmptySlotContainer' -import MachineContainer from '../../../../../containers/app/sidebars/topology/rack/MachineContainer' import { machineList } from './MachineListComponent.module.scss' +import MachineComponent from './MachineComponent' +import { Machine } from '../../../../../shapes' +import EmptySlotComponent from './EmptySlotComponent' -const MachineListComponent = ({ machineIds }) => { +const MachineListComponent = ({ machines = [], onSelect, onAdd }) => { return ( <ul className={`list-group ${machineList}`}> - {machineIds.map((machineId, index) => { - if (machineId === null) { - return <EmptySlotContainer key={index} position={index + 1} /> + {machines.map((machine, index) => { + if (machine === null) { + return <EmptySlotComponent key={index} onAdd={() => onAdd(index + 1)} /> } else { - return <MachineContainer key={index} position={index + 1} machineId={machineId} /> + return <MachineComponent key={index} onClick={() => onSelect(index + 1)} machine={machine} /> } })} </ul> @@ -19,7 +20,9 @@ const MachineListComponent = ({ machineIds }) => { } MachineListComponent.propTypes = { - machineIds: PropTypes.array, + machines: PropTypes.arrayOf(Machine), + onSelect: PropTypes.func.isRequired, + onAdd: PropTypes.func.isRequired, } export default MachineListComponent |
