summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/components/portfolios
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-03-07 18:19:21 +0100
committerFabian Mastenbroek <mail.fabianm@gmail.com>2022-04-04 12:48:05 +0200
commit3d1c02e50ee619598bcd7fad4368be8b4a039e84 (patch)
tree89baaf3250eb0495295616a9945c681f5e1ccdb8 /opendc-web/opendc-web-ui/src/components/portfolios
parentd12efc754a1611a624d170b4d1fa6085e6bb177b (diff)
refactor(web/ui): Fix compatibility with new API
This change updates the web interface in React to be compatible with the new API written in Kotlin. Several changes have been made in the new API to ensure consistency.
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/portfolios')
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js20
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js48
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js23
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js19
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js6
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js31
6 files changed, 69 insertions, 78 deletions
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js b/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js
index 856282a7..fd9a72d2 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js
@@ -24,21 +24,15 @@ import PropTypes from 'prop-types'
import { PlusIcon } from '@patternfly/react-icons'
import { Button } from '@patternfly/react-core'
import { useState } from 'react'
-import { useMutation } from 'react-query'
+import { useNewScenario } from '../../data/project'
import NewScenarioModal from './NewScenarioModal'
-function NewScenario({ portfolioId }) {
+function NewScenario({ projectId, portfolioId }) {
const [isVisible, setVisible] = useState(false)
- const { mutate: addScenario } = useMutation('addScenario')
+ const { mutate: addScenario } = useNewScenario()
- const onSubmit = (name, portfolioId, trace, topology, operational) => {
- addScenario({
- portfolioId,
- name,
- trace,
- topology,
- operational,
- })
+ const onSubmit = (projectId, portfolioNumber, data) => {
+ addScenario({ projectId, portfolioNumber, data })
setVisible(false)
}
@@ -48,6 +42,7 @@ function NewScenario({ portfolioId }) {
New Scenario
</Button>
<NewScenarioModal
+ projectId={projectId}
portfolioId={portfolioId}
isOpen={isVisible}
onSubmit={onSubmit}
@@ -58,7 +53,8 @@ function NewScenario({ portfolioId }) {
}
NewScenario.propTypes = {
- portfolioId: PropTypes.string,
+ projectId: PropTypes.number,
+ portfolioId: PropTypes.number,
}
export default NewScenario
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js b/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js
index 7f620c8c..ed35c163 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js
@@ -12,14 +12,14 @@ import {
TextInput,
} from '@patternfly/react-core'
import { useSchedulers, useTraces } from '../../data/experiments'
-import { useProjectTopologies } from '../../data/topology'
+import { useTopologies } from '../../data/topology'
import { usePortfolio } from '../../data/project'
-const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onCancel: onCancelUpstream }) => {
- const { data: portfolio } = usePortfolio(portfolioId)
- const { data: topologies = [] } = useProjectTopologies(portfolio?.projectId)
- const { data: traces = [] } = useTraces()
- const { data: schedulers = [] } = useSchedulers()
+function NewScenarioModal({ projectId, portfolioId, isOpen, onSubmit: onSubmitUpstream, onCancel: onCancelUpstream }) {
+ const { data: portfolio } = usePortfolio(projectId, portfolioId)
+ const { data: topologies = [] } = useTopologies(projectId, { enabled: isOpen })
+ const { data: traces = [] } = useTraces({ enabled: isOpen })
+ const { data: schedulers = [] } = useSchedulers({ enabled: isOpen })
// eslint-disable-next-line no-unused-vars
const [isSubmitted, setSubmitted] = useState(false)
@@ -51,22 +51,19 @@ const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onC
const name = nameInput.current.value
- onSubmitUpstream(
+ onSubmitUpstream(portfolio.project.id, portfolio.number, {
name,
- portfolio._id,
- {
- traceId: trace || traces[0]._id,
- loadSamplingFraction: traceLoad / 100,
+ workload: {
+ trace: trace || traces[0].id,
+ samplingFraction: traceLoad / 100,
},
- {
- topologyId: topology || topologies[0]._id,
+ topology: topology || topologies[0].number,
+ phenomena: {
+ failures: failuresEnabled,
+ interference: opPhenEnabled,
},
- {
- failuresEnabled,
- performanceInterferenceEnabled: opPhenEnabled,
- schedulerName: scheduler || schedulers[0].name,
- }
- )
+ schedulerName: scheduler || schedulers[0],
+ })
resetState()
return true
@@ -84,8 +81,8 @@ const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onC
id="name"
name="name"
type="text"
- isDisabled={portfolio?.scenarioIds?.length === 0}
- defaultValue={portfolio?.scenarioIds?.length === 0 ? 'Base scenario' : ''}
+ isDisabled={portfolio?.scenarios?.length === 0}
+ defaultValue={portfolio?.scenarios?.length === 0 ? 'Base scenario' : ''}
ref={nameInput}
/>
</FormGroup>
@@ -93,7 +90,7 @@ const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onC
<FormGroup label="Trace" fieldId="trace" isRequired>
<FormSelect id="trace" name="trace" value={trace} onChange={setTrace}>
{traces.map((trace) => (
- <FormSelectOption value={trace._id} key={trace._id} label={trace.name} />
+ <FormSelectOption value={trace.id} key={trace.id} label={trace.name} />
))}
</FormSelect>
</FormGroup>
@@ -115,7 +112,7 @@ const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onC
<FormGroup label="Topology" fieldId="topology" isRequired>
<FormSelect id="topology" name="topology" value={topology} onChange={setTopology}>
{topologies.map((topology) => (
- <FormSelectOption value={topology._id} key={topology._id} label={topology.name} />
+ <FormSelectOption value={topology.number} key={topology.number} label={topology.name} />
))}
</FormSelect>
</FormGroup>
@@ -123,7 +120,7 @@ const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onC
<FormGroup label="Scheduler" fieldId="scheduler" isRequired>
<FormSelect id="scheduler" name="scheduler" value={scheduler} onChange={setScheduler}>
{schedulers.map((scheduler) => (
- <FormSelectOption value={scheduler.name} key={scheduler.name} label={scheduler.name} />
+ <FormSelectOption value={scheduler} key={scheduler} label={scheduler} />
))}
</FormSelect>
</FormGroup>
@@ -150,7 +147,8 @@ const NewScenarioModal = ({ portfolioId, isOpen, onSubmit: onSubmitUpstream, onC
}
NewScenarioModal.propTypes = {
- portfolioId: PropTypes.string,
+ projectId: PropTypes.number,
+ portfolioId: PropTypes.number,
isOpen: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js
index 580b0a29..e561b655 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js
@@ -43,8 +43,8 @@ import { METRIC_NAMES } from '../../util/available-metrics'
import NewScenario from './NewScenario'
import ScenarioTable from './ScenarioTable'
-function PortfolioOverview({ portfolioId }) {
- const { data: portfolio } = usePortfolio(portfolioId)
+function PortfolioOverview({ projectId, portfolioId }) {
+ const { status, data: portfolio } = usePortfolio(projectId, portfolioId)
return (
<Grid hasGutter>
@@ -62,16 +62,16 @@ function PortfolioOverview({ portfolioId }) {
<DescriptionListGroup>
<DescriptionListTerm>Scenarios</DescriptionListTerm>
<DescriptionListDescription>
- {portfolio?.scenarioIds.length ?? <Skeleton screenreaderText="Loading portfolio" />}
+ {portfolio?.scenarios?.length ?? <Skeleton screenreaderText="Loading portfolio" />}
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>Metrics</DescriptionListTerm>
<DescriptionListDescription>
- {portfolio?.targets?.enabledMetrics ? (
- portfolio.targets.enabledMetrics.length > 0 ? (
+ {portfolio ? (
+ portfolio.targets.metrics.length > 0 ? (
<ChipGroup>
- {portfolio.targets.enabledMetrics.map((metric) => (
+ {portfolio.targets.metrics.map((metric) => (
<Chip isReadOnly key={metric}>
{METRIC_NAMES[metric]}
</Chip>
@@ -88,9 +88,7 @@ function PortfolioOverview({ portfolioId }) {
<DescriptionListGroup>
<DescriptionListTerm>Repeats per Scenario</DescriptionListTerm>
<DescriptionListDescription>
- {portfolio?.targets?.repeatsPerScenario ?? (
- <Skeleton screenreaderText="Loading portfolio" />
- )}
+ {portfolio?.targets?.repeats ?? <Skeleton screenreaderText="Loading portfolio" />}
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
@@ -101,12 +99,12 @@ function PortfolioOverview({ portfolioId }) {
<Card>
<CardHeader>
<CardActions>
- <NewScenario portfolioId={portfolioId} />
+ <NewScenario projectId={projectId} portfolioId={portfolioId} />
</CardActions>
<CardTitle>Scenarios</CardTitle>
</CardHeader>
<CardBody>
- <ScenarioTable portfolioId={portfolioId} />
+ <ScenarioTable portfolio={portfolio} status={status} />
</CardBody>
</Card>
</GridItem>
@@ -115,7 +113,8 @@ function PortfolioOverview({ portfolioId }) {
}
PortfolioOverview.propTypes = {
- portfolioId: PropTypes.string,
+ projectId: PropTypes.number,
+ portfolioId: PropTypes.number,
}
export default PortfolioOverview
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js
index 00023d9e..f63f0c7f 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js
@@ -42,12 +42,14 @@ import {
Title,
} from '@patternfly/react-core'
import { ErrorCircleOIcon, CubesIcon } from '@patternfly/react-icons'
-import { usePortfolioScenarios } from '../../data/project'
+import { usePortfolio } from '../../data/project'
import PortfolioResultInfo from './PortfolioResultInfo'
import NewScenario from './NewScenario'
-const PortfolioResults = ({ portfolioId }) => {
- const { status, data: scenarios = [] } = usePortfolioScenarios(portfolioId)
+const PortfolioResults = ({ projectId, portfolioId }) => {
+ const { status, data: scenarios = [] } = usePortfolio(projectId, portfolioId, {
+ select: (portfolio) => portfolio.scenarios,
+ })
if (status === 'loading') {
return (
@@ -86,7 +88,7 @@ const PortfolioResults = ({ portfolioId }) => {
No results are currently available for this portfolio. Run a scenario to obtain simulation
results.
</EmptyStateBody>
- <NewScenario portfolioId={portfolioId} />
+ <NewScenario projectId={projectId} portfolioId={portfolioId} />
</EmptyState>
</Bullseye>
)
@@ -96,11 +98,11 @@ const PortfolioResults = ({ portfolioId }) => {
AVAILABLE_METRICS.forEach((metric) => {
dataPerMetric[metric] = scenarios
- .filter((scenario) => scenario.results)
+ .filter((scenario) => scenario.job?.results)
.map((scenario) => ({
name: scenario.name,
- value: mean(scenario.results[metric]),
- errorX: std(scenario.results[metric]),
+ value: mean(scenario.job.results[metric]),
+ errorX: std(scenario.job.results[metric]),
}))
})
@@ -150,7 +152,8 @@ const PortfolioResults = ({ portfolioId }) => {
}
PortfolioResults.propTypes = {
- portfolioId: PropTypes.string,
+ projectId: PropTypes.number,
+ portfolioId: PropTypes.number,
}
export default PortfolioResults
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js
index 66691580..99d83f64 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js
@@ -20,13 +20,13 @@
* SOFTWARE.
*/
-import PropTypes from 'prop-types'
import { ClockIcon, CheckCircleIcon, ErrorCircleOIcon } from '@patternfly/react-icons'
+import { JobState } from '../../shapes'
function ScenarioState({ state }) {
switch (state) {
+ case 'PENDING':
case 'CLAIMED':
- case 'QUEUED':
return (
<span>
<ClockIcon color="blue" /> Queued
@@ -56,7 +56,7 @@ function ScenarioState({ state }) {
}
ScenarioState.propTypes = {
- state: PropTypes.oneOf(['QUEUED', 'CLAIMED', 'RUNNING', 'FINISHED', 'FAILED']),
+ state: JobState.isRequired,
}
export default ScenarioState
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
index 9966e3ba..68647957 100644
--- a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
+++ b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
@@ -20,44 +20,38 @@
* SOFTWARE.
*/
-import PropTypes from 'prop-types'
import Link from 'next/link'
import { Table, TableBody, TableHeader } from '@patternfly/react-table'
import React from 'react'
+import { Portfolio, Status } from '../../shapes'
import TableEmptyState from '../util/TableEmptyState'
import ScenarioState from './ScenarioState'
-import { usePortfolio, usePortfolioScenarios } from '../../data/project'
-import { useProjectTopologies } from '../../data/topology'
-import { useMutation } from 'react-query'
+import { useDeleteScenario } from '../../data/project'
-const ScenarioTable = ({ portfolioId }) => {
- const { data: portfolio } = usePortfolio(portfolioId)
- const { status, data: scenarios = [] } = usePortfolioScenarios(portfolioId)
- const { data: topologies } = useProjectTopologies(portfolio?.projectId, {
- select: (topologies) => new Map(topologies.map((topology) => [topology._id, topology])),
- })
-
- const { mutate: deleteScenario } = useMutation('deleteScenario')
+function ScenarioTable({ portfolio, status }) {
+ const { mutate: deleteScenario } = useDeleteScenario()
+ const projectId = portfolio?.project?.id
+ const scenarios = portfolio?.scenarios ?? []
const columns = ['Name', 'Topology', 'Trace', 'State']
const rows =
scenarios.length > 0
? scenarios.map((scenario) => {
- const topology = topologies?.get(scenario.topology.topologyId)
+ const topology = scenario.topology
return [
scenario.name,
{
title: topology ? (
- <Link href={`/projects/${topology.projectId}/topologies/${topology._id}`}>
+ <Link href={`/projects/${projectId}/topologies/${topology.number}`}>
<a>{topology.name}</a>
</Link>
) : (
'Unknown Topology'
),
},
- scenario.trace.traceId,
- { title: <ScenarioState state={scenario.simulation.state} /> },
+ `${scenario.workload.trace.name} (${scenario.workload.samplingFraction * 100}%)`,
+ { title: <ScenarioState state={scenario.job.state} /> },
]
})
: [
@@ -82,7 +76,7 @@ const ScenarioTable = ({ portfolioId }) => {
const actionResolver = (_, { rowIndex }) => [
{
title: 'Delete Scenario',
- onClick: (_, rowId) => deleteScenario(scenarios[rowId]._id),
+ onClick: (_, rowId) => deleteScenario({ projectId: projectId, number: scenarios[rowId].number }),
isDisabled: rowIndex === 0,
},
]
@@ -102,7 +96,8 @@ const ScenarioTable = ({ portfolioId }) => {
}
ScenarioTable.propTypes = {
- portfolioId: PropTypes.string,
+ portfolio: Portfolio,
+ status: Status.isRequired,
}
export default ScenarioTable