@gregoriusrippenstein/node-red-contrib-nodedev 0.1.2 → 0.1.3
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/examples/config-node-with-sidebar.json +113 -0
- package/nodes/05-node-dev-ops.html +31 -13
- package/nodes/10-node-factory.html +27 -16
- package/nodes/10-node-factory.js +144 -83
- package/nodes/templates/tmpl.js +2 -2
- package/nodes/templates/tmplpackage.json +9 -4
- package/nodes/templates/tmplsidebar.html +138 -0
- package/nodes/templates/tmplsidebarnode.html +22 -0
- package/nodes/templates/tmplsidebarnode.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "e68c8450d6e047e6",
|
|
4
|
+
"type": "NpmTarBall",
|
|
5
|
+
"z": "5644e181ee8af639",
|
|
6
|
+
"name": "",
|
|
7
|
+
"x": 905,
|
|
8
|
+
"y": 656,
|
|
9
|
+
"wires": [
|
|
10
|
+
[
|
|
11
|
+
"ddb9e4e7ca9e2797"
|
|
12
|
+
]
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "ddb9e4e7ca9e2797",
|
|
17
|
+
"type": "NodeRedInstall",
|
|
18
|
+
"z": "5644e181ee8af639",
|
|
19
|
+
"name": "",
|
|
20
|
+
"x": 983,
|
|
21
|
+
"y": 710,
|
|
22
|
+
"wires": [
|
|
23
|
+
[]
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "6f04b8605d139351",
|
|
28
|
+
"type": "group",
|
|
29
|
+
"z": "5644e181ee8af639",
|
|
30
|
+
"name": "Step 1: Generate the missing nodes",
|
|
31
|
+
"style": {
|
|
32
|
+
"label": true
|
|
33
|
+
},
|
|
34
|
+
"nodes": [
|
|
35
|
+
"4f2e91f3e9fa51b7"
|
|
36
|
+
],
|
|
37
|
+
"x": 326,
|
|
38
|
+
"y": 562,
|
|
39
|
+
"w": 232,
|
|
40
|
+
"h": 82
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "4f2e91f3e9fa51b7",
|
|
44
|
+
"type": "NodeFactory",
|
|
45
|
+
"z": "5644e181ee8af639",
|
|
46
|
+
"g": "6f04b8605d139351",
|
|
47
|
+
"name": "",
|
|
48
|
+
"nodename": "Fubar",
|
|
49
|
+
"color": "#FFF0F0",
|
|
50
|
+
"hasbutton": true,
|
|
51
|
+
"hasinput": true,
|
|
52
|
+
"outputcount": 1,
|
|
53
|
+
"category": "snafu",
|
|
54
|
+
"summary": "Summary",
|
|
55
|
+
"description": "Description",
|
|
56
|
+
"icon": "font-awesome/fa-venus-double",
|
|
57
|
+
"frt2bakcomm": false,
|
|
58
|
+
"bak2frtcomm": false,
|
|
59
|
+
"createmanifest": true,
|
|
60
|
+
"isplugin": true,
|
|
61
|
+
"x": 422,
|
|
62
|
+
"y": 603,
|
|
63
|
+
"wires": [
|
|
64
|
+
[]
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "a599fd3ebf69cdb1",
|
|
69
|
+
"type": "group",
|
|
70
|
+
"z": "5644e181ee8af639",
|
|
71
|
+
"name": "Step 2: Connect and installing to Node-RED",
|
|
72
|
+
"style": {
|
|
73
|
+
"label": true
|
|
74
|
+
},
|
|
75
|
+
"nodes": [
|
|
76
|
+
"b45307819c625e63"
|
|
77
|
+
],
|
|
78
|
+
"x": 326,
|
|
79
|
+
"y": 232,
|
|
80
|
+
"w": 284,
|
|
81
|
+
"h": 82
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "b45307819c625e63",
|
|
85
|
+
"type": "NodeDevOps",
|
|
86
|
+
"z": "5644e181ee8af639",
|
|
87
|
+
"g": "a599fd3ebf69cdb1",
|
|
88
|
+
"name": "",
|
|
89
|
+
"pname": "@johnsmith/fubar-node",
|
|
90
|
+
"pversion": "0.0.1",
|
|
91
|
+
"pauthorname": "Alfred E. Neumann",
|
|
92
|
+
"pauthoremail": "alfred@example.com",
|
|
93
|
+
"pdescription": "Fubar nods.",
|
|
94
|
+
"noderedinstall": true,
|
|
95
|
+
"randompackagename": true,
|
|
96
|
+
"gitcommit": false,
|
|
97
|
+
"gitcheckforchange": false,
|
|
98
|
+
"githubowner": "",
|
|
99
|
+
"githubrepo": "",
|
|
100
|
+
"githubbranch": "main",
|
|
101
|
+
"githubauthor": "",
|
|
102
|
+
"githubauthoremail": "",
|
|
103
|
+
"githubmessage": "",
|
|
104
|
+
"npmpublish": false,
|
|
105
|
+
"npmunpublish": false,
|
|
106
|
+
"npmotp": "",
|
|
107
|
+
"x": 442,
|
|
108
|
+
"y": 273,
|
|
109
|
+
"wires": [
|
|
110
|
+
[]
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
]
|
|
@@ -47,20 +47,23 @@
|
|
|
47
47
|
defaults: {
|
|
48
48
|
name: { value:"" },
|
|
49
49
|
|
|
50
|
-
pname:
|
|
51
|
-
pversion:
|
|
50
|
+
pname: { value: "", required: true },
|
|
51
|
+
pversion: { value: "", required: true },
|
|
52
|
+
pauthorname: { value: "", required: true },
|
|
53
|
+
pauthoremail: { value: "", required: true },
|
|
54
|
+
pdescription: { value: "", required: true },
|
|
52
55
|
|
|
53
56
|
noderedinstall: { value: false },
|
|
54
57
|
randompackagename: { value: false },
|
|
55
58
|
|
|
56
|
-
gitcommit:
|
|
59
|
+
gitcommit: { value: false },
|
|
57
60
|
gitcheckforchange: { value: false },
|
|
58
|
-
githubowner:
|
|
59
|
-
githubrepo:
|
|
60
|
-
githubbranch:
|
|
61
|
-
githubauthor:
|
|
61
|
+
githubowner: { value: ""},
|
|
62
|
+
githubrepo: { value: ""},
|
|
63
|
+
githubbranch: { value: "main"},
|
|
64
|
+
githubauthor: { value: ""},
|
|
62
65
|
githubauthoremail: { value: "" },
|
|
63
|
-
githubmessage:
|
|
66
|
+
githubmessage: { value: "" },
|
|
64
67
|
|
|
65
68
|
npmpublish: { value: false },
|
|
66
69
|
npmunpublish: { value: false },
|
|
@@ -196,6 +199,21 @@
|
|
|
196
199
|
<input type="text" id="node-input-pversion" placeholder="0.0.1"/>
|
|
197
200
|
</div>
|
|
198
201
|
|
|
202
|
+
<div class="form-row">
|
|
203
|
+
<label for="node-input-pauthorname" style="min-width: 250px;"><i class="fa fa-address-book-o"></i> Package Author Name</label>
|
|
204
|
+
<input type="text" id="node-input-pauthorname" placeholder="Alfred E. Neumann"/>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<div class="form-row">
|
|
208
|
+
<label for="node-input-pauthoremail" style="min-width: 250px;"><i class="fa fa-envelope-o"></i> Package Author Email</label>
|
|
209
|
+
<input type="text" id="node-input-pauthoremail" placeholder="joe.blog@example.com"/>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<div class="form-row">
|
|
213
|
+
<label for="node-input-pdescription" style="min-width: 150px;"><i class="fa fa-book"></i> Package Description</label>
|
|
214
|
+
<input type="text" id="node-input-pdescription" placeholder="Package description"/>
|
|
215
|
+
</div>
|
|
216
|
+
|
|
199
217
|
<hr/>
|
|
200
218
|
|
|
201
219
|
<div class="form-row">
|
|
@@ -248,15 +266,15 @@
|
|
|
248
266
|
|
|
249
267
|
<div id="github-options">
|
|
250
268
|
<div class="form-row">
|
|
251
|
-
<label for="node-input-githubowner" style="min-width: 150px;"><i class="fa fa-
|
|
269
|
+
<label for="node-input-githubowner" style="min-width: 150px;"><i class="fa fa-user-o"></i> GitHub Username</label>
|
|
252
270
|
<input type="text" id="node-input-githubowner" placeholder="username"/>
|
|
253
271
|
</div>
|
|
254
272
|
<div class="form-row">
|
|
255
|
-
<label for="node-input-githubrepo" style="min-width: 150px;"><i class="fa fa-
|
|
273
|
+
<label for="node-input-githubrepo" style="min-width: 150px;"><i class="fa fa-paw"></i> Repository</label>
|
|
256
274
|
<input type="text" id="node-input-githubrepo" placeholder=""/>
|
|
257
275
|
</div>
|
|
258
276
|
<div class="form-row">
|
|
259
|
-
<label for="node-input-githubbranch" style="min-width: 150px;"><i class="fa fa-
|
|
277
|
+
<label for="node-input-githubbranch" style="min-width: 150px;"><i class="fa fa-tree"></i> Branch</label>
|
|
260
278
|
<input type="text" id="node-input-githubbranch" placeholder="main"/>
|
|
261
279
|
</div>
|
|
262
280
|
</div>
|
|
@@ -267,11 +285,11 @@
|
|
|
267
285
|
<input type="text" id="node-input-githubmessage" placeholder="Initial Commit"/>
|
|
268
286
|
</div>
|
|
269
287
|
<div class="form-row">
|
|
270
|
-
<label for="node-input-githubauthor" style="min-width: 150px;"><i class="fa fa-
|
|
288
|
+
<label for="node-input-githubauthor" style="min-width: 150px;"><i class="fa fa-address-book-o"></i> Author Name</label>
|
|
271
289
|
<input type="text" id="node-input-githubauthor" placeholder="Joe Blog"/>
|
|
272
290
|
</div>
|
|
273
291
|
<div class="form-row">
|
|
274
|
-
<label for="node-input-githubauthoremail" style="min-width: 150px;"><i class="fa fa-
|
|
292
|
+
<label for="node-input-githubauthoremail" style="min-width: 150px;"><i class="fa fa-envelope-o"></i> Author Email</label>
|
|
275
293
|
<input type="text" id="node-input-githubauthoremail" placeholder="joe@spreads-the.love"/>
|
|
276
294
|
</div>
|
|
277
295
|
</div>
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
<div class="form-row">
|
|
48
48
|
<label for="node-input-summary">
|
|
49
49
|
<i class="fa fa-tag"></i>
|
|
50
|
-
<span>Summary</span>
|
|
50
|
+
<span>Summary (REQUIRED)</span>
|
|
51
51
|
</label>
|
|
52
52
|
<div style="height: 150px; min-height:150px; max-height: 150px;" class="node-text-editor" id="node-input-summary">
|
|
53
53
|
</div>
|
|
@@ -56,12 +56,19 @@
|
|
|
56
56
|
<div class="form-row">
|
|
57
57
|
<label for="node-input-description">
|
|
58
58
|
<i class="fa fa-tag"></i>
|
|
59
|
-
<span>Description</span>
|
|
59
|
+
<span>Description (REQUIRED)</span>
|
|
60
60
|
</label>
|
|
61
61
|
<div style="height: 350px; min-height:350px; max-height: 350px;" class="node-text-editor" id="node-input-description">
|
|
62
62
|
</div>
|
|
63
63
|
</div>
|
|
64
64
|
|
|
65
|
+
<div class="form-row">
|
|
66
|
+
<label for="node-input-isplugin" style="min-width: 250px;">
|
|
67
|
+
<span>Plugin: Sidebar + Config?</span>
|
|
68
|
+
</label>
|
|
69
|
+
<input type="checkbox" id="node-input-isplugin" style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
70
|
+
</div>
|
|
71
|
+
|
|
65
72
|
<div class="form-row">
|
|
66
73
|
<label for="node-input-frt2bakcomm" style="min-width: 250px;">
|
|
67
74
|
<span>Frontend to Backend communication?</span>
|
|
@@ -119,7 +126,9 @@
|
|
|
119
126
|
|
|
120
127
|
data["color"] = $('#node-input-colour').val();
|
|
121
128
|
data["icon"] = $('#red-ui-editor-node-icon').val();
|
|
129
|
+
data["iconclass"] = "fa " + data["icon"].split("/")[1]; /* Assume font-awesomeness */
|
|
122
130
|
data["name"] = $('#node-input-nodename').val();
|
|
131
|
+
data["namelwr"] = data["name"].toLowerCase();
|
|
123
132
|
data["outputcount"] = $('#node-input-outputcount').val();
|
|
124
133
|
data["category"] = $('#node-input-category').val();
|
|
125
134
|
|
|
@@ -128,7 +137,8 @@
|
|
|
128
137
|
data["bak2frtcomm"] = $('#node-input-bak2frtcomm').is(":checked");
|
|
129
138
|
data["frt2bakcomm"] = $('#node-input-frt2bakcomm').is(":checked");
|
|
130
139
|
data["createmanifest"] = $('#node-input-createmanifest').is(":checked");
|
|
131
|
-
|
|
140
|
+
data["isplugin"] = $('#node-input-isplugin').is(":checked");
|
|
141
|
+
|
|
132
142
|
data["__task"] = "generate_from_templates";
|
|
133
143
|
|
|
134
144
|
$.ajax({
|
|
@@ -177,19 +187,20 @@
|
|
|
177
187
|
color: "#e5e4ef",
|
|
178
188
|
category: 'nodedev',
|
|
179
189
|
defaults: {
|
|
180
|
-
name:
|
|
181
|
-
nodename:
|
|
182
|
-
color:
|
|
183
|
-
hasbutton:
|
|
184
|
-
hasinput:
|
|
185
|
-
outputcount:
|
|
186
|
-
category:
|
|
187
|
-
summary:
|
|
188
|
-
description:
|
|
189
|
-
icon:
|
|
190
|
-
frt2bakcomm:
|
|
191
|
-
bak2frtcomm:
|
|
192
|
-
createmanifest: { value: false }
|
|
190
|
+
name: { value: "" },
|
|
191
|
+
nodename: { value: "", required: true },
|
|
192
|
+
color: { value: "#e5e4ef" },
|
|
193
|
+
hasbutton: { value: false },
|
|
194
|
+
hasinput: { value: true },
|
|
195
|
+
outputcount: { value: 1 },
|
|
196
|
+
category: { value: "" },
|
|
197
|
+
summary: { value: "", required: true },
|
|
198
|
+
description: { value: "", required: true },
|
|
199
|
+
icon: { value: "font-awesome/fa-industry" },
|
|
200
|
+
frt2bakcomm: { value: false },
|
|
201
|
+
bak2frtcomm: { value: false },
|
|
202
|
+
createmanifest: { value: false },
|
|
203
|
+
isplugin: { value: false },
|
|
193
204
|
},
|
|
194
205
|
inputs: 1,
|
|
195
206
|
outputs: 1,
|
package/nodes/10-node-factory.js
CHANGED
|
@@ -165,62 +165,137 @@ module.exports = function (RED) {
|
|
|
165
165
|
});
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
function
|
|
169
|
-
var
|
|
170
|
-
|
|
171
|
-
var
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
168
|
+
function createPluginNodeDefintions(msg, node) {
|
|
169
|
+
var sidebarHtmlPath = path.join(__dirname, 'templates', 'tmplsidebar.html');
|
|
170
|
+
var nodeJsPath = path.join(__dirname, 'templates', 'tmplsidebarnode.js');
|
|
171
|
+
var nodeHtmlPath = path.join(__dirname, 'templates', 'tmplsidebarnode.html');
|
|
172
|
+
|
|
173
|
+
var content = {};
|
|
174
|
+
|
|
175
|
+
var promises = [
|
|
176
|
+
handleTemplate(msg, node, fs.readFileSync(sidebarHtmlPath, 'utf8')).then((c) => { content["sbht"] = c }),
|
|
177
|
+
handleTemplate(msg, node, fs.readFileSync(nodeJsPath, 'utf8')).then((c) => { content["ndjs"] = c }),
|
|
178
|
+
handleTemplate(msg, node, fs.readFileSync(nodeHtmlPath, 'utf8')).then((c) => { content["ndht"] = c }),
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
return Promise.all(promises).then(() => {
|
|
182
|
+
var secondId = RED.util.generateId();
|
|
183
|
+
var thirdId = RED.util.generateId();
|
|
184
|
+
|
|
185
|
+
return [{
|
|
186
|
+
id: RED.util.generateId(),
|
|
187
|
+
type: "PkgFile",
|
|
188
|
+
name: msg.node.name + "Cfg.js",
|
|
189
|
+
filename: "nodes/" + msg.node.namelwr + ".js",
|
|
190
|
+
template: content["ndjs"],
|
|
191
|
+
syntax: "mustache",
|
|
192
|
+
format: "javascript",
|
|
193
|
+
output: "str",
|
|
194
|
+
x: 100,
|
|
195
|
+
y: 50,
|
|
196
|
+
wires: [[secondId]]
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
{
|
|
200
|
+
id: secondId,
|
|
201
|
+
type: "PkgFile",
|
|
202
|
+
name: "Sidebar: " + msg.node.name + ".html",
|
|
203
|
+
filename: "plugins/" + msg.node.namelwr + ".html",
|
|
204
|
+
template: content["sbht"],
|
|
205
|
+
syntax: "mustache",
|
|
206
|
+
format: "html",
|
|
207
|
+
output: "str",
|
|
208
|
+
x: 100,
|
|
209
|
+
y: 100,
|
|
210
|
+
wires: [[thirdId]]
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
{
|
|
214
|
+
id: thirdId,
|
|
215
|
+
type: "PkgFile",
|
|
216
|
+
name: msg.node.name + "Cfg.html",
|
|
217
|
+
filename: "nodes/" + msg.node.namelwr + ".html",
|
|
218
|
+
template: content["ndht"],
|
|
219
|
+
syntax: "mustache",
|
|
220
|
+
format: "html",
|
|
221
|
+
output: "str",
|
|
222
|
+
x: 100,
|
|
223
|
+
y: 150,
|
|
224
|
+
wires: [[]]
|
|
225
|
+
}]
|
|
185
226
|
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function createSimpleNodeDefintions(msg,node) {
|
|
230
|
+
var htmlPath = path.join(__dirname, 'templates', 'tmpl.html');
|
|
231
|
+
var jsPath = path.join(__dirname, 'templates', 'tmpl.js');
|
|
232
|
+
|
|
233
|
+
var content = {};
|
|
186
234
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
235
|
+
var promises = [
|
|
236
|
+
handleTemplate(msg, node, fs.readFileSync(htmlPath, 'utf8')).then((c) => { content["html"] = c }),
|
|
237
|
+
handleTemplate(msg, node, fs.readFileSync(jsPath, 'utf8')).then((c) => { content["jasc"] = c }),
|
|
238
|
+
];
|
|
239
|
+
|
|
240
|
+
return Promise.all(promises).then(() => {
|
|
241
|
+
var secondId = RED.util.generateId();
|
|
242
|
+
|
|
243
|
+
return [{
|
|
244
|
+
id: RED.util.generateId(),
|
|
245
|
+
type: "PkgFile",
|
|
246
|
+
name: msg.node.name + ".js",
|
|
247
|
+
filename: "nodes/" + msg.node.namelwr + ".js",
|
|
248
|
+
template: content["jasc"],
|
|
249
|
+
syntax: "mustache",
|
|
250
|
+
format: "javascript",
|
|
251
|
+
output: "str",
|
|
252
|
+
x: 100,
|
|
253
|
+
y: 50,
|
|
254
|
+
wires: [[secondId]]
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
{
|
|
258
|
+
id: secondId,
|
|
259
|
+
type: "PkgFile",
|
|
260
|
+
name: msg.node.name + ".html",
|
|
261
|
+
filename: "nodes/" + msg.node.namelwr + ".html",
|
|
262
|
+
template: content["html"],
|
|
263
|
+
syntax: "mustache",
|
|
264
|
+
format: "html",
|
|
265
|
+
output: "str",
|
|
266
|
+
x: 100,
|
|
267
|
+
y: 100,
|
|
268
|
+
wires: [[]]
|
|
269
|
+
}]
|
|
199
270
|
})
|
|
271
|
+
}
|
|
200
272
|
|
|
201
|
-
|
|
273
|
+
function createNodeDefintions(msg, node) {
|
|
274
|
+
if ( msg.node.isplugin ) {
|
|
275
|
+
return createPluginNodeDefintions(msg, node)
|
|
276
|
+
} else {
|
|
277
|
+
return createSimpleNodeDefintions(msg, node)
|
|
278
|
+
}
|
|
202
279
|
}
|
|
203
280
|
|
|
204
281
|
function createManifestFiles(msg, node, nodeDefinitions) {
|
|
205
|
-
/* ASSUMPTION: assume the .js file is defined first and
|
|
206
|
-
then the .html file in the node definitions */
|
|
207
|
-
|
|
208
282
|
var packageJsonPath = path.join(__dirname, 'templates', 'tmplpackage.json');
|
|
209
283
|
var readmePath = path.join(__dirname, 'templates', 'tmplreadme.md');
|
|
210
284
|
var licensePath = path.join(__dirname, 'templates', 'tmpllicense');
|
|
211
285
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
286
|
+
/* ASSUMPTION: assume the .js file is defined first and
|
|
287
|
+
then the .html file in the node definitions */
|
|
288
|
+
spcRepDict["nodestanza"] = " \"" + msg.node.namelwr + "\": \"" + nodeDefinitions[0].filename + "\""
|
|
289
|
+
if ( msg.node.isplugin ) {
|
|
290
|
+
spcRepDict["pluginstanza"] = " \"sidebar-plugin\": \"" + nodeDefinitions[1].filename + "\""
|
|
291
|
+
}
|
|
217
292
|
|
|
218
293
|
var content = {};
|
|
219
294
|
|
|
220
295
|
var promises = [
|
|
221
|
-
handleTemplate(msg, node,
|
|
222
|
-
handleTemplate(msg, node,
|
|
223
|
-
handleTemplate(msg, node,
|
|
296
|
+
handleTemplate(msg, node, fs.readFileSync(packageJsonPath, 'utf8')).then((c) => { content["pkjs"] = c }),
|
|
297
|
+
handleTemplate(msg, node, fs.readFileSync(readmePath, 'utf8')).then((c) => { content["rdme"] = c }),
|
|
298
|
+
handleTemplate(msg, node, fs.readFileSync(licensePath, 'utf8')).then((c) => { content["lcns"] = c }),
|
|
224
299
|
];
|
|
225
300
|
|
|
226
301
|
return Promise.all(promises).then( () => {
|
|
@@ -284,43 +359,15 @@ module.exports = function (RED) {
|
|
|
284
359
|
});
|
|
285
360
|
|
|
286
361
|
node.on("input", function (msg, send, done) {
|
|
362
|
+
send({ payload: msg.node })
|
|
363
|
+
|
|
287
364
|
if (msg.node && msg.node.__task == "generate_from_templates") {
|
|
288
365
|
try {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
handleTemplate(msg, node, jsonTmpl).then(function (data) {
|
|
296
|
-
var jsData = data;
|
|
297
|
-
|
|
298
|
-
handleTemplate(msg, node, htmlTmpl).then(function (data) {
|
|
299
|
-
var nodeDef = convertToPkgFileNodes(msg, jsData, data)
|
|
300
|
-
|
|
301
|
-
if (msg.node.createmanifest ) {
|
|
302
|
-
/* create the package.json, readme and license files */
|
|
303
|
-
createManifestFiles(msg, node, nodeDef).then( (data) => {
|
|
304
|
-
var nodeImpStr = JSON.stringify(data);
|
|
305
|
-
|
|
306
|
-
send({ payload: nodeImpStr })
|
|
307
|
-
|
|
308
|
-
RED.comms.publish(
|
|
309
|
-
"nodedev:perform-autoimport-nodes",
|
|
310
|
-
RED.util.encodeObject({
|
|
311
|
-
msg: "autoimport",
|
|
312
|
-
payload: nodeImpStr,
|
|
313
|
-
topic: msg.topic,
|
|
314
|
-
nodeid: node.id,
|
|
315
|
-
_msg: msg
|
|
316
|
-
})
|
|
317
|
-
);
|
|
318
|
-
}).catch( (err) => {
|
|
319
|
-
msg.error = err
|
|
320
|
-
done(err.message, msg)
|
|
321
|
-
})
|
|
322
|
-
} else {
|
|
323
|
-
var nodeImpStr = JSON.stringify(nodeDef);
|
|
366
|
+
createNodeDefintions(msg,node).then( (nodeDef) => {
|
|
367
|
+
if (msg.node.createmanifest ) {
|
|
368
|
+
/* create the package.json, readme and license files */
|
|
369
|
+
createManifestFiles(msg, node, nodeDef).then( (data) => {
|
|
370
|
+
var nodeImpStr = JSON.stringify(data);
|
|
324
371
|
|
|
325
372
|
send({ payload: nodeImpStr })
|
|
326
373
|
|
|
@@ -334,17 +381,31 @@ module.exports = function (RED) {
|
|
|
334
381
|
_msg: msg
|
|
335
382
|
})
|
|
336
383
|
);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
384
|
+
}).catch( (err) => {
|
|
385
|
+
msg.error = err
|
|
386
|
+
done(err.message, msg)
|
|
387
|
+
})
|
|
388
|
+
} else {
|
|
389
|
+
var nodeImpStr = JSON.stringify(nodeDef);
|
|
390
|
+
|
|
391
|
+
send({ payload: nodeImpStr })
|
|
392
|
+
|
|
393
|
+
RED.comms.publish(
|
|
394
|
+
"nodedev:perform-autoimport-nodes",
|
|
395
|
+
RED.util.encodeObject({
|
|
396
|
+
msg: "autoimport",
|
|
397
|
+
payload: nodeImpStr,
|
|
398
|
+
topic: msg.topic,
|
|
399
|
+
nodeid: node.id,
|
|
400
|
+
_msg: msg
|
|
401
|
+
})
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
done()
|
|
343
405
|
}).catch((err) => {
|
|
344
406
|
msg.error = err
|
|
345
407
|
done(err.message, msg)
|
|
346
408
|
})
|
|
347
|
-
//send({ payload: jsonString })
|
|
348
409
|
} catch (err) {
|
|
349
410
|
msg.error = err
|
|
350
411
|
done(err.message, msg)
|
package/nodes/templates/tmpl.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = function(RED) {
|
|
2
|
-
function {{ node.name }}Functionality(config) {
|
|
2
|
+
function Core{{ node.name }}Functionality(config) {
|
|
3
3
|
RED.nodes.createNode(this,config);
|
|
4
4
|
|
|
5
5
|
var node = this;
|
|
@@ -24,7 +24,7 @@ module.exports = function(RED) {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
RED.nodes.registerType("{{ node.name }}", {{ node.name }}Functionality);
|
|
27
|
+
RED.nodes.registerType("{{ node.name }}", Core{{ node.name }}Functionality);
|
|
28
28
|
|
|
29
29
|
{{ #node.frt2bakcomm }}
|
|
30
30
|
RED.httpAdmin.post("/{{ node.name }}/:id",
|
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name" : "{{__.ocb3}} pname {{__.ccb3}}",
|
|
3
|
-
"version": "{{__.
|
|
3
|
+
"version": "{{__.ocb3}} pversion {{__.ccb3}}",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
},
|
|
6
6
|
|
|
7
|
+
"description": "{{__.ocb3}} pdescription {{__.ccb3}}",
|
|
7
8
|
"keywords": [
|
|
8
9
|
"node-red"
|
|
9
10
|
],
|
|
10
11
|
|
|
11
|
-
"homepage": "https://github.com/{{__.ocb2}} githubowner {{__.ccb2}}/{{__.ocb2}} githubrepo {{__.ccb2}}#readme",
|
|
12
12
|
"license": "Don't do evil.",
|
|
13
|
-
"
|
|
13
|
+
"homepage": "https://github.com/{{__.ocb2}} githubowner {{__.ccb2}}/{{__.ocb2}} githubrepo {{__.ccb2}}#readme",
|
|
14
|
+
"author": "{{__.ocb3}} pauthorname {{__.ccb3}} <{{__.ocb3}} pauthoremail {{__.ccb3}}>",
|
|
14
15
|
"engines": {
|
|
15
16
|
"node": ">=14"
|
|
16
17
|
},
|
|
17
18
|
|
|
18
19
|
"node-red" : {
|
|
19
20
|
"version": ">=3.0.0",
|
|
21
|
+
{{#node.isplugin}}
|
|
22
|
+
"plugins": {
|
|
23
|
+
{{{__.pluginstanza}}}
|
|
24
|
+
},
|
|
25
|
+
{{/node.isplugin}}
|
|
20
26
|
"nodes": {
|
|
21
27
|
{{{__.nodestanza}}}
|
|
22
28
|
}
|
|
23
29
|
},
|
|
24
30
|
|
|
25
|
-
"description": "Description of what these nodes do.",
|
|
26
31
|
"repository": {
|
|
27
32
|
"type": "github",
|
|
28
33
|
"url": "git+https://github.com/{{__.ocb2}} githubowner {{__.ccb2}}/{{__.ocb2}} githubrepo {{__.ccb2}}.git"
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
(function() {
|
|
3
|
+
var globalYourConfigNode = null;
|
|
4
|
+
|
|
5
|
+
function ensureYourConfigNodeExists() {
|
|
6
|
+
// This function makes sure there is 1 instance of your config node is available, and that the globalYourConfigNode variable refers to it.
|
|
7
|
+
// Explained in the next step of this tutorial... --> https://discourse.nodered.org/t/tutorial-create-a-sidebar-plugin-and-persist-the-data-in-a-config-node/82020
|
|
8
|
+
|
|
9
|
+
// If we had found it previously, check if it has been deleted by the user behind our back
|
|
10
|
+
if (globalYourConfigNode !== null) {
|
|
11
|
+
var configNode = RED.nodes.node(globalYourConfigNode.id);
|
|
12
|
+
if (configNode === null) { globalYourConfigNode = null; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// If not found previously, let's go find it
|
|
16
|
+
if (globalYourConfigNode === null) {
|
|
17
|
+
var configNodes = [];
|
|
18
|
+
RED.nodes.eachConfig(function(configNode) {
|
|
19
|
+
if (configNode.type === '{{ node.name }}') {
|
|
20
|
+
configNodes.push(configNode);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Make sure we only have 1 config node
|
|
25
|
+
while (configNodes.length > 1) {
|
|
26
|
+
var configNode = configNodes.pop();
|
|
27
|
+
RED.nodes.remove(configNode.id);
|
|
28
|
+
RED.nodes.dirty(true);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// When we found a config node, let's use that one
|
|
32
|
+
if (configNodes.length === 1) { globalYourConfigNode = configNodes[0]; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// When it doesn't exist yet, create it if required
|
|
36
|
+
if (globalYourConfigNode === null) {
|
|
37
|
+
// Remark: since this config node is dynamically created (and only used in this sidebar which isn't another node), the config
|
|
38
|
+
// node is in fact "unused". But since we don't want it to appear "unused" in the "config nodes" panel, we need to set hasUsers
|
|
39
|
+
// to false (see https://github.com/node-red/node-red/blob/master/CHANGELOG.md#0161-maintenance-release).
|
|
40
|
+
// The hasUsers needs also to be specified in the RED.nodes.registerType statement!
|
|
41
|
+
globalYourConfigNode = {
|
|
42
|
+
id: RED.nodes.id(), // on the server side, this is called RED.util.generateId()
|
|
43
|
+
_def: RED.nodes.getType("{{ node.name }}Cfg"),
|
|
44
|
+
type: "{{ node.name }}Cfg",
|
|
45
|
+
hasUsers: false,
|
|
46
|
+
users: [],
|
|
47
|
+
name: "{{ node.name }}",
|
|
48
|
+
label: function() { return this.name || "{{ node.name }}"},
|
|
49
|
+
/* values and data defined by this config node */
|
|
50
|
+
data: "some default value", // Default data
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Add the new config node to the collection of Node-RED nodes
|
|
54
|
+
RED.nodes.add(globalYourConfigNode);
|
|
55
|
+
|
|
56
|
+
// Make sure the "Deploy" button becomes active
|
|
57
|
+
RED.nodes.dirty(true);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add your plugin as a new tabsheet in the right sidebar AFTER the flow editor is completely started
|
|
62
|
+
var initialiseConfigNodeOnce = () => {
|
|
63
|
+
RED.events.off('runtime-state', initialiseConfigNodeOnce);
|
|
64
|
+
|
|
65
|
+
// The html content of the sidebar has been specified below as a data-template, from where it can be loaded:
|
|
66
|
+
var content = $($('script[type="text/x-red"][data-template-name="{{ node.name }}"]').i18n().html());
|
|
67
|
+
|
|
68
|
+
// Add a "Your sidebar" tabsheet to the right sidebar panel, in which this sidebar panel can be displayed
|
|
69
|
+
// --> more details: https://nodered.org/docs/api/ui/sidebar/
|
|
70
|
+
RED.sidebar.addTab({
|
|
71
|
+
id: "{{ node.name }}",
|
|
72
|
+
label: "{{ node.namelwr }}", // short name for the tab
|
|
73
|
+
name: "{{ node.name }}", // long name for the menu
|
|
74
|
+
content: content,
|
|
75
|
+
closeable: true,
|
|
76
|
+
// disableOnEdit: true,
|
|
77
|
+
enableOnEdit: true,
|
|
78
|
+
iconClass: "{{{ node.iconclass }}}" // your fontawesome icon
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
ensureYourConfigNodeExists();
|
|
82
|
+
|
|
83
|
+
{{#node.hasbutton}}
|
|
84
|
+
var doSomething = (e) => {
|
|
85
|
+
if (e) { e.preventDefault(); }
|
|
86
|
+
RED.notify("Button pressed in the side or action "+
|
|
87
|
+
"triggered. Current value: <b>" + globalYourConfigNode.data + "</b>",
|
|
88
|
+
"success");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
$('#node-input-button').on('click', (e) => {
|
|
92
|
+
doSomething(e);
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
/* name of action will become "My Sidebar Action", label is generated
|
|
96
|
+
from action name - see https://nodered.org/docs/api/ui/actions/ */
|
|
97
|
+
RED.actions.add("{{ node.namelwr }}:my-sidebar-action",function() {
|
|
98
|
+
doSomething();
|
|
99
|
+
});
|
|
100
|
+
{{/node.hasbutton}}
|
|
101
|
+
|
|
102
|
+
// At startup load your config node data into the plugin sidebar html elements
|
|
103
|
+
$("#node-input-data").val(globalYourConfigNode.data);
|
|
104
|
+
|
|
105
|
+
// When the user has entered new data in the sidebar, then store it into the config node
|
|
106
|
+
$("#node-input-data").on("change", function() {
|
|
107
|
+
ensureYourConfigNodeExists();
|
|
108
|
+
|
|
109
|
+
let data = $(this).val();
|
|
110
|
+
|
|
111
|
+
if (globalYourConfigNode.data != data) {
|
|
112
|
+
globalYourConfigNode.data = data;
|
|
113
|
+
// Since the config node has been updated, the 'Deploy' button should become active
|
|
114
|
+
RED.nodes.dirty(true);
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
};
|
|
118
|
+
RED.events.on('runtime-state', initialiseConfigNodeOnce);
|
|
119
|
+
})();
|
|
120
|
+
</script>
|
|
121
|
+
|
|
122
|
+
<!-- The html for the right sidebar plugin screen -->
|
|
123
|
+
<script type="text/x-red" data-template-name="{{ node.name }}">
|
|
124
|
+
<div class="form-row">
|
|
125
|
+
<div style="position: relative; height: 100%; margin: 15px;">
|
|
126
|
+
<label for="node-input-data" style="margin-top: 15px"><i class="fa fa-cog"></i> Data</label>
|
|
127
|
+
<input type="text" id="node-input-data" style="width: 100%; margin-top: 30px">
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
{{#node.hasbutton}}
|
|
132
|
+
<div class="form-row">
|
|
133
|
+
<div style="position: relative; height: 100%; margin: 15px;">
|
|
134
|
+
<button id="node-input-button" class="success" style="width: 100%; margin-top: 30px">Do something</button>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
{{/node.hasbutton}}
|
|
138
|
+
</script>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
(function ($) {
|
|
3
|
+
RED.nodes.registerType('{{ node.name }}Cfg', {
|
|
4
|
+
category: 'config',
|
|
5
|
+
hasUsers: false,
|
|
6
|
+
defaults: {
|
|
7
|
+
name: { value: "" },
|
|
8
|
+
data: { value: "" }
|
|
9
|
+
},
|
|
10
|
+
paletteLabel: '{{ node.name }}Cfg',
|
|
11
|
+
label: function () {
|
|
12
|
+
return this.name;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
})(jQuery);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<!-- The html for the config node info panel (in right sidebar) -->
|
|
19
|
+
<script type="text/x-red" data-template-name="{{ node.name }}Cfg">
|
|
20
|
+
<p>{{{ node.summary }}}</p>
|
|
21
|
+
{{{ node.description }}}
|
|
22
|
+
</script>
|