Compare commits

..

54 Commits

Author SHA1 Message Date
Dave Conway-Jones
638d0d2f3f let icons be settable by loading from server endpoint 2023-10-23 19:09:39 +01:00
Nick O'Leary
eb940d6d57 Merge pull request #4367 from hlovdal/timer_testing_fix
Timer testing fix
2023-09-25 18:19:30 +01:00
Håkon Løvdal
9091935d77 Update variable names 2023-09-25 18:53:11 +02:00
Håkon Løvdal
34e8d2b051 Add workaround for timers triggering too early in test 2023-09-24 18:16:59 +02:00
Håkon Løvdal
0c2ab13c48 Print all delta values in case of error, not just the last value
Which might not even be the one triggering the error condition.
2023-09-24 18:16:59 +02:00
Håkon Løvdal
9489953a8f Introduce timeout constant 2023-09-24 18:16:59 +02:00
Nick O'Leary
cef3a01042 Merge pull request #4322 from node-red/prep4
Bump to 4.0.0-dev
2023-09-06 15:04:41 +01:00
Nick O'Leary
0c042abcab Bump to 4.0.0-dev 2023-09-06 14:45:45 +01:00
Nick O'Leary
a48c57dd17 Merge pull request #4321 from node-red/rel-310
Bump version and changelog for 3.1.0 release
2023-09-06 13:57:44 +01:00
Nick O'Leary
77b235655c Bump version and changelog 2023-09-05 21:29:20 +01:00
Nick O'Leary
8dc0261993 Merge pull request #4319 from Rotzbua/fix_duplicate
Fix duplicate declaration
2023-09-05 20:41:38 +01:00
Rotzbua
65d2ad68d3 Fix duplicate declaration 2023-09-05 19:02:39 +02:00
Nick O'Leary
52fde088e9 Merge pull request #4318 from node-red/4315-small-catalogs-fix
Default filter to All Catalogues and show nodes for small lists
2023-09-05 17:59:57 +01:00
Nick O'Leary
ab6d537c3e Default filter to All Catalogues and show nodes for small lists 2023-09-05 17:49:50 +01:00
Nick O'Leary
3a6078a56a Merge pull request #4317 from node-red/update-deps-31
Dependency updates
2023-09-05 17:21:06 +01:00
Nick O'Leary
b0c3fefcab Dependency updates 2023-09-05 17:16:05 +01:00
Nick O'Leary
2bc739194e Merge pull request #4316 from node-red/4221-handle-concurrent-write-file
Ensure storage/util.writeFile handles concurrent write attempts
2023-09-05 15:57:27 +01:00
Nick O'Leary
afb06e8c9a Update packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/util.js 2023-09-05 15:11:47 +01:00
Nick O'Leary
2c1274ff76 Ensure storage/util.writeFile handles concurrent write attempts 2023-09-05 15:09:11 +01:00
Nick O'Leary
e18721a03e Merge pull request #4313 from Rotzbua/fix_https
Migrate http -> https for nodered.org
2023-09-05 14:20:32 +01:00
Rotzbua
aea32cc279 Migrate http -> https for nodered.org 2023-09-05 14:55:56 +02:00
Nick O'Leary
ce0feb2f42 Merge pull request #4310 from node-red/4206-ctrl-click-behaviour
Better distinguish between ctrl and meta keys on mac
2023-09-05 13:48:17 +01:00
Nick O'Leary
d307968880 Better distinguish between ctrl and meta keys on mac
Fixes #4206, #4205
2023-09-05 12:36:44 +01:00
Nick O'Leary
1f98d19f77 Merge pull request #4309 from node-red/pr_4265
Adding function timeout to settings file (#4265)
2023-09-05 11:44:41 +01:00
Nick O'Leary
9a934c941f Tidy up functionTimeout setting 2023-09-05 10:34:18 +01:00
Nick O'Leary
de63e17a4d Merge pull request #4305 from Rotzbua/add_node_20_to_test
Add Node 20 to GH Action test matrix
2023-09-05 09:44:23 +01:00
Nick O'Leary
1bad643b30 Merge pull request #4302 from node-red/4291-auto-sub-mqtt-error
Remove unnecessary check for clientid if autoUnsub set
2023-09-05 09:43:52 +01:00
Nick O'Leary
57c44d4b18 Merge pull request #4301 from node-red/4292-fix-catch-in-subflow
Handle group-scoped nodes inside subflow
2023-09-05 09:43:44 +01:00
Nick O'Leary
7d06133787 Merge pull request #4299 from node-red/4296-fix-function-setup-height
Fix function setup tab layout
2023-09-05 09:43:35 +01:00
Nick O'Leary
261998201b Merge pull request #4298 from node-red/4295-urlencode-context-api
Handle non-url-safe chars in context api
2023-09-05 09:43:17 +01:00
Nick O'Leary
9a899b929e Merge pull request #4297 from node-red/4294-fix-junction-quick-add
Ensure junction appears when filtering quick-add list
2023-09-05 09:42:42 +01:00
Rotzbua
5fcace8776 Add Node 20 to GH Action test matrix 2023-09-04 14:31:30 +02:00
Nick O'Leary
a12826e719 Remove unnecessary check for clientid if autoUnsub set
Fixes #4291
2023-09-02 20:48:13 +01:00
Nick O'Leary
0dc024c722 Handle group-scoped nodes inside subflow
Fixes #4292
2023-09-01 16:38:46 +01:00
Nick O'Leary
f6f36c5599 Fix function setup tab layout 2023-09-01 16:17:29 +01:00
Nick O'Leary
18bd318da2 Handle non-url-safe chars in context api 2023-09-01 16:06:05 +01:00
Nick O'Leary
e1712073c9 Ensure junction appears when filtering quick-add list 2023-09-01 15:41:33 +01:00
Nick O'Leary
2478a7194e Merge pull request #4287 from kazuhitoyokoi/dev-fixjsonata
Update message catalogs for JSONata Expression editor
2023-08-21 15:42:37 +01:00
Nick O'Leary
89b8e88df3 Merge pull request #4290 from kazuhitoyokoi/dev-fixgitpull
Fix git pull operation in project feature
2023-08-21 15:42:11 +01:00
Kazuhito Yokoi
a7e80f351a Fix git pull operation in project feature 2023-08-21 11:18:01 +09:00
Stephen McLaughlin
c39d3db121 Merge pull request #4288 from kazuhitoyokoi/dev-tooltip4nodesearch
Add tooltip to relevance sort button in user settings UI
2023-08-20 08:45:25 +01:00
Kazuhito Yokoi
e7f9e61f2a Add tooltip to relevance sort button in user settings UI 2023-08-20 16:20:18 +09:00
Kazuhito Yokoi
3047ed1253 Improve message catalogs for JSONata Expression editor 2023-08-19 13:33:42 +09:00
Kazuhito Yokoi
cf0c7ce583 Fix typo in Korean message catalog 2023-08-19 13:24:34 +09:00
Kazuhito Yokoi
206211f9ef Fix typo in English message catalog 2023-08-19 13:21:42 +09:00
Kazuhito Yokoi
8220ff8a35 Add docs for function in Japanese message catalog 2023-08-19 13:19:55 +09:00
Nick O'Leary
927fc5424b Merge pull request #4283 from node-red/4282-dirty-junction-undo
Capture workspace dirty state when quick-adding junction
2023-08-18 15:53:25 +01:00
Nick O'Leary
64b94c68d3 Merge pull request #4284 from node-red/4268-add-clone-jsonata-docs
Add docs for $clone function
2023-08-18 15:52:45 +01:00
Nick O'Leary
3391d18942 Merge pull request #4286 from kazuhitoyokoi/dev-fixlinefeed
Change linefeed codes from "\r\n" to "\n" in Korean message catalogs
2023-08-18 15:52:27 +01:00
Kazuhito Yokoi
1414fed776 Change linefeed codes from "\r\n" to "\n" in Korean message catalogs 2023-08-18 20:39:13 +09:00
Nick O'Leary
f884cb015a Merge pull request #4285 from kazuhitoyokoi/dev-fixpermission
Fix file permissions of message catalogs
2023-08-17 10:29:25 +01:00
Kazuhito Yokoi
7e6a96db87 Fix file permissions of message catalogs 2023-08-17 18:17:58 +09:00
Nick O'Leary
966bbe2856 Add docs for $clone function 2023-08-16 16:02:33 +01:00
Kilian Hertel
f7b64b101e adding function timeout to settings file
adding function timeout to settings file
2023-08-04 14:20:49 +02:00
57 changed files with 1953 additions and 1778 deletions

View File

@@ -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 }}

View File

@@ -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

View File

@@ -1,16 +1,16 @@
# Node-RED
http://nodered.org
https://nodered.org
[![Build Status](https://github.com/node-red/node-red/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/node-red/node-red/actions?query=branch%3Amaster)
Low-code programming for event-driven applications.
![Node-RED: Low-code programming for event-driven applications](http://nodered.org/images/node-red-screenshot.png)
![Node-RED: Low-code programming for event-driven applications](https://nodered.org/images/node-red-screenshot.png)
## 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).

View File

@@ -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",

View File

@@ -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",

View File

@@ -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]",

View File

@@ -627,6 +627,7 @@
"tab-nodes": "Nodes",
"tab-install": "Install",
"sort": "sort:",
"sortRelevance": "relevance",
"sortAZ": "a-z",
"sortRecent": "recent",
"more": "+ __count__ more",

View File

@@ -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."
}
}

View File

View 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]",

View File

@@ -627,6 +627,7 @@
"tab-nodes": "現在のノード",
"tab-install": "ノードを追加",
"sort": "並べ替え:",
"sortRelevance": "関連順",
"sortAZ": "辞書順",
"sortRecent": "日付順",
"more": "+ さらに __count__ 個",

View File

@@ -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比較関数は、leftrightの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": "オブジェクトを安全に複製します。"
}
}

View File

@@ -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]",

View File

View 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]",

View File

@@ -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",

View File

@@ -137,7 +137,7 @@
},
"$sort": {
"args": "array [, function]",
"desc": "输出排序后的数组 `array` 。\n\n如果使用了比较函数 `function` ,则下述两个参数需要被指定。\n\n `function(left, right)` \n\n该比较函数是为了比较leftright两个值而被排序算法调用的。如果用户希望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",

View File

@@ -137,7 +137,7 @@
},
"$sort": {
"args": "array [, function]",
"desc": "輸出排序後的陣列`array`。\n\n如果使用了比較函數`function`,則下述兩個參數需要被指定。\n\n`function(left, right)`\n\n該比較函數是為了比較leftright兩個值而被排序演算法調用的。如果使用者希望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",

View File

@@ -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",

View File

@@ -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" });

View File

@@ -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"));

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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";
}

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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");

View File

@@ -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;
}

View File

@@ -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",

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
View File

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"
}
}

View File

@@ -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"
}

View File

@@ -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:""
})

View File

@@ -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);

View File

@@ -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,

View File

@@ -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",

View File

@@ -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",

View File

@@ -1,14 +1,14 @@
# Node-RED
http://nodered.org
https://nodered.org
Low-code programming for event-driven applications.
![Node-RED: Low-code programming for event-driven applications.](http://nodered.org/images/node-red-screenshot.png)
![Node-RED: Low-code programming for event-driven applications.](https://nodered.org/images/node-red-screenshot.png)
## 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).

View File

@@ -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"

View File

@@ -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();
}

View File

@@ -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:

View File

@@ -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();
}

View File

@@ -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() {});

View File

@@ -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);

View File

@@ -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}');