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. --- opendc-web/opendc-web-ui/src/pages/App.js | 168 ++++++++++++------------------ 1 file changed, 67 insertions(+), 101 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/pages/App.js') 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 -- 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 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/pages/App.js') 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} + + + + + + + + + ) } -- 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/pages/App.js | 103 ------------------------------ 1 file changed, 103 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/pages/App.js (limited to 'opendc-web/opendc-web-ui/src/pages/App.js') 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 -- cgit v1.2.3