@gregoriusrippenstein/node-red-contrib-introspection 0.6.16 → 0.7.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 +7 -0
- package/nodes/51-install-package.html +111 -0
- package/nodes/51-install-package.js +137 -0
- package/package.json +7 -6
- package/plugins/sidebar.html +40 -3
package/README.md
CHANGED
|
@@ -99,6 +99,12 @@ Inspired by the [dsm](https://flows.nodered.org/node/node-red-contrib-dsm) packa
|
|
|
99
99
|
|
|
100
100
|
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.
|
|
101
101
|
|
|
102
|
+
### InstallPackage
|
|
103
|
+
|
|
104
|
+
Node used to install packages on other Node-RED installations. Can be used to install existing modules using or .tgz files that can installed on the instance. To install an existing package, use `msg.payload = { module: '@fubar/example' }` with an optional `version`, this defaults to 'latest'.
|
|
105
|
+
|
|
106
|
+
To install a package on the fly, generate a .tgz as a Buffer and set the the payload to: `msg.payload = { data: Buffer[...]}` where buffer contains the .tgz contents.
|
|
107
|
+
|
|
102
108
|
### ClientCode
|
|
103
109
|
|
|
104
110
|
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.
|
|
@@ -165,6 +171,7 @@ There are [example flows](/examples) contained in the package, examples can also
|
|
|
165
171
|
- [Orphans](https://flowhub.org/f/2401c255b056e0e1)
|
|
166
172
|
- [Sink and Seeker](https://flowhub.org/f/139a816449acd89f)
|
|
167
173
|
- [Obfuscation](https://flowhub.org/f/825ddf24d98eb011)
|
|
174
|
+
- [InstallPackage](https://flowhub.org/f/6dcbd2643ea80615)
|
|
168
175
|
|
|
169
176
|
## License
|
|
170
177
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('InstallPackage',{
|
|
3
|
+
color: '#e5e4ef',
|
|
4
|
+
icon: "introspesubflow.svg",
|
|
5
|
+
category: 'introspection',
|
|
6
|
+
defaults: {
|
|
7
|
+
name: {
|
|
8
|
+
value:"",
|
|
9
|
+
},
|
|
10
|
+
hostUrl: {
|
|
11
|
+
value: ""
|
|
12
|
+
},
|
|
13
|
+
useAuthentication: {
|
|
14
|
+
value:false
|
|
15
|
+
},
|
|
16
|
+
apiUsername: {
|
|
17
|
+
value: "",
|
|
18
|
+
},
|
|
19
|
+
apiUsernameType: {
|
|
20
|
+
value: "env",
|
|
21
|
+
},
|
|
22
|
+
apiPassword: {
|
|
23
|
+
value: "",
|
|
24
|
+
},
|
|
25
|
+
apiPasswordType: {
|
|
26
|
+
value: "env",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
inputs:1,
|
|
30
|
+
outputs:1,
|
|
31
|
+
|
|
32
|
+
label: function() {
|
|
33
|
+
return (this.name || this._def.paletteLabel);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
labelStyle: function() {
|
|
37
|
+
return this.name?"node_label_italic":"";
|
|
38
|
+
},
|
|
39
|
+
oneditprepare: function() {
|
|
40
|
+
$("#node-input-apiUsername").typedInput({
|
|
41
|
+
types:["env", "msg", "flow","global", "cred"],
|
|
42
|
+
typeField: "#node-input-apiUsernameType"
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
$("#node-input-apiPassword").typedInput({
|
|
46
|
+
types:["env", "msg", "flow","global", "env", "cred"],
|
|
47
|
+
typeField: "#node-input-apiPasswordType"
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if ( $('#node-input-useAuthentication').is(":checked") ) {
|
|
51
|
+
$('#useAuthentication-input-fields').show();
|
|
52
|
+
} else {
|
|
53
|
+
$('#useAuthentication-input-fields').hide()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
$('#node-input-useAuthentication').on( 'change', function() {
|
|
57
|
+
if ( $('#node-input-useAuthentication').is(":checked") ) {
|
|
58
|
+
$('#useAuthentication-input-fields').show();
|
|
59
|
+
} else {
|
|
60
|
+
$('#useAuthentication-input-fields').hide()
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<script type="text/html" data-template-name="InstallPackage">
|
|
68
|
+
<div class="form-row">
|
|
69
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
70
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="form-row">
|
|
74
|
+
<label for="node-input-hostUrl"><i class="fa fa-tag"></i> Host</label>
|
|
75
|
+
<input type="text" id="node-input-hostUrl" placeholder="Host URL">
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="form-row">
|
|
79
|
+
<label for="node-input-useAuthentication">
|
|
80
|
+
<i class="fa "></i>
|
|
81
|
+
<span>Use Authentication?</span>
|
|
82
|
+
</label>
|
|
83
|
+
|
|
84
|
+
<input type="checkbox" id="node-input-useAuthentication"
|
|
85
|
+
style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div id="useAuthentication-input-fields" class="hidden">
|
|
89
|
+
<div class="form-row">
|
|
90
|
+
<label for="node-input-apiUsername">
|
|
91
|
+
<i class="fa fa-tag"></i>
|
|
92
|
+
Username
|
|
93
|
+
</label>
|
|
94
|
+
<input type="text" id="node-input-apiUsername">
|
|
95
|
+
<input type="hidden" id="node-input-apiUsernameType">
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="form-row">
|
|
99
|
+
<label for="node-input-apiPassword">
|
|
100
|
+
<i class="fa fa-tag"></i>
|
|
101
|
+
Password
|
|
102
|
+
</label>
|
|
103
|
+
<input type="text" id="node-input-apiPassword">
|
|
104
|
+
<input type="hidden" id="node-input-apiPasswordType">
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<script type="text/html" data-help-name="InstallPackage">
|
|
110
|
+
<p>Send flow to another Node-RED instance.</p>
|
|
111
|
+
</script>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module.exports = function(RED) {
|
|
2
|
+
function InstallPackageFunctionality(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
|
+
|
|
14
|
+
if (!msg.payload || Object.prototype.toString.call(msg.payload) !== '[object Object]') {
|
|
15
|
+
return node.error("msg.payload missing or payload not hash")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var installPackage = (hdrs, got) => {
|
|
19
|
+
let body = undefined
|
|
20
|
+
let headers = {}
|
|
21
|
+
|
|
22
|
+
if ( msg.payload.module ) {
|
|
23
|
+
body = JSON.stringify({
|
|
24
|
+
module: msg.payload.module,
|
|
25
|
+
version: msg.payload.version || "latest"
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
headers = {
|
|
29
|
+
"Content-Type": "application/json"
|
|
30
|
+
}
|
|
31
|
+
} else if ( msg.payload.data && Buffer.isBuffer(msg.payload.data) ) {
|
|
32
|
+
|
|
33
|
+
let formData = require('form-data')
|
|
34
|
+
body = new formData();
|
|
35
|
+
body.append("tarball", msg.payload.data, "tarball.tgz");
|
|
36
|
+
headers = body.getHeaders()
|
|
37
|
+
body = body.getBuffer()
|
|
38
|
+
|
|
39
|
+
} else {
|
|
40
|
+
return node.error("msg.payload not well defined")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
got.post( cfg.hostUrl + "/nodes", {
|
|
44
|
+
headers: {
|
|
45
|
+
...headers,
|
|
46
|
+
...hdrs
|
|
47
|
+
},
|
|
48
|
+
body: body
|
|
49
|
+
}).then( res => {
|
|
50
|
+
send({
|
|
51
|
+
...msg,
|
|
52
|
+
payload: JSON.parse(res.body)
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
node.status({fill:"green",shape:"dot",text:"Good"});
|
|
56
|
+
setTimeout( function() {
|
|
57
|
+
node.status({})
|
|
58
|
+
}, 450);
|
|
59
|
+
|
|
60
|
+
}).catch( err => {
|
|
61
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
62
|
+
node.error(err)
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Authentication
|
|
68
|
+
**/
|
|
69
|
+
if ( cfg.useAuthentication ) {
|
|
70
|
+
var username = undefined;
|
|
71
|
+
var password = undefined;
|
|
72
|
+
|
|
73
|
+
node.status({fill:"blue",shape:"dot",text:"Requesting token"});
|
|
74
|
+
|
|
75
|
+
RED.util.evaluateNodeProperty(cfg.apiUsername, cfg.apiUsernameType,
|
|
76
|
+
node, msg, (err, result) => {
|
|
77
|
+
if (err) {
|
|
78
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
79
|
+
node.error(err)
|
|
80
|
+
} else {
|
|
81
|
+
username = result;
|
|
82
|
+
|
|
83
|
+
RED.util.evaluateNodeProperty(cfg.apiPassword, cfg.apiPasswordType,
|
|
84
|
+
node, msg, (err, result) => {
|
|
85
|
+
if (err) {
|
|
86
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
87
|
+
node.error(err)
|
|
88
|
+
} else {
|
|
89
|
+
password = result;
|
|
90
|
+
|
|
91
|
+
var data = {
|
|
92
|
+
"client_id": "node-red-admin",
|
|
93
|
+
"grant_type": "password",
|
|
94
|
+
"scope": "*",
|
|
95
|
+
"username": username,
|
|
96
|
+
"password": password
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
import('got').then( (module) => {
|
|
100
|
+
module.got.post( cfg.hostUrl + "/auth/token", {
|
|
101
|
+
json: data
|
|
102
|
+
}).then( res => {
|
|
103
|
+
node.status({
|
|
104
|
+
fill:"blue",
|
|
105
|
+
shape:"dot",
|
|
106
|
+
text:"Sending flow"
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
var access_token = JSON.parse(res.body).access_token;
|
|
110
|
+
|
|
111
|
+
installPackage({
|
|
112
|
+
"Authorization": "Bearer " + access_token
|
|
113
|
+
}, module.got);
|
|
114
|
+
|
|
115
|
+
}).catch((err) => {
|
|
116
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
117
|
+
node.error( err );
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
} else {
|
|
125
|
+
/*
|
|
126
|
+
* Authentication free zone...
|
|
127
|
+
*/
|
|
128
|
+
node.status({fill:"blue",shape:"dot",text:"Sending flow"});
|
|
129
|
+
import('got').then( (module) => {
|
|
130
|
+
installPackage({}, module.got);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
RED.nodes.registerType("InstallPackage", InstallPackageFunctionality);
|
|
137
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gregoriusrippenstein/node-red-contrib-introspection",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"got": "^13",
|
|
6
6
|
"uglify-js": "^3.17.4",
|
|
@@ -28,11 +28,12 @@
|
|
|
28
28
|
"screenshot": "plugins/sidebar.html"
|
|
29
29
|
},
|
|
30
30
|
"nodes": {
|
|
31
|
-
"seeker":
|
|
32
|
-
"sink":
|
|
33
|
-
"getflows":
|
|
34
|
-
"sendflow":
|
|
35
|
-
"
|
|
31
|
+
"seeker": "nodes/05-seeker.js",
|
|
32
|
+
"sink": "nodes/10-sink.js",
|
|
33
|
+
"getflows": "nodes/45-get-flows.js",
|
|
34
|
+
"sendflow": "nodes/50-send-flow.js",
|
|
35
|
+
"installpackage": "nodes/51-install-package.js",
|
|
36
|
+
"clientcode": "nodes/60-client-code.js"
|
|
36
37
|
}
|
|
37
38
|
},
|
|
38
39
|
|
package/plugins/sidebar.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
let obfuscateHelpers={getFlowDataFromCurrentWorkspace:e=>{var e=e||RED.workspaces.active(),t=RED.nodes.groups(e),e=(t=(t=t.concat(RED.nodes.junctions(e))).concat(RED.nodes.filterNodes({z:e})),RED.nodes.eachConfig(function(e){e.z===RED.workspaces.active()&&!1===e._def.hasUsers&&t.push(e)}),RED.nodes.workspace(e)||RED.nodes.subflow(e));return t.unshift(e),RED.nodes.createExportableNodeSet(t)},openImportDialog:e=>{RED.clipboard.import();let t=e;setTimeout(()=>{$("#red-ui-clipboard-dialog-import-text").val(JSON.stringify(t)).trigger("paste")},300)}};function obfuscatieCurrentFlow(l){let p=obfuscateHelpers.getFlowDataFromCurrentWorkspace(),f=(l.remove_groups&&(p=p.filter(e=>"group"!=e.type)).forEach(e=>{delete e.g}),{}),t={},d={},c={},s=[],h={},r={};if(p.forEach(e=>{"subflow"==(f[e.id]=e).type&&(r[e.id]=e),"junction"==e.type&&(t[e.id]=e),"link out"==e.type&&(c[e.id]=e),"link in"==e.type&&(d[e.id]=e),"link call"==e.type&&s.push(e.id),"catch"==e.type&&(h[e.id]=(e.wires||[])[0]||[])}),l.remove_junctions&&(Object.keys(t).forEach(n=>{let s=t[n];r[s.z]||p.forEach(t=>{for(let e=0;e<(t.wires||[]).length;e++){var r=t.wires[e].indexOf(n);-1<r&&(t.wires[e].splice(r,1),t.wires[e].push(...s.wires[0]))}})}),p=p.filter(e=>!("junction"==e.type&&!r[e.z]))),l.remove_linkout_nodes||l.remove_linkcall_nodes){let r=[],n=[],i=[],a=(l.remove_linkout_nodes&&!l.copy_linkin_nodes&&Object.keys(c).forEach(n=>{var e=c[n];let s=e.links||[];s.reduce((e,t)=>e&&(!!d[t]||l.ignore_off_flow_links),!0)&&"return"!=e.mode&&(r.push(n),p.forEach(r=>{for(let t=0;t<(r.wires||[]).length;t++){var e=r.wires[t].indexOf(n);-1<e&&(r.wires[t].splice(e,1),s.forEach(e=>{d[e]&&r.wires[t].push(...d[e].wires[0])}))}}))}),(s,e)=>{if(!e)return!1;let t=[],o=[],r=[];function u(e){if(r.indexOf(e.id)<0)switch(r.push(e.id),t.push(e),e.type){case"link out":if("return"!=e.mode)throw"not handable";break;case"link call":throw"unhandled";default:RED.nodes.getNodeLinks(e).forEach(function(e){u(e.target)})}}try{RED.nodes.getNodeLinks(e).forEach(function(e){u(e.target),o.push(e.target.id)});if(Object.keys(h).forEach(e=>{((t,e)=>{try{return e.map(e=>e.id).forEach(e=>{if(t.includes(e))throw"yes"}),!1}catch(e){return!0}})(h[e],t)&&t.push(f[e])}),0==t.length)return!1;let r={};var i=t[0];let n={x:s.x-i.x,y:s.y-i.y};var a=t.map(e=>{var t=structuredClone(f[e.id]);return t||console.log("WARNING: nodeid not found",[e.id,f[e.id]]),t.id=RED.nodes.id(),t.x+=n.x,t.y+=n.y,r[e.id]=t});return a.forEach(e=>{"catch"==e.type&&Array.isArray(e.scope)&&(e.scope=e.scope.map(e=>{var t=r[e];return t&&t.id||e})),e.wires&&(e.wires=e.wires.map(e=>e.map(e=>{var t=r[e];return t&&"link out"==t.type?[...s.wires[0],(t||{}).id||e]:(t||{}).id||e}).flat()))}),{nodes:a.filter(e=>"link out"!=e.type),entryNodes:o.map(e=>r[e])}}catch(e){return!1}});l.remove_linkout_nodes&&l.copy_linkin_nodes&&Object.keys(c).forEach(s=>{let o=c[s],u=o.links||[];if("return"!=o.mode){let t=u.map(e=>{var t=d[e],t=a(o,t);return t?[e,t]:[void 0,void 0]});t.reduce((e,t)=>e&&(!!t[0]||l.ignore_off_flow_links),!0)&&(r.push(s),p.forEach(n=>{for(let r=0;r<(n.wires||[]).length;r++){var e=n.wires[r].indexOf(s);-1<e&&(n.wires[r].splice(e,1),(t=u.map(e=>{var t=d[e],t=a(o,t);return t?[e,t]:[void 0,void 0]})).forEach(([,e])=>{var t;e&&(t=e.entryNodes.map(e=>e.id),n.wires[r].push(...t),i.push(...e.nodes))}))}}))}}),l.remove_linkcall_nodes&&s.forEach(s=>{var e=f[s],t=d[e.links[0]];let o=a(e,t);t&&o&&(n.push(e.id),p.forEach(t=>{for(let e=0;e<(t.wires||[]).length;e++){var r,n=t.wires[e].indexOf(s);-1<n&&(r=o.entryNodes.map(e=>e.id),t.wires[e].splice(n,1),t.wires[e].push(...r),i.push(...o.nodes))}}))}),(p=p.filter(e=>r.indexOf(e.id)<0&&n.indexOf(e.id)<0)).push(...i)}if((p=l.remove_debugs?p.filter(e=>"debug"!=e.type&&"comment"!=e.type):p).forEach(e=>{l.name&&(e.name=RED.nodes.id()),l.shrink_node&&(e.l=!1),l.info&&(e.info="",delete e.outputLabels,delete e.inputLabels),l.add_license&&(l.append_license?e.info=(e.info||"")+"\n---\n\n"+l.license_text:e.info=l.license_text),l.position&&(e.x=150,e.y=150),l.remove_icons&&delete e.icon}),l.replace_switch){let n=(t,r)=>{for(let e=0;e<r.rules.length;e++){var n=r.rules[e];if("nnull"==n.t)t.push("if ( _propValue != null ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }");else if("null"==n.t)t.push("if ( _propValue == null ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }");else if("eq"==n.t&&"str"==n.vt){s=n.v;s=btoa(encodeURIComponent(s).replace(/%([0-9A-F]{2})/g,function(e,t){return String.fromCharCode("0x"+t)}));t.push("if ( _propValue === Buffer.from('"+s+"', 'base64').toString('utf-8') ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }")}else if("gt"==n.t&&"num"==n.vt)t.push("if ( _propValue > "+n.v+" ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }");else if("eq"==n.t&&"num"==n.vt)t.push("if ( _propValue == "+n.v+" ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }");else if("empty"==n.t)t.push('let p = _propValue ; if ( (Array.isArray(p) && p.length == 0) || ((typeof p === "object") && p != null && Object.keys(p).length == 0) || ((typeof p === "string") && p.length == 0) ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }');else if("nempty"==n.t)t.push('let p = _propValue ; if ( (Array.isArray(p) && p.length > 0) || ((typeof p === "object") && p != null && Object.keys(p).length > 0) || ((typeof p === "string") && p.length > 0) ) { _returnValue.push(msg) ; return node.send(_returnValue) } else { _returnValue.push(undefined) }');else{if("else"!=n.t)throw"unhandled";t.push("_returnValue.push(msg)","return node.send(_returnValue)")}}var s};p=p.map(t=>{if("switch"!=t.type)return t;var e={id:t.id,name:t.name,type:"function",x:t.x,y:t.y,func:"",outputs:t.outputs,timeout:"",noerr:0,initialize:"",finalize:"",libs:[{var:"process",module:"process"},{var:"jsonata",module:"jsonata"}],wires:t.wires};t.hasOwnProperty("z")&&(e.z=t.z),t.hasOwnProperty("l")&&(e.l=t.l);try{var r=[];if(t.checkAll)throw"unhandled";if("msg"==t.propertyType)r.push("((msg,node) => {","let _propValue = undefined","try { _propValue = RED.util.getMessageProperty(msg, '"+t.property+"') } catch (ex) {}","let _returnValue = []"),n(r,t),r.push("})(msg,node);");else{if("jsonata"!=t.propertyType)throw"unhandled";r.push("jsonata('"+t.property+"').evaluate(msg).then(_propValue => {","let _returnValue = []"),n(r,t),r.push("})")}return e.func=r.join("\n"),e}catch(e){return t}})}if(l.replace_change){let s=e=>btoa(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g,function(e,t){return String.fromCharCode("0x"+t)}));p=p.map(t=>{if("change"!=t.type)return t;var e={id:t.id,name:t.name,type:"function",x:t.x,y:t.y,func:"",outputs:1,timeout:"",noerr:0,initialize:"",finalize:"",libs:[{var:"process",module:"process"},{var:"jsonata",module:"jsonata"}],wires:t.wires};t.hasOwnProperty("z")&&(e.z=t.z),t.hasOwnProperty("l")&&(e.l=t.l);try{var r=["(async (msg,node) => {","let __s = RED.util.setMessageProperty","let __g = RED.util.getMessageProperty"];for(let e=0;e<t.rules.length;e++){var n=t.rules[e];if("set"==n.t){if(n.dc)throw"unhandled";if("msg"==n.pt&&"str"==n.tot)r.push("__s(msg,'"+n.p+"', Buffer.from('"+s(n.to)+"', 'base64').toString('utf-8') )");else if("msg"==n.pt&&"bool"==n.tot)r.push("__s(msg,'"+n.p+"', "+n.to+")");else if("msg"==n.pt&&"num"==n.tot)r.push("__s(msg,'"+n.p+"', Number(Buffer.from('"+s(n.to)+"', 'base64').toString('utf-8')))");else if("msg"==n.pt&&"json"==n.tot)r.push("__s(msg,'"+n.p+"', JSON.parse(Buffer.from('"+s(n.to)+"', 'base64').toString('utf-8')))");else if("msg"==n.pt&&"msg"==n.tot)r.push("try { __s(msg,'"+n.p+"', __g(msg, '"+n.to+"')) } catch (ex) {}");else if("msg"==n.pt&&"env"==n.tot)r.push("__s(msg,'"+n.p+"', process.env['"+n.to+"'])");else{if("msg"!=n.pt||"jsonata"!=n.tot||!n.to.startsWith("/* @obfuscate-safe */"))throw"unhandlable";r.push("__s(msg,'"+n.p+"', await jsonata(Buffer.from('"+s(n.to)+"', 'base64').toString('utf-8')).evaluate(msg) )")}}else{if("delete"!=n.t||"msg"!=n.pt)throw"unhandlable";r.push("delete msg."+n.p)}}return r.push("node.send(msg) })(msg,node);"),e.func=r.join("\n"),e}catch(e){return console.log(e),t}})}if(l.javascript){let r={},t=[];p.forEach(e=>{"javascript"!=(r[e.id]=e).format&&"function"!=e.type&&"css"!=e.format&&"json"!=e.format||t.push(e)});var e={parse:{bare_returns:!0,expression:!1},compress:{},mangle:{reserved:["$","export","require"]},output:null,sourceMap:null,nameCache:null,toplevel:!1,warnings:!1},o={compatibility:"*",level:2};$.ajax({url:"ClientCode/"+RED.nodes.id()+"/ugify",type:"POST",contentType:"application/json; charset=utf-8",data:JSON.stringify({nodes:t,jscfg:e,csscfg:o}),success:function(e){e.forEach(e=>{var t=r[e.id];e._error&&console.log("ERROR NODE",e),"function"==t.type?t.func=e.func:"javascript"!=t.format&&"css"!=t.format&&"json"!=t.format||(t.template=e.template)}),obfuscateHelpers.openImportDialog(p)},error:function(e,t,r){RED.notify("ClientCode Communcation Failure: "+n.id+": "+t,{type:"error",timeout:3e3})}})}else obfuscateHelpers.openImportDialog(p)}
|
|
6
6
|
|
|
7
|
-
function setupTreelist(){var e=collectOrphans();if(0==e.length){RED.notify("No Orphans Found",{type:"
|
|
7
|
+
function setupTreelist(){var e=collectOrphans();if(0==e.length){RED.notify("No Orphans Found",{type:"success",timeout:2e3});try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){}}else{try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){$("#node-input-orphan-target-container-div").css({width:"100%",height:"calc(100%)"}).treeList({multi:!1}).on("treelistitemmouseover",function(e,t){}).on("treelistitemmouseout",function(e,t){}).on("treelistselect",function(e,t){t.node&&(RED.workspaces.show(t.node.z,!1,!1,!0),RED.view.reveal(t.node.id,!0),RED.view.redraw())}).on("treelistconfirm",function(e,t){var n;t.node&&(n=t.node.id,setTimeout(()=>{var e=RED.nodes.node(n);e&&(RED.view.reveal(e.id),RED.view.select(e.id),RED.editor.edit(e)),n==RED.workspaces.active()&&RED.workspaces.edit()},50))}),$("#node-input-orphan-target-filter").show();var n=$("#node-input-orphan-target-filter").searchBox({style:"compact",delay:300,change:function(){var e,t=$(this).val().trim().toLowerCase();""===t?($("#node-input-orphan-target-container-div").treeList("filter",null),n.searchBox("count","")):(e=$("#node-input-orphan-target-container-div").treeList("filter",function(e){return-1<e.label.toLowerCase().indexOf(t)||-1<e.node.type.toLowerCase().indexOf(t)}),n.searchBox("count",e+" / "+$("#node-input-orphan-target-container-div").treeList("data").length))}})}$("#node-input-orphan-target-container-div").treeList("data",e.sort((e,t)=>e.node.z>t.node.z))}}function collectOrphans(){const t=new Set;var n=[],i=(RED.nodes.eachLink(e=>{t.add(e.source),t.add(e.target)}),RED.nodes.eachNode(e=>{(!t.has(e)||"link out"==e.type&&"link"==e.mode&&0==e.links.reduce((e,t)=>e||!!RED.nodes.node(t),!1))&&n.push(e)}),[]),r={};return n.forEach(function(e){var t=RED.nodes.getType(e.type);if(t){var n=t.label,n=("function"==typeof n?n.call(e):n)||"",o=e.type;if(0===o.indexOf("subflow:"))return}t&&n||(n=e.type),r[e.id]={node:e,label:n,sublabel:o,selected:!1,checkbox:!1},i.push(r[e.id])}),i}
|
|
8
8
|
|
|
9
9
|
function nr_intro_generate_svg_3_1(r,t){return e=>{try{handleSvgObject($($("svg[width=8000]")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?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">'+n+"</text></svg>")}}}function nr_intro_generate_svg_3_0(r,t){return e=>{try{handleSvgObject($($("svg")[0]),e,t)}catch(t){var n="Error Generating SVG: "+JSON.stringify(t);r.notify(n,{type:"error"}),e('<?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">'+n+"</text></svg>")}}}function handleSvgObject(a,e,t){var n=a.clone(),r=(n.find("foreignObject").remove(),n.find("svg.__screenshot").remove(),'width="'+a.attr("width")+'" height="'+a.attr("height")+'"'),s=RED.settings.version.split("."),i=parseInt(s[0]),s=parseInt(s[1]);if(3<=i&&1<=s){var o=$($($(a).children("g")[0]).children("g")[0]).children("g"),l={x:8e3,y:8e3,w:-1,h:-1};for(let t=1;t<o.length;t++){var g=o[t].getBBox();0==g.width&&0==g.height||(l.x=Math.min(g.x,l.x),l.y=Math.min(g.y,l.y),l.w=Math.max(g.width,l.w),l.h=Math.max(g.height,l.h))}r+=` viewBox='${l.x} ${l.y} ${l.w} ${l.h}'`}function c(t,e){for(var n=0;n<t.length;n++){var s=t.item(n),i=e[n];["stroke-width","fill-opacity","stroke-opacity","opacity","stroke-dasharray"].forEach(function(t){s.setAttribute(t,$(i).attr(t)||$(i).css(t))}),["fill","stroke"].forEach(function(t){var e,n,r=(e=$(i).attr(t)||$(i).css(t))&&null!==e&&"none"!=e?(n=e.match(/^#(.)(.)(.)$/))?"#"+n[1]+n[1]+n[2]+n[2]+n[3]+n[3]:(n=e.match(/^#......$/))?e:null===(n=e.match(/^rgb\(([0-9]+),\s+([0-9]+),\s+([0-9]+)/))?(r=e.match(/^rgba\(([0-9]+),\s+([0-9]+),\s+([0-9]+),\s+([0-9]+)/))?{clr:"#"+("0"+parseInt(r[1],10).toString(16)).slice(-2)+("0"+parseInt(r[2],10).toString(16)).slice(-2)+("0"+parseInt(r[3],10).toString(16)).slice(-2),opa:r[4]}:(console.log("Screenshot node: returned unknown color: "+e),e):"#"+("0"+parseInt(n[1],10).toString(16)).slice(-2)+("0"+parseInt(n[2],10).toString(16)).slice(-2)+("0"+parseInt(n[3],10).toString(16)).slice(-2):"none";"object"==typeof r?(s.setAttribute(t+"-opacity",r.opa),s.setAttribute(t,r.clr)):s.setAttribute(t,r)}),$(i).hasClass("hide")&&("g"==s.tagName&&s.setAttribute("opacity","0"),s.setAttribute("visibility","hidden"))}}var i='<?xml version="1.0" standalone="no"?>\r\n<svg '+r+' pointer-events="all" style="cursor: crosshair; touch-action: none;" xmlns="http://www.w3.org/2000/svg" class="__screenshot" xmlns:xlink="http://www.w3.org/1999/xlink">\r\n',s=n.html(),h=(new DOMParser).parseFromString(i+s+"\r\n</svg>","image/svg+xml"),v=t=>t,f=(t.rmidsandclasses&&(v=e=>(["g","rect","line","path","circle","image","text"].forEach(t=>{$(e.getElementsByTagName(t)).each((t,e)=>{e.setAttribute("class",""),e.setAttribute("id","")})}),e)),["g","rect","line","path","circle","image"].forEach(function(t){c(h.getElementsByTagName(t),a.find(t))}),["text"].forEach(function(t){c(h.getElementsByTagName(t),a.find(t));for(var e=h.getElementsByTagName(t),n=a.find(t),r=0;r<e.length;r++){var s=e.item(r),i=n[r];["font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","text-anchor","dominant-baseline"].forEach(function(t){s.setAttribute(t,$(i).attr(t)||$(i).css(t))})}}),h.getElementsByTagName("image")),m={},w=(n,r,s)=>{var i=n.getAttribute("xlink:href"),a=i.substr(-4,4).toLowerCase(),o={".jpg":"jpeg",jpeg:"jpeg",".png":"png",".svg":"svg+xml"};if(m[i])return n.setAttribute("xlink:href","data:image/"+o[a]+";base64,"+m[i]),s(r-1);switch(a){case".jpg":case"jpeg":case".png":var l=new XMLHttpRequest;l.open("GET",i,!0),l.responseType="arraybuffer";l.onload=function(t){var e=l.response;e&&(e=(t=>{for(var e="",n=new Uint8Array(t),r=n.byteLength,s=0;s<r;s++)e+=String.fromCharCode(n[s]);return window.btoa(e)})(e),m[i]=e,n.setAttribute("xlink:href","data:image/"+o[a]+";base64,"+e)),s(r-1)},l.send(null);break;case".svg":$.get(i,function(t){var e=new XMLSerializer,e=btoa(e.serializeToString(t));m[i]=e,n.setAttribute("xlink:href","data:image/svg+xml;base64,"+e),s(r-1)})}},d=t=>{t<0?e((new XMLSerializer).serializeToString(v(h))):w(f.item(t),t,d)};0<f.length?w(f.item(f.length-1),f.length-1,d):e((new XMLSerializer).serializeToString(v(h)))}function generatorFunctionForVersion(t,e){var n,r=t.settings.version.split("."),s=r[0],r=r[1];if("3"==s){if("0"==r)return nr_intro_generate_svg_3_0(t,e);if("1"==r)return nr_intro_generate_svg_3_1(t,e)}return n=t,t=>{var e="Node-RED version ("+n.settings.version+") not supported";n.notify(e,{type:"error"}),t&&t('<?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">'+e+"</text></svg>")}}function addPanZoom(){var t=d3.select("#node-input-screenshot-svgcontainer svg"),e=(t.html("<g>"+t.html()+"</g>"),setTimeout(()=>{var t=$("#node-input-screenshot-svgcontainer svg"),e=$(t).attr("viewBox").split(" ");t.animate({height:parseInt(e[3]),width:parseInt(e[2])},800,"swing")},100),t.select("g")),n=d3.behavior.zoom().scaleExtent([.1,200]).on("zoom",function(t){e.attr({transform:"translate("+n.translate()+") scale("+n.scale()+")"})});t.call(n)}
|
|
10
10
|
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
function highlightAllLinkCalls(){let e=[];RED.nodes.eachNode(t=>{t.z==RED.workspaces.active()&&"link call"==t.type&&e.push(t)}),e.forEach(t=>{$("#grplnkcallclk-"+t.id).remove();var e=document.createElementNS("http://www.w3.org/2000/svg","g"),l=(e.setAttribute("class","red-ui-linkcall-link-indicator"),e.setAttribute("transform","translate(12,0)"),e.setAttribute("id","grplnkcallclk-"+t.id),document.createElementNS("http://www.w3.org/2000/svg","circle")),i=(l.setAttribute("cx","5"),l.setAttribute("cy","5"),l.setAttribute("r","5"),l.setAttribute("id","lnkcallclk-"+t.id),l.setAttribute("style","cursor: pointer;"),t.links[0]);i?RED.nodes.node(i)?l.setAttribute("fill","green"):l.setAttribute("fill","red"):l.setAttribute("fill","orange"),e.append(l),$(e).insertBefore($("#"+t.id).find(".red-ui-flow-node-changed"));let r=t.id;$("#lnkcallclk-"+t.id).on("click",t=>{t&&t.preventDefault();t=RED.nodes.node(r);if(t){let l=t.links[0];1<t.links.length&&RED.notify("Multiple links, showing first","warning"),RED.nodes.node(l)?(RED.view.reveal(l),RED.view.select(l),setTimeout(()=>{$("#lnkcallclk-"+l).remove();var t=document.createElementNS("http://www.w3.org/2000/svg","g"),e=(t.setAttribute("class","red-ui-linkcall-link-indicator"),t.setAttribute("transform","translate(12,0)"),t.setAttribute("id","lnkcallclk-"+l),document.createElementNS("http://www.w3.org/2000/svg","circle"));e.setAttribute("cx","5"),e.setAttribute("cy","5"),e.setAttribute("r","5"),e.setAttribute("id","lnkcallclk-"+l),e.setAttribute("style","cursor: pointer;"),e.setAttribute("fill","green"),t.append(e),$(t).insertBefore($("#"+l).find(".red-ui-flow-node-changed")),$("#lnkcallclk-"+l).on("click",t=>{t&&t.preventDefault(),RED.view.reveal(r),RED.view.select(r),setTimeout(highlightAllLinkCalls,500)})},500)):RED.notify("Link in node not found","error")}else RED.notify("Node not found","error")})})}
|
|
14
14
|
|
|
15
|
+
function setupTreelistAllLinksForLinkIn(e){e=collectAllLinksNodes(e);if(0==e.length){RED.notify("No links found",{type:"error",timeout:2e3});try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){}}else{try{$("#node-input-orphan-target-container-div").treeList("empty")}catch(e){$("#node-input-orphan-target-container-div").css({width:"100%",height:"calc(100%)"}).treeList({multi:!1}).on("treelistitemmouseover",function(e,t){}).on("treelistitemmouseout",function(e,t){}).on("treelistselect",function(e,t){t.node&&(RED.workspaces.show(t.node.z,!1,!1,!0),RED.view.reveal(t.node.id,!0),RED.view.redraw())}).on("treelistconfirm",function(e,t){var n;t.node&&(n=t.node.id,setTimeout(()=>{var e=RED.nodes.node(n);e&&(RED.view.reveal(e.id),RED.view.select(e.id),RED.editor.edit(e,"editor-tab-description")),n==RED.workspaces.active()&&RED.workspaces.edit()},50))}),$("#node-input-orphan-target-filter").show();var n=$("#node-input-orphan-target-filter").searchBox({style:"compact",delay:300,change:function(){var e,t=$(this).val().trim().toLowerCase();""===t?($("#node-input-orphan-target-container-div").treeList("filter",null),n.searchBox("count","")):(e=$("#node-input-orphan-target-container-div").treeList("filter",function(e){return-1<e.label.toLowerCase().indexOf(t)||-1<e.node.type.toLowerCase().indexOf(t)}),n.searchBox("count",e+" / "+$("#node-input-orphan-target-container-div").treeList("data").length))}})}$("#node-input-orphan-target-container-div").treeList("data",e.sort((e,t)=>e.node.z>t.node.z))}}function collectAllLinksNodes(t){let n=[];RED.nodes.eachNode(e=>{"link call"!=e.type&&"link out"!=e.type||-1<e.links.indexOf(t)&&n.push(e)});var i=[],r={};return n.forEach(function(e){var t=RED.nodes.getType(e.type);if(t){var n,o=t.label,o=("function"==typeof o?o.call(e):o)||"";if(0===(n=e.type).indexOf("subflow:"))return}t&&o||(o=e.type),r[e.id]={node:e,label:o,sublabel:n,selected:!1,checkbox:!1},i.push(r[e.id])}),i}
|
|
16
|
+
|
|
15
17
|
// Add your plugin as a new tabsheet in the right sidebar AFTER the flow editor is completely started
|
|
16
18
|
var initialiseConfigNodeOnce = () => {
|
|
17
19
|
RED.events.off('runtime-state', initialiseConfigNodeOnce);
|
|
@@ -48,8 +50,8 @@
|
|
|
48
50
|
// Add tab, orphans
|
|
49
51
|
tabs.addTab({
|
|
50
52
|
id: 'func-introspection-tab-orphans',
|
|
51
|
-
iconClass: 'fa fa-
|
|
52
|
-
label: '
|
|
53
|
+
iconClass: 'fa fa-eyedropper',
|
|
54
|
+
label: 'Lint'
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
// Add tab, obfuscation
|
|
@@ -213,11 +215,38 @@
|
|
|
213
215
|
setupTreelistInfoness();
|
|
214
216
|
})
|
|
215
217
|
|
|
218
|
+
$('#node-input-linkin-nodes-find-btn').on('click', (e) => {
|
|
219
|
+
if ( e ) { e.preventDefault() }
|
|
220
|
+
|
|
221
|
+
let linkNodes = (RED.view.selection().nodes || []).filter( (e) => {
|
|
222
|
+
return e.type == "link in"
|
|
223
|
+
}).map( e => e.id )
|
|
224
|
+
|
|
225
|
+
if ( linkNodes.length == 0 ) {
|
|
226
|
+
RED.notify(
|
|
227
|
+
"No link in node selected, selected exactly one.", {
|
|
228
|
+
type: "error"
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
setupTreelistAllLinksForLinkIn(linkNodes[0])
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
$('#node-input-orphan-clear-workspace-btn').on('click', (e) => {
|
|
237
|
+
if ( e ) { e.preventDefault() }
|
|
238
|
+
$('.red-ui-linkcall-link-indicator').remove()
|
|
239
|
+
})
|
|
240
|
+
|
|
216
241
|
RED.actions.add( "introspection:show-link-call-links", highlightAllLinkCalls)
|
|
217
242
|
|
|
218
243
|
$('#node-input-linkcalls-find-btn').on('click', (e) => {
|
|
219
244
|
if ( e ) { e.preventDefault() }
|
|
220
245
|
highlightAllLinkCalls()
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
$("#node-input-orphan-target-container-div").treeList('empty')
|
|
249
|
+
} catch (ex) { }
|
|
221
250
|
})
|
|
222
251
|
};
|
|
223
252
|
RED.events.on('runtime-state', initialiseConfigNodeOnce);
|
|
@@ -301,6 +330,13 @@
|
|
|
301
330
|
class="red-ui-button"><i class="fa fa-cc"></i> Undocumented</button>
|
|
302
331
|
<button id="node-input-linkcalls-find-btn"
|
|
303
332
|
class="red-ui-button"><i class="fa fa-link"></i> Link Calls</button>
|
|
333
|
+
<button id="node-input-linkin-nodes-find-btn"
|
|
334
|
+
class="red-ui-button"><i class="fa fa-link"></i> Link Ins</button>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
338
|
+
<button id="node-input-orphan-clear-workspace-btn"
|
|
339
|
+
class="red-ui-button">Clear dots</button>
|
|
304
340
|
</div>
|
|
305
341
|
|
|
306
342
|
<div class="form-row node-input-target-row node-input-target-list-row"
|
|
@@ -310,6 +346,7 @@
|
|
|
310
346
|
</div>
|
|
311
347
|
<div id="node-input-orphan-target-container-div"></div>
|
|
312
348
|
</div>
|
|
349
|
+
|
|
313
350
|
</div>
|
|
314
351
|
</div>
|
|
315
352
|
</div>
|