From aa788a3ad18badfac8beaabdaffc88b9e52f9306 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 7 Jul 2021 15:07:11 +0200 Subject: ui: Remove current ids state from Redux This change removes the current active identifiers from the Redux state. Instead, we use the router query to track the active project, portfolio and topology. --- .../opendc-web-ui/src/redux/sagas/portfolios.js | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js') diff --git a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js index 340cb490..48d1ad3e 100644 --- a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js +++ b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js @@ -12,35 +12,37 @@ export function* onOpenPortfolioSucceeded(action) { const project = yield call(getProject, auth, action.projectId) yield put(addToStore('project', project)) yield fetchAndStoreAllTopologiesOfProject(project._id) - yield fetchPortfoliosOfProject() + yield fetchPortfoliosOfProject(project) yield fetchAndStoreAllSchedulers() yield fetchAndStoreAllTraces() - yield watchForPortfolioResults() + yield watchForPortfolioResults(action.portfolioId) } catch (error) { console.error(error) } } -export function* watchForPortfolioResults() { +export function* watchForPortfolioResults(portfolioId) { try { - const currentPortfolioId = yield select((state) => state.currentPortfolioId) - let unfinishedScenarios = yield getCurrentUnfinishedScenarios() + let unfinishedScenarios = yield getCurrentUnfinishedScenarios(portfolioId) while (unfinishedScenarios.length > 0) { yield delay(3000) - yield fetchPortfolioWithScenarios(currentPortfolioId) - unfinishedScenarios = yield getCurrentUnfinishedScenarios() + yield fetchPortfolioWithScenarios(portfolioId) + unfinishedScenarios = yield getCurrentUnfinishedScenarios(portfolioId) } } catch (error) { console.error(error) } } -export function* getCurrentUnfinishedScenarios() { +export function* getCurrentUnfinishedScenarios(portfolioId) { try { - const currentPortfolioId = yield select((state) => state.currentPortfolioId) - const scenarioIds = yield select((state) => state.objects.portfolio[currentPortfolioId].scenarioIds) + if (!portfolioId) { + return [] + } + + const scenarioIds = yield select((state) => state.objects.portfolio[portfolioId].scenarioIds) const scenarioObjects = yield select((state) => state.objects.scenario) const scenarios = scenarioIds.map((s) => scenarioObjects[s]) return scenarios.filter((s) => !s || s.simulation.state === 'QUEUED' || s.simulation.state === 'RUNNING') @@ -49,16 +51,13 @@ export function* getCurrentUnfinishedScenarios() { } } -export function* fetchPortfoliosOfProject() { +export function* fetchPortfoliosOfProject(project) { try { - const currentProjectId = yield select((state) => state.currentProjectId) - const currentProject = yield select((state) => state.objects.project[currentProjectId]) - yield fetchAndStoreAllSchedulers() yield fetchAndStoreAllTraces() - for (let i in currentProject.portfolioIds) { - yield fetchPortfolioWithScenarios(currentProject.portfolioIds[i]) + for (const i in project.portfolioIds) { + yield fetchPortfolioWithScenarios(project.portfolioIds[i]) } } catch (error) { console.error(error) @@ -83,22 +82,22 @@ export function* fetchPortfolioWithScenarios(portfolioId) { export function* onAddPortfolio(action) { try { - const currentProjectId = yield select((state) => state.currentProjectId) + const { projectId } = action const auth = yield getContext('auth') const portfolio = yield call( addPortfolio, auth, - currentProjectId, + projectId, Object.assign({}, action.portfolio, { - projectId: currentProjectId, + projectId: projectId, scenarioIds: [], }) ) yield put(addToStore('portfolio', portfolio)) - const portfolioIds = yield select((state) => state.objects.project[currentProjectId].portfolioIds) + const portfolioIds = yield select((state) => state.objects.project[projectId].portfolioIds) yield put( - addPropToStoreObject('project', currentProjectId, { + addPropToStoreObject('project', projectId, { portfolioIds: portfolioIds.concat([portfolio._id]), }) ) @@ -120,13 +119,14 @@ export function* onUpdatePortfolio(action) { export function* onDeletePortfolio(action) { try { const auth = yield getContext('auth') + const portfolio = yield select((state) => state.objects.portfolio[action.id]) + yield call(deletePortfolio, auth, action.id) - const currentProjectId = yield select((state) => state.currentProjectId) - const portfolioIds = yield select((state) => state.objects.project[currentProjectId].portfolioIds) + const portfolioIds = yield select((state) => state.objects.project[portfolio.projectId].portfolioIds) yield put( - addPropToStoreObject('project', currentProjectId, { + addPropToStoreObject('project', portfolio.projectId, { portfolioIds: portfolioIds.filter((id) => id !== action.id), }) ) -- 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. --- .../opendc-web-ui/src/redux/sagas/portfolios.js | 29 ++++++---------------- 1 file changed, 7 insertions(+), 22 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js') diff --git a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js index 48d1ad3e..c32fcdc0 100644 --- a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js +++ b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js @@ -1,7 +1,7 @@ import { call, put, select, delay, getContext } from 'redux-saga/effects' -import { addPropToStoreObject, addToStore } from '../actions/objects' +import { addToStore } from '../actions/objects' import { addPortfolio, deletePortfolio, getPortfolio, updatePortfolio } from '../../api/portfolios' -import { getProject } from '../../api/projects' +import { fetchProject } from '../../api/projects' import { fetchAndStoreAllSchedulers, fetchAndStoreAllTraces } from './objects' import { fetchAndStoreAllTopologiesOfProject } from './topology' import { getScenario } from '../../api/scenarios' @@ -9,9 +9,11 @@ import { getScenario } from '../../api/scenarios' export function* onOpenPortfolioSucceeded(action) { try { const auth = yield getContext('auth') - const project = yield call(getProject, auth, action.projectId) - yield put(addToStore('project', project)) - yield fetchAndStoreAllTopologiesOfProject(project._id) + const queryClient = yield getContext('queryClient') + const project = yield call(() => + queryClient.fetchQuery(`projects/${action.projectId}`, () => fetchProject(auth, action.projectId)) + ) + yield fetchAndStoreAllTopologiesOfProject(action.projectId) yield fetchPortfoliosOfProject(project) yield fetchAndStoreAllSchedulers() yield fetchAndStoreAllTraces() @@ -94,13 +96,6 @@ export function* onAddPortfolio(action) { }) ) yield put(addToStore('portfolio', portfolio)) - - const portfolioIds = yield select((state) => state.objects.project[projectId].portfolioIds) - yield put( - addPropToStoreObject('project', projectId, { - portfolioIds: portfolioIds.concat([portfolio._id]), - }) - ) } catch (error) { console.error(error) } @@ -119,17 +114,7 @@ export function* onUpdatePortfolio(action) { export function* onDeletePortfolio(action) { try { const auth = yield getContext('auth') - const portfolio = yield select((state) => state.objects.portfolio[action.id]) - yield call(deletePortfolio, auth, action.id) - - const portfolioIds = yield select((state) => state.objects.project[portfolio.projectId].portfolioIds) - - yield put( - addPropToStoreObject('project', portfolio.projectId, { - portfolioIds: portfolioIds.filter((id) => id !== action.id), - }) - ) } catch (error) { console.error(error) } -- cgit v1.2.3 From d28a2f194a75eb86095485ae4f88be349bcc18b6 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 7 Jul 2021 16:36:54 +0200 Subject: ui: Fetch schedulers and traces using React Query This change updates the OpenDC frontend to fetch schedulers and traces using React Query, removing its dependency on Redux. --- opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js | 7 ------- 1 file changed, 7 deletions(-) (limited to 'opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js') diff --git a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js index c32fcdc0..68956225 100644 --- a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js +++ b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js @@ -2,8 +2,6 @@ import { call, put, select, delay, getContext } from 'redux-saga/effects' import { addToStore } from '../actions/objects' import { addPortfolio, deletePortfolio, getPortfolio, updatePortfolio } from '../../api/portfolios' import { fetchProject } from '../../api/projects' -import { fetchAndStoreAllSchedulers, fetchAndStoreAllTraces } from './objects' -import { fetchAndStoreAllTopologiesOfProject } from './topology' import { getScenario } from '../../api/scenarios' export function* onOpenPortfolioSucceeded(action) { @@ -15,8 +13,6 @@ export function* onOpenPortfolioSucceeded(action) { ) yield fetchAndStoreAllTopologiesOfProject(action.projectId) yield fetchPortfoliosOfProject(project) - yield fetchAndStoreAllSchedulers() - yield fetchAndStoreAllTraces() yield watchForPortfolioResults(action.portfolioId) } catch (error) { @@ -55,9 +51,6 @@ export function* getCurrentUnfinishedScenarios(portfolioId) { export function* fetchPortfoliosOfProject(project) { try { - yield fetchAndStoreAllSchedulers() - yield fetchAndStoreAllTraces() - for (const i in project.portfolioIds) { yield fetchPortfolioWithScenarios(project.portfolioIds[i]) } -- 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 --- .../opendc-web-ui/src/redux/sagas/portfolios.js | 114 --------------------- 1 file changed, 114 deletions(-) delete mode 100644 opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js (limited to 'opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js') diff --git a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js b/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js deleted file mode 100644 index 68956225..00000000 --- a/opendc-web/opendc-web-ui/src/redux/sagas/portfolios.js +++ /dev/null @@ -1,114 +0,0 @@ -import { call, put, select, delay, getContext } from 'redux-saga/effects' -import { addToStore } from '../actions/objects' -import { addPortfolio, deletePortfolio, getPortfolio, updatePortfolio } from '../../api/portfolios' -import { fetchProject } from '../../api/projects' -import { getScenario } from '../../api/scenarios' - -export function* onOpenPortfolioSucceeded(action) { - try { - const auth = yield getContext('auth') - const queryClient = yield getContext('queryClient') - const project = yield call(() => - queryClient.fetchQuery(`projects/${action.projectId}`, () => fetchProject(auth, action.projectId)) - ) - yield fetchAndStoreAllTopologiesOfProject(action.projectId) - yield fetchPortfoliosOfProject(project) - - yield watchForPortfolioResults(action.portfolioId) - } catch (error) { - console.error(error) - } -} - -export function* watchForPortfolioResults(portfolioId) { - try { - let unfinishedScenarios = yield getCurrentUnfinishedScenarios(portfolioId) - - while (unfinishedScenarios.length > 0) { - yield delay(3000) - yield fetchPortfolioWithScenarios(portfolioId) - unfinishedScenarios = yield getCurrentUnfinishedScenarios(portfolioId) - } - } catch (error) { - console.error(error) - } -} - -export function* getCurrentUnfinishedScenarios(portfolioId) { - try { - if (!portfolioId) { - return [] - } - - const scenarioIds = yield select((state) => state.objects.portfolio[portfolioId].scenarioIds) - const scenarioObjects = yield select((state) => state.objects.scenario) - const scenarios = scenarioIds.map((s) => scenarioObjects[s]) - return scenarios.filter((s) => !s || s.simulation.state === 'QUEUED' || s.simulation.state === 'RUNNING') - } catch (error) { - console.error(error) - } -} - -export function* fetchPortfoliosOfProject(project) { - try { - for (const i in project.portfolioIds) { - yield fetchPortfolioWithScenarios(project.portfolioIds[i]) - } - } catch (error) { - console.error(error) - } -} - -export function* fetchPortfolioWithScenarios(portfolioId) { - try { - const auth = yield getContext('auth') - const portfolio = yield call(getPortfolio, auth, portfolioId) - yield put(addToStore('portfolio', portfolio)) - - for (let i in portfolio.scenarioIds) { - const scenario = yield call(getScenario, auth, portfolio.scenarioIds[i]) - yield put(addToStore('scenario', scenario)) - } - return portfolio - } catch (error) { - console.error(error) - } -} - -export function* onAddPortfolio(action) { - try { - const { projectId } = action - const auth = yield getContext('auth') - const portfolio = yield call( - addPortfolio, - auth, - projectId, - Object.assign({}, action.portfolio, { - projectId: projectId, - scenarioIds: [], - }) - ) - yield put(addToStore('portfolio', portfolio)) - } catch (error) { - console.error(error) - } -} - -export function* onUpdatePortfolio(action) { - try { - const auth = yield getContext('auth') - const portfolio = yield call(updatePortfolio, auth, action.portfolio._id, action.portfolio) - yield put(addToStore('portfolio', portfolio)) - } catch (error) { - console.error(error) - } -} - -export function* onDeletePortfolio(action) { - try { - const auth = yield getContext('auth') - yield call(deletePortfolio, auth, action.id) - } catch (error) { - console.error(error) - } -} -- cgit v1.2.3