summaryrefslogtreecommitdiff
path: root/opendc-web/opendc-web-ui/src/components/modals/custom-components
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web/opendc-web-ui/src/components/modals/custom-components')
-rw-r--r--opendc-web/opendc-web-ui/src/components/modals/custom-components/NewPortfolioModalComponent.js78
-rw-r--r--opendc-web/opendc-web-ui/src/components/modals/custom-components/NewScenarioModalComponent.js144
-rw-r--r--opendc-web/opendc-web-ui/src/components/modals/custom-components/NewTopologyModalComponent.js71
3 files changed, 293 insertions, 0 deletions
diff --git a/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewPortfolioModalComponent.js b/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewPortfolioModalComponent.js
new file mode 100644
index 00000000..3c6b8724
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewPortfolioModalComponent.js
@@ -0,0 +1,78 @@
+import PropTypes from 'prop-types'
+import React, { useRef } from 'react'
+import { Form, FormGroup, Input, Label } from 'reactstrap'
+import Modal from '../Modal'
+import { AVAILABLE_METRICS, METRIC_NAMES } from '../../../util/available-metrics'
+
+const NewPortfolioModalComponent = ({ show, callback }) => {
+ const form = useRef(null)
+ const textInput = useRef(null)
+ const repeatsInput = useRef(null)
+ const metricCheckboxes = useRef({})
+
+ const onSubmit = () => {
+ if (form.current.reportValidity()) {
+ callback(textInput.current.value, {
+ enabledMetrics: AVAILABLE_METRICS.filter((metric) => metricCheckboxes.current[metric].checked),
+ repeatsPerScenario: parseInt(repeatsInput.current.value),
+ })
+
+ return true
+ } else {
+ return false
+ }
+ }
+ const onCancel = () => callback(undefined)
+
+ return (
+ <Modal title="New Portfolio" show={show} onSubmit={onSubmit} onCancel={onCancel}>
+ <Form
+ onSubmit={(e) => {
+ e.preventDefault()
+ this.onSubmit()
+ }}
+ innerRef={form}
+ >
+ <FormGroup>
+ <Label for="name">Name</Label>
+ <Input name="name" type="text" required innerRef={textInput} placeholder="My Portfolio" />
+ </FormGroup>
+ <h4>Targets</h4>
+ <h5>Metrics</h5>
+ <FormGroup>
+ {AVAILABLE_METRICS.map((metric) => (
+ <FormGroup check key={metric}>
+ <Label for={metric} check>
+ <Input
+ name={metric}
+ type="checkbox"
+ innerRef={(ref) => (metricCheckboxes.current[metric] = ref)}
+ />
+ {METRIC_NAMES[metric]}
+ </Label>
+ </FormGroup>
+ ))}
+ </FormGroup>
+ <FormGroup>
+ <Label for="repeats">Repeats per scenario</Label>
+ <Input
+ name="repeats"
+ type="number"
+ required
+ innerRef={repeatsInput}
+ defaultValue="1"
+ min="1"
+ step="1"
+ />
+ </FormGroup>
+ </Form>
+ </Modal>
+ )
+}
+
+NewPortfolioModalComponent.propTypes = {
+ show: PropTypes.bool.isRequired,
+ callback: PropTypes.func.isRequired,
+}
+
+export default NewPortfolioModalComponent
diff --git a/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewScenarioModalComponent.js b/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewScenarioModalComponent.js
new file mode 100644
index 00000000..01a5719c
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewScenarioModalComponent.js
@@ -0,0 +1,144 @@
+import PropTypes from 'prop-types'
+import React, { useRef } from 'react'
+import { Form, FormGroup, Input, Label } from 'reactstrap'
+import Shapes from '../../../shapes'
+import Modal from '../Modal'
+
+const NewScenarioModalComponent = ({
+ show,
+ callback,
+ currentPortfolioId,
+ currentPortfolioScenarioIds,
+ traces,
+ topologies,
+ schedulers,
+}) => {
+ const form = useRef(null)
+ const textInput = useRef(null)
+ const traceSelect = useRef(null)
+ const traceLoadInput = useRef(null)
+ const topologySelect = useRef(null)
+ const failuresCheckbox = useRef(null)
+ const performanceInterferenceCheckbox = useRef(null)
+ const schedulerSelect = useRef(null)
+
+ const onSubmit = () => {
+ if (!form.current.reportValidity()) {
+ return false
+ }
+ callback(
+ textInput.current.value,
+ currentPortfolioId,
+ {
+ traceId: traceSelect.current.value,
+ loadSamplingFraction: parseFloat(traceLoadInput.current.value),
+ },
+ {
+ topologyId: topologySelect.current.value,
+ },
+ {
+ failuresEnabled: failuresCheckbox.current.checked,
+ performanceInterferenceEnabled: performanceInterferenceCheckbox.current.checked,
+ schedulerName: schedulerSelect.current.value,
+ }
+ )
+ return true
+ }
+ const onCancel = () => {
+ callback(undefined)
+ }
+
+ return (
+ <Modal title="New Scenario" show={show} onSubmit={onSubmit} onCancel={onCancel}>
+ <Form
+ onSubmit={(e) => {
+ e.preventDefault()
+ onSubmit()
+ }}
+ innerRef={form}
+ >
+ <FormGroup>
+ <Label for="name">Name</Label>
+ <Input
+ name="name"
+ type="text"
+ required
+ disabled={currentPortfolioScenarioIds.length === 0}
+ defaultValue={currentPortfolioScenarioIds.length === 0 ? 'Base scenario' : ''}
+ innerRef={textInput}
+ />
+ </FormGroup>
+ <h4>Trace</h4>
+ <FormGroup>
+ <Label for="trace">Trace</Label>
+ <Input name="trace" type="select" innerRef={traceSelect}>
+ {traces.map((trace) => (
+ <option value={trace._id} key={trace._id}>
+ {trace.name}
+ </option>
+ ))}
+ </Input>
+ </FormGroup>
+ <FormGroup>
+ <Label for="trace-load">Load sampling fraction</Label>
+ <Input
+ name="trace-load"
+ type="number"
+ innerRef={traceLoadInput}
+ required
+ defaultValue="1"
+ min="0"
+ max="1"
+ step="0.1"
+ />
+ </FormGroup>
+ <h4>Topology</h4>
+ <div className="form-group">
+ <Label for="topology">Topology</Label>
+ <Input name="topology" type="select" innerRef={topologySelect}>
+ {topologies.map((topology) => (
+ <option value={topology._id} key={topology._id}>
+ {topology.name}
+ </option>
+ ))}
+ </Input>
+ </div>
+ <h4>Operational Phenomena</h4>
+ <FormGroup check>
+ <Label check for="failures">
+ <Input type="checkbox" name="failures" innerRef={failuresCheckbox} />{' '}
+ <span className="ml-2">Enable failures</span>
+ </Label>
+ </FormGroup>
+ <FormGroup check>
+ <Label check for="perf-interference">
+ <Input type="checkbox" name="perf-interference" innerRef={performanceInterferenceCheckbox} />{' '}
+ <span className="ml-2">Enable performance interference</span>
+ </Label>
+ </FormGroup>
+ <FormGroup>
+ <Label for="scheduler">Scheduler</Label>
+ <Input name="scheduler" type="select" innerRef={schedulerSelect}>
+ {schedulers.map((scheduler) => (
+ <option value={scheduler.name} key={scheduler.name}>
+ {scheduler.name}
+ </option>
+ ))}
+ </Input>
+ </FormGroup>
+ </Form>
+ </Modal>
+ )
+}
+
+NewScenarioModalComponent.propTypes = {
+ show: PropTypes.bool.isRequired,
+ currentPortfolioId: PropTypes.string.isRequired,
+ currentPortfolioScenarioIds: PropTypes.arrayOf(PropTypes.string),
+ traces: PropTypes.arrayOf(Shapes.Trace),
+ topologies: PropTypes.arrayOf(Shapes.Topology),
+ schedulers: PropTypes.arrayOf(Shapes.Scheduler),
+ callback: PropTypes.func.isRequired,
+}
+
+export default NewScenarioModalComponent
diff --git a/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewTopologyModalComponent.js b/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewTopologyModalComponent.js
new file mode 100644
index 00000000..9fee8831
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/modals/custom-components/NewTopologyModalComponent.js
@@ -0,0 +1,71 @@
+import PropTypes from 'prop-types'
+import { Form, FormGroup, Input, Label } from 'reactstrap'
+import React, { useRef } from 'react'
+import Shapes from '../../../shapes'
+import Modal from '../Modal'
+
+const NewTopologyModalComponent = ({ show, onCreateTopology, onDuplicateTopology, onCancel, topologies }) => {
+ const form = useRef(null)
+ const textInput = useRef(null)
+ const originTopology = useRef(null)
+
+ const onCreate = () => {
+ onCreateTopology(textInput.current.value)
+ }
+
+ const onDuplicate = () => {
+ onDuplicateTopology(textInput.current.value, originTopology.current.value)
+ }
+
+ const onSubmit = () => {
+ if (!form.current.reportValidity()) {
+ return false
+ } else if (originTopology.current.selectedIndex === 0) {
+ onCreate()
+ } else {
+ onDuplicate()
+ }
+
+ return true
+ }
+
+ return (
+ <Modal title="New Topology" show={show} onSubmit={onSubmit} onCancel={onCancel}>
+ <Form
+ onSubmit={(e) => {
+ e.preventDefault()
+ onSubmit()
+ }}
+ innerRef={form}
+ >
+ <FormGroup>
+ <Label for="name">Name</Label>
+ <Input name="name" type="text" required innerRef={textInput} />
+ </FormGroup>
+ <FormGroup>
+ <Label for="origin">Topology to duplicate</Label>
+ <Input name="origin" type="select" innerRef={originTopology}>
+ <option value={-1} key={-1}>
+ None - start from scratch
+ </option>
+ {topologies.map((topology) => (
+ <option value={topology._id} key={topology._id}>
+ {topology.name}
+ </option>
+ ))}
+ </Input>
+ </FormGroup>
+ </Form>
+ </Modal>
+ )
+}
+
+NewTopologyModalComponent.propTypes = {
+ show: PropTypes.bool.isRequired,
+ topologies: PropTypes.arrayOf(Shapes.Topology),
+ onCreateTopology: PropTypes.func.isRequired,
+ onDuplicateTopology: PropTypes.func.isRequired,
+ onCancel: PropTypes.func.isRequired,
+}
+
+export default NewTopologyModalComponent