summaryrefslogtreecommitdiff
path: root/frontend/src
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2020-10-28 13:29:54 +0100
committerGitHub <noreply@github.com>2020-10-28 13:29:54 +0100
commit93fa55749c40ed1f1a7bee9157bce81708988656 (patch)
treec386e6f0cbac347d15cc10a64d044cb70a6df7f0 /frontend/src
parent44342c83b886c4d65ef8b74a3bea1d0e12b37f38 (diff)
parent34b45675b3de56c847818dbcc829f7ce02ddce56 (diff)
Merge pull request #52 from atlarge-research/refactor/jquery
Eliminate jQuery from frontend dependencies
Diffstat (limited to 'frontend/src')
-rw-r--r--frontend/src/components/app/map/MapStageComponent.js3
-rw-r--r--frontend/src/components/app/sidebars/topology/machine/UnitComponent.js94
-rw-r--r--frontend/src/components/home/SimulationSection.js2
-rw-r--r--frontend/src/components/modals/Modal.js163
-rw-r--r--frontend/src/components/modals/TextInputModal.js2
-rw-r--r--frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js12
-rw-r--r--frontend/src/components/modals/custom-components/NewScenarioModalComponent.js26
-rw-r--r--frontend/src/components/modals/custom-components/NewTopologyModalComponent.js6
-rw-r--r--frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js1
-rw-r--r--frontend/src/index.sass3
-rw-r--r--frontend/src/pages/Home.js61
11 files changed, 138 insertions, 235 deletions
diff --git a/frontend/src/components/app/map/MapStageComponent.js b/frontend/src/components/app/map/MapStageComponent.js
index cecb34de..2cd0ed6e 100644
--- a/frontend/src/components/app/map/MapStageComponent.js
+++ b/frontend/src/components/app/map/MapStageComponent.js
@@ -4,7 +4,6 @@ import { Shortcuts } from 'react-shortcuts'
import MapLayer from '../../../containers/app/map/layers/MapLayer'
import ObjectHoverLayer from '../../../containers/app/map/layers/ObjectHoverLayer'
import RoomHoverLayer from '../../../containers/app/map/layers/RoomHoverLayer'
-import jQuery from '../../../util/jquery'
import { NAVBAR_HEIGHT } from '../../navigation/Navbar'
import { MAP_MOVE_PIXELS_PER_EVENT } from './MapConstants'
import { Provider } from 'react-redux'
@@ -43,7 +42,7 @@ class MapStageComponent extends React.Component {
}
updateDimensions() {
- this.props.setMapDimensions(jQuery(window).width(), jQuery(window).height() - NAVBAR_HEIGHT)
+ this.props.setMapDimensions(window.innerWidth, window.innerHeight - NAVBAR_HEIGHT)
}
updateScale(e) {
diff --git a/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js b/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js
index 4816ca23..de55e506 100644
--- a/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js
+++ b/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js
@@ -1,58 +1,52 @@
import React from 'react'
-import jQuery from '../../../../../util/jquery'
+import { UncontrolledPopover, PopoverHeader, PopoverBody, Button } from 'reactstrap'
-class UnitComponent extends React.Component {
- componentDidMount() {
- jQuery('.unit-info-popover').popover({
- trigger: 'focus',
- })
+function UnitComponent({ index, unitType, unit, onDelete }) {
+ let unitInfo
+ if (unitType === 'cpu' || unitType === 'gpu') {
+ unitInfo = (
+ <>
+ <strong>Clockrate: </strong>
+ <code>{unit.clockRateMhz}</code>
+ <br />
+ <strong>Num. Cores: </strong>
+ <code>{unit.numberOfCores}</code>
+ <br />
+ <strong>Energy Cons.: </strong>
+ <code>{unit.energyConsumptionW} W</code>
+ <br />
+ </>
+ )
+ } else if (unitType === 'memory' || unitType === 'storage') {
+ unitInfo = (
+ <>
+ <strong>Speed:</strong>
+ <code>{unit.speedMbPerS} Mb/s</code>
+ <br />
+ <strong>Size:</strong>
+ <code>{unit.sizeMb} MB</code>
+ <br />
+ <strong>Energy Cons.:</strong>
+ <code>{unit.energyConsumptionW} W</code>
+ <br />
+ </>
+ )
}
- render() {
- let unitInfo
- if (this.props.unitType === 'cpu' || this.props.unitType === 'gpu') {
- unitInfo =
- '<strong>Clockrate:</strong> <code>' +
- this.props.unit.clockRateMhz +
- ' MHz</code><br/>' +
- '<strong>Num. Cores:</strong> <code>' +
- this.props.unit.numberOfCores +
- '</code><br/>' +
- '<strong>Energy Cons.:</strong> <code>' +
- this.props.unit.energyConsumptionW +
- ' W</code>'
- } else if (this.props.unitType === 'memory' || this.props.unitType === 'storage') {
- unitInfo =
- '<strong>Speed:</strong> <code>' +
- this.props.unit.speedMbPerS +
- ' Mb/s</code><br/>' +
- '<strong>Size:</strong> <code>' +
- this.props.unit.sizeMb +
- ' MB</code><br/>' +
- '<strong>Energy Cons.:</strong> <code> ' +
- this.props.unit.energyConsumptionW +
- ' W</code>'
- }
+ return (
+ <li className="d-flex list-group-item justify-content-between align-items-center">
+ <span style={{ maxWidth: '60%' }}>{unit.name}</span>
+ <span>
+ <Button outline={true} color="info" className="mr-1 fa fa-info-circle" id={`unit-${index}`} />
+ <UncontrolledPopover trigger="focus" placement="left" target={`unit-${index}`}>
+ <PopoverHeader>Unit Information</PopoverHeader>
+ <PopoverBody>{unitInfo}</PopoverBody>
+ </UncontrolledPopover>
- return (
- <li className="d-flex list-group-item justify-content-between align-items-center">
- <span style={{ maxWidth: '60%' }}>{this.props.unit.name}</span>
- <span>
- <span
- tabIndex="0"
- className="unit-info-popover btn btn-outline-info mr-1 fa fa-info-circle"
- role="button"
- data-toggle="popover"
- data-trigger="focus"
- title="Unit information"
- data-content={unitInfo}
- data-html="true"
- />
- <span className="btn btn-outline-danger fa fa-trash" onClick={this.props.onDelete} />
- </span>
- </li>
- )
- }
+ <span className="btn btn-outline-danger fa fa-trash" onClick={onDelete} />
+ </span>
+ </li>
+ )
}
export default UnitComponent
diff --git a/frontend/src/components/home/SimulationSection.js b/frontend/src/components/home/SimulationSection.js
index e7a02068..b0244cb5 100644
--- a/frontend/src/components/home/SimulationSection.js
+++ b/frontend/src/components/home/SimulationSection.js
@@ -3,7 +3,7 @@ import ScreenshotSection from './ScreenshotSection'
const ModelingSection = () => (
<ScreenshotSection
- name="simulation"
+ name="project"
title="Datacenter Simulation"
imageUrl="/img/screenshot-simulation-zoom.png"
caption="Running an experiment in OpenDC"
diff --git a/frontend/src/components/modals/Modal.js b/frontend/src/components/modals/Modal.js
index 40656dc1..36bb498e 100644
--- a/frontend/src/components/modals/Modal.js
+++ b/frontend/src/components/modals/Modal.js
@@ -1,124 +1,51 @@
-import classNames from 'classnames'
+import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
-import React from 'react'
-import jQuery from '../../util/jquery'
-
-class Modal extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- show: PropTypes.bool.isRequired,
- onSubmit: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
- submitButtonType: PropTypes.string,
- submitButtonText: PropTypes.string,
- }
- static defaultProps = {
- submitButtonType: 'primary',
- submitButtonText: 'Save',
- }
- static idCounter = 0
-
- // Local, up-to-date copy of modal visibility for time between close event and a props update (to prevent duplicate
- // 'close' triggers)
- visible = false
-
- constructor(props) {
- super(props)
- this.id = 'modal-' + Modal.idCounter++
- }
-
- componentDidMount() {
- this.visible = this.props.show
- this.openOrCloseModal()
-
- // Trigger auto-focus
- jQuery('#' + this.id)
- .on('shown.bs.modal', function () {
- jQuery(this).find('input').first().focus()
- })
- .on('hide.bs.modal', () => {
- if (this.visible) {
- this.props.onCancel()
- }
- })
- .on('keydown', (e) => {
- e.stopPropagation()
- })
- }
-
- componentDidUpdate() {
- if (this.visible !== this.props.show) {
- this.visible = this.props.show
- this.openOrCloseModal()
- }
- }
-
- onSubmit() {
- if (this.visible) {
- this.props.onSubmit()
- this.visible = false
- this.closeModal()
- }
- }
-
- onCancel() {
- if (this.visible) {
- this.props.onCancel()
- this.visible = false
- this.closeModal()
- }
- }
-
- openModal() {
- jQuery('#' + this.id).modal('show')
- }
-
- closeModal() {
- jQuery('#' + this.id).modal('hide')
- }
+import { Modal as RModal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap'
+
+function Modal({ children, title, show, onSubmit, onCancel, submitButtonType, submitButtonText }) {
+ const [modal, setModal] = useState(show)
+
+ useEffect(() => setModal(show), [show])
+
+ const toggle = () => setModal(!modal)
+ const cancel = () => {
+ toggle()
+ onCancel()
+ }
+ const submit = () => {
+ toggle()
+ onSubmit()
+ }
+
+ return (
+ <RModal isOpen={modal} toggle={toggle}>
+ <ModalHeader toggle={toggle}>{title}</ModalHeader>
+ <ModalBody>{children}</ModalBody>
+ <ModalFooter>
+ <Button color="secondary" onClick={cancel}>
+ Close
+ </Button>
+ <Button color={submitButtonType} onClick={submit}>
+ {submitButtonText}
+ </Button>
+ </ModalFooter>
+ </RModal>
+ )
+}
- openOrCloseModal() {
- if (this.visible) {
- this.openModal()
- } else {
- this.closeModal()
- }
- }
+Modal.propTypes = {
+ title: PropTypes.string.isRequired,
+ show: PropTypes.bool.isRequired,
+ onSubmit: PropTypes.func.isRequired,
+ onCancel: PropTypes.func.isRequired,
+ submitButtonType: PropTypes.string,
+ submitButtonText: PropTypes.string,
+}
- render() {
- return (
- <div className="modal fade" id={this.id} role="dialog">
- <div className="modal-dialog" role="document">
- <div className="modal-content">
- <div className="modal-header">
- <h5 className="modal-title">{this.props.title}</h5>
- <button
- type="button"
- className="close"
- onClick={this.onCancel.bind(this)}
- aria-label="Close"
- >
- <span>&times;</span>
- </button>
- </div>
- <div className="modal-body">{this.props.children}</div>
- <div className="modal-footer">
- <button type="button" className="btn btn-secondary" onClick={this.onCancel.bind(this)}>
- Close
- </button>
- <button
- type="button"
- className={classNames('btn', 'btn-' + this.props.submitButtonType)}
- onClick={this.onSubmit.bind(this)}
- >
- {this.props.submitButtonText}
- </button>
- </div>
- </div>
- </div>
- </div>
- )
- }
+Modal.defaultProps = {
+ submitButtonType: 'primary',
+ submitButtonText: 'Save',
+ show: false,
}
export default Modal
diff --git a/frontend/src/components/modals/TextInputModal.js b/frontend/src/components/modals/TextInputModal.js
index d5edb60b..d0918c7e 100644
--- a/frontend/src/components/modals/TextInputModal.js
+++ b/frontend/src/components/modals/TextInputModal.js
@@ -12,7 +12,7 @@ class TextInputModal extends React.Component {
}
componentDidUpdate() {
- if (this.props.initialValue) {
+ if (this.props.initialValue && this.textInput) {
this.textInput.value = this.props.initialValue
}
}
diff --git a/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js b/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js
index 2d001302..19049931 100644
--- a/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js
@@ -19,11 +19,13 @@ class NewPortfolioModalComponent extends React.Component {
}
reset() {
- this.textInput.value = ''
- AVAILABLE_METRICS.forEach((metric) => {
- this.metricCheckboxes[metric].checked = true
- })
- this.repeatsInput.value = 1
+ if (this.textInput) {
+ this.textInput.value = ''
+ AVAILABLE_METRICS.forEach((metric) => {
+ this.metricCheckboxes[metric].checked = true
+ })
+ this.repeatsInput.value = 1
+ }
}
onSubmit() {
diff --git a/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js b/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js
index d7d99982..5ba74b0f 100644
--- a/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js
@@ -19,21 +19,25 @@ class NewScenarioModalComponent extends React.Component {
}
componentDidUpdate() {
- if (this.props.currentPortfolioScenarioIds.length === 0) {
- this.textInput.value = 'Base scenario'
- } else if (this.textInput.value === 'Base scenario') {
- this.textInput.value = ''
+ if (this.textInput) {
+ if (this.props.currentPortfolioScenarioIds.length === 0) {
+ this.textInput.value = 'Base scenario'
+ } else if (this.textInput.value === 'Base scenario') {
+ this.textInput.value = ''
+ }
}
}
reset() {
- this.textInput.value = this.props.currentPortfolioScenarioIds.length === 0 ? 'Base scenario' : ''
- this.traceSelect.selectedIndex = 0
- this.traceLoadInput.value = 1.0
- this.topologySelect.selectedIndex = 0
- this.failuresCheckbox.checked = false
- this.performanceInterferenceCheckbox.checked = false
- this.schedulerSelect.selectedIndex = 0
+ if (this.textInput) {
+ this.textInput.value = this.props.currentPortfolioScenarioIds.length === 0 ? 'Base scenario' : ''
+ this.traceSelect.selectedIndex = 0
+ this.traceLoadInput.value = 1.0
+ this.topologySelect.selectedIndex = 0
+ this.failuresCheckbox.checked = false
+ this.performanceInterferenceCheckbox.checked = false
+ this.schedulerSelect.selectedIndex = 0
+ }
}
onSubmit() {
diff --git a/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
index d8262baa..8a625b13 100644
--- a/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
@@ -13,8 +13,10 @@ class NewTopologyModalComponent extends React.Component {
}
reset() {
- this.textInput.value = ''
- this.originTopology.selectedIndex = 0
+ if (this.textInput) {
+ this.textInput.value = ''
+ this.originTopology.selectedIndex = 0
+ }
}
onSubmit() {
diff --git a/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js b/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js
index a028ebce..f334f9f2 100644
--- a/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js
+++ b/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js
@@ -5,6 +5,7 @@ import UnitComponent from '../../../../../components/app/sidebars/topology/machi
const mapStateToProps = (state, ownProps) => {
return {
unit: state.objects[ownProps.unitType][ownProps.unitId],
+ index: ownProps.unitId,
}
}
diff --git a/frontend/src/index.sass b/frontend/src/index.sass
index 77acc23a..efb2bed5 100644
--- a/frontend/src/index.sass
+++ b/frontend/src/index.sass
@@ -10,6 +10,9 @@ html, body, #root
font-family: Roboto, Helvetica, Verdana, sans-serif
background: #eee
+ // Scroll padding for top navbar
+ scroll-padding-top: 60px
+
.full-height
position: relative
height: 100% !important
diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js
index 1bdfc5c7..5000ebfe 100644
--- a/frontend/src/pages/Home.js
+++ b/frontend/src/pages/Home.js
@@ -9,54 +9,25 @@ import StakeholderSection from '../components/home/StakeholderSection'
import TeamSection from '../components/home/TeamSection'
import TechnologiesSection from '../components/home/TechnologiesSection'
import HomeNavbar from '../components/navigation/HomeNavbar'
-import jQuery from '../util/jquery'
import './Home.css'
-class Home extends React.Component {
- state = {
- scrollSpySetup: false,
- }
-
- componentDidMount() {
- const scrollOffset = 60
- jQuery('#navbar')
- .find('li a')
- .click(function (e) {
- if (jQuery(e.target).parents('.auth-links').length > 0) {
- return
- }
- e.preventDefault()
- jQuery(jQuery(this).attr('href'))[0].scrollIntoView()
- window.scrollBy(0, -scrollOffset)
- })
-
- if (!this.state.scrollSpySetup) {
- jQuery('body').scrollspy({
- target: '#navbar',
- offset: scrollOffset,
- })
- this.setState({ scrollSpySetup: true })
- }
- }
-
- render() {
- return (
- <div>
- <HomeNavbar />
- <div className="body-wrapper page-container">
- <JumbotronHeader />
- <IntroSection />
- <StakeholderSection />
- <ModelingSection />
- <SimulationSection />
- <TechnologiesSection />
- <TeamSection />
- <ContactSection />
- <DocumentTitle title="OpenDC" />
- </div>
+function Home() {
+ return (
+ <div>
+ <HomeNavbar />
+ <div className="body-wrapper page-container">
+ <JumbotronHeader />
+ <IntroSection />
+ <StakeholderSection />
+ <ModelingSection />
+ <SimulationSection />
+ <TechnologiesSection />
+ <TeamSection />
+ <ContactSection />
+ <DocumentTitle title="OpenDC" />
</div>
- )
- }
+ </div>
+ )
}
export default Home