diff options
Diffstat (limited to 'frontend/src/pages')
| -rw-r--r-- | frontend/src/pages/App.js | 125 | ||||
| -rw-r--r-- | frontend/src/pages/Experiments.js | 75 | ||||
| -rw-r--r-- | frontend/src/pages/Home.js | 62 | ||||
| -rw-r--r-- | frontend/src/pages/Home.sass | 9 | ||||
| -rw-r--r-- | frontend/src/pages/NotFound.js | 14 | ||||
| -rw-r--r-- | frontend/src/pages/NotFound.sass | 11 | ||||
| -rw-r--r-- | frontend/src/pages/Profile.js | 40 | ||||
| -rw-r--r-- | frontend/src/pages/Simulations.js | 46 |
8 files changed, 382 insertions, 0 deletions
diff --git a/frontend/src/pages/App.js b/frontend/src/pages/App.js new file mode 100644 index 00000000..ad201e7d --- /dev/null +++ b/frontend/src/pages/App.js @@ -0,0 +1,125 @@ +import PropTypes from "prop-types"; +import React from "react"; +import DocumentTitle from "react-document-title"; +import { connect } from "react-redux"; +import { ShortcutManager } from "react-shortcuts"; +import { openExperimentSucceeded } from "../actions/experiments"; +import { openSimulationSucceeded } from "../actions/simulations"; +import { resetCurrentDatacenter } from "../actions/topology/building"; +import ToolPanelComponent from "../components/app/map/controls/ToolPanelComponent"; +import LoadingScreen from "../components/app/map/LoadingScreen"; +import SimulationSidebarComponent from "../components/app/sidebars/simulation/SimulationSidebarComponent"; +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 TimelineContainer from "../containers/app/timeline/TimelineContainer"; +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"; + +const shortcutManager = new ShortcutManager(KeymapConfiguration); + +class AppComponent extends React.Component { + static propTypes = { + simulationId: PropTypes.number.isRequired, + inSimulation: PropTypes.bool, + experimentId: PropTypes.number, + simulationName: PropTypes.string + }; + static childContextTypes = { + shortcuts: PropTypes.object.isRequired + }; + + componentDidMount() { + this.props.resetCurrentDatacenter(); + if (this.props.inSimulation) { + this.props.openExperimentSucceeded( + this.props.simulationId, + this.props.experimentId + ); + return; + } + this.props.openSimulationSucceeded(this.props.simulationId); + } + + getChildContext() { + return { + shortcuts: shortcutManager + }; + } + + render() { + return ( + <DocumentTitle + title={ + this.props.simulationName + ? this.props.simulationName + " - OpenDC" + : "Simulation - OpenDC" + } + > + <div className="page-container full-height"> + <AppNavbar + simulationId={this.props.simulationId} + inSimulation={true} + fullWidth={true} + /> + {this.props.datacenterIsLoading ? ( + <div className="full-height d-flex align-items-center justify-content-center"> + <LoadingScreen /> + </div> + ) : ( + <div className="full-height"> + <MapStage /> + <ScaleIndicatorContainer /> + <ToolPanelComponent /> + <TopologySidebar /> + {this.props.inSimulation ? <TimelineContainer /> : undefined} + {this.props.inSimulation ? ( + <SimulationSidebarComponent /> + ) : ( + undefined + )} + </div> + )} + <EditRoomNameModal /> + <DeleteRoomModal /> + <EditRackNameModal /> + <DeleteRackModal /> + <DeleteMachineModal /> + </div> + </DocumentTitle> + ); + } +} + +const mapStateToProps = state => { + let simulationName = undefined; + if ( + state.currentSimulationId !== -1 && + state.objects.simulation[state.currentSimulationId] + ) { + simulationName = state.objects.simulation[state.currentSimulationId].name; + } + + return { + datacenterIsLoading: state.currentDatacenterId === -1, + simulationName + }; +}; + +const mapDispatchToProps = dispatch => { + return { + resetCurrentDatacenter: () => dispatch(resetCurrentDatacenter()), + openSimulationSucceeded: id => dispatch(openSimulationSucceeded(id)), + openExperimentSucceeded: (simulationId, experimentId) => + dispatch(openExperimentSucceeded(simulationId, experimentId)) + }; +}; + +const App = connect(mapStateToProps, mapDispatchToProps)(AppComponent); + +export default App; diff --git a/frontend/src/pages/Experiments.js b/frontend/src/pages/Experiments.js new file mode 100644 index 00000000..2f73cd7e --- /dev/null +++ b/frontend/src/pages/Experiments.js @@ -0,0 +1,75 @@ +import PropTypes from "prop-types"; +import React from "react"; +import DocumentTitle from "react-document-title"; +import { connect } from "react-redux"; +import { fetchExperimentsOfSimulation } from "../actions/experiments"; +import { openSimulationSucceeded } from "../actions/simulations"; +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 = { + simulationId: PropTypes.number.isRequired, + simulationName: PropTypes.string + }; + + componentDidMount() { + this.props.storeSimulationId(this.props.simulationId); + this.props.fetchExperimentsOfSimulation(this.props.simulationId); + } + + render() { + return ( + <DocumentTitle + title={ + this.props.simulationName + ? "Experiments - " + this.props.simulationName + " - OpenDC" + : "Experiments - OpenDC" + } + > + <div className="full-height"> + <AppNavbar + simulationId={this.props.simulationId} + inSimulation={true} + fullWidth={true} + /> + <div className="container text-page-container full-height"> + <ExperimentListContainer /> + <NewExperimentButtonContainer /> + </div> + <NewExperimentModal /> + </div> + </DocumentTitle> + ); + } +} + +const mapStateToProps = state => { + let simulationName = undefined; + if ( + state.currentSimulationId !== -1 && + state.objects.simulation[state.currentSimulationId] + ) { + simulationName = state.objects.simulation[state.currentSimulationId].name; + } + + return { + simulationName + }; +}; + +const mapDispatchToProps = dispatch => { + return { + storeSimulationId: id => dispatch(openSimulationSucceeded(id)), + fetchExperimentsOfSimulation: id => + dispatch(fetchExperimentsOfSimulation(id)) + }; +}; + +const Experiments = connect(mapStateToProps, mapDispatchToProps)( + ExperimentsComponent +); + +export default Experiments; diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js new file mode 100644 index 00000000..f6479722 --- /dev/null +++ b/frontend/src/pages/Home.js @@ -0,0 +1,62 @@ +import React from "react"; +import DocumentTitle from "react-document-title"; +import ContactSection from "../components/home/ContactSection"; +import IntroSection from "../components/home/IntroSection"; +import JumbotronHeader from "../components/home/JumbotronHeader"; +import ModelingSection from "../components/home/ModelingSection"; +import SimulationSection from "../components/home/SimulationSection"; +import StakeholderSection from "../components/home/StakeholderSection"; +import TeamSection from "../components/home/TeamSection"; +import TechnologiesSection from "../components/home/TechnologiesSection"; +import HomeNavbar from "../components/navigation/HomeNavbar"; +import jQuery from "../util/jquery"; +import "./Home.css"; + +class Home extends React.Component { + state = { + scrollSpySetup: false + }; + + componentDidMount() { + const scrollOffset = 60; + jQuery("#navbar") + .find("li a") + .click(function(e) { + if (jQuery(e.target).parents(".auth-links").length > 0) { + return; + } + e.preventDefault(); + jQuery(jQuery(this).attr("href"))[0].scrollIntoView(); + window.scrollBy(0, -scrollOffset); + }); + + if (!this.state.scrollSpySetup) { + jQuery("body").scrollspy({ + target: "#navbar", + offset: scrollOffset + }); + this.setState({ scrollSpySetup: true }); + } + } + + render() { + return ( + <div> + <HomeNavbar /> + <div className="body-wrapper page-container"> + <JumbotronHeader /> + <IntroSection /> + <StakeholderSection /> + <ModelingSection /> + <SimulationSection /> + <TechnologiesSection /> + <TeamSection /> + <ContactSection /> + <DocumentTitle title="OpenDC" /> + </div> + </div> + ); + } +} + +export default Home; diff --git a/frontend/src/pages/Home.sass b/frontend/src/pages/Home.sass new file mode 100644 index 00000000..9c812db2 --- /dev/null +++ b/frontend/src/pages/Home.sass @@ -0,0 +1,9 @@ +.body-wrapper + position: relative + overflow-y: hidden + +.intro-section, .modeling-section, .technologies-section + background-color: #fff + +.stakeholder-section, .simulation-section, .team-section + background-color: #f2f2f2 diff --git a/frontend/src/pages/NotFound.js b/frontend/src/pages/NotFound.js new file mode 100644 index 00000000..b344e923 --- /dev/null +++ b/frontend/src/pages/NotFound.js @@ -0,0 +1,14 @@ +import React from "react"; +import DocumentTitle from "react-document-title"; +import TerminalWindow from "../components/not-found/TerminalWindow"; +import "./NotFound.css"; + +const NotFound = () => ( + <DocumentTitle title="Page Not Found - OpenDC"> + <div className="not-found-backdrop"> + <TerminalWindow /> + </div> + </DocumentTitle> +); + +export default NotFound; diff --git a/frontend/src/pages/NotFound.sass b/frontend/src/pages/NotFound.sass new file mode 100644 index 00000000..9457da01 --- /dev/null +++ b/frontend/src/pages/NotFound.sass @@ -0,0 +1,11 @@ +.not-found-backdrop + position: absolute + left: 0 + top: 0 + + margin: 0 + padding: 0 + width: 100% + height: 100% + + background-image: linear-gradient(135deg, #00678a, #008fbf, #00A6D6) diff --git a/frontend/src/pages/Profile.js b/frontend/src/pages/Profile.js new file mode 100644 index 00000000..106ec97e --- /dev/null +++ b/frontend/src/pages/Profile.js @@ -0,0 +1,40 @@ +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"; + +const ProfileContainer = ({ onDelete }) => ( + <DocumentTitle title="My Profile - OpenDC"> + <div className="full-height"> + <AppNavbar inSimulation={false} 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 + </button> + <p className="text-muted text-center"> + This does not delete your Google account, but simply disconnects it + from the OpenDC platform and deletes any simulation info that is + associated with you (simulations you own and any authorizations you + may have on other projects). + </p> + </div> + <DeleteProfileModal /> + </div> + </DocumentTitle> +); + +const mapDispatchToProps = dispatch => { + return { + onDelete: () => dispatch(openDeleteProfileModal()) + }; +}; + +const Profile = connect(undefined, mapDispatchToProps)(ProfileContainer); + +export default Profile; diff --git a/frontend/src/pages/Simulations.js b/frontend/src/pages/Simulations.js new file mode 100644 index 00000000..ecff8fe6 --- /dev/null +++ b/frontend/src/pages/Simulations.js @@ -0,0 +1,46 @@ +import React from "react"; +import DocumentTitle from "react-document-title"; +import { connect } from "react-redux"; +import { openNewSimulationModal } from "../actions/modals/simulations"; +import { fetchAuthorizationsOfCurrentUser } from "../actions/users"; +import AppNavbar from "../components/navigation/AppNavbar"; +import SimulationFilterPanel from "../components/simulations/FilterPanel"; +import NewSimulationModal from "../containers/modals/NewSimulationModal"; +import NewSimulationButtonContainer from "../containers/simulations/NewSimulationButtonContainer"; +import VisibleSimulationList from "../containers/simulations/VisibleSimulationAuthList"; + +class SimulationsContainer extends React.Component { + componentDidMount() { + this.props.fetchAuthorizationsOfCurrentUser(); + } + + render() { + return ( + <DocumentTitle title="My Simulations - OpenDC"> + <div className="full-height"> + <AppNavbar inSimulation={false} fullWidth={false} /> + <div className="container text-page-container full-height"> + <SimulationFilterPanel /> + <VisibleSimulationList /> + <NewSimulationButtonContainer /> + </div> + <NewSimulationModal /> + </div> + </DocumentTitle> + ); + } +} + +const mapDispatchToProps = dispatch => { + return { + fetchAuthorizationsOfCurrentUser: () => + dispatch(fetchAuthorizationsOfCurrentUser()), + openNewSimulationModal: () => dispatch(openNewSimulationModal()) + }; +}; + +const Simulations = connect(undefined, mapDispatchToProps)( + SimulationsContainer +); + +export default Simulations; |
