Merge branch 'dev' into tab-context-menu

This commit is contained in:
Nick O'Leary
2023-02-02 11:33:06 +00:00
172 changed files with 1938 additions and 454 deletions

View File

@@ -656,7 +656,12 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select();
dialogContainer.i18n();
var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini";
const userFormat = RED.settings.get("editor.dialog.export.pretty")
if (userFormat === false || userFormat === true) {
format = userFormat ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini";
}
$("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) {
evt.preventDefault();
@@ -672,7 +677,8 @@ RED.clipboard = (function() {
var nodes = JSON.parse(flow);
format = $(this).attr('id');
if (format === 'red-ui-clipboard-dialog-export-fmt-full') {
const pretty = format === "red-ui-clipboard-dialog-export-fmt-full";
if (pretty) {
flow = JSON.stringify(nodes,null,4);
} else {
flow = JSON.stringify(nodes);
@@ -681,6 +687,7 @@ RED.clipboard = (function() {
setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50);
$("#red-ui-clipboard-dialog-export-text").trigger("focus");
RED.settings.set("editor.dialog.export.pretty", pretty)
}
});

View File

@@ -160,7 +160,7 @@
this.element.css("maxHeight",null);
}
if (this.options.height !== 'auto') {
this.uiContainer.css("overflow-y","scroll");
this.uiContainer.css("overflow-y","auto");
if (!isNaN(this.options.height)) {
this.uiHeight = this.options.height;
}

View File

@@ -829,7 +829,7 @@ RED.tabs = (function() {
event.preventDefault();
removeTab(tab.id);
});
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
RED.popover.tooltip(closeLink,RED._("workspace.closeFlow"));
}
// if (tab.hideable) {
// li.addClass("red-ui-tabs-closeable")

View File

@@ -90,10 +90,10 @@
optEl.append(generateSpans(srcMatch));
optEl.appendTo(element);
}
matches.push({
value: optVal,
label: element,
i: (valMatch.found ? valMatch.index : srcMatch.index)
matches.push({
value: optVal,
label: element,
i: (valMatch.found ? valMatch.index : srcMatch.index)
});
}
})
@@ -146,7 +146,7 @@
{ value: "reset", source: ["delay","trigger","join","rbe"] },
{ value: "responseCookies", source: ["http request"] },
{ value: "responseTopic", source: ["mqtt"] },
{ value: "responseURL", source: ["http request"] },
{ value: "responseUrl", source: ["http request"] },
{ value: "restartTimeout", source: ["join"] },
{ value: "retain", source: ["mqtt"] },
{ value: "schema", source: ["json"] },
@@ -501,7 +501,7 @@
this.options.types = this.options.types||Object.keys(allOptions);
}
this.selectTrigger = $('<button class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
this.selectTrigger = $('<button type="button" class="red-ui-typedInput-type-select" tabindex="0"></button>').prependTo(this.uiSelect);
$('<i class="red-ui-typedInput-icon fa fa-caret-down"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
this.selectLabel = $('<span class="red-ui-typedInput-type-label"></span>').appendTo(this.selectTrigger);
@@ -570,7 +570,7 @@
})
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectTrigger = $('<button type="button" tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-caret-down"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
// RED.popover.tooltip(this.optionSelectLabel,function() {
// return that.optionValue;
@@ -591,7 +591,7 @@
that.uiSelect.addClass('red-ui-typedInput-focus');
});
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
this.optionExpandButton = $('<button type="button" tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"></button>').appendTo(this.uiSelect);
this.optionExpandButtonIcon = $('<i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>').appendTo(this.optionExpandButton);
this.type(this.typeField.val() || this.options.default||this.typeList[0].value);

View File

@@ -238,6 +238,7 @@ RED.editor = (function() {
var valid = validateNodeProperty(node, defaults, property,value);
if (((typeof valid) === "string") || !valid) {
input.addClass("input-error");
input.next(".red-ui-typedInput-container").addClass("input-error");
if ((typeof valid) === "string") {
var tooltip = input.data("tooltip");
if (tooltip) {
@@ -250,6 +251,7 @@ RED.editor = (function() {
}
} else {
input.removeClass("input-error");
input.next(".red-ui-typedInput-container").removeClass("input-error");
var tooltip = input.data("tooltip");
if (tooltip) {
input.data("tooltip", null);
@@ -1105,6 +1107,10 @@ RED.editor = (function() {
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
RED.sidebar.help.show(editing_node.type, false);
//ensure focused element is NOT body (for keyboard scope to operate correctly)
if (document.activeElement.tagName === 'BODY') {
$('#red-ui-editor-stack').trigger('focus')
}
}
}
}

View File

@@ -45,6 +45,9 @@
selectedCodeEditor = RED.editor.codeEditor[defaultEditor];
initialised = selectedCodeEditor.init();
}
$('<div id="red-ui-image-drop-target"><div data-i18n="[append]workspace.dropImageHere"><i class="fa fa-download"></i><br></div></div>').appendTo('#red-ui-editor');
$("#red-ui-image-drop-target").hide();
}
function create(options) {
@@ -64,6 +67,7 @@
options = {};
}
var editor = null;
if (this.editor.type === MONACO) {
// compatibility (see above note)
if (!options.element && !options.id) {
@@ -74,10 +78,14 @@
console.warn("createEditor() options.element or options.id is not valid", options);
$("#dialog-form").append('<div id="' + options.id + '" style="display: none;" />');
}
return this.editor.create(options);
editor = this.editor.create(options);
} else {
return this.editor.create(options);//fallback to ACE
editor = this.editor.create(options);//fallback to ACE
}
if (options.mode === "ace/mode/markdown") {
RED.editor.customEditTypes['_markdown'].postInit(editor, options);
}
return editor;
}
return {

View File

@@ -100,7 +100,7 @@ RED.editor.codeEditor.monaco = (function() {
"node-red-util": {package: "node-red", module: "util", path: "node-red/util.d.ts" },
"node-red-func": {package: "node-red", module: "func", path: "node-red/func.d.ts" },
}
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"] ];
const defaultServerSideTypes = [ knownModules["node-red-util"], knownModules["node-red-func"], knownModules["globals"], knownModules["console"], knownModules["buffer"] , knownModules["util"] ];
const modulesCache = {};
@@ -764,7 +764,7 @@ RED.editor.codeEditor.monaco = (function() {
if(!options.stateId && options.stateId !== false) {
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title).split("/").pop());
options.stateId = RED.editor.generateViewStateId("monaco", options, (options.mode || options.title || "").split("/").pop());
}
var el = options.element || $("#"+options.id)[0];
var toolbarRow = $("<div>").appendTo(el);

View File

@@ -76,6 +76,9 @@ RED.editor.colorPicker = RED.colorPicker = (function() {
var focusTarget = colorInput;
colorInput.on("change", function (e) {
var color = colorInput.val();
if (options.defaultValue && !color.match(/^([a-z]+|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3})$/)) {
color = options.defaultValue;
}
colorHiddenInput.val(color).trigger('change');
refreshDisplay(color);
});

View File

@@ -255,6 +255,9 @@
var currentExpression = expressionEditor.getValue();
var expr;
var usesContext = false;
var usesEnv = false;
var usesMoment = false;
var usesClone = false;
var legacyMode = /(^|[^a-zA-Z0-9_'".])msg([^a-zA-Z0-9_'"]|$)/.test(currentExpression);
$(".red-ui-editor-type-expression-legacy").toggle(legacyMode);
try {
@@ -267,6 +270,18 @@
usesContext = true;
return null;
});
expr.assign("env", function(name) {
usesEnv = true;
return null;
});
expr.assign("moment", function(name) {
usesMoment = true;
return null;
});
expr.assign("clone", function(name) {
usesClone = true;
return null;
});
} catch(err) {
testResultEditor.setValue(RED._("expressionEditor.errors.invalid-expr",{message:err.message}),-1);
return;
@@ -284,6 +299,18 @@
testResultEditor.setValue(RED._("expressionEditor.errors.context-unsupported"),-1);
return;
}
if (usesEnv) {
testResultEditor.setValue(RED._("expressionEditor.errors.env-unsupported"),-1);
return;
}
if (usesMoment) {
testResultEditor.setValue(RED._("expressionEditor.errors.moment-unsupported"),-1);
return;
}
if (usesClone) {
testResultEditor.setValue(RED._("expressionEditor.errors.clone-unsupported"),-1);
return;
}
var formattedResult;
if (result !== undefined) {

View File

@@ -14,6 +14,61 @@
* limitations under the License.
**/
(function() {
/**
* Converts dropped image file to date URL
*/
function file2base64Image(file, cb) {
var reader = new FileReader();
reader.onload = (function (fd) {
return function (e) {
cb(e.target.result);
};
})(file);
reader.readAsDataURL(file);
}
var initialized = false;
var currentEditor = null;
/**
* Initialize handler for image file drag events
*/
function initImageDrag(elem, editor) {
$(elem).on("dragenter", function (ev) {
ev.preventDefault();
$("#red-ui-image-drop-target").css({display:'table'}).focus();
currentEditor = editor;
});
if (!initialized) {
initialized = true;
$("#red-ui-image-drop-target").on("dragover", function (ev) {
ev.preventDefault();
}).on("dragleave", function (ev) {
$("#red-ui-image-drop-target").hide();
}).on("drop", function (ev) {
ev.preventDefault();
if ($.inArray("Files",ev.originalEvent.dataTransfer.types) != -1) {
var files = ev.originalEvent.dataTransfer.files;
if (files.length === 1) {
var file = files[0];
var name = file.name.toLowerCase();
if (name.match(/\.(apng|avif|gif|jpeg|png|svg|webp)$/)) {
file2base64Image(file, function (image) {
var session = currentEditor.getSession();
var img = `<img src="${image}"/>\n`;
var pos = session.getCursorPosition();
session.insert(pos, img);
$("#red-ui-image-drop-target").hide();
});
return;
}
}
}
$("#red-ui-image-drop-target").hide();
});
}
}
var toolbarTemplate = '<div style="margin-bottom: 5px">'+
'<span class="button-group">'+
@@ -114,6 +169,7 @@
var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop();
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
$(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop);
mermaid.init();
},200);
})
if (options.header) {
@@ -122,6 +178,7 @@
if (value) {
$(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue()));
mermaid.init();
}
panels = RED.panels.create({
id:"red-ui-editor-type-markdown-panels",
@@ -148,10 +205,14 @@
});
RED.popover.tooltip($("#node-btn-markdown-preview"), RED._("markdownEditor.toggle-preview"));
if (options.cursor && !expressionEditor._initState) {
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
}
if(!expressionEditor._initState) {
if (options.cursor) {
expressionEditor.gotoLine(options.cursor.row+1,options.cursor.column,false);
}
else {
expressionEditor.gotoLine(0, 0, false);
}
}
dialogForm.i18n();
},
close: function() {
@@ -215,7 +276,11 @@
}
})
return toolbar;
}
},
postInit: function (editor, options) {
var elem = $("#"+options.id);
initImageDrag(elem, editor);
}
}
RED.editor.registerTypeEditor("_markdown", definition);
})();

View File

@@ -235,6 +235,7 @@
RED.editor.colorPicker.create({
id: "red-ui-editor-node-color",
value: color,
defaultValue: "#DDAA99",
palette: recommendedColors,
sortPalette: function (a, b) {return a.l - b.l;}
}).appendTo(colorRow);

View File

@@ -0,0 +1,175 @@
RED.envVar = (function() {
function saveEnvList(list) {
const items = list.editableList("items")
const new_env = [];
items.each(function (i,el) {
var data = el.data('data');
var item;
if (data.nameField && data.valueField) {
item = {
name: data.nameField.val(),
value: data.valueField.typedInput("value"),
type: data.valueField.typedInput("type")
};
new_env.push(item);
}
});
return new_env;
}
function getGlobalConf(create) {
var gconf = null;
RED.nodes.eachConfig(function (conf) {
if (conf.type === "global-config") {
gconf = conf;
}
});
if ((gconf === null) && create) {
var cred = {
_ : {},
map: {}
};
gconf = {
id: RED.nodes.id(),
type: "global-config",
env: [],
name: "global-config",
label: "",
hasUsers: false,
users: [],
credentials: cred,
_def: RED.nodes.getType("global-config"),
};
RED.nodes.add(gconf);
}
return gconf;
}
function applyChanges(list) {
var gconf = getGlobalConf(false);
var new_env = [];
var items = list.editableList('items');
var credentials = gconf ? gconf.credentials : null;
if (!credentials) {
credentials = {
_ : {},
map: {}
};
}
items.each(function (i,el) {
var data = el.data('data');
if (data.nameField && data.valueField) {
var item = {
name: data.nameField.val(),
value: data.valueField.typedInput("value"),
type: data.valueField.typedInput("type")
};
if (item.name.trim() !== "") {
new_env.push(item);
if ((item.type === "cred") && (item.value !== "__PWRD__")) {
credentials.map[item.name] = item.value;
credentials.map["has_"+item.name] = (item.value !== "");
item.value = "__PWRD__";
}
}
}
});
if (gconf === null) {
gconf = getGlobalConf(true);
}
if ((JSON.stringify(new_env) !== JSON.stringify(gconf.env)) ||
(JSON.stringify(credentials) !== JSON.stringify(gconf.credentials))) {
gconf.env = new_env;
gconf.credentials = credentials;
RED.nodes.dirty(true);
}
}
function getSettingsPane() {
var gconf = getGlobalConf(false);
var env = gconf ? gconf.env : [];
var cred = gconf ? gconf.credentials : null;
if (!cred) {
cred = {
_ : {},
map: {}
};
}
var pane = $("<div/>", {
id: "red-ui-settings-tab-envvar",
class: "form-horizontal"
});
var content = $("<div/>", {
class: "form-row node-input-env-container-row"
}).css({
"margin": "10px"
}).appendTo(pane);
var label = $("<label></label>").css({
width: "100%"
}).appendTo(content);
$("<i/>", {
class: "fa fa-list"
}).appendTo(label);
$("<span/>").text(" "+RED._("env-var.header")).appendTo(label);
var list = $("<ol/>", {
id: "node-input-env-container"
}).appendTo(content);
var node = {
type: "",
env: env,
credentials: cred.map,
};
RED.editor.envVarList.create(list, node);
var buttons = $("<div/>").css({
"text-align": "right",
}).appendTo(content);
var revertButton = $("<button/>", {
class: "red-ui-button"
}).css({
}).text(RED._("env-var.revert")).appendTo(buttons);
var items = saveEnvList(list);
revertButton.on("click", function (ev) {
list.editableList("empty");
list.editableList("addItems", items);
});
return pane;
}
function init(done) {
if (!RED.user.hasPermission("settings.write")) {
RED.notify(RED._("user.errors.settings"),"error");
return;
}
RED.userSettings.add({
id:'envvar',
title: RED._("env-var.environment"),
get: getSettingsPane,
focus: function() {
var height = $("#red-ui-settings-tab-envvar").parent().height();
$("#node-input-env-container").editableList("height", (height -100));
},
close: function() {
var list = $("#node-input-env-container");
try {
applyChanges(list);
}
catch (e) {
console.log(e);
console.log(e.stack);
}
}
});
}
return {
init: init,
};
})();

View File

@@ -101,6 +101,7 @@ RED.group = (function() {
RED.editor.colorPicker.create({
id:"node-input-style-stroke",
value: style.stroke || defaultGroupStyle.stroke || "#a4a4a4",
defaultValue: "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
@@ -112,6 +113,7 @@ RED.group = (function() {
RED.editor.colorPicker.create({
id:"node-input-style-fill",
value: style.fill || defaultGroupStyle.fill ||"none",
defaultValue: "none",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,
@@ -129,6 +131,7 @@ RED.group = (function() {
RED.editor.colorPicker.create({
id:"node-input-style-color",
value: style.color || defaultGroupStyle.color ||"#a4a4a4",
defaultValue: "#a4a4a4",
palette: colorPalette,
cellPerRow: colorCount,
cellWidth: 16,

0
packages/node_modules/@node-red/editor-client/src/js/ui/library.js vendored Executable file → Normal file
View File

View File

@@ -0,0 +1,46 @@
// Mermaid diagram stub library for on-demand dynamic loading
// Will be overwritten after script loading by $.getScript
var mermaid = (function () {
var enabled /* = undefined */;
var initializing = false;
var initCalled = false;
function initialize(opt) {
if (enabled === undefined) {
if (RED.settings.markdownEditor &&
RED.settings.markdownEditor.mermaid) {
enabled = RED.settings.markdownEditor.mermaid.enabled;
}
else {
enabled = true;
}
}
if (enabled) {
initializing = true;
$.getScript("vendor/mermaid/mermaid.min.js",
function (data, stat, jqxhr) {
$(".mermaid").show();
// invoke loaded mermaid API
initializing = false;
mermaid.initialize(opt);
if (initCalled) {
mermaid.init();
initCalled = false;
}
});
}
}
function init() {
if (initializing) {
$(".mermaid").hide();
initCalled = true;
}
}
return {
initialize: initialize,
init: init,
};
})();

16
packages/node_modules/@node-red/editor-client/src/js/ui/palette.js vendored Executable file → Normal file
View File

@@ -175,9 +175,19 @@ RED.palette = (function() {
$('<button type="button" onclick="RED.workspaces.show(\''+type.substring(8).replace(/'/g,"\\'")+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-pencil"></i></button>').appendTo(popOverContent)
}
var safeType = type.replace(/'/g,"\\'");
const safeType = type.replace(/'/g,"\\'");
const wrapStr = function (str) {
if(str.indexOf(' ') >= 0) {
return '"' + str + '"'
}
return str
}
$('<button type="button" onclick="RED.search.show(\'type:'+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>').appendTo(popOverContent)
$('<button type="button"; return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-search"></i></button>')
.appendTo(popOverContent)
.on('click', function() {
RED.search.show('type:' + wrapStr(safeType))
})
$('<button type="button" onclick="RED.sidebar.help.show(\''+safeType+'\'); return false;" class="red-ui-button red-ui-button-small" style="float: right; margin-left: 5px;"><i class="fa fa-book"></i></button>').appendTo(popOverContent)
$('<p>',{style:"font-size: 0.8em"}).text(metaData).appendTo(popOverContent);
@@ -428,6 +438,7 @@ RED.palette = (function() {
categoryNode.find(".red-ui-palette-content").slideToggle();
categoryNode.find("i").toggleClass("expanded");
}
categoryNode.hide();
}
}
@@ -506,6 +517,7 @@ RED.palette = (function() {
currentCategoryNode.find(".red-ui-palette-content").slideToggle();
currentCategoryNode.find("i").toggleClass("expanded");
}
currentCategoryNode.hide();
}
}

View File

@@ -545,7 +545,7 @@ RED.projects = (function() {
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.clone-project.ssh-key-desc")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).on("click", function(e) {
e.preventDefault();
dialog.dialog( "close" );
RED.userSettings.show('gitconfig');
@@ -1171,11 +1171,11 @@ RED.projects = (function() {
row = $('<div class="form-row button-group"></div>').appendTo(container);
var openProject = $('<button data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
var openProject = $('<button type="button" data-type="open" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button type="button" data-type="empty" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button type="button" data-type="copy" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button type="button" data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button type="button" data-type="clone" class="red-ui-button red-ui-projects-dialog-button red-ui-projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
row.find(".red-ui-projects-dialog-screen-create-type").on("click", function(evt) {
evt.preventDefault();
container.find(".red-ui-projects-dialog-screen-create-type").removeClass('selected');
@@ -1271,7 +1271,7 @@ RED.projects = (function() {
var credentialsLeftBox = $('<div class="red-ui-projects-dialog-credentials-box-left">').appendTo(credentialsBox);
var credentialsEnabledBox = $('<div class="form-row red-ui-projects-dialog-credentials-box-enabled"></div>').appendTo(credentialsLeftBox);
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="enabled"> <i class="fa fa-lock"></i> <span>'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="enabled" checked> <i class="fa fa-lock"></i> <span>'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
var credentialsDisabledBox = $('<div class="form-row red-ui-projects-dialog-credentials-box-disabled disabled"></div>').appendTo(credentialsLeftBox);
$('<label class="red-ui-projects-edit-form-inline-label"><input type="radio" name="projects-encryption-type" value="disabled"> <i class="fa fa-unlock"></i> <span>'+RED._("projects.encryption-config.disable")+'</span></label>').appendTo(credentialsDisabledBox);
@@ -1397,7 +1397,7 @@ RED.projects = (function() {
var sshwarningRow = $('<div class="red-ui-projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.create.desc2")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).on("click", function(e) {
e.preventDefault();
$('#red-ui-projects-dialog-cancel').trigger("click");
RED.userSettings.show('gitconfig');
@@ -1631,14 +1631,14 @@ RED.projects = (function() {
function deleteProject(row,name,done) {
var cover = $('<div class="red-ui-projects-dialog-project-list-entry-delete-confirm"></div>').on("click", function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button">'+RED._("common.label.cancel")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
cover.remove();
done(true);
});
$('<button class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button primary">'+RED._("common.label.delete")+'</button>')
.appendTo(cover)
.on("click", function(e) {
e.stopPropagation();
@@ -1822,7 +1822,7 @@ RED.projects = (function() {
header.addClass("selectable");
var tools = $('<div class="red-ui-projects-dialog-project-list-entry-tools"></div>').appendTo(header);
$('<button class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
$('<button type="button" class="red-ui-button red-ui-projects-dialog-button red-ui-button-small" style="float: right;"><i class="fa fa-trash"></i></button>')
.appendTo(tools)
.on("click", function(e) {
e.stopPropagation();

View File

@@ -106,38 +106,51 @@ RED.search = (function() {
return val;
}
function search(val) {
var results = [];
var typeFilter;
var m = /(?:^| )type:([^ ]+)/.exec(val);
if (m) {
val = val.replace(/(?:^| )type:[^ ]+/,"");
typeFilter = m[1];
function extractType(val, flags) {
// extracts: type:XYZ & type:"X Y Z"
const regEx = /(?:type):\s*(?:"([^"]+)"|([^" ]+))/;
let m
while ((m = regEx.exec(val)) !== null) {
// avoid infinite loops with zero-width matches
if (m.index === regEx.lastIndex) {
regEx.lastIndex++;
}
val = val.replace(m[0]," ").trim()
const flag = m[2] || m[1] // quoted entries in capture group 1, unquoted in capture group 2
flags.type = flags.type || [];
flags.type.push(flag);
}
var flags = {};
return val;
}
function search(val) {
const results = [];
const flags = {};
val = extractFlag(val,"invalid",flags);
val = extractFlag(val,"unused",flags);
val = extractFlag(val,"config",flags);
val = extractFlag(val,"subflow",flags);
val = extractFlag(val,"hidden",flags);
val = extractFlag(val,"modified",flags);
val = extractValue(val,"flow",flags);// flow:active or flow:<flow-id>
val = extractValue(val,"flow",flags);// flow:current or flow:<flow-id>
val = extractValue(val,"uses",flags);// uses:<node-id>
val = extractType(val,flags);// type:<node-type>
val = val.trim();
var hasFlags = Object.keys(flags).length > 0;
const hasFlags = Object.keys(flags).length > 0;
const hasTypeFilter = flags.type && flags.type.length > 0
if (flags.flow && flags.flow.indexOf("current") >= 0) {
let idx = flags.flow.indexOf("current");
flags.flow[idx] = RED.workspaces.active();//convert active to flow ID
flags.flow[idx] = RED.workspaces.active();//convert 'current' to active flow ID
}
if (flags.flow && flags.flow.length) {
flags.flow = [ ...new Set(flags.flow) ]; //deduplicate
}
if (val.length > 0 || typeFilter || hasFlags) {
if (val.length > 0 || hasFlags) {
val = val.toLowerCase();
var i;
var j;
var list = [];
var nodes = {};
let i;
let j;
let list = [];
const nodes = {};
let keys = [];
if (flags.uses) {
keys = flags.uses;
@@ -145,10 +158,10 @@ RED.search = (function() {
keys = Object.keys(index);
}
for (i=0;i<keys.length;i++) {
var key = keys[i];
var kpos = keys[i].indexOf(val);
if (kpos > -1) {
var ids = Object.keys(index[key]||{});
const key = keys[i];
const kpos = val ? keys[i].indexOf(val) : -1;
if (kpos > -1 || (val === "" && hasFlags)) {
const ids = Object.keys(index[key]||{});
for (j=0;j<ids.length;j++) {
var node = index[key][ids[j]];
var isConfigNode = node.node._def.category === "config" && node.node.type !== 'group';
@@ -156,7 +169,7 @@ RED.search = (function() {
continue;
}
if (flags.hasOwnProperty("invalid")) {
var nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
const nodeIsValid = !node.node.hasOwnProperty("valid") || node.node.valid;
if (flags.invalid === nodeIsValid) {
continue;
}
@@ -186,8 +199,8 @@ RED.search = (function() {
}
}
if (flags.hasOwnProperty("unused")) {
var isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0)
const isUnused = (node.node.type === 'subflow' && node.node.instances.length === 0) ||
(isConfigNode && node.node.users.length === 0 && node.node._def.hasUsers !== false)
if (flags.unused !== isUnused) {
continue;
}
@@ -197,12 +210,16 @@ RED.search = (function() {
continue;
}
}
if (!typeFilter || node.node.type === typeFilter) {
nodes[node.node.id] = nodes[node.node.id] = {
let typeIndex = -1
if(hasTypeFilter) {
typeIndex = flags.type.indexOf(node.node.type)
}
if (!hasTypeFilter || typeIndex > -1) {
nodes[node.node.id] = nodes[node.node.id] || {
node: node.node,
label: node.label
};
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
nodes[node.node.id].index = Math.min(nodes[node.node.id].index || Infinity, typeIndex > -1 ? typeIndex : kpos);
}
}
}
@@ -538,7 +555,7 @@ RED.search = (function() {
$(previousActiveElement).trigger("focus");
}
previousActiveElement = null;
}
}
if(!keepSearchToolbar) {
clearActiveSearch();
}
@@ -630,7 +647,7 @@ RED.search = (function() {
$("#red-ui-sidebar-shade").on('mousedown',hide);
$("#red-ui-view-searchtools-close").on("click", function close() {
clearActiveSearch();
clearActiveSearch();
updateSearchToolbar();
});
$("#red-ui-view-searchtools-close").trigger("click");

View File

@@ -521,6 +521,13 @@ RED.subflow = (function() {
RED.nodes.groups(id).forEach(function(n) {
removedGroups.push(n);
})
var removedJunctions = RED.nodes.junctions(id)
for (var i=0;i<removedJunctions.length;i++) {
var removedEntities = RED.nodes.removeJunction(removedJunctions[i])
removedLinks = removedLinks.concat(removedEntities.links)
}
var removedConfigNodes = [];
for (var i=0;i<removedNodes.length;i++) {
var removedEntities = RED.nodes.remove(removedNodes[i].id);
@@ -551,6 +558,7 @@ RED.subflow = (function() {
nodes:removedNodes,
links:removedLinks,
groups: removedGroups,
junctions: removedJunctions,
subflows: [activeSubflow]
}
}
@@ -950,7 +958,6 @@ RED.subflow = (function() {
function buildEnvUIRow(row, tenv, ui, node) {
console.log(tenv, ui)
ui.label = ui.label||{};
if ((tenv.type === "cred" || (tenv.parent && tenv.parent.type === "cred")) && !ui.type) {
ui.type = "cred";

View File

@@ -50,7 +50,7 @@ RED.sidebar.help = (function() {
tocPanel = $("<div>", {class: "red-ui-sidebar-help-toc"}).appendTo(stackContainer);
var helpPanel = $("<div>").css({
"overflow-y": "scroll"
"overflow-y": "auto"
}).appendTo(stackContainer);
panels = RED.panels.create({

View File

@@ -108,7 +108,7 @@ RED.sidebar.info = (function() {
propertiesPanelContent = $("<div>").css({
"flex":"1 1 auto",
"overflow-y":"scroll",
"overflow-y":"auto",
}).appendTo(propertiesPanel);
@@ -463,7 +463,8 @@ RED.sidebar.info = (function() {
el = el.next();
}
$(this).toggleClass('expanded',!isExpanded);
})
});
mermaid.init();
}
var tips = (function() {

View File

@@ -269,8 +269,8 @@ RED.typeSearch = (function() {
moveCallback = opts.move;
RED.events.emit("type-search:open");
//shade.show();
if ($("#red-ui-main-container").height() - opts.y - 150 < 0) {
opts.y = opts.y - 235;
if ($("#red-ui-main-container").height() - opts.y - 195 < 0) {
opts.y = opts.y - 275;
}
dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
searchResultsDiv.slideDown(300);

View File

@@ -96,6 +96,37 @@ RED.utils = (function() {
}
}
var mermaidIsInitialized = false;
var mermaidIsEnabled /* = undefined */;
renderer.code = function (code, lang) {
if(lang === "mermaid") {
// mermaid diagram rendering
if (mermaidIsEnabled === undefined) {
if (RED.settings.markdownEditor &&
RED.settings.markdownEditor.mermaid) {
mermaidIsEnabled = RED.settings.markdownEditor.mermaid.enabled;
}
else {
mermaidIsEnabled = true;
}
}
if (mermaidIsEnabled) {
if (!mermaidIsInitialized) {
mermaidIsInitialized = true;
mermaid.initialize({startOnLoad:false});
}
return `<pre class='mermaid'>${code}</pre>`;
}
else {
return `<details><summary>${RED._("markdownEditor.mermaid.summary")}</summary><pre><code>${code}</code></pre></details>`;
}
}
else {
return "<pre><code>" +code +"</code></pre>";
}
};
window._marked.setOptions({
renderer: renderer,
gfm: true,

View File

@@ -1043,7 +1043,7 @@ RED.view.tools = (function() {
const nodeDef = n._def || RED.nodes.getType(n.type)
if (nodeDef && nodeDef.defaults && nodeDef.defaults.name) {
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
const defaultNodeNameRE = new RegExp('^'+paletteLabel+' (\\d+)$')
const defaultNodeNameRE = new RegExp('^'+paletteLabel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')+' (\\d+)$')
if (!typeIndex.hasOwnProperty(n.type)) {
const existingNodes = RED.nodes.filterNodes({type: n.type})
let maxNameNumber = 0;
@@ -1242,7 +1242,7 @@ RED.view.tools = (function() {
url += '/edit'
}
if (RED.clipboard.copyText(url)) {
RED.notify('Copied url to clipboard', { timeout: 2000 })
RED.notify(RED._("sidebar.info.copyURL2Clipboard"), { timeout: 2000 })
}
}
}

75
packages/node_modules/@node-red/editor-client/src/js/ui/view.js vendored Executable file → Normal file
View File

@@ -1105,12 +1105,15 @@ RED.view = (function() {
RED.view.redraw();
}
// `point` is the place in the workspace the mouse has clicked.
// This takes into account scrolling and scaling of the workspace.
var ox = point[0];
var oy = point[1];
// Need to map that to browser location to position the pop-up
const offset = $("#red-ui-workspace-chart").offset()
var clientX = ox + offset.left - $("#red-ui-workspace-chart").scrollLeft()
var clientY = oy + offset.top - $("#red-ui-workspace-chart").scrollTop()
var clientX = (ox * scaleFactor) + offset.left - $("#red-ui-workspace-chart").scrollLeft()
var clientY = (oy * scaleFactor) + offset.top - $("#red-ui-workspace-chart").scrollTop()
if (RED.settings.get("editor").view['view-snap-grid']) {
// eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
@@ -3413,6 +3416,9 @@ RED.view = (function() {
d3.event.stopPropagation();
return
}
// Avoid dbl click causing text selection.
d3.event.preventDefault()
document.getSelection().removeAllRanges()
if (d.type != "subflow") {
if (/^subflow:/.test(d.type) && (d3.event.ctrlKey || d3.event.metaKey)) {
RED.workspaces.show(d.type.substring(8));
@@ -4954,7 +4960,7 @@ 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')) {
if (RED.runtime && RED.runtime.started !== undefined) {
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-stopped", !RED.runtime.started);
}
@@ -5651,7 +5657,24 @@ RED.view = (function() {
if (activeSubflow) {
activeSubflowChanged = activeSubflow.changed;
}
var result = RED.nodes.import(nodesToImport,{generateIds:options.generateIds, addFlow: addNewFlow, importMap: options.importMap});
var filteredNodesToImport = nodesToImport;
var globalConfig = null;
var gconf = null;
RED.nodes.eachConfig(function (conf) {
if (conf.type === "global-config") {
gconf = conf;
}
});
if (gconf) {
filteredNodesToImport = nodesToImport.filter(function (n) {
return (n.type !== "global-config");
});
globalConfig = nodesToImport.find(function (n) {
return (n.type === "global-config");
});
}
var result = RED.nodes.import(filteredNodesToImport,{generateIds:options.generateIds, addFlow: addNewFlow, importMap: options.importMap});
if (result) {
var new_nodes = result.nodes;
var new_links = result.links;
@@ -5783,6 +5806,50 @@ RED.view = (function() {
}
}
if (globalConfig) {
// merge global env to existing global-config
var env0 = gconf.env;
var env1 = globalConfig.env;
var newEnv = Array.from(env0);
var changed = false;
env1.forEach(function (item1) {
var index = newEnv.findIndex(function (item0) {
return (item0.name === item1.name);
});
if (index >= 0) {
var item0 = newEnv[index];
if ((item0.type !== item1.type) ||
(item0.value !== item1.value)) {
newEnv[index] = item1;
changed = true;
}
}
else {
newEnv.push(item1);
changed = true;
}
});
if(changed) {
gconf.env = newEnv;
var replaceEvent = {
t: "edit",
node: gconf,
changed: true,
changes: {
env: env0
}
};
historyEvent = {
t:"multi",
events: [
replaceEvent,
historyEvent,
]
};
}
}
RED.history.push(historyEvent);
updateActiveNodes();

View File

@@ -152,6 +152,13 @@ RED.workspaces = (function() {
const hiddenflowCount = hiddenFlows.size;
let activeWorkspace = tab || RED.nodes.workspace(RED.workspaces.active()) || RED.nodes.subflow(RED.workspaces.active())
let isFlowDisabled = activeWorkspace ? activeWorkspace.disabled : false
const currentTabs = workspace_tabs.listTabs();
let flowCount = 0;
currentTabs.forEach(tab => {
if (RED.nodes.workspace(tab)) {
flowCount++;
}
});
let isCurrentLocked = RED.workspaces.isActiveLocked()
if (tab) {
@@ -224,8 +231,7 @@ RED.workspaces = (function() {
null
)
}
const currentTabs = workspace_tabs.listTabs()
const activeIndex = currentTabs.findIndex(id => id === activeWorkspace.id)
const activeIndex = currentTabs.findIndex(id => (activeWorkspace && (id === activeWorkspace.id)));
menuItems.push(
{
label: RED._("workspace.moveToStart"),
@@ -267,11 +273,13 @@ RED.workspaces = (function() {
)
}
menuItems.push(
{
id:"red-ui-tabs-menu-option-add-hide-all-flows",
label: RED._("workspace.hideAllFlows"),
onselect: "core:hide-all-flows"
onselect: "core:hide-all-flows",
disabled: (hiddenflowCount === flowCount)
},
{
id:"red-ui-tabs-menu-option-add-show-all-flows",
@@ -298,7 +306,8 @@ RED.workspaces = (function() {
} else if (tab.type === 'subflow') {
RED.subflow.delete(tab.id)
}
}
},
disabled: (workspaceTabCount === 1)
},
{
label: RED._("menu.label.export"),