diff options
Diffstat (limited to 'frontend/src/components')
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 |
