summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2020-10-28 00:36:19 +0100
committerFabian Mastenbroek <mail.fabianm@gmail.com>2020-10-28 11:38:34 +0100
commit7e05dc7a885cf562052461565376e174e6a9c962 (patch)
tree025412c87b233b88d715f082be37e964e2090931
parent5ec42736f3f17e9f5432063b4cc17e6ad9a75713 (diff)
Migrate to Reactstrap for Modal implementation
-rw-r--r--frontend/package.json1
-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/yarn.lock64
7 files changed, 133 insertions, 141 deletions
diff --git a/frontend/package.json b/frontend/package.json
index 57e27d2f..1a3fc7cb 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -38,6 +38,7 @@
"react-router-dom": "~5.1.2",
"react-scripts": "~3.4.1",
"react-shortcuts": "~2.1.0",
+ "reactstrap": "^8.6.0",
"recharts": "~1.8.5",
"redux": "~4.0.5",
"redux-localstorage": "~0.4.1",
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/yarn.lock b/frontend/yarn.lock
index 592e7d32..2d867878 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1076,6 +1076,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.2.0":
+ version "7.12.1"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
+ integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/template@^7.10.1", "@babel/template@^7.10.3", "@babel/template@^7.4.0", "@babel/template@^7.8.6":
version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.3.tgz#4d13bc8e30bf95b0ce9d175d30306f42a2c9a7b8"
@@ -2959,7 +2966,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
-classnames@^2.2.5, classnames@~2.2.5:
+classnames@^2.2.3, classnames@^2.2.5, classnames@~2.2.5:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@@ -3390,6 +3397,14 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
+create-react-context@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c"
+ integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==
+ dependencies:
+ gud "^1.0.0"
+ warning "^4.0.3"
+
cross-spawn@7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
@@ -3827,7 +3842,7 @@ deep-diff@^0.3.5:
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=
-deep-equal@^1.0.1:
+deep-equal@^1.0.1, deep-equal@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
@@ -8518,6 +8533,11 @@ pnp-webpack-plugin@1.6.4:
dependencies:
ts-pnp "^1.1.6"
+popper.js@^1.14.4:
+ version "1.16.1"
+ resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
+ integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
+
portfinder@^1.0.25:
version "1.0.26"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
@@ -9271,7 +9291,7 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.4"
-prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@~15.7.2:
+prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@~15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -9528,6 +9548,19 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+react-popper@^1.3.6:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324"
+ integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ create-react-context "^0.3.0"
+ deep-equal "^1.1.1"
+ popper.js "^1.14.4"
+ prop-types "^15.6.1"
+ typed-styles "^0.0.7"
+ warning "^4.0.2"
+
react-reconciler@^0.25.1:
version "0.25.1"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.25.1.tgz#f9814d59d115e1210762287ce987801529363aaa"
@@ -9677,7 +9710,7 @@ react-smooth@^1.0.5:
raf "^3.4.0"
react-transition-group "^2.5.0"
-react-transition-group@^2.5.0:
+react-transition-group@^2.3.1, react-transition-group@^2.5.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
@@ -9696,6 +9729,17 @@ react@~16.13.1:
object-assign "^4.1.1"
prop-types "^15.6.2"
+reactstrap@^8.6.0:
+ version "8.6.0"
+ resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-8.6.0.tgz#baee0d12990c9fef3c82199fb05e84d9f0af1a26"
+ integrity sha512-03/UMbLPR6MhVStVUfCLuKh8xh4JOtNVkRxDB9/uHixN+cEQPOpSYa0K69YyK1/2YdZBs2qS6y0cQkK8NQKBHA==
+ dependencies:
+ "@babel/runtime" "^7.2.0"
+ classnames "^2.2.3"
+ prop-types "^15.5.8"
+ react-popper "^1.3.6"
+ react-transition-group "^2.3.1"
+
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -11457,6 +11501,11 @@ typed-function@^2.0.0:
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.0.0.tgz#15ab3825845138a8b1113bd89e60cd6a435739e8"
integrity sha512-Hhy1Iwo/e4AtLZNK10ewVVcP2UEs408DS35ubP825w/YgSBK1KVLwALvvIG4yX75QJrxjCpcWkzkVRB0BwwYlA==
+typed-styles@^0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
+ integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==
+
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -11738,6 +11787,13 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
+warning@^4.0.2, warning@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
+ integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
+ dependencies:
+ loose-envify "^1.0.0"
+
watchpack-chokidar2@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"