diff options
36 files changed, 242 insertions, 311 deletions
diff --git a/src/api/routes/jobs.js b/src/api/routes/jobs.js index 90947a51..e96c12ba 100644 --- a/src/api/routes/jobs.js +++ b/src/api/routes/jobs.js @@ -1,8 +1,4 @@ -import {getAll, getById} from "./util"; - -export function getAllJobs() { - return getAll("/jobs"); -} +import {getById} from "./util"; export function getTasksOfJob(jobId) { return getById("/jobs/{jobId}/tasks", {jobId}); diff --git a/src/api/routes/tasks.js b/src/api/routes/tasks.js deleted file mode 100644 index 69736af8..00000000 --- a/src/api/routes/tasks.js +++ /dev/null @@ -1,5 +0,0 @@ -import {getAll} from "./util"; - -export function getAllTasks() { - return getAll("/tasks"); -} diff --git a/src/components/experiments/ExperimentListComponent.js b/src/components/experiments/ExperimentListComponent.js index 001b0e32..473a7651 100644 --- a/src/components/experiments/ExperimentListComponent.js +++ b/src/components/experiments/ExperimentListComponent.js @@ -2,23 +2,33 @@ import PropTypes from "prop-types"; import React from "react"; import ExperimentRowContainer from "../../containers/experiments/ExperimentRowContainer"; -const ExperimentListComponent = ({experimentIds}) => ( - <table className="table"> - <thead> - <tr> - <th>Name</th> - <th>Path</th> - <th>Trace</th> - <th>Scheduler</th> - </tr> - </thead> - <tbody> - {experimentIds.map(experimentId => ( - <ExperimentRowContainer experimentId={experimentId}/> - ))} - </tbody> - </table> -); +const ExperimentListComponent = ({experimentIds}) => { + return ( + <div className="vertically-expanding-container"> + {experimentIds.length === 0 ? + <div className="alert alert-info"> + <span className="info-icon fa fa-question-circle mr-2"/> + <strong>No experiments here yet...</strong> Add some with the button below! + </div> : + <table className="table"> + <thead> + <tr> + <th>Name</th> + <th>Path</th> + <th>Trace</th> + <th>Scheduler</th> + </tr> + </thead> + <tbody> + {experimentIds.map(experimentId => ( + <ExperimentRowContainer experimentId={experimentId} key={experimentId}/> + ))} + </tbody> + </table> + } + </div> + ); +}; ExperimentListComponent.propTypes = { experimentIds: PropTypes.arrayOf(PropTypes.number).isRequired, diff --git a/src/components/experiments/ExperimentRowComponent.js b/src/components/experiments/ExperimentRowComponent.js index 79ce3eea..fbb0aac7 100644 --- a/src/components/experiments/ExperimentRowComponent.js +++ b/src/components/experiments/ExperimentRowComponent.js @@ -4,7 +4,7 @@ import Shapes from "../../shapes/index"; const ExperimentRowComponent = ({experiment}) => ( <tr> <td>{experiment.name}</td> - <td>{experiment.path.name}</td> + <td>{experiment.path.name ? experiment.path.name : "Path " + experiment.path.id}</td> <td>{experiment.trace.name}</td> <td>{experiment.scheduler.name}</td> </tr> diff --git a/src/components/experiments/NewExperimentButtonComponent.js b/src/components/experiments/NewExperimentButtonComponent.js new file mode 100644 index 00000000..559a7218 --- /dev/null +++ b/src/components/experiments/NewExperimentButtonComponent.js @@ -0,0 +1,17 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +const NewExperimentButtonComponent = ({onClick}) => ( + <div className="bottom-btn-container"> + <div className="btn btn-primary float-right" onClick={onClick}> + <span className="fa fa-plus mr-2"/> + New Experiment + </div> + </div> +); + +NewExperimentButtonComponent.propTypes = { + onClick: PropTypes.func.isRequired, +}; + +export default NewExperimentButtonComponent; diff --git a/src/components/modals/TextInputModal.js b/src/components/modals/TextInputModal.js index e4a55372..132df9fe 100644 --- a/src/components/modals/TextInputModal.js +++ b/src/components/modals/TextInputModal.js @@ -38,7 +38,7 @@ class TextInputModal extends React.Component { this.onSubmit(); }}> <div className="form-group"> - <label className="form-control-label">{this.props.label}:</label> + <label className="form-control-label">{this.props.label}</label> <input type="text" className="form-control" ref={textInput => this.textInput = textInput}/> </div> diff --git a/src/components/modals/custom-components/NewExperimentModalComponent.js b/src/components/modals/custom-components/NewExperimentModalComponent.js index 9efccc8a..d56d2316 100644 --- a/src/components/modals/custom-components/NewExperimentModalComponent.js +++ b/src/components/modals/custom-components/NewExperimentModalComponent.js @@ -20,8 +20,12 @@ class NewExperimentModalComponent extends React.Component { } onSubmit() { - this.props.callback(this.textInput.value, this.pathSelect.value, this.traceSelect.value, - this.schedulerSelect.value); + this.props.callback( + this.textInput.value, + parseInt(this.pathSelect.value, 10), + parseInt(this.traceSelect.value, 10), + this.schedulerSelect.value + ); this.reset(); } @@ -41,23 +45,23 @@ class NewExperimentModalComponent extends React.Component { this.onSubmit(); }}> <div className="form-group"> - <label className="form-control-label">Name:</label> + <label className="form-control-label">Name</label> <input type="text" className="form-control" ref={textInput => this.textInput = textInput}/> </div> <div className="form-group"> - <label className="form-control-label">Path:</label> + <label className="form-control-label">Path</label> <select className="form-control" ref={pathSelect => this.pathSelect = pathSelect}> {this.props.paths.map(path => ( <option value={path.id} key={path.id}> - {path.name} + {path.name ? path.name : "Path " + path.id} </option> ))} </select> </div> <div className="form-group"> - <label className="form-control-label">Trace:</label> + <label className="form-control-label">Trace</label> <select className="form-control" ref={traceSelect => this.traceSelect = traceSelect}> {this.props.traces.map(trace => ( @@ -68,7 +72,7 @@ class NewExperimentModalComponent extends React.Component { </select> </div> <div className="form-group"> - <label className="form-control-label">Scheduler:</label> + <label className="form-control-label">Scheduler</label> <select className="form-control" ref={schedulerSelect => this.schedulerSelect = schedulerSelect}> {this.props.schedulers.map(scheduler => ( diff --git a/src/components/simulations/FilterButton.js b/src/components/simulations/FilterButton.js index 2105d281..f95c35fa 100644 --- a/src/components/simulations/FilterButton.js +++ b/src/components/simulations/FilterButton.js @@ -1,17 +1,16 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import "./FilterButton.css"; const FilterButton = ({active, children, onClick}) => ( - <div className={classNames("simulation-filter-button", {"active": active})} - onClick={() => { + <button className={classNames("btn btn-secondary", {"active": active})} + onClick={() => { if (!active) { onClick(); } }}> {children} - </div> + </button> ); FilterButton.propTypes = { diff --git a/src/components/simulations/FilterButton.sass b/src/components/simulations/FilterButton.sass deleted file mode 100644 index 698bc9a4..00000000 --- a/src/components/simulations/FilterButton.sass +++ /dev/null @@ -1,18 +0,0 @@ -@import ../../style-globals/_mixins.sass -@import ../../style-globals/_variables.sass - -.simulation-filter-button - display: inline-block - width: 33.3% - padding: 10px $global-padding - - font-size: 12pt - - +clickable - +transition(background, $transition-length) - -.simulation-filter-button:hover - background: #0c60bf - -.simulation-filter-button:active, .simulation-filter-button.active - background: #073d7d diff --git a/src/components/simulations/FilterPanel.js b/src/components/simulations/FilterPanel.js index 811da005..504e24e4 100644 --- a/src/components/simulations/FilterPanel.js +++ b/src/components/simulations/FilterPanel.js @@ -3,12 +3,10 @@ import FilterLink from "../../containers/simulations/FilterLink"; import "./FilterPanel.css"; const FilterPanel = () => ( - <div className="filter-menu"> - <div className="simulation-filters"> - <FilterLink filter="SHOW_ALL">All Simulations</FilterLink> - <FilterLink filter="SHOW_OWN">My Simulations</FilterLink> - <FilterLink filter="SHOW_SHARED">Shared with me</FilterLink> - </div> + <div className="btn-group filter-panel mb-2"> + <FilterLink filter="SHOW_ALL">All Simulations</FilterLink> + <FilterLink filter="SHOW_OWN">My Simulations</FilterLink> + <FilterLink filter="SHOW_SHARED">Shared with me</FilterLink> </div> ); diff --git a/src/components/simulations/FilterPanel.sass b/src/components/simulations/FilterPanel.sass index 70401dcb..e10e4746 100644 --- a/src/components/simulations/FilterPanel.sass +++ b/src/components/simulations/FilterPanel.sass @@ -1,20 +1,5 @@ -@import ../../style-globals/_mixins.sass -@import ../../style-globals/_variables.sass +.filter-panel + display: flex -.filter-menu - display: block - - background: #0761b1 - color: #eee - - text-align: center - - +border-radius(25px) - overflow: hidden - - margin-bottom: 20px - - .simulation-filters - display: block - overflow: hidden - margin: 0 -1px + button + flex: 1 !important diff --git a/src/components/simulations/NewSimulationButton.js b/src/components/simulations/NewSimulationButton.js deleted file mode 100644 index 468f7678..00000000 --- a/src/components/simulations/NewSimulationButton.js +++ /dev/null @@ -1,16 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import './NewSimulationButton.css'; - -const NewSimulationButton = ({onClick}) => ( - <div className="new-simulation-btn" onClick={onClick}> - <span className="fa fa-plus"/> - New Simulation - </div> -); - -NewSimulationButton.propTypes = { - onClick: PropTypes.func.isRequired, -}; - -export default NewSimulationButton; diff --git a/src/components/simulations/NewSimulationButton.sass b/src/components/simulations/NewSimulationButton.sass deleted file mode 100644 index 9bf82c49..00000000 --- a/src/components/simulations/NewSimulationButton.sass +++ /dev/null @@ -1,31 +0,0 @@ -@import ../../style-globals/_mixins.sass -@import ../../style-globals/_variables.sass - -.new-simulation-btn - $button-height: 35px - - display: inline-block - position: absolute - bottom: $navbar-height + 40px - right: 40px - padding: 0 10px - height: $button-height - line-height: $button-height - font-size: 14pt - - background: #679436 - color: #eee - border: 1px solid #507830 - - +border-radius($standard-border-radius) - +clickable - +transition(all, $transition-length) - - span - margin-right: 10px - -.new-simulation-btn:hover - background: #73ac45 - -.new-simulation-btn:active - background: #5c8835 diff --git a/src/components/simulations/NewSimulationButtonComponent.js b/src/components/simulations/NewSimulationButtonComponent.js new file mode 100644 index 00000000..74036c1b --- /dev/null +++ b/src/components/simulations/NewSimulationButtonComponent.js @@ -0,0 +1,17 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +const NewSimulationButtonComponent = ({onClick}) => ( + <div className="bottom-btn-container"> + <div className="btn btn-primary float-right" onClick={onClick}> + <span className="fa fa-plus mr-2"/> + New Simulation + </div> + </div> +); + +NewSimulationButtonComponent.propTypes = { + onClick: PropTypes.func.isRequired, +}; + +export default NewSimulationButtonComponent; diff --git a/src/components/simulations/NoSimulationsAlert.js b/src/components/simulations/NoSimulationsAlert.js deleted file mode 100644 index d688ae56..00000000 --- a/src/components/simulations/NoSimulationsAlert.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import "./NoSimulationsAlert.css"; - -const NoSimulationsAlert = () => ( - <div className="no-simulations-alert alert alert-info"> - <span className="info-icon fa fa-2x fa-question-circle"/> - <strong>No simulations here yet...</strong> Add some with the 'New Simulation' button! - </div> -); - -export default NoSimulationsAlert; diff --git a/src/components/simulations/NoSimulationsAlert.sass b/src/components/simulations/NoSimulationsAlert.sass deleted file mode 100644 index 10e89e51..00000000 --- a/src/components/simulations/NoSimulationsAlert.sass +++ /dev/null @@ -1,10 +0,0 @@ -.no-simulations-alert - position: relative - padding-left: 50px - - .info-icon - position: absolute - top: 11px - left: 15px - bottom: 10px - font-size: 20pt diff --git a/src/components/simulations/SimulationActionButtons.js b/src/components/simulations/SimulationActionButtons.js index 29872fcb..1cb80c94 100644 --- a/src/components/simulations/SimulationActionButtons.js +++ b/src/components/simulations/SimulationActionButtons.js @@ -3,7 +3,7 @@ import React from 'react'; import {Link} from "react-router-dom"; const SimulationActionButtons = ({simulationId, onViewUsers, onDelete}) => ( - <div className="simulation-icons"> + <td className="simulation-icons"> <Link to={"/simulations/" + simulationId} className="open" title="Open this simulation"> <span className="fa fa-play"/> </Link> @@ -14,7 +14,7 @@ const SimulationActionButtons = ({simulationId, onViewUsers, onDelete}) => ( <div className="delete" title="Delete this simulation" onClick={() => onDelete(simulationId)}> <span className="fa fa-trash"/> </div> - </div> + </td> ); SimulationActionButtons.propTypes = { diff --git a/src/components/simulations/SimulationAuthList.js b/src/components/simulations/SimulationAuthList.js index 7653f178..fd5173a8 100644 --- a/src/components/simulations/SimulationAuthList.js +++ b/src/components/simulations/SimulationAuthList.js @@ -1,27 +1,33 @@ import PropTypes from 'prop-types'; import React from 'react'; import Shapes from "../../shapes/index"; -import NoSimulationsAlert from "./NoSimulationsAlert"; -import SimulationAuth from "./SimulationAuth"; import "./SimulationAuthList.css"; +import SimulationAuthRow from "./SimulationAuthRow"; const SimulationAuthList = ({authorizations}) => { - if (authorizations.length === 0) { - return <NoSimulationsAlert/>; - } - return ( - <div className="simulation-list"> - <div className="list-head"> - <div>Simulation name</div> - <div>Last edited</div> - <div>Access rights</div> - </div> - <div className="list-body"> - {authorizations.map(authorization => ( - <SimulationAuth simulationAuth={authorization} key={authorization.simulation.id}/> - ))} - </div> + <div className="vertically-expanding-container"> + {authorizations.length === 0 ? + <div className="alert alert-info"> + <span className="info-icon fa fa-question-circle mr-2"/> + <strong>No simulations here yet...</strong> Add some with the 'New Simulation' button! + </div> : + <table className="table"> + <thead> + <tr> + <th>Simulation name</th> + <th>Last edited</th> + <th>Access rights</th> + <th/> + </tr> + </thead> + <tbody> + {authorizations.map(authorization => ( + <SimulationAuthRow simulationAuth={authorization} key={authorization.simulation.id}/> + ))} + </tbody> + </table> + } </div> ); }; diff --git a/src/components/simulations/SimulationAuthList.sass b/src/components/simulations/SimulationAuthList.sass index cb1fe4cc..b09c7869 100644 --- a/src/components/simulations/SimulationAuthList.sass +++ b/src/components/simulations/SimulationAuthList.sass @@ -1,70 +1,15 @@ @import ../../style-globals/_mixins.sass @import ../../style-globals/_variables.sass -.simulation-list - display: block - font-size: 12pt - border: 0 - - .list-head, .list-body .simulation-row - display: block - position: relative - - .list-head div, .list-body .simulation-row div - padding: 0 10px - display: inline-block - - .list-head - font-weight: bold - - // Address default margin between inline-blocks - div - margin-right: -4px - -.simulation-row - background: #f8f8f8 - border: 1px solid #b6b6b6 - height: 40px - line-height: 40px - clear: both - -.simulation-row:not(:first-of-type) - margin-top: -1px - -// Sizing of table columns -.simulation-row, .simulation-list .list-head - div:first-of-type - width: 40% - - div:nth-of-type(2) - width: 20% - - div:nth-of-type(3) - width: 20% - - div:last-of-type - width: 20% - - span - margin-right: 10px - -.simulation-row > div:not(:first-of-type) - padding-left: 0 !important - -.simulation-list .list-head > div:not(:first-of-type) - padding-left: 5px !important - .simulation-icons text-align: right - padding-right: 0 !important -.simulation-row .simulation-icons div, .simulation-row .simulation-icons a +.simulation-icons div, .simulation-icons a display: inline-block - position: relative - top: 4px - width: 30px - height: 30px + width: 35px + height: 35px margin-right: 5px + padding: 5px font-size: 12pt color: white +border-radius(100%) @@ -73,17 +18,13 @@ span position: relative - top: -4px - left: -1px + left: -6px background-color: $blue-dark &.open $icon-color: #0a00bf - span - left: 1px - &:hover background: lighten($icon-color, 10%) @@ -91,11 +32,10 @@ background: darken($icon-color, 10%) &.users - font-size: 10pt $icon-color: #17bf55 span - left: -2px + left: -3px &:hover background: $icon-color diff --git a/src/components/simulations/SimulationAuth.js b/src/components/simulations/SimulationAuthRow.js index 9b887991..26e01570 100644 --- a/src/components/simulations/SimulationAuth.js +++ b/src/components/simulations/SimulationAuthRow.js @@ -5,20 +5,20 @@ import Shapes from "../../shapes/index"; import {AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP} from "../../util/authorizations"; import {parseAndFormatDateTime} from "../../util/date-time"; -const SimulationAuth = ({simulationAuth}) => ( - <div className="simulation-row"> - <div>{simulationAuth.simulation.name}</div> - <div>{parseAndFormatDateTime(simulationAuth.simulation.datetimeLastEdited)}</div> - <div> - <span className={classNames("fa", "fa-" + AUTH_ICON_MAP[simulationAuth.authorizationLevel])}/> +const SimulationAuthRow = ({simulationAuth}) => ( + <tr> + <td>{simulationAuth.simulation.name}</td> + <td>{parseAndFormatDateTime(simulationAuth.simulation.datetimeLastEdited)}</td> + <td> + <span className={classNames("fa", "fa-" + AUTH_ICON_MAP[simulationAuth.authorizationLevel], "mr-2")}/> {AUTH_DESCRIPTION_MAP[simulationAuth.authorizationLevel]} - </div> + </td> <SimulationActions simulationId={simulationAuth.simulation.id}/> - </div> + </tr> ); -SimulationAuth.propTypes = { +SimulationAuthRow.propTypes = { simulationAuth: Shapes.Authorization.isRequired, }; -export default SimulationAuth; +export default SimulationAuthRow; diff --git a/src/containers/experiments/ExperimentListContainer.js b/src/containers/experiments/ExperimentListContainer.js index 38e5a9f6..0c6818fa 100644 --- a/src/containers/experiments/ExperimentListContainer.js +++ b/src/containers/experiments/ExperimentListContainer.js @@ -2,7 +2,7 @@ import {connect} from "react-redux"; import ExperimentListComponent from "../../components/experiments/ExperimentListComponent"; const mapStateToProps = state => { - if (!state.currentSimulationId) { + if (state.currentSimulationId === -1 || !("experimentIds" in state.objects.simulation[state.currentSimulationId])) { return { experimentIds: [], }; @@ -14,10 +14,6 @@ const mapStateToProps = state => { experimentIds, }; } - - return { - experimentIds: [], - }; }; const ExperimentListContainer = connect( diff --git a/src/containers/experiments/NewExperimentButtonContainer.js b/src/containers/experiments/NewExperimentButtonContainer.js new file mode 100644 index 00000000..1abbb7b7 --- /dev/null +++ b/src/containers/experiments/NewExperimentButtonContainer.js @@ -0,0 +1,16 @@ +import {connect} from "react-redux"; +import {openNewExperimentModal} from "../../actions/modals/experiments"; +import NewExperimentButtonComponent from "../../components/experiments/NewExperimentButtonComponent"; + +const mapDispatchToProps = dispatch => { + return { + onClick: () => dispatch(openNewExperimentModal()) + }; +}; + +const NewExperimentButtonContainer = connect( + undefined, + mapDispatchToProps +)(NewExperimentButtonComponent); + +export default NewExperimentButtonContainer; diff --git a/src/containers/simulations/NewSimulationButtonContainer.js b/src/containers/simulations/NewSimulationButtonContainer.js new file mode 100644 index 00000000..722f8e44 --- /dev/null +++ b/src/containers/simulations/NewSimulationButtonContainer.js @@ -0,0 +1,16 @@ +import {connect} from "react-redux"; +import {openNewSimulationModal} from "../../actions/modals/simulations"; +import NewSimulationButtonComponent from "../../components/simulations/NewSimulationButtonComponent"; + +const mapDispatchToProps = dispatch => { + return { + onClick: () => dispatch(openNewSimulationModal()) + }; +}; + +const NewSimulationButtonContainer = connect( + undefined, + mapDispatchToProps +)(NewSimulationButtonComponent); + +export default NewSimulationButtonContainer; diff --git a/src/containers/simulations/VisibleSimulationAuthList.js b/src/containers/simulations/VisibleSimulationAuthList.js index 578ae303..324608c6 100644 --- a/src/containers/simulations/VisibleSimulationAuthList.js +++ b/src/containers/simulations/VisibleSimulationAuthList.js @@ -1,6 +1,5 @@ import {connect} from "react-redux"; import SimulationList from "../../components/simulations/SimulationAuthList"; -import {denormalize} from "../../store/denormalizer"; const getVisibleSimulationAuths = (simulationAuths, filter) => { switch (filter) { @@ -16,9 +15,12 @@ const getVisibleSimulationAuths = (simulationAuths, filter) => { }; const mapStateToProps = state => { - const denormalizedAuthorizations = state.simulationList.authorizationsOfCurrentUser.map(authorizationIds => - denormalize(state, "authorization", authorizationIds) - ); + const denormalizedAuthorizations = state.simulationList.authorizationsOfCurrentUser.map(authorizationIds => { + const authorization = state.objects.authorization[authorizationIds]; + authorization.user = state.objects.user[authorization.userId]; + authorization.simulation = state.objects.simulation[authorization.simulationId]; + return authorization; + }); return { authorizations: getVisibleSimulationAuths(denormalizedAuthorizations, state.simulationList.authVisibilityFilter) diff --git a/src/index.sass b/src/index.sass index 54a426f9..09be977d 100644 --- a/src/index.sass +++ b/src/index.sass @@ -18,6 +18,16 @@ html, body, #root .text-page-container padding-top: 80px + display: flex + flex-flow: column + +.vertically-expanding-container + flex: 1 1 auto + overflow-y: auto + +.bottom-btn-container + flex: 0 1 auto + padding: 20px 0 .btn, .list-group-item-action +clickable diff --git a/src/pages/Experiments.js b/src/pages/Experiments.js index d1d19d9f..71b9cfc9 100644 --- a/src/pages/Experiments.js +++ b/src/pages/Experiments.js @@ -5,6 +5,7 @@ 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 { @@ -23,6 +24,7 @@ class ExperimentsComponent extends React.Component { <AppNavbar simulationId={this.props.simulationId} inSimulation={true}/> <div className="container text-page-container full-height"> <ExperimentListContainer/> + <NewExperimentButtonContainer/> </div> <NewExperimentModal/> </div> diff --git a/src/pages/Simulations.js b/src/pages/Simulations.js index 33e04a9d..d06fe43d 100644 --- a/src/pages/Simulations.js +++ b/src/pages/Simulations.js @@ -4,8 +4,8 @@ import {openNewSimulationModal} from "../actions/modals/simulations"; import {fetchAuthorizationsOfCurrentUser} from "../actions/users"; import AppNavbar from "../components/navigation/AppNavbar"; import SimulationFilterPanel from "../components/simulations/FilterPanel"; -import NewSimulationButton from "../components/simulations/NewSimulationButton"; import NewSimulationModal from "../containers/modals/NewSimulationModal"; +import NewSimulationButtonContainer from "../containers/simulations/NewSimulationButtonContainer"; import VisibleSimulationList from "../containers/simulations/VisibleSimulationAuthList"; class SimulationsContainer extends React.Component { @@ -20,7 +20,7 @@ class SimulationsContainer extends React.Component { <div className="container text-page-container full-height"> <SimulationFilterPanel/> <VisibleSimulationList/> - <NewSimulationButton onClick={() => {this.props.openNewSimulationModal()}}/> + <NewSimulationButtonContainer/> </div> <NewSimulationModal/> </div> diff --git a/src/reducers/objects.js b/src/reducers/objects.js index b75e9ae6..df148dee 100644 --- a/src/reducers/objects.js +++ b/src/reducers/objects.js @@ -24,6 +24,11 @@ export const objects = combineReducers({ datacenter: object("datacenter"), section: object("section"), path: object("path"), + task: object("task"), + job: object("job"), + trace: object("trace"), + scheduler: object("scheduler"), + experiment: object("experiment"), }); function object(type) { diff --git a/src/sagas/experiments.js b/src/sagas/experiments.js index 0ac919f4..2c5395e8 100644 --- a/src/sagas/experiments.js +++ b/src/sagas/experiments.js @@ -2,13 +2,7 @@ import {call, put, select} from "redux-saga/effects"; import {addPropToStoreObject, addToStore} from "../actions/objects"; import {deleteExperiment} from "../api/routes/experiments"; import {addExperiment, getExperimentsOfSimulation} from "../api/routes/simulations"; -import { - fetchAndStoreAllJobs, - fetchAndStoreAllSchedulers, - fetchAndStoreAllTasks, - fetchAndStoreAllTraces, - fetchAndStorePathsOfSimulation -} from "./objects"; +import {fetchAndStoreAllSchedulers, fetchAndStoreAllTraces, fetchAndStorePathsOfSimulation} from "./objects"; export function* onFetchExperimentsOfSimulation() { try { @@ -22,21 +16,18 @@ export function* onFetchExperimentsOfSimulation() { yield put(addPropToStoreObject("simulation", currentSimulationId, {experimentIds: experiments.map(experiment => experiment.id)})); } catch (error) { - console.log(error); + console.error(error); } } function* fetchExperimentSpecifications() { try { const currentSimulationId = yield select(state => state.currentSimulationId); - yield fetchAndStorePathsOfSimulation(currentSimulationId); - yield fetchAndStoreAllTasks(); - yield fetchAndStoreAllJobs(); yield fetchAndStoreAllTraces(); yield fetchAndStoreAllSchedulers(); } catch (error) { - console.log(error); + console.error(error); } } @@ -44,17 +35,20 @@ export function* onAddExperiment(action) { try { const currentSimulationId = yield select(state => state.currentSimulationId); - const experiment = yield call(addExperiment, currentSimulationId, Object.assign({}, action.experiment, { - id: -1, - simulationId: currentSimulationId - })); + const experiment = yield call(addExperiment, + currentSimulationId, + Object.assign({}, action.experiment, { + id: -1, + simulationId: currentSimulationId + }) + ); yield put(addToStore("experiment", experiment)); - const experimentIds = yield select(state => state.objects.simulation[currentSimulationId]); + const experimentIds = (yield select(state => state.objects.simulation[currentSimulationId])).experimentIds; yield put(addPropToStoreObject("simulation", currentSimulationId, {experimentIds: experimentIds.concat([experiment.id])})); } catch (error) { - console.log(error); + console.error(error); } } @@ -68,6 +62,6 @@ export function* onDeleteExperiment(action) { yield put(addPropToStoreObject("simulation", currentSimulationId, {experimentIds: experimentIds.filter(id => id !== action.id)})); } catch (error) { - console.log(error); + console.error(error); } } diff --git a/src/sagas/index.js b/src/sagas/index.js index e86ef8a1..30ca2f89 100644 --- a/src/sagas/index.js +++ b/src/sagas/index.js @@ -1,7 +1,7 @@ import {takeEvery} from "redux-saga/effects"; import {LOG_IN} from "../actions/auth"; import {ADD_EXPERIMENT, DELETE_EXPERIMENT, FETCH_EXPERIMENTS_OF_SIMULATION} from "../actions/experiments"; -import {ADD_SIMULATION, DELETE_SIMULATION} from "../actions/simulations"; +import {ADD_SIMULATION, DELETE_SIMULATION, OPEN_SIMULATION_SUCCEEDED} from "../actions/simulations"; import { ADD_TILE, CANCEL_NEW_ROOM_CONSTRUCTION, @@ -15,7 +15,7 @@ import {ADD_RACK_TO_TILE, DELETE_ROOM, EDIT_ROOM_NAME} from "../actions/topology import {DELETE_CURRENT_USER, FETCH_AUTHORIZATIONS_OF_CURRENT_USER} from "../actions/users"; import {onAddExperiment, onDeleteExperiment, onFetchExperimentsOfSimulation} from "./experiments"; import {onDeleteCurrentUser} from "./profile"; -import {onSimulationAdd, onSimulationDelete} from "./simulations"; +import {onOpenSimulationSucceeded, onSimulationAdd, onSimulationDelete} from "./simulations"; import { onAddMachine, onAddRackToTile, @@ -43,6 +43,8 @@ export default function* rootSaga() { yield takeEvery(DELETE_CURRENT_USER, onDeleteCurrentUser); + yield takeEvery(OPEN_SIMULATION_SUCCEEDED, onOpenSimulationSucceeded); + yield takeEvery(FETCH_LATEST_DATACENTER, onFetchLatestDatacenter); yield takeEvery(START_NEW_ROOM_CONSTRUCTION, onStartNewRoomConstruction); yield takeEvery(CANCEL_NEW_ROOM_CONSTRUCTION, onCancelNewRoomConstruction); diff --git a/src/sagas/objects.js b/src/sagas/objects.js index 375781be..0a0154cc 100644 --- a/src/sagas/objects.js +++ b/src/sagas/objects.js @@ -1,7 +1,6 @@ import {call, put, select} from "redux-saga/effects"; import {addToStore} from "../actions/objects"; import {getDatacenter, getRoomsOfDatacenter} from "../api/routes/datacenters"; -import {getAllJobs} from "../api/routes/jobs"; import {getPath, getSectionsOfPath} from "../api/routes/paths"; import {getTilesOfRoom} from "../api/routes/rooms"; import {getAllSchedulers} from "../api/routes/schedulers"; @@ -20,7 +19,6 @@ import { getPSU, getStorage } from "../api/routes/specifications"; -import {getAllTasks} from "../api/routes/tasks"; import {getMachinesOfRackByTile, getRackByTile} from "../api/routes/tiles"; import {getAllTraces} from "../api/routes/traces"; import {getUser} from "../api/routes/users"; @@ -132,11 +130,11 @@ export const fetchAndStorePathsOfSimulation = (simulationId) => export const fetchAndStoreAllTraces = () => fetchAndStoreObjects("trace", call(getAllTraces)); -export const fetchAndStoreAllJobs = () => - fetchAndStoreObjects("job", call(getAllJobs)); - -export const fetchAndStoreAllTasks = () => - fetchAndStoreObjects("task", call(getAllTasks)); - -export const fetchAndStoreAllSchedulers = () => - fetchAndStoreObjects("scheduler", call(getAllSchedulers)); +export const fetchAndStoreAllSchedulers = function* () { + const objects = yield call(getAllSchedulers); + for (let index in objects) { + objects[index].id = objects[index].name; + yield put(addToStore("scheduler", objects[index])); + } + return objects; +}; diff --git a/src/sagas/profile.js b/src/sagas/profile.js index 6a72e7c2..5eacbc73 100644 --- a/src/sagas/profile.js +++ b/src/sagas/profile.js @@ -7,6 +7,6 @@ export function* onDeleteCurrentUser(action) { yield call(deleteUser, action.userId); yield put(deleteCurrentUserSucceeded()); } catch (error) { - console.log(error); + console.error(error); } } diff --git a/src/sagas/simulations.js b/src/sagas/simulations.js index b699002e..57eb6bad 100644 --- a/src/sagas/simulations.js +++ b/src/sagas/simulations.js @@ -1,7 +1,16 @@ import {call, put} from "redux-saga/effects"; import {addToStore} from "../actions/objects"; import {addSimulationSucceeded, deleteSimulationSucceeded} from "../actions/simulations"; -import {addSimulation, deleteSimulation} from "../api/routes/simulations"; +import {addSimulation, deleteSimulation, getSimulation} from "../api/routes/simulations"; + +export function* onOpenSimulationSucceeded(action) { + try { + const simulation = yield call(getSimulation, action.id); + yield put(addToStore("simulation", simulation)); + } catch (error) { + console.error(error); + } +} export function* onSimulationAdd(action) { try { @@ -16,7 +25,7 @@ export function* onSimulationAdd(action) { yield put(addToStore("authorization", authorization)); yield put(addSimulationSucceeded([authorization.userId, authorization.simulationId])); } catch (error) { - console.log(error); + console.error(error); } } @@ -25,6 +34,6 @@ export function* onSimulationDelete(action) { yield call(deleteSimulation, action.id); yield put(deleteSimulationSucceeded(action.id)); } catch (error) { - console.log(error); + console.error(error); } } diff --git a/src/sagas/topology.js b/src/sagas/topology.js index d1e42d70..763d4569 100644 --- a/src/sagas/topology.js +++ b/src/sagas/topology.js @@ -57,7 +57,7 @@ export function* onFetchLatestDatacenter(action) { yield fetchDatacenter(latestSection.datacenterId); yield put(fetchLatestDatacenterSucceeded(latestSection.datacenterId)); } catch (error) { - console.log(error); + console.error(error); } } @@ -71,7 +71,7 @@ function* fetchDatacenter(datacenterId) { yield fetchRoom(rooms[index].id); } } catch (error) { - console.log(error); + console.error(error); } } @@ -82,7 +82,7 @@ function* fetchAllUnitSpecifications() { yield fetchAndStoreAllMemories(); yield fetchAndStoreAllStorages(); } catch (error) { - console.log(error); + console.error(error); } } @@ -155,7 +155,7 @@ export function* onStartNewRoomConstruction() { yield put(addIdToStoreObjectListProp("datacenter", datacenterId, "roomIds", room.id)); yield put(startNewRoomConstructionSucceeded(room.id)); } catch (error) { - console.log(error); + console.error(error); } } @@ -167,7 +167,7 @@ export function* onCancelNewRoomConstruction() { yield put(removeIdFromStoreObjectListProp("datacenter", datacenterId, "roomIds", roomId)); yield put(cancelNewRoomConstructionSucceeded()); } catch (error) { - console.log(error); + console.error(error); } } @@ -182,7 +182,7 @@ export function* onAddTile(action) { yield put(addToStore("tile", tile)); yield put(addIdToStoreObjectListProp("room", roomId, "tileIds", tile.id)); } catch (error) { - console.log(error); + console.error(error); } } @@ -192,7 +192,7 @@ export function* onDeleteTile(action) { yield call(deleteTile, action.tileId); yield put(removeIdFromStoreObjectListProp("room", roomId, "tileIds", action.tileId)); } catch (error) { - console.log(error); + console.error(error); } } @@ -204,7 +204,7 @@ export function* onEditRoomName(action) { yield call(updateRoom, room); yield put(addPropToStoreObject("room", roomId, {name: action.name})); } catch (error) { - console.log(error); + console.error(error); } } @@ -216,7 +216,7 @@ export function* onDeleteRoom() { yield put(goDownOneInteractionLevel()); yield put(removeIdFromStoreObjectListProp("datacenter", datacenterId, "roomIds", roomId)); } catch (error) { - console.log(error); + console.error(error); } } @@ -229,7 +229,7 @@ export function* onEditRackName(action) { yield call(updateRackOnTile, tileId, rack); yield put(addPropToStoreObject("rack", rackId, {name: action.name})); } catch (error) { - console.log(error); + console.error(error); } } @@ -241,7 +241,7 @@ export function* onDeleteRack() { yield put(addPropToStoreObject("tile", tileId, {objectType: undefined})); yield put(addPropToStoreObject("tile", tileId, {objectId: undefined})); } catch (error) { - console.log(error); + console.error(error); } } @@ -258,7 +258,7 @@ export function* onAddRackToTile(action) { yield put(addPropToStoreObject("tile", action.tileId, {objectId: rack.id})); yield put(addPropToStoreObject("tile", action.tileId, {objectType: "RACK"})); } catch (error) { - console.log(error); + console.error(error); } } @@ -284,7 +284,7 @@ export function* onAddMachine(action) { machineIds[machine.position - 1] = machine.id; yield put(addPropToStoreObject("rack", rackId, {machineIds})); } catch (error) { - console.log(error); + console.error(error); } } @@ -299,7 +299,7 @@ export function* onDeleteMachine() { yield put(goDownOneInteractionLevel()); yield put(addPropToStoreObject("rack", rack.id, {machineIds})); } catch (error) { - console.log(error); + console.error(error); } } @@ -322,7 +322,7 @@ export function* onAddUnit(action) { yield put(addPropToStoreObject("machine", machine.id, {[action.unitType + "Ids"]: units})); } catch (error) { - console.log(error); + console.error(error); } } @@ -339,6 +339,6 @@ export function* onDeleteUnit(action) { yield call(updateMachineInRackOnTile, tileId, position, updatedMachine); yield put(addPropToStoreObject("machine", machine.id, {[action.unitType + "Ids"]: unitIds})); } catch (error) { - console.log(error); + console.error(error); } } diff --git a/src/sagas/users.js b/src/sagas/users.js index 5f9bffa1..f1ee9823 100644 --- a/src/sagas/users.js +++ b/src/sagas/users.js @@ -20,7 +20,7 @@ export function* onFetchLoggedInUser(action) { yield put(logInSucceeded(Object.assign({userId}, action.payload))); } catch (error) { - console.log(error); + console.error(error); } } @@ -41,6 +41,6 @@ export function* onFetchAuthorizationsOfCurrentUser(action) { yield put(fetchAuthorizationsOfCurrentUserSucceeded(authorizationIds)); } catch (error) { - console.log(error); + console.error(error); } } diff --git a/src/shapes/index.js b/src/shapes/index.js index cfe0ff54..c84e66e0 100644 --- a/src/shapes/index.js +++ b/src/shapes/index.js @@ -131,7 +131,7 @@ Shapes.Section = PropTypes.shape({ Shapes.Path = PropTypes.shape({ id: PropTypes.number.isRequired, simulationId: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, + name: PropTypes.string, datetimeCreated: PropTypes.string.isRequired, sections: PropTypes.arrayOf(Shapes.Section), }); |
