Compare commits

...

32 Commits

Author SHA1 Message Date
Nick O'Leary
fb54c05d9f Ensure subflow instances keep track of their groups 2023-11-29 16:12:12 +00:00
Stephen McLaughlin
a55554193b Merge pull request #4441 from node-red/4274-allow-theme-to-set-mermaid-theme
Allow a theme to specifiy which theme mermaid should use
2023-11-20 21:43:03 +00:00
Nick O'Leary
d2a8338d4a Rename mermaidOptions to mermaid for contrib themes 2023-11-20 17:50:59 +00:00
Nick O'Leary
e945deeab6 Allow mermaid theme to be set via editorTheme and custom themes
Fixes #4274
2023-11-20 17:47:39 +00:00
Nick O'Leary
3dec609459 Merge pull request #4438 from node-red/update-deps-2
Update node-red-admin version
2023-11-20 10:00:44 +01:00
Nick O'Leary
e73b9f646d Update nr package to match 2023-11-17 10:44:34 +00:00
Nick O'Leary
3cea6400d1 Update node-red-admin version 2023-11-17 10:42:06 +00:00
Nick O'Leary
c6a8eee73d Merge pull request #4416 from node-red/mqtt-check-topic-length
check topic length > 0 before publish
2023-11-07 17:46:33 +00:00
Nick O'Leary
74d431ea36 Merge pull request #4427 from node-red/4394-update-page-title-on-flow-nav
Update browser title with flow name if set
2023-11-07 17:40:36 +00:00
Nick O'Leary
409a559a13 Merge pull request #4411 from node-red/4376-handle-falsy-env-vars
Handle false-like env vars properly
2023-11-07 17:40:18 +00:00
Nick O'Leary
6829535350 Merge pull request #4409 from node-red/4381-avoid-multiple-settings-saves
Only save settings once during node load process
2023-11-07 17:40:03 +00:00
Nick O'Leary
6488111f79 Merge pull request #4423 from node-red/4415-handle-excluded-core-nodes
Ensure typeSearch handles undefined node definitions
2023-11-07 17:39:46 +00:00
Nick O'Leary
923339c1d8 Merge pull request #4426 from node-red/4044-group-bb-import
Ensure group w/h are imported if present
2023-11-07 17:39:30 +00:00
Nick O'Leary
3f4d96f4cd Merge pull request #4425 from node-red/4418-fix-empty-status-background
Hide node status background when there is no status to show
2023-11-07 17:26:00 +00:00
Nick O'Leary
c52985d245 Update browser title with flow name if set
Fixes #4394
2023-11-07 17:24:04 +00:00
Nick O'Leary
88e6c71aa0 Ensure group w/h are imported if present
Fixes #4044
2023-11-07 17:09:22 +00:00
Nick O'Leary
4d08e297c4 Hide node status background when there is no status to show
Fixes #4418
2023-11-07 16:34:36 +00:00
Nick O'Leary
ad2b30691f Ensure typeSearch handles undefined node definitions
Fixes #4415
2023-11-03 11:28:04 +01:00
Dave Conway-Jones
369bad01b8 check topic length > 0 before publish
to close #4414
2023-11-03 08:55:38 +00:00
Nick O'Leary
b6ecc6d9ea Handle false-like env vars properly 2023-11-02 00:40:55 +01:00
Nick O'Leary
0117df0960 Only save settings once during node load process 2023-11-01 16:18:03 +01:00
Nick O'Leary
6ac905f264 Merge pull request #4407 from node-red/4392-add-close-button-to-restart-notification
Add a close button to the restart-required notification
2023-11-01 15:20:48 +01:00
Nick O'Leary
e5307f6604 Add a close button to the restart-required notification
Fixes #4392
2023-11-01 14:39:51 +01:00
Nick O'Leary
8d9b6dd859 Merge pull request #4405 from node-red/4396-fix-global-config-cred-lookup
Ensure global-config nodes lookup cred values properly
2023-11-01 14:20:56 +01:00
Nick O'Leary
01821ead0f Merge pull request #4371 from ralphwetzel/master
Extend typedInput "num" type validity check to NaN, binary, octal & hex
2023-11-01 14:20:31 +01:00
Nick O'Leary
1451fb9e2f Merge pull request #4399 from kazuhitoyokoi/master-fixrepeat4inject
Fix unintended new line in node name
2023-11-01 14:17:21 +01:00
Nick O'Leary
245751bb23 Merge pull request #4382 from hazymat/master
Ctrl-Enter does not close tray (Monaco) #4377
2023-11-01 14:15:08 +01:00
Nick O'Leary
f07519c705 Merge pull request #4393 from node-red/Fix-buffer-viewer-to-handle-0b-style-
fix buffer viewer to handle 0b style binary
2023-11-01 14:14:20 +01:00
Kazuhito Yokoi
fae3a5c26a Fix unintended new line in node name 2023-10-29 14:58:03 +09:00
Dave Conway-Jones
1a52c0adfc fix buffer viewer to handle 0b style binary 2023-10-24 23:15:34 +01:00
Mat Smith
44c0bbc61e Ctrl-Enter does not close tray (Monaco) #4377 2023-10-12 18:53:34 +01:00
ralphwetzel
5ac50fae3a Extend typedInput "num" type validity check to NaN, binary, octal & hex 2023-09-26 20:00:48 +02:00
21 changed files with 96 additions and 50 deletions

View File

@@ -64,7 +64,7 @@
"mqtt": "4.3.7",
"multer": "1.4.5-lts.1",
"mustache": "4.2.0",
"node-red-admin": "^3.1.0",
"node-red-admin": "^3.1.1",
"node-watch": "0.7.4",
"nopt": "5.0.0",
"oauth2orize": "1.11.1",

View File

@@ -339,6 +339,8 @@ module.exports = {
}
theme.codeEditor = theme.codeEditor || {}
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
theme.mermaid = Object.assign({}, themePlugin.mermaid, theme.mermaid)
}
activeThemeInitialised = true;
}

View File

@@ -2198,6 +2198,12 @@ RED.nodes = (function() {
}
node._config.x = node.x;
node._config.y = node.y;
if (n.hasOwnProperty('w')) {
node.w = n.w
}
if (n.hasOwnProperty('h')) {
node.h = n.h
}
} else if (n.type.substring(0,7) === "subflow") {
var parentId = n.type.split(":")[1];
var subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId);

View File

@@ -498,6 +498,15 @@ var RED = (function() {
]
}
}
} else if (notificationId === 'restart-required') {
options.buttons = [
{
text: RED._("common.label.close"),
click: function() {
persistentNotifications[notificationId].hideNotification();
}
}
]
}
if (!persistentNotifications.hasOwnProperty(notificationId)) {
persistentNotifications[notificationId] = RED.notify(text,options);

View File

@@ -182,7 +182,9 @@
valueLabel: contextLabel
},
str: {value:"str",label:"string",icon:"red/images/typedInput/az.svg"},
num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/},
num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate: function(v) {
return (true === RED.utils.validateTypedProperty(v, "num"));
} },
bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.svg",options:["true","false"]},
json: {
value:"json",

View File

@@ -121,7 +121,7 @@
var i=0,l=bufferBinValue.length;
var c = 0;
for(i=0;i<l;i++) {
var d = parseInt(bufferBinValue[i]);
var d = parseInt(Number(bufferBinValue[i]));
if (!isString && (isNaN(d) || d < 0 || d > 255)) {
valid = false;
break;

View File

@@ -966,12 +966,10 @@ RED.editor.codeEditor.monaco = (function() {
//Unbind ctrl-Enter (default action is to insert a newline in editor) This permits the shortcut to close the tray.
try {
ed._standaloneKeybindingService.addDynamicKeybinding(
'-editor.action.insertLineAfter', // command ID prefixed by '-'
null, // keybinding
() => {} // need to pass an empty handler
);
} catch (error) { }
monaco.editor.addKeybindingRule({keybinding: 0, command: "-editor.action.insertLineAfter"});
} catch (error) {
console.warn(error)
}
ed.nodered = {
refreshModuleLibs: refreshModuleLibs //expose this for function node externalModules refresh

View File

@@ -15,7 +15,8 @@ RED.editor.mermaid = (function () {
'vendor/mermaid/mermaid.min.js',
function (data, stat, jqxhr) {
mermaid.initialize({
startOnLoad: false
startOnLoad: false,
theme: RED.settings.get('mermaid', {}).theme
})
loaded = true
while(pendingEvals.length > 0) {

View File

@@ -323,7 +323,7 @@ RED.typeSearch = (function() {
}
}
function applyFilter(filter,type,def) {
return !filter ||
return !def || !filter ||
(
(!filter.spliceMultiple) &&
(!filter.type || type === filter.type) &&

View File

@@ -921,7 +921,7 @@ RED.utils = (function() {
error = RED._("validator.errors.invalid-prop")
}
} else if (propertyType === 'num') {
if (!/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(propertyValue)) {
if (!/^NaN$|^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$|^[+-]?(0b|0B)[01]+$|^[+-]?(0o|0O)[0-7]+$|^[+-]?(0x|0X)[0-9a-fA-F]+$/.test(propertyValue)) {
error = RED._("validator.errors.invalid-num")
}
} else if (propertyType === 'jsonata') {

View File

@@ -4187,7 +4187,7 @@ RED.view = (function() {
nodeEl.__statusGroup__.style.display = "none";
} else {
nodeEl.__statusGroup__.style.display = "inline";
let backgroundWidth = 12
let backgroundWidth = 15
var fill = status_colours[d.status.fill]; // Only allow our colours for now
if (d.status.shape == null && fill == null) {
backgroundWidth = 0
@@ -4207,7 +4207,11 @@ RED.view = (function() {
nodeEl.__statusLabel__.textContent = "";
}
const textSize = nodeEl.__statusLabel__.getBBox()
nodeEl.__statusBackground__.setAttribute('width', backgroundWidth + textSize.width + 6)
backgroundWidth += textSize.width
if (backgroundWidth > 0 && textSize.width > 0) {
backgroundWidth += 6
}
nodeEl.__statusBackground__.setAttribute('width', backgroundWidth)
}
delete d.dirtyStatus;
}
@@ -4619,8 +4623,8 @@ RED.view = (function() {
statusBackground.setAttribute("y",-1);
statusBackground.setAttribute("width",200);
statusBackground.setAttribute("height",13);
statusBackground.setAttribute("rx",1);
statusBackground.setAttribute("ry",1);
statusBackground.setAttribute("rx",2);
statusBackground.setAttribute("ry",2);
statusEl.appendChild(statusBackground);
node[0][0].__statusBackground__ = statusBackground;

View File

@@ -17,6 +17,8 @@
RED.workspaces = (function() {
const documentTitle = document.title;
var activeWorkspace = 0;
var workspaceIndex = 0;
@@ -339,12 +341,18 @@ RED.workspaces = (function() {
$("#red-ui-workspace-chart").show();
activeWorkspace = tab.id;
window.location.hash = 'flow/'+tab.id;
if (tab.label) {
document.title = `${documentTitle} : ${tab.label}`
} else {
document.title = documentTitle
}
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled);
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked", !!tab.locked);
} else {
$("#red-ui-workspace-chart").hide();
activeWorkspace = 0;
window.location.hash = '';
document.title = documentTitle
}
event.workspace = activeWorkspace;
RED.events.emit("workspace:change",event);

View File

@@ -320,7 +320,7 @@
}
// but replace with repeat one if set to repeat
if ((this.repeat && this.repeat != 0) || this.crontab) {
suffix = " ↻";
suffix = "\t↻";
}
if (this.name) {
return this.name+suffix;

View File

@@ -109,9 +109,8 @@ module.exports = function(RED) {
}
const p = props.shift()
const property = p.p;
const value = p.v ? p.v : '';
const valueType = p.vt ? p.vt : 'str';
const value = p.v !== undefined ? p.v : '';
const valueType = p.vt !== undefined ? p.vt : 'str';
if (property) {
if (valueType === "jsonata") {
if (p.v) {

View File

@@ -86,7 +86,7 @@
},
label: function() {
var suffix = "";
if (this.console === true || this.console === "true") { suffix = " ⇲"; }
if (this.console === true || this.console === "true") { suffix = "\t⇲"; }
if (this.targetType === "jsonata") {
return (this.name || "JSONata") + suffix;
}

View File

@@ -104,6 +104,7 @@ module.exports = function(RED) {
* @returns `true` if it is a valid topic
*/
function isValidPublishTopic(topic) {
if (topic.length === 0) return false;
return !/[\+#\b\f\n\r\t\v\0]/.test(topic);
}
@@ -219,8 +220,8 @@ module.exports = function(RED) {
*/
function subscriptionHandler(node, datatype ,topic, payload, packet) {
const msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
const v5 = (node && node.brokerConn)
? node.brokerConn.v5()
const v5 = (node && node.brokerConn)
? node.brokerConn.v5()
: Object.prototype.hasOwnProperty.call(packet, "properties");
if(v5 && packet.properties) {
setStrProp(packet.properties, msg, "responseTopic");
@@ -451,7 +452,7 @@ module.exports = function(RED) {
/**
* Perform the disconnect action
* @param {MQTTInNode|MQTTOutNode} node
* @param {MQTTInNode|MQTTOutNode} node
* @param {Function} done
*/
function handleDisconnectAction(node, done) {
@@ -865,7 +866,7 @@ module.exports = function(RED) {
* Call end and wait for the client to end (or timeout)
* @param {mqtt.MqttClient} client The broker client
* @param {number} ms The time to wait for the client to end
* @returns
* @returns
*/
let waitEnd = (client, ms) => {
return new Promise( (resolve, reject) => {
@@ -905,7 +906,7 @@ module.exports = function(RED) {
node.subid = 1;
//typedef for subscription object:
/**
/**
* @typedef {Object} Subscription
* @property {String} topic - topic to subscribe to
* @property {Object} [options] - options object
@@ -933,7 +934,7 @@ module.exports = function(RED) {
const ref = _ref || 0;
let options
let qos = 1 // default to QoS 1 (AWS and several other brokers don't support QoS 2)
// if options is an object, then clone it
if (typeof _options == "object") {
options = RED.util.cloneMessage(_options || {})
@@ -947,7 +948,7 @@ module.exports = function(RED) {
if (typeof qos === "number" && qos >= 0 && qos <= 2) {
options.qos = qos;
}
subscription.topic = _topic;
subscription.qos = qos;
subscription.options = RED.util.cloneMessage(options);
@@ -957,16 +958,16 @@ module.exports = function(RED) {
}
/**
* If topic is a subscription object, then use that, otherwise look up the topic in
* If topic is a subscription object, then use that, otherwise look up the topic in
* the subscriptions object. If the topic is not found, then create a new subscription
* object and add it to the subscriptions object.
* @param {Subscription|String} topic
* @param {*} options
* @param {*} callback
* @param {*} ref
* @param {Subscription|String} topic
* @param {*} options
* @param {*} callback
* @param {*} ref
*/
node.subscribe = function (topic, options, callback, ref) {
/** @type {Subscription} */
/** @type {Subscription} */
let subscription
let doCompare = false
let changesFound = false
@@ -1004,7 +1005,7 @@ module.exports = function(RED) {
_brokerConn.unsubscribe(sub.topic, sub.ref, true)
}
})
// if subscription is found (or sent in as a parameter), then check for changes.
// if there are any changes requested, tidy up the old subscription
if (subscription) {
@@ -1091,7 +1092,7 @@ module.exports = function(RED) {
delete sub[ref]
}
}
// if instructed to remove the actual MQTT client subscription
// if instructed to remove the actual MQTT client subscription
if (unsub) {
// if there are no more subscriptions for the topic, then remove the topic
if (Object.keys(sub).length === 0) {

View File

@@ -143,6 +143,12 @@ function loadModuleFiles(modules) {
return loadNodeSetList(pluginList);
}).then(function() {
return loadNodeSetList(nodeList);
}).then(function () {
if (settings.available()) {
return registry.saveNodeList();
} else {
return
}
})
}
@@ -436,7 +442,7 @@ async function loadPlugin(plugin) {
return plugin;
}
}
let invocation = 0
function loadNodeSetList(nodes) {
var promises = [];
nodes.forEach(function(node) {
@@ -451,13 +457,7 @@ function loadNodeSetList(nodes) {
}
});
return Promise.all(promises).then(function() {
if (settings.available()) {
return registry.saveNodeList();
} else {
return;
}
});
return Promise.all(promises)
}
function addModule(module) {

View File

@@ -99,6 +99,9 @@ var api = module.exports = {
safeSettings.markdownEditor = runtime.settings.editorTheme.markdownEditor || {};
safeSettings.markdownEditor.mermaid = safeSettings.markdownEditor.mermaid || { enabled: true };
}
if (runtime.settings.editorTheme.mermaid) {
safeSettings.mermaid = runtime.settings.editorTheme.mermaid
}
}
safeSettings.libraries = runtime.library.getLibraries();
if (util.isArray(runtime.settings.paletteCategories)) {

View File

@@ -73,9 +73,20 @@ class Subflow extends Flow {
id: subflowInstance.id,
configs: {},
nodes: {},
groups: {},
subflows: {}
}
if (subflowDef.groups) {
// Clone all of the subflow group definitions and give them new IDs
for (i in subflowDef.groups) {
if (subflowDef.groups.hasOwnProperty(i)) {
node = createNodeInSubflow(subflowInstance.id,subflowDef.groups[i]);
node_map[node._alias] = node;
subflowInternalFlowConfig.groups[node.id] = node;
}
}
}
if (subflowDef.configs) {
// Clone all of the subflow config node definitions and give them new IDs
for (i in subflowDef.configs) {

View File

@@ -57,18 +57,20 @@ var EnvVarPropertyRE = /^\${(\S+)}$/;
function mapEnvVarProperties(obj,prop,flow,config) {
var v = obj[prop];
const v = obj[prop];
if (Buffer.isBuffer(v)) {
return;
} else if (Array.isArray(v)) {
for (var i=0;i<v.length;i++) {
for (let i=0;i<v.length;i++) {
mapEnvVarProperties(v,i,flow,config);
}
} else if (typeof obj[prop] === 'string') {
if (obj[prop][0] === "$" && (EnvVarPropertyRE_old.test(v) || EnvVarPropertyRE.test(v)) ) {
var envVar = v.substring(2,v.length-1);
var r = redUtil.getSetting(config, envVar, flow);
obj[prop] = r ? r : obj[prop];
const envVar = v.substring(2,v.length-1);
const r = redUtil.getSetting(config, envVar, flow);
if (r !== undefined && r !== '') {
obj[prop] = r
}
}
} else {
for (var p in v) {

View File

@@ -39,7 +39,7 @@
"bcryptjs": "2.4.3",
"express": "4.18.2",
"fs-extra": "11.1.1",
"node-red-admin": "^3.1.0",
"node-red-admin": "^3.1.1",
"nopt": "5.0.0",
"semver": "7.5.4"
},