@node-red/editor-client 3.1.8 → 4.0.0-beta.2
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/locales/de/editor.json +2 -0
- package/locales/en-US/editor.json +10 -1
- package/locales/fr/editor.json +8 -1
- package/locales/ja/editor.json +10 -3
- package/package.json +1 -1
- package/public/red/about +52 -0
- package/public/red/red.js +1433 -263
- package/public/red/red.min.js +3 -3
- package/public/red/style.min.css +2 -2
- package/public/red/tours/3.1/welcome.js +231 -0
- package/public/red/tours/images/nr4-auto-complete.png +0 -0
- package/public/red/tours/images/nr4-config-select.png +0 -0
- package/public/red/tours/images/nr4-multiplayer.png +0 -0
- package/public/red/tours/images/nr4-plugins.png +0 -0
- package/public/red/tours/images/nr4-sf-config.png +0 -0
- package/public/red/tours/images/nr4-timestamp-formatting.png +0 -0
- package/public/red/tours/welcome.js +105 -161
- package/public/types/node/assert/strict.d.ts +1 -1
- package/public/types/node/assert.d.ts +8 -9
- package/public/types/node/async_hooks.d.ts +9 -5
- package/public/types/node/buffer.d.ts +43 -18
- package/public/types/node/child_process.d.ts +8 -5
- package/public/types/node/cluster.d.ts +15 -19
- package/public/types/node/console.d.ts +2 -2
- package/public/types/node/crypto.d.ts +165 -70
- package/public/types/node/dgram.d.ts +4 -4
- package/public/types/node/diagnostics_channel.d.ts +8 -7
- package/public/types/node/dns/promises.d.ts +11 -9
- package/public/types/node/dns.d.ts +18 -13
- package/public/types/node/dom-events.d.ts +129 -0
- package/public/types/node/domain.d.ts +2 -2
- package/public/types/node/events.d.ts +49 -12
- package/public/types/node/fs/promises.d.ts +68 -24
- package/public/types/node/fs.d.ts +132 -59
- package/public/types/node/globals.d.ts +31 -17
- package/public/types/node/http.d.ts +138 -27
- package/public/types/node/http2.d.ts +38 -5
- package/public/types/node/https.d.ts +12 -3
- package/public/types/node/module.d.ts +1 -2
- package/public/types/node/net.d.ts +69 -28
- package/public/types/node/os.d.ts +16 -5
- package/public/types/node/path.d.ts +5 -5
- package/public/types/node/perf_hooks.d.ts +48 -9
- package/public/types/node/process.d.ts +18 -17
- package/public/types/node/querystring.d.ts +2 -2
- package/public/types/node/readline/promises.d.ts +146 -0
- package/public/types/node/readline.d.ts +141 -31
- package/public/types/node/stream/consumers.d.ts +2 -2
- package/public/types/node/stream/promises.d.ts +1 -1
- package/public/types/node/stream/web.d.ts +4 -66
- package/public/types/node/stream.d.ts +96 -118
- package/public/types/node/string_decoder.d.ts +2 -2
- package/public/types/node/test.d.ts +200 -16
- package/public/types/node/timers/promises.d.ts +1 -26
- package/public/types/node/timers.d.ts +2 -2
- package/public/types/node/tls.d.ts +21 -12
- package/public/types/node/trace_events.d.ts +12 -2
- package/public/types/node/ts4.8/assert/strict.d.ts +11 -0
- package/public/types/node/ts4.8/assert.d.ts +964 -0
- package/public/types/node/ts4.8/async_hooks.d.ts +504 -0
- package/public/types/node/ts4.8/buffer.d.ts +2262 -0
- package/public/types/node/ts4.8/child_process.d.ts +1372 -0
- package/public/types/node/ts4.8/cluster.d.ts +413 -0
- package/public/types/node/ts4.8/console.d.ts +415 -0
- package/public/types/node/ts4.8/crypto.d.ts +3967 -0
- package/public/types/node/ts4.8/dgram.d.ts +548 -0
- package/public/types/node/ts4.8/diagnostics_channel.d.ts +156 -0
- package/public/types/node/ts4.8/dns/promises.d.ts +373 -0
- package/public/types/node/ts4.8/dns.d.ts +662 -0
- package/public/types/node/ts4.8/dom-events.d.ts +129 -0
- package/public/types/node/ts4.8/domain.d.ts +173 -0
- package/public/types/node/ts4.8/events.d.ts +681 -0
- package/public/types/node/ts4.8/fs/promises.d.ts +1141 -0
- package/public/types/node/ts4.8/fs.d.ts +3875 -0
- package/public/types/node/ts4.8/globals.d.ts +297 -0
- package/public/types/node/ts4.8/http.d.ts +1617 -0
- package/public/types/node/ts4.8/http2.d.ts +2137 -0
- package/public/types/node/ts4.8/https.d.ts +544 -0
- package/public/types/node/ts4.8/module.d.ts +117 -0
- package/public/types/node/ts4.8/net.d.ts +872 -0
- package/public/types/node/ts4.8/os.d.ts +469 -0
- package/public/types/node/ts4.8/path.d.ts +194 -0
- package/public/types/node/ts4.8/perf_hooks.d.ts +628 -0
- package/public/types/node/ts4.8/process.d.ts +1485 -0
- package/public/types/node/ts4.8/querystring.d.ts +134 -0
- package/public/types/node/ts4.8/readline/promises.d.ts +146 -0
- package/public/types/node/ts4.8/readline.d.ts +656 -0
- package/public/types/node/ts4.8/stream/consumers.d.ts +15 -0
- package/public/types/node/ts4.8/stream/promises.d.ts +45 -0
- package/public/types/node/ts4.8/stream/web.d.ts +333 -0
- package/public/types/node/ts4.8/stream.d.ts +1343 -0
- package/public/types/node/ts4.8/string_decoder.d.ts +70 -0
- package/public/types/node/ts4.8/test.d.ts +377 -0
- package/public/types/node/ts4.8/timers/promises.d.ts +71 -0
- package/public/types/node/ts4.8/timers.d.ts +97 -0
- package/public/types/node/ts4.8/tls.d.ts +1031 -0
- package/public/types/node/ts4.8/trace_events.d.ts +174 -0
- package/public/types/node/ts4.8/tty.d.ts +209 -0
- package/public/types/node/ts4.8/url.d.ts +900 -0
- package/public/types/node/ts4.8/util.d.ts +1853 -0
- package/public/types/node/ts4.8/v8.d.ts +399 -0
- package/public/types/node/ts4.8/vm.d.ts +512 -0
- package/public/types/node/ts4.8/wasi.d.ts +161 -0
- package/public/types/node/ts4.8/worker_threads.d.ts +692 -0
- package/public/types/node/ts4.8/zlib.d.ts +520 -0
- package/public/types/node/tty.d.ts +5 -3
- package/public/types/node/url.d.ts +81 -39
- package/public/types/node/util.d.ts +269 -13
- package/public/types/node/v8.d.ts +22 -4
- package/public/types/node/vm.d.ts +7 -5
- package/public/types/node/wasi.d.ts +2 -2
- package/public/types/node/worker_threads.d.ts +51 -11
- package/public/types/node/zlib.d.ts +2 -2
- package/public/types/node-red/func.d.ts +26 -17
- package/public/vendor/ace/worker-jsonata.js +1 -1
- package/public/vendor/monaco/dist/{fa2cc0ab9f0bec2b3365.ttf → 0c718f5b7d2bce997c5f.ttf} +0 -0
- package/public/vendor/monaco/dist/css.worker.js +1 -1
- package/public/vendor/monaco/dist/css.worker.js.LICENSE.txt +1 -1
- package/public/vendor/monaco/dist/editor.js +1 -29
- package/public/vendor/monaco/dist/editor.js.LICENSE.txt +2 -2
- package/public/vendor/monaco/dist/editor.worker.js +1 -1
- package/public/vendor/monaco/dist/html.worker.js +1 -1
- package/public/vendor/monaco/dist/html.worker.js.LICENSE.txt +1 -1
- package/public/vendor/monaco/dist/json.worker.js +1 -1
- package/public/vendor/monaco/dist/json.worker.js.LICENSE.txt +1 -1
- package/public/vendor/monaco/dist/locale/cs.js +324 -106
- package/public/vendor/monaco/dist/locale/de.js +336 -118
- package/public/vendor/monaco/dist/locale/es.js +329 -111
- package/public/vendor/monaco/dist/locale/fr.js +334 -116
- package/public/vendor/monaco/dist/locale/it.js +327 -109
- package/public/vendor/monaco/dist/locale/ja.js +329 -111
- package/public/vendor/monaco/dist/locale/ko.js +330 -112
- package/public/vendor/monaco/dist/locale/pl.js +329 -111
- package/public/vendor/monaco/dist/locale/pt-br.js +329 -111
- package/public/vendor/monaco/dist/locale/qps-ploc.js +330 -112
- package/public/vendor/monaco/dist/locale/ru.js +331 -113
- package/public/vendor/monaco/dist/locale/tr.js +329 -111
- package/public/vendor/monaco/dist/locale/zh-hans.js +331 -113
- package/public/vendor/monaco/dist/locale/zh-hant.js +331 -113
- package/public/vendor/monaco/dist/ts.worker.js +2 -2
- package/public/vendor/vendor.js +1 -1
- package/public/vendor/monaco/dist/7064e66c3890a12c47b4.ttf +0 -0
- /package/public/red/tours/{images → 3.1/images}/context-menu.png +0 -0
- /package/public/red/tours/{images → 3.1/images}/global-env-vars.png +0 -0
- /package/public/red/tours/{images → 3.1/images}/hiding-flows.png +0 -0
- /package/public/red/tours/{images → 3.1/images}/locking-flows.png +0 -0
- /package/public/red/tours/{images → 3.1/images}/mermaid.png +0 -0
- /package/public/red/tours/{images → 3.1/images}/node-help.png +0 -0
- /package/public/red/tours/{images → 3.1/images}/tab-changes.png +0 -0
package/public/red/red.js
CHANGED
|
@@ -116,6 +116,7 @@ var RED = (function() {
|
|
|
116
116
|
cache: false,
|
|
117
117
|
url: 'plugins',
|
|
118
118
|
success: function(data) {
|
|
119
|
+
RED.plugins.setPluginList(data);
|
|
119
120
|
loader.reportProgress(RED._("event.loadPlugins"), 13)
|
|
120
121
|
RED.i18n.loadPluginCatalogs(function() {
|
|
121
122
|
loadPlugins(function() {
|
|
@@ -625,6 +626,41 @@ var RED = (function() {
|
|
|
625
626
|
RED.view.redrawStatus(node);
|
|
626
627
|
}
|
|
627
628
|
});
|
|
629
|
+
RED.comms.subscribe("notification/plugin/#",function(topic,msg) {
|
|
630
|
+
if (topic == "notification/plugin/added") {
|
|
631
|
+
RED.settings.refreshSettings(function(err, data) {
|
|
632
|
+
let addedPlugins = [];
|
|
633
|
+
msg.forEach(function(m) {
|
|
634
|
+
let id = m.id;
|
|
635
|
+
RED.plugins.addPlugin(m);
|
|
636
|
+
|
|
637
|
+
m.plugins.forEach((p) => {
|
|
638
|
+
addedPlugins.push(p.id);
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
RED.i18n.loadNodeCatalog(id, function() {
|
|
642
|
+
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
|
643
|
+
$.ajax({
|
|
644
|
+
headers: {
|
|
645
|
+
"Accept":"text/html",
|
|
646
|
+
"Accept-Language": lang
|
|
647
|
+
},
|
|
648
|
+
cache: false,
|
|
649
|
+
url: 'plugins/'+id,
|
|
650
|
+
success: function(data) {
|
|
651
|
+
appendPluginConfig(data);
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
if (addedPlugins.length) {
|
|
657
|
+
let pluginList = "<ul><li>"+addedPlugins.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
|
658
|
+
// ToDo: Adapt notification (node -> plugin)
|
|
659
|
+
RED.notify(RED._("palette.event.nodeAdded", {count:addedPlugins.length})+pluginList,"success");
|
|
660
|
+
}
|
|
661
|
+
})
|
|
662
|
+
}
|
|
663
|
+
});
|
|
628
664
|
|
|
629
665
|
let pendingNodeRemovedNotifications = []
|
|
630
666
|
let pendingNodeRemovedTimeout
|
|
@@ -894,6 +930,10 @@ var RED = (function() {
|
|
|
894
930
|
|
|
895
931
|
RED.nodes.init();
|
|
896
932
|
RED.runtime.init()
|
|
933
|
+
|
|
934
|
+
if (RED.settings.theme("multiplayer.enabled",false)) {
|
|
935
|
+
RED.multiplayer.init()
|
|
936
|
+
}
|
|
897
937
|
RED.comms.connect();
|
|
898
938
|
|
|
899
939
|
$("#red-ui-main-container").show();
|
|
@@ -1812,6 +1852,7 @@ RED.user = (function() {
|
|
|
1812
1852
|
}
|
|
1813
1853
|
|
|
1814
1854
|
function logout() {
|
|
1855
|
+
RED.events.emit('logout')
|
|
1815
1856
|
var tokens = RED.settings.get("auth-tokens");
|
|
1816
1857
|
var token = tokens?tokens.access_token:"";
|
|
1817
1858
|
$.ajax({
|
|
@@ -1850,6 +1891,7 @@ RED.user = (function() {
|
|
|
1850
1891
|
});
|
|
1851
1892
|
}
|
|
1852
1893
|
});
|
|
1894
|
+
$('<i class="fa fa-user"></i>').appendTo("#red-ui-header-button-user");
|
|
1853
1895
|
} else {
|
|
1854
1896
|
RED.menu.addItem("red-ui-header-button-user",{
|
|
1855
1897
|
id:"usermenu-item-username",
|
|
@@ -1862,6 +1904,15 @@ RED.user = (function() {
|
|
|
1862
1904
|
RED.user.logout();
|
|
1863
1905
|
}
|
|
1864
1906
|
});
|
|
1907
|
+
const userMenu = $("#red-ui-header-button-user")
|
|
1908
|
+
userMenu.empty()
|
|
1909
|
+
if (RED.settings.user.image) {
|
|
1910
|
+
$('<span class="user-profile"></span>').css({
|
|
1911
|
+
backgroundImage: "url("+RED.settings.user.image+")",
|
|
1912
|
+
}).appendTo(userMenu);
|
|
1913
|
+
} else {
|
|
1914
|
+
$('<i class="fa fa-user"></i>').appendTo(userMenu);
|
|
1915
|
+
}
|
|
1865
1916
|
}
|
|
1866
1917
|
|
|
1867
1918
|
}
|
|
@@ -1872,14 +1923,6 @@ RED.user = (function() {
|
|
|
1872
1923
|
|
|
1873
1924
|
var userMenu = $('<li><a id="red-ui-header-button-user" class="button hide" href="#"></a></li>')
|
|
1874
1925
|
.prependTo(".red-ui-header-toolbar");
|
|
1875
|
-
if (RED.settings.user.image) {
|
|
1876
|
-
$('<span class="user-profile"></span>').css({
|
|
1877
|
-
backgroundImage: "url("+RED.settings.user.image+")",
|
|
1878
|
-
}).appendTo(userMenu.find("a"));
|
|
1879
|
-
} else {
|
|
1880
|
-
$('<i class="fa fa-user"></i>').appendTo(userMenu.find("a"));
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
1926
|
RED.menu.init({id:"red-ui-header-button-user",
|
|
1884
1927
|
options: []
|
|
1885
1928
|
});
|
|
@@ -1979,6 +2022,15 @@ RED.comms = (function() {
|
|
|
1979
2022
|
var reconnectAttempts = 0;
|
|
1980
2023
|
var active = false;
|
|
1981
2024
|
|
|
2025
|
+
RED.events.on('login', function(username) {
|
|
2026
|
+
// User has logged in
|
|
2027
|
+
// Need to upgrade the connection to be authenticated
|
|
2028
|
+
if (ws && ws.readyState == 1) {
|
|
2029
|
+
const auth_tokens = RED.settings.get("auth-tokens");
|
|
2030
|
+
ws.send(JSON.stringify({auth:auth_tokens.access_token}))
|
|
2031
|
+
}
|
|
2032
|
+
})
|
|
2033
|
+
|
|
1982
2034
|
function connectWS() {
|
|
1983
2035
|
active = true;
|
|
1984
2036
|
var wspath;
|
|
@@ -2009,6 +2061,7 @@ RED.comms = (function() {
|
|
|
2009
2061
|
ws.send(JSON.stringify({subscribe:t}));
|
|
2010
2062
|
}
|
|
2011
2063
|
}
|
|
2064
|
+
emit('connect')
|
|
2012
2065
|
}
|
|
2013
2066
|
|
|
2014
2067
|
ws = new WebSocket(wspath);
|
|
@@ -2133,10 +2186,54 @@ RED.comms = (function() {
|
|
|
2133
2186
|
}
|
|
2134
2187
|
}
|
|
2135
2188
|
|
|
2189
|
+
function send(topic, msg) {
|
|
2190
|
+
if (ws && ws.readyState == 1) {
|
|
2191
|
+
ws.send(JSON.stringify({
|
|
2192
|
+
topic,
|
|
2193
|
+
data: msg
|
|
2194
|
+
}))
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
const eventHandlers = {};
|
|
2199
|
+
function on(evt,func) {
|
|
2200
|
+
eventHandlers[evt] = eventHandlers[evt]||[];
|
|
2201
|
+
eventHandlers[evt].push(func);
|
|
2202
|
+
}
|
|
2203
|
+
function off(evt,func) {
|
|
2204
|
+
const handler = eventHandlers[evt];
|
|
2205
|
+
if (handler) {
|
|
2206
|
+
for (let i=0;i<handler.length;i++) {
|
|
2207
|
+
if (handler[i] === func) {
|
|
2208
|
+
handler.splice(i,1);
|
|
2209
|
+
return;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
function emit() {
|
|
2215
|
+
const evt = arguments[0]
|
|
2216
|
+
const args = Array.prototype.slice.call(arguments,1);
|
|
2217
|
+
if (eventHandlers[evt]) {
|
|
2218
|
+
let cpyHandlers = [...eventHandlers[evt]];
|
|
2219
|
+
for (let i=0;i<cpyHandlers.length;i++) {
|
|
2220
|
+
try {
|
|
2221
|
+
cpyHandlers[i].apply(null, args);
|
|
2222
|
+
} catch(err) {
|
|
2223
|
+
console.warn("RED.comms.emit error: ["+evt+"] "+(err.toString()));
|
|
2224
|
+
console.warn(err);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2136
2230
|
return {
|
|
2137
2231
|
connect: connectWS,
|
|
2138
2232
|
subscribe: subscribe,
|
|
2139
|
-
unsubscribe:unsubscribe
|
|
2233
|
+
unsubscribe:unsubscribe,
|
|
2234
|
+
on,
|
|
2235
|
+
off,
|
|
2236
|
+
send
|
|
2140
2237
|
}
|
|
2141
2238
|
})();
|
|
2142
2239
|
;RED.runtime = (function() {
|
|
@@ -2175,6 +2272,223 @@ RED.comms = (function() {
|
|
|
2175
2272
|
}
|
|
2176
2273
|
}
|
|
2177
2274
|
})()
|
|
2275
|
+
;RED.multiplayer = (function () {
|
|
2276
|
+
|
|
2277
|
+
// sessionId - used to identify sessions across websocket reconnects
|
|
2278
|
+
let sessionId
|
|
2279
|
+
|
|
2280
|
+
let headerWidget
|
|
2281
|
+
// Map of session id to { session:'', user:{}, location:{}}
|
|
2282
|
+
let connections = {}
|
|
2283
|
+
// Map of username to { user:{}, connections:[] }
|
|
2284
|
+
let users = {}
|
|
2285
|
+
|
|
2286
|
+
function addUserConnection (connection) {
|
|
2287
|
+
if (connections[connection.session]) {
|
|
2288
|
+
// This is an existing connection that has been authenticated
|
|
2289
|
+
const existingConnection = connections[connection.session]
|
|
2290
|
+
if (existingConnection.user.username !== connection.user.username) {
|
|
2291
|
+
removeUserButton(users[existingConnection.user.username])
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
connections[connection.session] = connection
|
|
2295
|
+
const user = users[connection.user.username] = users[connection.user.username] || {
|
|
2296
|
+
user: connection.user,
|
|
2297
|
+
connections: []
|
|
2298
|
+
}
|
|
2299
|
+
connection.location = connection.location || {}
|
|
2300
|
+
user.connections.push(connection)
|
|
2301
|
+
|
|
2302
|
+
if (connection.user.username === RED.settings.user?.username ||
|
|
2303
|
+
connection.session === sessionId
|
|
2304
|
+
) {
|
|
2305
|
+
// This is the current user - do not add a extra button for them
|
|
2306
|
+
} else {
|
|
2307
|
+
if (user.connections.length === 1) {
|
|
2308
|
+
if (user.button) {
|
|
2309
|
+
clearTimeout(user.inactiveTimeout)
|
|
2310
|
+
clearTimeout(user.removeTimeout)
|
|
2311
|
+
user.button.removeClass('inactive')
|
|
2312
|
+
} else {
|
|
2313
|
+
addUserButton(user)
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
function removeUserConnection (session, isDisconnected) {
|
|
2320
|
+
const connection = connections[session]
|
|
2321
|
+
delete connections[session]
|
|
2322
|
+
const user = users[connection.user.username]
|
|
2323
|
+
const i = user.connections.indexOf(connection)
|
|
2324
|
+
user.connections.splice(i, 1)
|
|
2325
|
+
if (isDisconnected) {
|
|
2326
|
+
removeUserButton(user)
|
|
2327
|
+
} else {
|
|
2328
|
+
if (user.connections.length === 0) {
|
|
2329
|
+
// Give the user 5s to reconnect before marking inactive
|
|
2330
|
+
user.inactiveTimeout = setTimeout(() => {
|
|
2331
|
+
user.button.addClass('inactive')
|
|
2332
|
+
// Give the user further 20 seconds to reconnect before removing them
|
|
2333
|
+
// from the user toolbar entirely
|
|
2334
|
+
user.removeTimeout = setTimeout(() => {
|
|
2335
|
+
removeUserButton(user)
|
|
2336
|
+
}, 20000)
|
|
2337
|
+
}, 5000)
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
function addUserButton (user) {
|
|
2343
|
+
user.button = $('<li class="red-ui-multiplayer-user"><button type="button" class="red-ui-multiplayer-user-icon" href="#"></button></li>')
|
|
2344
|
+
.attr('data-username', user.user.username)
|
|
2345
|
+
.prependTo("#red-ui-multiplayer-user-list");
|
|
2346
|
+
var button = user.button.find("button")
|
|
2347
|
+
button.on('click', function () {
|
|
2348
|
+
RED.popover.create({
|
|
2349
|
+
target:button,
|
|
2350
|
+
trigger: 'modal',
|
|
2351
|
+
interactive: true,
|
|
2352
|
+
width: "250px",
|
|
2353
|
+
direction: 'bottom',
|
|
2354
|
+
content: () => {
|
|
2355
|
+
const content = $('<div>')
|
|
2356
|
+
$('<div style="text-align: center">').text(user.user.username).appendTo(content)
|
|
2357
|
+
|
|
2358
|
+
const location = user.connections[0].location
|
|
2359
|
+
if (location.workspace) {
|
|
2360
|
+
const ws = RED.nodes.workspace(location.workspace) || RED.nodes.subflow(location.workspace)
|
|
2361
|
+
if (ws) {
|
|
2362
|
+
$('<div>').text(`${ws.type}: ${ws.label||ws.name||ws.id}`).appendTo(content)
|
|
2363
|
+
} else {
|
|
2364
|
+
$('<div>').text(`tab: unknown`).appendTo(content)
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
if (location.node) {
|
|
2368
|
+
const node = RED.nodes.node(location.node)
|
|
2369
|
+
if (node) {
|
|
2370
|
+
$('<div>').text(`node: ${node.id}`).appendTo(content)
|
|
2371
|
+
} else {
|
|
2372
|
+
$('<div>').text(`node: unknown`).appendTo(content)
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
return content
|
|
2376
|
+
},
|
|
2377
|
+
}).open()
|
|
2378
|
+
})
|
|
2379
|
+
if (!user.user.image) {
|
|
2380
|
+
$('<i class="fa fa-user"></i>').appendTo(button);
|
|
2381
|
+
} else {
|
|
2382
|
+
$('<span class="user-profile"></span>').css({
|
|
2383
|
+
backgroundImage: "url("+user.user.image+")",
|
|
2384
|
+
}).appendTo(button);
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
function getLocation () {
|
|
2389
|
+
const location = {
|
|
2390
|
+
workspace: RED.workspaces.active()
|
|
2391
|
+
}
|
|
2392
|
+
const editStack = RED.editor.getEditStack()
|
|
2393
|
+
for (let i = editStack.length - 1; i >= 0; i--) {
|
|
2394
|
+
if (editStack[i].id) {
|
|
2395
|
+
location.node = editStack[i].id
|
|
2396
|
+
break
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
return location
|
|
2400
|
+
}
|
|
2401
|
+
function updateLocation () {
|
|
2402
|
+
const location = getLocation()
|
|
2403
|
+
if (location.workspace !== 0) {
|
|
2404
|
+
log('send', 'multiplayer/location', location)
|
|
2405
|
+
RED.comms.send('multiplayer/location', location)
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
function removeUserButton (user) {
|
|
2410
|
+
user.button.remove()
|
|
2411
|
+
delete user.button
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
function updateUserLocation (data) {
|
|
2415
|
+
connections[data.session].location = data
|
|
2416
|
+
delete data.session
|
|
2417
|
+
}
|
|
2418
|
+
return {
|
|
2419
|
+
init: function () {
|
|
2420
|
+
|
|
2421
|
+
|
|
2422
|
+
sessionId = RED.settings.getLocal('multiplayer:sessionId')
|
|
2423
|
+
if (!sessionId) {
|
|
2424
|
+
sessionId = RED.nodes.id()
|
|
2425
|
+
RED.settings.setLocal('multiplayer:sessionId', sessionId)
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
headerWidget = $('<li><ul id="red-ui-multiplayer-user-list"></ul></li>').prependTo('.red-ui-header-toolbar')
|
|
2429
|
+
|
|
2430
|
+
RED.comms.on('connect', () => {
|
|
2431
|
+
const location = getLocation()
|
|
2432
|
+
const connectInfo = {
|
|
2433
|
+
session: sessionId
|
|
2434
|
+
}
|
|
2435
|
+
if (location.workspace !== 0) {
|
|
2436
|
+
connectInfo.location = location
|
|
2437
|
+
}
|
|
2438
|
+
RED.comms.send('multiplayer/connect', connectInfo)
|
|
2439
|
+
})
|
|
2440
|
+
RED.comms.subscribe('multiplayer/#', (topic, msg) => {
|
|
2441
|
+
log('recv', topic, msg)
|
|
2442
|
+
if (topic === 'multiplayer/init') {
|
|
2443
|
+
// We have just reconnected, runtime has sent state to
|
|
2444
|
+
// initialise the world
|
|
2445
|
+
connections = {}
|
|
2446
|
+
users = {}
|
|
2447
|
+
$('#red-ui-multiplayer-user-list').empty()
|
|
2448
|
+
|
|
2449
|
+
msg.forEach(connection => {
|
|
2450
|
+
addUserConnection(connection)
|
|
2451
|
+
})
|
|
2452
|
+
} else if (topic === 'multiplayer/connection-added') {
|
|
2453
|
+
addUserConnection(msg)
|
|
2454
|
+
} else if (topic === 'multiplayer/connection-removed') {
|
|
2455
|
+
removeUserConnection(msg.session, msg.disconnected)
|
|
2456
|
+
} else if (topic === 'multiplayer/location') {
|
|
2457
|
+
updateUserLocation(msg)
|
|
2458
|
+
}
|
|
2459
|
+
})
|
|
2460
|
+
|
|
2461
|
+
RED.events.on('workspace:change', (event) => {
|
|
2462
|
+
updateLocation()
|
|
2463
|
+
})
|
|
2464
|
+
RED.events.on('editor:open', () => {
|
|
2465
|
+
updateLocation()
|
|
2466
|
+
})
|
|
2467
|
+
RED.events.on('editor:close', () => {
|
|
2468
|
+
updateLocation()
|
|
2469
|
+
})
|
|
2470
|
+
RED.events.on('editor:change', () => {
|
|
2471
|
+
updateLocation()
|
|
2472
|
+
})
|
|
2473
|
+
RED.events.on('login', () => {
|
|
2474
|
+
updateLocation()
|
|
2475
|
+
})
|
|
2476
|
+
RED.events.on('logout', () => {
|
|
2477
|
+
const disconnectInfo = {
|
|
2478
|
+
session: sessionId
|
|
2479
|
+
}
|
|
2480
|
+
RED.comms.send('multiplayer/disconnect', disconnectInfo)
|
|
2481
|
+
RED.settings.removeLocal('multiplayer:sessionId')
|
|
2482
|
+
})
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
function log() {
|
|
2487
|
+
if (RED.multiplayer.DEBUG) {
|
|
2488
|
+
console.log('[multiplayer]', ...arguments)
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
})();
|
|
2178
2492
|
;/**
|
|
2179
2493
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
2180
2494
|
*
|
|
@@ -3672,6 +3986,7 @@ RED.state = {
|
|
|
3672
3986
|
;RED.plugins = (function() {
|
|
3673
3987
|
var plugins = {};
|
|
3674
3988
|
var pluginsByType = {};
|
|
3989
|
+
var moduleList = {};
|
|
3675
3990
|
|
|
3676
3991
|
function registerPlugin(id,definition) {
|
|
3677
3992
|
plugins[id] = definition;
|
|
@@ -3709,10 +4024,44 @@ RED.state = {
|
|
|
3709
4024
|
function getPluginsByType(type) {
|
|
3710
4025
|
return pluginsByType[type] || [];
|
|
3711
4026
|
}
|
|
4027
|
+
|
|
4028
|
+
function setPluginList(list) {
|
|
4029
|
+
for(let i=0;i<list.length;i++) {
|
|
4030
|
+
let p = list[i];
|
|
4031
|
+
addPlugin(p);
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4034
|
+
|
|
4035
|
+
function addPlugin(p) {
|
|
4036
|
+
|
|
4037
|
+
moduleList[p.module] = moduleList[p.module] || {
|
|
4038
|
+
name:p.module,
|
|
4039
|
+
version:p.version,
|
|
4040
|
+
local:p.local,
|
|
4041
|
+
sets:{},
|
|
4042
|
+
plugin: true,
|
|
4043
|
+
id: p.id
|
|
4044
|
+
};
|
|
4045
|
+
if (p.pending_version) {
|
|
4046
|
+
moduleList[p.module].pending_version = p.pending_version;
|
|
4047
|
+
}
|
|
4048
|
+
moduleList[p.module].sets[p.name] = p;
|
|
4049
|
+
|
|
4050
|
+
RED.events.emit("registry:plugin-module-added",p.module);
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
function getModule(module) {
|
|
4054
|
+
return moduleList[module];
|
|
4055
|
+
}
|
|
4056
|
+
|
|
3712
4057
|
return {
|
|
3713
4058
|
registerPlugin: registerPlugin,
|
|
3714
4059
|
getPlugin: getPlugin,
|
|
3715
|
-
getPluginsByType: getPluginsByType
|
|
4060
|
+
getPluginsByType: getPluginsByType,
|
|
4061
|
+
|
|
4062
|
+
setPluginList: setPluginList,
|
|
4063
|
+
addPlugin: addPlugin,
|
|
4064
|
+
getModule: getModule
|
|
3716
4065
|
}
|
|
3717
4066
|
})();
|
|
3718
4067
|
;/**
|
|
@@ -3808,6 +4157,31 @@ RED.nodes = (function() {
|
|
|
3808
4157
|
getNodeTypes: function() {
|
|
3809
4158
|
return Object.keys(nodeDefinitions);
|
|
3810
4159
|
},
|
|
4160
|
+
/**
|
|
4161
|
+
* Get an array of node definitions
|
|
4162
|
+
* @param {Object} options - options object
|
|
4163
|
+
* @param {boolean} [options.configOnly] - if true, only return config nodes
|
|
4164
|
+
* @param {function} [options.filter] - a filter function to apply to the list of nodes
|
|
4165
|
+
* @returns array of node definitions
|
|
4166
|
+
*/
|
|
4167
|
+
getNodeDefinitions: function(options) {
|
|
4168
|
+
const result = []
|
|
4169
|
+
const configOnly = (options && options.configOnly)
|
|
4170
|
+
const filter = (options && options.filter)
|
|
4171
|
+
const keys = Object.keys(nodeDefinitions)
|
|
4172
|
+
for (const key of keys) {
|
|
4173
|
+
const def = nodeDefinitions[key]
|
|
4174
|
+
if(!def) { continue }
|
|
4175
|
+
if (configOnly && def.category !== "config") {
|
|
4176
|
+
continue
|
|
4177
|
+
}
|
|
4178
|
+
if (filter && !filter(nodeDefinitions[key])) {
|
|
4179
|
+
continue
|
|
4180
|
+
}
|
|
4181
|
+
result.push(nodeDefinitions[key])
|
|
4182
|
+
}
|
|
4183
|
+
return result
|
|
4184
|
+
},
|
|
3811
4185
|
setNodeList: function(list) {
|
|
3812
4186
|
nodeList = [];
|
|
3813
4187
|
for(var i=0;i<list.length;i++) {
|
|
@@ -3841,6 +4215,8 @@ RED.nodes = (function() {
|
|
|
3841
4215
|
},
|
|
3842
4216
|
removeNodeSet: function(id) {
|
|
3843
4217
|
var ns = nodeSets[id];
|
|
4218
|
+
if (!ns) { return {} }
|
|
4219
|
+
|
|
3844
4220
|
for (var j=0;j<ns.types.length;j++) {
|
|
3845
4221
|
delete typeToId[ns.types[j]];
|
|
3846
4222
|
}
|
|
@@ -9015,6 +9391,16 @@ RED.utils = (function() {
|
|
|
9015
9391
|
$('<span class="red-ui-debug-msg-type-string-swatch"></span>').css('backgroundColor',obj).appendTo(e);
|
|
9016
9392
|
}
|
|
9017
9393
|
|
|
9394
|
+
let n = RED.nodes.node(obj) ?? RED.nodes.workspace(obj);
|
|
9395
|
+
if (n) {
|
|
9396
|
+
if (options.nodeSelector && "function" == typeof options.nodeSelector) {
|
|
9397
|
+
e.css('cursor', 'pointer').on("click", function(evt) {
|
|
9398
|
+
evt.preventDefault();
|
|
9399
|
+
options.nodeSelector(n.id);
|
|
9400
|
+
})
|
|
9401
|
+
}
|
|
9402
|
+
}
|
|
9403
|
+
|
|
9018
9404
|
} else if (typeof obj === 'number') {
|
|
9019
9405
|
e = $('<span class="red-ui-debug-msg-type-number"></span>').appendTo(entryObj);
|
|
9020
9406
|
|
|
@@ -9121,6 +9507,7 @@ RED.utils = (function() {
|
|
|
9121
9507
|
exposeApi: exposeApi,
|
|
9122
9508
|
// tools: tools // Do not pass tools down as we
|
|
9123
9509
|
// keep them attached to the top-level header
|
|
9510
|
+
nodeSelector: options.nodeSelector,
|
|
9124
9511
|
}
|
|
9125
9512
|
).appendTo(row);
|
|
9126
9513
|
}
|
|
@@ -9151,6 +9538,7 @@ RED.utils = (function() {
|
|
|
9151
9538
|
exposeApi: exposeApi,
|
|
9152
9539
|
// tools: tools // Do not pass tools down as we
|
|
9153
9540
|
// keep them attached to the top-level header
|
|
9541
|
+
nodeSelector: options.nodeSelector,
|
|
9154
9542
|
}
|
|
9155
9543
|
).appendTo(row);
|
|
9156
9544
|
}
|
|
@@ -9207,6 +9595,7 @@ RED.utils = (function() {
|
|
|
9207
9595
|
exposeApi: exposeApi,
|
|
9208
9596
|
// tools: tools // Do not pass tools down as we
|
|
9209
9597
|
// keep them attached to the top-level header
|
|
9598
|
+
nodeSelector: options.nodeSelector,
|
|
9210
9599
|
}
|
|
9211
9600
|
).appendTo(row);
|
|
9212
9601
|
}
|
|
@@ -10191,12 +10580,24 @@ RED.utils = (function() {
|
|
|
10191
10580
|
this.uiContainer.width(m[1]);
|
|
10192
10581
|
}
|
|
10193
10582
|
if (this.options.sortable) {
|
|
10583
|
+
var isCanceled = false; // Flag to track if an item has been canceled from being dropped into a different list
|
|
10584
|
+
var noDrop = false; // Flag to track if an item is being dragged into a different list
|
|
10194
10585
|
var handle = (typeof this.options.sortable === 'string')?
|
|
10195
10586
|
this.options.sortable :
|
|
10196
10587
|
".red-ui-editableList-item-handle";
|
|
10197
10588
|
var sortOptions = {
|
|
10198
10589
|
axis: "y",
|
|
10199
10590
|
update: function( event, ui ) {
|
|
10591
|
+
// dont trigger update if the item is being canceled
|
|
10592
|
+
const targetList = $(event.target);
|
|
10593
|
+
const draggedItem = ui.item;
|
|
10594
|
+
const draggedItemParent = draggedItem.parent();
|
|
10595
|
+
if (!targetList.is(draggedItemParent) && draggedItem.hasClass("red-ui-editableList-item-constrained")) {
|
|
10596
|
+
noDrop = true;
|
|
10597
|
+
}
|
|
10598
|
+
if (isCanceled || noDrop) {
|
|
10599
|
+
return;
|
|
10600
|
+
}
|
|
10200
10601
|
if (that.options.sortItems) {
|
|
10201
10602
|
that.options.sortItems(that.items());
|
|
10202
10603
|
}
|
|
@@ -10206,8 +10607,32 @@ RED.utils = (function() {
|
|
|
10206
10607
|
tolerance: "pointer",
|
|
10207
10608
|
forcePlaceholderSize:true,
|
|
10208
10609
|
placeholder: "red-ui-editabelList-item-placeholder",
|
|
10209
|
-
start: function(
|
|
10210
|
-
|
|
10610
|
+
start: function (event, ui) {
|
|
10611
|
+
isCanceled = false;
|
|
10612
|
+
ui.placeholder.height(ui.item.height() - 4);
|
|
10613
|
+
ui.item.css('cursor', 'grabbing'); // TODO: this doesn't seem to work, use a class instead?
|
|
10614
|
+
},
|
|
10615
|
+
stop: function (event, ui) {
|
|
10616
|
+
ui.item.css('cursor', 'auto');
|
|
10617
|
+
},
|
|
10618
|
+
receive: function (event, ui) {
|
|
10619
|
+
if (ui.item.hasClass("red-ui-editableList-item-constrained")) {
|
|
10620
|
+
isCanceled = true;
|
|
10621
|
+
$(ui.sender).sortable('cancel');
|
|
10622
|
+
}
|
|
10623
|
+
},
|
|
10624
|
+
over: function (event, ui) {
|
|
10625
|
+
// if the dragged item is constrained, prevent it from being dropped into a different list
|
|
10626
|
+
const targetList = $(event.target);
|
|
10627
|
+
const draggedItem = ui.item;
|
|
10628
|
+
const draggedItemParent = draggedItem.parent();
|
|
10629
|
+
if (!targetList.is(draggedItemParent) && draggedItem.hasClass("red-ui-editableList-item-constrained")) {
|
|
10630
|
+
noDrop = true;
|
|
10631
|
+
draggedItem.css('cursor', 'no-drop'); // TODO: this doesn't seem to work, use a class instead?
|
|
10632
|
+
} else {
|
|
10633
|
+
noDrop = false;
|
|
10634
|
+
draggedItem.css('cursor', 'grabbing'); // TODO: this doesn't seem to work, use a class instead?
|
|
10635
|
+
}
|
|
10211
10636
|
}
|
|
10212
10637
|
};
|
|
10213
10638
|
if (this.options.connectWith) {
|
|
@@ -12254,7 +12679,7 @@ RED.popover = (function() {
|
|
|
12254
12679
|
closePopup(true);
|
|
12255
12680
|
});
|
|
12256
12681
|
}
|
|
12257
|
-
if (trigger === 'hover' && options.interactive) {
|
|
12682
|
+
if (/*trigger === 'hover' && */options.interactive) {
|
|
12258
12683
|
div.on('mouseenter', function(e) {
|
|
12259
12684
|
clearTimeout(timer);
|
|
12260
12685
|
active = true;
|
|
@@ -14171,25 +14596,26 @@ RED.stack = (function() {
|
|
|
14171
14596
|
return icon;
|
|
14172
14597
|
}
|
|
14173
14598
|
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
|
|
14184
|
-
|
|
14185
|
-
|
|
14186
|
-
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
|
|
14599
|
+
function getMatch(value, searchValue) {
|
|
14600
|
+
const idx = value.toLowerCase().indexOf(searchValue.toLowerCase());
|
|
14601
|
+
const len = idx > -1 ? searchValue.length : 0;
|
|
14602
|
+
return {
|
|
14603
|
+
index: idx,
|
|
14604
|
+
found: idx > -1,
|
|
14605
|
+
pre: value.substring(0,idx),
|
|
14606
|
+
match: value.substring(idx,idx+len),
|
|
14607
|
+
post: value.substring(idx+len),
|
|
14608
|
+
}
|
|
14609
|
+
}
|
|
14610
|
+
function generateSpans(match) {
|
|
14611
|
+
const els = [];
|
|
14612
|
+
if(match.pre) { els.push($('<span/>').text(match.pre)); }
|
|
14613
|
+
if(match.match) { els.push($('<span/>',{style:"font-weight: bold; color: var(--red-ui-text-color-link);"}).text(match.match)); }
|
|
14614
|
+
if(match.post) { els.push($('<span/>').text(match.post)); }
|
|
14615
|
+
return els;
|
|
14616
|
+
}
|
|
14617
|
+
|
|
14618
|
+
const msgAutoComplete = function(options) {
|
|
14193
14619
|
return function(val) {
|
|
14194
14620
|
var matches = [];
|
|
14195
14621
|
options.forEach(opt => {
|
|
@@ -14219,6 +14645,197 @@ RED.stack = (function() {
|
|
|
14219
14645
|
}
|
|
14220
14646
|
}
|
|
14221
14647
|
|
|
14648
|
+
function getEnvVars (obj, envVars = {}) {
|
|
14649
|
+
contextKnownKeys.env = contextKnownKeys.env || {}
|
|
14650
|
+
if (contextKnownKeys.env[obj.id]) {
|
|
14651
|
+
return contextKnownKeys.env[obj.id]
|
|
14652
|
+
}
|
|
14653
|
+
let parent
|
|
14654
|
+
if (obj.type === 'tab' || obj.type === 'subflow') {
|
|
14655
|
+
RED.nodes.eachConfig(function (conf) {
|
|
14656
|
+
if (conf.type === "global-config") {
|
|
14657
|
+
parent = conf;
|
|
14658
|
+
}
|
|
14659
|
+
})
|
|
14660
|
+
} else if (obj.g) {
|
|
14661
|
+
parent = RED.nodes.group(obj.g)
|
|
14662
|
+
} else if (obj.z) {
|
|
14663
|
+
parent = RED.nodes.workspace(obj.z) || RED.nodes.subflow(obj.z)
|
|
14664
|
+
}
|
|
14665
|
+
if (parent) {
|
|
14666
|
+
getEnvVars(parent, envVars)
|
|
14667
|
+
}
|
|
14668
|
+
if (obj.env) {
|
|
14669
|
+
obj.env.forEach(env => {
|
|
14670
|
+
envVars[env.name] = obj
|
|
14671
|
+
})
|
|
14672
|
+
}
|
|
14673
|
+
contextKnownKeys.env[obj.id] = envVars
|
|
14674
|
+
return envVars
|
|
14675
|
+
}
|
|
14676
|
+
|
|
14677
|
+
const envAutoComplete = function (val) {
|
|
14678
|
+
const editStack = RED.editor.getEditStack()
|
|
14679
|
+
if (editStack.length === 0) {
|
|
14680
|
+
done([])
|
|
14681
|
+
return
|
|
14682
|
+
}
|
|
14683
|
+
const editingNode = editStack.pop()
|
|
14684
|
+
if (!editingNode) {
|
|
14685
|
+
return []
|
|
14686
|
+
}
|
|
14687
|
+
const envVarsMap = getEnvVars(editingNode)
|
|
14688
|
+
const envVars = Object.keys(envVarsMap)
|
|
14689
|
+
const matches = []
|
|
14690
|
+
const i = val.lastIndexOf('${')
|
|
14691
|
+
let searchKey = val
|
|
14692
|
+
let isSubkey = false
|
|
14693
|
+
if (i > -1) {
|
|
14694
|
+
if (val.lastIndexOf('}') < i) {
|
|
14695
|
+
searchKey = val.substring(i+2)
|
|
14696
|
+
isSubkey = true
|
|
14697
|
+
}
|
|
14698
|
+
}
|
|
14699
|
+
envVars.forEach(v => {
|
|
14700
|
+
let valMatch = getMatch(v, searchKey);
|
|
14701
|
+
if (valMatch.found) {
|
|
14702
|
+
const optSrc = envVarsMap[v]
|
|
14703
|
+
const element = $('<div>',{style: "display: flex"});
|
|
14704
|
+
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
|
|
14705
|
+
valEl.append(generateSpans(valMatch))
|
|
14706
|
+
valEl.appendTo(element)
|
|
14707
|
+
|
|
14708
|
+
if (optSrc) {
|
|
14709
|
+
const optEl = $('<div>').css({ "font-size": "0.8em" });
|
|
14710
|
+
let label
|
|
14711
|
+
if (optSrc.type === 'global-config') {
|
|
14712
|
+
label = RED._('sidebar.context.global')
|
|
14713
|
+
} else if (optSrc.type === 'group') {
|
|
14714
|
+
label = RED.utils.getNodeLabel(optSrc) || (RED._('sidebar.info.group') + ': '+optSrc.id)
|
|
14715
|
+
} else {
|
|
14716
|
+
label = RED.utils.getNodeLabel(optSrc) || optSrc.id
|
|
14717
|
+
}
|
|
14718
|
+
|
|
14719
|
+
optEl.append(generateSpans({ match: label }));
|
|
14720
|
+
optEl.appendTo(element);
|
|
14721
|
+
}
|
|
14722
|
+
matches.push({
|
|
14723
|
+
value: isSubkey ? val + v + '}' : v,
|
|
14724
|
+
label: element,
|
|
14725
|
+
i: valMatch.index
|
|
14726
|
+
});
|
|
14727
|
+
}
|
|
14728
|
+
})
|
|
14729
|
+
matches.sort(function(A,B){return A.i-B.i})
|
|
14730
|
+
return matches
|
|
14731
|
+
}
|
|
14732
|
+
|
|
14733
|
+
let contextKnownKeys = {}
|
|
14734
|
+
let contextCache = {}
|
|
14735
|
+
if (RED.events) {
|
|
14736
|
+
RED.events.on("editor:close", function () {
|
|
14737
|
+
contextCache = {}
|
|
14738
|
+
contextKnownKeys = {}
|
|
14739
|
+
});
|
|
14740
|
+
}
|
|
14741
|
+
|
|
14742
|
+
const contextAutoComplete = function() {
|
|
14743
|
+
const that = this
|
|
14744
|
+
const getContextKeysFromRuntime = function(scope, store, searchKey, done) {
|
|
14745
|
+
contextKnownKeys[scope] = contextKnownKeys[scope] || {}
|
|
14746
|
+
contextKnownKeys[scope][store] = contextKnownKeys[scope][store] || new Set()
|
|
14747
|
+
if (searchKey.length > 0) {
|
|
14748
|
+
try {
|
|
14749
|
+
RED.utils.normalisePropertyExpression(searchKey)
|
|
14750
|
+
} catch (err) {
|
|
14751
|
+
// Not a valid context key, so don't try looking up
|
|
14752
|
+
done()
|
|
14753
|
+
return
|
|
14754
|
+
}
|
|
14755
|
+
}
|
|
14756
|
+
const url = `context/${scope}/${encodeURIComponent(searchKey)}?store=${store}&keysOnly`
|
|
14757
|
+
if (contextCache[url]) {
|
|
14758
|
+
// console.log('CACHED', url)
|
|
14759
|
+
done()
|
|
14760
|
+
} else {
|
|
14761
|
+
// console.log('GET', url)
|
|
14762
|
+
$.getJSON(url, function(data) {
|
|
14763
|
+
// console.log(data)
|
|
14764
|
+
contextCache[url] = true
|
|
14765
|
+
const result = data[store] || {}
|
|
14766
|
+
const keys = result.keys || []
|
|
14767
|
+
const keyPrefix = searchKey + (searchKey.length > 0 ? '.' : '')
|
|
14768
|
+
keys.forEach(key => {
|
|
14769
|
+
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(key)) {
|
|
14770
|
+
contextKnownKeys[scope][store].add(keyPrefix + key)
|
|
14771
|
+
} else {
|
|
14772
|
+
contextKnownKeys[scope][store].add(searchKey + "[\""+key.replace(/"/,"\\\"")+"\"]")
|
|
14773
|
+
}
|
|
14774
|
+
})
|
|
14775
|
+
done()
|
|
14776
|
+
})
|
|
14777
|
+
}
|
|
14778
|
+
}
|
|
14779
|
+
const getContextKeys = function(key, done) {
|
|
14780
|
+
const keyParts = key.split('.')
|
|
14781
|
+
const partialKey = keyParts.pop()
|
|
14782
|
+
let scope = that.propertyType
|
|
14783
|
+
if (scope === 'flow') {
|
|
14784
|
+
// Get the flow id of the node we're editing
|
|
14785
|
+
const editStack = RED.editor.getEditStack()
|
|
14786
|
+
if (editStack.length === 0) {
|
|
14787
|
+
done([])
|
|
14788
|
+
return
|
|
14789
|
+
}
|
|
14790
|
+
const editingNode = editStack.pop()
|
|
14791
|
+
if (editingNode.z) {
|
|
14792
|
+
scope = `${scope}/${editingNode.z}`
|
|
14793
|
+
} else {
|
|
14794
|
+
done([])
|
|
14795
|
+
return
|
|
14796
|
+
}
|
|
14797
|
+
}
|
|
14798
|
+
const store = (contextStoreOptions.length === 1) ? contextStoreOptions[0].value : that.optionValue
|
|
14799
|
+
const searchKey = keyParts.join('.')
|
|
14800
|
+
|
|
14801
|
+
getContextKeysFromRuntime(scope, store, searchKey, function() {
|
|
14802
|
+
if (contextKnownKeys[scope][store].has(key) || key.endsWith(']')) {
|
|
14803
|
+
getContextKeysFromRuntime(scope, store, key, function() {
|
|
14804
|
+
done(contextKnownKeys[scope][store])
|
|
14805
|
+
})
|
|
14806
|
+
}
|
|
14807
|
+
done(contextKnownKeys[scope][store])
|
|
14808
|
+
})
|
|
14809
|
+
}
|
|
14810
|
+
|
|
14811
|
+
return function(val, done) {
|
|
14812
|
+
getContextKeys(val, function (keys) {
|
|
14813
|
+
const matches = []
|
|
14814
|
+
keys.forEach(v => {
|
|
14815
|
+
let optVal = v
|
|
14816
|
+
let valMatch = getMatch(optVal, val);
|
|
14817
|
+
if (!valMatch.found && val.length > 0 && val.endsWith('.')) {
|
|
14818
|
+
// Search key ends in '.' - but doesn't match. Check again
|
|
14819
|
+
// with [" at the end instead so we match bracket notation
|
|
14820
|
+
valMatch = getMatch(optVal, val.substring(0, val.length - 1) + '["')
|
|
14821
|
+
}
|
|
14822
|
+
if (valMatch.found) {
|
|
14823
|
+
const element = $('<div>',{style: "display: flex"});
|
|
14824
|
+
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
|
|
14825
|
+
valEl.append(generateSpans(valMatch))
|
|
14826
|
+
valEl.appendTo(element)
|
|
14827
|
+
matches.push({
|
|
14828
|
+
value: optVal,
|
|
14829
|
+
label: element,
|
|
14830
|
+
});
|
|
14831
|
+
}
|
|
14832
|
+
})
|
|
14833
|
+
matches.sort(function(a, b) { return a.value.localeCompare(b.value) });
|
|
14834
|
+
done(matches);
|
|
14835
|
+
})
|
|
14836
|
+
}
|
|
14837
|
+
}
|
|
14838
|
+
|
|
14222
14839
|
// This is a hand-generated list of completions for the core nodes (based on the node help html).
|
|
14223
14840
|
var msgCompletions = [
|
|
14224
14841
|
{ value: "payload" },
|
|
@@ -14283,20 +14900,22 @@ RED.stack = (function() {
|
|
|
14283
14900
|
{ value: "_session", source: ["websocket out","tcp out"] },
|
|
14284
14901
|
]
|
|
14285
14902
|
var allOptions = {
|
|
14286
|
-
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete:
|
|
14903
|
+
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: msgAutoComplete(msgCompletions)},
|
|
14287
14904
|
flow: {value:"flow",label:"flow.",hasValue:true,
|
|
14288
14905
|
options:[],
|
|
14289
14906
|
validate:RED.utils.validatePropertyExpression,
|
|
14290
14907
|
parse: contextParse,
|
|
14291
14908
|
export: contextExport,
|
|
14292
|
-
valueLabel: contextLabel
|
|
14909
|
+
valueLabel: contextLabel,
|
|
14910
|
+
autoComplete: contextAutoComplete
|
|
14293
14911
|
},
|
|
14294
14912
|
global: {value:"global",label:"global.",hasValue:true,
|
|
14295
14913
|
options:[],
|
|
14296
14914
|
validate:RED.utils.validatePropertyExpression,
|
|
14297
14915
|
parse: contextParse,
|
|
14298
14916
|
export: contextExport,
|
|
14299
|
-
valueLabel: contextLabel
|
|
14917
|
+
valueLabel: contextLabel,
|
|
14918
|
+
autoComplete: contextAutoComplete
|
|
14300
14919
|
},
|
|
14301
14920
|
str: {value:"str",label:"string",icon:"red/images/typedInput/az.svg"},
|
|
14302
14921
|
num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate: function(v) {
|
|
@@ -14331,7 +14950,25 @@ RED.stack = (function() {
|
|
|
14331
14950
|
}
|
|
14332
14951
|
},
|
|
14333
14952
|
re: {value:"re",label:"regular expression",icon:"red/images/typedInput/re.svg"},
|
|
14334
|
-
date: {
|
|
14953
|
+
date: {
|
|
14954
|
+
value:"date",
|
|
14955
|
+
label:"timestamp",
|
|
14956
|
+
icon:"fa fa-clock-o",
|
|
14957
|
+
options:[
|
|
14958
|
+
{
|
|
14959
|
+
label: 'milliseconds since epoch',
|
|
14960
|
+
value: ''
|
|
14961
|
+
},
|
|
14962
|
+
{
|
|
14963
|
+
label: 'YYYY-MM-DDTHH:mm:ss.sssZ',
|
|
14964
|
+
value: 'iso'
|
|
14965
|
+
},
|
|
14966
|
+
{
|
|
14967
|
+
label: 'JavaScript Date Object',
|
|
14968
|
+
value: 'object'
|
|
14969
|
+
}
|
|
14970
|
+
]
|
|
14971
|
+
},
|
|
14335
14972
|
jsonata: {
|
|
14336
14973
|
value: "jsonata",
|
|
14337
14974
|
label: "expression",
|
|
@@ -14368,7 +15005,8 @@ RED.stack = (function() {
|
|
|
14368
15005
|
env: {
|
|
14369
15006
|
value: "env",
|
|
14370
15007
|
label: "env variable",
|
|
14371
|
-
icon: "red/images/typedInput/env.svg"
|
|
15008
|
+
icon: "red/images/typedInput/env.svg",
|
|
15009
|
+
autoComplete: envAutoComplete
|
|
14372
15010
|
},
|
|
14373
15011
|
node: {
|
|
14374
15012
|
value: "node",
|
|
@@ -14500,18 +15138,75 @@ RED.stack = (function() {
|
|
|
14500
15138
|
eyeButton.show();
|
|
14501
15139
|
}
|
|
14502
15140
|
}
|
|
15141
|
+
},
|
|
15142
|
+
'conf-types': {
|
|
15143
|
+
value: "conf-types",
|
|
15144
|
+
label: "config",
|
|
15145
|
+
icon: "fa fa-cog",
|
|
15146
|
+
// hasValue: false,
|
|
15147
|
+
valueLabel: function (container, value) {
|
|
15148
|
+
// get the selected option (for access to the "name" and "module" properties)
|
|
15149
|
+
const _options = this._optionsCache || this.typeList.find(opt => opt.value === value)?.options || []
|
|
15150
|
+
const selectedOption = _options.find(opt => opt.value === value) || {
|
|
15151
|
+
title: '',
|
|
15152
|
+
name: '',
|
|
15153
|
+
module: ''
|
|
15154
|
+
}
|
|
15155
|
+
container.attr("title", selectedOption.title) // set tooltip to the full path/id of the module/node
|
|
15156
|
+
container.text(selectedOption.name) // apply the "name" of the selected option
|
|
15157
|
+
// set "line-height" such as to make the "name" appear further up, giving room for the "module" to be displayed below the value
|
|
15158
|
+
container.css("line-height", "1.4em")
|
|
15159
|
+
// add the module name in smaller, lighter font below the value
|
|
15160
|
+
$('<div></div>').text(selectedOption.module).css({
|
|
15161
|
+
// "font-family": "var(--red-ui-monospace-font)",
|
|
15162
|
+
color: "var(--red-ui-tertiary-text-color)",
|
|
15163
|
+
"font-size": "0.8em",
|
|
15164
|
+
"line-height": "1em",
|
|
15165
|
+
opacity: 0.8
|
|
15166
|
+
}).appendTo(container);
|
|
15167
|
+
},
|
|
15168
|
+
// hasValue: false,
|
|
15169
|
+
options: function () {
|
|
15170
|
+
if (this._optionsCache) {
|
|
15171
|
+
return this._optionsCache
|
|
15172
|
+
}
|
|
15173
|
+
const configNodes = RED.nodes.registry.getNodeDefinitions({configOnly: true, filter: (def) => def.type !== "global-config"}).map((def) => {
|
|
15174
|
+
// create a container with with 2 rows (row 1 for the name, row 2 for the module name in smaller, lighter font)
|
|
15175
|
+
const container = $('<div style="display: flex; flex-direction: column; justify-content: space-between; row-gap: 1px;">')
|
|
15176
|
+
const row1Name = $('<div>').text(def.type)
|
|
15177
|
+
const row2Module = $('<div style="font-size: 0.8em; color: var(--red-ui-tertiary-text-color);">').text(def.set.module)
|
|
15178
|
+
container.append(row1Name, row2Module)
|
|
15179
|
+
|
|
15180
|
+
return {
|
|
15181
|
+
value: def.type,
|
|
15182
|
+
name: def.type,
|
|
15183
|
+
enabled: def.set.enabled ?? true,
|
|
15184
|
+
local: def.set.local,
|
|
15185
|
+
title: def.set.id, // tooltip e.g. "node-red-contrib-foo/bar"
|
|
15186
|
+
module: def.set.module,
|
|
15187
|
+
icon: container[0].outerHTML.trim(), // the typeInput will interpret this as html text and render it in the anchor
|
|
15188
|
+
}
|
|
15189
|
+
})
|
|
15190
|
+
this._optionsCache = configNodes
|
|
15191
|
+
return configNodes
|
|
15192
|
+
}
|
|
14503
15193
|
}
|
|
14504
15194
|
};
|
|
14505
15195
|
|
|
15196
|
+
|
|
14506
15197
|
// For a type with options, check value is a valid selection
|
|
14507
15198
|
// If !opt.multiple, returns the valid option object
|
|
14508
15199
|
// if opt.multiple, returns an array of valid option objects
|
|
14509
15200
|
// If not valid, returns null;
|
|
14510
15201
|
|
|
14511
15202
|
function isOptionValueValid(opt, currentVal) {
|
|
15203
|
+
let _options = opt.options
|
|
15204
|
+
if (typeof _options === "function") {
|
|
15205
|
+
_options = _options.call(this)
|
|
15206
|
+
}
|
|
14512
15207
|
if (!opt.multiple) {
|
|
14513
|
-
for (var i=0;i<
|
|
14514
|
-
op =
|
|
15208
|
+
for (var i=0;i<_options.length;i++) {
|
|
15209
|
+
op = _options[i];
|
|
14515
15210
|
if (typeof op === "string" && op === currentVal) {
|
|
14516
15211
|
return {value:currentVal}
|
|
14517
15212
|
} else if (op.value === currentVal) {
|
|
@@ -14528,8 +15223,8 @@ RED.stack = (function() {
|
|
|
14528
15223
|
currentValues[v] = true;
|
|
14529
15224
|
}
|
|
14530
15225
|
});
|
|
14531
|
-
for (var i=0;i<
|
|
14532
|
-
op =
|
|
15226
|
+
for (var i=0;i<_options.length;i++) {
|
|
15227
|
+
op = _options[i];
|
|
14533
15228
|
var val = typeof op === "string" ? op : op.value;
|
|
14534
15229
|
if (currentValues.hasOwnProperty(val)) {
|
|
14535
15230
|
delete currentValues[val];
|
|
@@ -14544,6 +15239,7 @@ RED.stack = (function() {
|
|
|
14544
15239
|
}
|
|
14545
15240
|
|
|
14546
15241
|
var nlsd = false;
|
|
15242
|
+
let contextStoreOptions;
|
|
14547
15243
|
|
|
14548
15244
|
$.widget( "nodered.typedInput", {
|
|
14549
15245
|
_create: function() {
|
|
@@ -14555,7 +15251,7 @@ RED.stack = (function() {
|
|
|
14555
15251
|
}
|
|
14556
15252
|
}
|
|
14557
15253
|
var contextStores = RED.settings.context.stores;
|
|
14558
|
-
|
|
15254
|
+
contextStoreOptions = contextStores.map(function(store) {
|
|
14559
15255
|
return {value:store,label: store, icon:'<i class="red-ui-typedInput-icon fa fa-database"></i>'}
|
|
14560
15256
|
}).sort(function(A,B) {
|
|
14561
15257
|
if (A.value === RED.settings.context.default) {
|
|
@@ -14566,13 +15262,17 @@ RED.stack = (function() {
|
|
|
14566
15262
|
return A.value.localeCompare(B.value);
|
|
14567
15263
|
}
|
|
14568
15264
|
})
|
|
14569
|
-
if (
|
|
15265
|
+
if (contextStoreOptions.length < 2) {
|
|
14570
15266
|
allOptions.flow.options = [];
|
|
14571
15267
|
allOptions.global.options = [];
|
|
14572
15268
|
} else {
|
|
14573
|
-
allOptions.flow.options =
|
|
14574
|
-
allOptions.global.options =
|
|
15269
|
+
allOptions.flow.options = contextStoreOptions;
|
|
15270
|
+
allOptions.global.options = contextStoreOptions;
|
|
14575
15271
|
}
|
|
15272
|
+
// Translate timestamp options
|
|
15273
|
+
allOptions.date.options.forEach(opt => {
|
|
15274
|
+
opt.label = RED._("typedInput.date.format." + (opt.value || 'timestamp'), {defaultValue: opt.label})
|
|
15275
|
+
})
|
|
14576
15276
|
}
|
|
14577
15277
|
nlsd = true;
|
|
14578
15278
|
var that = this;
|
|
@@ -14661,7 +15361,7 @@ RED.stack = (function() {
|
|
|
14661
15361
|
that.element.trigger('paste',evt);
|
|
14662
15362
|
});
|
|
14663
15363
|
this.input.on('keydown', function(evt) {
|
|
14664
|
-
if (that.typeMap[that.propertyType].autoComplete) {
|
|
15364
|
+
if (that.typeMap[that.propertyType].autoComplete || that.input.hasClass('red-ui-autoComplete')) {
|
|
14665
15365
|
return
|
|
14666
15366
|
}
|
|
14667
15367
|
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
|
@@ -14955,7 +15655,9 @@ RED.stack = (function() {
|
|
|
14955
15655
|
if (this.optionMenu) {
|
|
14956
15656
|
this.optionMenu.remove();
|
|
14957
15657
|
}
|
|
14958
|
-
this.menu
|
|
15658
|
+
if (this.menu) {
|
|
15659
|
+
this.menu.remove();
|
|
15660
|
+
}
|
|
14959
15661
|
this.uiSelect.remove();
|
|
14960
15662
|
},
|
|
14961
15663
|
types: function(types) {
|
|
@@ -14988,7 +15690,7 @@ RED.stack = (function() {
|
|
|
14988
15690
|
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
|
|
14989
15691
|
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
|
|
14990
15692
|
if (!firstCall) {
|
|
14991
|
-
this.type(this.typeList[0]
|
|
15693
|
+
this.type(this.typeList[0]?.value || ""); // permit empty typeList
|
|
14992
15694
|
}
|
|
14993
15695
|
} else {
|
|
14994
15696
|
this.propertyType = null;
|
|
@@ -15025,6 +15727,11 @@ RED.stack = (function() {
|
|
|
15025
15727
|
var selectedOption = [];
|
|
15026
15728
|
var valueToCheck = value;
|
|
15027
15729
|
if (opt.options) {
|
|
15730
|
+
let _options = opt.options
|
|
15731
|
+
if (typeof opt.options === "function") {
|
|
15732
|
+
_options = opt.options.call(this)
|
|
15733
|
+
}
|
|
15734
|
+
|
|
15028
15735
|
if (opt.hasValue && opt.parse) {
|
|
15029
15736
|
var parts = opt.parse(value);
|
|
15030
15737
|
if (this.options.debug) { console.log(this.identifier,"new parse",parts) }
|
|
@@ -15038,8 +15745,8 @@ RED.stack = (function() {
|
|
|
15038
15745
|
checkValues = valueToCheck.split(",");
|
|
15039
15746
|
}
|
|
15040
15747
|
checkValues.forEach(function(valueToCheck) {
|
|
15041
|
-
for (var i=0;i<
|
|
15042
|
-
var op =
|
|
15748
|
+
for (var i=0;i<_options.length;i++) {
|
|
15749
|
+
var op = _options[i];
|
|
15043
15750
|
if (typeof op === "string") {
|
|
15044
15751
|
if (op === valueToCheck || op === ""+valueToCheck) {
|
|
15045
15752
|
selectedOption.push(that.activeOptions[op]);
|
|
@@ -15074,7 +15781,7 @@ RED.stack = (function() {
|
|
|
15074
15781
|
},
|
|
15075
15782
|
type: function(type) {
|
|
15076
15783
|
if (!arguments.length) {
|
|
15077
|
-
return this.propertyType;
|
|
15784
|
+
return this.propertyType || this.options?.default || '';
|
|
15078
15785
|
} else {
|
|
15079
15786
|
var that = this;
|
|
15080
15787
|
if (this.options.debug) { console.log(this.identifier,"----- SET TYPE -----",type) }
|
|
@@ -15084,6 +15791,9 @@ RED.stack = (function() {
|
|
|
15084
15791
|
// If previousType is !null, then this is a change of the type, rather than the initialisation
|
|
15085
15792
|
var previousType = this.typeMap[this.propertyType];
|
|
15086
15793
|
previousValue = this.input.val();
|
|
15794
|
+
if (this.input.hasClass('red-ui-autoComplete')) {
|
|
15795
|
+
this.input.autoComplete("destroy");
|
|
15796
|
+
}
|
|
15087
15797
|
|
|
15088
15798
|
if (previousType && this.typeChanged) {
|
|
15089
15799
|
if (this.options.debug) { console.log(this.identifier,"typeChanged",{previousType,previousValue}) }
|
|
@@ -15130,7 +15840,9 @@ RED.stack = (function() {
|
|
|
15130
15840
|
this.input.val(this.oldValues.hasOwnProperty("_")?this.oldValues["_"]:(opt.default||""))
|
|
15131
15841
|
}
|
|
15132
15842
|
if (previousType.autoComplete) {
|
|
15133
|
-
this.input.autoComplete
|
|
15843
|
+
if (this.input.hasClass('red-ui-autoComplete')) {
|
|
15844
|
+
this.input.autoComplete("destroy");
|
|
15845
|
+
}
|
|
15134
15846
|
}
|
|
15135
15847
|
}
|
|
15136
15848
|
this.propertyType = type;
|
|
@@ -15170,6 +15882,10 @@ RED.stack = (function() {
|
|
|
15170
15882
|
this.optionMenu = null;
|
|
15171
15883
|
}
|
|
15172
15884
|
if (opt.options) {
|
|
15885
|
+
let _options = opt.options
|
|
15886
|
+
if (typeof _options === "function") {
|
|
15887
|
+
_options = opt.options.call(this);
|
|
15888
|
+
}
|
|
15173
15889
|
if (this.optionExpandButton) {
|
|
15174
15890
|
this.optionExpandButton.hide();
|
|
15175
15891
|
this.optionExpandButton.shown = false;
|
|
@@ -15186,7 +15902,7 @@ RED.stack = (function() {
|
|
|
15186
15902
|
this.valueLabelContainer.hide();
|
|
15187
15903
|
}
|
|
15188
15904
|
this.activeOptions = {};
|
|
15189
|
-
|
|
15905
|
+
_options.forEach(function(o) {
|
|
15190
15906
|
if (typeof o === 'string') {
|
|
15191
15907
|
that.activeOptions[o] = {label:o,value:o};
|
|
15192
15908
|
} else {
|
|
@@ -15206,7 +15922,7 @@ RED.stack = (function() {
|
|
|
15206
15922
|
if (validValues) {
|
|
15207
15923
|
that._updateOptionSelectLabel(validValues)
|
|
15208
15924
|
} else {
|
|
15209
|
-
op =
|
|
15925
|
+
op = _options[0] || {value:""}; // permit zero options
|
|
15210
15926
|
if (typeof op === "string") {
|
|
15211
15927
|
this.value(op);
|
|
15212
15928
|
that._updateOptionSelectLabel({value:op});
|
|
@@ -15225,7 +15941,7 @@ RED.stack = (function() {
|
|
|
15225
15941
|
that._updateOptionSelectLabel(validValues);
|
|
15226
15942
|
}
|
|
15227
15943
|
} else {
|
|
15228
|
-
var selectedOption = this.optionValue||
|
|
15944
|
+
var selectedOption = this.optionValue||_options[0];
|
|
15229
15945
|
if (opt.parse) {
|
|
15230
15946
|
var selectedOptionObj = typeof selectedOption === "string"?{value:selectedOption}:selectedOption
|
|
15231
15947
|
var parts = opt.parse(this.input.val(),selectedOptionObj);
|
|
@@ -15258,8 +15974,18 @@ RED.stack = (function() {
|
|
|
15258
15974
|
} else {
|
|
15259
15975
|
this.optionSelectTrigger.hide();
|
|
15260
15976
|
}
|
|
15977
|
+
if (opt.autoComplete) {
|
|
15978
|
+
let searchFunction = opt.autoComplete
|
|
15979
|
+
if (searchFunction.length === 0) {
|
|
15980
|
+
searchFunction = opt.autoComplete.call(this)
|
|
15981
|
+
}
|
|
15982
|
+
this.input.autoComplete({
|
|
15983
|
+
search: searchFunction,
|
|
15984
|
+
minLength: 0
|
|
15985
|
+
})
|
|
15986
|
+
}
|
|
15261
15987
|
}
|
|
15262
|
-
this.optionMenu = this._createMenu(
|
|
15988
|
+
this.optionMenu = this._createMenu(_options,opt,function(v){
|
|
15263
15989
|
if (!opt.multiple) {
|
|
15264
15990
|
that._updateOptionSelectLabel(that.activeOptions[v]);
|
|
15265
15991
|
if (!opt.hasValue) {
|
|
@@ -15300,8 +16026,12 @@ RED.stack = (function() {
|
|
|
15300
16026
|
this.valueLabelContainer.hide();
|
|
15301
16027
|
this.elementDiv.show();
|
|
15302
16028
|
if (opt.autoComplete) {
|
|
16029
|
+
let searchFunction = opt.autoComplete
|
|
16030
|
+
if (searchFunction.length === 0) {
|
|
16031
|
+
searchFunction = opt.autoComplete.call(this)
|
|
16032
|
+
}
|
|
15303
16033
|
this.input.autoComplete({
|
|
15304
|
-
search:
|
|
16034
|
+
search: searchFunction,
|
|
15305
16035
|
minLength: 0
|
|
15306
16036
|
})
|
|
15307
16037
|
}
|
|
@@ -19560,10 +20290,6 @@ RED.keyboard = (function() {
|
|
|
19560
20290
|
}
|
|
19561
20291
|
|
|
19562
20292
|
function init(done) {
|
|
19563
|
-
if (!RED.user.hasPermission("settings.write")) {
|
|
19564
|
-
RED.notify(RED._("user.errors.settings"),"error");
|
|
19565
|
-
return;
|
|
19566
|
-
}
|
|
19567
20293
|
RED.userSettings.add({
|
|
19568
20294
|
id:'envvar',
|
|
19569
20295
|
title: RED._("env-var.environment"),
|
|
@@ -26818,6 +27544,10 @@ RED.view = (function() {
|
|
|
26818
27544
|
}
|
|
26819
27545
|
})
|
|
26820
27546
|
}
|
|
27547
|
+
if (selection.links) {
|
|
27548
|
+
selectedLinks.clear();
|
|
27549
|
+
selection.links.forEach(selectedLinks.add);
|
|
27550
|
+
}
|
|
26821
27551
|
}
|
|
26822
27552
|
}
|
|
26823
27553
|
updateSelection();
|
|
@@ -29071,6 +29801,10 @@ RED.palette = (function() {
|
|
|
29071
29801
|
var categoryContainers = {};
|
|
29072
29802
|
var sidebarControls;
|
|
29073
29803
|
|
|
29804
|
+
let paletteState = { filter: "", collapsed: [] };
|
|
29805
|
+
|
|
29806
|
+
let filterRefreshTimeout
|
|
29807
|
+
|
|
29074
29808
|
function createCategory(originalCategory,rootCategory,category,ns) {
|
|
29075
29809
|
if ($("#red-ui-palette-base-category-"+rootCategory).length === 0) {
|
|
29076
29810
|
createCategoryContainer(originalCategory,rootCategory, ns+":palette.label."+rootCategory);
|
|
@@ -29096,20 +29830,57 @@ RED.palette = (function() {
|
|
|
29096
29830
|
catDiv.data('label',label);
|
|
29097
29831
|
categoryContainers[category] = {
|
|
29098
29832
|
container: catDiv,
|
|
29099
|
-
|
|
29833
|
+
hide: function (instant) {
|
|
29834
|
+
if (instant) {
|
|
29835
|
+
catDiv.hide()
|
|
29836
|
+
} else {
|
|
29837
|
+
catDiv.slideUp()
|
|
29838
|
+
}
|
|
29839
|
+
},
|
|
29840
|
+
show: function () {
|
|
29841
|
+
catDiv.show()
|
|
29842
|
+
},
|
|
29843
|
+
isOpen: function () {
|
|
29844
|
+
return !!catDiv.hasClass("red-ui-palette-open")
|
|
29845
|
+
},
|
|
29846
|
+
getNodeCount: function (visibleOnly) {
|
|
29847
|
+
const nodes = catDiv.find(".red-ui-palette-node")
|
|
29848
|
+
if (visibleOnly) {
|
|
29849
|
+
return nodes.filter(function() { return $(this).css('display') !== 'none'}).length
|
|
29850
|
+
} else {
|
|
29851
|
+
return nodes.length
|
|
29852
|
+
}
|
|
29853
|
+
},
|
|
29854
|
+
close: function(instant, skipSaveState) {
|
|
29100
29855
|
catDiv.removeClass("red-ui-palette-open");
|
|
29101
29856
|
catDiv.addClass("red-ui-palette-closed");
|
|
29102
|
-
|
|
29857
|
+
if (instant) {
|
|
29858
|
+
$("#red-ui-palette-base-category-"+category).hide();
|
|
29859
|
+
} else {
|
|
29860
|
+
$("#red-ui-palette-base-category-"+category).slideUp();
|
|
29861
|
+
}
|
|
29103
29862
|
$("#red-ui-palette-header-"+category+" i").removeClass("expanded");
|
|
29863
|
+
if (!skipSaveState) {
|
|
29864
|
+
if (!paletteState.collapsed.includes(category)) {
|
|
29865
|
+
paletteState.collapsed.push(category);
|
|
29866
|
+
savePaletteState();
|
|
29867
|
+
}
|
|
29868
|
+
}
|
|
29104
29869
|
},
|
|
29105
|
-
open: function() {
|
|
29870
|
+
open: function(skipSaveState) {
|
|
29106
29871
|
catDiv.addClass("red-ui-palette-open");
|
|
29107
29872
|
catDiv.removeClass("red-ui-palette-closed");
|
|
29108
29873
|
$("#red-ui-palette-base-category-"+category).slideDown();
|
|
29109
29874
|
$("#red-ui-palette-header-"+category+" i").addClass("expanded");
|
|
29875
|
+
if (!skipSaveState) {
|
|
29876
|
+
if (paletteState.collapsed.includes(category)) {
|
|
29877
|
+
paletteState.collapsed.splice(paletteState.collapsed.indexOf(category), 1);
|
|
29878
|
+
savePaletteState();
|
|
29879
|
+
}
|
|
29880
|
+
}
|
|
29110
29881
|
},
|
|
29111
29882
|
toggle: function() {
|
|
29112
|
-
if (
|
|
29883
|
+
if (categoryContainers[category].isOpen()) {
|
|
29113
29884
|
categoryContainers[category].close();
|
|
29114
29885
|
} else {
|
|
29115
29886
|
categoryContainers[category].open();
|
|
@@ -29451,8 +30222,16 @@ RED.palette = (function() {
|
|
|
29451
30222
|
|
|
29452
30223
|
var categoryNode = $("#red-ui-palette-container-"+rootCategory);
|
|
29453
30224
|
if (categoryNode.find(".red-ui-palette-node").length === 1) {
|
|
29454
|
-
|
|
30225
|
+
if (!paletteState?.collapsed?.includes(rootCategory)) {
|
|
30226
|
+
categoryContainers[rootCategory].open();
|
|
30227
|
+
} else {
|
|
30228
|
+
categoryContainers[rootCategory].close(true);
|
|
30229
|
+
}
|
|
29455
30230
|
}
|
|
30231
|
+
clearTimeout(filterRefreshTimeout)
|
|
30232
|
+
filterRefreshTimeout = setTimeout(() => {
|
|
30233
|
+
refreshFilter()
|
|
30234
|
+
}, 200)
|
|
29456
30235
|
|
|
29457
30236
|
}
|
|
29458
30237
|
}
|
|
@@ -29552,7 +30331,8 @@ RED.palette = (function() {
|
|
|
29552
30331
|
paletteNode.css("backgroundColor", sf.color);
|
|
29553
30332
|
}
|
|
29554
30333
|
|
|
29555
|
-
function
|
|
30334
|
+
function refreshFilter() {
|
|
30335
|
+
const val = $("#red-ui-palette-search input").val()
|
|
29556
30336
|
var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i');
|
|
29557
30337
|
$("#red-ui-palette-container .red-ui-palette-node").each(function(i,el) {
|
|
29558
30338
|
var currentLabel = $(el).attr("data-palette-label");
|
|
@@ -29564,16 +30344,26 @@ RED.palette = (function() {
|
|
|
29564
30344
|
}
|
|
29565
30345
|
});
|
|
29566
30346
|
|
|
29567
|
-
for (
|
|
30347
|
+
for (let category in categoryContainers) {
|
|
29568
30348
|
if (categoryContainers.hasOwnProperty(category)) {
|
|
29569
|
-
|
|
29570
|
-
|
|
29571
|
-
|
|
29572
|
-
categoryContainers[category].close();
|
|
29573
|
-
categoryContainers[category].container.slideUp();
|
|
30349
|
+
const categorySection = categoryContainers[category]
|
|
30350
|
+
if (categorySection.getNodeCount(true) === 0) {
|
|
30351
|
+
categorySection.hide()
|
|
29574
30352
|
} else {
|
|
29575
|
-
|
|
29576
|
-
|
|
30353
|
+
categorySection.show()
|
|
30354
|
+
if (val) {
|
|
30355
|
+
// There is a filter being applied and it has matched
|
|
30356
|
+
// something in this category - show the contents
|
|
30357
|
+
categorySection.open(true)
|
|
30358
|
+
} else {
|
|
30359
|
+
// No filter. Only show the category if it isn't in lastState
|
|
30360
|
+
if (!paletteState.collapsed.includes(category)) {
|
|
30361
|
+
categorySection.open(true)
|
|
30362
|
+
} else if (categorySection.isOpen()) {
|
|
30363
|
+
// This section should be collapsed but isn't - so make it so
|
|
30364
|
+
categorySection.close(true, true)
|
|
30365
|
+
}
|
|
30366
|
+
}
|
|
29577
30367
|
}
|
|
29578
30368
|
}
|
|
29579
30369
|
}
|
|
@@ -29589,6 +30379,9 @@ RED.palette = (function() {
|
|
|
29589
30379
|
|
|
29590
30380
|
$("#red-ui-palette > .red-ui-palette-spinner").show();
|
|
29591
30381
|
|
|
30382
|
+
RED.events.on('logout', function () {
|
|
30383
|
+
RED.settings.removeLocal('palette-state')
|
|
30384
|
+
})
|
|
29592
30385
|
|
|
29593
30386
|
RED.events.on('registry:node-type-added', function(nodeType) {
|
|
29594
30387
|
var def = RED.nodes.getType(nodeType);
|
|
@@ -29632,14 +30425,14 @@ RED.palette = (function() {
|
|
|
29632
30425
|
|
|
29633
30426
|
RED.events.on("subflows:change",refreshSubflow);
|
|
29634
30427
|
|
|
29635
|
-
|
|
29636
|
-
|
|
29637
30428
|
$("#red-ui-palette-search input").searchBox({
|
|
29638
30429
|
delay: 100,
|
|
29639
30430
|
change: function() {
|
|
29640
|
-
|
|
30431
|
+
refreshFilter();
|
|
30432
|
+
paletteState.filter = $(this).val();
|
|
30433
|
+
savePaletteState();
|
|
29641
30434
|
}
|
|
29642
|
-
})
|
|
30435
|
+
});
|
|
29643
30436
|
|
|
29644
30437
|
sidebarControls = $('<div class="red-ui-sidebar-control-left"><i class="fa fa-chevron-left"></i></div>').appendTo($("#red-ui-palette"));
|
|
29645
30438
|
RED.popover.tooltip(sidebarControls,RED._("keyboard.togglePalette"),"core:toggle-palette");
|
|
@@ -29705,7 +30498,23 @@ RED.palette = (function() {
|
|
|
29705
30498
|
togglePalette(state);
|
|
29706
30499
|
}
|
|
29707
30500
|
});
|
|
30501
|
+
|
|
30502
|
+
try {
|
|
30503
|
+
paletteState = JSON.parse(RED.settings.getLocal("palette-state") || '{"filter":"", "collapsed": []}');
|
|
30504
|
+
if (paletteState.filter) {
|
|
30505
|
+
// Apply the category filter
|
|
30506
|
+
$("#red-ui-palette-search input").searchBox("value", paletteState.filter);
|
|
30507
|
+
}
|
|
30508
|
+
} catch (error) {
|
|
30509
|
+
console.error("Unexpected error loading palette state from localStorage: ", error);
|
|
30510
|
+
}
|
|
30511
|
+
setTimeout(() => {
|
|
30512
|
+
// Lazily tidy up any categories that haven't been reloaded
|
|
30513
|
+
paletteState.collapsed = paletteState.collapsed.filter(category => !!categoryContainers[category])
|
|
30514
|
+
savePaletteState()
|
|
30515
|
+
}, 10000)
|
|
29708
30516
|
}
|
|
30517
|
+
|
|
29709
30518
|
function togglePalette(state) {
|
|
29710
30519
|
if (!state) {
|
|
29711
30520
|
$("#red-ui-main-container").addClass("red-ui-palette-closed");
|
|
@@ -29725,6 +30534,15 @@ RED.palette = (function() {
|
|
|
29725
30534
|
})
|
|
29726
30535
|
return categories;
|
|
29727
30536
|
}
|
|
30537
|
+
|
|
30538
|
+
function savePaletteState() {
|
|
30539
|
+
try {
|
|
30540
|
+
RED.settings.setLocal("palette-state", JSON.stringify(paletteState));
|
|
30541
|
+
} catch (error) {
|
|
30542
|
+
console.error("Unexpected error saving palette state to localStorage: ", error);
|
|
30543
|
+
}
|
|
30544
|
+
}
|
|
30545
|
+
|
|
29728
30546
|
return {
|
|
29729
30547
|
init: init,
|
|
29730
30548
|
add:addNodeType,
|
|
@@ -31214,8 +32032,10 @@ RED.sidebar.help = (function() {
|
|
|
31214
32032
|
|
|
31215
32033
|
function refreshSubflow(sf) {
|
|
31216
32034
|
var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
|
|
31217
|
-
|
|
31218
|
-
|
|
32035
|
+
if (item) {
|
|
32036
|
+
item.subflowLabel = sf._def.label().toLowerCase();
|
|
32037
|
+
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
|
|
32038
|
+
}
|
|
31219
32039
|
}
|
|
31220
32040
|
|
|
31221
32041
|
function hideTOC() {
|
|
@@ -32582,86 +33402,106 @@ RED.palette.editor = (function() {
|
|
|
32582
33402
|
var moduleInfo = nodeEntries[module].info;
|
|
32583
33403
|
var nodeEntry = nodeEntries[module].elements;
|
|
32584
33404
|
if (nodeEntry) {
|
|
32585
|
-
|
|
32586
|
-
|
|
32587
|
-
|
|
32588
|
-
|
|
32589
|
-
|
|
32590
|
-
|
|
32591
|
-
|
|
32592
|
-
|
|
32593
|
-
|
|
32594
|
-
|
|
32595
|
-
var set = moduleInfo.sets[setName];
|
|
32596
|
-
var setElements = nodeEntry.sets[setName];
|
|
32597
|
-
if (set.err) {
|
|
32598
|
-
errorCount++;
|
|
32599
|
-
var errMessage = set.err;
|
|
32600
|
-
if (set.err.message) {
|
|
32601
|
-
errMessage = set.err.message;
|
|
32602
|
-
} else if (set.err.code) {
|
|
32603
|
-
errMessage = set.err.code;
|
|
32604
|
-
}
|
|
32605
|
-
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
|
|
32606
|
-
}
|
|
32607
|
-
if (set.enabled) {
|
|
32608
|
-
activeTypeCount += set.types.length;
|
|
32609
|
-
}
|
|
32610
|
-
typeCount += set.types.length;
|
|
32611
|
-
for (var i=0;i<moduleInfo.sets[setName].types.length;i++) {
|
|
32612
|
-
var t = moduleInfo.sets[setName].types[i];
|
|
32613
|
-
inUseCount += (typesInUse[t]||0);
|
|
32614
|
-
var swatch = setElements.swatches[t];
|
|
32615
|
-
if (set.enabled) {
|
|
32616
|
-
var def = RED.nodes.getType(t);
|
|
32617
|
-
if (def && def.color) {
|
|
32618
|
-
swatch.css({background:RED.utils.getNodeColor(t,def)});
|
|
32619
|
-
swatch.css({border: "1px solid "+getContrastingBorder(swatch.css('backgroundColor'))})
|
|
32620
|
-
}
|
|
33405
|
+
if (moduleInfo.plugin) {
|
|
33406
|
+
nodeEntry.enableButton.hide();
|
|
33407
|
+
nodeEntry.removeButton.show();
|
|
33408
|
+
|
|
33409
|
+
let pluginCount = 0;
|
|
33410
|
+
for (let setName in moduleInfo.sets) {
|
|
33411
|
+
if (moduleInfo.sets.hasOwnProperty(setName)) {
|
|
33412
|
+
let set = moduleInfo.sets[setName];
|
|
33413
|
+
if (set.plugins) {
|
|
33414
|
+
pluginCount += set.plugins.length;
|
|
32621
33415
|
}
|
|
32622
33416
|
}
|
|
32623
|
-
|
|
32624
|
-
|
|
33417
|
+
}
|
|
33418
|
+
|
|
33419
|
+
nodeEntry.setCount.text(RED._('palette.editor.pluginCount',{count:pluginCount,label:pluginCount}));
|
|
32625
33420
|
|
|
32626
|
-
|
|
32627
|
-
|
|
32628
|
-
|
|
32629
|
-
|
|
32630
|
-
|
|
33421
|
+
} else {
|
|
33422
|
+
var activeTypeCount = 0;
|
|
33423
|
+
var typeCount = 0;
|
|
33424
|
+
var errorCount = 0;
|
|
33425
|
+
nodeEntry.errorList.empty();
|
|
33426
|
+
nodeEntries[module].totalUseCount = 0;
|
|
33427
|
+
nodeEntries[module].setUseCount = {};
|
|
33428
|
+
|
|
33429
|
+
for (var setName in moduleInfo.sets) {
|
|
33430
|
+
if (moduleInfo.sets.hasOwnProperty(setName)) {
|
|
33431
|
+
var inUseCount = 0;
|
|
33432
|
+
const set = moduleInfo.sets[setName];
|
|
33433
|
+
const setElements = nodeEntry.sets[setName]
|
|
33434
|
+
|
|
33435
|
+
if (set.err) {
|
|
33436
|
+
errorCount++;
|
|
33437
|
+
var errMessage = set.err;
|
|
33438
|
+
if (set.err.message) {
|
|
33439
|
+
errMessage = set.err.message;
|
|
33440
|
+
} else if (set.err.code) {
|
|
33441
|
+
errMessage = set.err.code;
|
|
33442
|
+
}
|
|
33443
|
+
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
|
|
33444
|
+
}
|
|
32631
33445
|
if (set.enabled) {
|
|
32632
|
-
|
|
32633
|
-
}
|
|
32634
|
-
|
|
33446
|
+
activeTypeCount += set.types.length;
|
|
33447
|
+
}
|
|
33448
|
+
typeCount += set.types.length;
|
|
33449
|
+
for (var i=0;i<moduleInfo.sets[setName].types.length;i++) {
|
|
33450
|
+
var t = moduleInfo.sets[setName].types[i];
|
|
33451
|
+
inUseCount += (typesInUse[t]||0);
|
|
33452
|
+
if (setElements && set.enabled) {
|
|
33453
|
+
var def = RED.nodes.getType(t);
|
|
33454
|
+
if (def && def.color) {
|
|
33455
|
+
setElements.swatches[t].css({background:RED.utils.getNodeColor(t,def)});
|
|
33456
|
+
setElements.swatches[t].css({border: "1px solid "+getContrastingBorder(setElements.swatches[t].css('backgroundColor'))})
|
|
33457
|
+
}
|
|
33458
|
+
}
|
|
33459
|
+
}
|
|
33460
|
+
nodeEntries[module].setUseCount[setName] = inUseCount;
|
|
33461
|
+
nodeEntries[module].totalUseCount += inUseCount;
|
|
33462
|
+
|
|
33463
|
+
if (setElements) {
|
|
33464
|
+
if (inUseCount > 0) {
|
|
33465
|
+
setElements.enableButton.text(RED._('palette.editor.inuse'));
|
|
33466
|
+
setElements.enableButton.addClass('disabled');
|
|
33467
|
+
} else {
|
|
33468
|
+
setElements.enableButton.removeClass('disabled');
|
|
33469
|
+
if (set.enabled) {
|
|
33470
|
+
setElements.enableButton.text(RED._('palette.editor.disable'));
|
|
33471
|
+
} else {
|
|
33472
|
+
setElements.enableButton.text(RED._('palette.editor.enable'));
|
|
33473
|
+
}
|
|
33474
|
+
}
|
|
33475
|
+
setElements.setRow.toggleClass("red-ui-palette-module-set-disabled",!set.enabled);
|
|
32635
33476
|
}
|
|
32636
33477
|
}
|
|
32637
|
-
setElements.setRow.toggleClass("red-ui-palette-module-set-disabled",!set.enabled);
|
|
32638
33478
|
}
|
|
32639
|
-
}
|
|
32640
33479
|
|
|
32641
|
-
|
|
32642
|
-
|
|
32643
|
-
|
|
32644
|
-
|
|
32645
|
-
|
|
33480
|
+
if (errorCount === 0) {
|
|
33481
|
+
nodeEntry.errorRow.hide()
|
|
33482
|
+
} else {
|
|
33483
|
+
nodeEntry.errorRow.show();
|
|
33484
|
+
}
|
|
32646
33485
|
|
|
32647
|
-
|
|
32648
|
-
|
|
33486
|
+
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
|
|
33487
|
+
nodeEntry.setCount.text(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
|
32649
33488
|
|
|
32650
|
-
|
|
32651
|
-
|
|
32652
|
-
|
|
32653
|
-
|
|
32654
|
-
} else {
|
|
32655
|
-
nodeEntry.enableButton.removeClass('disabled');
|
|
32656
|
-
if (moduleInfo.local) {
|
|
32657
|
-
nodeEntry.removeButton.css('display', 'inline-block');
|
|
32658
|
-
}
|
|
32659
|
-
if (activeTypeCount === 0) {
|
|
32660
|
-
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
|
|
33489
|
+
if (nodeEntries[module].totalUseCount > 0) {
|
|
33490
|
+
nodeEntry.enableButton.text(RED._('palette.editor.inuse'));
|
|
33491
|
+
nodeEntry.enableButton.addClass('disabled');
|
|
33492
|
+
nodeEntry.removeButton.hide();
|
|
32661
33493
|
} else {
|
|
32662
|
-
nodeEntry.enableButton.
|
|
33494
|
+
nodeEntry.enableButton.removeClass('disabled');
|
|
33495
|
+
if (moduleInfo.local) {
|
|
33496
|
+
nodeEntry.removeButton.css('display', 'inline-block');
|
|
33497
|
+
}
|
|
33498
|
+
if (activeTypeCount === 0) {
|
|
33499
|
+
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
|
|
33500
|
+
} else {
|
|
33501
|
+
nodeEntry.enableButton.text(RED._('palette.editor.disableall'));
|
|
33502
|
+
}
|
|
33503
|
+
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
|
32663
33504
|
}
|
|
32664
|
-
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
|
32665
33505
|
}
|
|
32666
33506
|
}
|
|
32667
33507
|
if (moduleInfo.pending_version) {
|
|
@@ -33012,6 +33852,33 @@ RED.palette.editor = (function() {
|
|
|
33012
33852
|
}
|
|
33013
33853
|
}
|
|
33014
33854
|
})
|
|
33855
|
+
|
|
33856
|
+
RED.events.on("registry:plugin-module-added", function(module) {
|
|
33857
|
+
|
|
33858
|
+
if (!nodeEntries.hasOwnProperty(module)) {
|
|
33859
|
+
nodeEntries[module] = {info:RED.plugins.getModule(module)};
|
|
33860
|
+
var index = [module];
|
|
33861
|
+
for (var s in nodeEntries[module].info.sets) {
|
|
33862
|
+
if (nodeEntries[module].info.sets.hasOwnProperty(s)) {
|
|
33863
|
+
index.push(s);
|
|
33864
|
+
index = index.concat(nodeEntries[module].info.sets[s].types)
|
|
33865
|
+
}
|
|
33866
|
+
}
|
|
33867
|
+
nodeEntries[module].index = index.join(",").toLowerCase();
|
|
33868
|
+
nodeList.editableList('addItem', nodeEntries[module]);
|
|
33869
|
+
} else {
|
|
33870
|
+
_refreshNodeModule(module);
|
|
33871
|
+
}
|
|
33872
|
+
|
|
33873
|
+
for (var i=0;i<filteredList.length;i++) {
|
|
33874
|
+
if (filteredList[i].info.id === module) {
|
|
33875
|
+
var installButton = filteredList[i].elements.installButton;
|
|
33876
|
+
installButton.addClass('disabled');
|
|
33877
|
+
installButton.text(RED._('palette.editor.installed'));
|
|
33878
|
+
break;
|
|
33879
|
+
}
|
|
33880
|
+
}
|
|
33881
|
+
});
|
|
33015
33882
|
}
|
|
33016
33883
|
|
|
33017
33884
|
var settingsPane;
|
|
@@ -33138,6 +34005,7 @@ RED.palette.editor = (function() {
|
|
|
33138
34005
|
errorRow: errorRow,
|
|
33139
34006
|
errorList: errorList,
|
|
33140
34007
|
setCount: setCount,
|
|
34008
|
+
setButton: setButton,
|
|
33141
34009
|
container: container,
|
|
33142
34010
|
shade: shade,
|
|
33143
34011
|
versionSpan: versionSpan,
|
|
@@ -33148,49 +34016,88 @@ RED.palette.editor = (function() {
|
|
|
33148
34016
|
if (container.hasClass('expanded')) {
|
|
33149
34017
|
container.removeClass('expanded');
|
|
33150
34018
|
contentRow.slideUp();
|
|
34019
|
+
setTimeout(() => {
|
|
34020
|
+
contentRow.empty()
|
|
34021
|
+
}, 200)
|
|
34022
|
+
object.elements.sets = {}
|
|
33151
34023
|
} else {
|
|
33152
34024
|
container.addClass('expanded');
|
|
34025
|
+
populateSetList()
|
|
33153
34026
|
contentRow.slideDown();
|
|
33154
34027
|
}
|
|
33155
34028
|
})
|
|
33156
|
-
|
|
33157
|
-
|
|
33158
|
-
|
|
33159
|
-
|
|
33160
|
-
|
|
33161
|
-
|
|
33162
|
-
|
|
33163
|
-
|
|
33164
|
-
|
|
33165
|
-
|
|
33166
|
-
|
|
33167
|
-
|
|
33168
|
-
|
|
33169
|
-
|
|
33170
|
-
|
|
33171
|
-
|
|
33172
|
-
|
|
33173
|
-
|
|
33174
|
-
|
|
33175
|
-
|
|
33176
|
-
shade.show();
|
|
33177
|
-
var newState = !currentSet.enabled
|
|
33178
|
-
changeNodeState(set.id,newState,shade,function(xhr){
|
|
33179
|
-
if (xhr) {
|
|
33180
|
-
if (xhr.responseJSON) {
|
|
33181
|
-
RED.notify(RED._('palette.editor.errors.'+(newState?'enable':'disable')+'Failed',{module: id,message:xhr.responseJSON.message}));
|
|
34029
|
+
const populateSetList = function () {
|
|
34030
|
+
var setList = Object.keys(entry.sets)
|
|
34031
|
+
setList.sort(function(A,B) {
|
|
34032
|
+
return A.toLowerCase().localeCompare(B.toLowerCase());
|
|
34033
|
+
});
|
|
34034
|
+
setList.forEach(function(setName) {
|
|
34035
|
+
var set = entry.sets[setName];
|
|
34036
|
+
var setRow = $('<div>',{class:"red-ui-palette-module-set"}).appendTo(contentRow);
|
|
34037
|
+
var buttonGroup = $('<div>',{class:"red-ui-palette-module-set-button-group"}).appendTo(setRow);
|
|
34038
|
+
var typeSwatches = {};
|
|
34039
|
+
let enableButton;
|
|
34040
|
+
if (set.types) {
|
|
34041
|
+
set.types.forEach(function(t) {
|
|
34042
|
+
var typeDiv = $('<div>',{class:"red-ui-palette-module-type"}).appendTo(setRow);
|
|
34043
|
+
typeSwatches[t] = $('<span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
|
34044
|
+
if (set.enabled) {
|
|
34045
|
+
var def = RED.nodes.getType(t);
|
|
34046
|
+
if (def && def.color) {
|
|
34047
|
+
typeSwatches[t].css({background:RED.utils.getNodeColor(t,def)});
|
|
34048
|
+
typeSwatches[t].css({border: "1px solid "+getContrastingBorder(typeSwatches[t].css('backgroundColor'))})
|
|
33182
34049
|
}
|
|
33183
34050
|
}
|
|
33184
|
-
|
|
34051
|
+
$('<span>',{class:"red-ui-palette-module-type-node"}).text(t).appendTo(typeDiv);
|
|
34052
|
+
})
|
|
34053
|
+
enableButton = $('<a href="#" class="red-ui-button red-ui-button-small"></a>').appendTo(buttonGroup);
|
|
34054
|
+
enableButton.on("click", function(evt) {
|
|
34055
|
+
evt.preventDefault();
|
|
34056
|
+
if (object.setUseCount[setName] === 0) {
|
|
34057
|
+
var currentSet = RED.nodes.registry.getNodeSet(set.id);
|
|
34058
|
+
shade.show();
|
|
34059
|
+
var newState = !currentSet.enabled
|
|
34060
|
+
changeNodeState(set.id,newState,shade,function(xhr){
|
|
34061
|
+
if (xhr) {
|
|
34062
|
+
if (xhr.responseJSON) {
|
|
34063
|
+
RED.notify(RED._('palette.editor.errors.'+(newState?'enable':'disable')+'Failed',{module: id,message:xhr.responseJSON.message}));
|
|
34064
|
+
}
|
|
34065
|
+
}
|
|
34066
|
+
});
|
|
34067
|
+
}
|
|
34068
|
+
})
|
|
34069
|
+
|
|
34070
|
+
if (object.setUseCount[setName] > 0) {
|
|
34071
|
+
enableButton.text(RED._('palette.editor.inuse'));
|
|
34072
|
+
enableButton.addClass('disabled');
|
|
34073
|
+
} else {
|
|
34074
|
+
enableButton.removeClass('disabled');
|
|
34075
|
+
if (set.enabled) {
|
|
34076
|
+
enableButton.text(RED._('palette.editor.disable'));
|
|
34077
|
+
} else {
|
|
34078
|
+
enableButton.text(RED._('palette.editor.enable'));
|
|
34079
|
+
}
|
|
34080
|
+
}
|
|
34081
|
+
setRow.toggleClass("red-ui-palette-module-set-disabled",!set.enabled);
|
|
34082
|
+
|
|
34083
|
+
|
|
34084
|
+
}
|
|
34085
|
+
if (set.plugins) {
|
|
34086
|
+
set.plugins.forEach(function(p) {
|
|
34087
|
+
var typeDiv = $('<div>',{class:"red-ui-palette-module-type"}).appendTo(setRow);
|
|
34088
|
+
// typeSwatches[p.id] = $('<span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
|
34089
|
+
$('<span><i class="fa fa-puzzle-piece" aria-hidden="true"></i> </span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
|
34090
|
+
$('<span>',{class:"red-ui-palette-module-type-node"}).text(p.id).appendTo(typeDiv);
|
|
34091
|
+
})
|
|
33185
34092
|
}
|
|
33186
|
-
})
|
|
33187
34093
|
|
|
33188
|
-
|
|
33189
|
-
|
|
33190
|
-
|
|
33191
|
-
|
|
33192
|
-
|
|
33193
|
-
|
|
34094
|
+
object.elements.sets[set.name] = {
|
|
34095
|
+
setRow: setRow,
|
|
34096
|
+
enableButton: enableButton,
|
|
34097
|
+
swatches: typeSwatches
|
|
34098
|
+
};
|
|
34099
|
+
});
|
|
34100
|
+
}
|
|
33194
34101
|
enableButton.on("click", function(evt) {
|
|
33195
34102
|
evt.preventDefault();
|
|
33196
34103
|
if (object.totalUseCount === 0) {
|
|
@@ -33560,7 +34467,55 @@ RED.palette.editor = (function() {
|
|
|
33560
34467
|
}
|
|
33561
34468
|
}
|
|
33562
34469
|
]
|
|
33563
|
-
});
|
|
34470
|
+
});
|
|
34471
|
+
}
|
|
34472
|
+
} else {
|
|
34473
|
+
// dedicated list management for plugins
|
|
34474
|
+
if (entry.plugin) {
|
|
34475
|
+
|
|
34476
|
+
let e = nodeEntries[entry.name];
|
|
34477
|
+
if (e) {
|
|
34478
|
+
nodeList.editableList('removeItem', e);
|
|
34479
|
+
delete nodeEntries[entry.name];
|
|
34480
|
+
}
|
|
34481
|
+
|
|
34482
|
+
// We assume that a plugin that implements onremove
|
|
34483
|
+
// cleans the editor accordingly of its left-overs.
|
|
34484
|
+
let found_onremove = true;
|
|
34485
|
+
|
|
34486
|
+
let keys = Object.keys(entry.sets);
|
|
34487
|
+
keys.forEach((key) => {
|
|
34488
|
+
let set = entry.sets[key];
|
|
34489
|
+
for (let i=0; i<set.plugins?.length; i++) {
|
|
34490
|
+
let plgn = RED.plugins.getPlugin(set.plugins[i].id);
|
|
34491
|
+
if (plgn && plgn.onremove && typeof plgn.onremove === 'function') {
|
|
34492
|
+
plgn.onremove();
|
|
34493
|
+
} else {
|
|
34494
|
+
if (plgn && plgn.onadd && typeof plgn.onadd === 'function') {
|
|
34495
|
+
// if there's no 'onadd', there shouldn't be any left-overs
|
|
34496
|
+
found_onremove = false;
|
|
34497
|
+
}
|
|
34498
|
+
}
|
|
34499
|
+
}
|
|
34500
|
+
});
|
|
34501
|
+
|
|
34502
|
+
if (!found_onremove) {
|
|
34503
|
+
let removeNotify = RED.notify("Removed plugin " + entry.name + ". Please reload the editor to clear left-overs.",{
|
|
34504
|
+
modal: true,
|
|
34505
|
+
fixed: true,
|
|
34506
|
+
type: 'warning',
|
|
34507
|
+
buttons: [
|
|
34508
|
+
{
|
|
34509
|
+
text: "Understood",
|
|
34510
|
+
class:"primary",
|
|
34511
|
+
click: function(e) {
|
|
34512
|
+
removeNotify.close();
|
|
34513
|
+
}
|
|
34514
|
+
}
|
|
34515
|
+
]
|
|
34516
|
+
});
|
|
34517
|
+
}
|
|
34518
|
+
}
|
|
33564
34519
|
}
|
|
33565
34520
|
})
|
|
33566
34521
|
notification.close();
|
|
@@ -33975,48 +34930,108 @@ RED.editor = (function() {
|
|
|
33975
34930
|
|
|
33976
34931
|
/**
|
|
33977
34932
|
* Create a config-node select box for this property
|
|
33978
|
-
* @param node - the node being edited
|
|
33979
|
-
* @param property - the name of the
|
|
33980
|
-
* @param type - the type of the config-node
|
|
34933
|
+
* @param {Object} node - the node being edited
|
|
34934
|
+
* @param {String} property - the name of the node property
|
|
34935
|
+
* @param {String} type - the type of the config-node
|
|
34936
|
+
* @param {"node-config-input"|"node-input"|"node-input-subflow-env"} prefix - the prefix to use in the input element ids
|
|
34937
|
+
* @param {Function} [filter] - a function to filter the list of config nodes
|
|
34938
|
+
* @param {Object} [env] - the environment variable object (only used for subflow env vars)
|
|
33981
34939
|
*/
|
|
33982
|
-
function prepareConfigNodeSelect(node,property,type,prefix,filter) {
|
|
33983
|
-
|
|
33984
|
-
if (
|
|
34940
|
+
function prepareConfigNodeSelect(node, property, type, prefix, filter, env) {
|
|
34941
|
+
let nodeValue
|
|
34942
|
+
if (prefix === 'node-input-subflow-env') {
|
|
34943
|
+
nodeValue = env?.value
|
|
34944
|
+
} else {
|
|
34945
|
+
nodeValue = node[property]
|
|
34946
|
+
}
|
|
34947
|
+
|
|
34948
|
+
const addBtnId = `${prefix}-btn-${property}-add`;
|
|
34949
|
+
const editBtnId = `${prefix}-btn-${property}-edit`;
|
|
34950
|
+
const selectId = prefix + '-' + property;
|
|
34951
|
+
const input = $(`#${selectId}`);
|
|
34952
|
+
if (input.length === 0) {
|
|
33985
34953
|
return;
|
|
33986
34954
|
}
|
|
33987
|
-
|
|
33988
|
-
|
|
33989
|
-
|
|
34955
|
+
const attrStyle = input.attr('style');
|
|
34956
|
+
let newWidth;
|
|
34957
|
+
let m;
|
|
33990
34958
|
if ((m = /(^|\s|;)width\s*:\s*([^;]+)/i.exec(attrStyle)) !== null) {
|
|
33991
34959
|
newWidth = m[2].trim();
|
|
33992
34960
|
} else {
|
|
33993
34961
|
newWidth = "70%";
|
|
33994
34962
|
}
|
|
33995
|
-
|
|
34963
|
+
const outerWrap = $("<div></div>").css({
|
|
33996
34964
|
width: newWidth,
|
|
33997
|
-
display:'inline-flex'
|
|
34965
|
+
display: 'inline-flex'
|
|
33998
34966
|
});
|
|
33999
|
-
|
|
34967
|
+
const select = $('<select id="' + selectId + '"></select>').appendTo(outerWrap);
|
|
34000
34968
|
input.replaceWith(outerWrap);
|
|
34001
34969
|
// set the style attr directly - using width() on FF causes a value of 114%...
|
|
34002
34970
|
select.css({
|
|
34003
34971
|
'flex-grow': 1
|
|
34004
34972
|
});
|
|
34005
|
-
|
|
34006
|
-
|
|
34007
|
-
|
|
34973
|
+
|
|
34974
|
+
updateConfigNodeSelect(property, type, nodeValue, prefix, filter);
|
|
34975
|
+
|
|
34976
|
+
// create the edit button
|
|
34977
|
+
const editButton = $('<a id="' + editBtnId + '" class="red-ui-button"><i class="fa fa-pencil"></i></a>')
|
|
34978
|
+
.css({ "margin-left": "10px" })
|
|
34008
34979
|
.appendTo(outerWrap);
|
|
34009
|
-
|
|
34010
|
-
|
|
34980
|
+
|
|
34981
|
+
RED.popover.tooltip(editButton, RED._('editor.editConfig', { type }));
|
|
34982
|
+
|
|
34983
|
+
// create the add button
|
|
34984
|
+
const addButton = $('<a id="' + addBtnId + '" class="red-ui-button"><i class="fa fa-plus"></i></a>')
|
|
34985
|
+
.css({ "margin-left": "10px" })
|
|
34986
|
+
.appendTo(outerWrap);
|
|
34987
|
+
RED.popover.tooltip(addButton, RED._('editor.addNewConfig', { type }));
|
|
34988
|
+
|
|
34989
|
+
const disableButton = function(button, disabled) {
|
|
34990
|
+
$(button).prop("disabled", !!disabled)
|
|
34991
|
+
$(button).toggleClass("disabled", !!disabled)
|
|
34992
|
+
};
|
|
34993
|
+
|
|
34994
|
+
// add the click handler
|
|
34995
|
+
addButton.on("click", function (e) {
|
|
34996
|
+
if (addButton.prop("disabled")) { return }
|
|
34997
|
+
showEditConfigNodeDialog(property, type, "_ADD_", prefix, node);
|
|
34998
|
+
e.preventDefault();
|
|
34999
|
+
});
|
|
35000
|
+
editButton.on("click", function (e) {
|
|
35001
|
+
const selectedOpt = select.find(":selected")
|
|
35002
|
+
if (selectedOpt.data('env')) { return } // don't show the dialog for env vars items (MVP. Future enhancement: lookup the env, if present, show the associated edit dialog)
|
|
35003
|
+
if (editButton.prop("disabled")) { return }
|
|
35004
|
+
showEditConfigNodeDialog(property, type, selectedOpt.val(), prefix, node);
|
|
34011
35005
|
e.preventDefault();
|
|
34012
35006
|
});
|
|
35007
|
+
|
|
35008
|
+
// dont permit the user to click the button if the selected option is an env var
|
|
35009
|
+
select.on("change", function () {
|
|
35010
|
+
const selectedOpt = select.find(":selected");
|
|
35011
|
+
const optionsLength = select.find("option").length;
|
|
35012
|
+
if (selectedOpt?.data('env')) {
|
|
35013
|
+
disableButton(addButton, true);
|
|
35014
|
+
disableButton(editButton, true);
|
|
35015
|
+
// disable the edit button if no options available
|
|
35016
|
+
} else if (optionsLength === 1 && selectedOpt.val() === "_ADD_") {
|
|
35017
|
+
disableButton(addButton, false);
|
|
35018
|
+
disableButton(editButton, true);
|
|
35019
|
+
} else if (selectedOpt.val() === "") {
|
|
35020
|
+
disableButton(addButton, false);
|
|
35021
|
+
disableButton(editButton, true);
|
|
35022
|
+
} else {
|
|
35023
|
+
disableButton(addButton, false);
|
|
35024
|
+
disableButton(editButton, false);
|
|
35025
|
+
}
|
|
35026
|
+
});
|
|
35027
|
+
|
|
34013
35028
|
var label = "";
|
|
34014
|
-
var configNode = RED.nodes.node(
|
|
34015
|
-
var node_def = RED.nodes.getType(type);
|
|
35029
|
+
var configNode = RED.nodes.node(nodeValue);
|
|
34016
35030
|
|
|
34017
35031
|
if (configNode) {
|
|
34018
|
-
label = RED.utils.getNodeLabel(configNode,configNode.id);
|
|
35032
|
+
label = RED.utils.getNodeLabel(configNode, configNode.id);
|
|
34019
35033
|
}
|
|
35034
|
+
|
|
34020
35035
|
input.val(label);
|
|
34021
35036
|
}
|
|
34022
35037
|
|
|
@@ -34417,12 +35432,9 @@ RED.editor = (function() {
|
|
|
34417
35432
|
}
|
|
34418
35433
|
|
|
34419
35434
|
function defaultConfigNodeSort(A,B) {
|
|
34420
|
-
|
|
34421
|
-
|
|
34422
|
-
|
|
34423
|
-
return 1;
|
|
34424
|
-
}
|
|
34425
|
-
return 0;
|
|
35435
|
+
// sort case insensitive so that `[env] node-name` items are at the top and
|
|
35436
|
+
// not mixed inbetween the the lower and upper case items
|
|
35437
|
+
return (A.__label__ || '').localeCompare((B.__label__ || ''), undefined, {sensitivity: 'base'})
|
|
34426
35438
|
}
|
|
34427
35439
|
|
|
34428
35440
|
function updateConfigNodeSelect(name,type,value,prefix,filter) {
|
|
@@ -34437,7 +35449,7 @@ RED.editor = (function() {
|
|
|
34437
35449
|
}
|
|
34438
35450
|
$("#"+prefix+"-"+name).val(value);
|
|
34439
35451
|
} else {
|
|
34440
|
-
|
|
35452
|
+
let inclSubflowEnvvars = false
|
|
34441
35453
|
var select = $("#"+prefix+"-"+name);
|
|
34442
35454
|
var node_def = RED.nodes.getType(type);
|
|
34443
35455
|
select.children().remove();
|
|
@@ -34445,6 +35457,7 @@ RED.editor = (function() {
|
|
|
34445
35457
|
var activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
|
|
34446
35458
|
if (!activeWorkspace) {
|
|
34447
35459
|
activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
|
|
35460
|
+
inclSubflowEnvvars = true
|
|
34448
35461
|
}
|
|
34449
35462
|
|
|
34450
35463
|
var configNodes = [];
|
|
@@ -34460,6 +35473,31 @@ RED.editor = (function() {
|
|
|
34460
35473
|
}
|
|
34461
35474
|
}
|
|
34462
35475
|
});
|
|
35476
|
+
|
|
35477
|
+
// as includeSubflowEnvvars is true, this is a subflow.
|
|
35478
|
+
// include any 'conf-types' env vars as a list of avaiable configs
|
|
35479
|
+
// in the config dropdown as `[env] node-name`
|
|
35480
|
+
if (inclSubflowEnvvars && activeWorkspace.env) {
|
|
35481
|
+
const parentEnv = activeWorkspace.env.filter(env => env.ui?.type === 'conf-types' && env.type === type)
|
|
35482
|
+
if (parentEnv && parentEnv.length > 0) {
|
|
35483
|
+
const locale = RED.i18n.lang()
|
|
35484
|
+
for (let i = 0; i < parentEnv.length; i++) {
|
|
35485
|
+
const tenv = parentEnv[i]
|
|
35486
|
+
const ui = tenv.ui || {}
|
|
35487
|
+
const labels = ui.label || {}
|
|
35488
|
+
const labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"] || tenv.name, locale)
|
|
35489
|
+
const config = {
|
|
35490
|
+
env: tenv,
|
|
35491
|
+
id: '${' + parentEnv[0].name + '}',
|
|
35492
|
+
type: type,
|
|
35493
|
+
label: labelText,
|
|
35494
|
+
__label__: `[env] ${labelText}`
|
|
35495
|
+
}
|
|
35496
|
+
configNodes.push(config)
|
|
35497
|
+
}
|
|
35498
|
+
}
|
|
35499
|
+
}
|
|
35500
|
+
|
|
34463
35501
|
var configSortFn = defaultConfigNodeSort;
|
|
34464
35502
|
if (typeof node_def.sort == "function") {
|
|
34465
35503
|
configSortFn = node_def.sort;
|
|
@@ -34471,7 +35509,10 @@ RED.editor = (function() {
|
|
|
34471
35509
|
}
|
|
34472
35510
|
|
|
34473
35511
|
configNodes.forEach(function(cn) {
|
|
34474
|
-
$('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'></option>').text(RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)).appendTo(select);
|
|
35512
|
+
const option = $('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'></option>').text(RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)).appendTo(select);
|
|
35513
|
+
if (cn.env) {
|
|
35514
|
+
option.data('env', cn.env) // set a data attribute to indicate this is an env var (to inhibit the edit button)
|
|
35515
|
+
}
|
|
34475
35516
|
delete cn.__label__;
|
|
34476
35517
|
});
|
|
34477
35518
|
|
|
@@ -34484,7 +35525,12 @@ RED.editor = (function() {
|
|
|
34484
35525
|
}
|
|
34485
35526
|
}
|
|
34486
35527
|
|
|
34487
|
-
|
|
35528
|
+
if (!configNodes.length) {
|
|
35529
|
+
select.append('<option value="_ADD_" selected>' + RED._("editor.addNewType", { type: label }) + '</option>');
|
|
35530
|
+
} else {
|
|
35531
|
+
select.append('<option value="">' + RED._("editor.inputs.none") + '</option>');
|
|
35532
|
+
}
|
|
35533
|
+
|
|
34488
35534
|
window.setTimeout(function() { select.trigger("change");},50);
|
|
34489
35535
|
}
|
|
34490
35536
|
}
|
|
@@ -35132,9 +36178,16 @@ RED.editor = (function() {
|
|
|
35132
36178
|
}
|
|
35133
36179
|
RED.tray.close(function() {
|
|
35134
36180
|
var filter = null;
|
|
35135
|
-
|
|
35136
|
-
|
|
35137
|
-
|
|
36181
|
+
// when editing a config via subflow edit panel, the `configProperty` will not
|
|
36182
|
+
// necessarily be a property of the editContext._def.defaults object
|
|
36183
|
+
// Also, when editing via dashboard sidebar, editContext can be null
|
|
36184
|
+
// so we need to guard both scenarios
|
|
36185
|
+
if (editContext?._def) {
|
|
36186
|
+
const isSubflow = (editContext._def.type === 'subflow' || /subflow:.*/.test(editContext._def.type))
|
|
36187
|
+
if (editContext && !isSubflow && typeof editContext._def.defaults?.[configProperty]?.filter === 'function') {
|
|
36188
|
+
filter = function(n) {
|
|
36189
|
+
return editContext._def.defaults[configProperty].filter.call(editContext,n);
|
|
36190
|
+
}
|
|
35138
36191
|
}
|
|
35139
36192
|
}
|
|
35140
36193
|
updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix,filter);
|
|
@@ -35195,7 +36248,7 @@ RED.editor = (function() {
|
|
|
35195
36248
|
RED.history.push(historyEvent);
|
|
35196
36249
|
RED.tray.close(function() {
|
|
35197
36250
|
var filter = null;
|
|
35198
|
-
if (editContext && typeof editContext._def.defaults[configProperty]
|
|
36251
|
+
if (editContext && typeof editContext._def.defaults[configProperty]?.filter === 'function') {
|
|
35199
36252
|
filter = function(n) {
|
|
35200
36253
|
return editContext._def.defaults[configProperty].filter.call(editContext,n);
|
|
35201
36254
|
}
|
|
@@ -35736,6 +36789,7 @@ RED.editor = (function() {
|
|
|
35736
36789
|
}
|
|
35737
36790
|
},
|
|
35738
36791
|
editBuffer: function(options) { showTypeEditor("_buffer", options) },
|
|
36792
|
+
getEditStack: function () { return [...editStack] },
|
|
35739
36793
|
buildEditForm: buildEditForm,
|
|
35740
36794
|
validateNode: validateNode,
|
|
35741
36795
|
updateNodeProperties: updateNodeProperties,
|
|
@@ -35780,7 +36834,8 @@ RED.editor = (function() {
|
|
|
35780
36834
|
filteredEditPanes[type] = filter
|
|
35781
36835
|
}
|
|
35782
36836
|
editPanes[type] = definition;
|
|
35783
|
-
}
|
|
36837
|
+
},
|
|
36838
|
+
prepareConfigNodeSelect: prepareConfigNodeSelect,
|
|
35784
36839
|
}
|
|
35785
36840
|
})();
|
|
35786
36841
|
;;(function() {
|
|
@@ -37434,8 +38489,9 @@ RED.editor = (function() {
|
|
|
37434
38489
|
;RED.editor.envVarList = (function() {
|
|
37435
38490
|
|
|
37436
38491
|
var currentLocale = 'en-US';
|
|
37437
|
-
|
|
37438
|
-
|
|
38492
|
+
const DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
|
|
38493
|
+
const DEFAULT_ENV_TYPE_LIST_INC_CONFTYPES = ['str','num','bool','json','bin','env','conf-types'];
|
|
38494
|
+
const DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred','jsonata'];
|
|
37439
38495
|
|
|
37440
38496
|
/**
|
|
37441
38497
|
* Create env var edit interface
|
|
@@ -37443,8 +38499,8 @@ RED.editor = (function() {
|
|
|
37443
38499
|
* @param node - subflow node
|
|
37444
38500
|
*/
|
|
37445
38501
|
function buildPropertiesList(envContainer, node) {
|
|
37446
|
-
|
|
37447
|
-
|
|
38502
|
+
if(RED.editor.envVarList.debug) { console.log('envVarList: buildPropertiesList', envContainer, node) }
|
|
38503
|
+
const isTemplateNode = (node.type === "subflow");
|
|
37448
38504
|
|
|
37449
38505
|
envContainer
|
|
37450
38506
|
.css({
|
|
@@ -37516,7 +38572,14 @@ RED.editor = (function() {
|
|
|
37516
38572
|
// if `opt.ui` does not exist, then apply defaults. If these
|
|
37517
38573
|
// defaults do not change then they will get stripped off
|
|
37518
38574
|
// before saving.
|
|
37519
|
-
if (opt.type === '
|
|
38575
|
+
if (opt.type === 'conf-types') {
|
|
38576
|
+
opt.ui = opt.ui || {
|
|
38577
|
+
icon: "fa fa-cog",
|
|
38578
|
+
type: "conf-types",
|
|
38579
|
+
opts: {opts:[]}
|
|
38580
|
+
}
|
|
38581
|
+
opt.ui.type = "conf-types";
|
|
38582
|
+
} else if (opt.type === 'cred') {
|
|
37520
38583
|
opt.ui = opt.ui || {
|
|
37521
38584
|
icon: "",
|
|
37522
38585
|
type: "cred"
|
|
@@ -37552,7 +38615,7 @@ RED.editor = (function() {
|
|
|
37552
38615
|
}
|
|
37553
38616
|
});
|
|
37554
38617
|
|
|
37555
|
-
buildEnvEditRow(uiRow, opt
|
|
38618
|
+
buildEnvEditRow(uiRow, opt, nameField, valueField);
|
|
37556
38619
|
nameField.trigger('change');
|
|
37557
38620
|
}
|
|
37558
38621
|
},
|
|
@@ -37614,21 +38677,23 @@ RED.editor = (function() {
|
|
|
37614
38677
|
* @param nameField - name field of env var
|
|
37615
38678
|
* @param valueField - value field of env var
|
|
37616
38679
|
*/
|
|
37617
|
-
function buildEnvEditRow(container,
|
|
38680
|
+
function buildEnvEditRow(container, opt, nameField, valueField) {
|
|
38681
|
+
const ui = opt.ui
|
|
38682
|
+
if(RED.editor.envVarList.debug) { console.log('envVarList: buildEnvEditRow', container, ui, nameField, valueField) }
|
|
37618
38683
|
container.addClass("red-ui-editor-subflow-env-ui-row")
|
|
37619
38684
|
var topRow = $('<div></div>').appendTo(container);
|
|
37620
38685
|
$('<div></div>').appendTo(topRow);
|
|
37621
38686
|
$('<div>').text(RED._("editor.icon")).appendTo(topRow);
|
|
37622
38687
|
$('<div>').text(RED._("editor.label")).appendTo(topRow);
|
|
37623
|
-
$('<div>').text(RED._("editor.inputType")).appendTo(topRow);
|
|
38688
|
+
$('<div class="red-env-ui-input-type-col">').text(RED._("editor.inputType")).appendTo(topRow);
|
|
37624
38689
|
|
|
37625
38690
|
var row = $('<div></div>').appendTo(container);
|
|
37626
38691
|
$('<div><i class="red-ui-editableList-item-handle fa fa-bars"></i></div>').appendTo(row);
|
|
37627
38692
|
var typeOptions = {
|
|
37628
|
-
|
|
37629
|
-
|
|
37630
|
-
|
|
37631
|
-
|
|
38693
|
+
'input': {types:DEFAULT_ENV_TYPE_LIST_INC_CONFTYPES},
|
|
38694
|
+
'select': {opts:[]},
|
|
38695
|
+
'spinner': {},
|
|
38696
|
+
'cred': {}
|
|
37632
38697
|
};
|
|
37633
38698
|
if (ui.opts) {
|
|
37634
38699
|
typeOptions[ui.type] = ui.opts;
|
|
@@ -37693,15 +38758,16 @@ RED.editor = (function() {
|
|
|
37693
38758
|
labelInput.attr("placeholder",$(this).val())
|
|
37694
38759
|
});
|
|
37695
38760
|
|
|
37696
|
-
var inputCell = $('<div></div>').appendTo(row);
|
|
37697
|
-
var
|
|
38761
|
+
var inputCell = $('<div class="red-env-ui-input-type-col"></div>').appendTo(row);
|
|
38762
|
+
var uiInputTypeInput = $('<input type="text">').css("width","100%").appendTo(inputCell);
|
|
37698
38763
|
if (ui.type === "input") {
|
|
37699
|
-
|
|
38764
|
+
uiInputTypeInput.val(ui.opts.types.join(","));
|
|
37700
38765
|
}
|
|
37701
38766
|
var checkbox;
|
|
37702
38767
|
var selectBox;
|
|
37703
38768
|
|
|
37704
|
-
|
|
38769
|
+
// the options presented in the UI section for an "input" type selection
|
|
38770
|
+
uiInputTypeInput.typedInput({
|
|
37705
38771
|
types: [
|
|
37706
38772
|
{
|
|
37707
38773
|
value:"input",
|
|
@@ -37862,7 +38928,7 @@ RED.editor = (function() {
|
|
|
37862
38928
|
}
|
|
37863
38929
|
});
|
|
37864
38930
|
ui.opts.opts = vals;
|
|
37865
|
-
|
|
38931
|
+
uiInputTypeInput.typedInput('value',Date.now())
|
|
37866
38932
|
}
|
|
37867
38933
|
}
|
|
37868
38934
|
}
|
|
@@ -37929,12 +38995,13 @@ RED.editor = (function() {
|
|
|
37929
38995
|
} else {
|
|
37930
38996
|
delete ui.opts.max;
|
|
37931
38997
|
}
|
|
37932
|
-
|
|
38998
|
+
uiInputTypeInput.typedInput('value',Date.now())
|
|
37933
38999
|
}
|
|
37934
39000
|
}
|
|
37935
39001
|
}
|
|
37936
39002
|
}
|
|
37937
39003
|
},
|
|
39004
|
+
'conf-types',
|
|
37938
39005
|
{
|
|
37939
39006
|
value:"none",
|
|
37940
39007
|
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
|
|
@@ -37952,14 +39019,20 @@ RED.editor = (function() {
|
|
|
37952
39019
|
// In the case of 'input' type, the typedInput uses the multiple-option
|
|
37953
39020
|
// mode. Its value needs to be set to a comma-separately list of the
|
|
37954
39021
|
// selected options.
|
|
37955
|
-
|
|
39022
|
+
uiInputTypeInput.typedInput('value',ui.opts.types.join(","))
|
|
39023
|
+
} else if (ui.type === 'conf-types') {
|
|
39024
|
+
// In the case of 'conf-types' type, the typedInput will be populated
|
|
39025
|
+
// with a list of all config nodes types installed.
|
|
39026
|
+
// Restore the value to the last selected type
|
|
39027
|
+
uiInputTypeInput.typedInput('value', opt.type)
|
|
37956
39028
|
} else {
|
|
37957
39029
|
// No other type cares about `value`, but doing this will
|
|
37958
39030
|
// force a refresh of the label now that `ui.opts` has
|
|
37959
39031
|
// been updated.
|
|
37960
|
-
|
|
39032
|
+
uiInputTypeInput.typedInput('value',Date.now())
|
|
37961
39033
|
}
|
|
37962
39034
|
|
|
39035
|
+
if(RED.editor.envVarList.debug) { console.log('envVarList: inputCellInput on:typedinputtypechange. ui.type = ' + ui.type) }
|
|
37963
39036
|
switch (ui.type) {
|
|
37964
39037
|
case 'input':
|
|
37965
39038
|
valueField.typedInput('types',ui.opts.types);
|
|
@@ -37977,7 +39050,7 @@ RED.editor = (function() {
|
|
|
37977
39050
|
valueField.typedInput('types',['cred']);
|
|
37978
39051
|
break;
|
|
37979
39052
|
default:
|
|
37980
|
-
valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
|
|
39053
|
+
valueField.typedInput('types', DEFAULT_ENV_TYPE_LIST);
|
|
37981
39054
|
}
|
|
37982
39055
|
if (ui.type === 'checkbox') {
|
|
37983
39056
|
valueField.typedInput('type','bool');
|
|
@@ -37989,8 +39062,46 @@ RED.editor = (function() {
|
|
|
37989
39062
|
}
|
|
37990
39063
|
|
|
37991
39064
|
}).on("change", function(evt,type) {
|
|
37992
|
-
|
|
37993
|
-
|
|
39065
|
+
const selectedType = $(this).typedInput('type') // the UI typedInput type
|
|
39066
|
+
if(RED.editor.envVarList.debug) { console.log('envVarList: inputCellInput on:change. selectedType = ' + selectedType) }
|
|
39067
|
+
if (selectedType === 'conf-types') {
|
|
39068
|
+
const selectedConfigType = $(this).typedInput('value') || opt.type
|
|
39069
|
+
let activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
|
|
39070
|
+
if (!activeWorkspace) {
|
|
39071
|
+
activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
|
|
39072
|
+
}
|
|
39073
|
+
|
|
39074
|
+
// get a list of all config nodes matching the selectedValue
|
|
39075
|
+
const configNodes = [];
|
|
39076
|
+
RED.nodes.eachConfig(function(config) {
|
|
39077
|
+
if (config.type == selectedConfigType && (!config.z || config.z === activeWorkspace.id)) {
|
|
39078
|
+
const modulePath = config._def?.set?.id || ''
|
|
39079
|
+
let label = RED.utils.getNodeLabel(config, config.id) || config.id;
|
|
39080
|
+
label += config.d ? ' ['+RED._('workspace.disabled')+']' : '';
|
|
39081
|
+
const _config = {
|
|
39082
|
+
_type: selectedConfigType,
|
|
39083
|
+
value: config.id,
|
|
39084
|
+
label: label,
|
|
39085
|
+
title: modulePath ? modulePath + ' - ' + label : label,
|
|
39086
|
+
enabled: config.d !== true,
|
|
39087
|
+
disabled: config.d === true,
|
|
39088
|
+
}
|
|
39089
|
+
configNodes.push(_config);
|
|
39090
|
+
}
|
|
39091
|
+
});
|
|
39092
|
+
const tiTypes = {
|
|
39093
|
+
value: selectedConfigType,
|
|
39094
|
+
label: "config",
|
|
39095
|
+
icon: "fa fa-cog",
|
|
39096
|
+
options: configNodes,
|
|
39097
|
+
}
|
|
39098
|
+
valueField.typedInput('types', [tiTypes]);
|
|
39099
|
+
valueField.typedInput('type', selectedConfigType);
|
|
39100
|
+
valueField.typedInput('value', opt.value);
|
|
39101
|
+
|
|
39102
|
+
|
|
39103
|
+
} else if (ui.type === 'input') {
|
|
39104
|
+
var types = uiInputTypeInput.typedInput('value');
|
|
37994
39105
|
ui.opts.types = (types === "") ? ["str"] : types.split(",");
|
|
37995
39106
|
valueField.typedInput('types',ui.opts.types);
|
|
37996
39107
|
}
|
|
@@ -38002,7 +39113,7 @@ RED.editor = (function() {
|
|
|
38002
39113
|
})
|
|
38003
39114
|
// Set the input to the right type. This will trigger the 'typedinputtypechange'
|
|
38004
39115
|
// event handler (just above ^^) to update the value if needed
|
|
38005
|
-
|
|
39116
|
+
uiInputTypeInput.typedInput('type',ui.type)
|
|
38006
39117
|
}
|
|
38007
39118
|
|
|
38008
39119
|
function setLocale(l, list) {
|
|
@@ -40529,7 +41640,7 @@ RED.editor.codeEditor.monaco = (function() {
|
|
|
40529
41640
|
createMonacoCompletionItem("set (flow context)", 'flow.set("${1:name}", ${1:value});','Set a value in flow context',range),
|
|
40530
41641
|
createMonacoCompletionItem("get (global context)", 'global.get("${1:name}");','Get a value from global context',range),
|
|
40531
41642
|
createMonacoCompletionItem("set (global context)", 'global.set("${1:name}", ${1:value});','Set a value in global context',range),
|
|
40532
|
-
createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME|}");','Get env variable value',range),
|
|
41643
|
+
createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME,NR_SUBFLOW_NAME,NR_SUBFLOW_ID,NR_SUBFLOW_PATH|}");','Get env variable value',range),
|
|
40533
41644
|
createMonacoCompletionItem("cloneMessage (RED.util)", 'RED.util.cloneMessage(${1:msg});',
|
|
40534
41645
|
["```typescript",
|
|
40535
41646
|
"RED.util.cloneMessage<T extends registry.NodeMessage>(msg: T): T",
|
|
@@ -41784,6 +42895,7 @@ RED.eventLog = (function() {
|
|
|
41784
42895
|
setTimeout(function() {
|
|
41785
42896
|
oldTray.tray.detach();
|
|
41786
42897
|
showTray(options);
|
|
42898
|
+
RED.events.emit('editor:change')
|
|
41787
42899
|
},250)
|
|
41788
42900
|
} else {
|
|
41789
42901
|
if (stack.length > 0) {
|
|
@@ -41853,6 +42965,7 @@ RED.eventLog = (function() {
|
|
|
41853
42965
|
RED.view.focus();
|
|
41854
42966
|
} else {
|
|
41855
42967
|
stack[stack.length-1].tray.css("z-index", "auto");
|
|
42968
|
+
RED.events.emit('editor:change')
|
|
41856
42969
|
}
|
|
41857
42970
|
},250)
|
|
41858
42971
|
}
|
|
@@ -46935,17 +48048,19 @@ RED.subflow = (function() {
|
|
|
46935
48048
|
|
|
46936
48049
|
|
|
46937
48050
|
/**
|
|
46938
|
-
*
|
|
48051
|
+
* Build the edit dialog for a subflow template (creating/modifying a subflow template)
|
|
48052
|
+
* @param {Object} uiContainer - the jQuery container for the environment variable list
|
|
48053
|
+
* @param {Object} node - the subflow template node
|
|
46939
48054
|
*/
|
|
46940
|
-
function buildEnvControl(
|
|
48055
|
+
function buildEnvControl(uiContainer,node) {
|
|
46941
48056
|
var tabs = RED.tabs.create({
|
|
46942
48057
|
id: "subflow-env-tabs",
|
|
46943
48058
|
onchange: function(tab) {
|
|
46944
48059
|
if (tab.id === "subflow-env-tab-preview") {
|
|
46945
48060
|
var inputContainer = $("#subflow-input-ui");
|
|
46946
|
-
var list =
|
|
48061
|
+
var list = uiContainer.editableList("items");
|
|
46947
48062
|
var exportedEnv = exportEnvList(list, true);
|
|
46948
|
-
buildEnvUI(inputContainer, exportedEnv,node);
|
|
48063
|
+
buildEnvUI(inputContainer, exportedEnv, node);
|
|
46949
48064
|
}
|
|
46950
48065
|
$("#subflow-env-tabs-content").children().hide();
|
|
46951
48066
|
$("#" + tab.id).show();
|
|
@@ -46983,12 +48098,33 @@ RED.subflow = (function() {
|
|
|
46983
48098
|
RED.editor.envVarList.setLocale(locale);
|
|
46984
48099
|
}
|
|
46985
48100
|
|
|
46986
|
-
|
|
46987
|
-
|
|
48101
|
+
/**
|
|
48102
|
+
* Build a UI row for a subflow instance environment variable
|
|
48103
|
+
* Also used to build the UI row for subflow template preview
|
|
48104
|
+
* @param {JQuery} row - A form row element
|
|
48105
|
+
* @param {Object} tenv - A template environment variable
|
|
48106
|
+
* @param {String} tenv.name - The name of the environment variable
|
|
48107
|
+
* @param {String} tenv.type - The type of the environment variable
|
|
48108
|
+
* @param {String} tenv.value - The value set for this environment variable
|
|
48109
|
+
* @param {Object} tenv.parent - The parent environment variable
|
|
48110
|
+
* @param {String} tenv.parent.value - The value set for the parent environment variable
|
|
48111
|
+
* @param {String} tenv.parent.type - The type of the parent environment variable
|
|
48112
|
+
* @param {Object} tenv.ui - The UI configuration for the environment variable
|
|
48113
|
+
* @param {String} tenv.ui.icon - The icon for the environment variable
|
|
48114
|
+
* @param {Object} tenv.ui.label - The label for the environment variable
|
|
48115
|
+
* @param {String} tenv.ui.type - The type of the UI control for the environment variable
|
|
48116
|
+
* @param {Object} node - The subflow instance node
|
|
48117
|
+
*/
|
|
48118
|
+
function buildEnvUIRow(row, tenv, node) {
|
|
48119
|
+
if(RED.subflow.debug) { console.log("buildEnvUIRow", tenv) }
|
|
48120
|
+
const ui = tenv.ui || {}
|
|
46988
48121
|
ui.label = ui.label||{};
|
|
46989
48122
|
if ((tenv.type === "cred" || (tenv.parent && tenv.parent.type === "cred")) && !ui.type) {
|
|
46990
48123
|
ui.type = "cred";
|
|
46991
48124
|
ui.opts = {};
|
|
48125
|
+
} else if (tenv.type === "conf-types") {
|
|
48126
|
+
ui.type = "conf-types"
|
|
48127
|
+
ui.opts = { types: ['conf-types'] }
|
|
46992
48128
|
} else if (!ui.type) {
|
|
46993
48129
|
ui.type = "input";
|
|
46994
48130
|
ui.opts = { types: RED.editor.envVarList.DEFAULT_ENV_TYPE_LIST }
|
|
@@ -47032,9 +48168,10 @@ RED.subflow = (function() {
|
|
|
47032
48168
|
if (tenv.hasOwnProperty('type')) {
|
|
47033
48169
|
val.type = tenv.type;
|
|
47034
48170
|
}
|
|
48171
|
+
const elId = getSubflowEnvPropertyName(tenv.name)
|
|
47035
48172
|
switch(ui.type) {
|
|
47036
48173
|
case "input":
|
|
47037
|
-
input = $('<input type="text">').css('width','70%').appendTo(row);
|
|
48174
|
+
input = $('<input type="text">').css('width','70%').attr('id', elId).appendTo(row);
|
|
47038
48175
|
if (ui.opts.types && ui.opts.types.length > 0) {
|
|
47039
48176
|
var inputType = val.type;
|
|
47040
48177
|
if (ui.opts.types.indexOf(inputType) === -1) {
|
|
@@ -47061,7 +48198,7 @@ RED.subflow = (function() {
|
|
|
47061
48198
|
}
|
|
47062
48199
|
break;
|
|
47063
48200
|
case "select":
|
|
47064
|
-
input = $('<select>').css('width','70%').appendTo(row);
|
|
48201
|
+
input = $('<select>').css('width','70%').attr('id', elId).appendTo(row);
|
|
47065
48202
|
if (ui.opts.opts) {
|
|
47066
48203
|
ui.opts.opts.forEach(function(o) {
|
|
47067
48204
|
$('<option>').val(o.v).text(RED.editor.envVarList.lookupLabel(o.l, o.l['en-US']||o.v, locale)).appendTo(input);
|
|
@@ -47072,7 +48209,7 @@ RED.subflow = (function() {
|
|
|
47072
48209
|
case "checkbox":
|
|
47073
48210
|
label.css("cursor","default");
|
|
47074
48211
|
var cblabel = $('<label>').css('width','70%').appendTo(row);
|
|
47075
|
-
input = $('<input type="checkbox">').css({
|
|
48212
|
+
input = $('<input type="checkbox">').attr('id', elId).css({
|
|
47076
48213
|
marginTop: 0,
|
|
47077
48214
|
width: 'auto',
|
|
47078
48215
|
height: '34px'
|
|
@@ -47090,7 +48227,7 @@ RED.subflow = (function() {
|
|
|
47090
48227
|
input.prop("checked",boolVal);
|
|
47091
48228
|
break;
|
|
47092
48229
|
case "spinner":
|
|
47093
|
-
input = $('<input>').css('width','70%').appendTo(row);
|
|
48230
|
+
input = $('<input>').css('width','70%').attr('id', elId).appendTo(row);
|
|
47094
48231
|
var spinnerOpts = {};
|
|
47095
48232
|
if (ui.opts.hasOwnProperty('min')) {
|
|
47096
48233
|
spinnerOpts.min = ui.opts.min;
|
|
@@ -47119,18 +48256,25 @@ RED.subflow = (function() {
|
|
|
47119
48256
|
default: 'cred'
|
|
47120
48257
|
})
|
|
47121
48258
|
break;
|
|
47122
|
-
|
|
47123
|
-
|
|
47124
|
-
|
|
48259
|
+
case "conf-types":
|
|
48260
|
+
// let clsId = 'config-node-input-' + val.type + '-' + val.value + '-' + Math.floor(Math.random() * 100000);
|
|
48261
|
+
// clsId = clsId.replace(/\W/g, '-');
|
|
48262
|
+
// input = $('<input>').css('width','70%').addClass(clsId).attr('id', elId).appendTo(row);
|
|
48263
|
+
input = $('<input>').css('width','70%').attr('id', elId).appendTo(row);
|
|
48264
|
+
const _type = tenv.parent?.type || tenv.type;
|
|
48265
|
+
RED.editor.prepareConfigNodeSelect(node, tenv.name, _type, 'node-input-subflow-env', null, tenv);
|
|
48266
|
+
break;
|
|
47125
48267
|
}
|
|
47126
48268
|
}
|
|
47127
48269
|
|
|
47128
48270
|
/**
|
|
47129
|
-
*
|
|
48271
|
+
* Build the edit form for a subflow instance
|
|
48272
|
+
* Also used to build the preview form in the subflow template edit dialog
|
|
47130
48273
|
* @param uiContainer - container for UI
|
|
47131
48274
|
* @param envList - env var definitions of template
|
|
47132
48275
|
*/
|
|
47133
48276
|
function buildEnvUI(uiContainer, envList, node) {
|
|
48277
|
+
if(RED.subflow.debug) { console.log("buildEnvUI",envList) }
|
|
47134
48278
|
uiContainer.empty();
|
|
47135
48279
|
for (var i = 0; i < envList.length; i++) {
|
|
47136
48280
|
var tenv = envList[i];
|
|
@@ -47138,7 +48282,7 @@ RED.subflow = (function() {
|
|
|
47138
48282
|
continue;
|
|
47139
48283
|
}
|
|
47140
48284
|
var row = $("<div/>", { class: "form-row" }).appendTo(uiContainer);
|
|
47141
|
-
buildEnvUIRow(row,
|
|
48285
|
+
buildEnvUIRow(row, tenv, node);
|
|
47142
48286
|
}
|
|
47143
48287
|
}
|
|
47144
48288
|
// buildEnvUI
|
|
@@ -47211,6 +48355,9 @@ RED.subflow = (function() {
|
|
|
47211
48355
|
delete ui.opts
|
|
47212
48356
|
}
|
|
47213
48357
|
break;
|
|
48358
|
+
case "conf-types":
|
|
48359
|
+
delete ui.opts;
|
|
48360
|
+
break;
|
|
47214
48361
|
default:
|
|
47215
48362
|
delete ui.opts;
|
|
47216
48363
|
}
|
|
@@ -47233,8 +48380,9 @@ RED.subflow = (function() {
|
|
|
47233
48380
|
if (/^subflow:/.test(node.type)) {
|
|
47234
48381
|
var subflowDef = RED.nodes.subflow(node.type.substring(8));
|
|
47235
48382
|
if (subflowDef.env) {
|
|
47236
|
-
subflowDef.env.forEach(function(env) {
|
|
48383
|
+
subflowDef.env.forEach(function(env, i) {
|
|
47237
48384
|
var item = {
|
|
48385
|
+
index: i,
|
|
47238
48386
|
name:env.name,
|
|
47239
48387
|
parent: {
|
|
47240
48388
|
type: env.type,
|
|
@@ -47271,14 +48419,20 @@ RED.subflow = (function() {
|
|
|
47271
48419
|
var nodePropValue = nodeProp;
|
|
47272
48420
|
if (prop.ui && prop.ui.type === "cred") {
|
|
47273
48421
|
nodePropType = "cred";
|
|
48422
|
+
} else if (prop.ui && prop.ui.type === "conf-types") {
|
|
48423
|
+
nodePropType = prop.value.type
|
|
47274
48424
|
} else {
|
|
47275
48425
|
switch(typeof nodeProp) {
|
|
47276
48426
|
case "string": nodePropType = "str"; break;
|
|
47277
48427
|
case "number": nodePropType = "num"; break;
|
|
47278
48428
|
case "boolean": nodePropType = "bool"; nodePropValue = nodeProp?"true":"false"; break;
|
|
47279
48429
|
default:
|
|
47280
|
-
|
|
47281
|
-
|
|
48430
|
+
if (nodeProp) {
|
|
48431
|
+
nodePropType = nodeProp.type;
|
|
48432
|
+
nodePropValue = nodeProp.value;
|
|
48433
|
+
} else {
|
|
48434
|
+
nodePropType = 'str'
|
|
48435
|
+
}
|
|
47282
48436
|
}
|
|
47283
48437
|
}
|
|
47284
48438
|
var item = {
|
|
@@ -47299,6 +48453,7 @@ RED.subflow = (function() {
|
|
|
47299
48453
|
}
|
|
47300
48454
|
|
|
47301
48455
|
function exportSubflowInstanceEnv(node) {
|
|
48456
|
+
if(RED.subflow.debug) { console.log("exportSubflowInstanceEnv",node) }
|
|
47302
48457
|
var env = [];
|
|
47303
48458
|
// First, get the values for the SubflowTemplate defined properties
|
|
47304
48459
|
// - these are the ones with custom UI elements
|
|
@@ -47345,6 +48500,9 @@ RED.subflow = (function() {
|
|
|
47345
48500
|
item.type = 'bool';
|
|
47346
48501
|
item.value = ""+input.prop("checked");
|
|
47347
48502
|
break;
|
|
48503
|
+
case "conf-types":
|
|
48504
|
+
item.value = input.val()
|
|
48505
|
+
item.type = data.parent.value;
|
|
47348
48506
|
}
|
|
47349
48507
|
if (ui.type === "cred" || item.type !== data.parent.type || item.value !== data.parent.value) {
|
|
47350
48508
|
env.push(item);
|
|
@@ -47358,8 +48516,15 @@ RED.subflow = (function() {
|
|
|
47358
48516
|
return 'node-input-subflow-env-'+name.replace(/[^a-z0-9-_]/ig,"_");
|
|
47359
48517
|
}
|
|
47360
48518
|
|
|
47361
|
-
|
|
48519
|
+
|
|
48520
|
+
/**
|
|
48521
|
+
* Build the subflow edit form
|
|
48522
|
+
* Called by subflow.oneditprepare for both instances and templates
|
|
48523
|
+
* @param {"subflow"|"subflow-template"} type - the type of subflow being edited
|
|
48524
|
+
* @param {Object} node - the node being edited
|
|
48525
|
+
*/
|
|
47362
48526
|
function buildEditForm(type,node) {
|
|
48527
|
+
if(RED.subflow.debug) { console.log("buildEditForm",type,node) }
|
|
47363
48528
|
if (type === "subflow-template") {
|
|
47364
48529
|
// This is the tabbed UI that offers the env list - with UI options
|
|
47365
48530
|
// plus the preview tab
|
|
@@ -55021,10 +56186,15 @@ RED.touch.radialMenu = (function() {
|
|
|
55021
56186
|
|
|
55022
56187
|
function listTour() {
|
|
55023
56188
|
return [
|
|
56189
|
+
{
|
|
56190
|
+
id: "4_0",
|
|
56191
|
+
label: "4.0",
|
|
56192
|
+
path: "./tours/welcome.js"
|
|
56193
|
+
},
|
|
55024
56194
|
{
|
|
55025
56195
|
id: "3_1",
|
|
55026
56196
|
label: "3.1",
|
|
55027
|
-
path: "./tours/welcome.js"
|
|
56197
|
+
path: "./tours/3.1/welcome.js"
|
|
55028
56198
|
},
|
|
55029
56199
|
{
|
|
55030
56200
|
id: "3_0",
|