mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
54 Commits
4282-dirty
...
loadable-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
638d0d2f3f | ||
|
|
eb940d6d57 | ||
|
|
9091935d77 | ||
|
|
34e8d2b051 | ||
|
|
0c2ab13c48 | ||
|
|
9489953a8f | ||
|
|
cef3a01042 | ||
|
|
0c042abcab | ||
|
|
a48c57dd17 | ||
|
|
77b235655c | ||
|
|
8dc0261993 | ||
|
|
65d2ad68d3 | ||
|
|
52fde088e9 | ||
|
|
ab6d537c3e | ||
|
|
3a6078a56a | ||
|
|
b0c3fefcab | ||
|
|
2bc739194e | ||
|
|
afb06e8c9a | ||
|
|
2c1274ff76 | ||
|
|
e18721a03e | ||
|
|
aea32cc279 | ||
|
|
ce0feb2f42 | ||
|
|
d307968880 | ||
|
|
1f98d19f77 | ||
|
|
9a934c941f | ||
|
|
de63e17a4d | ||
|
|
1bad643b30 | ||
|
|
57c44d4b18 | ||
|
|
7d06133787 | ||
|
|
261998201b | ||
|
|
9a899b929e | ||
|
|
5fcace8776 | ||
|
|
a12826e719 | ||
|
|
0dc024c722 | ||
|
|
f6f36c5599 | ||
|
|
18bd318da2 | ||
|
|
e1712073c9 | ||
|
|
2478a7194e | ||
|
|
89b8e88df3 | ||
|
|
a7e80f351a | ||
|
|
c39d3db121 | ||
|
|
e7f9e61f2a | ||
|
|
3047ed1253 | ||
|
|
cf0c7ce583 | ||
|
|
206211f9ef | ||
|
|
8220ff8a35 | ||
|
|
927fc5424b | ||
|
|
64b94c68d3 | ||
|
|
3391d18942 | ||
|
|
1414fed776 | ||
|
|
f884cb015a | ||
|
|
7e6a96db87 | ||
|
|
966bbe2856 | ||
|
|
f7b64b101e |
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16, 18]
|
||||
node-version: [16, 18, 20]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
|
||||
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,4 +1,38 @@
|
||||
#### 3.1.0-beta.4: Beta Release
|
||||
#### 3.1.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
||||
- Default filter to All Catalogues and show nodes for small lists (#4318) @knolleary
|
||||
- Better distinguish between ctrl and meta keys on mac (#4310) @knolleary
|
||||
- Ensure junction appears when filtering quick-add list (#4297) @knolleary
|
||||
- Update message catalogs for JSONata Expression editor (#4287) @kazuhitoyokoi
|
||||
- Add tooltip to relevance sort button in user settings UI (#4288) @kazuhitoyokoi
|
||||
- Capture workspace dirty state when quick-adding junction (#4283) @knolleary
|
||||
- Add docs for $clone function (#4284) @knolleary
|
||||
|
||||
Runtime
|
||||
|
||||
- Dependency updates (#4317) @knolleary
|
||||
- Ensure storage/util.writeFile handles concurrent write attempts (#4316) @knolleary
|
||||
- Migrate http -> https for nodered.org (#4313) @Rotzbua
|
||||
- Add Node 20 to GH Action test matrix (#4305) @Rotzbua
|
||||
- Handle group-scoped nodes inside subflow (#4301) @knolleary
|
||||
- Handle non-url-safe chars in context api (#4298) @knolleary
|
||||
- Fix git pull operation in project feature (#4290) @kazuhitoyokoi
|
||||
- Change linefeed codes in Korean message catalogs (#4286) @kazuhitoyokoi
|
||||
- Fix file permissions of message catalogs (#4285) @kazuhitoyokoi
|
||||
- Update tour (#4278) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- File: Fix handling in file nodes when number is specified as file name (#4267) @kazuhitoyokoi
|
||||
- Function: Adding function timeout to settings file (#4265) (#4309) @knolleary
|
||||
- Function: Fix function setup tab layout (#4299) @knolleary
|
||||
- HTTP Request: Handle 204 in httprequest JSON (#4262) @sammachin
|
||||
- JSON: Fix test cases of JSON node (#4275) @kazuhitoyokoi
|
||||
- MQTT: Remove unnecessary check for clientid if autoUnsub set (#4302) @knolleary
|
||||
|
||||
##### 3.1.0-beta.4: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
@@ -28,7 +62,7 @@
|
||||
- Fix delay node flush issue (#4203) @dceejay
|
||||
- Update status and catch node labels in group mode (#4207) @Steve-Mcl
|
||||
|
||||
#### 3.1.0-beta.3: Beta Release
|
||||
##### 3.1.0-beta.3: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
@@ -63,7 +97,7 @@ Nodes
|
||||
- MQTT: Option to disable MQTT topic unsubscribe on disconnect (#4078) @flying7eleven
|
||||
|
||||
|
||||
#### 3.1.0-beta.2: Beta Release
|
||||
##### 3.1.0-beta.2: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
@@ -113,7 +147,7 @@ Nodes
|
||||
- File Out: Fix extra newline append for multipart file write (#3915) @dceejay
|
||||
- Add validators for complete and link call nodes (#4056) @kazuhitoyokoi
|
||||
|
||||
#### 3.1.0-beta.1: Beta Release
|
||||
##### 3.1.0-beta.1: Beta Release
|
||||
|
||||
Editor
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Node-RED
|
||||
|
||||
http://nodered.org
|
||||
https://nodered.org
|
||||
|
||||
[](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
|
||||
|
||||
Low-code programming for event-driven applications.
|
||||
|
||||

|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
started.
|
||||
|
||||
1. `sudo npm install -g --unsafe-perm node-red`
|
||||
@@ -19,7 +19,7 @@ started.
|
||||
|
||||
## Getting Help
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
More documentation can be found [here](https://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
|
||||
16
package.json
16
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -64,8 +64,8 @@
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^3.0.0",
|
||||
"node-watch": "0.7.3",
|
||||
"node-red-admin": "^3.1.0",
|
||||
"node-watch": "0.7.4",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
"on-headers": "1.0.2",
|
||||
@@ -73,16 +73,16 @@
|
||||
"passport-http-bearer": "1.0.1",
|
||||
"passport-oauth2-client-password": "0.1.2",
|
||||
"raw-body": "2.5.2",
|
||||
"semver": "7.5.0",
|
||||
"semver": "7.5.4",
|
||||
"tar": "6.1.13",
|
||||
"tough-cookie": "4.1.2",
|
||||
"tough-cookie": "4.1.3",
|
||||
"uglify-js": "3.17.4",
|
||||
"uuid": "9.0.0",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.6.0"
|
||||
"xml2js": "0.6.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.1.0"
|
||||
"bcrypt": "5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dompurify": "2.4.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/editor-client": "3.1.0-beta.4",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"@node-red/editor-client": "4.0.0-dev",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.20.2",
|
||||
"clone": "2.1.2",
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
},
|
||||
"$formatNumber": {
|
||||
"args": "number, picture [, options]",
|
||||
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in eine dezimale Darstellung, wie im `picture`-String-Parameter vorgegeben.\n\nDas Verhalten dieser Funktion ist mit der XPath/XQuery-Funktion fn:formatnummer konsistent, wie sie in der XPath F&O 3.1-Spezifikation definiert ist. Der `picture`-String-Parameter definiert, wie die Zahl formatiert ist und hat die gleiche Syntax wie fn:format-number.\n\nDer optionale dritte Parameter `options` wird verwendet, um die standardmäßigen länderspezifischen Formatierungszeichen, wie z.B. das Dezimaltrennzeichen, zu überschreiben. Wenn dieser Parameter vorgegeben wird, muss es sich um ein Objekt handeln, das Name/Wert-Paare enthält, die im Abschnitt mit dem Dezimalformat der XPath F&O 3.1-Spezifikation vorgegeben sind."
|
||||
"desc": "Wandelt `number` in eine Zeichenfolge um und formatiert sie in eine dezimale Darstellung, wie im `picture`-String-Parameter vorgegeben.\n\nDas Verhalten dieser Funktion ist mit der XPath/XQuery-Funktion `fn:formatnummer` konsistent, wie sie in der XPath F&O 3.1-Spezifikation definiert ist. Der `picture`-String-Parameter definiert, wie die Zahl formatiert ist und hat die gleiche Syntax wie `fn:format-number`.\n\nDer optionale dritte Parameter `options` wird verwendet, um die standardmäßigen länderspezifischen Formatierungszeichen, wie z.B. das Dezimaltrennzeichen, zu überschreiben. Wenn dieser Parameter vorgegeben wird, muss es sich um ein Objekt handeln, das Name/Wert-Paare enthält, die im Abschnitt mit dem Dezimalformat der XPath F&O 3.1-Spezifikation vorgegeben sind."
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
|
||||
@@ -627,6 +627,7 @@
|
||||
"tab-nodes": "Nodes",
|
||||
"tab-install": "Install",
|
||||
"sort": "sort:",
|
||||
"sortRelevance": "relevance",
|
||||
"sortAZ": "a-z",
|
||||
"sortRecent": "recent",
|
||||
"more": "+ __count__ more",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
},
|
||||
"$now": {
|
||||
"args": "$[picture [, timezone]]",
|
||||
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional picture and timezone parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
||||
"desc": "Generates a timestamp in ISO 8601 compatible format and returns it as a string. If the optional `picture` and `timezone` parameters are supplied, then the current timestamp is formatted as described by the `$fromMillis()` function"
|
||||
},
|
||||
"$base64encode": {
|
||||
"args": "string",
|
||||
@@ -137,7 +137,7 @@
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values left and right. If the value of left should be placed after the value of right in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
||||
"desc": "Returns an array containing all the values in the `array` parameter, but sorted into order.\n\nIf a comparator `function` is supplied, then it must be a function that takes two parameters:\n\n`function(left, right)`\n\nThis function gets invoked by the sorting algorithm to compare two values `left` and `right`. If the value of `left` should be placed after the value of `right` in the desired sort order, then the function must return Boolean `true` to indicate a swap. Otherwise it must return `false`."
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
@@ -201,11 +201,11 @@
|
||||
},
|
||||
"$fromMillis": {
|
||||
"args": "number, [, picture [, timezone]]",
|
||||
"desc": "Convert the `number` representing milliseconds since the Unix Epoch (1 January, 1970 UTC) to a formatted string representation of the timestamp as specified by the picture string.\n\nIf the optional `picture` parameter is omitted, then the timestamp is formatted in the ISO 8601 format.\n\nIf the optional `picture` string is supplied, then the timestamp is formatted occording to the representation specified in that string. The behaviour of this function is consistent with the two-argument version of the XPath/XQuery function `format-dateTime` as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the timestamp is formatted and has the same syntax as `format-dateTime`.\n\nIf the optional `timezone` string is supplied, then the formatted timestamp will be in that timezone. The `timezone` string should be in the format '±HHMM', where ± is either the plus or minus sign and HHMM is the offset in hours and minutes from UTC. Positive offset for timezones east of UTC, negative offset for timezones west of UTC."
|
||||
"desc": "Convert the `number` representing milliseconds since the Unix Epoch (1 January, 1970 UTC) to a formatted string representation of the timestamp as specified by the picture string.\n\nIf the optional `picture` parameter is omitted, then the timestamp is formatted in the ISO 8601 format.\n\nIf the optional `picture` string is supplied, then the timestamp is formatted according to the representation specified in that string. The behaviour of this function is consistent with the two-argument version of the XPath/XQuery function `format-dateTime` as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the timestamp is formatted and has the same syntax as `format-dateTime`.\n\nIf the optional `timezone` string is supplied, then the formatted timestamp will be in that timezone. The `timezone` string should be in the format '±HHMM', where ± is either the plus or minus sign and HHMM is the offset in hours and minutes from UTC. Positive offset for timezones east of UTC, negative offset for timezones west of UTC."
|
||||
},
|
||||
"$formatNumber": {
|
||||
"args": "number, picture [, options]",
|
||||
"desc": "Casts the `number` to a string and formats it to a decimal representation as specified by the `picture` string.\n\n The behaviour of this function is consistent with the XPath/XQuery function fn:format-number as defined in the XPath F&O 3.1 specification. The picture string parameter defines how the number is formatted and has the same syntax as fn:format-number.\n\nThe optional third argument `options` is used to override the default locale specific formatting characters such as the decimal separator. If supplied, this argument must be an object containing name/value pairs specified in the decimal format section of the XPath F&O 3.1 specification."
|
||||
"desc": "Casts the `number` to a string and formats it to a decimal representation as specified by the `picture` string.\n\n The behaviour of this function is consistent with the XPath/XQuery function `fn:format-number` as defined in the XPath F&O 3.1 specification. The `picture` string parameter defines how the number is formatted and has the same syntax as `fn:format-number`.\n\nThe optional third argument `options` is used to override the default locale specific formatting characters such as the decimal separator. If supplied, this argument must be an object containing name/value pairs specified in the decimal format section of the XPath F&O 3.1 specification."
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
@@ -237,7 +237,7 @@
|
||||
},
|
||||
"$assert": {
|
||||
"args": "arg, str",
|
||||
"desc": "If `arg` is true the function returns undefined. If `arg` is false an exception is thrown with `str` as the message of the exception."
|
||||
"desc": "If `arg` is `true` the function returns `undefined`. If `arg` is `false` an exception is thrown with `str` as the message of the exception."
|
||||
},
|
||||
"$single": {
|
||||
"args": "array, function",
|
||||
@@ -270,5 +270,9 @@
|
||||
"$moment": {
|
||||
"args": "[str]",
|
||||
"desc": "Gets a date object using the Moment library."
|
||||
},
|
||||
"$clone": {
|
||||
"args": "value",
|
||||
"desc": "Safely clone an object."
|
||||
}
|
||||
}
|
||||
|
||||
0
packages/node_modules/@node-red/editor-client/locales/fr/infotips.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/fr/infotips.json
vendored
Executable file → Normal file
4
packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json
vendored
Executable file → Normal file
4
packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json
vendored
Executable file → Normal file
@@ -137,7 +137,7 @@
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais triées dans l'ordre.\n\nSi un comparateur `function` est fourni, alors il doit s'agir d'une fonction qui prend deux paramètres :\n\n`function(left , droite)`\n\nCette fonction est invoquée par l'algorithme de tri pour comparer deux valeurs à gauche et à droite. Si la valeur de left doit être placée après la valeur de right dans l'ordre de tri souhaité, la fonction doit renvoyer un booléen `true` pour indiquer un échange. Sinon, il doit renvoyer `false`."
|
||||
"desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais triées dans l'ordre.\n\nSi un comparateur `function` est fourni, alors il doit s'agir d'une fonction qui prend deux paramètres :\n\n`function(left , droite)`\n\nCette fonction est invoquée par l'algorithme de tri pour comparer deux valeurs à gauche et à droite. Si la valeur de `left` doit être placée après la valeur de `right` dans l'ordre de tri souhaité, la fonction doit renvoyer un booléen `true` pour indiquer un échange. Sinon, il doit renvoyer `false`."
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
@@ -205,7 +205,7 @@
|
||||
},
|
||||
"$formatNumber": {
|
||||
"args": "number, picture [, options]",
|
||||
"desc": "Convertit le `number` en une chaîne et le formate en une représentation décimale comme spécifié par la chaîne `picture`.\n\n Le comportement de cette fonction est cohérent avec la fonction XPath/XQuery fn:format-number telle que définie dans le Spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que fn:format-number.\n\nLe troisième argument facultatif `options` est utilisé pour remplacer les caractères de formatage spécifiques aux paramètres régionaux par défaut, tels que le séparateur décimal. S'il est fourni, cet argument doit être un objet contenant des paires nom/valeur spécifiées dans la section de format décimal de la spécification XPath F&O 3.1."
|
||||
"desc": "Convertit le `number` en une chaîne et le formate en une représentation décimale comme spécifié par la chaîne `picture`.\n\n Le comportement de cette fonction est cohérent avec la fonction XPath/XQuery `fn:format-number` telle que définie dans le Spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-number`.\n\nLe troisième argument facultatif `options` est utilisé pour remplacer les caractères de formatage spécifiques aux paramètres régionaux par défaut, tels que le séparateur décimal. S'il est fourni, cet argument doit être un objet contenant des paires nom/valeur spécifiées dans la section de format décimal de la spécification XPath F&O 3.1."
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
|
||||
@@ -627,6 +627,7 @@
|
||||
"tab-nodes": "現在のノード",
|
||||
"tab-install": "ノードを追加",
|
||||
"sort": "並べ替え:",
|
||||
"sortRelevance": "関連順",
|
||||
"sortAZ": "辞書順",
|
||||
"sortRecent": "日付順",
|
||||
"more": "+ さらに __count__ 個",
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
},
|
||||
"$now": {
|
||||
"args": "$[picture [, timezone]]",
|
||||
"desc": "ISO 8601互換形式の時刻を生成し、文字列として返します。pictureおよびtimezoneパラメータが指定されている場合、現在時刻を`$fromMillis()`関数の説明に従ってフォーマットします。"
|
||||
"desc": "ISO 8601互換形式の時刻を生成し、文字列として返します。`picture` および `timezone` パラメータが指定されている場合、現在時刻を `$fromMillis()` 関数の説明に従ってフォーマットします。"
|
||||
},
|
||||
"$base64encode": {
|
||||
"args": "string",
|
||||
@@ -117,11 +117,11 @@
|
||||
},
|
||||
"$boolean": {
|
||||
"args": "arg",
|
||||
"desc": "以下のルールを用いて、ブーリアン型へ型変換します。:\n\n - `Boolean` : 変換しない\n - `string`: 空 : `false`\n - `string`: 空でない : `true`\n - `number`: `0` : `false`\n - `number`: 0でない : `true`\n - `null` : `false`\n - `array`: 空 : `false`\n - `array`: `true` に型変換された要素を持つ: `true`\n - `array`: 全ての要素が `false` に型変換: `false`\n - `object`: 空 : `false`\n - `object`: 空でない : `true`\n - `function` : `false`"
|
||||
"desc": "以下のルールを用いて、真偽型へ型変換します。:\n\n - `Boolean` : 変換しない\n - `string`: 空 : `false`\n - `string`: 空でない : `true`\n - `number`: `0` : `false`\n - `number`: 0でない : `true`\n - `null` : `false`\n - `array`: 空 : `false`\n - `array`: `true` に型変換された要素を持つ: `true`\n - `array`: 全ての要素が `false` に型変換: `false`\n - `object`: 空 : `false`\n - `object`: 空でない : `true`\n - `function` : `false`"
|
||||
},
|
||||
"$not": {
|
||||
"args": "arg",
|
||||
"desc": "引数の否定をブーリアン型で返します。 `arg` は最初にブーリアン型に型変換されます。"
|
||||
"desc": "引数の否定を真偽型で返します。 `arg` は最初に真偽型に型変換されます。"
|
||||
},
|
||||
"$exists": {
|
||||
"args": "arg",
|
||||
@@ -137,7 +137,7 @@
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "配列 `array` 内の値を並び変えた配列を返します。\n\n比較関数 `function` を用いる場合、比較関数は以下のとおり2つの引数を持つ必要があります。\n\n`function(left, right)`\n\n比較関数は、leftとrightの2つの値を比較するために、値を並び替える処理で呼び出されます。もし、求められる並び順にてleftの値をrightの値より後ろに置きたい場合は、比較関数は置き換えを表すブーリアン型の `true` を返す必要があります。一方、置き換えが不要の場合は `false` を返す必要があります。"
|
||||
"desc": "配列 `array` 内の値を並び変えた配列を返します。\n\n比較関数 `function` を用いる場合、比較関数は以下のとおり2つの引数を持つ必要があります。\n\n`function(left, right)`\n\n比較関数は、`left` と `right` の2つの値を比較するために、値を並び替える処理で呼び出されます。もし、求められる並び順にて `left` の値を `right` の値より後ろに置きたい場合は、比較関数は置き換えを表す真偽型の `true` を返す必要があります。一方、置き換えが不要の場合は `false` を返す必要があります。"
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
@@ -205,7 +205,7 @@
|
||||
},
|
||||
"$formatNumber": {
|
||||
"args": "number, picture [, options]",
|
||||
"desc": "`number` を文字列へ変換し、文字列 `picture` に指定した数値表現になるよう書式を変更します。\n\nこの関数の動作は、XPath F&O 3.1の仕様に定義されているXPath/XQuery関数のfn:format-numberの動作と同じです。引数の文字列 picture は、fn:format-numberと同じ構文で数値の書式を定義します。\n\n任意の第三引数 `options` は、小数点記号の様な既定のロケール固有の書式設定文字を上書きするために使用します。この引数を指定する場合、XPath F&O 3.1の仕様の数値形式の項に記述されているname/valueペアを含むオブジェクトでなければなりません。"
|
||||
"desc": "`number` を文字列へ変換し、文字列 `picture` に指定した数値表現になるよう書式を変更します。\n\nこの関数の動作は、XPath F&O 3.1の仕様に定義されているXPath/XQuery関数の `fn:format-number` の動作と同じです。引数の文字列 `picture` は、 `fn:format-number` と同じ構文で数値の書式を定義します。\n\n任意の第三引数 `options` は、小数点記号の様な既定のロケール固有の書式設定文字を上書きするために使用します。この引数を指定する場合、XPath F&O 3.1の仕様の数値形式の項に記述されているname/valueペアを含むオブジェクトでなければなりません。"
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
@@ -237,7 +237,7 @@
|
||||
},
|
||||
"$assert": {
|
||||
"args": "arg, str",
|
||||
"desc": "`arg`が真の場合、undefinedを返します。偽の場合、`str`をメッセージとする例外を送出します。"
|
||||
"desc": "`arg`が真の場合、`undefined`を返します。偽の場合、`str`をメッセージとする例外を送出します。"
|
||||
},
|
||||
"$single": {
|
||||
"args": "array, function",
|
||||
@@ -270,5 +270,9 @@
|
||||
"$moment": {
|
||||
"args": "[str]",
|
||||
"desc": "Momentライブラリを使用して日付オブジェクトを取得します。"
|
||||
},
|
||||
"$clone": {
|
||||
"args": "value",
|
||||
"desc": "オブジェクトを安全に複製します。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다. \n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다. \n\n `function(left,right)` \n\n 비교함수는 left와 right의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 right값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 ``true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다."
|
||||
"desc": "배열 `array`의 모든 값을 순서대로 정렬하여 반환합니다.\n\n 비교함수 `function`을 이용하는 경우, 비교함수는 아래와 같은 두개의 인수를 가져야 합니다.\n\n `function(left,right)`\n\n 비교함수는 `left`와 `right`의 두개의 값을 비교하기에, 값을 정렬하는 처리에서 호출됩니다. 만약 요구되는 정렬에서 left값을 `right`값보다 뒤로 두고싶은 경우에는, 비교함수는 치환을 나타내는 Boolean형의 `true`를, 그렇지 않은 경우에는 `false`를 반환해야 합니다."
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
@@ -205,7 +205,7 @@
|
||||
},
|
||||
"$formatNumber": {
|
||||
"args": "number, picture [, options]",
|
||||
"desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다. \n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 fn:format-number의 동작과 같습니다. 인수의 문자열 picture은 fn:format-number 과 같은 구문으로 수치의 서식을 정의합니다. \n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다."
|
||||
"desc": "`number`를 문자열로 변환하고 `picture` 문자열에 지정된 표현으로 서식을 변경합니다.\n\n 이 함수의 동작은 XPath F&O 3.1사양에 정의된 XPath/XQuery함수의 `fn:format-number`의 동작과 같습니다. 인수의 문자열 `picture`은 `fn:format-number` 과 같은 구문으로 수치의 서식을 정의합니다.\n\n 임의의 제3 인수 `option`은 소수점기호와 같은 기본 로케일 고유의 서식설정문자를 덮어쓰는데에 사용됩니다. 이 인수를 지정할 경우, XPath F&O 3.1사양의 수치형식에 기술되어있는 name/value 쌍을 포함하는 오브젝트여야 합니다."
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
|
||||
0
packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json
vendored
Executable file → Normal file
2
packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json
vendored
Executable file → Normal file
2
packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json
vendored
Executable file → Normal file
@@ -205,7 +205,7 @@
|
||||
},
|
||||
"$formatNumber": {
|
||||
"args": "number, picture [, options]",
|
||||
"desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação decimal conforme especificado pela cadeia de caracteres `picture`.\n\n O comportamento desta função é consistente com a função XPath/XQuery fn: format-number conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de fn: format-number.\n\nO terceiro argumento opcional `options` é usado para substituir os caracteres de formatação específicos da localidade padrão, como o separador decimal. Se fornecido, este argumento deve ser um objeto contendo pares de nome/valor especificados na seção de formato decimal da especificação XPath F&O 3.1."
|
||||
"desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação decimal conforme especificado pela cadeia de caracteres `picture`.\n\n O comportamento desta função é consistente com a função XPath/XQuery `fn:format-number` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn:format-number`.\n\nO terceiro argumento opcional `options` é usado para substituir os caracteres de formatação específicos da localidade padrão, como o separador decimal. Se fornecido, este argumento deve ser um objeto contendo pares de nome/valor especificados na seção de formato decimal da especificação XPath F&O 3.1."
|
||||
},
|
||||
"$formatBase": {
|
||||
"args": "number [, radix]",
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
},
|
||||
"$assert": {
|
||||
"args": "arg, str",
|
||||
"desc": "Если значение `arg` равно true, функция возвращает значение undefined. Если значение `arg` равно false, генерируется исключение с `str` в качестве сообщения об исключении."
|
||||
"desc": "Если значение `arg` равно `true`, функция возвращает значение undefined. Если значение `arg` равно `false`, генерируется исключение с `str` в качестве сообщения об исключении."
|
||||
},
|
||||
"$single": {
|
||||
"args": "array, function",
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较left和right两个值而被排序算法调用的。如果用户希望left的值被置于right的值之后,那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
|
||||
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)`\n\n该比较函数是为了比较`left`和`right`两个值而被排序算法调用的。如果用户希望`left`的值被置于`right`的值之后,那么该函数必须输出布尔值 `true` 来表示位置交换。而在不需要位置交换时函数必须输出 `false` 。"
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
@@ -237,7 +237,7 @@
|
||||
},
|
||||
"$assert": {
|
||||
"args": "arg, str",
|
||||
"desc": "如果 `arg` 为真,则该函数返回。 如果arg为假,则抛出带有str的异常作为异常消息。"
|
||||
"desc": "如果 `arg` 为真,则该函数返回。 如果`arg`为假,则抛出带有`str`的异常作为异常消息。"
|
||||
},
|
||||
"$single": {
|
||||
"args": "array, function",
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
},
|
||||
"$sort": {
|
||||
"args": "array [, function]",
|
||||
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較left和right兩個值而被排序演算法調用的。如果使用者希望left的值被置於right的值之後,那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
|
||||
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較`left`和`right`兩個值而被排序演算法調用的。如果使用者希望left的值被置於`right`的值之後,那麼該函數必須輸出布林值`true`來表示位置交換。而在不需要位置交換時函數必須輸出`false`。"
|
||||
},
|
||||
"$reverse": {
|
||||
"args": "array",
|
||||
@@ -237,7 +237,7 @@
|
||||
},
|
||||
"$assert": {
|
||||
"args": "arg, str",
|
||||
"desc": "如果`arg`為真,則該函數返回。 如果arg為假,則拋出帶有str的異常作為異常消息。"
|
||||
"desc": "如果`arg`為真,則該函數返回。 如果`arg`為假,則拋出帶有`str`的異常作為異常消息。"
|
||||
},
|
||||
"$single": {
|
||||
"args": "array, function",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -731,7 +731,7 @@ var RED = (function() {
|
||||
}
|
||||
menuOptions.push({id:"menu-item-help",
|
||||
label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
|
||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||
href: RED.settings.theme("menu.menu-item-help.url","https://nodered.org/docs")
|
||||
});
|
||||
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });
|
||||
|
||||
|
||||
@@ -494,6 +494,7 @@ RED.palette.editor = (function() {
|
||||
// if there is only 1 catalog, hide the select
|
||||
if (catalogEntries.length > 1) {
|
||||
catalogSelection.prepend(`<option value="all">${RED._('palette.editor.allCatalogs')}</option>`)
|
||||
catalogSelection.val('all')
|
||||
catalogSelection.removeAttr('disabled') // permit the user to select a catalog
|
||||
}
|
||||
// refresh the searchInput counter and trigger a change
|
||||
@@ -523,7 +524,7 @@ RED.palette.editor = (function() {
|
||||
function refreshFilteredItems() {
|
||||
packageList.editableList('empty');
|
||||
var currentFilter = searchInput.searchBox('value').trim();
|
||||
if (currentFilter === ""){
|
||||
if (currentFilter === "" && loadedList.length > 20){
|
||||
packageList.editableList('addItem',{count:loadedList.length})
|
||||
return;
|
||||
}
|
||||
@@ -893,7 +894,7 @@ RED.palette.editor = (function() {
|
||||
delay: 300,
|
||||
change: function() {
|
||||
var searchTerm = $(this).val().trim().toLowerCase();
|
||||
if (searchTerm.length > 0) {
|
||||
if (searchTerm.length > 0 || loadedList.length < 20) {
|
||||
filteredList = loadedList.filter(function(m) {
|
||||
return (m.index.indexOf(searchTerm) > -1);
|
||||
}).map(function(f) { return {info:f}});
|
||||
@@ -917,6 +918,7 @@ RED.palette.editor = (function() {
|
||||
const sortRelevance = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle selected"><i class="fa fa-sort-amount-desc"></i></a>').appendTo(sortGroup);
|
||||
const sortAZ = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle"><i class="fa fa-sort-alpha-asc"></i></a>').appendTo(sortGroup);
|
||||
const sortRecent = $('<a href="#" class="red-ui-palette-editor-install-sort-option red-ui-sidebar-header-button-toggle"><i class="fa fa-calendar"></i></a>').appendTo(sortGroup);
|
||||
RED.popover.tooltip(sortRelevance,RED._("palette.editor.sortRelevance"));
|
||||
RED.popover.tooltip(sortAZ,RED._("palette.editor.sortAZ"));
|
||||
RED.popover.tooltip(sortRecent,RED._("palette.editor.sortRecent"));
|
||||
|
||||
|
||||
@@ -218,11 +218,11 @@ RED.sidebar.context = (function() {
|
||||
var obj = $(propRow.children()[0]);
|
||||
obj.text(k);
|
||||
var tools = $('<span class="button-group"></span>');
|
||||
|
||||
const urlSafeK = encodeURIComponent(k)
|
||||
var refreshItem = $('<button class="red-ui-button red-ui-button-small"><i class="fa fa-refresh"></i></button>').appendTo(tools).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$.getJSON(baseUrl+"/"+k+"?store="+v.store, function(data) {
|
||||
$.getJSON(baseUrl+"/"+urlSafeK+"?store="+v.store, function(data) {
|
||||
if (data.msg !== payload || data.format !== format) {
|
||||
payload = data.msg;
|
||||
format = data.format;
|
||||
@@ -258,11 +258,12 @@ RED.sidebar.context = (function() {
|
||||
$('<button class="red-ui-button primary" data-i18n="common.label.delete"></button>').appendTo(bg).on("click", function(e) {
|
||||
e.preventDefault();
|
||||
popover.close();
|
||||
const urlSafeK = encodeURIComponent(k)
|
||||
$.ajax({
|
||||
url: baseUrl+"/"+k+"?store="+v.store,
|
||||
url: baseUrl+"/"+urlSafeK+"?store="+v.store,
|
||||
type: "DELETE"
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
$.getJSON(baseUrl+"/"+k+"?store="+v.store, function(data) {
|
||||
$.getJSON(baseUrl+"/"+urlSafeK+"?store="+v.store, function(data) {
|
||||
if (data.format === 'undefined') {
|
||||
propRow.remove();
|
||||
if (container.children().length === 0) {
|
||||
|
||||
@@ -362,6 +362,7 @@ RED.typeSearch = (function() {
|
||||
items.push({type:t,def: def, label:getTypeLabel(t,def)});
|
||||
}
|
||||
});
|
||||
items.push({ type: 'junction', def: { inputs:1, outputs: 1, label: 'junction', type: 'junction'}, label: 'junction' })
|
||||
items.sort(sortTypeLabels);
|
||||
|
||||
var commonCount = 0;
|
||||
|
||||
@@ -1118,6 +1118,22 @@ RED.utils = (function() {
|
||||
if (def.category === 'subflows') {
|
||||
return RED.settings.apiRootUrl+"icons/node-red/subflow.svg";
|
||||
}
|
||||
|
||||
if (node?.type) {
|
||||
// this regex might be too restrictive/specific but got to start somewhere
|
||||
const re = new RegExp("^\/"+node.type+"\/icon\/.*\.svg$","i");
|
||||
if (typeof def.icon === "function") {
|
||||
try {
|
||||
const di = def.icon.call(node);
|
||||
if (re.test(di)) { return RED.settings.authTokensSuffix.replace(/-/,'/') + di; }
|
||||
}
|
||||
catch(e) { console.log("Bad Icon",e) }
|
||||
}
|
||||
else {
|
||||
if (re.test(def.icon)) { return RED.settings.authTokensSuffix.replace(/-/,'/') + def.icon; }
|
||||
}
|
||||
}
|
||||
|
||||
return RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg";
|
||||
}
|
||||
|
||||
|
||||
@@ -302,11 +302,21 @@ RED.view = (function() {
|
||||
return api
|
||||
})()
|
||||
|
||||
const isMac = RED.utils.getBrowserInfo().os === 'mac'
|
||||
// 'Control' is the main modifier key for mouse actions. On Windows,
|
||||
// that is the standard Ctrl key. On Mac that is the Cmd key.
|
||||
function isControlPressed (event) {
|
||||
return (isMac && event.metaKey) || (!isMac && event.ctrlKey)
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
chart = $("#red-ui-workspace-chart");
|
||||
chart.on('contextmenu', function(evt) {
|
||||
if (RED.view.DEBUG) {
|
||||
console.warn("contextmenu", { mouse_mode, event: d3.event });
|
||||
}
|
||||
mouse_mode = RED.state.DEFAULT
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
RED.contextMenu.show({
|
||||
@@ -1190,7 +1200,7 @@ RED.view = (function() {
|
||||
lasso = null;
|
||||
}
|
||||
if (d3.event.touches || d3.event.button === 0) {
|
||||
if ((mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) && (d3.event.metaKey || d3.event.ctrlKey) && !(d3.event.altKey || d3.event.shiftKey)) {
|
||||
if ((mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) {
|
||||
// Trigger quick add dialog
|
||||
d3.event.stopPropagation();
|
||||
clearSelection();
|
||||
@@ -1200,7 +1210,7 @@ RED.view = (function() {
|
||||
clickedGroup = clickedGroup || RED.nodes.group(drag_lines[0].node.g)
|
||||
}
|
||||
showQuickAddDialog({ position: point, group: clickedGroup });
|
||||
} else if (mouse_mode === 0 && !(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
} else if (mouse_mode === 0 && !isControlPressed(d3.event)) {
|
||||
// CTRL not being held
|
||||
if (!d3.event.altKey) {
|
||||
// ALT not held (shift is allowed) Trigger lasso
|
||||
@@ -3540,7 +3550,7 @@ RED.view = (function() {
|
||||
d3.event.preventDefault()
|
||||
document.getSelection().removeAllRanges()
|
||||
if (d.type != "subflow") {
|
||||
if (/^subflow:/.test(d.type) && (d3.event.ctrlKey || d3.event.metaKey)) {
|
||||
if (/^subflow:/.test(d.type) && isControlPressed(d3.event)) {
|
||||
RED.workspaces.show(d.type.substring(8));
|
||||
} else {
|
||||
RED.editor.edit(d);
|
||||
@@ -3704,12 +3714,12 @@ RED.view = (function() {
|
||||
d.type !== 'junction'
|
||||
lastClickNode = mousedown_node;
|
||||
|
||||
if (d.selected && (d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
if (d.selected && isControlPressed(d3.event)) {
|
||||
mousedown_node.selected = false;
|
||||
movingSet.remove(mousedown_node);
|
||||
} else {
|
||||
if (d3.event.shiftKey) {
|
||||
if (!(d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
if (!isControlPressed(d3.event)) {
|
||||
clearSelection();
|
||||
}
|
||||
var clickPosition = (d3.event.offsetX/scaleFactor - mousedown_node.x)
|
||||
@@ -3878,10 +3888,10 @@ RED.view = (function() {
|
||||
}
|
||||
mousedown_link = d;
|
||||
|
||||
if (!(d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
if (!isControlPressed(d3.event)) {
|
||||
clearSelection();
|
||||
}
|
||||
if (d3.event.metaKey || d3.event.ctrlKey) {
|
||||
if (isControlPressed(d3.event)) {
|
||||
if (!selectedLinks.has(mousedown_link)) {
|
||||
selectedLinks.add(mousedown_link);
|
||||
} else {
|
||||
@@ -3896,7 +3906,7 @@ RED.view = (function() {
|
||||
redraw();
|
||||
focusView();
|
||||
d3.event.stopPropagation();
|
||||
if (!mousedown_link.link && movingSet.length() === 0 && (d3.event.touches || d3.event.button === 0) && selectedLinks.length() === 1 && selectedLinks.has(mousedown_link) && (d3.event.metaKey || d3.event.ctrlKey)) {
|
||||
if (!mousedown_link.link && movingSet.length() === 0 && (d3.event.touches || d3.event.button === 0) && selectedLinks.length() === 1 && selectedLinks.has(mousedown_link) && isControlPressed(d3.event)) {
|
||||
d3.select(this).classed("red-ui-flow-link-splice",true);
|
||||
var point = d3.mouse(this);
|
||||
var clickedGroup = getGroupAt(point[0],point[1]);
|
||||
@@ -3977,7 +3987,7 @@ RED.view = (function() {
|
||||
);
|
||||
lastClickNode = g;
|
||||
|
||||
if (g.selected && (d3.event.ctrlKey||d3.event.metaKey)) {
|
||||
if (g.selected && isControlPressed(d3.event)) {
|
||||
selectedGroups.remove(g);
|
||||
d3.event.stopPropagation();
|
||||
} else {
|
||||
|
||||
@@ -77,15 +77,16 @@
|
||||
<div id="func-tabs-content" style="min-height: calc(100% - 95px);">
|
||||
|
||||
<div id="func-tab-config" style="display:none">
|
||||
<div class="form-row">
|
||||
<div>
|
||||
<div class="form-row" style="display: inline-block; margin-right: 50px;">
|
||||
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label>
|
||||
<input id="node-input-outputs" style="width: 60px;" value="1">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-row" style="display: inline-block;">
|
||||
<label for="node-input-timeout"><i class="fa fa-clock-o"></i> <span data-i18n="function.label.timeout"></span></label>
|
||||
<input id="node-input-timeout" style="width: 60px;" data-i18n="[placeholder]join.seconds">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row node-input-libs-row hide" style="margin-bottom: 0px;">
|
||||
<label><i class="fa fa-cubes"></i> <span data-i18n="function.label.modules"></span></label>
|
||||
@@ -365,7 +366,7 @@
|
||||
name: {value:"_DEFAULT_"},
|
||||
func: {value:"\nreturn msg;"},
|
||||
outputs: {value:1},
|
||||
timeout:{value:0},
|
||||
timeout:{value:RED.settings.functionTimeout || 0},
|
||||
noerr: {value:0,required:true,
|
||||
validate: function(v, opt) {
|
||||
if (!v) {
|
||||
|
||||
@@ -521,7 +521,8 @@ module.exports = function(RED) {
|
||||
RED.nodes.registerType("function",FunctionNode, {
|
||||
dynamicModuleList: "libs",
|
||||
settings: {
|
||||
functionExternalModules: { value: true, exportable: true }
|
||||
functionExternalModules: { value: true, exportable: true },
|
||||
functionTimeout: { value:0, exportable: true }
|
||||
}
|
||||
});
|
||||
RED.library.register("functions");
|
||||
|
||||
@@ -492,12 +492,12 @@
|
||||
let ok = true;
|
||||
if ($("#node-config-input-clientid").length) {
|
||||
// Currently editing the node
|
||||
let needClientId = !$("#node-config-input-cleansession").is(":checked") || !$("#node-config-input-autoUnsubscribe").is(":checked")
|
||||
let needClientId = !$("#node-config-input-cleansession").is(":checked")
|
||||
if (needClientId) {
|
||||
ok = (v||"").length > 0;
|
||||
}
|
||||
} else {
|
||||
let needClientId = !(this.cleansession===undefined || this.cleansession) || this.autoUnsubscribe;
|
||||
let needClientId = !(this.cleansession===undefined || this.cleansession)
|
||||
if (needClientId) {
|
||||
ok = (v||"").length > 0;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ module.exports = function(RED) {
|
||||
"text/css":"string",
|
||||
"text/html":"string",
|
||||
"text/plain":"string",
|
||||
"text/html":"string",
|
||||
"application/json":"json",
|
||||
"application/octet-stream":"buffer",
|
||||
"application/pdf":"buffer",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<p>Wenn ein promise-Objekt aus dem Start-Code zurückgegeben wird,
|
||||
beginnt danach die reguläre Verarbeitung der Eingangsnachrichten.</p>
|
||||
<h3>Details</h3>
|
||||
<p>Siehe <a target="_blank" href="http://nodered.org/docs/writing-functions.html">Onlinedokumentation</a>
|
||||
<p>Siehe <a target="_blank" href="https://nodered.org/docs/writing-functions.html">Onlinedokumentation</a>
|
||||
für weitere Informationen zum Schreiben von Funktionen.</p>
|
||||
<h4><b>Nachrichten senden</b></h4>
|
||||
<p>Die Funktion kann die Nachrichten zurückgeben, die sie an die nächsten Nodes im Flow weitergeben möchte,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<p>If the On Start code returns a Promise object, the node will not start handling messages
|
||||
until the promise is resolved.</p>
|
||||
<h3>Details</h3>
|
||||
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
|
||||
<p>See the <a target="_blank" href="https://nodered.org/docs/writing-functions.html">online documentation</a>
|
||||
for more information on writing functions.</p>
|
||||
<h4>Sending messages</h4>
|
||||
<p>The function can either return the messages it wants to pass on to the next nodes
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<p>Si le code 'Au démarrage' renvoie un objet Promise (promesse), le noeud ne commencera pas à gérer les messages
|
||||
jusqu'à ce que la promesse soit résolue.</p>
|
||||
<h3>Détails</h3>
|
||||
<p>Voir la <a target="_blank" href="http://nodered.org/docs/writing-functions.html">documentation en ligne</a>
|
||||
<p>Voir la <a target="_blank" href="https://nodered.org/docs/writing-functions.html">documentation en ligne</a>
|
||||
pour plus d'informations sur les fonctions d'écriture.</p>
|
||||
<h4>Envoi de messages</h4>
|
||||
<p>La fonction peut envoyer les messages qu'elle souhaite transmettre aux noeuds suivants
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<p><b>初期化処理</b>タブにはノードの開始時に実行されるコードを、<b>終了処理</b>タブにはノードの終了時に実行されるコードを指定します。</p>
|
||||
<p>初期化処理タブの返却値としてPromiseオブジェクトを返却すると、入力メッセージの処理を開始する前にその完了を待ちます。</p>
|
||||
<h3>詳細</h3>
|
||||
<p>コードの書き方の詳細については、<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
|
||||
<p>コードの書き方の詳細については、<a target="_blank" href="https://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
|
||||
<h4>メッセージの送信</h4>
|
||||
<p>フロー内の次ノードにメッセージを渡すためには、メッセージを返却するか<code>node.send(messages)</code>を呼び出します。</p>
|
||||
<p>返却/sendの対象は次のとおりです:</p>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<p><code>msg</code>오브젝트는<code>msg.payload</code>프로퍼티에 메시지 본체를 유지하는 것이 관례입니다.</p>
|
||||
<p>보통 코드는 메시지 오브젝트(혹은 여러 메시지 객체)를 반환합니다.후속 플로우의 실행을 정지하고 싶은 경우에는, 오브젝트를 반환하지 않아도 상관없습니다.</p>
|
||||
<h3>상세</h3>
|
||||
<p>코드 쓰는 방식에 대한 자세한 내용은, <a target="_blank" href="http://nodered.org/docs/writing-functions.html">공식 홈페이지</a>를 참조해 주세요.</p>
|
||||
<p>코드 쓰는 방식에 대한 자세한 내용은, <a target="_blank" href="https://nodered.org/docs/writing-functions.html">공식 홈페이지</a>를 참조해 주세요.</p>
|
||||
<h4>메세지 송신</h4>
|
||||
<p>플로우 내의 다음 노드에 메세지를 전달하기 위해서는, 메세지를 반환하거나, <code>node.send(messages)</code>를 호출합니다.</p>
|
||||
<p>반환/send 대상은 다음과 같습니다:</p>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<p>Se o código <b>On Start</b> retornar um objeto do tipo promessa, o nó não começará a tratar as mensagens
|
||||
até que a promessa seja resolvida.</p>
|
||||
<h3>Detalhes</h3>
|
||||
<p>Consulte a <a target="_blank" href="http://nodered.org/docs/writing-functions.html">documentação online</a>
|
||||
<p>Consulte a <a target="_blank" href="https://nodered.org/docs/writing-functions.html">documentação online</a>
|
||||
para obter maiores informações sobre funções de escrita.</p>
|
||||
<h4>Enviando mensagens</h4>
|
||||
<p>A função pode retornar as mensagens que deseja passar para os próximos nós
|
||||
|
||||
0
packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json
vendored
Executable file → Normal file
0
packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json
vendored
Executable file → Normal file
@@ -36,7 +36,7 @@
|
||||
|
||||
<h3>Подробности</h3>
|
||||
<p>
|
||||
Смотрите <a target="_blank" href="http://nodered.org/docs/writing-functions.html">онлайн-документацию</a> для получения дополнительной информации по написанию функций.
|
||||
Смотрите <a target="_blank" href="https://nodered.org/docs/writing-functions.html">онлайн-документацию</a> для получения дополнительной информации по написанию функций.
|
||||
</p>
|
||||
|
||||
<h4>Отправка сообщений</h4>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<p>通常,<code>msg</code>对象将消息正文保留在<code>msg.payload</code>属性中。</p>
|
||||
<p>该函数一般会返回一个消息对象(或多个消息对象),但也可以为了停止流而什么都不返回。</p>
|
||||
<h3>详细</h3>
|
||||
<p>请参见<a target="_blank" href="http://nodered.org/docs/writing-functions.html">在线文档</a>来获得更多有关编写函数的信息。</p>
|
||||
<p>请参见<a target="_blank" href="https://nodered.org/docs/writing-functions.html">在线文档</a>来获得更多有关编写函数的信息。</p>
|
||||
<h4>传送消息</h4>
|
||||
<p>要将消息传递到流中的下一个节点,请返回消息或调用<code>node.send(messages)</code>。</p>
|
||||
<p>它将返回/send:</p>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<p>通常,<code>msg</code>對象將消息正文保留在<code>msg.payload</code>屬性中。</p>
|
||||
<p>該函數一般會返回一個消息對象(或多個消息對象),但也可以爲了停止流程而什麽都不返回。</p>
|
||||
<h3>詳細</h3>
|
||||
<p>請參見<a target="_blank" href="http://nodered.org/docs/writing-functions.html">在線文檔</a>來獲得更多有關編寫函數的信息。</p>
|
||||
<p>請參見<a target="_blank" href="https://nodered.org/docs/writing-functions.html">在線文檔</a>來獲得更多有關編寫函數的信息。</p>
|
||||
<h4>傳送消息</h4>
|
||||
<p>要將消息傳遞到流程中的下一個節點,請返回消息或調用<code>node.send(messages)</code>。</p>
|
||||
<p>它將返回/send:</p>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -38,13 +38,13 @@
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-watch": "0.7.3",
|
||||
"node-watch": "0.7.4",
|
||||
"on-headers": "1.0.2",
|
||||
"raw-body": "2.5.2",
|
||||
"tough-cookie": "4.1.2",
|
||||
"tough-cookie": "4.1.3",
|
||||
"uuid": "9.0.0",
|
||||
"ws": "7.5.6",
|
||||
"xml2js": "0.6.0",
|
||||
"xml2js": "0.6.2",
|
||||
"iconv-lite": "0.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,10 +16,10 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"semver": "7.5.0",
|
||||
"semver": "7.5.4",
|
||||
"tar": "6.1.13",
|
||||
"uglify-js": "3.17.4"
|
||||
}
|
||||
|
||||
@@ -479,7 +479,7 @@ function remapSubflowNodes(nodes,nodeMap) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((node.type === 'complete' || node.type === 'catch' || node.type === 'status') && node.scope) {
|
||||
if ((node.type === 'complete' || node.type === 'catch' || node.type === 'status') && Array.isArray(node.scope)) {
|
||||
node.scope = node.scope.map(function(id) {
|
||||
return nodeMap[id]?nodeMap[id].id:""
|
||||
})
|
||||
|
||||
@@ -431,7 +431,7 @@ module.exports = {
|
||||
return runGitCommand(args,cwd);
|
||||
},
|
||||
pull: function(cwd,remote,branch,allowUnrelatedHistories,auth,gitUser) {
|
||||
var args = ["pull"];
|
||||
var args = ["pull", "--no-rebase"];
|
||||
if (remote && branch) {
|
||||
args.push(remote);
|
||||
args.push(branch);
|
||||
|
||||
@@ -71,30 +71,30 @@ function readFile(path,backupPath,emptyResponse,type) {
|
||||
});
|
||||
}
|
||||
|
||||
const writeFileLocks = {}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Write content to a file using UTF8 encoding.
|
||||
* This forces a fsync before completing to ensure
|
||||
* the write hits disk.
|
||||
*/
|
||||
writeFile: function(path,content,backupPath) {
|
||||
writeFile: async function(path,content,backupPath) {
|
||||
if (!writeFileLocks[path]) {
|
||||
writeFileLocks[path] = Promise.resolve()
|
||||
}
|
||||
const result = writeFileLocks[path].then(async () => {
|
||||
var backupPromise;
|
||||
if (backupPath && fs.existsSync(path)) {
|
||||
backupPromise = fs.copy(path,backupPath);
|
||||
} else {
|
||||
backupPromise = Promise.resolve();
|
||||
await fs.copy(path,backupPath);
|
||||
log.trace(`utils.writeFile - copied ${path} TO ${backupPath}`)
|
||||
}
|
||||
|
||||
const dirname = fspath.dirname(path);
|
||||
const tempFile = `${path}.$$$`;
|
||||
await fs.ensureDir(dirname)
|
||||
|
||||
return backupPromise.then(() => {
|
||||
if (backupPath) {
|
||||
log.trace(`utils.writeFile - copied ${path} TO ${backupPath}`)
|
||||
}
|
||||
return fs.ensureDir(dirname)
|
||||
}).then(() => {
|
||||
return new Promise(function(resolve,reject) {
|
||||
await new Promise(function(resolve,reject) {
|
||||
var stream = fs.createWriteStream(tempFile);
|
||||
stream.on('open',function(fd) {
|
||||
stream.write(content,'utf8',function() {
|
||||
@@ -110,10 +110,11 @@ module.exports = {
|
||||
log.warn(log._("storage.localfilesystem.fsync-fail",{path: tempFile, message: err.toString()}));
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}).then(() => {
|
||||
})
|
||||
|
||||
log.trace(`utils.writeFile - written content to ${tempFile}`)
|
||||
return new Promise(function(resolve,reject) {
|
||||
|
||||
await new Promise(function(resolve,reject) {
|
||||
fs.rename(tempFile,path,err => {
|
||||
if (err) {
|
||||
log.warn(log._("storage.localfilesystem.fsync-fail",{path: path, message: err.toString()}));
|
||||
@@ -122,8 +123,10 @@ module.exports = {
|
||||
log.trace(`utils.writeFile - renamed ${tempFile} to ${path}`)
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
writeFileLocks[path] = result.catch(() => {})
|
||||
return result
|
||||
},
|
||||
readFile: readFile,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "3.1.0-beta.4",
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/registry": "4.0.0-dev",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"async-mutex": "0.4.0",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.18.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
8
packages/node_modules/node-red/README.md
vendored
8
packages/node_modules/node-red/README.md
vendored
@@ -1,14 +1,14 @@
|
||||
# Node-RED
|
||||
|
||||
http://nodered.org
|
||||
https://nodered.org
|
||||
|
||||
Low-code programming for event-driven applications.
|
||||
|
||||

|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out http://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
Check out https://nodered.org/docs/getting-started/ for full instructions on getting
|
||||
started.
|
||||
|
||||
1. `sudo npm install -g --unsafe-perm node-red`
|
||||
@@ -17,7 +17,7 @@ started.
|
||||
|
||||
## Getting Help
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
More documentation can be found [here](https://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, please use the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
|
||||
16
packages/node_modules/node-red/package.json
vendored
16
packages/node_modules/node-red/package.json
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.1.0-beta.4",
|
||||
"version": "4.0.0-dev",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "http://nodered.org",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -31,17 +31,17 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "3.1.0-beta.4",
|
||||
"@node-red/runtime": "3.1.0-beta.4",
|
||||
"@node-red/util": "3.1.0-beta.4",
|
||||
"@node-red/nodes": "3.1.0-beta.4",
|
||||
"@node-red/editor-api": "4.0.0-dev",
|
||||
"@node-red/runtime": "4.0.0-dev",
|
||||
"@node-red/util": "4.0.0-dev",
|
||||
"@node-red/nodes": "4.0.0-dev",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.18.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"node-red-admin": "^3.0.0",
|
||||
"node-red-admin": "^3.1.0",
|
||||
"nopt": "5.0.0",
|
||||
"semver": "7.5.0"
|
||||
"semver": "7.5.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcrypt": "5.1.0"
|
||||
|
||||
2
packages/node_modules/node-red/red.js
vendored
2
packages/node_modules/node-red/red.js
vendored
@@ -88,7 +88,7 @@ if (parsedArgs.help) {
|
||||
console.log(" -?, --help show this help");
|
||||
console.log(" admin <command> run an admin command");
|
||||
console.log("");
|
||||
console.log("Documentation can be found at http://nodered.org");
|
||||
console.log("Documentation can be found at https://nodered.org");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
|
||||
8
packages/node_modules/node-red/settings.js
vendored
8
packages/node_modules/node-red/settings.js
vendored
@@ -71,7 +71,7 @@ module.exports = {
|
||||
******************************************************************************/
|
||||
|
||||
/** To password protect the Node-RED editor and admin API, the following
|
||||
* property can be used. See http://nodered.org/docs/security.html for details.
|
||||
* property can be used. See https://nodered.org/docs/security.html for details.
|
||||
*/
|
||||
//adminAuth: {
|
||||
// type: "credentials",
|
||||
@@ -120,7 +120,7 @@ module.exports = {
|
||||
* including node-red-dashboard, or the static content (httpStatic), the
|
||||
* following properties can be used.
|
||||
* The `pass` field is a bcrypt hash of the password.
|
||||
* See http://nodered.org/docs/security.html#generating-the-password-hash
|
||||
* See https://nodered.org/docs/security.html#generating-the-password-hash
|
||||
*/
|
||||
//httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
|
||||
//httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."},
|
||||
@@ -444,6 +444,7 @@ module.exports = {
|
||||
* - fileWorkingDirectory
|
||||
* - functionGlobalContext
|
||||
* - functionExternalModules
|
||||
* - functionTimeout
|
||||
* - nodeMessageBufferMaxLength
|
||||
* - ui (for use with Node-RED Dashboard)
|
||||
* - debugUseColors
|
||||
@@ -468,6 +469,9 @@ module.exports = {
|
||||
/** Allow the Function node to load additional npm modules directly */
|
||||
functionExternalModules: true,
|
||||
|
||||
/** Default timeout, in seconds, for the Function node. 0 means no timeout is applied */
|
||||
functionTimeout: 0,
|
||||
|
||||
/** The following property can be used to set predefined values in Global Context.
|
||||
* This allows extra node modules to be made available with in Function node.
|
||||
* For example, the following:
|
||||
|
||||
@@ -1449,6 +1449,34 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('check if default function timeout settings are recognized', function (done) {
|
||||
RED.settings.functionTimeout = 0.01;
|
||||
var flow = [{id: "n1",type: "function",timeout: RED.settings.functionTimeout,wires: [["n2"]],func: "while(1==1){};\nreturn msg;"}];
|
||||
helper.load(functionNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.receive({ payload: "foo", topic: "bar" });
|
||||
setTimeout(function () {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "function";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var msg = logEvents[0][0];
|
||||
msg.should.have.property('level', helper.log().ERROR);
|
||||
msg.should.have.property('id', 'n1');
|
||||
msg.should.have.property('type', 'function');
|
||||
should.equal(RED.settings.functionTimeout, 0.01);
|
||||
should.equal(msg.msg.message, 'Script execution timed out after 10ms');
|
||||
delete RED.settings.functionTimeout;
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
describe("finalize function", function() {
|
||||
|
||||
it('should execute', function(done) {
|
||||
@@ -1690,9 +1718,13 @@ describe('function node', function() {
|
||||
describe("init function", function() {
|
||||
|
||||
it('should delay handling messages until init completes', function(done) {
|
||||
const timeoutMS = 200;
|
||||
// Since helper.load uses process.nextTick timers might occasionally finish
|
||||
// a couple of milliseconds too early, so give some leeway to the check.
|
||||
const timeoutCheckMargin = 5;
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],initialize: `
|
||||
return new Promise((resolve,reject) => {
|
||||
setTimeout(resolve,200)
|
||||
setTimeout(resolve, ${timeoutMS});
|
||||
})`,
|
||||
func:"return msg;"
|
||||
},
|
||||
@@ -1705,9 +1737,10 @@ describe('function node', function() {
|
||||
msg.delta = Date.now() - msg.payload;
|
||||
receivedMsgs.push(msg)
|
||||
if (receivedMsgs.length === 5) {
|
||||
var errors = receivedMsgs.filter(msg => msg.delta < 200)
|
||||
let deltas = receivedMsgs.map(msg => msg.delta);
|
||||
var errors = deltas.filter(delta => delta < (timeoutMS - timeoutCheckMargin))
|
||||
if (errors.length > 0) {
|
||||
done(new Error(`Message received before init completed - was ${msg.delta} expected >300`))
|
||||
done(new Error(`Message received before init completed - delta values ${JSON.stringify(deltas)} expected to be > ${timeoutMS - timeoutCheckMargin}`))
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
|
||||
@@ -126,6 +126,26 @@ describe("api/admin/context", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should call context.getValue to get a node context value - url unsafe keyname', function (done) {
|
||||
stub.returns(Promise.resolve(nContext));
|
||||
request(app)
|
||||
.get('/context/node/5678/foo%23123?store=file')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
stub.args[0][0].should.have.property('user', undefined);
|
||||
stub.args[0][0].should.have.property('scope', 'node');
|
||||
stub.args[0][0].should.have.property('id', '5678');
|
||||
stub.args[0][0].should.have.property('key', 'foo#123');
|
||||
stub.args[0][0].should.have.property('store', 'file');
|
||||
var body = res.body;
|
||||
body.should.eql(nContext);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should handle error which context.getValue causes', function (done) {
|
||||
var stubbedResult = Promise.reject('error');
|
||||
stubbedResult.catch(function() {});
|
||||
@@ -214,6 +234,24 @@ describe("api/admin/context", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should call context.delete to delete a node context - url unsafe keyname', function (done) {
|
||||
stub.returns(Promise.resolve());
|
||||
request(app)
|
||||
.delete('/context/node/5678/foo%23123?store=file')
|
||||
.expect(204)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
stub.args[0][0].should.have.property('user', undefined);
|
||||
stub.args[0][0].should.have.property('scope', 'node');
|
||||
stub.args[0][0].should.have.property('id', '5678');
|
||||
stub.args[0][0].should.have.property('key', 'foo#123');
|
||||
stub.args[0][0].should.have.property('store', 'file');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle error which context.delete causes', function (done) {
|
||||
var stubbedResult = Promise.reject('error');
|
||||
stubbedResult.catch(function() {});
|
||||
|
||||
@@ -98,7 +98,7 @@ describe("api/editor/theme", function () {
|
||||
},
|
||||
header: {
|
||||
title: "Test Header Title",
|
||||
url: "http://nodered.org",
|
||||
url: "https://nodered.org",
|
||||
image: "/absolute/path/to/header/image" // or null to remove image
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@ describe("api/editor/theme", function () {
|
||||
context.page.tabicon.should.have.a.property("colour", "#8f008f")
|
||||
context.should.have.a.property("header");
|
||||
context.header.should.have.a.property("title", "Test Header Title");
|
||||
context.header.should.have.a.property("url", "http://nodered.org");
|
||||
context.header.should.have.a.property("url", "https://nodered.org");
|
||||
context.header.should.have.a.property("image", "theme/header/image");
|
||||
context.page.should.have.a.property("css");
|
||||
context.page.css.should.have.lengthOf(1);
|
||||
|
||||
@@ -14,11 +14,33 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var NR_TEST_UTILS = require("nr-test-utils");
|
||||
var util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
|
||||
const should = require("should");
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
const util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
|
||||
const { mkdtemp, readFile } = require('fs/promises');
|
||||
const { join } = require('path');
|
||||
const { tmpdir } = require('os');
|
||||
|
||||
describe('storage/localfilesystem/util', function() {
|
||||
describe('writeFile', function () {
|
||||
it('manages concurrent calls to modify the same file', async function () {
|
||||
const testDirectory = await mkdtemp(join(tmpdir(), 'nr-test-'));
|
||||
const testFile = join(testDirectory, 'foo.txt')
|
||||
const testBackupFile = testFile + '.$$$'
|
||||
|
||||
let counter = 0
|
||||
const promises = [
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile ),
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile ),
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile )
|
||||
]
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
const result = await readFile(testFile, { encoding: 'utf-8' })
|
||||
result.should.equal('update-2')
|
||||
})
|
||||
})
|
||||
describe('parseJSON', function() {
|
||||
it('returns parsed JSON', function() {
|
||||
var result = util.parseJSON('{"a":123}');
|
||||
|
||||
Reference in New Issue
Block a user