1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add copy path/value buttons to debug messages

This commit is contained in:
Nick O'Leary 2017-05-10 15:49:12 +01:00
parent a84efeb5d5
commit 00460d856b
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
10 changed files with 306 additions and 90 deletions

View File

@ -270,10 +270,44 @@ RED.clipboard = (function() {
$("#dropTarget").hide(); $("#dropTarget").hide();
RED.keyboard.remove("escape"); RED.keyboard.remove("escape");
} }
function copyText(value,element,msg) {
var truncated = false;
if (typeof value !== "string" ) {
value = JSON.stringify(value, function(key,value) {
if (value !== null && typeof value === 'object') {
if (value.__encoded__ && value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
truncated = value.data.length !== value.length;
return value.data;
}
}
return value;
});
}
if (truncated) {
msg += "_truncated";
}
$("#clipboard-hidden").val(value).select();
var result = document.execCommand("copy");
if (result && element) {
var popover = RED.popover.create({
target: element,
direction: 'left',
size: 'small',
content: RED._(msg)
});
setTimeout(function() {
popover.close();
},1000);
popover.open();
}
return result;
}
return { return {
init: function() { init: function() {
setupDialogs(); setupDialogs();
$('<input type="text" id="clipboard-hidden">').appendTo("body");
RED.events.on("view:selection-changed",function(selection) { RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) { if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true); RED.menu.setDisabled("menu-item-export",true);
@ -339,6 +373,7 @@ RED.clipboard = (function() {
}, },
import: importNodes, import: importNodes,
export: exportNodes export: exportNodes,
copyText: copyText
} }
})(); })();

View File

@ -15,26 +15,61 @@
**/ **/
RED.popover = (function() { RED.popover = (function() {
var deltaSizes = {
"default": {
top: 10,
leftRight: 17,
leftLeft: 25
},
"small": {
top: 5,
leftRight: 8,
leftLeft: 16
}
}
function createPopover(options) { function createPopover(options) {
var target = options.target; var target = options.target;
var direction = options.direction || "right";
var trigger = options.trigger;
var content = options.content; var content = options.content;
var delay = options.delay; var delay = options.delay;
var width = options.width||"auto";
var size = options.size||"default";
if (!deltaSizes[size]) {
throw new Error("Invalid RED.popover size value:",size);
}
var timer = null; var timer = null;
var active; var active;
var div; var div;
var openPopup = function() { var openPopup = function() {
if (active) { if (active) {
div = $('<div class="red-ui-popover"></div>').html(content).appendTo("body"); div = $('<div class="red-ui-popover red-ui-popover-'+direction+'"></div>').appendTo("body");
if (size !== "default") {
div.addClass("red-ui-popover-size-"+size);
}
if (typeof content === 'function') {
content.call(res).appendTo(div);
} else {
div.html(content);
}
if (width !== "auto") {
div.width(width);
}
var targetPos = target.offset(); var targetPos = target.offset();
var targetWidth = target.width(); var targetWidth = target.width();
var targetHeight = target.height(); var targetHeight = target.height();
var divHeight = div.height(); var divHeight = div.height();
div.css({top: targetPos.top+targetHeight/2-divHeight/2-10,left:targetPos.left+targetWidth+17}); var divWidth = div.width();
if (direction === 'right') {
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left+targetWidth+deltaSizes[size].leftRight});
} else if (direction === 'left') {
div.css({top: targetPos.top+targetHeight/2-divHeight/2-deltaSizes[size].top,left:targetPos.left-deltaSizes[size].leftLeft-divWidth});
}
div.fadeIn("fast"); div.fadeIn("fast");
} }
@ -50,6 +85,8 @@ RED.popover = (function() {
} }
} }
if (trigger === 'hover') {
target.on('mouseenter',function(e) { target.on('mouseenter',function(e) {
clearTimeout(timer); clearTimeout(timer);
active = true; active = true;
@ -62,12 +99,31 @@ RED.popover = (function() {
active = false; active = false;
setTimeout(closePopup,delay.hide); setTimeout(closePopup,delay.hide);
}); });
} else if (trigger === 'click') {
target.click(function(e) {
e.preventDefault();
e.stopPropagation();
active = !active;
if (!active) {
closePopup();
} else {
openPopup();
}
});
}
var res = { var res = {
setContent: function(_content) { setContent: function(_content) {
content = _content; content = _content;
},
open: function () {
active = true;
openPopup();
},
close: function () {
active = false;
closePopup();
} }
} }
target.data('popover',res);
return res; return res;
} }

View File

@ -185,11 +185,14 @@ RED.palette = (function() {
$("#palette-"+category).append(d); $("#palette-"+category).append(d);
d.onmousedown = function(e) { e.preventDefault(); }; d.onmousedown = function(e) { e.preventDefault(); };
RED.popover.create({ var popover = RED.popover.create({
target:$(d), target:$(d),
trigger: "hover",
width: "300px",
content: "hi", content: "hi",
delay: { show: 750, hide: 50 } delay: { show: 750, hide: 50 }
}); });
$(d).data('popover',popover);
// $(d).popover({ // $(d).popover({
// title:d.type, // title:d.type,

View File

@ -31,7 +31,7 @@ RED.utils = (function() {
result = $('<span class="debug-message-object-value debug-message-type-null">null</span>'); result = $('<span class="debug-message-object-value debug-message-type-null">null</span>');
} else if (typeof value === 'object') { } else if (typeof value === 'object') {
if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) { if (value.hasOwnProperty('type') && value.type === 'Buffer' && value.hasOwnProperty('data')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.data.length+']'); result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('buffer['+value.length+']');
} else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) { } else if (value.hasOwnProperty('type') && value.type === 'array' && value.hasOwnProperty('data')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']'); result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
} else { } else {
@ -66,8 +66,22 @@ RED.utils = (function() {
e.preventDefault(); e.preventDefault();
}); });
} }
function addMessageControls(obj,key,msg) {
var tools = $('<span class="debug-message-tools button-group"></span>').appendTo(obj);
var copyPath = $('<button class="editor-button editor-button-small"><i class="fa fa-terminal"></i></button>').appendTo(tools).click(function(e) {
e.preventDefault();
e.stopPropagation();
RED.clipboard.copyText(key,copyPath,"clipboard.copyMessagePath");
})
var copyPayload = $('<button class="editor-button editor-button-small"><i class="fa fa-clipboard"></i></button>').appendTo(tools).click(function(e) {
e.preventDefault();
e.stopPropagation();
RED.clipboard.copyText(msg,copyPayload,"clipboard.copyMessageValue");
})
function buildMessageElement(obj,key,typeHint,hideKey) { }
function buildMessageElement(obj,key,typeHint,hideKey,path) {
var i; var i;
var e; var e;
var entryObj; var entryObj;
@ -75,16 +89,16 @@ RED.utils = (function() {
var headerHead; var headerHead;
var value; var value;
var element = $('<span class="debug-message-element"></span>'); var element = $('<span class="debug-message-element"></span>');
header = $('<span class="debug-message-row"></span>').appendTo(element);
addMessageControls(header,path,obj);
if (!key) { if (!key) {
element.addClass("debug-message-top-level"); element.addClass("debug-message-top-level");
} } else {
if (!hideKey) {
header = $('<span></span>').appendTo(element);
if (key && !hideKey) {
$('<span class="debug-message-object-key"></span>').text(key).appendTo(header); $('<span class="debug-message-object-key"></span>').text(key).appendTo(header);
$('<span>: </span>').appendTo(header); $('<span>: </span>').appendTo(header);
} }
}
entryObj = $('<span class="debug-message-object-value"></span>').appendTo(header); entryObj = $('<span class="debug-message-object-value"></span>').appendTo(header);
var isArray = Array.isArray(obj); var isArray = Array.isArray(obj);
@ -166,6 +180,7 @@ RED.utils = (function() {
if (type === 'buffer') { if (type === 'buffer') {
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element); var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
var sr = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(stringRow); var sr = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(stringRow);
var stringEncoding = ""; var stringEncoding = "";
try { try {
stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data)) stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data))
@ -190,7 +205,7 @@ RED.utils = (function() {
if (fullLength <= 10) { if (fullLength <= 10) {
for (i=0;i<fullLength;i++) { for (i=0;i<fullLength;i++) {
row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows); row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows);
buildMessageElement(data[i],""+i,false).appendTo(row); buildMessageElement(data[i],""+i,false,false,path+"["+i+"]").appendTo(row);
} }
} else { } else {
for (i=0;i<fullLength;i+=10) { for (i=0;i<fullLength;i+=10) {
@ -205,7 +220,7 @@ RED.utils = (function() {
return function() { return function() {
for (var i=min;i<=max;i++) { for (var i=min;i<=max;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent); var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent);
buildMessageElement(data[i],""+i,false).appendTo(row); buildMessageElement(data[i],""+i,false,false,path+"["+i+"]").appendTo(row);
} }
} }
})()); })());
@ -249,7 +264,13 @@ RED.utils = (function() {
} }
for (i=0;i<keys.length;i++) { for (i=0;i<keys.length;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element); var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
buildMessageElement(obj[keys[i]],keys[i],false).appendTo(row); var newPath = path;
if (/^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(keys[i])) {
newPath += "."+keys[i];
} else {
newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]"
}
buildMessageElement(obj[keys[i]],keys[i],false,false,newPath).appendTo(row);
} }
if (keys.length === 0) { if (keys.length === 0) {
$('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element); $('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element);
@ -405,6 +426,6 @@ RED.utils = (function() {
createObjectElement: buildMessageElement, createObjectElement: buildMessageElement,
validatePropertyExpression: validatePropertyExpression, validatePropertyExpression: validatePropertyExpression,
getNodeIcon: getNodeIcon, getNodeIcon: getNodeIcon,
getNodeLabel: getNodeLabel getNodeLabel: getNodeLabel,
} }
})(); })();

View File

@ -46,11 +46,31 @@
} }
.debug-message { .debug-message {
position: relative;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
border-left: 8px solid #eee; border-left: 8px solid #eee;
border-right: 8px solid #eee; border-right: 8px solid #eee;
padding: 2px; padding: 2px;
&.debug-message-hover {
border-right-color: #999;
&>.debug-message-meta .debug-message-tools {
display: inline-block;
}
}
} }
.debug-message-row .debug-message-tools .editor-button-small {
height: 16px;
line-height: 14px;
font-size: 8px;
border-radius: 1px;
padding: 0 3px;
}
.debug-message-row:hover {
&>.debug-message-tools {
display: inline-block;
}
}
.debug-message-meta { .debug-message-meta {
background: #fff; background: #fff;
font-size: 10px; font-size: 10px;
@ -67,6 +87,12 @@
padding: 1px 5px; padding: 1px 5px;
color: #777; color: #777;
} }
.debug-message-tools {
position: absolute;
top: 3px;
right: 1px;
display: none;
}
.debug-message-payload { .debug-message-payload {
display: block; display: block;
padding: 2px; padding: 2px;
@ -85,9 +111,8 @@
border-right-color: #f99; border-right-color: #f99;
} }
.debug-message-object-entry { .debug-message-object-entry {
position: relative;
padding-left: 15px; padding-left: 15px;
padding-bottom: 3px;
padding-top: 3px;
} }
.debug-message-element { .debug-message-element {
color: #333; color: #333;
@ -153,12 +178,17 @@
.debug-message-type-number { color: #2033d6; }; .debug-message-type-number { color: #2033d6; };
.debug-message-type-number-toggle { cursor: pointer;} .debug-message-type-number-toggle { cursor: pointer;}
.debug-message-row {
display: block;
padding: 4px 2px 2px;
position: relative;
&:hover {
background: #f3f3f3;
}
}
.debug-message-expandable { .debug-message-expandable {
cursor: pointer; cursor: pointer;
} }
.debug-message-expandable:hover {
background: #fefefe;
}
.debug-message-expandable:hover .debug-message-object-handle { .debug-message-expandable:hover .debug-message-object-handle {
color: #b72828 !important; color: #b72828 !important;
} }

View File

@ -292,3 +292,8 @@
border-color: $primary-border-color; border-color: $primary-border-color;
} }
} }
#clipboard-hidden {
position: absolute;
top: -3000px;
}

View File

@ -15,10 +15,10 @@
**/ **/
.red-ui-popover { .red-ui-popover {
display: none; display: none;
position: absolute; position: absolute;
width: 300px; width: auto;
padding: 10px; padding: 10px;
height: auto; height: auto;
background: #fff; background: #fff;
@ -27,9 +27,9 @@
font-size: 14px; font-size: 14px;
line-height: 1.4em; line-height: 1.4em;
@include component-shadow; @include component-shadow;
} }
.red-ui-popover:after, .red-ui-popover:before {
right: 100%; .red-ui-popover:after, .red-ui-popover:before {
top: 50%; top: 50%;
border: solid transparent; border: solid transparent;
content: " "; content: " ";
@ -37,17 +37,60 @@
width: 0; width: 0;
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
} }
.red-ui-popover.red-ui-popover-right:after, .red-ui-popover.red-ui-popover-right:before {
right: 100%;
}
.red-ui-popover.red-ui-popover-left:after, .red-ui-popover.red-ui-popover-left:before {
left: 100%;
}
.red-ui-popover:after {
.red-ui-popover.red-ui-popover-right:after {
border-color: rgba(136, 183, 213, 0); border-color: rgba(136, 183, 213, 0);
border-right-color: #fff; border-right-color: #fff;
border-width: 10px; border-width: 10px;
margin-top: -10px; margin-top: -10px;
} }
.red-ui-popover:before { .red-ui-popover.red-ui-popover-right:before {
border-color: rgba(194, 225, 245, 0); border-color: rgba(194, 225, 245, 0);
border-right-color: $primary-border-color; border-right-color: $primary-border-color;
border-width: 11px; border-width: 11px;
margin-top: -11px; margin-top: -11px;
}
.red-ui-popover.red-ui-popover-left:after {
border-color: rgba(136, 183, 213, 0);
border-left-color: #fff;
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover.red-ui-popover-left:before {
border-color: rgba(194, 225, 245, 0);
border-left-color: $primary-border-color;
border-width: 11px;
margin-top: -11px;
}
.red-ui-popover-size-small {
font-size: 11px;
padding: 5px;
&.red-ui-popover-right:after {
border-width: 5px;
margin-top: -5px;
} }
&.red-ui-popover-right:before {
border-width: 6px;
margin-top: -6px;
}
&.red-ui-popover-left:after {
border-width: 5px;
margin-top: -5px;
}
&.red-ui-popover-left:before {
border-width: 6px;
margin-top: -6px;
}
}

View File

@ -90,10 +90,9 @@ module.exports = function(RED) {
msg.msg = msg.msg.toString('hex'); msg.msg = msg.msg.toString('hex');
if (msg.msg.length > debuglength) { if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substring(0,debuglength); msg.msg = msg.msg.substring(0,debuglength);
msg.modified = true;
} }
} else if (msg.msg && typeof msg.msg === 'object') { } else if (msg.msg && typeof msg.msg === 'object') {
var seen = [];
var seenAts = [];
try { try {
msg.format = msg.msg.constructor.name || "Object"; msg.format = msg.msg.constructor.name || "Object";
// Handle special case of msg.req/res objects from HTTP In node // Handle special case of msg.req/res objects from HTTP In node
@ -113,38 +112,54 @@ module.exports = function(RED) {
if (isArray) { if (isArray) {
msg.format = "array["+msg.msg.length+"]"; msg.format = "array["+msg.msg.length+"]";
if (msg.msg.length > debuglength) { if (msg.msg.length > debuglength) {
msg.msg = msg.msg.slice(0,debuglength); // msg.msg = msg.msg.slice(0,debuglength);
msg.msg = {
__encoded__: true,
type: "array",
data: msg.msg.slice(0,debuglength),
length: msg.msg.length
}
msg.modified = true;
} }
} }
if (isArray || (msg.format === "Object")) { if (isArray || (msg.format === "Object")) {
var modified = false;
msg.msg = safeJSONStringify(msg.msg, function(key, value) { msg.msg = safeJSONStringify(msg.msg, function(key, value) {
if (key === '_req' || key === '_res') { if (key === '_req' || key === '_res') {
return "[internal]" value = "[internal]"
} } else if (value instanceof Error) {
if (value instanceof Error) { value = value.toString()
return value.toString() } else if (util.isArray(value) && value.length > debuglength) {
}
if (util.isArray(value) && value.length > debuglength) {
value = { value = {
__encoded__: true, __encoded__: true,
type: "array", type: "array",
data: value.slice(0,debuglength), data: value.slice(0,debuglength),
length: value.length length: value.length
} }
} modified = true;
if (typeof value === 'string') { } else if (typeof value === 'string') {
if (value.length > debuglength) { if (value.length > debuglength) {
return value.substring(0,debuglength)+"..."; modified = true;
value = value.substring(0,debuglength)+"...";
}
} else if (value !== null && typeof value === 'object' && value.type === "Buffer") {
value.__encoded__ = true;
value.length = value.data.length;
if (value.length > debuglength) {
value.data = value.data.slice(0,debuglength);
modified = true;
} }
} }
return value; return value;
}," "); }," ");
if (modified) {
msg.modified = modified;
}
} else { } else {
try { msg.msg = msg.msg.toString(); } try { msg.msg = msg.msg.toString(); }
catch(e) { msg.msg = "[Type not printable]"; } catch(e) { msg.msg = "[Type not printable]"; }
} }
} }
seen = null;
} else if (typeof msg.msg === "boolean") { } else if (typeof msg.msg === "boolean") {
msg.format = "boolean"; msg.format = "boolean";
msg.msg = msg.msg.toString(); msg.msg = msg.msg.toString();
@ -161,6 +176,7 @@ module.exports = function(RED) {
msg.format = "string["+msg.msg.length+"]"; msg.format = "string["+msg.msg.length+"]";
if (msg.msg.length > debuglength) { if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substring(0,debuglength)+"..."; msg.msg = msg.msg.substring(0,debuglength)+"...";
msg.modified = true;
} }
} }
// if (msg.msg.length > debuglength) { // if (msg.msg.length > debuglength) {

View File

@ -184,13 +184,13 @@ RED.debug = (function() {
var sourceNode = o._source; var sourceNode = o._source;
msg.onmouseenter = function() { msg.onmouseenter = function() {
msg.style.borderRightColor = "#999"; $(msg).addClass('debug-message-hover');
if (o._source) { if (o._source) {
config.messageMouseEnter(o._source.id); config.messageMouseEnter(o._source.id);
} }
}; };
msg.onmouseleave = function() { msg.onmouseleave = function() {
msg.style.borderRightColor = ""; $(msg).removeClass('debug-message-hover');
if (o._source) { if (o._source) {
config.messageMouseLeave(o._source.id); config.messageMouseLeave(o._source.id);
} }
@ -225,6 +225,9 @@ RED.debug = (function() {
$(msg).addClass('debug-message-level-' + errorLvl); $(msg).addClass('debug-message-level-' + errorLvl);
$('<span class="debug-message-topic">function : (' + errorLvlType + ')</span>').appendTo(metaRow); $('<span class="debug-message-topic">function : (' + errorLvlType + ')</span>').appendTo(metaRow);
} else { } else {
// var tools = $('<span class="debug-message-tools button-group"></span>').appendTo(metaRow);
// var filterMessage = $('<button class="editor-button editor-button-small"><i class="fa fa-filter"></i></button>').appendTo(tools);
$('<span class="debug-message-topic">'+ $('<span class="debug-message-topic">'+
(o.topic?topic+' : ':'')+ (o.topic?topic+' : ':'')+
(o.property?'msg.'+property:'msg')+" : "+format+ (o.property?'msg.'+property:'msg')+" : "+format+
@ -247,7 +250,8 @@ RED.debug = (function() {
} }
} }
var el = $('<span class="debug-message-payload"></span>').appendTo(msg); var el = $('<span class="debug-message-payload"></span>').appendTo(msg);
RED.utils.createObjectElement(payload,/*true*/null,format).appendTo(el); var path = (o.property?'msg.'+property:'msg');
RED.utils.createObjectElement(payload,/*true*/null,format,false,path).appendTo(el);
var atBottom = (sbc.scrollHeight-messageList.height()-sbc.scrollTop) < 5; var atBottom = (sbc.scrollHeight-messageList.height()-sbc.scrollTop) < 5;
var m = { var m = {
el: msg el: msg

View File

@ -112,7 +112,10 @@
"import": { "import": {
"import": "Import to", "import": "Import to",
"newFlow": "new flow" "newFlow": "new flow"
} },
"copyMessagePath": "Path copied",
"copyMessageValue": "Value copied",
"copyMessageValue_truncated": "Truncated value copied"
}, },
"deploy": { "deploy": {
"deploy": "Deploy", "deploy": "Deploy",