@gregoriusrippenstein/node-red-contrib-introspection 0.3.5 → 0.4.1

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
@@ -89,9 +89,17 @@ Inspired by the [dsm](https://flows.nodered.org/node/node-red-contrib-dsm) packa
89
89
 
90
90
  Send a flow to another Node-RED instance. This will replace **any existing** flows on the other server, use with care. Under the hood this uses the [Node-RED API](https://nodered.org/docs/api/admin/methods/post/flows/) to post a new flow to the server. This node also supports authentication if the other server happens to have some.
91
91
 
92
- ### TriggerImport
92
+ ### ClientCode
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. 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
+
96
+ The context in which the code is exected includes:
97
+
98
+ - `payload` which is the the `msg.payload` value
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
93
102
 
94
- This node will open the Node-RED import dialog and insert the payload, i.e. a flow object, into the dialog. The flow can then be imported into the existing workspace. See the [RSS example](https://flowhub.org/f/e02ba6e534f7a0f4) for more details. Payload must be a valid flow object, i.e. a Javascript array with one object per node. The import dialog will complain should this not be the case.
95
103
 
96
104
  ## Node-RED Versions
97
105
 
@@ -106,7 +114,7 @@ There are [example flows](/examples) contained in the package, examples can also
106
114
  - [Screenshot](https://flowhub.org/f/07b2d0f3b0445ab5)
107
115
  - [DrawSVG](https://flowhub.org/f/141037dcda5b69fd)
108
116
  - [GetFlows](https://flowhub.org/f/0b1bfbf6e540be66)
109
- - [TriggerImport](https://flowhub.org/f/e02ba6e534f7a0f4)
117
+ - [ClientCode](https://flowhub.org/f/e02ba6e534f7a0f4)
110
118
 
111
119
  ## License
112
120
 
@@ -0,0 +1,197 @@
1
+ <script type="text/javascript">
2
+
3
+ RED.comms.subscribe('introspect:client-code-perform', (event,data) => {
4
+ if ( data.msg == "execfunc" ) {
5
+
6
+ var doSend = (data, nodeid) => {
7
+ $.ajax({
8
+ url: "ClientCode/" + nodeid,
9
+ type: "POST",
10
+ contentType: "application/json; charset=utf-8",
11
+ data: JSON.stringify(data),
12
+
13
+ success: function (resp) {
14
+ },
15
+
16
+ error: function (jqXHR, textStatus, errorThrown) {
17
+ RED.notify("ClientCode Communcation Failure: " +
18
+ nodeid + ": " + textStatus, {
19
+ type: "error",
20
+ id: nodeid,
21
+ timeout: 3000
22
+ });
23
+ }
24
+ });
25
+ };
26
+
27
+ var doError = (msg,nodeid) => {
28
+ RED.notify("ClientCode Failed: " + nodeid + ": " + msg, {
29
+ type: "error",
30
+ id: nodeid,
31
+ timeout: 3000
32
+ });
33
+ console.log( "ClientCode: Error with node: " + nodeid +": " +msg);
34
+ };
35
+
36
+ var nodeid = data.nodeid;
37
+
38
+ var node = {
39
+ send: (dt) => {
40
+ doSend(dt, nodeid)
41
+ },
42
+ error: (mg) => {
43
+ doError(mg, nodeid)
44
+ }
45
+ };
46
+
47
+ var payload = data.payload;
48
+ var topic = data.topic;
49
+
50
+ eval( data.func );
51
+ }
52
+ });
53
+
54
+ RED.nodes.registerType('ClientCode',{
55
+ color: '#e5e4ef',
56
+ icon: "icons/subflow.svg",
57
+ category: 'introspection',
58
+ paletteLabel: "ClientCode",
59
+ defaults: {
60
+ name: {
61
+ value:"",
62
+ },
63
+ clientcode: {
64
+ value: ""
65
+ },
66
+ format: {
67
+ value: ""
68
+ }
69
+ },
70
+ inputs:1,
71
+ outputs:1,
72
+
73
+ label: function() {
74
+ return (this.name || this._def.paletteLabel);
75
+ },
76
+
77
+ labelStyle: function() {
78
+ return this.name?"node_label_italic":"";
79
+ },
80
+
81
+ oneditsave: function() {
82
+ $('#node-input-clientcode').val(this.editor.getValue());
83
+ this.editor.destroy();
84
+ delete this.editor;
85
+ },
86
+
87
+ oneditcancel: function() {
88
+ this.editor.destroy();
89
+ delete this.editor;
90
+ },
91
+
92
+ oneditprepare: function() {
93
+ const that = this;
94
+ const stateId = RED.editor.generateViewStateId("node", this, "");
95
+
96
+ this.editor = RED.editor.createEditor({
97
+ id: 'node-input-clientcode-editor',
98
+ mode: 'ace/mode/html',
99
+ stateId: stateId,
100
+ value: $("#node-input-screenshot").val()
101
+ });
102
+
103
+ this.editor.setValue( that.clientcode );
104
+
105
+ $("#node-input-format").on("change", function() {
106
+ var mod = "ace/mode/"+$("#node-input-format").val();
107
+ that.editor.getSession().setMode({
108
+ path: mod,
109
+ v: Date.now()
110
+ });
111
+ });
112
+
113
+ RED.popover.tooltip($("#node-clientcode-expand-editor"), RED._("node-red:common.label.expand"));
114
+ $("#node-clientcode-expand-editor").on("click", function (e) {
115
+ e.preventDefault();
116
+ const value = that.editor.getValue();
117
+ that.editor.saveView();
118
+ RED.editor.editText({
119
+ mode: $("#node-input-format").val(),
120
+ value: value,
121
+ stateId: stateId,
122
+ width: "Infinity",
123
+ focus: true,
124
+ complete: function (v, cursor) {
125
+ that.editor.setValue(v, -1);
126
+ setTimeout(function () {
127
+ that.editor.restoreView();
128
+ that.editor.focus();
129
+ }, 250);
130
+ }
131
+ })
132
+ })
133
+
134
+ },
135
+
136
+ oneditresize: function(size) {
137
+ var rows = $("#dialog-form>div:not(.node-text-editor-row)");
138
+ var height = $("#dialog-form").height();
139
+ for (var i=0; i<rows.length; i++) {
140
+ height -= $(rows[i]).outerHeight(true);
141
+ }
142
+ var editorRow = $("#dialog-form>div.node-text-editor-row");
143
+ height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
144
+ $(".node-text-editor").css("height",height+"px");
145
+ this.editor.resize();
146
+ }
147
+ });
148
+ </script>
149
+
150
+ <script type="text/html" data-template-name="ClientCode">
151
+ <div class="form-row">
152
+ <label for="node-input-name">
153
+ <i class="fa fa-tag"></i>
154
+ <span data-i18n="common.label.name">Name</span>
155
+ </label>
156
+ <input type="text" id="node-input-name" placeholder="Name">
157
+ </div>
158
+
159
+ <div class="form-row" style="position: relative; margin-bottom: 0px;">
160
+ <label for="node-input-clientcode">
161
+ <i class="fa fa-file-code-o"></i> Client Code
162
+ </label>
163
+ <input type="hidden" id="node-input-clientcode" autofocus="autofocus">
164
+
165
+ <div style="position: absolute; right:0;display:inline-block; text-align: right; font-size: 0.8em;">
166
+ Syntax:
167
+ <select id="node-input-format" style="width:110px; font-size: 10px !important; height: 24px; padding:0;">
168
+ <option value="handlebars">mustache</option>
169
+ <option value="html">HTML</option>
170
+ <option value="json">JSON</option>
171
+ <option value="javascript">JavaScript</option>
172
+ <option value="css">CSS</option>
173
+ <option value="markdown">Markdown</option>
174
+ <option value="php">PHP</option>
175
+ <option value="python">Python</option>
176
+ <option value="sql">SQL</option>
177
+ <option value="yaml">YAML</option>
178
+ <option value="text">None</option>
179
+ </select>
180
+ <button type="button" id="node-clientcode-expand-editor"
181
+ class="red-ui-button red-ui-button-small">
182
+ <i class="fa fa-expand"></i>
183
+ </button>
184
+ </div>
185
+ </div>
186
+
187
+ <div class="form-row node-text-editor-row">
188
+ <div style="height: 250px; min-height:150px;"
189
+ class="node-text-editor"
190
+ id="node-input-clientcode-editor" ></div>
191
+ </div>
192
+ <input type="hidden" id="node-input-clientcode">
193
+ </script>
194
+
195
+ <script type="text/html" data-help-name="ClientCode">
196
+ <p>Execute Javascript code in the Node-RED frontend, triggered from the server.</p>
197
+ </script>
@@ -0,0 +1,49 @@
1
+ module.exports = function(RED) {
2
+ function ClientCodeFunctionality(config) {
3
+ RED.nodes.createNode(this,config);
4
+
5
+ var node = this;
6
+ var cfg = config;
7
+
8
+ node.on('close', function() {
9
+ node.status({});
10
+ });
11
+
12
+ node.on("input", function(msg, send, done) {
13
+ RED.comms.publish(
14
+ "introspect:client-code-perform",
15
+ RED.util.encodeObject({
16
+ msg: "execfunc",
17
+ payload: msg.payload,
18
+ topic: msg.topic,
19
+ func: cfg.clientcode,
20
+ nodeid: node.id
21
+ })
22
+ );
23
+ });
24
+ }
25
+ RED.nodes.registerType("ClientCode", ClientCodeFunctionality);
26
+
27
+ RED.httpAdmin.post("/ClientCode/:id",
28
+ RED.auth.needsPermission("ClientCode.write"),
29
+ (req,res) => {
30
+ var node = RED.nodes.getNode(req.params.id);
31
+ if (node != null) {
32
+ try {
33
+ if (req.body && node.type == "ClientCode" ) {
34
+ node.send(req.body);
35
+ res.sendStatus(200);
36
+ } else {
37
+ res.sendStatus(404);
38
+ }
39
+ } catch(err) {
40
+ res.sendStatus(500);
41
+ node.error("ClientCode: Submission failed: " +
42
+ err.toString())
43
+ }
44
+ } else {
45
+ res.sendStatus(404);
46
+ }
47
+ });
48
+
49
+ }
@@ -1,5 +1,37 @@
1
1
  <script type="text/javascript">
2
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
+
3
35
  RED.comms.subscribe('introspect:trigger-import-delete', (event,data) => {
4
36
  if ( data.msg == "delete-old-nodes" ) {
5
37
  RED.view.select(false)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gregoriusrippenstein/node-red-contrib-introspection",
3
- "version": "0.3.5",
3
+ "version": "0.4.1",
4
4
  "dependencies": {
5
5
  "got": "latest"
6
6
  },
@@ -16,16 +16,16 @@
16
16
  "node-red": {
17
17
  "version": ">=2.0.0",
18
18
  "nodes": {
19
- "seeker": "nodes/05-seeker.js",
20
- "sink": "nodes/10-sink.js",
21
- "screenshot": "nodes/15-screenshot.js",
22
- "orphans": "nodes/20-orphans.js",
23
- "ismobile": "nodes/25-ismobile.js",
24
- "navigator": "nodes/30-navigator.js",
25
- "drawsvg": "nodes/40-drawsvg.js",
26
- "getflows": "nodes/45-get-flows.js",
27
- "sendflow": "nodes/50-send-flow.js",
28
- "triggerimport": "nodes/55-trigger-import.js"
19
+ "seeker": "nodes/05-seeker.js",
20
+ "sink": "nodes/10-sink.js",
21
+ "screenshot": "nodes/15-screenshot.js",
22
+ "orphans": "nodes/20-orphans.js",
23
+ "ismobile": "nodes/25-ismobile.js",
24
+ "navigator": "nodes/30-navigator.js",
25
+ "drawsvg": "nodes/40-drawsvg.js",
26
+ "getflows": "nodes/45-get-flows.js",
27
+ "sendflow": "nodes/50-send-flow.js",
28
+ "clientcode": "nodes/60-client-code.js"
29
29
  }
30
30
  },
31
31
  "description": "Node-RED Editor-only nodes for introspecting flows.",
@@ -1,38 +0,0 @@
1
- module.exports = function(RED) {
2
- function TriggerImportFunctionality(config) {
3
- RED.nodes.createNode(this,config);
4
-
5
- var node = this;
6
- var cfg = config;
7
-
8
- node.on('close', function() {
9
- node.status({});
10
- });
11
-
12
- node.on("input", function(msg, send, done) {
13
- if ( msg.payload && msg.payload.cmd == "delete-nodes" ) {
14
- RED.comms.publish('introspect:trigger-import-delete',
15
- RED.util.encodeObject({
16
- msg: "delete-old-nodes",
17
- payload: msg.payload,
18
- })
19
- );
20
-
21
- send(msg);
22
- return;
23
- }
24
-
25
- RED.comms.publish("introspect:trigger-import-tripped",
26
- RED.util.encodeObject({
27
- flowContent: msg.payload,
28
- msg: "import-flow",
29
- autoimport: cfg.autoimport,
30
- removeduplicates: cfg.removeduplicates,
31
- })
32
- );
33
-
34
- send(msg);
35
- });
36
- }
37
- RED.nodes.registerType("TriggerImport", TriggerImportFunctionality);
38
- }
File without changes