@ralphwetzel/node-red-context-monitor 1.2.0 → 2.0.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 +13 -1
- package/examples/context-monitor.json +231 -40
- package/lib/monitor.js +3 -9
- package/monitor.html +258 -165
- package/monitor.js +58 -9
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -79,4 +79,16 @@ You may define a setup that doesn't monitor the (whole) object, but only one of
|
|
|
79
79
|
<img alt="flow" src="https://raw.githubusercontent.com/ralphwetzel/node-red-context-monitor/main/resources/object_prop.png"
|
|
80
80
|
style="min-width: 474px; width: 474px; align: center; border: 1px solid lightgray;"/>
|
|
81
81
|
|
|
82
|
-
Such a monitor will react _only_, when this property and - if it's an object - its child properties are written to.
|
|
82
|
+
Such a monitor will react _only_, when this property and - if it's an object - its child properties are written to.
|
|
83
|
+
|
|
84
|
+
### Subflow considerations
|
|
85
|
+
You may use this node in [subflows](https://nodered.org/docs/user-guide/editor/workspace/subflows).
|
|
86
|
+
|
|
87
|
+
Monitoring a `Node` scope context of a node within a subflow is only supported if both nodes (the context monitor and the node to be monitored) belong to the same subflow. Please select `Current Flow` when defining the monitoring context reference.
|
|
88
|
+
|
|
89
|
+
Please be aware that all instances of a subflow commonly share a single `Flow` scope context. According to the [Node-RED documentation](https://nodered.org/docs/user-guide/context#context-scopes), you can reference the context of the superior flow by prepending `$parent` to the context key.
|
|
90
|
+
|
|
91
|
+
### Handling of context definition issues
|
|
92
|
+
If you edit this node's properties, it ensures that the context reference defined is always valid.
|
|
93
|
+
By _copy/paste_-ing a node already configured its configuration yet might become invalid. Same applies if you delete flows or nodes that were referenced earlier.
|
|
94
|
+
To ensure the setup, the node does a lazy validation of the context reference definition - when editing its properties and when it is (re)launched. You yet won't get a "red triangle" even if the reference became invalid - to allow a smooth flow editing experience.
|
|
@@ -1,6 +1,107 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
|
-
"id": "
|
|
3
|
+
"id": "6780aa88c7c4d336",
|
|
4
|
+
"type": "subflow",
|
|
5
|
+
"name": "context in subflow",
|
|
6
|
+
"info": "",
|
|
7
|
+
"category": "",
|
|
8
|
+
"in": [
|
|
9
|
+
{
|
|
10
|
+
"x": 120,
|
|
11
|
+
"y": 80,
|
|
12
|
+
"wires": [
|
|
13
|
+
{
|
|
14
|
+
"id": "a328f1e205c03a15"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"out": [
|
|
20
|
+
{
|
|
21
|
+
"x": 330,
|
|
22
|
+
"y": 160,
|
|
23
|
+
"wires": [
|
|
24
|
+
{
|
|
25
|
+
"id": "88f5bf36b88ae76b",
|
|
26
|
+
"port": 0
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"x": 340,
|
|
32
|
+
"y": 240,
|
|
33
|
+
"wires": [
|
|
34
|
+
{
|
|
35
|
+
"id": "88f5bf36b88ae76b",
|
|
36
|
+
"port": 1
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"env": [],
|
|
42
|
+
"meta": {},
|
|
43
|
+
"color": "#DDAA99",
|
|
44
|
+
"outputLabels": [
|
|
45
|
+
"context set",
|
|
46
|
+
"context change"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "a328f1e205c03a15",
|
|
51
|
+
"type": "function",
|
|
52
|
+
"z": "6780aa88c7c4d336",
|
|
53
|
+
"name": "set subflow & node context",
|
|
54
|
+
"func": "flow.set(\"subflow_flow_test\", \"flow\");\ncontext.set(\"subflow_node_test\", \"node\");\nreturn msg;",
|
|
55
|
+
"outputs": 1,
|
|
56
|
+
"timeout": 0,
|
|
57
|
+
"noerr": 0,
|
|
58
|
+
"initialize": "",
|
|
59
|
+
"finalize": "",
|
|
60
|
+
"libs": [],
|
|
61
|
+
"x": 300,
|
|
62
|
+
"y": 80,
|
|
63
|
+
"wires": [
|
|
64
|
+
[]
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "88f5bf36b88ae76b",
|
|
69
|
+
"type": "context-monitor",
|
|
70
|
+
"z": "6780aa88c7c4d336",
|
|
71
|
+
"name": "",
|
|
72
|
+
"monitoring": [
|
|
73
|
+
{
|
|
74
|
+
"scope": "global",
|
|
75
|
+
"key": "global_test"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"scope": "flow",
|
|
79
|
+
"flow": ".",
|
|
80
|
+
"key": "subflow_flow_test"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"scope": "flow",
|
|
84
|
+
"flow": ".",
|
|
85
|
+
"key": "$parent.flow_test"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"scope": "node",
|
|
89
|
+
"flow": ".",
|
|
90
|
+
"node": "a328f1e205c03a15",
|
|
91
|
+
"key": "subflow_node_test",
|
|
92
|
+
"node_label": "set subflow & node context"
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"tostatus": false,
|
|
96
|
+
"x": 160,
|
|
97
|
+
"y": 200,
|
|
98
|
+
"wires": [
|
|
99
|
+
[],
|
|
100
|
+
[]
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "841613b260a4c5ce",
|
|
4
105
|
"type": "tab",
|
|
5
106
|
"label": "Context Monitoring Example",
|
|
6
107
|
"disabled": false,
|
|
@@ -8,9 +109,9 @@
|
|
|
8
109
|
"env": []
|
|
9
110
|
},
|
|
10
111
|
{
|
|
11
|
-
"id": "
|
|
112
|
+
"id": "88cfd03e4a1d674a",
|
|
12
113
|
"type": "inject",
|
|
13
|
-
"z": "
|
|
114
|
+
"z": "841613b260a4c5ce",
|
|
14
115
|
"name": "",
|
|
15
116
|
"props": [
|
|
16
117
|
{
|
|
@@ -28,34 +129,36 @@
|
|
|
28
129
|
"topic": "",
|
|
29
130
|
"payload": "",
|
|
30
131
|
"payloadType": "date",
|
|
31
|
-
"x":
|
|
32
|
-
"y":
|
|
132
|
+
"x": 120,
|
|
133
|
+
"y": 120,
|
|
33
134
|
"wires": [
|
|
34
135
|
[
|
|
35
|
-
"
|
|
136
|
+
"ee1a6dc083b2db28",
|
|
137
|
+
"5384329446d6d4bd"
|
|
36
138
|
]
|
|
37
139
|
]
|
|
38
140
|
},
|
|
39
141
|
{
|
|
40
|
-
"id": "
|
|
142
|
+
"id": "cc42435c8c1e18d2",
|
|
41
143
|
"type": "debug",
|
|
42
|
-
"z": "
|
|
43
|
-
"name": "
|
|
144
|
+
"z": "841613b260a4c5ce",
|
|
145
|
+
"name": "timestamp",
|
|
44
146
|
"active": true,
|
|
45
147
|
"tosidebar": true,
|
|
46
148
|
"console": false,
|
|
47
149
|
"tostatus": false,
|
|
48
|
-
"complete": "
|
|
150
|
+
"complete": "payload",
|
|
151
|
+
"targetType": "msg",
|
|
49
152
|
"statusVal": "",
|
|
50
153
|
"statusType": "auto",
|
|
51
|
-
"x":
|
|
154
|
+
"x": 750,
|
|
52
155
|
"y": 80,
|
|
53
156
|
"wires": []
|
|
54
157
|
},
|
|
55
158
|
{
|
|
56
|
-
"id": "
|
|
159
|
+
"id": "ee1a6dc083b2db28",
|
|
57
160
|
"type": "change",
|
|
58
|
-
"z": "
|
|
161
|
+
"z": "841613b260a4c5ce",
|
|
59
162
|
"name": "",
|
|
60
163
|
"rules": [
|
|
61
164
|
{
|
|
@@ -71,6 +174,20 @@
|
|
|
71
174
|
"pt": "global",
|
|
72
175
|
"to": "hello!",
|
|
73
176
|
"tot": "str"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"t": "set",
|
|
180
|
+
"p": "obj_test",
|
|
181
|
+
"pt": "flow",
|
|
182
|
+
"to": "{\"x\": 1,\"y\": 2}",
|
|
183
|
+
"tot": "jsonata"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"t": "set",
|
|
187
|
+
"p": "obj_test.y",
|
|
188
|
+
"pt": "flow",
|
|
189
|
+
"to": "",
|
|
190
|
+
"tot": "str"
|
|
74
191
|
}
|
|
75
192
|
],
|
|
76
193
|
"action": "",
|
|
@@ -78,18 +195,18 @@
|
|
|
78
195
|
"from": "",
|
|
79
196
|
"to": "",
|
|
80
197
|
"reg": false,
|
|
81
|
-
"x":
|
|
198
|
+
"x": 310,
|
|
82
199
|
"y": 80,
|
|
83
200
|
"wires": [
|
|
84
201
|
[
|
|
85
|
-
"
|
|
202
|
+
"5bb28494f5abb001"
|
|
86
203
|
]
|
|
87
204
|
]
|
|
88
205
|
},
|
|
89
206
|
{
|
|
90
|
-
"id": "
|
|
207
|
+
"id": "6af64a8365dc83ca",
|
|
91
208
|
"type": "debug",
|
|
92
|
-
"z": "
|
|
209
|
+
"z": "841613b260a4c5ce",
|
|
93
210
|
"name": "debug on set",
|
|
94
211
|
"active": true,
|
|
95
212
|
"tosidebar": true,
|
|
@@ -99,41 +216,42 @@
|
|
|
99
216
|
"targetType": "full",
|
|
100
217
|
"statusVal": "",
|
|
101
218
|
"statusType": "auto",
|
|
102
|
-
"x":
|
|
103
|
-
"y":
|
|
219
|
+
"x": 530,
|
|
220
|
+
"y": 240,
|
|
104
221
|
"wires": []
|
|
105
222
|
},
|
|
106
223
|
{
|
|
107
|
-
"id": "
|
|
224
|
+
"id": "5bb28494f5abb001",
|
|
108
225
|
"type": "function",
|
|
109
|
-
"z": "
|
|
110
|
-
"name": "set node context",
|
|
111
|
-
"func": "context.set(\"node_test\", 15);\nreturn msg;",
|
|
226
|
+
"z": "841613b260a4c5ce",
|
|
227
|
+
"name": "set node & object context",
|
|
228
|
+
"func": "context.set(\"node_test\", 15);\n\nlet ot = flow.get(\"obj_test\");\not.y = \"17\";\n\nreturn msg;",
|
|
112
229
|
"outputs": 1,
|
|
113
230
|
"timeout": 0,
|
|
114
231
|
"noerr": 0,
|
|
115
232
|
"initialize": "",
|
|
116
233
|
"finalize": "",
|
|
117
234
|
"libs": [],
|
|
118
|
-
"x":
|
|
235
|
+
"x": 530,
|
|
119
236
|
"y": 80,
|
|
120
237
|
"wires": [
|
|
121
238
|
[
|
|
122
|
-
"
|
|
239
|
+
"cc42435c8c1e18d2"
|
|
123
240
|
]
|
|
124
241
|
]
|
|
125
242
|
},
|
|
126
243
|
{
|
|
127
|
-
"id": "
|
|
244
|
+
"id": "3d32ba0d798b3044",
|
|
128
245
|
"type": "context-monitor",
|
|
129
|
-
"z": "
|
|
246
|
+
"z": "841613b260a4c5ce",
|
|
130
247
|
"name": "",
|
|
131
248
|
"monitoring": [
|
|
132
249
|
{
|
|
133
250
|
"scope": "node",
|
|
134
|
-
"flow": "
|
|
135
|
-
"node": "
|
|
136
|
-
"key": "node_test"
|
|
251
|
+
"flow": ".",
|
|
252
|
+
"node": "5bb28494f5abb001",
|
|
253
|
+
"key": "node_test",
|
|
254
|
+
"node_label": "set node & object context"
|
|
137
255
|
},
|
|
138
256
|
{
|
|
139
257
|
"scope": "global",
|
|
@@ -141,26 +259,31 @@
|
|
|
141
259
|
},
|
|
142
260
|
{
|
|
143
261
|
"scope": "flow",
|
|
144
|
-
"flow": "
|
|
145
|
-
"node": "f2874060375785b7",
|
|
262
|
+
"flow": ".",
|
|
146
263
|
"key": "flow_test"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"scope": "flow",
|
|
267
|
+
"key": "obj_test[\"y\"]",
|
|
268
|
+
"flow": "."
|
|
147
269
|
}
|
|
148
270
|
],
|
|
149
|
-
"
|
|
150
|
-
"
|
|
271
|
+
"tostatus": false,
|
|
272
|
+
"x": 340,
|
|
273
|
+
"y": 260,
|
|
151
274
|
"wires": [
|
|
152
275
|
[
|
|
153
|
-
"
|
|
276
|
+
"6af64a8365dc83ca"
|
|
154
277
|
],
|
|
155
278
|
[
|
|
156
|
-
"
|
|
279
|
+
"73e8a36b611ff4b5"
|
|
157
280
|
]
|
|
158
281
|
]
|
|
159
282
|
},
|
|
160
283
|
{
|
|
161
|
-
"id": "
|
|
284
|
+
"id": "73e8a36b611ff4b5",
|
|
162
285
|
"type": "debug",
|
|
163
|
-
"z": "
|
|
286
|
+
"z": "841613b260a4c5ce",
|
|
164
287
|
"name": "debug on change",
|
|
165
288
|
"active": true,
|
|
166
289
|
"tosidebar": true,
|
|
@@ -170,8 +293,76 @@
|
|
|
170
293
|
"targetType": "full",
|
|
171
294
|
"statusVal": "",
|
|
172
295
|
"statusType": "auto",
|
|
173
|
-
"x":
|
|
174
|
-
"y":
|
|
296
|
+
"x": 550,
|
|
297
|
+
"y": 280,
|
|
298
|
+
"wires": []
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"id": "5384329446d6d4bd",
|
|
302
|
+
"type": "subflow:6780aa88c7c4d336",
|
|
303
|
+
"z": "841613b260a4c5ce",
|
|
304
|
+
"name": "",
|
|
305
|
+
"x": 310,
|
|
306
|
+
"y": 160,
|
|
307
|
+
"wires": [
|
|
308
|
+
[
|
|
309
|
+
"65585d8fc2043584"
|
|
310
|
+
],
|
|
311
|
+
[
|
|
312
|
+
"7740234648a5e725"
|
|
313
|
+
]
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"id": "65585d8fc2043584",
|
|
318
|
+
"type": "debug",
|
|
319
|
+
"z": "841613b260a4c5ce",
|
|
320
|
+
"name": "subflow on set",
|
|
321
|
+
"active": true,
|
|
322
|
+
"tosidebar": true,
|
|
323
|
+
"console": false,
|
|
324
|
+
"tostatus": false,
|
|
325
|
+
"complete": "true",
|
|
326
|
+
"targetType": "full",
|
|
327
|
+
"statusVal": "",
|
|
328
|
+
"statusType": "auto",
|
|
329
|
+
"x": 540,
|
|
330
|
+
"y": 140,
|
|
331
|
+
"wires": []
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"id": "7740234648a5e725",
|
|
335
|
+
"type": "debug",
|
|
336
|
+
"z": "841613b260a4c5ce",
|
|
337
|
+
"name": "subflow on change",
|
|
338
|
+
"active": true,
|
|
339
|
+
"tosidebar": true,
|
|
340
|
+
"console": false,
|
|
341
|
+
"tostatus": false,
|
|
342
|
+
"complete": "true",
|
|
343
|
+
"targetType": "full",
|
|
344
|
+
"statusVal": "",
|
|
345
|
+
"statusType": "auto",
|
|
346
|
+
"x": 550,
|
|
347
|
+
"y": 180,
|
|
175
348
|
"wires": []
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"id": "1b20ba795e278a6c",
|
|
352
|
+
"type": "comment",
|
|
353
|
+
"z": "841613b260a4c5ce",
|
|
354
|
+
"name": "If you got a warning that some of these nodes already exist and\\n you decided to import the flow by creating copies of these nodes,\\n the \"Node\" scope context refences might become invalid & might need to be adjusted.",
|
|
355
|
+
"info": "",
|
|
356
|
+
"x": 320,
|
|
357
|
+
"y": 380,
|
|
358
|
+
"wires": []
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"id": "4569e4487b4e777f",
|
|
362
|
+
"type": "global-config",
|
|
363
|
+
"env": [],
|
|
364
|
+
"modules": {
|
|
365
|
+
"@ralphwetzel/node-red-context-monitor": "2.0.0"
|
|
366
|
+
}
|
|
176
367
|
}
|
|
177
368
|
]
|
package/lib/monitor.js
CHANGED
|
@@ -290,18 +290,12 @@ let trigger = function(root_id, context_id, key, new_value, previous_value, prop
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
switch (node.data.scope) {
|
|
293
|
-
case "global":
|
|
294
|
-
msg.monitoring.key = node.data.key;
|
|
295
|
-
break;
|
|
296
|
-
case "flow":
|
|
297
|
-
msg.monitoring.flow = node.data.flow;
|
|
298
|
-
msg.monitoring.key = node.data.key;
|
|
299
|
-
break;
|
|
300
293
|
case "node":
|
|
301
|
-
msg.monitoring.flow = node.data.flow;
|
|
302
294
|
msg.monitoring.node = node.data.node;
|
|
295
|
+
case "flow":
|
|
296
|
+
msg.monitoring.flow = node.data.flow;
|
|
297
|
+
case "global":
|
|
303
298
|
msg.monitoring.key = node.data.key;
|
|
304
|
-
break;
|
|
305
299
|
}
|
|
306
300
|
|
|
307
301
|
n.receive(msg);
|
package/monitor.html
CHANGED
|
@@ -79,21 +79,78 @@
|
|
|
79
79
|
function add_context(tpl) {
|
|
80
80
|
let c = {
|
|
81
81
|
"scope": tpl.scope ?? "global",
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
|
|
83
|
+
// There's a special flow marker "." that indicates "Current Flow"!
|
|
84
|
+
"flow": tpl.flow ?? ".",
|
|
85
|
+
|
|
84
86
|
"node": tpl.node,
|
|
85
|
-
"key": tpl.key ?? ""
|
|
87
|
+
"key": tpl.key ?? "",
|
|
88
|
+
|
|
89
|
+
// only to display invalid definitions
|
|
90
|
+
"flow_label": "." == tpl.flow ? "Current Flow" : (tpl.flow_label ?? "Unknown Flow"),
|
|
91
|
+
"node_label": tpl.node_label ?? "Unknown Node"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// prior 2.0, unnecessary data was stored in the config, that now might cause issues.
|
|
95
|
+
switch (c.scope) {
|
|
96
|
+
case "global":
|
|
97
|
+
delete c.flow;
|
|
98
|
+
case "flow":
|
|
99
|
+
delete c.node;
|
|
100
|
+
default:
|
|
101
|
+
delete c.group;
|
|
86
102
|
}
|
|
103
|
+
|
|
87
104
|
ctx.push(c);
|
|
88
105
|
return c;
|
|
89
106
|
}
|
|
90
107
|
|
|
108
|
+
function get_node_options(flow_id) {
|
|
109
|
+
let opts = [];
|
|
110
|
+
|
|
111
|
+
if ("." == flow_id) {
|
|
112
|
+
// try to get id of "Current Flow"
|
|
113
|
+
flow_id = RED.nodes.workspace(node.z)?.id ?? RED.nodes.subflow(node.z)?.id;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
RED.nodes.eachNode( n => {
|
|
117
|
+
|
|
118
|
+
if (n.z == flow_id) {
|
|
119
|
+
|
|
120
|
+
// from 25-status.html
|
|
121
|
+
let nodeDef = RED.nodes.getType(n.type);
|
|
122
|
+
let label;
|
|
123
|
+
let sublabel;
|
|
124
|
+
if (nodeDef) {
|
|
125
|
+
let l = nodeDef.label;
|
|
126
|
+
label = (typeof l === "function" ? l.call(n) : l)||"";
|
|
127
|
+
}
|
|
128
|
+
if (!nodeDef || !label) {
|
|
129
|
+
label = n.type;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
opts.push({
|
|
133
|
+
value: n.id,
|
|
134
|
+
label: label
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return opts;
|
|
140
|
+
}
|
|
141
|
+
|
|
91
142
|
$('#node-input-context-container').css('min-height','150px').css('min-width','450px').editableList({
|
|
92
143
|
addItem: function(container, index, cfg) {
|
|
93
144
|
|
|
94
145
|
let data = add_context(cfg);
|
|
95
146
|
data.index = index;
|
|
96
147
|
|
|
148
|
+
// to manage the visual state e.g. of the error indicators
|
|
149
|
+
data.ok = {
|
|
150
|
+
flow: true,
|
|
151
|
+
node: true,
|
|
152
|
+
}
|
|
153
|
+
|
|
97
154
|
// cfg is the data object from the node definition, stored in the 'data' store.
|
|
98
155
|
// We shall keep cfg untouched to ensure automated (non-)dirty check by the runtime.
|
|
99
156
|
// Thus we exchange the data stored against the 'data' object we just created.
|
|
@@ -118,11 +175,12 @@
|
|
|
118
175
|
$(`<input type="text" id="context-scope-flows-${index}" placeholder="Flows">`).appendTo(line_flow);
|
|
119
176
|
line_flow.appendTo(fragment);
|
|
120
177
|
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
178
|
+
let line_flow_missing = $('<div class="form-row" style="margin-bottom: 6px">');
|
|
179
|
+
// $(`<label for="context-scope-key-${index}"" style="margin-left:10px; width: 90px"><i class="fa fa-tag"></i> Key</label>`).appendTo(line_key);
|
|
180
|
+
$(`<label for="context-scope-flow-error-${index}" style="margin-left:10px; width: 90px"></label>`).appendTo(line_flow_missing);
|
|
181
|
+
//$(`<input type="text" id="context-scope-key-${index}" placeholder="Context Variable Key">`).appendTo(line_key);
|
|
182
|
+
$(`<div id="context-scope-flow-error-${index}" style="display:inline"><i class="fa fa-exclamation-circle" style="color: red"></i><span style="font-size: small"> This flow does not exist.</span></div>`).appendTo(line_flow_missing);
|
|
183
|
+
line_flow_missing.appendTo(fragment).hide();
|
|
126
184
|
|
|
127
185
|
let line_node = $('<div class="form-row" style="margin-bottom: 6px">');
|
|
128
186
|
// $(`<label for="context-scope-nodes-${index}"" style="margin-left:10px; width: 90px"><i class="fa fa-tag"></i> Nodes</label>`).appendTo(line_node);
|
|
@@ -130,6 +188,13 @@
|
|
|
130
188
|
$(`<input type="text" id="context-scope-nodes-${index}" placeholder="Nodes">`).appendTo(line_node);
|
|
131
189
|
line_node.appendTo(fragment);
|
|
132
190
|
|
|
191
|
+
let line_node_missing = $('<div class="form-row" style="margin-bottom: 6px">');
|
|
192
|
+
// $(`<label for="context-scope-key-${index}"" style="margin-left:10px; width: 90px"><i class="fa fa-tag"></i> Key</label>`).appendTo(line_key);
|
|
193
|
+
$(`<label for="context-scope-node-error-${index}" style="margin-left:10px; width: 90px"></label>`).appendTo(line_node_missing);
|
|
194
|
+
//$(`<input type="text" id="context-scope-key-${index}" placeholder="Context Variable Key">`).appendTo(line_key);
|
|
195
|
+
$(`<div id="context-scope-node-error-${index}" style="display:inline"><i class="fa fa-exclamation-circle" style="color: red"></i><span style="font-size: small"> This node does not exist.</span></div>`).appendTo(line_node_missing);
|
|
196
|
+
line_node_missing.appendTo(fragment).hide();
|
|
197
|
+
|
|
133
198
|
let line_key = $('<div class="form-row" style="margin-bottom: 6px">');
|
|
134
199
|
// $(`<label for="context-scope-key-${index}"" style="margin-left:10px; width: 90px"><i class="fa fa-tag"></i> Key</label>`).appendTo(line_key);
|
|
135
200
|
$(`<label for="context-scope-key-${index}" style="margin-left:10px; width: 90px">Key: </label>`).appendTo(line_key);
|
|
@@ -138,171 +203,207 @@
|
|
|
138
203
|
|
|
139
204
|
container[0].appendChild(fragment);
|
|
140
205
|
|
|
206
|
+
let scope_opts = [
|
|
207
|
+
{ value: "global", label: "Global"},
|
|
208
|
+
{ value: "flow", label: "Flow"},
|
|
209
|
+
{ value: "node", label: "Node"},
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
let flow_opts = [{
|
|
213
|
+
value: ".", // special marker
|
|
214
|
+
label: "Current Flow"
|
|
215
|
+
}];
|
|
216
|
+
|
|
217
|
+
RED.nodes.eachWorkspace( ws => {
|
|
218
|
+
flow_opts.push({
|
|
219
|
+
value: ws.id,
|
|
220
|
+
label: ws.label
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
let node_opts = get_node_options(data.flow ?? ".");
|
|
225
|
+
|
|
226
|
+
// this function - called by TypedInput - displays the label of the node
|
|
227
|
+
// and (!!) does as well the error management
|
|
228
|
+
let node_valueLabel = function(container, value) {
|
|
229
|
+
|
|
230
|
+
// If an "invalid" value was selected, this function always receives value == ""!
|
|
231
|
+
// In such a case, go via data.node (!!)
|
|
232
|
+
// =>> line 1257 @ packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
|
|
233
|
+
if ("" === value) {
|
|
234
|
+
value = data.node;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
let err = false; // to draw red frame in case of anomaly
|
|
238
|
+
let f = node_opts?.filter( opts => {
|
|
239
|
+
return opts?.value == value;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (node_opts.length < 1) {
|
|
243
|
+
container.text("No nodes in this flow.");
|
|
244
|
+
line_node_missing.hide();
|
|
245
|
+
data.ok.node = true;
|
|
246
|
+
err = true;
|
|
247
|
+
} else if (f.length > 0) {
|
|
248
|
+
container.text(f[0].label);
|
|
249
|
+
line_node_missing.hide();
|
|
250
|
+
data.ok.node = true;
|
|
251
|
+
err = false;
|
|
252
|
+
} else {
|
|
253
|
+
let label;
|
|
254
|
+
switch (value) {
|
|
255
|
+
case ".": {
|
|
256
|
+
label = "No node selected."
|
|
257
|
+
line_node_missing.hide();
|
|
258
|
+
data.ok.node = true;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
default: {
|
|
262
|
+
console.log("@default");
|
|
263
|
+
label = data.node_label ?? "Unknown Node";
|
|
264
|
+
line_node_missing.show();
|
|
265
|
+
data.ok.node = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
container.text(label);
|
|
269
|
+
err = true;
|
|
270
|
+
}
|
|
271
|
+
container.css("color", (err == true) ? "darkgrey" : "var(--red-ui-form-text-color)");
|
|
272
|
+
|
|
273
|
+
// This draws / removes the red frame around the widget
|
|
274
|
+
setTimeout(() => {
|
|
275
|
+
$(`#context-scope-nodes-${index}`).next().toggleClass("input-error", err);
|
|
276
|
+
}, 150);
|
|
277
|
+
}
|
|
278
|
+
|
|
141
279
|
$(`#context-scope-${index}`).typedInput({type:"scope", types:[{
|
|
142
280
|
value: "scope",
|
|
143
|
-
options:
|
|
144
|
-
{ value: "global", label: "Global"},
|
|
145
|
-
{ value: "flow", label: "Flow"},
|
|
146
|
-
// { value: "group", label: "Group"},
|
|
147
|
-
{ value: "node", label: "Node"},
|
|
148
|
-
]
|
|
281
|
+
options: scope_opts
|
|
149
282
|
}]}).on("change", function (event, type, value) {
|
|
283
|
+
|
|
150
284
|
switch (value) {
|
|
151
285
|
case "global": {
|
|
152
286
|
line_flow.hide();
|
|
153
|
-
|
|
287
|
+
line_flow_missing.toggle(false);
|
|
154
288
|
line_node.hide();
|
|
289
|
+
line_node_missing.toggle(false);
|
|
155
290
|
break;
|
|
156
291
|
}
|
|
157
292
|
case "flow": {
|
|
158
293
|
line_flow.show();
|
|
159
|
-
|
|
160
|
-
line_node.hide();
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case "group": {
|
|
164
|
-
line_flow.show();
|
|
165
|
-
// line_group.show();
|
|
294
|
+
line_flow_missing.toggle(!data.ok.flow);
|
|
166
295
|
line_node.hide();
|
|
296
|
+
line_node_missing.toggle(false);
|
|
297
|
+
|
|
298
|
+
// Initialize if not defined
|
|
299
|
+
if (!_initing) {
|
|
300
|
+
data.flow ??= ".";
|
|
301
|
+
if (data.flow !== $(`#context-scope-flows-${index}`).typedInput("value")) {
|
|
302
|
+
$(`#context-scope-flows-${index}`).typedInput("value", data.flow);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
167
305
|
break;
|
|
168
306
|
}
|
|
169
307
|
case "node": {
|
|
170
308
|
line_flow.show();
|
|
171
|
-
|
|
309
|
+
line_flow_missing.toggle(!data.ok.flow);
|
|
172
310
|
line_node.show();
|
|
173
|
-
|
|
311
|
+
line_node_missing.toggle(!data.ok.node);
|
|
312
|
+
|
|
313
|
+
if (!_initing) {
|
|
314
|
+
// Initialize if not defined
|
|
315
|
+
data.flow ??= ".";
|
|
316
|
+
if (data.flow !== $(`#context-scope-flows-${index}`).typedInput("value")) {
|
|
317
|
+
$(`#context-scope-flows-${index}`).typedInput("value", data.flow);
|
|
318
|
+
}
|
|
319
|
+
data.node ??= $(`#context-scope-nodes-${index}`).typedInput("value") ?? ".";
|
|
320
|
+
if (data.node !== $(`#context-scope-nodes-${index}`).typedInput("value")) {
|
|
321
|
+
$(`#context-scope-nodes-${index}`).typedInput("value", data.node);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
174
324
|
}
|
|
175
325
|
}
|
|
176
326
|
if (!_initing) {
|
|
177
327
|
data.scope = value;
|
|
178
|
-
|
|
179
|
-
data.flow = data.flow ?? $(`#context-scope-flows-${index}`).typedInput("value");
|
|
180
|
-
// data.group = data.group ?? $(`#context-scope-groups-${index}`).typedInput("value");
|
|
181
|
-
data.node = data.node ?? $(`#context-scope-nodes-${index}`).typedInput("value");
|
|
182
328
|
node.dirty = true;
|
|
183
329
|
}
|
|
184
|
-
|
|
185
|
-
switch (data.scope) {
|
|
186
|
-
// case "group": {
|
|
187
|
-
// $(`#context-scope-key-${index}`).prop("disabled", data.group == "");
|
|
188
|
-
// break;
|
|
189
|
-
// }
|
|
190
|
-
case "node": {
|
|
191
|
-
$(`#context-scope-key-${index}`).prop("disabled", data.node == "");
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
let flow_opts = [];
|
|
199
|
-
// let group_opts = [];
|
|
200
|
-
let node_opts;
|
|
201
|
-
|
|
202
|
-
RED.nodes.eachWorkspace( cb => {
|
|
203
|
-
flow_opts.push({
|
|
204
|
-
value: cb.id,
|
|
205
|
-
label: cb.label
|
|
206
|
-
});
|
|
207
330
|
});
|
|
208
331
|
|
|
209
332
|
$(`#context-scope-flows-${index}`).typedInput({type:"flow", types:[{
|
|
210
333
|
value: "flow",
|
|
211
|
-
options: flow_opts
|
|
212
|
-
|
|
334
|
+
options: flow_opts,
|
|
335
|
+
valueLabel: function(container, value) {
|
|
336
|
+
|
|
337
|
+
// If an "invalid" value was selected, this function always receives value == ""!
|
|
338
|
+
// In such a case, go via data.node (!!)
|
|
339
|
+
// =>> line 1257 @ packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js
|
|
340
|
+
if ("" === value) {
|
|
341
|
+
value = data.flow;
|
|
342
|
+
}
|
|
213
343
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// group_opts.push({
|
|
218
|
-
// value: g.id,
|
|
219
|
-
// label: g.label ?? g.id
|
|
220
|
-
// });
|
|
221
|
-
// }
|
|
222
|
-
// });
|
|
223
|
-
// let gol = group_opts.length;
|
|
224
|
-
// $(`#context-scope-groups-${index}`).typedInput('disable', gol < 1);
|
|
225
|
-
// if (gol < 1) {
|
|
226
|
-
// group_opts.push({
|
|
227
|
-
// value: undefined,
|
|
228
|
-
// label: "No group in this flow"
|
|
229
|
-
// })
|
|
230
|
-
// }
|
|
231
|
-
// $(`#context-scope-groups-${index}`).typedInput('types', [{options: group_opts}]);
|
|
232
|
-
// $(`#context-scope-groups-${index}`).parent().find(".red-ui-typedInput-option-label").css("color", gol < 1 ? "darkgrey" : "var(--red-ui-form-text-color)");
|
|
233
|
-
// if ($(`#context-scope-${index}`).typedInput("value") == "group") {
|
|
234
|
-
// $(`#context-scope-key-${index}`).prop("disabled", gol < 1);
|
|
235
|
-
// }
|
|
236
|
-
|
|
237
|
-
node_opts = [];
|
|
238
|
-
RED.nodes.eachNode( n => {
|
|
239
|
-
|
|
240
|
-
if (n.z == value) {
|
|
241
|
-
|
|
242
|
-
// from 25-status.html
|
|
243
|
-
let nodeDef = RED.nodes.getType(n.type);
|
|
244
|
-
let label;
|
|
245
|
-
let sublabel;
|
|
246
|
-
if (nodeDef) {
|
|
247
|
-
let l = nodeDef.label;
|
|
248
|
-
label = (typeof l === "function" ? l.call(n) : l)||"";
|
|
249
|
-
// sublabel = n.type;
|
|
250
|
-
// if (sublabel.indexOf("subflow:") === 0) {
|
|
251
|
-
// let subflowId = sublabel.substring(8);
|
|
252
|
-
// let subflow = RED.nodes.subflow(subflowId);
|
|
253
|
-
// sublabel = "subflow : "+subflow.name;
|
|
254
|
-
// }
|
|
255
|
-
}
|
|
256
|
-
if (!nodeDef || !label) {
|
|
257
|
-
label = n.type;
|
|
258
|
-
}
|
|
344
|
+
let f = flow_opts?.filter( opts => {
|
|
345
|
+
return opts?.value == value;
|
|
346
|
+
});
|
|
259
347
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
348
|
+
let err = false;
|
|
349
|
+
|
|
350
|
+
if (f.length > 0) {
|
|
351
|
+
// to display the label of the "Current Flow"
|
|
352
|
+
if ("." == value) {
|
|
353
|
+
let label = RED.nodes.workspace(node.z)?.label ?? RED.nodes.subflow(node.z)?.name ?? "";
|
|
354
|
+
$(`<div style="display: inline"><span>Current Flow </span><span style="font-size: x-small">>> ${label}</span></div>`).appendTo(container);
|
|
355
|
+
} else {
|
|
356
|
+
container.text(f[0].label);
|
|
357
|
+
}
|
|
358
|
+
line_flow_missing.hide();
|
|
359
|
+
data.ok.flow = true;
|
|
360
|
+
} else {
|
|
361
|
+
container.text(data.flow_label ?? "Unknown Flow");
|
|
362
|
+
line_flow_missing.show();
|
|
363
|
+
data.ok.flow = false;
|
|
364
|
+
err = true;
|
|
264
365
|
}
|
|
265
|
-
|
|
366
|
+
|
|
367
|
+
container.css("color", (err == true) ? "darkgrey" : "var(--red-ui-form-text-color)");
|
|
368
|
+
// This draws / removes the red frame around the widget
|
|
369
|
+
setTimeout(() => {
|
|
370
|
+
$(`#context-scope-flows-${index}`).next().toggleClass("input-error", err);
|
|
371
|
+
}, 150);
|
|
372
|
+
}
|
|
373
|
+
}]}).on("change", function (event, type, value) {
|
|
374
|
+
|
|
375
|
+
node_opts = get_node_options(value);
|
|
266
376
|
let nol = node_opts.length;
|
|
267
377
|
$(`#context-scope-nodes-${index}`).typedInput('disable', nol < 1);
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
$(`#context-scope-nodes-${index}`).typedInput('types', [{options: node_opts}]);
|
|
275
|
-
$(`#context-scope-nodes-${index}`).parent().find(".red-ui-typedInput-option-label").css("color", nol < 1 ? "darkgrey" : "var(--red-ui-form-text-color)");
|
|
276
|
-
if ($(`#context-scope-${index}`).typedInput("value") == "node") {
|
|
277
|
-
$(`#context-scope-key-${index}`).prop("disabled", nol < 1);
|
|
278
|
-
}
|
|
378
|
+
|
|
379
|
+
$(`#context-scope-nodes-${index}`).typedInput('types', [{
|
|
380
|
+
value: "node",
|
|
381
|
+
options: node_opts,
|
|
382
|
+
valueLabel: node_valueLabel
|
|
383
|
+
}]);
|
|
279
384
|
|
|
280
385
|
if (!_initing) {
|
|
386
|
+
|
|
281
387
|
data.flow = value;
|
|
388
|
+
data.flow_label = flow_opts.find((opt) => opt.value == value)?.label;
|
|
389
|
+
data.node = node_opts[0]?.value ?? ".";
|
|
390
|
+
|
|
391
|
+
$(`#context-scope-nodes-${index}`).typedInput('value', data.node);
|
|
282
392
|
node.dirty = true;
|
|
283
393
|
}
|
|
284
394
|
});
|
|
285
395
|
|
|
286
|
-
// $(`#context-scope-groups-${index}`).typedInput({type:"group", types:[{
|
|
287
|
-
// value: "group",
|
|
288
|
-
// options: [
|
|
289
|
-
// { value: "test", label: "TEST"}
|
|
290
|
-
// ]
|
|
291
|
-
// }]}).on("change", function (event, type, value) {
|
|
292
|
-
// if (!_initing) {
|
|
293
|
-
// data.group = value;
|
|
294
|
-
// node.dirty = true;
|
|
295
|
-
// }
|
|
296
|
-
// });
|
|
297
|
-
|
|
298
396
|
$(`#context-scope-nodes-${index}`).typedInput({type:"node", types:[{
|
|
299
|
-
value: "node"
|
|
397
|
+
value: "node",
|
|
398
|
+
options: node_opts,
|
|
399
|
+
valueLabel: node_valueLabel
|
|
300
400
|
}]}).on("change", function (event, type, value) {
|
|
401
|
+
|
|
301
402
|
if (!_initing) {
|
|
302
403
|
data.node = value;
|
|
404
|
+
data.node_label = node_opts.find((opt) => opt.value == value)?.label;
|
|
303
405
|
node.dirty = true;
|
|
304
406
|
}
|
|
305
|
-
$(`#context-scope-key-${index}`).prop("disabled", false);
|
|
306
407
|
|
|
307
408
|
});
|
|
308
409
|
|
|
@@ -318,37 +419,22 @@
|
|
|
318
419
|
$(this).toggleClass("input-error", !validate_context_key($(this).val()));
|
|
319
420
|
});
|
|
320
421
|
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return opts?.value == f;
|
|
328
|
-
}).length > 0) {
|
|
329
|
-
$(`#context-scope-flows-${index}`).typedInput("value", f);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
422
|
+
// *****
|
|
423
|
+
// Initialize the form
|
|
424
|
+
//
|
|
425
|
+
|
|
426
|
+
$(`#context-scope-key-${index}`).val(data.key).prop("disabled", false);
|
|
427
|
+
$(`#context-scope-key-${index}`).toggleClass("input-error", !validate_context_key(data.key));
|
|
332
428
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
// }).length > 0) {
|
|
338
|
-
// $(`#context-scope-groups-${index}`).typedInput("value", g);
|
|
339
|
-
// }
|
|
340
|
-
// }
|
|
341
|
-
|
|
342
|
-
let n = data.node || node_opts[0]?.value;
|
|
343
|
-
if (n) {
|
|
344
|
-
if (node_opts.filter( opts => {
|
|
345
|
-
return opts?.value == n;
|
|
346
|
-
}).length > 0) {
|
|
347
|
-
$(`#context-scope-nodes-${index}`).typedInput("value", n);
|
|
429
|
+
if ("global" !== data.scope) {
|
|
430
|
+
$(`#context-scope-flows-${index}`).typedInput("value", data.flow ?? flow_opts[0]?.value);
|
|
431
|
+
if ("node" == data.scope) {
|
|
432
|
+
$(`#context-scope-nodes-${index}`).typedInput("value", data.node);
|
|
348
433
|
}
|
|
349
434
|
}
|
|
350
435
|
|
|
351
|
-
|
|
436
|
+
// Once Flow & Node are set, select Scope...
|
|
437
|
+
$(`#context-scope-${index}`).typedInput("value", data.scope);
|
|
352
438
|
|
|
353
439
|
_initing = false;
|
|
354
440
|
},
|
|
@@ -383,7 +469,9 @@
|
|
|
383
469
|
node.monitoring.forEach(data => {
|
|
384
470
|
$('#node-input-context-container').editableList('addItem', data);
|
|
385
471
|
});
|
|
386
|
-
} catch {
|
|
472
|
+
} catch (err) {
|
|
473
|
+
console.log(err);
|
|
474
|
+
}
|
|
387
475
|
|
|
388
476
|
node._ctx = ctx;
|
|
389
477
|
|
|
@@ -402,6 +490,7 @@
|
|
|
402
490
|
width = ti.next().outerWidth();
|
|
403
491
|
}
|
|
404
492
|
if (width) {
|
|
493
|
+
$('[id*=context-scope-nodes]').outerWidth(width);
|
|
405
494
|
$('[id*=context-scope-key]').outerWidth(width);
|
|
406
495
|
}
|
|
407
496
|
|
|
@@ -423,22 +512,26 @@
|
|
|
423
512
|
|
|
424
513
|
ctx.forEach( data => {
|
|
425
514
|
delete data.index;
|
|
515
|
+
delete data.ok;
|
|
426
516
|
|
|
427
517
|
switch (data.scope) {
|
|
428
518
|
case "global":
|
|
429
519
|
delete data.flow;
|
|
520
|
+
delete data.flow_label;
|
|
430
521
|
case "flow":
|
|
431
|
-
delete data.
|
|
432
|
-
|
|
433
|
-
// delete data.node;
|
|
434
|
-
// break;
|
|
522
|
+
delete data.node;
|
|
523
|
+
delete data.node_label;
|
|
435
524
|
case "node":
|
|
525
|
+
// handle "current flow" special marker
|
|
526
|
+
if ("." == data.flow) {
|
|
527
|
+
delete data.flow_label;
|
|
528
|
+
}
|
|
529
|
+
// for a node, "." means 'no node selected'!
|
|
530
|
+
if ("." == data.node) {
|
|
531
|
+
delete data.node_label;
|
|
532
|
+
}
|
|
533
|
+
default:
|
|
436
534
|
delete data.group;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (data.flow == node.z) {
|
|
440
|
-
// set a special marker that 'this flow' shall be referenced
|
|
441
|
-
data.flow = ".";
|
|
442
535
|
}
|
|
443
536
|
})
|
|
444
537
|
|
package/monitor.js
CHANGED
|
@@ -25,7 +25,6 @@ function scan_for_require_path(req_path) {
|
|
|
25
25
|
|
|
26
26
|
if (process.env.NODE_RED_HOME) {
|
|
27
27
|
found = path.join(process.env.NODE_RED_HOME, "..", req_path);
|
|
28
|
-
console.log("@f", found);
|
|
29
28
|
if (fs.existsSync(found)) {
|
|
30
29
|
return found;
|
|
31
30
|
}
|
|
@@ -64,7 +63,6 @@ function scan_for_require_path(req_path) {
|
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
console.log(found);
|
|
68
66
|
return found;
|
|
69
67
|
}
|
|
70
68
|
|
|
@@ -122,14 +120,69 @@ module.exports = function(RED) {
|
|
|
122
120
|
|
|
123
121
|
node.monitoring = [];
|
|
124
122
|
|
|
123
|
+
let nodes = {};
|
|
124
|
+
let flows = {}
|
|
125
|
+
|
|
126
|
+
// collect all known flows & nodes
|
|
127
|
+
RED.nodes.eachNode( n => {
|
|
128
|
+
if (n.id) {
|
|
129
|
+
nodes[n.id] ??= true;
|
|
130
|
+
}
|
|
131
|
+
if (n.z) {
|
|
132
|
+
flows[n.z] ??= true;
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
125
136
|
scopes.forEach( data => {
|
|
126
137
|
|
|
127
|
-
|
|
138
|
+
// Let's validate the given monitoring context first...
|
|
139
|
+
switch (data.scope) {
|
|
140
|
+
case "node": {
|
|
141
|
+
if (!data.node || "." == data.node || data.node.length < 1) {
|
|
142
|
+
node.warn('Scope is "Node" but node reference is missing.');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (!nodes[data.node]) {
|
|
146
|
+
node.warn('Referenced node does not exist.');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
case "flow": {
|
|
151
|
+
if (!flows[data.flow]) {
|
|
152
|
+
if ("." !== data.flow) {
|
|
153
|
+
node.warn('Referenced flow does not exist.');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
default: {
|
|
159
|
+
if (!data.key || data.key.length < 1) {
|
|
160
|
+
node.warn("Monitoring context key is missing.")
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if ("." === data.flow) {
|
|
167
|
+
data.flow = node.z;
|
|
168
|
+
}
|
|
128
169
|
|
|
129
|
-
// support for complex keys
|
|
130
|
-
// test["mm"].value becomes test.mm.value
|
|
131
170
|
let key = data.key;
|
|
132
171
|
|
|
172
|
+
// resolve $parent to true flow id ... if the monitor sits in a subflow!
|
|
173
|
+
if ("flow" == data.scope && key.startsWith("$parent.")) {
|
|
174
|
+
let fl = RED.nodes.getNode(data.flow);
|
|
175
|
+
if ("subflow" == fl?.TYPE) {
|
|
176
|
+
// This might not create the expected result, if .parent is not a flow!
|
|
177
|
+
// ... but a group or another subflow!
|
|
178
|
+
// >> Fix it if someone asks for.
|
|
179
|
+
data.flow = fl.parent.id;
|
|
180
|
+
data.key = key = key.substring("$parent.".length);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// support for complex keys
|
|
185
|
+
// test["mm"].value becomes test.mm.value
|
|
133
186
|
try {
|
|
134
187
|
let key_parts = RED.util.normalisePropertyExpression(key);
|
|
135
188
|
for (i=0; i<key_parts.length; i++) {
|
|
@@ -142,10 +195,6 @@ module.exports = function(RED) {
|
|
|
142
195
|
return;
|
|
143
196
|
}
|
|
144
197
|
|
|
145
|
-
if ("." === data.flow) {
|
|
146
|
-
data.flow = node.z;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
198
|
let ctx = "global";
|
|
150
199
|
switch (data.scope) {
|
|
151
200
|
case "global":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ralphwetzel/node-red-context-monitor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A Node-RED node to monitor a context.",
|
|
5
5
|
"main": "monitor.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/ralphwetzel/node-red-context-monitor#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"fs-extra": "^11.1.
|
|
30
|
+
"fs-extra": "^11.1.0"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=14.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"mocha": "^
|
|
37
|
-
"node-red
|
|
38
|
-
"node-red": "^3.
|
|
36
|
+
"mocha": "^11.7.0",
|
|
37
|
+
"node-red": "^3.0.0",
|
|
38
|
+
"node-red-node-test-helper": "^0.3.5"
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"/examples",
|