diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 70d36deb1..cf871716a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18, 20, 22] + node-version: [18, 20, 22.4.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js index dae3f6fa6..60615671e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js @@ -32,24 +32,28 @@ RED.contextMenu = (function () { const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g let hasGroup, isAllGroups = true, hasDisabledNode, hasEnabledNode, hasLabeledNode, hasUnlabeledNode; if (hasSelection) { - selection.nodes.forEach(n => { + const nodes = selection.nodes.slice(); + while (nodes.length) { + const n = nodes.shift(); if (n.type === 'group') { hasGroup = true; + nodes.push(...n.nodes); } else { isAllGroups = false; - } - if (n.d) { - hasDisabledNode = true; - } else { - hasEnabledNode = true; + if (n.d) { + hasDisabledNode = true; + } else { + hasEnabledNode = true; + } } if (n.l === undefined || n.l) { hasLabeledNode = true; } else { hasUnlabeledNode = true; } - }); + } } + const offset = $("#red-ui-workspace-chart").offset() let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft() diff --git a/packages/node_modules/@node-red/nodes/core/sequence/17-split.html b/packages/node_modules/@node-red/nodes/core/sequence/17-split.html index d19be77f5..f1237231f 100644 --- a/packages/node_modules/@node-red/nodes/core/sequence/17-split.html +++ b/packages/node_modules/@node-red/nodes/core/sequence/17-split.html @@ -21,7 +21,7 @@
msg.payload
based on type:",
"object": "Object",
"objectSend": "Send a message for each key/value pair",
"strBuff": "String / Buffer",
"array": "Array",
+ "splitThe": "Split the",
"splitUsing": "Split using",
"splitLength": "Fixed length of",
"stream": "Handle as a stream of messages",
@@ -1113,6 +1114,7 @@
"too-many": "too many pending messages in batch node",
"unexpected": "unexpected mode",
"no-parts": "no parts property in message",
+ "honourParts": "Allow msg.parts to also complete batch operation.",
"error": {
"invalid-count": "Invalid count",
"invalid-overlap": "Invalid overlap",
diff --git a/packages/node_modules/@node-red/nodes/locales/ja/messages.json b/packages/node_modules/@node-red/nodes/locales/ja/messages.json
index fe81a80ad..8d38ac077 100644
--- a/packages/node_modules/@node-red/nodes/locales/ja/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/ja/messages.json
@@ -1017,6 +1017,7 @@
"objectSend": "各key/valueペアのメッセージを送信",
"strBuff": "文字列 / バッファ",
"array": "配列",
+ "splitThe": "に基づく",
"splitUsing": "分割",
"splitLength": "固定長",
"stream": "メッセージのストリームとして処理",
diff --git a/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json b/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json
index 274053bc6..51e1fd897 100644
--- a/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json
@@ -44,7 +44,7 @@
"global": "contexto global",
"str": "Cadeia de caracteres",
"num": "número",
- "bool": "booliano",
+ "bool": "booliano",
"json": "objeto",
"bin": "Armazenamento temporário",
"date": "Carimbo de data/hora",
@@ -352,8 +352,8 @@
}
},
"trigger": {
- "send": "Enviar",
- "then": "então",
+ "send": "Enviar",
+ "then": "então",
"then-send": "então enviem",
"output": {
"string": "a cadeia de caracteres",
@@ -446,7 +446,7 @@
"staticTopic": "Assinar um tópico único",
"dynamicTopic": "Assinatura dinâmica",
"auto-connect": "Conectar automaticamente",
- "auto-mode-depreciated": "Esta opção está deprecada. Favor utilizar o novo modo de auto-detecção."
+ "auto-mode-depreciated": "Esta opção está deprecada. Favor utilizar o novo modo de auto-detecção."
},
"sections-label": {
"birth-message": "Mensagem enviada na conexão (mensagem de nascimento)",
@@ -466,8 +466,8 @@
"close-topic": "Deixe em branco para desativar a mensagem de fechamento"
},
"state": {
- "connected": "Conectado ao negociante: _ broker _",
- "disconnected": "Desconectado do negociante: _ broker _",
+ "connected": "Conectado ao negociante: _ broker _",
+ "disconnected": "Desconectado do negociante: _ broker _",
"connect-failed": "Falha na conexão com o negociante: __broker__",
"broker-disconnected": "Cliente de negociante __broker__ desconectado: __reasonCode__ __reasonString__"
},
@@ -898,7 +898,7 @@
"o2j": "Objeto para opções JSON",
"pretty": "Formatar cadeia de caracteres JSON",
"action": "Ação",
- "property": "Propriedade",
+ "property": "Propriedade",
"actions": {
"toggle": "Converter entre cadeia de caracteres JSON e Objeto",
"str": "Sempre converter em cadeia de caracteres JSON",
@@ -929,7 +929,7 @@
"write": "escrever arquivo",
"read": "ler arquivo",
"filename": "Nome do arquivo",
- "path": "caminho",
+ "path": "caminho",
"action": "Ação",
"addnewline": "Adicionar nova linha (\\n) a cada carga útil?",
"createdir": "Criar diretório se não existir?",
@@ -994,6 +994,7 @@
"objectSend": "Envia uma mensagem para cada par chave/valor",
"strBuff": "Cadeia de caracteres / Armazenamento Temporário",
"array": "Matriz",
+ "splitThe": "Dividir",
"splitUsing": "Dividir usando",
"splitLength": "Comprimento fixo de",
"stream": "Tratar como uma transmissão de mensagens",
@@ -1066,9 +1067,9 @@
"batch" : {
"batch": "lote",
"mode": {
- "label": "Modo",
- "num-msgs": "Agrupar por número de mensagens",
- "interval": "Agrupar por intervalo de tempo",
+ "label": "Modo",
+ "num-msgs": "Agrupar por número de mensagens",
+ "interval": "Agrupar por intervalo de tempo",
"concat": "Concatenar sequências"
},
"count": {
diff --git a/packages/node_modules/@node-red/nodes/locales/ru/messages.json b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
index d2bb5777e..2694ac6a5 100644
--- a/packages/node_modules/@node-red/nodes/locales/ru/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
@@ -874,6 +874,7 @@
"objectSend":"Отправлять сообщение для каждой пары ключ/значение",
"strBuff":"Строка / Буфер",
"array":"Массив",
+ "splitThe": "Pазделить",
"splitUsing":"С помощью",
"splitLength":"Фикс. длина",
"stream":"Обрабатывать как поток сообщений",
diff --git a/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json b/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json
index 7a0ea4ae4..7d5616a8f 100644
--- a/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json
@@ -997,6 +997,7 @@
"objectSend": "每个键值对作为单个消息发送",
"strBuff": "字符串 / Buffer",
"array": "数组",
+ "splitThe": "Split",
"splitUsing": "拆分使用",
"splitLength": "固定长度",
"stream": "作为消息流处理",
diff --git a/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json b/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json
index f43531fb1..7d16c5817 100644
--- a/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json
@@ -866,6 +866,7 @@
"objectSend": "每個鍵值對作為單個消息發送",
"strBuff": "字串 / Buffer",
"array": "陣列",
+ "splitThe": "Split",
"splitUsing": "拆分使用",
"splitLength": "固定長度",
"stream": "作為消息流處理",
diff --git a/test/nodes/core/sequence/19-batch_spec.js b/test/nodes/core/sequence/19-batch_spec.js
index 2ebcb8d4d..b4025a3f8 100644
--- a/test/nodes/core/sequence/19-batch_spec.js
+++ b/test/nodes/core/sequence/19-batch_spec.js
@@ -98,7 +98,7 @@ describe('BATCH node', function() {
var n2 = helper.getNode("n2");
check_data(n1, n2, results, done);
for(var i = 0; i < 6; i++) {
- n1.receive({payload: i});
+ n1.receive({payload: i, parts: { count:6, index:i }});
}
});
}
@@ -168,6 +168,25 @@ describe('BATCH node', function() {
check_count(flow, results, done);
});
+ it('should create seq. with count (more sent than count)', function(done) {
+ var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 4, overlap: 0, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]},
+ {id:"n2", type:"helper"}];
+ var results = [
+ [0, 1, 2, 3]
+ ];
+ check_count(flow, results, done);
+ });
+
+ it('should create seq. with count and terminate early if parts honoured', function(done) {
+ var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 4, overlap: 0, interval: 10, allowEmptySequence:false, honourParts:true, topics: [], wires:[["n2"]]},
+ {id:"n2", type:"helper"}];
+ var results = [
+ [0, 1, 2, 3],
+ [4, 5]
+ ];
+ check_count(flow, results, done);
+ });
+
it('should create seq. with count and overlap', function(done) {
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 3, overlap: 2, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]},
{id:"n2", type:"helper"}];
@@ -455,7 +474,7 @@ describe('BATCH node', function() {
function mapiDoneTestHelper(done, mode, count, overlap, interval, allowEmptySequence, msgAndTimings) {
const completeNode = require("nr-test-utils").require("@node-red/nodes/core/common/24-complete.js");
const catchNode = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js");
- const flow = [{id:"batchNode1", type:"batch", name: "BatchNode", mode, count, overlap, interval,
+ const flow = [{id:"batchNode1", type:"batch", name: "BatchNode", mode, count, overlap, interval,
allowEmptySequence, topics: [{topic: "TA"}], wires:[[]]},
{id:"completeNode1",type:"complete",scope: ["batchNode1"],uncaught:false,wires:[["helperNode1"]]},
{id:"catchNode1", type:"catch",scope: ["batchNode1"],uncaught:false,wires:[["helperNode1"]]},
@@ -482,13 +501,13 @@ describe('BATCH node', function() {
}
it('should call done() when message is sent (mode: count)', function(done) {
- mapiDoneTestHelper(done, "count", 2, 0, 2, false, [
+ mapiDoneTestHelper(done, "count", 2, 0, 2, false, [
{ msg: {payload: 0}, delay: 0, avr: 0, var: 100},
{ msg: {payload: 1}, delay: 0, avr: 0, var: 100}
]);
});
it('should call done() when reset (mode: count)', function(done) {
- mapiDoneTestHelper(done, "count", 2, 0, 2, false, [
+ mapiDoneTestHelper(done, "count", 2, 0, 2, false, [
{ msg: {payload: 0}, delay: 0, avr: 200, var: 100},
{ msg: {payload: 1, reset:true}, delay: 200, avr: 200, var: 100}
]);