@flowfuse/nr-mqtt-nodes 0.1.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/.eslintrc +21 -0
- package/.github/dependabot.yml +15 -0
- package/.github/workflows/project-automation.yml +10 -0
- package/.github/workflows/publish.yml +51 -0
- package/.github/workflows/release-publish.yml +21 -0
- package/CHANGELOG.md +3 -0
- package/LICENSE +178 -0
- package/README.md +29 -0
- package/nodes/ff-mqtt.html +488 -0
- package/nodes/ff-mqtt.js +1826 -0
- package/nodes/icons/ff-logo.svg +6 -0
- package/nodes/lib/TeamBrokerApi.js +83 -0
- package/nodes/lib/proxyHelper.js +301 -0
- package/nodes/lib/util.js +112 -0
- package/nodes/locales/en-US/ff-mqtt.html +121 -0
- package/nodes/locales/en-US/ff-mqtt.json +136 -0
- package/npmignore +5 -0
- package/package.json +54 -0
- package/test/unit/ff-mqtt_spec.js +920 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
This is a fork of the MQTT nodes from Node-RED.
|
|
3
|
+
The original code can be found at:
|
|
4
|
+
https://github.com/node-red/node-red/blob/b428e24ea51e00e2260739987dfab74872765a9f/packages/node_modules/@node-red/nodes/core/network/21-httpin.html
|
|
5
|
+
Below is the copyright notice for the original code.
|
|
6
|
+
The copyright notice for this fork is the same as the original.
|
|
7
|
+
### Changes:
|
|
8
|
+
- Hide advanced features
|
|
9
|
+
- Remove the config node for MQTT broker
|
|
10
|
+
- Remove the dynamic connection control
|
|
11
|
+
- lint errors fixed up
|
|
12
|
+
-->
|
|
13
|
+
<!--
|
|
14
|
+
Copyright JS Foundation and other contributors, http://js.foundation
|
|
15
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
16
|
+
you may not use this file except in compliance with the License.
|
|
17
|
+
You may obtain a copy of the License at
|
|
18
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
Unless required by applicable law or agreed to in writing, software
|
|
20
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
21
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
22
|
+
See the License for the specific language governing permissions and
|
|
23
|
+
limitations under the License.
|
|
24
|
+
-->
|
|
25
|
+
<style>
|
|
26
|
+
|
|
27
|
+
.mqtt-form-row-cols2 > input.mqtt-form-row-col1 {
|
|
28
|
+
width: calc(35% - 75px);
|
|
29
|
+
}
|
|
30
|
+
.mqtt-form-row-cols2 > select.mqtt-form-row-col1 {
|
|
31
|
+
width: calc(35% - 75px);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.mqtt-form-row-cols2 > label.mqtt-form-row-col2 {
|
|
35
|
+
width: 100px;
|
|
36
|
+
margin-left: 42px;
|
|
37
|
+
display: inline-block;
|
|
38
|
+
}
|
|
39
|
+
.mqtt-form-row-cols2 > input.mqtt-form-row-col2 {
|
|
40
|
+
width: calc(35% - 75px);
|
|
41
|
+
display: inline-block;
|
|
42
|
+
}
|
|
43
|
+
.mqtt-form-row-cols2 > select.mqtt-form-row-col2 {
|
|
44
|
+
width: calc(35% - 75px);
|
|
45
|
+
display: inline-block;
|
|
46
|
+
}
|
|
47
|
+
.form-row.mqtt5-out > label {
|
|
48
|
+
width: 130px;
|
|
49
|
+
}
|
|
50
|
+
.form-row.mqtt-flags-row > label {
|
|
51
|
+
vertical-align: top;
|
|
52
|
+
}
|
|
53
|
+
.form-row.mqtt-flags-row > .mqtt-flags {
|
|
54
|
+
display: inline-block;
|
|
55
|
+
width: 70%
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label {
|
|
59
|
+
display: block;
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
.form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label > input {
|
|
63
|
+
position: relative;
|
|
64
|
+
vertical-align: bottom;
|
|
65
|
+
top: -2px;
|
|
66
|
+
width: 15px;
|
|
67
|
+
height: 15px;
|
|
68
|
+
}
|
|
69
|
+
.form-row-mqtt5 {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
.form-row-mqtt5.form-row-mqtt5-active:not(.form-row-mqtt-static-disabled) {
|
|
73
|
+
display: block
|
|
74
|
+
}
|
|
75
|
+
.form-row-mqtt-static-disabled {
|
|
76
|
+
display: none;
|
|
77
|
+
/* opacity: 0.3;
|
|
78
|
+
pointer-events: none; */
|
|
79
|
+
}
|
|
80
|
+
.form-row.form-row-mqtt-datatype-tip > .form-tips {
|
|
81
|
+
width: calc(70% - 18px);
|
|
82
|
+
display: inline-block;
|
|
83
|
+
margin-top: -8px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Hide advanced options in initial offering */
|
|
87
|
+
.form-row.ff-no-use {
|
|
88
|
+
display: none !important;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
</style>
|
|
92
|
+
|
|
93
|
+
<script type="text/html" data-template-name="ff-mqtt-in">
|
|
94
|
+
<div class="form-row" id="ff-mqtt-client-link-feature-disabled" style="color: var(--red-ui-text-color-error);">
|
|
95
|
+
<label><i class="fa fa-warning"></i> <span></span></label>
|
|
96
|
+
<span data-i18n="ff-mqtt.label.featureDisabled"></span>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="form-row">
|
|
99
|
+
<label><i class="fa fa-globe"></i> <span data-i18n="ff-mqtt.label.broker"></span></label>
|
|
100
|
+
<span class="red-ui-help">
|
|
101
|
+
<a href="#" class="red-ui-link" id="ff-mqtt-client-link" target="_blank">
|
|
102
|
+
<span>Configure Access Control </span><i class="fa fa-external-link"></i>
|
|
103
|
+
</a>
|
|
104
|
+
</span>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="form-row">
|
|
107
|
+
<label for="node-input-topicType" data-i18n="ff-mqtt.label.action"></label>
|
|
108
|
+
<select id="node-input-topicType" style="width: 70%">
|
|
109
|
+
<option value="topic" data-i18n="ff-mqtt.label.staticTopic"></option>
|
|
110
|
+
<option value="dynamic" data-i18n="ff-mqtt.label.dynamicTopic"></option>
|
|
111
|
+
</select>
|
|
112
|
+
<input type="hidden" id="node-input-inputs">
|
|
113
|
+
</div>
|
|
114
|
+
<div class="form-row form-row-mqtt-static">
|
|
115
|
+
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
|
116
|
+
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
|
|
117
|
+
</div>
|
|
118
|
+
<div class="form-row form-row-mqtt-static">
|
|
119
|
+
<label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="ff-mqtt.label.qos"></span></label>
|
|
120
|
+
<select id="node-input-qos" style="width:125px !important">
|
|
121
|
+
<option value="0">0</option>
|
|
122
|
+
<option value="1">1</option>
|
|
123
|
+
<option value="2">2</option>
|
|
124
|
+
</select>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="form-row mqtt-flags-row form-row-mqtt5 form-row-mqtt-static ff-no-use">
|
|
127
|
+
<label for="node-input-nl" ><i class="fa fa-flag"></i> <span data-i18n="ff-mqtt.label.flags">Flags</span></label>
|
|
128
|
+
<div class="mqtt-flags">
|
|
129
|
+
<div class="mqtt-flag">
|
|
130
|
+
<label for="node-input-nl">
|
|
131
|
+
<input type="checkbox" id="node-input-nl">
|
|
132
|
+
<span data-i18n="ff-mqtt.label.nl"></span>
|
|
133
|
+
</label>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="mqtt-flag">
|
|
136
|
+
<label for="node-input-rap">
|
|
137
|
+
<input type="checkbox" id="node-input-rap">
|
|
138
|
+
<span data-i18n="ff-mqtt.label.rap"></span>
|
|
139
|
+
</label>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
<div class="form-row form-row-mqtt5 form-row-mqtt-static ff-no-use">
|
|
144
|
+
<label for="node-input-rh" style="width:100%"><i class="fa fa-tag"></i> <span data-i18n="ff-mqtt.label.rh"></span></label>
|
|
145
|
+
<select id="node-input-rh" style="margin-left: 104px; width: 70%">
|
|
146
|
+
<option value="0" data-i18n="ff-mqtt.label.rh0"></option>
|
|
147
|
+
<option value="1" data-i18n="ff-mqtt.label.rh1"></option>
|
|
148
|
+
<option value="2" data-i18n="ff-mqtt.label.rh2"></option>
|
|
149
|
+
</select>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="form-row">
|
|
152
|
+
<label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="ff-mqtt.label.output"></span></label>
|
|
153
|
+
<select id="node-input-datatype" style="width:70%;">
|
|
154
|
+
<option value="auto-detect" data-i18n="ff-mqtt.output.auto-detect"></option>
|
|
155
|
+
<option value="buffer" data-i18n="ff-mqtt.output.buffer"></option>
|
|
156
|
+
<option value="utf8" data-i18n="ff-mqtt.output.string"></option>
|
|
157
|
+
<option value="json" data-i18n="ff-mqtt.output.json"></option>
|
|
158
|
+
<option value="base64" data-i18n="ff-mqtt.output.base64"></option>
|
|
159
|
+
</select>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="form-row">
|
|
162
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
|
163
|
+
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
|
164
|
+
</div>
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<script type="text/html" data-template-name="ff-mqtt-out">
|
|
168
|
+
<div class="form-row" id="ff-mqtt-client-link-feature-disabled" style="color: var(--red-ui-text-color-error);">
|
|
169
|
+
<label><i class="fa fa-warning"></i> <span></span></label>
|
|
170
|
+
<span data-i18n="ff-mqtt.label.featureDisabled"></span>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="form-row">
|
|
173
|
+
<label><i class="fa fa-globe"></i> <span data-i18n="ff-mqtt.label.broker"></span></label>
|
|
174
|
+
<span class="red-ui-help">
|
|
175
|
+
<a href="#" class="red-ui-link" id="ff-mqtt-client-link" target="_blank">
|
|
176
|
+
<span>Configure Access Control </span><i class="fa fa-external-link"></i>
|
|
177
|
+
</a>
|
|
178
|
+
</span>
|
|
179
|
+
</div>
|
|
180
|
+
<div class="form-row">
|
|
181
|
+
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
|
|
182
|
+
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<div class="form-row mqtt-form-row-cols2">
|
|
186
|
+
<label for="node-input-qos" class="mqtt-form-row-col1"><i class="fa fa-empire"></i> <span data-i18n="ff-mqtt.label.qos"></span></label>
|
|
187
|
+
<select id="node-input-qos" class="mqtt-form-row-col1">
|
|
188
|
+
<option value=""></option>
|
|
189
|
+
<option value="0">0</option>
|
|
190
|
+
<option value="1">1</option>
|
|
191
|
+
<option value="2">2</option>
|
|
192
|
+
</select>
|
|
193
|
+
|
|
194
|
+
<label for="node-input-retain" class="mqtt-form-row-col2"><i class="fa fa-history"></i> <span data-i18n="ff-mqtt.retain"></span></label>
|
|
195
|
+
<select id="node-input-retain" class="mqtt-form-row-col2" >
|
|
196
|
+
<option value=""></option>
|
|
197
|
+
<option value="false" data-i18n="ff-mqtt.false"></option>
|
|
198
|
+
<option value="true" data-i18n="ff-mqtt.true"></option>
|
|
199
|
+
</select>
|
|
200
|
+
</div>
|
|
201
|
+
<div class="form-row mqtt5 mqtt5-out ff-no-use">
|
|
202
|
+
<label for="node-input-userProps"><span data-i18n="ff-mqtt.label.userProperties"></span></label>
|
|
203
|
+
<input type="text" id="node-input-userProps" style="width: calc(100% - 166px);">
|
|
204
|
+
</div>
|
|
205
|
+
<div class="form-row mqtt5 mqtt5-out ff-no-use">
|
|
206
|
+
<label for="node-input-respTopic"><span data-i18n="ff-mqtt.label.responseTopic"></span></label>
|
|
207
|
+
<input type="text" id="node-input-respTopic" style="width: calc(100% - 166px);">
|
|
208
|
+
</div>
|
|
209
|
+
<div class="form-row mqtt5 mqtt5-out ff-no-use">
|
|
210
|
+
<label for="node-input-correl"><span data-i18n="ff-mqtt.label.correlationData"></span></label>
|
|
211
|
+
<input type="text" id="node-input-correl" style="width: calc(100% - 166px);">
|
|
212
|
+
</div>
|
|
213
|
+
<div class="form-row mqtt5 mqtt5-out ff-no-use">
|
|
214
|
+
<label for="node-input-contentType"><span data-i18n="ff-mqtt.label.contentType"></span></label>
|
|
215
|
+
<input type="text" id="node-input-contentType" style="width: calc(100% - 166px);">
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="form-row mqtt-form-row-cols2 mqtt5 mqtt5-out ff-no-use">
|
|
219
|
+
<label for="node-input-expiry" class="mqtt-form-row-col1"><span data-i18n="ff-mqtt.label.expiry"></span></label>
|
|
220
|
+
<input id="node-input-expiry" style="width: calc(100% - 166px);" class="mqtt-form-row-col1" >
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div class="form-row">
|
|
224
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
|
225
|
+
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
|
|
226
|
+
</div>
|
|
227
|
+
<div class="form-tips"><span data-i18n="ff-mqtt.tip"></span></div>
|
|
228
|
+
</script>
|
|
229
|
+
|
|
230
|
+
<script type="text/javascript">
|
|
231
|
+
/* global RED, $ */
|
|
232
|
+
(function () {
|
|
233
|
+
const typedInputNoneOpt = {
|
|
234
|
+
value: 'none',
|
|
235
|
+
label: RED._('ff-mqtt.label.none'),
|
|
236
|
+
hasValue: false
|
|
237
|
+
}
|
|
238
|
+
const makeTypedInputOpt = function (value) {
|
|
239
|
+
return {
|
|
240
|
+
value,
|
|
241
|
+
label: value,
|
|
242
|
+
hasValue: false
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const contentTypeOpts = [
|
|
246
|
+
typedInputNoneOpt,
|
|
247
|
+
makeTypedInputOpt('application/json'),
|
|
248
|
+
makeTypedInputOpt('application/octet-stream'),
|
|
249
|
+
makeTypedInputOpt('text/csv'),
|
|
250
|
+
makeTypedInputOpt('text/html'),
|
|
251
|
+
makeTypedInputOpt('text/plain'),
|
|
252
|
+
{
|
|
253
|
+
value: 'other',
|
|
254
|
+
label: RED._('ff-mqtt.label.other'),
|
|
255
|
+
icon: 'red/images/typedInput/az.svg'
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
function getDefaultContentType (value) {
|
|
260
|
+
let defaultContentType
|
|
261
|
+
const matchedContentType = contentTypeOpts.filter(function (v) {
|
|
262
|
+
return v.value === value
|
|
263
|
+
})
|
|
264
|
+
if (matchedContentType.length > 0) {
|
|
265
|
+
defaultContentType = matchedContentType[0].value
|
|
266
|
+
}
|
|
267
|
+
if (value && !defaultContentType) {
|
|
268
|
+
defaultContentType = 'other'
|
|
269
|
+
}
|
|
270
|
+
return defaultContentType || 'none'
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Test a topic string is valid for publishing
|
|
274
|
+
* @param {string} topic
|
|
275
|
+
* @returns `true` if it is a valid topic
|
|
276
|
+
*/
|
|
277
|
+
function validateMQTTPublishTopic (topic, opts) {
|
|
278
|
+
if (!topic || topic === '' || !/[\\+#\b\f\n\r\t\v\0]/.test(topic)) {
|
|
279
|
+
return true
|
|
280
|
+
}
|
|
281
|
+
return RED._('ff-mqtt.errors.invalid-topic')
|
|
282
|
+
}
|
|
283
|
+
function setupTopicField (node, input) {
|
|
284
|
+
input.autoComplete({
|
|
285
|
+
minLength: 0,
|
|
286
|
+
completionPluginType: 'node-red-mqtt-topic-autocomplete-source',
|
|
287
|
+
context: {
|
|
288
|
+
node
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
RED.nodes.registerType('ff-mqtt-in', {
|
|
293
|
+
category: 'FlowFuse',
|
|
294
|
+
defaults: {
|
|
295
|
+
name: { value: '' },
|
|
296
|
+
topic: {
|
|
297
|
+
value: '',
|
|
298
|
+
validate: function (v, opt) {
|
|
299
|
+
let isDynamic = this.inputs === 1
|
|
300
|
+
const topicTypeSelect = $('#node-input-topicType')
|
|
301
|
+
if (topicTypeSelect.length) {
|
|
302
|
+
isDynamic = topicTypeSelect.val() === 'dynamic'
|
|
303
|
+
}
|
|
304
|
+
if (isDynamic || ((!!v) && RED.validators.regex(/^(#$|(\\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)(v))) {
|
|
305
|
+
return true
|
|
306
|
+
}
|
|
307
|
+
return RED._('ff-mqtt.errors.invalid-topic')
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
qos: { value: '2' },
|
|
311
|
+
datatype: { value: 'auto-detect', required: true },
|
|
312
|
+
nl: { value: false },
|
|
313
|
+
rap: { value: true },
|
|
314
|
+
rh: { value: 0 },
|
|
315
|
+
inputs: { value: 0 }
|
|
316
|
+
},
|
|
317
|
+
color: '#d8bfd8',
|
|
318
|
+
inputs: 0,
|
|
319
|
+
outputs: 1,
|
|
320
|
+
icon: 'ff-logo.svg',
|
|
321
|
+
paletteLabel: 'ff mqtt in',
|
|
322
|
+
label: function () {
|
|
323
|
+
let label = 'ff mqtt in'
|
|
324
|
+
if (this.topicType !== 'dynamic' && this.topic) {
|
|
325
|
+
label = this.topic
|
|
326
|
+
}
|
|
327
|
+
return this.name || label
|
|
328
|
+
},
|
|
329
|
+
labelStyle: function () {
|
|
330
|
+
return this.name ? 'node_label_italic' : ''
|
|
331
|
+
},
|
|
332
|
+
oneditprepare: function () {
|
|
333
|
+
const node = this
|
|
334
|
+
|
|
335
|
+
const forgeUrl = RED.settings.ffMqttInUserTeamBrokerClientUrl || RED.settings.ffMqttInForgeUrl || ''
|
|
336
|
+
$('#ff-mqtt-client-link').attr('href', forgeUrl)
|
|
337
|
+
const featureEnabled = RED.settings.ffMqttInFeatureEnabled !== false || RED.settings.ffMqttOutFeatureEnabled !== false
|
|
338
|
+
if (featureEnabled === false) {
|
|
339
|
+
$('#ff-mqtt-client-link-feature-disabled').show()
|
|
340
|
+
} else {
|
|
341
|
+
$('#ff-mqtt-client-link-feature-disabled').hide()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
setupTopicField(node, $('#node-input-topic'))
|
|
345
|
+
const isV5Broker = function () {
|
|
346
|
+
// const confNode = RED.nodes.node($('#node-input-broker').val())
|
|
347
|
+
// return confNode && confNode.protocolVersion === '5'
|
|
348
|
+
return true
|
|
349
|
+
}
|
|
350
|
+
const isDynamic = function () {
|
|
351
|
+
return $('#node-input-topicType').val() === 'dynamic'
|
|
352
|
+
}
|
|
353
|
+
const updateVisibility = function () {
|
|
354
|
+
const v5 = isV5Broker()
|
|
355
|
+
const dynamic = isDynamic()
|
|
356
|
+
$('div.form-row-mqtt5').toggleClass('form-row-mqtt5-active', !!v5)
|
|
357
|
+
$('div.form-row.form-row-mqtt-static').toggleClass('form-row-mqtt-static-disabled', !!dynamic)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// $('#node-input-broker').on('change', function (d) {
|
|
361
|
+
// updateVisibility()
|
|
362
|
+
// })
|
|
363
|
+
|
|
364
|
+
$('#node-input-topicType').on('change', function () {
|
|
365
|
+
$('#node-input-inputs').val(isDynamic() ? 1 : 0)
|
|
366
|
+
updateVisibility()
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
if (node.inputs === 1) {
|
|
370
|
+
$('#node-input-topicType').val('dynamic')
|
|
371
|
+
} else {
|
|
372
|
+
$('#node-input-topicType').val('topic')
|
|
373
|
+
}
|
|
374
|
+
$('#node-input-topicType').trigger('change')
|
|
375
|
+
|
|
376
|
+
if (node.qos === undefined) {
|
|
377
|
+
$('#node-input-qos').val('2')
|
|
378
|
+
}
|
|
379
|
+
if (node.datatype === undefined) {
|
|
380
|
+
$('#node-input-datatype').val('auto-detect')
|
|
381
|
+
}
|
|
382
|
+
updateVisibility()
|
|
383
|
+
},
|
|
384
|
+
oneditsave: function () {
|
|
385
|
+
if ($('#node-input-topicType').val() === 'dynamic') {
|
|
386
|
+
$('#node-input-topic').val('')
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
RED.nodes.registerType('ff-mqtt-out', {
|
|
392
|
+
category: 'FlowFuse',
|
|
393
|
+
defaults: {
|
|
394
|
+
name: { value: '' },
|
|
395
|
+
topic: { value: '', validate: validateMQTTPublishTopic },
|
|
396
|
+
qos: { value: '' },
|
|
397
|
+
retain: { value: '' },
|
|
398
|
+
respTopic: { value: '' },
|
|
399
|
+
contentType: { value: '' },
|
|
400
|
+
userProps: { value: '' },
|
|
401
|
+
correl: { value: '' },
|
|
402
|
+
expiry: { value: '' }
|
|
403
|
+
},
|
|
404
|
+
color: '#d8bfd8',
|
|
405
|
+
inputs: 1,
|
|
406
|
+
outputs: 0,
|
|
407
|
+
icon: 'ff-logo.svg',
|
|
408
|
+
paletteLabel: 'ff mqtt out',
|
|
409
|
+
align: 'right',
|
|
410
|
+
label: function () {
|
|
411
|
+
return this.name || this.topic || 'ff mqtt out'
|
|
412
|
+
},
|
|
413
|
+
oneditprepare: function () {
|
|
414
|
+
const that = this
|
|
415
|
+
const forgeUrl = RED.settings.ffMqttOutUserTeamBrokerClientUrl || RED.settings.ffMqttOutForgeUrl || ''
|
|
416
|
+
$('#ff-mqtt-client-link').attr('href', forgeUrl)
|
|
417
|
+
const featureEnabled = RED.settings.ffMqttInFeatureEnabled !== false || RED.settings.ffMqttOutFeatureEnabled !== false
|
|
418
|
+
if (featureEnabled === false) {
|
|
419
|
+
$('#ff-mqtt-client-link-feature-disabled').show()
|
|
420
|
+
} else {
|
|
421
|
+
$('#ff-mqtt-client-link-feature-disabled').hide()
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
setupTopicField(that, $('#node-input-topic'))
|
|
425
|
+
|
|
426
|
+
function showHideDynamicFields () {
|
|
427
|
+
const confNode = RED.nodes.node($('#node-input-broker').val())
|
|
428
|
+
const v5 = confNode && confNode.protocolVersion === '5'
|
|
429
|
+
if (v5) {
|
|
430
|
+
$('div.form-row.mqtt5').show()
|
|
431
|
+
const t = $('#node-input-respTopic').typedInput('type')
|
|
432
|
+
if (t === 'none') {
|
|
433
|
+
$('#node-input-correl').parent().hide()
|
|
434
|
+
} else {
|
|
435
|
+
$('#node-input-correl').parent().show()
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
$('div.form-row.mqtt5').hide()
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// $('#node-input-broker').on('change', function (d) {
|
|
443
|
+
showHideDynamicFields()
|
|
444
|
+
// })
|
|
445
|
+
|
|
446
|
+
const respTopicTI = $('#node-input-respTopic').typedInput({
|
|
447
|
+
default: !this.respTopic ? 'none' : 'str',
|
|
448
|
+
types: [typedInputNoneOpt, 'str']
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
$('#node-input-correl').typedInput({
|
|
452
|
+
default: !this.correl ? 'none' : 'str',
|
|
453
|
+
types: [typedInputNoneOpt, 'str']
|
|
454
|
+
})
|
|
455
|
+
// show / hide correlation data depending on respTopic
|
|
456
|
+
respTopicTI.on('change', showHideDynamicFields)
|
|
457
|
+
respTopicTI.triggerHandler('change')
|
|
458
|
+
|
|
459
|
+
$('#node-input-userProps').typedInput({
|
|
460
|
+
default: !this.userProps ? 'none' : 'json',
|
|
461
|
+
types: [typedInputNoneOpt, 'json']
|
|
462
|
+
})
|
|
463
|
+
$('#node-input-expiry').typedInput({
|
|
464
|
+
default: !this.expiry ? 'none' : 'num',
|
|
465
|
+
types: [typedInputNoneOpt, 'num']
|
|
466
|
+
})
|
|
467
|
+
$('#node-input-contentType').typedInput({
|
|
468
|
+
default: getDefaultContentType(this.contentType),
|
|
469
|
+
types: contentTypeOpts
|
|
470
|
+
})
|
|
471
|
+
},
|
|
472
|
+
oneditsave: function () {
|
|
473
|
+
let contentType = $('#node-input-contentType').val().trim()
|
|
474
|
+
if (contentType === '') {
|
|
475
|
+
contentType = $('#node-input-contentType').typedInput('type')
|
|
476
|
+
if (contentType === 'none' || contentType === 'other') {
|
|
477
|
+
contentType = ''
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
$('#node-input-contentType').val(contentType)
|
|
481
|
+
},
|
|
482
|
+
labelStyle: function () {
|
|
483
|
+
return this.name ? 'node_label_italic' : ''
|
|
484
|
+
}
|
|
485
|
+
})
|
|
486
|
+
})()
|
|
487
|
+
</script>
|
|
488
|
+
|