diff options
143 files changed, 926 insertions, 1985 deletions
diff --git a/frontend/README.md b/frontend/README.md index 0ed1f44a..c18e18d2 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -59,7 +59,7 @@ All pages are represented by a component in the `src/pages` directory. There are **Home.js** - Entry page (`/`) -**Simulations.js** - Overview of simulations of the user (`/simulations`) +**Projects.js** - Overview of simulations of the user (`/simulations`) **App.js** - Main application, with datacenter construction and simulation UI (`/simulations/:simulationId` and `/simulations/:simulationId/experiments/:experimentId`) diff --git a/frontend/src/actions/experiments.js b/frontend/src/actions/experiments.js index 5d384abf..dce48a09 100644 --- a/frontend/src/actions/experiments.js +++ b/frontend/src/actions/experiments.js @@ -1,12 +1,12 @@ -export const FETCH_EXPERIMENTS_OF_SIMULATION = 'FETCH_EXPERIMENTS_OF_SIMULATION' +export const FETCH_EXPERIMENTS_OF_PROJECT = 'FETCH_EXPERIMENTS_OF_PROJECT' export const ADD_EXPERIMENT = 'ADD_EXPERIMENT' export const DELETE_EXPERIMENT = 'DELETE_EXPERIMENT' export const OPEN_EXPERIMENT_SUCCEEDED = 'OPEN_EXPERIMENT_SUCCEEDED' -export function fetchExperimentsOfSimulation(simulationId) { +export function fetchExperimentsOfProject(projectId) { return { - type: FETCH_EXPERIMENTS_OF_SIMULATION, - simulationId, + type: FETCH_EXPERIMENTS_OF_PROJECT, + projectId, } } @@ -24,10 +24,10 @@ export function deleteExperiment(id) { } } -export function openExperimentSucceeded(simulationId, experimentId) { +export function openExperimentSucceeded(projectId, experimentId) { return { type: OPEN_EXPERIMENT_SUCCEEDED, - simulationId, + projectId, experimentId, } } diff --git a/frontend/src/actions/modals/projects.js b/frontend/src/actions/modals/projects.js new file mode 100644 index 00000000..d1043cbb --- /dev/null +++ b/frontend/src/actions/modals/projects.js @@ -0,0 +1,14 @@ +export const OPEN_NEW_PROJECT_MODAL = 'OPEN_NEW_PROJECT_MODAL' +export const CLOSE_NEW_PROJECT_MODAL = 'CLOSE_PROJECT_MODAL' + +export function openNewProjectModal() { + return { + type: OPEN_NEW_PROJECT_MODAL, + } +} + +export function closeNewProjectModal() { + return { + type: CLOSE_NEW_PROJECT_MODAL, + } +} diff --git a/frontend/src/actions/modals/simulations.js b/frontend/src/actions/modals/simulations.js deleted file mode 100644 index 0ef1cbaa..00000000 --- a/frontend/src/actions/modals/simulations.js +++ /dev/null @@ -1,14 +0,0 @@ -export const OPEN_NEW_SIMULATION_MODAL = 'OPEN_NEW_SIMULATION_MODAL' -export const CLOSE_NEW_SIMULATION_MODAL = 'CLOSE_SIMULATION_MODAL' - -export function openNewSimulationModal() { - return { - type: OPEN_NEW_SIMULATION_MODAL, - } -} - -export function closeNewSimulationModal() { - return { - type: CLOSE_NEW_SIMULATION_MODAL, - } -} diff --git a/frontend/src/actions/projects.js b/frontend/src/actions/projects.js new file mode 100644 index 00000000..add0f242 --- /dev/null +++ b/frontend/src/actions/projects.js @@ -0,0 +1,52 @@ +export const SET_AUTH_VISIBILITY_FILTER = 'SET_AUTH_VISIBILITY_FILTER' +export const ADD_PROJECT = 'ADD_PROJECT' +export const ADD_PROJECT_SUCCEEDED = 'ADD_PROJECT_SUCCEEDED' +export const DELETE_PROJECT = 'DELETE_PROJECT' +export const DELETE_PROJECT_SUCCEEDED = 'DELETE_PROJECT_SUCCEEDED' +export const OPEN_PROJECT_SUCCEEDED = 'OPEN_PROJECT_SUCCEEDED' + +export function setAuthVisibilityFilter(filter) { + return { + type: SET_AUTH_VISIBILITY_FILTER, + filter, + } +} + +export function addProject(name) { + return (dispatch, getState) => { + const { auth } = getState() + dispatch({ + type: ADD_PROJECT, + name, + userId: auth.userId, + }) + } +} + +export function addProjectSucceeded(authorization) { + return { + type: ADD_PROJECT_SUCCEEDED, + authorization, + } +} + +export function deleteProject(id) { + return { + type: DELETE_PROJECT, + id, + } +} + +export function deleteProjectSucceeded(id) { + return { + type: DELETE_PROJECT_SUCCEEDED, + id, + } +} + +export function openProjectSucceeded(id) { + return { + type: OPEN_PROJECT_SUCCEEDED, + id, + } +} diff --git a/frontend/src/actions/simulation/load-metric.js b/frontend/src/actions/simulation/load-metric.js deleted file mode 100644 index c59338ed..00000000 --- a/frontend/src/actions/simulation/load-metric.js +++ /dev/null @@ -1,8 +0,0 @@ -export const CHANGE_LOAD_METRIC = 'CHANGE_LOAD_METRIC' - -export function changeLoadMetric(metric) { - return { - type: CHANGE_LOAD_METRIC, - metric, - } -} diff --git a/frontend/src/actions/simulation/playback.js b/frontend/src/actions/simulation/playback.js deleted file mode 100644 index 5d7d8af2..00000000 --- a/frontend/src/actions/simulation/playback.js +++ /dev/null @@ -1,15 +0,0 @@ -export const SET_PLAYING = 'SET_PLAYING' - -export function playSimulation() { - return { - type: SET_PLAYING, - playing: true, - } -} - -export function pauseSimulation() { - return { - type: SET_PLAYING, - playing: false, - } -} diff --git a/frontend/src/actions/simulation/tick.js b/frontend/src/actions/simulation/tick.js deleted file mode 100644 index ca2027a4..00000000 --- a/frontend/src/actions/simulation/tick.js +++ /dev/null @@ -1,25 +0,0 @@ -export const GO_TO_TICK = 'GO_TO_TICK' -export const SET_LAST_SIMULATED_TICK = 'SET_LAST_SIMULATED_TICK' - -export function incrementTick() { - return (dispatch, getState) => { - const { currentTick } = getState() - dispatch(goToTick(currentTick + 1)) - } -} - -export function goToTick(tick) { - return (dispatch, getState) => { - dispatch({ - type: GO_TO_TICK, - tick, - }) - } -} - -export function setLastSimulatedTick(tick) { - return { - type: SET_LAST_SIMULATED_TICK, - tick, - } -} diff --git a/frontend/src/actions/simulations.js b/frontend/src/actions/simulations.js deleted file mode 100644 index 779e9b9e..00000000 --- a/frontend/src/actions/simulations.js +++ /dev/null @@ -1,52 +0,0 @@ -export const SET_AUTH_VISIBILITY_FILTER = 'SET_AUTH_VISIBILITY_FILTER' -export const ADD_SIMULATION = 'ADD_SIMULATION' -export const ADD_SIMULATION_SUCCEEDED = 'ADD_SIMULATION_SUCCEEDED' -export const DELETE_SIMULATION = 'DELETE_SIMULATION' -export const DELETE_SIMULATION_SUCCEEDED = 'DELETE_SIMULATION_SUCCEEDED' -export const OPEN_SIMULATION_SUCCEEDED = 'OPEN_SIMULATION_SUCCEEDED' - -export function setAuthVisibilityFilter(filter) { - return { - type: SET_AUTH_VISIBILITY_FILTER, - filter, - } -} - -export function addSimulation(name) { - return (dispatch, getState) => { - const { auth } = getState() - dispatch({ - type: ADD_SIMULATION, - name, - userId: auth.userId, - }) - } -} - -export function addSimulationSucceeded(authorization) { - return { - type: ADD_SIMULATION_SUCCEEDED, - authorization, - } -} - -export function deleteSimulation(id) { - return { - type: DELETE_SIMULATION, - id, - } -} - -export function deleteSimulationSucceeded(id) { - return { - type: DELETE_SIMULATION_SUCCEEDED, - id, - } -} - -export function openSimulationSucceeded(id) { - return { - type: OPEN_SIMULATION_SUCCEEDED, - id, - } -} diff --git a/frontend/src/actions/states.js b/frontend/src/actions/states.js deleted file mode 100644 index 430fbd09..00000000 --- a/frontend/src/actions/states.js +++ /dev/null @@ -1,9 +0,0 @@ -export const ADD_BATCH_TO_STATES = 'ADD_BATCH_TO_STATES' - -export function addBatchToStates(objectType, objects) { - return { - type: ADD_BATCH_TO_STATES, - objectType, - objects, - } -} diff --git a/frontend/src/api/routes/experiments.js b/frontend/src/api/routes/experiments.js index ab85613c..acc72f34 100644 --- a/frontend/src/api/routes/experiments.js +++ b/frontend/src/api/routes/experiments.js @@ -1,16 +1,16 @@ import { deleteById, getById } from './util' import { sendRequest } from '../index' -export function addExperiment(simulationId, experiment) { +export function addExperiment(projectId, experiment) { return sendRequest({ - path: '/simulations/{simulationId}/experiments', + path: '/projects/{projectId}/experiments', method: 'POST', parameters: { body: { experiment, }, path: { - simulationId, + projectId, }, query: {}, }, @@ -24,17 +24,3 @@ export function getExperiment(experimentId) { export function deleteExperiment(experimentId) { return deleteById('/experiments/{experimentId}', { experimentId }) } - -export function getAllMachineStates(experimentId) { - return getById('/experiments/{experimentId}/machine-states', { - experimentId, - }) -} - -export function getAllRackStates(experimentId) { - return getById('/experiments/{experimentId}/rack-states', { experimentId }) -} - -export function getAllRoomStates(experimentId) { - return getById('/experiments/{experimentId}/room-states', { experimentId }) -} diff --git a/frontend/src/api/routes/simulations.js b/frontend/src/api/routes/projects.js index e22fbc07..a261adb8 100644 --- a/frontend/src/api/routes/simulations.js +++ b/frontend/src/api/routes/projects.js @@ -1,17 +1,17 @@ import { sendRequest } from '../index' import { deleteById, getById } from './util' -export function getSimulation(simulationId) { - return getById('/simulations/{simulationId}', { simulationId }) +export function getProject(projectId) { + return getById('/projects/{projectId}', { projectId }) } -export function addSimulation(simulation) { +export function addProject(project) { return sendRequest({ - path: '/simulations', + path: '/projects', method: 'POST', parameters: { body: { - simulation, + project, }, path: {}, query: {}, @@ -19,36 +19,36 @@ export function addSimulation(simulation) { }) } -export function updateSimulation(simulation) { +export function updateProject(project) { return sendRequest({ - path: '/simulations/{simulationId}', + path: '/projects/{projectId}', method: 'PUT', parameters: { body: { - simulation, + project, }, path: { - simulationId: simulation._id, + projectId: project._id, }, query: {}, }, }) } -export function deleteSimulation(simulationId) { - return deleteById('/simulations/{simulationId}', { simulationId }) +export function deleteProject(projectId) { + return deleteById('/projects/{projectId}', { projectId }) } -export function addExperiment(simulationId, experiment) { +export function addExperiment(projectId, experiment) { return sendRequest({ - path: '/simulations/{simulationId}/experiments', + path: '/projects/{projectId}/experiments', method: 'POST', parameters: { body: { experiment, }, path: { - simulationId, + projectId, }, query: {}, }, diff --git a/frontend/src/api/routes/topologies.js b/frontend/src/api/routes/topologies.js index 307ea7ab..a8f0d6b1 100644 --- a/frontend/src/api/routes/topologies.js +++ b/frontend/src/api/routes/topologies.js @@ -3,14 +3,14 @@ import { sendRequest } from '../index' export function addTopology(topology) { return sendRequest({ - path: '/simulations/{simulationId}/topologies', + path: '/projects/{projectId}/topologies', method: 'POST', parameters: { body: { topology, }, path: { - simulationId: topology.simulationId, + projectId: topology.projectId, }, query: {}, }, diff --git a/frontend/src/auth/index.js b/frontend/src/auth/index.js index f93c7141..b5953990 100644 --- a/frontend/src/auth/index.js +++ b/frontend/src/auth/index.js @@ -41,7 +41,7 @@ export const authRedirectMiddleware = (store) => (next) => (action) => { switch (action.type) { case LOG_IN_SUCCEEDED: saveAuthLocalStorage(action.payload) - window.location.href = '/simulations' + window.location.href = '/projects' break case LOG_OUT: case DELETE_CURRENT_USER_SUCCEEDED: diff --git a/frontend/src/components/app/map/groups/RackGroup.js b/frontend/src/components/app/map/groups/RackGroup.js index 6de939a9..5d4ee5e2 100644 --- a/frontend/src/components/app/map/groups/RackGroup.js +++ b/frontend/src/components/app/map/groups/RackGroup.js @@ -4,23 +4,17 @@ import RackEnergyFillContainer from '../../../../containers/app/map/RackEnergyFi import RackSpaceFillContainer from '../../../../containers/app/map/RackSpaceFillContainer' import Shapes from '../../../../shapes/index' import { RACK_BACKGROUND_COLOR } from '../../../../util/colors' -import { convertLoadToSimulationColor } from '../../../../util/simulation-load' import TileObject from '../elements/TileObject' -const RackGroup = ({ tile, inSimulation, rackLoad }) => { - let color = RACK_BACKGROUND_COLOR - if (inSimulation && rackLoad >= 0) { - color = convertLoadToSimulationColor(rackLoad) - } - +const RackGroup = ({ tile }) => { return ( <Group> <TileObject positionX={tile.positionX} positionY={tile.positionY} - color={color} + color={RACK_BACKGROUND_COLOR} /> - <Group opacity={inSimulation ? 0.3 : 1}> + <Group> <RackSpaceFillContainer tileId={tile._id} positionX={tile.positionX} diff --git a/frontend/src/components/app/map/groups/TileGroup.js b/frontend/src/components/app/map/groups/TileGroup.js index 54f4ae17..e984f05b 100644 --- a/frontend/src/components/app/map/groups/TileGroup.js +++ b/frontend/src/components/app/map/groups/TileGroup.js @@ -4,10 +4,9 @@ import { Group } from 'react-konva' import RackContainer from '../../../../containers/app/map/RackContainer' import Shapes from '../../../../shapes/index' import { ROOM_DEFAULT_COLOR, ROOM_IN_CONSTRUCTION_COLOR } from '../../../../util/colors' -import { convertLoadToSimulationColor } from '../../../../util/simulation-load' import RoomTile from '../elements/RoomTile' -const TileGroup = ({ tile, newTile, inSimulation, roomLoad, onClick }) => { +const TileGroup = ({ tile, newTile, roomLoad, onClick }) => { let tileObject if (tile.rackId) { tileObject = <RackContainer tile={tile}/> @@ -18,8 +17,6 @@ const TileGroup = ({ tile, newTile, inSimulation, roomLoad, onClick }) => { let color = ROOM_DEFAULT_COLOR if (newTile) { color = ROOM_IN_CONSTRUCTION_COLOR - } else if (inSimulation && roomLoad >= 0) { - color = convertLoadToSimulationColor(roomLoad) } return ( diff --git a/frontend/src/components/app/sidebars/elements/LoadBarComponent.js b/frontend/src/components/app/sidebars/elements/LoadBarComponent.js deleted file mode 100644 index 01005085..00000000 --- a/frontend/src/components/app/sidebars/elements/LoadBarComponent.js +++ /dev/null @@ -1,22 +0,0 @@ -import classNames from 'classnames' -import React from 'react' - -const LoadBarComponent = ({ percent, disabled }) => ( - <div className="mt-1"> - <strong>Current load</strong> - <div className={classNames('progress', { disabled })}> - <div - className="progress-bar" - role="progressbar" - aria-valuenow={percent} - aria-valuemin="0" - aria-valuemax="100" - style={{ width: percent + '%' }} - > - {percent}% - </div> - </div> - </div> -) - -export default LoadBarComponent diff --git a/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js b/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js deleted file mode 100644 index 30990a13..00000000 --- a/frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' - -const ExperimentMetadataComponent = ({ - experimentName, - topologyName, - traceName, - schedulerName, - }) => ( - <div> - <h2>{experimentName}</h2> - <p> - Topology: <strong>{topologyName}</strong> - </p> - <p> - Trace: <strong>{traceName}</strong> - </p> - <p> - Scheduler: <strong>{schedulerName}</strong> - </p> - </div> -) - -export default ExperimentMetadataComponent diff --git a/frontend/src/components/app/sidebars/simulation/LoadMetricComponent.js b/frontend/src/components/app/sidebars/simulation/LoadMetricComponent.js deleted file mode 100644 index 6ee6a3b9..00000000 --- a/frontend/src/components/app/sidebars/simulation/LoadMetricComponent.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react' -import { SIM_HIGH_COLOR, SIM_LOW_COLOR, SIM_MID_HIGH_COLOR, SIM_MID_LOW_COLOR } from '../../../../util/colors' -import { LOAD_NAME_MAP } from '../../../../util/simulation-load' - -const LoadMetricComponent = ({ loadMetric }) => ( - <div> - <div> - Colors represent <strong>{LOAD_NAME_MAP[loadMetric]}</strong> - </div> - <div className="btn-group mb-2" style={{ display: 'flex' }}> - <span - className="btn btn-secondary" - style={{ backgroundColor: SIM_LOW_COLOR, flex: 1 }} - title="0-25%" - /> - <span - className="btn btn-secondary" - style={{ backgroundColor: SIM_MID_LOW_COLOR, flex: 1 }} - title="25-50%" - /> - <span - className="btn btn-secondary" - style={{ backgroundColor: SIM_MID_HIGH_COLOR, flex: 1 }} - title="50-75%" - /> - <span - className="btn btn-secondary" - style={{ backgroundColor: SIM_HIGH_COLOR, flex: 1 }} - title="75-100%" - /> - </div> - </div> -) - -export default LoadMetricComponent diff --git a/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js b/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js deleted file mode 100644 index dba75eb2..00000000 --- a/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react' -import ExperimentMetadataContainer from '../../../../containers/app/sidebars/simulation/ExperimentMetadataContainer' -import LoadMetricContainer from '../../../../containers/app/sidebars/simulation/LoadMetricContainer' -import Sidebar from '../Sidebar' -import './SimulationSidebarComponent.css' - -const SimulationSidebarComponent = () => { - return ( - <Sidebar isRight={false}> - <div className="simulation-sidebar-container flex-column"> - <ExperimentMetadataContainer/> - <LoadMetricContainer/> - </div> - </Sidebar> - ) -} - -export default SimulationSidebarComponent diff --git a/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.sass b/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.sass deleted file mode 100644 index 6490cf8d..00000000 --- a/frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.sass +++ /dev/null @@ -1,8 +0,0 @@ -.simulation-sidebar-container - display: flex - height: 100% - max-height: 100% - -.trace-container - flex: 1 - overflow-y: scroll diff --git a/frontend/src/components/app/sidebars/topology/building/BuildingSidebarComponent.js b/frontend/src/components/app/sidebars/topology/building/BuildingSidebarComponent.js index 00965c18..4cc87798 100644 --- a/frontend/src/components/app/sidebars/topology/building/BuildingSidebarComponent.js +++ b/frontend/src/components/app/sidebars/topology/building/BuildingSidebarComponent.js @@ -2,18 +2,11 @@ import React from 'react' import NewRoomConstructionContainer from '../../../../../containers/app/sidebars/topology/building/NewRoomConstructionContainer' -const BuildingSidebarComponent = ({ inSimulation }) => { +const BuildingSidebarComponent = () => { return ( <div> <h2>Building</h2> - {inSimulation ? ( - <div className="alert alert-info"> - <span className="fa fa-info-circle mr-2"/> - <strong>Click on individual rooms</strong> to see their stats! - </div> - ) : ( - <NewRoomConstructionContainer/> - )} + <NewRoomConstructionContainer/> </div> ) } diff --git a/frontend/src/components/app/sidebars/topology/machine/MachineSidebarComponent.js b/frontend/src/components/app/sidebars/topology/machine/MachineSidebarComponent.js index 66c8c84f..d78c20eb 100644 --- a/frontend/src/components/app/sidebars/topology/machine/MachineSidebarComponent.js +++ b/frontend/src/components/app/sidebars/topology/machine/MachineSidebarComponent.js @@ -1,24 +1,15 @@ import React from 'react' -import LoadBarContainer from '../../../../../containers/app/sidebars/elements/LoadBarContainer' -import LoadChartContainer from '../../../../../containers/app/sidebars/elements/LoadChartContainer' import BackToRackContainer from '../../../../../containers/app/sidebars/topology/machine/BackToRackContainer' import DeleteMachineContainer from '../../../../../containers/app/sidebars/topology/machine/DeleteMachineContainer' import MachineNameContainer from '../../../../../containers/app/sidebars/topology/machine/MachineNameContainer' import UnitTabsContainer from '../../../../../containers/app/sidebars/topology/machine/UnitTabsContainer' -const MachineSidebarComponent = ({ inSimulation, machineId }) => { +const MachineSidebarComponent = ({ machineId }) => { return ( <div> <MachineNameContainer/> <BackToRackContainer/> - {inSimulation ? ( - <div> - <LoadBarContainer objectType="machine" objectId={machineId}/> - <LoadChartContainer objectType="machine" objectId={machineId}/> - </div> - ) : ( - <DeleteMachineContainer/> - )} + <DeleteMachineContainer/> <UnitTabsContainer/> </div> ) diff --git a/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js b/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js index bde6d444..3953347a 100644 --- a/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js +++ b/frontend/src/components/app/sidebars/topology/machine/UnitComponent.js @@ -53,14 +53,10 @@ class UnitComponent extends React.Component { data-content={unitInfo} data-html="true" /> - {this.props.inSimulation ? ( - undefined - ) : ( - <span - className="btn btn-outline-danger fa fa-trash" - onClick={this.props.onDelete} - /> - )} + <span + className="btn btn-outline-danger fa fa-trash" + onClick={this.props.onDelete} + /> </span> </li> ) diff --git a/frontend/src/components/app/sidebars/topology/machine/UnitListComponent.js b/frontend/src/components/app/sidebars/topology/machine/UnitListComponent.js index da65da23..fcd3e03b 100644 --- a/frontend/src/components/app/sidebars/topology/machine/UnitListComponent.js +++ b/frontend/src/components/app/sidebars/topology/machine/UnitListComponent.js @@ -1,7 +1,7 @@ import React from 'react' import UnitContainer from '../../../../../containers/app/sidebars/topology/machine/UnitContainer' -const UnitListComponent = ({ unitType, unitIds, inSimulation }) => ( +const UnitListComponent = ({ unitType, unitIds }) => ( <ul className="list-group mt-1"> {unitIds.length !== 0 ? ( unitIds.map((unitId, index) => ( @@ -14,13 +14,9 @@ const UnitListComponent = ({ unitType, unitIds, inSimulation }) => ( )) ) : ( <div className="alert alert-info"> - {inSimulation ? ( - <strong>No units of this type in this machine</strong> - ) : ( - <span> - <strong>No units...</strong> Add some with the menu above! - </span> - )} + <span> + <strong>No units...</strong> Add some with the menu above! + </span> </div> )} </ul> diff --git a/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js b/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js index df7eeb77..c774036f 100644 --- a/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js +++ b/frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js @@ -2,7 +2,7 @@ import React from 'react' import UnitAddContainer from '../../../../../containers/app/sidebars/topology/machine/UnitAddContainer' import UnitListContainer from '../../../../../containers/app/sidebars/topology/machine/UnitListContainer' -const UnitTabsComponent = ({ inSimulation }) => ( +const UnitTabsComponent = () => ( <div> <ul className="nav nav-tabs mt-2 mb-1" role="tablist"> <li className="nav-item"> @@ -43,19 +43,19 @@ const UnitTabsComponent = ({ inSimulation }) => ( </ul> <div className="tab-content"> <div className="tab-pane active" id="cpu-units" role="tabpanel"> - {inSimulation ? undefined : <UnitAddContainer unitType="cpu"/>} + <UnitAddContainer unitType="cpu"/> <UnitListContainer unitType="cpu"/> </div> <div className="tab-pane" id="gpu-units" role="tabpanel"> - {inSimulation ? undefined : <UnitAddContainer unitType="gpu"/>} + <UnitAddContainer unitType="gpu"/> <UnitListContainer unitType="gpu"/> </div> <div className="tab-pane" id="memory-units" role="tabpanel"> - {inSimulation ? undefined : <UnitAddContainer unitType="memory"/>} + <UnitAddContainer unitType="memory"/> <UnitListContainer unitType="memory"/> </div> <div className="tab-pane" id="storage-units" role="tabpanel"> - {inSimulation ? undefined : <UnitAddContainer unitType="storage"/>} + <UnitAddContainer unitType="storage"/> <UnitListContainer unitType="storage"/> </div> </div> diff --git a/frontend/src/components/app/sidebars/topology/rack/EmptySlotComponent.js b/frontend/src/components/app/sidebars/topology/rack/EmptySlotComponent.js index f182a78c..03b44aa6 100644 --- a/frontend/src/components/app/sidebars/topology/rack/EmptySlotComponent.js +++ b/frontend/src/components/app/sidebars/topology/rack/EmptySlotComponent.js @@ -1,18 +1,14 @@ import React from 'react' -const EmptySlotComponent = ({ position, onAdd, inSimulation }) => ( +const EmptySlotComponent = ({ position, onAdd }) => ( <li className="list-group-item d-flex justify-content-between align-items-center"> <span className="badge badge-default badge-info mr-1 disabled"> {position} </span> - {inSimulation ? ( - <span className="badge badge-default badge-success">Empty Slot</span> - ) : ( - <button className="btn btn-outline-primary" onClick={onAdd}> - <span className="fa fa-plus mr-2"/> - Add machine - </button> - )} + <button className="btn btn-outline-primary" onClick={onAdd}> + <span className="fa fa-plus mr-2"/> + Add machine + </button> </li> ) diff --git a/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js b/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js index b4204136..cec3c912 100644 --- a/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js +++ b/frontend/src/components/app/sidebars/topology/rack/MachineComponent.js @@ -1,6 +1,5 @@ import React from 'react' import Shapes from '../../../../../shapes' -import { convertLoadToSimulationColor } from '../../../../../util/simulation-load' const UnitIcon = ({ id, type }) => ( <div> @@ -16,14 +15,8 @@ const UnitIcon = ({ id, type }) => ( const MachineComponent = ({ position, machine, - inSimulation, - machineLoad, onClick, }) => { - let color = 'white' - if (inSimulation && machineLoad >= 0) { - color = convertLoadToSimulationColor(machineLoad) - } const hasNoUnits = machine.cpuIds.length + machine.gpuIds.length + @@ -35,7 +28,7 @@ const MachineComponent = ({ <li className="d-flex list-group-item list-group-item-action justify-content-between align-items-center" onClick={onClick} - style={{ backgroundColor: color }} + style={{ backgroundColor: 'white' }} > <span className="badge badge-default badge-info mr-1">{position}</span> <div className="d-inline-flex"> diff --git a/frontend/src/components/app/sidebars/topology/rack/RackSidebarComponent.js b/frontend/src/components/app/sidebars/topology/rack/RackSidebarComponent.js index 47d99254..23e8e743 100644 --- a/frontend/src/components/app/sidebars/topology/rack/RackSidebarComponent.js +++ b/frontend/src/components/app/sidebars/topology/rack/RackSidebarComponent.js @@ -1,28 +1,17 @@ import React from 'react' -import LoadBarContainer from '../../../../../containers/app/sidebars/elements/LoadBarContainer' -import LoadChartContainer from '../../../../../containers/app/sidebars/elements/LoadChartContainer' import BackToRoomContainer from '../../../../../containers/app/sidebars/topology/rack/BackToRoomContainer' import DeleteRackContainer from '../../../../../containers/app/sidebars/topology/rack/DeleteRackContainer' import MachineListContainer from '../../../../../containers/app/sidebars/topology/rack/MachineListContainer' import RackNameContainer from '../../../../../containers/app/sidebars/topology/rack/RackNameContainer' import './RackSidebarComponent.css' -const RackSidebarComponent = ({ inSimulation, rackId }) => { +const RackSidebarComponent = () => { return ( <div className="rack-sidebar-container flex-column"> <div className="rack-sidebar-header-container"> <RackNameContainer/> <BackToRoomContainer/> - {inSimulation ? ( - <div> - <LoadBarContainer objectType="rack" objectId={rackId}/> - <LoadChartContainer objectType="rack" objectId={rackId}/> - </div> - ) : ( - <div> - <DeleteRackContainer/> - </div> - )} + <DeleteRackContainer/> </div> <div className="machine-list-container mt-2"> <MachineListContainer/> diff --git a/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js b/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js index d8a805cb..a23ac381 100644 --- a/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js +++ b/frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js @@ -1,29 +1,18 @@ import React from 'react' -import LoadBarContainer from '../../../../../containers/app/sidebars/elements/LoadBarContainer' -import LoadChartContainer from '../../../../../containers/app/sidebars/elements/LoadChartContainer' import BackToBuildingContainer from '../../../../../containers/app/sidebars/topology/room/BackToBuildingContainer' import DeleteRoomContainer from '../../../../../containers/app/sidebars/topology/room/DeleteRoomContainer' import EditRoomContainer from '../../../../../containers/app/sidebars/topology/room/EditRoomContainer' import RackConstructionContainer from '../../../../../containers/app/sidebars/topology/room/RackConstructionContainer' import RoomNameContainer from '../../../../../containers/app/sidebars/topology/room/RoomNameContainer' -const RoomSidebarComponent = ({ roomId, inSimulation }) => { +const RoomSidebarComponent = () => { return ( <div> <RoomNameContainer/> <BackToBuildingContainer/> - {inSimulation ? ( - <div> - <LoadBarContainer objectType="room" objectId={roomId}/> - <LoadChartContainer objectType="room" objectId={roomId}/> - </div> - ) : ( - <div> - <RackConstructionContainer/> - <EditRoomContainer/> - <DeleteRoomContainer/> - </div> - )} + <RackConstructionContainer/> + <EditRoomContainer/> + <DeleteRoomContainer/> </div> ) } diff --git a/frontend/src/components/app/timeline/PlayButtonComponent.js b/frontend/src/components/app/timeline/PlayButtonComponent.js deleted file mode 100644 index 7968c68d..00000000 --- a/frontend/src/components/app/timeline/PlayButtonComponent.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react' - -const PlayButtonComponent = ({ - isPlaying, - currentTick, - lastSimulatedTick, - onPlay, - onPause, - }) => ( - <div - className="play-btn" - onClick={() => { - if (isPlaying) { - onPause() - } else { - if (currentTick !== lastSimulatedTick) { - onPlay() - } - } - }} - > - {isPlaying ? ( - <span className="fa fa-pause"/> - ) : ( - <span className="fa fa-play"/> - )} - </div> -) - -export default PlayButtonComponent diff --git a/frontend/src/components/app/timeline/Timeline.sass b/frontend/src/components/app/timeline/Timeline.sass deleted file mode 100644 index 2d2cb979..00000000 --- a/frontend/src/components/app/timeline/Timeline.sass +++ /dev/null @@ -1,116 +0,0 @@ -@import ../../../style-globals/_variables.sass -@import ../../../style-globals/_mixins.sass - -$container-size: 500px -$play-btn-size: 40px -$border-width: 1px -$timeline-border: $border-width solid $gray-semi-dark - -.timeline-bar - display: block - position: absolute - left: 0 - bottom: 20px - width: 100% - text-align: center - z-index: 2000 - - pointer-events: none - -.timeline-container - display: inline-block - margin: 0 auto - text-align: left - - width: $container-size - -.timeline-labels - display: block - height: 25px - line-height: 25px - - div - display: inline-block - - .start-time-label - margin-left: $play-btn-size - $border-width - padding-left: 4px - - .end-time-label - padding-right: 4px - float: right - -.timeline-controls - display: flex - border: $timeline-border - overflow: hidden - - pointer-events: all - - +border-radius($standard-border-radius) - - .play-btn - width: $play-btn-size - height: $play-btn-size + $border-width - line-height: $play-btn-size + $border-width - text-align: center - float: left - margin-top: -$border-width - - font-size: 16pt - background: #333 - color: #eee - - +transition(background, $transition-length) - +user-select - +clickable - - .play-btn:hover - background: #656565 - - .play-btn:active - background: #000 - - .timeline - position: relative - flex: 1 - height: $play-btn-size - line-height: $play-btn-size - float: right - - background: $blue-light - - z-index: 500 - - div - +transition(all, $transition-length) - - .time-marker - position: absolute - top: 0 - left: 0 - - width: 6px - height: 100% - - background: $blue-very-dark - - +border-radius(2px) - - z-index: 503 - - pointer-events: none - - .section-marker - position: absolute - top: 0 - left: 0 - - width: 3px - height: 100% - - background: #222222 - - z-index: 504 - - pointer-events: none diff --git a/frontend/src/components/app/timeline/TimelineComponent.js b/frontend/src/components/app/timeline/TimelineComponent.js deleted file mode 100644 index c183c0e8..00000000 --- a/frontend/src/components/app/timeline/TimelineComponent.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import TimelineControlsContainer from '../../../containers/app/timeline/TimelineControlsContainer' -import TimelineLabelsContainer from '../../../containers/app/timeline/TimelineLabelsContainer' -import './Timeline.css' - -class TimelineComponent extends React.Component { - componentDidMount() { - this.interval = setInterval(() => { - if (!this.props.isPlaying) { - return - } - - if (this.props.currentTick < this.props.lastSimulatedTick) { - this.props.incrementTick() - } else { - this.props.pauseSimulation() - } - }, 1000) - } - - componentWillUnmount() { - clearInterval(this.interval) - } - - render() { - return ( - <div className="timeline-bar"> - <div className="timeline-container"> - <TimelineLabelsContainer/> - <TimelineControlsContainer/> - </div> - </div> - ) - } -} - -export default TimelineComponent diff --git a/frontend/src/components/app/timeline/TimelineControlsComponent.js b/frontend/src/components/app/timeline/TimelineControlsComponent.js deleted file mode 100644 index 01911aff..00000000 --- a/frontend/src/components/app/timeline/TimelineControlsComponent.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import PlayButtonContainer from '../../../containers/app/timeline/PlayButtonContainer' -import { convertTickToPercentage } from '../../../util/timeline' - -class TimelineControlsComponent extends React.Component { - onTimelineClick(e) { - const percentage = e.nativeEvent.offsetX / this.timeline.clientWidth - const tick = Math.floor(percentage * (this.props.lastSimulatedTick + 1)) - this.props.goToTick(tick) - } - - render() { - return ( - <div className="timeline-controls"> - <PlayButtonContainer/> - <div - className="timeline" - ref={timeline => (this.timeline = timeline)} - onClick={this.onTimelineClick.bind(this)} - > - <div - className="time-marker" - style={{ - left: convertTickToPercentage( - this.props.currentTick, - this.props.lastSimulatedTick, - ), - }} - /> - </div> - </div> - ) - } -} - -export default TimelineControlsComponent diff --git a/frontend/src/components/app/timeline/TimelineLabelsComponent.js b/frontend/src/components/app/timeline/TimelineLabelsComponent.js deleted file mode 100644 index 55818d24..00000000 --- a/frontend/src/components/app/timeline/TimelineLabelsComponent.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import { convertSecondsToFormattedTime } from '../../../util/date-time' - -const TimelineLabelsComponent = ({ currentTick, lastSimulatedTick }) => ( - <div className="timeline-labels"> - <div className="start-time-label"> - {convertSecondsToFormattedTime(currentTick)} - </div> - <div className="end-time-label"> - {convertSecondsToFormattedTime(lastSimulatedTick)} - </div> - </div> -) - -export default TimelineLabelsComponent diff --git a/frontend/src/components/experiments/ExperimentRowComponent.js b/frontend/src/components/experiments/ExperimentRowComponent.js index 880d7e31..c6ae1ba4 100644 --- a/frontend/src/components/experiments/ExperimentRowComponent.js +++ b/frontend/src/components/experiments/ExperimentRowComponent.js @@ -3,7 +3,7 @@ import React from 'react' import { Link } from 'react-router-dom' import Shapes from '../../shapes/index' -const ExperimentRowComponent = ({ experiment, simulationId, onDelete }) => ( +const ExperimentRowComponent = ({ experiment, projectId, onDelete }) => ( <tr> <td className="pt-3">{experiment.name}</td> <td className="pt-3">{experiment.topology.name}</td> @@ -11,7 +11,7 @@ const ExperimentRowComponent = ({ experiment, simulationId, onDelete }) => ( <td className="pt-3">{experiment.scheduler.name}</td> <td className="text-right"> <Link - to={'/simulations/' + simulationId + '/experiments/' + experiment._id} + to={'/projects/' + projectId + '/experiments/' + experiment._id} className="btn btn-outline-primary btn-sm mr-2" title="Open this experiment" > @@ -30,7 +30,7 @@ const ExperimentRowComponent = ({ experiment, simulationId, onDelete }) => ( ExperimentRowComponent.propTypes = { experiment: Shapes.Experiment.isRequired, - simulationId: PropTypes.string.isRequired, + projectId: PropTypes.string.isRequired, } export default ExperimentRowComponent diff --git a/frontend/src/components/home/TechnologiesSection.js b/frontend/src/components/home/TechnologiesSection.js index 13d8ca02..01d55937 100644 --- a/frontend/src/components/home/TechnologiesSection.js +++ b/frontend/src/components/home/TechnologiesSection.js @@ -26,7 +26,7 @@ const TechnologiesSection = () => ( <FontAwesome name="database" className="mr-2"/> <strong>Database</strong> </span> - <span className="text-right">MariaDB</span> + <span className="text-right">MongoDB</span> </li> <li className="d-flex list-group-item justify-content-between align-items-center list-group-item-danger"> <span style={{ minWidth: 100 }}> diff --git a/frontend/src/components/navigation/AppNavbar.js b/frontend/src/components/navigation/AppNavbar.js index 15f08b5f..876d4abd 100644 --- a/frontend/src/components/navigation/AppNavbar.js +++ b/frontend/src/components/navigation/AppNavbar.js @@ -4,21 +4,21 @@ import { Link } from 'react-router-dom' import Navbar, { NavItem } from './Navbar' import './Navbar.css' -const AppNavbar = ({ simulationId, inSimulation, fullWidth, onViewTopologies }) => ( +const AppNavbar = ({ projectId, inProject, fullWidth, onViewTopologies }) => ( <Navbar fullWidth={fullWidth}> - <NavItem route="/simulations"> - <Link className="nav-link" title="My Simulations" to="/simulations"> + <NavItem route="/projects"> + <Link className="nav-link" title="My Projects" to="/projects"> <FontAwesome name="list" className="mr-2"/> - My Simulations + My Projects </Link> </NavItem> - {inSimulation ? ( + {inProject ? ( <> - <NavItem route={'/simulations/' + simulationId}> + <NavItem route={'/projects/' + projectId}> <Link className="nav-link" title="Construction" - to={'/simulations/' + simulationId} + to={'/projects/' + projectId} > <FontAwesome name="industry" className="mr-2"/> Construction @@ -34,11 +34,11 @@ const AppNavbar = ({ simulationId, inSimulation, fullWidth, onViewTopologies }) Topologies </span> </NavItem> - <NavItem route={'/simulations/' + simulationId + '/experiments'}> + <NavItem route={'/projects/' + projectId + '/experiments'}> <Link className="nav-link" title="Experiments" - to={'/simulations/' + simulationId + '/experiments'} + to={'/projects/' + projectId + '/experiments'} > <FontAwesome name="play" className="mr-2"/> Experiments diff --git a/frontend/src/components/navigation/HomeNavbar.js b/frontend/src/components/navigation/HomeNavbar.js index 5bb6721d..4e3f3869 100644 --- a/frontend/src/components/navigation/HomeNavbar.js +++ b/frontend/src/components/navigation/HomeNavbar.js @@ -14,7 +14,7 @@ const HomeNavbar = () => ( <Navbar fullWidth={false}> <ScrollNavItem id="#stakeholders" name="Stakeholders"/> <ScrollNavItem id="#modeling" name="Modeling"/> - <ScrollNavItem id="#simulation" name="Simulation"/> + <ScrollNavItem id="#project" name="Project"/> <ScrollNavItem id="#technologies" name="Technologies"/> <ScrollNavItem id="#team" name="Team"/> <ScrollNavItem id="#contact" name="Contact"/> diff --git a/frontend/src/components/navigation/Navbar.js b/frontend/src/components/navigation/Navbar.js index b47f1f94..0ef19ecb 100644 --- a/frontend/src/components/navigation/Navbar.js +++ b/frontend/src/components/navigation/Navbar.js @@ -40,9 +40,9 @@ const LoggedInSectionWithoutRoute = ({ location }) => ( {userIsLoggedIn() ? ( [ location.pathname === '/' ? ( - <NavItem route="/simulations" key="simulations"> - <Link className="nav-link" title="My Simulations" to="/simulations"> - My Simulations + <NavItem route="/projects" key="projects"> + <Link className="nav-link" title="My Projects" to="/projects"> + My Projects </Link> </NavItem> ) : ( diff --git a/frontend/src/components/simulations/FilterButton.js b/frontend/src/components/projects/FilterButton.js index 664f9b46..664f9b46 100644 --- a/frontend/src/components/simulations/FilterButton.js +++ b/frontend/src/components/projects/FilterButton.js diff --git a/frontend/src/components/simulations/FilterPanel.js b/frontend/src/components/projects/FilterPanel.js index cbc3bf6a..0970f573 100644 --- a/frontend/src/components/simulations/FilterPanel.js +++ b/frontend/src/components/projects/FilterPanel.js @@ -1,11 +1,11 @@ import React from 'react' -import FilterLink from '../../containers/simulations/FilterLink' +import FilterLink from '../../containers/projects/FilterLink' import './FilterPanel.css' const FilterPanel = () => ( <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_ALL">All Projects</FilterLink> + <FilterLink filter="SHOW_OWN">My Projects</FilterLink> <FilterLink filter="SHOW_SHARED">Shared with me</FilterLink> </div> ) diff --git a/frontend/src/components/simulations/FilterPanel.sass b/frontend/src/components/projects/FilterPanel.sass index f71cf6c8..f71cf6c8 100644 --- a/frontend/src/components/simulations/FilterPanel.sass +++ b/frontend/src/components/projects/FilterPanel.sass diff --git a/frontend/src/components/simulations/NewSimulationButtonComponent.js b/frontend/src/components/projects/NewProjectButtonComponent.js index d07a6419..3ddef5e5 100644 --- a/frontend/src/components/simulations/NewSimulationButtonComponent.js +++ b/frontend/src/components/projects/NewProjectButtonComponent.js @@ -1,17 +1,17 @@ import PropTypes from 'prop-types' import React from 'react' -const NewSimulationButtonComponent = ({ onClick }) => ( +const NewProjectButtonComponent = ({ onClick }) => ( <div className="bottom-btn-container"> <div className="btn btn-primary float-right" onClick={onClick}> <span className="fa fa-plus mr-2"/> - New Simulation + New Project </div> </div> ) -NewSimulationButtonComponent.propTypes = { +NewProjectButtonComponent.propTypes = { onClick: PropTypes.func.isRequired, } -export default NewSimulationButtonComponent +export default NewProjectButtonComponent diff --git a/frontend/src/components/simulations/SimulationActionButtons.js b/frontend/src/components/projects/ProjectActionButtons.js index 3395cdeb..456dd6b6 100644 --- a/frontend/src/components/simulations/SimulationActionButtons.js +++ b/frontend/src/components/projects/ProjectActionButtons.js @@ -2,36 +2,36 @@ import PropTypes from 'prop-types' import React from 'react' import { Link } from 'react-router-dom' -const SimulationActionButtons = ({ simulationId, onViewUsers, onDelete }) => ( +const ProjectActionButtons = ({ projectId, onViewUsers, onDelete }) => ( <td className="text-right"> <Link - to={'/simulations/' + simulationId} + to={'/projects/' + projectId} className="btn btn-outline-primary btn-sm mr-2" - title="Open this simulation" + title="Open this project" > <span className="fa fa-play"/> </Link> <div className="btn btn-outline-success btn-sm disabled mr-2" title="View and edit collaborators (not supported currently)" - onClick={() => onViewUsers(simulationId)} + onClick={() => onViewUsers(projectId)} > <span className="fa fa-users"/> </div> <div className="btn btn-outline-danger btn-sm" - title="Delete this simulation" - onClick={() => onDelete(simulationId)} + title="Delete this project" + onClick={() => onDelete(projectId)} > <span className="fa fa-trash"/> </div> </td> ) -SimulationActionButtons.propTypes = { - simulationId: PropTypes.string.isRequired, +ProjectActionButtons.propTypes = { + projectId: PropTypes.string.isRequired, onViewUsers: PropTypes.func, onDelete: PropTypes.func, } -export default SimulationActionButtons +export default ProjectActionButtons diff --git a/frontend/src/components/simulations/SimulationAuthList.js b/frontend/src/components/projects/ProjectAuthList.js index c760d08f..5a2c6695 100644 --- a/frontend/src/components/simulations/SimulationAuthList.js +++ b/frontend/src/components/projects/ProjectAuthList.js @@ -1,22 +1,22 @@ import PropTypes from 'prop-types' import React from 'react' import Shapes from '../../shapes/index' -import SimulationAuthRow from './SimulationAuthRow' +import ProjectAuthRow from './ProjectAuthRow' -const SimulationAuthList = ({ authorizations }) => { +const ProjectAuthList = ({ authorizations }) => { return ( <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! + <strong>No projects here yet...</strong> Add some with the 'New + Project' button! </div> ) : ( <table className="table table-striped"> <thead> <tr> - <th>Simulation name</th> + <th>Project name</th> <th>Last edited</th> <th>Access rights</th> <th/> @@ -24,9 +24,9 @@ const SimulationAuthList = ({ authorizations }) => { </thead> <tbody> {authorizations.map(authorization => ( - <SimulationAuthRow - simulationAuth={authorization} - key={authorization.simulation._id} + <ProjectAuthRow + projectAuth={authorization} + key={authorization.project._id} /> ))} </tbody> @@ -36,8 +36,8 @@ const SimulationAuthList = ({ authorizations }) => { ) } -SimulationAuthList.propTypes = { +ProjectAuthList.propTypes = { authorizations: PropTypes.arrayOf(Shapes.Authorization).isRequired, } -export default SimulationAuthList +export default ProjectAuthList diff --git a/frontend/src/components/projects/ProjectAuthRow.js b/frontend/src/components/projects/ProjectAuthRow.js new file mode 100644 index 00000000..be9de6e0 --- /dev/null +++ b/frontend/src/components/projects/ProjectAuthRow.js @@ -0,0 +1,32 @@ +import classNames from 'classnames' +import React from 'react' +import ProjectActions from '../../containers/projects/ProjectActions' +import Shapes from '../../shapes/index' +import { AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP } from '../../util/authorizations' +import { parseAndFormatDateTime } from '../../util/date-time' + +const ProjectAuthRow = ({ projectAuth }) => ( + <tr> + <td className="pt-3">{projectAuth.project.name}</td> + <td className="pt-3"> + {parseAndFormatDateTime(projectAuth.project.datetimeLastEdited)} + </td> + <td className="pt-3"> + <span + className={classNames( + 'fa', + 'fa-' + AUTH_ICON_MAP[projectAuth.authorizationLevel], + 'mr-2', + )} + /> + {AUTH_DESCRIPTION_MAP[projectAuth.authorizationLevel]} + </td> + <ProjectActions projectId={projectAuth.project._id}/> + </tr> +) + +ProjectAuthRow.propTypes = { + projectAuth: Shapes.Authorization.isRequired, +} + +export default ProjectAuthRow diff --git a/frontend/src/components/simulations/SimulationAuthRow.js b/frontend/src/components/simulations/SimulationAuthRow.js deleted file mode 100644 index 0e9c36da..00000000 --- a/frontend/src/components/simulations/SimulationAuthRow.js +++ /dev/null @@ -1,32 +0,0 @@ -import classNames from 'classnames' -import React from 'react' -import SimulationActions from '../../containers/simulations/SimulationActions' -import Shapes from '../../shapes/index' -import { AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP } from '../../util/authorizations' -import { parseAndFormatDateTime } from '../../util/date-time' - -const SimulationAuthRow = ({ simulationAuth }) => ( - <tr> - <td className="pt-3">{simulationAuth.simulation.name}</td> - <td className="pt-3"> - {parseAndFormatDateTime(simulationAuth.simulation.datetimeLastEdited)} - </td> - <td className="pt-3"> - <span - className={classNames( - 'fa', - 'fa-' + AUTH_ICON_MAP[simulationAuth.authorizationLevel], - 'mr-2', - )} - /> - {AUTH_DESCRIPTION_MAP[simulationAuth.authorizationLevel]} - </td> - <SimulationActions simulationId={simulationAuth.simulation._id}/> - </tr> -) - -SimulationAuthRow.propTypes = { - simulationAuth: Shapes.Authorization.isRequired, -} - -export default SimulationAuthRow diff --git a/frontend/src/containers/app/map/RackContainer.js b/frontend/src/containers/app/map/RackContainer.js index 34e7bbab..40077608 100644 --- a/frontend/src/containers/app/map/RackContainer.js +++ b/frontend/src/containers/app/map/RackContainer.js @@ -1,27 +1,9 @@ import { connect } from 'react-redux' import RackGroup from '../../../components/app/map/groups/RackGroup' -import { getStateLoad } from '../../../util/simulation-load' - -const mapStateToProps = (state, ownProps) => { - const inSimulation = state.currentExperimentId !== '-1' - - let rackLoad = undefined - if (inSimulation) { - if ( - state.states.rack[state.currentTick] && - state.states.rack[state.currentTick][ownProps.tile.rackId] - ) { - rackLoad = getStateLoad( - state.loadMetric, - state.states.rack[state.currentTick][ownProps.tile.rackId], - ) - } - } +const mapStateToProps = (state) => { return { interactionLevel: state.interactionLevel, - inSimulation, - rackLoad, } } diff --git a/frontend/src/containers/app/map/TileContainer.js b/frontend/src/containers/app/map/TileContainer.js index 28289206..ddef097c 100644 --- a/frontend/src/containers/app/map/TileContainer.js +++ b/frontend/src/containers/app/map/TileContainer.js @@ -1,30 +1,13 @@ import { connect } from 'react-redux' import { goFromRoomToRack } from '../../../actions/interaction-level' import TileGroup from '../../../components/app/map/groups/TileGroup' -import { getStateLoad } from '../../../util/simulation-load' const mapStateToProps = (state, ownProps) => { const tile = state.objects.tile[ownProps.tileId] - const inSimulation = state.currentExperimentId !== '-1' - - let roomLoad = undefined - if (inSimulation) { - if ( - state.states.room[state.currentTick] && - state.states.room[state.currentTick][tile.roomId] - ) { - roomLoad = getStateLoad( - state.loadMetric, - state.states.room[state.currentTick][tile.roomId], - ) - } - } return { interactionLevel: state.interactionLevel, tile, - inSimulation, - roomLoad, } } diff --git a/frontend/src/containers/app/sidebars/elements/LoadBarContainer.js b/frontend/src/containers/app/sidebars/elements/LoadBarContainer.js deleted file mode 100644 index 5c423490..00000000 --- a/frontend/src/containers/app/sidebars/elements/LoadBarContainer.js +++ /dev/null @@ -1,32 +0,0 @@ -import { connect } from 'react-redux' -import LoadBarComponent from '../../../../components/app/sidebars/elements/LoadBarComponent' -import { getStateLoad } from '../../../../util/simulation-load' - -const mapStateToProps = (state, ownProps) => { - let percent = 0 - let enabled = false - - const objectStates = state.states[ownProps.objectType] - if ( - objectStates[state.currentTick] && - objectStates[state.currentTick][ownProps.objectId] - ) { - percent = Math.floor( - 100 * - getStateLoad( - state.loadMetric, - objectStates[state.currentTick][ownProps.objectId], - ), - ) - enabled = true - } - - return { - percent, - enabled, - } -} - -const LoadBarContainer = connect(mapStateToProps)(LoadBarComponent) - -export default LoadBarContainer diff --git a/frontend/src/containers/app/sidebars/elements/LoadChartContainer.js b/frontend/src/containers/app/sidebars/elements/LoadChartContainer.js index 49962d57..61f95932 100644 --- a/frontend/src/containers/app/sidebars/elements/LoadChartContainer.js +++ b/frontend/src/containers/app/sidebars/elements/LoadChartContainer.js @@ -1,25 +1,9 @@ import { connect } from 'react-redux' import LoadChartComponent from '../../../../components/app/sidebars/elements/LoadChartComponent' -import { getStateLoad } from '../../../../util/simulation-load' const mapStateToProps = (state, ownProps) => { const data = [] - if (state.lastSimulatedTick !== -1) { - const objectStates = state.states[ownProps.objectType] - Object.keys(objectStates).forEach(tick => { - if (objectStates[tick][ownProps.objectId]) { - data.push({ - x: tick, - y: getStateLoad( - state.loadMetric, - objectStates[tick][ownProps.objectId], - ), - }) - } - }) - } - return { data, currentTick: state.currentTick, diff --git a/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js b/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js deleted file mode 100644 index 0dc20ea7..00000000 --- a/frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js +++ /dev/null @@ -1,38 +0,0 @@ -import { connect } from 'react-redux' -import ExperimentMetadataComponent from '../../../../components/app/sidebars/simulation/ExperimentMetadataComponent' - -const mapStateToProps = state => { - if (!state.objects.experiment[state.currentExperimentId]) { - return { - experimentName: 'Loading experiment', - topologyName: '', - traceName: '', - schedulerName: '', - } - } - - const topology = - state.objects.topology[ - state.objects.experiment[state.currentExperimentId].topologyId - ] - const topologyName = topology.name - - return { - experimentName: state.objects.experiment[state.currentExperimentId].name, - topologyName, - traceName: - state.objects.trace[ - state.objects.experiment[state.currentExperimentId].traceId - ].name, - schedulerName: - state.objects.scheduler[ - state.objects.experiment[state.currentExperimentId].schedulerName - ].name, - } -} - -const ExperimentMetadataContainer = connect(mapStateToProps)( - ExperimentMetadataComponent, -) - -export default ExperimentMetadataContainer diff --git a/frontend/src/containers/app/sidebars/simulation/LoadMetricContainer.js b/frontend/src/containers/app/sidebars/simulation/LoadMetricContainer.js deleted file mode 100644 index a8654698..00000000 --- a/frontend/src/containers/app/sidebars/simulation/LoadMetricContainer.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import LoadMetricComponent from '../../../../components/app/sidebars/simulation/LoadMetricComponent' - -const mapStateToProps = state => { - return { - loadMetric: state.loadMetric, - } -} - -const LoadMetricContainer = connect(mapStateToProps)(LoadMetricComponent) - -export default LoadMetricContainer diff --git a/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js index 8c8cb79b..a0b52e56 100644 --- a/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js @@ -1,14 +1,5 @@ -import { connect } from 'react-redux' import BuildingSidebarComponent from '../../../../../components/app/sidebars/topology/building/BuildingSidebarComponent' -const mapStateToProps = state => { - return { - inSimulation: state.currentExperimentId !== '-1', - } -} - -const BuildingSidebarContainer = connect(mapStateToProps)( - BuildingSidebarComponent, -) +const BuildingSidebarContainer = BuildingSidebarComponent export default BuildingSidebarContainer diff --git a/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js index 3cff7cd1..868f26da 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js @@ -3,7 +3,6 @@ import MachineSidebarComponent from '../../../../../components/app/sidebars/topo const mapStateToProps = state => { return { - inSimulation: state.currentExperimentId !== '-1', machineId: state.objects.rack[ state.objects.tile[state.interactionLevel.tileId].rackId diff --git a/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js b/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js index 7c26b47f..bd629564 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js @@ -4,7 +4,6 @@ import UnitComponent from '../../../../../components/app/sidebars/topology/machi const mapStateToProps = (state, ownProps) => { return { - inSimulation: state.currentExperimentId !== '-1', unit: state.objects[ownProps.unitType][ownProps.unitId], } } diff --git a/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js b/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js index 2596c2bd..e3ad77fd 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js @@ -3,11 +3,10 @@ import UnitListComponent from '../../../../../components/app/sidebars/topology/m const mapStateToProps = (state, ownProps) => { return { - inSimulation: state.currentExperimentId !== '-1', unitIds: state.objects.machine[ state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].rackId + state.objects.tile[state.interactionLevel.tileId].rackId ].machineIds[state.interactionLevel.position - 1] ][ownProps.unitType + 'Ids'], } diff --git a/frontend/src/containers/app/sidebars/topology/machine/UnitTabsContainer.js b/frontend/src/containers/app/sidebars/topology/machine/UnitTabsContainer.js index 5c606de4..00fe4067 100644 --- a/frontend/src/containers/app/sidebars/topology/machine/UnitTabsContainer.js +++ b/frontend/src/containers/app/sidebars/topology/machine/UnitTabsContainer.js @@ -1,12 +1,5 @@ -import { connect } from 'react-redux' import UnitTabsComponent from '../../../../../components/app/sidebars/topology/machine/UnitTabsComponent' -const mapStateToProps = state => { - return { - inSimulation: state.currentExperimentId !== '-1', - } -} - -const UnitTabsContainer = connect(mapStateToProps)(UnitTabsComponent) +const UnitTabsContainer = UnitTabsComponent export default UnitTabsContainer diff --git a/frontend/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js b/frontend/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js index d580a3e0..ab287bac 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js @@ -2,19 +2,13 @@ import { connect } from 'react-redux' import { addMachine } from '../../../../../actions/topology/rack' import EmptySlotComponent from '../../../../../components/app/sidebars/topology/rack/EmptySlotComponent' -const mapStateToProps = state => { - return { - inSimulation: state.currentExperimentId !== '-1', - } -} - const mapDispatchToProps = (dispatch, ownProps) => { return { onAdd: () => dispatch(addMachine(ownProps.position)), } } -const EmptySlotContainer = connect(mapStateToProps, mapDispatchToProps)( +const EmptySlotContainer = connect(undefined, mapDispatchToProps)( EmptySlotComponent, ) diff --git a/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js b/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js index 43558329..6b0f0a04 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js @@ -1,29 +1,10 @@ import { connect } from 'react-redux' import { goFromRackToMachine } from '../../../../../actions/interaction-level' import MachineComponent from '../../../../../components/app/sidebars/topology/rack/MachineComponent' -import { getStateLoad } from '../../../../../util/simulation-load' const mapStateToProps = (state, ownProps) => { - const machine = state.objects.machine[ownProps.machineId] - const inSimulation = state.currentExperimentId !== '-1' - - let machineLoad = undefined - if (inSimulation) { - if ( - state.states.machine[state.currentTick] && - state.states.machine[state.currentTick][machine._id] - ) { - machineLoad = getStateLoad( - state.loadMetric, - state.states.machine[state.currentTick][machine._id], - ) - } - } - return { - machine, - inSimulation, - machineLoad, + machine: state.objects.machine[ownProps.machineId], } } diff --git a/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js b/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js index 1eb885fc..4d8e8936 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js @@ -6,7 +6,7 @@ const mapStateToProps = state => { return { rackName: state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].rackId + state.objects.tile[state.interactionLevel.tileId].rackId ].name, } } diff --git a/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js index 7f931979..d9be1e8b 100644 --- a/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js @@ -4,7 +4,6 @@ import RackSidebarComponent from '../../../../../components/app/sidebars/topolog const mapStateToProps = state => { return { rackId: state.objects.tile[state.interactionLevel.tileId].rackId, - inSimulation: state.currentExperimentId !== '-1', } } diff --git a/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js b/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js index 413c8f21..a95e290d 100644 --- a/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js +++ b/frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js @@ -3,7 +3,6 @@ import RoomSidebarComponent from '../../../../../components/app/sidebars/topolog const mapStateToProps = state => { return { - inSimulation: state.currentExperimentId !== '-1', roomId: state.interactionLevel.roomId, } } diff --git a/frontend/src/containers/app/timeline/PlayButtonContainer.js b/frontend/src/containers/app/timeline/PlayButtonContainer.js deleted file mode 100644 index 9662d753..00000000 --- a/frontend/src/containers/app/timeline/PlayButtonContainer.js +++ /dev/null @@ -1,24 +0,0 @@ -import { connect } from 'react-redux' -import { pauseSimulation, playSimulation } from '../../../actions/simulation/playback' -import PlayButtonComponent from '../../../components/app/timeline/PlayButtonComponent' - -const mapStateToProps = state => { - return { - isPlaying: state.isPlaying, - currentTick: state.currentTick, - lastSimulatedTick: state.lastSimulatedTick, - } -} - -const mapDispatchToProps = dispatch => { - return { - onPlay: () => dispatch(playSimulation()), - onPause: () => dispatch(pauseSimulation()), - } -} - -const PlayButtonContainer = connect(mapStateToProps, mapDispatchToProps)( - PlayButtonComponent, -) - -export default PlayButtonContainer diff --git a/frontend/src/containers/app/timeline/TimelineContainer.js b/frontend/src/containers/app/timeline/TimelineContainer.js deleted file mode 100644 index 9b196a1b..00000000 --- a/frontend/src/containers/app/timeline/TimelineContainer.js +++ /dev/null @@ -1,26 +0,0 @@ -import { connect } from 'react-redux' -import { pauseSimulation } from '../../../actions/simulation/playback' -import { incrementTick } from '../../../actions/simulation/tick' -import TimelineComponent from '../../../components/app/timeline/TimelineComponent' - -const mapStateToProps = state => { - return { - isPlaying: state.isPlaying, - currentTick: state.currentTick, - lastSimulatedTick: state.lastSimulatedTick, - currentTopologyId: state.currentTopologyId, - } -} - -const mapDispatchToProps = dispatch => { - return { - incrementTick: () => dispatch(incrementTick()), - pauseSimulation: () => dispatch(pauseSimulation()), - } -} - -const TimelineContainer = connect(mapStateToProps, mapDispatchToProps)( - TimelineComponent, -) - -export default TimelineContainer diff --git a/frontend/src/containers/app/timeline/TimelineControlsContainer.js b/frontend/src/containers/app/timeline/TimelineControlsContainer.js deleted file mode 100644 index 91aba98d..00000000 --- a/frontend/src/containers/app/timeline/TimelineControlsContainer.js +++ /dev/null @@ -1,22 +0,0 @@ -import { connect } from 'react-redux' -import { goToTick } from '../../../actions/simulation/tick' -import TimelineControlsComponent from '../../../components/app/timeline/TimelineControlsComponent' - -const mapStateToProps = state => { - return { - currentTick: state.currentTick, - lastSimulatedTick: state.lastSimulatedTick, - } -} - -const mapDispatchToProps = dispatch => { - return { - goToTick: tick => dispatch(goToTick(tick)), - } -} - -const TimelineControlsContainer = connect(mapStateToProps, mapDispatchToProps)( - TimelineControlsComponent, -) - -export default TimelineControlsContainer diff --git a/frontend/src/containers/app/timeline/TimelineLabelsContainer.js b/frontend/src/containers/app/timeline/TimelineLabelsContainer.js deleted file mode 100644 index 192d21c3..00000000 --- a/frontend/src/containers/app/timeline/TimelineLabelsContainer.js +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux' -import TimelineLabelsComponent from '../../../components/app/timeline/TimelineLabelsComponent' - -const mapStateToProps = state => { - return { - currentTick: state.currentTick, - lastSimulatedTick: state.lastSimulatedTick, - } -} - -const TimelineLabelsContainer = connect(mapStateToProps)( - TimelineLabelsComponent, -) - -export default TimelineLabelsContainer diff --git a/frontend/src/containers/experiments/ExperimentListContainer.js b/frontend/src/containers/experiments/ExperimentListContainer.js index fc8f203b..0b3b70ca 100644 --- a/frontend/src/containers/experiments/ExperimentListContainer.js +++ b/frontend/src/containers/experiments/ExperimentListContainer.js @@ -3,8 +3,8 @@ import ExperimentListComponent from '../../components/experiments/ExperimentList const mapStateToProps = state => { if ( - state.currentSimulationId === '-1' || - !('experimentIds' in state.objects.simulation[state.currentSimulationId]) + state.currentProjectId === '-1' || + !('experimentIds' in state.objects.project[state.currentProjectId]) ) { return { loading: true, @@ -13,7 +13,7 @@ const mapStateToProps = state => { } const experimentIds = - state.objects.simulation[state.currentSimulationId].experimentIds + state.objects.project[state.currentProjectId].experimentIds if (experimentIds) { return { experimentIds, diff --git a/frontend/src/containers/experiments/ExperimentRowContainer.js b/frontend/src/containers/experiments/ExperimentRowContainer.js index 523c0747..87d8af67 100644 --- a/frontend/src/containers/experiments/ExperimentRowContainer.js +++ b/frontend/src/containers/experiments/ExperimentRowContainer.js @@ -13,7 +13,7 @@ const mapStateToProps = (state, ownProps) => { return { experiment, - simulationId: state.currentSimulationId, + projectId: state.currentProjectId, } } diff --git a/frontend/src/containers/modals/ChangeTopologyModal.js b/frontend/src/containers/modals/ChangeTopologyModal.js index a1db9032..7904ef59 100644 --- a/frontend/src/containers/modals/ChangeTopologyModal.js +++ b/frontend/src/containers/modals/ChangeTopologyModal.js @@ -5,7 +5,7 @@ import { addTopology, deleteTopology } from '../../actions/topologies' import { setCurrentTopology } from '../../actions/topology/building' const mapStateToProps = state => { - let topologies = state.objects.simulation[state.currentSimulationId] ? state.objects.simulation[state.currentSimulationId].topologyIds.map(t => ( + let topologies = state.objects.project[state.currentProjectId] ? state.objects.project[state.currentProjectId].topologyIds.map(t => ( state.objects.topology[t] )) : [] if (topologies.filter(t => !t).length > 0) { @@ -23,14 +23,14 @@ const mapDispatchToProps = dispatch => { return { onChooseTopology: (id) => { dispatch( - setCurrentTopology(id) + setCurrentTopology(id), ) dispatch(closeChangeTopologyModal()) }, onCreateTopology: (name) => { if (name) { dispatch( - addTopology({name, rooms: []}) + addTopology({ name, rooms: [] }), ) } dispatch(closeChangeTopologyModal()) @@ -39,7 +39,7 @@ const mapDispatchToProps = dispatch => { if (name) { // TODO different handling here dispatch( - addTopology({name, rooms: []}) + addTopology({ name, rooms: [] }), ) } dispatch(closeChangeTopologyModal()) @@ -47,7 +47,7 @@ const mapDispatchToProps = dispatch => { onDeleteTopology: (id) => { if (id) { dispatch( - deleteTopology(id) + deleteTopology(id), ) } }, diff --git a/frontend/src/containers/modals/EditRackNameModal.js b/frontend/src/containers/modals/EditRackNameModal.js index 495c107b..fb7727f1 100644 --- a/frontend/src/containers/modals/EditRackNameModal.js +++ b/frontend/src/containers/modals/EditRackNameModal.js @@ -20,7 +20,7 @@ const mapStateToProps = state => { previousName: state.interactionLevel.mode === 'RACK' ? state.objects.rack[ - state.objects.tile[state.interactionLevel.tileId].rackId + state.objects.tile[state.interactionLevel.tileId].rackId ].name : '', } diff --git a/frontend/src/containers/modals/NewExperimentModal.js b/frontend/src/containers/modals/NewExperimentModal.js index 2ac5a4b8..f07b53e6 100644 --- a/frontend/src/containers/modals/NewExperimentModal.js +++ b/frontend/src/containers/modals/NewExperimentModal.js @@ -6,7 +6,7 @@ import NewExperimentModalComponent from '../../components/modals/custom-componen const mapStateToProps = state => { return { show: state.modals.newExperimentModalVisible, - topologies: state.objects.simulation[state.currentSimulationId].topologyIds.map(t => ( + topologies: state.objects.project[state.currentProjectId].topologyIds.map(t => ( state.objects.topology[t] )), traces: Object.values(state.objects.trace), diff --git a/frontend/src/containers/modals/NewProjectModal.js b/frontend/src/containers/modals/NewProjectModal.js new file mode 100644 index 00000000..1d0ebbbc --- /dev/null +++ b/frontend/src/containers/modals/NewProjectModal.js @@ -0,0 +1,37 @@ +import React from 'react' +import { connect } from 'react-redux' +import { closeNewProjectModal } from '../../actions/modals/projects' +import { addProject } from '../../actions/projects' +import TextInputModal from '../../components/modals/TextInputModal' + +const NewProjectModalComponent = ({ visible, callback }) => ( + <TextInputModal + title="New Project" + label="Project title" + show={visible} + callback={callback} + /> +) + +const mapStateToProps = state => { + return { + visible: state.modals.newProjectModalVisible, + } +} + +const mapDispatchToProps = dispatch => { + return { + callback: text => { + if (text) { + dispatch(addProject(text)) + } + dispatch(closeNewProjectModal()) + }, + } +} + +const NewProjectModal = connect(mapStateToProps, mapDispatchToProps)( + NewProjectModalComponent, +) + +export default NewProjectModal diff --git a/frontend/src/containers/modals/NewSimulationModal.js b/frontend/src/containers/modals/NewSimulationModal.js deleted file mode 100644 index e95ac4b0..00000000 --- a/frontend/src/containers/modals/NewSimulationModal.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import { connect } from 'react-redux' -import { closeNewSimulationModal } from '../../actions/modals/simulations' -import { addSimulation } from '../../actions/simulations' -import TextInputModal from '../../components/modals/TextInputModal' - -const NewSimulationModalComponent = ({ visible, callback }) => ( - <TextInputModal - title="New Simulation" - label="Simulation title" - show={visible} - callback={callback} - /> -) - -const mapStateToProps = state => { - return { - visible: state.modals.newSimulationModalVisible, - } -} - -const mapDispatchToProps = dispatch => { - return { - callback: text => { - if (text) { - dispatch(addSimulation(text)) - } - dispatch(closeNewSimulationModal()) - }, - } -} - -const NewSimulationModal = connect(mapStateToProps, mapDispatchToProps)( - NewSimulationModalComponent, -) - -export default NewSimulationModal diff --git a/frontend/src/containers/simulations/FilterLink.js b/frontend/src/containers/projects/FilterLink.js index 9eedd549..dfd6affe 100644 --- a/frontend/src/containers/simulations/FilterLink.js +++ b/frontend/src/containers/projects/FilterLink.js @@ -1,10 +1,10 @@ import { connect } from 'react-redux' -import { setAuthVisibilityFilter } from '../../actions/simulations' -import FilterButton from '../../components/simulations/FilterButton' +import { setAuthVisibilityFilter } from '../../actions/projects' +import FilterButton from '../../components/projects/FilterButton' const mapStateToProps = (state, ownProps) => { return { - active: state.simulationList.authVisibilityFilter === ownProps.filter, + active: state.projectList.authVisibilityFilter === ownProps.filter, } } diff --git a/frontend/src/containers/projects/NewProjectButtonContainer.js b/frontend/src/containers/projects/NewProjectButtonContainer.js new file mode 100644 index 00000000..f1d83ea3 --- /dev/null +++ b/frontend/src/containers/projects/NewProjectButtonContainer.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux' +import { openNewProjectModal } from '../../actions/modals/projects' +import NewProjectButtonComponent from '../../components/projects/NewProjectButtonComponent' + +const mapDispatchToProps = dispatch => { + return { + onClick: () => dispatch(openNewProjectModal()), + } +} + +const NewProjectButtonContainer = connect(undefined, mapDispatchToProps)( + NewProjectButtonComponent, +) + +export default NewProjectButtonContainer diff --git a/frontend/src/containers/projects/ProjectActions.js b/frontend/src/containers/projects/ProjectActions.js new file mode 100644 index 00000000..b9f9a534 --- /dev/null +++ b/frontend/src/containers/projects/ProjectActions.js @@ -0,0 +1,23 @@ +import { connect } from 'react-redux' +import { deleteProject } from '../../actions/projects' +import ProjectActionButtons from '../../components/projects/ProjectActionButtons' + +const mapStateToProps = (state, ownProps) => { + return { + projectId: ownProps.projectId, + } +} + +const mapDispatchToProps = dispatch => { + return { + onViewUsers: id => { + }, // TODO implement user viewing + onDelete: id => dispatch(deleteProject(id)), + } +} + +const ProjectActions = connect(mapStateToProps, mapDispatchToProps)( + ProjectActionButtons, +) + +export default ProjectActions diff --git a/frontend/src/containers/projects/VisibleProjectAuthList.js b/frontend/src/containers/projects/VisibleProjectAuthList.js new file mode 100644 index 00000000..b7ef6d24 --- /dev/null +++ b/frontend/src/containers/projects/VisibleProjectAuthList.js @@ -0,0 +1,42 @@ +import { connect } from 'react-redux' +import ProjectList from '../../components/projects/ProjectAuthList' + +const getVisibleProjectAuths = (projectAuths, filter) => { + switch (filter) { + case 'SHOW_ALL': + return projectAuths + case 'SHOW_OWN': + return projectAuths.filter( + projectAuth => projectAuth.authorizationLevel === 'OWN', + ) + case 'SHOW_SHARED': + return projectAuths.filter( + projectAuth => projectAuth.authorizationLevel !== 'OWN', + ) + default: + return projectAuths + } +} + +const mapStateToProps = state => { + const denormalizedAuthorizations = state.projectList.authorizationsOfCurrentUser.map( + authorizationIds => { + const authorization = state.objects.authorization[authorizationIds] + authorization.user = state.objects.user[authorization.userId] + authorization.project = + state.objects.project[authorization.projectId] + return authorization + }, + ) + + return { + authorizations: getVisibleProjectAuths( + denormalizedAuthorizations, + state.projectList.authVisibilityFilter, + ), + } +} + +const VisibleProjectAuthList = connect(mapStateToProps)(ProjectList) + +export default VisibleProjectAuthList diff --git a/frontend/src/containers/simulations/NewSimulationButtonContainer.js b/frontend/src/containers/simulations/NewSimulationButtonContainer.js deleted file mode 100644 index 2d7c7385..00000000 --- a/frontend/src/containers/simulations/NewSimulationButtonContainer.js +++ /dev/null @@ -1,15 +0,0 @@ -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/frontend/src/containers/simulations/SimulationActions.js b/frontend/src/containers/simulations/SimulationActions.js deleted file mode 100644 index 6c662912..00000000 --- a/frontend/src/containers/simulations/SimulationActions.js +++ /dev/null @@ -1,23 +0,0 @@ -import { connect } from 'react-redux' -import { deleteSimulation } from '../../actions/simulations' -import SimulationActionButtons from '../../components/simulations/SimulationActionButtons' - -const mapStateToProps = (state, ownProps) => { - return { - simulationId: ownProps.simulationId, - } -} - -const mapDispatchToProps = dispatch => { - return { - onViewUsers: id => { - }, // TODO implement user viewing - onDelete: id => dispatch(deleteSimulation(id)), - } -} - -const SimulationActions = connect(mapStateToProps, mapDispatchToProps)( - SimulationActionButtons, -) - -export default SimulationActions diff --git a/frontend/src/containers/simulations/VisibleSimulationAuthList.js b/frontend/src/containers/simulations/VisibleSimulationAuthList.js deleted file mode 100644 index f2b30542..00000000 --- a/frontend/src/containers/simulations/VisibleSimulationAuthList.js +++ /dev/null @@ -1,42 +0,0 @@ -import { connect } from 'react-redux' -import SimulationList from '../../components/simulations/SimulationAuthList' - -const getVisibleSimulationAuths = (simulationAuths, filter) => { - switch (filter) { - case 'SHOW_ALL': - return simulationAuths - case 'SHOW_OWN': - return simulationAuths.filter( - simulationAuth => simulationAuth.authorizationLevel === 'OWN', - ) - case 'SHOW_SHARED': - return simulationAuths.filter( - simulationAuth => simulationAuth.authorizationLevel !== 'OWN', - ) - default: - return simulationAuths - } -} - -const mapStateToProps = state => { - 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, - ), - } -} - -const VisibleSimulationAuthList = connect(mapStateToProps)(SimulationList) - -export default VisibleSimulationAuthList diff --git a/frontend/src/pages/App.js b/frontend/src/pages/App.js index 89d1fa32..5075cec0 100644 --- a/frontend/src/pages/App.js +++ b/frontend/src/pages/App.js @@ -4,16 +4,14 @@ import DocumentTitle from 'react-document-title' import { connect } from 'react-redux' import { ShortcutManager } from 'react-shortcuts' import { openExperimentSucceeded } from '../actions/experiments' -import { openSimulationSucceeded } from '../actions/simulations' +import { openProjectSucceeded } from '../actions/projects' import { resetCurrentTopology } from '../actions/topology/building' import ToolPanelComponent from '../components/app/map/controls/ToolPanelComponent' import LoadingScreen from '../components/app/map/LoadingScreen' -import SimulationSidebarComponent from '../components/app/sidebars/simulation/SimulationSidebarComponent' import AppNavbar from '../components/navigation/AppNavbar' import ScaleIndicatorContainer from '../containers/app/map/controls/ScaleIndicatorContainer' import MapStage from '../containers/app/map/MapStage' import TopologySidebar from '../containers/app/sidebars/topology/TopologySidebar' -import TimelineContainer from '../containers/app/timeline/TimelineContainer' import DeleteMachineModal from '../containers/modals/DeleteMachineModal' import DeleteRackModal from '../containers/modals/DeleteRackModal' import DeleteRoomModal from '../containers/modals/DeleteRoomModal' @@ -27,10 +25,9 @@ const shortcutManager = new ShortcutManager(KeymapConfiguration) class AppComponent extends React.Component { static propTypes = { - simulationId: PropTypes.string.isRequired, - inSimulation: PropTypes.bool, + projectId: PropTypes.string.isRequired, experimentId: PropTypes.number, - simulationName: PropTypes.string, + projectName: PropTypes.string, onViewTopologies: PropTypes.func, } static childContextTypes = { @@ -38,12 +35,7 @@ class AppComponent extends React.Component { } componentDidMount() { - // TODO this.props.resetCurrentTopology() - if (this.props.inSimulation) { - this.props.openExperimentSucceeded(this.props.simulationId, this.props.experimentId) - return - } - this.props.openSimulationSucceeded(this.props.simulationId) + this.props.openProjectSucceeded(this.props.projectId) } getChildContext() { @@ -55,35 +47,33 @@ class AppComponent extends React.Component { render() { return ( <DocumentTitle - title={this.props.simulationName ? this.props.simulationName + ' - OpenDC' : 'Simulation - OpenDC'} + title={this.props.projectName ? this.props.projectName + ' - OpenDC' : 'Simulation - OpenDC'} > <div className="page-container full-height"> <AppNavbar - simulationId={this.props.simulationId} - inSimulation={true} + projectId={this.props.projectId} + inProject={true} fullWidth={true} onViewTopologies={this.props.onViewTopologies} /> {this.props.topologyIsLoading ? ( <div className="full-height d-flex align-items-center justify-content-center"> - <LoadingScreen /> + <LoadingScreen/> </div> ) : ( <div className="full-height"> - <MapStage /> - <ScaleIndicatorContainer /> - <ToolPanelComponent /> - <TopologySidebar /> - {this.props.inSimulation ? <TimelineContainer /> : undefined} - {this.props.inSimulation ? <SimulationSidebarComponent /> : undefined} + <MapStage/> + <ScaleIndicatorContainer/> + <ToolPanelComponent/> + <TopologySidebar/> </div> )} - <ChangeTopologyModal /> - <EditRoomNameModal /> - <DeleteRoomModal /> - <EditRackNameModal /> - <DeleteRackModal /> - <DeleteMachineModal /> + <ChangeTopologyModal/> + <EditRoomNameModal/> + <DeleteRoomModal/> + <EditRackNameModal/> + <DeleteRackModal/> + <DeleteMachineModal/> </div> </DocumentTitle> ) @@ -91,24 +81,24 @@ class AppComponent extends React.Component { } const mapStateToProps = (state) => { - let simulationName = undefined - if (state.currentSimulationId !== '-1' && state.objects.simulation[state.currentSimulationId]) { - simulationName = state.objects.simulation[state.currentSimulationId].name + let projectName = undefined + if (state.currentProjectId !== '-1' && state.objects.project[state.currentProjectId]) { + projectName = state.objects.project[state.currentProjectId].name } return { topologyIsLoading: state.currentTopologyId === '-1', - simulationName, + projectName, } } const mapDispatchToProps = (dispatch) => { return { resetCurrentTopology: () => dispatch(resetCurrentTopology()), - openSimulationSucceeded: (id) => dispatch(openSimulationSucceeded(id)), + openProjectSucceeded: (id) => dispatch(openProjectSucceeded(id)), onViewTopologies: () => dispatch(openChangeTopologyModal()), - openExperimentSucceeded: (simulationId, experimentId) => - dispatch(openExperimentSucceeded(simulationId, experimentId)), + openExperimentSucceeded: (projectId, experimentId) => + dispatch(openExperimentSucceeded(projectId, experimentId)), } } diff --git a/frontend/src/pages/Experiments.js b/frontend/src/pages/Experiments.js index 43bd15be..66362299 100644 --- a/frontend/src/pages/Experiments.js +++ b/frontend/src/pages/Experiments.js @@ -2,8 +2,8 @@ import PropTypes from 'prop-types' import React from 'react' import DocumentTitle from 'react-document-title' import { connect } from 'react-redux' -import { fetchExperimentsOfSimulation } from '../actions/experiments' -import { openSimulationSucceeded } from '../actions/simulations' +import { fetchExperimentsOfProject } from '../actions/experiments' +import { openProjectSucceeded } from '../actions/projects' import AppNavbar from '../components/navigation/AppNavbar' import ExperimentListContainer from '../containers/experiments/ExperimentListContainer' import NewExperimentButtonContainer from '../containers/experiments/NewExperimentButtonContainer' @@ -11,31 +11,31 @@ import NewExperimentModal from '../containers/modals/NewExperimentModal' class ExperimentsComponent extends React.Component { static propTypes = { - simulationId: PropTypes.string.isRequired, - simulationName: PropTypes.string, + projectId: PropTypes.string.isRequired, + projectName: PropTypes.string, } componentDidMount() { - this.props.storeSimulationId(this.props.simulationId) - this.props.fetchExperimentsOfSimulation(this.props.simulationId) + this.props.storeProjectId(this.props.projectId) + this.props.fetchExperimentsOfProject(this.props.projectId) } render() { return ( <DocumentTitle title={ - this.props.simulationName - ? 'Experiments - ' + this.props.simulationName + ' - OpenDC' + this.props.projectName + ? 'Experiments - ' + this.props.projectName + ' - OpenDC' : 'Experiments - OpenDC' } > <div className="full-height"> - <AppNavbar simulationId={this.props.simulationId} inSimulation={true} fullWidth={true} /> + <AppNavbar projectId={this.props.projectId} inProject={true} fullWidth={true}/> <div className="container text-page-container full-height"> - <ExperimentListContainer /> - <NewExperimentButtonContainer /> + <ExperimentListContainer/> + <NewExperimentButtonContainer/> </div> - <NewExperimentModal /> + <NewExperimentModal/> </div> </DocumentTitle> ) @@ -43,20 +43,20 @@ class ExperimentsComponent extends React.Component { } const mapStateToProps = (state) => { - let simulationName = undefined - if (state.currentSimulationId !== '-1' && state.objects.simulation[state.currentSimulationId]) { - simulationName = state.objects.simulation[state.currentSimulationId].name + let projectName = undefined + if (state.currentProjectId !== '-1' && state.objects.project[state.currentProjectId]) { + projectName = state.objects.project[state.currentProjectId].name } return { - simulationName, + projectName, } } const mapDispatchToProps = (dispatch) => { return { - storeSimulationId: (id) => dispatch(openSimulationSucceeded(id)), - fetchExperimentsOfSimulation: (id) => dispatch(fetchExperimentsOfSimulation(id)), + storeProjectId: (id) => dispatch(openProjectSucceeded(id)), + fetchExperimentsOfProject: (id) => dispatch(fetchExperimentsOfProject(id)), } } diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js index 1bdfc5c7..e69c2049 100644 --- a/frontend/src/pages/Home.js +++ b/frontend/src/pages/Home.js @@ -21,7 +21,7 @@ class Home extends React.Component { const scrollOffset = 60 jQuery('#navbar') .find('li a') - .click(function (e) { + .click(function(e) { if (jQuery(e.target).parents('.auth-links').length > 0) { return } @@ -42,17 +42,17 @@ class Home extends React.Component { render() { return ( <div> - <HomeNavbar /> + <HomeNavbar/> <div className="body-wrapper page-container"> - <JumbotronHeader /> - <IntroSection /> - <StakeholderSection /> - <ModelingSection /> - <SimulationSection /> - <TechnologiesSection /> - <TeamSection /> - <ContactSection /> - <DocumentTitle title="OpenDC" /> + <JumbotronHeader/> + <IntroSection/> + <StakeholderSection/> + <ModelingSection/> + <SimulationSection/> + <TechnologiesSection/> + <TeamSection/> + <ContactSection/> + <DocumentTitle title="OpenDC"/> </div> </div> ) diff --git a/frontend/src/pages/NotFound.js b/frontend/src/pages/NotFound.js index f72c7d01..959cceec 100644 --- a/frontend/src/pages/NotFound.js +++ b/frontend/src/pages/NotFound.js @@ -6,7 +6,7 @@ import './NotFound.css' const NotFound = () => ( <DocumentTitle title="Page Not Found - OpenDC"> <div className="not-found-backdrop"> - <TerminalWindow /> + <TerminalWindow/> </div> </DocumentTitle> ) diff --git a/frontend/src/pages/Profile.js b/frontend/src/pages/Profile.js index 45b48247..00bf903e 100644 --- a/frontend/src/pages/Profile.js +++ b/frontend/src/pages/Profile.js @@ -8,18 +8,18 @@ import DeleteProfileModal from '../containers/modals/DeleteProfileModal' const ProfileContainer = ({ onDelete }) => ( <DocumentTitle title="My Profile - OpenDC"> <div className="full-height"> - <AppNavbar inSimulation={false} fullWidth={false} /> + <AppNavbar inProject={false} fullWidth={false}/> <div className="container text-page-container full-height"> <button className="btn btn-danger mb-2 ml-auto mr-auto" style={{ maxWidth: 300 }} onClick={onDelete}> Delete my account on OpenDC </button> <p className="text-muted text-center"> This does not delete your Google account, but simply disconnects it from the OpenDC platform and - deletes any simulation info that is associated with you (simulations you own and any authorizations + deletes any project info that is associated with you (projects you own and any authorizations you may have on other projects). </p> </div> - <DeleteProfileModal /> + <DeleteProfileModal/> </div> </DocumentTitle> ) diff --git a/frontend/src/pages/Projects.js b/frontend/src/pages/Projects.js new file mode 100644 index 00000000..450ff695 --- /dev/null +++ b/frontend/src/pages/Projects.js @@ -0,0 +1,43 @@ +import React from 'react' +import DocumentTitle from 'react-document-title' +import { connect } from 'react-redux' +import { openNewProjectModal } from '../actions/modals/projects' +import { fetchAuthorizationsOfCurrentUser } from '../actions/users' +import AppNavbar from '../components/navigation/AppNavbar' +import ProjectFilterPanel from '../components/projects/FilterPanel' +import NewProjectModal from '../containers/modals/NewProjectModal' +import NewProjectButtonContainer from '../containers/projects/NewProjectButtonContainer' +import VisibleProjectList from '../containers/projects/VisibleProjectAuthList' + +class ProjectsContainer extends React.Component { + componentDidMount() { + this.props.fetchAuthorizationsOfCurrentUser() + } + + render() { + return ( + <DocumentTitle title="My Projects - OpenDC"> + <div className="full-height"> + <AppNavbar inProject={false} fullWidth={false}/> + <div className="container text-page-container full-height"> + <ProjectFilterPanel/> + <VisibleProjectList/> + <NewProjectButtonContainer/> + </div> + <NewProjectModal/> + </div> + </DocumentTitle> + ) + } +} + +const mapDispatchToProps = (dispatch) => { + return { + fetchAuthorizationsOfCurrentUser: () => dispatch(fetchAuthorizationsOfCurrentUser()), + openNewProjectModal: () => dispatch(openNewProjectModal()), + } +} + +const Projects = connect(undefined, mapDispatchToProps)(ProjectsContainer) + +export default Projects diff --git a/frontend/src/pages/Simulations.js b/frontend/src/pages/Simulations.js deleted file mode 100644 index ce2386fd..00000000 --- a/frontend/src/pages/Simulations.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react' -import DocumentTitle from 'react-document-title' -import { connect } from 'react-redux' -import { openNewSimulationModal } from '../actions/modals/simulations' -import { fetchAuthorizationsOfCurrentUser } from '../actions/users' -import AppNavbar from '../components/navigation/AppNavbar' -import SimulationFilterPanel from '../components/simulations/FilterPanel' -import NewSimulationModal from '../containers/modals/NewSimulationModal' -import NewSimulationButtonContainer from '../containers/simulations/NewSimulationButtonContainer' -import VisibleSimulationList from '../containers/simulations/VisibleSimulationAuthList' - -class SimulationsContainer extends React.Component { - componentDidMount() { - this.props.fetchAuthorizationsOfCurrentUser() - } - - render() { - return ( - <DocumentTitle title="My Simulations - OpenDC"> - <div className="full-height"> - <AppNavbar inSimulation={false} fullWidth={false} /> - <div className="container text-page-container full-height"> - <SimulationFilterPanel /> - <VisibleSimulationList /> - <NewSimulationButtonContainer /> - </div> - <NewSimulationModal /> - </div> - </DocumentTitle> - ) - } -} - -const mapDispatchToProps = (dispatch) => { - return { - fetchAuthorizationsOfCurrentUser: () => dispatch(fetchAuthorizationsOfCurrentUser()), - openNewSimulationModal: () => dispatch(openNewSimulationModal()), - } -} - -const Simulations = connect(undefined, mapDispatchToProps)(SimulationsContainer) - -export default Simulations diff --git a/frontend/src/reducers/construction-mode.js b/frontend/src/reducers/construction-mode.js index fb33da72..b15ac834 100644 --- a/frontend/src/reducers/construction-mode.js +++ b/frontend/src/reducers/construction-mode.js @@ -4,7 +4,8 @@ import { GO_DOWN_ONE_INTERACTION_LEVEL } from '../actions/interaction-level' import { CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED, FINISH_NEW_ROOM_CONSTRUCTION, - FINISH_ROOM_EDIT, SET_CURRENT_TOPOLOGY, + FINISH_ROOM_EDIT, + SET_CURRENT_TOPOLOGY, START_NEW_ROOM_CONSTRUCTION_SUCCEEDED, START_ROOM_EDIT, } from '../actions/topology/building' diff --git a/frontend/src/reducers/current-ids.js b/frontend/src/reducers/current-ids.js index b80d2ecf..0726da6d 100644 --- a/frontend/src/reducers/current-ids.js +++ b/frontend/src/reducers/current-ids.js @@ -1,5 +1,5 @@ import { OPEN_EXPERIMENT_SUCCEEDED } from '../actions/experiments' -import { OPEN_SIMULATION_SUCCEEDED } from '../actions/simulations' +import { OPEN_PROJECT_SUCCEEDED } from '../actions/projects' import { RESET_CURRENT_TOPOLOGY, SET_CURRENT_TOPOLOGY } from '../actions/topology/building' export function currentTopologyId(state = '-1', action) { @@ -13,12 +13,12 @@ export function currentTopologyId(state = '-1', action) { } } -export function currentSimulationId(state = '-1', action) { +export function currentProjectId(state = '-1', action) { switch (action.type) { - case OPEN_SIMULATION_SUCCEEDED: + case OPEN_PROJECT_SUCCEEDED: return action.id case OPEN_EXPERIMENT_SUCCEEDED: - return action.simulationId + return action.projectId default: return state } diff --git a/frontend/src/reducers/index.js b/frontend/src/reducers/index.js index 1c3ee145..6ca95ec6 100644 --- a/frontend/src/reducers/index.js +++ b/frontend/src/reducers/index.js @@ -1,29 +1,21 @@ import { combineReducers } from 'redux' import { auth } from './auth' import { construction } from './construction-mode' -import { currentTopologyId, currentSimulationId } from './current-ids' +import { currentProjectId, currentTopologyId } from './current-ids' import { interactionLevel } from './interaction-level' import { map } from './map' import { modals } from './modals' import { objects } from './objects' -import { simulationList } from './simulation-list' -import { currentExperimentId, currentTick, isPlaying, lastSimulatedTick, loadMetric } from './simulation-mode' -import { states } from './states' +import { projectList } from './project-list' const rootReducer = combineReducers({ objects, - states, modals, - simulationList, + projectList: projectList, construction, map, - currentSimulationId, + currentProjectId, currentTopologyId, - currentExperimentId, - currentTick, - lastSimulatedTick, - loadMetric, - isPlaying, interactionLevel, auth, }) diff --git a/frontend/src/reducers/interaction-level.js b/frontend/src/reducers/interaction-level.js index 88c3b30e..21aba715 100644 --- a/frontend/src/reducers/interaction-level.js +++ b/frontend/src/reducers/interaction-level.js @@ -5,13 +5,13 @@ import { GO_FROM_RACK_TO_MACHINE, GO_FROM_ROOM_TO_RACK, } from '../actions/interaction-level' -import { OPEN_SIMULATION_SUCCEEDED } from '../actions/simulations' +import { OPEN_PROJECT_SUCCEEDED } from '../actions/projects' import { SET_CURRENT_TOPOLOGY } from '../actions/topology/building' export function interactionLevel(state = { mode: 'BUILDING' }, action) { switch (action.type) { case OPEN_EXPERIMENT_SUCCEEDED: - case OPEN_SIMULATION_SUCCEEDED: + case OPEN_PROJECT_SUCCEEDED: case SET_CURRENT_TOPOLOGY: return { mode: 'BUILDING', diff --git a/frontend/src/reducers/modals.js b/frontend/src/reducers/modals.js index 81a0660e..a042aaea 100644 --- a/frontend/src/reducers/modals.js +++ b/frontend/src/reducers/modals.js @@ -2,7 +2,7 @@ import { combineReducers } from 'redux' import { OPEN_EXPERIMENT_SUCCEEDED } from '../actions/experiments' 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 { CLOSE_NEW_PROJECT_MODAL, OPEN_NEW_PROJECT_MODAL } from '../actions/modals/projects' import { CLOSE_CHANGE_TOPOLOGY_MODAL, CLOSE_DELETE_MACHINE_MODAL, @@ -19,7 +19,7 @@ import { } from '../actions/modals/topology' function modal(openAction, closeAction) { - return function (state = false, action) { + return function(state = false, action) { switch (action.type) { case openAction: return true @@ -33,7 +33,7 @@ function modal(openAction, closeAction) { } export const modals = combineReducers({ - newSimulationModalVisible: modal(OPEN_NEW_SIMULATION_MODAL, CLOSE_NEW_SIMULATION_MODAL), + newProjectModalVisible: modal(OPEN_NEW_PROJECT_MODAL, CLOSE_NEW_PROJECT_MODAL), deleteProfileModalVisible: modal(OPEN_DELETE_PROFILE_MODAL, CLOSE_DELETE_PROFILE_MODAL), changeTopologyModalVisible: modal(OPEN_CHANGE_TOPOLOGY_MODAL, CLOSE_CHANGE_TOPOLOGY_MODAL), editRoomNameModalVisible: modal(OPEN_EDIT_ROOM_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL), diff --git a/frontend/src/reducers/objects.js b/frontend/src/reducers/objects.js index f52ca369..d25eb136 100644 --- a/frontend/src/reducers/objects.js +++ b/frontend/src/reducers/objects.js @@ -8,9 +8,9 @@ import { import { CPU_UNITS, GPU_UNITS, MEMORY_UNITS, STORAGE_UNITS } from '../util/unit-specifications' export const objects = combineReducers({ - simulation: object('simulation'), + project: object('project'), user: object('user'), - authorization: objectWithId('authorization', (object) => [object.userId, object.simulationId]), + authorization: objectWithId('authorization', (object) => [object.userId, object.projectId]), cpu: object('cpu', CPU_UNITS), gpu: object('gpu', GPU_UNITS), memory: object('memory', MEMORY_UNITS), diff --git a/frontend/src/reducers/simulation-list.js b/frontend/src/reducers/project-list.js index 383f4b35..1f1aa8d0 100644 --- a/frontend/src/reducers/simulation-list.js +++ b/frontend/src/reducers/project-list.js @@ -1,18 +1,14 @@ import { combineReducers } from 'redux' -import { - ADD_SIMULATION_SUCCEEDED, - DELETE_SIMULATION_SUCCEEDED, - SET_AUTH_VISIBILITY_FILTER, -} from '../actions/simulations' +import { ADD_PROJECT_SUCCEEDED, DELETE_PROJECT_SUCCEEDED, SET_AUTH_VISIBILITY_FILTER } from '../actions/projects' import { FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED } from '../actions/users' export function authorizationsOfCurrentUser(state = [], action) { switch (action.type) { case FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED: return action.authorizationsOfCurrentUser - case ADD_SIMULATION_SUCCEEDED: + case ADD_PROJECT_SUCCEEDED: return [...state, action.authorization] - case DELETE_SIMULATION_SUCCEEDED: + case DELETE_PROJECT_SUCCEEDED: return state.filter((authorization) => authorization[1] !== action.id) default: return state @@ -28,7 +24,7 @@ export function authVisibilityFilter(state = 'SHOW_ALL', action) { } } -export const simulationList = combineReducers({ +export const projectList = combineReducers({ authorizationsOfCurrentUser, authVisibilityFilter, }) diff --git a/frontend/src/reducers/simulation-mode.js b/frontend/src/reducers/simulation-mode.js deleted file mode 100644 index 5f938ec8..00000000 --- a/frontend/src/reducers/simulation-mode.js +++ /dev/null @@ -1,58 +0,0 @@ -import { OPEN_EXPERIMENT_SUCCEEDED } from '../actions/experiments' -import { CHANGE_LOAD_METRIC } from '../actions/simulation/load-metric' -import { SET_PLAYING } from '../actions/simulation/playback' -import { GO_TO_TICK, SET_LAST_SIMULATED_TICK } from '../actions/simulation/tick' -import { OPEN_SIMULATION_SUCCEEDED } from '../actions/simulations' - -export function currentExperimentId(state = '-1', action) { - switch (action.type) { - case OPEN_EXPERIMENT_SUCCEEDED: - return action.experimentId - case OPEN_SIMULATION_SUCCEEDED: - return '-1' - default: - return state - } -} - -export function currentTick(state = 0, action) { - switch (action.type) { - case GO_TO_TICK: - return action.tick - case OPEN_EXPERIMENT_SUCCEEDED: - return 0 - default: - return state - } -} - -export function loadMetric(state = 'LOAD', action) { - switch (action.type) { - case CHANGE_LOAD_METRIC: - return action.metric - default: - return state - } -} - -export function isPlaying(state = false, action) { - switch (action.type) { - case SET_PLAYING: - return action.playing - case OPEN_EXPERIMENT_SUCCEEDED: - return false - default: - return state - } -} - -export function lastSimulatedTick(state = -1, action) { - switch (action.type) { - case SET_LAST_SIMULATED_TICK: - return action.tick - case OPEN_EXPERIMENT_SUCCEEDED: - return -1 - default: - return state - } -} diff --git a/frontend/src/reducers/states.js b/frontend/src/reducers/states.js deleted file mode 100644 index c9bb4158..00000000 --- a/frontend/src/reducers/states.js +++ /dev/null @@ -1,32 +0,0 @@ -import { combineReducers } from 'redux' -import { ADD_BATCH_TO_STATES } from '../actions/states' - -export const states = combineReducers({ - room: objectStates('room'), - rack: objectStates('rack'), - machine: objectStates('machine'), -}) - -function objectStates(type) { - return (state = {}, action) => { - if (action.objectType !== type) { - return state - } - - if (action.type === ADD_BATCH_TO_STATES) { - const batch = {} - for (let i in action.objects) { - batch[action.objects[i].tick] = Object.assign( - {}, - state[action.objects[i].tick], - batch[action.objects[i].tick], - { [action.objects[i][action.objectType + 'Id']]: action.objects[i] } - ) - } - - return Object.assign({}, state, batch) - } - - return state - } -} diff --git a/frontend/src/routes/index.js b/frontend/src/routes/index.js index ea703567..d3f50be5 100644 --- a/frontend/src/routes/index.js +++ b/frontend/src/routes/index.js @@ -2,36 +2,23 @@ import React from 'react' import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom' import { userIsLoggedIn } from '../auth/index' import App from '../pages/App' -import Experiments from '../pages/Experiments' import Home from '../pages/Home' import NotFound from '../pages/NotFound' import Profile from '../pages/Profile' -import Simulations from '../pages/Simulations' +import Projects from '../pages/Projects' -const ProtectedComponent = (component) => () => (userIsLoggedIn() ? component : <Redirect to="/" />) +const ProtectedComponent = (component) => () => (userIsLoggedIn() ? component : <Redirect to="/"/>) const AppComponent = ({ match }) => - userIsLoggedIn() ? <App simulationId={match.params.simulationId} /> : <Redirect to="/" /> - -const ExperimentsComponent = ({ match }) => - userIsLoggedIn() ? <Experiments simulationId={match.params.simulationId} /> : <Redirect to="/" /> - -const SimulationComponent = ({ match }) => - userIsLoggedIn() ? ( - <App simulationId={match.params.simulationId} inSimulation={true} experimentId={match.params.experimentId} /> - ) : ( - <Redirect to="/" /> - ) + userIsLoggedIn() ? <App projectId={match.params.projectId}/> : <Redirect to="/"/> const Routes = () => ( <BrowserRouter> <Switch> - <Route exact path="/" component={Home} /> - <Route exact path="/simulations" render={ProtectedComponent(<Simulations />)} /> - <Route exact path="/simulations/:simulationId" component={AppComponent} /> - <Route exact path="/simulations/:simulationId/experiments" component={ExperimentsComponent} /> - <Route exact path="/simulations/:simulationId/experiments/:experimentId" component={SimulationComponent} /> - <Route exact path="/profile" render={ProtectedComponent(<Profile />)} /> - <Route path="/*" component={NotFound} /> + <Route exact path="/" component={Home}/> + <Route exact path="/projects" render={ProtectedComponent(<Projects/>)}/> + <Route exact path="/projects/:projectId" component={AppComponent}/> + <Route exact path="/profile" render={ProtectedComponent(<Profile/>)}/> + <Route path="/*" component={NotFound}/> </Switch> </BrowserRouter> ) diff --git a/frontend/src/sagas/experiments.js b/frontend/src/sagas/experiments.js index e5aeeb46..f2b23017 100644 --- a/frontend/src/sagas/experiments.js +++ b/frontend/src/sagas/experiments.js @@ -1,22 +1,14 @@ -import { call, delay, put, select } from 'redux-saga/effects' +import { call, put, select } from 'redux-saga/effects' import { addPropToStoreObject, addToStore } from '../actions/objects' -import { setLastSimulatedTick } from '../actions/simulation/tick' -import { addBatchToStates } from '../actions/states' -import { - deleteExperiment, - getAllMachineStates, - getAllRackStates, - getAllRoomStates, - getExperiment, -} from '../api/routes/experiments' -import { addExperiment, getSimulation } from '../api/routes/simulations' +import { deleteExperiment, getExperiment } from '../api/routes/experiments' +import { addExperiment, getProject } from '../api/routes/projects' import { fetchAndStoreAllSchedulers, fetchAndStoreAllTraces } from './objects' -import { fetchAndStoreAllTopologiesOfSimulation, fetchTopologyOfExperiment } from './topology' +import { fetchAndStoreAllTopologiesOfProject, fetchTopologyOfExperiment } from './topology' export function* onOpenExperimentSucceeded(action) { try { - const simulation = yield call(getSimulation, action.simulationId) - yield put(addToStore('simulation', simulation)) + const project = yield call(getProject, action.projectId) + yield put(addToStore('project', project)) const experiment = yield call(getExperiment, action.experimentId) yield put(addToStore('experiment', experiment)) @@ -24,46 +16,20 @@ export function* onOpenExperimentSucceeded(action) { yield fetchExperimentSpecifications() yield fetchTopologyOfExperiment(experiment) - yield startStateFetchLoop(action.experimentId) } catch (error) { console.error(error) } } -function* startStateFetchLoop(experimentId) { +export function* onFetchExperimentsOfProject() { try { - while ((yield select((state) => state.currentExperimentId)) !== '-1') { - const lastSimulatedTick = (yield call(getExperiment, experimentId)).lastSimulatedTick - if (lastSimulatedTick !== (yield select((state) => state.lastSimulatedTick))) { - yield put(setLastSimulatedTick(lastSimulatedTick)) - - const machineStates = yield call(getAllMachineStates, experimentId) - const rackStates = yield call(getAllRackStates, experimentId) - const roomStates = yield call(getAllRoomStates, experimentId) - - yield put(addBatchToStates('machine', machineStates)) - yield put(addBatchToStates('rack', rackStates)) - yield put(addBatchToStates('room', roomStates)) - - yield delay(5000) - } else { - yield delay(10000) - } - } - } catch (error) { - console.error(error) - } -} - -export function* onFetchExperimentsOfSimulation() { - try { - const currentSimulationId = yield select((state) => state.currentSimulationId) - const currentSimulation = yield select((state) => state.object.simulation[currentSimulationId]) + const currentProjectId = yield select((state) => state.currentProjectId) + const currentProject = yield select((state) => state.object.project[currentProjectId]) yield fetchExperimentSpecifications() - for (let i in currentSimulation.experimentIds) { - const experiment = yield call(getExperiment, currentSimulation.experimentIds[i]) + for (let i in currentProject.experimentIds) { + const experiment = yield call(getExperiment, currentProject.experimentIds[i]) yield put(addToStore('experiment', experiment)) } } catch (error) { @@ -73,8 +39,8 @@ export function* onFetchExperimentsOfSimulation() { function* fetchExperimentSpecifications() { try { - const currentSimulationId = yield select((state) => state.currentSimulationId) - yield fetchAndStoreAllTopologiesOfSimulation(currentSimulationId) + const currentProjectId = yield select((state) => state.currentProjectId) + yield fetchAndStoreAllTopologiesOfProject(currentProjectId) yield fetchAndStoreAllTraces() yield fetchAndStoreAllSchedulers() } catch (error) { @@ -84,23 +50,23 @@ function* fetchExperimentSpecifications() { export function* onAddExperiment(action) { try { - const currentSimulationId = yield select((state) => state.currentSimulationId) + const currentProjectId = yield select((state) => state.currentProjectId) const experiment = yield call( addExperiment, - currentSimulationId, + currentProjectId, Object.assign({}, action.experiment, { id: '-1', - simulationId: currentSimulationId, - }) + projectId: currentProjectId, + }), ) yield put(addToStore('experiment', experiment)) - const experimentIds = yield select((state) => state.objects.simulation[currentSimulationId].experimentIds) + const experimentIds = yield select((state) => state.objects.project[currentProjectId].experimentIds) yield put( - addPropToStoreObject('simulation', currentSimulationId, { + addPropToStoreObject('project', currentProjectId, { experimentIds: experimentIds.concat([experiment._id]), - }) + }), ) } catch (error) { console.error(error) @@ -111,13 +77,13 @@ 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].experimentIds) + const currentProjectId = yield select((state) => state.currentProjectId) + const experimentIds = yield select((state) => state.objects.project[currentProjectId].experimentIds) yield put( - addPropToStoreObject('simulation', currentSimulationId, { + addPropToStoreObject('project', currentProjectId, { experimentIds: experimentIds.filter((id) => id !== action.id), - }) + }), ) } catch (error) { console.error(error) diff --git a/frontend/src/sagas/index.js b/frontend/src/sagas/index.js index 0947befc..26d19d58 100644 --- a/frontend/src/sagas/index.js +++ b/frontend/src/sagas/index.js @@ -3,10 +3,10 @@ import { LOG_IN } from '../actions/auth' import { ADD_EXPERIMENT, DELETE_EXPERIMENT, - FETCH_EXPERIMENTS_OF_SIMULATION, + FETCH_EXPERIMENTS_OF_PROJECT, OPEN_EXPERIMENT_SUCCEEDED, } from '../actions/experiments' -import { ADD_SIMULATION, DELETE_SIMULATION, OPEN_SIMULATION_SUCCEEDED } from '../actions/simulations' +import { ADD_PROJECT, DELETE_PROJECT, OPEN_PROJECT_SUCCEEDED } from '../actions/projects' import { ADD_TILE, CANCEL_NEW_ROOM_CONSTRUCTION, @@ -20,11 +20,11 @@ import { DELETE_CURRENT_USER, FETCH_AUTHORIZATIONS_OF_CURRENT_USER } from '../ac import { onAddExperiment, onDeleteExperiment, - onFetchExperimentsOfSimulation, + onFetchExperimentsOfProject, onOpenExperimentSucceeded, } from './experiments' import { onDeleteCurrentUser } from './profile' -import { onOpenSimulationSucceeded, onSimulationAdd, onSimulationDelete } from './simulations' +import { onOpenProjectSucceeded, onProjectAdd, onProjectDelete } from './projects' import { onAddMachine, onAddRackToTile, @@ -49,12 +49,12 @@ 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(ADD_PROJECT, onProjectAdd) + yield takeEvery(DELETE_PROJECT, onProjectDelete) yield takeEvery(DELETE_CURRENT_USER, onDeleteCurrentUser) - yield takeEvery(OPEN_SIMULATION_SUCCEEDED, onOpenSimulationSucceeded) + yield takeEvery(OPEN_PROJECT_SUCCEEDED, onOpenProjectSucceeded) yield takeEvery(OPEN_EXPERIMENT_SUCCEEDED, onOpenExperimentSucceeded) yield takeEvery(ADD_TOPOLOGY, onAddTopology) @@ -73,7 +73,7 @@ export default function* rootSaga() { yield takeEvery(ADD_UNIT, onAddUnit) yield takeEvery(DELETE_UNIT, onDeleteUnit) - yield takeEvery(FETCH_EXPERIMENTS_OF_SIMULATION, onFetchExperimentsOfSimulation) + yield takeEvery(FETCH_EXPERIMENTS_OF_PROJECT, onFetchExperimentsOfProject) yield takeEvery(ADD_EXPERIMENT, onAddExperiment) yield takeEvery(DELETE_EXPERIMENT, onDeleteExperiment) } diff --git a/frontend/src/sagas/objects.js b/frontend/src/sagas/objects.js index 1a31c195..8a12bd13 100644 --- a/frontend/src/sagas/objects.js +++ b/frontend/src/sagas/objects.js @@ -1,14 +1,14 @@ import { call, put, select } from 'redux-saga/effects' import { addToStore } from '../actions/objects' import { getAllSchedulers } from '../api/routes/schedulers' -import { getSimulation } from '../api/routes/simulations' +import { getProject } from '../api/routes/projects' import { getAllTraces } from '../api/routes/traces' import { getUser } from '../api/routes/users' import { getTopology, updateTopology } from '../api/routes/topologies' import { uuid } from 'uuidv4' export const OBJECT_SELECTORS = { - simulation: (state) => state.objects.simulation, + project: (state) => state.objects.project, user: (state) => state.objects.user, authorization: (state) => state.objects.authorization, cpu: (state) => state.objects.cpu, @@ -40,7 +40,7 @@ function* fetchAndStoreObjects(objectType, apiCall) { return objects } -export const fetchAndStoreSimulation = (id) => fetchAndStoreObject('simulation', id, call(getSimulation, id)) +export const fetchAndStoreProject = (id) => fetchAndStoreObject('project', id, call(getProject, id)) export const fetchAndStoreUser = (id) => fetchAndStoreObject('user', id, call(getUser, id)) @@ -94,7 +94,7 @@ export const fetchAndStoreTopology = function* (id) { const filledSlots = new Array(fullRack.capacity).fill(null) fullRack.machines.forEach( - (machine) => (filledSlots[machine.position - 1] = machine._id) + (machine) => (filledSlots[machine.position - 1] = machine._id), ) let rack = (({ _id, name, capacity, powerCapacityW }) => ({ _id, @@ -163,21 +163,21 @@ export const updateTopologyOnServer = function* (id) { rack: !tileStore[tileId].rackId ? undefined : { - _id: rackStore[tileStore[tileId].rackId]._id, - name: rackStore[tileStore[tileId].rackId].name, - capacity: rackStore[tileStore[tileId].rackId].capacity, - powerCapacityW: rackStore[tileStore[tileId].rackId].powerCapacityW, - machines: rackStore[tileStore[tileId].rackId].machineIds - .filter((m) => m !== null) - .map((machineId) => ({ - _id: machineId, - position: machineStore[machineId].position, - cpus: machineStore[machineId].cpuIds.map((id) => cpuStore[id]), - gpus: machineStore[machineId].gpuIds.map((id) => gpuStore[id]), - memories: machineStore[machineId].memoryIds.map((id) => memoryStore[id]), - storages: machineStore[machineId].storageIds.map((id) => storageStore[id]), - })), - }, + _id: rackStore[tileStore[tileId].rackId]._id, + name: rackStore[tileStore[tileId].rackId].name, + capacity: rackStore[tileStore[tileId].rackId].capacity, + powerCapacityW: rackStore[tileStore[tileId].rackId].powerCapacityW, + machines: rackStore[tileStore[tileId].rackId].machineIds + .filter((m) => m !== null) + .map((machineId) => ({ + _id: machineId, + position: machineStore[machineId].position, + cpus: machineStore[machineId].cpuIds.map((id) => cpuStore[id]), + gpus: machineStore[machineId].gpuIds.map((id) => gpuStore[id]), + memories: machineStore[machineId].memoryIds.map((id) => memoryStore[id]), + storages: machineStore[machineId].storageIds.map((id) => storageStore[id]), + })), + }, })), })), } diff --git a/frontend/src/sagas/projects.js b/frontend/src/sagas/projects.js new file mode 100644 index 00000000..d1f5e7f7 --- /dev/null +++ b/frontend/src/sagas/projects.js @@ -0,0 +1,43 @@ +import { call, put } from 'redux-saga/effects' +import { addToStore } from '../actions/objects' +import { addProjectSucceeded, deleteProjectSucceeded } from '../actions/projects' +import { addProject, deleteProject, getProject } from '../api/routes/projects' +import { fetchAndStoreAllTopologiesOfProject } from './topology' + +export function* onOpenProjectSucceeded(action) { + try { + const project = yield call(getProject, action.id) + yield put(addToStore('project', project)) + + yield fetchAndStoreAllTopologiesOfProject(action.id) + } catch (error) { + console.error(error) + } +} + +export function* onProjectAdd(action) { + try { + const project = yield call(addProject, { name: action.name }) + yield put(addToStore('project', project)) + + const authorization = { + projectId: project._id, + userId: action.userId, + authorizationLevel: 'OWN', + project, + } + yield put(addToStore('authorization', authorization)) + yield put(addProjectSucceeded([authorization.userId, authorization.projectId])) + } catch (error) { + console.error(error) + } +} + +export function* onProjectDelete(action) { + try { + yield call(deleteProject, action.id) + yield put(deleteProjectSucceeded(action.id)) + } catch (error) { + console.error(error) + } +} diff --git a/frontend/src/sagas/simulations.js b/frontend/src/sagas/simulations.js deleted file mode 100644 index be69fedd..00000000 --- a/frontend/src/sagas/simulations.js +++ /dev/null @@ -1,43 +0,0 @@ -import { call, put } from 'redux-saga/effects' -import { addToStore } from '../actions/objects' -import { addSimulationSucceeded, deleteSimulationSucceeded } from '../actions/simulations' -import { addSimulation, deleteSimulation, getSimulation } from '../api/routes/simulations' -import { fetchAndStoreAllTopologiesOfSimulation } from './topology' - -export function* onOpenSimulationSucceeded(action) { - try { - const simulation = yield call(getSimulation, action.id) - yield put(addToStore('simulation', simulation)) - - yield fetchAndStoreAllTopologiesOfSimulation(action.id) - } catch (error) { - console.error(error) - } -} - -export function* onSimulationAdd(action) { - try { - const simulation = yield call(addSimulation, { name: action.name }) - yield put(addToStore('simulation', simulation)) - - const authorization = { - simulationId: simulation._id, - userId: action.userId, - authorizationLevel: 'OWN', - simulation, - } - yield put(addToStore('authorization', authorization)) - yield put(addSimulationSucceeded([authorization.userId, authorization.simulationId])) - } catch (error) { - console.error(error) - } -} - -export function* onSimulationDelete(action) { - try { - yield call(deleteSimulation, action.id) - yield put(deleteSimulationSucceeded(action.id)) - } catch (error) { - console.error(error) - } -} diff --git a/frontend/src/sagas/topology.js b/frontend/src/sagas/topology.js index 2e55156b..008c7b63 100644 --- a/frontend/src/sagas/topology.js +++ b/frontend/src/sagas/topology.js @@ -29,15 +29,15 @@ export function* fetchTopologyOfExperiment(experiment) { } } -export function* fetchAndStoreAllTopologiesOfSimulation(simulationId) { +export function* fetchAndStoreAllTopologiesOfProject(projectId) { try { - const simulation = yield select((state) => state.objects.simulation[simulationId]) + const project = yield select((state) => state.objects.project[projectId]) - for (let i in simulation.topologyIds) { - yield fetchAndStoreTopology(simulation.topologyIds[i]) + for (let i in project.topologyIds) { + yield fetchAndStoreTopology(project.topologyIds[i]) } - yield put(setCurrentTopology(simulation.topologyIds[0])) + yield put(setCurrentTopology(project.topologyIds[0])) } catch (error) { console.error(error) } @@ -45,21 +45,21 @@ export function* fetchAndStoreAllTopologiesOfSimulation(simulationId) { export function* onAddTopology(action) { try { - const currentSimulationId = yield select((state) => state.currentSimulationId) + const currentProjectId = yield select((state) => state.currentProjectId) const topology = yield call( addTopology, Object.assign({}, action.topology, { - simulationId: currentSimulationId, - }) + projectId: currentProjectId, + }), ) yield fetchAndStoreTopology(topology._id) - const topologyIds = yield select((state) => state.objects.simulation[currentSimulationId].topologyIds) + const topologyIds = yield select((state) => state.objects.project[currentProjectId].topologyIds) yield put( - addPropToStoreObject('simulation', currentSimulationId, { + addPropToStoreObject('project', currentProjectId, { topologyIds: topologyIds.concat([topology._id]), - }) + }), ) yield put(setCurrentTopology(topology._id)) } catch (error) { @@ -69,8 +69,8 @@ export function* onAddTopology(action) { export function* onDeleteTopology(action) { try { - const currentSimulationId = yield select((state) => state.currentSimulationId) - const topologyIds = yield select((state) => state.objects.simulation[currentSimulationId].topologyIds) + const currentProjectId = yield select((state) => state.currentProjectId) + const topologyIds = yield select((state) => state.objects.project[currentProjectId].topologyIds) const currentTopologyId = yield select((state) => state.currentTopologyId) if (currentTopologyId === action.id) { yield put(setCurrentTopology(topologyIds.filter((t) => t !== action.id)[0])) @@ -79,9 +79,9 @@ export function* onDeleteTopology(action) { yield call(deleteTopology, action.id) yield put( - addPropToStoreObject('simulation', currentSimulationId, { + addPropToStoreObject('project', currentProjectId, { topologyIds: topologyIds.filter((id) => id !== action.id), - }) + }), ) } catch (error) { console.error(error) @@ -265,7 +265,7 @@ export function* onAddUnit(action) { const position = yield select((state) => state.interactionLevel.position) const machine = yield select( (state) => - state.objects.machine[state.objects.rack[state.objects.tile[tileId].rackId].machineIds[position - 1]] + state.objects.machine[state.objects.rack[state.objects.tile[tileId].rackId].machineIds[position - 1]], ) if (machine[action.unitType + 'Ids'].length >= MAX_NUM_UNITS_PER_MACHINE) { @@ -276,7 +276,7 @@ export function* onAddUnit(action) { yield put( addPropToStoreObject('machine', machine._id, { [action.unitType + 'Ids']: units, - }) + }), ) yield updateTopologyOnServer(topologyId) } catch (error) { @@ -291,7 +291,7 @@ export function* onDeleteUnit(action) { const position = yield select((state) => state.interactionLevel.position) const machine = yield select( (state) => - state.objects.machine[state.objects.rack[state.objects.tile[tileId].rackId].machineIds[position - 1]] + state.objects.machine[state.objects.rack[state.objects.tile[tileId].rackId].machineIds[position - 1]], ) const unitIds = machine[action.unitType + 'Ids'].slice() unitIds.splice(action.index, 1) @@ -299,7 +299,7 @@ export function* onDeleteUnit(action) { yield put( addPropToStoreObject('machine', machine._id, { [action.unitType + 'Ids']: unitIds, - }) + }), ) yield updateTopologyOnServer(topologyId) } catch (error) { diff --git a/frontend/src/sagas/users.js b/frontend/src/sagas/users.js index a95893d2..74e652f6 100644 --- a/frontend/src/sagas/users.js +++ b/frontend/src/sagas/users.js @@ -5,7 +5,7 @@ import { fetchAuthorizationsOfCurrentUserSucceeded } from '../actions/users' import { performTokenSignIn } from '../api/routes/token-signin' import { addUser } from '../api/routes/users' import { saveAuthLocalStorage } from '../auth/index' -import { fetchAndStoreSimulation, fetchAndStoreUser } from './objects' +import { fetchAndStoreProject, fetchAndStoreUser } from './objects' export function* onFetchLoggedInUser(action) { try { @@ -32,10 +32,10 @@ export function* onFetchAuthorizationsOfCurrentUser(action) { for (const authorization of user.authorizations) { authorization.userId = action.userId yield put(addToStore('authorization', authorization)) - yield fetchAndStoreSimulation(authorization.simulationId) + yield fetchAndStoreProject(authorization.projectId) } - const authorizationIds = user.authorizations.map((authorization) => [action.userId, authorization.simulationId]) + const authorizationIds = user.authorizations.map((authorization) => [action.userId, authorization.projectId]) yield put(fetchAuthorizationsOfCurrentUserSucceeded(authorizationIds)) } catch (error) { diff --git a/frontend/src/shapes/index.js b/frontend/src/shapes/index.js index d43496d9..b3889243 100644 --- a/frontend/src/shapes/index.js +++ b/frontend/src/shapes/index.js @@ -11,7 +11,7 @@ Shapes.User = PropTypes.shape({ authorizations: PropTypes.array.isRequired, }) -Shapes.Simulation = PropTypes.shape({ +Shapes.Project = PropTypes.shape({ _id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, datetimeCreated: PropTypes.string.isRequired, @@ -23,8 +23,8 @@ Shapes.Simulation = PropTypes.shape({ Shapes.Authorization = PropTypes.shape({ userId: PropTypes.string.isRequired, user: Shapes.User, - simulationId: PropTypes.string.isRequired, - simulation: Shapes.Simulation, + projectId: PropTypes.string.isRequired, + project: Shapes.Project, authorizationLevel: PropTypes.string.isRequired, }) @@ -98,7 +98,7 @@ Shapes.Trace = PropTypes.shape({ Shapes.Experiment = PropTypes.shape({ _id: PropTypes.string.isRequired, - simulationId: PropTypes.string.isRequired, + projectId: PropTypes.string.isRequired, topologyId: PropTypes.string.isRequired, topology: Shapes.Topology, traceId: PropTypes.string.isRequired, diff --git a/frontend/src/util/date-time.test.js b/frontend/src/util/date-time.test.js index 3d95eba6..9274d4b7 100644 --- a/frontend/src/util/date-time.test.js +++ b/frontend/src/util/date-time.test.js @@ -15,7 +15,7 @@ describe('date-time parsing', () => { }) describe('tick formatting', () => { - it("returns '0s' for numbers <= 0", () => { + it('returns \'0s\' for numbers <= 0', () => { expect(convertSecondsToFormattedTime(-1)).toEqual('0s') expect(convertSecondsToFormattedTime(0)).toEqual('0s') }) diff --git a/frontend/src/util/simulation-load.js b/frontend/src/util/simulation-load.js deleted file mode 100644 index 40b65917..00000000 --- a/frontend/src/util/simulation-load.js +++ /dev/null @@ -1,32 +0,0 @@ -import { SIM_HIGH_COLOR, SIM_LOW_COLOR, SIM_MID_HIGH_COLOR, SIM_MID_LOW_COLOR } from './colors' - -export const LOAD_NAME_MAP = { - LOAD: 'computational load', - TEMPERATURE: 'temperature', - MEMORY: 'memory use', -} - -export function convertLoadToSimulationColor(load) { - if (load <= 0.25) { - return SIM_LOW_COLOR - } else if (load <= 0.5) { - return SIM_MID_LOW_COLOR - } else if (load <= 0.75) { - return SIM_MID_HIGH_COLOR - } else { - return SIM_HIGH_COLOR - } -} - -export function getStateLoad(loadMetric, state) { - switch (loadMetric) { - case 'LOAD': - return state.loadFraction - case 'TEMPERATURE': - return state.temperatureC / 100.0 - case 'MEMORY': - return state.inUseMemoryMb / 10000.0 - default: - return -1 - } -} diff --git a/mongodb/mongo-init-opendc-db.sh b/mongodb/mongo-init-opendc-db.sh index cda4ec93..5cac0a57 100644 --- a/mongodb/mongo-init-opendc-db.sh +++ b/mongodb/mongo-init-opendc-db.sh @@ -14,7 +14,7 @@ MONGO_CMD="mongo $OPENDC_DB -u $OPENDC_DB_USERNAME -p $OPENDC_DB_PASSWORD --auth echo 'Creating collections' $MONGO_CMD --eval 'db.createCollection("users");' -$MONGO_CMD --eval 'db.createCollection("simulations");' +$MONGO_CMD --eval 'db.createCollection("projects");' $MONGO_CMD --eval 'db.createCollection("topologies");' $MONGO_CMD --eval 'db.createCollection("experiments");' $MONGO_CMD --eval 'db.createCollection("traces");' diff --git a/opendc-api-spec.yml b/opendc-api-spec.yml index df8f8e94..0dfac326 100644 --- a/opendc-api-spec.yml +++ b/opendc-api-spec.yml @@ -131,15 +131,15 @@ paths: description: Forbidden from deleting User. '404': description: User not found. - '/simulations': + '/projects': post: tags: - - simulations - description: Add a Simulation. + - projects + description: Add a Project. parameters: - - name: simulation + - name: project in: body - description: The new Simulation. + description: The new Project. required: true schema: properties: @@ -147,105 +147,105 @@ paths: type: string responses: '200': - description: Successfully added Simulation. + description: Successfully added Project. schema: - $ref: '#/definitions/Simulation' + $ref: '#/definitions/Project' '400': description: Missing or incorrectly typed parameter. '401': description: Unauthorized. - '/simulations/{simulationId}': + '/projects/{projectId}': get: tags: - - simulations - description: Get this Simulation. + - projects + description: Get this Project. parameters: - - name: simulationId + - name: projectId in: path - description: Simulation's ID. + description: Project's ID. required: true type: string responses: '200': - description: Successfully retrieved Simulation. + description: Successfully retrieved Project. schema: - $ref: '#/definitions/Simulation' + $ref: '#/definitions/Project' '400': description: Missing or incorrectly typed parameter. '401': description: Unauthorized. '403': - description: Forbidden from retrieving Simulation. + description: Forbidden from retrieving Project. '404': - description: Simulation not found + description: Project not found put: tags: - - simulations - description: Update this Simulation. + - projects + description: Update this Project. parameters: - - name: simulationId + - name: projectId in: path - description: Simulation's ID. + description: Project's ID. required: true type: string - - name: simulation + - name: project in: body - description: Simulation's new properties. + description: Project's new properties. required: true schema: properties: - simulation: - $ref: '#/definitions/Simulation' + project: + $ref: '#/definitions/Project' responses: '200': - description: Successfully updated Simulation. + description: Successfully updated Project. schema: - $ref: '#/definitions/Simulation' + $ref: '#/definitions/Project' '400': description: Missing or incorrectly typed parameter. '401': description: Unauthorized. '403': - description: Forbidden from updating Simulation. + description: Forbidden from updating Project. '404': - description: Simulation not found. + description: Project not found. delete: tags: - - simulations - description: Delete this simulation. + - projects + description: Delete this project. parameters: - - name: simulationId + - name: projectId in: path - description: Simulation's ID. + description: Project's ID. required: true type: string responses: '200': - description: Successfully deleted Simulation. + description: Successfully deleted Project. schema: - $ref: '#/definitions/Simulation' + $ref: '#/definitions/Project' '400': description: Missing or incorrectly typed parameter. '401': description: Unauthorized. '403': - description: Forbidden from deleting Simulation. + description: Forbidden from deleting Project. '404': - description: Simulation not found. - '/simulations/{simulationId}/authorizations': + description: Project not found. + '/projects/{projectId}/authorizations': get: tags: - - simulations - description: Get this Simulation's Authorizations. + - projects + description: Get this Project's Authorizations. parameters: - - name: simulationId + - name: projectId in: path - description: Simulation's ID. + description: Project's ID. required: true type: string responses: '200': - description: Successfully retrieved Simulation's Authorizations. + description: Successfully retrieved Project's Authorizations. schema: type: array items: @@ -253,7 +253,7 @@ paths: properties: userId: type: string - simulationId: + projectId: type: string authorizationLevel: type: string @@ -262,18 +262,18 @@ paths: '401': description: Unauthorized. '403': - description: Forbidden from retrieving this Simulation's Authorizations. + description: Forbidden from retrieving this Project's Authorizations. '404': - description: Simulation not found. - '/simulations/{simulationId}/topologies': + description: Project not found. + '/projects/{projectId}/topologies': post: tags: - - simulations + - projects description: Add a Topology. parameters: - - name: simulationId + - name: projectId in: path - description: Simulation's ID. + description: Project's ID. required: true type: string - name: topology @@ -293,15 +293,15 @@ paths: description: Missing or incorrectly typed parameter. '401': description: Unauthorized. - '/simulations/{simulationId}/experiments': + '/projects/{projectId}/experiments': post: tags: - experiments description: Add an Experiment. parameters: - - name: simulationId + - name: projectId in: path - description: Simulation's ID. + description: Project's ID. required: true type: string - name: experiment @@ -481,132 +481,6 @@ paths: description: Forbidden from deleting Experiment. '404': description: Experiment not found. - '/experiments/{experimentId}/machine-states': - get: - tags: - - simulations - - states - description: Get this experiment's Machine States. - parameters: - - name: experimentId - in: path - description: Experiment's ID. - required: true - type: string - - name: tick - in: query - description: Tick to filter on. - required: false - type: integer - - name: machineId - in: query - description: Machine's ID to filter on. - required: false - type: string - - name: rackId - in: query - description: Rack's ID to filter on. - required: false - type: string - - name: roomId - in: query - description: Room's ID to filter on. - required: false - type: string - responses: - '200': - description: Successfully retrieved Machine States. - schema: - type: array - items: - $ref: '#/definitions/MachineState' - '400': - description: Missing or incorrectly typed parameter. - '401': - description: Unauthorized. - '403': - description: Forbidden from getting Experiment's Machine States. - '404': - description: 'Experiment, Machine, Rack, Room or Tick not found.' - '/experiments/{experimentId}/rack-states': - get: - tags: - - simulations - - states - description: Get this Experiment's Rack States. - parameters: - - name: experimentId - in: path - description: Experiment's ID. - required: true - type: string - - name: tick - in: query - description: Tick to filter on. - required: false - type: integer - - name: rackId - in: query - description: Rack's ID to filter on. - required: false - type: string - - name: roomId - in: query - description: Room's ID to filter on. - required: false - type: string - responses: - '200': - description: Successfully retrieved Rack States. - schema: - type: array - items: - $ref: '#/definitions/RackState' - '400': - description: Missing or incorrectly typed parameter. - '401': - description: Unauthorized. - '403': - description: Forbidden from getting Experiment's Rack States. - '404': - description: 'Experiment, Room, Rack or Tick not found.' - '/experiments/{experimentId}/room-states': - get: - tags: - - simulations - - states - description: Get this Experiment's Room States. - parameters: - - name: experimentId - in: path - description: Experiment's ID. - required: true - type: string - - name: tick - in: query - description: Tick to filter on. - required: false - type: integer - - name: roomId - in: query - description: Room's ID to filter on. - required: false - type: string - responses: - '200': - description: Successfully retrieved Room States. - schema: - type: array - items: - $ref: '#/definitions/RoomState' - '400': - description: Missing or incorrectly typed parameter. - '401': - description: Unauthorized. - '403': - description: Forbidden from getting Experiment's Room States. - '404': - description: 'Experiment, Room or Tick not found.' /schedulers: get: tags: @@ -723,7 +597,7 @@ paths: required: true schema: properties: - simulation: + project: $ref: '#/definitions/Prefab' responses: '200': @@ -768,7 +642,7 @@ definitions: properties: _id: type: string - simulationId: + projectId: type: string topologyId: type: string @@ -849,7 +723,7 @@ definitions: properties: name: type: string - Simulation: + Project: type: object properties: _id: @@ -875,7 +749,7 @@ definitions: properties: _id: type: string - simulationId: + projectId: type: string name: type: string @@ -986,7 +860,7 @@ definitions: items: type: object properties: - simulationId: + projectId: type: string authorizationLevel: type: string diff --git a/simulator/odcsim/README.md b/simulator/odcsim/README.md index b930315a..78cfaa27 100644 --- a/simulator/odcsim/README.md +++ b/simulator/odcsim/README.md @@ -9,7 +9,7 @@ ## Introduction **odcsim** is a framework for discrete event simulation in Kotlin, used by the [OpenDC](https://opendc.org) project. -Simulations are defined in terms of a hierarchical grouping of actors +Projects are defined in terms of a hierarchical grouping of actors and the interactions between these actors ([Actor model](https://en.wikipedia.org/wiki/Actor_model)). diff --git a/web-server/README.md b/web-server/README.md index e5a46016..49c605c5 100644 --- a/web-server/README.md +++ b/web-server/README.md @@ -32,7 +32,7 @@ The `Util` package handles several miscellaneous tasks: ### API Package -The `API` package contains the logic for the HTTP methods in each API endpoint. Packages are structured to mirror the API: the code for the endpoint `GET api/simulations`, for example, would be located at the `endpoint.py` inside the `simulations` package (so at `api/simulations/endpoint.py`). +The `API` package contains the logic for the HTTP methods in each API endpoint. Packages are structured to mirror the API: the code for the endpoint `GET api/projects`, for example, would be located at the `endpoint.py` inside the `projects` package (so at `api/projects/endpoint.py`). An `endpoint.py` file contains methods for each HTTP method it supports, which takes a request as input (such as `def GET(request):`). Typically, such a method checks whether the parameters were passed correctly (using the `Parameter Checker`); fetches some model from the database; checks whether the data exists and is accessible by the user who made the request; possibly modifies this data and writes it back to the database; and returns a JSON representation of the model. @@ -40,7 +40,7 @@ The `REST` component dynamically imports the appropriate method from the appropr ### Models Package -The `models` package contains the logic for mapping Python objects to their database representations. This involves an abstract `model` which has generic CRUD operations. Extensions of `model`, such as a `User` or `Simulation`, specify some more specific operations and their collection metadata. +The `models` package contains the logic for mapping Python objects to their database representations. This involves an abstract `model` which has generic CRUD operations. Extensions of `model`, such as a `User` or `Project`, specify some more specific operations and their collection metadata. `Endpoint`s import these `models` and use them to execute requests. diff --git a/web-server/main.py b/web-server/main.py index 7f499b34..af3e95b9 100644 --- a/web-server/main.py +++ b/web-server/main.py @@ -138,12 +138,12 @@ def serve_web_server_test(): @FLASK_CORE_APP.route('/') -@FLASK_CORE_APP.route('/simulations') -@FLASK_CORE_APP.route('/simulations/<path:simulation_id>') -@FLASK_CORE_APP.route('/simulations/<path:simulation_id>/experiments') -@FLASK_CORE_APP.route('/simulations/<path:simulation_id>/experiments/<path:experiment_id>') +@FLASK_CORE_APP.route('/projects') +@FLASK_CORE_APP.route('/projects/<path:project_id>') +@FLASK_CORE_APP.route('/projects/<path:project_id>/experiments') +@FLASK_CORE_APP.route('/projects/<path:project_id>/experiments/<path:experiment_id>') @FLASK_CORE_APP.route('/profile') -def serve_index(simulation_id=None, experiment_id=None): +def serve_index(project_id=None, experiment_id=None): return send_from_directory(STATIC_ROOT, 'index.html') diff --git a/web-server/opendc/api/v2/experiments/experimentId/endpoint.py b/web-server/opendc/api/v2/experiments/experimentId/endpoint.py index dc056454..6706dc57 100644 --- a/web-server/opendc/api/v2/experiments/experimentId/endpoint.py +++ b/web-server/opendc/api/v2/experiments/experimentId/endpoint.py @@ -1,5 +1,5 @@ from opendc.models.experiment import Experiment -from opendc.models.simulation import Simulation +from opendc.models.project import Project from opendc.util.rest import Response @@ -45,11 +45,11 @@ def DELETE(request): experiment.check_exists() experiment.check_user_access(request.google_id, True) - simulation = Simulation.from_id(experiment.obj['simulationId']) - simulation.check_exists() - if request.params_path['experimentId'] in simulation.obj['experimentIds']: - simulation.obj['experimentIds'].remove(request.params_path['experimentId']) - simulation.update() + project = Project.from_id(experiment.obj['projectId']) + project.check_exists() + if request.params_path['experimentId'] in project.obj['experimentIds']: + project.obj['experimentIds'].remove(request.params_path['experimentId']) + project.update() old_object = experiment.delete() diff --git a/web-server/opendc/api/v2/experiments/experimentId/test_endpoint.py b/web-server/opendc/api/v2/experiments/experimentId/test_endpoint.py index 3532f9ae..a284cf32 100644 --- a/web-server/opendc/api/v2/experiments/experimentId/test_endpoint.py +++ b/web-server/opendc/api/v2/experiments/experimentId/test_endpoint.py @@ -7,7 +7,7 @@ def test_get_experiment_non_existing(client, mocker): def test_get_experiment_no_authorizations(client, mocker): - mocker.patch.object(DB, 'fetch_one', return_value={'simulationId': '1', 'authorizations': []}) + mocker.patch.object(DB, 'fetch_one', return_value={'projectId': '1', 'authorizations': []}) res = client.get('/api/v2/experiments/1') assert '403' in res.status @@ -16,10 +16,10 @@ def test_get_experiment_not_authorized(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ - 'simulationId': '1', + 'projectId': '1', '_id': '1', 'authorizations': [{ - 'simulationId': '2', + 'projectId': '2', 'authorizationLevel': 'OWN' }] }) @@ -31,10 +31,10 @@ def test_get_experiment(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ - 'simulationId': '1', + 'projectId': '1', '_id': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'EDIT' }] }) @@ -60,9 +60,9 @@ def test_update_experiment_not_authorized(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }] }) @@ -79,9 +79,9 @@ def test_update_experiment(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }] }) @@ -93,20 +93,20 @@ def test_update_experiment(client, mocker): assert '200' in res.status -def test_delete_simulation_non_existing(client, mocker): +def test_delete_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) assert '404' in client.delete('/api/v2/experiments/1').status -def test_delete_simulation_different_user(client, mocker): +def test_delete_project_different_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'googleId': 'other_test', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }] }) @@ -114,16 +114,16 @@ def test_delete_simulation_different_user(client, mocker): assert '403' in client.delete('/api/v2/experiments/1').status -def test_delete_simulation(client, mocker): +def test_delete_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'googleId': 'test', 'experimentIds': ['1'], 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }] }) diff --git a/web-server/opendc/api/v2/paths.json b/web-server/opendc/api/v2/paths.json index c0aa4dd4..01a7dcff 100644 --- a/web-server/opendc/api/v2/paths.json +++ b/web-server/opendc/api/v2/paths.json @@ -1,12 +1,12 @@ [ "/users", "/users/{userId}", - "/simulations", - "/simulations/{simulationId}", - "/simulations/{simulationId}/authorizations", - "/simulations/{simulationId}/topologies", + "/projects", + "/projects/{projectId}", + "/projects/{projectId}/authorizations", + "/projects/{projectId}/topologies", "/topologies/{topologyId}", - "/simulations/{simulationId}/experiments", + "/projects/{projectId}/experiments", "/experiments/{experimentId}", "/schedulers", "/traces", diff --git a/web-server/opendc/api/v2/simulations/__init__.py b/web-server/opendc/api/v2/projects/__init__.py index e69de29b..e69de29b 100644 --- a/web-server/opendc/api/v2/simulations/__init__.py +++ b/web-server/opendc/api/v2/projects/__init__.py diff --git a/web-server/opendc/api/v2/projects/endpoint.py b/web-server/opendc/api/v2/projects/endpoint.py new file mode 100644 index 00000000..10954cdd --- /dev/null +++ b/web-server/opendc/api/v2/projects/endpoint.py @@ -0,0 +1,32 @@ +from datetime import datetime + +from opendc.models.project import Project +from opendc.models.topology import Topology +from opendc.models.user import User +from opendc.util.database import Database +from opendc.util.rest import Response + + +def POST(request): + """Create a new project, and return that new project.""" + + request.check_required_parameters(body={'project': {'name': 'string'}}) + + topology = Topology({'name': 'Default topology', 'rooms': []}) + topology.insert() + + project = Project(request.params_body['project']) + project.set_property('datetimeCreated', Database.datetime_to_string(datetime.now())) + project.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now())) + project.set_property('topologyIds', [topology.get_id()]) + project.set_property('experimentIds', []) + project.insert() + + topology.set_property('projectId', project.get_id()) + topology.update() + + user = User.from_google_id(request.google_id) + user.obj['authorizations'].append({'projectId': project.get_id(), 'authorizationLevel': 'OWN'}) + user.update() + + return Response(200, 'Successfully created project.', project.obj) diff --git a/web-server/opendc/api/v2/simulations/simulationId/__init__.py b/web-server/opendc/api/v2/projects/projectId/__init__.py index e69de29b..e69de29b 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/__init__.py +++ b/web-server/opendc/api/v2/projects/projectId/__init__.py diff --git a/web-server/opendc/api/v2/simulations/simulationId/authorizations/__init__.py b/web-server/opendc/api/v2/projects/projectId/authorizations/__init__.py index e69de29b..e69de29b 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/authorizations/__init__.py +++ b/web-server/opendc/api/v2/projects/projectId/authorizations/__init__.py diff --git a/web-server/opendc/api/v2/projects/projectId/authorizations/endpoint.py b/web-server/opendc/api/v2/projects/projectId/authorizations/endpoint.py new file mode 100644 index 00000000..9f6a60ec --- /dev/null +++ b/web-server/opendc/api/v2/projects/projectId/authorizations/endpoint.py @@ -0,0 +1,17 @@ +from opendc.models.project import Project +from opendc.util.rest import Response + + +def GET(request): + """Find all authorizations for a Project.""" + + request.check_required_parameters(path={'projectId': 'string'}) + + project = Project.from_id(request.params_path['projectId']) + + project.check_exists() + project.check_user_access(request.google_id, False) + + authorizations = project.get_all_authorizations() + + return Response(200, 'Successfully retrieved project authorizations', authorizations) diff --git a/web-server/opendc/api/v2/simulations/simulationId/authorizations/test_endpoint.py b/web-server/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py index 4369d807..c3bbc093 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/authorizations/test_endpoint.py +++ b/web-server/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py @@ -4,7 +4,7 @@ from opendc.util.database import DB def test_get_authorizations_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) mocker.patch.object(DB, 'fetch_all', return_value=None) - assert '404' in client.get('/api/v2/simulations/1/authorizations').status + assert '404' in client.get('/api/v2/projects/1/authorizations').status def test_get_authorizations_not_authorized(client, mocker): @@ -14,12 +14,12 @@ def test_get_authorizations_not_authorized(client, mocker): '_id': '1', 'name': 'test trace', 'authorizations': [{ - 'simulationId': '2', + 'projectId': '2', 'authorizationLevel': 'OWN' }] }) mocker.patch.object(DB, 'fetch_all', return_value=[]) - res = client.get('/api/v2/simulations/1/authorizations') + res = client.get('/api/v2/projects/1/authorizations') assert '403' in res.status @@ -30,11 +30,11 @@ def test_get_authorizations(client, mocker): '_id': '1', 'name': 'test trace', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }] }) mocker.patch.object(DB, 'fetch_all', return_value=[]) - res = client.get('/api/v2/simulations/1/authorizations') + res = client.get('/api/v2/projects/1/authorizations') assert len(res.json['content']) == 0 assert '200' in res.status diff --git a/web-server/opendc/api/v2/projects/projectId/endpoint.py b/web-server/opendc/api/v2/projects/projectId/endpoint.py new file mode 100644 index 00000000..6f80f827 --- /dev/null +++ b/web-server/opendc/api/v2/projects/projectId/endpoint.py @@ -0,0 +1,66 @@ +from datetime import datetime + +from opendc.models.experiment import Experiment +from opendc.models.project import Project +from opendc.models.topology import Topology +from opendc.models.user import User +from opendc.util.database import Database +from opendc.util.rest import Response + + +def GET(request): + """Get this Project.""" + + request.check_required_parameters(path={'projectId': 'string'}) + + project = Project.from_id(request.params_path['projectId']) + + project.check_exists() + project.check_user_access(request.google_id, False) + + return Response(200, 'Successfully retrieved project', project.obj) + + +def PUT(request): + """Update a project's name.""" + + request.check_required_parameters(body={'project': {'name': 'name'}}, path={'projectId': 'string'}) + + project = Project.from_id(request.params_path['projectId']) + + project.check_exists() + project.check_user_access(request.google_id, True) + + project.set_property('name', request.params_body['project']['name']) + project.set_property('datetime_last_edited', Database.datetime_to_string(datetime.now())) + project.update() + + return Response(200, 'Successfully updated project.', project.obj) + + +def DELETE(request): + """Delete this Project.""" + + request.check_required_parameters(path={'projectId': 'string'}) + + project = Project.from_id(request.params_path['projectId']) + + project.check_exists() + project.check_user_access(request.google_id, True) + + for topology_id in project.obj['topologyIds']: + topology = Topology.from_id(topology_id) + topology.delete() + + for experiment_id in project.obj['experimentIds']: + experiment = Experiment.from_id(experiment_id) + experiment.delete() + + user = User.from_google_id(request.google_id) + user.obj['authorizations'] = list( + filter(lambda x: str(x['projectId']) != request.params_path['projectId'], user.obj['authorizations'])) + user.update() + + old_object = project.delete() + + return Response(200, 'Successfully deleted project.', old_object) diff --git a/web-server/opendc/api/v2/simulations/simulationId/experiments/__init__.py b/web-server/opendc/api/v2/projects/projectId/experiments/__init__.py index e69de29b..e69de29b 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/experiments/__init__.py +++ b/web-server/opendc/api/v2/projects/projectId/experiments/__init__.py diff --git a/web-server/opendc/api/v2/simulations/simulationId/experiments/endpoint.py b/web-server/opendc/api/v2/projects/projectId/experiments/endpoint.py index 0d7c208d..2e5b93df 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/experiments/endpoint.py +++ b/web-server/opendc/api/v2/projects/projectId/experiments/endpoint.py @@ -1,12 +1,12 @@ from opendc.models.experiment import Experiment -from opendc.models.simulation import Simulation +from opendc.models.project import Project from opendc.util.rest import Response def POST(request): - """Add a new Experiment for this Simulation.""" + """Add a new Experiment for this Project.""" - request.check_required_parameters(path={'simulationId': 'string'}, + request.check_required_parameters(path={'projectId': 'string'}, body={ 'experiment': { 'topologyId': 'string', @@ -16,20 +16,20 @@ def POST(request): } }) - simulation = Simulation.from_id(request.params_path['simulationId']) + project = Project.from_id(request.params_path['projectId']) - simulation.check_exists() - simulation.check_user_access(request.google_id, True) + project.check_exists() + project.check_user_access(request.google_id, True) experiment = Experiment(request.params_body['experiment']) - experiment.set_property('simulationId', request.params_path['simulationId']) + experiment.set_property('projectId', request.params_path['projectId']) experiment.set_property('state', 'QUEUED') experiment.set_property('lastSimulatedTick', 0) experiment.insert() - simulation.obj['experimentIds'].append(experiment.get_id()) - simulation.update() + project.obj['experimentIds'].append(experiment.get_id()) + project.update() return Response(200, 'Successfully added Experiment.', experiment.obj) diff --git a/web-server/opendc/api/v2/simulations/simulationId/experiments/test_endpoint.py b/web-server/opendc/api/v2/projects/projectId/experiments/test_endpoint.py index 1fe09b10..11b79154 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/experiments/test_endpoint.py +++ b/web-server/opendc/api/v2/projects/projectId/experiments/test_endpoint.py @@ -2,12 +2,12 @@ from opendc.util.database import DB def test_add_experiment_missing_parameter(client): - assert '400' in client.post('/api/v2/simulations/1/experiments').status + assert '400' in client.post('/api/v2/projects/1/experiments').status -def test_add_experiment_non_existing_simulation(client, mocker): +def test_add_experiment_non_existing_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.post('/api/v2/simulations/1/experiments', + assert '404' in client.post('/api/v2/projects/1/experiments', json={ 'experiment': { 'topologyId': '1', @@ -23,13 +23,13 @@ def test_add_experiment_not_authorized(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }] }) - assert '403' in client.post('/api/v2/simulations/1/experiments', + assert '403' in client.post('/api/v2/projects/1/experiments', json={ 'experiment': { 'topologyId': '1', @@ -45,10 +45,10 @@ def test_add_experiment(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'experimentIds': ['1'], 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'EDIT' }] }) @@ -65,7 +65,7 @@ def test_add_experiment(client, mocker): }) mocker.patch.object(DB, 'update', return_value=None) res = client.post( - '/api/v2/simulations/1/experiments', + '/api/v2/projects/1/experiments', json={'experiment': { 'topologyId': '1', 'traceId': '1', diff --git a/web-server/opendc/api/v2/simulations/simulationId/test_endpoint.py b/web-server/opendc/api/v2/projects/projectId/test_endpoint.py index 3ab0161d..c7450b5a 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/test_endpoint.py +++ b/web-server/opendc/api/v2/projects/projectId/test_endpoint.py @@ -1,113 +1,113 @@ from opendc.util.database import DB -def test_get_simulation_non_existing(client, mocker): +def test_get_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get('/api/v2/simulations/1').status + assert '404' in client.get('/api/v2/projects/1').status -def test_get_simulation_no_authorizations(client, mocker): +def test_get_project_no_authorizations(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'authorizations': []}) - res = client.get('/api/v2/simulations/1') + res = client.get('/api/v2/projects/1') assert '403' in res.status -def test_get_simulation_not_authorized(client, mocker): +def test_get_project_not_authorized(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', 'authorizations': [{ - 'simulationId': '2', + 'projectId': '2', 'authorizationLevel': 'OWN' }] }) - res = client.get('/api/v2/simulations/1') + res = client.get('/api/v2/projects/1') assert '403' in res.status -def test_get_simulation(client, mocker): +def test_get_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'EDIT' }] }) - res = client.get('/api/v2/simulations/1') + res = client.get('/api/v2/projects/1') assert '200' in res.status -def test_update_simulation_missing_parameter(client): - assert '400' in client.put('/api/v2/simulations/1').status +def test_update_project_missing_parameter(client): + assert '400' in client.put('/api/v2/projects/1').status -def test_update_simulation_non_existing(client, mocker): +def test_update_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put('/api/v2/simulations/1', json={'simulation': {'name': 'S'}}).status + assert '404' in client.put('/api/v2/projects/1', json={'project': {'name': 'S'}}).status -def test_update_simulation_not_authorized(client, mocker): +def test_update_project_not_authorized(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }] }) mocker.patch.object(DB, 'update', return_value={}) - assert '403' in client.put('/api/v2/simulations/1', json={'simulation': {'name': 'S'}}).status + assert '403' in client.put('/api/v2/projects/1', json={'project': {'name': 'S'}}).status -def test_update_simulation(client, mocker): +def test_update_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }] }) mocker.patch.object(DB, 'update', return_value={}) - res = client.put('/api/v2/simulations/1', json={'simulation': {'name': 'S'}}) + res = client.put('/api/v2/projects/1', json={'project': {'name': 'S'}}) assert '200' in res.status -def test_delete_simulation_non_existing(client, mocker): +def test_delete_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete('/api/v2/simulations/1').status + assert '404' in client.delete('/api/v2/projects/1').status -def test_delete_simulation_different_user(client, mocker): +def test_delete_project_different_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', 'googleId': 'other_test', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }], 'topologyIds': [] }) mocker.patch.object(DB, 'delete_one', return_value=None) - assert '403' in client.delete('/api/v2/simulations/1').status + assert '403' in client.delete('/api/v2/projects/1').status -def test_delete_simulation(client, mocker): +def test_delete_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={ '_id': '1', 'googleId': 'test', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }], 'topologyIds': [], @@ -115,5 +115,5 @@ def test_delete_simulation(client, mocker): }) mocker.patch.object(DB, 'update', return_value=None) mocker.patch.object(DB, 'delete_one', return_value={'googleId': 'test'}) - res = client.delete('/api/v2/simulations/1') + res = client.delete('/api/v2/projects/1') assert '200' in res.status diff --git a/web-server/opendc/api/v2/simulations/simulationId/topologies/__init__.py b/web-server/opendc/api/v2/projects/projectId/topologies/__init__.py index e69de29b..e69de29b 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/topologies/__init__.py +++ b/web-server/opendc/api/v2/projects/projectId/topologies/__init__.py diff --git a/web-server/opendc/api/v2/projects/projectId/topologies/endpoint.py b/web-server/opendc/api/v2/projects/projectId/topologies/endpoint.py new file mode 100644 index 00000000..211dc15d --- /dev/null +++ b/web-server/opendc/api/v2/projects/projectId/topologies/endpoint.py @@ -0,0 +1,31 @@ +from datetime import datetime + +from opendc.models.project import Project +from opendc.models.topology import Topology +from opendc.util.rest import Response +from opendc.util.database import Database + + +def POST(request): + """Add a new Topology to the specified project and return it""" + + request.check_required_parameters(path={'projectId': 'string'}, body={'topology': {'name': 'string'}}) + + project = Project.from_id(request.params_path['projectId']) + + project.check_exists() + project.check_user_access(request.google_id, True) + + topology = Topology({ + 'projectId': request.params_path['projectId'], + 'name': request.params_body['topology']['name'], + 'rooms': request.params_body['topology']['rooms'], + }) + + topology.insert() + + project.obj['topologyIds'].append(topology.get_id()) + project.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now())) + project.update() + + return Response(200, 'Successfully inserted topology.', topology.obj) diff --git a/web-server/opendc/api/v2/simulations/simulationId/topologies/test_endpoint.py b/web-server/opendc/api/v2/projects/projectId/topologies/test_endpoint.py index 1314be13..ca123a73 100644 --- a/web-server/opendc/api/v2/simulations/simulationId/topologies/test_endpoint.py +++ b/web-server/opendc/api/v2/projects/projectId/topologies/test_endpoint.py @@ -2,7 +2,7 @@ from opendc.util.database import DB def test_add_topology_missing_parameter(client): - assert '400' in client.post('/api/v2/simulations/1/topologies').status + assert '400' in client.post('/api/v2/projects/1/topologies').status def test_add_topology(client, mocker): @@ -11,7 +11,7 @@ def test_add_topology(client, mocker): return_value={ '_id': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }], 'topologyIds': [] @@ -25,7 +25,7 @@ def test_add_topology(client, mocker): 'topologyIds': [] }) mocker.patch.object(DB, 'update', return_value={}) - res = client.post('/api/v2/simulations/1/topologies', json={'topology': {'name': 'test simulation', 'rooms': []}}) + res = client.post('/api/v2/projects/1/topologies', json={'topology': {'name': 'test project', 'rooms': []}}) assert 'rooms' in res.json['content'] assert '200' in res.status @@ -35,13 +35,13 @@ def test_add_topology_not_authorized(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }] }) - assert '403' in client.post('/api/v2/simulations/1/topologies', + assert '403' in client.post('/api/v2/projects/1/topologies', json={ 'topology': { 'name': 'test_topology', diff --git a/web-server/opendc/api/v2/simulations/test_endpoint.py b/web-server/opendc/api/v2/projects/test_endpoint.py index ae1b5a7c..a50735b0 100644 --- a/web-server/opendc/api/v2/simulations/test_endpoint.py +++ b/web-server/opendc/api/v2/projects/test_endpoint.py @@ -1,11 +1,11 @@ from opendc.util.database import DB -def test_add_simulation_missing_parameter(client): - assert '400' in client.post('/api/v2/simulations').status +def test_add_project_missing_parameter(client): + assert '400' in client.post('/api/v2/projects').status -def test_add_simulation(client, mocker): +def test_add_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'_id': '1', 'authorizations': []}) mocker.patch.object(DB, 'insert', @@ -16,7 +16,7 @@ def test_add_simulation(client, mocker): 'topologyIds': [] }) mocker.patch.object(DB, 'update', return_value={}) - res = client.post('/api/v2/simulations', json={'simulation': {'name': 'test simulation'}}) + res = client.post('/api/v2/projects', json={'project': {'name': 'test project'}}) assert 'datetimeCreated' in res.json['content'] assert 'datetimeLastEdited' in res.json['content'] assert 'topologyIds' in res.json['content'] diff --git a/web-server/opendc/api/v2/simulations/endpoint.py b/web-server/opendc/api/v2/simulations/endpoint.py deleted file mode 100644 index 993e317a..00000000 --- a/web-server/opendc/api/v2/simulations/endpoint.py +++ /dev/null @@ -1,32 +0,0 @@ -from datetime import datetime - -from opendc.models.simulation import Simulation -from opendc.models.topology import Topology -from opendc.models.user import User -from opendc.util.database import Database -from opendc.util.rest import Response - - -def POST(request): - """Create a new simulation, and return that new simulation.""" - - request.check_required_parameters(body={'simulation': {'name': 'string'}}) - - topology = Topology({'name': 'Default topology', 'rooms': []}) - topology.insert() - - simulation = Simulation(request.params_body['simulation']) - simulation.set_property('datetimeCreated', Database.datetime_to_string(datetime.now())) - simulation.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now())) - simulation.set_property('topologyIds', [topology.get_id()]) - simulation.set_property('experimentIds', []) - simulation.insert() - - topology.set_property('simulationId', simulation.get_id()) - topology.update() - - user = User.from_google_id(request.google_id) - user.obj['authorizations'].append({'simulationId': simulation.get_id(), 'authorizationLevel': 'OWN'}) - user.update() - - return Response(200, 'Successfully created simulation.', simulation.obj) diff --git a/web-server/opendc/api/v2/simulations/simulationId/authorizations/endpoint.py b/web-server/opendc/api/v2/simulations/simulationId/authorizations/endpoint.py deleted file mode 100644 index 49d0fc20..00000000 --- a/web-server/opendc/api/v2/simulations/simulationId/authorizations/endpoint.py +++ /dev/null @@ -1,17 +0,0 @@ -from opendc.models.simulation import Simulation -from opendc.util.rest import Response - - -def GET(request): - """Find all authorizations for a Simulation.""" - - request.check_required_parameters(path={'simulationId': 'string'}) - - simulation = Simulation.from_id(request.params_path['simulationId']) - - simulation.check_exists() - simulation.check_user_access(request.google_id, False) - - authorizations = simulation.get_all_authorizations() - - return Response(200, 'Successfully retrieved simulation authorizations', authorizations) diff --git a/web-server/opendc/api/v2/simulations/simulationId/endpoint.py b/web-server/opendc/api/v2/simulations/simulationId/endpoint.py deleted file mode 100644 index 0cee3e9c..00000000 --- a/web-server/opendc/api/v2/simulations/simulationId/endpoint.py +++ /dev/null @@ -1,66 +0,0 @@ -from datetime import datetime - -from opendc.models.experiment import Experiment -from opendc.models.simulation import Simulation -from opendc.models.topology import Topology -from opendc.models.user import User -from opendc.util.database import Database -from opendc.util.rest import Response - - -def GET(request): - """Get this Simulation.""" - - request.check_required_parameters(path={'simulationId': 'string'}) - - simulation = Simulation.from_id(request.params_path['simulationId']) - - simulation.check_exists() - simulation.check_user_access(request.google_id, False) - - return Response(200, 'Successfully retrieved simulation', simulation.obj) - - -def PUT(request): - """Update a simulation's name.""" - - request.check_required_parameters(body={'simulation': {'name': 'name'}}, path={'simulationId': 'string'}) - - simulation = Simulation.from_id(request.params_path['simulationId']) - - simulation.check_exists() - simulation.check_user_access(request.google_id, True) - - simulation.set_property('name', request.params_body['simulation']['name']) - simulation.set_property('datetime_last_edited', Database.datetime_to_string(datetime.now())) - simulation.update() - - return Response(200, 'Successfully updated simulation.', simulation.obj) - - -def DELETE(request): - """Delete this Simulation.""" - - request.check_required_parameters(path={'simulationId': 'string'}) - - simulation = Simulation.from_id(request.params_path['simulationId']) - - simulation.check_exists() - simulation.check_user_access(request.google_id, True) - - for topology_id in simulation.obj['topologyIds']: - topology = Topology.from_id(topology_id) - topology.delete() - - for experiment_id in simulation.obj['experimentIds']: - experiment = Experiment.from_id(experiment_id) - experiment.delete() - - user = User.from_google_id(request.google_id) - user.obj['authorizations'] = list( - filter(lambda x: str(x['simulationId']) != request.params_path['simulationId'], user.obj['authorizations'])) - user.update() - - old_object = simulation.delete() - - return Response(200, 'Successfully deleted simulation.', old_object) diff --git a/web-server/opendc/api/v2/simulations/simulationId/topologies/endpoint.py b/web-server/opendc/api/v2/simulations/simulationId/topologies/endpoint.py deleted file mode 100644 index 7c07e63b..00000000 --- a/web-server/opendc/api/v2/simulations/simulationId/topologies/endpoint.py +++ /dev/null @@ -1,31 +0,0 @@ -from datetime import datetime - -from opendc.models.simulation import Simulation -from opendc.models.topology import Topology -from opendc.util.rest import Response -from opendc.util.database import Database - - -def POST(request): - """Add a new Topology to the specified simulation and return it""" - - request.check_required_parameters(path={'simulationId': 'string'}, body={'topology': {'name': 'string'}}) - - simulation = Simulation.from_id(request.params_path['simulationId']) - - simulation.check_exists() - simulation.check_user_access(request.google_id, True) - - topology = Topology({ - 'simulationId': request.params_path['simulationId'], - 'name': request.params_body['topology']['name'], - 'rooms': request.params_body['topology']['rooms'], - }) - - topology.insert() - - simulation.obj['topologyIds'].append(topology.get_id()) - simulation.set_property('datetimeLastEdited', Database.datetime_to_string(datetime.now())) - simulation.update() - - return Response(200, 'Successfully inserted topology.', topology.obj) diff --git a/web-server/opendc/api/v2/topologies/topologyId/endpoint.py b/web-server/opendc/api/v2/topologies/topologyId/endpoint.py index 1dcccb3e..512b050a 100644 --- a/web-server/opendc/api/v2/topologies/topologyId/endpoint.py +++ b/web-server/opendc/api/v2/topologies/topologyId/endpoint.py @@ -1,7 +1,7 @@ from datetime import datetime from opendc.util.database import Database -from opendc.models.simulation import Simulation +from opendc.models.project import Project from opendc.models.topology import Topology from opendc.util.rest import Response @@ -45,11 +45,11 @@ def DELETE(request): topology.check_exists() topology.check_user_access(request.google_id, True) - simulation = Simulation.from_id(topology.obj['simulationId']) - simulation.check_exists() - if request.params_path['topologyId'] in simulation.obj['topologyIds']: - simulation.obj['topologyIds'].remove(request.params_path['topologyId']) - simulation.update() + project = Project.from_id(topology.obj['projectId']) + project.check_exists() + if request.params_path['topologyId'] in project.obj['topologyIds']: + project.obj['topologyIds'].remove(request.params_path['topologyId']) + project.update() old_object = topology.delete() diff --git a/web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py b/web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py index d3c20de3..b25cb798 100644 --- a/web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py +++ b/web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py @@ -6,9 +6,9 @@ def test_get_topology(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'EDIT' }] }) @@ -26,9 +26,9 @@ def test_get_topology_not_authorized(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '2', + 'projectId': '2', 'authorizationLevel': 'OWN' }] }) @@ -37,7 +37,7 @@ def test_get_topology_not_authorized(client, mocker): def test_get_topology_no_authorizations(client, mocker): - mocker.patch.object(DB, 'fetch_one', return_value={'simulationId': '1', 'authorizations': []}) + mocker.patch.object(DB, 'fetch_one', return_value={'projectId': '1', 'authorizations': []}) res = client.get('/api/v2/topologies/1') assert '403' in res.status @@ -56,9 +56,9 @@ def test_update_topology_not_authorized(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'VIEW' }] }) @@ -76,9 +76,9 @@ def test_update_topology(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }] }) @@ -97,11 +97,11 @@ def test_delete_topology(client, mocker): 'fetch_one', return_value={ '_id': '1', - 'simulationId': '1', + 'projectId': '1', 'googleId': 'test', 'topologyIds': ['1'], 'authorizations': [{ - 'simulationId': '1', + 'projectId': '1', 'authorizationLevel': 'OWN' }] }) diff --git a/web-server/opendc/api/v2/users/userId/endpoint.py b/web-server/opendc/api/v2/users/userId/endpoint.py index 7a4fb104..be3462c0 100644 --- a/web-server/opendc/api/v2/users/userId/endpoint.py +++ b/web-server/opendc/api/v2/users/userId/endpoint.py @@ -1,4 +1,4 @@ -from opendc.models.simulation import Simulation +from opendc.models.project import Project from opendc.models.user import User from opendc.util.rest import Response @@ -51,8 +51,8 @@ def DELETE(request): if authorization['authorizationLevel'] != 'OWN': continue - simulation = Simulation.from_id(authorization['simulationId']) - simulation.delete() + project = Project.from_id(authorization['projectId']) + project.delete() old_object = user.delete() diff --git a/web-server/opendc/models/experiment.py b/web-server/opendc/models/experiment.py index 36b5d415..46373b99 100644 --- a/web-server/opendc/models/experiment.py +++ b/web-server/opendc/models/experiment.py @@ -12,13 +12,13 @@ class Experiment(Model): def check_user_access(self, google_id, edit_access): """Raises an error if the user with given [google_id] has insufficient access. - Checks access on the parent simulation. + Checks access on the parent project. :param google_id: The Google ID of the user. :param edit_access: True when edit access should be checked, otherwise view access. """ user = User.from_google_id(google_id) authorizations = list( - filter(lambda x: str(x['simulationId']) == str(self.obj['simulationId']), user.obj['authorizations'])) + filter(lambda x: str(x['projectId']) == str(self.obj['projectId']), user.obj['authorizations'])) if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'): raise ClientError(Response(403, 'Forbidden from retrieving/editing experiment.')) diff --git a/web-server/opendc/models/prefab.py b/web-server/opendc/models/prefab.py index ca9f0b3a..42c29697 100644 --- a/web-server/opendc/models/prefab.py +++ b/web-server/opendc/models/prefab.py @@ -6,7 +6,7 @@ from opendc.util.rest import Response class Prefab(Model): - """Model representing a Simulation.""" + """Model representing a Project.""" collection_name = 'prefabs' @@ -22,7 +22,7 @@ class Prefab(Model): raise ClientError(Response(403, "Forbidden from retrieving prefab.")) def get_all_authorizations(self): - """Get all user IDs having access to this simulation.""" + """Get all user IDs having access to this project.""" return [ str(user['_id']) for user in DB.fetch_all({'authorizations': { 'prefabId': self.obj['_id'] diff --git a/web-server/opendc/models/simulation.py b/web-server/opendc/models/project.py index 9a2770cf..b57e9f77 100644 --- a/web-server/opendc/models/simulation.py +++ b/web-server/opendc/models/project.py @@ -5,10 +5,10 @@ from opendc.util.exceptions import ClientError from opendc.util.rest import Response -class Simulation(Model): - """Model representing a Simulation.""" +class Project(Model): + """Model representing a Project.""" - collection_name = 'simulations' + collection_name = 'projects' def check_user_access(self, google_id, edit_access): """Raises an error if the user with given [google_id] has insufficient access. @@ -17,15 +17,15 @@ class Simulation(Model): :param edit_access: True when edit access should be checked, otherwise view access. """ user = User.from_google_id(google_id) - authorizations = list(filter(lambda x: str(x['simulationId']) == str(self.get_id()), + authorizations = list(filter(lambda x: str(x['projectId']) == str(self.get_id()), user.obj['authorizations'])) if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'): - raise ClientError(Response(403, "Forbidden from retrieving simulation.")) + raise ClientError(Response(403, "Forbidden from retrieving project.")) def get_all_authorizations(self): - """Get all user IDs having access to this simulation.""" + """Get all user IDs having access to this project.""" return [ str(user['_id']) for user in DB.fetch_all({'authorizations': { - 'simulationId': self.obj['_id'] + 'projectId': self.obj['_id'] }}, User.collection_name) ] diff --git a/web-server/opendc/models/topology.py b/web-server/opendc/models/topology.py index 0ceecec5..cb4c4bab 100644 --- a/web-server/opendc/models/topology.py +++ b/web-server/opendc/models/topology.py @@ -5,23 +5,23 @@ from opendc.util.rest import Response class Topology(Model): - """Model representing a Simulation.""" + """Model representing a Project.""" collection_name = 'topologies' def check_user_access(self, google_id, edit_access): """Raises an error if the user with given [google_id] has insufficient access. - Checks access on the parent simulation. + Checks access on the parent project. :param google_id: The Google ID of the user. :param edit_access: True when edit access should be checked, otherwise view access. """ user = User.from_google_id(google_id) - if 'simulationId' not in self.obj: - raise ClientError(Response(400, 'Missing simulationId in topology.')) + if 'projectId' not in self.obj: + raise ClientError(Response(400, 'Missing projectId in topology.')) authorizations = list( - filter(lambda x: str(x['simulationId']) == str(self.obj['simulationId']), user.obj['authorizations'])) + filter(lambda x: str(x['projectId']) == str(self.obj['projectId']), user.obj['authorizations'])) if len(authorizations) == 0 or (edit_access and authorizations[0]['authorizationLevel'] == 'VIEW'): raise ClientError(Response(403, 'Forbidden from retrieving topology.')) |
