summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-15 12:53:26 +0200
committerGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-23 10:06:03 +0200
commita1d95b3685cffb6a9344d0d1e5505dd391193f16 (patch)
tree42851ec0726881dd9f82a3ea12a7987324a68ef8 /src
parentf604406453f95c82c3e5e4294a51245661868bbe (diff)
Implement experiment list and add
Diffstat (limited to 'src')
-rw-r--r--src/api/routes/jobs.js6
-rw-r--r--src/api/routes/tasks.js5
-rw-r--r--src/components/experiments/ExperimentListComponent.js44
-rw-r--r--src/components/experiments/ExperimentRowComponent.js2
-rw-r--r--src/components/experiments/NewExperimentButtonComponent.js17
-rw-r--r--src/components/modals/TextInputModal.js2
-rw-r--r--src/components/modals/custom-components/NewExperimentModalComponent.js18
-rw-r--r--src/components/simulations/FilterButton.js7
-rw-r--r--src/components/simulations/FilterButton.sass18
-rw-r--r--src/components/simulations/FilterPanel.js10
-rw-r--r--src/components/simulations/FilterPanel.sass23
-rw-r--r--src/components/simulations/NewSimulationButton.js16
-rw-r--r--src/components/simulations/NewSimulationButton.sass31
-rw-r--r--src/components/simulations/NewSimulationButtonComponent.js17
-rw-r--r--src/components/simulations/NoSimulationsAlert.js11
-rw-r--r--src/components/simulations/NoSimulationsAlert.sass10
-rw-r--r--src/components/simulations/SimulationActionButtons.js4
-rw-r--r--src/components/simulations/SimulationAuthList.js40
-rw-r--r--src/components/simulations/SimulationAuthList.sass72
-rw-r--r--src/components/simulations/SimulationAuthRow.js (renamed from src/components/simulations/SimulationAuth.js)20
-rw-r--r--src/containers/experiments/ExperimentListContainer.js6
-rw-r--r--src/containers/experiments/NewExperimentButtonContainer.js16
-rw-r--r--src/containers/simulations/NewSimulationButtonContainer.js16
-rw-r--r--src/containers/simulations/VisibleSimulationAuthList.js10
-rw-r--r--src/index.sass10
-rw-r--r--src/pages/Experiments.js2
-rw-r--r--src/pages/Simulations.js4
-rw-r--r--src/reducers/objects.js5
-rw-r--r--src/sagas/experiments.js32
-rw-r--r--src/sagas/index.js6
-rw-r--r--src/sagas/objects.js18
-rw-r--r--src/sagas/profile.js2
-rw-r--r--src/sagas/simulations.js15
-rw-r--r--src/sagas/topology.js32
-rw-r--r--src/sagas/users.js4
-rw-r--r--src/shapes/index.js2
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),
});