summaryrefslogtreecommitdiff
path: root/frontend/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components')
-rw-r--r--frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js8
-rw-r--r--frontend/src/components/modals/Modal.js4
-rw-r--r--frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js145
-rw-r--r--frontend/src/components/modals/custom-components/NewScenarioModalComponent.js268
-rw-r--r--frontend/src/components/modals/custom-components/NewTopologyModalComponent.js121
-rw-r--r--frontend/src/components/navigation/AppNavbarComponent.js9
-rw-r--r--frontend/src/components/navigation/HomeNavbar.js9
-rw-r--r--frontend/src/components/navigation/LogoutButton.js5
-rw-r--r--frontend/src/components/navigation/Navbar.js131
9 files changed, 312 insertions, 388 deletions
diff --git a/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js b/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js
index 569166d8..6599fefd 100644
--- a/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js
+++ b/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js
@@ -14,7 +14,7 @@ const UnitTabsComponent = () => {
<Nav tabs>
<NavItem>
<NavLink
- className={activeTab === 'cpu-units' && 'active'}
+ className={activeTab === 'cpu-units' ? 'active' : ''}
onClick={() => {
toggle('cpu-units')
}}
@@ -24,7 +24,7 @@ const UnitTabsComponent = () => {
</NavItem>
<NavItem>
<NavLink
- className={activeTab === 'gpu-units' && 'active'}
+ className={activeTab === 'gpu-units' ? 'active' : ''}
onClick={() => {
toggle('gpu-units')
}}
@@ -34,7 +34,7 @@ const UnitTabsComponent = () => {
</NavItem>
<NavItem>
<NavLink
- className={activeTab === 'memory-units' && 'active'}
+ className={activeTab === 'memory-units' ? 'active' : ''}
onClick={() => {
toggle('memory-units')
}}
@@ -44,7 +44,7 @@ const UnitTabsComponent = () => {
</NavItem>
<NavItem>
<NavLink
- className={activeTab === 'storage-units' && 'active'}
+ className={activeTab === 'storage-units' ? 'active' : ''}
onClick={() => {
toggle('storage-units')
}}
diff --git a/frontend/src/components/modals/Modal.js b/frontend/src/components/modals/Modal.js
index 36bb498e..b494d970 100644
--- a/frontend/src/components/modals/Modal.js
+++ b/frontend/src/components/modals/Modal.js
@@ -18,8 +18,8 @@ function Modal({ children, title, show, onSubmit, onCancel, submitButtonType, su
}
return (
- <RModal isOpen={modal} toggle={toggle}>
- <ModalHeader toggle={toggle}>{title}</ModalHeader>
+ <RModal isOpen={modal} toggle={cancel}>
+ <ModalHeader toggle={cancel}>{title}</ModalHeader>
<ModalBody>{children}</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={cancel}>
diff --git a/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js b/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js
index 19049931..978ca11d 100644
--- a/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewPortfolioModalComponent.js
@@ -1,98 +1,69 @@
import PropTypes from 'prop-types'
-import React from 'react'
+import React, { useRef } from 'react'
+import { Form, FormGroup, Input, Label } from 'reactstrap'
import Modal from '../Modal'
import { AVAILABLE_METRICS } from '../../../util/available-metrics'
-class NewPortfolioModalComponent extends React.Component {
- static propTypes = {
- show: PropTypes.bool.isRequired,
- callback: PropTypes.func.isRequired,
- }
+const NewPortfolioModalComponent = ({ show, callback }) => {
+ const textInput = useRef(null)
+ const repeatsInput = useRef(null)
+ const metricCheckboxes = useRef({})
- constructor(props) {
- super(props)
- this.metricCheckboxes = {}
- }
-
- componentDidMount() {
- this.reset()
- }
-
- reset() {
- if (this.textInput) {
- this.textInput.value = ''
- AVAILABLE_METRICS.forEach((metric) => {
- this.metricCheckboxes[metric].checked = true
- })
- this.repeatsInput.value = 1
- }
- }
-
- onSubmit() {
- this.props.callback(this.textInput.value, {
- enabledMetrics: AVAILABLE_METRICS.filter((metric) => this.metricCheckboxes[metric].checked),
- repeatsPerScenario: parseInt(this.repeatsInput.value),
+ const onSubmit = () =>
+ callback(textInput.current.value, {
+ enabledMetrics: AVAILABLE_METRICS.filter((metric) => metricCheckboxes.current[metric].checked),
+ repeatsPerScenario: parseInt(repeatsInput.current.value),
})
- this.reset()
- }
+ const onCancel = () => callback(undefined)
- onCancel() {
- this.props.callback(undefined)
- this.reset()
- }
-
- render() {
- return (
- <Modal
- title="New Portfolio"
- show={this.props.show}
- onSubmit={this.onSubmit.bind(this)}
- onCancel={this.onCancel.bind(this)}
+ return (
+ <Modal title="New Portfolio" show={show} onSubmit={onSubmit} onCancel={onCancel}>
+ <Form
+ onSubmit={(e) => {
+ e.preventDefault()
+ this.onSubmit()
+ }}
>
- <form
- onSubmit={(e) => {
- e.preventDefault()
- this.onSubmit()
- }}
- >
- <div className="form-group">
- <label className="form-control-label">Name</label>
- <input
- type="text"
- className="form-control"
- required
- ref={(textInput) => (this.textInput = textInput)}
- />
- </div>
- <h4>Targets</h4>
- <h5>Metrics</h5>
- <div className="form-group">
- {AVAILABLE_METRICS.map((metric) => (
- <div className="form-check" key={metric}>
- <label className="form-check-label">
- <input
- type="checkbox"
- className="form-check-input"
- ref={(checkbox) => (this.metricCheckboxes[metric] = checkbox)}
- />
- <code>{metric}</code>
- </label>
- </div>
- ))}
- </div>
- <div className="form-group">
- <label className="form-control-label">Repeats per scenario</label>
- <input
- type="number"
- className="form-control"
- required
- ref={(repeatsInput) => (this.repeatsInput = repeatsInput)}
- />
- </div>
- </form>
- </Modal>
- )
- }
+ <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)}
+ />
+ <code>{metric}</code>
+ </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/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js b/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js
index 5ba74b0f..631082a2 100644
--- a/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewScenarioModalComponent.js
@@ -1,168 +1,138 @@
import PropTypes from 'prop-types'
-import React from 'react'
+import React, { useRef } from 'react'
+import { Form, FormGroup, Input, Label } from 'reactstrap'
import Shapes from '../../../shapes'
import Modal from '../Modal'
-class NewScenarioModalComponent extends React.Component {
- static 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,
- }
-
- componentDidMount() {
- this.reset()
- }
+const NewScenarioModalComponent = ({
+ show,
+ callback,
+ currentPortfolioId,
+ currentPortfolioScenarioIds,
+ traces,
+ topologies,
+ schedulers,
+}) => {
+ 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)
- componentDidUpdate() {
- 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() {
- 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() {
- this.props.callback(
- this.textInput.value,
- this.props.currentPortfolioId,
+ const onSubmit = () => {
+ callback(
+ textInput.current.value,
+ currentPortfolioId,
{
- traceId: this.traceSelect.value,
- loadSamplingFraction: parseFloat(this.traceLoadInput.value),
+ traceId: traceSelect.current.value,
+ loadSamplingFraction: parseFloat(traceLoadInput.current.value),
},
{
- topologyId: this.topologySelect.value,
+ topologyId: topologySelect.current.value,
},
{
- failuresEnabled: this.failuresCheckbox.checked,
- performanceInterferenceEnabled: this.performanceInterferenceCheckbox.checked,
- schedulerName: this.schedulerSelect.value,
+ failuresEnabled: failuresCheckbox.current.checked,
+ performanceInterferenceEnabled: performanceInterferenceCheckbox.current.checked,
+ schedulerName: schedulerSelect.current.value,
}
)
- this.reset()
}
-
- onCancel() {
- this.props.callback(undefined)
- this.reset()
+ const onCancel = () => {
+ callback(undefined)
}
- render() {
- return (
- <Modal
- title="New Scenario"
- show={this.props.show}
- onSubmit={this.onSubmit.bind(this)}
- onCancel={this.onCancel.bind(this)}
+ return (
+ <Modal title="New Scenario" show={show} onSubmit={onSubmit} onCancel={onCancel}>
+ <Form
+ onSubmit={(e) => {
+ e.preventDefault()
+ onSubmit()
+ }}
>
- <form
- onSubmit={(e) => {
- e.preventDefault()
- this.onSubmit()
- }}
- >
- <div className="form-group">
- <label className="form-control-label">Name</label>
- <input
- type="text"
- className="form-control"
- required
- disabled={this.props.currentPortfolioScenarioIds.length === 0}
- ref={(textInput) => (this.textInput = textInput)}
- />
- </div>
- <h4>Trace</h4>
- <div className="form-group">
- <label className="form-control-label">Trace</label>
- <select className="form-control" ref={(traceSelect) => (this.traceSelect = traceSelect)}>
- {this.props.traces.map((trace) => (
- <option value={trace._id} key={trace._id}>
- {trace.name}
- </option>
- ))}
- </select>
- </div>
- <div className="form-group">
- <label className="form-control-label">Load sampling fraction</label>
- <input
- type="number"
- className="form-control"
- required
- ref={(traceLoadInput) => (this.traceLoadInput = traceLoadInput)}
- />
- </div>
- <h4>Topology</h4>
- <div className="form-group">
- <label className="form-control-label">Topology</label>
- <select
- className="form-control"
- ref={(topologySelect) => (this.topologySelect = topologySelect)}
- >
- {this.props.topologies.map((topology) => (
- <option value={topology._id} key={topology._id}>
- {topology.name}
- </option>
- ))}
- </select>
- </div>
- <h4>Operational Phenomena</h4>
- <div className="form-check">
- <label className="form-check-label">
- <input
- type="checkbox"
- className="form-check-input"
- ref={(failuresCheckbox) => (this.failuresCheckbox = failuresCheckbox)}
- />
- <span className="ml-2">Enable failures</span>
- </label>
- </div>
- <div className="form-check">
- <label className="form-check-label">
- <input
- type="checkbox"
- className="form-check-input"
- ref={(performanceInterferenceCheckbox) =>
- (this.performanceInterferenceCheckbox = performanceInterferenceCheckbox)
- }
- />
- <span className="ml-2">Enable performance interference</span>
- </label>
- </div>
- <div className="form-group">
- <label className="form-control-label">Scheduler</label>
- <select
- className="form-control"
- ref={(schedulerSelect) => (this.schedulerSelect = schedulerSelect)}
- >
- {this.props.schedulers.map((scheduler) => (
- <option value={scheduler.name} key={scheduler.name}>
- {scheduler.name}
- </option>
- ))}
- </select>
- </div>
- </form>
- </Modal>
- )
- }
+ <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/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
index 8a625b13..b20ec13b 100644
--- a/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
@@ -1,90 +1,65 @@
import PropTypes from 'prop-types'
-import React from 'react'
+import { Form, FormGroup, Input, Label } from 'reactstrap'
+import React, { useRef } from 'react'
import Shapes from '../../../shapes'
import Modal from '../Modal'
-class NewTopologyModalComponent extends React.Component {
- static propTypes = {
- show: PropTypes.bool.isRequired,
- topologies: PropTypes.arrayOf(Shapes.Topology),
- onCreateTopology: PropTypes.func.isRequired,
- onDuplicateTopology: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
+const NewTopologyModalComponent = ({ show, onCreateTopology, onDuplicateTopology, onCancel, topologies }) => {
+ const textInput = useRef(null)
+ const originTopology = useRef(null)
+
+ const onCreate = () => {
+ onCreateTopology(textInput.current.value)
}
- reset() {
- if (this.textInput) {
- this.textInput.value = ''
- this.originTopology.selectedIndex = 0
- }
+ const onDuplicate = () => {
+ onDuplicateTopology(textInput.current.value, originTopology.current.value)
}
- onSubmit() {
- if (this.originTopology.selectedIndex === 0) {
- this.onCreate()
+ const onSubmit = () => {
+ if (originTopology.current.selectedIndex === 0) {
+ onCreate()
} else {
- this.onDuplicate()
+ onDuplicate()
}
}
- onCreate() {
- this.props.onCreateTopology(this.textInput.value)
- this.reset()
- }
-
- onDuplicate() {
- this.props.onDuplicateTopology(this.textInput.value, this.originTopology.value)
- this.reset()
- }
-
- onCancel() {
- this.props.onCancel()
- this.reset()
- }
-
- render() {
- return (
- <Modal
- title="New Topology"
- show={this.props.show}
- onSubmit={this.onSubmit.bind(this)}
- onCancel={this.onCancel.bind(this)}
+ return (
+ <Modal title="New Topology" show={show} onSubmit={onSubmit} onCancel={onCancel}>
+ <Form
+ onSubmit={(e) => {
+ e.preventDefault()
+ onSubmit()
+ }}
>
- <form
- onSubmit={(e) => {
- e.preventDefault()
- this.onSubmit()
- }}
- >
- <div className="form-group">
- <label className="form-control-label">Name</label>
- <input
- type="text"
- className="form-control"
- required
- ref={(textInput) => (this.textInput = textInput)}
- />
- </div>
- <div className="form-group">
- <label className="form-control-label">Topology to duplicate</label>
- <select
- className="form-control"
- ref={(originTopology) => (this.originTopology = originTopology)}
- >
- <option value={-1} key={-1}>
- None - start from scratch
+ <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>
- {this.props.topologies.map((topology) => (
- <option value={topology._id} key={topology._id}>
- {topology.name}
- </option>
- ))}
- </select>
- </div>
- </form>
- </Modal>
- )
- }
+ ))}
+ </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
diff --git a/frontend/src/components/navigation/AppNavbarComponent.js b/frontend/src/components/navigation/AppNavbarComponent.js
index 7a1c2462..c5de3d0b 100644
--- a/frontend/src/components/navigation/AppNavbarComponent.js
+++ b/frontend/src/components/navigation/AppNavbarComponent.js
@@ -1,22 +1,23 @@
import React from 'react'
import FontAwesome from 'react-fontawesome'
import { Link } from 'react-router-dom'
+import { NavLink } from 'reactstrap'
import Navbar, { NavItem } from './Navbar'
import './Navbar.sass'
const AppNavbarComponent = ({ project, fullWidth }) => (
<Navbar fullWidth={fullWidth}>
<NavItem route="/projects">
- <Link className="nav-link" title="My Projects" to="/projects">
+ <NavLink tag={Link} title="My Projects" to="/projects">
<FontAwesome name="list" className="mr-2" />
My Projects
- </Link>
+ </NavLink>
</NavItem>
{project ? (
<NavItem>
- <Link className="nav-link" title="Current Project" to={`/projects/${project._id}`}>
+ <NavLink tag={Link} title="Current Project" to={`/projects/${project._id}`}>
<span>{project.name}</span>
- </Link>
+ </NavLink>
</NavItem>
) : undefined}
</Navbar>
diff --git a/frontend/src/components/navigation/HomeNavbar.js b/frontend/src/components/navigation/HomeNavbar.js
index e22933af..08d222ea 100644
--- a/frontend/src/components/navigation/HomeNavbar.js
+++ b/frontend/src/components/navigation/HomeNavbar.js
@@ -1,13 +1,12 @@
import React from 'react'
+import { NavItem, NavLink } from 'reactstrap'
import Navbar from './Navbar'
import './Navbar.sass'
const ScrollNavItem = ({ id, name }) => (
- <li className="nav-item">
- <a className="nav-link" href={id}>
- {name}
- </a>
- </li>
+ <NavItem>
+ <NavLink href={id}>{name}</NavLink>
+ </NavItem>
)
const HomeNavbar = () => (
diff --git a/frontend/src/components/navigation/LogoutButton.js b/frontend/src/components/navigation/LogoutButton.js
index e3de2ec7..78b02b44 100644
--- a/frontend/src/components/navigation/LogoutButton.js
+++ b/frontend/src/components/navigation/LogoutButton.js
@@ -2,11 +2,12 @@ import PropTypes from 'prop-types'
import React from 'react'
import FontAwesome from 'react-fontawesome'
import { Link } from 'react-router-dom'
+import { NavLink } from 'reactstrap'
const LogoutButton = ({ onLogout }) => (
- <Link className="logout nav-link" title="Sign out" to="#" onClick={onLogout}>
+ <NavLink tag={Link} className="logout" title="Sign out" to="#" onClick={onLogout}>
<FontAwesome name="power-off" size="lg" />
- </Link>
+ </NavLink>
)
LogoutButton.propTypes = {
diff --git a/frontend/src/components/navigation/Navbar.js b/frontend/src/components/navigation/Navbar.js
index 164a2309..55f98900 100644
--- a/frontend/src/components/navigation/Navbar.js
+++ b/frontend/src/components/navigation/Navbar.js
@@ -1,6 +1,15 @@
-import classNames from 'classnames'
-import React from 'react'
-import { Link, withRouter } from 'react-router-dom'
+import React, { useState } from 'react'
+import { Link, useLocation } from 'react-router-dom'
+import {
+ Navbar as RNavbar,
+ NavItem as RNavItem,
+ NavLink,
+ NavbarBrand,
+ NavbarToggler,
+ Collapse,
+ Nav,
+ Container,
+} from 'reactstrap'
import { userIsLoggedIn } from '../../auth/index'
import Login from '../../containers/auth/Login'
import Logout from '../../containers/auth/Logout'
@@ -9,9 +18,6 @@ import './Navbar.sass'
export const NAVBAR_HEIGHT = 60
-export const NavItem = withRouter((props) => <NavItemWithoutRoute {...props} />)
-export const LoggedInSection = withRouter((props) => <LoggedInSectionWithoutRoute {...props} />)
-
const GitHubLink = () => (
<a
href="https://github.com/atlarge-research/opendc"
@@ -22,64 +28,65 @@ const GitHubLink = () => (
</a>
)
-const NavItemWithoutRoute = ({ route, location, children }) => (
- <li className={classNames('nav-item clickable', location.pathname === route ? 'active' : undefined)}>{children}</li>
-)
+export const NavItem = ({ route, children }) => {
+ const location = useLocation()
+ return <RNavItem active={location.pathname === route}>{children}</RNavItem>
+}
-const LoggedInSectionWithoutRoute = ({ location }) => (
- <ul className="navbar-nav auth-links">
- {userIsLoggedIn() ? (
- [
- location.pathname === '/' ? (
- <NavItem route="/projects" key="projects">
- <Link className="nav-link" title="My Projects" to="/projects">
- My Projects
- </Link>
- </NavItem>
- ) : (
- <NavItem route="/profile" key="profile">
- <Link className="nav-link" title="My Profile" to="/profile">
- <ProfileName />
- </Link>
- </NavItem>
- ),
- <NavItem route="logout" key="logout">
- <Logout />
- </NavItem>,
- ]
- ) : (
- <NavItem route="login">
- <GitHubLink />
- <Login visible={true} />
- </NavItem>
- )}
- </ul>
-)
+export const LoggedInSection = () => {
+ const location = useLocation()
+ return (
+ <Nav navbar className="auth-links">
+ {userIsLoggedIn() ? (
+ [
+ location.pathname === '/' ? (
+ <NavItem route="/projects" key="projects">
+ <NavLink tag={Link} title="My Projects" to="/projects">
+ My Projects
+ </NavLink>
+ </NavItem>
+ ) : (
+ <NavItem route="/profile" key="profile">
+ <NavLink tag={Link} title="My Profile" to="/profile">
+ <ProfileName />
+ </NavLink>
+ </NavItem>
+ ),
+ <NavItem route="logout" key="logout">
+ <Logout />
+ </NavItem>,
+ ]
+ ) : (
+ <NavItem route="login">
+ <GitHubLink />
+ <Login visible={true} />
+ </NavItem>
+ )}
+ </Nav>
+ )
+}
-const Navbar = ({ fullWidth, children }) => (
- <nav className="navbar fixed-top navbar-expand-lg navbar-light bg-faded" id="navbar">
- <div className={fullWidth ? 'container-fluid' : 'container'}>
- <button
- className="navbar-toggler navbar-toggler-right"
- type="button"
- data-toggle="collapse"
- data-target="#navbarSupportedContent"
- aria-controls="navbarSupportedContent"
- aria-expanded="false"
- aria-label="Toggle navigation"
- >
- <span className="navbar-toggler-icon" />
- </button>
- <Link className="navbar-brand opendc-brand" to="/" title="OpenDC" onClick={() => window.scrollTo(0, 0)}>
- <img src="/img/logo.png" alt="OpenDC" />
- </Link>
+const Navbar = ({ fullWidth, children }) => {
+ const [isOpen, setIsOpen] = useState(false)
+ const toggle = () => setIsOpen(!isOpen)
- <div className="collapse navbar-collapse" id="navbarSupportedContent">
- <ul className="navbar-nav mr-auto">{children}</ul>
- <LoggedInSection />
- </div>
- </div>
- </nav>
-)
+ return (
+ <RNavbar fixed="top" color="light" light expand="lg" id="navbar">
+ <Container fluid={fullWidth}>
+ <NavbarToggler onClick={toggle} />
+ <NavbarBrand tag={Link} to="/" title="OpenDC" className="opendc-brand">
+ <img src="/img/logo.png" alt="OpenDC" />
+ </NavbarBrand>
+
+ <Collapse isOpen={isOpen} navbar>
+ <Nav className="mr-auto" navbar>
+ {children}
+ </Nav>
+ <LoggedInSection />
+ </Collapse>
+ </Container>
+ </RNavbar>
+ )
+}
export default Navbar