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();
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 {
init: function() {
setupDialogs();
$('<input type="text" id="clipboard-hidden">').appendTo("body");
RED.events.on("view:selection-changed",function(selection) {
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
@ -339,6 +373,7 @@ RED.clipboard = (function() {
},
import: importNodes,
export: exportNodes
export: exportNodes,
copyText: copyText
}
})();

View File

@ -15,26 +15,61 @@
**/
RED.popover = (function() {
var deltaSizes = {
"default": {
top: 10,
leftRight: 17,
leftLeft: 25
},
"small": {
top: 5,
leftRight: 8,
leftLeft: 16
}
}
function createPopover(options) {
var target = options.target;
var direction = options.direction || "right";
var trigger = options.trigger;
var content = options.content;
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 active;
var div;
var openPopup = function() {
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 targetWidth = target.width();
var targetHeight = target.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");
}
@ -50,24 +85,45 @@ RED.popover = (function() {
}
}
target.on('mouseenter',function(e) {
clearTimeout(timer);
active = true;
timer = setTimeout(openPopup,delay.show);
});
target.on('mouseleave', function(e) {
if (timer) {
if (trigger === 'hover') {
target.on('mouseenter',function(e) {
clearTimeout(timer);
}
active = false;
setTimeout(closePopup,delay.hide);
});
active = true;
timer = setTimeout(openPopup,delay.show);
});
target.on('mouseleave', function(e) {
if (timer) {
clearTimeout(timer);
}
active = false;
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 = {
setContent: function(_content) {
content = _content;
},
open: function () {
active = true;
openPopup();
},
close: function () {
active = false;
closePopup();
}
}
target.data('popover',res);
return res;
}

View File

@ -185,11 +185,14 @@ RED.palette = (function() {
$("#palette-"+category).append(d);
d.onmousedown = function(e) { e.preventDefault(); };
RED.popover.create({
var popover = RED.popover.create({
target:$(d),
trigger: "hover",
width: "300px",
content: "hi",
delay: { show: 750, hide: 50 }
});
$(d).data('popover',popover);
// $(d).popover({
// 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>');
} else if (typeof value === 'object') {
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')) {
result = $('<span class="debug-message-object-value debug-message-type-meta"></span>').html('array['+value.length+']');
} else {
@ -66,8 +66,22 @@ RED.utils = (function() {
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 e;
var entryObj;
@ -75,15 +89,15 @@ RED.utils = (function() {
var headerHead;
var value;
var element = $('<span class="debug-message-element"></span>');
header = $('<span class="debug-message-row"></span>').appendTo(element);
addMessageControls(header,path,obj);
if (!key) {
element.addClass("debug-message-top-level");
}
header = $('<span></span>').appendTo(element);
if (key && !hideKey) {
$('<span class="debug-message-object-key"></span>').text(key).appendTo(header);
$('<span>: </span>').appendTo(header);
} else {
if (!hideKey) {
$('<span class="debug-message-object-key"></span>').text(key).appendTo(header);
$('<span>: </span>').appendTo(header);
}
}
entryObj = $('<span class="debug-message-object-value"></span>').appendTo(header);
@ -166,6 +180,7 @@ RED.utils = (function() {
if (type === 'buffer') {
var stringRow = $('<div class="debug-message-string-rows"></div>').appendTo(element);
var sr = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(stringRow);
var stringEncoding = "";
try {
stringEncoding = String.fromCharCode.apply(null, new Uint16Array(data))
@ -190,7 +205,7 @@ RED.utils = (function() {
if (fullLength <= 10) {
for (i=0;i<fullLength;i++) {
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 {
for (i=0;i<fullLength;i+=10) {
@ -205,7 +220,7 @@ RED.utils = (function() {
return function() {
for (var i=min;i<=max;i++) {
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++) {
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) {
$('<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,
validatePropertyExpression: validatePropertyExpression,
getNodeIcon: getNodeIcon,
getNodeLabel: getNodeLabel
getNodeLabel: getNodeLabel,
}
})();

View File

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

View File

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

View File

@ -15,39 +15,82 @@
**/
.red-ui-popover {
display: none;
position: absolute;
width: 300px;
padding: 10px;
height: auto;
background: #fff;
z-index: 1000;
font-size: 14px;
line-height: 1.4em;
@include component-shadow;
}
.red-ui-popover:after, .red-ui-popover:before {
right: 100%;
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.red-ui-popover {
display: none;
position: absolute;
width: auto;
padding: 10px;
height: auto;
background: #fff;
.red-ui-popover:after {
border-color: rgba(136, 183, 213, 0);
border-right-color: #fff;
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover:before {
border-color: rgba(194, 225, 245, 0);
border-right-color: $primary-border-color;
border-width: 11px;
margin-top: -11px;
}
z-index: 1000;
font-size: 14px;
line-height: 1.4em;
@include component-shadow;
}
.red-ui-popover:after, .red-ui-popover:before {
top: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
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.red-ui-popover-right:after {
border-color: rgba(136, 183, 213, 0);
border-right-color: #fff;
border-width: 10px;
margin-top: -10px;
}
.red-ui-popover.red-ui-popover-right:before {
border-color: rgba(194, 225, 245, 0);
border-right-color: $primary-border-color;
border-width: 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');
if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substring(0,debuglength);
msg.modified = true;
}
} else if (msg.msg && typeof msg.msg === 'object') {
var seen = [];
var seenAts = [];
try {
msg.format = msg.msg.constructor.name || "Object";
// Handle special case of msg.req/res objects from HTTP In node
@ -113,38 +112,54 @@ module.exports = function(RED) {
if (isArray) {
msg.format = "array["+msg.msg.length+"]";
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")) {
var modified = false;
msg.msg = safeJSONStringify(msg.msg, function(key, value) {
if (key === '_req' || key === '_res') {
return "[internal]"
}
if (value instanceof Error) {
return value.toString()
}
if (util.isArray(value) && value.length > debuglength) {
value = "[internal]"
} else if (value instanceof Error) {
value = value.toString()
} else if (util.isArray(value) && value.length > debuglength) {
value = {
__encoded__: true,
type: "array",
data: value.slice(0,debuglength),
length: value.length
}
}
if (typeof value === 'string') {
modified = true;
} else if (typeof value === 'string') {
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;
}," ");
if (modified) {
msg.modified = modified;
}
} else {
try { msg.msg = msg.msg.toString(); }
catch(e) { msg.msg = "[Type not printable]"; }
}
}
seen = null;
} else if (typeof msg.msg === "boolean") {
msg.format = "boolean";
msg.msg = msg.msg.toString();
@ -161,6 +176,7 @@ module.exports = function(RED) {
msg.format = "string["+msg.msg.length+"]";
if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substring(0,debuglength)+"...";
msg.modified = true;
}
}
// if (msg.msg.length > debuglength) {

View File

@ -184,13 +184,13 @@ RED.debug = (function() {
var sourceNode = o._source;
msg.onmouseenter = function() {
msg.style.borderRightColor = "#999";
$(msg).addClass('debug-message-hover');
if (o._source) {
config.messageMouseEnter(o._source.id);
}
};
msg.onmouseleave = function() {
msg.style.borderRightColor = "";
$(msg).removeClass('debug-message-hover');
if (o._source) {
config.messageMouseLeave(o._source.id);
}
@ -225,6 +225,9 @@ RED.debug = (function() {
$(msg).addClass('debug-message-level-' + errorLvl);
$('<span class="debug-message-topic">function : (' + errorLvlType + ')</span>').appendTo(metaRow);
} 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">'+
(o.topic?topic+' : ':'')+
(o.property?'msg.'+property:'msg')+" : "+format+
@ -247,7 +250,8 @@ RED.debug = (function() {
}
}
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 m = {
el: msg

View File

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