summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-14 14:07:21 +0200
committerGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-23 10:06:02 +0200
commitf604406453f95c82c3e5e4294a51245661868bbe (patch)
tree6282cc3eb3164ddd94052175f872c8fc2ee2f623
parent7151ae60cf587a502a7e09d19ebd0fd33e761bf2 (diff)
First attempt at experiment list UI
-rw-r--r--src/actions/experiments.js24
-rw-r--r--src/actions/modals/experiments.js14
-rw-r--r--src/actions/modals/simulations.js2
-rw-r--r--src/api/routes/jobs.js9
-rw-r--r--src/api/routes/tasks.js5
-rw-r--r--src/components/experiments/ExperimentListComponent.js19
-rw-r--r--src/components/experiments/ExperimentRowComponent.js17
-rw-r--r--src/components/modals/custom-components/NewExperimentModalComponent.js87
-rw-r--r--src/containers/experiments/ExperimentListContainer.js27
-rw-r--r--src/containers/experiments/ExperimentRowContainer.js19
-rw-r--r--src/containers/modals/NewExperimentModal.js36
-rw-r--r--src/pages/Experiments.js9
-rw-r--r--src/reducers/modals.js2
-rw-r--r--src/sagas/experiments.js73
-rw-r--r--src/sagas/index.js9
-rw-r--r--src/sagas/objects.js16
-rw-r--r--src/shapes/index.js36
17 files changed, 392 insertions, 12 deletions
diff --git a/src/actions/experiments.js b/src/actions/experiments.js
new file mode 100644
index 00000000..b067f5d9
--- /dev/null
+++ b/src/actions/experiments.js
@@ -0,0 +1,24 @@
+export const FETCH_EXPERIMENTS_OF_SIMULATION = "FETCH_EXPERIMENTS_OF_SIMULATION";
+export const ADD_EXPERIMENT = "ADD_EXPERIMENT";
+export const DELETE_EXPERIMENT = "DELETE_EXPERIMENT";
+
+export function fetchExperimentsOfSimulation(simulationId) {
+ return {
+ type: FETCH_EXPERIMENTS_OF_SIMULATION,
+ simulationId
+ };
+}
+
+export function addExperiment(experiment) {
+ return {
+ type: ADD_EXPERIMENT,
+ experiment
+ };
+}
+
+export function deleteExperiment(id) {
+ return {
+ type: DELETE_EXPERIMENT,
+ id
+ };
+}
diff --git a/src/actions/modals/experiments.js b/src/actions/modals/experiments.js
new file mode 100644
index 00000000..43a53a3a
--- /dev/null
+++ b/src/actions/modals/experiments.js
@@ -0,0 +1,14 @@
+export const OPEN_NEW_EXPERIMENT_MODAL = "OPEN_NEW_EXPERIMENT_MODAL";
+export const CLOSE_NEW_EXPERIMENT_MODAL = "CLOSE_EXPERIMENT_MODAL";
+
+export function openNewExperimentModal() {
+ return {
+ type: OPEN_NEW_EXPERIMENT_MODAL
+ };
+}
+
+export function closeNewExperimentModal() {
+ return {
+ type: CLOSE_NEW_EXPERIMENT_MODAL
+ };
+}
diff --git a/src/actions/modals/simulations.js b/src/actions/modals/simulations.js
index 53d2c565..8281238d 100644
--- a/src/actions/modals/simulations.js
+++ b/src/actions/modals/simulations.js
@@ -1,5 +1,5 @@
export const OPEN_NEW_SIMULATION_MODAL = "OPEN_NEW_SIMULATION_MODAL";
-export const CLOSE_NEW_SIMULATION_MODAL = "CLOSE_SIMULATION_POPUP";
+export const CLOSE_NEW_SIMULATION_MODAL = "CLOSE_SIMULATION_MODAL";
export function openNewSimulationModal() {
return {
diff --git a/src/api/routes/jobs.js b/src/api/routes/jobs.js
new file mode 100644
index 00000000..90947a51
--- /dev/null
+++ b/src/api/routes/jobs.js
@@ -0,0 +1,9 @@
+import {getAll, getById} from "./util";
+
+export function getAllJobs() {
+ return getAll("/jobs");
+}
+
+export function getTasksOfJob(jobId) {
+ return getById("/jobs/{jobId}/tasks", {jobId});
+}
diff --git a/src/api/routes/tasks.js b/src/api/routes/tasks.js
new file mode 100644
index 00000000..69736af8
--- /dev/null
+++ b/src/api/routes/tasks.js
@@ -0,0 +1,5 @@
+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 c3e3db8d..001b0e32 100644
--- a/src/components/experiments/ExperimentListComponent.js
+++ b/src/components/experiments/ExperimentListComponent.js
@@ -1,6 +1,8 @@
+import PropTypes from "prop-types";
import React from "react";
+import ExperimentRowContainer from "../../containers/experiments/ExperimentRowContainer";
-const ExperimentListContainer = ({experiments}) => (
+const ExperimentListComponent = ({experimentIds}) => (
<table className="table">
<thead>
<tr>
@@ -11,16 +13,15 @@ const ExperimentListContainer = ({experiments}) => (
</tr>
</thead>
<tbody>
- {experiments.map(experiment => (
- <tr>
- <td>{experiment.name}</td>
- <td>{experiment.path.name}</td>
- <td>{experiment.trace.name}</td>
- <td>{experiment.scheduler.name}</td>
- </tr>
+ {experimentIds.map(experimentId => (
+ <ExperimentRowContainer experimentId={experimentId}/>
))}
</tbody>
</table>
);
-export default ExperimentListContainer;
+ExperimentListComponent.propTypes = {
+ experimentIds: PropTypes.arrayOf(PropTypes.number).isRequired,
+};
+
+export default ExperimentListComponent;
diff --git a/src/components/experiments/ExperimentRowComponent.js b/src/components/experiments/ExperimentRowComponent.js
new file mode 100644
index 00000000..79ce3eea
--- /dev/null
+++ b/src/components/experiments/ExperimentRowComponent.js
@@ -0,0 +1,17 @@
+import React from "react";
+import Shapes from "../../shapes/index";
+
+const ExperimentRowComponent = ({experiment}) => (
+ <tr>
+ <td>{experiment.name}</td>
+ <td>{experiment.path.name}</td>
+ <td>{experiment.trace.name}</td>
+ <td>{experiment.scheduler.name}</td>
+ </tr>
+);
+
+ExperimentRowComponent.propTypes = {
+ experiment: Shapes.Experiment
+};
+
+export default ExperimentRowComponent;
diff --git a/src/components/modals/custom-components/NewExperimentModalComponent.js b/src/components/modals/custom-components/NewExperimentModalComponent.js
new file mode 100644
index 00000000..9efccc8a
--- /dev/null
+++ b/src/components/modals/custom-components/NewExperimentModalComponent.js
@@ -0,0 +1,87 @@
+import PropTypes from "prop-types";
+import React from "react";
+import Shapes from "../../../shapes";
+import Modal from "../Modal";
+
+class NewExperimentModalComponent extends React.Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ paths: PropTypes.arrayOf(Shapes.Path),
+ schedulers: PropTypes.arrayOf(Shapes.Scheduler),
+ traces: PropTypes.arrayOf(Shapes.Trace),
+ callback: PropTypes.func.isRequired,
+ };
+
+ reset() {
+ this.textInput.value = "";
+ this.pathSelect.selectedIndex = 0;
+ this.traceSelect.selectedIndex = 0;
+ this.schedulerSelect.selectedIndex = 0;
+ }
+
+ onSubmit() {
+ this.props.callback(this.textInput.value, this.pathSelect.value, this.traceSelect.value,
+ this.schedulerSelect.value);
+ this.reset();
+ }
+
+ onCancel() {
+ this.props.callback(undefined);
+ this.reset();
+ }
+
+ render() {
+ return (
+ <Modal title="New Experiment"
+ show={this.props.show}
+ onSubmit={this.onSubmit.bind(this)}
+ onCancel={this.onCancel.bind(this)}>
+ <form onSubmit={e => {
+ e.preventDefault();
+ this.onSubmit();
+ }}>
+ <div className="form-group">
+ <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>
+ <select className="form-control"
+ ref={pathSelect => this.pathSelect = pathSelect}>
+ {this.props.paths.map(path => (
+ <option value={path.id} key={path.id}>
+ {path.name}
+ </option>
+ ))}
+ </select>
+ </div>
+ <div className="form-group">
+ <label className="form-control-label">Trace:</label>
+ <select className="form-control"
+ ref={traceSelect => this.traceSelect = traceSelect}>
+ {this.props.traces.map(trace => (
+ <option value={trace.id} key={trace.id}>
+ {trace.name}
+ </option>
+ ))}
+ </select>
+ </div>
+ <div className="form-group">
+ <label className="form-control-label">Scheduler:</label>
+ <select className="form-control"
+ ref={schedulerSelect => this.schedulerSelect = schedulerSelect}>
+ {this.props.schedulers.map(scheduler => (
+ <option value={scheduler.name} key={scheduler.name}>
+ {scheduler.name}
+ </option>
+ ))}
+ </select>
+ </div>
+ </form>
+ </Modal>
+ );
+ }
+}
+
+export default NewExperimentModalComponent;
diff --git a/src/containers/experiments/ExperimentListContainer.js b/src/containers/experiments/ExperimentListContainer.js
new file mode 100644
index 00000000..38e5a9f6
--- /dev/null
+++ b/src/containers/experiments/ExperimentListContainer.js
@@ -0,0 +1,27 @@
+import {connect} from "react-redux";
+import ExperimentListComponent from "../../components/experiments/ExperimentListComponent";
+
+const mapStateToProps = state => {
+ if (!state.currentSimulationId) {
+ return {
+ experimentIds: [],
+ };
+ }
+
+ const experimentIds = state.objects.simulation[state.currentSimulationId].experimentIds;
+ if (experimentIds) {
+ return {
+ experimentIds,
+ };
+ }
+
+ return {
+ experimentIds: [],
+ };
+};
+
+const ExperimentListContainer = connect(
+ mapStateToProps
+)(ExperimentListComponent);
+
+export default ExperimentListContainer;
diff --git a/src/containers/experiments/ExperimentRowContainer.js b/src/containers/experiments/ExperimentRowContainer.js
new file mode 100644
index 00000000..99b35779
--- /dev/null
+++ b/src/containers/experiments/ExperimentRowContainer.js
@@ -0,0 +1,19 @@
+import {connect} from "react-redux";
+import ExperimentRowComponent from "../../components/experiments/ExperimentRowComponent";
+
+const mapStateToProps = (state, ownProps) => {
+ const experiment = Object.assign({}, state.objects.experiment[ownProps.experimentId]);
+ experiment.trace = state.objects.trace[experiment.traceId];
+ experiment.scheduler = state.objects.scheduler[experiment.schedulerName];
+ experiment.path = state.objects.path[experiment.pathId];
+
+ return {
+ experiment,
+ };
+};
+
+const ExperimentRowContainer = connect(
+ mapStateToProps
+)(ExperimentRowComponent);
+
+export default ExperimentRowContainer;
diff --git a/src/containers/modals/NewExperimentModal.js b/src/containers/modals/NewExperimentModal.js
new file mode 100644
index 00000000..13aed74d
--- /dev/null
+++ b/src/containers/modals/NewExperimentModal.js
@@ -0,0 +1,36 @@
+import {connect} from "react-redux";
+import {addExperiment} from "../../actions/experiments";
+import {closeNewExperimentModal} from "../../actions/modals/experiments";
+import NewExperimentModalComponent from "../../components/modals/custom-components/NewExperimentModalComponent";
+
+const mapStateToProps = state => {
+ return {
+ show: state.modals.newExperimentModalVisible,
+ paths: Object.values(state.objects.path).filter(path => path.simulationId === state.currentSimulationId),
+ traces: Object.values(state.objects.trace),
+ schedulers: Object.values(state.objects.scheduler),
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ callback: (name, pathId, traceId, schedulerName) => {
+ if (name) {
+ dispatch(addExperiment({
+ name,
+ pathId,
+ traceId,
+ schedulerName
+ }));
+ }
+ dispatch(closeNewExperimentModal());
+ }
+ };
+};
+
+const NewExperimentModal = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(NewExperimentModalComponent);
+
+export default NewExperimentModal;
diff --git a/src/pages/Experiments.js b/src/pages/Experiments.js
index 9dbe0dc0..d1d19d9f 100644
--- a/src/pages/Experiments.js
+++ b/src/pages/Experiments.js
@@ -1,8 +1,11 @@
import PropTypes from "prop-types";
import React from "react";
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 NewExperimentModal from "../containers/modals/NewExperimentModal";
class ExperimentsComponent extends React.Component {
static propTypes = {
@@ -11,7 +14,7 @@ class ExperimentsComponent extends React.Component {
componentDidMount() {
this.props.storeSimulationId(this.props.simulationId);
- // TODO fetch experiments
+ this.props.fetchExperimentsOfSimulation(this.props.simulationId);
}
render() {
@@ -19,8 +22,9 @@ class ExperimentsComponent extends React.Component {
<div className="full-height">
<AppNavbar simulationId={this.props.simulationId} inSimulation={true}/>
<div className="container text-page-container full-height">
- Test
+ <ExperimentListContainer/>
</div>
+ <NewExperimentModal/>
</div>
);
}
@@ -29,6 +33,7 @@ class ExperimentsComponent extends React.Component {
const mapDispatchToProps = dispatch => {
return {
storeSimulationId: id => dispatch(openSimulationSucceeded(id)),
+ fetchExperimentsOfSimulation: id => dispatch(fetchExperimentsOfSimulation(id)),
};
};
diff --git a/src/reducers/modals.js b/src/reducers/modals.js
index 0dafcde4..9f73c6ec 100644
--- a/src/reducers/modals.js
+++ b/src/reducers/modals.js
@@ -1,4 +1,5 @@
import {combineReducers} from "redux";
+import {CLOSE_NEW_EXPERIMENT_MODAL, OPEN_NEW_EXPERIMENT_MODAL} from "../actions/modals/experiments";
import {CLOSE_DELETE_PROFILE_MODAL, OPEN_DELETE_PROFILE_MODAL} from "../actions/modals/profile";
import {CLOSE_NEW_SIMULATION_MODAL, OPEN_NEW_SIMULATION_MODAL} from "../actions/modals/simulations";
import {
@@ -35,4 +36,5 @@ export const modals = combineReducers({
editRackNameModalVisible: modal(OPEN_EDIT_RACK_NAME_MODAL, CLOSE_EDIT_RACK_NAME_MODAL),
deleteRackModalVisible: modal(OPEN_DELETE_RACK_MODAL, CLOSE_DELETE_RACK_MODAL),
deleteMachineModalVisible: modal(OPEN_DELETE_MACHINE_MODAL, CLOSE_DELETE_MACHINE_MODAL),
+ newExperimentModalVisible: modal(OPEN_NEW_EXPERIMENT_MODAL, CLOSE_NEW_EXPERIMENT_MODAL),
});
diff --git a/src/sagas/experiments.js b/src/sagas/experiments.js
new file mode 100644
index 00000000..0ac919f4
--- /dev/null
+++ b/src/sagas/experiments.js
@@ -0,0 +1,73 @@
+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";
+
+export function* onFetchExperimentsOfSimulation() {
+ try {
+ const currentSimulationId = yield select(state => state.currentSimulationId);
+
+ yield fetchExperimentSpecifications();
+ const experiments = yield call(getExperimentsOfSimulation, currentSimulationId);
+ for (let i in experiments) {
+ yield put(addToStore("experiment", experiments[i]));
+ }
+ yield put(addPropToStoreObject("simulation", currentSimulationId,
+ {experimentIds: experiments.map(experiment => experiment.id)}));
+ } catch (error) {
+ console.log(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);
+ }
+}
+
+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
+ }));
+ yield put(addToStore("experiment", experiment));
+
+ const experimentIds = yield select(state => state.objects.simulation[currentSimulationId]);
+ yield put(addPropToStoreObject("simulation", currentSimulationId,
+ {experimentIds: experimentIds.concat([experiment.id])}));
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+export function* onDeleteExperiment(action) {
+ try {
+ yield call(deleteExperiment, action.id);
+
+ const currentSimulationId = yield select(state => state.currentSimulationId);
+ const experimentIds = yield select(state => state.objects.simulation[currentSimulationId]);
+
+ yield put(addPropToStoreObject("simulation", currentSimulationId,
+ {experimentIds: experimentIds.filter(id => id !== action.id)}));
+ } catch (error) {
+ console.log(error);
+ }
+}
diff --git a/src/sagas/index.js b/src/sagas/index.js
index 5cb25202..e86ef8a1 100644
--- a/src/sagas/index.js
+++ b/src/sagas/index.js
@@ -1,5 +1,6 @@
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_TILE,
@@ -12,6 +13,7 @@ import {ADD_UNIT, DELETE_MACHINE, DELETE_UNIT} from "../actions/topology/machine
import {ADD_MACHINE, DELETE_RACK, EDIT_RACK_NAME} from "../actions/topology/rack";
import {ADD_RACK_TO_TILE, DELETE_ROOM, EDIT_ROOM_NAME} from "../actions/topology/room";
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 {
@@ -34,10 +36,13 @@ import {onFetchAuthorizationsOfCurrentUser, onFetchLoggedInUser} from "./users";
export default function* rootSaga() {
yield takeEvery(LOG_IN, onFetchLoggedInUser);
+
yield takeEvery(FETCH_AUTHORIZATIONS_OF_CURRENT_USER, onFetchAuthorizationsOfCurrentUser);
yield takeEvery(ADD_SIMULATION, onSimulationAdd);
yield takeEvery(DELETE_SIMULATION, onSimulationDelete);
+
yield takeEvery(DELETE_CURRENT_USER, onDeleteCurrentUser);
+
yield takeEvery(FETCH_LATEST_DATACENTER, onFetchLatestDatacenter);
yield takeEvery(START_NEW_ROOM_CONSTRUCTION, onStartNewRoomConstruction);
yield takeEvery(CANCEL_NEW_ROOM_CONSTRUCTION, onCancelNewRoomConstruction);
@@ -52,4 +57,8 @@ export default function* rootSaga() {
yield takeEvery(DELETE_MACHINE, onDeleteMachine);
yield takeEvery(ADD_UNIT, onAddUnit);
yield takeEvery(DELETE_UNIT, onDeleteUnit);
+
+ yield takeEvery(FETCH_EXPERIMENTS_OF_SIMULATION, onFetchExperimentsOfSimulation);
+ yield takeEvery(ADD_EXPERIMENT, onAddExperiment);
+ yield takeEvery(DELETE_EXPERIMENT, onDeleteExperiment);
}
diff --git a/src/sagas/objects.js b/src/sagas/objects.js
index 508f1cf5..375781be 100644
--- a/src/sagas/objects.js
+++ b/src/sagas/objects.js
@@ -1,8 +1,10 @@
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";
import {getSection} from "../api/routes/sections";
import {getPathsOfSimulation, getSimulation} from "../api/routes/simulations";
import {
@@ -18,7 +20,9 @@ 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";
export const OBJECT_SELECTORS = {
@@ -124,3 +128,15 @@ export const fetchAndStorePath = (id) =>
export const fetchAndStorePathsOfSimulation = (simulationId) =>
fetchAndStoreObjects("path", call(getPathsOfSimulation, 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));
diff --git a/src/shapes/index.js b/src/shapes/index.js
index 07fa512d..cfe0ff54 100644
--- a/src/shapes/index.js
+++ b/src/shapes/index.js
@@ -136,6 +136,42 @@ Shapes.Path = PropTypes.shape({
sections: PropTypes.arrayOf(Shapes.Section),
});
+Shapes.Scheduler = PropTypes.shape({
+ name: PropTypes.string.isRequired,
+});
+
+Shapes.Task = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ jobId: PropTypes.number.isRequired,
+ startTick: PropTypes.number.isRequired,
+ totalFlopCount: PropTypes.number.isRequired,
+});
+
+Shapes.Job = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ traceId: PropTypes.number.isRequired,
+ taskIds: PropTypes.arrayOf(PropTypes.number),
+});
+
+Shapes.Trace = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ jobIds: PropTypes.arrayOf(PropTypes.number),
+});
+
+Shapes.Experiment = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ simulationId: PropTypes.number.isRequired,
+ traceId: PropTypes.number.isRequired,
+ trace: Shapes.Trace,
+ pathId: PropTypes.number.isRequired,
+ path: Shapes.Path,
+ schedulerName: PropTypes.string.isRequired,
+ scheduler: Shapes.Scheduler,
+ name: PropTypes.string.isRequired,
+});
+
Shapes.WallSegment = PropTypes.shape({
startPosX: PropTypes.number.isRequired,
startPosY: PropTypes.number.isRequired,