From 1ce8bf170cda2afab334cd330325cd4fbb97dab4 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 7 Jul 2021 11:46:57 +0200 Subject: ui: Split App container into separate components This change splits the App container into separate pages, as a starting point for removing much of the unnecessary state from Redux. --- .../src/pages/projects/[project]/index.js | 16 +---- .../projects/[project]/portfolios/[portfolio].js | 45 +++++++++--- .../projects/[project]/topologies/[topology].js | 81 ++++++++++++++++++++++ 3 files changed, 120 insertions(+), 22 deletions(-) create mode 100644 opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js (limited to 'opendc-web/opendc-web-ui/src/pages/projects') diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js index 72316bc9..cce887aa 100644 --- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js @@ -20,18 +20,6 @@ * SOFTWARE. */ -import { useRouter } from 'next/router' -import App from '../../../containers/app/App' +import Topology from './topologies/[topology]' -function Project() { - const router = useRouter() - const { project } = router.query - - if (project) { - return - } - - return
-} - -export default Project +export default Topology diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js index 76a8d23b..b21db44c 100644 --- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js @@ -21,17 +21,46 @@ */ import { useRouter } from 'next/router' -import App from '../../../../containers/app/App' +import Head from 'next/head' +import AppNavbarContainer from '../../../../containers/navigation/AppNavbarContainer' +import React, { useEffect } from 'react' +import { useProject } from '../../../../data/project' +import ProjectSidebarContainer from '../../../../containers/app/sidebars/project/ProjectSidebarContainer' +import PortfolioResultsContainer from '../../../../containers/app/results/PortfolioResultsContainer' +import { useDispatch } from 'react-redux' +import { openPortfolioSucceeded } from '../../../../redux/actions/portfolios' -function Project() { +/** + * Page that displays the results in a portfolio. + */ +function Portfolio() { const router = useRouter() - const { project, portfolio } = router.query + const { project: projectId, portfolio: portfolioId } = router.query + + const project = useProject(projectId) + const title = project?.name ? project?.name + ' - OpenDC' : 'Simulation - OpenDC' - if (project && portfolio) { - return - } + const dispatch = useDispatch() + useEffect(() => { + if (portfolioId) { + dispatch(openPortfolioSucceeded(projectId, portfolioId)) + } + }, [projectId, portfolioId, dispatch]) - return
+ return ( +
+ + {title} + + +
+ +
+ +
+
+
+ ) } -export default Project +export default Portfolio diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js new file mode 100644 index 00000000..28db1531 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js @@ -0,0 +1,81 @@ +/* + * 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 { useRouter } from 'next/router' +import { useProject } from '../../../../data/project' +import { useDispatch, useSelector } from 'react-redux' +import React, { useEffect } from 'react' +import { openProjectSucceeded } from '../../../../redux/actions/projects' +import { HotKeys } from 'react-hotkeys' +import { KeymapConfiguration } from '../../../../hotkeys' +import Head from 'next/head' +import AppNavbarContainer from '../../../../containers/navigation/AppNavbarContainer' +import LoadingScreen from '../../../../components/app/map/LoadingScreen' +import MapStage from '../../../../containers/app/map/MapStage' +import ScaleIndicatorContainer from '../../../../containers/app/map/controls/ScaleIndicatorContainer' +import ToolPanelComponent from '../../../../components/app/map/controls/ToolPanelComponent' +import ProjectSidebarContainer from '../../../../containers/app/sidebars/project/ProjectSidebarContainer' +import TopologySidebarContainer from '../../../../containers/app/sidebars/topology/TopologySidebarContainer' + +/** + * Page that displays a datacenter topology. + */ +function Topology() { + const router = useRouter() + const { project: projectId, topology: topologyId } = router.query + + const project = useProject(projectId) + const title = project?.name ? project?.name + ' - OpenDC' : 'Simulation - OpenDC' + + const dispatch = useDispatch() + useEffect(() => { + if (projectId) { + dispatch(openProjectSucceeded(projectId)) + } + }, [projectId, topologyId, dispatch]) + + const topologyIsLoading = useSelector((state) => state.currentTopologyId === '-1') + + return ( + + + {title} + + + {topologyIsLoading ? ( +
+ +
+ ) : ( +
+ + + + + +
+ )} +
+ ) +} + +export default Topology -- cgit v1.2.3 From e5e5d2c65e583493870bc0b62fb185c5e757c13f Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 7 Jul 2021 16:27:49 +0200 Subject: ui: Migrate project APIs to React Query This change updates the OpenDC frontend to use React Query for fetching and mutating project data. Previously, this state was tracked and synchronized via Redux. Migrating to React Query greatly simplifies the state synchronization logic necessary in the frontend. --- .../src/pages/projects/[project]/topologies/[topology].js | 4 ++-- opendc-web/opendc-web-ui/src/pages/projects/index.js | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/pages/projects') diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js index 28db1531..a9dfdb19 100644 --- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js @@ -24,7 +24,6 @@ import { useRouter } from 'next/router' import { useProject } from '../../../../data/project' import { useDispatch, useSelector } from 'react-redux' import React, { useEffect } from 'react' -import { openProjectSucceeded } from '../../../../redux/actions/projects' import { HotKeys } from 'react-hotkeys' import { KeymapConfiguration } from '../../../../hotkeys' import Head from 'next/head' @@ -35,6 +34,7 @@ import ScaleIndicatorContainer from '../../../../containers/app/map/controls/Sca import ToolPanelComponent from '../../../../components/app/map/controls/ToolPanelComponent' import ProjectSidebarContainer from '../../../../containers/app/sidebars/project/ProjectSidebarContainer' import TopologySidebarContainer from '../../../../containers/app/sidebars/topology/TopologySidebarContainer' +import { openProjectSucceeded } from '../../../../redux/actions/projects' /** * Page that displays a datacenter topology. @@ -43,7 +43,7 @@ function Topology() { const router = useRouter() const { project: projectId, topology: topologyId } = router.query - const project = useProject(projectId) + const { data: project } = useProject(projectId) const title = project?.name ? project?.name + ' - OpenDC' : 'Simulation - OpenDC' const dispatch = useDispatch() diff --git a/opendc-web/opendc-web-ui/src/pages/projects/index.js b/opendc-web/opendc-web-ui/src/pages/projects/index.js index 958ca622..2d8e6de7 100644 --- a/opendc-web/opendc-web-ui/src/pages/projects/index.js +++ b/opendc-web/opendc-web-ui/src/pages/projects/index.js @@ -1,22 +1,17 @@ -import React, { useEffect, useState } from 'react' +import React, { useState } from 'react' import Head from 'next/head' -import { useDispatch } from 'react-redux' import ProjectFilterPanel from '../../components/projects/FilterPanel' import NewProjectContainer from '../../containers/projects/NewProjectContainer' import ProjectListContainer from '../../containers/projects/ProjectListContainer' import AppNavbarContainer from '../../containers/navigation/AppNavbarContainer' import { useRequireAuth } from '../../auth' import { Container } from 'reactstrap' -import { fetchProjects } from '../../redux/actions/projects' function Projects() { useRequireAuth() - const dispatch = useDispatch() const [filter, setFilter] = useState('SHOW_ALL') - useEffect(() => dispatch(fetchProjects()), [dispatch]) - return ( <> -- cgit v1.2.3 From 9c8a987556d0fb0cdf0eb67e0c191a8dcc5593b9 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 7 Jul 2021 17:30:15 +0200 Subject: ui: Fetch scenarios and portfolios using React Query --- .../src/pages/projects/[project]/portfolios/[portfolio].js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/pages/projects') diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js index b21db44c..d3d61271 100644 --- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js @@ -23,12 +23,11 @@ import { useRouter } from 'next/router' import Head from 'next/head' import AppNavbarContainer from '../../../../containers/navigation/AppNavbarContainer' -import React, { useEffect } from 'react' +import React from 'react' import { useProject } from '../../../../data/project' import ProjectSidebarContainer from '../../../../containers/app/sidebars/project/ProjectSidebarContainer' import PortfolioResultsContainer from '../../../../containers/app/results/PortfolioResultsContainer' import { useDispatch } from 'react-redux' -import { openPortfolioSucceeded } from '../../../../redux/actions/portfolios' /** * Page that displays the results in a portfolio. @@ -41,11 +40,6 @@ function Portfolio() { const title = project?.name ? project?.name + ' - OpenDC' : 'Simulation - OpenDC' const dispatch = useDispatch() - useEffect(() => { - if (portfolioId) { - dispatch(openPortfolioSucceeded(projectId, portfolioId)) - } - }, [projectId, portfolioId, dispatch]) return (
-- cgit v1.2.3