@gregoriusrippenstein/node-red-contrib-introspection 0.11.5 → 0.12.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.
@@ -0,0 +1,113 @@
1
+ [
2
+ {
3
+ "id": "94afd585fb41a438",
4
+ "type": "tab",
5
+ "label": "client code loop",
6
+ "disabled": false,
7
+ "info": "Using the client code default values feature, create a loop counter.\n\nCreating a max loop counter for loop through data or whatever.",
8
+ "env": []
9
+ },
10
+ {
11
+ "id": "e0c808876e8685bd",
12
+ "type": "ClientCode",
13
+ "z": "94afd585fb41a438",
14
+ "name": "",
15
+ "clientcode": "if (msg.MAXLOOP > msg.loopcounter) {\n node.send(msg)\n}",
16
+ "format": "javascript",
17
+ "rules": [
18
+ {
19
+ "t": "default",
20
+ "p": "MAXLOOP",
21
+ "pt": "msg",
22
+ "to": "12",
23
+ "tot": "num"
24
+ },
25
+ {
26
+ "t": "fixed",
27
+ "p": "loopcounter",
28
+ "pt": "msg",
29
+ "to": "$filter([$$.loopcounter,0,0], function ($v) { $exists($v) })[0] + 1",
30
+ "tot": "jsonata"
31
+ }
32
+ ],
33
+ "x": 691,
34
+ "y": 357,
35
+ "wires": [
36
+ [
37
+ "893c3ec0bf9d100a",
38
+ "0fc98024bdd207cb"
39
+ ]
40
+ ]
41
+ },
42
+ {
43
+ "id": "523c5f1c268546ed",
44
+ "type": "inject",
45
+ "z": "94afd585fb41a438",
46
+ "name": "",
47
+ "props": [
48
+ {
49
+ "p": "MAXLOOP",
50
+ "v": "24",
51
+ "vt": "num"
52
+ },
53
+ {
54
+ "p": "topic",
55
+ "vt": "str"
56
+ }
57
+ ],
58
+ "repeat": "",
59
+ "crontab": "",
60
+ "once": false,
61
+ "onceDelay": 0.1,
62
+ "topic": "",
63
+ "x": 513,
64
+ "y": 481,
65
+ "wires": [
66
+ [
67
+ "e0c808876e8685bd"
68
+ ]
69
+ ]
70
+ },
71
+ {
72
+ "id": "893c3ec0bf9d100a",
73
+ "type": "debug",
74
+ "z": "94afd585fb41a438",
75
+ "name": "debug 1",
76
+ "active": true,
77
+ "tosidebar": true,
78
+ "console": false,
79
+ "tostatus": false,
80
+ "complete": "true",
81
+ "targetType": "full",
82
+ "statusVal": "",
83
+ "statusType": "auto",
84
+ "x": 917,
85
+ "y": 273,
86
+ "wires": []
87
+ },
88
+ {
89
+ "id": "0fc98024bdd207cb",
90
+ "type": "delay",
91
+ "z": "94afd585fb41a438",
92
+ "name": "",
93
+ "pauseType": "delay",
94
+ "timeout": "500",
95
+ "timeoutUnits": "milliseconds",
96
+ "rate": "1",
97
+ "nbRateUnits": "1",
98
+ "rateUnits": "second",
99
+ "randomFirst": "1",
100
+ "randomLast": "5",
101
+ "randomUnits": "seconds",
102
+ "drop": false,
103
+ "allowrate": false,
104
+ "outputs": 1,
105
+ "x": 915,
106
+ "y": 358,
107
+ "wires": [
108
+ [
109
+ "e0c808876e8685bd"
110
+ ]
111
+ ]
112
+ }
113
+ ]
@@ -2,7 +2,7 @@
2
2
 
3
3
  function handleMsgTracePacket(e,r){if(r.nodeid){let a=RED.nodes.node(r.nodeid);if(a){var s,r=$("#node-input-msgtracer-trace-treelist").treeList("data");let t=!1;r.forEach(e=>{e.id==a.id&&(t=!0,e.seenCounter+=1,e.sublabel=e.seenCounter+" @ "+e.workspaceLabel)}),t?$("#node-input-msgtracer-trace-treelist").treeList("data",r):(s={id:a.id,label:"",_label:RED.utils.getNodeLabel(a),seenCounter:1,workspaceLabel:(RED.nodes.workspace(a.z)||{label:a.z}).label,sublabel:"1 @ "+(RED.nodes.workspace(a.z)||{label:a.z}).label,selected:!1,checkbox:!1,node:a,icon:RED.utils.createNodeIcon(a,!0)},$("#node-input-msgtracer-trace-treelist").treeList("data",[s,...r]))}}}RED.comms.subscribe("msgtracer:node-received",(e,t)=>{try{handleMsgTracePacket(e,t)}catch(e){console.error(e)}});
4
4
 
5
- function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid,_msg,msg,node,payload,topic;"execfunc"==data.msg&&(doSend=(o,d,e)=>{"object"==typeof o&&(o={...e,...o}),$.ajax({url:"ClientCode/"+d,type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify(o),success:function(o){},error:function(o,e,t){RED.notify("ClientCode Communcation Failure: "+d+": "+e,{type:"error",id:d,timeout:3e3})}})},doStatus=(o,d,e)=>{$.ajax({url:"ClientCode/"+d+"/status",type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify(o),success:function(o){},error:function(o,e,t){RED.notify("ClientCode Communcation Failure: "+d+": "+e,{type:"error",id:d,timeout:3e3})}})},doError=(o,e,t)=>{RED.notify("ClientCode Failed: "+e+": "+o,{type:"error",id:e,timeout:3e3}),console.log("ClientCode: Error with node: "+e+": "+o)},nodeid=data.nodeid,_msg=data._msg,msg=data._msg,node={id:data.nodeid,send:o=>{doSend(o,nodeid,_msg)},error:o=>{doError(o,nodeid,_msg)},status:o=>{doStatus(o,nodeid,_msg)}},payload=data.payload,topic=data.topic,eval(data.func))}RED.comms.subscribe("introspect:client-code-perform",(o,e)=>{try{handleClientCodeFrontend(o,e)}catch(o){console.error(o)}});
5
+ function handleClientCodeFrontend(event,data){if("execfunc"==data.msg){let doSend=(e,n,t)=>{"object"==typeof e&&(e={...t,...e}),$.ajax({url:"ClientCode/"+n,type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify(e),success:function(e){},error:function(e,t,o){RED.notify("ClientCode Communcation Failure: "+n+": "+t,{type:"error",id:n,timeout:3e3})}})},doStatus=(e,n,t)=>{$.ajax({url:"ClientCode/"+n+"/status",type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify(e),success:function(e){},error:function(e,t,o){RED.notify("ClientCode Communcation Failure: "+n+": "+t,{type:"error",id:n,timeout:3e3})}})},doError=(e,t,o)=>{RED.notify("ClientCode Failed: "+t+": "+e,{type:"error",id:t,timeout:3e3}),console.log("ClientCode: Error with node: "+t+": "+e)},nodeid=data.nodeid,_msg=data._msg,msg=data._msg??{},cfg=data._cfg,node={id:data.nodeid,send:e=>{doSend(e,nodeid,_msg)},error:e=>{doError(e,nodeid,_msg)},status:e=>{doStatus(e,nodeid,_msg)}},payload=data.payload,topic=data.topic;eval(data.func)}}RED.comms.subscribe("introspect:client-code-perform",(e,t)=>{try{handleClientCodeFrontend(e,t)}catch(e){console.error(e)}});
6
6
 
7
7
  RED.nodes.registerType('ClientCode',{
8
8
  color: '#e5e4ef',
@@ -18,6 +18,9 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
18
18
  },
19
19
  format: {
20
20
  value: "javascript"
21
+ },
22
+ rules: {
23
+ value: [{ t: "default", p: "payload", pt: "msg", to: "", tot: "str" }]
21
24
  }
22
25
  },
23
26
  inputs:1,
@@ -35,6 +38,28 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
35
38
  $('#node-input-clientcode').val(this.editor.getValue());
36
39
  this.editor.destroy();
37
40
  delete this.editor;
41
+
42
+ var rules = $("#node-inpclientcode-defaults-container").editableList('items');
43
+
44
+ var node = this;
45
+ node.rules = [];
46
+
47
+ rules.each(function (i) {
48
+ var rule = $(this);
49
+ var type = rule.find(".node-input-rule-type").val();
50
+
51
+ var r = {
52
+ t: type,
53
+ p: rule.find(".node-input-rule-property-name").typedInput('value'),
54
+ pt: rule.find(".node-input-rule-property-name").typedInput('type')
55
+ };
56
+
57
+ if (type !== "notset" && type !== "debug" && type !== "set") {
58
+ r.to = rule.find(".node-input-rule-property-value").typedInput('value');
59
+ r.tot = rule.find(".node-input-rule-property-value").typedInput('type');
60
+ }
61
+ node.rules.push(r);
62
+ });
38
63
  },
39
64
 
40
65
  oneditcancel: function() {
@@ -42,16 +67,170 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
42
67
  delete this.editor;
43
68
  },
44
69
 
70
+ //
71
+ // ***********************
72
+ // Prepare editor panel
73
+ // ***********************
74
+ //
45
75
  oneditprepare: function() {
46
76
  const that = this;
77
+ const node = this;
47
78
  const stateId = RED.editor.generateViewStateId("node", this, "");
48
79
 
80
+ var to = this._("clientcode.action.to");
81
+ var toValueLabel = this._("clientcode.action.toValue", to);
82
+ var search = this._("clientcode.action.search");
83
+ var replace = this._("clientcode.action.replace");
84
+ var regex = this._("clientcode.label.regex");
85
+
86
+ function createPropertyValue(row2_1, row2_2, defaultType) {
87
+ var propValInput = $('<input/>', { class: "node-input-rule-property-value", type: "text" })
88
+ .appendTo(row2_1)
89
+ .typedInput({ default: defaultType || 'str', types: ['str', 'num', 'bool', 'json', 'bin', 'date', 'jsonata'] });
90
+
91
+ propValInput.on("change", function (evt, type, val) {
92
+ row2_2.toggle(type === "msg" || type === "flow" || type === "global" || type === "env");
93
+ })
94
+ return [propValInput, undefined];
95
+ }
96
+
97
+ var tabs = RED.tabs.create({
98
+ id: "client-code-tabs",
99
+ onchange: function (tab) {
100
+ $("#client-code-tabs-content").children().hide();
101
+ $("#" + tab.id).show();
102
+ }
103
+ });
104
+
105
+ tabs.addTab({
106
+ id: "client-code-tabs-default-values",
107
+ iconClass: "fa fa-cog",
108
+ label: "msg parameters"
109
+ });
110
+
111
+ tabs.addTab({
112
+ id: "client-code-tabs-code-editor",
113
+ iconClass: "fa fa-edit",
114
+ label: "editor"
115
+ });
116
+
117
+ tabs.activateTab("client-code-tabs-code-editor");
118
+
119
+
120
+ $('#node-inpclientcode-defaults-container').css('min-height', '150px').css('min-width', '450px').editableList({
121
+ addItem: function (container, i, opt) {
122
+ var rule = opt;
123
+ if (!rule.hasOwnProperty('t')) {
124
+ rule = { t: "default", p: "payload", to: "", tot: "str" };
125
+ }
126
+ container.css({
127
+ overflow: 'hidden',
128
+ whiteSpace: 'nowrap'
129
+ });
130
+ let fragment = document.createDocumentFragment();
131
+ var row1 = $('<div/>', { style: "display:flex; align-items: baseline" }).appendTo(fragment);
132
+ var row2 = $('<div/>', { style: "margin-top:8px;" }).appendTo(fragment);
133
+ var row3 = $('<div/>', { style: "margin-top:8px;" }).appendTo(fragment);
134
+ var row4 = $('<div/>', { style: "display:flex;margin-top:8px;align-items: baseline" }).appendTo(fragment);
135
+
136
+ var selectField = $('<select/>', { class: "node-input-rule-type", style: "width:110px; margin-right:10px;" }).appendTo(row1);
137
+ var selectOptions = [
138
+ { v: "default" },
139
+ { v: "overwrite" },
140
+ { v: "fixed" },
141
+ ];
142
+ for (var i = 0; i < selectOptions.length; i++) {
143
+ let label = node._("clientcode.action." + (selectOptions[i].l || selectOptions[i].v))
144
+ selectField.append($("<option></option>").val(selectOptions[i].v).text(label));
145
+ }
146
+
147
+ var propertyName = $('<input/>', { class: "node-input-rule-property-name", type: "text" })
148
+ .appendTo(row1)
149
+ .typedInput({ types: ['msg'] });
150
+
151
+ var row2_1 = $('<div/>', { style: "display:flex;align-items: baseline" }).appendTo(row2);
152
+ $('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
153
+ .text(toValueLabel)
154
+ .appendTo(row2_1);
155
+
156
+ var row2_2 = $('<div/>', { style: "margin-top: 4px;" }).appendTo(row2);
157
+
158
+ var row3_1 = $('<div/>', { style: "display:flex;align-items: baseline" }).appendTo(row3);
159
+ $('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
160
+ .text(search)
161
+ .appendTo(row3_1);
162
+
163
+ var row3_2 = $('<div/>', { style: "display:flex;margin-top:8px;align-items: baseline" }).appendTo(row3);
164
+ $('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
165
+ .text(replace)
166
+ .appendTo(row3_2);
167
+
168
+ $('<div/>', { style: "display:inline-block;text-align:right; width:120px; padding-right:10px; box-sizing:border-box;" })
169
+ .text(to)
170
+ .appendTo(row4);
171
+
172
+ let propertyValue = null;
173
+ let fromValue = null;
174
+ let toValue = null;
175
+ let moveValue = null;
176
+
177
+ selectField.on("change", function () {
178
+ var type = $(this).val();
179
+ if (propertyValue) {
180
+ propertyValue.typedInput('hide');
181
+ }
182
+ if (fromValue) {
183
+ fromValue.typedInput('hide');
184
+ }
185
+ if (toValue) {
186
+ toValue.typedInput('hide');
187
+ }
188
+ if (moveValue) {
189
+ moveValue.typedInput('hide');
190
+ }
191
+
192
+ if (type != "notset" && type != "debug" && type != "set") {
193
+ if (!propertyValue) {
194
+ var parts = createPropertyValue(row2_1, row2_2);
195
+ propertyValue = parts[0];
196
+ }
197
+
198
+ propertyValue.typedInput('show');
199
+ propertyValue.typedInput('value', rule.to);
200
+ propertyValue.typedInput('type', rule.tot);
201
+
202
+ row2.show();
203
+ row3.hide();
204
+ row4.hide();
205
+ } else {
206
+ row2.hide();
207
+ row3.hide();
208
+ row4.hide();
209
+ }
210
+ });
211
+
212
+ selectField.val(rule.t);
213
+ propertyName.typedInput('value', rule.p);
214
+ propertyName.typedInput('type', rule.pt);
215
+ selectField.change();
216
+ container[0].appendChild(fragment);
217
+ },
218
+ removable: true,
219
+ sortable: true
220
+ });
221
+
222
+ this.rules = this.rules ?? [{t: "default", p: "payload", pt: "msg", to: "", tot: "str"}]
223
+ for (var i = 0; i < this.rules.length; i++) {
224
+ var rule = this.rules[i];
225
+ $("#node-inpclientcode-defaults-container").editableList('addItem', rule);
226
+ }
227
+
49
228
  this.editor = RED.editor.createEditor({
50
229
  id: 'node-input-clientcode-editor',
51
230
  mode: 'ace/mode/nrjavascript',
52
231
  stateId: stateId,
53
232
  globals: {
54
- msg:true,
233
+ msg:true,
55
234
  RED: true,
56
235
  node: true,
57
236
  alert: true,
@@ -96,22 +275,53 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
96
275
 
97
276
  },
98
277
 
278
+ //
279
+ // *******************
280
+ // Resize event
281
+ // *******************
282
+ //
99
283
  oneditresize: function(size) {
100
- var rows = $("#dialog-form>div:not(.node-text-editor-row)");
284
+ var rows = $("#dialog-form #client-code-tabs-code-editor>div:not(.node-text-editor-row)");
101
285
  var height = $("#dialog-form").height();
102
286
  for (var i=0; i<rows.length; i++) {
103
287
  height -= $(rows[i]).outerHeight(true);
104
288
  }
105
- var editorRow = $("#dialog-form>div.node-text-editor-row");
289
+
290
+ var rows = $("#dialog-form>.client-code-node-name-row");
291
+ for (var i=0; i<rows.length; i++) {
292
+ height -= $(rows[i]).outerHeight(true);
293
+ }
294
+
295
+ // footer
296
+ height -= 40;
297
+
298
+ var editorRow = $("#dialog-form #client-code-tabs-code-editor>div.node-text-editor-row");
106
299
  height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
107
300
  $(".node-text-editor").css("height",height+"px");
301
+
108
302
  this.editor.resize();
303
+
304
+ //
305
+ //
306
+ //
307
+ if ($('#client-code-tabs-default-values').is(":visible")) {
308
+ var rows = $("#dialog-form #client-code-tabs-default-values>div:not(.node-inpclientcode-defaults-container-row)");
309
+ var height = size.height;
310
+ for (var i=0; i<rows.length; i++) {
311
+ height -= $(rows[i]).outerHeight(true);
312
+ }
313
+ var editorRow = $("#dialog-form #client-code-tabs-default-values>div.node-input-rule-container-row");
314
+ height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
315
+ $("#node-inpclientcode-defaults-container").editableList('height', height-60);
316
+ } else {
317
+ $("#node-inpclientcode-defaults-container").editableList('height', height/3);
318
+ }
109
319
  }
110
320
  });
111
321
  </script>
112
322
 
113
323
  <script type="text/html" data-template-name="ClientCode">
114
- <div class="form-row">
324
+ <div class="form-row client-code-node-name-row">
115
325
  <label for="node-input-name">
116
326
  <i class="fa fa-tag"></i>
117
327
  <span data-i18n="common.label.name">Name</span>
@@ -119,40 +329,56 @@ function handleClientCodeFrontend(event,data){var doSend,doStatus,doError,nodeid
119
329
  <input type="text" id="node-input-name" placeholder="Name">
120
330
  </div>
121
331
 
122
- <div class="form-row" style="position: relative; margin-bottom: 0px;">
123
- <label for="node-input-clientcode">
124
- <i class="fa fa-file-code-o"></i> Client Code
125
- </label>
332
+ <div class="form-row func-tabs-row">
333
+ <ul style="min-width: 400px; margin-bottom: 20px;" id="client-code-tabs"></ul>
334
+ </div>
335
+
336
+ <div id="client-code-tabs-content" style="min-height: calc(100% - 95px);">
126
337
 
127
- <div style="position: absolute; right:0;display:inline-block; text-align: right; font-size: 0.8em;">
128
- Syntax:
129
- <select id="node-input-format" style="width:110px; font-size: 10px !important; height: 24px; padding:0;">
130
- <option value="handlebars">mustache</option>
131
- <option value="html">HTML</option>
132
- <option value="json">JSON</option>
133
- <option value="javascript">JavaScript</option>
134
- <option value="css">CSS</option>
135
- <option value="markdown">Markdown</option>
136
- <option value="php">PHP</option>
137
- <option value="python">Python</option>
138
- <option value="sql">SQL</option>
139
- <option value="yaml">YAML</option>
140
- <option value="text">None</option>
141
- </select>
142
- <button type="button" id="node-clientcode-expand-editor"
143
- class="red-ui-button red-ui-button-small">
144
- <i class="fa fa-expand"></i>
145
- </button>
338
+ <div id="client-code-tabs-default-values" style="display:none;">
339
+ <div class="form-row node-input-rule-container-row node-inpclientcode-defaults-container-row">
340
+ <ol id="node-inpclientcode-defaults-container"></ol>
146
341
  </div>
147
- </div>
342
+ </div>
148
343
 
149
- <div class="form-row node-text-editor-row">
150
- <div style="height: 250px; min-height:150px;"
151
- class="node-text-editor"
152
- id="node-input-clientcode-editor" ></div>
153
- </div>
344
+ <div id="client-code-tabs-code-editor">
345
+ <div class="form-row" style="position: relative; margin-bottom: 0px;">
346
+ <label for="node-input-clientcode">
347
+ <i class="fa fa-file-code-o"></i> Client Code
348
+ </label>
349
+
350
+ <div style="position: absolute; right:0;display:inline-block; text-align: right; font-size: 0.8em;">
351
+ Syntax:
352
+ <select id="node-input-format" style="width:110px; font-size: 10px !important; height: 24px; padding:0;">
353
+ <option value="handlebars">mustache</option>
354
+ <option value="html">HTML</option>
355
+ <option value="json">JSON</option>
356
+ <option value="javascript">JavaScript</option>
357
+ <option value="css">CSS</option>
358
+ <option value="markdown">Markdown</option>
359
+ <option value="php">PHP</option>
360
+ <option value="python">Python</option>
361
+ <option value="sql">SQL</option>
362
+ <option value="yaml">YAML</option>
363
+ <option value="text">None</option>
364
+ </select>
365
+ <button type="button" id="node-clientcode-expand-editor"
366
+ class="red-ui-button red-ui-button-small">
367
+ <i class="fa fa-expand"></i>
368
+ </button>
369
+ </div>
370
+ </div>
371
+
372
+ <div class="form-row node-text-editor-row">
373
+ <div style="height: 250px; min-height:150px;"
374
+ class="node-text-editor"
375
+ id="node-input-clientcode-editor" ></div>
376
+ </div>
154
377
 
155
- <input type="hidden" id="node-input-clientcode" autofocus="autofocus">
378
+ <input type="hidden" id="node-input-clientcode" autofocus="autofocus">
379
+ </div>
380
+
381
+ </div>
156
382
  </script>
157
383
 
158
384
  <script type="text/html" data-help-name="ClientCode">
@@ -168,6 +394,7 @@ Variables:
168
394
  node.id - id of this node, same as `nodeid` above
169
395
  payload - a reference to msg.payload as it was received by this node
170
396
  topic - a reference to the msg.topic as it was recieved by this node
397
+ cfg - an object that represents the default values defined in the msg parameters tab
171
398
 
172
399
  Functionality:
173
400
  node.send({..}) - send data to the output port of this node
@@ -191,4 +418,19 @@ Functionality:
191
418
  The code to be executed by the client can also be passed in via the `msg` object using the
192
419
  `clientcode` attribute on the `msg` object. If this attribute is set, it will take precendence
193
420
  over the code defined in the node itself.
421
+
422
+ <p>
423
+ Handling of Default Values
424
+ <p>
425
+ Each default value can either be default, overwrite or fixed:
426
+ <li>
427
+ <ul><b>Default</b> - value is set on the message if value isn't set on the msg object already. Else the msg value is used.</ul>
428
+ <ul><b>Overwrite</b> - default value overwrites the existing value on the message. If the property does not exist on the message, then the default value is ignored. A default value will only overwrite if the value is already defined on the msg object.</ul>
429
+ <ul><b>Fixed</b> - the default value is always used, ignoring whether the value is already set or not on the msg object. This is useful for constants or JSONata expressions - see loop counter below.</ul>
430
+ </li>
431
+ <p>
432
+ Loop counters using jsonata
433
+ <p>
434
+ One usage of the default values is as an loop counter for messages going around and around. To define a loopcounter which is only defined on the msg object, define a default value <code>loopcounter</code> with the following JSONata code <code>$filter([$$.loopcounter,0,0], function ($v) { $exists($v) })[0] + 1</code> ($filter returns a single value if the array only contains one value else it returns an array).
435
+
194
436
  </script>
@@ -58,6 +58,49 @@ module.exports = function (RED) {
58
58
  var node = this;
59
59
  var cfg = config;
60
60
 
61
+ function getToValue(msg, rule, done) {
62
+ var value = rule.to;
63
+
64
+ if (rule.tot === 'json') {
65
+ value = JSON.parse(rule.to);
66
+ } else if (rule.tot === 'bin') {
67
+ value = Buffer.from(JSON.parse(rule.to))
68
+ } else if (rule.tot === 'str') {
69
+ value = rule.to
70
+ } else if (rule.tot === "num") {
71
+ value = Number(rule.to)
72
+ } else if (rule.tot === "bool") {
73
+ value = /^true$/i.test(rule.to);
74
+ }
75
+
76
+ if (rule.tot === "msg") {
77
+ value = RED.util.getMessageProperty(msg, rule.to);
78
+ } else if ((rule.tot === 'flow') || (rule.tot === 'global')) {
79
+ RED.util.evaluateNodeProperty(rule.to, rule.tot, node, msg, (err, value) => {
80
+ if (err) {
81
+ done(undefined, undefined);
82
+ } else {
83
+ done(undefined, value);
84
+ }
85
+ });
86
+ return
87
+ } else if (rule.tot === 'date') {
88
+ value = RED.util.evaluateNodeProperty(rule.to, rule.tot, node)
89
+ } else if (rule.tot === 'jsonata') {
90
+ let jsonExpr = RED.util.prepareJSONataExpression(rule.to, node);
91
+
92
+ RED.util.evaluateJSONataExpression(jsonExpr, msg, (err, value) => {
93
+ if (err) {
94
+ done(RED._("change.errors.invalid-expr", { error: err.message }))
95
+ } else {
96
+ done(undefined, value);
97
+ }
98
+ });
99
+ return;
100
+ }
101
+ done(undefined, value);
102
+ }
103
+
61
104
  node.on('close', function () {
62
105
  node.status({});
63
106
  });
@@ -72,17 +115,48 @@ module.exports = function (RED) {
72
115
  node.error(e)
73
116
  }
74
117
 
75
- RED.comms.publish(
76
- "introspect:client-code-perform",
77
- RED.util.encodeObject({
78
- msg: "execfunc",
79
- payload: msg.payload,
80
- topic: msg.topic,
81
- func: msg.clientcode || cfg.clientcode,
82
- nodeid: node.id,
83
- _msg: msg
84
- })
85
- );
118
+ let defaultValues = {}
119
+
120
+ let stupidLoop = (ruleIdx) => {
121
+ if ( ruleIdx >= (cfg.rules || []).length) {
122
+ RED.comms.publish(
123
+ "introspect:client-code-perform",
124
+ RED.util.encodeObject({
125
+ msg: "execfunc",
126
+ payload: msg.payload,
127
+ topic: msg.topic,
128
+ func: msg.clientcode || cfg.clientcode,
129
+ nodeid: node.id,
130
+ _msg: msg,
131
+ _cfg: defaultValues
132
+ })
133
+ );
134
+ done()
135
+ } else {
136
+ try {
137
+ let rule = cfg.rules[ruleIdx]
138
+ let name = rule.p
139
+
140
+ getToValue(msg, rule, (err, value) => {
141
+ defaultValues[name] = value
142
+ if ( rule.t == "fixed" ) {
143
+ msg[name] = value
144
+ } else if (rule.t == "default") {
145
+ msg[name] = msg[name] ?? value
146
+ } else if (rule.t == "overwrite" && msg.hasOwnProperty(name)) {
147
+ msg[name] = value ?? msg[name]
148
+ }
149
+
150
+ stupidLoop(ruleIdx+1)
151
+ })
152
+ } catch (e) {
153
+ console.log(e)
154
+ stupidLoop(ruleIdx + 1)
155
+ }
156
+ }
157
+ }
158
+
159
+ stupidLoop(0)
86
160
  });
87
161
  }
88
162
 
@@ -0,0 +1,62 @@
1
+ {
2
+ "clientcode": {
3
+ "label": {
4
+ "statusset": "Status Set",
5
+ "rules": "Rules",
6
+ "rule": "rule",
7
+
8
+ "set": "set __property__",
9
+ "change": "change __property__",
10
+ "delete": "delete __property__",
11
+ "move": "move __property__",
12
+
13
+ "changeCount": "assert: __count__ values",
14
+ "regex": "Use regular expressions",
15
+ "deepCopy": "Deep copy value",
16
+
17
+ "notmth": "not match __property__",
18
+ "mth": "match __property__",
19
+ "eql": "equal __property__",
20
+ "noteql": "not equal __property__",
21
+ "notset": "not set __property__",
22
+ "debug": "debug __property__",
23
+ "unsupported": "supported rule __property__",
24
+
25
+ "ignore_failure_if_succeed": "Ignore failure if succeed once"
26
+ },
27
+
28
+ "action": {
29
+ "default": "Default",
30
+ "overwrite": "Overwrite",
31
+ "fixed": "Fixed",
32
+ "set": "Defined",
33
+ "change": "Change",
34
+ "delete": "Delete",
35
+ "move": "Move",
36
+ "toValue": "to the value",
37
+ "to": "to",
38
+ "search": "Search for",
39
+ "replace": "Replace with",
40
+
41
+ "notmth": "Not Match",
42
+ "mth": "Match",
43
+ "eql": "Equal",
44
+ "noteql": "Not Equal",
45
+ "notset": "Not Defined",
46
+ "debug": "Debug"
47
+ },
48
+
49
+ "errors": {
50
+ "invalid-from": "Invalid 'from' property: __error__",
51
+ "invalid-json": "Invalid 'to' JSON property",
52
+ "invalid-expr": "Invalid JSONata expression: __error__",
53
+ "no-override": "Cannot set property of non-object type: __property__",
54
+ "invalid-prop": "Invalid property expression: __property__",
55
+ "invalid-json-data": "Invalid JSON data: __error__"
56
+ },
57
+ "status": {
58
+ "waiting": "Waiting for Godot",
59
+ "timeout": "No more time to waiting"
60
+ }
61
+ }
62
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gregoriusrippenstein/node-red-contrib-introspection",
3
- "version": "0.11.5",
3
+ "version": "0.12.1",
4
4
  "dependencies": {
5
5
  "got": "^13",
6
6
  "uglify-js": "^3.17.4",