@gregoriusrippenstein/node-red-contrib-introspection 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -91,14 +91,15 @@ Send a flow to another Node-RED instance. This will replace **any existing** flo
|
|
|
91
91
|
|
|
92
92
|
### ClientCode
|
|
93
93
|
|
|
94
|
-
ClientCode is a node for executing client side, i.e., in the editor, Javascript code triggered by a server side event. Any code that can be executed in the browseer console can be executed in the ClientCode node.
|
|
94
|
+
ClientCode is a node for executing client side, i.e., in the editor, Javascript code triggered by a server side event. Any code that can be executed in the browseer console can be executed in the ClientCode node. A ClientCode node can also send a message back to the server using `node.send(...)` which becomes the server side output of the node.
|
|
95
95
|
|
|
96
|
-
The context
|
|
96
|
+
The context in which the code is exected includes:
|
|
97
97
|
|
|
98
98
|
- `payload` which is the the `msg.payload` value
|
|
99
99
|
- `topic` which is the `msg.topic` value
|
|
100
|
+
- `node.send(payload)` where `payload` becomes the output the node on the server side
|
|
101
|
+
- `node.error("msg")` where msg is shown as a notification within the editor
|
|
100
102
|
|
|
101
|
-
For more details, [client side code](https://github.com/gorenje/node-red-contrib-introspection/blob/2f5aca9374b28fcb6890c312f943f913ecb4cfce/nodes/60-client-code.html#L3-L8) with the context and [server side code](https://github.com/gorenje/node-red-contrib-introspection/blob/2f5aca9374b28fcb6890c312f943f913ecb4cfce/nodes/60-client-code.js#L13-L22).
|
|
102
103
|
|
|
103
104
|
## Node-RED Versions
|
|
104
105
|
|
|
@@ -2,7 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
RED.comms.subscribe('introspect:client-code-perform', (event,data) => {
|
|
4
4
|
if ( data.msg == "execfunc" ) {
|
|
5
|
+
|
|
6
|
+
var doSend = (data, nodeid, _msg) => {
|
|
7
|
+
if ( typeof data == "object" ) {
|
|
8
|
+
data = {
|
|
9
|
+
..._msg,
|
|
10
|
+
...data
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
$.ajax({
|
|
15
|
+
url: "ClientCode/" + nodeid,
|
|
16
|
+
type: "POST",
|
|
17
|
+
contentType: "application/json; charset=utf-8",
|
|
18
|
+
data: JSON.stringify(data),
|
|
19
|
+
|
|
20
|
+
success: function (resp) {
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
error: function (jqXHR, textStatus, errorThrown) {
|
|
24
|
+
RED.notify("ClientCode Communcation Failure: " +
|
|
25
|
+
nodeid + ": " + textStatus, {
|
|
26
|
+
type: "error",
|
|
27
|
+
id: nodeid,
|
|
28
|
+
timeout: 3000
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
var doError = (msg, nodeid, _msg) => {
|
|
35
|
+
RED.notify("ClientCode Failed: " + nodeid + ": " + msg, {
|
|
36
|
+
type: "error",
|
|
37
|
+
id: nodeid,
|
|
38
|
+
timeout: 3000
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log( "ClientCode: Error with node: " + nodeid + ": " + msg);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var nodeid = data.nodeid;
|
|
45
|
+
var _msg = data._msg;
|
|
46
|
+
|
|
47
|
+
var node = {
|
|
48
|
+
send: (dt) => {
|
|
49
|
+
doSend(dt, nodeid, _msg)
|
|
50
|
+
},
|
|
51
|
+
error: (mg) => {
|
|
52
|
+
doError(mg, nodeid, _msg)
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
5
56
|
var payload = data.payload;
|
|
57
|
+
var topic = data.topic;
|
|
58
|
+
|
|
6
59
|
eval( data.func );
|
|
7
60
|
}
|
|
8
61
|
});
|
|
@@ -20,7 +73,7 @@
|
|
|
20
73
|
value: ""
|
|
21
74
|
},
|
|
22
75
|
format: {
|
|
23
|
-
value: ""
|
|
76
|
+
value: "javascript"
|
|
24
77
|
}
|
|
25
78
|
},
|
|
26
79
|
inputs:1,
|
|
@@ -51,13 +104,11 @@
|
|
|
51
104
|
|
|
52
105
|
this.editor = RED.editor.createEditor({
|
|
53
106
|
id: 'node-input-clientcode-editor',
|
|
54
|
-
mode: 'ace/mode/
|
|
107
|
+
mode: 'ace/mode/javascript',
|
|
55
108
|
stateId: stateId,
|
|
56
|
-
value: $("#node-input-
|
|
109
|
+
value: $("#node-input-clientcode").val()
|
|
57
110
|
});
|
|
58
111
|
|
|
59
|
-
this.editor.setValue( that.clientcode );
|
|
60
|
-
|
|
61
112
|
$("#node-input-format").on("change", function() {
|
|
62
113
|
var mod = "ace/mode/"+$("#node-input-format").val();
|
|
63
114
|
that.editor.getSession().setMode({
|
package/nodes/60-client-code.js
CHANGED
|
@@ -17,12 +17,34 @@ module.exports = function(RED) {
|
|
|
17
17
|
payload: msg.payload,
|
|
18
18
|
topic: msg.topic,
|
|
19
19
|
func: cfg.clientcode,
|
|
20
|
-
nodeid: node.id
|
|
20
|
+
nodeid: node.id,
|
|
21
|
+
_msg: msg
|
|
21
22
|
})
|
|
22
23
|
);
|
|
23
|
-
|
|
24
|
-
send(msg);
|
|
25
24
|
});
|
|
26
25
|
}
|
|
27
26
|
RED.nodes.registerType("ClientCode", ClientCodeFunctionality);
|
|
27
|
+
|
|
28
|
+
RED.httpAdmin.post("/ClientCode/:id",
|
|
29
|
+
RED.auth.needsPermission("ClientCode.write"),
|
|
30
|
+
(req,res) => {
|
|
31
|
+
var node = RED.nodes.getNode(req.params.id);
|
|
32
|
+
if (node != null) {
|
|
33
|
+
try {
|
|
34
|
+
if (req.body && node.type == "ClientCode" ) {
|
|
35
|
+
node.send(req.body);
|
|
36
|
+
res.sendStatus(200);
|
|
37
|
+
} else {
|
|
38
|
+
res.sendStatus(404);
|
|
39
|
+
}
|
|
40
|
+
} catch(err) {
|
|
41
|
+
res.sendStatus(500);
|
|
42
|
+
node.error("ClientCode: Submission failed: " +
|
|
43
|
+
err.toString())
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
res.sendStatus(404);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
28
50
|
}
|
package/package.json
CHANGED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* How to connect nodes:
|
|
5
|
-
var namesToId = {}
|
|
6
|
-
|
|
7
|
-
RED.nodes.eachNode((n) => {
|
|
8
|
-
if ( n._def.category == "rssfeeds") {
|
|
9
|
-
namesToId[n.name] = n.id
|
|
10
|
-
}
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
RED.nodes.eachNode((n) => {
|
|
14
|
-
if ( n._def.category == "rssfeeds" && n._def.label() == "Hacker News: New Comments") {
|
|
15
|
-
var title = n.name.match(/^New[ ]+comment[ ]+by.+\"(.*)\"/)[1];
|
|
16
|
-
var tgtId = namesToId[title];
|
|
17
|
-
if ( tgtId ) {
|
|
18
|
-
var t = RED.nodes.node(tgtId);
|
|
19
|
-
RED.nodes.addLink( { source: n, sourcePort: 0, target: t});
|
|
20
|
-
RED.view.select([t,n])
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
* How to move
|
|
26
|
-
|
|
27
|
-
var t = RED.nodes.node("23e18922a0b896f1")
|
|
28
|
-
t.x = XXXX;
|
|
29
|
-
t.y = YYYY;
|
|
30
|
-
t.dirty = true;
|
|
31
|
-
RED.view.redraw(true)
|
|
32
|
-
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
RED.comms.subscribe('introspect:trigger-import-delete', (event,data) => {
|
|
36
|
-
if ( data.msg == "delete-old-nodes" ) {
|
|
37
|
-
RED.view.select(false)
|
|
38
|
-
|
|
39
|
-
// close any dialog that explains that there are duplicates and therefore
|
|
40
|
-
// only a copy can be imported, hit the cancel button on that one.
|
|
41
|
-
// Five clicks should do the job ...
|
|
42
|
-
for ( var idx = 0 ; idx < 5; idx++ ) {
|
|
43
|
-
$($('.ui-dialog-buttonset').find("button")[0]).trigger('click')
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
var allSelectNodes = [];
|
|
47
|
-
|
|
48
|
-
RED.nodes.eachNode( function(e) {
|
|
49
|
-
if ( e._def && e.env && e.env[1] &&
|
|
50
|
-
e._def.category == data.payload.category &&
|
|
51
|
-
(Date.parse(e.env[1].value) <
|
|
52
|
-
(new Date().getTime() - parseInt(data.payload.old_than_ms))) ) {
|
|
53
|
-
allSelectNodes.push(e)
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
RED.view.select({ nodes: allSelectNodes })
|
|
58
|
-
setTimeout( () => {
|
|
59
|
-
RED.actions.invoke("core:delete-selection")
|
|
60
|
-
}, 1500);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
RED.comms.subscribe('introspect:trigger-import-tripped', (event,data) => {
|
|
65
|
-
if ( data.msg == "import-flow" ) {
|
|
66
|
-
var content = data.flowContent;
|
|
67
|
-
|
|
68
|
-
if ( data.removeduplicates ) {
|
|
69
|
-
content = content.filter( (elem) => {
|
|
70
|
-
return RED.nodes.node(elem.id) == undefined
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if ( content.length == 0 ) {
|
|
75
|
-
RED.notify("No new content", {
|
|
76
|
-
type: "ok",
|
|
77
|
-
id: "TriggerImport",
|
|
78
|
-
timeout: 2000
|
|
79
|
-
});
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
RED.clipboard.import();
|
|
83
|
-
|
|
84
|
-
setTimeout( () => {
|
|
85
|
-
$('#red-ui-clipboard-dialog-import-text').val(
|
|
86
|
-
JSON.stringify(content)
|
|
87
|
-
).trigger("paste");
|
|
88
|
-
|
|
89
|
-
if ( data.autoimport ) {
|
|
90
|
-
setTimeout( () => {
|
|
91
|
-
$('#red-ui-clipboard-dialog-ok').trigger('click');
|
|
92
|
-
}, 435);
|
|
93
|
-
}
|
|
94
|
-
}, 300);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
RED.nodes.registerType('TriggerImport',{
|
|
99
|
-
color: '#e5e4ef',
|
|
100
|
-
icon: "icons/subflow.svg",
|
|
101
|
-
category: 'introspection',
|
|
102
|
-
paletteLabel: "TriggerImport",
|
|
103
|
-
defaults: {
|
|
104
|
-
name: {
|
|
105
|
-
value:"",
|
|
106
|
-
},
|
|
107
|
-
autoimport: {
|
|
108
|
-
value: false
|
|
109
|
-
},
|
|
110
|
-
removeduplicates: {
|
|
111
|
-
value: false
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
inputs:1,
|
|
115
|
-
outputs:1,
|
|
116
|
-
|
|
117
|
-
label: function() {
|
|
118
|
-
return (this.name || this._def.paletteLabel);
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
labelStyle: function() {
|
|
122
|
-
return this.name?"node_label_italic":"";
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
</script>
|
|
126
|
-
|
|
127
|
-
<script type="text/html" data-template-name="TriggerImport">
|
|
128
|
-
<div class="form-row">
|
|
129
|
-
<label for="node-input-name">
|
|
130
|
-
<i class="fa fa-tag"></i>
|
|
131
|
-
<span data-i18n="common.label.name">Name</span>
|
|
132
|
-
</label>
|
|
133
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
134
|
-
</div>
|
|
135
|
-
|
|
136
|
-
<div class="form-row">
|
|
137
|
-
<label for="node-input-autoimport" style="width: 150px !important;">
|
|
138
|
-
<span>Automatic Import?</span>
|
|
139
|
-
</label>
|
|
140
|
-
<input type="checkbox"
|
|
141
|
-
id="node-input-autoimport"
|
|
142
|
-
style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
143
|
-
</div>
|
|
144
|
-
|
|
145
|
-
<div class="form-row">
|
|
146
|
-
<label for="node-input-removeduplicates" style="width: 150px !important;">
|
|
147
|
-
<span>Remove duplicates?</span>
|
|
148
|
-
</label>
|
|
149
|
-
<input type="checkbox"
|
|
150
|
-
id="node-input-removeduplicates"
|
|
151
|
-
style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
152
|
-
</div>
|
|
153
|
-
|
|
154
|
-
</script>
|
|
155
|
-
|
|
156
|
-
<script type="text/html" data-help-name="TriggerImport">
|
|
157
|
-
<p>Trigger import opens the flow import dialog with data that came from the server.</p>
|
|
158
|
-
</script>
|
|
File without changes
|