Compare commits

...

91 Commits

Author SHA1 Message Date
Nick O'Leary
02893d3e78 Merge pull request #4755 from node-red/rel3110
Bump for 3.1.10 release
2024-06-11 09:22:16 +01:00
Nick O'Leary
5124bc6bf8 Bump for 3.1.10 release 2024-06-10 21:14:20 +01:00
Nick O'Leary
1048b16f3c Merge pull request #4754 from node-red/4752-add-rewired-to-stoplist
Include rewired nodes when calculating Modified Flows stop list
2024-06-10 20:44:20 +01:00
Nick O'Leary
bbbbb1b1e0 Merge pull request #4753 from node-red/4751-fix-group-json
Fix clone of group env var properties
2024-06-10 20:42:49 +01:00
Nick O'Leary
14b452c996 Merge pull request #4750 from GogoVega/fix-4749
Fix losing links when importing a copy of links into a subflow
2024-06-10 20:42:36 +01:00
GogoVega
bb91a08939 Just move the block before the Id is updated 2024-06-10 18:28:30 +02:00
Nick O'Leary
526b3fda91 Include rewired nodes when calculating Modified Flows stop list 2024-06-10 16:56:49 +01:00
Nick O'Leary
d70b7ea924 Fix clone of group env var properties
Closes #4751
2024-06-10 16:15:06 +01:00
GogoVega
1d342a778d Fix new_nodes should be used instead of node_map 2024-06-05 14:12:35 +02:00
GogoVega
476016cbcc Fix node_map does not contain as key the new id of a copied node 2024-06-05 12:22:22 +02:00
Nick O'Leary
61b12f6bbe Merge pull request #3743 from bonanitech/fix-build-script
Ensure all CSS variables are in the output file
2024-05-30 13:43:25 +01:00
Nick O'Leary
d71b22412b Merge pull request #4734 from GogoVega/fix-sidebar-config
Fix the Sidebar Config is not refreshed after a deploy
2024-05-30 13:40:12 +01:00
Nick O'Leary
e408c6b376 Merge pull request #4729 from GogoVega/fix-4728
Fix checkboxes are not updated when calling `typedInput("value", "")`
2024-05-30 10:32:27 +01:00
GogoVega
bf30c24e8e Fix the Sidebar Config is not refreshed after a deploy 2024-05-29 20:44:49 +02:00
GogoVega
6c14ed0ef5 Revert and fix an undefined value returned instead of a false value 2024-05-28 22:08:42 +02:00
Nick O'Leary
6d41ecdae0 Merge pull request #4716 from corentin-sodebo-voile/master
Fix panning with middle mouse button on windows 10/11
2024-05-28 10:28:57 +01:00
Nick O'Leary
3f89bc2733 Merge pull request #4727 from kazuhitoyokoi/master-addjpn
Add Japanese translation for sidebar tooltip
2024-05-28 09:49:35 +01:00
Nick O'Leary
87a25df162 Merge pull request #4730 from GogoVega/translate-multiple-option-label
Translate the number of items selected in the options list
2024-05-28 09:49:03 +01:00
GogoVega
341f43610a Translate the number of items selected in the options list 2024-05-27 19:56:51 +02:00
GogoVega
67cdf3ef96 Fix checkboxes are not updated when calling typedInput("value", "") 2024-05-27 18:59:25 +02:00
Kazuhito Yokoi
cd98f448e9 Add Japanese translation for sidebar tooltip 2024-05-26 23:34:32 +09:00
corentin-sodebo-voile
fac79fd068 Fix panning with middle mouse button on windows 10/11
Without preventDefault, when you try to drag the canvas with middle mouse button on Windows (e.g. in Chrome), the cursor change to a "scroll cursor" and the canvas scrolls endlessly instead of being dragged accurately.
2024-05-23 15:30:13 +02:00
Nick O'Leary
da97c5d558 Merge pull request #4715 from GogoVega/fix-validateNodeEditorProperty
Fix a checkbox should return a Boolean value and not the string `on`
2024-05-23 13:43:55 +01:00
Nick O'Leary
ae7b9fe62e Merge pull request #4714 from GogoVega/fix-4712
Deleting a grouped node should update the group
2024-05-23 13:43:26 +01:00
GogoVega
e52c2911da Fix a checkbox must return a boolean value and not on 2024-05-23 10:57:51 +02:00
Nick O'Leary
07a29ff779 Merge pull request #4711 from GogoVega/change-config-node-cursor
Change the Config Node cursor to `pointer`
2024-05-22 17:02:05 +01:00
Nick O'Leary
1b4a8ebe83 Merge branch 'master' into fix-4712 2024-05-22 17:01:29 +01:00
GogoVega
abf2eacf18 Revert and fix without using RED.group.removeFromGroup 2024-05-21 19:48:21 +02:00
Gauthier Dandele
f808f4e2e8 Apply suggestions from code review
Co-authored-by: Nick O'Leary <nick.oleary@gmail.com>
2024-05-21 19:01:57 +02:00
Nick O'Leary
ca33d6b799 Merge pull request #4713 from GogoVega/add-missing-sidebar-tooltips
Add missing tooltips to Sidebar
2024-05-21 17:15:52 +01:00
Nick O'Leary
940740f15d Merge pull request #4710 from node-red/4704-node-edit-history
Allow nodes to return additional history entries in onEditSave
2024-05-21 17:10:23 +01:00
GogoVega
51208fcd0c Fix indexOf returns -1 2024-05-21 16:06:15 +02:00
GogoVega
707152d82f Deleting a grouped node should update the group 2024-05-21 15:07:26 +02:00
GogoVega
5538f6dd8a Add missing tooltips to Sidebar 2024-05-21 12:58:29 +02:00
GogoVega
d601e2caa4 Change the config node cursor to pointer 2024-05-21 11:37:01 +02:00
Nick O'Leary
46fdf56c79 Allow nodes to return additional history entries in onEditSave 2024-05-20 16:41:44 +01:00
Nick O'Leary
f55ee6e665 Merge pull request #4685 from node-red/4683-preserve-full-error-obj
Pass full error object in Function node and copy over cause property
2024-05-13 15:25:02 +01:00
Nick O'Leary
03648dc7e8 Update tests for changed function node low-level output 2024-05-09 17:25:47 +01:00
Nick O'Leary
66a667fe58 Pass full error object in Function node and copy over cause property
Fixes #4683
2024-05-09 16:48:51 +01:00
Nick O'Leary
1bb3a0eca5 Merge pull request #4534 from patlux/master
Replacing vm.createScript in favour of vm.Script
2024-05-09 15:19:45 +01:00
Nick O'Leary
08927dfb55 Merge pull request #4684 from node-red/4363-autoLogin-redirect-loop
Avoid login loops when autoLogin enabled but login fails
2024-05-08 15:48:21 +01:00
Nick O'Leary
b27483de9c Avoid login loops when autoLogin enabled but login fails
Fixes #4363
2024-05-08 15:09:51 +01:00
Nick O'Leary
211d420fb2 Merge pull request #4667 from node-red/fix-subflow-property-undo
Fix undo of subflow env property edits
2024-04-23 23:45:46 +02:00
Nick O'Leary
b8ca4665c1 Merge pull request #4660 from JoshuaCWebDeveloper/patch-1
Fix three error typos in monaco.js
2024-04-23 23:45:16 +02:00
Nick O'Leary
960af87fb0 Ensure subflow change state is cleared after deploy 2024-04-23 21:17:35 +02:00
Nick O'Leary
de7339ae97 Fix undo of subflow env property edits 2024-04-23 20:39:14 +02:00
Stephen McLaughlin
0995af62b6 Merge pull request #4664 from ZJvandeWeg/patch-3
docs: Add closing paragraph tag
2024-04-20 13:54:37 +01:00
Zeger-Jan van de Weg
c2e03a40b4 docs: Add closing paragraph tag
Minor change that only improves xpath parsing.
2024-04-20 14:20:59 +02:00
Joshua Carter
c855050bcf Fix three error typos in monaco.js 2024-04-15 08:09:26 -07:00
Nick O'Leary
29ed5b2792 Merge pull request #4655 from node-red/rel319
Bump for 3.1.9 release
2024-04-11 19:22:24 +01:00
Nick O'Leary
e39216e65a Bump for 3.1.9 release 2024-04-11 19:15:46 +01:00
Nick O'Leary
7ac7f9b4c8 Merge pull request #4654 from node-red/fix-subflow-recursion-check
Prevent subflow being added to itself
2024-04-11 19:12:43 +01:00
Stephen McLaughlin
4709eb9d49 Merge pull request #4652 from node-red/fix-windows-spawn
Fix use of spawn on windows with cmd files
2024-04-11 17:51:13 +01:00
Nick O'Leary
c13b8266dd Prevent subflow being added to itself 2024-04-11 17:05:10 +01:00
Nick O'Leary
bd58431603 Fix use of spawn on windows with cmd files 2024-04-11 14:40:29 +01:00
Nick O'Leary
9a3cb0b2b5 Merge pull request #4640 from node-red/fix-subflow-init-err
Guard refresh of unknown subflow
2024-04-02 20:06:47 +01:00
Nick O'Leary
6beae5a806 Merge pull request #4642 from node-red/4641-fix-subflow-module-debug-logging
Fix subflow module sending messages to debug sidebar
2024-04-02 20:06:31 +01:00
Nick O'Leary
a0636632a1 Fix subflow module sending messages to debug sidebar
Fixes #4641
2024-04-02 17:42:19 +01:00
Nick O'Leary
5dfa47ab6c Guard refresh of unknown subflow 2024-04-02 15:54:34 +01:00
Nick O'Leary
ade4679e8c Merge pull request #4636 from node-red/rel318
Bump for 3.1.8
2024-03-28 15:23:07 +00:00
Nick O'Leary
410b938442 Bump for 3.1.8 2024-03-28 15:02:02 +00:00
Nick O'Leary
19dcc3a683 Merge pull request #4632 from node-red/4625-sf-env-err-handling
Add validation and error handling on subflow instance properties
2024-03-28 11:10:28 +00:00
Nick O'Leary
20d067c1ea Merge pull request #4633 from node-red/4617-hide-library-context-options
Hide import/export context menu if disabled in theme
2024-03-28 11:10:14 +00:00
Nick O'Leary
9526566799 Hide import/export context menu if disabled in theme 2024-03-28 11:00:10 +00:00
Nick O'Leary
0b9dd82c91 Merge pull request #4631 from node-red/4626-subflow-change-notification
Show change indicator on subflow tabs
2024-03-27 19:10:39 +00:00
Nick O'Leary
19213434f9 Add validation to subflow instance env properties 2024-03-27 19:08:25 +00:00
Nick O'Leary
014691346a Handle malformed env var values and log errors 2024-03-27 18:23:12 +00:00
Nick O'Leary
6738b95c29 Merge pull request #4630 from node-red/bump-express
Bump dependencies
2024-03-27 18:11:54 +00:00
Nick O'Leary
6a8230ec1e Show change icon on subflow tabs
Fixes #4626
2024-03-27 18:10:04 +00:00
Nick O'Leary
5679d264b6 Bump dependencies 2024-03-27 18:00:06 +00:00
Nick O'Leary
37265cf4ef Merge pull request #4619 from node-red/4600-reset-workspace-index
Reset workspace index when clearing nodes
2024-03-21 17:38:39 +00:00
Nick O'Leary
8a63275989 Merge pull request #4613 from kazuhitoyokoi/master-fixglobalconfig
Remove typo in global config
2024-03-21 16:54:01 +00:00
Nick O'Leary
7fc64a84e8 Bump test helper 2024-03-21 15:16:49 +00:00
Nick O'Leary
02f7cdd5aa Ensure all httpRequest test servers are ready before tests run 2024-03-21 15:03:37 +00:00
Nick O'Leary
d7dcceef60 Add debug for http tests 2024-03-21 11:32:29 +00:00
Nick O'Leary
ae5e1570ae Reset workspace index when clearing nodes
Fixes #4600
2024-03-21 11:14:34 +00:00
Kazuhito Yokoi
3ca045394a Remove typo in global config 2024-03-16 18:51:13 +09:00
Nick O'Leary
179032cd4d Merge pull request #4608 from node-red/rel317
Bump for 3.1.7 release
2024-03-12 17:43:32 +00:00
Nick O'Leary
6a6f0d04d6 Bump for 3.1.7 release 2024-03-12 14:25:41 +00:00
Nick O'Leary
add4d9758c Merge pull request #4603 from kazuhitoyokoi/master-addjpn
Add Japanese translation for v3.1.6
2024-03-11 16:07:28 +00:00
Kazuhito Yokoi
a0d3ea62b2 Add Japanese translation for v3.1.6 2024-03-10 23:36:20 +09:00
Nick O'Leary
7447e88a50 Merge pull request #4593 from hardillb/hardillb-patch-1
Update jsonata version
2024-03-07 14:26:02 +00:00
Ben Hardill
a193b79d3d Bump jsonata to match utils 2024-03-05 10:31:03 +00:00
Ben Hardill
da380f7464 Update jsonata version
Pulls in fix for CVE-2024-27307
2024-03-05 10:22:49 +00:00
Patrick Wozniak
28907082f1 fix usage of vm.Script() 2024-01-21 02:16:00 +01:00
Patrick Wozniak
f83174c40a fix use of vm.Script by adding new 2024-01-21 01:23:07 +01:00
Patrick Wozniak
ec062d008f replace vm.createScript in favor of vm.Script 2024-01-21 01:13:00 +01:00
Patrick Wozniak
a587655a5a adding pollyfill for vm.createScript
adds support for bun.sh
2024-01-21 01:00:02 +01:00
Mauricio Bonani
3e6f0acf79 Refactor code 2023-10-03 15:42:33 -04:00
Mauricio Bonani
7f93d943d7 Merge remote-tracking branch 'upstream/master' into fix-build-script 2023-10-03 09:04:40 -04:00
Mauricio Bonani
12543d2c2a Ensure all CSS variables are in the output file 2022-07-06 19:06:11 -04:00
40 changed files with 507 additions and 299 deletions

View File

@@ -1,3 +1,47 @@
#### 3.1.10: Maintenance Release
- Include rewired nodes when calculating Modified Flows stop list (#4754) @knolleary
- Fix clone of group env var properties (#4753) @knolleary
- Fix losing links when importing a copy of links into a subflow (#4750) @GogoVega
- Ensure all CSS variables are in the output file (#3743) @bonanitech
- Fix the Sidebar Config is not refreshed after a deploy (#4734) @GogoVega
- Fix checkboxes are not updated when calling `typedInput("value", "")` (#4729) @GogoVega
- Fix panning with middle mouse button on windows 10/11 (#4716) @corentin-sodebo-voile
- Add Japanese translation for sidebar tooltip (#4727) @kazuhitoyokoi
- Translate the number of items selected in the options list (#4730) @GogoVega
- Fix a checkbox should return a Boolean value and not the string `on` (#4715) @GogoVega
- Deleting a grouped node should update the group (#4714) @GogoVega
- Change the Config Node cursor to `pointer` (#4711) @GogoVega
- Add missing tooltips to Sidebar (#4713) @GogoVega
- Allow nodes to return additional history entries in onEditSave (#4710) @knolleary
- Pass full error object in Function node and copy over cause property (#4685) @knolleary
- Replacing vm.createScript in favour of vm.Script (#4534) @patlux
- Avoid login loops when autoLogin enabled but login fails (#4684) @knolleary
- Fix undo of subflow env property edits (#4667) @knolleary
- Fix three error typos in monaco.js (#4660) @JoshuaCWebDeveloper
- docs: Add closing paragraph tag (#4664) @ZJvandeWeg
#### 3.1.9: Maintenance Release
- Prevent subflow being added to itself (#4654) @knolleary
- Fix use of spawn on windows with cmd files (#4652) @knolleary
- Guard refresh of unknown subflow (#4640) @knolleary
- Fix subflow module sending messages to debug sidebar (#4642) @knolleary
#### 3.1.8: Maintenance Release
- Add validation and error handling on subflow instance properties (#4632) @knolleary
- Hide import/export context menu if disabled in theme (#4633) @knolleary
- Show change indicator on subflow tabs (#4631) @knolleary
- Bump dependencies (#4630) @knolleary
- Reset workspace index when clearing nodes (#4619) @knolleary
- Remove typo in global config (#4613) @kazuhitoyokoi
#### 3.1.7: Maintenance Release
- Add Japanese translation for v3.1.6 (#4603) @kazuhitoyokoi
- Update jsonata version (#4593) @hardillb
#### 3.1.6: Maintenance Release #### 3.1.6: Maintenance Release
Editor Editor

View File

@@ -1,6 +1,6 @@
{ {
"name": "node-red", "name": "node-red",
"version": "3.1.6", "version": "3.1.10",
"description": "Low-code programming for event-driven applications", "description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org", "homepage": "https://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -41,7 +41,7 @@
"cors": "2.8.5", "cors": "2.8.5",
"cronosjs": "1.7.1", "cronosjs": "1.7.1",
"denque": "2.1.0", "denque": "2.1.0",
"express": "4.18.2", "express": "4.19.2",
"express-session": "1.17.3", "express-session": "1.17.3",
"form-data": "4.0.0", "form-data": "4.0.0",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
@@ -54,7 +54,7 @@
"is-utf8": "0.2.1", "is-utf8": "0.2.1",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
"jsonata": "1.8.6", "jsonata": "1.8.7",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0", "media-typer": "1.1.0",
"memorystore": "1.6.7", "memorystore": "1.6.7",
@@ -64,7 +64,7 @@
"mqtt": "4.3.7", "mqtt": "4.3.7",
"multer": "1.4.5-lts.1", "multer": "1.4.5-lts.1",
"mustache": "4.2.0", "mustache": "4.2.0",
"node-red-admin": "^3.1.2", "node-red-admin": "^3.1.3",
"node-watch": "0.7.4", "node-watch": "0.7.4",
"nopt": "5.0.0", "nopt": "5.0.0",
"oauth2orize": "1.11.1", "oauth2orize": "1.11.1",
@@ -74,7 +74,7 @@
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"semver": "7.5.4", "semver": "7.5.4",
"tar": "6.1.13", "tar": "6.2.1",
"tough-cookie": "4.1.3", "tough-cookie": "4.1.3",
"uglify-js": "3.17.4", "uglify-js": "3.17.4",
"uuid": "9.0.0", "uuid": "9.0.0",
@@ -112,7 +112,7 @@
"mermaid": "^10.4.0", "mermaid": "^10.4.0",
"minami": "1.2.3", "minami": "1.2.3",
"mocha": "9.2.2", "mocha": "9.2.2",
"node-red-node-test-helper": "^0.3.2", "node-red-node-test-helper": "^0.3.3",
"nodemon": "2.0.20", "nodemon": "2.0.20",
"proxy": "^1.0.2", "proxy": "^1.0.2",
"sass": "1.62.1", "sass": "1.62.1",

View File

@@ -205,9 +205,10 @@ function genericStrategy(adminApp,strategy) {
passport.use(new strategy.strategy(options, verify)); passport.use(new strategy.strategy(options, verify));
adminApp.get('/auth/strategy', adminApp.get('/auth/strategy',
passport.authenticate(strategy.name, {session:false, passport.authenticate(strategy.name, {
session:false,
failureMessage: true, failureMessage: true,
failureRedirect: settings.httpAdminRoot failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
}), }),
completeGenerateStrategyAuth, completeGenerateStrategyAuth,
handleStrategyError handleStrategyError
@@ -221,7 +222,7 @@ function genericStrategy(adminApp,strategy) {
passport.authenticate(strategy.name, { passport.authenticate(strategy.name, {
session:false, session:false,
failureMessage: true, failureMessage: true,
failureRedirect: settings.httpAdminRoot failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
}), }),
completeGenerateStrategyAuth, completeGenerateStrategyAuth,
handleStrategyError handleStrategyError

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-api", "name": "@node-red/editor-api",
"version": "3.1.6", "version": "3.1.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -16,14 +16,14 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/util": "3.1.6", "@node-red/util": "3.1.10",
"@node-red/editor-client": "3.1.6", "@node-red/editor-client": "3.1.10",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.20.2", "body-parser": "1.20.2",
"clone": "2.1.2", "clone": "2.1.2",
"cors": "2.8.5", "cors": "2.8.5",
"express-session": "1.17.3", "express-session": "1.17.3",
"express": "4.18.2", "express": "4.19.2",
"memorystore": "1.6.7", "memorystore": "1.6.7",
"mime": "3.0.0", "mime": "3.0.0",
"multer": "1.4.5-lts.1", "multer": "1.4.5-lts.1",

View File

@@ -719,6 +719,7 @@
"nodeHelp": "Node Help", "nodeHelp": "Node Help",
"showHelp": "Show help", "showHelp": "Show help",
"showInOutline": "Show in outline", "showInOutline": "Show in outline",
"hideTopics": "Hide topics",
"showTopics": "Show topics", "showTopics": "Show topics",
"noHelp": "No help topic selected", "noHelp": "No help topic selected",
"changeLog": "Change Log" "changeLog": "Change Log"
@@ -914,6 +915,8 @@
} }
}, },
"typedInput": { "typedInput": {
"selected": "__count__ selected",
"selected_plural": "__count__ selected",
"type": { "type": {
"str": "string", "str": "string",
"num": "number", "num": "number",

View File

@@ -719,6 +719,7 @@
"nodeHelp": "Aide sur les noeuds", "nodeHelp": "Aide sur les noeuds",
"showHelp": "Afficher l'aide", "showHelp": "Afficher l'aide",
"showInOutline": "Afficher dans les grandes lignes", "showInOutline": "Afficher dans les grandes lignes",
"hideTopics": "Masquer les sujets",
"showTopics": "Afficher les sujets", "showTopics": "Afficher les sujets",
"noHelp": "Aucune rubrique d'aide sélectionnée", "noHelp": "Aucune rubrique d'aide sélectionnée",
"changeLog": "Journal des modifications" "changeLog": "Journal des modifications"
@@ -914,6 +915,8 @@
} }
}, },
"typedInput": { "typedInput": {
"selected": "__count__ sélectionnée",
"selected_plural": "__count__ sélectionnées",
"type": { "type": {
"str": "chaîne de caractères", "str": "chaîne de caractères",
"num": "nombre", "num": "nombre",

View File

@@ -303,7 +303,8 @@
"missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません" "missingType": "不正なフロー - __index__ 番目の要素に'type'プロパティがありません"
}, },
"conflictNotification1": "読み込もうとしているノードのいくつかは、既にワークスペース内に存在しています。", "conflictNotification1": "読み込もうとしているノードのいくつかは、既にワークスペース内に存在しています。",
"conflictNotification2": "読み込むノードを選択し、また既存のノードを置き換えるか、もしくはそれらのコピーを読み込むかも選択してください。" "conflictNotification2": "読み込むノードを選択し、また既存のノードを置き換えるか、もしくはそれらのコピーを読み込むかも選択してください。",
"alreadyExists": "本ノードは既に存在"
}, },
"copyMessagePath": "パスをコピーしました", "copyMessagePath": "パスをコピーしました",
"copyMessageValue": "値をコピーしました", "copyMessageValue": "値をコピーしました",
@@ -718,6 +719,7 @@
"nodeHelp": "ノードヘルプ", "nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示", "showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示", "showInOutline": "アウトラインに表示",
"hideTopics": "トピックを非表示",
"showTopics": "トピックを表示", "showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択", "noHelp": "ヘルプのトピックが未選択",
"changeLog": "更新履歴" "changeLog": "更新履歴"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/editor-client", "name": "@node-red/editor-client",
"version": "3.1.6", "version": "3.1.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -547,12 +547,16 @@ RED.nodes = (function() {
* @param {String} z tab id * @param {String} z tab id
*/ */
checkTabState: function (z) { checkTabState: function (z) {
const ws = workspaces[z] const ws = workspaces[z] || subflows[z]
if (ws) { if (ws) {
const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0 const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0
if (Boolean(ws.contentsChanged) !== contentsChanged) { if (Boolean(ws.contentsChanged) !== contentsChanged) {
ws.contentsChanged = contentsChanged ws.contentsChanged = contentsChanged
RED.events.emit("flows:change", ws); if (ws.type === 'tab') {
RED.events.emit("flows:change", ws);
} else {
RED.events.emit("subflows:change", ws);
}
} }
} }
} }
@@ -1025,7 +1029,22 @@ RED.nodes = (function() {
RED.nodes.registerType("subflow:"+sf.id, { RED.nodes.registerType("subflow:"+sf.id, {
defaults:{ defaults:{
name:{value:""}, name:{value:""},
env:{value:[]} env:{value:[], validate: function(value) {
const errors = []
if (value) {
value.forEach(env => {
const r = RED.utils.validateTypedProperty(env.value, env.type)
if (r !== true) {
errors.push(env.name+': '+r)
}
})
}
if (errors.length === 0) {
return true
} else {
return errors
}
}}
}, },
icon: function() { return sf.icon||"subflow.svg" }, icon: function() { return sf.icon||"subflow.svg" },
category: sf.category || "subflows", category: sf.category || "subflows",
@@ -2360,6 +2379,13 @@ RED.nodes = (function() {
} else { } else {
delete n.g delete n.g
} }
// If importing into a subflow, ensure an outbound-link doesn't get added
if (activeSubflow && /^link /.test(n.type) && n.links) {
n.links = n.links.filter(function(id) {
const otherNode = node_map[id] || RED.nodes.node(id);
return (otherNode && otherNode.z === activeWorkspace);
});
}
for (var d3 in n._def.defaults) { for (var d3 in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d3)) { if (n._def.defaults.hasOwnProperty(d3)) {
if (n._def.defaults[d3].type) { if (n._def.defaults[d3].type) {
@@ -2383,14 +2409,6 @@ RED.nodes = (function() {
} }
} }
} }
// If importing into a subflow, ensure an outbound-link doesn't
// get added
if (activeSubflow && /^link /.test(n.type) && n.links) {
n.links = n.links.filter(function(id) {
const otherNode = node_map[id] || RED.nodes.node(id);
return (otherNode && otherNode.z === activeWorkspace)
});
}
} }
for (i=0;i<new_subflows.length;i++) { for (i=0;i<new_subflows.length;i++) {
n = new_subflows[i]; n = new_subflows[i];

View File

@@ -734,12 +734,12 @@
} }
if (menu.opts.multiple) { if (menu.opts.multiple) {
var selected = {}; var selected = {};
this.value().split(",").forEach(function(f) { this.value().split(",").forEach(function(f) {
selected[f] = true; selected[f] = true;
}) });
menu.find('input[type="checkbox"]').each(function() { menu.find('input[type="checkbox"]').each(function() {
$(this).prop("checked",selected[$(this).data('value')]) $(this).prop("checked", selected[$(this).data('value')] || false);
}) });
} }
@@ -830,7 +830,7 @@
this.input.trigger('change',[this.propertyType,this.value()]); this.input.trigger('change',[this.propertyType,this.value()]);
} }
} else { } else {
this.optionSelectLabel.text(o.length+" selected"); this.optionSelectLabel.text(RED._("typedInput.selected", { count: o.length }));
} }
} }
}, },

View File

@@ -118,10 +118,16 @@ RED.contextMenu = (function () {
onselect: 'core:split-wire-with-link-nodes', onselect: 'core:split-wire-with-link-nodes',
disabled: !canEdit || !hasLinks disabled: !canEdit || !hasLinks
}, },
null, null
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
) )
if (RED.settings.theme("menu.menu-item-import-library", true)) {
insertOptions.push(
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
)
}
if (hasSelection && canEdit) { if (hasSelection && canEdit) {
const nodeOptions = [] const nodeOptions = []
if (!hasMultipleSelection && !isGroup) { if (!hasMultipleSelection && !isGroup) {
@@ -194,8 +200,14 @@ RED.contextMenu = (function () {
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() }, { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() },
{ onselect: 'core:delete-selection', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete }, { onselect: 'core:delete-selection', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete },
{ onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete }, { onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete },
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, )
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") }, if (RED.settings.theme("menu.menu-item-export-library", true)) {
menuItems.push(
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }
)
}
menuItems.push(
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") }
) )
} }

View File

@@ -612,7 +612,10 @@ RED.deploy = (function() {
} }
}); });
RED.nodes.eachSubflow(function (subflow) { RED.nodes.eachSubflow(function (subflow) {
subflow.changed = false; if (subflow.changed) {
subflow.changed = false;
RED.events.emit("subflows:change", subflow);
}
}); });
RED.nodes.eachWorkspace(function (ws) { RED.nodes.eachWorkspace(function (ws) {
if (ws.changed || ws.added) { if (ws.changed || ws.added) {
@@ -628,6 +631,7 @@ RED.deploy = (function() {
// Once deployed, cannot undo back to a clean state // Once deployed, cannot undo back to a clean state
RED.history.markAllDirty(); RED.history.markAllDirty();
RED.view.redraw(); RED.view.redraw();
RED.sidebar.config.refresh();
RED.events.emit("deploy"); RED.events.emit("deploy");
}).fail(function (xhr, textStatus, err) { }).fail(function (xhr, textStatus, err) {
RED.nodes.dirty(true); RED.nodes.dirty(true);

View File

@@ -248,6 +248,8 @@ RED.editor = (function() {
var value = input.val(); var value = input.val();
if (defaults[property].hasOwnProperty("format") && defaults[property].format !== "" && input[0].nodeName === "DIV") { if (defaults[property].hasOwnProperty("format") && defaults[property].format !== "" && input[0].nodeName === "DIV") {
value = input.text(); value = input.text();
} else if (input.attr("type") === "checkbox") {
value = input.prop("checked");
} }
var valid = validateNodeProperty(node, defaults, property,value); var valid = validateNodeProperty(node, defaults, property,value);
if (((typeof valid) === "string") || !valid) { if (((typeof valid) === "string") || !valid) {
@@ -741,9 +743,16 @@ RED.editor = (function() {
} }
try { try {
var rc = editing_node._def.oneditsave.call(editing_node); const rc = editing_node._def.oneditsave.call(editing_node);
if (rc === true) { if (rc === true) {
editState.changed = true; editState.changed = true;
} else if (typeof rc === 'object' && rc !== null ) {
if (rc.changed === true) {
editState.changed = true
}
if (Array.isArray(rc.history) && rc.history.length > 0) {
editState.history = rc.history
}
} }
} catch(err) { } catch(err) {
console.warn("oneditsave",editing_node.id,editing_node.type,err.toString()); console.warn("oneditsave",editing_node.id,editing_node.type,err.toString());
@@ -914,6 +923,17 @@ RED.editor = (function() {
dirty: startDirty dirty: startDirty
} }
if (editing_node.g) {
const group = RED.nodes.group(editing_node.g);
// Don't use RED.group.removeFromGroup as that emits
// a change event on the node - but we're deleting it
const index = group?.nodes.indexOf(editing_node) ?? -1;
if (index > -1) {
group.nodes.splice(index, 1);
RED.group.markDirty(group);
}
}
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.redraw(true); RED.view.redraw(true);
RED.history.push(historyEvent); RED.history.push(historyEvent);
@@ -1015,7 +1035,7 @@ RED.editor = (function() {
} }
}); });
} }
var historyEvent = { let historyEvent = {
t:'edit', t:'edit',
node:editing_node, node:editing_node,
changes:editState.changes, changes:editState.changes,
@@ -1031,6 +1051,15 @@ RED.editor = (function() {
instances:subflowInstances instances:subflowInstances
} }
} }
if (editState.history) {
historyEvent = {
t: 'multi',
events: [ historyEvent, ...editState.history ],
dirty: wasDirty
}
}
RED.history.push(historyEvent); RED.history.push(historyEvent);
} }
editing_node.dirty = true; editing_node.dirty = true;
@@ -1623,8 +1652,8 @@ RED.editor = (function() {
} }
if (!isSameObj(old_env, new_env)) { if (!isSameObj(old_env, new_env)) {
editing_node.env = new_env;
editState.changes.env = editing_node.env; editState.changes.env = editing_node.env;
editing_node.env = new_env;
editState.changed = true; editState.changed = true;
} }

View File

@@ -514,7 +514,7 @@ RED.editor.codeEditor.monaco = (function() {
_monaco.languages.json.jsonDefaults.setDiagnosticsOptions(diagnosticOptions); _monaco.languages.json.jsonDefaults.setDiagnosticsOptions(diagnosticOptions);
if(modeConfiguration) { _monaco.languages.json.jsonDefaults.setModeConfiguration(modeConfiguration); } if(modeConfiguration) { _monaco.languages.json.jsonDefaults.setModeConfiguration(modeConfiguration); }
} catch (error) { } catch (error) {
console.warn("monaco - Error setting up json options", err) console.warn("monaco - Error setting up json options", error)
} }
} }
@@ -526,7 +526,7 @@ RED.editor.codeEditor.monaco = (function() {
if(htmlDefaults) { _monaco.languages.html.htmlDefaults.setOptions(htmlDefaults); } if(htmlDefaults) { _monaco.languages.html.htmlDefaults.setOptions(htmlDefaults); }
if(handlebarDefaults) { _monaco.languages.html.handlebarDefaults.setOptions(handlebarDefaults); } if(handlebarDefaults) { _monaco.languages.html.handlebarDefaults.setOptions(handlebarDefaults); }
} catch (error) { } catch (error) {
console.warn("monaco - Error setting up html options", err) console.warn("monaco - Error setting up html options", error)
} }
} }
@@ -546,7 +546,7 @@ RED.editor.codeEditor.monaco = (function() {
if(lessDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(lessDefaults_modeConfiguration); } if(lessDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(lessDefaults_modeConfiguration); }
if(scssDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(scssDefaults_modeConfiguration); } if(scssDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(scssDefaults_modeConfiguration); }
} catch (error) { } catch (error) {
console.warn("monaco - Error setting up CSS/SCSS/LESS options", err) console.warn("monaco - Error setting up CSS/SCSS/LESS options", error)
} }
} }

View File

@@ -382,9 +382,11 @@ RED.sidebar.config = (function() {
refreshConfigNodeList(); refreshConfigNodeList();
} }
}); });
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes")); RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes")); RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-collapse-all'), RED._("palette.actions.collapse-all"));
RED.popover.tooltip($('#red-ui-sidebar-config-expand-all'), RED._("palette.actions.expand-all"));
} }
function flashConfigNode(el) { function flashConfigNode(el) {

View File

@@ -36,7 +36,13 @@ RED.sidebar.help = (function() {
toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content); toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-button red-ui-button-small selected" href="#"><i class="fa fa-list-ul"></i></a></span>').appendTo(toolbar) $('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-button red-ui-button-small selected" href="#"><i class="fa fa-list-ul"></i></a></span>').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc') var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics")); RED.popover.tooltip(showTOCButton, function () {
if ($(showTOCButton).hasClass('selected')) {
return RED._("sidebar.help.hideTopics");
} else {
return RED._("sidebar.help.showTopics");
}
});
showTOCButton.on("click",function(e) { showTOCButton.on("click",function(e) {
e.preventDefault(); e.preventDefault();
if ($(this).hasClass('selected')) { if ($(this).hasClass('selected')) {
@@ -158,8 +164,10 @@ RED.sidebar.help = (function() {
function refreshSubflow(sf) { function refreshSubflow(sf) {
var item = treeList.treeList('get',"node-type:subflow:"+sf.id); var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
item.subflowLabel = sf._def.label().toLowerCase(); if (item) {
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()})); item.subflowLabel = sf._def.label().toLowerCase();
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
}
} }
function hideTOC() { function hideTOC() {

View File

@@ -646,120 +646,128 @@ RED.view = (function() {
} }
d3.event = event; d3.event = event;
var selected_tool = $(ui.draggable[0]).attr("data-palette-type"); var selected_tool = $(ui.draggable[0]).attr("data-palette-type");
var result = createNode(selected_tool);
if (!result) {
return;
}
var historyEvent = result.historyEvent;
var nn = RED.nodes.add(result.node);
var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
nn.l = showLabel;
}
var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
var helperWidth = ui.helper.width();
var helperHeight = ui.helper.height();
var mousePos = d3.touches(this)[0]||d3.mouse(this);
try { try {
var isLink = (nn.type === "link in" || nn.type === "link out") var result = createNode(selected_tool);
var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink; if (!result) {
return;
var label = RED.utils.getNodeLabel(nn, nn.type);
var labelParts = getLabelParts(label, "red-ui-flow-node-label");
if (hideLabel) {
nn.w = node_height;
nn.h = Math.max(node_height,(nn.outputs || 0) * 15);
} else {
nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) );
nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30);
} }
} catch(err) { var historyEvent = result.historyEvent;
} var nn = RED.nodes.add(result.node);
mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]); var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label");
mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]); if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) {
mousePos[1] /= scaleFactor; nn.l = showLabel;
mousePos[0] /= scaleFactor; }
nn.x = mousePos[0]; var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0));
nn.y = mousePos[1]; var helperWidth = ui.helper.width();
var helperHeight = ui.helper.height();
var mousePos = d3.touches(this)[0]||d3.mouse(this);
var minX = nn.w/2 -5; try {
if (nn.x < minX) { var isLink = (nn.type === "link in" || nn.type === "link out")
nn.x = minX; var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink;
}
var minY = nn.h/2 -5;
if (nn.y < minY) {
nn.y = minY;
}
var maxX = space_width -nn.w/2 +5;
if (nn.x > maxX) {
nn.x = maxX;
}
var maxY = space_height -nn.h +5;
if (nn.y > maxY) {
nn.y = maxY;
}
if (snapGrid) { var label = RED.utils.getNodeLabel(nn, nn.type);
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn); var labelParts = getLabelParts(label, "red-ui-flow-node-label");
nn.x -= gridOffset.x; if (hideLabel) {
nn.y -= gridOffset.y; nn.w = node_height;
} nn.h = Math.max(node_height,(nn.outputs || 0) * 15);
} else {
nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) );
nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30);
}
} catch(err) {
}
var linkToSplice = $(ui.helper).data("splice"); mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]);
if (linkToSplice) { mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]);
spliceLink(linkToSplice, nn, historyEvent) mousePos[1] /= scaleFactor;
} mousePos[0] /= scaleFactor;
nn.x = mousePos[0];
nn.y = mousePos[1];
var minX = nn.w/2 -5;
if (nn.x < minX) {
nn.x = minX;
}
var minY = nn.h/2 -5;
if (nn.y < minY) {
nn.y = minY;
}
var maxX = space_width -nn.w/2 +5;
if (nn.x > maxX) {
nn.x = maxX;
}
var maxY = space_height -nn.h +5;
if (nn.y > maxY) {
nn.y = maxY;
}
if (snapGrid) {
var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn);
nn.x -= gridOffset.x;
nn.y -= gridOffset.y;
}
var linkToSplice = $(ui.helper).data("splice");
if (linkToSplice) {
spliceLink(linkToSplice, nn, historyEvent)
}
var group = $(ui.helper).data("group");
if (group) {
var oldX = group.x;
var oldY = group.y;
RED.group.addToGroup(group, nn);
var moveEvent = null;
if ((group.x !== oldX) ||
(group.y !== oldY)) {
moveEvent = {
t: "move",
nodes: [{n: group,
ox: oldX, oy: oldY,
dx: group.x -oldX,
dy: group.y -oldY}],
dirty: true
};
}
historyEvent = {
t: 'multi',
events: [historyEvent],
var group = $(ui.helper).data("group");
if (group) {
var oldX = group.x;
var oldY = group.y;
RED.group.addToGroup(group, nn);
var moveEvent = null;
if ((group.x !== oldX) ||
(group.y !== oldY)) {
moveEvent = {
t: "move",
nodes: [{n: group,
ox: oldX, oy: oldY,
dx: group.x -oldX,
dy: group.y -oldY}],
dirty: true
}; };
if (moveEvent) {
historyEvent.events.push(moveEvent)
}
historyEvent.events.push({
t: "addToGroup",
group: group,
nodes: nn
})
} }
historyEvent = {
t: 'multi',
events: [historyEvent],
}; RED.history.push(historyEvent);
if (moveEvent) { RED.editor.validateNode(nn);
historyEvent.events.push(moveEvent) RED.nodes.dirty(true);
// auto select dropped node - so info shows (if visible)
clearSelection();
nn.selected = true;
movingSet.add(nn);
updateActiveNodes();
updateSelection();
redraw();
if (nn._def.autoedit) {
RED.editor.edit(nn);
}
} catch (error) {
if (error.code != "NODE_RED") {
RED.notify(RED._("notification.error",{message:error.toString()}),"error");
} else {
RED.notify(RED._("notification.error",{message:error.message}),"error");
} }
historyEvent.events.push({
t: "addToGroup",
group: group,
nodes: nn
})
}
RED.history.push(historyEvent);
RED.editor.validateNode(nn);
RED.nodes.dirty(true);
// auto select dropped node - so info shows (if visible)
clearSelection();
nn.selected = true;
movingSet.add(nn);
updateActiveNodes();
updateSelection();
redraw();
if (nn._def.autoedit) {
RED.editor.edit(nn);
} }
} }
}); });
@@ -1182,6 +1190,7 @@ RED.view = (function() {
if (d3.event.button === 1) { if (d3.event.button === 1) {
// Middle Click pan // Middle Click pan
d3.event.preventDefault();
mouse_mode = RED.state.PANNING; mouse_mode = RED.state.PANNING;
mouse_position = [d3.event.pageX,d3.event.pageY] mouse_position = [d3.event.pageX,d3.event.pageY]
scroll_position = [chart.scrollLeft(),chart.scrollTop()]; scroll_position = [chart.scrollLeft(),chart.scrollTop()];
@@ -6063,14 +6072,19 @@ RED.view = (function() {
function createNode(type, x, y, z) { function createNode(type, x, y, z) {
const wasDirty = RED.nodes.dirty() const wasDirty = RED.nodes.dirty()
var m = /^subflow:(.+)$/.exec(type); var m = /^subflow:(.+)$/.exec(type);
var activeSubflow = z ? RED.nodes.subflow(z) : null; var activeSubflow = (z || RED.workspaces.active()) ? RED.nodes.subflow(z || RED.workspaces.active()) : null;
if (activeSubflow && m) { if (activeSubflow && m) {
var subflowId = m[1]; var subflowId = m[1];
let err
if (subflowId === activeSubflow.id) { if (subflowId === activeSubflow.id) {
throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddSubflowToItself") })) err = new Error(RED._("notification.errors.cannotAddSubflowToItself"))
} else if (RED.nodes.subflowContains(m[1], activeSubflow.id)) {
err = new Error(RED._("notification.errors.cannotAddCircularReference"))
} }
if (RED.nodes.subflowContains(m[1], activeSubflow.id)) { if (err) {
throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddCircularReference") })) err.code = 'NODE_RED'
throw err
} }
} }

View File

@@ -491,6 +491,11 @@ RED.workspaces = (function() {
createWorkspaceTabs(); createWorkspaceTabs();
RED.events.on("sidebar:resize",workspace_tabs.resize); RED.events.on("sidebar:resize",workspace_tabs.resize);
RED.events.on("workspace:clear", () => {
// Reset the index used to generate new flow names
workspaceIndex = 0
})
RED.actions.add("core:show-next-tab",function() { RED.actions.add("core:show-next-tab",function() {
var oldActive = activeWorkspace; var oldActive = activeWorkspace;
workspace_tabs.nextTab(); workspace_tabs.nextTab();
@@ -657,6 +662,9 @@ RED.workspaces = (function() {
RED.events.on("flows:change", (ws) => { RED.events.on("flows:change", (ws) => {
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added)); $("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
}) })
RED.events.on("subflows:change", (ws) => {
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
})
hideWorkspace(); hideWorkspace();
} }

View File

@@ -37,7 +37,6 @@ ul.red-ui-sidebar-node-config-list {
} }
.red-ui-palette-node { .red-ui-palette-node {
// overflow: hidden; // overflow: hidden;
cursor: default;
&.selected { &.selected {
border-color: transparent; border-color: transparent;
box-shadow: 0 0 0 2px var(--red-ui-node-selected-color); box-shadow: 0 0 0 2px var(--red-ui-node-selected-color);

View File

@@ -378,7 +378,7 @@
return { id: id, label: RED.nodes.workspace(id).label } //flow id + name return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
} else { } else {
const instanceNode = RED.nodes.node(id) const instanceNode = RED.nodes.node(id)
const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name) const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8))?.name || instanceNode.type)
return { id: id, label: pathLabel } return { id: id, label: pathLabel }
} }
}) })

View File

@@ -194,27 +194,46 @@
nodeMap[node.links[i]].new = true; nodeMap[node.links[i]].new = true;
} }
} }
var n;
for (var id in nodeMap) { let editHistories = []
let n;
for (let id in nodeMap) {
if (nodeMap.hasOwnProperty(id)) { if (nodeMap.hasOwnProperty(id)) {
n = RED.nodes.node(id); n = RED.nodes.node(id);
if (n) { if (n) {
editHistories.push({
t:'edit',
node: n,
changes: {
links: [...n.links]
},
changed: n.changed
})
if (nodeMap[id].old && !nodeMap[id].new) { if (nodeMap[id].old && !nodeMap[id].new) {
// Removed id // Removed id
i = n.links.indexOf(node.id); i = n.links.indexOf(node.id);
if (i > -1) { if (i > -1) {
n.links.splice(i,1); n.links.splice(i,1);
n.changed = true
n.dirty = true
} }
} else if (!nodeMap[id].old && nodeMap[id].new) { } else if (!nodeMap[id].old && nodeMap[id].new) {
// Added id // Added id
i = n.links.indexOf(id); i = n.links.indexOf(id);
if (i === -1) { if (i === -1) {
n.links.push(node.id); n.links.push(node.id);
n.changed = true
n.dirty = true
} }
} }
} }
} }
} }
if (editHistories.length > 0) {
return {
history: editHistories
}
}
} }
function onAdd() { function onAdd() {
@@ -254,13 +273,14 @@
onEditPrepare(this,"link out"); onEditPrepare(this,"link out");
}, },
oneditsave: function() { oneditsave: function() {
onEditSave(this); const result = onEditSave(this);
// In case the name has changed, ensure any link call nodes on this // In case the name has changed, ensure any link call nodes on this
// tab are redrawn with the updated name // tab are redrawn with the updated name
var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"}); var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"});
localCallNodes.forEach(function(node) { localCallNodes.forEach(function(node) {
node.dirty = true; node.dirty = true;
}); });
return result
}, },
onadd: onAdd, onadd: onAdd,
oneditresize: resizeNodeList oneditresize: resizeNodeList
@@ -329,7 +349,7 @@
onEditPrepare(this,"link in"); onEditPrepare(this,"link in");
}, },
oneditsave: function() { oneditsave: function() {
onEditSave(this); return onEditSave(this);
}, },
oneditresize: resizeNodeList oneditresize: resizeNodeList
}); });
@@ -373,7 +393,7 @@
}, },
oneditsave: function() { oneditsave: function() {
onEditSave(this); return onEditSave(this);
}, },
onadd: onAdd, onadd: onAdd,
oneditresize: resizeNodeList oneditresize: resizeNodeList

View File

@@ -374,7 +374,7 @@ module.exports = function(RED) {
iniOpt.breakOnSigint = true; iniOpt.breakOnSigint = true;
} }
} }
node.script = vm.createScript(functionText, createVMOpt(node, "")); node.script = new vm.Script(functionText, createVMOpt(node, ""));
if (node.fin && (node.fin !== "")) { if (node.fin && (node.fin !== "")) {
var finText = `(function () { var finText = `(function () {
var node = { var node = {
@@ -438,10 +438,9 @@ module.exports = function(RED) {
//store the error in msg to be used in flows //store the error in msg to be used in flows
msg.error = err; msg.error = err;
var line = 0;
var errorMessage;
if (stack.length > 0) { if (stack.length > 0) {
let line = 0;
let errorMessage;
while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) { while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) {
line++; line++;
} }
@@ -455,11 +454,13 @@ module.exports = function(RED) {
errorMessage += " (line "+lineno+", col "+cha+")"; errorMessage += " (line "+lineno+", col "+cha+")";
} }
} }
if (errorMessage) {
err.message = errorMessage
}
} }
if (!errorMessage) { // Pass the whole error object so any additional properties
errorMessage = err.toString(); // (such as cause) are preserved
} done(err);
done(errorMessage);
} }
else if (typeof err === "string") { else if (typeof err === "string") {
done(err); done(err);

View File

@@ -20,6 +20,7 @@ module.exports = function(RED) {
var exec = require('child_process').exec; var exec = require('child_process').exec;
var fs = require('fs'); var fs = require('fs');
var isUtf8 = require('is-utf8'); var isUtf8 = require('is-utf8');
const isWindows = process.platform === 'win32'
function ExecNode(n) { function ExecNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
@@ -85,9 +86,12 @@ module.exports = function(RED) {
} }
}); });
var cmd = arg.shift(); var cmd = arg.shift();
// Since 18.20.2/20.12.2, it is invalid to call spawn on Windows with a .bat/.cmd file
// without using shell: true.
const opts = isWindows ? { ...node.spawnOpt, shell: true } : node.spawnOpt
/* istanbul ignore else */ /* istanbul ignore else */
node.debug(cmd+" ["+arg+"]"); node.debug(cmd+" ["+arg+"]");
child = spawn(cmd,arg,node.spawnOpt); child = spawn(cmd,arg,opts);
node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid}); node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid});
var unknownCommand = (child.pid === undefined); var unknownCommand = (child.pid === undefined);
if (node.timer !== 0) { if (node.timer !== 0) {

View File

@@ -103,7 +103,7 @@
<h4>Automatic mode</h4> <h4>Automatic mode</h4>
<p>Automatic mode uses the <code>parts</code> property of incoming messages to <p>Automatic mode uses the <code>parts</code> property of incoming messages to
determine how the sequence should be joined. This allows it to automatically determine how the sequence should be joined. This allows it to automatically
reverse the action of a <b>split</b> node. reverse the action of a <b>split</b> node.</p>
<h4>Manual mode</h4> <h4>Manual mode</h4>
<p>When configured to join in manual mode, the node is able to join sequences <p>When configured to join in manual mode, the node is able to join sequences

View File

@@ -1,3 +1,3 @@
<script type="text/html" data-help-name="global-config"> <script type="text/html" data-help-name="global-config">
<p>大域的なフローの設定を保持するノード大域的な環境変数の定義を含みます</p> <p>大域的なフローの設定を保持するノード大域的な環境変数の定義を含みます</p>
</script>p </script>

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/nodes", "name": "@node-red/nodes",
"version": "3.1.6", "version": "3.1.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -273,7 +273,7 @@ async function installModule(moduleDetails) {
let extraArgs = triggerPayload.args || []; let extraArgs = triggerPayload.args || [];
let args = ['install', ...extraArgs, installSpec] let args = ['install', ...extraArgs, installSpec]
log.trace(NPM_COMMAND + JSON.stringify(args)); log.trace(NPM_COMMAND + JSON.stringify(args));
return exec.run(NPM_COMMAND, args, { cwd: installDir },true) return exec.run(NPM_COMMAND, args, { cwd: installDir, shell: true },true)
} else { } else {
log.trace("skipping npm install"); log.trace("skipping npm install");
} }

View File

@@ -25,12 +25,15 @@ const registryUtil = require("./util");
const library = require("./library"); const library = require("./library");
const {exec,log,events,hooks} = require("@node-red/util"); const {exec,log,events,hooks} = require("@node-red/util");
const child_process = require('child_process'); const child_process = require('child_process');
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
let installerEnabled = false;
const isWindows = process.platform === 'win32'
const npmCommand = isWindows ? 'npm.cmd' : 'npm';
let installerEnabled = false;
let settings; let settings;
const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/; const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/;
const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/; const slashRe = isWindows ? /\\|[/]/ : /[/]/;
const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//; const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//;
const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/; const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/;
@@ -225,7 +228,7 @@ async function installModule(module,version,url) {
let extraArgs = triggerPayload.args || []; let extraArgs = triggerPayload.args || [];
let args = ['install', ...extraArgs, installName] let args = ['install', ...extraArgs, installName]
log.trace(npmCommand + JSON.stringify(args)); log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{ cwd: installDir}, true) return exec.run(npmCommand,args,{ cwd: installDir, shell: true }, true)
} else { } else {
log.trace("skipping npm install"); log.trace("skipping npm install");
} }
@@ -260,7 +263,7 @@ async function installModule(module,version,url) {
log.warn("------------------------------------------"); log.warn("------------------------------------------");
e = new Error(log._("server.install.install-failed")+": "+err.toString()); e = new Error(log._("server.install.install-failed")+": "+err.toString());
if (err.hook === "postInstall") { if (err.hook === "postInstall") {
return exec.run(npmCommand,["remove",module],{ cwd: installDir}, false).finally(() => { return exec.run(npmCommand,["remove",module],{ cwd: installDir, shell: true }, false).finally(() => {
throw e; throw e;
}) })
} }
@@ -356,7 +359,7 @@ async function getModuleVersionFromNPM(module, version) {
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
child_process.execFile(npmCommand,['info','--json',installName],function(err,stdout,stderr) { child_process.execFile(npmCommand,['info','--json',installName],{ shell: true },function(err,stdout,stderr) {
try { try {
if (!stdout) { if (!stdout) {
log.warn(log._("server.install.install-failed-not-found",{name:module})); log.warn(log._("server.install.install-failed-not-found",{name:module}));
@@ -511,7 +514,7 @@ function uninstallModule(module) {
let extraArgs = triggerPayload.args || []; let extraArgs = triggerPayload.args || [];
let args = ['remove', ...extraArgs, module] let args = ['remove', ...extraArgs, module]
log.trace(npmCommand + JSON.stringify(args)); log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{ cwd: installDir}, true) return exec.run(npmCommand,args,{ cwd: installDir, shell: true }, true)
} else { } else {
log.trace("skipping npm uninstall"); log.trace("skipping npm uninstall");
} }
@@ -578,7 +581,7 @@ async function checkPrereq() {
installerEnabled = false; installerEnabled = false;
} else { } else {
return new Promise(resolve => { return new Promise(resolve => {
child_process.execFile(npmCommand,['-v'],function(err,stdout) { child_process.execFile(npmCommand,['-v'],{ shell: true },function(err,stdout) {
if (err) { if (err) {
log.info(log._("server.palette-editor.npm-not-found")); log.info(log._("server.palette-editor.npm-not-found"));
installerEnabled = false; installerEnabled = false;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/registry", "name": "@node-red/registry",
"version": "3.1.6", "version": "3.1.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -16,11 +16,11 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/util": "3.1.6", "@node-red/util": "3.1.10",
"clone": "2.1.2", "clone": "2.1.2",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"semver": "7.5.4", "semver": "7.5.4",
"tar": "6.1.13", "tar": "6.2.1",
"uglify-js": "3.17.4" "uglify-js": "3.17.4"
} }
} }

View File

@@ -678,6 +678,9 @@ class Flow {
if (logMessage.hasOwnProperty('stack')) { if (logMessage.hasOwnProperty('stack')) {
errorMessage.error.stack = logMessage.stack; errorMessage.error.stack = logMessage.stack;
} }
if (logMessage.hasOwnProperty('cause')) {
errorMessage.error.cause = logMessage.cause;
}
targetCatchNode.receive(errorMessage); targetCatchNode.receive(errorMessage);
handled = true; handled = true;
}); });

View File

@@ -1,5 +1,6 @@
const flowUtil = require("./util"); const flowUtil = require("./util");
const credentials = require("../nodes/credentials"); const credentials = require("../nodes/credentials");
const clone = require("clone");
/** /**
* This class represents a group within the runtime. * This class represents a group within the runtime.

View File

@@ -462,9 +462,8 @@ function stop(type,diff,muteLog,isDeploy) {
if (type === 'nodes') { if (type === 'nodes') {
stopList = diff.changed.concat(diff.removed); stopList = diff.changed.concat(diff.removed);
} else if (type === 'flows') { } else if (type === 'flows') {
stopList = diff.changed.concat(diff.removed).concat(diff.linked); stopList = diff.changed.concat(diff.removed).concat(diff.linked).concat(diff.rewired);
} }
events.emit("flows:stopping",{config: activeConfig, type: type, diff: diff}) events.emit("flows:stopping",{config: activeConfig, type: type, diff: diff})
// Stop the global flow object last // Stop the global flow object last

View File

@@ -106,14 +106,22 @@ async function evaluateEnvProperties(flow, env, credentials) {
result = { value: result, __clone__: true} result = { value: result, __clone__: true}
} }
evaluatedEnv[name] = result evaluatedEnv[name] = result
} else {
evaluatedEnv[name] = undefined
flow.error(`Error evaluating env property '${name}': ${err.toString()}`)
} }
resolve() resolve()
}); });
})) }))
} else { } else {
value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null); try {
if (typeof value === 'object') { value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null);
value = { value: value, __clone__: true} if (typeof value === 'object') {
value = { value: value, __clone__: true}
}
} catch (err) {
value = undefined
flow.error(`Error evaluating env property '${name}': ${err.toString()}`)
} }
} }
evaluatedEnv[name] = value evaluatedEnv[name] = value

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/runtime", "name": "@node-red/runtime",
"version": "3.1.6", "version": "3.1.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "./lib/index.js", "main": "./lib/index.js",
"repository": { "repository": {
@@ -16,11 +16,11 @@
} }
], ],
"dependencies": { "dependencies": {
"@node-red/registry": "3.1.6", "@node-red/registry": "3.1.10",
"@node-red/util": "3.1.6", "@node-red/util": "3.1.10",
"async-mutex": "0.4.0", "async-mutex": "0.4.0",
"clone": "2.1.2", "clone": "2.1.2",
"express": "4.18.2", "express": "4.19.2",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"json-stringify-safe": "5.0.1" "json-stringify-safe": "5.0.1"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@node-red/util", "name": "@node-red/util",
"version": "3.1.6", "version": "3.1.10",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -18,7 +18,7 @@
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"i18next": "21.10.0", "i18next": "21.10.0",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
"jsonata": "1.8.6", "jsonata": "1.8.7",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"moment": "2.29.4", "moment": "2.29.4",
"moment-timezone": "0.5.43" "moment-timezone": "0.5.43"

View File

@@ -1,6 +1,6 @@
{ {
"name": "node-red", "name": "node-red",
"version": "3.1.6", "version": "3.1.10",
"description": "Low-code programming for event-driven applications", "description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org", "homepage": "https://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
@@ -31,15 +31,15 @@
"flow" "flow"
], ],
"dependencies": { "dependencies": {
"@node-red/editor-api": "3.1.6", "@node-red/editor-api": "3.1.10",
"@node-red/runtime": "3.1.6", "@node-red/runtime": "3.1.10",
"@node-red/util": "3.1.6", "@node-red/util": "3.1.10",
"@node-red/nodes": "3.1.6", "@node-red/nodes": "3.1.10",
"basic-auth": "2.0.1", "basic-auth": "2.0.1",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"express": "4.18.2", "express": "4.19.2",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"node-red-admin": "^3.1.2", "node-red-admin": "^3.1.3",
"nopt": "5.0.0", "nopt": "5.0.0",
"semver": "7.5.4" "semver": "7.5.4"
}, },

View File

@@ -13,7 +13,7 @@
// 4. Edit your settings file to set the theme: // 4. Edit your settings file to set the theme:
// editorTheme: { // editorTheme: {
// page: { // page: {
// css: "/path/to/file/generated/by/this/script" // css: '/path/to/file/generated/by/this/script'
// } // }
// } // }
// //
@@ -22,110 +22,69 @@
const os = require("os"); const os = require('os');
const nopt = require("nopt"); const nopt = require('nopt');
const path = require("path"); const path = require('path');
const fs = require("fs-extra"); const fs = require('fs-extra');
const sass = require("sass"); const sass = require('sass');
const knownOpts = { const knownOpts = {
"help": Boolean, 'help': Boolean,
"long": Boolean, 'long': Boolean,
"in": [path], 'in': [path],
"out": [path] 'out': [path]
}; };
const shortHands = { const shortHands = {
"?":["--help"] '?':['--help']
}; };
nopt.invalidHandler = function(k,v,t) {} nopt.invalidHandler = function(k,v,t) {}
const parsedArgs = nopt(knownOpts,shortHands,process.argv,2) const parsedArgs = nopt(knownOpts,shortHands,process.argv,2)
if (parsedArgs.help) { if (parsedArgs.help) {
console.log("Usage: build-custom-theme [-?] [--in FILE] [--out FILE]"); showUsageAndExit(0)
console.log("");
console.log("Options:");
console.log(" --in FILE Custom colors sass file");
console.log(" --out FILE Where you write the result");
console.log(" --long Do not compress the output");
console.log(" -?, --help Show this help");
console.log("");
process.exit();
} }
if (!parsedArgs.in) {
const ruleRegex = /(\$.*?) *: *(\S[\S\s]*?);/g; console.warn('Missing argument: in')
var match; showUsageAndExit(1)
const customColors = {};
if (parsedArgs.in && fs.existsSync(parsedArgs.in)) {
let customColorsFile = fs.readFileSync(parsedArgs.in,"utf-8");
while((match = ruleRegex.exec(customColorsFile)) !== null) {
customColors[match[1]] = match[2];
}
} }
// Load base colours
let colorsFile = fs.readFileSync(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/colors.scss"),"utf-8")
let updatedColors = [];
while((match = ruleRegex.exec(colorsFile)) !== null) {
updatedColors.push(match[1]+": "+(customColors[match[1]]||match[2])+";")
}
(async function() { (async function() {
const tmpDir = os.tmpdir(); const tmpDir = os.tmpdir();
const workingDir = await fs.mkdtemp(`${tmpDir}${path.sep}`); const workingDir = await fs.mkdtemp(`${tmpDir}${path.sep}`);
await fs.copy(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/"),workingDir)
await fs.writeFile(path.join(workingDir,"colors.scss"),updatedColors.join("\n"))
const result = sass.renderSync({ await fs.copy(path.join(__dirname, '../packages/node_modules/@node-red/editor-client/src/sass/'), workingDir);
outputStyle: "expanded", await fs.copyFile(parsedArgs.in, path.join(workingDir,'colors.scss'));
file: path.join(workingDir,"style-custom-theme.scss"),
});
const css = result.css.toString() const output = sass.compile(
const lines = css.split("\n"); path.join(workingDir, 'style-custom-theme.scss'),
const colorCSS = [] {style: parsedArgs.long === true ? 'expanded' : 'compressed'}
const nonColorCSS = []; );
let inKeyFrameBlock = false; const nrPkg = require('../package.json');
lines.forEach(l => {
if (inKeyFrameBlock) {
nonColorCSS.push(l);
if (/^}/.test(l)) {
inKeyFrameBlock = false;
}
} else if (/^@keyframes/.test(l)) {
nonColorCSS.push(l);
inKeyFrameBlock = true;
} else if (!/^ /.test(l)) {
colorCSS.push(l);
nonColorCSS.push(l);
} else if (/color|border|background|fill|stroke|outline|box-shadow/.test(l)) {
colorCSS.push(l);
} else {
nonColorCSS.push(l);
}
});
const nrPkg = require("../package.json");
const now = new Date().toISOString(); const now = new Date().toISOString();
const header = `/*\n* Theme generated with Node-RED ${nrPkg.version} on ${now}\n*/`;
const header = `/*
* Theme generated with Node-RED ${nrPkg.version} on ${now}
*/`;
var output = sass.renderSync({outputStyle: parsedArgs.long?"expanded":"compressed",data:colorCSS.join("\n")});
if (parsedArgs.out) { if (parsedArgs.out) {
await fs.writeFile(parsedArgs.out, header+'\n'+output.css);
await fs.writeFile(parsedArgs.out,header+"\n"+output.css);
} else { } else {
console.log(header); console.log(header);
console.log(output.css.toString()); console.log(output.css.toString());
} }
await fs.remove(workingDir); await fs.remove(workingDir);
})() })()
function showUsageAndExit (exitCode) {
console.log('');
console.log('Usage: build-custom-theme [-?] [--in FILE] [--out FILE]');
console.log('');
console.log('Options:');
console.log(' --in FILE Custom colors sass file');
console.log(' --out FILE Where you write the result');
console.log(' --long Do not compress the output');
console.log(' -?, --help Show this help');
console.log('');
process.exit(exitCode);
}

View File

@@ -390,7 +390,8 @@ describe('function node', function() {
msg.should.have.property('level', helper.log().ERROR); msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', 'n1'); msg.should.have.property('id', 'n1');
msg.should.have.property('type', 'function'); msg.should.have.property('type', 'function');
msg.should.have.property('msg', 'ReferenceError: retunr is not defined (line 2, col 1)'); msg.should.have.property('msg')
msg.msg.message.should.equal('ReferenceError: retunr is not defined (line 2, col 1)');
done(); done();
} catch(err) { } catch(err) {
done(err); done(err);
@@ -659,7 +660,8 @@ describe('function node', function() {
msg.should.have.property('level', helper.log().ERROR); msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', name); msg.should.have.property('id', name);
msg.should.have.property('type', 'function'); msg.should.have.property('type', 'function');
msg.should.have.property('msg', 'Error: Callback must be a function'); msg.should.have.property('msg')
msg.msg.message.should.equal('Callback must be a function');
done(); done();
} }
catch (e) { catch (e) {

View File

@@ -60,6 +60,7 @@ describe('HTTP Request Node', function() {
function startServer(done) { function startServer(done) {
testPort += 1; testPort += 1;
testServer = stoppable(http.createServer(testApp)); testServer = stoppable(http.createServer(testApp));
const promises = []
testServer.listen(testPort,function(err) { testServer.listen(testPort,function(err) {
testSslPort += 1; testSslPort += 1;
console.log("ssl port", testSslPort); console.log("ssl port", testSslPort);
@@ -81,13 +82,17 @@ describe('HTTP Request Node', function() {
*/ */
}; };
testSslServer = stoppable(https.createServer(sslOptions,testApp)); testSslServer = stoppable(https.createServer(sslOptions,testApp));
testSslServer.listen(testSslPort, function(err){ console.log('> start testSslServer')
if (err) { promises.push(new Promise((resolve, reject) => {
console.log(err); testSslServer.listen(testSslPort, function(err){
} else { console.log(' done testSslServer')
console.log("started testSslServer"); if (err) {
} reject(err)
}); } else {
resolve()
}
});
}))
testSslClientPort += 1; testSslClientPort += 1;
var sslClientOptions = { var sslClientOptions = {
@@ -97,10 +102,17 @@ describe('HTTP Request Node', function() {
requestCert: true requestCert: true
}; };
testSslClientServer = stoppable(https.createServer(sslClientOptions, testApp)); testSslClientServer = stoppable(https.createServer(sslClientOptions, testApp));
testSslClientServer.listen(testSslClientPort, function(err){ console.log('> start testSslClientServer')
console.log("ssl-client", err) promises.push(new Promise((resolve, reject) => {
}); testSslClientServer.listen(testSslClientPort, function(err){
console.log(' done testSslClientServer')
if (err) {
reject(err)
} else {
resolve()
}
});
}))
testProxyPort += 1; testProxyPort += 1;
testProxyServer = stoppable(httpProxy(http.createServer())) testProxyServer = stoppable(httpProxy(http.createServer()))
@@ -109,7 +121,17 @@ describe('HTTP Request Node', function() {
res.setHeader("x-testproxy-header", "foobar") res.setHeader("x-testproxy-header", "foobar")
} }
}) })
testProxyServer.listen(testProxyPort) console.log('> testProxyServer')
promises.push(new Promise((resolve, reject) => {
testProxyServer.listen(testProxyPort, function(err) {
console.log(' done testProxyServer')
if (err) {
reject(err)
} else {
resolve()
}
})
}))
testProxyAuthPort += 1 testProxyAuthPort += 1
testProxyServerAuth = stoppable(httpProxy(http.createServer())) testProxyServerAuth = stoppable(httpProxy(http.createServer()))
@@ -131,9 +153,19 @@ describe('HTTP Request Node', function() {
res.setHeader("x-testproxy-header", "foobar") res.setHeader("x-testproxy-header", "foobar")
} }
}) })
testProxyServerAuth.listen(testProxyAuthPort) console.log('> testProxyServerAuth')
promises.push(new Promise((resolve, reject) => {
testProxyServerAuth.listen(testProxyAuthPort, function(err) {
console.log(' done testProxyServerAuth')
if (err) {
reject(err)
} else {
resolve()
}
})
}))
done(err); Promise.all(promises).then(() => { done() }).catch(done)
}); });
} }
@@ -429,7 +461,11 @@ describe('HTTP Request Node', function() {
if (err) { if (err) {
done(err); done(err);
} }
helper.startServer(done); console.log('> helper.startServer')
helper.startServer(function(err) {
console.log('> helper started')
done(err)
});
}); });
}); });

View File

@@ -16,6 +16,31 @@ describe('Group', function () {
group.getSetting("NR_GROUP_NAME").should.equal("g1") group.getSetting("NR_GROUP_NAME").should.equal("g1")
group.getSetting("NR_GROUP_ID").should.equal("group1") group.getSetting("NR_GROUP_ID").should.equal("group1")
}) })
it("returns cloned env var property", async function () {
const group = new Group({
getSetting: v => v+v
}, {
name: "g1",
id: "group1",
env: [
{
name: 'jsonEnvVar',
type: 'json',
value: '{"a":1}'
}
]
})
await group.start()
const result = group.getSetting('jsonEnvVar')
result.should.have.property('a', 1)
result.a = 2
result.b = 'hello'
const result2 = group.getSetting('jsonEnvVar')
result2.should.have.property('a', 1)
result2.should.not.have.property('b')
})
it("delegates to parent if not found", async function () { it("delegates to parent if not found", async function () {
const group = new Group({ const group = new Group({
getSetting: v => v+v getSetting: v => v+v