Compare commits

...

29 Commits

Author SHA1 Message Date
Nick O'Leary
610cb170e7 Fix connection keep-alive in http request node 2023-06-21 15:45:23 +01:00
Nick O'Leary
2571949e90 Merge pull request #4143 from inNETMonitoring/fix/joinManual
fix: closes #4142
2023-06-21 14:24:53 +01:00
Nick O'Leary
01c56f6515 Merge pull request #4200 from GogoVega/french-translation-of-welcome-tours
French translation of Welcome Tours
2023-06-21 14:03:56 +01:00
Nick O'Leary
026be5a990 Merge pull request #4199 from GogoVega/french-translation-of-v3.1.0-beta.3
French translation of v3.1.0-beta.3 changes
2023-06-21 14:01:10 +01:00
Nick O'Leary
1a24efe85d Merge pull request #4209 from HiroyasuNishiyama/jp-message
add Japanese message for 3.1.0 beta 3
2023-06-21 13:34:23 +01:00
Nick O'Leary
0b3f7dbb1f Merge pull request #4203 from node-red/fix-delay-node-flush-issue-4202
Fix delay node flush issue
2023-06-21 13:27:32 +01:00
Nick O'Leary
e90007860c Merge pull request #4207 from node-red/4197-status-catch-label
Update status and catch node labels in group mode
2023-06-21 13:27:09 +01:00
BitCaesar
0db288e6dc Merge branch 'dev' into fix/joinManual 2023-05-31 16:10:41 +02:00
Stephen McLaughlin
f8175fc325 Update packages/node_modules/@node-red/nodes/locales/en-US/messages.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2023-05-31 14:11:06 +01:00
Stephen McLaughlin
5eee38e7de Update packages/node_modules/@node-red/nodes/locales/en-US/messages.json
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2023-05-31 14:10:59 +01:00
Nick O'Leary
fb5b470966 Merge pull request #4208 from node-red/4198-group-edit-stack-overflow
Dont clone the group nodes `node` array when saving edits
2023-05-31 09:50:31 +01:00
GogoVega
9714ef19de Missing french translation of beta 3 changes 2023-05-30 14:19:39 +02:00
HiroyasuNishiyama
613a345771 add additional Japanese translation for status and catch node 2023-05-30 20:58:17 +09:00
BitCaesar
4fe29dd33f Merge branch 'dev' into fix/joinManual 2023-05-30 10:42:04 +02:00
Steve-Mcl
4b24223290 Dont clone group node node array
fixes #4198
2023-05-29 23:55:52 +01:00
Steve-Mcl
a78da0db1e Update status and catch node labels in group mode 2023-05-29 22:47:29 +01:00
Dave Conway-Jones
5e4fce1e12 Fix delay node flush issue
to close #4202
2023-05-27 17:51:21 +01:00
GogoVega
4cb2624a5d French translation of Welcome Tours 2023-05-26 20:58:50 +02:00
GogoVega
58e045f25d French translation of changes from v3.1.0-beta.3 2023-05-26 20:52:25 +02:00
Nick O'Leary
26a770e490 Merge pull request #4192 from node-red/prep-310-beta3
Bump everything for beta.3
2023-05-26 13:31:53 +01:00
Nick O'Leary
dfe145a0ed Merge pull request #4190 from Steve-Mcl/fix-mqtt-keep-subscription-4132
Fix new feature "mqtt keep subscription"
2023-05-26 13:31:15 +01:00
Steve-Mcl
6cb4c9224d Merge remote-tracking branch 'upstream/dev' into fix-mqtt-keep-subscription-4132 2023-05-26 10:46:59 +01:00
Nick O'Leary
1978a360af Merge pull request #4191 from node-red/update-xml2js
Update xml2js
2023-05-26 10:30:13 +01:00
Nick O'Leary
47a945d92e Merge pull request #4195 from node-red/4191-function-error-badge-not-shown
fix function node error badge not shown
2023-05-26 10:29:23 +01:00
Steve-Mcl
59ec87a393 fix function node error badge not shown
fixes #4194
2023-05-26 10:12:48 +01:00
Nick O'Leary
cfa25dc655 Update xml2js 2023-05-25 17:30:17 +01:00
Steve-Mcl
0528c12782 Merge remote-tracking branch 'upstream/dev' into fix-mqtt-keep-subscription-4132 2023-05-25 12:07:33 +01:00
Steve-Mcl
dee68b903c fix sub/unsub when using "dont unsub" 2023-05-13 11:14:57 +01:00
BitCaesar
e16d5cf83d fix: closes #4142
The issue occured because the partId is set to "_" by default and is never overwritten in manual mode.
With concurrent messages and different processing times all parts of all messages have the identifier "_" and are assembled following the FIFO principle.
2023-04-20 12:28:36 +02:00
18 changed files with 467 additions and 188 deletions

View File

@@ -79,7 +79,7 @@
"uglify-js": "3.17.4",
"uuid": "9.0.0",
"ws": "7.5.6",
"xml2js": "0.5.0"
"xml2js": "0.6.0"
},
"optionalDependencies": {
"bcrypt": "5.1.0"

View File

@@ -504,6 +504,7 @@
"unassigned": "Non attribué",
"global": "global",
"workspace": "espace de travail",
"editor": "boîte de dialogue d'édition",
"selectAll": "Tout sélectionner",
"selectNone": "Ne rien sélectionner",
"selectAllConnected": "Sélectionner tous les éléments connectés",

View File

@@ -720,7 +720,10 @@ RED.editor = (function() {
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
oldValues[d] = editing_node[d];
} else {
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
// Dont clone the group node `nodes` array
if (editing_node.type !== 'group' || d !== "nodes") {
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
}
}
}
}

View File

@@ -1168,19 +1168,19 @@ RED.editor.codeEditor.monaco = (function() {
// Warning: 4
// Error: 8
ed.getAnnotations = function getAnnotations() {
var aceCompatibleMarkers = [];
let aceCompatibleMarkers;
try {
var _model = ed.getModel();
const _model = ed.getModel();
if (_model !== null) {
var id = _model._languageId; // e.g. javascript
var ra = _model._associatedResource.authority; //e.g. model
var rp = _model._associatedResource.path; //e.g. /18
var rs = _model._associatedResource.scheme; //e.g. inmemory
var modelMarkers = monaco.editor.getModelMarkers(_model) || [];
var thisEditorsMarkers = modelMarkers.filter(function (marker) {
var _ra = marker.resource.authority; //e.g. model
var _rp = marker.resource.path; //e.g. /18
var _rs = marker.resource.scheme; //e.g. inmemory
const id = _model.getLanguageId(); // e.g. javascript
const ra = _model.uri.authority; // e.g. model
const rp = _model.uri.path; // e.g. /18
const rs = _model.uri.scheme; // e.g. inmemory
const modelMarkers = monaco.editor.getModelMarkers(_model) || [];
const thisEditorsMarkers = modelMarkers.filter(function (marker) {
const _ra = marker.resource.authority; // e.g. model
const _rp = marker.resource.path; // e.g. /18
const _rs = marker.resource.scheme; // e.g. inmemory
return marker.owner == id && _ra === ra && _rp === rp && _rs === rs;
})
aceCompatibleMarkers = thisEditorsMarkers.map(function (marker) {

View File

@@ -5,17 +5,20 @@ export default {
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 3.0!",
"ja": "Node-RED 3.0へようこそ!"
"ja": "Node-RED 3.0へようこそ!",
"fr": "Bienvenue dans Node-RED 3.0 !"
},
description: {
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>"
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>",
"fr": "<p>Prenons un moment pour découvrir les nouvelles fonctionnalités de cette version.</p>"
}
},
{
title: {
"en-US": "Context Menu",
"ja": "コンテキストメニュー"
"ja": "コンテキストメニュー",
"fr": "Menu contextuel"
},
image: '3.0/images/context-menu.png',
description: {
@@ -24,13 +27,17 @@ export default {
<p>This makes many of the built-in actions much easier
to access.</p>`,
"ja": `<p>ワークスペースで右クリックすると、エディタに独自のコンテキストメニューが表示されるようになりました。</p>
<p>これによって多くの組み込み動作を、より簡単に利用できます。</p>`
<p>これによって多くの組み込み動作を、より簡単に利用できます。</p>`,
"fr": `<p>L'éditeur a maintenant son propre menu contextuel lorsque vous
faites un clic droit dans l'espace de travail.</p>
<p>Cela facilite l'accès à de nombreuses actions intégrées.</p>`
}
},
{
title: {
"en-US": "Wire Junctions",
"ja": "分岐点をワイヤーに追加"
"ja": "分岐点をワイヤーに追加",
"fr": "Jonctions de fils"
},
image: '3.0/images/junction-slice.gif',
description: {
@@ -40,13 +47,18 @@ export default {
<p>Junctions can be added to wires by holding both the Alt key and the Shift key
then click and drag the mouse across the wires.</p>`,
"ja": `<p>フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。</p>
<p>Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`
<p>Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。</p>`,
"fr": `<p>Pour faciliter le routage des câbles autour de vos flux, il est désormais possible d'ajouter des noeuds
de jonction qui vous donnent plus de contrôle.</p>
<p>Les jonctions peuvent être ajoutées aux fils en maintenant les touches Alt et Maj enfoncées, puis en cliquant
et en faisant glisser la souris sur les fils.</p>`
},
},
{
title: {
"en-US": "Wire Junctions",
"ja": "分岐点をワイヤーに追加"
"ja": "分岐点をワイヤーに追加",
"fr": "Jonctions de fils"
},
image: '3.0/images/junction-quick-add.png',
description: {
@@ -54,13 +66,16 @@ export default {
<p>The dialog is opened by holding the Ctrl (or Cmd) key when
clicking in the workspace.</p>`,
"ja": `<p>クイック追加ダイアログを用いて、分岐点を追加することもできます。</p>
<p>本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。</p>`
<p>本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。</p>`,
"fr": `<p>Les jonctions peuvent également être ajoutées à l'aide de la boîte de dialogue d'ajout rapide.</p>
<p>La boîte de dialogue s'ouvre en maintenant la touche Ctrl (ou Cmd) enfoncée lors d'un clic dans l'espace de travail.</p>`
},
},
{
title: {
"en-US": "Debug Path Tooltip",
"ja": "デバッグパスのツールチップ"
"ja": "デバッグパスのツールチップ",
"fr": "Info-bulle du chemin de débogage"
},
image: '3.0/images/debug-path-tooltip.png',
description: {
@@ -73,26 +88,33 @@ export default {
the workspace.</p>`,
"ja": `<p>デバックサイドバー内のノード名の上にマウスカーソルを乗せると、新たにツールチップが表示され、ノードの場所が分かるようになっています。</p>
<p>これは、サブフローを用いる時に役立つ機能であり、メッセージがどのノードから出力されたかを正確に特定することが遥かに簡単になります。</p>
<p>本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。</p>`
<p>本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。</p>`,
"fr": `<p>Lorsque vous passez la souris sur un nom de noeud dans la barre latérale de débogage, une nouvelle info-bulle affiche l'emplacement complet du noeud.</p>
<p>C'est utile lorsque vous travaillez avec des sous-flux, ce qui facilite l'identification exacte du noeud qui a généré le message.</p>
<p>Cliquer sur n'importe quel élément de la liste le révélera dans l'espace de travail.</p>`
},
},
{
title: {
"en-US": "Continuous Search",
"ja": "連続した検索"
"ja": "連続した検索",
"fr": "Recherche continue"
},
image: '3.0/images/continuous-search.png',
description: {
"en-US": `<p>When searching for things in the editor, a new toolbar in
the workspace provides options to quickly jump between
the search results.</p>`,
"ja": `<p>ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。</p>`
"ja": `<p>ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。</p>`,
"fr": `<p>Lorsque vous recherchez des éléments dans l'éditeur, une nouvelle barre d'outils dans l'espace de travail fournit des options pour passer
rapidement d'un résultat de recherche à l'autre.</p>`
},
},
{
title: {
"en-US": "New wiring actions",
"ja": "新しいワイヤー操作"
"ja": "新しいワイヤー操作",
"fr": "Nouvelles actions de câblage"
},
image: "3.0/images/split-wire-with-links.gif",
description: {
@@ -106,12 +128,18 @@ export default {
<li><b><code>ワイヤーをlinkードで分割</code></b></li>
</ul>
<p>本アクションは、メインメニュー内の動作一覧から呼び出せます。</p>`,
"fr": `<p>Une nouvelle action a été ajoutée pour remplacer un fil par une paire de noeuds de lien connectés :</p>
<ul>
<li><b><code>Diviser le fil avec les noeuds de liaison</code></b></li>
</ul>
<p>Les actions sont accessibles à partir de la liste d'actions dans le menu principal.</p>`
},
},
{
title: {
"en-US": "Default node names",
"ja": "標準ノードの名前"
"ja": "標準ノードの名前",
"fr": "Noms de noeud par défaut"
},
// image: "images/",
description: {
@@ -129,13 +157,22 @@ export default {
<ul>
<li><b><code>ノード名を生成</code></b></li>
</ul><p>本アクションは、メインメニュー内の動作一覧から呼び出せます。</p>
`
`,
"fr": `<p>Certains noeuds ont été mis à jour pour générer un nom unique lorsque
de nouvelles instances sont ajoutées à l'espace de travail. Ceci s'applique aux
noeuds <code>Debug</code>, <code>Function</code> et <code>Link</code>.</p>
<p>Une nouvelle action a également été ajoutée pour générer des noms par défaut pour les noeuds sélectionnés :</p>
<ul>
<li><b><code>Générer des noms de noeud</code></b></li>
</ul>
<p>Les actions sont accessibles à partir de la liste d'actions dans le menu principal.</p>`
}
},
{
title: {
"en-US": "Node Updates",
"ja": "ノードの更新"
"ja": "ノードの更新",
"fr": "Mises à jour des noeuds"
},
// image: "images/",
description: {
@@ -148,6 +185,11 @@ export default {
<li>Debugードは、受信したメッセージの数をカウントするよう設定できるようになりました。</li>
<li>Link Callードは、メッセージのプロパティによって、呼び出し対象のlinkを動的に指定できるようになりました。</li>
<li>HTTP Requestードは、HTTPヘッダを事前設定できるようになりました。</li>
</ul>`,
"fr": `<ul>
<li>Le noeud de débogage peut être configuré pour compter les messages qu'il reçoit</li>
<li>Le noeud Link Call peut utiliser une propriété de message pour cibler dynamiquement le lien qu'il doit appeler</li>
<li>Le noeud de requête HTTP peut être préconfiguré avec des en-têtes HTTP</li>
</ul>`
}
}

View File

@@ -3,12 +3,14 @@ export default {
{
title: {
'en-US': 'Create your first flow',
'ja': 'はじめてのフローを作成'
'ja': 'はじめてのフローを作成',
'fr': "Créer votre premier flux"
},
width: 400,
description: {
'en-US': 'This tutorial will guide you through creating your first flow',
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。'
'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。',
'fr': "Ce didacticiel vous guidera dans la création de votre premier flux"
},
nextButton: 'start'
},
@@ -16,7 +18,8 @@ export default {
element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add",
description: {
'en-US': 'To add a new tab, click the <i class="fa fa-plus"></i> button',
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。'
'ja': '新しいタブを追加するため、 <i class="fa fa-plus"></i> ボタンをクリックします。',
'fr': 'Pour ajouter un nouvel onglet, cliquez sur le bouton <i class="fa fa-plus"></i>'
},
wait: {
type: "dom-event",
@@ -29,7 +32,8 @@ export default {
direction: 'right',
description: {
'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.',
'ja': 'パレットには、利用できる全てのードが一覧表示されます。injectードをワークスペースにドラッグします。'
'ja': 'パレットには、利用できる全てのードが一覧表示されます。injectードをワークスペースにドラッグします。',
'fr': "La palette répertorie tous les noeuds disponibles à utiliser. Faites glisser un nouveau noeud Inject dans l'espace de travail."
},
fallback: 'inset-bottom-right',
wait: {
@@ -52,7 +56,8 @@ export default {
direction: 'right',
description: {
'en-US': 'Next, drag a new Debug node into the workspace.',
'ja': '次に、debugードをワークスペースにドラッグします。'
'ja': '次に、debugードをワークスペースにドラッグします。',
'fr': "Ensuite, faites glisser un nouveau noeud Debug dans l'espace de travail."
},
fallback: 'inset-bottom-right',
wait: {
@@ -74,7 +79,8 @@ export default {
element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") },
description: {
'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node',
'ja': 'injectードの出力から、debugードの入力へワイヤーで接続します。'
'ja': 'injectードの出力から、debugードの入力へワイヤーで接続します。',
'fr': "Ajoutez un fil de la sortie du noeud Inject à l'entrée du noeud Debug"
},
fallback: 'inset-bottom-right',
wait: {
@@ -89,7 +95,8 @@ export default {
element: "#red-ui-header-button-deploy",
description: {
'en-US': 'Deploy your changes so the flow is active in the runtime',
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。'
'ja': 'フローをランタイムで実行させるため、変更をデプロイします。',
'fr': "Déployez vos modifications afin que le flux soit actif dans le runtime"
},
width: 200,
wait: {

View File

@@ -5,17 +5,20 @@ export default {
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 3.1 Beta 3!",
"ja": "Node-RED 3.1 ベータ3へようこそ!"
"ja": "Node-RED 3.1 ベータ3へようこそ!",
"fr": "Bienvenue dans Node-RED 3.1 Bêta 3 !"
},
description: {
"en-US": "<p>This is the third beta release for 3.1.0. This is mostly a bug fix release, so you can skip this tour if you've tried the other betas.</p><p>If not, stick around to see what's new in Node-RED 3.1.</p>",
"ja": "<p>これは3.1.0の3回目のベータリリースです。不具合修正のリリースのため、もし他のベータ版を試したことがある場合は、このツアーを読み飛ばしてもかまいません。</p><p>そうでない場合は、Node-RED 3.1の新機能を確認してください。</p>"
"ja": "<p>これは3.1.0の3回目のベータリリースです。不具合修正のリリースのため、もし他のベータ版を試したことがある場合は、このツアーを読み飛ばしてもかまいません。</p><p>そうでない場合は、Node-RED 3.1の新機能を確認してください。</p>",
"fr": "<p>Il s'agit de la troisième bêta de la version 3.1.0. Cette version apporte principalement la correction de bugs, vous pouvez donc ignorer cette visite guidée si vous avez essayé les autres versions bêta.</p><p>Si ce n'est pas le cas, restez dans les parages pour voir les nouveautés de Node-RED 3.1.</p>"
}
},
{
title: {
"en-US": "New ways to work with groups",
"ja": "グループの新たな操作方法"
"ja": "グループの新たな操作方法",
"fr": "De nouvelles façons de travailler avec les groupes"
},
description: {
"en-US": `<p>We have changed how you interact with groups in the editor.</p>
@@ -31,28 +34,41 @@ export default {
<li>「前面へ移動」と「背面へ移動」の動作を用いて、複数のグループの表示順序を変えることができます。</li>
<li>グループ内へ一度に複数のノードをドラッグできるようになりました。</li>
<li><code>Alt</code> を押したまま、グループ内のノードをドラッグすると、そのグループから *除く* ことができます。</li>
</ul>`,
"fr": `<p>Nous avons modifié la façon dont vous interagissez avec les groupes dans l'éditeur.</p>
<ul>
<li>Ils ne gênent plus lorsque vous cliquez sur un noeud</li>
<li>Ils peuvent être réorganisés à l'aide des actions Avancer et Reculer</li>
<li>Plusieurs noeuds peuvent être glissés dans un groupe en une seule fois</li>
<li>Maintenir <code>Alt</code> lors du déplacement d'un noeud le *supprimera* de son groupe</li>
</ul>`
}
},
{
title: {
"en-US": "Change notification on tabs",
"ja": "タブ上の変更通知"
"ja": "タブ上の変更通知",
"fr": "Notification de changement sur les onglets"
},
image: 'images/tab-changes.png',
description: {
"en-US": `<p>When a tab contains undeployed changes it now shows the
same style of change icon used by nodes.</p>
<p>This will make it much easier to track down changes when you're
working across multiple flows.</p>`,
same style of change icon used by nodes.</p>
<p>This will make it much easier to track down changes when you're
working across multiple flows.</p>`,
"ja": `<p>タブ内にデプロイされていない変更が存在する時は、ノードと同じスタイルで変更の印が表示されるようになりました。</p>
<p>これによって複数のフローを編集している時に、変更を見つけるのが簡単になりました。</p>`
<p>これによって複数のフローを編集している時に、変更を見つけるのが簡単になりました。</p>`,
"fr": `<p>Lorsqu'un onglet contient des modifications non déployées, il affiche désormais le
même style d'icône de changement utilisé par les noeuds.</p>
<p>Cela facilitera grandement le suivi des modifications lorsque vous
travaillez sur plusieurs flux.</p>`
}
},
{
title: {
"en-US": "A bigger canvas to work with",
"ja": "より広くなった作業キャンバス"
"ja": "より広くなった作業キャンバス",
"fr": "Un canevas plus grand pour travailler"
},
description: {
"en-US": `<p>The default canvas size has been increased so you can fit more
@@ -60,13 +76,18 @@ export default {
<p>We still recommend using tools such as subflows and Link Nodes to help
keep things organised, but now you have more room to work in.</p>`,
"ja": `<p>標準のキャンバスが広くなったため、1つのフローに沢山のものを含めることができるようになりました。</p>
<p>引き続き、サブフローやリンクノードなどの方法を用いて整理することをお勧めしますが、作業できる場所が増えました。</p>`
<p>引き続き、サブフローやリンクノードなどの方法を用いて整理することをお勧めしますが、作業できる場所が増えました。</p>`,
"fr": `<p>La taille par défaut du canevas a été augmentée pour que vous puissiez en mettre plus
sur un seul flux.</p>
<p>Nous recommandons toujours d'utiliser des outils tels que les sous-flux et les noeuds de lien pour vous aider
à garder les choses organisées, mais vous avez maintenant plus d'espace pour travailler.</p>`
}
},
{
title: {
"en-US": "Finding help",
"ja": "ヘルプを見つける"
"ja": "ヘルプを見つける",
"fr": "Trouver de l'aide"
},
image: 'images/node-help.png',
description: {
@@ -74,23 +95,29 @@ export default {
in the footer.</p>
<p>Clicking it will open up the Help sidebar showing the help for that node.</p>`,
"ja": `<p>全てのノードの編集ダイアログの下に、ノードのヘルプへのリンクが追加されました。</p>
<p>これをクリックすると、ノードのヘルプサイドバーが表示されます。</p>`
<p>これをクリックすると、ノードのヘルプサイドバーが表示されます。</p>`,
"fr": `<p>Toutes les boîtes de dialogue d'édition de noeud incluent désormais un lien vers l'aide de ce noeud
dans le pied de page.</p>
<p>Cliquer dessus ouvrira la barre latérale d'aide affichant l'aide pour ce noeud.</p>`
}
},
{
title: {
"en-US": "And lots more...",
"ja": "そしてさらに沢山あります..."
"ja": "そしてさらに沢山あります...",
"fr": "Et plus encore..."
},
description: {
"en-US": `<p>Of course we have everything from 3.1.0-beta.1 as well....</p>`,
"ja": `<p>もちろん3.1.0 ベータ1の全ての機能があります....</p>`
"ja": `<p>もちろん3.1.0 ベータ1の全ての機能があります....</p>`,
"fr": `<p>Bien sûr, nous avons également tout ce qui concerne la version 3.1.0-beta.1...</p>`
}
},
{
title: {
"en-US": "Improved Context Menu",
"ja": "コンテキストメニューの改善"
"ja": "コンテキストメニューの改善",
"fr": "Menu contextuel amélioré"
},
image: 'images/context-menu.png',
description: {
@@ -102,13 +129,17 @@ export default {
with your flows much easier.</p>`,
"ja": `<p>より多くの組み込み動作を利用できるように、エディタのコンテキストメニューが拡張されました。</p>
<p>ノードの追加、グループの操作、その他の便利なツールをクリックするだけで実行できるようになりました。</p>
<p>フローのタブバーには、フローの操作をより簡単にする独自のコンテキストメニューもあります。</p>`
<p>フローのタブバーには、フローの操作をより簡単にする独自のコンテキストメニューもあります。</p>`,
"fr": `<p>Le menu contextuel de l'éditeur a été étendu pour faire beaucoup plus d'actions intégrées disponibles.</p>
<p>Ajouter des noeuds, travailler avec des groupes et beaucoup d'autres outils utiles sont désormais à portée de clic.</p>
<p>La barre d'onglets de flux possède également son propre menu contextuel pour faciliter l'utilisation de vos flux.</p>`
}
},
{
title: {
"en-US": "Hiding Flows",
"ja": "フローを非表示"
"ja": "フローを非表示",
"fr": "Masquage de flux"
},
image: 'images/hiding-flows.png',
description: {
@@ -116,13 +147,17 @@ export default {
<p>The 'hide' button in previous releases has been removed from the tabs
as they were being clicked accidentally too often.</p>`,
"ja": `<p>フローを非表示にする機能は、フローのコンテキストメニューから実行するようになりました。</p>
<p>これまでのリリースでタブに存在していた「非表示」ボタンは、よく誤ってクリックされていたため、削除されました。</p>`
<p>これまでのリリースでタブに存在していた「非表示」ボタンは、よく誤ってクリックされていたため、削除されました。</p>`,
"fr": `<p>Le masquage des flux s'effectue désormais via le menu contextuel du flux.</p>
<p>Le bouton "Masquer" des versions précédentes a été supprimé des onglets
car il était cliqué accidentellement trop souvent.</p>`
},
},
{
title: {
"en-US": "Locking Flows",
"ja": "フローを固定"
"ja": "フローを固定",
"fr": "Verrouillage de flux"
},
image: 'images/locking-flows.png',
description: {
@@ -132,13 +167,18 @@ export default {
as well as in the Info sidebar explorer.</p>`,
"ja": `<p>誤ってフローに変更が加えられてしまうのを防ぐために、フローを固定できるようになりました。</p>
<p>固定されている時は、ノードを修正することはできません。</p>
<p>フローのコンテキストメニューと、情報サイドバーのエクスプローラには、フローの固定や解除をするためのオプションが用意されています。</p>`
<p>フローのコンテキストメニューと、情報サイドバーのエクスプローラには、フローの固定や解除をするためのオプションが用意されています。</p>`,
"fr": `<p>Les flux peuvent désormais être verrouillés pour éviter toute modification accidentelle.</p>
<p>Lorsqu'il est verrouillé, vous ne pouvez en aucun cas modifier les noeuds.</p>
<p>Le menu contextuel du flux fournit les options pour verrouiller et déverrouiller les flux,
ainsi que dans l'explorateur de la barre latérale d'informations.</p>`
},
},
{
title: {
"en-US": "Adding Images to node/flow descriptions",
"ja": "ノードやフローの説明へ画像を追加"
"ja": "ノードやフローの説明へ画像を追加",
"fr": "Ajout d'images aux descriptions de noeud/flux"
},
// image: 'images/debug-path-tooltip.png',
description: {
@@ -147,44 +187,56 @@ export default {
<p>When the description is shown in the Info sidebar, the image will be displayed.</p>`,
"ja": `<p>ノードまたはフローの説明に、画像を追加できるようになりました。</p>
<p>画像をテキストエディタにドラッグするだけで、行内に埋め込まれます。</p>
<p>情報サイドバーの説明を開くと、その画像が表示されます。</p>`
<p>情報サイドバーの説明を開くと、その画像が表示されます。</p>`,
"fr": `<p>Vous pouvez désormais ajouter des images à la description d'un noeud ou d'un flux.</p>
<p>Faites simplement glisser l'image dans l'éditeur de texte et elle sera ajoutée en ligne.</p>
<p>Lorsque la description s'affiche dans la barre latérale d'informations, l'image s'affiche.</p>`
},
},
{
title: {
"en-US": "Adding Mermaid Diagrams",
"ja": "Mermaid図を追加"
"ja": "Mermaid図を追加",
"fr": "Ajout de diagrammes Mermaid"
},
image: 'images/mermaid.png',
description: {
"en-US": `<p>You can also add <a href="https://github.com/mermaid-js/mermaid">Mermaid</a> diagrams directly into your node or flow descriptions.</p>
<p>This gives you much richer options for documenting your flows.</p>`,
"ja": `<p>ノードやフローの説明に、<a href="https://github.com/mermaid-js/mermaid">Mermaid</a>図を直接追加することもできます。</p>
<p>これによって、フローを説明する文書作成の選択肢がより多くなります。</p>`
<p>これによって、フローを説明する文書作成の選択肢がより多くなります。</p>`,
"fr": `<p>Vous pouvez également ajouter des diagrammes <a href="https://github.com/mermaid-js/mermaid">Mermaid</a> directement dans vos descriptions de noeud ou de flux.</p>
<p>Cela vous offre des options beaucoup plus riches pour documenter vos flux.</p>`
},
},
{
title: {
"en-US": "Managing Global Environment Variables",
"ja": "グローバル環境変数の管理"
"ja": "グローバル環境変数の管理",
"fr": "Gestion des variables d'environnement globales"
},
image: 'images/global-env-vars.png',
description: {
"en-US": `<p>You can set environment variables that apply to all nodes and flows in the new
'Global Environment Variables' section of User Settings.</p>`,
"ja": `<p>ユーザ設定に新しく追加された「大域環境変数」のセクションで、全てのノードとフローに適用される環境変数を登録できます。</p>`
"ja": `<p>ユーザ設定に新しく追加された「大域環境変数」のセクションで、全てのノードとフローに適用される環境変数を登録できます。</p>`,
"fr": `<p>Vous pouvez définir des variables d'environnement qui s'appliquent à tous les noeuds et flux dans la nouvelle
section "Global Environment Variables" des paramètres utilisateur.</p>`
},
},
{
title: {
"en-US": "Node Updates",
"ja": "ノードの更新"
"ja": "ノードの更新",
"fr": "Mises à jour des noeuds"
},
// image: "images/",
description: {
"en-US": `<p>The core nodes have received lots of minor fixes, documentation updates and
small enhancements. Check the full changelog in the Help sidebar for a full list.</p>`,
"ja": `<p>コアノードにマイナーな修正、ドキュメント更新、小規模な拡張が数多く追加されています。全ての一覧は、ヘルプサイドバーの全ての更新履歴を確認してください。</p>`
"ja": `<p>コアノードにマイナーな修正、ドキュメント更新、小規模な拡張が数多く追加されています。全ての一覧は、ヘルプサイドバーの全ての更新履歴を確認してください。</p>`,
"fr": `<p>Les noeuds principaux ont reçu de nombreux correctifs mineurs, mises à jour de la documentation et
petites améliorations. Consulter le journal des modifications complet dans la barre latérale d'aide.</p>`
}
}
]

View File

@@ -41,7 +41,9 @@
if (this.name) {
return this.name;
}
if (this.scope) {
if (this.scope === "group") {
return this._("catch.catchGroup");
} else if (Array.isArray(this.scope)) {
return this._("catch.catchNodes",{number:this.scope.length});
}
return this.uncaught?this._("catch.catchUncaught"):this._("catch.catch")

View File

@@ -33,7 +33,15 @@
outputs:1,
icon: "status.svg",
label: function() {
return this.name||(this.scope?this._("status.statusNodes",{number:this.scope.length}):this._("status.status"));
if (this.name) {
return this.name;
}
if (this.scope === "group") {
return this._("status.statusGroup");
} else if (Array.isArray(this.scope)) {
return this._("status.statusNodes",{number:this.scope.length});
}
return this._("status.status")
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -229,6 +229,7 @@ module.exports = function(RED) {
node.on("input", function(msg, send, done) {
if (!node.drop) {
var m = RED.util.cloneMessage(msg);
delete m.flush;
if (Object.keys(m).length > 1) {
if (node.intervalID !== -1) {
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate)) && node.rate !== m.rate) {

View File

@@ -219,8 +219,10 @@ module.exports = function(RED) {
* Handle the payload / packet recieved in MQTT In and MQTT Sub nodes
*/
function subscriptionHandler(node, datatype ,topic, payload, packet) {
const v5 = node.brokerConn.options && node.brokerConn.options.protocolVersion == 5;
var msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
const msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
const v5 = (node && node.brokerConn)
? node.brokerConn.v5()
: Object.prototype.hasOwnProperty.call(packet, "properties");
if(v5 && packet.properties) {
setStrProp(packet.properties, msg, "responseTopic");
setBufferProp(packet.properties, msg, "correlationData");
@@ -300,7 +302,7 @@ module.exports = function(RED) {
//}
}
msg.payload = payload;
if ((node.brokerConn.broker === "localhost")||(node.brokerConn.broker === "127.0.0.1")) {
if (node.brokerConn && (node.brokerConn.broker === "localhost" || node.brokerConn.broker === "127.0.0.1")) {
msg._topic = topic;
}
node.send(msg);
@@ -412,6 +414,12 @@ module.exports = function(RED) {
}
}
/**
* Perform the connect action
* @param {MQTTInNode|MQTTOutNode} node
* @param {Object} msg
* @param {Function} done
*/
function handleConnectAction(node, msg, done) {
let actionData = typeof msg.broker === 'object' ? msg.broker : null;
if (node.brokerConn.canConnect()) {
@@ -442,12 +450,17 @@ module.exports = function(RED) {
}
}
/**
* Perform the disconnect action
* @param {MQTTInNode|MQTTOutNode} node
* @param {Function} done
*/
function handleDisconnectAction(node, done) {
node.brokerConn.disconnect(function () {
done();
});
}
const unsubscribeCandidates = {}
//#endregion "Supporting functions"
//#region "Broker node"
@@ -591,10 +604,9 @@ module.exports = function(RED) {
if (typeof node.cleansession === 'undefined') {
node.cleansession = true;
}
if (typeof node.autoUnsubscribe === 'undefined') {
if (typeof node.autoUnsubscribe !== 'boolean') {
node.autoUnsubscribe = true;
}
//use url or build a url from usetls://broker:port
if (node.url && node.brokerurl !== node.url) {
node.brokerurl = node.url;
@@ -664,7 +676,6 @@ module.exports = function(RED) {
node.options.password = node.password;
node.options.keepalive = node.keepalive;
node.options.clean = node.cleansession;
node.options.autoUnsubscribe = node.autoUnsubscribe;
node.options.clientId = node.clientid || 'nodered_' + RED.util.generateId();
node.options.reconnectPeriod = RED.settings.mqttReconnectTime||5000;
delete node.options.protocolId; //V4+ default
@@ -785,18 +796,11 @@ module.exports = function(RED) {
// Re-subscribe to stored topics
for (var s in node.subscriptions) {
if (node.subscriptions.hasOwnProperty(s)) {
let topic = s;
let qos = 0;
let _options = {};
for (var r in node.subscriptions[s]) {
if (node.subscriptions[s].hasOwnProperty(r)) {
qos = Math.max(qos,node.subscriptions[s][r].qos);
_options = node.subscriptions[s][r].options;
node._clientOn('message',node.subscriptions[s][r].handler);
node.subscribe(node.subscriptions[s][r])
}
}
_options.qos = _options.qos || qos;
node.client.subscribe(topic, _options);
}
}
@@ -858,22 +862,28 @@ module.exports = function(RED) {
if(!node.client) { return _callback(); }
if(node.closing) { return _callback(); }
/**
* Call end and wait for the client to end (or timeout)
* @param {mqtt.MqttClient} client The broker client
* @param {number} ms The time to wait for the client to end
* @returns
*/
let waitEnd = (client, ms) => {
return new Promise( (resolve, reject) => {
node.closing = true;
if(!client) {
if (!client) {
resolve();
} else {
} else {
const t = setTimeout(() => {
//clean end() has exceeded WAIT_END, lets force end!
client && client.end(true);
reject();
resolve();
}, ms);
client.end(() => {
clearTimeout(t);
resolve()
});
}
clearTimeout(t);
resolve()
});
}
});
};
if(node.connected && node.closeMessage) {
@@ -894,69 +904,222 @@ module.exports = function(RED) {
}
node.subscriptionIds = {};
node.subid = 1;
node.subscribe = function (topic,options,callback,ref) {
ref = ref||0;
var qos;
if(typeof options == "object") {
qos = options.qos;
} else {
qos = options;
options = {};
//typedef for subscription object:
/**
* @typedef {Object} Subscription
* @property {String} topic - topic to subscribe to
* @property {Object} [options] - options object
* @property {Number} [options.qos] - quality of service
* @property {Number} [options.nl] - no local
* @property {Number} [options.rap] - retain as published
* @property {Number} [options.rh] - retain handling
* @property {Number} [options.properties] - MQTT 5.0 properties
* @property {Number} [options.properties.subscriptionIdentifier] - MQTT 5.0 subscription identifier
* @property {Number} [options.properties.userProperties] - MQTT 5.0 user properties
* @property {Function} callback
* @property {String} ref - reference to the node that created the subscription
*/
/**
* Create a subscription object
* @param {String} _topic - topic to subscribe to
* @param {Object} _options - options object
* @param {String} _ref - reference to the node that created the subscription
* @returns {Subscription}
*/
function createSubscriptionObject(_topic, _options, _ref, _brokerId) {
/** @type {Subscription} */
const subscription = {};
const ref = _ref || 0;
let options
let qos = 1 // default to QoS 1 (AWS and several other brokers don't support QoS 2)
// if options is an object, then clone it
if (typeof _options == "object") {
options = RED.util.cloneMessage(_options || {})
qos = _options.qos;
} else if (typeof _options == "number") {
qos = _options;
}
options.qos = qos;
options = options || {};
// sanitise qos
if (typeof qos === "number" && qos >= 0 && qos <= 2) {
options.qos = qos;
}
subscription.topic = _topic;
subscription.qos = qos;
subscription.options = RED.util.cloneMessage(options);
subscription.ref = ref;
subscription.brokerId = _brokerId;
return subscription;
}
/**
* If topic is a subscription object, then use that, otherwise look up the topic in
* the subscriptions object. If the topic is not found, then create a new subscription
* object and add it to the subscriptions object.
* @param {Subscription|String} topic
* @param {*} options
* @param {*} callback
* @param {*} ref
*/
node.subscribe = function (topic, options, callback, ref) {
/** @type {Subscription} */
let subscription
let doCompare = false
let changesFound = false
// function signature 1: subscribe(subscription: Subscription)
if (typeof topic === "object" && topic !== null) {
subscription = topic
topic = subscription.topic
options = subscription.options
ref = subscription.ref
callback = subscription.callback
}
// function signature 2: subscribe(topic: String, options: Object, callback: Function, ref: String)
else if (typeof topic === "string") {
// since this is a call where all params are provided, it might be
// a node change (modification) so we need to check for changes
doCompare = true
subscription = node.subscriptions[topic] && node.subscriptions[topic][ref]
}
// bad function call
else {
console.warn('Invalid call to node.subscribe')
return
}
const thisBrokerId = node.type === 'mqtt-broker' ? node.id : node.broker
// unsubscribe topics where the broker has changed
const oldBrokerSubs = (unsubscribeCandidates[ref] || []).filter(sub => sub.brokerId !== thisBrokerId)
oldBrokerSubs.forEach(sub => {
/** @type {MQTTBrokerNode} */
const _brokerConn = RED.nodes.getNode(sub.brokerId)
if (_brokerConn) {
_brokerConn.unsubscribe(sub.topic, sub.ref, true)
}
})
// if subscription is found (or sent in as a parameter), then check for changes.
// if there are any changes requested, tidy up the old subscription
if (subscription) {
if (doCompare) {
// compare the current sub to the passed in parameters. Use RED.util.compareObjects against
// only the minimal set of properties to identify if the subscription has changed
const currentSubscription = createSubscriptionObject(subscription.topic, subscription.options, subscription.ref)
const newSubscription = createSubscriptionObject(topic, options, ref)
changesFound = RED.util.compareObjects(currentSubscription, newSubscription) === false
}
}
if (changesFound) {
if (subscription.handler) {
node._clientRemoveListeners('message', subscription.handler)
subscription.handler = null
}
const _brokerConn = RED.nodes.getNode(subscription.brokerId)
if (_brokerConn) {
_brokerConn.unsubscribe(subscription.topic, subscription.ref, true)
}
}
// clean up the unsubscribe candidate list
delete unsubscribeCandidates[ref]
// determine if this is an existing subscription
const existingSubscription = typeof subscription === "object" && subscription !== null
// if existing subscription is not found or has changed, create a new subscription object
if (existingSubscription === false || changesFound) {
subscription = createSubscriptionObject(topic, options, ref, node.id)
}
// setup remainder of subscription properties and event handling
node.subscriptions[topic] = node.subscriptions[topic] || {};
node.subscriptions[topic][ref] = subscription
if (!node.subscriptionIds[topic]) {
node.subscriptionIds[topic] = node.subid++;
}
options.properties = options.properties || {};
options.properties.subscriptionIdentifier = node.subscriptionIds[topic];
subscription.options = subscription.options || {};
subscription.options.properties = options.properties || {};
subscription.options.properties.subscriptionIdentifier = node.subscriptionIds[topic];
subscription.callback = callback;
node.subscriptions[topic] = node.subscriptions[topic]||{};
var sub = {
topic:topic,
qos:qos,
options:options,
handler:function(mtopic,mpayload, mpacket) {
if(mpacket.properties && options.properties && mpacket.properties.subscriptionIdentifier && options.properties.subscriptionIdentifier && (mpacket.properties.subscriptionIdentifier !== options.properties.subscriptionIdentifier) ) {
//do nothing as subscriptionIdentifier does not match
} else if (matchTopic(topic,mtopic)) {
callback(mtopic,mpayload, mpacket);
}
},
ref: ref
};
node.subscriptions[topic][ref] = sub;
// if the client is connected, then setup the handler and subscribe
if (node.connected) {
const subIdsAvailable = node.subscriptionIdentifiersAvailable()
node._clientOn('message',sub.handler);
// if the broker doesn't support subscription identifiers (e.g. AWS core), then don't send them
if (options.properties && options.properties.subscriptionIdentifier && subIdsAvailable !== true) {
delete options.properties.subscriptionIdentifier
}
node.client.subscribe(topic, options);
}
};
node.unsubscribe = function (topic, ref, removed) {
ref = ref||0;
var sub = node.subscriptions[topic];
if (sub) {
if (sub[ref]) {
if(node.client) {
node._clientRemoveListeners('message',sub[ref].handler);
}
delete sub[ref];
}
//TODO: Review. The `if(removed)` was commented out to always delete and remove subscriptions.
// if we dont then property changes dont get applied and old subs still trigger
//if (removed) {
if (Object.keys(sub).length === 0) {
delete node.subscriptions[topic];
delete node.subscriptionIds[topic];
if (node.connected) {
node.client.unsubscribe(topic);
if (!subscription.handler) {
subscription.handler = function (mtopic, mpayload, mpacket) {
const sops = subscription.options ? subscription.options.properties : {}
const pops = mpacket.properties || {}
if (subIdsAvailable && pops.subscriptionIdentifier && sops.subscriptionIdentifier && (pops.subscriptionIdentifier !== sops.subscriptionIdentifier)) {
//do nothing as subscriptionIdentifier does not match
} else if (matchTopic(topic, mtopic)) {
subscription.callback && subscription.callback(mtopic, mpayload, mpacket)
}
}
//}
}
node._clientOn('message', subscription.handler)
// if the broker doesn't support subscription identifiers, then don't send them (AWS support)
if (subscription.options.properties && subscription.options.properties.subscriptionIdentifier && subIdsAvailable !== true) {
delete subscription.options.properties.subscriptionIdentifier
}
node.client.subscribe(topic, subscription.options)
}
}
node.unsubscribe = function (topic, ref, removeClientSubscription) {
ref = ref||0;
const unsub = removeClientSubscription || node.autoUnsubscribe !== false
const sub = node.subscriptions[topic];
let brokerId = node.id
if (sub) {
if (sub[ref]) {
brokerId = sub[ref].brokerId || brokerId
if(node.client && sub[ref].handler) {
node._clientRemoveListeners('message', sub[ref].handler);
sub[ref].handler = null
}
if (unsub) {
delete sub[ref]
}
}
// if instructed to remove the actual MQTT client subscription
if (unsub) {
// if there are no more subscriptions for the topic, then remove the topic
if (Object.keys(sub).length === 0) {
try {
node.client.unsubscribe(topic)
} catch (_err) {
// do nothing
} finally {
// remove unsubscribe candidate as it is now REALLY unsubscribed
delete node.subscriptions[topic];
delete node.subscriptionIds[topic];
if (unsubscribeCandidates[ref]) {
unsubscribeCandidates[ref] = unsubscribeCandidates[ref].filter(sub => sub.topic !== topic)
}
}
}
} else {
// if instructed to not remove the client subscription, then add it to the candidate list
// of subscriptions to be removed when the the same ref is used in a subsequent subscribe
// and the topic has changed
unsubscribeCandidates[ref] = unsubscribeCandidates[ref] || [];
unsubscribeCandidates[ref].push({
topic: topic,
ref: ref,
brokerId: brokerId
})
}
}
};
node.topicAliases = {};
@@ -994,7 +1157,7 @@ module.exports = function(RED) {
setStrProp(msg, options.properties, "contentType");
setIntProp(msg, options.properties, "messageExpiryInterval", 0);
setUserProperties(msg.userProperties, options.properties);
setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0);
setIntProp(msg, options.properties, "topicAlias", 1, bsp.topicAliasMaximum || 0);
setBoolProp(msg, options.properties, "payloadFormatIndicator");
//FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455);
@@ -1130,7 +1293,7 @@ module.exports = function(RED) {
if(node.rap === "true" || node.rap === true) options.rap = true;
else if(node.rap === "false" || node.rap === false) options.rap = false;
}
node._topic = node.topic; // store the original topic incase node is later changed
node.brokerConn.subscribe(node.topic,options,function(topic, payload, packet) {
subscriptionHandler(node, node.datatype, topic, payload, packet);
},node.id);
@@ -1183,7 +1346,7 @@ module.exports = function(RED) {
}
if (action === Actions.UNSUBSCRIBE) {
subscriptions.forEach(function (sub) {
node.brokerConn.unsubscribe(sub.topic, node.id);
node.brokerConn.unsubscribe(sub.topic, node.id, true);
delete node.dynamicSubs[sub.topic];
})
//user can access current subscriptions through the complete node is so desired
@@ -1193,7 +1356,7 @@ module.exports = function(RED) {
subscriptions.forEach(function (sub) {
//always unsubscribe before subscribe to prevent multiple subs to same topic
if (node.dynamicSubs[sub.topic]) {
node.brokerConn.unsubscribe(sub.topic, node.id);
node.brokerConn.unsubscribe(sub.topic, node.id, true);
delete node.dynamicSubs[sub.topic];
}
@@ -1239,16 +1402,12 @@ module.exports = function(RED) {
node.on('close', function(removed, done) {
if (node.brokerConn) {
if(node.isDynamic) {
if (node.brokerConn.options.autoUnsubscribe) {
Object.keys(node.dynamicSubs).forEach(function (topic) {
node.brokerConn.unsubscribe(topic, node.id, removed);
});
node.dynamicSubs = {};
}
Object.keys(node.dynamicSubs).forEach(function (topic) {
node.brokerConn.unsubscribe(topic, node.id, removed);
});
node.dynamicSubs = {};
} else {
if (node.brokerConn.options.autoUnsubscribe) {
node.brokerConn.unsubscribe(node.topic, node.id, removed);
}
node.brokerConn.unsubscribe(node.topic, node.id, removed);
}
node.brokerConn.deregister(node, done, removed);
node.brokerConn = null;

View File

@@ -23,6 +23,8 @@ module.exports = async function(RED) {
const { v4: uuid } = require('uuid');
const crypto = require('crypto');
const URL = require("url").URL
const http = require("http")
const https = require("https")
var mustache = require("mustache");
var querystring = require("querystring");
var cookie = require("cookie");
@@ -65,16 +67,27 @@ in your Node-RED user directory (${RED.settings.userDir}).
function HTTPRequest(n) {
RED.nodes.createNode(this,n);
checkNodeAgentPatch();
var node = this;
var nodeUrl = n.url;
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
var nodeMethod = n.method || "GET";
var paytoqs = false;
var paytobody = false;
var redirectList = [];
var sendErrorsToCatch = n.senderr;
const node = this;
const nodeUrl = n.url;
const isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
const nodeMethod = n.method || "GET";
let paytoqs = false;
let paytobody = false;
let redirectList = [];
const sendErrorsToCatch = n.senderr;
node.headers = n.headers || [];
var nodeHTTPPersistent = n["persist"];
const useKeepAlive = n["persist"];
let agents = null
if (useKeepAlive) {
agents = {
http: new http.Agent({ keepAlive: true }),
https: new https.Agent({ keepAlive: true })
}
node.on('close', function () {
agents.http.destroy()
agents.https.destroy()
})
}
if (n.tls) {
var tlsNode = RED.nodes.getNode(n.tls);
}
@@ -560,12 +573,14 @@ in your Node-RED user directory (${RED.settings.userDir}).
opts.agent = {
http: new HttpProxyAgent(proxyOptions),
https: new HttpsProxyAgent(proxyOptions)
};
}
} else {
node.warn("Bad proxy url: "+ prox);
}
}
if (useKeepAlive && !opts.agent) {
opts.agent = agents
}
if (tlsNode) {
opts.https = {};
tlsNode.addTLSOptions(opts.https);

View File

@@ -33,14 +33,7 @@ module.exports = function(RED) {
parseString(value, options, function (err, result) {
if (err) { done(err); }
else {
// TODO: With xml2js@0.5.0, they return an object with
// a null prototype. This could cause unexpected
// issues. So for now, we have to reconstruct
// the object with a proper prototype.
// Once https://github.com/Leonidas-from-XIV/node-xml2js/pull/674
// is merged, we can revisit and hopefully remove this hack
value = fixObj(result)
RED.util.setMessageProperty(msg,node.property,value);
RED.util.setMessageProperty(msg,node.property,result);
send(msg);
done();
}
@@ -52,18 +45,4 @@ module.exports = function(RED) {
});
}
RED.nodes.registerType("xml",XMLNode);
function fixObj(obj) {
const res = {}
const keys = Object.keys(obj)
keys.forEach(k => {
if (typeof obj[k] === 'object' && obj[k]) {
res[k] = fixObj(obj[k])
} else {
res[k] = obj[k]
}
})
return res
}
}

View File

@@ -629,6 +629,9 @@ module.exports = function(RED) {
joinChar = node.joiner;
if (n.count === "" && msg.hasOwnProperty('parts')) {
targetCount = msg.parts.count || 0;
if (msg.parts.hasOwnProperty('id')) {
partId = msg.parts.id;
}
}
if (node.build === 'object') {
propertyKey = RED.util.getMessageProperty(msg,node.key);

View File

@@ -94,6 +94,7 @@
},
"catch": {
"catch": "catch: all",
"catchGroup": "catch: group",
"catchNodes": "catch: __number__",
"catchUncaught": "catch: uncaught",
"label": {
@@ -109,6 +110,7 @@
},
"status": {
"status": "status: all",
"statusGroup": "status: group",
"statusNodes": "status: __number__",
"label": {
"source": "Report status from",

View File

@@ -103,6 +103,7 @@
},
"scope": {
"all": "tous les noeuds",
"group": "dans le même groupe",
"selected": "noeuds sélectionnés"
}
},
@@ -115,6 +116,7 @@
},
"scope": {
"all": "tous les noeuds",
"group": "dans le même groupe",
"selected": "noeuds sélectionnés"
}
},
@@ -414,6 +416,7 @@
"port": "Port",
"keepalive": "Rester en vie",
"cleansession": "Utiliser une session propre",
"autoUnsubscribe": "Se désabonner automatiquement lors de la déconnexion",
"cleanstart": "Utiliser un démarrage propre",
"use-tls": "Utiliser TLS",
"tls-config": "Configuration TLS",

View File

@@ -103,6 +103,7 @@
},
"scope": {
"all": "全てのノード",
"group": "同一グループ内",
"selected": "選択したノード"
}
},
@@ -115,6 +116,7 @@
},
"scope": {
"all": "全てのノード",
"group": "同一グループ内",
"selected": "選択したノード"
}
},

View File

@@ -44,7 +44,7 @@
"tough-cookie": "4.1.2",
"uuid": "9.0.0",
"ws": "7.5.6",
"xml2js": "0.5.0",
"xml2js": "0.6.0",
"iconv-lite": "0.6.3"
}
}