@gregoriusrippenstein/node-red-contrib-introspection 0.2.6 → 0.3.0

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
@@ -75,7 +75,7 @@ This is a hack that uses the `onpaletteadd` callback to do its magic. If this fu
75
75
 
76
76
  A node for inserting an SVG image into the workspace. The image is layered above the grid but below nodes and their connections. The input message must contain SVG data (in string form) in the `payload` attribute.
77
77
 
78
- ### GetFlows -- Experimental
78
+ ### GetFlows
79
79
 
80
80
  Node retrieves the current `flows.json` from the server but using the [Node-RED API](https://nodered.org/docs/api/admin/methods/get/flows/) so that it is storage independent. It returns the flows as a `payload` of the message.
81
81
 
@@ -85,18 +85,18 @@ GetFlows supports version selection of the flows and it has limited authenticati
85
85
 
86
86
  Inspired by the [dsm](https://flows.nodered.org/node/node-red-contrib-dsm) package that has a [backup](https://github.com/cflurin/node-red-contrib-dsm/wiki/Backup) state machine.
87
87
 
88
- ## Examples
88
+ ## Node-RED Versions
89
89
 
90
- There are [example flows](/examples) contained in the package, examples can also be found online:
90
+ These nodes have been tested and found to work on Node-RED 3.0.2 and 3.1.0.beta.4.
91
91
 
92
- - [Orphans](https://demo.openmindmap.org/omm/#flow/3ebb65fdbecb182e/n/2be3f8794979d47b) - node is top left of flow or search for `type:Orphans`
93
- - [Seeker](https://demo.openmindmap.org/omm/#flow/40ea5f2aea6592ae/n/b5f189a78d829197) - top left and the [Sink](https://demo.openmindmap.org/omm/#flow/459c271a96458c7c/n/e3262d9d2791ab78) - top right
94
- - [Screenshot](https://demo.openmindmap.org/omm/#flow/4e2d8c13066b705e/n/499b1383580831aa) - top left
95
- - [DrawSVG](https://demo.openmindmap.org/omm/#flow/6c8ce462533a1da4/n/248f2edd3d8acd96)
92
+ ## Examples
96
93
 
97
- Example screenshot:
94
+ There are [example flows](/examples) contained in the package, examples can also be found online at [FlowHub.org](https://flowhub.org):
98
95
 
99
- ![example screenshot](/assets/screenshot.svg)
96
+ - [Orphans](https://flowhub.org/f/2401c255b056e0e1)
97
+ - [Sink and Seeker](https://flowhub.org/f/139a816449acd89f)
98
+ - [Screenshot](https://flowhub.org/f/07b2d0f3b0445ab5)
99
+ - [DrawSVG](https://flowhub.org/f/141037dcda5b69fd)
100
100
 
101
101
  ## License
102
102
 
@@ -1,10 +1,48 @@
1
1
  <script type="text/javascript">
2
- function nr_intro_generate_svg( callbackWithSvgCode ) {
3
- //
4
- // begin the SVG conversion code.
5
- //
6
- var origSvg = $($('svg')[0]);
2
+ function nr_intro_generate_svg_3_1( callbackWithSvgCode ) {
3
+ //****
4
+ // Node-RED 3.1.x has multiple SVGs all over the place, so we
5
+ // need to look for the one with 8000x8000.
6
+ // Tested this on Node-RED 3.1.0.beta.4 - dunno about other 3.1.x.beta.y
7
+ //****
7
8
 
9
+ return (callbackWithSvgCode) => {
10
+ try {
11
+ handleSvgObject( $($('svg[width=8000]')[0]), callbackWithSvgCode );
12
+ } catch ( e ) {
13
+ var msg = "Error Generating SVG: " + JSON.stringify(e);
14
+
15
+ red.notify(msg,{ type: "error" });
16
+
17
+ var svgData = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+msg+'</text></svg>';
18
+
19
+ callbackWithSvgCode(svgData);
20
+ }
21
+ }
22
+ }
23
+
24
+ function nr_intro_generate_svg_3_0( red ) {
25
+ //****
26
+ // for Node-RED v3.0.x (well 3.0.2 tested, dunno about 3.0.1)
27
+ //****
28
+
29
+ return (callbackWithSvgCode) => {
30
+ try {
31
+ handleSvgObject( $($('svg')[0]), callbackWithSvgCode);
32
+ } catch ( e ) {
33
+ var msg = "Error Generating SVG: " + JSON.stringify(e);
34
+
35
+ red.notify(msg,{ type: "error" });
36
+
37
+ var svgData = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+msg+'</text></svg>';
38
+
39
+ callbackWithSvgCode(svgData);
40
+ }
41
+ }
42
+ }
43
+
44
+
45
+ function handleSvgObject( origSvg, callbackWithSvgCode ) {
8
46
  // the DOMParser of Firefox does not like foreignObjects, so remove them.
9
47
  // Correction: DOMParser doesn't mind foreignObjects as long as there is
10
48
  // any HTML/<img>-tags in the foreignObjects.,,, of course, image tags
@@ -15,6 +53,9 @@
15
53
  var preParseSvg = origSvg.clone();
16
54
  preParseSvg.find("foreignObject").remove();
17
55
 
56
+ // these are svgdraw inserts, this would be mirroring mirroring ...
57
+ preParseSvg.find("svg.__screenshot").remove();
58
+
18
59
  var hwAttrs = (
19
60
  'width="' + origSvg.attr('width') + '" height="' +
20
61
  origSvg.attr('height') + '"'
@@ -25,7 +66,7 @@
25
66
  '<?xml version="1.0" standalone="no"?>\r\n' +
26
67
  '<svg ' + hwAttrs + ' pointer-events="all" style="cursor: crosshair; '+
27
68
  'touch-action: none;" xmlns="http://www.w3.org/2000/svg" '+
28
- 'xmlns:xlink="http://www.w3.org/1999/xlink">\r\n'
69
+ 'class="__screenshot" xmlns:xlink="http://www.w3.org/1999/xlink">\r\n'
29
70
  );
30
71
 
31
72
  var svgBody = preParseSvg.html();
@@ -137,6 +178,17 @@
137
178
  }
138
179
  }
139
180
 
181
+ var removeAllClassAndIdAttrs = (doc) => {
182
+ ["g", "rect", "line", "path", "circle", "image", "text"].forEach((t)=>{
183
+ $(doc.getElementsByTagName(t)).each( (idx, elem ) => {
184
+ elem.setAttribute("class","");
185
+ elem.setAttribute("id","");
186
+ });
187
+ });
188
+
189
+ return doc;
190
+ };
191
+
140
192
  // probably missed some elements ...
141
193
  var tagnames = [ "g", "rect", "line", "path", "circle", "image" ];
142
194
  tagnames.forEach( function(tagname) {
@@ -169,7 +221,6 @@
169
221
  };
170
222
 
171
223
  if ( imageCache[hrefSrc] ) {
172
- console.log( "FOUND " + hrefSrc + " in cache");
173
224
  elem.setAttribute(
174
225
  "xlink:href",
175
226
  "data:image/" + fileType[postfix] + ";base64," + imageCache[hrefSrc]
@@ -229,7 +280,9 @@
229
280
  var cb = (cntr) => {
230
281
  if ( cntr < 0 ) {
231
282
  delete imageCache;
232
- callbackWithSvgCode((new XMLSerializer()).serializeToString(doc));
283
+ callbackWithSvgCode((new XMLSerializer()).serializeToString(
284
+ removeAllClassAndIdAttrs(doc)
285
+ ));
233
286
  } else {
234
287
  getDataAndCallbackWhenDone( imageColl.item(cntr), cntr, cb );
235
288
  }
@@ -241,10 +294,37 @@
241
294
  cb );
242
295
  } else {
243
296
  delete imageCache;
244
- callbackWithSvgCode( (new XMLSerializer()).serializeToString(doc) );
297
+ callbackWithSvgCode( (new XMLSerializer()).serializeToString(
298
+ removeAllClassAndIdAttrs(doc)
299
+ ));
245
300
  }
246
301
  };
247
302
 
303
+ function generatorFunctionForVersion(red) {
304
+ var version = red.settings.version.split(".")
305
+ var major = version[0]; // 3.0.x or 3.1.x --> making assumptions that
306
+ var minor = version[1]; // between minor version nothing changed
307
+
308
+ var dummy = (red) => {
309
+ return (cb) => {
310
+ var msg = "Node-RED version (" + red.settings.version + ") not supported";
311
+ red.notify(msg,{ type: "error" });
312
+
313
+ if ( cb ) {
314
+ var svgData = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="1000" viewBox="0 0 1000 1000" pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style>.small { font: bold 20px sans-serif; fill: red;}</style><text x="10" y="30" class="small">'+msg+'</text></svg>';
315
+ cb(svgData);
316
+ }
317
+ };
318
+ };
319
+
320
+ if ( major == "3" ) {
321
+ if ( minor == "0" ) { return nr_intro_generate_svg_3_0(red); }
322
+ if ( minor == "1" ) { return nr_intro_generate_svg_3_1(red); }
323
+ }
324
+
325
+ return dummy(red);
326
+ };
327
+
248
328
  /*
249
329
  When the server side of this node is triggered, it posts a message on
250
330
  the communication channel. The frontend node captures that message,
@@ -259,11 +339,12 @@
259
339
  }
260
340
 
261
341
  var notification = data.notification;
262
- nr_intro_generate_svg( (svgdata) => {
342
+
343
+ generatorFunctionForVersion(RED)( (svgdata) => {
263
344
  $.ajax({
264
345
  type: "POST",
265
- url: "/screenshot",
266
- dataType: "image/svg+xml;charset=utf-8",
346
+ url: data.endpoint,
347
+ dataType: "application/json;charset=utf-8",
267
348
  data: {
268
349
  ...data,
269
350
  d: svgdata
@@ -283,7 +364,7 @@
283
364
  case 404:
284
365
  // Http-in POST node is missing
285
366
  RED.notify(
286
- "Missing http-in node: method: POST, path: /screenshot.", {
367
+ "Missing http-in node: method: POST, path: " + data.endpoint, {
287
368
  type: "error"
288
369
  }
289
370
  );
@@ -315,10 +396,13 @@
315
396
  paletteLabel: "Screenshot",
316
397
  defaults: {
317
398
  name: {
318
- value:"",
399
+ value: "",
319
400
  },
320
401
  screenshot: {
321
- value:""
402
+ value: ""
403
+ },
404
+ endpoint: {
405
+ value: "/screenshot"
322
406
  },
323
407
  },
324
408
  inputs:1,
@@ -363,7 +447,7 @@
363
447
 
364
448
  this.editor.setValue( "Please wait, screenshot being prepared ..." );
365
449
 
366
- nr_intro_generate_svg( (svgdata) => {
450
+ generatorFunctionForVersion(RED)( (svgdata) => {
367
451
  that.editor.setValue( svgdata );
368
452
  });
369
453
 
@@ -447,6 +531,14 @@
447
531
  <input type="text" id="node-input-name" placeholder="Name">
448
532
  </div>
449
533
 
534
+ <div class="form-row">
535
+ <label for="node-input-endpoint">
536
+ <i class="fa fa-send-o"></i>
537
+ <span>Post Endpoint</span>
538
+ </label>
539
+ <input type="text" id="node-input-endpoint" placeholder="/screenshot">
540
+ </div>
541
+
450
542
  <div class="form-row" style="position: relative; margin-bottom: 0px;">
451
543
  <label for="node-input-screenshot"><i class="fa fa-file-code-o"></i> <span data-i18n="screenshot.label.screenshot">Screenshot</span></label>
452
544
  <input type="hidden" id="node-input-screenshot" autofocus="autofocus">
@@ -14,6 +14,7 @@ module.exports = function(RED) {
14
14
  RED.util.encodeObject({
15
15
  ...msg,
16
16
  msg: "timer-tripped",
17
+ endpoint: cfg.endpoint,
17
18
  })
18
19
  );
19
20
 
@@ -23,5 +24,6 @@ module.exports = function(RED) {
23
24
  send(msg);
24
25
  });
25
26
  }
27
+
26
28
  RED.nodes.registerType("Screenshot", ScreenshotFunctionality);
27
29
  }
@@ -135,6 +135,19 @@
135
135
  });
136
136
 
137
137
  dirList.treeList('data',items);
138
+
139
+ $("#node-input-back-home-but").on("click", function(e) {
140
+ e.preventDefault();
141
+ var nde = RED.nodes.node(node.id);
142
+ if ( nde ) {
143
+ RED.workspaces.show(nde.z,false,false,true);
144
+ nde.highlighted = true;
145
+ nde.dirty = true;
146
+ RED.view.reveal(nde.id,true)
147
+ RED.view.redraw();
148
+ RED.tray.close();
149
+ }
150
+ });
138
151
  },
139
152
 
140
153
  oneditsave: function() {
@@ -148,8 +161,9 @@
148
161
  </script>
149
162
 
150
163
  <script type="text/html" data-template-name="Orphans">
151
- <div class="form-row">
152
- <label><i class="fa fa-tag"></i> <span>Orphans</span></label>
164
+ <div class="form-row node-input-target-row">
165
+ <button id="node-input-back-home-but"
166
+ class="red-ui-button">Back Home</button>
153
167
  </div>
154
168
 
155
169
  <div class="form-row node-input-target-row node-input-target-list-row" style="position: relative; min-height: 100px">
@@ -1,7 +1,19 @@
1
1
  <script type="text/javascript">
2
2
  RED.comms.subscribe("introspect:drawsvg", (event,data) => {
3
3
  if ( data.msg == "svgdata" ) {
4
- $($($('svg')[0]).find('> g > g > g')[2]).append(data.payload);
4
+ var version = RED.settings.version.split(".");
5
+
6
+ if ( version[0] == "3" && version[1] == "0" ) {
7
+ $($($('svg')[0]).find('> g > g > g')[2]).append(
8
+ data.payload
9
+ );
10
+ }
11
+
12
+ if ( version[0] == "3" && version[1] == "1" ) {
13
+ $($($('svg[width=8000]')[0]).find('> g > g > g')[2]).append(
14
+ data.payload
15
+ );
16
+ }
5
17
  }
6
18
  });
7
19
 
@@ -11,7 +11,7 @@ module.exports = function(RED) {
11
11
 
12
12
  node.on("input", function(msg, send, done) {
13
13
  RED.comms.publish("introspect:drawsvg", RED.util.encodeObject({
14
- ...msg,
14
+ payload: msg.payload,
15
15
  msg: "svgdata",
16
16
  }));
17
17
 
@@ -11,13 +11,41 @@ module.exports = function(RED) {
11
11
 
12
12
  node.on("input", function(msg, send, done) {
13
13
  var os = require('os');
14
- var got = require('got');
15
14
 
16
15
  var baseUrl = "http://" + os.hostname() + ":" + RED.settings.get("uiPort");
17
16
  if ( RED.settings.get("httpAdminRoot") != "/" ) {
18
17
  baseUrl += RED.settings.get("httpAdminRoot");
19
18
  }
20
19
 
20
+ var getFlows = (hdrs, got) => {
21
+ got.get( baseUrl + "/flows", {
22
+ headers: {
23
+ "Node-RED-API-Version": cfg.flowVersion,
24
+ ...hdrs
25
+ }
26
+ }).then( res => {
27
+ var bodySize = res.body.length;
28
+
29
+ send({
30
+ ...msg,
31
+ payload: res.body
32
+ });
33
+
34
+ node.status({fill:"green",shape:"dot",text:"Good"});
35
+ setTimeout( function() {
36
+ node.status({
37
+ fill: "blue",
38
+ shape: "dot",
39
+ text: "Flow size: " + bodySize
40
+ })
41
+ }, 450);
42
+
43
+ }).catch( err => {
44
+ node.status({fill:"red",shape:"dot",text:"Failed"});
45
+ node.error(err)
46
+ });
47
+ };
48
+
21
49
  if ( cfg.useAuthentication ) {
22
50
  var username = undefined;
23
51
  var password = undefined;
@@ -48,41 +76,26 @@ module.exports = function(RED) {
48
76
  "password": password
49
77
  }
50
78
 
51
- got.post( baseUrl + "/auth/token", {
52
- json: data
53
- }).then( res => {
54
- node.status({fill:"blue",shape:"dot",text:"Requesting flows"});
55
-
56
- var access_token = JSON.parse(res.body).access_token;
57
- got.get( baseUrl + "/flows", {
58
- headers: {
59
- "Node-RED-API-Version": cfg.flowVersion,
60
- "Authorization": "Bearer " + access_token
61
- }
79
+ import('got').then( (module) => {
80
+ module.got.post( baseUrl + "/auth/token", {
81
+ json: data
62
82
  }).then( res => {
63
- var bodySize = res.body.length;
64
-
65
- send( {
66
- ...msg,
67
- payload: res.body
83
+ node.status({
84
+ fill:"blue",
85
+ shape:"dot",
86
+ text:"Requesting flows"
68
87
  });
69
88
 
70
- node.status({fill:"green",shape:"dot",text:"Good"});
71
- setTimeout( function() {
72
- node.status({
73
- fill: "blue",
74
- shape: "dot",
75
- text: "Flow size: " + bodySize
76
- })
77
- }, 450);
89
+ var access_token = JSON.parse(res.body).access_token;
78
90
 
79
- }).catch( err => {
91
+ getFlows({
92
+ "Authorization": "Bearer " + access_token
93
+ }, module.got);
94
+
95
+ }).catch((err) => {
80
96
  node.status({fill:"red",shape:"dot",text:"Failed"});
81
- node.error(err)
97
+ node.error( err );
82
98
  });
83
- }).catch((err) => {
84
- node.status({fill:"red",shape:"dot",text:"Failed"});
85
- node.error( err );
86
99
  });
87
100
  }
88
101
  })
@@ -93,36 +106,12 @@ module.exports = function(RED) {
93
106
  * Authentication free zone...
94
107
  */
95
108
  node.status({fill:"blue",shape:"dot",text:"Requesting flows"});
96
-
97
- got.get( baseUrl + "/flows",
98
- {headers: {"Node-RED-API-Version": cfg.flowVersion}}
99
- ).then( res => {
100
- if ( res.statusCode == 200 ) {
101
- var bodySize = res.body.length;
102
-
103
- send( {
104
- ...msg,
105
- payload: res.body
106
- });
107
-
108
- node.status({fill:"green",shape:"dot",text:"Good"});
109
- setTimeout( function() {
110
- node.status({
111
- fill: "blue",
112
- shape: "dot",
113
- text: "Flow size: " + bodySize
114
- })
115
- }, 450);
116
- } else {
117
- node.error( res );
118
- node.status({fill:"red",shape:"dot",text:"Failed"});
119
- }
120
- }).catch( err => {
121
- node.status({fill:"red",shape:"dot",text:"Failed"});
122
- node.error(err)
109
+ import('got').then( (module) => {
110
+ getFlows({}, module.got);
123
111
  });
124
112
  }
125
113
  });
126
114
  }
115
+
127
116
  RED.nodes.registerType("GetFlows", GetFlowsFunctionality);
128
117
  }
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@gregoriusrippenstein/node-red-contrib-introspection",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
+ "dependencies": {
5
+ "got": "latest"
6
+ },
4
7
  "keywords": [
5
8
  "node-red"
6
9
  ],
@@ -8,7 +11,7 @@
8
11
  "license": "SEE LICENSE IN https://github.com/gorenje/node-red-contrib-introspection/blob/main/LICENSE",
9
12
  "author": "Gerrit Riessen <nodered@spreads-the.love> (https://spread-the.love)",
10
13
  "engines": {
11
- "node": ">=8"
14
+ "node": ">=16"
12
15
  },
13
16
  "node-red": {
14
17
  "version": ">=2.0.0",