summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/frontend.yml21
-rw-r--r--.github/workflows/web-server.yml26
-rw-r--r--.gitignore2
-rw-r--r--database/Dockerfile (renamed from mongodb/Dockerfile)0
-rw-r--r--database/mongo-init-opendc-db.sh (renamed from mongodb/mongo-init-opendc-db.sh)5
-rwxr-xr-xdatabase/prefab.py (renamed from mongodb/prefab.py)0
-rwxr-xr-xdatabase/prefabs.py (renamed from mongodb/prefabs.py)0
-rw-r--r--docker-compose.yml2
-rw-r--r--frontend/README.md2
-rw-r--r--frontend/package.json2
-rw-r--r--frontend/public/index.html90
-rw-r--r--frontend/src/actions/experiments.js12
-rw-r--r--frontend/src/actions/modals/projects.js14
-rw-r--r--frontend/src/actions/modals/simulations.js14
-rw-r--r--frontend/src/actions/modals/topology.js12
-rw-r--r--frontend/src/actions/projects.js52
-rw-r--r--frontend/src/actions/simulation/load-metric.js8
-rw-r--r--frontend/src/actions/simulation/playback.js15
-rw-r--r--frontend/src/actions/simulation/tick.js25
-rw-r--r--frontend/src/actions/simulations.js52
-rw-r--r--frontend/src/actions/states.js9
-rw-r--r--frontend/src/api/routes/experiments.js20
-rw-r--r--frontend/src/api/routes/projects.js (renamed from frontend/src/api/routes/simulations.js)28
-rw-r--r--frontend/src/api/routes/topologies.js4
-rw-r--r--frontend/src/auth/index.js2
-rw-r--r--frontend/src/components/app/map/LoadingScreen.js2
-rw-r--r--frontend/src/components/app/map/groups/RackGroup.js12
-rw-r--r--frontend/src/components/app/map/groups/TileGroup.js5
-rw-r--r--frontend/src/components/app/sidebars/elements/LoadBarComponent.js22
-rw-r--r--frontend/src/components/app/sidebars/project/ProjectSidebarComponent.js12
-rw-r--r--frontend/src/components/app/sidebars/project/TopologyListComponent.js63
-rw-r--r--frontend/src/components/app/sidebars/simulation/ExperimentMetadataComponent.js23
-rw-r--r--frontend/src/components/app/sidebars/simulation/LoadMetricComponent.js35
-rw-r--r--frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.js18
-rw-r--r--frontend/src/components/app/sidebars/simulation/SimulationSidebarComponent.sass8
-rw-r--r--frontend/src/components/app/sidebars/topology/building/BuildingSidebarComponent.js11
-rw-r--r--frontend/src/components/app/sidebars/topology/machine/MachineSidebarComponent.js13
-rw-r--r--frontend/src/components/app/sidebars/topology/machine/UnitComponent.js12
-rw-r--r--frontend/src/components/app/sidebars/topology/machine/UnitListComponent.js12
-rw-r--r--frontend/src/components/app/sidebars/topology/machine/UnitTabsComponent.js10
-rw-r--r--frontend/src/components/app/sidebars/topology/rack/EmptySlotComponent.js14
-rw-r--r--frontend/src/components/app/sidebars/topology/rack/MachineComponent.js9
-rw-r--r--frontend/src/components/app/sidebars/topology/rack/RackSidebarComponent.js15
-rw-r--r--frontend/src/components/app/sidebars/topology/room/RoomSidebarComponent.js19
-rw-r--r--frontend/src/components/app/timeline/PlayButtonComponent.js30
-rw-r--r--frontend/src/components/app/timeline/Timeline.sass116
-rw-r--r--frontend/src/components/app/timeline/TimelineComponent.js37
-rw-r--r--frontend/src/components/app/timeline/TimelineControlsComponent.js36
-rw-r--r--frontend/src/components/app/timeline/TimelineLabelsComponent.js15
-rw-r--r--frontend/src/components/experiments/ExperimentRowComponent.js6
-rw-r--r--frontend/src/components/home/TechnologiesSection.js2
-rw-r--r--frontend/src/components/modals/custom-components/NewTopologyModalComponent.js (renamed from frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js)45
-rw-r--r--frontend/src/components/navigation/AppNavbar.js54
-rw-r--r--frontend/src/components/navigation/AppNavbarComponent.js27
-rw-r--r--frontend/src/components/navigation/HomeNavbar.js2
-rw-r--r--frontend/src/components/navigation/Navbar.js6
-rw-r--r--frontend/src/components/projects/FilterButton.js (renamed from frontend/src/components/simulations/FilterButton.js)0
-rw-r--r--frontend/src/components/projects/FilterPanel.js (renamed from frontend/src/components/simulations/FilterPanel.js)6
-rw-r--r--frontend/src/components/projects/FilterPanel.sass (renamed from frontend/src/components/simulations/FilterPanel.sass)0
-rw-r--r--frontend/src/components/projects/NewProjectButtonComponent.js (renamed from frontend/src/components/simulations/NewSimulationButtonComponent.js)8
-rw-r--r--frontend/src/components/projects/ProjectActionButtons.js (renamed from frontend/src/components/simulations/SimulationActionButtons.js)18
-rw-r--r--frontend/src/components/projects/ProjectAuthList.js (renamed from frontend/src/components/simulations/SimulationAuthList.js)20
-rw-r--r--frontend/src/components/projects/ProjectAuthRow.js32
-rw-r--r--frontend/src/components/simulations/SimulationAuthRow.js32
-rw-r--r--frontend/src/containers/app/map/RackContainer.js20
-rw-r--r--frontend/src/containers/app/map/TileContainer.js17
-rw-r--r--frontend/src/containers/app/sidebars/elements/LoadBarContainer.js32
-rw-r--r--frontend/src/containers/app/sidebars/elements/LoadChartContainer.js16
-rw-r--r--frontend/src/containers/app/sidebars/project/ProjectSidebarContainer.js5
-rw-r--r--frontend/src/containers/app/sidebars/project/TopologyListContainer.js46
-rw-r--r--frontend/src/containers/app/sidebars/simulation/ExperimentMetadataContainer.js38
-rw-r--r--frontend/src/containers/app/sidebars/simulation/LoadMetricContainer.js12
-rw-r--r--frontend/src/containers/app/sidebars/topology/TopologySidebarContainer.js (renamed from frontend/src/containers/app/sidebars/topology/TopologySidebar.js)4
-rw-r--r--frontend/src/containers/app/sidebars/topology/building/BuildingSidebarContainer.js11
-rw-r--r--frontend/src/containers/app/sidebars/topology/machine/MachineSidebarContainer.js1
-rw-r--r--frontend/src/containers/app/sidebars/topology/machine/UnitContainer.js1
-rw-r--r--frontend/src/containers/app/sidebars/topology/machine/UnitListContainer.js3
-rw-r--r--frontend/src/containers/app/sidebars/topology/machine/UnitTabsContainer.js9
-rw-r--r--frontend/src/containers/app/sidebars/topology/rack/EmptySlotContainer.js8
-rw-r--r--frontend/src/containers/app/sidebars/topology/rack/MachineContainer.js21
-rw-r--r--frontend/src/containers/app/sidebars/topology/rack/RackNameContainer.js2
-rw-r--r--frontend/src/containers/app/sidebars/topology/rack/RackSidebarContainer.js1
-rw-r--r--frontend/src/containers/app/sidebars/topology/room/RoomSidebarContainer.js1
-rw-r--r--frontend/src/containers/app/timeline/PlayButtonContainer.js24
-rw-r--r--frontend/src/containers/app/timeline/TimelineContainer.js26
-rw-r--r--frontend/src/containers/app/timeline/TimelineControlsContainer.js22
-rw-r--r--frontend/src/containers/app/timeline/TimelineLabelsContainer.js15
-rw-r--r--frontend/src/containers/experiments/ExperimentListContainer.js6
-rw-r--r--frontend/src/containers/experiments/ExperimentRowContainer.js2
-rw-r--r--frontend/src/containers/modals/ChangeTopologyModal.js64
-rw-r--r--frontend/src/containers/modals/EditRackNameModal.js2
-rw-r--r--frontend/src/containers/modals/NewExperimentModal.js2
-rw-r--r--frontend/src/containers/modals/NewProjectModal.js37
-rw-r--r--frontend/src/containers/modals/NewSimulationModal.js37
-rw-r--r--frontend/src/containers/modals/NewTopologyModal.js49
-rw-r--r--frontend/src/containers/navigation/AppNavbarContainer.js12
-rw-r--r--frontend/src/containers/projects/FilterLink.js (renamed from frontend/src/containers/simulations/FilterLink.js)6
-rw-r--r--frontend/src/containers/projects/NewProjectButtonContainer.js15
-rw-r--r--frontend/src/containers/projects/ProjectActions.js23
-rw-r--r--frontend/src/containers/projects/VisibleProjectAuthList.js42
-rw-r--r--frontend/src/containers/simulations/NewSimulationButtonContainer.js15
-rw-r--r--frontend/src/containers/simulations/SimulationActions.js23
-rw-r--r--frontend/src/containers/simulations/VisibleSimulationAuthList.js42
-rw-r--r--frontend/src/pages/App.js75
-rw-r--r--frontend/src/pages/Experiments.js65
-rw-r--r--frontend/src/pages/Home.js22
-rw-r--r--frontend/src/pages/NotFound.js2
-rw-r--r--frontend/src/pages/Profile.js8
-rw-r--r--frontend/src/pages/Projects.js43
-rw-r--r--frontend/src/pages/Simulations.js43
-rw-r--r--frontend/src/reducers/construction-mode.js3
-rw-r--r--frontend/src/reducers/current-ids.js8
-rw-r--r--frontend/src/reducers/index.js16
-rw-r--r--frontend/src/reducers/interaction-level.js4
-rw-r--r--frontend/src/reducers/modals.js12
-rw-r--r--frontend/src/reducers/objects.js4
-rw-r--r--frontend/src/reducers/project-list.js (renamed from frontend/src/reducers/simulation-list.js)12
-rw-r--r--frontend/src/reducers/simulation-mode.js58
-rw-r--r--frontend/src/reducers/states.js32
-rw-r--r--frontend/src/routes/index.js29
-rw-r--r--frontend/src/sagas/experiments.js82
-rw-r--r--frontend/src/sagas/index.js16
-rw-r--r--frontend/src/sagas/objects.js38
-rw-r--r--frontend/src/sagas/projects.js43
-rw-r--r--frontend/src/sagas/simulations.js43
-rw-r--r--frontend/src/sagas/topology.js38
-rw-r--r--frontend/src/sagas/users.js6
-rw-r--r--frontend/src/shapes/index.js8
-rw-r--r--frontend/src/util/date-time.test.js2
-rw-r--r--frontend/src/util/simulation-load.js32
-rw-r--r--opendc-api-spec.yml1879
-rw-r--r--simulator/odcsim/README.md2
-rw-r--r--web-server/README.md6
-rw-r--r--web-server/main.py10
-rw-r--r--web-server/opendc/api/v2/experiments/experimentId/endpoint.py21
-rw-r--r--web-server/opendc/api/v2/experiments/experimentId/test_endpoint.py62
-rw-r--r--web-server/opendc/api/v2/paths.json12
-rw-r--r--web-server/opendc/api/v2/projects/__init__.py (renamed from web-server/opendc/api/v2/simulations/__init__.py)0
-rw-r--r--web-server/opendc/api/v2/projects/endpoint.py32
-rw-r--r--web-server/opendc/api/v2/projects/projectId/__init__.py (renamed from web-server/opendc/api/v2/simulations/simulationId/__init__.py)0
-rw-r--r--web-server/opendc/api/v2/projects/projectId/authorizations/__init__.py (renamed from web-server/opendc/api/v2/simulations/simulationId/authorizations/__init__.py)0
-rw-r--r--web-server/opendc/api/v2/projects/projectId/authorizations/endpoint.py17
-rw-r--r--web-server/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py (renamed from web-server/opendc/api/v2/simulations/simulationId/authorizations/test_endpoint.py)10
-rw-r--r--web-server/opendc/api/v2/projects/projectId/endpoint.py66
-rw-r--r--web-server/opendc/api/v2/projects/projectId/experiments/__init__.py (renamed from web-server/opendc/api/v2/simulations/simulationId/experiments/__init__.py)0
-rw-r--r--web-server/opendc/api/v2/projects/projectId/experiments/endpoint.py (renamed from web-server/opendc/api/v2/simulations/simulationId/experiments/endpoint.py)18
-rw-r--r--web-server/opendc/api/v2/projects/projectId/experiments/test_endpoint.py (renamed from web-server/opendc/api/v2/simulations/simulationId/experiments/test_endpoint.py)18
-rw-r--r--web-server/opendc/api/v2/projects/projectId/test_endpoint.py (renamed from web-server/opendc/api/v2/simulations/simulationId/test_endpoint.py)56
-rw-r--r--web-server/opendc/api/v2/projects/projectId/topologies/__init__.py (renamed from web-server/opendc/api/v2/simulations/simulationId/topologies/__init__.py)0
-rw-r--r--web-server/opendc/api/v2/projects/projectId/topologies/endpoint.py31
-rw-r--r--web-server/opendc/api/v2/projects/projectId/topologies/test_endpoint.py (renamed from web-server/opendc/api/v2/simulations/simulationId/topologies/test_endpoint.py)15
-rw-r--r--web-server/opendc/api/v2/projects/test_endpoint.py (renamed from web-server/opendc/api/v2/simulations/test_endpoint.py)8
-rw-r--r--web-server/opendc/api/v2/simulations/endpoint.py32
-rw-r--r--web-server/opendc/api/v2/simulations/simulationId/authorizations/endpoint.py17
-rw-r--r--web-server/opendc/api/v2/simulations/simulationId/endpoint.py66
-rw-r--r--web-server/opendc/api/v2/simulations/simulationId/topologies/endpoint.py31
-rw-r--r--web-server/opendc/api/v2/topologies/topologyId/endpoint.py12
-rw-r--r--web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py35
-rw-r--r--web-server/opendc/api/v2/users/userId/endpoint.py6
-rw-r--r--web-server/opendc/models/experiment.py4
-rw-r--r--web-server/opendc/models/prefab.py7
-rw-r--r--web-server/opendc/models/project.py (renamed from web-server/opendc/models/simulation.py)14
-rw-r--r--web-server/opendc/models/topology.py10
163 files changed, 2095 insertions, 3082 deletions
diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml
new file mode 100644
index 00000000..494c0829
--- /dev/null
+++ b/.github/workflows/frontend.yml
@@ -0,0 +1,21 @@
+name: Frontend
+
+on: [push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Node.js
+ uses: actions/setup-node@v1
+ with:
+ node-version: 12.x
+ - run: npm install
+ working-directory: frontend
+ - run: npm run build --if-present
+ working-directory: frontend
+ - run: npm test
+ working-directory: frontend
+ env:
+ CI: true
diff --git a/.github/workflows/web-server.yml b/.github/workflows/web-server.yml
new file mode 100644
index 00000000..af843266
--- /dev/null
+++ b/.github/workflows/web-server.yml
@@ -0,0 +1,26 @@
+name: Web server
+
+on: [push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Install dependencies
+ working-directory: web-server
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ - name: Lint with pylint
+ working-directory: web-server
+ run: |
+ ./check.sh
+ - name: Test with pytest
+ working-directory: web-server
+ run: |
+ pytest opendc
diff --git a/.gitignore b/.gitignore
index fc1cd81f..3d504e99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,7 @@
# pyenv version files
.python-version
-mongodb/opendc_testing/*
+database/opendc_testing/*
# macOS-specific files
.DS_Store
diff --git a/mongodb/Dockerfile b/database/Dockerfile
index 12803f8e..12803f8e 100644
--- a/mongodb/Dockerfile
+++ b/database/Dockerfile
diff --git a/mongodb/mongo-init-opendc-db.sh b/database/mongo-init-opendc-db.sh
index cda4ec93..44fa75a3 100644
--- a/mongodb/mongo-init-opendc-db.sh
+++ b/database/mongo-init-opendc-db.sh
@@ -14,9 +14,10 @@ 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("portfolios");'
+$MONGO_CMD --eval 'db.createCollection("scenarios");'
$MONGO_CMD --eval 'db.createCollection("traces");'
$MONGO_CMD --eval 'db.createCollection("prefabs");'
diff --git a/mongodb/prefab.py b/database/prefab.py
index 124f45e3..124f45e3 100755
--- a/mongodb/prefab.py
+++ b/database/prefab.py
diff --git a/mongodb/prefabs.py b/database/prefabs.py
index f6f46cbc..f6f46cbc 100755
--- a/mongodb/prefabs.py
+++ b/database/prefabs.py
diff --git a/docker-compose.yml b/docker-compose.yml
index d3493e97..917312ea 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -47,7 +47,7 @@ services:
mongo:
build:
- context: ./mongodb
+ context: database
restart: on-failure
environment:
- MONGO_INITDB_ROOT_USERNAME
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/package.json b/frontend/package.json
index 2180f092..f5ade772 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -44,7 +44,7 @@
"redux-thunk": "~2.3.0",
"socket.io-client": "~2.3.0",
"svgsaver": "~0.9.0",
- "uuidv4": "^6.1.1",
+ "uuidv4": "~6.1.1",
"victory": "~34.2.1"
},
"lint-staged": {
diff --git a/frontend/public/index.html b/frontend/public/index.html
index e88cca42..0254eff4 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -1,59 +1,63 @@
<!doctype html>
<html lang="en">
<head>
- <meta charset="utf-8">
- <title>OpenDC</title>
+ <meta charset="utf-8">
+ <title>OpenDC</title>
- <!-- Standard meta tags -->
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- <meta name="theme-color" content="#00A6D6">
- <meta name="description" content="Collaborative Datacenter Simulation and Exploration for Everybody">
- <meta name="author" content="@Large Research">
- <meta name="keywords" content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster">
- <link rel="manifest" href="/manifest.json">
- <link rel="shortcut icon" href="/favicon.ico">
+ <!-- Standard meta tags -->
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+ <meta name="theme-color" content="#00A6D6">
+ <meta name="description" content="Collaborative Datacenter Simulation and Exploration for Everybody">
+ <meta name="author" content="@Large Research">
+ <meta name="keywords" content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster">
+ <link rel="manifest" href="/manifest.json">
+ <link rel="shortcut icon" href="/favicon.ico">
- <!-- Twitter Card data -->
- <meta name="twitter:card" content="summary">
- <meta name="twitter:site" content="@LargeResearch">
- <meta name="twitter:title" content="OpenDC">
- <meta name="twitter:description" content="Collaborative Datacenter Simulation and Exploration for Everybody">
- <meta name="twitter:creator" content="@LargeResearch">
- <meta name="twitter:image" content="http://opendc.org/img/logo.png">
+ <!-- Twitter Card data -->
+ <meta name="twitter:card" content="summary">
+ <meta name="twitter:site" content="@LargeResearch">
+ <meta name="twitter:title" content="OpenDC">
+ <meta name="twitter:description" content="Collaborative Datacenter Simulation and Exploration for Everybody">
+ <meta name="twitter:creator" content="@LargeResearch">
+ <meta name="twitter:image" content="http://opendc.org/img/logo.png">
- <!-- OpenGraph meta tags -->
- <meta property="og:title" content="OpenDC">
- <meta property="og:site_name" content="OpenDC">
- <meta property="og:type" content="website">
- <meta property="og:image" content="http://opendc.org/img/logo.png">
- <meta property="og:url" content="http://opendc.org/">
- <meta property="og:description"
- content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter
+ <!-- OpenGraph meta tags -->
+ <meta property="og:title" content="OpenDC">
+ <meta property="og:site_name" content="OpenDC">
+ <meta property="og:type" content="website">
+ <meta property="og:image" content="http://opendc.org/img/logo.png">
+ <meta property="og:url" content="http://opendc.org/">
+ <meta property="og:description"
+ content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter
simulation, and exploratory datacenter performance feedback.">
- <meta property="og:locale" content="en_US">
+ <meta property="og:locale" content="en_US">
- <!-- Google meta tags -->
- <meta name="google-signin-client_id" content="%REACT_APP_OAUTH_CLIENT_ID%">
- <meta name="google-site-verification" content="YIR4LkQTv6WmOdWv8MkeiUKni-0Yu3WHylLp4VvUMig"/>
+ <!-- Google meta tags -->
+ <meta name="google-signin-client_id" content="%REACT_APP_OAUTH_CLIENT_ID%">
+ <meta name="google-site-verification" content="YIR4LkQTv6WmOdWv8MkeiUKni-0Yu3WHylLp4VvUMig"/>
- <!-- CDN dependencies -->
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css"
- integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
- <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
- <script src="https://use.fontawesome.com/ece66a2e7c.js"></script>
+ <!-- CDN dependencies -->
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css"
+ integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
+ <script src="https://use.fontawesome.com/ece66a2e7c.js"></script>
- <!-- Google Analytics -->
- <script async src="https://www.googletagmanager.com/gtag/js?id=UA-84285092-3"></script>
- <script>
- window.dataLayer = window.dataLayer || [];
- function gtag() {dataLayer.push(arguments);}
- gtag('js', new Date());
- gtag('config', 'UA-84285092-3');
- </script>
+ <!-- Google Analytics -->
+ <script async src="https://www.googletagmanager.com/gtag/js?id=UA-84285092-3"></script>
+ <script>
+ window.dataLayer = window.dataLayer || []
+
+ function gtag() {
+ dataLayer.push(arguments)
+ }
+
+ gtag('js', new Date())
+ gtag('config', 'UA-84285092-3')
+ </script>
</head>
<body data-spy="scroll" data-target="#navbar">
<noscript>
- You need to enable JavaScript to run this app.
+ You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
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/modals/topology.js b/frontend/src/actions/modals/topology.js
index 7b74e820..b5fecac1 100644
--- a/frontend/src/actions/modals/topology.js
+++ b/frontend/src/actions/modals/topology.js
@@ -1,5 +1,5 @@
-export const OPEN_CHANGE_TOPOLOGY_MODAL = 'OPEN_CHANGE_TOPOLOGY_MODAL'
-export const CLOSE_CHANGE_TOPOLOGY_MODAL = 'CLOSE_CHANGE_TOPOLOGY_MODAL'
+export const OPEN_NEW_TOPOLOGY_MODAL = 'OPEN_NEW_TOPOLOGY_MODAL'
+export const CLOSE_NEW_TOPOLOGY_MODAL = 'CLOSE_NEW_TOPOLOGY_MODAL'
export const OPEN_EDIT_ROOM_NAME_MODAL = 'OPEN_EDIT_ROOM_NAME_MODAL'
export const CLOSE_EDIT_ROOM_NAME_MODAL = 'CLOSE_EDIT_ROOM_NAME_MODAL'
export const OPEN_DELETE_ROOM_MODAL = 'OPEN_DELETE_ROOM_MODAL'
@@ -11,15 +11,15 @@ export const CLOSE_DELETE_RACK_MODAL = 'CLOSE_DELETE_RACK_MODAL'
export const OPEN_DELETE_MACHINE_MODAL = 'OPEN_DELETE_MACHINE_MODAL'
export const CLOSE_DELETE_MACHINE_MODAL = 'CLOSE_DELETE_MACHINE_MODAL'
-export function openChangeTopologyModal() {
+export function openNewTopologyModal() {
return {
- type: OPEN_CHANGE_TOPOLOGY_MODAL,
+ type: OPEN_NEW_TOPOLOGY_MODAL,
}
}
-export function closeChangeTopologyModal() {
+export function closeNewTopologyModal() {
return {
- type: CLOSE_CHANGE_TOPOLOGY_MODAL,
+ type: CLOSE_NEW_TOPOLOGY_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/LoadingScreen.js b/frontend/src/components/app/map/LoadingScreen.js
index 1fd470fc..03daa692 100644
--- a/frontend/src/components/app/map/LoadingScreen.js
+++ b/frontend/src/components/app/map/LoadingScreen.js
@@ -4,7 +4,7 @@ import FontAwesome from 'react-fontawesome'
const LoadingScreen = () => (
<div className="display-4">
<FontAwesome name="refresh" className="mr-4" spin/>
- Loading your topology...
+ Loading your project...
</div>
)
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/project/ProjectSidebarComponent.js b/frontend/src/components/app/sidebars/project/ProjectSidebarComponent.js
new file mode 100644
index 00000000..d6e39ff6
--- /dev/null
+++ b/frontend/src/components/app/sidebars/project/ProjectSidebarComponent.js
@@ -0,0 +1,12 @@
+import React from 'react'
+import Sidebar from '../Sidebar'
+import TopologyListContainer from '../../../../containers/app/sidebars/project/TopologyListContainer'
+
+const ProjectSidebarComponent = () => (
+ <Sidebar isRight={false}>
+ <TopologyListContainer/>
+ <h2>Portfolios</h2>
+ </Sidebar>
+ )
+
+export default ProjectSidebarComponent
diff --git a/frontend/src/components/app/sidebars/project/TopologyListComponent.js b/frontend/src/components/app/sidebars/project/TopologyListComponent.js
new file mode 100644
index 00000000..98615711
--- /dev/null
+++ b/frontend/src/components/app/sidebars/project/TopologyListComponent.js
@@ -0,0 +1,63 @@
+import PropTypes from 'prop-types'
+import React from 'react'
+import Shapes from '../../../../shapes'
+import FontAwesome from 'react-fontawesome'
+
+class TopologyListComponent extends React.Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ topologies: PropTypes.arrayOf(Shapes.Topology),
+ currentTopologyId: PropTypes.string,
+ onChooseTopology: PropTypes.func.isRequired,
+ onNewTopology: PropTypes.func.isRequired,
+ onDeleteTopology: PropTypes.func.isRequired,
+ }
+
+ onChoose(id) {
+ this.props.onChooseTopology(id)
+ }
+
+ onDuplicate() {
+ this.props.onNewTopology(
+ this.textInput.value,
+ this.originTopology.value,
+ )
+ }
+
+ onDelete(id) {
+ this.props.onDeleteTopology(id)
+ }
+
+ render() {
+ return (
+ <div className="pb-3">
+ <h2>
+ Topologies
+ <button className="btn btn-outline-primary float-right" onClick={this.props.onNewTopology}>
+ <FontAwesome name="plus"/>
+ </button>
+ </h2>
+
+ {this.props.topologies.map((topology, idx) => (
+ <div key={topology._id} className="row mb-1">
+ <div className={'col-8 align-self-center ' + (topology._id === this.props.currentTopologyId ? 'font-weight-bold' : '')}>
+ {topology.name}
+ </div>
+ <div className="col-4 text-right">
+ <span
+ className="btn btn-outline-primary mr-1 fa fa-play"
+ onClick={() => this.onChoose(topology._id)}
+ />
+ <span
+ className={'btn btn-outline-danger fa fa-trash ' + (idx === 0 ? 'disabled' : '')}
+ onClick={() => idx !== 0 ? this.onDelete(topology._id) : undefined}
+ />
+ </div>
+ </div>
+ ))}
+ </div>
+ )
+ }
+}
+
+export default TopologyListComponent
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/modals/custom-components/ChangeTopologyModalComponent.js b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
index 22ef4585..a0d736a1 100644
--- a/frontend/src/components/modals/custom-components/ChangeTopologyModalComponent.js
+++ b/frontend/src/components/modals/custom-components/NewTopologyModalComponent.js
@@ -3,15 +3,12 @@ import React from 'react'
import Shapes from '../../../shapes'
import Modal from '../Modal'
-class ChangeTopologyModalComponent extends React.Component {
+class NewTopologyModalComponent extends React.Component {
static propTypes = {
show: PropTypes.bool.isRequired,
topologies: PropTypes.arrayOf(Shapes.Topology),
- currentTopologyId: PropTypes.string,
- onChooseTopology: PropTypes.func.isRequired,
onCreateTopology: PropTypes.func.isRequired,
onDuplicateTopology: PropTypes.func.isRequired,
- onDeleteTopology: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
}
@@ -28,11 +25,6 @@ class ChangeTopologyModalComponent extends React.Component {
}
}
- onChoose(id) {
- this.props.onChooseTopology(id)
- this.reset()
- }
-
onCreate() {
this.props.onCreateTopology(this.textInput.value)
this.reset()
@@ -46,11 +38,6 @@ class ChangeTopologyModalComponent extends React.Component {
this.reset()
}
- onDelete(id) {
- this.props.onDeleteTopology(id)
- this.reset()
- }
-
onCancel() {
this.props.onCancel()
this.reset()
@@ -59,37 +46,11 @@ class ChangeTopologyModalComponent extends React.Component {
render() {
return (
<Modal
- title="Change Topology"
+ title="New Topology"
show={this.props.show}
onSubmit={this.onSubmit.bind(this)}
onCancel={this.onCancel.bind(this)}
>
- <div>
- {this.props.topologies.map((topology, idx) => (
- <div key={topology._id} className="row mb-1">
- <div className="col-6">
- <em>{topology._id === this.props.currentTopologyId ? 'Active: ' : ''}</em>
- {topology.name}
- </div>
- <div className="col-6 text-right">
- <span
- className="btn btn-primary mr-1"
- onClick={() => this.onChoose(topology._id)}
- >
- Choose
- </span>
- <span
- className={'btn btn-danger ' + (idx === 0 ? 'disabled' : '')}
- onClick={() => idx !== 0 ? this.onDelete(topology._id) : undefined}
- >
- Delete
- </span>
- </div>
- </div>
- ))}
- </div>
-
- <h5 className="pt-3 pt-1">New Topology</h5>
<form
onSubmit={e => {
e.preventDefault()
@@ -128,4 +89,4 @@ class ChangeTopologyModalComponent extends React.Component {
}
}
-export default ChangeTopologyModalComponent
+export default NewTopologyModalComponent
diff --git a/frontend/src/components/navigation/AppNavbar.js b/frontend/src/components/navigation/AppNavbar.js
deleted file mode 100644
index 15f08b5f..00000000
--- a/frontend/src/components/navigation/AppNavbar.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from 'react'
-import FontAwesome from 'react-fontawesome'
-import { Link } from 'react-router-dom'
-import Navbar, { NavItem } from './Navbar'
-import './Navbar.css'
-
-const AppNavbar = ({ simulationId, inSimulation, fullWidth, onViewTopologies }) => (
- <Navbar fullWidth={fullWidth}>
- <NavItem route="/simulations">
- <Link className="nav-link" title="My Simulations" to="/simulations">
- <FontAwesome name="list" className="mr-2"/>
- My Simulations
- </Link>
- </NavItem>
- {inSimulation ? (
- <>
- <NavItem route={'/simulations/' + simulationId}>
- <Link
- className="nav-link"
- title="Construction"
- to={'/simulations/' + simulationId}
- >
- <FontAwesome name="industry" className="mr-2"/>
- Construction
- </Link>
- </NavItem>
- <NavItem route="topologies">
- <span
- className="nav-link"
- title="Topologies"
- onClick={onViewTopologies}
- >
- <FontAwesome name="server" className="mr-2"/>
- Topologies
- </span>
- </NavItem>
- <NavItem route={'/simulations/' + simulationId + '/experiments'}>
- <Link
- className="nav-link"
- title="Experiments"
- to={'/simulations/' + simulationId + '/experiments'}
- >
- <FontAwesome name="play" className="mr-2"/>
- Experiments
- </Link>
- </NavItem>
- </>
- ) : (
- undefined
- )}
- </Navbar>
-)
-
-export default AppNavbar
diff --git a/frontend/src/components/navigation/AppNavbarComponent.js b/frontend/src/components/navigation/AppNavbarComponent.js
new file mode 100644
index 00000000..10a2b92c
--- /dev/null
+++ b/frontend/src/components/navigation/AppNavbarComponent.js
@@ -0,0 +1,27 @@
+import React from 'react'
+import FontAwesome from 'react-fontawesome'
+import { Link } from 'react-router-dom'
+import Navbar, { NavItem } from './Navbar'
+import './Navbar.css'
+
+const AppNavbarComponent = ({ project, fullWidth }) => (
+ <Navbar fullWidth={fullWidth}>
+ <NavItem route="/projects">
+ <Link className="nav-link" title="My Projects" to="/projects">
+ <FontAwesome name="list" className="mr-2"/>
+ My Projects
+ </Link>
+ </NavItem>
+ {project ? (
+ <NavItem>
+ <Link className="nav-link" title="Current Project" to={`/projects/${project._id}`}>
+ <span>{project.name}</span>
+ </Link>
+ </NavItem>
+ ) : (
+ undefined
+ )}
+ </Navbar>
+)
+
+export default AppNavbarComponent
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/project/ProjectSidebarContainer.js b/frontend/src/containers/app/sidebars/project/ProjectSidebarContainer.js
new file mode 100644
index 00000000..ced0b18b
--- /dev/null
+++ b/frontend/src/containers/app/sidebars/project/ProjectSidebarContainer.js
@@ -0,0 +1,5 @@
+import ProjectSidebarComponent from '../../../../components/app/sidebars/project/ProjectSidebarComponent'
+
+const ProjectSidebarContainer = ProjectSidebarComponent
+
+export default ProjectSidebarContainer
diff --git a/frontend/src/containers/app/sidebars/project/TopologyListContainer.js b/frontend/src/containers/app/sidebars/project/TopologyListContainer.js
new file mode 100644
index 00000000..cab47c8d
--- /dev/null
+++ b/frontend/src/containers/app/sidebars/project/TopologyListContainer.js
@@ -0,0 +1,46 @@
+import { connect } from 'react-redux'
+import TopologyListComponent from '../../../../components/app/sidebars/project/TopologyListComponent'
+import { setCurrentTopology } from '../../../../actions/topology/building'
+import { openNewTopologyModal } from '../../../../actions/modals/topology'
+import { deleteTopology } from '../../../../actions/topologies'
+
+const mapStateToProps = state => {
+ 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) {
+ topologies = []
+ }
+
+ return {
+ show: state.modals.changeTopologyModalVisible,
+ currentTopologyId: state.currentTopologyId,
+ topologies,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onChooseTopology: (id) => {
+ dispatch(
+ setCurrentTopology(id),
+ )
+ },
+ onNewTopology: () => {
+ dispatch(openNewTopologyModal())
+ },
+ onDeleteTopology: (id) => {
+ if (id) {
+ dispatch(
+ deleteTopology(id),
+ )
+ }
+ },
+ }
+}
+
+const TopologyListContainer = connect(mapStateToProps, mapDispatchToProps)(
+ TopologyListComponent,
+)
+
+export default TopologyListContainer
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/TopologySidebar.js b/frontend/src/containers/app/sidebars/topology/TopologySidebarContainer.js
index 8e929d3d..f9bc10bf 100644
--- a/frontend/src/containers/app/sidebars/topology/TopologySidebar.js
+++ b/frontend/src/containers/app/sidebars/topology/TopologySidebarContainer.js
@@ -7,6 +7,6 @@ const mapStateToProps = state => {
}
}
-const TopologySidebar = connect(mapStateToProps)(TopologySidebarComponent)
+const TopologySidebarContainer = connect(mapStateToProps)(TopologySidebarComponent)
-export default TopologySidebar
+export default TopologySidebarContainer
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
deleted file mode 100644
index a1db9032..00000000
--- a/frontend/src/containers/modals/ChangeTopologyModal.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import { connect } from 'react-redux'
-import ChangeTopologyModalComponent from '../../components/modals/custom-components/ChangeTopologyModalComponent'
-import { closeChangeTopologyModal } from '../../actions/modals/topology'
-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 => (
- state.objects.topology[t]
- )) : []
- if (topologies.filter(t => !t).length > 0) {
- topologies = []
- }
-
- return {
- show: state.modals.changeTopologyModalVisible,
- currentTopologyId: state.currentTopologyId,
- topologies,
- }
-}
-
-const mapDispatchToProps = dispatch => {
- return {
- onChooseTopology: (id) => {
- dispatch(
- setCurrentTopology(id)
- )
- dispatch(closeChangeTopologyModal())
- },
- onCreateTopology: (name) => {
- if (name) {
- dispatch(
- addTopology({name, rooms: []})
- )
- }
- dispatch(closeChangeTopologyModal())
- },
- onDuplicateTopology: (name) => {
- if (name) {
- // TODO different handling here
- dispatch(
- addTopology({name, rooms: []})
- )
- }
- dispatch(closeChangeTopologyModal())
- },
- onDeleteTopology: (id) => {
- if (id) {
- dispatch(
- deleteTopology(id)
- )
- }
- },
- onCancel: () => {
- dispatch(closeChangeTopologyModal())
- },
- }
-}
-
-const ChangeTopologyModal = connect(mapStateToProps, mapDispatchToProps)(
- ChangeTopologyModalComponent,
-)
-
-export default ChangeTopologyModal
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/modals/NewTopologyModal.js b/frontend/src/containers/modals/NewTopologyModal.js
new file mode 100644
index 00000000..282f0db9
--- /dev/null
+++ b/frontend/src/containers/modals/NewTopologyModal.js
@@ -0,0 +1,49 @@
+import { connect } from 'react-redux'
+import NewTopologyModalComponent from '../../components/modals/custom-components/NewTopologyModalComponent'
+import { closeNewTopologyModal } from '../../actions/modals/topology'
+import { addTopology } from '../../actions/topologies'
+
+const mapStateToProps = state => {
+ 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) {
+ topologies = []
+ }
+
+ return {
+ show: state.modals.changeTopologyModalVisible,
+ topologies,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onCreateTopology: (name) => {
+ if (name) {
+ dispatch(
+ addTopology({ name, rooms: [] }),
+ )
+ }
+ dispatch(closeNewTopologyModal())
+ },
+ onDuplicateTopology: (name) => {
+ if (name) {
+ // TODO different handling here
+ dispatch(
+ addTopology({ name, rooms: [] }),
+ )
+ }
+ dispatch(closeNewTopologyModal())
+ },
+ onCancel: () => {
+ dispatch(closeNewTopologyModal())
+ },
+ }
+}
+
+const NewTopologyModal = connect(mapStateToProps, mapDispatchToProps)(
+ NewTopologyModalComponent,
+)
+
+export default NewTopologyModal
diff --git a/frontend/src/containers/navigation/AppNavbarContainer.js b/frontend/src/containers/navigation/AppNavbarContainer.js
new file mode 100644
index 00000000..bba44d77
--- /dev/null
+++ b/frontend/src/containers/navigation/AppNavbarContainer.js
@@ -0,0 +1,12 @@
+import { connect } from 'react-redux'
+import AppNavbarComponent from '../../components/navigation/AppNavbarComponent'
+
+const mapStateToProps = state => {
+ return {
+ project: state.currentProjectId !== '-1' ? state.objects.project[state.currentProjectId] : undefined,
+ }
+}
+
+const AppNavbarContainer = connect(mapStateToProps)(AppNavbarComponent)
+
+export default AppNavbarContainer
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..8f99d1bd 100644
--- a/frontend/src/pages/App.js
+++ b/frontend/src/pages/App.js
@@ -4,33 +4,31 @@ 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 TopologySidebarContainer from '../containers/app/sidebars/topology/TopologySidebarContainer'
import DeleteMachineModal from '../containers/modals/DeleteMachineModal'
import DeleteRackModal from '../containers/modals/DeleteRackModal'
import DeleteRoomModal from '../containers/modals/DeleteRoomModal'
import EditRackNameModal from '../containers/modals/EditRackNameModal'
import EditRoomNameModal from '../containers/modals/EditRoomNameModal'
import KeymapConfiguration from '../shortcuts/keymap'
-import ChangeTopologyModal from '../containers/modals/ChangeTopologyModal'
-import { openChangeTopologyModal } from '../actions/modals/topology'
+import NewTopologyModal from '../containers/modals/NewTopologyModal'
+import { openNewTopologyModal } from '../actions/modals/topology'
+import AppNavbarContainer from '../containers/navigation/AppNavbarContainer'
+import ProjectSidebarContainer from '../containers/app/sidebars/project/ProjectSidebarContainer'
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 +36,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 +48,29 @@ 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}
- fullWidth={true}
- onViewTopologies={this.props.onViewTopologies}
- />
+ <AppNavbarContainer fullWidth={true} />
{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/>
+ <ProjectSidebarContainer/>
+ <TopologySidebarContainer/>
</div>
)}
- <ChangeTopologyModal />
- <EditRoomNameModal />
- <DeleteRoomModal />
- <EditRackNameModal />
- <DeleteRackModal />
- <DeleteMachineModal />
+ <NewTopologyModal/>
+ <EditRoomNameModal/>
+ <DeleteRoomModal/>
+ <EditRackNameModal/>
+ <DeleteRackModal/>
+ <DeleteMachineModal/>
</div>
</DocumentTitle>
)
@@ -91,24 +78,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)),
- onViewTopologies: () => dispatch(openChangeTopologyModal()),
- openExperimentSucceeded: (simulationId, experimentId) =>
- dispatch(openExperimentSucceeded(simulationId, experimentId)),
+ openProjectSucceeded: (id) => dispatch(openProjectSucceeded(id)),
+ onViewTopologies: () => dispatch(openNewTopologyModal()),
+ openExperimentSucceeded: (projectId, experimentId) =>
+ dispatch(openExperimentSucceeded(projectId, experimentId)),
}
}
diff --git a/frontend/src/pages/Experiments.js b/frontend/src/pages/Experiments.js
deleted file mode 100644
index 43bd15be..00000000
--- a/frontend/src/pages/Experiments.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import DocumentTitle from 'react-document-title'
-import { connect } from 'react-redux'
-import { fetchExperimentsOfSimulation } from '../actions/experiments'
-import { openSimulationSucceeded } from '../actions/simulations'
-import AppNavbar from '../components/navigation/AppNavbar'
-import ExperimentListContainer from '../containers/experiments/ExperimentListContainer'
-import NewExperimentButtonContainer from '../containers/experiments/NewExperimentButtonContainer'
-import NewExperimentModal from '../containers/modals/NewExperimentModal'
-
-class ExperimentsComponent extends React.Component {
- static propTypes = {
- simulationId: PropTypes.string.isRequired,
- simulationName: PropTypes.string,
- }
-
- componentDidMount() {
- this.props.storeSimulationId(this.props.simulationId)
- this.props.fetchExperimentsOfSimulation(this.props.simulationId)
- }
-
- render() {
- return (
- <DocumentTitle
- title={
- this.props.simulationName
- ? 'Experiments - ' + this.props.simulationName + ' - OpenDC'
- : 'Experiments - OpenDC'
- }
- >
- <div className="full-height">
- <AppNavbar simulationId={this.props.simulationId} inSimulation={true} fullWidth={true} />
- <div className="container text-page-container full-height">
- <ExperimentListContainer />
- <NewExperimentButtonContainer />
- </div>
- <NewExperimentModal />
- </div>
- </DocumentTitle>
- )
- }
-}
-
-const mapStateToProps = (state) => {
- let simulationName = undefined
- if (state.currentSimulationId !== '-1' && state.objects.simulation[state.currentSimulationId]) {
- simulationName = state.objects.simulation[state.currentSimulationId].name
- }
-
- return {
- simulationName,
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- storeSimulationId: (id) => dispatch(openSimulationSucceeded(id)),
- fetchExperimentsOfSimulation: (id) => dispatch(fetchExperimentsOfSimulation(id)),
- }
-}
-
-const Experiments = connect(mapStateToProps, mapDispatchToProps)(ExperimentsComponent)
-
-export default Experiments
diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js
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..527dc721 100644
--- a/frontend/src/pages/Profile.js
+++ b/frontend/src/pages/Profile.js
@@ -2,24 +2,24 @@ import React from 'react'
import DocumentTitle from 'react-document-title'
import { connect } from 'react-redux'
import { openDeleteProfileModal } from '../actions/modals/profile'
-import AppNavbar from '../components/navigation/AppNavbar'
import DeleteProfileModal from '../containers/modals/DeleteProfileModal'
+import AppNavbarContainer from '../containers/navigation/AppNavbarContainer'
const ProfileContainer = ({ onDelete }) => (
<DocumentTitle title="My Profile - OpenDC">
<div className="full-height">
- <AppNavbar inSimulation={false} fullWidth={false} />
+ <AppNavbarContainer 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..f4af10c3
--- /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 ProjectFilterPanel from '../components/projects/FilterPanel'
+import NewProjectModal from '../containers/modals/NewProjectModal'
+import NewProjectButtonContainer from '../containers/projects/NewProjectButtonContainer'
+import VisibleProjectList from '../containers/projects/VisibleProjectAuthList'
+import AppNavbarContainer from '../containers/navigation/AppNavbarContainer'
+
+class ProjectsContainer extends React.Component {
+ componentDidMount() {
+ this.props.fetchAuthorizationsOfCurrentUser()
+ }
+
+ render() {
+ return (
+ <DocumentTitle title="My Projects - OpenDC">
+ <div className="full-height">
+ <AppNavbarContainer 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..77927cff 100644
--- a/frontend/src/reducers/modals.js
+++ b/frontend/src/reducers/modals.js
@@ -2,15 +2,15 @@ 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_NEW_TOPOLOGY_MODAL,
CLOSE_DELETE_MACHINE_MODAL,
CLOSE_DELETE_RACK_MODAL,
CLOSE_DELETE_ROOM_MODAL,
CLOSE_EDIT_RACK_NAME_MODAL,
CLOSE_EDIT_ROOM_NAME_MODAL,
- OPEN_CHANGE_TOPOLOGY_MODAL,
+ OPEN_NEW_TOPOLOGY_MODAL,
OPEN_DELETE_MACHINE_MODAL,
OPEN_DELETE_RACK_MODAL,
OPEN_DELETE_ROOM_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,9 +33,9 @@ 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),
+ changeTopologyModalVisible: modal(OPEN_NEW_TOPOLOGY_MODAL, CLOSE_NEW_TOPOLOGY_MODAL),
editRoomNameModalVisible: modal(OPEN_EDIT_ROOM_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL),
deleteRoomModalVisible: modal(OPEN_DELETE_ROOM_MODAL, CLOSE_DELETE_ROOM_MODAL),
editRackNameModalVisible: modal(OPEN_EDIT_RACK_NAME_MODAL, CLOSE_EDIT_RACK_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/opendc-api-spec.yml b/opendc-api-spec.yml
index df8f8e94..d633b9cc 100644
--- a/opendc-api-spec.yml
+++ b/opendc-api-spec.yml
@@ -1,992 +1,919 @@
swagger: '2.0'
info:
- version: 1.0.0
- title: OpenDC API
- description: 'OpenDC is an open-source datacenter simulator for education, featuring real-time online collaboration, diverse simulation models, and detailed performance feedback statistics.'
+ version: 1.0.0
+ title: OpenDC API
+ description: 'OpenDC is an open-source datacenter simulator for education, featuring real-time online collaboration, diverse simulation models, and detailed performance feedback statistics.'
host: opendc.org
basePath: /v2
schemes:
- - https
+ - https
paths:
- '/users':
- get:
- tags:
- - users
- description: Search for a User using their email address.
- parameters:
- - name: email
- in: query
- description: User's email address.
- required: true
- type: string
- responses:
- '200':
- description: Successfully searched Users.
- schema:
- $ref: '#/definitions/User'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '404':
- description: User not found.
- post:
- tags:
- - users
- description: Add a new User.
- parameters:
- - name: user
- in: body
- description: The new User.
- required: true
- schema:
- $ref: '#/definitions/User'
- responses:
- '200':
- description: Successfully added User.
- schema:
- $ref: '#/definitions/User'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '409':
- description: User already exists.
- '/users/{userId}':
- get:
- tags:
- - users
- description: Get this User.
- parameters:
- - name: userId
- in: path
- description: User's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved User.
- schema:
- $ref: '#/definitions/User'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '404':
- description: User not found.
- put:
- tags:
- - users
- description: Update this User's given name and/ or family name.
- parameters:
- - name: userId
- in: path
- description: User's ID.
- required: true
- type: string
- - name: user
- in: body
- description: User's new properties.
- required: true
- schema:
- properties:
- givenName:
- type: string
- familyName:
- type: string
- responses:
- '200':
- description: Successfully updated User.
- schema:
- $ref: '#/definitions/User'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from updating User.
- '404':
- description: User not found.
- delete:
- tags:
- - users
- description: Delete this User.
- parameters:
- - name: userId
- in: path
- description: User's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully deleted User.
- schema:
- $ref: '#/definitions/User'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from deleting User.
- '404':
- description: User not found.
- '/simulations':
- post:
- tags:
- - simulations
- description: Add a Simulation.
- parameters:
- - name: simulation
- in: body
- description: The new Simulation.
- required: true
- schema:
- properties:
- name:
- type: string
- responses:
- '200':
- description: Successfully added Simulation.
- schema:
- $ref: '#/definitions/Simulation'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '/simulations/{simulationId}':
- get:
- tags:
- - simulations
- description: Get this Simulation.
- parameters:
- - name: simulationId
- in: path
- description: Simulation's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved Simulation.
- schema:
- $ref: '#/definitions/Simulation'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from retrieving Simulation.
- '404':
- description: Simulation not found
- put:
- tags:
- - simulations
- description: Update this Simulation.
- parameters:
- - name: simulationId
- in: path
- description: Simulation's ID.
- required: true
- type: string
- - name: simulation
- in: body
- description: Simulation's new properties.
- required: true
- schema:
- properties:
- simulation:
- $ref: '#/definitions/Simulation'
- responses:
- '200':
- description: Successfully updated Simulation.
- schema:
- $ref: '#/definitions/Simulation'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from updating Simulation.
- '404':
- description: Simulation not found.
- delete:
- tags:
- - simulations
- description: Delete this simulation.
- parameters:
- - name: simulationId
- in: path
- description: Simulation's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully deleted Simulation.
- schema:
- $ref: '#/definitions/Simulation'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from deleting Simulation.
- '404':
- description: Simulation not found.
- '/simulations/{simulationId}/authorizations':
- get:
- tags:
- - simulations
- description: Get this Simulation's Authorizations.
- parameters:
- - name: simulationId
- in: path
- description: Simulation's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved Simulation's Authorizations.
- schema:
- type: array
- items:
- type: object
- properties:
- userId:
- type: string
- simulationId:
- type: string
- authorizationLevel:
- type: string
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from retrieving this Simulation's Authorizations.
- '404':
- description: Simulation not found.
- '/simulations/{simulationId}/topologies':
- post:
- tags:
- - simulations
- description: Add a Topology.
- parameters:
- - name: simulationId
- in: path
- description: Simulation's ID.
- required: true
- type: string
- - name: topology
- in: body
- description: The new Topology.
- required: true
- schema:
- properties:
- topology:
- $ref: '#/definitions/Topology'
- responses:
- '200':
- description: Successfully added Topology.
- schema:
- $ref: '#/definitions/Topology'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '/simulations/{simulationId}/experiments':
- post:
- tags:
- - experiments
- description: Add an Experiment.
- parameters:
- - name: simulationId
- in: path
- description: Simulation's ID.
- required: true
- type: string
- - name: experiment
- in: body
- description: The new Experiment.
- required: true
- schema:
- properties:
- topology:
- $ref: '#/definitions/Experiment'
- responses:
- '200':
- description: Successfully added Topology.
- schema:
- $ref: '#/definitions/Topology'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '/topologies/{topologyId}':
- get:
- tags:
- - topologies
- description: Get this Topology.
- parameters:
- - name: topologyId
- in: path
- description: Topology's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved Topology.
- schema:
- $ref: '#/definitions/Topology'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from retrieving Topology.
- '404':
- description: Topology not found.
- put:
- tags:
- - topologies
- description: Update this Topology's name.
- parameters:
- - name: topologyId
- in: path
- description: Topology's ID.
- required: true
- type: string
- - name: topology
- in: body
- description: Topology's new properties.
- required: true
- schema:
- properties:
- topology:
- $ref: '#/definitions/Topology'
- responses:
- '200':
- description: Successfully updated Topology.
- schema:
- $ref: '#/definitions/Topology'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from updating Topology.
- '404':
- description: Topology not found.
- delete:
- tags:
- - topologies
- description: Delete this Topology.
- parameters:
- - name: topologyId
- in: path
- description: Topology's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully deleted Topology.
- schema:
- $ref: '#/definitions/Topology'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from deleting Topology.
- '404':
- description: Topology not found.
- '/experiments/{experimentId}':
- get:
- tags:
- - experiments
- description: Get this Experiment.
- parameters:
- - name: experimentId
- in: path
- description: Experiment's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved Experiment.
- schema:
- $ref: '#/definitions/Experiment'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from retrieving Experiment.
- '404':
- description: Experiment not found.
- put:
- tags:
- - experiments
- description: "Update this Experiment's Topology, Trace, Scheduler, and/or name."
- parameters:
- - name: experimentId
- in: path
- description: Experiment's ID.
- required: true
- type: string
- - name: experiment
- in: body
- description: Experiment's new properties.
- required: true
- schema:
- properties:
- topologyId:
- type: string
- traceId:
- type: string
- schedulerName:
- type: string
- name:
- type: string
- responses:
- '200':
- description: Successfully updated Experiment.
- schema:
- $ref: '#/definitions/Experiment'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from updating Experiment.
- '404':
- description: 'Experiment, Topology, Trace, or Scheduler not found.'
- delete:
- tags:
- - experiments
- description: Delete this Experiment.
- parameters:
- - name: experimentId
- in: path
- description: Experiment's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully deleted Experiment.
- schema:
- $ref: '#/definitions/Experiment'
- '401':
- description: Unauthorized.
- '403':
- 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:
- - experiments
- description: Get all available Schedulers
- responses:
- '200':
- description: Successfully retrieved Schedulers.
- schema:
- type: array
- items:
- $ref: '#/definitions/Scheduler'
- '401':
- description: Unauthorized.
- /traces:
- get:
- tags:
- - experiments
- description: Get all available Traces (non-populated).
- responses:
- '200':
- description: Successfully retrieved Traces (non-populated).
- schema:
- type: array
- items:
- type: object
- properties:
- _id:
- type: string
- name:
- type: string
- '401':
- description: Unauthorized.
- '/traces/{traceId}':
- get:
- tags:
- - experiments
- description: Get this Trace.
- parameters:
- - name: traceId
- in: path
- description: Trace's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved Trace.
- schema:
- $ref: '#/definitions/Trace'
- '401':
- description: Unauthorized.
- '404':
- description: Trace not found.
- /prefabs:
- post:
- tags:
- - prefabs
- description: Add a Prefab.
- parameters:
- - name: prefab
- in: body
- description: The new Prefab.
- required: true
- schema:
- properties:
- name:
- type: string
- responses:
- '200':
- description: Successfully added Prefab.
- schema:
- $ref: '#/definitions/Prefab'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '/prefabs/{prefabId}':
- get:
- tags:
- - prefabs
- description: Get this Prefab.
- parameters:
- - name: prefabId
- in: path
- description: Prefab's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully retrieved Prefab.
- schema:
- $ref: '#/definitions/Prefab'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from retrieving Prefab.
- '404':
- description: Prefab not found
- put:
- tags:
- - prefabs
- description: Update this Prefab.
- parameters:
- - name: prefabId
- in: path
- description: Prefab's ID.
- required: true
- type: string
- - name: prefab
- in: body
- description: Prefab's new properties.
- required: true
- schema:
- properties:
- simulation:
- $ref: '#/definitions/Prefab'
- responses:
- '200':
- description: Successfully updated Prefab.
- schema:
- $ref: '#/definitions/Prefab'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from updating Prefab.
- '404':
- description: Prefab not found.
- delete:
- tags:
- - prefabs
- description: Delete this prefab.
- parameters:
- - name: prefabId
- in: path
- description: Prefab's ID.
- required: true
- type: string
- responses:
- '200':
- description: Successfully deleted Prefab.
- schema:
- $ref: '#/definitions/Prefab'
- '400':
- description: Missing or incorrectly typed parameter.
- '401':
- description: Unauthorized.
- '403':
- description: Forbidden from deleting Prefab.
- '404':
- description: Prefab not found.
+ '/users':
+ get:
+ tags:
+ - users
+ description: Search for a User using their email address.
+ parameters:
+ - name: email
+ in: query
+ description: User's email address.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully searched Users.
+ schema:
+ $ref: '#/definitions/User'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '404':
+ description: User not found.
+ post:
+ tags:
+ - users
+ description: Add a new User.
+ parameters:
+ - name: user
+ in: body
+ description: The new User.
+ required: true
+ schema:
+ $ref: '#/definitions/User'
+ responses:
+ '200':
+ description: Successfully added User.
+ schema:
+ $ref: '#/definitions/User'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '409':
+ description: User already exists.
+ '/users/{userId}':
+ get:
+ tags:
+ - users
+ description: Get this User.
+ parameters:
+ - name: userId
+ in: path
+ description: User's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved User.
+ schema:
+ $ref: '#/definitions/User'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '404':
+ description: User not found.
+ put:
+ tags:
+ - users
+ description: Update this User's given name and/ or family name.
+ parameters:
+ - name: userId
+ in: path
+ description: User's ID.
+ required: true
+ type: string
+ - name: user
+ in: body
+ description: User's new properties.
+ required: true
+ schema:
+ properties:
+ givenName:
+ type: string
+ familyName:
+ type: string
+ responses:
+ '200':
+ description: Successfully updated User.
+ schema:
+ $ref: '#/definitions/User'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from updating User.
+ '404':
+ description: User not found.
+ delete:
+ tags:
+ - users
+ description: Delete this User.
+ parameters:
+ - name: userId
+ in: path
+ description: User's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully deleted User.
+ schema:
+ $ref: '#/definitions/User'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from deleting User.
+ '404':
+ description: User not found.
+ '/projects':
+ post:
+ tags:
+ - projects
+ description: Add a Project.
+ parameters:
+ - name: project
+ in: body
+ description: The new Project.
+ required: true
+ schema:
+ properties:
+ name:
+ type: string
+ responses:
+ '200':
+ description: Successfully added Project.
+ schema:
+ $ref: '#/definitions/Project'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '/projects/{projectId}':
+ get:
+ tags:
+ - projects
+ description: Get this Project.
+ parameters:
+ - name: projectId
+ in: path
+ description: Project's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved Project.
+ schema:
+ $ref: '#/definitions/Project'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from retrieving Project.
+ '404':
+ description: Project not found
+ put:
+ tags:
+ - projects
+ description: Update this Project.
+ parameters:
+ - name: projectId
+ in: path
+ description: Project's ID.
+ required: true
+ type: string
+ - name: project
+ in: body
+ description: Project's new properties.
+ required: true
+ schema:
+ properties:
+ project:
+ $ref: '#/definitions/Project'
+ responses:
+ '200':
+ description: Successfully updated Project.
+ schema:
+ $ref: '#/definitions/Project'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from updating Project.
+ '404':
+ description: Project not found.
+ delete:
+ tags:
+ - projects
+ description: Delete this project.
+ parameters:
+ - name: projectId
+ in: path
+ description: Project's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully deleted Project.
+ schema:
+ $ref: '#/definitions/Project'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from deleting Project.
+ '404':
+ description: Project not found.
+ '/projects/{projectId}/authorizations':
+ get:
+ tags:
+ - projects
+ description: Get this Project's Authorizations.
+ parameters:
+ - name: projectId
+ in: path
+ description: Project's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved Project's Authorizations.
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ userId:
+ type: string
+ projectId:
+ type: string
+ authorizationLevel:
+ type: string
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from retrieving this Project's Authorizations.
+ '404':
+ description: Project not found.
+ '/projects/{projectId}/topologies':
+ post:
+ tags:
+ - projects
+ description: Add a Topology.
+ parameters:
+ - name: projectId
+ in: path
+ description: Project's ID.
+ required: true
+ type: string
+ - name: topology
+ in: body
+ description: The new Topology.
+ required: true
+ schema:
+ properties:
+ topology:
+ $ref: '#/definitions/Topology'
+ responses:
+ '200':
+ description: Successfully added Topology.
+ schema:
+ $ref: '#/definitions/Topology'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '/projects/{projectId}/experiments':
+ post:
+ tags:
+ - experiments
+ description: Add an Experiment.
+ parameters:
+ - name: projectId
+ in: path
+ description: Project's ID.
+ required: true
+ type: string
+ - name: experiment
+ in: body
+ description: The new Experiment.
+ required: true
+ schema:
+ properties:
+ topology:
+ $ref: '#/definitions/Experiment'
+ responses:
+ '200':
+ description: Successfully added Topology.
+ schema:
+ $ref: '#/definitions/Topology'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '/topologies/{topologyId}':
+ get:
+ tags:
+ - topologies
+ description: Get this Topology.
+ parameters:
+ - name: topologyId
+ in: path
+ description: Topology's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved Topology.
+ schema:
+ $ref: '#/definitions/Topology'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from retrieving Topology.
+ '404':
+ description: Topology not found.
+ put:
+ tags:
+ - topologies
+ description: Update this Topology's name.
+ parameters:
+ - name: topologyId
+ in: path
+ description: Topology's ID.
+ required: true
+ type: string
+ - name: topology
+ in: body
+ description: Topology's new properties.
+ required: true
+ schema:
+ properties:
+ topology:
+ $ref: '#/definitions/Topology'
+ responses:
+ '200':
+ description: Successfully updated Topology.
+ schema:
+ $ref: '#/definitions/Topology'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from updating Topology.
+ '404':
+ description: Topology not found.
+ delete:
+ tags:
+ - topologies
+ description: Delete this Topology.
+ parameters:
+ - name: topologyId
+ in: path
+ description: Topology's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully deleted Topology.
+ schema:
+ $ref: '#/definitions/Topology'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from deleting Topology.
+ '404':
+ description: Topology not found.
+ '/experiments/{experimentId}':
+ get:
+ tags:
+ - experiments
+ description: Get this Experiment.
+ parameters:
+ - name: experimentId
+ in: path
+ description: Experiment's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved Experiment.
+ schema:
+ $ref: '#/definitions/Experiment'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from retrieving Experiment.
+ '404':
+ description: Experiment not found.
+ put:
+ tags:
+ - experiments
+ description: "Update this Experiment's Topology, Trace, Scheduler, and/or name."
+ parameters:
+ - name: experimentId
+ in: path
+ description: Experiment's ID.
+ required: true
+ type: string
+ - name: experiment
+ in: body
+ description: Experiment's new properties.
+ required: true
+ schema:
+ properties:
+ topologyId:
+ type: string
+ traceId:
+ type: string
+ schedulerName:
+ type: string
+ name:
+ type: string
+ responses:
+ '200':
+ description: Successfully updated Experiment.
+ schema:
+ $ref: '#/definitions/Experiment'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from updating Experiment.
+ '404':
+ description: 'Experiment, Topology, Trace, or Scheduler not found.'
+ delete:
+ tags:
+ - experiments
+ description: Delete this Experiment.
+ parameters:
+ - name: experimentId
+ in: path
+ description: Experiment's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully deleted Experiment.
+ schema:
+ $ref: '#/definitions/Experiment'
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from deleting Experiment.
+ '404':
+ description: Experiment not found.
+ /schedulers:
+ get:
+ tags:
+ - experiments
+ description: Get all available Schedulers
+ responses:
+ '200':
+ description: Successfully retrieved Schedulers.
+ schema:
+ type: array
+ items:
+ $ref: '#/definitions/Scheduler'
+ '401':
+ description: Unauthorized.
+ /traces:
+ get:
+ tags:
+ - experiments
+ description: Get all available Traces (non-populated).
+ responses:
+ '200':
+ description: Successfully retrieved Traces (non-populated).
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ _id:
+ type: string
+ name:
+ type: string
+ '401':
+ description: Unauthorized.
+ '/traces/{traceId}':
+ get:
+ tags:
+ - experiments
+ description: Get this Trace.
+ parameters:
+ - name: traceId
+ in: path
+ description: Trace's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved Trace.
+ schema:
+ $ref: '#/definitions/Trace'
+ '401':
+ description: Unauthorized.
+ '404':
+ description: Trace not found.
+ /prefabs:
+ post:
+ tags:
+ - prefabs
+ description: Add a Prefab.
+ parameters:
+ - name: prefab
+ in: body
+ description: The new Prefab.
+ required: true
+ schema:
+ properties:
+ name:
+ type: string
+ responses:
+ '200':
+ description: Successfully added Prefab.
+ schema:
+ $ref: '#/definitions/Prefab'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '/prefabs/{prefabId}':
+ get:
+ tags:
+ - prefabs
+ description: Get this Prefab.
+ parameters:
+ - name: prefabId
+ in: path
+ description: Prefab's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully retrieved Prefab.
+ schema:
+ $ref: '#/definitions/Prefab'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from retrieving Prefab.
+ '404':
+ description: Prefab not found
+ put:
+ tags:
+ - prefabs
+ description: Update this Prefab.
+ parameters:
+ - name: prefabId
+ in: path
+ description: Prefab's ID.
+ required: true
+ type: string
+ - name: prefab
+ in: body
+ description: Prefab's new properties.
+ required: true
+ schema:
+ properties:
+ project:
+ $ref: '#/definitions/Prefab'
+ responses:
+ '200':
+ description: Successfully updated Prefab.
+ schema:
+ $ref: '#/definitions/Prefab'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from updating Prefab.
+ '404':
+ description: Prefab not found.
+ delete:
+ tags:
+ - prefabs
+ description: Delete this prefab.
+ parameters:
+ - name: prefabId
+ in: path
+ description: Prefab's ID.
+ required: true
+ type: string
+ responses:
+ '200':
+ description: Successfully deleted Prefab.
+ schema:
+ $ref: '#/definitions/Prefab'
+ '400':
+ description: Missing or incorrectly typed parameter.
+ '401':
+ description: Unauthorized.
+ '403':
+ description: Forbidden from deleting Prefab.
+ '404':
+ description: Prefab not found.
definitions:
- Experiment:
- type: object
- properties:
- _id:
- type: string
- simulationId:
- type: string
- topologyId:
- type: string
- traceId:
- type: string
- schedulerName:
- type: string
- name:
- type: string
- state:
- type: string
- lastSimulatedTick:
- type: integer
- MachineState:
- type: object
- properties:
- _id:
- type: string
- machineId:
- type: string
- experimentId:
- type: string
- tick:
- type: integer
- inUseMemoryMb:
- type: integer
- loadFraction:
- type: number
- format: float
- Prefab:
- type: object
- properties:
- _id:
- type: string
- name:
- type: string
- datetimeCreated:
- type: string
- format: dateTime
- datetimeLastEdited:
- type: string
- format: dateTime
-
- RackState:
- type: object
- properties:
- _id:
- type: string
- rackId:
- type: string
- experimentId:
- type: string
- tick:
- type: integer
- inUseMemoryMb:
- type: integer
- loadFraction:
- type: number
- format: float
- RoomState:
- type: object
- properties:
- _id:
- type: string
- roomId:
- type: string
- experimentId:
- type: string
- tick:
- type: integer
- inUseMemoryMb:
- type: integer
- loadFraction:
- type: number
- format: float
- Scheduler:
- type: object
- properties:
- name:
- type: string
- Simulation:
- type: object
- properties:
- _id:
- type: string
- name:
- type: string
- datetimeCreated:
- type: string
- format: dateTime
- datetimeLastEdited:
- type: string
- format: dateTime
- topologyIds:
- type: array
- items:
- type: string
- experimentIds:
- type: array
- items:
- type: string
- Topology:
- type: object
- properties:
- _id:
- type: string
- simulationId:
- type: string
- name:
- type: string
- rooms:
- type: array
- items:
- type: object
- properties:
+ Experiment:
+ type: object
+ properties:
_id:
- type: string
+ type: string
+ projectId:
+ type: string
+ topologyId:
+ type: string
+ traceId:
+ type: string
+ schedulerName:
+ type: string
name:
- type: string
- tiles:
- type: array
- items:
- type: object
- properties:
- _id:
+ type: string
+ state:
+ type: string
+ lastSimulatedTick:
+ type: integer
+ MachineState:
+ type: object
+ properties:
+ _id:
+ type: string
+ machineId:
+ type: string
+ experimentId:
+ type: string
+ tick:
+ type: integer
+ inUseMemoryMb:
+ type: integer
+ loadFraction:
+ type: number
+ format: float
+ Prefab:
+ type: object
+ properties:
+ _id:
+ type: string
+ name:
+ type: string
+ datetimeCreated:
+ type: string
+ format: dateTime
+ datetimeLastEdited:
+ type: string
+ format: dateTime
+ RackState:
+ type: object
+ properties:
+ _id:
+ type: string
+ rackId:
+ type: string
+ experimentId:
+ type: string
+ tick:
+ type: integer
+ inUseMemoryMb:
+ type: integer
+ loadFraction:
+ type: number
+ format: float
+ RoomState:
+ type: object
+ properties:
+ _id:
+ type: string
+ roomId:
+ type: string
+ experimentId:
+ type: string
+ tick:
+ type: integer
+ inUseMemoryMb:
+ type: integer
+ loadFraction:
+ type: number
+ format: float
+ Scheduler:
+ type: object
+ properties:
+ name:
+ type: string
+ Project:
+ type: object
+ properties:
+ _id:
+ type: string
+ name:
+ type: string
+ datetimeCreated:
+ type: string
+ format: dateTime
+ datetimeLastEdited:
+ type: string
+ format: dateTime
+ topologyIds:
+ type: array
+ items:
type: string
- positionX:
- type: integer
- positionY:
- type: integer
- object:
+ experimentIds:
+ type: array
+ items:
+ type: string
+ Topology:
+ type: object
+ properties:
+ _id:
+ type: string
+ projectId:
+ type: string
+ name:
+ type: string
+ rooms:
+ type: array
+ items:
type: object
properties:
- capacity:
- type: integer
- powerCapacityW:
- type: integer
- machines:
- type: array
- items:
- type: object
- properties:
- position:
- type: integer
- cpuItems:
- type: array
- items:
+ _id:
+ type: string
+ name:
+ type: string
+ tiles:
+ type: array
+ items:
type: object
properties:
- name:
- type: string
- clockRateMhz:
- type: integer
- numberOfCores:
- type: integer
- gpuItems:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- clockRateMhz:
- type: integer
- numberOfCores:
- type: integer
- memoryItems:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- speedMbPerS:
- type: integer
- sizeMb:
- type: integer
- storageItems:
- type: array
- items:
- type: integer
- properties:
- name:
- type: string
- speedMbPerS:
- type: integer
- sizeMb:
- type: integer
- Trace:
- type: object
- properties:
- _id:
- type: string
- name:
- type: string
- path:
- type: string
- type:
- type: string
- User:
- type: object
- properties:
- _id:
- type: string
- googleId:
- type: integer
- email:
- type: string
- givenName:
- type: string
- familyName:
- type: string
- authorizations:
- type: array
- items:
- type: object
- properties:
- simulationId:
- type: string
- authorizationLevel:
- type: string
+ _id:
+ type: string
+ positionX:
+ type: integer
+ positionY:
+ type: integer
+ object:
+ type: object
+ properties:
+ capacity:
+ type: integer
+ powerCapacityW:
+ type: integer
+ machines:
+ type: array
+ items:
+ type: object
+ properties:
+ position:
+ type: integer
+ cpuItems:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ clockRateMhz:
+ type: integer
+ numberOfCores:
+ type: integer
+ gpuItems:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ clockRateMhz:
+ type: integer
+ numberOfCores:
+ type: integer
+ memoryItems:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ speedMbPerS:
+ type: integer
+ sizeMb:
+ type: integer
+ storageItems:
+ type: array
+ items:
+ type: integer
+ properties:
+ name:
+ type: string
+ speedMbPerS:
+ type: integer
+ sizeMb:
+ type: integer
+ Portfolio:
+ type: object
+ properties:
+ _id:
+ type: string
+ projectId:
+ type: string
+ name:
+ type: string
+ type:
+ type: string
+ scenarioIds:
+ type: array
+ items:
+ type: string
+ targets:
+ type: object
+ properties:
+ enabledMetrics:
+ type: array
+ items:
+ type: string
+ repeatsPerScenario:
+ type: integer
+ Scenario:
+ type: object
+ properties:
+ _id:
+ type: string
+ portfolioId:
+ type: string
+ name:
+ type: string
+ trace:
+ type: object
+ properties:
+ traceId:
+ type: string
+ loadSamplingFraction:
+ type: number
+ topology:
+ type: object
+ properties:
+ topologyId:
+ type: string
+ operational:
+ type: object
+ properties:
+ failuresEnabled:
+ type: boolean
+ performanceInterferenceEnabled:
+ type: boolean
+ schedulerName:
+ type: string
+ Trace:
+ type: object
+ properties:
+ _id:
+ type: string
+ name:
+ type: string
+ path:
+ type: string
+ type:
+ type: string
+ User:
+ type: object
+ properties:
+ _id:
+ type: string
+ googleId:
+ type: integer
+ email:
+ type: string
+ givenName:
+ type: string
+ familyName:
+ type: string
+ authorizations:
+ type: array
+ items:
+ type: object
+ properties:
+ 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..84fd09cc 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.
@@ -58,7 +58,7 @@ Make sure you have Python 3.7+ installed (if not, get it [here](https://www.pyth
pip install -r requirements.txt
```
-The web server also requires a running MongoDB instance. We recommend setting this up through docker, by running `docker-compose build` and `docker-compose up` in the [`mongodb` directory](../mongodb) of the main OpenDC repository.
+The web server also requires a running MongoDB instance. We recommend setting this up through docker, by running `docker-compose build` and `docker-compose up` in the [`mongodb` directory](../database) of the main OpenDC repository.
#### Get and configure the code
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 1611f889..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
@@ -19,12 +19,9 @@ def GET(request):
def PUT(request):
"""Update this Experiments name."""
- request.check_required_parameters(path={'experimentId': 'string'},
- body={
- 'experiment': {
- 'name': 'string',
- }
- })
+ request.check_required_parameters(path={'experimentId': 'string'}, body={'experiment': {
+ 'name': 'string',
+ }})
experiment = Experiment.from_id(request.params_path['experimentId'])
@@ -48,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 f3aa111c..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'
}]
})
@@ -48,12 +48,11 @@ def test_update_experiment_missing_parameter(client):
def test_update_experiment_non_existing(client, mocker):
mocker.patch.object(DB, 'fetch_one', return_value=None)
- assert '404' in client.put('/api/v2/experiments/1',
- json={
- 'experiment': {
- 'name': 'test',
- }
- }).status
+ assert '404' in client.put('/api/v2/experiments/1', json={
+ 'experiment': {
+ 'name': 'test',
+ }
+ }).status
def test_update_experiment_not_authorized(client, mocker):
@@ -61,19 +60,18 @@ 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'
}]
})
mocker.patch.object(DB, 'update', return_value={})
- assert '403' in client.put('/api/v2/experiments/1',
- json={
- 'experiment': {
- 'name': 'test',
- }
- }).status
+ assert '403' in client.put('/api/v2/experiments/1', json={
+ 'experiment': {
+ 'name': 'test',
+ }
+ }).status
def test_update_experiment(client, mocker):
@@ -81,36 +79,34 @@ def test_update_experiment(client, mocker):
'fetch_one',
return_value={
'_id': '1',
- 'simulationId': '1',
+ 'projectId': '1',
'authorizations': [{
- 'simulationId': '1',
+ 'projectId': '1',
'authorizationLevel': 'OWN'
}]
})
mocker.patch.object(DB, 'update', return_value={})
- res = client.put(
- '/api/v2/experiments/1',
- json={'experiment': {
- 'name': 'test',
- }})
+ res = client.put('/api/v2/experiments/1', json={'experiment': {
+ 'name': 'test',
+ }})
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'
}]
})
@@ -118,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 720e34cb..01a7dcff 100644
--- a/web-server/opendc/api/v2/paths.json
+++ b/web-server/opendc/api/v2/paths.json
@@ -1,16 +1,16 @@
[
"/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",
"/traces/{traceId}",
"/prefabs",
- "/prefabs/{prefabId}",
+ "/prefabs/{prefabId}"
]
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 74a1e398..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,9 +25,8 @@ 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'}})
- assert 'datetimeCreated' in res.json['content']
- assert 'datetimeLastEdited' in res.json['content']
+ 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
@@ -36,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 fa88c497..b25cb798 100644
--- a/web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py
+++ b/web-server/opendc/api/v2/topologies/topologyId/test_endpoint.py
@@ -1,7 +1,4 @@
from opendc.util.database import DB
-'''
-GET /topologies/{topologyId}
-'''
def test_get_topology(client, mocker):
@@ -9,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'
}]
})
@@ -29,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'
}]
})
@@ -40,16 +37,11 @@ def test_get_topology_not_authorized(client, mocker):
def test_get_topology_no_authorizations(client, mocker):
- mocker.patch.object(DB, 'fetch_one', return_value={'authorizations': []})
+ mocker.patch.object(DB, 'fetch_one', return_value={'projectId': '1', 'authorizations': []})
res = client.get('/api/v2/topologies/1')
assert '403' in res.status
-'''
-PUT /topologies/{topologyId}
-'''
-
-
def test_update_topology_missing_parameter(client):
assert '400' in client.put('/api/v2/topologies/1').status
@@ -64,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'
}]
})
@@ -84,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'
}]
})
@@ -100,21 +92,16 @@ def test_update_topology(client, mocker):
}).status
-'''
-DELETE /topologies/{topologyId}
-'''
-
-
def test_delete_topology(client, mocker):
mocker.patch.object(DB,
'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 d3b1a5d5..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 Prefab."""
+ """Model representing a Project."""
collection_name = 'prefabs'
@@ -17,13 +17,12 @@ class Prefab(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['prefabId']) == str(self.get_id()),
- user.obj['authorizations']))
+ authorizations = list(filter(lambda x: str(x['prefabId']) == 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 prefab."))
def get_all_authorizations(self):
- """Get all user IDs having access to this prefab."""
+ """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.'))