diff options
18 files changed, 289 insertions, 296 deletions
diff --git a/frontend/public/index.html b/frontend/public/index.html index e88cca42..0254eff4 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -1,59 +1,63 @@ <!doctype html> <html lang="en"> <head> - <meta charset="utf-8"> - <title>OpenDC</title> + <meta charset="utf-8"> + <title>OpenDC</title> - <!-- Standard meta tags --> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <meta name="theme-color" content="#00A6D6"> - <meta name="description" content="Collaborative Datacenter Simulation and Exploration for Everybody"> - <meta name="author" content="@Large Research"> - <meta name="keywords" content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster"> - <link rel="manifest" href="/manifest.json"> - <link rel="shortcut icon" href="/favicon.ico"> + <!-- Standard meta tags --> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="theme-color" content="#00A6D6"> + <meta name="description" content="Collaborative Datacenter Simulation and Exploration for Everybody"> + <meta name="author" content="@Large Research"> + <meta name="keywords" content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster"> + <link rel="manifest" href="/manifest.json"> + <link rel="shortcut icon" href="/favicon.ico"> - <!-- Twitter Card data --> - <meta name="twitter:card" content="summary"> - <meta name="twitter:site" content="@LargeResearch"> - <meta name="twitter:title" content="OpenDC"> - <meta name="twitter:description" content="Collaborative Datacenter Simulation and Exploration for Everybody"> - <meta name="twitter:creator" content="@LargeResearch"> - <meta name="twitter:image" content="http://opendc.org/img/logo.png"> + <!-- Twitter Card data --> + <meta name="twitter:card" content="summary"> + <meta name="twitter:site" content="@LargeResearch"> + <meta name="twitter:title" content="OpenDC"> + <meta name="twitter:description" content="Collaborative Datacenter Simulation and Exploration for Everybody"> + <meta name="twitter:creator" content="@LargeResearch"> + <meta name="twitter:image" content="http://opendc.org/img/logo.png"> - <!-- OpenGraph meta tags --> - <meta property="og:title" content="OpenDC"> - <meta property="og:site_name" content="OpenDC"> - <meta property="og:type" content="website"> - <meta property="og:image" content="http://opendc.org/img/logo.png"> - <meta property="og:url" content="http://opendc.org/"> - <meta property="og:description" - content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter + <!-- OpenGraph meta tags --> + <meta property="og:title" content="OpenDC"> + <meta property="og:site_name" content="OpenDC"> + <meta property="og:type" content="website"> + <meta property="og:image" content="http://opendc.org/img/logo.png"> + <meta property="og:url" content="http://opendc.org/"> + <meta property="og:description" + content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter simulation, and exploratory datacenter performance feedback."> - <meta property="og:locale" content="en_US"> + <meta property="og:locale" content="en_US"> - <!-- Google meta tags --> - <meta name="google-signin-client_id" content="%REACT_APP_OAUTH_CLIENT_ID%"> - <meta name="google-site-verification" content="YIR4LkQTv6WmOdWv8MkeiUKni-0Yu3WHylLp4VvUMig"/> + <!-- Google meta tags --> + <meta name="google-signin-client_id" content="%REACT_APP_OAUTH_CLIENT_ID%"> + <meta name="google-site-verification" content="YIR4LkQTv6WmOdWv8MkeiUKni-0Yu3WHylLp4VvUMig"/> - <!-- CDN dependencies --> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" - integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> - <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"> - <script src="https://use.fontawesome.com/ece66a2e7c.js"></script> + <!-- CDN dependencies --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" + integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> + <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> + <script src="https://use.fontawesome.com/ece66a2e7c.js"></script> - <!-- Google Analytics --> - <script async src="https://www.googletagmanager.com/gtag/js?id=UA-84285092-3"></script> - <script> - window.dataLayer = window.dataLayer || []; - function gtag() {dataLayer.push(arguments);} - gtag('js', new Date()); - gtag('config', 'UA-84285092-3'); - </script> + <!-- Google Analytics --> + <script async src="https://www.googletagmanager.com/gtag/js?id=UA-84285092-3"></script> + <script> + window.dataLayer = window.dataLayer || [] + + function gtag() { + dataLayer.push(arguments) + } + + gtag('js', new Date()) + gtag('config', 'UA-84285092-3') + </script> </head> <body data-spy="scroll" data-target="#navbar"> <noscript> - You need to enable JavaScript to run this app. + You need to enable JavaScript to run this app. </noscript> <div id="root"></div> diff --git a/frontend/src/actions/modals/topology.js b/frontend/src/actions/modals/topology.js index 7b74e820..b5fecac1 100644 --- a/frontend/src/actions/modals/topology.js +++ b/frontend/src/actions/modals/topology.js @@ -1,5 +1,5 @@ -export const OPEN_CHANGE_TOPOLOGY_MODAL = 'OPEN_CHANGE_TOPOLOGY_MODAL' -export const CLOSE_CHANGE_TOPOLOGY_MODAL = 'CLOSE_CHANGE_TOPOLOGY_MODAL' +export const OPEN_NEW_TOPOLOGY_MODAL = 'OPEN_NEW_TOPOLOGY_MODAL' +export const CLOSE_NEW_TOPOLOGY_MODAL = 'CLOSE_NEW_TOPOLOGY_MODAL' export const OPEN_EDIT_ROOM_NAME_MODAL = 'OPEN_EDIT_ROOM_NAME_MODAL' export const CLOSE_EDIT_ROOM_NAME_MODAL = 'CLOSE_EDIT_ROOM_NAME_MODAL' export const OPEN_DELETE_ROOM_MODAL = 'OPEN_DELETE_ROOM_MODAL' @@ -11,15 +11,15 @@ export const CLOSE_DELETE_RACK_MODAL = 'CLOSE_DELETE_RACK_MODAL' export const OPEN_DELETE_MACHINE_MODAL = 'OPEN_DELETE_MACHINE_MODAL' export const CLOSE_DELETE_MACHINE_MODAL = 'CLOSE_DELETE_MACHINE_MODAL' -export function openChangeTopologyModal() { +export function openNewTopologyModal() { return { - type: OPEN_CHANGE_TOPOLOGY_MODAL, + type: OPEN_NEW_TOPOLOGY_MODAL, } } -export function closeChangeTopologyModal() { +export function closeNewTopologyModal() { return { - type: CLOSE_CHANGE_TOPOLOGY_MODAL, + type: CLOSE_NEW_TOPOLOGY_MODAL, } } diff --git a/frontend/src/components/app/sidebars/project/ProjectSidebarComponent.js b/frontend/src/components/app/sidebars/project/ProjectSidebarComponent.js new file mode 100644 index 00000000..d6e39ff6 --- /dev/null +++ b/frontend/src/components/app/sidebars/project/ProjectSidebarComponent.js @@ -0,0 +1,12 @@ +import React from 'react' +import Sidebar from '../Sidebar' +import TopologyListContainer from '../../../../containers/app/sidebars/project/TopologyListContainer' + +const ProjectSidebarComponent = () => ( + <Sidebar isRight={false}> + <TopologyListContainer/> + <h2>Portfolios</h2> + </Sidebar> + ) + +export default ProjectSidebarComponent diff --git a/frontend/src/components/app/sidebars/project/TopologyListComponent.js b/frontend/src/components/app/sidebars/project/TopologyListComponent.js new file mode 100644 index 00000000..98615711 --- /dev/null +++ b/frontend/src/components/app/sidebars/project/TopologyListComponent.js @@ -0,0 +1,63 @@ +import PropTypes from 'prop-types' +import React from 'react' +import Shapes from '../../../../shapes' +import FontAwesome from 'react-fontawesome' + +class TopologyListComponent extends React.Component { + static propTypes = { + show: PropTypes.bool.isRequired, + topologies: PropTypes.arrayOf(Shapes.Topology), + currentTopologyId: PropTypes.string, + onChooseTopology: PropTypes.func.isRequired, + onNewTopology: PropTypes.func.isRequired, + onDeleteTopology: PropTypes.func.isRequired, + } + + onChoose(id) { + this.props.onChooseTopology(id) + } + + onDuplicate() { + this.props.onNewTopology( + this.textInput.value, + this.originTopology.value, + ) + } + + onDelete(id) { + this.props.onDeleteTopology(id) + } + + render() { + return ( + <div className="pb-3"> + <h2> + Topologies + <button className="btn btn-outline-primary float-right" onClick={this.props.onNewTopology}> + <FontAwesome name="plus"/> + </button> + </h2> + + {this.props.topologies.map((topology, idx) => ( + <div key={topology._id} className="row mb-1"> + <div className={'col-8 align-self-center ' + (topology._id === this.props.currentTopologyId ? 'font-weight-bold' : '')}> + {topology.name} + </div> + <div className="col-4 text-right"> + <span + className="btn btn-outline-primary mr-1 fa fa-play" + onClick={() => this.onChoose(topology._id)} + /> + <span + className={'btn btn-outline-danger fa fa-trash ' + (idx === 0 ? 'disabled' : '')} + onClick={() => idx !== 0 ? this.onDelete(topology._id) : undefined} + /> + </div> + </div> + ))} + </div> + ) + } +} + +export default TopologyListComponent diff --git a/frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js index 22ef4585..a0d736a1 100644 --- a/frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js +++ b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js @@ -3,15 +3,12 @@ import React from 'react' import Shapes from '../../../shapes' import Modal from '../Modal' -class ChangeTopologyModalComponent extends React.Component { +class NewTopologyModalComponent extends React.Component { static propTypes = { show: PropTypes.bool.isRequired, topologies: PropTypes.arrayOf(Shapes.Topology), - currentTopologyId: PropTypes.string, - onChooseTopology: PropTypes.func.isRequired, onCreateTopology: PropTypes.func.isRequired, onDuplicateTopology: PropTypes.func.isRequired, - onDeleteTopology: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired, } @@ -28,11 +25,6 @@ class ChangeTopologyModalComponent extends React.Component { } } - onChoose(id) { - this.props.onChooseTopology(id) - this.reset() - } - onCreate() { this.props.onCreateTopology(this.textInput.value) this.reset() @@ -46,11 +38,6 @@ class ChangeTopologyModalComponent extends React.Component { this.reset() } - onDelete(id) { - this.props.onDeleteTopology(id) - this.reset() - } - onCancel() { this.props.onCancel() this.reset() @@ -59,37 +46,11 @@ class ChangeTopologyModalComponent extends React.Component { render() { return ( <Modal - title="Change Topology" + title="New Topology" show={this.props.show} onSubmit={this.onSubmit.bind(this)} onCancel={this.onCancel.bind(this)} > - <div> - {this.props.topologies.map((topology, idx) => ( - <div key={topology._id} className="row mb-1"> - <div className="col-6"> - <em>{topology._id === this.props.currentTopologyId ? 'Active: ' : ''}</em> - {topology.name} - </div> - <div className="col-6 text-right"> - <span - className="btn btn-primary mr-1" - onClick={() => this.onChoose(topology._id)} - > - Choose - </span> - <span - className={'btn btn-danger ' + (idx === 0 ? 'disabled' : '')} - onClick={() => idx !== 0 ? this.onDelete(topology._id) : undefined} - > - Delete - </span> - </div> - </div> - ))} - </div> - - <h5 className="pt-3 pt-1">New Topology</h5> <form onSubmit={e => { e.preventDefault() @@ -128,4 +89,4 @@ class ChangeTopologyModalComponent extends React.Component { } } -export default ChangeTopologyModalComponent +export default NewTopologyModalComponent diff --git a/frontend/src/components/navigation/AppNavbar.js b/frontend/src/components/navigation/AppNavbar.js deleted file mode 100644 index 876d4abd..00000000 --- a/frontend/src/components/navigation/AppNavbar.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react' -import FontAwesome from 'react-fontawesome' -import { Link } from 'react-router-dom' -import Navbar, { NavItem } from './Navbar' -import './Navbar.css' - -const AppNavbar = ({ projectId, inProject, fullWidth, onViewTopologies }) => ( - <Navbar fullWidth={fullWidth}> - <NavItem route="/projects"> - <Link className="nav-link" title="My Projects" to="/projects"> - <FontAwesome name="list" className="mr-2"/> - My Projects - </Link> - </NavItem> - {inProject ? ( - <> - <NavItem route={'/projects/' + projectId}> - <Link - className="nav-link" - title="Construction" - to={'/projects/' + projectId} - > - <FontAwesome name="industry" className="mr-2"/> - Construction - </Link> - </NavItem> - <NavItem route="topologies"> - <span - className="nav-link" - title="Topologies" - onClick={onViewTopologies} - > - <FontAwesome name="server" className="mr-2"/> - Topologies - </span> - </NavItem> - <NavItem route={'/projects/' + projectId + '/experiments'}> - <Link - className="nav-link" - title="Experiments" - to={'/projects/' + projectId + '/experiments'} - > - <FontAwesome name="play" className="mr-2"/> - Experiments - </Link> - </NavItem> - </> - ) : ( - undefined - )} - </Navbar> -) - -export default AppNavbar diff --git a/frontend/src/components/navigation/AppNavbarComponent.js b/frontend/src/components/navigation/AppNavbarComponent.js new file mode 100644 index 00000000..10a2b92c --- /dev/null +++ b/frontend/src/components/navigation/AppNavbarComponent.js @@ -0,0 +1,27 @@ +import React from 'react' +import FontAwesome from 'react-fontawesome' +import { Link } from 'react-router-dom' +import Navbar, { NavItem } from './Navbar' +import './Navbar.css' + +const AppNavbarComponent = ({ project, fullWidth }) => ( + <Navbar fullWidth={fullWidth}> + <NavItem route="/projects"> + <Link className="nav-link" title="My Projects" to="/projects"> + <FontAwesome name="list" className="mr-2"/> + My Projects + </Link> + </NavItem> + {project ? ( + <NavItem> + <Link className="nav-link" title="Current Project" to={`/projects/${project._id}`}> + <span>{project.name}</span> + </Link> + </NavItem> + ) : ( + undefined + )} + </Navbar> +) + +export default AppNavbarComponent diff --git a/frontend/src/containers/app/sidebars/project/ProjectSidebarContainer.js b/frontend/src/containers/app/sidebars/project/ProjectSidebarContainer.js new file mode 100644 index 00000000..ced0b18b --- /dev/null +++ b/frontend/src/containers/app/sidebars/project/ProjectSidebarContainer.js @@ -0,0 +1,5 @@ +import ProjectSidebarComponent from '../../../../components/app/sidebars/project/ProjectSidebarComponent' + +const ProjectSidebarContainer = ProjectSidebarComponent + +export default ProjectSidebarContainer diff --git a/frontend/src/containers/app/sidebars/project/TopologyListContainer.js b/frontend/src/containers/app/sidebars/project/TopologyListContainer.js new file mode 100644 index 00000000..cab47c8d --- /dev/null +++ b/frontend/src/containers/app/sidebars/project/TopologyListContainer.js @@ -0,0 +1,46 @@ +import { connect } from 'react-redux' +import TopologyListComponent from '../../../../components/app/sidebars/project/TopologyListComponent' +import { setCurrentTopology } from '../../../../actions/topology/building' +import { openNewTopologyModal } from '../../../../actions/modals/topology' +import { deleteTopology } from '../../../../actions/topologies' + +const mapStateToProps = state => { + let topologies = state.objects.project[state.currentProjectId] ? state.objects.project[state.currentProjectId].topologyIds.map(t => ( + state.objects.topology[t] + )) : [] + if (topologies.filter(t => !t).length > 0) { + topologies = [] + } + + return { + show: state.modals.changeTopologyModalVisible, + currentTopologyId: state.currentTopologyId, + topologies, + } +} + +const mapDispatchToProps = dispatch => { + return { + onChooseTopology: (id) => { + dispatch( + setCurrentTopology(id), + ) + }, + onNewTopology: () => { + dispatch(openNewTopologyModal()) + }, + onDeleteTopology: (id) => { + if (id) { + dispatch( + deleteTopology(id), + ) + } + }, + } +} + +const TopologyListContainer = connect(mapStateToProps, mapDispatchToProps)( + TopologyListComponent, +) + +export default TopologyListContainer diff --git a/frontend/src/containers/app/sidebars/topology/TopologySidebar.js b/frontend/src/containers/app/sidebars/topology/TopologySidebarContainer.js index 8e929d3d..f9bc10bf 100644 --- a/frontend/src/containers/app/sidebars/topology/TopologySidebar.js +++ b/frontend/src/containers/app/sidebars/topology/TopologySidebarContainer.js @@ -7,6 +7,6 @@ const mapStateToProps = state => { } } -const TopologySidebar = connect(mapStateToProps)(TopologySidebarComponent) +const TopologySidebarContainer = connect(mapStateToProps)(TopologySidebarComponent) -export default TopologySidebar +export default TopologySidebarContainer diff --git a/frontend/src/containers/modals/ChangeTopologyModal.js b/frontend/src/containers/modals/ChangeTopologyModal.js deleted file mode 100644 index 7904ef59..00000000 --- a/frontend/src/containers/modals/ChangeTopologyModal.js +++ /dev/null @@ -1,64 +0,0 @@ -import { connect } from 'react-redux' -import ChangeTopologyModalComponent from '../../components/modals/custom-components/ChangeTopologyModalComponent' -import { closeChangeTopologyModal } from '../../actions/modals/topology' -import { addTopology, deleteTopology } from '../../actions/topologies' -import { setCurrentTopology } from '../../actions/topology/building' - -const mapStateToProps = state => { - let topologies = state.objects.project[state.currentProjectId] ? state.objects.project[state.currentProjectId].topologyIds.map(t => ( - state.objects.topology[t] - )) : [] - if (topologies.filter(t => !t).length > 0) { - topologies = [] - } - - return { - show: state.modals.changeTopologyModalVisible, - currentTopologyId: state.currentTopologyId, - topologies, - } -} - -const mapDispatchToProps = dispatch => { - return { - onChooseTopology: (id) => { - dispatch( - setCurrentTopology(id), - ) - dispatch(closeChangeTopologyModal()) - }, - onCreateTopology: (name) => { - if (name) { - dispatch( - addTopology({ name, rooms: [] }), - ) - } - dispatch(closeChangeTopologyModal()) - }, - onDuplicateTopology: (name) => { - if (name) { - // TODO different handling here - dispatch( - addTopology({ name, rooms: [] }), - ) - } - dispatch(closeChangeTopologyModal()) - }, - onDeleteTopology: (id) => { - if (id) { - dispatch( - deleteTopology(id), - ) - } - }, - onCancel: () => { - dispatch(closeChangeTopologyModal()) - }, - } -} - -const ChangeTopologyModal = connect(mapStateToProps, mapDispatchToProps)( - ChangeTopologyModalComponent, -) - -export default ChangeTopologyModal diff --git a/frontend/src/containers/modals/NewTopologyModal.js b/frontend/src/containers/modals/NewTopologyModal.js new file mode 100644 index 00000000..282f0db9 --- /dev/null +++ b/frontend/src/containers/modals/NewTopologyModal.js @@ -0,0 +1,49 @@ +import { connect } from 'react-redux' +import NewTopologyModalComponent from '../../components/modals/custom-components/NewTopologyModalComponent' +import { closeNewTopologyModal } from '../../actions/modals/topology' +import { addTopology } from '../../actions/topologies' + +const mapStateToProps = state => { + let topologies = state.objects.project[state.currentProjectId] ? state.objects.project[state.currentProjectId].topologyIds.map(t => ( + state.objects.topology[t] + )) : [] + if (topologies.filter(t => !t).length > 0) { + topologies = [] + } + + return { + show: state.modals.changeTopologyModalVisible, + topologies, + } +} + +const mapDispatchToProps = dispatch => { + return { + onCreateTopology: (name) => { + if (name) { + dispatch( + addTopology({ name, rooms: [] }), + ) + } + dispatch(closeNewTopologyModal()) + }, + onDuplicateTopology: (name) => { + if (name) { + // TODO different handling here + dispatch( + addTopology({ name, rooms: [] }), + ) + } + dispatch(closeNewTopologyModal()) + }, + onCancel: () => { + dispatch(closeNewTopologyModal()) + }, + } +} + +const NewTopologyModal = connect(mapStateToProps, mapDispatchToProps)( + NewTopologyModalComponent, +) + +export default NewTopologyModal diff --git a/frontend/src/containers/navigation/AppNavbarContainer.js b/frontend/src/containers/navigation/AppNavbarContainer.js new file mode 100644 index 00000000..bba44d77 --- /dev/null +++ b/frontend/src/containers/navigation/AppNavbarContainer.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import AppNavbarComponent from '../../components/navigation/AppNavbarComponent' + +const mapStateToProps = state => { + return { + project: state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined, + } +} + +const AppNavbarContainer = connect(mapStateToProps)(AppNavbarComponent) + +export default AppNavbarContainer diff --git a/frontend/src/pages/App.js b/frontend/src/pages/App.js index 5075cec0..8f99d1bd 100644 --- a/frontend/src/pages/App.js +++ b/frontend/src/pages/App.js @@ -8,18 +8,19 @@ import { openProjectSucceeded } from '../actions/projects' import { resetCurrentTopology } from '../actions/topology/building' import ToolPanelComponent from '../components/app/map/controls/ToolPanelComponent' import LoadingScreen from '../components/app/map/LoadingScreen' -import AppNavbar from '../components/navigation/AppNavbar' import ScaleIndicatorContainer from '../containers/app/map/controls/ScaleIndicatorContainer' import MapStage from '../containers/app/map/MapStage' -import TopologySidebar from '../containers/app/sidebars/topology/TopologySidebar' +import TopologySidebarContainer from '../containers/app/sidebars/topology/TopologySidebarContainer' import DeleteMachineModal from '../containers/modals/DeleteMachineModal' import DeleteRackModal from '../containers/modals/DeleteRackModal' import DeleteRoomModal from '../containers/modals/DeleteRoomModal' import EditRackNameModal from '../containers/modals/EditRackNameModal' import EditRoomNameModal from '../containers/modals/EditRoomNameModal' import KeymapConfiguration from '../shortcuts/keymap' -import ChangeTopologyModal from '../containers/modals/ChangeTopologyModal' -import { openChangeTopologyModal } from '../actions/modals/topology' +import NewTopologyModal from '../containers/modals/NewTopologyModal' +import { openNewTopologyModal } from '../actions/modals/topology' +import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' +import ProjectSidebarContainer from '../containers/app/sidebars/project/ProjectSidebarContainer' const shortcutManager = new ShortcutManager(KeymapConfiguration) @@ -50,12 +51,7 @@ class AppComponent extends React.Component { title={this.props.projectName ? this.props.projectName + ' - OpenDC' : 'Simulation - OpenDC'} > <div className="page-container full-height"> - <AppNavbar - projectId={this.props.projectId} - inProject={true} - fullWidth={true} - onViewTopologies={this.props.onViewTopologies} - /> + <AppNavbarContainer fullWidth={true} /> {this.props.topologyIsLoading ? ( <div className="full-height d-flex align-items-center justify-content-center"> <LoadingScreen/> @@ -65,10 +61,11 @@ class AppComponent extends React.Component { <MapStage/> <ScaleIndicatorContainer/> <ToolPanelComponent/> - <TopologySidebar/> + <ProjectSidebarContainer/> + <TopologySidebarContainer/> </div> )} - <ChangeTopologyModal/> + <NewTopologyModal/> <EditRoomNameModal/> <DeleteRoomModal/> <EditRackNameModal/> @@ -96,7 +93,7 @@ const mapDispatchToProps = (dispatch) => { return { resetCurrentTopology: () => dispatch(resetCurrentTopology()), openProjectSucceeded: (id) => dispatch(openProjectSucceeded(id)), - onViewTopologies: () => dispatch(openChangeTopologyModal()), + onViewTopologies: () => dispatch(openNewTopologyModal()), openExperimentSucceeded: (projectId, experimentId) => dispatch(openExperimentSucceeded(projectId, experimentId)), } diff --git a/frontend/src/pages/Experiments.js b/frontend/src/pages/Experiments.js deleted file mode 100644 index 66362299..00000000 --- a/frontend/src/pages/Experiments.js +++ /dev/null @@ -1,65 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' -import DocumentTitle from 'react-document-title' -import { connect } from 'react-redux' -import { fetchExperimentsOfProject } from '../actions/experiments' -import { openProjectSucceeded } from '../actions/projects' -import AppNavbar from '../components/navigation/AppNavbar' -import ExperimentListContainer from '../containers/experiments/ExperimentListContainer' -import NewExperimentButtonContainer from '../containers/experiments/NewExperimentButtonContainer' -import NewExperimentModal from '../containers/modals/NewExperimentModal' - -class ExperimentsComponent extends React.Component { - static propTypes = { - projectId: PropTypes.string.isRequired, - projectName: PropTypes.string, - } - - componentDidMount() { - this.props.storeProjectId(this.props.projectId) - this.props.fetchExperimentsOfProject(this.props.projectId) - } - - render() { - return ( - <DocumentTitle - title={ - this.props.projectName - ? 'Experiments - ' + this.props.projectName + ' - OpenDC' - : 'Experiments - OpenDC' - } - > - <div className="full-height"> - <AppNavbar projectId={this.props.projectId} inProject={true} fullWidth={true}/> - <div className="container text-page-container full-height"> - <ExperimentListContainer/> - <NewExperimentButtonContainer/> - </div> - <NewExperimentModal/> - </div> - </DocumentTitle> - ) - } -} - -const mapStateToProps = (state) => { - let projectName = undefined - if (state.currentProjectId !== '-1' && state.objects.project[state.currentProjectId]) { - projectName = state.objects.project[state.currentProjectId].name - } - - return { - projectName, - } -} - -const mapDispatchToProps = (dispatch) => { - return { - storeProjectId: (id) => dispatch(openProjectSucceeded(id)), - fetchExperimentsOfProject: (id) => dispatch(fetchExperimentsOfProject(id)), - } -} - -const Experiments = connect(mapStateToProps, mapDispatchToProps)(ExperimentsComponent) - -export default Experiments diff --git a/frontend/src/pages/Profile.js b/frontend/src/pages/Profile.js index 00bf903e..527dc721 100644 --- a/frontend/src/pages/Profile.js +++ b/frontend/src/pages/Profile.js @@ -2,13 +2,13 @@ import React from 'react' import DocumentTitle from 'react-document-title' import { connect } from 'react-redux' import { openDeleteProfileModal } from '../actions/modals/profile' -import AppNavbar from '../components/navigation/AppNavbar' import DeleteProfileModal from '../containers/modals/DeleteProfileModal' +import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' const ProfileContainer = ({ onDelete }) => ( <DocumentTitle title="My Profile - OpenDC"> <div className="full-height"> - <AppNavbar inProject={false} fullWidth={false}/> + <AppNavbarContainer fullWidth={false}/> <div className="container text-page-container full-height"> <button className="btn btn-danger mb-2 ml-auto mr-auto" style={{ maxWidth: 300 }} onClick={onDelete}> Delete my account on OpenDC diff --git a/frontend/src/pages/Projects.js b/frontend/src/pages/Projects.js index 450ff695..f4af10c3 100644 --- a/frontend/src/pages/Projects.js +++ b/frontend/src/pages/Projects.js @@ -3,11 +3,11 @@ import DocumentTitle from 'react-document-title' import { connect } from 'react-redux' import { openNewProjectModal } from '../actions/modals/projects' import { fetchAuthorizationsOfCurrentUser } from '../actions/users' -import AppNavbar from '../components/navigation/AppNavbar' import ProjectFilterPanel from '../components/projects/FilterPanel' import NewProjectModal from '../containers/modals/NewProjectModal' import NewProjectButtonContainer from '../containers/projects/NewProjectButtonContainer' import VisibleProjectList from '../containers/projects/VisibleProjectAuthList' +import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' class ProjectsContainer extends React.Component { componentDidMount() { @@ -18,7 +18,7 @@ class ProjectsContainer extends React.Component { return ( <DocumentTitle title="My Projects - OpenDC"> <div className="full-height"> - <AppNavbar inProject={false} fullWidth={false}/> + <AppNavbarContainer fullWidth={false}/> <div className="container text-page-container full-height"> <ProjectFilterPanel/> <VisibleProjectList/> diff --git a/frontend/src/reducers/modals.js b/frontend/src/reducers/modals.js index a042aaea..77927cff 100644 --- a/frontend/src/reducers/modals.js +++ b/frontend/src/reducers/modals.js @@ -4,13 +4,13 @@ import { CLOSE_NEW_EXPERIMENT_MODAL, OPEN_NEW_EXPERIMENT_MODAL } from '../action import { CLOSE_DELETE_PROFILE_MODAL, OPEN_DELETE_PROFILE_MODAL } from '../actions/modals/profile' import { CLOSE_NEW_PROJECT_MODAL, OPEN_NEW_PROJECT_MODAL } from '../actions/modals/projects' import { - CLOSE_CHANGE_TOPOLOGY_MODAL, + CLOSE_NEW_TOPOLOGY_MODAL, CLOSE_DELETE_MACHINE_MODAL, CLOSE_DELETE_RACK_MODAL, CLOSE_DELETE_ROOM_MODAL, CLOSE_EDIT_RACK_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL, - OPEN_CHANGE_TOPOLOGY_MODAL, + OPEN_NEW_TOPOLOGY_MODAL, OPEN_DELETE_MACHINE_MODAL, OPEN_DELETE_RACK_MODAL, OPEN_DELETE_ROOM_MODAL, @@ -35,7 +35,7 @@ function modal(openAction, closeAction) { export const modals = combineReducers({ newProjectModalVisible: modal(OPEN_NEW_PROJECT_MODAL, CLOSE_NEW_PROJECT_MODAL), deleteProfileModalVisible: modal(OPEN_DELETE_PROFILE_MODAL, CLOSE_DELETE_PROFILE_MODAL), - changeTopologyModalVisible: modal(OPEN_CHANGE_TOPOLOGY_MODAL, CLOSE_CHANGE_TOPOLOGY_MODAL), + changeTopologyModalVisible: modal(OPEN_NEW_TOPOLOGY_MODAL, CLOSE_NEW_TOPOLOGY_MODAL), editRoomNameModalVisible: modal(OPEN_EDIT_ROOM_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL), deleteRoomModalVisible: modal(OPEN_DELETE_ROOM_MODAL, CLOSE_DELETE_ROOM_MODAL), editRackNameModalVisible: modal(OPEN_EDIT_RACK_NAME_MODAL, CLOSE_EDIT_RACK_NAME_MODAL), |
