@machhub-dev/node-red-nodes 1.0.5 → 1.0.7
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
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# MACHHUB Node-RED Nodes
|
|
2
|
+
|
|
3
|
+
A collection of custom Node-RED nodes for integrating with the MACHHUB platform. These nodes provide seamless connectivity to MACHHUB's tag system, database collections, and real-time data capabilities.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Configuration](#configuration)
|
|
9
|
+
- [Available Nodes](#available-nodes)
|
|
10
|
+
- [MACHHUB Config](#machhub-config)
|
|
11
|
+
- [Tag Read](#tag-read)
|
|
12
|
+
- [Tag Write](#tag-write)
|
|
13
|
+
- [Bulk Tag Write](#bulk-tag-write)
|
|
14
|
+
- [Collection](#collection)
|
|
15
|
+
- [DB Query](#db-query)
|
|
16
|
+
- [Usage Examples](#usage-examples)
|
|
17
|
+
- [License](#license)
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
1. Navigate to your Node-RED user directory (typically `~/.node-red`)
|
|
22
|
+
2. Install the MACHHUB nodes package:
|
|
23
|
+
```bash
|
|
24
|
+
npm install <machhub-nodes-package>
|
|
25
|
+
```
|
|
26
|
+
3. Restart Node-RED
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
### MACHHUB Config Node
|
|
31
|
+
|
|
32
|
+
Before using any MACHHUB nodes, you need to configure a connection to your MACHHUB server. You have two options:
|
|
33
|
+
|
|
34
|
+
#### Option 1: Using Config Node (Recommended for multiple servers)
|
|
35
|
+
|
|
36
|
+
1. Add any MACHHUB node to your flow
|
|
37
|
+
2. Check "Use Config Node"
|
|
38
|
+
3. Click the pencil icon to create a new MACHHUB Config
|
|
39
|
+
4. Fill in the following details:
|
|
40
|
+
- **Name**: A friendly name for this configuration
|
|
41
|
+
- **Host**: MACHHUB server hostname or IP (default: localhost)
|
|
42
|
+
- **HTTP Port**: MACHHUB HTTP API port (default: 6188)
|
|
43
|
+
- **MQTT Port**: MACHHUB MQTT broker port (default: 1883)
|
|
44
|
+
- **Client ID**: Your MACHHUB client ID
|
|
45
|
+
- **Client Secret**: Your MACHHUB client secret
|
|
46
|
+
|
|
47
|
+
#### Option 2: Using machhub.env.json
|
|
48
|
+
|
|
49
|
+
1. Create a `machhub.env.json` file in your Node-RED working directory
|
|
50
|
+
2. Leave "Use Config Node" unchecked in your MACHHUB nodes
|
|
51
|
+
3. The nodes will automatically read configuration from the JSON file
|
|
52
|
+
|
|
53
|
+
## Available Nodes
|
|
54
|
+
|
|
55
|
+
### MACHHUB Config
|
|
56
|
+
|
|
57
|
+
**Category:** Config
|
|
58
|
+
|
|
59
|
+
A configuration node that stores connection details for MACHHUB server. This node is referenced by other MACHHUB nodes and doesn't appear in the flow directly.
|
|
60
|
+
|
|
61
|
+
**Properties:**
|
|
62
|
+
- **Name**: Optional friendly name
|
|
63
|
+
- **Host**: MACHHUB server address
|
|
64
|
+
- **HTTP Port**: HTTP API port number
|
|
65
|
+
- **MQTT Port**: MQTT broker port number
|
|
66
|
+
- **Client ID**: Authentication client ID
|
|
67
|
+
- **Client Secret**: Authentication client secret
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### Tag Read
|
|
72
|
+
|
|
73
|
+
**Category:** MACHHUB
|
|
74
|
+
**Icon:** 🏷️
|
|
75
|
+
**Color:** Purple (#c777f1)
|
|
76
|
+
|
|
77
|
+
Reads data from MACHHUB tags or subscribes to custom MQTT topics.
|
|
78
|
+
|
|
79
|
+
**Configuration:**
|
|
80
|
+
- **Name**: Optional node name
|
|
81
|
+
- **Tag/Topic**: Select from available tags or enter custom topic
|
|
82
|
+
- **Use Config Node**: Toggle between config node and machhub.env.json
|
|
83
|
+
|
|
84
|
+
**Features:**
|
|
85
|
+
- Dropdown list of available tags
|
|
86
|
+
- Manual topic entry support
|
|
87
|
+
- MQTT wildcard support:
|
|
88
|
+
- `+` - Single level wildcard
|
|
89
|
+
- `#` - Multi-level wildcard
|
|
90
|
+
|
|
91
|
+
**Output:**
|
|
92
|
+
- `msg.payload`: Data received from the subscribed topic
|
|
93
|
+
|
|
94
|
+
**Examples:**
|
|
95
|
+
```
|
|
96
|
+
sensor/temperature → Specific tag
|
|
97
|
+
sensor/+/temperature → All sensors' temperature
|
|
98
|
+
sensor/# → All topics under sensor
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### Tag Write
|
|
104
|
+
|
|
105
|
+
**Category:** MACHHUB
|
|
106
|
+
**Icon:** 🏷️
|
|
107
|
+
**Color:** Purple (#c777f1)
|
|
108
|
+
|
|
109
|
+
Writes data to a selected MACHHUB tag.
|
|
110
|
+
|
|
111
|
+
**Configuration:**
|
|
112
|
+
- **Name**: Optional node name
|
|
113
|
+
- **Select Tag**: Choose from available tags
|
|
114
|
+
- **Use Config Node**: Toggle between config node and machhub.env.json
|
|
115
|
+
|
|
116
|
+
**Input:**
|
|
117
|
+
- `msg.payload`: JSON data to publish to the tag
|
|
118
|
+
|
|
119
|
+
**Example:**
|
|
120
|
+
```javascript
|
|
121
|
+
msg.payload = {
|
|
122
|
+
temperature: 25.5,
|
|
123
|
+
humidity: 60,
|
|
124
|
+
timestamp: Date.now()
|
|
125
|
+
};
|
|
126
|
+
return msg;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### Bulk Tag Write
|
|
132
|
+
|
|
133
|
+
**Category:** MACHHUB
|
|
134
|
+
**Icon:** 🏷️
|
|
135
|
+
**Color:** Purple (#c777f1)
|
|
136
|
+
|
|
137
|
+
Performs bulk write operations to multiple MACHHUB tags simultaneously.
|
|
138
|
+
|
|
139
|
+
**Configuration:**
|
|
140
|
+
- **Name**: Optional node name
|
|
141
|
+
- **Use Config Node**: Toggle between config node and machhub.env.json
|
|
142
|
+
|
|
143
|
+
**Input:**
|
|
144
|
+
- `msg.payload`: Object with tag paths as keys and values to write
|
|
145
|
+
|
|
146
|
+
**Example:**
|
|
147
|
+
```javascript
|
|
148
|
+
msg.payload = {
|
|
149
|
+
"Namespace1/FolderA/Tag1": 123,
|
|
150
|
+
"Namespace1/FolderA/Tag2": 456,
|
|
151
|
+
"Namespace2/FolderB/Temperature": 25.5
|
|
152
|
+
};
|
|
153
|
+
return msg;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Collection
|
|
159
|
+
|
|
160
|
+
**Category:** MACHHUB
|
|
161
|
+
**Icon:** 💾
|
|
162
|
+
**Color:** Purple (#c777f1)
|
|
163
|
+
|
|
164
|
+
Performs CRUD operations on MACHHUB database collections.
|
|
165
|
+
|
|
166
|
+
**Configuration:**
|
|
167
|
+
- **Name**: Optional node name
|
|
168
|
+
- **Use Config Node**: Toggle between config node and machhub.env.json
|
|
169
|
+
- **Collection**: Select target collection from dropdown
|
|
170
|
+
- **Action**: Choose operation type
|
|
171
|
+
|
|
172
|
+
**Actions:**
|
|
173
|
+
|
|
174
|
+
#### 1. Select
|
|
175
|
+
Query and filter records from a collection.
|
|
176
|
+
|
|
177
|
+
**Configuration:**
|
|
178
|
+
- **Select Fields**: Comma-separated list of fields to return (leave empty for all)
|
|
179
|
+
- **Filters**: Add filter conditions with operators: `=`, `!=`, `>`, `<`, `>=`, `<=`
|
|
180
|
+
|
|
181
|
+
**Output:**
|
|
182
|
+
```javascript
|
|
183
|
+
msg.payload = [
|
|
184
|
+
{ field1: "value1", field2: "value2" },
|
|
185
|
+
{ field1: "value3", field2: "value4" }
|
|
186
|
+
];
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### 2. Create
|
|
190
|
+
Insert a new record into a collection.
|
|
191
|
+
|
|
192
|
+
**Input:**
|
|
193
|
+
```javascript
|
|
194
|
+
msg.payload = {
|
|
195
|
+
field1: "value1",
|
|
196
|
+
field2: "value2"
|
|
197
|
+
};
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Output:**
|
|
201
|
+
```javascript
|
|
202
|
+
msg.payload = {
|
|
203
|
+
id: "table_name:new_record_id",
|
|
204
|
+
field1: "value1",
|
|
205
|
+
field2: "value2"
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### 3. Update
|
|
210
|
+
Modify an existing record in a collection.
|
|
211
|
+
|
|
212
|
+
**Input:**
|
|
213
|
+
```javascript
|
|
214
|
+
msg.payload = {
|
|
215
|
+
id: "table_name:05nwoy566jasfwgak5r3",
|
|
216
|
+
record: {
|
|
217
|
+
field1: "updated_value1",
|
|
218
|
+
field2: "updated_value2"
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### 4. Delete
|
|
224
|
+
Remove a record from a collection.
|
|
225
|
+
|
|
226
|
+
**Input:**
|
|
227
|
+
```javascript
|
|
228
|
+
msg.payload = "table_name:05nwoy566jasfwgak5r3";
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### DB Query
|
|
234
|
+
|
|
235
|
+
**Category:** MACHHUB
|
|
236
|
+
**Icon:** 🔍
|
|
237
|
+
**Color:** Purple (#c777f1)
|
|
238
|
+
|
|
239
|
+
Execute custom SurrealQL queries against the MACHHUB database.
|
|
240
|
+
|
|
241
|
+
**Configuration:**
|
|
242
|
+
- **Name**: Optional node name
|
|
243
|
+
- **Use Config Node**: Toggle between config node and machhub.env.json
|
|
244
|
+
- **Query**: SurrealQL query to execute
|
|
245
|
+
|
|
246
|
+
**Input (Optional):**
|
|
247
|
+
- `msg.query`: Override the configured query at runtime
|
|
248
|
+
|
|
249
|
+
**Output:**
|
|
250
|
+
- `msg.payload`: Array of query results
|
|
251
|
+
|
|
252
|
+
**Important:** Wrap table names with backticks: `` `domain_id.table_name` ``
|
|
253
|
+
|
|
254
|
+
**Example Queries:**
|
|
255
|
+
```sql
|
|
256
|
+
SELECT * FROM `domain_id.purchase_orders` WHERE po_number = 'PO_0016'
|
|
257
|
+
|
|
258
|
+
SELECT id, name FROM `domain_id.products` LIMIT 10
|
|
259
|
+
|
|
260
|
+
SELECT COUNT(*) as total FROM `domain_id.orders`
|
|
261
|
+
|
|
262
|
+
SELECT * FROM `domain_id.sensors` WHERE temperature > 25
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Runtime Override Example:**
|
|
266
|
+
```javascript
|
|
267
|
+
msg.query = "SELECT * FROM `domain_id.purchase_orders` WHERE status = 'pending'";
|
|
268
|
+
return msg;
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Usage Examples
|
|
274
|
+
|
|
275
|
+
### Example 1: Reading and Writing Tags
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
[Inject] → [Tag Read] → [Function] → [Tag Write]
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Function Node:**
|
|
282
|
+
```javascript
|
|
283
|
+
// Read temperature, add 5, write to another tag
|
|
284
|
+
msg.payload = {
|
|
285
|
+
value: msg.payload.value + 5,
|
|
286
|
+
timestamp: Date.now()
|
|
287
|
+
};
|
|
288
|
+
return msg;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Example 2: Querying and Filtering Collection Data
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
[Inject] → [Collection: Select] → [Debug]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Collection Configuration:**
|
|
298
|
+
- Action: Select
|
|
299
|
+
- Select Fields: `id,name,status`
|
|
300
|
+
- Filters:
|
|
301
|
+
- `status = active`
|
|
302
|
+
- `priority > 5`
|
|
303
|
+
|
|
304
|
+
### Example 3: Bulk Tag Update
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
[Inject] → [Function] → [Bulk Tag Write]
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Function Node:**
|
|
311
|
+
```javascript
|
|
312
|
+
msg.payload = {
|
|
313
|
+
"Production/Line1/Speed": 1500,
|
|
314
|
+
"Production/Line1/Temperature": 85.2,
|
|
315
|
+
"Production/Line1/Status": "Running"
|
|
316
|
+
};
|
|
317
|
+
return msg;
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Example 4: Custom Database Query
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
[Inject] → [DB Query] → [Function] → [Debug]
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**DB Query Configuration:**
|
|
327
|
+
```sql
|
|
328
|
+
SELECT * FROM `domain_id.production_data`
|
|
329
|
+
WHERE timestamp > time::now() - 1h
|
|
330
|
+
ORDER BY timestamp DESC
|
|
331
|
+
LIMIT 100
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Example 5: Create-Read-Update-Delete Workflow
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
[Inject] → [Collection: Create] → [Collection: Select] → [Function] → [Collection: Update]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Troubleshooting
|
|
343
|
+
|
|
344
|
+
### Tags Not Loading
|
|
345
|
+
- Verify MACHHUB server is running and accessible
|
|
346
|
+
- Check Client ID and Client Secret are correct
|
|
347
|
+
- Ensure HTTP Port is correct (default: 6188)
|
|
348
|
+
- Check network connectivity to the MACHHUB server
|
|
349
|
+
|
|
350
|
+
### Collection Operations Failing
|
|
351
|
+
- Verify the collection exists in the database
|
|
352
|
+
- Check field names match the collection schema
|
|
353
|
+
- Ensure proper permissions are set for the client
|
|
354
|
+
|
|
355
|
+
### MQTT Subscription Not Receiving Data
|
|
356
|
+
- Verify MQTT Port is correct (default: 1883)
|
|
357
|
+
- Check the topic path is correct
|
|
358
|
+
- Ensure tags are publishing data
|
|
359
|
+
- Verify firewall settings allow MQTT traffic
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## License
|
|
364
|
+
|
|
365
|
+
See [LICENSE](LICENSE) file for details.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Support
|
|
370
|
+
|
|
371
|
+
For issues, questions, or contributions, please contact your MACHHUB administrator or refer to the MACHHUB documentation.
|
|
@@ -112,12 +112,14 @@ class HTTPAPIService {
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
// Collection Example
|
|
115
|
-
static getCollectionsExample(settings, collectionID) {
|
|
115
|
+
static getCollectionsExample(settings, collectionID, isSelectQuery) {
|
|
116
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
117
117
|
try {
|
|
118
118
|
const res = yield this.service(settings).request
|
|
119
119
|
.post('collections/example', undefined, {
|
|
120
|
-
collectionID
|
|
120
|
+
collectionID,
|
|
121
|
+
// @ts-ignore: need to pass as boolean not string
|
|
122
|
+
isSelectQuery: isSelectQuery
|
|
121
123
|
});
|
|
122
124
|
return res;
|
|
123
125
|
}
|
|
@@ -208,7 +208,7 @@ function default_1(RED) {
|
|
|
208
208
|
// HTTP endpoint to fetch collection example for admin UI
|
|
209
209
|
RED.httpAdmin.post("/collections/example", (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
210
210
|
try {
|
|
211
|
-
const { collectionID, host, httpPort, clientId, clientSecret } = req.body;
|
|
211
|
+
const { collectionID, isSelectQuery, host, httpPort, clientId, clientSecret } = req.body;
|
|
212
212
|
let configData;
|
|
213
213
|
// Check if credentials are provided (config node)
|
|
214
214
|
if (clientId && clientSecret) {
|
|
@@ -229,7 +229,7 @@ function default_1(RED) {
|
|
|
229
229
|
clientSecret: envConfig.clientSecret
|
|
230
230
|
};
|
|
231
231
|
}
|
|
232
|
-
const result = yield http_api_services_1.HTTPAPIService.getCollectionsExample(configData, collectionID);
|
|
232
|
+
const result = yield http_api_services_1.HTTPAPIService.getCollectionsExample(configData, collectionID, isSelectQuery);
|
|
233
233
|
res.json(result);
|
|
234
234
|
}
|
|
235
235
|
catch (e) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
RED.nodes.registerType('machhub-config', {
|
|
3
3
|
category: 'config',
|
|
4
4
|
defaults: {
|
|
5
|
+
name: { value: "", required: false },
|
|
5
6
|
host: { value: "localhost", required: true },
|
|
6
7
|
httpPort: { value: 6188, required: true, validate: RED.validators.number() },
|
|
7
8
|
mqttPort: { value: 1883, required: true, validate: RED.validators.number() },
|
|
@@ -9,12 +10,16 @@
|
|
|
9
10
|
clientSecret: { value: "", required: true }
|
|
10
11
|
},
|
|
11
12
|
label: function() {
|
|
12
|
-
return this.host + ":" + this.httpPort + " / MQTT:" + this.mqttPort;
|
|
13
|
+
return this.name || (this.host + ":" + this.httpPort + " / MQTT:" + this.mqttPort);
|
|
13
14
|
}
|
|
14
15
|
});
|
|
15
16
|
</script>
|
|
16
17
|
|
|
17
18
|
<script type="text/html" data-template-name="machhub-config">
|
|
19
|
+
<div class="form-row">
|
|
20
|
+
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
21
|
+
<input type="text" id="node-config-input-name" placeholder="My MACHHUB Server">
|
|
22
|
+
</div>
|
|
18
23
|
<div class="form-row">
|
|
19
24
|
<label for="node-config-input-host"><i class="fa fa-server"></i> Host</label>
|
|
20
25
|
<input type="text" id="node-config-input-host" placeholder="localhost">
|
|
@@ -54,28 +54,32 @@
|
|
|
54
54
|
try {
|
|
55
55
|
// Get the selected machhub config
|
|
56
56
|
const machhubConfigId = $machhub.val();
|
|
57
|
+
const useConfigNodeChecked = $useConfigNode.is(":checked");
|
|
57
58
|
let configData = {};
|
|
58
59
|
|
|
59
|
-
if (machhubConfigId) {
|
|
60
|
+
if (useConfigNodeChecked && machhubConfigId) {
|
|
60
61
|
const configNode = RED.nodes.node(machhubConfigId);
|
|
61
62
|
if (configNode) {
|
|
62
63
|
configData = {
|
|
64
|
+
useConfigNode: "true",
|
|
63
65
|
host: configNode.host || "127.0.0.1",
|
|
64
66
|
httpPort: configNode.httpPort || 6188,
|
|
65
67
|
clientId: configNode.clientId || "",
|
|
66
68
|
clientSecret: configNode.clientSecret || ""
|
|
67
69
|
};
|
|
68
70
|
}
|
|
69
|
-
} else if (machhubNodes.length > 0) {
|
|
71
|
+
} else if (useConfigNodeChecked && machhubNodes.length > 0) {
|
|
70
72
|
// Use first available config
|
|
71
73
|
const configNode = machhubNodes[0];
|
|
72
74
|
configData = {
|
|
75
|
+
useConfigNode: "true",
|
|
73
76
|
host: configNode.host || "127.0.0.1",
|
|
74
77
|
httpPort: configNode.httpPort || 6188,
|
|
75
78
|
clientId: configNode.clientId || "",
|
|
76
79
|
clientSecret: configNode.clientSecret || ""
|
|
77
80
|
};
|
|
78
81
|
}
|
|
82
|
+
// If useConfigNode is false, send empty params to use machhub.env.json
|
|
79
83
|
|
|
80
84
|
// Build query string (revert back to working approach)
|
|
81
85
|
const queryParams = new URLSearchParams(configData).toString();
|
|
@@ -100,10 +104,11 @@
|
|
|
100
104
|
|
|
101
105
|
const tags = await res.json();
|
|
102
106
|
|
|
103
|
-
// Populate
|
|
107
|
+
// Populate datalist
|
|
108
|
+
const $datalist = $("#node-input-selectedTag-datalist");
|
|
104
109
|
if (tags && tags.length > 0) {
|
|
105
|
-
let options = tags.map(tag => `<option value="${tag}"
|
|
106
|
-
$
|
|
110
|
+
let options = tags.map(tag => `<option value="${tag}">`);
|
|
111
|
+
$datalist.html(options.join("")); // Set options
|
|
107
112
|
} else {
|
|
108
113
|
console.log("No tags available from API");
|
|
109
114
|
}
|
|
@@ -114,9 +119,9 @@
|
|
|
114
119
|
}
|
|
115
120
|
} catch (error) {
|
|
116
121
|
console.error("Error fetching tags:", error);
|
|
117
|
-
//
|
|
122
|
+
// Keep the currently selected tag value
|
|
118
123
|
if (node.selectedTag) {
|
|
119
|
-
$selected_tag.
|
|
124
|
+
$selected_tag.val(node.selectedTag);
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
}
|
|
@@ -139,7 +144,8 @@
|
|
|
139
144
|
</div>
|
|
140
145
|
<div class="form-row">
|
|
141
146
|
<label for="node-input-selectedTag"><i class="fa fa-list"></i> Select Tag</label>
|
|
142
|
-
<
|
|
147
|
+
<input type="text" id="node-input-selectedTag" list="node-input-selectedTag-datalist" placeholder="Start typing or select a tag...">
|
|
148
|
+
<datalist id="node-input-selectedTag-datalist"></datalist>
|
|
143
149
|
</div>
|
|
144
150
|
<div class="form-row">
|
|
145
151
|
<label for="node-input-useConfigNode" style="width: auto; padding-right: 10px;">
|