21 Commits

Author SHA1 Message Date
David Walsh
ec08e572fb Add title in name 2019-05-07 12:55:32 -04:00
David Walsh
03ccc8b2e3 Update to Node webserver 2019-05-06 21:54:23 -04:00
David Walsh
5f1aaa0bbe Add use of url variables. 2019-04-29 00:46:06 -04:00
David Walsh
88a10010f4 Add dependencies 2019-04-26 16:38:07 -04:00
David Walsh
404fcf686e Fix default rosbridge connection 2019-04-26 15:33:46 -04:00
David Walsh
397f14a441 Remove vision content loaded from main page 2019-04-26 15:28:52 -04:00
David Walsh
c52a5ba6bc Remove duplicate vision 2019-04-26 15:24:18 -04:00
David Walsh
f4f60e0188 Remove Titan specific config. 2019-04-26 15:18:10 -04:00
David Walsh
baab18447d Fixed label styles 2019-04-19 19:18:08 -04:00
David Walsh
a6a0343154 Add safety controller status 2019-04-19 18:51:28 -04:00
David Walsh
365a4bb790 Disable topic update 2019-04-19 18:28:23 -04:00
David Walsh
78bb28132f Add workflow updates after feedback from Eric 2019-04-19 12:28:26 -04:00
David Walsh
50186dd5e7 Added switch to specific controllers before recording and playback. 2019-04-17 12:44:19 -04:00
David Walsh
130edaa280 Add thermal camera view. 2019-04-17 12:25:38 -04:00
David Walsh
7bea1128df Updates for Ready Mode 2019-04-17 11:26:08 -04:00
David Walsh
5a822a5927 Added Rhea lab_ui config. 2019-04-16 19:36:07 -04:00
David Walsh
e0fe291366 Add execution and recording status. 2019-04-16 18:23:23 -04:00
David Walsh
2687f2e4de Add ros master label. 2019-04-04 15:46:07 -04:00
David Walsh
faed7b42bb Merge branch 'feature/vision' into develop 2019-04-03 14:51:17 -04:00
David Walsh
27f19ed19c Changed video streams to use compressed streams. 2019-04-03 14:23:56 -04:00
David Walsh
83cf9ccdb0 Initial vision panel 2019-03-28 14:58:32 -04:00
12 changed files with 491 additions and 65 deletions

View File

@@ -1,5 +1,12 @@
# Aescape Lab UI
## To install
```
sudo apt install npm -y
sudo npm install http-server -g
sudo ln -s /usr/bin/nodejs /usr/bin/node
```
## To run
Set your master to be what you want - default is `phoebe`.
Then run

View File

@@ -7,8 +7,32 @@ ros.recording = false;
ros.connected = false;
// ros.connectionName = 'ws://192.168.1.105:9090';
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){
return pair[1];
}
}
}
var master = "localhost"
master = getQueryVariable("master")
if(master == null)
{
master = window.location.hostname
//"localhost"
}
console.log('Master = ' + master);
ros.connectionName = 'ws://' + master + ':9090';
// ros.connectionName = 'ws://localhost:9090';
ros.connectionName = 'ws://titan.aescape.co:9090';
// ros.connectionName = 'ws://titan.aescape.co:9090';
console.log('ros.connectionName = ' + ros.connectionName);
// If there is an error on the backend, an 'error' emit will be emitted.
ros.on('error', function(error) {
@@ -20,7 +44,7 @@ ros.on('error', function(error) {
document.getElementById("ROSNodes").innerHTML = "No Nodes Detected";
rosbridgeconnection_badge
console.log(error);192
console.log(error);
});
// Find out exactly when we made a connection.
ros.on('connection', function() {
@@ -119,6 +143,7 @@ bagNotifier.subscribe(function(message) {
// attept to connect to the ros master from the IP given orgrab it from the form
ros.attemptConnection = function(ipAddress)
{
ros.close();
if( typeof ipAddress !== "undefined")
{
ros.connectionName = ipAddress;
@@ -129,6 +154,7 @@ ros.attemptConnection = function(ipAddress)
}
console.log('Connection = ' + ros.connectionName);
ros.connect(ros.connectionName);
getMasterName();
}
function toggleRecording()
@@ -155,3 +181,25 @@ function toggleRecording()
}
}
}
function getMasterName()
{
var service = new ROSLIB.Service({
ros : ros,
name : '/rosapi/service_host',
serviceType : 'rosapi/ServiceHost'
});
var request = new ROSLIB.ServiceRequest({
service: '/rosout/get_loggers' // Only the master hosts this service.
});
service.callService(request, function(result) {
console.log('Master Name = ' + result.host);
document.getElementById("MasterName").innerHTML = result.host;
var title = result.host + " Lab UI"
document.title = title;
document.getElementById("Title").innerHTML = title;
});
}

View File

@@ -47,12 +47,12 @@ function updateNodesGUI()
};
window.setInterval(function(){
// window.setInterval(function(){
updateTopicsGUI();
updateNodesGUI();
// updateTopicsGUI();
// updateNodesGUI();
}, 5000);
// }, 5000);
function validateForm()
{

View File

@@ -4,19 +4,40 @@
Select Operation Mode
</div>
<div class="panel-body text-center">
<button id="teachingModeButton" type="button" onclick="triggerService('/aescape/mode/activateTeachingController')" class="btn btn-primary">
Teaching Mode
</button>
<button id="executionModeButton" type="button" onclick="triggerService('/aescape/mode/activateExecutionController')" class="btn btn-primary">
Massage Mode
</button>
<button id="standbyModeButton" type="button" onclick="triggerService('/aescape/mode/activateStandbyController')" class="btn btn-primary">
Standby Mode
</button>
<button id="stoppedModeButton" type="button" onclick="triggerService('/aescape/mode/stopControllers')" class="btn btn-primary">
Stopped Mode
</button>
<div class="col-md-6">
<button id="teachingModeButton" type="button" onclick="triggerService('/aescape/mode/activateTeachingController')" class="btn btn-primary">
Teaching Mode
</button>
<button id="executionModeButton" type="button" onclick="triggerService('/aescape/mode/activateExecutionController')" class="btn btn-primary">
Massage Mode
</button>
<button id="readyModeButton" type="button" onclick="triggerService('/aescape/mode/activateReadyController')" class="btn btn-primary">
Ready Mode
</button>
<button id="standbyModeButton" type="button" onclick="triggerService('/aescape/mode/activateStandbyController')" class="btn btn-primary">
Standby Mode
</button>
<button id="stoppedModeButton" type="button" onclick="triggerService('/aescape/mode/stopControllers')" class="btn btn-primary">
Stopped Mode
</button>
</div>
<div class="col-md-6">
Safety Monitor Status:
<div class="row-md-3">
<h4><span id="safetyRunning" class="label label-default">Running</span></h4>
</div>
<div class="row-md-3">
<h4><span id="safetyStopped" class="label label-default">Stopped</span></h4>
</div>
<div class="row-md-3">
<button type="button" onclick="triggerService('/aescape/mode/activateSafetyController')" class="btn btn-sm btn-default">
Activate Safety Monitor
</button>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@@ -84,10 +105,18 @@
Teaching Mode Operations
</div>
<div class="panel-body text-center">
<button id="recordingStartButton" type="button" onclick="triggerService('/aescape/bags/startTeachRecording')" class="btn btn-primary">
<span class="row">
<label id="RecordingStatusLabel" class="label-warning">
Bag manager not connected!
</label>
</span>
<button type="button" onclick="triggerService('/aescape/mode/activateReadyController')" class="btn btn-default">
Activate Ready Mode
</button>
<button id="recordingStartButton" type="button" onclick="triggerService('/aescape/hardware/calibrateRobotiq'); triggerService('/aescape/mode/activateTeachingController'); triggerService('/aescape/bags/startTeachRecording')" class="btn btn-primary">
Start Teach Recording
</button>
<button id="recordingStopButton" type="button" onclick="triggerService('/aescape/bags/stopTeachRecording')" class="btn btn-primary">
<button id="recordingStopButton" type="button" onclick="triggerService('/aescape/bags/stopTeachRecording'); triggerService('/aescape/mode/activateReadyController')" class="btn btn-primary">
Stop Teach Recording
</button>
</div>
@@ -97,16 +126,28 @@
<div class="panel-heading">
Execution Mode Operations
</div>
<div class="panel-body text-center">
<span class="row">
<label id="ExecutionStatusLabel" class="label-warning">
Bag manager not connected!
</label>
</span>
Last Bag Playing:
<span id="bagPlayingText">
<span id="lastbagText">
None
</span>
<div>
<button id="executionStartButton" type="button" onclick="triggerService('/aescape/bags/startPlayingLastRecording')" class="btn btn-primary">
<button type="button" onclick="triggerService('/aescape/mode/activateReadyController')" class="btn btn-default">
Activate Ready Mode
</button>
<button id="executionStartButton" type="button" onclick="triggerService('/aescape/mode/activateExecutionController'); triggerService('/aescape/bags/startPlayingLastRecording')" class="btn btn-primary">
Play Last Recording
</button>
<button id="executionStopButton" type="button" onclick="triggerService('/aescape/bags/stopPlayingBag')" class="btn btn-primary">
<button id="executionStopButton" type="button" onclick="triggerService('/aescape/bags/stopPlayingBag'); triggerService('/aescape/mode/activateReadyController')" class="btn btn-primary">
Stop Playing Recording
</button>
<div class="row">
@@ -124,6 +165,8 @@
</div>
</div>
</div>
<!-- </div> -->
</div>
</div>

View File

@@ -27,33 +27,112 @@ var modeStatus = new ROSLIB.Topic({
modeStatus.subscribe(function(message) {
document.getElementById("stoppedModeButton").className = "btn btn-secondary"
document.getElementById("standbyModeButton").className = "btn btn-primary"
document.getElementById("readyModeButton").className = "btn btn-primary"
document.getElementById("teachingModeButton").className = "btn btn-primary"
document.getElementById("executionModeButton").className = "btn btn-primary"
document.getElementById("recordingStartButton").disabled = true
document.getElementById("executionStartButton").disabled = true
if (message.data == "stopped") {
if (message.data == "stopped")
{
document.getElementById("stoppedModeButton").className = "btn btn-warning"
} else if (message.data == "standby")
}
else if (message.data == "standby")
{
document.getElementById("standbyModeButton").className = "btn btn-primary btn-success"
} else if (message.data == "teach")
}
else if (message.data == "teach")
{
document.getElementById("teachingModeButton").className = "btn btn-primary btn-success"
} else if (message.data == "execution")
}
else if (message.data == "execution")
{
document.getElementById("executionModeButton").className = "btn btn-primary btn-success"
}
else if (message.data == "ready")
{
document.getElementById("readyModeButton").className = "btn btn-primary btn-success"
document.getElementById("recordingStartButton").disabled = false
document.getElementById("executionStartButton").disabled = false
}
});
// Playing Bag
// Safety Status
var safetyStatusTopic = new ROSLIB.Topic({
ros : ros,
name : '/aescape/mode/safety_status',
messageType : 'std_msgs/String',
throttle_rate : 500 // 2Hz
});
safetyStatusTopic.subscribe(function(message) {
document.getElementById("safetyRunning").className = 'label label-default';
document.getElementById("safetyStopped").className = 'label label-default';
if (message.data == "stopped")
{
document.getElementById("safetyStopped").className = 'label label-danger';
}
else if (message.data == "running")
{
document.getElementById("safetyRunning").className = 'label label-success';
}
});
// Recording Bag
var recordingBagTopic = new ROSLIB.Topic({
ros : ros,
name : '/aescape/bags/recording_status',
messageType : 'std_msgs/String'
});
recordingBagTopic.subscribe(function(message) {
if (message.data == "stopped")
{
document.getElementById("RecordingStatusLabel").innerHTML = 'Not Running';
document.getElementById("RecordingStatusLabel").className = 'label label-warning';
}
else if (message.data == "running")
{
document.getElementById("RecordingStatusLabel").innerHTML = 'RUNNING!';
document.getElementById("RecordingStatusLabel").className = 'label label-success';
}
});
// Executing Bag
var executingBagTopic = new ROSLIB.Topic({
ros : ros,
name : '/aescape/bags/execution_status',
messageType : 'std_msgs/String'
});
executingBagTopic.subscribe(function(message) {
if (message.data == "stopped")
{
document.getElementById("ExecutionStatusLabel").innerHTML = 'Not Running';
document.getElementById("ExecutionStatusLabel").className = 'label label-warning';
}
else if (message.data == "running")
{
document.getElementById("ExecutionStatusLabel").innerHTML = 'RUNNING!';
document.getElementById("ExecutionStatusLabel").className = 'label label-success';
}
});
// Last Bag
var bagPlayingTopic = new ROSLIB.Topic({
ros : ros,
name : '/aescape/bags/playing',
name : '/aescape/bags/last_played',
messageType : 'std_msgs/String'
});
bagPlayingTopic.subscribe(function(message) {
document.getElementById("bagPlayingText").innerHTML = message.data
document.getElementById("lastbagText").innerHTML = message.data
});
// FrankaState

View File

@@ -39,48 +39,63 @@ Tutorials can be found here: http://www.w3schools.com/bootstrap/default.asp
<script type="text/javascript" src="coordinator/js/update_guis.js"></script>
<script>
<!-- <script>
$(function(){
$("#visionContent").load("vision/vision.html");
});
</script>
<script type="text/javascript" src="vision/js/ros_scripts.js"></script>
<script type="text/javascript" src="vision/js/update_guis.js"></script>
<script type="text/javascript" src="vision/js/update_guis.js"></script> -->
<meta content="text/html; charset=UTF-8; X-Content-Type-Options=nosniff" http-equiv="Content-Type" />
</head>
<body>
<div class="container">
<div id="jumbotronTitle" class="jumbotron text-center">
<h1>Lab UI</h1>
</div>
<h1 id="Title">Lab UI</h1>
<ul id="tabs" class="nav nav-pills" data-tabs="tabs" >
<li> <a href="#rosbridgeconnection" data-toggle="tab">
ROS Bridge Connection
<span id="rosbridgeconnection_badge" class="badge">
Not Connected
</span></a>
</li>
<li class="active">
<a href="#Coordinator" data-toggle="tab">
Coordinator
</a>
</li>
<li>
<a href="#Vision" data-toggle="tab">
Vision
</a>
</li>
</ul>
</div>
<div class="container">
<div class="col-md-1">
Master:
</div>
<div class="col-md-3">
<label id="MasterName"></label>
<script>
getMasterName();
</script>
</div>
</div>
<div class="row-md-3">
<ul id="tabs" class="nav nav-pills" data-tabs="tabs" >
<li> <a href="#rosbridgeconnection" data-toggle="tab">
ROS Bridge Connection
<span id="rosbridgeconnection_badge" class="badge">
Not Connected
</span></a>
</li>
<li class="active">
<a href="#Coordinator" data-toggle="tab">
Coordinator
</a>
</li>
<li>
<a href="vision/vision.html">
Vision
</a>
</li>
</ul>
</div>
<div id="my-tab-content" class="tab-content">
<div class="tab-pane active" id="Coordinator">
<div id="coordinatorContent"></div>
</div>
<div class="tab-pane" id="Vision">
<!-- <div class="tab-pane" id="Vision">
<div id="visionContent"></div>
</div>
</div> -->
<div class="tab-pane" id="rosbridgeconnection">
@@ -118,26 +133,26 @@ Tutorials can be found here: http://www.w3schools.com/bootstrap/default.asp
Predefined ROSBridge Connections
</div>
<div class="panel-body">
<!-- <button id="localhostButton" type="button" onclick="ros.attemptConnection('ws://localhost:9090')" class="btn btn-primary">
<button id="localhostButton" type="button" onclick="ros.attemptConnection('ws://localhost:9090')" class="btn btn-primary">
localhost
<script type="text/javascript">
document.getElementById("ConnectionIPInput").value = ros.connectionName;
</script>
</button>
<button id="TitanButton" type="button" onclick="ros.attemptConnection('ws://titan.local:9090')" class="btn btn-primary">
Titan
<script type="text/javascript">
document.getElementById("ConnectionIPInput").value = ros.connectionName;
</script>
</button>
<button id="PhoebeButton" type="button" onclick="ros.attemptConnection('ws://phoebe.local:9090')" class="btn btn-primary">
Phoebe
<script type="text/javascript">
document.getElementById("ConnectionIPInput").value = ros.connectionName;
</script>
</button>
<button id="TitanButton" type="button" onclick="ros.attemptConnection('ws://titan.local:9090')" class="btn btn-primary">
Titan
<script type="text/javascript">
document.getElementById("ConnectionIPInput").value = ros.connectionName;
</script>
</button> -->
<button id="TitanButton" type="button" onclick="ros.attemptConnection('ws://titan.aescape.co:9090')" class="btn btn-primary">
titan.aescape.co
<button id="RheaButton" type="button" onclick="ros.attemptConnection('ws://rhea.local:9090')" class="btn btn-primary">
Rhea
<script type="text/javascript">
document.getElementById("ConnectionIPInput").value = ros.connectionName;
</script>

View File

@@ -1,5 +1,8 @@
<launch>
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" />
<node name="lab_ui_webserver" pkg="aescape_lab_ui" type="webserver.sh" respawn="true" />
<node name="lab_ui_web_server" pkg="aescape_lab_ui" type="webserver.sh" respawn="false" />
<node name="lab_ui_video_server" pkg="web_video_server" type="web_video_server" respawn="false" />
</launch>

View File

@@ -41,6 +41,8 @@
<run_depend>rospy</run_depend>
<run_depend>std_msgs</run_depend>
<run_depend>web_video_server</run_depend>
<run_depend>rosbridge_server</run_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>

View File

@@ -1,4 +1,7 @@
#!/usr/bin/env bash
cd $(rospack find aescape_lab_ui)
python3 -m http.server 8000 --bind titan.aescape.co
# python3 -m http.server 8000
# Node webserver: https://www.npmjs.com/package/http-server
http-server -p 8000

104
vision/js/ros_scripts.js Normal file
View File

@@ -0,0 +1,104 @@
///////////////////////////////////////////////////////////////////////////////////
// Publishers
///////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Topics
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Subscribers
////////////////////////////////////////////////////////////////
// Operation Mode
var modeStatus = new ROSLIB.Topic({
ros : ros,
name : '/aescape/mode/status',
messageType : 'std_msgs/String'
});
modeStatus.subscribe(function(message) {
document.getElementById("stoppedModeButton").className = "btn btn-secondary"
document.getElementById("standbyModeButton").className = "btn btn-primary"
document.getElementById("teachingModeButton").className = "btn btn-primary"
document.getElementById("executionModeButton").className = "btn btn-primary"
if (message.data === "stopped") {
document.getElementById("stoppedModeButton").className = "btn btn-warning"
} else if (message.data === "standby")
{
document.getElementById("standbyModeButton").className = "btn btn-primary btn-success"
} else if (message.data === "teach")
{
document.getElementById("teachingModeButton").className = "btn btn-primary btn-success"
} else if (message.data === "execution")
{
document.getElementById("executionModeButton").className = "btn btn-primary btn-success"
}
});
// Playing Bag
var bagPlayingTopic = new ROSLIB.Topic({
ros : ros,
name : '/aescape/bags/playing',
messageType : 'std_msgs/String'
});
bagPlayingTopic.subscribe(function(message) {
document.getElementById("bagPlayingText").innerHTML = message.data
});
////////////////////////////////////////////////////////////////
// Services
////////////////////////////////////////////////////////////////
function triggerService(serviceName)
{
var service = new ROSLIB.Service({
ros : ros,
name : serviceName,
serviceType : 'std_srvs/Trigger'
});
var request = new ROSLIB.ServiceRequest({});
service.callService(request, function(result) {
console.log('Result for service call on '
+ serviceName
+ ': '
+ result.sum);
});
}
function triggerMessageService(serviceName, textInput)
{
var text = document.getElementById(textInput).value
var service = new ROSLIB.Service({
ros : ros,
name : serviceName,
serviceType : 'demobot.TriggerMessage'
});
var request = new ROSLIB.ServiceRequest({
message : text
});
service.callService(request, function(result) {
console.log('Result for service call on '
+ serviceName
+ ': '
+ result.sum);
});
}

0
vision/js/update_guis.js Normal file
View File

122
vision/vision.html Normal file
View File

@@ -0,0 +1,122 @@
<!-- <div class="panel panel-default">
<div class="panel-heading">
Select Operation Mode
</div>
<div class="panel-body text-center">
<button id="teachingModeButton" type="button" onclick="triggerService('/aescape/mode/activateTeachingController')" class="btn btn-primary">
Teaching Mode
</button>
<button id="executionModeButton" type="button" onclick="triggerService('/aescape/mode/activateExecutionController')" class="btn btn-primary">
Massage Mode
</button>
<button id="standbyModeButton" type="button" onclick="triggerService('/aescape/mode/activateStandbyController')" class="btn btn-primary">
Standby Mode
</button>
<button id="stoppedModeButton" type="button" onclick="triggerService('/aescape/mode/stopControllers')" class="btn btn-primary">
Stopped Mode
</button>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
Hardware Commands
</div>
<div class="panel-body text-center">
<button id="fixFrankaButton" type="button" onclick="triggerService('/aescape/hardware/resetFrankaError')" class="btn btn-primary">
Fix Franka Errors
</button>
<button id="calibrateButton" type="button" onclick="triggerService('/aescape/hardware/calibrateRobotiq')" class="btn btn-primary">
Calibrate Robotiq
</button>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
Teaching Mode Operations
</div>
<div class="panel-body text-center">
<button id="recordingStartButton" type="button" onclick="triggerService('/aescape/bags/startTeachRecording')" class="btn btn-primary">
Start Teach Recording
</button>
<button id="recordingStopButton" type="button" onclick="triggerService('/aescape/bags/stopTeachRecording')" class="btn btn-primary">
Stop Teach Recording
</button>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
Execution Mode Operations
</div>
<div class="panel-body text-center">
Last Bag Playing:
<span id="bagPlayingText">
None
</span>
<div>
<button id="executionStartButton" type="button" onclick="triggerService('/aescape/bags/startPlayingLastRecording')" class="btn btn-primary">
Play Last Recording
</button>
<button id="executionStopButton" type="button" onclick="triggerService('/aescape/bags/stopPlayingBag')" class="btn btn-primary">
Stop Playing Recording
</button>
<div class="row">
<div class="col-md-3">
Bagfile name must not start with "/"
<div class="input-group">
<input type="text" id="bagNameText" class="form-control" placeholder="bag_filename">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" onclick="triggerMessageService('/startPlayingRecording', 'bagNameText')">
<span>
Start Playing Bag
</span>
</button>
</span>
</div>
</div>
</div>
</div>
</div> -->
<script type="text/javascript" src="vision/js/ros_scripts.js"></script>
<script type="text/javascript" src="vision/js/update_guis.js"></script>
<div class="panel panel-default">
<div class="panel-heading">
Camera Views
</div>
<div class="panel-body">
Webcam
<div class="row-lg-4">
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/webcam/image_raw&type=ros_compressed"></img>
</div>
Realsense Red
<div class="row-lg-4">
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/real_red/color/image_raw&type=ros_compressed"></img>
</div>
Realsense Green
<div class="row-lg-4">
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/real_green/color/image_raw&type=ros_compressed"></img>
</div>
Thermal
<div class="row-lg-4">
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/thermal/image_raw&type=ros_compressed"></img>
</div>
</div>
</div>
<!-- <div class="panel panel-default">
<div class="panel-heading">
Execution Recording Operations
</div>
<div class="panel-body text-center">
<button id="executionStartButton" type="button" onclick="triggerService('/startExecutionRecording')" class="btn btn-primary">
Start Recording Execution
</button>
<button id="executionRecordingStopButton" type="button" onclick="triggerService('/stopExecutionRecording')" class="btn btn-primary">
Stop Recording Execution
</button>
</div>
</div> -->