From e64e8902fb7e4cb7820c2ae066463af3a59c214c Mon Sep 17 00:00:00 2001
From: Sandro Weber <webers@in.tum.de>
Date: Mon, 24 May 2021 22:39:09 +0200
Subject: [PATCH] simulation view can start/pause simulation

---
 src/App.js                                    |  4 +-
 .../experiment-list/simulation-details.js     | 12 +++--
 .../simulation-view/simulation-view.css       |  8 +--
 .../simulation-view/simulation-view.js        | 51 ++++++++++++-------
 .../execution/experiment-execution-service.js |  2 +-
 .../execution/running-simulation-service.js   | 19 ++++++-
 6 files changed, 67 insertions(+), 29 deletions(-)

diff --git a/src/App.js b/src/App.js
index 2fb35e2..63e3253 100644
--- a/src/App.js
+++ b/src/App.js
@@ -14,8 +14,8 @@ class App extends React.Component {
         <ErrorDialog />
         <HashRouter>
           <Switch>
-            <Route path='/experiments-overview'  component={ExperimentOverview} />
-            <Route path='/simulation-view/:simID' component={SimulationView} />
+            <Route path='/experiments-overview' component={ExperimentOverview} />
+            <Route path='/simulation-view/:serverIP/:simulationID' component={SimulationView} />
             <Route path='/' component={EntryPage} />
           </Switch>
         </HashRouter>
diff --git a/src/components/experiment-list/simulation-details.js b/src/components/experiment-list/simulation-details.js
index 26107c7..6b2950f 100644
--- a/src/components/experiment-list/simulation-details.js
+++ b/src/components/experiment-list/simulation-details.js
@@ -55,6 +55,13 @@ class SimulationDetails extends React.Component {
     });
   }
 
+  joinSimulation(simulationInfo) {
+    console.info(simulationInfo);
+    this.props.history.push({
+      pathname: '/simulation-view/' + simulationInfo.server + '/' + simulationInfo.runningSimulation.simulationID
+    });
+  }
+
   render() {
     return (
       <div className='simulations-details-wrapper'>
@@ -81,10 +88,7 @@ class SimulationDetails extends React.Component {
                   type="button" className='nrp-btn btn-default'
                   disabled={this.isJoinDisabled(simulation)}
                   onClick={() => {
-                    console.info(simulation);
-                    this.props.history.push({
-                      pathname: '/simulation-view/' + simulation.runningSimulation.simulationID
-                    });
+                    this.joinSimulation(simulation);
                   }}>
                   <ImEnter className='icon' />Join
                 </button>
diff --git a/src/components/simulation-view/simulation-view.css b/src/components/simulation-view/simulation-view.css
index 0477b6a..3371c7a 100644
--- a/src/components/simulation-view/simulation-view.css
+++ b/src/components/simulation-view/simulation-view.css
@@ -1,7 +1,7 @@
 .simulation-view-wrapper {
   display: grid;
-  grid-template-rows: 63px auto;
-  grid-template-columns: 100px auto;
+  grid-template-rows: auto auto;
+  grid-template-columns: 66px auto;
   grid-template-areas: 
       "simulation-view-header simulation-view-header"
       "simulation-view-sidebar simulation-view-mainview";
@@ -28,7 +28,7 @@
   background-color: red;
 }
 
-.simulation-view-flexlayout {
+.flexlayout__layout {
   position: relative;
   height: calc(100vh - 63px);
 }
@@ -69,7 +69,9 @@
   margin: 2px;
   padding: 2px;
   font-size: 0.7em;
+  color: black;
   font-weight: bold;
+  background-color: lightgray;
 }
 
 iframe {
diff --git a/src/components/simulation-view/simulation-view.js b/src/components/simulation-view/simulation-view.js
index 8c903ae..568d8f4 100644
--- a/src/components/simulation-view/simulation-view.js
+++ b/src/components/simulation-view/simulation-view.js
@@ -1,12 +1,14 @@
 import React from 'react';
 import FlexLayout from 'flexlayout-react';
 import { OverlayTrigger, Tooltip, Button } from 'react-bootstrap';
-import { RiPlayFill, RiLayout6Line } from 'react-icons/ri';
+import { RiPlayFill, RiPauseFill, RiLayout6Line } from 'react-icons/ri';
 import { GiExitDoor } from 'react-icons/gi';
 import { TiMediaRecord } from 'react-icons/ti';
 import { VscDebugRestart } from 'react-icons/vsc';
 
 import SimulationToolsService from './simulation-tools-service';
+import RunningSimulationService from '../../services/experiments/execution/running-simulation-service';
+import { EXPERIMENT_STATE } from '../../services/experiments/experiment-constants';
 
 import '../../../node_modules/flexlayout-react/style/light.css';
 import './simulation-view.css';
@@ -34,29 +36,34 @@ const jsonBaseLayout = {
   }
 };
 
-const classNameMapper = (className) => {
-  if (className === 'flexlayout__layout') {
-    return 'simulation-view-flexlayout';
-  }
-  else {
-    return className;
-  }
-};
-
 export default class SimulationView extends React.Component {
   constructor(props) {
     super(props);
-    console.info(this.state);
-    console.info(this.props);
+
+    const {serverIP, simulationID} = props.match.params;
+    //console.info('SimulationView ' + serverIP + ' ' + simulationID);
+    this.serverIP = serverIP;
+    this.simulationID = simulationID;
+    this.serverURL = 'http://' + this.serverIP + ':8080';
 
     this.state = {model: FlexLayout.Model.fromJson(jsonBaseLayout)};
-    console.info(this.state);
+    this.updateSimulationInfo();
 
     this.refLayout = React.createRef();
   }
 
-  factory = (node) => {
-    return SimulationToolsService.instance.flexlayoutNodeFactory(node);
+  async updateSimulationInfo() {
+    let simInfo = await RunningSimulationService.instance.getInfo(this.serverURL, this.simulationID);
+    this.setState({simulationInfo: simInfo});
+  }
+
+  async onButtonStartPause() {
+    let newState = this.state.simulationInfo.state === EXPERIMENT_STATE.PAUSED
+      ? EXPERIMENT_STATE.STARTED
+      : EXPERIMENT_STATE.PAUSED;
+    await RunningSimulationService.instance.updateState(this.serverURL, this.simulationID, newState);
+
+    this.updateSimulationInfo();
   }
 
   render() {
@@ -67,7 +74,13 @@ export default class SimulationView extends React.Component {
             <div className='simulation-view-control-buttons'>
               <button className='nrp-btn btn-default'><GiExitDoor className='icon' /></button>
               <button className='nrp-btn btn-default'><VscDebugRestart className='icon' /></button>
-              <button className='nrp-btn btn-default'><RiPlayFill className='icon' /></button>
+              <button className='nrp-btn btn-default' onClick={() => {
+                this.onButtonStartPause();
+              }}>
+                {this.state.simulationInfo && this.state.simulationInfo.state === EXPERIMENT_STATE.PAUSED
+                  ? <RiPlayFill className='icon' />
+                  : <RiPauseFill className='icon' />}
+              </button>
               <button className='nrp-btn btn-default'><TiMediaRecord className='icon' /></button>
             </div>
 
@@ -108,8 +121,10 @@ export default class SimulationView extends React.Component {
           })}
         </div>
         <div className='simulation-view-mainview'>
-          <FlexLayout.Layout ref={this.refLayout} model={this.state.model} factory={this.factory}
-            classNameMapper={classNameMapper}/>
+          <FlexLayout.Layout ref={this.refLayout} model={this.state.model}
+            factory={(node) => {
+              return SimulationToolsService.instance.flexlayoutNodeFactory(node);
+            }} />
         </div>
       </div>
     );
diff --git a/src/services/experiments/execution/experiment-execution-service.js b/src/services/experiments/execution/experiment-execution-service.js
index 0076fbf..eb01587 100644
--- a/src/services/experiments/execution/experiment-execution-service.js
+++ b/src/services/experiments/execution/experiment-execution-service.js
@@ -200,7 +200,7 @@ class ExperimentExecutionService extends HttpService {
             return SimulationService.instance.updateState(
               serverURL,
               simulationID,
-              { state: state }
+              state
             );
           }
 
diff --git a/src/services/experiments/execution/running-simulation-service.js b/src/services/experiments/execution/running-simulation-service.js
index 754ccc8..b5f148a 100644
--- a/src/services/experiments/execution/running-simulation-service.js
+++ b/src/services/experiments/execution/running-simulation-service.js
@@ -164,13 +164,30 @@ class SimulationService extends HttpService {
   async updateState(serverURL, simulationID, state) {
     let url = serverURL + '/simulation/' + simulationID + '/state';
     try {
-      let response = await this.httpRequestPUT(url, JSON.stringify(state));
+      let response = await this.httpRequestPUT(url, JSON.stringify({ state: state }));
       return response;
     }
     catch (error) {
       ErrorHandlerService.instance.updateSimulationError(error);
     }
   }
+
+  /**
+   * Get simulation information.
+   * @param {string} serverURL The full URL of the server the simulation is running on
+   * @param {string} simulationID The simulation ID
+   * @returns The simulation information
+   */
+  async getInfo(serverURL, simulationID) {
+    let url = serverURL + '/simulation/' + simulationID;
+    try {
+      let response = await (await this.httpRequestGET(url)).json();
+      return response;
+    }
+    catch (error) {
+      ErrorHandlerService.instance.networkError(error);
+    }
+  }
 }
 
 export default SimulationService;
-- 
GitLab