diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 92a0abb8a..d673df676 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -30,5 +30,5 @@ the [forum](https://discourse.nodered.org) or - [ ] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md) - [ ] For non-bugfix PRs, I have discussed this change on the forum/slack team. -- [ ] I have run `grunt` to verify the unit tests pass +- [ ] I have run `npm run test` to verify the unit tests pass - [ ] I have added suitable unit tests to cover the new/changed functionality diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..ad3a4ca7a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f3c8a6ce..6e66ce5d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,26 +5,29 @@ on: release: types: [published] +permissions: + contents: read + jobs: generate: name: 'Update node-red-docker image' runs-on: ubuntu-latest steps: - name: Check out node-red repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: 'node-red' - name: Check out node-red-docker repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: 'node-red/node-red-docker' path: 'node-red-docker' - name: Check out node-red.github.io repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: 'node-red/node-red.github.io' path: 'node-red.github.io' - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: node-version: '16' - run: node ./node-red/.github/scripts/update-node-red-docker.js diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0db909da6..d89394afa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,16 +6,22 @@ on: pull_request: branches: [ master, dev ] +permissions: + contents: read + jobs: build: + permissions: + checks: write # for coverallsapp/github-action to create new checks + contents: read # for actions/checkout to fetch code runs-on: ubuntu-latest strategy: matrix: - node-version: [14, 16] + node-version: [16, 18, 20] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: Install Dependencies @@ -23,8 +29,8 @@ jobs: - name: Run tests run: | npm run test - - name: Publish to coveralls.io - if: ${{ matrix.node-version == 14 }} - uses: coverallsapp/github-action@v1.1.2 - with: - github-token: ${{ github.token }} + # - name: Publish to coveralls.io + # if: ${{ matrix.node-version == 16 }} + # uses: coverallsapp/github-action@v1.1.2 + # with: + # github-token: ${{ github.token }} diff --git a/.gitignore b/.gitignore index d4c991688..6a2ebfaa1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ docs .vscode .nyc_output sync.ffs_db +package-lock.json diff --git a/.jshintrc b/.jshintrc index 719eecb49..0886c1dc0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -15,5 +15,5 @@ "shadow": true, // allow variable shadowing (re-use of names...) "sub": true, // don't warn that foo['bar'] should be written as foo.bar "proto": true, // allow setting of __proto__ in node < v0.12, - "esversion": 6 // allow es6 + "esversion": 11 // allow es11(ES2020) } diff --git a/CHANGELOG.md b/CHANGELOG.md index fb99d8e0e..26ec431bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,314 @@ +#### 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 + + - Add Japanese translation for 3.1.0 (#4252) @kazuhitoyokoi + - Improve Catalogue visibility (#4248) @Steve-Mcl + - Add support for wiring and moving junctions on touch device (#4244) @Steve-Mcl + - Show errors and statuses of config nodes in the sidebar when no catch node is available (#4231) @bvmensvoort + - Improve wiring for horizontally aligned nodes (#4232) @knolleary + - French translation of Welcome Tours (#4200) @GogoVega + - French translation of v3.1.0-beta.3 changes (#4199) @GogoVega + - add Japanese message for 3.1.0 beta 3 (#4209) @HiroyasuNishiyama + - Dont clone the group nodes `node` array when saving edits (#4208) @Steve-Mcl + + Runtime + + - Add NR_SUBFLOW_NAME/ID/PATH env vars (#4250) @knolleary + - Evaluate all env vars as part of async flow start (#4230) @knolleary + - Add support for httpStatic middleware (#4229) @knolleary + + Nodes + + - Fix JSONata in file nodes (#4246) @kazuhitoyokoi + - Fix timeout icon in function and link call nodes (#4253) @kazuhitoyokoi + - Fix connection keep-alive in http request node (#4228) @knolleary + - adding timeout attribute to function node (#4177) @k1ln + - Fix manual mode join when multiple sequences being handled (#4143) @BitCaesar + - 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 + +Editor + + - Select the item that is specified in a deep link URL (#4113) @Steve-Mcl + - Update to Monaco 0.38.0 (#4189) @Steve-Mcl + - Place subflow outputs/inputs relative to current view (#4183) @knolleary + - Enable RED.view.select to select group by id (#4184) @knolleary + - Combine existing env vars when merging groups (#4182) @knolleary + - Avoid creating empty global-config node if not needed (#4153) @knolleary + - Fix group selection when using lasso (#4108) @knolleary + - Use editor path in generating localStorage keys (#4151) @mw75 + - Ensure no node credentials are included when exporting to clipboard (#4112) @knolleary + - Fix jsonata expression test ui (#4097) @knolleary + - Fix search button in palette popover (#4096) @knolleary + +Runtime + + - Allow options object on each httpStatic configuration (#4109) @kevinGodell + - Ensure non-zero exit codes for errors (#4181) @knolleary + - Ensure external modules are installed synchronously (#4180) @knolleary + - Update dependecies include got (#4155) @knolleary + - Add Japanese translations for v3.1 beta.2 (#4158) @kazuhitoyokoi + - Ensure express server options are applied consistently (#4178) @knolleary + - Remove version info from theme endpoint (#4179) @knolleary + - Add Japanese translations for welcome tour of 3.1.0 beta.2 (#4145) @kazuhitoyokoi + - Added SHA-256 and SHA-512-256 digest authentication (#4100) @sroebert + - Add "timers" types to known types (#4103) @Steve-Mcl + +Nodes + + - Allow Catch/Status nodes to be scoped to their group (#4185) @NetHans + - MQTT: Option to disable MQTT topic unsubscribe on disconnect (#4078) @flying7eleven + + +##### 3.1.0-beta.2: Beta Release + +Editor + + - NEW: Add change icon to tabs (#4068) @knolleary + - NEW: Complete overhaul of Group UX (#4079) @knolleary + - NEW: Add link to node help in node edit dialog footer (#4065) @knolleary + - NEW: Added editor feature for connecting multiple nodes to single node (#4051) @sonntam + - NEW: Increase workspace size to 8000x8000 (#4094) @knolleary + - Ensure node buttons are redrawn when flow lock state is changed (#4091) @knolleary + - Prevent loops being created with junction nodes (#4087) @knolleary + - Prevent opening locked node's edit dialog (#4069) @knolleary + - Reverse direction of tab scroll to expected direction (#4064) @knolleary + - Add cancel operation to editableList (#4077) @HiroyasuNishiyama + - Apply Mermaid diagram for project settings UI (#4054) @kazuhitoyokoi + - Add tooltip for show/hide button on info sidebar (#4050) @kazuhitoyokoi + - Fix align nodes on locked tab (#4072) @HiroyasuNishiyama + - Fix importing connected link nodes into a subflow (#4082) @knolleary + - Fix to add empty marker to empty group (#4060) @HiroyasuNishiyama + - Fix image URLs for v3.0 tour (#4053) @kazuhitoyokoi + - Show scrollbar in notification dialog only when needed (#4048) @kazuhitoyokoi + - Update-monaco-and-typings (#4089) @Steve-Mcl + - Update jquery UI (#4088) @knolleary + - Support i18n of lock/unlock buttons in flow property UI (#4049) @kazuhitoyokoi + - Translation kr (#3895) @hae-iotplatform + - Translation zhcn (!!请懂中文的帮忙review) (#3952) @cliyr + - Add French translation of nodes (#3964) @GogoVega + - Add French translation (#3962) @GogoVega + - Portuguese Brazilian (pt-BR) translation (#3804) @FabsMuller + + +Runtime + + - NEW: Generate stable ids for subflow instance internal nodes (#4093) @knolleary + - NEW: Change default file name to flows.json in project feature (#4073) @kazuhitoyokoi + - NEW: Deprecate synchronous access to jsonata (#4090) @knolleary + - Add Node 18 to test matrix (#4084) @knolleary + - Bump minimum nodejs version supported to match documented value (#4086) @knolleary + - Update monaco docs link in settings.js (#4075) @Steve-Mcl + - Remove duplicated messages in the message catalog (#4066) @kazuhitoyokoi + - Ensure errors in preDeliver callback are handled (#3911) @knolleary + - Fix "EADDRINUSE" error (#4046) @bggbr + +Nodes + + - Link Call: Clear link-call timeouts when node is closed (#4085) @knolleary + - Join: ensure inflight status is cleared when in auto mode (#4083) @knolleary + - 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 + +Editor + + - NEW: Locking Flows (#3938) @knolleary + - NEW: Improve UX around hiding flows via context menu (#3930) @knolleary + - NEW: Add support for inline image in markdown editor by drag and drop of an image file (#4006) @HiroyasuNishiyama + - NEW: Add support for mermaid diagram to markdown editor (#4007) @HiroyasuNishiyama + - NEW: Support uri fragments for nodes and groups including edit support (#3870) @knolleary + - NEW: Add global environment variable feature (#3941) @HiroyasuNishiyama + + - Remember compact/pretty flow export user choice (#3974) @Steve-Mcl + - fix .red-ui-notification class (#4035) @xiaobinqt + - Fix border radius on Modules list header (#4038) @bonanitech + - fix workspace reference error in case of empty tabs (#4029) @HiroyasuNishiyama + - Disable delete tab menu when single tab exists (#4030) @HiroyasuNishiyama + - Disable hide all menu if all tabs hidden (#4031) @HiroyasuNishiyama + - fix hide subflow tooltip (#4033) @HiroyasuNishiyama + - Fix disabled menu items in project feature (#4027) @kazuhitoyokoi + - Let themes change radialMenu text colors (#3995) @bonanitech + - Add Japanese translations for v3.0.3 (#4012) @kazuhitoyokoi + - Add Japanese translation for v3.1.0-beta.0 (#3997) @kazuhitoyokoi + - Add Japanese translation for v3.1.0-beta.0 (#3916) @kazuhitoyokoi + - Hide subflow category after deleting subflow (#3980) @kazuhitoyokoi + - Prevent dbl-click opening node edit dialog with text selected (#3970) @knolleary + - Handle replacing unknown node inside group or subflow (#3921) @knolleary + - Fix #3939, red border red-ui-typedInput-container (#3949) @Steveorevo + - i18n item URL copy notification & add Japanese message (#3946) @HiroyasuNishiyama + - add Japanese message for item url copy actions (#3947) @HiroyasuNishiyama + - Fix autocomplete entry for responseUrl (#3884) @knolleary + - Fix Japanese translation for JSONata editor (#3872) @HiroyasuNishiyama + - Fix search type with spaces (#3841) @Steve-Mcl + - Fix error hanndling of JSONata expression editor for extended functions (#3871) @HiroyasuNishiyama + - Add button type to the adding SSH key button (#3866) @kazuhitoyokoi + - Check radio button as default in project dialog (#3879) @kazuhitoyokoi + - Add $clone as supported function (#3874) @HiroyasuNishiyama + - Env var jsonata (#3807) @HiroyasuNishiyama + - Add Japanese translation for v3.0.2 (#3852) @kazuhitoyokoi + +Runtime + + - Force IPv4 name resolution to have priority (#4019) @dceejay + - Fix async loading of modules containing both nodes and plugins (#3999) @knolleary + - Use main branch as default in project feature (#4036) @kazuhitoyokoi + - Rename package var to avoid strict mode error (#4020) @knolleary + - Fix typos in settings.js (#4013) @ypid + - Ensure credentials object is removed before returning node in getFlow request (#3971) @knolleary + - Ignore commit error in project feature (#3987) @kazuhitoyokoi + - Update dependencies (#3969) @knolleary + - Add check that node sends object rather than primitive type (#3909) @knolleary + - Ensure key_path is quoted in GIT_SSH_COMMAND in case of spaces in pathname (#3912) @knolleary + - Fix nodesDir scan when node package has js/html in sub dir to package.json (#3867) @Steve-Mcl + - Fix file permissions (#3917) @kazuhitoyokoi + - ci: add minimum GitHub token permissions for workflows (#3907) @boahc077 + +Nodes + + - Catch: fix typo in catch.html (#3965) @we11adam + - Change: Fix change node overwriting msg with itself (#3899) @dceejay + - Comment node: Clarify where the text will appear (#4004) @dirkjanfaber + - CSV: change replace to replaceAll (#3990) @dceejay + - CSV node: check header properties for ' and " (#3920) @dceejay + - CSV: Fix for CSV undefined property (#3906) @dceejay + - Delay: let delay node handle both flush then reset (#3898) @dceejay + - Function: Limit number of ports in function node (#3886) @kazuhitoyokoi + - Function: Remove dot from variable name for external module in function node (#3880) @kazuhitoyokoi + - Function: add function node monaco types util and promisify (#3868) @Steve-Mcl + - HTTP In: Ensure msg.req.headers is enumerable (#3908) @knolleary + - HTTP Request: Support form-data arrays (#3991) @hardillb + - HTTP Request: Fix httprequest tests to be more lenient on error message (#3922) @knolleary + - HTTP Request: Add missing property to node object HTTPRequest (#3842) @hardillb + - HTTP Request/Response: Support sortable list on property UI of http request and http response nodes (#3857) @kazuhitoyokoi + - HTTP Response: Ensure statusCode is a number (#3894) @hardillb + - Inject: Allow Inject node to work with async context stores (#4021) @knolleary + - Join/Batch: Add count to join and batch node labels (#4028) @dceejay + - MQTT: Fix birth topic handling in MQTT node (#3905) @Steve-Mcl + - MQTT: Fix pull-down menus of MQTT configuration node (#3890) @kazuhitoyokoi + - MQTT: Prevent invalid mqtt birth topic crashing node-red (#3869) @Steve-Mcl + - MQTT: ensure sessionExpiry(Interval) is applied (#3840) @Steve-Mcl + - MQTT: Fix mqtt nodes not reconnecting on modified-flows deploy (#3992) @knolleary + - MQTT: fix single subscription mqtt node status (#3966) @Steve-Mcl + - Range: Add drop mode to range node (#3935) @dceejay + - Remove done from describe (#3873) @HiroyasuNishiyama + - Split node: avoid duplicate done call for buffer split (#4000) @knolleary + - Status: Fix typo in 25-status.html (#3981) @kazuhitoyokoi + - TCP Node: ensure newline substitution applies to whole message (#4009) @dceejay + - Template: Add information about environment variable to template node (#3882) @kazuhitoyokoi + - Trigger: Hide trigger node repeat send option if sending nothing (#4023) @dceejay + - Watch: fix watch node test on MacOS/ARM (#3942) @HiroyasuNishiyama + +#### 3.0.2: Maintenance Release + +Editor + + - Fix workspace chart bottom property (#3812) @bonanitech + - Update german translation (#3802) @Dennis14e + - Support color reset to the default in subflow and group (#3801) @kazuhitoyokoi + - Allow generateNodeNames to handle names containing regex control chars (#3817) @knolleary + - Hide scrollbars until they're needed (#3808) @bonanitech + - Include junctions/groups when exporting subflows plus related fixes (#3816) @knolleary + - remove console.log (#3820) @Steve-Mcl + +Runtime + + - Register subflow module instance node with parent flow (#3818) @knolleary + +Nodes + + - HTTP Request: Allow HTTP Headers not in spec (#3776) @hardillb + +#### 3.0.1: Maintenance Release + +Editor + + - Allow codeEditor theme to be set even if `codeEditor` is not set in settings.js (#3794) @Steve-Mcl + - Sys info (diagnostics report) amendments (#3793) @Steve-Mcl + - Allow `mode` and `title` to be omitted in `options` argument for `createEditor` (#3791) @Steve-Mcl + - Fix focus issues (#3789) @Steve-Mcl + - Ensure all typedInput buttons have button type set (#3788) @knolleary + - Do not flag hasUsers=false nodes as unused in search (#3787) @knolleary + - Properly position quick-add dialog in all cases (#3786) @knolleary + - Ensure quick-add dialog does not obscure ghost node when shifted (#3785) @knolleary + - Remove use of Object.hasOwn (#3784) @knolleary + +#### 3.0.0: Milestone Release + +Editor + + - Use theme page and header values if settings.js values are not present (#3767) @Steve-Mcl + - Focus editor for undo after some actions in menu (#3759) @kazuhitoyokoi + - Ensure node icon shade has properly rounded corners (#3763) @knolleary + - Fix storing subflow credential type when input has multiple types (#3762) @knolleary + - Ensure global-config and flow-config have info in the hierarchy popover (#3752) @Steve-Mcl + - Include dirty state in history event (#3748) @Steve-Mcl + - Fix display direction of context sub-menu (#3746) @knolleary + - Fix clear pinned paths of debug sidebar menu (#3745) @HiroyasuNishiyama + - prevent exception generating tooltip for deleted nodes (#3742) @Steve-Mcl + - Fix context menu issues ready for v3 beta.5 (#3741) @Steve-Mcl + - Do not generate new node-ids when pasting a cut flow (#3729) @knolleary + - Fix to prevent node from moving out of workspace (#3731) @HiroyasuNishiyama + - Don't let themes change disabled config node background color (#3736) @bonanitech + - Move colors left behind in #3692 to CSS variables (#3737) @bonanitech + - Fix handling of global debug message (#3733) @HiroyasuNishiyama + - Fix label overflow @ config-node palette (#3730) @ralphwetzel + - Fix defaulting to monaco if settings does not contain codeEditor (#3732) @knolleary + - Disable keyboard shortcut mapping when showing Edit[..]Dialog (#3700) @ralphwetzel + - Update add-junction menu to work in more cases (#3727) @knolleary + - Ensure importMap is not null when using import UI (#3723) @Steve-Mcl + - Add Japanese translations for v3.0-beta.4 (#3724) @kazuhitoyokoi + - Fix "split with" on virtual links (#3766) @Steve-Mcl + +Runtime + + - Do not remove unknown credentials of Subflow Modules (#3728) @knolleary + - Add missing entries from beta.4 changelog (#3721) @knolleary + +Nodes + + - Change: Fix change node, not handling from field properly when using context (#3754) @Fadoli + - Link Call: Fix linkcall registry bugs (#3751) @Steve-Mcl + - WebSocket: Fix close timeout of websocket node (#3734) @HiroyasuNishiyama + #### 3.0.0-beta.4: Beta Release Editor @@ -185,528 +496,6 @@ Nodes - Watch: Update Watch node to use node-watch module (#3559 #3569) @knolleary - WebSocket: call done after ws disconnects (#3531) @Steve-Mcl - -#### 2.2.2: Maintenance Release - -Nodes - - - Fix "close timed out" error when performing full deploy or modifying broker node. (#3451) @Steve-Mcl - - -#### 2.2.1: Maintenance Release - -Editor - - - Handle mixed-cased filter terms in keyboard shortcut dialog (#3444) @knolleary - - Prevent duplicate links being added between nodes (#3442) @knolleary - - Fix to hide tooltip after removing subflow tab (#3391) @HiroyasuNishiyama - - Fix node validation to be applied to config node (#3397) @HiroyasuNishiyama - - Fix: Dont add wires to undo buffer twice (#3437) @Steve-Mcl - -Runtime - - - Improve module location parsing (of stack info) when adding hook (#3447) @Steve-Mcl - - Fix substitution of NR_NODE_PATH (#3445) @HiroyasuNishiyama - - Remove console.log when ignoring disabled module (#3439) @knolleary - - Improve "Unexpected Node Error" logging (#3446) @Steve-Mcl - -Nodes - - - Debug: Fix no-prototype-builtins bug in debug node and utils (#3394) @Alkarex - - Delay: Fix Japanese message of delay node (#3434) - - Allow nbRateUnits to be undefined when validating (#3443) @knolleary - - Coding help for recently added node-red Predefined Environment Variables (#3440) @Steve-Mcl - - -#### 2.2.0: Milestone Release - -Editor - - - Add editorTheme.tours property to default settings file (#3375) @knolleary - - Remember Zoom level and Sidebar tab selection between sessions (#3361) @knolleary - - Fix timing issue when merging background changes fixes #3364 (#3373) @Steve-Mcl - - Use a nodes palette label in help tree (#3372) @Steve-Mcl - - Subflow: Add labels to OUTPUT nodes (#3352) @ralphwetzel - - Fix vertical align subflow port (#3370) @knolleary - - Make actions list i18n ready and Japanese translation (#3359) @HiroyasuNishiyama - - Update tour for 2.2.0 (#3378) @knolleary - - Include paletteLabel when building search index (#3380) @Steve-Mcl - - Fix opening/closing subflow template not to make subflow changed (#3382) @HiroyasuNishiyama - - Add Japanese translations for v2.2.0 (#3353, #3381) @kazuhitoyokoi - -Runtime - - - Add support for accessing node id & name as environment variable (#3356) @HiroyasuNishiyama - - Clear context contents when switching projects (#3243) @knolleary - -Nodes - - - MQTT: reject invalid topics (#3374) @Steve-Mcl - - Function: Expose node.path property (#3371) @knolleary - - Function: Update `node` declarations in func.d.ts (#3377) @Steve-Mcl - -#### 2.2.0-beta.1: Beta Release - -Editor - - - Add search history to main search box (#3262) @knolleary - - Check availability of type of config node on deploy (#3304) @k-toumura - - Add wire-slice mode to delete wires with Ctrl-RHClick-Drag (#3340) @knolleary - - Wiring keyboard shortcuts (#3288) @knolleary - - Snap nodes on grid using either edge as reference (#3289) @knolleary - - Detach node action (#3338) @knolleary - - Highlight links when selecting nodes (#3323) @knolleary - - Allow multiple links to be selected by ctrl-click (#3294) @knolleary - -Nodes - - - JSON: Let JSON node attempt to parse buffer if it contains a valid string (#3296) @dceejay - - Remove use of verbose flag in core nodes - and use node.debug level instead (#3300) @dceejay - - TCP: Add TLS option to tcp client nodes (#3307) @dceejay - - WebSocket: Implemented support for Websocket Subprotocols in WS Client Node. (#3333) @tobiasoort - -#### 2.1.6: Maintenance Release - -Editor - - - Revert copy-text change and apply alternative fix (#3363) @knolleary - - Update marked to latest (#3362) @knolleary - - fix to make start of property error tooltip messages aligned (#3358) @HiroyasuNishiyama - -Nodes - - - Inject: fix JSON propety validation of inject node (#3349) @HiroyasuNishiyama - - Delay: fix unit value validation of delay node (#3351) @HiroyasuNishiyama - -#### 2.1.5: Maintenance Release - -Runtime - - - Handle reporting error location when stack is truncated (#3346) @knolleary - - Initialize passport when only adminAuth.tokens is set (#3343) @knolleary - - Add log logging (#3342) @knolleary - -Editor - - - Fix copy buttons on the debug window (another method) (#3331) @kazuhitoyokoi - - Add Japanese translations for hidden flow (#3302) @kazuhitoyokoi - - Improve jsonata legacy mode detection regex (#3345) @knolleary - - Fix generating flow name with incrementing number (#3347) @knolleary - - resume focus after import/export dialog close (#3337) @HiroyasuNishiyama - - Fix findPreviousVisibleTab action (#3321) @knolleary - - Fix storing hidden tab state when not hidden via action (#3312) @knolleary - - Avoid adding empty env properties to tabs/groups (#3311) @knolleary - - Fix hide icon in tour guide (#3301) @kazuhitoyokoi - -Nodes - - - File: Update file node examples according to node name change (#3335) @HiroyasuNishiyama - - Filter (RBE): Fix for filter node narrrowbandEq mode start condition failure (#3339) @dceejay - - Function: Prevent function scrollbar from obscuring expand button (#3348) @knolleary - - Function: load extralibs when expanding monaco. fixes #3319 (#3334) @Steve-Mcl - - Function: Update Function to use correct api to access env vars (#3310) @knolleary - - HTTP Request: Fix basic auth with empty username or password (#3325) @hardillb - - Inject: Fix incorrect clearing of blank payload property in Inject node (#3322) @knolleary - - Link Call: add link call example (#3336) @HiroyasuNishiyama - - WebSocket: Only setup ws client heartbeat once it is connected (#3344) @knolleary - - Update Japanese translations in node help (#3332) @kazuhitoyokoi - -#### 2.1.4: Maintenance Release - -Runtime - - - fix env var access using $parent for groups (#3278) @HiroyasuNishiyama - - Add proper error handling for 404 errors when serving debug files (#3277) @knolleary - - Add Japanese translations for Node-RED v2.1.0-beta.1 (#3179) @kazuhitoyokoi - - Include full user object on login audit events (#3269) @knolleary - - Remove styling from de locale files (#3237) @knolleary - -Editor - - - Change tab hide button icon to an eye and add search option (#3282) @knolleary - - Fix i18n handling of namespaces with spaces in (#3281) @knolleary - - Trigger change event when autoComplete fills in input (#3280) @knolleary - - Apply CN i18n fix (#3279) @knolleary - - fix select menu label of config node to use paletteLabel (#3273) @HiroyasuNishiyama - - fix removed tab not to cause node conflict (#3275) @HiroyasuNishiyama - - Group diff fix (#3239) @knolleary - - Only toggle disabled workspace flag if on activeWorkspace (#3252) @knolleary - - Do not show status for disabled nodes (#3253) @knolleary - - Set dimension value for tour guide (#3265) @kazuhitoyokoi - - Avoid redundant initialisation of TypedInput type (#3263) @knolleary - - Don't let themes change flow port label color (#3270) @bonanitech - - Fix treeList gutter calculation to handle floating gutters (#3238) @knolleary - -Nodes - -- Debug: Handle RegExp types in Debug sidebar (#3251) @knolleary -- Delay: fix 2nd output when in rate limit per topic modes (#3261) @dceejay -- Link: fix to show link target when selected (#3267) @HiroyasuNishiyama -- Inject: Do not modify inject node props in oneditprepare (#3242) @knolleary -- HTTP Request: HTTP Basic Auth should always add : between username and password even if empty (#3236) @hardillb - -#### 2.1.3: Maintenance Release - -Runtime - - - Update gen-publish script to update 'next' tag for main releases - - Add environment variable to enable/disable tours (#3221) @hardillb - - Fix loading non-default language files leaving runtime in wrong locale (#3225) @knolleary - -Editor - - - Refresh editor settings whenever a node is added or enabled (#3227) @knolleary - - Revert spinner css change that made it shrink in some cases (#3229) @knolleary - - Fix import notification message when importing config nodes (#3224) @knolleary - - Handle changing types of TypedInput repeatedly (#3223) @knolleary - - -#### 2.1.2: Maintenance Release - - -Runtime - - - node-red-pi: Remove bash dependency (#3216) @a16bitsysop - -Editor - - - Improved regex for markdown renderer (#3213) @GerwinvBeek - - Fix TypedInput initialisation (#3220) @knolleary - -Nodes - - - MQTT: fix datatype in node config not used. fixes #3215 (#3219) @Steve-Mcl - -#### 2.1.1: Maintenance Release - -Editor - - - Ensure tourGuide popover doesn't fall offscreen (#3212) @knolleary - - Fix issue with old inject nodes that migrated topic to 'string' type (#3210) @knolleary - - Add cache-busting query params to index.mst (#3211) @knolleary - - Fix TypedInput validation of type without options (#3207) @knolleary - -#### 2.1.0: Milestone Release - -Editor - - - Position popover properly on a scrolled page - - Fixes from 2.1.0-beta.2 (#3202) @knolleary - -Nodes - -- Link Out: Fix saving link out node links (#3201) @knolleary - - Switch: Refix #3170 - copy switch rule type when adding new rule - - TCP Request: Add string option to TCP request node output (#3204) @dceejay - -#### 2.1.0-beta.2: Beta Release - -Editor - - - Fix switching projects (#3199) @knolleary - - Use locale setting when installing/enabling node (#3198) @knolleary - - Do not show projects-wecome dialog until welcome tour completes (#3197) @knolleary - - Fix converting selection to subflow (#3196) @knolleary - - Avoid conflicts with native browser cmd-ctrl type shortcuts (#3195) @knolleary - - Ensure message tools stay attached to top-level entry in Debug/Context (#3186) @knolleary - - Ensure tab state updates properly when toggling enable state (#3175) @knolleary - - Improve handling of long labels in TreeList (#3176) @knolleary - - Shift-click tab scroll arrows to jump to start/end (#3177) @knolleary - -Runtime - - - Update package dependencies - - Update to latest node-red-admin - -Nodes - - - Dynamic MQTT connections (#3189) - - Link: Filter out Link Out Return nodes in Link In edit dialog Fixes #3187 - - Link: Fix link call label (#3200) @knolleary - - Debug: Redesign debug filter options and make them persistant (#3183) @knolleary - - Inject: Widen Inject interval box for >1 digit (#3184) @knolleary - - Switch: Fix rule focus when switch 'otherwise' rule is used (#3185) @knolleary - -#### 2.1.0-beta.1: Beta Release - -Editor - - - Add Tour Guide component (#3136) @knolleary - - Allow tabs to be hidden (#3120) @knolleary - - Add align actions to editor (#3110) @knolleary - - Add support of environment variable for tab & group (#3112) @HiroyasuNishiyama - - Add autoComplete widget and add to TypedInput for msg. props (#3171) @knolleary - - Render node documentation to node-red style guide when written in markdown. (#3169) @Steve-Mcl - - Allow colouring of tab icon svg (#3140) @harmonic7 - - Restore tab selection after merging conflicts (#3151) @GerwinvBeek - - Fix serving of theme files on Windows (#3154) @knolleary - - Ensure config-node select inherits width properly from input (#3155) @knolleary - - Do better remembering TypedInput values whilst switching types (#3159) @knolleary - - Update monaco to 0.28.1 (#3153) @knolleary - - Improve themeing of tourGuide (#3161) @knolleary - - Allow a node to specify a filter for the config nodes it can pick from (#3160) @knolleary - - Allow RED.notify.update to modify any notification setting (#3163) @knolleary - - Fix typo in ko editor.json Fixes #3119 - - Improve RED.actions api to ensure actions cannot be overridden - - Ensure treeList row has suitable min-height when no content Fixes #3109 - - Refactor edit dialogs to use separate edit panes - - Ensure type select button is not focussable when TypedInput only has one type - - Place close tab link in front of fade - -Runtime - - - Improve error reporting with oauth login strategies (#3148) @knolleary - - Add allowUpdate feature to externalModules.palette (#3143) @knolleary - - Improve node install error reporting (#3158) @knolleary - - Improve unit test coverage (#3168) @knolleary - - Allow coreNodesDir to be set to false (#3149) @hardillb - - Update package dependencies - - uncaughtException debug improvements (#3146) @renatojuniorrs - -Nodes - - - Change: Add option to deep-clone properties in Change node (#3156) @knolleary - - Delay: Add push to front of rate limit queue. (#3069) @dceejay - - File: Add paletteLabel to file nodes to make read/write more obvious (#3157) @knolleary - - HTTP Request: Extend HTTP request node to log detailed timing information (#3116) @k-toumura - - HTTP Response: Fix sizing of HTTP Response header fields (#3164) @knolleary - - Join: Support for msg.restartTimeout (#3121) @magma1447 - - Link Call: Add Link Call node (#3152) @knolleary - - Switch: Copy previous rule type when adding rule to switch node (#3170) @knolleary - - Delay node: add option to send intermediate messages on separate output (#3166) @knolleary - - Typo in http request set method translation (#3173) @mailsvb - -#### 2.0.6: Maintenance Release - -Editor - - - Fix typo in ko editor.json Fixes #3119 - - Change fade color when hovering an inactive tab (#3106) @bonanitech - - Ensure treeList row has suitable min-height when no content Fixes #3109 - -Runtime - - - Update tar to latest (#3128) @aksswami - - Give passport verify callback the same arity as the original callback (#3117) @dschmidt - - Handle HTTPS Key and certificate as string or buffer (#3115) @bartbutenaers - -#### 2.0.5: Maintenance Release - -Editor - - - Remove default ctrl-enter keybinding from monaco editor Fixes #3093 - -Runtime - - - Update tar dependency - - Add support for maintenance streams in generate-publish-script - - -Nodes - - - Fix regression in Join node when manual joining array with msg.parts present Fixes #3096 - -#### 2.0.4: Maintenance Release - -Editor - - - Fix tab fade CSS for when using themes (#3085) @bonanitech - - Handle just-copied-but-not-deployed node with credentials in editor Fixes #3090 - -Nodes - - - Filter: Fix RBE node handling of default topi property Fixes #3087 - - HTTP Request: Handle partially encoded url query strings in request node - - HTTP Request: Fix support for supplied CA certs (#3089) @hardillb - - HTTP Request: Ensure TLS Cert is used (#3092) @hardillb - - Inject: Fix inject now button unable to send empty props - - Inject: Inject now button success notification should use label with updated props - -#### 2.0.3: Maintenance Release - -Nodes - - - HTML: Fix HTML parsing when body is included in the select tag Fixes #3079 - - HTTP Request: Preserve case of user-provided http headers in request node Fixes #3081 - - HTTP Request: Set decompress to false for HTTP Request to keep 1.x compatibility Fixes #3083 - - HTTP Request: Add unit tests for HTTP Request encodeURI and error response - - HTTP Request: Do not throw HTTP errors in request node Fixes #3082 - - HTTP Request: Ensure uri is properly encoded before passing to got module Fixes #3080 - -#### 2.0.2: Maintenance Release - -Runtime - - - Use file:// url with dynamic import - - Detect if agent-base has patched https.request and undo it Fixes #3072 - -Editor - - - Fix tab fade css because Safari Fixes #3073 - - Fix error closing library dialog with monaco - - Handle other error types in Manage Palette view - - -Nodes - - - HTTP Request node - ignore invalid cookies rather than fail request Fixes #3075 - - Fix msg.reset handling in Delay node Fixes #3074 - -#### 2.0.1: Maintenance Release - -Nodes - - - Function: Ensure default module export is exposed in Function node - -#### 2.0.0: Milestone Release - -**Migration from 1.x** - - - Node-RED now requires Node.js 12.x or later. - - - The following nodes have had significant dependency updates. Unless stated, - they should be fully backward compatible. - - - RBE: Relabelled as 'filter' to make it more discoverable and made part of - the core palette, rather than as a separate module. - - Tail: This node has been removed from the default palette. You can reinstall it - from node-red-node-tail - - HTTP Request: Reimplemented with a different underlying module. We have - tried to maintain 100% functional compatibility, but it is possible - some edge cases remain. - - JSON: The schema validation option no longer supports JSON-Schema draft-04 - - HTML: Its underlying module has had a major version update. Should be fully - backward compatible. - - - `functionExternalModules` is now enabled by default for new installs. - If you have an existing settings file that contains this setting, you will - need to set it to `true` yourself. - - The external modules will now get installed in your Node-RED user directory, - (`~/.node-red`) rather than in a subdirectory. This means all dependencies will - be listed in your top-level `package.json`. If you have existing external modules, - they will get reinstalled to the new location when you first run Node-RED 2.0. - - -Runtime - - - Fix missing dependencies (#3052, #2057) @kazuhitoyokoi - - Ensure node.types is defined if node html file missing - - Fix reporting of type_already_registered error - - Move install location of external modules (#3064) @knolleary - -Editor - - - Update translations (#3063) @kazuhitoyokoi - - Add a slight fade to tab labels that overflow - - Show config node details when selected in outliner - - Fix layout of info outliner for subflow entries - -Nodes - - - Delay: let `msg.flush` specify how many messages to flush from node (#3059) @dceejay - - Function: external modules is now enabled by default (#3065) @knolleary - - Function: external modules now supports both ES6 and CJS modules (#3065) @knolleary - - WebSocket: add option for client node to send automatic pings (#3056) @knolleary - - -##### 2.0.0-beta.2: Beta Release - -Runtime - - - Add `node-red admin init` (via `node-red-admin@2.1.0`) - - Move to GH Actions rather than Travis for build (#3042) @knolleary - -Editor - - - Include hasUser=false config nodes when exporting whole flow (#3048) - - Emit nodes:change for any updated config node when node deleted/added - - Fix padding of compact notification Closes #3045 - - Ensure any html in changelog is escaped before displaying - - Add support for Map/Set property types on Debug (#3040) @knolleary - - Add 'theme' to default settings file - - Add RED.view.annotations api (#3032) @knolleary - - Update monaco editor to V0.25.2 (#3031) @Steve-Mcl - - Lower tray zIndex when overlay tray being opened Fixes #3019 - - Reduce z-Index of Function expand buttons to prevent overlap Part of #3019 - - Ensure RED.clipboard.import displays the right library Fixes #3021 - - Batch messages sent over comms to prevent flooding (#3025) @knolleary - - Allow RED.popover.panel to specify a closeButton to ignore click events on - - Use browser default language for initial page load - - Add css var for node font color - - Fix label padding of toggleButton - - Give sidebar open tab a bit more room for its label - - Various Monaco updates (#3015) @Steve-Mcl - - Log readOnly on startup (#3024) @sammachin - - Translation updates (#3020 #3022) @HiroyasuNishiyama @kazuhitoyokoi - -Nodes - - - HTTP Request: Fix proxy handling (#3044) @hardillb - - HTTP Request: Handle basic auth with @ in username (#3017) @hardillb - - Add Japanese translation for file-in node (#3037 #3039) @kazuhitoyokoi - - File In: Add option for file-in node to include all properties (default off) (#3035) @dceejay - - Exec: add windowsHide option to hide windows under Windows (#3026) @natcl - - Support loading external module sub path Fixes #3023 - -##### 2.0.0-beta.1: Beta Release - - - -Runtime - - - [MAJOR] Set minimum node version to 12. - - [MAJOR] Fix flowfile name to flows.json in settings (#2951) @dceejay - - [MAJOR] Update to latest i18n in editor and runtime (#2940) @knolleary - - [MAJOR] Deprecate usage of httpRoot (#2953) @knolleary - - Add pre/postInstall hooks to npm install handling (#2936) @knolleary - - Add engine-strict flag to npm install args (#2965) @nileio - - Restructure default settings.js to be more organised (#3012) @knolleary - - Ensure httpServerOptions gets applied to ALL the express apps - - Allow RED.settings.set to replace string property with object property - - Update debug tests to handle compact comms format - - Updates to encode/decode message when passed over debug comms link - - Remove all input event listeners on a node once it is closed - - Move hooks to util package - - Rework hooks structure to be a linkedlist - - Update dependencies (#2922) @knolleary - -Editor - - - [MAJOR] Change node id generation to give fixed length values without '.' (#2987) @knolleary - - [MAJOR] Add Monaco code editor (#2971) @Steve-Mcl - - Update to latest Monaco (#3007) @Steve-Mcl - - Update Node-RED Function typings in Monaco (#3008) @Steve-Mcl - - Add css named variables for certain key colours (#2994) @knolleary - - Improve contrast of export dialog JSON font color - - Switch editableList buttons from to ').prependTo(this.uiSelect); + this.selectTrigger = $('').prependTo(this.uiSelect); $('').toggle(this.options.types.length > 1).appendTo(this.selectTrigger); this.selectLabel = $('').appendTo(this.selectTrigger); @@ -570,7 +570,7 @@ }) // explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline' - this.optionSelectTrigger = $('').appendTo(this.uiSelect); + this.optionSelectTrigger = $('').appendTo(this.uiSelect); this.optionSelectLabel = $('').prependTo(this.optionSelectTrigger); // RED.popover.tooltip(this.optionSelectLabel,function() { // return that.optionValue; @@ -591,7 +591,7 @@ that.uiSelect.addClass('red-ui-typedInput-focus'); }); - this.optionExpandButton = $('').appendTo(this.uiSelect); + this.optionExpandButton = $('').appendTo(this.uiSelect); this.optionExpandButtonIcon = $('').appendTo(this.optionExpandButton); this.type(this.typeField.val() || this.options.default||this.typeList[0].value); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js index a8b787ba5..f53e7458e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js @@ -1,25 +1,6 @@ -RED.contextMenu = (function() { +RED.contextMenu = (function () { let menu; - function createMenu() { - // menu = RED.popover.menu({ - // options: [ - // { - // label: 'delete selection', - // onselect: function() { - // RED.actions.invoke('core:delete-selection') - // RED.view.focus() - // } - // }, - // { label: 'world' } - // ], - // width: 200, - // }) - - - - - } function disposeMenu() { $(document).off("mousedown.red-ui-workspace-context-menu"); @@ -32,138 +13,193 @@ RED.contextMenu = (function() { if (menu) { menu.remove() } + let menuItems = [] + if (options.options) { + menuItems = options.options + } else if (options.type === 'workspace') { + const selection = RED.view.selection() + const noSelection = !selection || Object.keys(selection).length === 0 + const hasSelection = (selection.nodes && selection.nodes.length > 0); + const hasMultipleSelection = hasSelection && selection.nodes.length > 1; + const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || []; + const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || []; + const hasLinks = wireLinks.length > 0; + const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1 + const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1 + const canDelete = hasSelection || hasLinks + const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group' + const canEdit = !RED.workspaces.isLocked() + const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g + const isAllGroups = hasSelection && selection.nodes.filter(n => n.type !== 'group').length === 0 + const hasGroup = hasSelection && selection.nodes.filter(n => n.type === 'group' ).length > 0 + const offset = $("#red-ui-workspace-chart").offset() - const selection = RED.view.selection() - const hasSelection = (selection.nodes && selection.nodes.length > 0); - const hasMultipleSelection = hasSelection && selection.nodes.length > 1; - const hasLinks = selection.links && selection.links.length > 0; - const isSingleLink = !hasSelection && hasLinks && selection.links.length === 1 - const isMultipleLinks = !hasSelection && hasLinks && selection.links.length > 1 - const canDelete = hasSelection || hasLinks - const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group' - - const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g - const offset = $("#red-ui-workspace-chart").offset() - - let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft() - let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop() - - if (RED.view.snapGrid) { - const gridSize = RED.view.gridSize() - addX = gridSize*Math.floor(addX/gridSize) - addY = gridSize*Math.floor(addY/gridSize) - } - - const menuItems = [ - { onselect: 'core:show-action-list', onpostselect: function() {} }, - { - label: RED._("contextMenu.insert"), - options: [ - { - label: RED._("contextMenu.node"), - onselect: function() { - RED.view.showQuickAddDialog({ - position: [ addX, addY ], - touchTrigger: true, - splice: isSingleLink?selection.links[0]:undefined, - // spliceMultiple: isMultipleLinks - }) - } - }, - ( hasSelection || hasLinks ) ? { - label: RED._("contextMenu.junction"), - onselect: 'core:split-wires-with-junctions', - disabled: !hasLinks - } : { - label: RED._("contextMenu.junction"), - onselect: function() { - const nn = { - _def: {defaults:{}}, - type: 'junction', - z: RED.workspaces.active(), - id: RED.nodes.id(), - x: addX, - y: addY, - w: 0, h: 0, - outputs: 1, - inputs: 1, - dirty: true - } - const historyEvent = { - dirty: RED.nodes.dirty(), - t:'add', - junctions:[nn] - } - RED.nodes.addJunction(nn); - RED.history.push(historyEvent); - RED.nodes.dirty(true); - RED.view.redraw(true) - } - }, - { - label: RED._("contextMenu.linkNodes"), - onselect: 'core:split-wire-with-link-nodes', - disabled: hasSelection || !hasLinks - } - ] - - + let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft() + let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop() + if (RED.view.snapGrid) { + const gridSize = RED.view.gridSize() + addX = gridSize * Math.floor(addX / gridSize) + addY = gridSize * Math.floor(addY / gridSize) } - ] - // menuItems.push( - // { - // label: (isSingleLink || isMultipleLinks)?'Insert into wire...':'Add node...', - // onselect: function() { - // RED.view.showQuickAddDialog({ - // position: [ options.x - offset.left, options.y - offset.top ], - // touchTrigger: true, - // splice: isSingleLink?selection.links[0]:undefined, - // spliceMultiple: isMultipleLinks - // }) - // } - // }, - // ) - // if (hasLinks && !hasSelection) { - // menuItems.push({ onselect: 'core:split-wires-with-junctions', label: 'Insert junction'}) - // } - menuItems.push( - null, - { onselect: 'core:undo', disabled: RED.history.list().length === 0 }, - { onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 }, - null, - { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection}, - { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection }, - { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() }, - { onselect: 'core:delete-selection', disabled: !canDelete }, - { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, - { onselect: 'core:select-all-nodes' } - ) - if (hasSelection) { + menuItems.push( + { onselect: 'core:show-action-list', onpostselect: function () { } } + ) + + const insertOptions = [] + menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions }) + insertOptions.push( + { + label: RED._("contextMenu.node"), + onselect: function () { + RED.view.showQuickAddDialog({ + position: [addX, addY], + touchTrigger: true, + splice: isSingleLink ? selection.links[0] : undefined, + // spliceMultiple: isMultipleLinks + }) + }, + disabled: !canEdit + }, + (hasLinks) ? { // has least 1 wire selected + label: RED._("contextMenu.junction"), + onselect: 'core:split-wires-with-junctions', + disabled: !canEdit || !hasLinks + } : { + label: RED._("contextMenu.junction"), + onselect: function () { + const nn = { + _def: { defaults: {} }, + type: 'junction', + z: RED.workspaces.active(), + id: RED.nodes.id(), + x: addX, + y: addY, + w: 0, h: 0, + outputs: 1, + inputs: 1, + dirty: true, + moved: true + } + const junction = RED.nodes.addJunction(nn); + const historyEvent = { + dirty: RED.nodes.dirty(), + t: 'add', + junctions: [junction] + } + RED.history.push(historyEvent); + RED.nodes.dirty(true); + RED.view.select({nodes: [junction] }); + RED.view.redraw(true) + }, + disabled: !canEdit + }, + { + label: RED._("contextMenu.linkNodes"), + onselect: 'core:split-wire-with-link-nodes', + disabled: !canEdit || !hasLinks + }, + null, + { onselect: 'core:show-import-dialog', label: RED._('common.label.import')}, + { onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') } + ) + if (hasSelection && canEdit) { + const nodeOptions = [] + if (!hasMultipleSelection && !isGroup) { + nodeOptions.push( + { onselect: 'core:show-node-help' }, + null + ) + } + nodeOptions.push( + { onselect: 'core:enable-selected-nodes' }, + { onselect: 'core:disable-selected-nodes' }, + null, + { onselect: 'core:show-selected-node-labels' }, + { onselect: 'core:hide-selected-node-labels' } + ) + menuItems.push({ + label: RED._('sidebar.info.node'), + options: nodeOptions + }) + menuItems.push({ + label: RED._('sidebar.info.group'), + options: [ + { onselect: 'core:group-selection' }, + { onselect: 'core:ungroup-selection', disabled: !hasGroup }, + ] + }) + if (hasGroup) { + menuItems[menuItems.length - 1].options.push( + { onselect: 'core:merge-selection-to-group', label: RED._("menu.label.groupMergeSelection") } + ) + + } + if (canRemoveFromGroup) { + menuItems[menuItems.length - 1].options.push( + { onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") } + ) + } + menuItems[menuItems.length - 1].options.push( + null, + { onselect: 'core:copy-group-style', disabled: !hasGroup }, + { onselect: 'core:paste-group-style', disabled: !hasGroup} + ) + } + if (canEdit && hasMultipleSelection) { + menuItems.push({ + label: RED._('menu.label.arrange'), + options: [ + { label:RED._("menu.label.alignLeft"), onselect: "core:align-selection-to-left"}, + { label:RED._("menu.label.alignCenter"), onselect: "core:align-selection-to-center"}, + { label:RED._("menu.label.alignRight"), onselect: "core:align-selection-to-right"}, + null, + { label:RED._("menu.label.alignTop"), onselect: "core:align-selection-to-top"}, + { label:RED._("menu.label.alignMiddle"), onselect: "core:align-selection-to-middle"}, + { label:RED._("menu.label.alignBottom"), onselect: "core:align-selection-to-bottom"}, + null, + { label:RED._("menu.label.distributeHorizontally"), onselect: "core:distribute-selection-horizontally"}, + { label:RED._("menu.label.distributeVertically"), onselect: "core:distribute-selection-vertically"} + ] + }) + } + + menuItems.push( null, - isGroup ? - { onselect: 'core:ungroup-selection', disabled: !isGroup } - : { onselect: 'core:group-selection', disabled: !hasSelection } + { onselect: 'core:undo', label: RED._("keyboard.undoChange"), disabled: RED.history.list().length === 0 }, + { onselect: 'core:redo', label: RED._("keyboard.redoChange"), disabled: RED.history.listRedo().length === 0 }, + null, + { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !canEdit || !hasSelection }, + { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection }, + { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() }, + { onselect: 'core:delete-selection', 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 (canRemoveFromGroup) { - menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") }) - } - } + + var direction = "right"; + var MENU_WIDTH = 500; // can not use menu width here + if ((options.x -$(document).scrollLeft()) > + ($(window).width() -MENU_WIDTH)) { + direction = "left"; + } + menu = RED.menu.init({ - direction: 'right', + direction: direction, onpreselect: function() { disposeMenu() }, - onpostselect: function() { + onpostselect: function () { RED.view.focus() }, options: menuItems }); - menu.attr("id","red-ui-workspace-context-menu"); + menu.attr("id", "red-ui-workspace-context-menu"); menu.css({ position: "absolute" }) @@ -174,34 +210,35 @@ RED.contextMenu = (function() { var top = options.y var left = options.x - if (top+menu.height()-$(document).scrollTop() > $(window).height()) { - top -= (top+menu.height())-$(window).height() + 22; + if (top + menu.height() - $(document).scrollTop() > $(window).height()) { + top -= (top + menu.height()) - $(window).height() + 22; } - if (left+menu.width()-$(document).scrollLeft() > $(window).width()) { - left -= (left+menu.width())-$(window).width() + 18; + if (left + menu.width() - $(document).scrollLeft() > $(window).width()) { + left -= (left + menu.width()) - $(window).width() + 18; } menu.css({ - top: top+"px", - left: left+"px" + top: top + "px", + left: left + "px" }) $(".red-ui-menu.red-ui-menu-dropdown").hide(); - $(document).on("mousedown.red-ui-workspace-context-menu", function(evt) { + $(document).on("mousedown.red-ui-workspace-context-menu", function (evt) { if (menu && menu[0].contains(evt.target)) { return } disposeMenu() }); menu.show(); - - // menu.show({ - // target: $('#red-ui-main-container'), - // x: options.x, - // y: options.y - // }) - + // set focus to first item so that pressing escape key closes the menu + $("#red-ui-workspace-context-menu :first(ul) > a").trigger("focus") } - + // Allow escape key hook and other editor events to close context menu + RED.keyboard.add("red-ui-workspace-context-menu", "escape", function () { RED.contextMenu.hide() }) + RED.events.on("editor:open", function () { RED.contextMenu.hide() }); + RED.events.on("search:open", function () { RED.contextMenu.hide() }); + RED.events.on("type-search:open", function () { RED.contextMenu.hide() }); + RED.events.on("actionList:open", function () { RED.contextMenu.hide() }); + RED.events.on("view:selection-changed", function () { RED.contextMenu.hide() }); return { show: show, hide: disposeMenu diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js index 8a8df6837..a09fdeb01 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js @@ -557,7 +557,17 @@ RED.deploy = (function() { } else { RED.notify('

' + RED._("deploy.successfulDeploy") + '

', "success"); } + const flowsToLock = new Set() + function ensureUnlocked(id) { + const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null); + const isLocked = flow ? flow.locked : false; + if (flow && isLocked) { + flow.locked = false; + flowsToLock.add(flow) + } + } RED.nodes.eachNode(function (node) { + ensureUnlocked(node.z) if (node.changed) { node.dirty = true; node.changed = false; @@ -570,7 +580,32 @@ RED.deploy = (function() { delete node.credentials; } }); + RED.nodes.eachGroup(function (node) { + ensureUnlocked(node.z) + if (node.changed) { + node.dirty = true; + node.changed = false; + } + if (node.moved) { + node.dirty = true; + node.moved = false; + } + }) + RED.nodes.eachJunction(function (node) { + ensureUnlocked(node.z) + if (node.changed) { + node.dirty = true; + node.changed = false; + } + if (node.moved) { + node.dirty = true; + node.moved = false; + } + }) RED.nodes.eachConfig(function (confNode) { + if (confNode.z) { + ensureUnlocked(confNode.z) + } confNode.changed = false; if (confNode.credentials) { delete confNode.credentials; @@ -580,8 +615,16 @@ RED.deploy = (function() { subflow.changed = false; }); RED.nodes.eachWorkspace(function (ws) { - ws.changed = false; + if (ws.changed || ws.added) { + ensureUnlocked(ws.z) + ws.changed = false; + delete ws.added + RED.events.emit("flows:change", ws) + } }); + flowsToLock.forEach(flow => { + flow.locked = true + }) // Once deployed, cannot undo back to a clean state RED.history.markAllDirty(); RED.view.redraw(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js b/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js index b6a069ab5..3f73e29aa 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js @@ -989,9 +989,10 @@ RED.diff = (function() { } if (localNode && remoteNode && typeof localNode[d] === "string") { if (/\n/.test(localNode[d]) || /\n/.test(remoteNode[d])) { - $('').on("click", function() { + var textDiff = $('').on("click", function() { showTextDiff(localNode[d],remoteNode[d]); }).appendTo(propertyNameCell); + RED.popover.tooltip(textDiff, RED._("diff.compareChanges")); } } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index fb4c200f5..62ce8dbe9 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -45,11 +45,13 @@ RED.editor = (function() { var hasChanged; if (node.type.indexOf("subflow:")===0) { subflow = RED.nodes.subflow(node.type.substring(8)); - isValid = subflow.valid; - hasChanged = subflow.changed; - if (isValid === undefined) { - isValid = validateNode(subflow); + if (subflow){ + isValid = subflow.valid; hasChanged = subflow.changed; + if (isValid === undefined) { + isValid = validateNode(subflow); + hasChanged = subflow.changed; + } } validationErrors = validateNodeProperties(node, node._def.defaults, node); node.valid = isValid && validationErrors.length === 0; @@ -113,8 +115,9 @@ RED.editor = (function() { var valid = validateNodeProperty(node, definition, prop, properties[prop]); if ((typeof valid) === "string") { result.push(valid); - } - else if(!valid) { + } else if (Array.isArray(valid)) { + result = result.concat(valid) + } else if(!valid) { result.push(prop); } } @@ -163,7 +166,7 @@ RED.editor = (function() { // If the validator takes two arguments, it is a 3.x validator that // can return a String to mean 'invalid' and provide a reason if ((definition[property].validate.length === 2) && - ((typeof valid) === "string")) { + ((typeof valid) === "string") || Array.isArray(valid)) { return valid; } else { // Otherwise, a 2.x returns a truth-like/false-like value that @@ -238,6 +241,7 @@ RED.editor = (function() { var valid = validateNodeProperty(node, defaults, property,value); if (((typeof valid) === "string") || !valid) { input.addClass("input-error"); + input.next(".red-ui-typedInput-container").addClass("input-error"); if ((typeof valid) === "string") { var tooltip = input.data("tooltip"); if (tooltip) { @@ -250,6 +254,7 @@ RED.editor = (function() { } } else { input.removeClass("input-error"); + input.next(".red-ui-typedInput-container").removeClass("input-error"); var tooltip = input.data("tooltip"); if (tooltip) { input.data("tooltip", null); @@ -716,7 +721,10 @@ RED.editor = (function() { if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") { oldValues[d] = editing_node[d]; } else { - oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v; + // Dont clone the group node `nodes` array + if (editing_node.type !== 'group' || d !== "nodes") { + oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v; + } } } } @@ -858,6 +866,7 @@ RED.editor = (function() { function showEditDialog(node, defaultTab) { if (buildingEditDialog) { return } buildingEditDialog = true; + if (node.z && RED.workspaces.isLocked(node.z)) { return } var editing_node = node; var removeInfoEditorOnClose = false; var skipInfoRefreshOnClose = false; @@ -1043,6 +1052,13 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) + var helpButton = $('').on("click", function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.sidebar.help.show(editing_node.type); + }).appendTo(trayFooterLeft); + RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp")); + $('').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({ enabledIcon: "fa-circle-thin", disabledIcon: "fa-ban", @@ -1105,6 +1121,10 @@ RED.editor = (function() { if (editing_node) { RED.sidebar.info.refresh(editing_node); RED.sidebar.help.show(editing_node.type, false); + //ensure focused element is NOT body (for keyboard scope to operate correctly) + if (document.activeElement.tagName === 'BODY') { + $('#red-ui-editor-stack').trigger('focus') + } } } } @@ -1142,6 +1162,8 @@ RED.editor = (function() { var editing_config_node = RED.nodes.node(id); var activeEditPanes = []; + if (editing_config_node && editing_config_node.z && RED.workspaces.isLocked(editing_config_node.z)) { return } + var configNodeScope = ""; // default to global var activeSubflow = RED.nodes.subflow(RED.workspaces.active()); if (activeSubflow) { @@ -1184,6 +1206,13 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) + var helpButton = $('').on("click", function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.sidebar.help.show(editing_config_node.type); + }).appendTo(trayFooterLeft); + RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp")); + $('').prop("checked",!!editing_config_node.d).appendTo(trayFooterLeft).toggleButton({ enabledIcon: "fa-circle-thin", disabledIcon: "fa-ban", @@ -1688,6 +1717,7 @@ RED.editor = (function() { function showEditGroupDialog(group, defaultTab) { if (buildingEditDialog) { return } buildingEditDialog = true; + if (group.z && RED.workspaces.isLocked(group.z)) { return } var editing_node = group; editStack.push(group); RED.view.state(RED.state.EDITING); @@ -1847,11 +1877,15 @@ RED.editor = (function() { workspace.disabled = disabled; $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled); - if (workspace.id === RED.workspaces.active()) { - $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled); - } } + var locked = $("#node-input-locked").prop("checked"); + if (workspace.locked !== locked) { + editState.changes.locked = workspace.locked; + editState.changed = true; + workspace.locked = locked; + $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked); + } if (editState.changed) { var historyEvent = { t: "edit", @@ -1892,6 +1926,7 @@ RED.editor = (function() { var trayBody = tray.find('.red-ui-tray-body'); trayBody.parent().css('overflow','hidden'); var trayFooterLeft = $('').appendTo(trayFooter) + var trayFooterRight = $('').appendTo(trayFooter) var nodeEditPanes = [ 'editor-tab-flow-properties', @@ -1906,6 +1941,18 @@ RED.editor = (function() { disabledIcon: "fa-ban", invertState: true }) + + if (!workspace.hasOwnProperty("locked")) { + workspace.locked = false; + } + $('').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({ + enabledLabel: RED._("common.label.unlocked"), + enabledIcon: "fa-unlock-alt", + disabledLabel: RED._("common.label.locked"), + disabledIcon: "fa-lock", + invertState: true + }) + prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) { activeEditPanes = _activeEditPanes; trayBody.i18n(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js index 7cee2026b..b92881764 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js @@ -45,6 +45,9 @@ selectedCodeEditor = RED.editor.codeEditor[defaultEditor]; initialised = selectedCodeEditor.init(); } + + $('

').appendTo('#red-ui-editor'); + $("#red-ui-image-drop-target").hide(); } function create(options) { @@ -64,6 +67,7 @@ options = {}; } + var editor = null; if (this.editor.type === MONACO) { // compatibility (see above note) if (!options.element && !options.id) { @@ -74,10 +78,14 @@ console.warn("createEditor() options.element or options.id is not valid", options); $("#dialog-form").append('