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/store') 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-ui/src/store/configure-store.js | 51 ++++++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/store') 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 13bcd69e..149536a3 100644 --- a/opendc-web/opendc-web-ui/src/store/configure-store.js +++ b/opendc-web/opendc-web-ui/src/store/configure-store.js @@ -1,6 +1,7 @@ +import { useMemo } from 'react' import { applyMiddleware, compose, createStore } from 'redux' -import persistState from 'redux-localstorage' import { createLogger } from 'redux-logger' +import persistState from 'redux-localstorage' import createSagaMiddleware from 'redux-saga' import thunk from 'redux-thunk' import { authRedirectMiddleware } from '../auth/index' @@ -8,20 +9,52 @@ import rootReducer from '../reducers/index' import rootSaga from '../sagas/index' import { viewportAdjustmentMiddleware } from './middlewares/viewport-adjustment' -const sagaMiddleware = createSagaMiddleware() +let store -const middlewares = [thunk, sagaMiddleware, authRedirectMiddleware, viewportAdjustmentMiddleware] +function initStore(initialState) { + const sagaMiddleware = createSagaMiddleware() -if (process.env.NODE_ENV !== 'production') { - middlewares.push(createLogger()) -} + const middlewares = [thunk, sagaMiddleware, authRedirectMiddleware, viewportAdjustmentMiddleware] -export let store = undefined + if (process.env.NODE_ENV !== 'production') { + middlewares.push(createLogger()) + } -export default function configureStore() { - const configuredStore = createStore(rootReducer, compose(persistState('auth'), applyMiddleware(...middlewares))) + let enhancer = applyMiddleware(...middlewares) + + if (global.localStorage) { + enhancer = compose(persistState('auth'), enhancer) + } + + const configuredStore = createStore(rootReducer, enhancer) sagaMiddleware.run(rootSaga) store = configuredStore return configuredStore } + +export const initializeStore = (preloadedState) => { + let _store = store ?? initStore(preloadedState) + + // After navigating to a page with an initial Redux state, merge that state + // with the current state in the store, and create a new store + if (preloadedState && store) { + _store = initStore({ + ...store.getState(), + ...preloadedState, + }) + // Reset the current store + store = undefined + } + + // For SSG and SSR always create a new store + if (typeof window === 'undefined') return _store + // Create the store once in the client + if (!store) store = _store + + return _store +} + +export function useStore(initialState) { + return useMemo(() => initializeStore(initialState), [initialState]) +} -- cgit v1.2.3 From 24147cba0f5723be3525e8f40d1954144841629b Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Thu, 13 May 2021 13:00:00 +0200 Subject: ui: Address technical dept in frontend --- opendc-web/opendc-web-ui/src/store/hooks/map.js | 41 ++++++++++++++++++++++ .../opendc-web-ui/src/store/hooks/project.js | 32 +++++++++++++++++ .../opendc-web-ui/src/store/hooks/topology.js | 30 ++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 opendc-web/opendc-web-ui/src/store/hooks/map.js create mode 100644 opendc-web/opendc-web-ui/src/store/hooks/project.js create mode 100644 opendc-web/opendc-web-ui/src/store/hooks/topology.js (limited to 'opendc-web/opendc-web-ui/src/store') diff --git a/opendc-web/opendc-web-ui/src/store/hooks/map.js b/opendc-web/opendc-web-ui/src/store/hooks/map.js new file mode 100644 index 00000000..6aef6ac5 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/hooks/map.js @@ -0,0 +1,41 @@ +/* + * 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 { useSelector } from 'react-redux' + +/** + * Return the map scale. + */ +export function useMapScale() { + return useSelector((state) => state.map.scale) +} + +/** + * Return the map position. + */ +export function useMapPosition() { + return useSelector((state) => state.map.position) +} + +export function useMapDimensions() { + return useSelector((state) => state.map.dimensions) +} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/project.js b/opendc-web/opendc-web-ui/src/store/hooks/project.js new file mode 100644 index 00000000..0f2f1b66 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/hooks/project.js @@ -0,0 +1,32 @@ +/* + * 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 { useSelector } from 'react-redux' + +/** + * Return the current active project. + */ +export function useProject() { + return useSelector((state) => + state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined + ) +} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/topology.js b/opendc-web/opendc-web-ui/src/store/hooks/topology.js new file mode 100644 index 00000000..e5e14804 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/hooks/topology.js @@ -0,0 +1,30 @@ +/* + * 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 { useSelector } from 'react-redux' + +/** + * Return the current active topology. + */ +export function useTopology() { + return useSelector((state) => state.currentTopologyId !== '-1' && state.objects.topology[state.currentTopologyId]) +} -- cgit v1.2.3 From 1edbae1a0224e30bafb98638f419e1f967a9286f Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Thu, 13 May 2021 17:42:53 +0200 Subject: ui: Move modal state outside of Redux This change updates the frontend so that the modal state is not stored inside Redux but instead is stored using the useState hook. This simplifies the design of the modal components. --- .../opendc-web-ui/src/store/hooks/experiments.js | 37 +++++++++++++++++ .../opendc-web-ui/src/store/hooks/project.js | 48 +++++++++++++++++++++- .../opendc-web-ui/src/store/hooks/topology.js | 21 +++++++++- 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 opendc-web/opendc-web-ui/src/store/hooks/experiments.js (limited to 'opendc-web/opendc-web-ui/src/store') diff --git a/opendc-web/opendc-web-ui/src/store/hooks/experiments.js b/opendc-web/opendc-web-ui/src/store/hooks/experiments.js new file mode 100644 index 00000000..aef512e5 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/store/hooks/experiments.js @@ -0,0 +1,37 @@ +/* + * 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 { useSelector } from 'react-redux' + +/** + * Return the available traces to experiment with. + */ +export function useTraces() { + return useSelector((state) => Object.values(state.objects.trace)) +} + +/** + * Return the available schedulers to experiment with. + */ +export function useSchedulers() { + return useSelector((state) => Object.values(state.objects.scheduler)) +} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/project.js b/opendc-web/opendc-web-ui/src/store/hooks/project.js index 0f2f1b66..0db49fdd 100644 --- a/opendc-web/opendc-web-ui/src/store/hooks/project.js +++ b/opendc-web/opendc-web-ui/src/store/hooks/project.js @@ -25,8 +25,54 @@ import { useSelector } from 'react-redux' /** * Return the current active project. */ -export function useProject() { +export function useActiveProject() { return useSelector((state) => state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined ) } + +/** + * Return the active portfolio. + */ +export function useActivePortfolio() { + return useSelector((state) => state.objects.portfolio[state.currentPortfolioId]) +} + +/** + * Return the active scenario. + */ +export function useActiveScenario() { + return useSelector((state) => state.objects.scenario[state.currentScenarioId]) +} + +/** + * Return the portfolios for the specified project id. + */ +export function usePortfolios(projectId) { + return useSelector((state) => { + let portfolios = state.objects.project[projectId] + ? state.objects.project[projectId].portfolioIds.map((t) => state.objects.portfolio[t]) + : [] + if (portfolios.filter((t) => !t).length > 0) { + portfolios = [] + } + + return portfolios + }) +} + +/** + * Return the scenarios for the specified portfolio id. + */ +export function useScenarios(portfolioId) { + return 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 scenarios + }) +} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/topology.js b/opendc-web/opendc-web-ui/src/store/hooks/topology.js index e5e14804..d3ffb3e1 100644 --- a/opendc-web/opendc-web-ui/src/store/hooks/topology.js +++ b/opendc-web/opendc-web-ui/src/store/hooks/topology.js @@ -25,6 +25,25 @@ import { useSelector } from 'react-redux' /** * Return the current active topology. */ -export function useTopology() { +export function useActiveTopology() { return useSelector((state) => state.currentTopologyId !== '-1' && state.objects.topology[state.currentTopologyId]) } + +/** + * Return the topologies for the active project. + */ +export function useProjectTopologies() { + return useSelector(({ 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) { + return [] + } + + return topologies + }) +} -- cgit v1.2.3 From d9e65dceb38cdb8dc4e464d388755f9456620566 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Sun, 16 May 2021 17:07:58 +0200 Subject: ui: Restructure OpenDC frontend This change updates the structure of the OpenDC frontend in order to improve the maintainability of the frontend. --- .../opendc-web-ui/src/store/configure-store.js | 60 ----------------- .../opendc-web-ui/src/store/hooks/experiments.js | 37 ---------- opendc-web/opendc-web-ui/src/store/hooks/map.js | 41 ------------ .../opendc-web-ui/src/store/hooks/project.js | 78 ---------------------- .../opendc-web-ui/src/store/hooks/topology.js | 49 -------------- .../src/store/middlewares/viewport-adjustment.js | 73 -------------------- 6 files changed, 338 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/store/configure-store.js delete mode 100644 opendc-web/opendc-web-ui/src/store/hooks/experiments.js delete mode 100644 opendc-web/opendc-web-ui/src/store/hooks/map.js delete mode 100644 opendc-web/opendc-web-ui/src/store/hooks/project.js delete mode 100644 opendc-web/opendc-web-ui/src/store/hooks/topology.js delete mode 100644 opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js (limited to 'opendc-web/opendc-web-ui/src/store') diff --git a/opendc-web/opendc-web-ui/src/store/configure-store.js b/opendc-web/opendc-web-ui/src/store/configure-store.js deleted file mode 100644 index 149536a3..00000000 --- a/opendc-web/opendc-web-ui/src/store/configure-store.js +++ /dev/null @@ -1,60 +0,0 @@ -import { useMemo } from 'react' -import { applyMiddleware, compose, createStore } from 'redux' -import { createLogger } from 'redux-logger' -import persistState from 'redux-localstorage' -import createSagaMiddleware from 'redux-saga' -import thunk from 'redux-thunk' -import { authRedirectMiddleware } from '../auth/index' -import rootReducer from '../reducers/index' -import rootSaga from '../sagas/index' -import { viewportAdjustmentMiddleware } from './middlewares/viewport-adjustment' - -let store - -function initStore(initialState) { - const sagaMiddleware = createSagaMiddleware() - - const middlewares = [thunk, sagaMiddleware, authRedirectMiddleware, viewportAdjustmentMiddleware] - - if (process.env.NODE_ENV !== 'production') { - middlewares.push(createLogger()) - } - - let enhancer = applyMiddleware(...middlewares) - - if (global.localStorage) { - enhancer = compose(persistState('auth'), enhancer) - } - - const configuredStore = createStore(rootReducer, enhancer) - sagaMiddleware.run(rootSaga) - store = configuredStore - - return configuredStore -} - -export const initializeStore = (preloadedState) => { - let _store = store ?? initStore(preloadedState) - - // After navigating to a page with an initial Redux state, merge that state - // with the current state in the store, and create a new store - if (preloadedState && store) { - _store = initStore({ - ...store.getState(), - ...preloadedState, - }) - // Reset the current store - store = undefined - } - - // For SSG and SSR always create a new store - if (typeof window === 'undefined') return _store - // Create the store once in the client - if (!store) store = _store - - return _store -} - -export function useStore(initialState) { - return useMemo(() => initializeStore(initialState), [initialState]) -} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/experiments.js b/opendc-web/opendc-web-ui/src/store/hooks/experiments.js deleted file mode 100644 index aef512e5..00000000 --- a/opendc-web/opendc-web-ui/src/store/hooks/experiments.js +++ /dev/null @@ -1,37 +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 { useSelector } from 'react-redux' - -/** - * Return the available traces to experiment with. - */ -export function useTraces() { - return useSelector((state) => Object.values(state.objects.trace)) -} - -/** - * Return the available schedulers to experiment with. - */ -export function useSchedulers() { - return useSelector((state) => Object.values(state.objects.scheduler)) -} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/map.js b/opendc-web/opendc-web-ui/src/store/hooks/map.js deleted file mode 100644 index 6aef6ac5..00000000 --- a/opendc-web/opendc-web-ui/src/store/hooks/map.js +++ /dev/null @@ -1,41 +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 { useSelector } from 'react-redux' - -/** - * Return the map scale. - */ -export function useMapScale() { - return useSelector((state) => state.map.scale) -} - -/** - * Return the map position. - */ -export function useMapPosition() { - return useSelector((state) => state.map.position) -} - -export function useMapDimensions() { - return useSelector((state) => state.map.dimensions) -} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/project.js b/opendc-web/opendc-web-ui/src/store/hooks/project.js deleted file mode 100644 index 0db49fdd..00000000 --- a/opendc-web/opendc-web-ui/src/store/hooks/project.js +++ /dev/null @@ -1,78 +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 { useSelector } from 'react-redux' - -/** - * Return the current active project. - */ -export function useActiveProject() { - return useSelector((state) => - state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined - ) -} - -/** - * Return the active portfolio. - */ -export function useActivePortfolio() { - return useSelector((state) => state.objects.portfolio[state.currentPortfolioId]) -} - -/** - * Return the active scenario. - */ -export function useActiveScenario() { - return useSelector((state) => state.objects.scenario[state.currentScenarioId]) -} - -/** - * Return the portfolios for the specified project id. - */ -export function usePortfolios(projectId) { - return useSelector((state) => { - let portfolios = state.objects.project[projectId] - ? state.objects.project[projectId].portfolioIds.map((t) => state.objects.portfolio[t]) - : [] - if (portfolios.filter((t) => !t).length > 0) { - portfolios = [] - } - - return portfolios - }) -} - -/** - * Return the scenarios for the specified portfolio id. - */ -export function useScenarios(portfolioId) { - return 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 scenarios - }) -} diff --git a/opendc-web/opendc-web-ui/src/store/hooks/topology.js b/opendc-web/opendc-web-ui/src/store/hooks/topology.js deleted file mode 100644 index d3ffb3e1..00000000 --- a/opendc-web/opendc-web-ui/src/store/hooks/topology.js +++ /dev/null @@ -1,49 +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 { useSelector } from 'react-redux' - -/** - * Return the current active topology. - */ -export function useActiveTopology() { - return useSelector((state) => state.currentTopologyId !== '-1' && state.objects.topology[state.currentTopologyId]) -} - -/** - * Return the topologies for the active project. - */ -export function useProjectTopologies() { - return useSelector(({ 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) { - return [] - } - - return topologies - }) -} diff --git a/opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js b/opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js deleted file mode 100644 index b4472c54..00000000 --- a/opendc-web/opendc-web-ui/src/store/middlewares/viewport-adjustment.js +++ /dev/null @@ -1,73 +0,0 @@ -import { SET_MAP_DIMENSIONS, setMapPosition, setMapScale } from '../../actions/map' -import { SET_CURRENT_TOPOLOGY } from '../../actions/topology/building' -import { - MAP_MAX_SCALE, - MAP_MIN_SCALE, - SIDEBAR_WIDTH, - TILE_SIZE_IN_PIXELS, - VIEWPORT_PADDING, -} from '../../components/app/map/MapConstants' -import { calculateRoomListBounds } from '../../util/tile-calculations' - -export const viewportAdjustmentMiddleware = (store) => (next) => (action) => { - const state = store.getState() - - let topologyId = '-1' - let mapDimensions = {} - if (action.type === SET_CURRENT_TOPOLOGY && action.topologyId !== '-1') { - topologyId = action.topologyId - mapDimensions = state.map.dimensions - } else if (action.type === SET_MAP_DIMENSIONS && state.currentTopologyId !== '-1') { - topologyId = state.currentTopologyId - mapDimensions = { width: action.width, height: action.height } - } - - if (topologyId !== '-1') { - const roomIds = state.objects.topology[topologyId].roomIds - const rooms = roomIds.map((id) => Object.assign({}, state.objects.room[id])) - rooms.forEach((room) => (room.tiles = room.tileIds.map((tileId) => state.objects.tile[tileId]))) - - let hasNoTiles = true - for (let i in rooms) { - if (rooms[i].tiles.length > 0) { - hasNoTiles = false - break - } - } - - if (!hasNoTiles) { - const viewportParams = calculateParametersToZoomInOnRooms(rooms, mapDimensions.width, mapDimensions.height) - store.dispatch(setMapPosition(viewportParams.newX, viewportParams.newY)) - store.dispatch(setMapScale(viewportParams.newScale)) - } - } - - next(action) -} - -function calculateParametersToZoomInOnRooms(rooms, mapWidth, mapHeight) { - const bounds = calculateRoomListBounds(rooms) - const newScale = calculateNewScale(bounds, mapWidth, mapHeight) - - // Coordinates of the center of the room, relative to the global origin of the map - const roomCenterCoordinates = { - x: bounds.center.x * TILE_SIZE_IN_PIXELS * newScale, - y: bounds.center.y * TILE_SIZE_IN_PIXELS * newScale, - } - - const newX = -roomCenterCoordinates.x + mapWidth / 2 - const newY = -roomCenterCoordinates.y + mapHeight / 2 - - return { newScale, newX, newY } -} - -function calculateNewScale(bounds, mapWidth, mapHeight) { - const width = bounds.max.x - bounds.min.x - const height = bounds.max.y - bounds.min.y - - const scaleX = (mapWidth - 2 * SIDEBAR_WIDTH) / (width * TILE_SIZE_IN_PIXELS + 2 * VIEWPORT_PADDING) - const scaleY = mapHeight / (height * TILE_SIZE_IN_PIXELS + 2 * VIEWPORT_PADDING) - const newScale = Math.min(scaleX, scaleY) - - return Math.min(Math.max(MAP_MIN_SCALE, newScale), MAP_MAX_SCALE) -} -- cgit v1.2.3