mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
implement flows runtime stop/start API and UI
This commit is contained in:
4
packages/node_modules/@node-red/editor-client/src/images/start.svg
vendored
Normal file
4
packages/node_modules/@node-red/editor-client/src/images/start.svg
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path color="#000" fill="#8c101c" d="M0 0h32v32H0z"></path>
|
||||
<path style="fill:#ffffff;stroke:#000000;stroke-width:0" d="M 24,16 8,24 8,8 Z" fill="none" stroke="#000" stroke-width="1.5"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 271 B |
4
packages/node_modules/@node-red/editor-client/src/images/stop.svg
vendored
Normal file
4
packages/node_modules/@node-red/editor-client/src/images/stop.svg
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path color="#000" fill="#8c101c" d="M0 0h32v32H0z"></path>
|
||||
<rect style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;" width="15" height="15" x="8" y="8.5"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 256 B |
@@ -297,6 +297,10 @@ var RED = (function() {
|
||||
// handled below
|
||||
return;
|
||||
}
|
||||
if (notificationId === "flows-run-state") {
|
||||
// handled in editor-client/src/js/runtime.js
|
||||
return;
|
||||
}
|
||||
if (notificationId === "project-update") {
|
||||
loader.start(RED._("event.loadingProject"), 0);
|
||||
RED.nodes.clear();
|
||||
@@ -747,6 +751,7 @@ var RED = (function() {
|
||||
RED.keyboard.init(buildMainMenu);
|
||||
|
||||
RED.nodes.init();
|
||||
RED.runtime.init()
|
||||
RED.comms.connect();
|
||||
|
||||
$("#red-ui-main-container").show();
|
||||
|
53
packages/node_modules/@node-red/editor-client/src/js/runtime.js
vendored
Normal file
53
packages/node_modules/@node-red/editor-client/src/js/runtime.js
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
RED.runtime = (function() {
|
||||
let state = ""
|
||||
let settings = {ui: true, enabled: true};
|
||||
const STOPPED = "stopped"
|
||||
const STARTED = "started"
|
||||
return {
|
||||
init: function() {
|
||||
// refresh the current runtime status from server
|
||||
settings = RED.settings.runtimeState;
|
||||
RED.runtime.requestState()
|
||||
|
||||
// {id:"flows-run-state", started: false, state: "stopped", retain:true}
|
||||
RED.comms.subscribe("notification/flows-run-state",function(topic,msg) {
|
||||
RED.events.emit("flows-run-state",msg);
|
||||
RED.runtime.updateState(msg.state);
|
||||
});
|
||||
},
|
||||
get state() {
|
||||
return state
|
||||
},
|
||||
get started() {
|
||||
return state === STARTED
|
||||
},
|
||||
get states() {
|
||||
return { STOPPED, STARTED }
|
||||
},
|
||||
updateState: function(newState) {
|
||||
state = newState;
|
||||
// disable pointer events on node buttons (e.g. inject/debug nodes)
|
||||
$(".red-ui-flow-node-button").toggleClass("red-ui-flow-node-button-stopped", state === STOPPED)
|
||||
// show/hide Start/Stop based on current state
|
||||
if(!RED.settings.runtimeState || RED.settings.runtimeState.ui !== false) {
|
||||
RED.menu.setVisible("deploymenu-item-runtime-stop", state === STARTED)
|
||||
RED.menu.setVisible("deploymenu-item-runtime-start", state === STOPPED)
|
||||
}
|
||||
},
|
||||
requestState: function(callback) {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"application/json"
|
||||
},
|
||||
cache: false,
|
||||
url: 'flows/state',
|
||||
success: function(data) {
|
||||
RED.runtime.updateState(data.state)
|
||||
if(callback) {
|
||||
callback(data.state)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})()
|
@@ -139,6 +139,9 @@ RED.menu = (function() {
|
||||
if (opt.disabled) {
|
||||
item.addClass("disabled");
|
||||
}
|
||||
if (opt.visible === false) {
|
||||
item.addClass("hide");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +252,14 @@ RED.menu = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function setVisible(id,state) {
|
||||
if (!state) {
|
||||
$("#"+id).parent().addClass("hide");
|
||||
} else {
|
||||
$("#"+id).parent().removeClass("hide");
|
||||
}
|
||||
}
|
||||
|
||||
function addItem(id,opt) {
|
||||
var item = createMenuItem(opt);
|
||||
if (opt !== null && opt.group) {
|
||||
@@ -305,6 +316,7 @@ RED.menu = (function() {
|
||||
isSelected: isSelected,
|
||||
toggleSelected: toggleSelected,
|
||||
setDisabled: setDisabled,
|
||||
setVisible: setVisible,
|
||||
addItem: addItem,
|
||||
removeItem: removeItem,
|
||||
setAction: setAction,
|
||||
|
@@ -63,16 +63,18 @@ RED.deploy = (function() {
|
||||
'</a>'+
|
||||
'<a id="red-ui-header-button-deploy-options" class="red-ui-deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
|
||||
'</span></li>').prependTo(".red-ui-header-toolbar");
|
||||
RED.menu.init({id:"red-ui-header-button-deploy-options",
|
||||
options: [
|
||||
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.svg",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
|
||||
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
|
||||
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}},
|
||||
null,
|
||||
{id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"},
|
||||
|
||||
]
|
||||
});
|
||||
const mainMenuItems = [
|
||||
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.svg",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
|
||||
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
|
||||
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}},
|
||||
null
|
||||
]
|
||||
if(!RED.settings.runtimeState || RED.settings.runtimeState.ui !== false) {
|
||||
mainMenuItems.push({id:"deploymenu-item-runtime-start", icon:"red/images/start.svg",label:"Start"/*RED._("deploy.startFlows")*/,sublabel:"Start Flows" /*RED._("deploy.startFlowsDesc")*/,onselect:"core:start-flows", visible:false})
|
||||
mainMenuItems.push({id:"deploymenu-item-runtime-stop", icon:"red/images/stop.svg",label:"Stop"/*RED._("deploy.startFlows")*/,sublabel:"Stop Flows" /*RED._("deploy.startFlowsDesc")*/,onselect:"core:stop-flows", visible:false})
|
||||
}
|
||||
mainMenuItems.push({id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"})
|
||||
RED.menu.init({id:"red-ui-header-button-deploy-options", options: mainMenuItems });
|
||||
} else if (type == "simple") {
|
||||
var label = options.label || RED._("deploy.deploy");
|
||||
var icon = 'red/images/deploy-full-o.svg';
|
||||
@@ -100,6 +102,8 @@ RED.deploy = (function() {
|
||||
|
||||
RED.actions.add("core:deploy-flows",save);
|
||||
if (type === "default") {
|
||||
RED.actions.add("core:stop-flows",function() { stopStartFlows("stop") });
|
||||
RED.actions.add("core:start-flows",function() { stopStartFlows("start") });
|
||||
RED.actions.add("core:restart-flows",restart);
|
||||
RED.actions.add("core:set-deploy-type-to-full",function() { RED.menu.setSelected("deploymenu-item-full",true);});
|
||||
RED.actions.add("core:set-deploy-type-to-modified-flows",function() { RED.menu.setSelected("deploymenu-item-flow",true); });
|
||||
@@ -270,18 +274,74 @@ RED.deploy = (function() {
|
||||
function sanitize(html) {
|
||||
return html.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")
|
||||
}
|
||||
function restart() {
|
||||
var startTime = Date.now();
|
||||
$(".red-ui-deploy-button-content").css('opacity',0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
deployInflight = true;
|
||||
|
||||
function shadeShow() {
|
||||
$("#red-ui-header-shade").show();
|
||||
$("#red-ui-editor-shade").show();
|
||||
$("#red-ui-palette-shade").show();
|
||||
$("#red-ui-sidebar-shade").show();
|
||||
|
||||
}
|
||||
function shadeHide() {
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
}
|
||||
function deployButtonSetBusy(){
|
||||
$(".red-ui-deploy-button-content").css('opacity',0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
}
|
||||
function deployButtonClearBusy(){
|
||||
$(".red-ui-deploy-button-content").css('opacity',1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
}
|
||||
function stopStartFlows(state) {
|
||||
const startTime = Date.now();
|
||||
const deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
|
||||
deployInflight = true;
|
||||
deployButtonSetBusy();
|
||||
shadeShow();
|
||||
RED.runtime.updateState(state);
|
||||
$.ajax({
|
||||
url:"flows/state",
|
||||
type: "POST",
|
||||
data: {state: state},
|
||||
headers: {
|
||||
"Node-RED-Flow-Run-State-Change": state
|
||||
}
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
if (deployWasEnabled) {
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
}
|
||||
RED.runtime.updateState((data && data.state) || "unknown" )
|
||||
RED.notify('<p>Done</p>',"success");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
if (deployWasEnabled) {
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
}
|
||||
if (xhr.status === 401) {
|
||||
RED.notify("Not authorized" ,"error");
|
||||
} else if (xhr.responseText) {
|
||||
RED.notify("Operation failed: " + xhr.responseText,"error");
|
||||
} else {
|
||||
RED.notify("Operation failed: no response","error");
|
||||
}
|
||||
RED.runtime.requestState()
|
||||
}).always(function() {
|
||||
const delta = Math.max(0,300-(Date.now()-startTime));
|
||||
setTimeout(function() {
|
||||
deployButtonClearBusy();
|
||||
shadeHide()
|
||||
deployInflight = false;
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
function restart() {
|
||||
var startTime = Date.now();
|
||||
var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
|
||||
deployInflight = true;
|
||||
deployButtonSetBusy();
|
||||
$.ajax({
|
||||
url:"flows",
|
||||
type: "POST",
|
||||
@@ -307,15 +367,10 @@ RED.deploy = (function() {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
|
||||
}
|
||||
}).always(function() {
|
||||
deployInflight = false;
|
||||
var delta = Math.max(0,300-(Date.now()-startTime));
|
||||
setTimeout(function() {
|
||||
$(".red-ui-deploy-button-content").css('opacity',1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
deployButtonClearBusy();
|
||||
deployInflight = false;
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
@@ -450,21 +505,17 @@ RED.deploy = (function() {
|
||||
const nns = RED.nodes.createCompleteNodeSet();
|
||||
const startTime = Date.now();
|
||||
|
||||
$(".red-ui-deploy-button-content").css('opacity', 0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
|
||||
deployButtonSetBusy();
|
||||
const data = { flows: nns };
|
||||
|
||||
if (!force) {
|
||||
data.runtimeState = RED.runtime.state;
|
||||
if (data.runtimeState === RED.runtime.states.STOPPED || force) {
|
||||
data._rev = RED.nodes.version();
|
||||
} else {
|
||||
data.rev = RED.nodes.version();
|
||||
}
|
||||
|
||||
|
||||
deployInflight = true;
|
||||
$("#red-ui-header-shade").show();
|
||||
$("#red-ui-editor-shade").show();
|
||||
$("#red-ui-palette-shade").show();
|
||||
$("#red-ui-sidebar-shade").show();
|
||||
shadeShow();
|
||||
$.ajax({
|
||||
url: "flows",
|
||||
type: "POST",
|
||||
@@ -550,15 +601,11 @@ RED.deploy = (function() {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: RED._("deploy.errors.noResponse") }), "error");
|
||||
}
|
||||
}).always(function () {
|
||||
deployInflight = false;
|
||||
const delta = Math.max(0, 300 - (Date.now() - startTime));
|
||||
setTimeout(function () {
|
||||
$(".red-ui-deploy-button-content").css('opacity', 1);
|
||||
$(".red-ui-deploy-button-spinner").hide();
|
||||
$("#red-ui-header-shade").hide();
|
||||
$("#red-ui-editor-shade").hide();
|
||||
$("#red-ui-palette-shade").hide();
|
||||
$("#red-ui-sidebar-shade").hide();
|
||||
deployInflight = false;
|
||||
deployButtonClearBusy()
|
||||
shadeHide()
|
||||
}, delta);
|
||||
});
|
||||
}
|
||||
|
@@ -4792,6 +4792,9 @@ RED.view = (function() {
|
||||
if (d._def.button) {
|
||||
var buttonEnabled = isButtonEnabled(d);
|
||||
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-disabled", !buttonEnabled);
|
||||
if(RED.runtime && Object.hasOwn(RED.runtime,'started')) {
|
||||
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-stopped", !RED.runtime.started);
|
||||
}
|
||||
|
||||
var x = d._def.align == "right"?d.w-6:-25;
|
||||
if (d._def.button.toggle && !d[d._def.button.toggle]) {
|
||||
|
@@ -176,6 +176,13 @@
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
&.red-ui-flow-node-button-stopped {
|
||||
opacity: 0.4;
|
||||
.red-ui-flow-node-button-button {
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.red-ui-flow-node-button-button {
|
||||
cursor: pointer;
|
||||
|
Reference in New Issue
Block a user