Merge pull request #5222 from node-red/dev

Merge dev branch to master ahead of 4.1 release
This commit is contained in:
Nick O'Leary
2025-07-29 15:41:43 +01:00
committed by GitHub
137 changed files with 3838 additions and 1237 deletions

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
node-version: [18, 20, 22, 24]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}

View File

@@ -1,3 +1,107 @@
#### 4.1.0-beta.2: Beta Release
Editor
- feat: tray's primary button function will no longer run when clicking anywhere in #red-ui-editor-shade (#5122) @AllanOricil
- Truncate topic of debug message and add tooltip (#5168) @GogoVega
- Add event-log widget to status bar (#5181) @knolleary
- Add `splice` property to nodes:add event context (#5195) @knolleary
- Add support for plugin sources of autoComplete fields (#5194) @knolleary
- setSuggestedFlow api improvements (#5180) @knolleary
- Do not update suggestion whilst typeSearch hiding (#5193) @knolleary
- Update jquery (#5192) @knolleary
- Hide event log status widget by default (#5191) @knolleary
- Swap manage/install-all buttons in dependency notification (#5189) @knolleary
- Follow-up tweaks to HTTP In skip body parser (#5188) @knolleary
- Fixes infotip handling of cursor keys and updates english tip (#5187) @knolleary
- Add Japanese translations for 4.1.0-beta.1 (#5173) @kazuhitoyokoi
- Do not use css display when counting filtered palette nodes (#5178) @knolleary
- Fix `pending_version` not set after module update (#5169) @GogoVega
Runtime
- Prevent library leaking full local paths (#5186) @hardillb
Nodes
- HTTP In: feat: Add an option to the HTTP In to include the raw body. (#5037) @debadutta98
- HTTP Request: Allow limited Strings for msg.rejectUnauthorized (#5172) @hardillb
#### 4.1.0-beta.1: Beta Release
Editor
- Add update notification (#5117) @knolleary
- Add a node annotation if the info property is set (#4955) @knolleary
- Add node suggestion api to editor and apply to typeSearch (#5135) @knolleary
- Node filter support for typedInput's builtin node (#5154) @GogoVega
- Import `got` module only once when sending metrics (#5152) @GogoVega
- Trigger button action of the selected nodes with new Hotkey (#4924) @GogoVega
- Handle deleting of subflow context entries (#5071) @knolleary
- Add the `changed` badge to the config node (#5062) @GogoVega
- Default Palette Search: Sort by Downloads (#5108) @joepavitt
- Show deprecated message if module flagged (#5134) @knolleary
- Add link icon to node docs and warn for major update (#5143) @GogoVega
- Support for a module with nodes and plugins in the palette (#4945) @GogoVega
- Include module list in global-config node when importing/exporting flows (#4599) @knolleary
- Add `Install all` button to the module list feature (#5123) @GogoVega
- Fix node tab filtering (#5119) @knolleary
- Cleanup global Palette Manager variables (#4958) @GogoVega
- Add a new `update available` widget to statusBar (#4948) @knolleary
- Add a queue while installing or removing a module from the Palette Manager (#4937) @GogoVega
- Ignore state of disabled nodes/flows during deployment (#5054) @GogoVega
- Exclude internal properties from node definition (#5144) @GogoVega
- Refresh config node sidebar when changing lock state of a flow (#5072) @knolleary
- Add a border to better distinguish typedInput type/option dropdowns (#5078) @knolleary
- Fix undo of subflow color change not applying to instances (#5012) @GogoVega
- Properly handle scale factor in getLinksAtPoint for firefox (#5087) @knolleary
- Update markdown drop-target appearance (#5059) @knolleary
- Support for disabled flows in Sidebar Config (#5061) @GogoVega
- Support text drag & drop into markdown editor (#5056) @gorenje
- Truncate long messages from the Debug Sidebar (#4944) @GogoVega
- Handle link nodes with show/hide label action (#5106) @knolleary
- Update the Node-RED logo to use the hex variant (#5103) @joepavitt
- Add the vertical marker to the palette hand (#4954) @GogoVega
- Monaco Latest (0.52.0) (#4930) @Steve-Mcl
- Updates monaco to 0.52.0 for action widget sizing fix (#5110) @Steve-Mcl
- Bump Multer to 2.0.1 (#5151) @hardillb
- Upgrade multer to 2.0.0 (#5148) @hardillb
- Update dompurify (#5120) @knolleary
- Colourise the Node-RED logs (#5109) @hardillb
- Only apply colours for non-default log lines (#5129) @knolleary
- feat: import default export if plugin is a transpiled es module (#5137) @dschmidt
- Add an additional git_auth_failed condition (#5145) @sonnyp
- Fix Sass deprecation warnings (#4922) @bonanitech
- chore(editor)!: remove Internet Explorer polyfill (#5070) @Rotzbua
- Remove Internet Explorer CSS hacks (#5142) @bonanitech
Runtime
- fix: set label in themeSettings.deployButton despite type attribute (#5053) @matiseni51
- fix(html): correct buggy html (#4768) @Rotzbua
- Update dev (#4836) @knolleary
- Update dependencies (#5107) @knolleary
- Bump i18next to 24.x and auto-migrate message catalog format (#5088) @knolleary
- chore(editor): update `DOMPurify` flag (#5073) @Rotzbua
- Add .editorconfig to .gitignore (#5060) @gorenje
Nodes
- Complete/Status: Fix complete node to not feedback immediately connected nodes (#5114) @dceejay
- Function: Add URL/URLSearchParams to Function sandbox (#5159) @knolleary
- Function: Add support for node: prefixed modules in function node (#5067) @knolleary
- Function: Add globalFunctionTimeout (#4985) @vasuvanka
- Exec: Make encoding handling consistent between stdout and err (#5158) @knolleary
- Split: Let split node send original msg to complete node (#5113) @dceejay
- Split: Rename Split The field (#5130) @dceejay
- MQTT: Ensure generated mqtt clientId uses only valid chars (#5156) @knolleary
- HTTP Request: Fix the capitisation for ALPN settings in http-request (#5105) @hardillb
- HTTP Request: (docs) Recommend HTTPS over HTTP (#5141) @ZJvandeWeg
- HTTP Request: Include URL query params in HTTP Digest (#5166) @hardillb
- Catch: Add code to error object sent by Catch node (#5081) @knolleary
- Debug: Improve debug display of error objects (#5079) @knolleary
#### 4.0.9: Maintenance Release
Editor

View File

@@ -133,7 +133,6 @@ module.exports = function(grunt) {
src: [
// Ensure editor source files are concatenated in
// the right order
"packages/node_modules/@node-red/editor-client/src/js/polyfills.js",
"packages/node_modules/@node-red/editor-client/src/js/jquery-addons.js",
"packages/node_modules/@node-red/editor-client/src/js/red.js",
"packages/node_modules/@node-red/editor-client/src/js/events.js",
@@ -215,9 +214,9 @@ module.exports = function(grunt) {
files: [
{
src: [
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.5.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.3.0.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-3.7.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-migrate-3.5.2.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui-1.14.1.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js",
"node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.min.js",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "4.0.9",
"version": "4.1.0-beta.2",
"description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org",
"license": "Apache-2.0",
@@ -26,13 +26,14 @@
}
],
"dependencies": {
"acorn": "8.14.1",
"acorn": "8.15.0",
"acorn-walk": "8.3.4",
"ajv": "8.17.1",
"async-mutex": "0.5.0",
"basic-auth": "2.0.1",
"bcryptjs": "3.0.2",
"body-parser": "1.20.3",
"chalk": "^4.1.2",
"cheerio": "1.0.0-rc.10",
"clone": "2.1.2",
"content-type": "1.0.5",
@@ -42,8 +43,8 @@
"cronosjs": "1.7.1",
"denque": "2.1.0",
"express": "4.21.2",
"express-session": "1.18.1",
"form-data": "4.0.2",
"express-session": "1.18.2",
"form-data": "4.0.4",
"fs-extra": "11.3.0",
"got": "12.6.1",
"hash-sum": "2.0.0",
@@ -62,13 +63,13 @@
"moment": "2.30.1",
"moment-timezone": "0.5.48",
"mqtt": "5.11.0",
"multer": "1.4.5-lts.2",
"multer": "2.0.2",
"mustache": "4.2.0",
"node-red-admin": "^4.0.2",
"node-red-admin": "^4.1.1",
"node-watch": "0.7.4",
"nopt": "5.0.0",
"oauth2orize": "1.12.0",
"on-headers": "1.0.2",
"on-headers": "1.1.0",
"passport": "0.7.0",
"passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2",
@@ -86,7 +87,7 @@
"@node-rs/bcrypt": "1.10.7"
},
"devDependencies": {
"dompurify": "2.5.8",
"dompurify": "3.2.6",
"grunt": "1.6.1",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.5.0",
@@ -110,7 +111,7 @@
"jquery-i18next": "1.2.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "4.3.0",
"mermaid": "11.6.0",
"mermaid": "11.9.0",
"minami": "1.2.3",
"mocha": "9.2.2",
"node-red-node-test-helper": "^0.3.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "4.0.9",
"version": "4.1.0-beta.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,17 +16,17 @@
}
],
"dependencies": {
"@node-red/util": "4.0.9",
"@node-red/editor-client": "4.0.9",
"@node-red/util": "4.1.0-beta.2",
"@node-red/editor-client": "4.1.0-beta.2",
"bcryptjs": "3.0.2",
"body-parser": "1.20.3",
"clone": "2.1.2",
"cors": "2.8.5",
"express-session": "1.18.1",
"express-session": "1.18.2",
"express": "4.21.2",
"memorystore": "1.6.7",
"mime": "3.0.0",
"multer": "1.4.5-lts.2",
"multer": "2.0.2",
"mustache": "4.2.0",
"oauth2orize": "1.12.0",
"passport-http-bearer": "1.0.1",

View File

@@ -111,6 +111,7 @@
"userSettings": "User Settings",
"nodes": "Nodes",
"displayStatus": "Show node status",
"displayInfoIcon": "Show node information icon",
"displayConfig": "Configuration nodes",
"import": "Import",
"importExample": "Import example flow",
@@ -264,6 +265,8 @@
"download": "Download",
"importUnrecognised": "Imported unrecognised type:",
"importUnrecognised_plural": "Imported unrecognised types:",
"importWithModuleInfo": "Required modules missing",
"importWithModuleInfoDesc": "These nodes are not currently installed in your palette and are required for the imported flow:",
"importDuplicate": "Imported duplicate node:",
"importDuplicate_plural": "Imported duplicate nodes:",
"nodesExported": "Nodes exported to clipboard",
@@ -570,6 +573,7 @@
"filter": "filter nodes",
"search": "search modules",
"addCategory": "Add new...",
"loadingSuggestions": "Loading suggestions...",
"label": {
"subflows": "subflows",
"network": "network",
@@ -623,12 +627,15 @@
"yearsMonthsV": "__y__ years, __count__ month ago",
"yearsMonthsV_plural": "__y__ years, __count__ months ago"
},
"manageModules": "Manage modules",
"nodeCount": "__label__ node",
"nodeCount_plural": "__label__ nodes",
"pluginCount": "__count__ plugin",
"pluginCount_plural": "__count__ plugins",
"moduleCount": "__count__ module available",
"moduleCount_plural": "__count__ modules available",
"updateCount": "__count__ update available",
"updateCount_plural": "__count__ updates available",
"inuse": "in use",
"enableall": "enable all",
"disableall": "disable all",
@@ -638,9 +645,12 @@
"update": "update to __version__",
"updated": "updated",
"install": "install",
"installAll": "Install all",
"installed": "installed",
"installing": "Module installation in progress: __module__",
"conflict": "conflict",
"conflictTip": "<p>This module cannot be installed as it includes a<br/>node type that has already been installed</p><p>Conflicts with <code>__module__</code></p>",
"majorVersion": "<p>This is a major version update of the node. Check the documentation for details of the update.</p>",
"loading": "Loading catalogues...",
"tab-nodes": "Nodes",
"tab-install": "Install",
@@ -648,9 +658,12 @@
"sortRelevance": "relevance",
"sortAZ": "a-z",
"sortRecent": "recent",
"successfulInstall": "Successfully installed modules",
"more": "+ __count__ more",
"upload": "Upload module tgz file",
"refresh": "Refresh module list",
"deprecated": "deprecated",
"deprecatedTip": "This module has been deprecated",
"errors": {
"catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
"installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
@@ -1273,5 +1286,15 @@
"environment": "Environment",
"header": "Global Environment Variables",
"revert": "Revert"
},
"telemetry": {
"label": "Update Notifications",
"settingsTitle": "Enable Update Notifications",
"settingsDescription": "<p>Node-RED can notify you when there is a new version available. This ensures you keep up to date with the latest features and fixes.</p><p>This requires sending anonymised data back to the Node-RED team. It does not include any details of your flows or users.</p><p>For full information on what information is collected and how it is used, please see the <a href=\"https://nodered.org/docs/telemetry\" target=\"_blank\">documentation</a>.</p>",
"settingsDescription2": "<p>You can change this setting at any time in the User Settings.</p>",
"enableLabel": "Yes, enable notifications",
"disableLabel": "No, do not enable notifications",
"updateAvailable": "Update available",
"updateAvailableDesc": "Node-RED __version__ is now available"
}
}

View File

@@ -6,7 +6,7 @@
"tip3": "You can manage your palette of nodes with {{core:manage-palette}}",
"tip4": "Your flow configuration nodes are listed in the sidebar panel. It can be accessed from the menu or with {{core:show-config-tab}}",
"tip5": "Enable or disable these tips from the option in the settings",
"tip6": "Move the selected nodes using the [left] [up] [down] and [right] keys. Hold [shift] to nudge them further",
"tip6": "Move the selected nodes using the [left] [up] [down] and [right] keys whilst holding [ctrl]. Hold [shift] to nudge them further",
"tip7": "Dragging a node onto a wire will splice it into the link",
"tip8": "Export the selected nodes, or the current tab with {{core:show-export-dialog}}",
"tip9": "Import a flow by dragging its JSON into the editor, or with {{core:show-import-dialog}}",

View File

@@ -6,7 +6,7 @@
"tip3": "Puedes gestionar tu paleta de nodos con {{core:manage-palette}}",
"tip4": "Tus nodos de configuración de flujo aparecen en el panel de la barra lateral. Se puede acceder desde el menú o con {{core:show-config-tab}}",
"tip5": "Activa o desactiva estos consejos desde la opción en la configuración",
"tip6": "Mueve los nodos seleccionados usando las teclas [izquierda] [arriba] [abajo] y [derecha]. Mantén pulsada [Mayús] para desplazarlos más",
"tip6": "Mueve los nodos seleccionados usando las teclas [left] [up] [down] y [right]. Mantén pulsada [shift] para desplazarlos más",
"tip7": "Arrastrar un nodo a un cable lo insertará en el enlace",
"tip8": "Exporta los nodos seleccionados, o la pestaña actual con {{core:show-export-dialog}}",
"tip9": "Importa un flujo arrastrando su JSON al editor, o con {{core:show-import-dialog}}",

View File

@@ -111,6 +111,7 @@
"userSettings": "Paramètres de l'utilisateur",
"nodes": "Noeuds",
"displayStatus": "Afficher l'état du noeud",
"displayInfoIcon": "Afficher l'icône d'information sur le noeud",
"displayConfig": "Noeuds de configuration",
"import": "Importer",
"importExample": "Importer un exemple de flux",
@@ -264,6 +265,8 @@
"download": "Télécharger",
"importUnrecognised": "Importation d'un type inconnu :",
"importUnrecognised_plural": "Importation de plusieurs types inconnus :",
"importWithModuleInfo": "Modules requis manquants",
"importWithModuleInfoDesc": "Ces noeuds ne sont pas actuellement installés dans votre palette et sont requis pour le flux importé :",
"importDuplicate": "Noeud en double importé :",
"importDuplicate_plural": "Noeuds en double importés :",
"nodesExported": "Noeuds exportés vers le presse-papiers",
@@ -623,12 +626,15 @@
"yearsMonthsV": "il y a __y__ ans, __count__ mois",
"yearsMonthsV_plural": "il y a __y__ ans, __count__ mois"
},
"manageModules": "Gérer les modules",
"nodeCount": "__label__ noeud",
"nodeCount_plural": "__label__ noeuds",
"pluginCount": "__count__ plugin",
"pluginCount_plural": "__count__ plugins",
"moduleCount": "__count__ module disponible",
"moduleCount_plural": "__count__ modules disponibles",
"updateCount": "__count__ mise à jour disponible",
"updateCount_plural": "__count__ mises à jour disponibles",
"inuse": "En cours d'utilisation",
"enableall": "Activer tout",
"disableall": "Désactiver tout",
@@ -638,9 +644,12 @@
"update": "Mettre à jour vers __version__",
"updated": "Mis à jour",
"install": "Installer",
"installAll": "Installer tout",
"installed": "Installé",
"installing": "Installation du module en cours : __module__",
"conflict": "Conflit",
"conflictTip": "<p>Ce module ne peut pas être installé car il inclut un<br/>type de noeud qui a déjà été installé</p><p>Conflits avec <code>__module__</code></p>",
"majorVersion": "<p>Il s'agit d'une mise à jour majeure du noeud. Consulter la documentation pour plus de détails sur la mise à jour.</p>",
"loading": "Chargement des catalogues...",
"tab-nodes": "Noeuds",
"tab-install": "Installer",
@@ -648,9 +657,12 @@
"sortRelevance": "Pertinence",
"sortAZ": "A-Z",
"sortRecent": "Récent",
"successfulInstall": "Modules installés avec succès",
"more": "+ __count__ en plus",
"upload": "Charger le fichier .tgz du module",
"refresh": "Actualiser la liste des modules",
"deprecated": "Obsolète",
"deprecatedTip": "Ce module est obsolète",
"errors": {
"catalogLoadFailed": "<p>Échec du chargement du catalogue de noeuds.</p><p>Vérifier la console du navigateur pour plus d'informations</p>",
"installFailed": "<p>Échec lors de l'installation : __module__</p><p>__message__</p><p>Consulter le journal pour plus d'informations</p>",
@@ -1262,6 +1274,16 @@
"header": "Variables d'environnement globales",
"revert": "Rétablir"
},
"telemetry": {
"label": "Notifications de mise à jour",
"settingsTitle": "Activer les notifications de mise à jour",
"settingsDescription": "<p>Node-RED peut vous avertir de la disponibilité d'une nouvelle version. Vous êtes ainsi informé des dernières fonctionnalités et correctifs.</p><p>Cela nécessite d'envoyer des données anonymes à l'équipe Node-RED. Elles n'incluent aucun détail sur vos flux ou vos utilisateurs.</p><p>Pour plus d'informations sur les informations collectées et leur utilisation, veuillez consulter la <a href=\"https://nodered.org/docs/telemetry\" target=\"_blank\">documentation</a>.</p>",
"settingsDescription2": "<p>Vous pouvez modifier ce paramètre à tout moment dans les paramètres de l'utilisateur.</p>",
"enableLabel": "Oui, activer les notifications",
"disableLabel": "Non, ne pas activer les notifications",
"updateAvailable": "Mise(s) à jour disponible(s)",
"updateAvailableDesc": "Node-RED __version__ est désormais disponible"
},
"action-list": {
"toggle-show-tips": "Basculer l'affichage des astuces",
"show-about": "Afficher la description de Node-RED",

View File

@@ -6,7 +6,7 @@
"tip3": "Vous pouvez gérer votre palette de noeuds avec {{core:manage-palette}}",
"tip4": "Vos noeuds de configuration de flux sont répertoriés dans le panneau de la barre latérale. Ils sont accessibles depuis le menu ou avec {{core:show-config-tab}}",
"tip5": "Activer ou désactiver ces conseils à partir de l'option dans les paramètres",
"tip6": "Déplacer les noeuds sélectionnés à l'aide des touches [gauche] [haut] [bas] et [droite]. Maintenir la touche [shift] enfoncée pour les pousser plus loin",
"tip6": "Déplacer les noeuds sélectionnés à l'aide des touches [left] [up] [down] et [right]. Maintenir la touche [shift] enfoncée pour les pousser plus loin",
"tip7": "Faire glisser un noeud sur un fil le raccordera au lien",
"tip8": "Exporter les noeuds sélectionnés, ou l'onglet actuel avec {{core:show-export-dialog}}",
"tip9": "Importer un flux en faisant glisser son JSON dans l'éditeur, ou avec {{core:show-import-dialog}}",

View File

@@ -111,6 +111,7 @@
"userSettings": "ユーザ設定",
"nodes": "ノード",
"displayStatus": "ノードのステータスを表示",
"displayInfoIcon": "ノード情報のアイコンを表示",
"displayConfig": "設定ノード",
"import": "読み込み",
"importExample": "フロー例を読み込み",
@@ -264,6 +265,8 @@
"download": "ダウンロード",
"importUnrecognised": "認識できない型が読み込まれました:",
"importUnrecognised_plural": "認識できない型が読み込まれました:",
"importWithModuleInfo": "必要なモジュールが不足",
"importWithModuleInfoDesc": "以下のノードは現在パレットにインストールされていませんが、読み込んだフローには必要なノードです:",
"importDuplicate": "重複したノードを読み込みました:",
"importDuplicate_plural": "重複したノードを読み込みました:",
"nodesExported": "クリップボードへフローを書き出しました",
@@ -570,6 +573,7 @@
"filter": "ノードを検索",
"search": "ノードを検索",
"addCategory": "新規追加...",
"loadingSuggestions": "提案を読み込み中...",
"label": {
"subflows": "サブフロー",
"network": "ネットワーク",
@@ -623,12 +627,15 @@
"yearsMonthsV": "__y__ 年 __count__ ヵ月前",
"yearsMonthsV_plural": "__y__ 年 __count__ ヵ月前"
},
"manageModules": "モジュールを管理",
"nodeCount": "__label__ 個のノード",
"nodeCount_plural": "__label__ 個のノード",
"pluginCount": "__count__ 個のプラグイン",
"pluginCount_plural": "__count__ 個のプラグイン",
"moduleCount": "__count__ 個のモジュール",
"moduleCount_plural": "__count__ 個のモジュール",
"updateCount": "__count__ 個の更新が存在",
"updateCount_plural": "__count__ 個の更新が存在",
"inuse": "使用中",
"enableall": "全て有効化",
"disableall": "全て無効化",
@@ -638,9 +645,12 @@
"update": "__version__ へ更新",
"updated": "更新済",
"install": "ノードを追加",
"installAll": "全てインストール",
"installed": "追加しました",
"installing": "モジュールのインストールが進行中: __module__",
"conflict": "競合",
"conflictTip": "<p>インストール済みのノードの種別と競合しているため<br/>ノードをインストールできません</p><p>競合: <code>__module__</code></p>",
"majorVersion": "<p>これはノードのメジャーバージョンの更新です。更新内容の詳細については、ドキュメントを確認してください。</p>",
"loading": "カタログを読み込み中",
"tab-nodes": "現在のノード",
"tab-install": "ノードを追加",
@@ -648,9 +658,12 @@
"sortRelevance": "関連順",
"sortAZ": "辞書順",
"sortRecent": "日付順",
"successfulInstall": "モジュールのインストールが成功",
"more": "+ さらに __count__ 個",
"upload": "モジュールのtgzファイルをアップロード",
"refresh": "モジュールリスト更新",
"deprecated": "非推奨",
"deprecatedTip": "本モジュールは非推奨です",
"errors": {
"catalogLoadFailed": "<p>ノードのカタログの読み込みに失敗しました。</p><p>詳細はブラウザのコンソールを確認してください。</p>",
"installFailed": "<p>追加処理が失敗しました: __module__</p><p>__message__</p><p>詳細はログを確認してください。</p>",
@@ -1262,6 +1275,16 @@
"header": "グローバル環境変数",
"revert": "破棄"
},
"telemetry": {
"label": "更新の通知",
"settingsTitle": "更新の通知を有効化",
"settingsDescription": "<p>新バージョンのNode-REDが存在した時に、通知を受けることができます。この機能によって最新機能の提供や修正があることを把握できます。</p><p>この通知を受け取るには、匿名化されたデータをNode-REDチームに送る必要があります。このデータには、フローやユーザの詳細は含まれません。</p><p>収集される情報と利用方法の詳細については、<a href=\"https://nodered.org/docs/telemetry\" target=\"_blank\">ドキュメント</a>を参照してください。</p>",
"settingsDescription2": "<p>この設定はユーザ設定からいつでも変更できます。</p>",
"enableLabel": "はい、通知を有効にします",
"disableLabel": "いいえ、通知を有効にしません",
"updateAvailable": "更新を利用可能",
"updateAvailableDesc": "現在、Node-RED __version__ が利用可能"
},
"action-list": {
"toggle-show-tips": "ヒント表示切替",
"show-about": "Node-REDの説明を表示",
@@ -1302,6 +1325,7 @@
"toggle-show-grid": "グリッド表示切替",
"toggle-snap-grid": "ノードの配置補助切替",
"toggle-status": "ステータス表示切替",
"toggle-node-info-icon": "ノード情報のアイコン表示切替",
"show-selected-node-labels": "選択したノードのラベルを表示",
"hide-selected-node-labels": "選択したノードのラベルを非表示",
"scroll-view-up": "上スクロール",
@@ -1414,6 +1438,7 @@
"show-global-env": "グローバル環境変数を表示",
"lock-flow": "フローを固定",
"unlock-flow": "フローの固定を解除",
"show-node-help": "ノードのヘルプを表示"
"show-node-help": "ノードのヘルプを表示",
"trigger-selected-nodes-action": "選択したノードのアクションを実行"
}
}

View File

@@ -6,15 +6,15 @@
"tip3" : "Вы можете управлять палитрой узлов с помощью {{core:manage-palette}}",
"tip4" : "Узлы конфигурации потока перечисляются на боковой панели. Доступ к списку можно получить из меню или с помощью {{core:show-config-tab}}",
"tip5" : "Эти советы можно включить/выключить через настройки",
"tip6" : "Перемещайте выбранные узлы клавишами [влево] [вверх] [вниз] и [вправо]. Удерживайте [Shift], чтобы увеличить шаг",
"tip6" : "Перемещайте выбранные узлы клавишами [left] [up] [down] и [right]. Удерживайте [shift], чтобы увеличить шаг",
"tip7" : "Перетаскивание узла на провод соединит его с обеих сторон",
"tip8" : "Экспортируйте выбранные узлы или текущую вкладку с {{core:show-export-dialog}}",
"tip9" : "Импортируйте поток, перетаскивая его JSON в редактор или с помощью {{core:show-import-dialog}}",
"tip10" : "Нажмите [Shift], [кликните] по порту узла и перетаскивайте подключенные провода на другой узел",
"tip10" : "Нажмите [shift], [кликните] по порту узла и перетаскивайте подключенные провода на другой узел",
"tip11" : "Открывайте вкладку Информация с {{core:show-info-tab}} или вкладку Отладка с {{core:show-debug-tab}}",
"tip12" : "Нажмите [ctrl] и [кликните] в рабочей области, чтобы открыть диалог быстрого добавления",
"tip13" : "Нажмите [ctrl] и [кликните] по порту узла, чтобы начать быстрое подключение",
"tip14" : "Нажмите [Shift] и [кликните] по узлу, чтобы выбрать все соединенные узлы",
"tip14" : "Нажмите [shift] и [кликните] по узлу, чтобы выбрать все соединенные узлы",
"tip15" : "Нажмите [ctrl] и [кликните] по узлу, чтобы добавить или убрать его из текущего выбора",
"tip16" : "Переключайте вкладки потока с помощью {{core:show-previous-tab}} и {{core:show-next-tab}}",
"tip17" : "Вы можете подтвердить изменения в редакторе узла с {{core:confirm-edit-tray}} или отменить их с {{core:cancel-edit-tray}}",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "4.0.9",
"version": "4.1.0-beta.2",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1 +1,20 @@
<svg width="46.994" height="18.006" xmlns="http://www.w3.org/2000/svg"><g stroke="#d6d6d6"><g fill="#9e3131" stroke-linejoin="round" stroke-width="3.847" transform="matrix(.25848 0 0 .2614 -63.87 -108.483)"><rect x="249.04" y="435.92" width="50.294" height="22.953" ry="6.608"/><rect x="345.63" y="416.93" width="50.294" height="22.953" ry="6.608"/><rect x="376.71" y="459.01" width="50.294" height="22.953" ry="6.608"/></g><path d="M301.04 447.43c24.406.184 7.107-18.84 42.708-19.03M374.82 470.48c-46.966.538-28.989-22.664-73.619-22.944" fill="none" stroke-width="5.771" transform="matrix(.25848 0 0 .2614 -63.87 -108.483)"/></g></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" height="647" width="560" version="1.1" xmlns:cc="http://creativecommons.org/ns#" viewBox="0 0 560.00001 647.00001" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g transform="translate(0 -405.36)">
<g transform="translate(.000014172 .000022107)">
<path opacity="0.98" style="color-rendering:auto;color:#000000;isolation:auto;mix-blend-mode:normal;shape-rendering:auto;solid-color:#000000;image-rendering:auto" d="m280 405.36 280 162.03v323.32l-280 161.69-280-161.7-0.0000055092-323.41z" fill="#8f0000"/>
<path d="m278.57 1019.5-28.122-14.758-219.32-239.19 3.8673-12.478h107.86l19.715-65.534 17.337 24.866 57.948-65.047 47.857-12.857 2.1429 33.571 33.571 3.5714 33.571 0.7143 87.143 2.1428 14.96-70.328 74.709 87.705-2.0935 65.238-115.11 0.0298-1.9844 60.416 120.23 12.653 1.4251 42.694z" fill-opacity=".19898" fill-rule="evenodd"/>
<path opacity="0.98" style="color-rendering:auto;text-decoration-color:#000000;color:#000000;isolation:auto;mix-blend-mode:normal;shape-rendering:auto;solid-color:#000000;block-progression:tb;text-decoration-line:none;text-decoration-style:solid;image-rendering:auto;white-space:normal;text-indent:0;text-transform:none" d="m21.75 766.85v108.15c-0.000146 1.7862 0.95284 3.4368 2.5 4.3301l253.25 145.97c1.5471 0.8927 3.4529 0.8927 5 0l252.86-145.98c1.5472-0.8933 2.6427-2.5439 2.6426-4.3301v-35.361-22.285-50.504-22.281-161.46c0.00015-1.7862-1.0954-3.4368-2.6426-4.3301l-252.86-145.95c-0.72594-0.41802-1.5453-0.64704-2.3828-0.66602-0.91698-0.0221-1.8224 0.20827-2.6172 0.66602l-253.25 145.95c-1.5472 0.8933-2.5001 2.5439-2.5 4.3301v88.68 20.795 51.99zm258.25-323.93l248 143.06v158.38h-99.357c-17.583 0-32.643 14.683-32.643 32.267v4.3203c-59.713-0.44167-77.52-15.896-99.729-35.316-18.46-16.144-41.584-33.808-88.092-41.188 8.6712-8.6968 13.887-18.575 18.533-27.002 4.9936-9.0548 9.5102-16.227 16.734-21.184 5.6262-3.8616 15.231-6.1887 27.666-6.9277v4.0606c0 17.583 13.655 31.97 31.238 31.97h127.3c17.583 0 33.352-14.386 33.352-31.97v-31.279c0-17.583-15.706-31.75-33.289-31.75l-127.3-0.002c-17.583 0-31.301 14.167-31.301 31.75v5.7031c-16.445 0.81071-30.442 4.0316-39.949 10.557-11.762 8.0728-18.195 19.038-23.461 28.586-5.2657 9.5484-9.5828 17.764-15.855 23.518-5.3491 4.9052-12.841 8.2718-25.018 9.8086-1.5749-16.163-15.629-27.827-32.172-27.921h-102.66v-86.38zm22.414 169.44h127.3c5.9367 0 10.289 3.8124 10.289 9.7492v31.279c0 5.9367-4.415 9.9717-10.352 9.9716h-127.3c-5.9367 0-10.766-4.035-10.766-9.9716v-31.279c0-5.9367 4.8916-9.7492 10.828-9.7492zm-270.41 80h102.65c5.9367 0 10.348 4.9199 10.348 10.857v31.281c0 5.9367-4.411 9.8623-10.348 9.8622h-102.65zm135.44 30.243c71.712 1.1287 91.494 19.195 114.55 39.359 22.126 19.349 49.351 39.661 114.01 40.516v5.4297c0 17.583 15.059 31.452 32.643 31.452h99.357v32.747l-248 143.09-248-143.09v-105.75h102.66c17.583 0 32.777-14.277 32.777-31.86zm261.21 43.757h99.355v51h-99.355c-5.9367 0-10.645-4.0661-10.645-10.003v-30.73c0-5.9367 4.7078-10.267 10.645-10.267z" fill="#fff"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 636 B

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -92,7 +92,6 @@
"ctrl-+": "core:zoom-in",
"ctrl--": "core:zoom-out",
"ctrl-0": "core:zoom-reset"
},
"red-ui-editor-stack": {
"ctrl-enter": "core:confirm-edit-tray",

View File

@@ -738,7 +738,7 @@ RED.nodes = (function() {
}
}
function addNode(n) {
function addNode(n, opt) {
let newNode
if (!n.__isProxy__) {
newNode = new Proxy(n, nodeProxyHandler)
@@ -777,7 +777,7 @@ RED.nodes = (function() {
nodeLinks[n.id] = {in:[],out:[]};
}
}
RED.events.emit('nodes:add',newNode);
RED.events.emit('nodes:add',newNode, opt);
return newNode
}
function addLink(l) {
@@ -1543,8 +1543,20 @@ RED.nodes = (function() {
}
/**
* Converts the current node selection to an exportable JSON Object
**/
function createExportableNodeSet(set, exportedIds, exportedSubflows, exportedConfigNodes) {
* @param {Array<Node>} set the node selection to export
* @param {Object} options
* @param {Record<string, boolean>} [options.exportedIds]
* @param {Record<string, boolean>} [options.exportedSubflows]
* @param {Record<string, boolean>} [options.exportedConfigNodes]
* @param {boolean} [options.includeModuleConfig]
* @returns {Array<Node>}
*/
function createExportableNodeSet(set, {
exportedIds,
exportedSubflows,
exportedConfigNodes,
includeModuleConfig = false
} = {}) {
var nns = [];
exportedIds = exportedIds || {};
@@ -1578,7 +1590,7 @@ RED.nodes = (function() {
subflowSet = subflowSet.concat(RED.nodes.junctions(subflowId))
subflowSet = subflowSet.concat(RED.nodes.groups(subflowId))
var exportableSubflow = createExportableNodeSet(subflowSet, exportedIds, exportedSubflows, exportedConfigNodes);
var exportableSubflow = createExportableNodeSet(subflowSet, { exportedIds, exportedSubflows, exportedConfigNodes });
nns = exportableSubflow.concat(nns);
}
}
@@ -1613,19 +1625,27 @@ RED.nodes = (function() {
}
nns.push(convertedNode);
if (node.type === "group") {
nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes));
nns = nns.concat(createExportableNodeSet(node.nodes, { exportedIds, exportedSubflows, exportedConfigNodes }));
}
} else {
var convertedSubflow = convertSubflow(node, { credentials: false });
nns.push(convertedSubflow);
}
}
if (includeModuleConfig) {
updateGlobalConfigModuleList(nns)
}
return nns;
}
// Create the Flow JSON for the current configuration
// opts.credentials (whether to include (known) credentials) - default: true
// opts.dimensions (whether to include node dimensions) - default: false
/**
* Converts the current configuration to an exportable JSON Object
* @param {object} opts
* @param {boolean} [opts.credentials] whether to include (known) credentials. Default `true`.
* @param {boolean} [opts.dimensions] whether to include node dimensions. Default `false`.
* @param {boolean} [opts.includeModuleConfig] whether to include modules. Default `false`.
* @returns {Array<object>}
*/
function createCompleteNodeSet(opts) {
var nns = [];
var i;
@@ -1657,6 +1677,9 @@ RED.nodes = (function() {
RED.nodes.eachNode(function(n) {
nns.push(convertNode(n, opts));
})
if (opts?.includeModuleConfig) {
updateGlobalConfigModuleList(nns);
}
return nns;
}
@@ -1884,14 +1907,26 @@ RED.nodes = (function() {
* - id:import - import as-is
* - id:copy - import with new id
* - id:replace - import over the top of existing
* - modules: map of module:version - hints for unknown nodes
* - applyNodeDefaults - whether to apply default values to the imported nodes (default: false)
* - eventContext - context to include in the `nodes:add` event
*/
function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) {
const defOpts = { generateIds: false, addFlow: false, markChanged: false, reimport: false, importMap: {} }
const defOpts = {
generateIds: false,
addFlow: false,
markChanged: false,
reimport: false,
importMap: {},
applyNodeDefaults: false,
eventContext: null
}
options = Object.assign({}, defOpts, options)
options.importMap = options.importMap || {}
const createNewIds = options.generateIds;
const reimport = (!createNewIds && !!options.reimport)
const createMissingWorkspace = options.addFlow;
const applyNodeDefaults = options.applyNodeDefaults;
var i;
var n;
var newNodes;
@@ -2019,12 +2054,73 @@ RED.nodes = (function() {
}
if (!isInitialLoad && unknownTypes.length > 0) {
var typeList = $("<ul>");
unknownTypes.forEach(function(t) {
$("<li>").text(t).appendTo(typeList);
})
typeList = typeList[0].outerHTML;
RED.notify("<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,"error",false,10000);
const notificationOptions = {
type: "error",
fixed: false,
timeout: 10000,
}
let unknownNotification
let missingModules = []
if (options.modules) {
missingModules = Object.keys(options.modules).filter(module => !RED.nodes.registry.getModule(module))
}
if (missingModules.length > 0) {
notificationOptions.fixed = true
delete notificationOptions.timeout
// We have module hint list from imported global-config
// Provide option to install missing modules
notificationOptions.buttons = [
{
text: RED._("palette.editor.installAll"),
class: "primary",
click: function(e) {
unknownNotification.close();
RED.actions.invoke('core:manage-palette', {
autoInstall: true,
modules: missingModules.reduce((modules, moduleName) => {
modules[moduleName] = options.modules[moduleName];
return modules;
}, {}),
});
}
},
{
text: RED._("palette.editor.manageModules"),
class: "pull-left",
click: function(e) {
unknownNotification.close();
RED.actions.invoke('core:manage-palette', {
view: 'install',
filter: '"' + missingModules.join('", "') + '"'
});
}
}
]
let moduleList = $("<ul>");
missingModules.forEach(function(t) {
$("<li>").text(t).appendTo(moduleList);
})
moduleList = moduleList[0].outerHTML;
unknownNotification = RED.notify(
"<p>"+RED._("clipboard.importWithModuleInfo")+"</p>"+
"<p>"+RED._("clipboard.importWithModuleInfoDesc")+"</p>"+
moduleList,
notificationOptions
);
} else {
var typeList = $("<ul>");
unknownTypes.forEach(function(t) {
$("<li>").text(t).appendTo(typeList);
})
typeList = typeList[0].outerHTML;
unknownNotification = RED.notify(
"<p>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</p>"+typeList,
notificationOptions
);
}
}
var activeWorkspace = RED.workspaces.active();
@@ -2224,6 +2320,13 @@ RED.nodes = (function() {
for (d in def.defaults) {
if (def.defaults.hasOwnProperty(d)) {
configNode[d] = n[d];
if (applyNodeDefaults && n[d] === undefined) {
// If the node has a default value, but the imported node does not
// set it, then set it to the default value
if (def.defaults[d].value !== undefined) {
configNode[d] = JSON.parse(JSON.stringify(def.defaults[d].value))
}
}
configNode._config[d] = JSON.stringify(n[d]);
if (def.defaults[d].type) {
configNode._configNodeReferences.add(n[d])
@@ -2452,6 +2555,9 @@ RED.nodes = (function() {
delete node.z;
}
}
const unknownTypeDef = RED.nodes.getType('unknown')
node._def.oneditprepare = unknownTypeDef.oneditprepare
var orig = {};
for (var p in n) {
if (n.hasOwnProperty(p) && p!="x" && p!="y" && p!="z" && p!="id" && p!="wires") {
@@ -2461,6 +2567,10 @@ RED.nodes = (function() {
node._orig = orig;
node.name = n.type;
node.type = "unknown";
if (options.modules) {
// We have a module hint list. Attach to the unknown node so we can reference it later
node.modules = Object.keys(options.modules)
}
}
if (node._def.category != "config") {
if (n.hasOwnProperty('inputs') && node._def.defaults.hasOwnProperty("inputs")) {
@@ -2491,6 +2601,13 @@ RED.nodes = (function() {
for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
node[d] = n[d];
if (applyNodeDefaults && n[d] === undefined) {
// If the node has a default value, but the imported node does not
// set it, then set it to the default value
if (node._def.defaults[d].value !== undefined) {
node[d] = JSON.parse(JSON.stringify(node._def.defaults[d].value))
}
}
node._config[d] = JSON.stringify(n[d]);
}
}
@@ -2678,7 +2795,7 @@ RED.nodes = (function() {
// Now the nodes have been fully updated, add them.
for (i=0;i<new_nodes.length;i++) {
new_nodes[i] = addNode(new_nodes[i])
new_nodes[i] = addNode(new_nodes[i], options.eventContext)
node_map[new_nodes[i].id] = new_nodes[i]
}
@@ -2744,7 +2861,8 @@ RED.nodes = (function() {
workspaces:new_workspaces,
subflows:new_subflows,
missingWorkspace: missingWorkspace,
removedNodes: removedNodes
removedNodes: removedNodes,
nodeMap: node_map
}
}
@@ -3148,6 +3266,44 @@ RED.nodes = (function() {
}
}
/**
* Gets the module list for the given nodes
* @param {Array<Node>} nodes the nodes to search in
* @returns {Record<string, string>} an object with {[moduleName]: moduleVersion}
*/
function getModuleListForNodes(nodes) {
const modules = {}
const typeSet = new Set()
nodes.forEach((n) => {
if (!typeSet.has(n.type)) {
typeSet.add(n.type)
const nodeSet = RED.nodes.registry.getNodeSetForType(n.type)
if (nodeSet) {
modules[nodeSet.module] = nodeSet.version
nodeSet.types.forEach((t) => typeSet.add(t))
}
}
})
return modules
}
function updateGlobalConfigModuleList(nodes) {
const modules = getModuleListForNodes(nodes)
delete modules['node-red']
const hasModules = (Object.keys(modules).length > 0)
let globalConfigNode = nodes.find((n) => n.type === 'global-config')
if (!globalConfigNode && hasModules) {
globalConfigNode = {
id: RED.nodes.id(),
type: 'global-config',
env: [],
modules
}
nodes.push(globalConfigNode)
} else if (hasModules) {
globalConfigNode.modules = modules
}
}
return {
init: function() {
RED.events.on("registry:node-type-added",function(type) {
@@ -3229,7 +3385,12 @@ RED.nodes = (function() {
});
RED.events.on('deploy', function () {
allNodes.clearState()
})
});
RED.actions.add("core:trigger-selected-nodes-action", function () {
const selectedNodes = RED.view.selection().nodes || [];
// Triggers the button action of the selected nodes
selectedNodes.forEach((node) => RED.view.clickNodeButton(node));
});
},
registry:registry,
setNodeList: registry.setNodeList,

View File

@@ -1,56 +0,0 @@
(function() {
var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
if (isIE11) {
// IE11 DOMTokenList.toggle does not support the two-argument variety
window.DOMTokenList.prototype.toggle = function(cl,bo) {
if (arguments.length === 1) {
bo = !this.contains(cl);
}
this[!!bo?"add":"remove"](cl);
}
// IE11 does not provide classList on SVGElements
if (! ("classList" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'classList', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'classList'));
}
// IE11 does not provide children on SVGElements
if (! ("children" in SVGElement.prototype)) {
Object.defineProperty(SVGElement.prototype, 'children', Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children'));
}
Array.from = function() {
if (arguments.length > 1) {
throw new Error("Node-RED's IE11 Array.from polyfill doesn't support multiple arguments");
}
var arrayLike = arguments[0]
var result = [];
if (arrayLike.forEach) {
arrayLike.forEach(function(i) {
result.push(i);
})
} else {
for (var i=0;i<arrayLike.length;i++) {
result.push(arrayList[i]);
}
}
return result;
}
if (new Set([0]).size === 0) {
// IE does not support passing an iterable to Set constructor
var _Set = Set;
/*global Set:true */
Set = function Set(iterable) {
var set = new _Set();
if (iterable) {
iterable.forEach(set.add, set);
}
return set;
};
Set.prototype = _Set.prototype;
Set.prototype.constructor = Set;
}
}
})();

View File

@@ -358,7 +358,10 @@ var RED = (function() {
});
return;
}
if (notificationId === "update-available") {
// re-emit as an event to be handled in editor-client/src/js/ui/palette-editor.js
RED.events.emit("notification/update-available", msg)
}
if (msg.text) {
msg.default = msg.text;
var text = RED._(msg.text,msg);
@@ -672,14 +675,48 @@ var RED = (function() {
setTimeout(function() {
loader.end();
checkFirstRun(function() {
if (showProjectWelcome) {
RED.projects.showStartup();
}
});
checkTelemetry(function () {
checkFirstRun(function() {
if (showProjectWelcome) {
RED.projects.showStartup();
}
});
})
},100);
}
function checkTelemetry(done) {
const telemetrySettings = RED.settings.telemetryEnabled;
// Can only get telemetry permission from a user with permission to modify settings
if (RED.user.hasPermission("settings.write") && telemetrySettings === undefined) {
const dialog = RED.popover.dialog({
title: RED._("telemetry.settingsTitle"),
content: `${RED._("telemetry.settingsDescription")}${RED._("telemetry.settingsDescription2")}`,
closeButton: false,
buttons: [
{
text: RED._("telemetry.enableLabel"),
click: () => {
RED.settings.set("telemetryEnabled", true)
dialog.close()
done()
}
},
{
text: RED._("telemetry.disableLabel"),
click: () => {
RED.settings.set("telemetryEnabled", false)
dialog.close()
done()
}
}
]
})
} else {
done()
}
}
function checkFirstRun(done) {
if (RED.settings.theme("tours") === false) {
done();

View File

@@ -34,23 +34,13 @@ RED.clipboard = (function() {
function downloadData(file, data) {
if (window.navigator.msSaveBlob) {
// IE11 workaround
// IE does not support data uri scheme for downloading data
var blob = new Blob([data], {
type: "data:application/json;charset=utf-8"
});
navigator.msSaveBlob(blob, file);
}
else {
var element = document.createElement('a');
element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(data));
element.setAttribute('download', file);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
const element = document.createElement('a');
element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(data));
element.setAttribute('download', file);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function setupDialogs() {
@@ -740,7 +730,7 @@ RED.clipboard = (function() {
nodes = RED.view.selection().nodes||[];
}
// Don't include the subflow meta-port nodes in the exported selection
nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}));
nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}), { includeModuleConfig: true });
} else if (type === 'flow') {
var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.groups(activeWorkspace);
@@ -755,9 +745,9 @@ RED.clipboard = (function() {
});
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
nodes.unshift(parentNode);
nodes = RED.nodes.createExportableNodeSet(nodes);
nodes = RED.nodes.createExportableNodeSet(nodes, { includeModuleConfig: true });
} else if (type === 'full') {
nodes = RED.nodes.createCompleteNodeSet({ credentials: false });
nodes = RED.nodes.createCompleteNodeSet({ credentials: false, includeModuleConfig: true });
}
if (nodes !== null) {
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
@@ -858,7 +848,7 @@ RED.clipboard = (function() {
children: []
};
treeSubflows.push(subflows[node.id])
} else {
} else if (node.type !== 'global-config') {
nodes.push(node);
}
});

View File

@@ -15,14 +15,25 @@
* The function must either return auto-complete options, or pass them
* to the optional 'done' parameter.
* If the function signature includes 'done', it must be used
* The auto-complete options can either be an array of strings, or an array of objects in the form:
* {
* value: String : the value to insert if selected
* label: String|DOM Element : the label to display in the dropdown.
* }
*
* minLength: number
* If `minLength` is 0, pressing down arrow will show the list
*
* completionPluginType: String
* If provided instead of `search`, this will look for any plugins
* registered with the given type that implement the `getCompletions` function. This
* can be an async function that returns an array of string completions. It does not support
* the full options object as above.
*
* The auto-complete options should be an array of objects in the form:
* {
* value: String : the value to insert if selected
* label: String|DOM Element : the label to display in the dropdown.
* }
* node: Node
* If provided, this will be passed to the `getCompletions` function of the plugin
* to allow the plugin to provide context-aware completions.
*
*
*/
@@ -31,6 +42,54 @@
const that = this;
this.completionMenuShown = false;
this.options.minLength = parseInteger(this.options.minLength, 1, 0);
if (!this.options.search) {
// No search function provided; nothing to provide completions
if (this.options.completionPluginType) {
const plugins = RED.plugins.getPluginsByType(this.options.completionPluginType)
if (plugins.length > 0) {
this.options.search = async function (value, done) {
// for now, only support a single plugin
const promises = plugins.map(plugin => plugin.getCompletions(value, that.options.context))
const completions = (await Promise.all(promises)).flat()
const results = []
completions.forEach(completion => {
const element = $('<div>',{style: "display: flex"})
const valEl = $('<div/>',{ class: "red-ui-autoComplete-completion" })
const valMatch = getMatch(completion, value)
if (valMatch.found) {
valEl.append(generateSpans(valMatch))
valEl.appendTo(element)
results.push({
value: completion,
label: element,
match: valMatch
})
}
results.sort((a, b) => {
if (a.match.exact && !b.match.exact) {
return -1;
} else if (!a.match.exact && b.match.exact) {
return 1;
} else if (a.match.index < b.match.index) {
return -1;
} else if (a.match.index > b.match.index) {
return 1;
} else {
return 0;
}
})
})
done(results)
}
} else {
// No search function and no plugins found
return
}
} else {
// No search function and no plugin type provided
return
}
}
this.options.search = this.options.search || function() { return [] };
this.element.addClass("red-ui-autoComplete");
this.element.on("keydown.red-ui-autoComplete", function(evt) {
@@ -92,6 +151,11 @@
}
return
}
if (typeof completions[0] === "string") {
completions = completions.map(function(c) {
return { value: c, label: c };
});
}
if (that.completionMenuShown) {
that.menu.options(completions);
} else {
@@ -123,4 +187,25 @@
if(isNaN(n) || n < min || n > max) { n = def || 0; }
return n;
}
// TODO: this is copied from typedInput - should be a shared utility
function getMatch(value, searchValue) {
const idx = value.toLowerCase().indexOf(searchValue.toLowerCase());
const len = idx > -1 ? searchValue.length : 0;
return {
index: idx,
found: idx > -1,
pre: value.substring(0,idx),
match: value.substring(idx,idx+len),
post: value.substring(idx+len),
exact: idx === 0 && value.length === searchValue.length
}
}
// TODO: this is copied from typedInput - should be a shared utility
function generateSpans(match) {
const els = [];
if(match.pre) { els.push($('<span/>').text(match.pre)); }
if(match.match) { els.push($('<span/>',{style:"font-weight: bold; color: var(--red-ui-text-color-link);"}).text(match.match)); }
if(match.post) { els.push($('<span/>').text(match.post)); }
return els;
}
})(jQuery);

View File

@@ -163,13 +163,18 @@ RED.popover = (function() {
}
var timer = null;
let isOpen = false
var active;
var div;
var contentDiv;
var currentStyle;
var openPopup = function(instant) {
if (isOpen) {
return
}
if (active) {
isOpen = true
var existingPopover = target.data("red-ui-popover");
if (options.tooltip && existingPopover) {
active = false;
@@ -334,6 +339,7 @@ RED.popover = (function() {
}
var closePopup = function(instant) {
isOpen = false
$(document).off('mousedown.red-ui-popover');
if (!active) {
if (div) {
@@ -673,6 +679,74 @@ RED.popover = (function() {
show:show,
hide:hide
}
},
dialog: function(options) {
const dialogContent = $('<div style="position:relative"></div>');
if (options.closeButton !== false) {
$('<button type="button" class="red-ui-button red-ui-button-small" style="float: right; margin-top: -4px; margin-right: -4px;"><i class="fa fa-times"></i></button>').appendTo(dialogContent).click(function(evt) {
evt.preventDefault();
close();
})
}
const dialogBody = $('<div class="red-ui-dialog-body"></div>').appendTo(dialogContent);
if (options.title) {
$('<h2>').text(options.title).appendTo(dialogBody);
}
$('<div>').css("text-align","left").html(options.content).appendTo(dialogBody);
const stepToolbar = $('<div>',{class:"red-ui-dialog-toolbar"}).appendTo(dialogContent);
if (options.buttons) {
options.buttons.forEach(button => {
const btn = $('<button type="button" class="red-ui-button"></button>').text(button.text).appendTo(stepToolbar);
if (button.class) {
btn.addClass(button.class);
}
if (button.click) {
btn.on('click', function(evt) {
evt.preventDefault();
button.click();
})
}
})
}
const width = 500;
const maxWidth = Math.min($(window).width()-10,Math.max(width || 0, 300));
let shade = $('<div class="red-ui-shade" style="z-index: 2000"></div>').appendTo(document.body);
shade.fadeIn()
let popover = RED.popover.create({
target: $(".red-ui-editor"),
width: width || "auto",
maxWidth: maxWidth+"px",
direction: "inset",
class: "red-ui-dialog",
trigger: "manual",
content: dialogContent
}).open()
function close() {
if (shade) {
shade.fadeOut(() => {
shade.remove()
shade = null
})
}
if (popover) {
popover.close()
popover = null
}
}
return {
close
}
}
}

View File

@@ -519,10 +519,25 @@
}
},
expand: function () {
var that = this;
const that = this;
let filter;
if (that.options.node) {
let nodeFilter = that.options.node.filter;
if ((typeof nodeFilter === "string" || typeof nodeFilter === "object") && nodeFilter) {
if (!Array.isArray(nodeFilter)) {
nodeFilter = [nodeFilter];
}
filter = function (node) {
return nodeFilter.includes(node.type);
};
} else if (typeof nodeFilter === "function") {
filter = nodeFilter;
}
}
RED.tray.hide();
RED.view.selectNodes({
single: true,
filter: filter,
selected: [that.value()],
onselect: function (selection) {
that.value(selection.id);

View File

@@ -1426,6 +1426,15 @@ RED.editor.codeEditor.monaco = (function() {
ed.gotoLine(row, col);
}
ed.type = type;
ed.onKeyDown((event) => {
if (event.keyCode === monaco.KeyCode.Escape) {
if (monacoWidgetsAreOpen(ed)) {
event.preventDefault();
}
}
})
return ed;
}
@@ -1435,6 +1444,16 @@ RED.editor.codeEditor.monaco = (function() {
return true;
}
function monacoWidgetsAreOpen(editor) {
/** @type {HTMLElement} */
const editorDomNode = editor.getDomNode()
const suggestVisible = !!editorDomNode.querySelector('.monaco-editor .suggest-widget.visible');
const parameterHintsVisible = !!editorDomNode.querySelector('.monaco-editor .parameter-hints-widget.visible');
const findWidgetVisible = !!editorDomNode.querySelector('.monaco-editor .find-widget.visible');
const renameInputVisible = !!editorDomNode.querySelector('.monaco-editor .rename-box');
return suggestVisible || parameterHintsVisible || findWidgetVisible || renameInputVisible
}
return {
/**
* Editor type

View File

@@ -33,8 +33,7 @@ RED.envVar = (function() {
id: RED.nodes.id(),
type: "global-config",
env: [],
name: "global-config",
label: "",
modules: {},
hasUsers: false,
users: [],
credentials: cred,

View File

@@ -15,11 +15,14 @@
**/
RED.eventLog = (function() {
var template = '<script type="text/x-red" data-template-name="_eventLog"><div class="form-row node-text-editor-row"><div style="height: 100%;min-height: 150px;" class="node-text-editor" id="red-ui-event-log-editor"></div></div></script>';
const template = '<script type="text/x-red" data-template-name="_eventLog"><div class="form-row node-text-editor-row"><div style="height: 100%;min-height: 150px;" class="node-text-editor" id="red-ui-event-log-editor"></div></div></script>';
let eventLogEditor;
let backlog = [];
let shown = false;
const activeLogs = new Set()
var eventLogEditor;
var backlog = [];
var shown = false;
function appendLogLine(line) {
backlog.push(line);
@@ -38,6 +41,18 @@ RED.eventLog = (function() {
init: function() {
$(template).appendTo("#red-ui-editor-node-configs");
RED.actions.add("core:show-event-log",RED.eventLog.show);
const statusWidget = $('<button type="button" class="red-ui-footer-button red-ui-event-log-status" style="line-height: normal"><img style="width: 80%" src="red/images/spin.svg"/></div></button>');
statusWidget.on("click", function(evt) {
RED.actions.invoke("core:show-event-log");
})
RED.statusBar.add({
id: "red-ui-event-log-status",
align: "right",
element: statusWidget
});
RED.statusBar.hide("red-ui-event-log-status");
},
show: function() {
if (shown) {
@@ -98,6 +113,12 @@ RED.eventLog = (function() {
},
log: function(id,payload) {
var ts = (new Date(payload.ts)).toISOString()+" ";
if (!payload.end) {
activeLogs.add(id)
} else {
activeLogs.delete(id);
}
if (payload.type) {
ts += "["+payload.type+"] "
}
@@ -111,6 +132,11 @@ RED.eventLog = (function() {
appendLogLine(ts+line);
})
}
if (activeLogs.size > 0) {
RED.statusBar.show("red-ui-event-log-status");
} else {
RED.statusBar.hide("red-ui-event-log-status");
}
},
startEvent: function(name) {
backlog.push("");

View File

@@ -35,6 +35,7 @@ RED.keyboard = (function() {
"backspace": 8,
"delete": 46,
"space": 32,
"tab": 9,
";":186,
"=":187,
"+":187, // <- QWERTY specific
@@ -301,23 +302,27 @@ RED.keyboard = (function() {
return resolveKeyEvent(evt);
}
}
d3.select(window).on("keydown",function() {
d3.select(window).on("keydown", () => {
handleEvent(d3.event)
})
function handleEvent (evt) {
if (!handlersActive) {
return;
}
if (metaKeyCodes[d3.event.keyCode]) {
if (metaKeyCodes[evt]) {
return;
}
var handler = resolveKeyEvent(d3.event);
var handler = resolveKeyEvent(evt);
if (handler && handler.ondown) {
if (typeof handler.ondown === "string") {
RED.actions.invoke(handler.ondown);
} else {
handler.ondown();
}
d3.event.preventDefault();
}
});
evt.preventDefault();
}
}
function addHandler(scope,key,modifiers,ondown) {
var mod = modifiers;
@@ -699,7 +704,8 @@ RED.keyboard = (function() {
formatKey: formatKey,
validateKey: validateKey,
disable: disable,
enable: enable
enable: enable,
handle: handleEvent
}
})();

View File

@@ -15,26 +15,35 @@
**/
RED.palette.editor = (function() {
var disabled = false;
let catalogues = []
const loadedCatalogs = []
var editorTabs;
let filterInput;
let searchInput;
let nodeList;
let packageList;
let fullList = []
// Loaded modules
let loadedList = [];
let filteredList = [];
let loadedIndex = {};
var typesInUse = {};
var nodeEntries = {};
var eventTimers = {};
var activeFilter = "";
// Module list
let fullList = [];
let filteredList = [];
var semverre = /^(\d+)(\.(\d+))?(\.(\d+))?(-([0-9A-Za-z-]+))?(\.([0-9A-Za-z-.]+))?$/;
var NUMBERS_ONLY = /^\d+$/;
// Modules installed
let nodeEntries = {};
// EditableList
let nodeList;
let packageList;
// Nodes tab - filter
let activeFilterTerms = [];
// Nodes tab - search input
let filterInput;
// Install tab - search input
let searchInput;
const typesInUse = {};
const semverre = /^(\d+)(\.(\d+))?(\.(\d+))?(-([0-9A-Za-z-]+))?(\.([0-9A-Za-z-.]+))?$/;
const NUMBERS_ONLY = /^\d+$/;
function SemVerPart(part) {
this.number = 0;
@@ -115,8 +124,65 @@ RED.palette.editor = (function() {
});
})
}
function installNodeModule(id,version,url,callback) {
var requestBody = {
const moduleQueue = [];
const processQueue = function () {
if (moduleQueue.length === 0) {
return;
}
const { type, body, callback } = moduleQueue[0];
if (type === "install") {
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install") + ` : ${body.module} ${body.version}`);
$.ajax({
url: "nodes",
type: "POST",
data: JSON.stringify(body),
contentType: "application/json; charset=utf-8"
}).done(function(_data, _textStatus, _xhr) {
callback();
}).fail(function(xhr, textStatus, err) {
callback(xhr, textStatus, err);
}).always(function () {
// Remove the task from the list
moduleQueue.shift();
// Process the next task
processQueue();
});
} else if (type === "remove") {
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.remove") + ` : ${body.id}`);
$.ajax({
url: "nodes/" + body.id,
type: "DELETE"
}).done(function(_data, _textStatus, _xhr) {
callback();
}).fail(function(xhr, _textStatus, _err) {
callback(xhr);
}).always(function () {
// Remove the task from the list
moduleQueue.shift();
// Process the next task
processQueue();
});
}
};
/**
* Adds a module to the processing queue to install or remove it
* @param {string} type the type of request to apply to the module
* @param {Object} body an object with module info
* @param {(xhr?: JQuery.jqXHR, textStatus?: JQuery.Ajax.ErrorTextStatus, err?: string) => void} callback a callback function called when the request is done
*/
function addModuleToQueue(type, body, callback) {
moduleQueue.push({ type, body, callback });
if (moduleQueue.length === 1) {
processQueue();
}
}
function installNodeModule(id, version, url, callback) {
const requestBody = {
module: id
};
if (version) {
@@ -125,26 +191,10 @@ RED.palette.editor = (function() {
if (url) {
requestBody.url = url;
}
$.ajax({
url:"nodes",
type: "POST",
data: JSON.stringify(requestBody),
contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) {
callback();
}).fail(function(xhr,textStatus,err) {
callback(xhr,textStatus,err);
});
addModuleToQueue("install", requestBody, callback);
}
function removeNodeModule(id,callback) {
$.ajax({
url:"nodes/"+id,
type: "DELETE"
}).done(function(data,textStatus,xhr) {
callback();
}).fail(function(xhr,textStatus,err) {
callback(xhr);
})
function removeNodeModule(id, callback) {
addModuleToQueue("remove", { id: id }, callback);
}
function refreshNodeModuleList() {
@@ -155,6 +205,7 @@ RED.palette.editor = (function() {
}
}
const eventTimers = {};
function refreshNodeModule(module) {
if (!eventTimers.hasOwnProperty(module)) {
eventTimers[module] = setTimeout(function() {
@@ -249,6 +300,11 @@ RED.palette.editor = (function() {
nodeEntries[module].info.pending_version = nodeInfo.pending_version;
}
if (loadedIndex[module] && loadedIndex[module].url) {
// Add the link to the node documentation if the catalog contains it
nodeEntries[module].info.url = loadedIndex[module].url;
}
for (const set in nodeInfo.sets) {
if (nodeInfo.sets.hasOwnProperty(set)) {
index.push(set);
@@ -414,7 +470,19 @@ RED.palette.editor = (function() {
}
function filterChange(val) {
activeFilter = val.toLowerCase();
const activeFilter = val.toLowerCase();
activeFilterTerms = []
activeFilter.split(',').forEach(term => {
term = term.trim()
if (term) {
const isExact = term[0] === '"' && term[term.length-1] === '"'
activeFilterTerms.push({
exact: isExact,
term: isExact ? term.substring(1,term.length-1) : term
})
}
})
var visible = nodeList.editableList('filter');
var size = nodeList.editableList('length');
if (val === "") {
@@ -424,58 +492,60 @@ RED.palette.editor = (function() {
}
}
let activeSort = sortModulesRelevance;
var catalogueCount;
var catalogueLoadStatus = [];
var catalogueLoadStart;
var catalogueLoadErrors = false;
var activeSort = sortModulesRelevance;
function handleCatalogResponse(err,catalog,index,v) {
const url = catalog.url
catalogueLoadStatus.push(err||v);
if (!err) {
if (v.modules) {
v.modules = v.modules.filter(function(m) {
if (RED.utils.checkModuleAllowed(m.id,m.version,installAllowList,installDenyList)) {
loadedIndex[m.id] = m;
m.index = [m.id];
if (m.keywords) {
m.index = m.index.concat(m.keywords);
}
if (m.types) {
m.index = m.index.concat(m.types);
}
if (m.updated_at) {
m.timestamp = new Date(m.updated_at).getTime();
} else {
m.timestamp = 0;
}
m.index = m.index.join(",").toLowerCase();
m.catalog = catalog;
m.catalogIndex = index;
return true;
function refreshCatalogues (done) {
const catalogueCount = catalogues.length;
loadedList = []
loadedIndex = {}
loadedCatalogs.length = 0
let handled = 0
for (let index = 0; index < catalogues.length; index++) {
const url = catalogues[index];
$.getJSON(url, {_: new Date().getTime()},function(v) {
loadedCatalogs.push({ index: index, url: url, name: v.name, updated_at: v.updated_at, modules_count: (v.modules || []).length })
handleCatalogResponse({ url: url, name: v.name},index,v);
}).fail(function(_jqxhr, _textStatus, error) {
console.warn("Error loading catalog",url,":",error);
}).always(function() {
handled++;
if (handled === catalogueCount) {
//sort loadedCatalogs by e.index ascending
loadedCatalogs.sort((a, b) => a.index - b.index)
refreshUpdateStatus();
if (done) {
done()
}
return false;
})
loadedList = loadedList.concat(v.modules);
}
} else {
catalogueLoadErrors = true;
}
})
}
if (catalogueCount > 1) {
$(".red-ui-palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>"+catalogueLoadStatus.length+"/"+catalogueCount);
}
if (catalogueLoadStatus.length === catalogueCount) {
if (catalogueLoadErrors) {
RED.notify(RED._('palette.editor.errors.catalogLoadFailed',{url: url}),"error",false,8000);
}
var delta = 250-(Date.now() - catalogueLoadStart);
setTimeout(function() {
$("#red-ui-palette-module-install-shade").hide();
},Math.max(delta,0));
}
function handleCatalogResponse(catalog,index,v) {
if (v.modules) {
v.modules = v.modules.filter(function(m) {
if (RED.utils.checkModuleAllowed(m.id,m.version,installAllowList,installDenyList)) {
loadedIndex[m.id] = m;
m.index = [m.id];
if (m.keywords) {
m.index = m.index.concat(m.keywords);
}
if (m.types) {
m.index = m.index.concat(m.types);
}
if (m.updated_at) {
m.timestamp = new Date(m.updated_at).getTime();
} else {
m.timestamp = 0;
}
m.index = m.index.join(",").toLowerCase();
m.catalog = catalog;
m.catalogIndex = index;
return true;
}
return false;
})
loadedList = loadedList.concat(v.modules);
}
}
@@ -487,35 +557,19 @@ RED.palette.editor = (function() {
packageList.editableList('empty');
$(".red-ui-palette-module-shade-status").text(RED._('palette.editor.loading'));
catalogueLoadStatus = [];
catalogueLoadErrors = false;
catalogueCount = catalogues.length;
if (catalogues.length > 1) {
$(".red-ui-palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>0/"+catalogues.length);
}
$("#red-ui-palette-module-install-shade").show();
catalogueLoadStart = Date.now();
var handled = 0;
loadedCatalogs.length = 0; // clear the loadedCatalogs array
for (let index = 0; index < catalogues.length; index++) {
const url = catalogues[index];
$.getJSON(url, {_: new Date().getTime()},function(v) {
loadedCatalogs.push({ index: index, url: url, name: v.name, updated_at: v.updated_at, modules_count: (v.modules || []).length })
handleCatalogResponse(null,{ url: url, name: v.name},index,v);
refreshNodeModuleList();
}).fail(function(jqxhr, textStatus, error) {
console.warn("Error loading catalog",url,":",error);
handleCatalogResponse(jqxhr,url,index);
}).always(function() {
handled++;
if (handled === catalogueCount) {
//sort loadedCatalogs by e.index ascending
loadedCatalogs.sort((a, b) => a.index - b.index)
updateCatalogFilter(loadedCatalogs)
}
})
}
const catalogueLoadStart = Date.now()
refreshCatalogues(function () {
refreshNodeModuleList();
updateCatalogFilter(loadedCatalogs)
const delta = 250-(Date.now() - catalogueLoadStart);
setTimeout(function() {
$("#red-ui-palette-module-install-shade").hide();
},Math.max(delta,0));
})
} else {
refreshNodeModuleList();
updateCatalogFilter(loadedCatalogs)
}
}
@@ -529,7 +583,6 @@ RED.palette.editor = (function() {
if (catalogSelection.length === 0) {
// sidebar not yet loaded (red-catalogue-filter-select is not in dom)
if (maxRetry > 0) {
// console.log("updateCatalogFilter: sidebar not yet loaded, retrying in 100ms")
// try again in 100ms
setTimeout(() => {
updateCatalogFilter(catalogEntries, maxRetry - 1)
@@ -591,7 +644,9 @@ RED.palette.editor = (function() {
packageList.editableList('addItem',{count:loadedList.length})
return;
}
// sort the filtered modules
filteredList.sort(activeSort);
// render the items in the package list
for (var i=0;i<Math.min(10,filteredList.length);i++) {
packageList.editableList('addItem',filteredList[i]);
}
@@ -603,15 +658,26 @@ RED.palette.editor = (function() {
}
}
function sortModulesRelevance(A,B) {
var currentFilter = searchInput.searchBox('value').trim();
if (currentFilter === "") {
return sortModulesAZ(A,B);
const defaultSort = sortModulesDownloads(A,B);
const currentFilter = searchInput.searchBox('value').trim();
if (defaultSort === 0) {
// same number of downloads
if (currentFilter === "") {
return sortModulesAZ(A,B);
}
var i = A.info.index.indexOf(currentFilter) - B.info.index.indexOf(currentFilter);
if (i === 0) {
return sortModulesAZ(A,B);
}
return i;
}
var i = A.info.index.indexOf(currentFilter) - B.info.index.indexOf(currentFilter);
if (i === 0) {
return sortModulesAZ(A,B);
}
return i;
return defaultSort;
}
function sortModulesDownloads(A,B) {
// check A has the info.downloads property - if not exising, prioritise it (likely a custom user catalogue)
const a = A.info && typeof A.info.downloads !== 'undefined' ? A.info.downloads.week : Number.MAX_SAFE_INTEGER;
const b = B.info && typeof B.info.downloads !== 'undefined' ? B.info.downloads.week : Number.MAX_SAFE_INTEGER;
return b - a;
}
function sortModulesAZ(A,B) {
return A.info.id.localeCompare(B.info.id);
@@ -620,36 +686,42 @@ RED.palette.editor = (function() {
return -1 * (A.info.timestamp-B.info.timestamp);
}
var installAllowList = ['*'];
var installDenyList = [];
var updateAllowed = true;
var updateAllowList = ['*'];
var updateDenyList = [];
let installAllowList = ['*'];
let installDenyList = [];
let updateAllowed = true;
let updateAllowList = ['*'];
let updateDenyList = [];
let editorTabs;
let settingsPane;
function init() {
catalogues = RED.settings.theme('palette.catalogues')||['https://catalogue.nodered.org/catalogue.json']
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
return;
}
var settingsAllowList = RED.settings.get("externalModules.palette.allowList")
var settingsDenyList = RED.settings.get("externalModules.palette.denyList")
const settingsAllowList = RED.settings.get("externalModules.palette.allowList")
const settingsDenyList = RED.settings.get("externalModules.palette.denyList")
const settingsUpdateAllowList = RED.settings.get("externalModules.palette.allowUpdateList")
const settingsUpdateDenyList = RED.settings.get("externalModules.palette.denyUpdateList")
if (settingsAllowList || settingsDenyList) {
installAllowList = settingsAllowList;
installDenyList = settingsDenyList
installDenyList = settingsDenyList;
}
installAllowList = RED.utils.parseModuleList(installAllowList);
installDenyList = RED.utils.parseModuleList(installDenyList);
var settingsUpdateAllowList = RED.settings.get("externalModules.palette.allowUpdateList")
var settingsUpdateDenyList = RED.settings.get("externalModules.palette.denyUpdateList")
if (settingsUpdateAllowList || settingsUpdateDenyList) {
updateAllowList = settingsUpdateAllowList;
updateDenyList = settingsUpdateDenyList;
}
installAllowList = RED.utils.parseModuleList(installAllowList);
installDenyList = RED.utils.parseModuleList(installDenyList);
updateAllowed = RED.settings.get("externalModules.palette.allowUpdate", true);
updateAllowList = RED.utils.parseModuleList(updateAllowList);
updateDenyList = RED.utils.parseModuleList(updateDenyList);
updateAllowed = RED.settings.get("externalModules.palette.allowUpdate",true);
catalogues = RED.settings.theme('palette.catalogues') || ['https://catalogue.nodered.org/catalogue.json']
createSettingsPane();
@@ -658,6 +730,9 @@ RED.palette.editor = (function() {
title: RED._("palette.editor.palette"),
get: getSettingsPane,
close: function() {
if (filterInput) {
filterInput.searchBox('value',"");
}
settingsPane.detach();
},
focus: function() {
@@ -668,12 +743,39 @@ RED.palette.editor = (function() {
}
})
RED.actions.add("core:manage-palette",function() {
// Add the update status to the status bar
addUpdateInfoToStatusBar();
// Load catalogues
refreshCatalogues()
RED.actions.add("core:manage-palette", function(opts) {
if (opts && opts.autoInstall && opts.modules) {
autoInstallModules(opts.modules);
} else {
RED.userSettings.show('palette');
});
if (opts) {
if (opts.view) {
editorTabs.activateTab(opts.view);
}
if (opts.filter) {
if (opts.view === 'install') {
searchInput.searchBox('value', opts.filter)
} else if (opts.view === 'nodes') {
filterInput.searchBox('value', opts.filter)
}
}
}
}
});
RED.events.on('registry:module-updated', function(ns) {
if (nodeEntries[ns.module]) {
// Set the node/plugin as updated
nodeEntries[ns.module].info.pending_version = ns.version;
}
refreshNodeModule(ns.module);
refreshUpdateStatus();
});
RED.events.on('registry:node-set-enabled', function(ns) {
refreshNodeModule(ns.module);
@@ -685,12 +787,14 @@ RED.palette.editor = (function() {
if (!/^subflow:/.test(nodeType)) {
var ns = RED.nodes.registry.getNodeSetForType(nodeType);
refreshNodeModule(ns.module);
refreshUpdateStatus();
}
});
RED.events.on('registry:node-type-removed', function(nodeType) {
if (!/^subflow:/.test(nodeType)) {
var ns = RED.nodes.registry.getNodeSetForType(nodeType);
refreshNodeModule(ns.module);
refreshUpdateStatus();
}
});
RED.events.on('registry:node-set-added', function(ns) {
@@ -760,6 +864,11 @@ RED.palette.editor = (function() {
nodeEntries[module].info.pending_version = pluginInfo.pending_version;
}
if (loadedIndex[module] && loadedIndex[module].url) {
// Add the link to the plugin documentation if the catalog contains it
nodeEntries[module].info.url = loadedIndex[module].url;
}
for (const set in pluginInfo.sets) {
if (pluginInfo.sets.hasOwnProperty(set)) {
index.push(set);
@@ -776,6 +885,7 @@ RED.palette.editor = (function() {
_refreshNodeModule(module);
}
refreshUpdateStatus();
for (var i=0;i<filteredList.length;i++) {
if (filteredList[i].info.id === module) {
var installButton = filteredList[i].elements.installButton;
@@ -785,9 +895,15 @@ RED.palette.editor = (function() {
}
}
});
}
var settingsPane;
RED.events.on("notification/update-available", function (msg) {
const updateKnownAbout = updateStatusState.version === msg.version
updateStatusState.version = msg.version
if (updateStatusWidgetPopover && !updateKnownAbout) {
setTimeout(() => { updateStatusWidgetPopover.open(); setTimeout(() => updateStatusWidgetPopover.close(), 20000) }, 1000)
}
})
}
function getSettingsPane() {
initInstallTab();
@@ -857,11 +973,26 @@ RED.palette.editor = (function() {
return A.info.name.localeCompare(B.info.name);
},
filter: function(data) {
if (activeFilter === "" ) {
if (activeFilterTerms.length === 0) {
return true;
}
return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1);
for (let i = 0; i < activeFilterTerms.length; i++) {
const searchTerm = activeFilterTerms[i]
const location = data.index.indexOf(searchTerm.term)
if (
(
searchTerm.exact &&
(
location === 0 && (
data.index.length === searchTerm.term.length ||
data.index[searchTerm.term.length] === ','
)
)
) ||
(!searchTerm.exact && location > -1)) {
return true
}
}
},
addItem: function(container,i,object) {
var entry = object.info;
@@ -869,6 +1000,12 @@ RED.palette.editor = (function() {
var headerRow = $('<div>',{class:"red-ui-palette-module-header"}).appendTo(container);
var titleRow = $('<div class="red-ui-palette-module-meta red-ui-palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
$('<span>').text(entry.name).appendTo(titleRow);
if (entry.url) {
// Add the link icon to the node documentation
$('<a target="_blank" class="red-ui-palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href', entry.url).appendTo(titleRow);
}
var metaRow = $('<div class="red-ui-palette-module-meta red-ui-palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
@@ -1058,8 +1195,35 @@ RED.palette.editor = (function() {
change: function() {
var searchTerm = $(this).val().trim().toLowerCase();
if (searchTerm.length > 0 || loadedList.length < 20) {
const searchTerms = []
searchTerm.split(',').forEach(term => {
term = term.trim()
if (term) {
const isExact = term[0] === '"' && term[term.length-1] === '"'
searchTerms.push({
exact: isExact,
term: isExact ? term.substring(1,term.length-1) : term
})
}
})
filteredList = loadedList.filter(function(m) {
return (m.index.indexOf(searchTerm) > -1);
for (let i = 0; i < searchTerms.length; i++) {
const location = m.index.indexOf(searchTerms[i].term)
if (
(
searchTerms[i].exact &&
(
location === 0 && (
m.index.length === searchTerms[i].term.length ||
m.index[searchTerms[i].term.length] === ','
)
)
) ||
(!searchTerms[i].exact && location > -1)) {
return true
}
}
return false
}).map(function(f) { return {info:f}});
refreshFilteredItems();
searchInput.searchBox('count',filteredList.length+" / "+loadedList.length);
@@ -1144,12 +1308,25 @@ RED.palette.editor = (function() {
var headerRow = $('<div>',{class:"red-ui-palette-module-header"}).appendTo(container);
var titleRow = $('<div class="red-ui-palette-module-meta red-ui-palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
$('<span>').text(entry.name||entry.id).appendTo(titleRow);
$('<a target="_blank" class="red-ui-palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
if (entry.url) {
$('<a target="_blank" class="red-ui-palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
}
if (entry.deprecated) {
const deprecatedWarning = $('<span class="red-ui-palette-module-deprecated"></span>').text(RED._('palette.editor.deprecated')).appendTo(titleRow);
let message = $('<span>').text(RED._('palette.editor.deprecatedTip'))
if (typeof entry.deprecated === 'string') {
$('<p>').text(entry.deprecated).appendTo(message)
}
RED.popover.tooltip(deprecatedWarning, message);
}
var descRow = $('<div class="red-ui-palette-module-meta"></div>').appendTo(headerRow);
$('<div>',{class:"red-ui-palette-module-description"}).text(entry.description).appendTo(descRow);
var metaRow = $('<div class="red-ui-palette-module-meta"></div>').appendTo(headerRow);
$('<span class="red-ui-palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
$('<span class="red-ui-palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
$('<span class="red-ui-palette-module-version" title="Latest Version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
$('<span class="red-ui-palette-module-updated" title="Last Updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
if (entry.downloads?.week !== undefined) {
$('<span class="red-ui-palette-module-downloads" title="Downloads - Last 7 Days"><i class="fa fa-download"></i> '+(new Intl.NumberFormat().format(entry.downloads.week))+'</span>').appendTo(metaRow);
}
if (loadedCatalogs.length > 1) {
$('<span class="red-ui-palette-module-updated"><i class="fa fa-cubes"></i>' + (entry.catalog.name || entry.catalog.url) + '</span>').appendTo(metaRow);
}
@@ -1282,64 +1459,88 @@ RED.palette.editor = (function() {
$('<div id="red-ui-palette-module-install-shade" class="red-ui-palette-module-shade hide"><div class="red-ui-palette-module-shade-status"></div><img src="red/images/spin.svg" class="red-ui-palette-spinner"/></div>').appendTo(installTab);
}
function update(entry,version,url,container,done) {
function update(entry, version, url, container, done) {
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
done(new Error('Palette not editable'));
return;
}
var notification = RED.notify(RED._("palette.editor.confirm.update.body",{module:entry.name}),{
let notification;
let msg = RED._("palette.editor.confirm.update.body", { module: entry.name });
const buttons = [
{
text: RED._("common.label.cancel"),
click: function () {
notification.close();
}
},
{
text: RED._("palette.editor.confirm.button.update"),
class: "primary red-ui-palette-module-install-confirm-button-update",
click: function () {
const spinner = RED.utils.addSpinnerOverlay(container, true);
const buttonRow = $('<div style="position: relative;bottom: calc(50% + 17px); padding-right: 10px;text-align: right;"></div>').appendTo(spinner);
$('<button class="red-ui-button"></button>').text(RED._("eventLog.view")).appendTo(buttonRow).on("click", function (evt) {
evt.preventDefault();
RED.actions.invoke("core:show-event-log");
});
installNodeModule(entry.name, version, url, function (xhr) {
spinner.remove();
if (xhr) {
if (xhr.responseJSON) {
const notification = RED.notify(RED._('palette.editor.errors.updateFailed',{module: entry.name,message:xhr.responseJSON.message}),{
type: 'error',
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.close"),
click: function () {
notification.close();
}
}, {
text: RED._("eventLog.view"),
click: function () {
notification.close();
RED.actions.invoke("core:show-event-log");
}
}
]
});
}
}
done(xhr);
});
notification.close();
}
}
];
const currentVersion = semverre.exec(nodeEntries[entry.name].info.version);
const targetVersion = semverre.exec(version);
if (currentVersion && targetVersion) {
if (targetVersion[1] > currentVersion[1]) {
// Updating to Major version
msg = msg + RED._("palette.editor.majorVersion");
if (entry.url) {
// Add a button to open the node documentation
buttons.splice(1, 0, {
text: RED._("palette.editor.confirm.button.review"),
class: "primary red-ui-palette-module-install-confirm-button-review",
click: function () {
window.open(entry.url);
}
});
}
}
}
notification = RED.notify(msg, {
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
notification.close();
}
},
{
text: RED._("palette.editor.confirm.button.update"),
class: "primary red-ui-palette-module-install-confirm-button-update",
click: function() {
var spinner = RED.utils.addSpinnerOverlay(container, true);
var buttonRow = $('<div style="position: relative;bottom: calc(50% + 17px); padding-right: 10px;text-align: right;"></div>').appendTo(spinner);
$('<button class="red-ui-button"></button>').text(RED._("eventLog.view")).appendTo(buttonRow).on("click", function(evt) {
evt.preventDefault();
RED.actions.invoke("core:show-event-log");
});
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.name+" "+version);
installNodeModule(entry.name,version,url,function(xhr) {
spinner.remove();
if (xhr) {
if (xhr.responseJSON) {
var notification = RED.notify(RED._('palette.editor.errors.updateFailed',{module: entry.name,message:xhr.responseJSON.message}),{
type: 'error',
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.close"),
click: function() {
notification.close();
}
},{
text: RED._("eventLog.view"),
click: function() {
notification.close();
RED.actions.invoke("core:show-event-log");
}
}
]
});
}
}
done(xhr);
});
notification.close();
}
}
]
})
buttons: buttons
});
}
function remove(entry,container,done) {
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
@@ -1366,7 +1567,6 @@ RED.palette.editor = (function() {
evt.preventDefault();
RED.actions.invoke("core:show-event-log");
});
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.remove")+" : "+entry.name);
removeNodeModule(entry.name, function(xhr) {
spinner.remove();
if (xhr) {
@@ -1399,6 +1599,7 @@ RED.palette.editor = (function() {
if (e) {
nodeList.editableList('removeItem', e);
delete nodeEntries[entry.name];
refreshUpdateStatus();
}
// We assume that a plugin that implements onremove
@@ -1480,7 +1681,6 @@ RED.palette.editor = (function() {
evt.preventDefault();
RED.actions.invoke("core:show-event-log");
});
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.id+" "+entry.version);
installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr, textStatus,err) {
spinner.remove();
if (err && xhr.status === 504) {
@@ -1538,6 +1738,154 @@ RED.palette.editor = (function() {
})
}
function autoInstallModules(modules) {
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
console.error('Palette not editable');
return;
}
let notification;
const notificationOptions = {
fixed: true,
buttons: [
{
text: RED._("common.label.close"),
click: function () {
notification.close();
}
}, {
text: RED._("eventLog.view"),
click: function () {
notification.close();
RED.actions.invoke("core:show-event-log");
}
}
]
};
const moduleArray = Object.entries(modules);
const installModule = function (module) {
const [moduleName, moduleVersion] = module;
const spinner = '<div style="text-align: center; height: 100%; padding-top: 20px;"><img src="red/images/spin.svg" style="width: 60px;"/></div>';
const msg = "<p>" + RED._("palette.editor.installing", { module: moduleName }) + "</p>" + spinner;
if (!notification) {
notification = RED.notify(msg, notificationOptions);
} else {
notification.update(msg, notificationOptions);
}
installNodeModule(moduleName, moduleVersion, undefined, function(xhr, textStatus, err) {
if (err && xhr.status === 504) {
notification.update(RED._("palette.editor.errors.installTimeout"), {
modal: true,
fixed: true,
buttons: notificationOptions.buttons
});
} else if (xhr) {
if (xhr.responseJSON) {
notification.update(RED._("palette.editor.errors.installFailed", { module: moduleName, message:xhr.responseJSON.message }), {
type: "error",
modal: true,
fixed: true,
buttons: notificationOptions.buttons
});
}
} else {
if (moduleArray.length) {
installModule(moduleArray.shift());
} else {
notification.update(RED._("palette.editor.successfulInstall"), { ...notificationOptions, type: "success", timeout: 10000 });
}
}
});
};
if (moduleArray.length) {
installModule(moduleArray.shift());
}
}
const updateStatusWidget = $('<button type="button" class="red-ui-footer-button red-ui-update-status"></button>');
let updateStatusWidgetPopover;
const updateStatusState = { moduleCount: 0 }
let updateAvailable = [];
function addUpdateInfoToStatusBar() {
updateStatusWidgetPopover = RED.popover.create({
target: updateStatusWidget,
trigger: "click",
interactive: true,
direction: "bottom",
content: function () {
const count = updateAvailable.length || 0;
const content = $('<div style="display: flex; flex-direction: column; gap: 5px;"></div>');
if (updateStatusState.version) {
$(`<a class='red-ui-button' href="https://github.com/node-red/node-red/releases/tag/${updateStatusState.version}" target="_blank">${RED._("telemetry.updateAvailableDesc", updateStatusState)}</a>`).appendTo(content)
}
if (count > 0) {
$(`<button type="button" class="red-ui-button"><i class="fa fa-cube"></i> ${RED._("palette.editor.updateCount", { count: count })}</button>`).on("click", function (evt) {
updateStatusWidgetPopover.close()
RED.actions.invoke("core:manage-palette", {
view: "nodes",
filter: '"' + updateAvailable.join('", "') + '"'
});
}).appendTo(content)
}
return content
},
delay: { show: 750, hide: 250 }
});
RED.statusBar.add({
id: "red-ui-status-package-update",
align: "right",
element: updateStatusWidget
});
updateStatus();
}
let pendingRefreshTimeout
function refreshUpdateStatus() {
clearTimeout(pendingRefreshTimeout)
pendingRefreshTimeout = setTimeout(() => {
updateAvailable = [];
for (const module of Object.keys(nodeEntries)) {
if (loadedIndex.hasOwnProperty(module)) {
const moduleInfo = nodeEntries[module].info;
if (moduleInfo.pending_version) {
// Module updated
continue;
}
if (updateAllowed &&
semVerCompare(loadedIndex[module].version, moduleInfo.version) > 0 &&
RED.utils.checkModuleAllowed(module, null, updateAllowList, updateDenyList)
) {
updateAvailable.push(module);
}
}
}
updateStatusState.moduleCount = updateAvailable.length;
updateStatus();
}, 200)
}
function updateStatus() {
if (updateStatusState.moduleCount || updateStatusState.version) {
updateStatusWidget.empty();
let count = updateStatusState.moduleCount || 0;
if (updateStatusState.version) {
count ++
}
$(`<span><i class="fa fa-cube"></i> ${RED._("telemetry.updateAvailable", { count: count })}</span>`).appendTo(updateStatusWidget);
RED.statusBar.show("red-ui-status-package-update");
} else {
RED.statusBar.hide("red-ui-status-package-update");
}
}
return {
init: init,
install: install

View File

@@ -80,7 +80,7 @@ RED.palette = (function() {
getNodeCount: function (visibleOnly) {
const nodes = catDiv.find(".red-ui-palette-node")
if (visibleOnly) {
return nodes.filter(function() { return $(this).css('display') !== 'none'}).length
return nodes.filter(function() { return $(this).attr("data-filter") !== "true"}).length
} else {
return nodes.length
}
@@ -572,8 +572,10 @@ RED.palette = (function() {
var currentLabel = $(el).attr("data-palette-label");
var type = $(el).attr("data-palette-type");
if (val === "" || re.test(type) || re.test(currentLabel)) {
$(el).attr("data-filter", null)
$(this).show();
} else {
$(el).attr("data-filter", "true")
$(this).hide();
}
});

View File

@@ -33,6 +33,7 @@ RED.statusBar = (function() {
var el = $('<span class="red-ui-statusbar-widget"></span>');
el.prop('id', options.id);
options.element.appendTo(el);
options.elementDiv = el;
if (options.align === 'left') {
leftBucket.append(el);
} else if (options.align === 'right') {
@@ -40,12 +41,30 @@ RED.statusBar = (function() {
}
}
function hideWidget(id) {
const widget = widgets[id];
if (widget && widget.elementDiv) {
widget.elementDiv.hide();
}
}
function showWidget(id) {
const widget = widgets[id];
if (widget && widget.elementDiv) {
widget.elementDiv.show();
}
}
return {
init: function() {
leftBucket = $('<span class="red-ui-statusbar-bucket red-ui-statusbar-bucket-left">').appendTo("#red-ui-workspace-footer");
rightBucket = $('<span class="red-ui-statusbar-bucket red-ui-statusbar-bucket-right">').appendTo("#red-ui-workspace-footer");
},
add: addWidget
add: addWidget,
hide: hideWidget,
show: showWidget
}
})();

View File

@@ -435,10 +435,15 @@ RED.tourGuide = (function() {
function listTour() {
return [
{
id: "4_1",
label: "4.1",
path: "./tours/welcome.js"
},
{
id: "4_0",
label: "4.0",
path: "./tours/welcome.js"
path: "./tours/4.0/welcome.js"
},
{
id: "3_1",

View File

@@ -230,14 +230,6 @@
editorStack = $("#red-ui-editor-stack");
$(window).on("resize", handleWindowResize);
RED.events.on("sidebar:resize",handleWindowResize);
$("#red-ui-editor-shade").on("click", function() {
if (!openingTray) {
var tray = stack[stack.length-1];
if (tray && tray.primaryButton) {
tray.primaryButton.click();
}
}
});
},
show: function show(options) {
lowerTrayZ();

View File

@@ -14,6 +14,7 @@ RED.typeSearch = (function() {
var addCallback;
var cancelCallback;
var moveCallback;
var suggestCallback
var typesUsed = {};
@@ -25,6 +26,11 @@ RED.typeSearch = (function() {
selected = 0;
searchResults.children().removeClass('selected');
searchResults.children(":visible:first").addClass('selected');
const children = searchResults.children(":visible");
const n = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (n) {
updateSuggestion(n)
}
},100);
}
@@ -63,7 +69,7 @@ RED.typeSearch = (function() {
}
});
searchInput.on('keydown',function(evt) {
var children = searchResults.children(":visible");
const children = searchResults.children(":visible");
if (evt.keyCode === 40 && evt.shiftKey) {
evt.preventDefault();
moveDialog(0,10);
@@ -86,9 +92,14 @@ RED.typeSearch = (function() {
selected++;
}
$(children[selected]).addClass('selected');
const n = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (n) {
updateSuggestion(n)
}
ensureSelectedIsVisible();
evt.preventDefault();
} else if (evt.keyCode === 38) {
// Up
if (selected > 0) {
if (selected < children.length) {
$(children[selected]).removeClass('selected');
@@ -96,6 +107,10 @@ RED.typeSearch = (function() {
selected--;
}
$(children[selected]).addClass('selected');
const n = $(children[selected]).find(".red-ui-editableList-item-content").data('data');
if (n) {
updateSuggestion(n)
}
ensureSelectedIsVisible();
evt.preventDefault();
} else if ((evt.metaKey || evt.ctrlKey) && evt.keyCode === 13 ) {
@@ -103,14 +118,14 @@ RED.typeSearch = (function() {
// (ctrl or cmd) and enter
var index = Math.max(0,selected);
if (index < children.length) {
var n = $(children[index]).find(".red-ui-editableList-item-content").data('data');
if (!/^_action_:/.test(n.type)) {
const n = $(children[index]).find(".red-ui-editableList-item-content").data('data');
if (!n.nodes && !/^_action_:/.test(n.type)) {
typesUsed[n.type] = Date.now();
}
if (n.def.outputs === 0) {
confirm(n);
} else {
addCallback(n.type,true);
addCallback(n, true);
}
$("#red-ui-type-search-input").val("").trigger("keyup");
setTimeout(function() {
@@ -142,7 +157,7 @@ RED.typeSearch = (function() {
if (activeFilter === "" ) {
return true;
}
if (data.recent || data.common) {
if (data.recent || data.common || data.suggestion) {
return false;
}
return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1);
@@ -164,67 +179,133 @@ RED.typeSearch = (function() {
}
return Ai-Bi;
},
addItem: function(container,i,object) {
var def = object.def;
object.index = object.type.toLowerCase();
if (object.separator) {
addItem: function(container, i, nodeItem) {
// nodeItem can take multiple forms
// - A node type: {type: "inject", def: RED.nodes.getType("inject"), label: "Inject"}
// - A placeholder suggestion: { suggestionPlaceholder: true, label: 'loading suggestions...' }
let nodeDef = nodeItem.def;
let nodeType = nodeItem.type;
if (nodeItem.suggestion && nodeItem.nodes.length > 0) {
nodeDef = RED.nodes.getType(nodeItem.nodes[0].type);
nodeType = nodeItem.nodes[0].type;
}
nodeItem.index = nodeItem.type?.toLowerCase() || '';
if (nodeItem.separator) {
container.addClass("red-ui-search-result-separator")
}
var div = $('<div>',{class:"red-ui-search-result"}).appendTo(container);
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
if (object.type === "junction") {
const div = $('<div>',{class:"red-ui-search-result"}).appendTo(container);
const nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
if (nodeItem.suggestionPlaceholder) {
nodeDiv.addClass("red-ui-palette-icon-suggestion")
const iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
$('<i class="spinner" style="margin-top: -1px">').appendTo(iconContainer);
} else if (nodeType === "junction") {
nodeDiv.addClass("red-ui-palette-icon-junction");
} else if (/^_action_:/.test(object.type)) {
nodeDiv.addClass("red-ui-palette-icon-junction")
} else {
var colour = RED.utils.getNodeColor(object.type,def);
nodeDiv.css('backgroundColor',colour);
nodeDiv.css('backgroundColor', RED.utils.getNodeColor(nodeType, nodeDef));
}
var icon_url = RED.utils.getNodeIcon(def);
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, false);
if (nodeDef) {
// Add the node icon
const icon_url = RED.utils.getNodeIcon(nodeDef);
const iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
RED.utils.createIconElement(icon_url, iconContainer, false);
}
if (/^subflow:/.test(object.type)) {
var sf = RED.nodes.subflow(object.type.substring(8));
if (/^subflow:/.test(nodeType)) {
var sf = RED.nodes.subflow(nodeType.substring(8));
if (sf.in.length > 0) {
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
}
if (sf.out.length > 0) {
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
}
} else if (!/^_action_:/.test(object.type) && object.type !== "junction") {
if (def.inputs > 0) {
} else if (nodeDef && nodeType !== "junction") {
if (nodeDef.inputs > 0) {
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
}
if (def.outputs > 0) {
if (nodeDef.outputs > 0) {
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
}
}
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
var label = object.label;
object.index += "|"+label.toLowerCase();
var label = nodeItem.label;
nodeItem.index += "|"+label.toLowerCase();
$('<div>',{class:"red-ui-search-result-node-label"}).text(label).appendTo(contentDiv);
nodeItem.element = container;
div.on("click", function(evt) {
evt.preventDefault();
confirm(object);
confirm(nodeItem);
});
div.on('mouseenter', function() {
const children = searchResults.children(":visible");
if (selected > -1 && selected < children.length) {
$(children[selected]).removeClass('selected');
}
const editableListItem = container.parent()
selected = children.index(editableListItem);
$(children[selected]).addClass('selected');
updateSuggestion(nodeItem);
})
},
scrollOnAdd: false
});
}
let activeSuggestion
function updateSuggestion(nodeItem) {
if (nodeItem === activeSuggestion) {
return
}
if (!visible && nodeItem) {
// Do not update suggestion if the dialog is not visible
// - for example, whilst the dialog is closing and the user mouses over a new item
return
}
activeSuggestion = nodeItem
if (suggestCallback) {
if (!nodeItem) {
suggestCallback(null);
} else if (nodeItem.nodes) {
// This is a multi-node suggestion
suggestCallback({
nodes: nodeItem.nodes
});
} else if (nodeItem.type) {
// Single node suggestion
suggestCallback({
nodes: [{
x: 0,
y: 0,
type: nodeItem.type
}]
});
}
}
}
function confirm(def) {
if (!activeSuggestion) {
// The user has hit Enter without selecting an entry in the list.
// This means no suggestion has been shown yet - and the position recalculation
// has not been done.
// Trigger an update of the suggestion to get the position right before
// applying.
updateSuggestion(def)
}
hide();
if (!/^_action_:/.test(def.type)) {
if (!def.nodes && !/^_action_:/.test(def.type)) {
typesUsed[def.type] = Date.now();
}
addCallback(def.type);
addCallback(def);
}
function handleMouseActivity(evt) {
@@ -255,6 +336,7 @@ RED.typeSearch = (function() {
}
visible = true;
} else {
updateSuggestion(null)
dialog.hide();
searchResultsDiv.hide();
}
@@ -274,6 +356,7 @@ RED.typeSearch = (function() {
addCallback = opts.add;
cancelCallback = opts.cancel;
moveCallback = opts.move;
suggestCallback = opts.suggest;
RED.events.emit("type-search:open");
//shade.show();
if ($("#red-ui-main-container").height() - opts.y - 195 < 0) {
@@ -294,6 +377,7 @@ RED.typeSearch = (function() {
},200);
}
function hide(fast) {
updateSuggestion(null)
if (visible) {
visible = false;
if (dialog !== null) {
@@ -356,11 +440,11 @@ RED.typeSearch = (function() {
(!filter.output || def.outputs > 0)
}
function refreshTypeList(opts) {
var i;
let i;
searchResults.editableList('empty');
searchInput.searchBox('value','').focus();
selected = -1;
var common = [
const common = [
'inject','debug','function','change','switch','junction'
].filter(function(t) { return applyFilter(opts.filter,t,RED.nodes.getType(t)); });
@@ -371,7 +455,7 @@ RED.typeSearch = (function() {
// common.push('_action_:core:split-wire-with-link-nodes')
// }
var recentlyUsed = Object.keys(typesUsed);
let recentlyUsed = Object.keys(typesUsed);
recentlyUsed.sort(function(a,b) {
return typesUsed[b]-typesUsed[a];
});
@@ -379,9 +463,10 @@ RED.typeSearch = (function() {
return applyFilter(opts.filter,t,RED.nodes.getType(t)) && common.indexOf(t) === -1;
});
var items = [];
const items = [];
RED.nodes.registry.getNodeTypes().forEach(function(t) {
var def = RED.nodes.getType(t);
const def = RED.nodes.getType(t);
if (def.set?.enabled !== false && def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
items.push({type:t,def: def, label:getTypeLabel(t,def)});
}
@@ -389,18 +474,51 @@ RED.typeSearch = (function() {
items.push({ type: 'junction', def: { inputs:1, outputs: 1, label: 'junction', type: 'junction'}, label: 'junction' })
items.sort(sortTypeLabels);
var commonCount = 0;
var item;
var index = 0;
let index = 0;
if (!opts.context?.virtualLink) {
// Check for suggestion plugins
const suggestionPlugins = RED.plugins.getPluginsByType('node-red-flow-suggestion-source');
if (suggestionPlugins.length > 0) {
const suggestionItem = {
suggestionPlaceholder: true,
label: RED._('palette.loadingSuggestions'),
separator: true,
i: index++
}
searchResults.editableList('addItem', suggestionItem);
suggestionPlugins[0].getSuggestions(opts.context).then(function (suggestedFlows) {
searchResults.editableList('removeItem', suggestionItem);
if (!Array.isArray(suggestedFlows)) {
suggestedFlows = [suggestedFlows];
}
suggestedFlows.forEach(function(suggestion, index) {
const suggestedItem = {
suggestion: true,
separator: index === suggestedFlows.length - 1,
i: suggestionItem.i,
...suggestion
}
if (!suggestion.label && suggestion.nodes && suggestion.nodes.length === 1 && suggestion.nodes[0].type) {
suggestedItem.label = getTypeLabel(suggestion.nodes[0].type, RED.nodes.getType(suggestion.nodes[0].type));
}
searchResults.editableList('addItem', suggestedItem);
})
})
}
}
for(i=0;i<common.length;i++) {
var itemDef = RED.nodes.getType(common[i]);
let itemDef
if (common[i] === 'junction') {
itemDef = { inputs:1, outputs: 1, label: 'junction', type: 'junction'}
} else if (/^_action_:/.test(common[i]) ) {
itemDef = { inputs:1, outputs: 1, label: common[i], type: common[i]}
} else {
itemDef = RED.nodes.getType(common[i]);
}
if (itemDef) {
item = {
const item = {
type: common[i],
common: true,
def: itemDef,
@@ -414,7 +532,7 @@ RED.typeSearch = (function() {
}
}
for(i=0;i<Math.min(5,recentlyUsed.length);i++) {
item = {
const item = {
type:recentlyUsed[i],
def: RED.nodes.getType(recentlyUsed[i]),
recent: true,
@@ -439,9 +557,10 @@ RED.typeSearch = (function() {
}
return {
show: show,
show,
refresh: refreshTypeList,
hide: hide
hide,
isVisible: () => visible
};
})();

View File

@@ -140,9 +140,22 @@ RED.userSettings = (function() {
title: "menu.label.nodes",
options: [
{setting:"view-node-status",oldSetting:"menu-menu-item-status",label:"menu.label.displayStatus",default: true, toggle:true,onchange:"core:toggle-status"},
{setting:"view-node-info-icon", label:"menu.label.displayInfoIcon", default: true, toggle:true,onchange:"core:toggle-node-info-icon"},
{setting:"view-node-show-label",label:"menu.label.showNodeLabelDefault",default: true, toggle:true}
]
},
{
title: "telemetry.label",
options: [
{
global: true,
setting: "telemetryEnabled",
label: "telemetry.settingsTitle",
description: "telemetry.settingsDescription",
toggle: true
},
]
},
{
title: "menu.label.other",
options: [
@@ -169,13 +182,20 @@ RED.userSettings = (function() {
var initialState;
if (opt.local) {
initialState = localStorage.getItem(opt.setting);
} else if (opt.global) {
initialState = RED.settings.get(opt.setting);
} else {
initialState = currentEditorSettings.view[opt.setting];
}
var row = $('<div class="red-ui-settings-row"></div>').appendTo(pane);
var input;
if (opt.toggle) {
input = $('<label for="user-settings-'+opt.setting+'"><input id="user-settings-'+opt.setting+'" type="checkbox"> '+RED._(opt.label)+'</label>').appendTo(row).find("input");
let label = RED._(opt.label)
if (opt.description) {
label = `<p>${label}</p>${RED._(opt.description)}`;
}
input = $('<input id="user-settings-'+opt.setting+'" type="checkbox">').appendTo(row)
$('<label for="user-settings-'+opt.setting+'">'+label+'</label>').appendTo(row)
input.prop('checked',initialState);
} else if (opt.options) {
$('<label for="user-settings-'+opt.setting+'">'+RED._(opt.label)+'</label>').appendTo(row);
@@ -209,6 +229,8 @@ RED.userSettings = (function() {
var opt = allSettings[id];
if (opt.local) {
localStorage.setItem(opt.setting,value);
} else if (opt.global) {
RED.settings.set(opt.setting, value)
} else {
var currentEditorSettings = RED.settings.get('editor') || {};
currentEditorSettings.view = currentEditorSettings.view || {};
@@ -237,7 +259,7 @@ RED.userSettings = (function() {
addPane({
id:'view',
title: RED._("menu.label.view.view"),
title: RED._("menu.label.settings"),
get: createViewPane,
close: function() {
viewSettings.forEach(function(section) {

View File

@@ -128,10 +128,25 @@ RED.utils = (function() {
function formatString(str) {
return str.replace(/\r?\n/g,"&crarr;").replace(/\t/g,"&rarr;");
}
function sanitize(m) {
return m.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
}
/**
* Truncates a string to a specified maximum length, adding ellipsis
* if truncated.
*
* @param {string} str The string to be truncated.
* @param {number} [maxLength = 120] The maximum length of the truncated
* string. Default `120`.
* @returns {string} The truncated string with ellipsis if it exceeds the
* maximum length.
*/
function truncateString(str, maxLength = 120) {
return str.length > maxLength ? str.slice(0, maxLength) + "..." : str;
}
function buildMessageSummaryValue(value) {
var result;
if (Array.isArray(value)) {
@@ -379,6 +394,9 @@ RED.utils = (function() {
}
}
// Max string length before truncating
const MAX_STRING_LENGTH = 80;
/**
* Create a DOM element representation of obj - as used by Debug sidebar etc
*
@@ -474,7 +492,7 @@ RED.utils = (function() {
} else if (typeHint === "internal" || (obj.__enc__ && obj.type === 'internal')) {
e = $('<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>').text("[internal]").appendTo(entryObj);
} else if (typeof obj === 'string') {
if (/[\t\n\r]/.test(obj)) {
if (/[\t\n\r]/.test(obj) || obj.length > MAX_STRING_LENGTH) {
element.addClass('collapsed');
$('<i class="fa fa-caret-right red-ui-debug-msg-object-handle"></i> ').prependTo(header);
makeExpandable(header, function() {
@@ -483,7 +501,7 @@ RED.utils = (function() {
$('<pre class="red-ui-debug-msg-type-string"></pre>').text(obj).appendTo(row);
},function(state) {if (ontoggle) { ontoggle(path,state);}}, checkExpanded(strippedKey, expandPaths, { expandLeafNodes }));
}
e = $('<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>').html('"'+formatString(sanitize(obj))+'"').appendTo(entryObj);
e = $('<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>').html('"'+formatString(sanitize(truncateString(obj, MAX_STRING_LENGTH)))+'"').appendTo(entryObj);
if (/^#[0-9a-f]{6}$/i.test(obj)) {
$('<span class="red-ui-debug-msg-type-string-swatch"></span>').css('backgroundColor',obj).appendTo(e);
}
@@ -1513,6 +1531,7 @@ RED.utils = (function() {
parseContextKey: parseContextKey,
createIconElement: createIconElement,
sanitize: sanitize,
truncateString: truncateString,
renderMarkdown: renderMarkdown,
createNodeIcon: createNodeIcon,
getDarkerColor: getDarkerColor,

View File

@@ -24,7 +24,7 @@ RED.view.annotations = (function() {
refreshAnnotation = !!evt.node[opts.refresh]
delete evt.node[opts.refresh]
} else if (typeof opts.refresh === "function") {
refreshAnnotation = opts.refresh(evnt.node)
refreshAnnotation = opts.refresh(evt.node)
}
if (refreshAnnotation) {
refreshAnnotationElement(annotation.id, annotation.node, annotation.element)

View File

@@ -1149,8 +1149,8 @@ RED.view.tools = (function() {
t: 'multi',
events: historyEvents
})
RED.nodes.dirty(true)
}
RED.nodes.dirty(true)
RED.view.redraw()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
@use "mixins";
.red-ui-editor, .red-ui-editor-dialog {
.ace_read-only {
@@ -42,7 +44,7 @@
background: var(--red-ui-popover-background);
color: var(--red-ui-popover-color);
border-radius: 4px;
@include component-shadow;
@include mixins.component-shadow;
border-color: var(--red-ui-popover-background);
}
.ace_content {

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -43,7 +45,7 @@ body {
}
#red-ui-palette-shade, #red-ui-editor-shade, #red-ui-header-shade, #red-ui-sidebar-shade {
@include shade;
@include mixins.shade;
z-index: 5;
}
#red-ui-sidebar-shade {
@@ -52,7 +54,7 @@ body {
bottom: -1px;
}
#red-ui-full-shade {
@include shade;
@include mixins.shade;
z-index: 15;
}
.red-ui-editor,

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -63,7 +65,7 @@
}
}
.red-ui-tray-header {
@include disable-selection;
@include mixins.disable-selection;
position: relative;
box-sizing: border-box;
font-weight: bold;
@@ -77,7 +79,7 @@
}
.red-ui-tray-footer {
@include component-footer;
@include mixins.component-footer;
height: 35px;
font-size: 14px !important;
line-height: 35px;
@@ -110,9 +112,9 @@
padding: 6px;
button {
@include editor-button;
@include mixins.editor-button;
&.toggle {
@include workspace-button-toggle;
@include mixins.workspace-button-toggle;
}
}
}
@@ -179,7 +181,7 @@
}
a.red-ui-tray-resize-button,
button.red-ui-tray-resize-button {
@include workspace-button;
@include mixins.workspace-button;
display: block;
height: 37px;
line-height: 35px;
@@ -274,7 +276,7 @@ button.editor-button, // Deprecated: use .red-ui-button
a.red-ui-button,
button.red-ui-button
{
@include workspace-button;
@include mixins.workspace-button;
height: 34px;
line-height: 32px;
font-size: 13px;
@@ -283,7 +285,7 @@ button.red-ui-button
white-space: nowrap;
text-overflow: ellipsis;
&.toggle {
@include workspace-button-toggle;
@include mixins.workspace-button-toggle;
}
}

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -41,7 +43,7 @@
font-size: 14px;
pointer-events: none;
-webkit-touch-callout: none;
@include disable-selection;
@include mixins.disable-selection;
.red-ui-flow-node-label-text {
dominant-baseline: middle;
@@ -60,7 +62,7 @@
text-anchor: middle;
pointer-events: none;
-webkit-touch-callout: none;
@include disable-selection;
@include mixins.disable-selection;
}
@@ -155,11 +157,19 @@ svg:not(.red-ui-workspace-lasso-active) {
stroke-opacity: var(--red-ui-group-default-stroke-opacity);
}
.red-ui-flow-group-label {
@include disable-selection;
@include mixins.disable-selection;
fill: var(--red-ui-group-default-label-color);
}
.red-ui-flow-node-ghost {
opacity: 0.6;
rect.red-ui-flow-node {
stroke: var(--red-ui-node-border-placeholder);
stroke-dasharray:10,4;
stroke-width: 2;
}
}
.red-ui-flow-node-unknown {
stroke-dasharray:10,4;
@@ -174,10 +184,10 @@ svg:not(.red-ui-workspace-lasso-active) {
}
.red-ui-flow-node-icon-group {
text {
@include disable-selection;
@include mixins.disable-selection;
}
.fa-lg {
@include disable-selection;
@include mixins.disable-selection;
stroke: none;
fill: var(--red-ui-node-icon-color);
text-anchor: middle;
@@ -242,6 +252,18 @@ svg:not(.red-ui-workspace-lasso-active) {
stroke-linecap: round;
}
.red-ui-flow-node-docs {
stroke-width: 1px;
stroke-linejoin: round;
stroke-linecap: round;
stroke: var(--red-ui-node-border);
fill: none;
cursor: pointer;
rect {
fill: white;
}
}
g.red-ui-flow-node-selected {
.red-ui-workspace-select-mode & {
opacity: 1;
@@ -311,7 +333,7 @@ g.red-ui-flow-node-selected {
fill-opacity: 0.9;
}
.red-ui-flow-node-status-label {
@include disable-selection;
@include mixins.disable-selection;
stroke-width: 0;
fill: var(--red-ui-secondary-text-color);
font-size:9pt;
@@ -387,6 +409,13 @@ g.red-ui-flow-node-selected {
g.red-ui-flow-link-selected path.red-ui-flow-link-line {
stroke: var(--red-ui-node-selected-color);
}
g.red-ui-flow-link-ghost path.red-ui-flow-link-line {
stroke: var(--red-ui-node-border-placeholder);
stroke-width: 2;
stroke-dasharray: 10, 4;
}
g.red-ui-flow-link-unknown path.red-ui-flow-link-line {
stroke: var(--red-ui-link-unknown-color);
stroke-width: 2;
@@ -417,7 +446,7 @@ g.red-ui-flow-link-unknown path.red-ui-flow-link-line {
pointer-events: none;
-webkit-touch-callout: none;
white-space: pre;
@include disable-selection;
@include mixins.disable-selection;
}
.red-ui-flow-junction-dragging {
.red-ui-flow-junction-background {

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -15,7 +17,7 @@
**/
.button {
@include disable-selection;
@include mixins.disable-selection;
}
#red-ui-header {
@@ -50,7 +52,7 @@
}
}
img {
height: 18px;
height: 32px;
}
a {

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -54,7 +56,7 @@
border-radius: 1px;
background: var(--red-ui-secondary-background);
padding: 0;
@include component-shadow;
@include mixins.component-shadow;
}
.ui-dialog .ui-dialog-content {
padding: 25px 25px 10px 25px;
@@ -92,7 +94,7 @@
}
.ui-dialog-buttonset button {
@include workspace-button;
@include mixins.workspace-button;
font-size: 14px;
padding: 6px 14px;
margin-right: 8px;
@@ -160,7 +162,7 @@
.ui-widget-overlay {
@include shade;
@include mixins.shade;
z-index: 100;
opacity: 1;
}

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -254,7 +256,7 @@
display: flex;
flex-direction: row;
span:not(:nth-child(2)) {
@include disable-selection;
@include mixins.disable-selection;
}
span {
padding: 8px 0;

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -117,19 +119,27 @@
.red-ui-palette-module-updated {
margin-left: 10px;
}
.red-ui-palette-module-downloads {
margin-left: 10px;
}
.red-ui-palette-module-link {
margin-left: 5px;
}
.red-ui-palette-module-deprecated {
cursor: pointer;
color: var(--red-ui-text-color-error);
font-size: 0.7em;
border: 1px solid var(--red-ui-text-color-error);
border-radius: 30px;
padding: 2px 5px;
}
.red-ui-palette-module-description {
margin-left: 20px;
font-size: 0.9em;
color: var(--red-ui-secondary-text-color);
}
.red-ui-palette-module-link {
}
.red-ui-palette-module-set-button-group {
}
.red-ui-palette-module-content {
display: none;
padding: 10px 3px;
@@ -167,7 +177,7 @@
color: var(--red-ui-secondary-text-color);
padding-left: 5px;
font-size: 0.9em;
@include enable-selection;
@include mixins.enable-selection;
}
.red-ui-palette-module-type-swatch {
display: inline-block;
@@ -226,12 +236,12 @@
.red-ui-palette-module-name {
color: var(--red-ui-primary-text-color);
white-space: nowrap;
@include enable-selection;
@include mixins.enable-selection;
}
.red-ui-palette-module-version, .red-ui-palette-module-updated, .red-ui-palette-module-link {
.red-ui-palette-module-version, .red-ui-palette-module-updated, .red-ui-palette-module-link, .red-ui-palette-module-downloads {
font-style:italic;
font-size: 0.8em;
@include enable-selection;
@include mixins.enable-selection;
}
.red-ui-palette-module-button-group {
position: absolute;
@@ -256,7 +266,7 @@ ul.red-ui-palette-module-error-list {
}
.red-ui-palette-module-shade {
@include shade;
@include mixins.shade;
text-align: center;
padding-top: 20px;
}
@@ -305,3 +315,8 @@ button.red-ui-palette-editor-upload-button {
margin-left: 10px;
}
}
button.red-ui-update-status {
width: auto;
padding: 0 3px;
}

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -23,9 +25,29 @@
background: var(--red-ui-primary-background);
width: 180px;
text-align: center;
@include disable-selection;
@include component-border;
@include mixins.disable-selection;
@include mixins.component-border;
transition: width 0.2s ease-in-out;
&:before {
content: '';
top: 0px;
bottom: 0px;
right: 0px;
width: 7px;
height: 100%;
z-index: 4;
position: absolute;
-webkit-mask-image: url(images/grip.svg);
mask-image: url(images/grip.svg);
-webkit-mask-size: auto;
mask-size: auto;
-webkit-mask-position: 50% 50%;
mask-position: 50% 50%;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
background-color: var(--red-ui-grip-color);
}
}
.red-ui-palette-closed {
@@ -112,7 +134,7 @@
line-height: 20px;
overflow: hidden;
text-align: center;
@include disable-selection;
@include mixins.disable-selection;
}
.red-ui-palette-label-right {
margin: 4px 32px 4px 0;

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -28,7 +30,7 @@
font-family: var(--red-ui-primary-font);
font-size: 14px;
line-height: 1.4em;
@include component-shadow;
@include mixins.component-shadow;
border-color: var(--red-ui-popover-border);
}
.red-ui-popover-content {
@@ -194,7 +196,7 @@
.red-ui-popover-panel {
@include component-shadow;
@include mixins.component-shadow;
font-family: var(--red-ui-primary-font);
font-size: var(--red-ui-primary-font-size);
position: absolute;
@@ -203,3 +205,39 @@
background: var(--red-ui-secondary-background);
z-index: 2000;
}
.red-ui-popover.red-ui-dialog {
z-index: 2003;
--red-ui-popover-background: var(--red-ui-secondary-background);
--red-ui-popover-border: var(--red-ui-tourGuide-border);
--red-ui-popover-color: var(--red-ui-primary-text-color);
.red-ui-popover-content {
h2 {
text-align: center;
margin-top: 0px;
line-height: 1.2em;
color: var(--red-ui-tourGuide-heading-color);
i.fa {
font-size: 1.5em
}
}
}
}
.red-ui-dialog-toolbar {
min-height: 36px;
position: relative;
display: flex;
justify-content: flex-end;
gap: 10px;
}
.red-ui-dialog-body {
padding: 20px 40px 10px;
a {
color: var(--red-ui-text-color-link) !important;
text-decoration: none;
}
}

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -23,7 +25,7 @@
background: var(--red-ui-primary-background);
box-sizing: border-box;
z-index: 10;
@include component-border;
@include mixins.component-border;
}
#red-ui-sidebar.closing {
@@ -73,7 +75,7 @@
.red-ui-sidebar-closed > #red-ui-editor-stack { right: 8px !important; }
#red-ui-sidebar .button {
@include workspace-button;
@include mixins.workspace-button;
line-height: 18px;
font-size: 12px;
margin-right: 5px;
@@ -92,23 +94,23 @@
/* Deprecated -> red-ui-footer-button */
.sidebar-footer-button {
@include component-footer-button;
@include mixins.component-footer-button;
}
/* Deprecated -> red-ui-footer-button-toggle */
.sidebar-footer-button-toggle {
@include component-footer-button-toggle;
@include mixins.component-footer-button-toggle;
}
a.sidebar-header-button,
button.sidebar-header-button, /* Deprecated -> red-ui-sidebar-header-button */
a.red-ui-sidebar-header-button,
button.red-ui-sidebar-header-button {
@include workspace-button;
@include mixins.workspace-button;
font-size: 13px;
line-height: 13px;
padding: 5px 8px;
&.toggle {
@include workspace-button-toggle;
@include mixins.workspace-button-toggle;
}
}
@@ -116,7 +118,7 @@ a.sidebar-header-button-toggle, /* Deprecated -> red-ui-sidebar-header-button-to
button.sidebar-header-button-toggle, /* Deprecated -> red-ui-sidebar-header-button-toggle */
a.red-ui-sidebar-header-button-toggle,
button.red-ui-sidebar-header-button-toggle {
@include workspace-button-toggle;
@include mixins.workspace-button-toggle;
font-size: 13px;
line-height: 13px;
padding: 5px 8px;
@@ -128,7 +130,7 @@ button.red-ui-sidebar-header-button-toggle {
}
.red-ui-sidebar-shade {
@include shade;
@include mixins.shade;
}

View File

@@ -14,6 +14,6 @@
* limitations under the License.
**/
@import "colors";
@import "sizes";
@import "variables";
@use "colors";
@use "sizes";
@use "variables";

View File

@@ -14,64 +14,64 @@
* limitations under the License.
**/
@import "colors";
@import "sizes";
@import "variables";
@import "mixins";
@use "colors";
@use "sizes";
@use "variables";
@use "mixins";
@import "base";
@import "forms";
@use "base";
@use "forms";
@import "jquery";
@import "ace";
@use "jquery";
@use "ace";
@import "dropdownMenu";
@use "dropdownMenu";
@import "header";
@import "palette";
@import "sidebar";
@import "workspace";
@import "workspaceToolbar";
@use "header";
@use "palette";
@use "sidebar";
@use "workspace";
@use "workspaceToolbar";
@import "notifications";
@use "notifications";
@import "editor";
@import "library";
@import "search";
@use "editor";
@use "library";
@use "search";
@import "panels";
@import "tabs";
@import "tab-config";
@import "tab-context";
@import "tab-info";
@import "tab-help";
@import "popover";
@import "flow";
@import "palette-editor";
@import "diff";
@use "panels";
@use "tabs";
@use "tab-config";
@use "tab-context";
@use "tab-info";
@use "tab-help";
@use "popover";
@use "flow";
@use "palette-editor";
@use "diff";
@import "userSettings";
@use "userSettings";
@import "projects";
@use "projects";
@import "ui/common/editableList";
@import "ui/common/searchBox";
@import "ui/common/typedInput";
@import "ui/common/nodeList";
@import "ui/common/checkboxSet";
@import "ui/common/stack";
@import "ui/common/treeList";
@import "ui/common/autoComplete";
@use "ui/common/editableList";
@use "ui/common/searchBox";
@use "ui/common/typedInput";
@use "ui/common/nodeList";
@use "ui/common/checkboxSet";
@use "ui/common/stack";
@use "ui/common/treeList";
@use "ui/common/autoComplete";
@import "dragdrop";
@use "dragdrop";
@import "keyboard";
@use "keyboard";
@import "debug";
@use "debug";
@import "radialMenu";
@use "radialMenu";
@import "tourGuide";
@use "tourGuide";
@import "multiplayer";
@use "multiplayer";

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -38,7 +40,7 @@
background: var(--red-ui-secondary-background);
height: 100%;
overflow-y:auto;
@include disable-selection;
@include mixins.disable-selection;
&:focus {
outline: none;

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -25,6 +27,7 @@
padding-left: 9px;
line-height: 21px;
cursor: default;
border-bottom: 1px solid var(--red-ui-secondary-border-color);
> * {
vertical-align: middle
}
@@ -33,7 +36,6 @@
margin-left: 5px;
overflow-wrap: anywhere;
}
border-bottom: 1px solid var(--red-ui-secondary-border-color);
}
table.red-ui-info-table {
font-size: 14px;
@@ -307,7 +309,7 @@ div.red-ui-info-table {
text-align: center;
line-height: 1.9em;
color : var(--red-ui-tertiary-text-color);
@include disable-selection;
@include mixins.disable-selection;
cursor: default;
}
.red-ui-help-tips-buttons {

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -41,7 +43,7 @@
box-sizing:border-box;
border-bottom: 1px solid var(--red-ui-primary-border-color);
white-space: nowrap;
@include disable-selection;
@include mixins.disable-selection;
li {
box-sizing: border-box;
@@ -244,7 +246,7 @@
z-index: 2;
a {
@include workspace-button;
@include mixins.workspace-button;
line-height: 30px;
height: 28px;
width: 28px;
@@ -266,7 +268,7 @@
border-bottom: 1px solid var(--red-ui-primary-border-color);
z-index: 2;
a {
@include workspace-button-toggle;
@include mixins.workspace-button-toggle;
line-height: 26px;
height: 28px;
width: 28px;

View File

@@ -1,3 +1,5 @@
@use "../../mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -67,7 +69,7 @@
}
}
.red-ui-treeList-label {
@include disable-selection;
@include mixins.disable-selection;
padding: 6px 0;
display: flex;
align-items: center;

View File

@@ -1,3 +1,5 @@
@use "../../mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -67,7 +69,7 @@
}
}
.red-ui-typedInput-options {
@include component-shadow;
@include mixins.component-shadow;
font-family: var(--red-ui-primary-font);
font-size: var(--red-ui-primary-font-size);

View File

@@ -70,8 +70,14 @@
overflow-y: auto;
}
.red-ui-settings-row {
display: flex;
gap: 10px;
align-items:flex-start;
padding: 5px 10px 2px;
}
.red-ui-settings-row input[type="checkbox"] {
margin-top: 8px;
}
.red-ui-settings-section {
position: relative;
&:after {

View File

@@ -1,305 +1,309 @@
@use "sass:map";
@use "colors";
@use "sizes";
:root {
--red-ui-primary-font: #{$primary-font};
--red-ui-primary-font-size: #{$primary-font-size};
--red-ui-monospace-font: #{$monospace-font};
--red-ui-primary-font: #{colors.$primary-font};
--red-ui-primary-font-size: #{colors.$primary-font-size};
--red-ui-monospace-font: #{colors.$monospace-font};
--red-ui-primary-background: #{$primary-background};
--red-ui-primary-background: #{colors.$primary-background};
--red-ui-secondary-background: #{$secondary-background};
--red-ui-secondary-background-selected: #{$secondary-background-selected};
--red-ui-secondary-background-inactive: #{$secondary-background-inactive};
--red-ui-secondary-background-hover: #{$secondary-background-hover};
--red-ui-secondary-background-disabled: #{$secondary-background-disabled};
--red-ui-secondary-background: #{colors.$secondary-background};
--red-ui-secondary-background-selected: #{colors.$secondary-background-selected};
--red-ui-secondary-background-inactive: #{colors.$secondary-background-inactive};
--red-ui-secondary-background-hover: #{colors.$secondary-background-hover};
--red-ui-secondary-background-disabled: #{colors.$secondary-background-disabled};
--red-ui-tertiary-background: #{$tertiary-background};
--red-ui-tertiary-background: #{colors.$tertiary-background};
--red-ui-shadow: #{$shadow};
--red-ui-shadow: #{colors.$shadow};
// Header Height
--red-ui-header-height: #{$header-height};
--red-ui-header-height: #{sizes.$header-height};
// Main body text
--red-ui-primary-text-color: #{$primary-text-color};
--red-ui-primary-text-color: #{colors.$primary-text-color};
// UI control label text
--red-ui-secondary-text-color: #{$secondary-text-color};
--red-ui-secondary-text-color-focus: #{$secondary-text-color-focus};
--red-ui-secondary-text-color-hover: #{$secondary-text-color-hover};
--red-ui-secondary-text-color-active: #{$secondary-text-color-active};
--red-ui-secondary-text-color-selected: #{$secondary-text-color-selected};
--red-ui-secondary-text-color-inactive: #{$secondary-text-color-inactive};
--red-ui-secondary-text-color-disabled: #{$secondary-text-color-disabled};
--red-ui-secondary-text-color-disabled-active: #{$secondary-text-color-disabled-active};
--red-ui-secondary-text-color-disabled-inactive: #{$secondary-text-color-disabled-inactive};
--red-ui-secondary-text-color: #{colors.$secondary-text-color};
--red-ui-secondary-text-color-focus: #{colors.$secondary-text-color-focus};
--red-ui-secondary-text-color-hover: #{colors.$secondary-text-color-hover};
--red-ui-secondary-text-color-active: #{colors.$secondary-text-color-active};
--red-ui-secondary-text-color-selected: #{colors.$secondary-text-color-selected};
--red-ui-secondary-text-color-inactive: #{colors.$secondary-text-color-inactive};
--red-ui-secondary-text-color-disabled: #{colors.$secondary-text-color-disabled};
--red-ui-secondary-text-color-disabled-active: #{colors.$secondary-text-color-disabled-active};
--red-ui-secondary-text-color-disabled-inactive: #{colors.$secondary-text-color-disabled-inactive};
// Sub label text
--red-ui-tertiary-text-color: #{$tertiary-text-color};
--red-ui-tertiary-text-color: #{colors.$tertiary-text-color};
// Heading text
--red-ui-header-text-color: #{$header-text-color};
--red-ui-header-text-color: #{colors.$header-text-color};
--red-ui-text-color-error: #{$text-color-error};
--red-ui-text-color-warning: #{$text-color-warning};
--red-ui-text-color-success: #{$text-color-success};
--red-ui-text-color-code: #{$text-color-code};
--red-ui-text-color-link: #{$text-color-link};
--red-ui-text-color-error: #{colors.$text-color-error};
--red-ui-text-color-warning: #{colors.$text-color-warning};
--red-ui-text-color-success: #{colors.$text-color-success};
--red-ui-text-color-code: #{colors.$text-color-code};
--red-ui-text-color-link: #{colors.$text-color-link};
--red-ui-primary-border-color: #{$primary-border-color};
--red-ui-secondary-border-color: #{$secondary-border-color};
--red-ui-tertiary-border-color: #{$tertiary-border-color};
--red-ui-primary-border-color: #{colors.$primary-border-color};
--red-ui-secondary-border-color: #{colors.$secondary-border-color};
--red-ui-tertiary-border-color: #{colors.$tertiary-border-color};
--red-ui-border-color-error: #{$border-color-error};
--red-ui-border-color-warning: #{$border-color-warning};
--red-ui-border-color-success: #{$border-color-success};
--red-ui-border-color-error: #{colors.$border-color-error};
--red-ui-border-color-warning: #{colors.$border-color-warning};
--red-ui-border-color-success: #{colors.$border-color-success};
--red-ui-form-background: #{$form-background};
--red-ui-form-placeholder-color: #{$form-placeholder-color};
--red-ui-form-text-color: #{$form-text-color};
--red-ui-form-text-color-disabled: #{$form-text-color-disabled};
--red-ui-form-input-focus-color: #{$form-input-focus-color};
--red-ui-form-input-border-color: #{$form-input-border-color};
--red-ui-form-input-border-selected-color: #{$form-input-border-selected-color};
--red-ui-form-input-border-error-color: #{$form-input-border-error-color};
--red-ui-form-input-background: #{$form-input-background};
--red-ui-form-input-background-disabled: #{$form-input-background-disabled};
--red-ui-form-button-background: #{$form-button-background};
--red-ui-form-background: #{colors.$form-background};
--red-ui-form-placeholder-color: #{colors.$form-placeholder-color};
--red-ui-form-text-color: #{colors.$form-text-color};
--red-ui-form-text-color-disabled: #{colors.$form-text-color-disabled};
--red-ui-form-input-focus-color: #{colors.$form-input-focus-color};
--red-ui-form-input-border-color: #{colors.$form-input-border-color};
--red-ui-form-input-border-selected-color: #{colors.$form-input-border-selected-color};
--red-ui-form-input-border-error-color: #{colors.$form-input-border-error-color};
--red-ui-form-input-background: #{colors.$form-input-background};
--red-ui-form-input-background-disabled: #{colors.$form-input-background-disabled};
--red-ui-form-button-background: #{colors.$form-button-background};
--red-ui-form-tips-background: #{$form-tips-background};
--red-ui-form-tips-background: #{colors.$form-tips-background};
--red-ui-text-editor-color: #{$text-editor-color};
--red-ui-text-editor-background: #{$text-editor-background};
--red-ui-text-editor-color-disabled: #{$text-editor-color-disabled};
--red-ui-text-editor-background-disabled: #{$text-editor-background-disabled};
--red-ui-text-editor-gutter-background: #{$text-editor-gutter-background};
--red-ui-text-editor-gutter-color: #{$text-editor-gutter-color};
--red-ui-text-editor-gutter-active-line-background: #{$text-editor-gutter-active-line-background};
--red-ui-text-editor-active-line-background: #{$text-editor-active-line-background};
--red-ui-text-editor-selection-background: #{$text-editor-selection-background};
--red-ui-text-editor-color: #{colors.$text-editor-color};
--red-ui-text-editor-background: #{colors.$text-editor-background};
--red-ui-text-editor-color-disabled: #{colors.$text-editor-color-disabled};
--red-ui-text-editor-background-disabled: #{colors.$text-editor-background-disabled};
--red-ui-text-editor-gutter-background: #{colors.$text-editor-gutter-background};
--red-ui-text-editor-gutter-color: #{colors.$text-editor-gutter-color};
--red-ui-text-editor-gutter-active-line-background: #{colors.$text-editor-gutter-active-line-background};
--red-ui-text-editor-active-line-background: #{colors.$text-editor-active-line-background};
--red-ui-text-editor-selection-background: #{colors.$text-editor-selection-background};
--red-ui-event-log-background: #{$event-log-background};
--red-ui-event-log-color: #{$event-log-color};
--red-ui-event-log-active-line-background: #{$event-log-active-line-background};
--red-ui-event-log-selection-background: #{$event-log-selection-background};
--red-ui-event-log-background: #{colors.$event-log-background};
--red-ui-event-log-color: #{colors.$event-log-color};
--red-ui-event-log-active-line-background: #{colors.$event-log-active-line-background};
--red-ui-event-log-selection-background: #{colors.$event-log-selection-background};
--red-ui-list-item-color: #{$list-item-color};
--red-ui-list-item-secondary-color: #{$list-item-secondary-color};
--red-ui-list-item-background: #{$list-item-background};
--red-ui-list-item-background-disabled: #{$list-item-background-disabled};
--red-ui-list-item-background-hover: #{$list-item-background-hover};
--red-ui-list-item-background-selected: #{$list-item-background-selected};
--red-ui-list-item-border-selected: #{$list-item-border-selected};
--red-ui-list-item-color: #{colors.$list-item-color};
--red-ui-list-item-secondary-color: #{colors.$list-item-secondary-color};
--red-ui-list-item-background: #{colors.$list-item-background};
--red-ui-list-item-background-disabled: #{colors.$list-item-background-disabled};
--red-ui-list-item-background-hover: #{colors.$list-item-background-hover};
--red-ui-list-item-background-selected: #{colors.$list-item-background-selected};
--red-ui-list-item-border-selected: #{colors.$list-item-border-selected};
--red-ui-tab-text-color-active: #{$tab-text-color-active};
--red-ui-tab-text-color-inactive: #{$tab-text-color-inactive};
--red-ui-tab-text-color-disabled-active: #{$tab-text-color-disabled-active};
--red-ui-tab-text-color-disabled-inactive: #{$tab-text-color-disabled-inactive};
--red-ui-tab-text-color-active: #{colors.$tab-text-color-active};
--red-ui-tab-text-color-inactive: #{colors.$tab-text-color-inactive};
--red-ui-tab-text-color-disabled-active: #{colors.$tab-text-color-disabled-active};
--red-ui-tab-text-color-disabled-inactive: #{colors.$tab-text-color-disabled-inactive};
--red-ui-tab-badge-color: #{$tab-badge-color};
--red-ui-tab-background: #{$tab-background};
--red-ui-tab-background-active: #{$tab-background-active};
--red-ui-tab-background-active-alpha: #{$tab-background-active-alpha};
--red-ui-tab-background-selected: #{$tab-background-selected};
--red-ui-tab-background-selected-alpha: #{$tab-background-selected-alpha};
--red-ui-tab-background-inactive: #{$tab-background-inactive};
--red-ui-tab-background-inactive-alpha: #{$tab-background-inactive-alpha};
--red-ui-tab-background-hover: #{$tab-background-hover};
--red-ui-tab-background-hover-alpha: #{$tab-background-hover-alpha};
--red-ui-tab-badge-color: #{colors.$tab-badge-color};
--red-ui-tab-background: #{colors.$tab-background};
--red-ui-tab-background-active: #{colors.$tab-background-active};
--red-ui-tab-background-active-alpha: #{colors.$tab-background-active-alpha};
--red-ui-tab-background-selected: #{colors.$tab-background-selected};
--red-ui-tab-background-selected-alpha: #{colors.$tab-background-selected-alpha};
--red-ui-tab-background-inactive: #{colors.$tab-background-inactive};
--red-ui-tab-background-inactive-alpha: #{colors.$tab-background-inactive-alpha};
--red-ui-tab-background-hover: #{colors.$tab-background-hover};
--red-ui-tab-background-hover-alpha: #{colors.$tab-background-hover-alpha};
--red-ui-palette-header-background: #{$palette-header-background};
--red-ui-palette-header-color: #{$palette-header-color};
--red-ui-palette-content-background: #{$palette-content-background};
--red-ui-palette-header-background: #{colors.$palette-header-background};
--red-ui-palette-header-color: #{colors.$palette-header-color};
--red-ui-palette-content-background: #{colors.$palette-content-background};
--red-ui-workspace-button-background: #{$workspace-button-background};
--red-ui-workspace-button-background-hover: #{$workspace-button-background-hover};
--red-ui-workspace-button-background-active: #{$workspace-button-background-active};
--red-ui-workspace-button-background: #{colors.$workspace-button-background};
--red-ui-workspace-button-background-hover: #{colors.$workspace-button-background-hover};
--red-ui-workspace-button-background-active: #{colors.$workspace-button-background-active};
--red-ui-workspace-button-color: #{$workspace-button-color};
--red-ui-workspace-button-color-disabled: #{$workspace-button-color-disabled};
--red-ui-workspace-button-color-focus: #{$workspace-button-color-focus};
--red-ui-workspace-button-color-hover: #{$workspace-button-color-hover};
--red-ui-workspace-button-color-active: #{$workspace-button-color-active};
--red-ui-workspace-button-color-selected: #{$workspace-button-color-selected};
--red-ui-workspace-button-color: #{colors.$workspace-button-color};
--red-ui-workspace-button-color-disabled: #{colors.$workspace-button-color-disabled};
--red-ui-workspace-button-color-focus: #{colors.$workspace-button-color-focus};
--red-ui-workspace-button-color-hover: #{colors.$workspace-button-color-hover};
--red-ui-workspace-button-color-active: #{colors.$workspace-button-color-active};
--red-ui-workspace-button-color-selected: #{colors.$workspace-button-color-selected};
--red-ui-workspace-button-color-primary: #{$workspace-button-color-primary};
--red-ui-workspace-button-background-primary: #{$workspace-button-background-primary};
--red-ui-workspace-button-background-primary-hover: #{$workspace-button-background-primary-hover};
--red-ui-workspace-button-color-primary: #{colors.$workspace-button-color-primary};
--red-ui-workspace-button-background-primary: #{colors.$workspace-button-background-primary};
--red-ui-workspace-button-background-primary-hover: #{colors.$workspace-button-background-primary-hover};
--red-ui-workspace-button-color-focus-outline: #{$workspace-button-color-focus-outline};
--red-ui-workspace-button-color-focus-outline: #{colors.$workspace-button-color-focus-outline};
--red-ui-shade-color: #{$shade-color};
--red-ui-shade-color: #{colors.$shade-color};
--red-ui-popover-background: #{$popover-background};
--red-ui-popover-border: #{$popover-border};
--red-ui-popover-color: #{$popover-color};
--red-ui-popover-button-border-color: #{$popover-button-border-color};
--red-ui-popover-button-border-color-hover: #{$popover-button-border-color-hover};
--red-ui-popover-background: #{colors.$popover-background};
--red-ui-popover-border: #{colors.$popover-border};
--red-ui-popover-color: #{colors.$popover-color};
--red-ui-popover-button-border-color: #{colors.$popover-button-border-color};
--red-ui-popover-button-border-color-hover: #{colors.$popover-button-border-color-hover};
--red-ui-diff-text-header-color: #{$diff-text-header-color};
--red-ui-diff-text-header-background: #{$diff-text-header-background};
--red-ui-diff-state-color: #{$diff-state-color};
--red-ui-diff-state-prefix-color: #{$diff-state-prefix-color};
--red-ui-diff-state-added: #{$diff-state-added};
--red-ui-diff-state-deleted: #{$diff-state-deleted};
--red-ui-diff-state-changed: #{$diff-state-changed};
--red-ui-diff-state-changed-background: #{$diff-state-changed-background};
--red-ui-diff-state-unchanged: #{$diff-state-unchanged};
--red-ui-diff-state-unchanged-background: #{$diff-state-unchanged-background};
--red-ui-diff-text-header-color: #{colors.$diff-text-header-color};
--red-ui-diff-text-header-background: #{colors.$diff-text-header-background};
--red-ui-diff-state-color: #{colors.$diff-state-color};
--red-ui-diff-state-prefix-color: #{colors.$diff-state-prefix-color};
--red-ui-diff-state-added: #{colors.$diff-state-added};
--red-ui-diff-state-deleted: #{colors.$diff-state-deleted};
--red-ui-diff-state-changed: #{colors.$diff-state-changed};
--red-ui-diff-state-changed-background: #{colors.$diff-state-changed-background};
--red-ui-diff-state-unchanged: #{colors.$diff-state-unchanged};
--red-ui-diff-state-unchanged-background: #{colors.$diff-state-unchanged-background};
--red-ui-diff-state-conflicted: #{$diff-state-conflicted};
--red-ui-diff-state-moved: #{$diff-state-moved};
--red-ui-diff-state-conflict: #{$diff-state-conflict};
--red-ui-diff-state-conflict-background: #{$diff-state-conflict-background};
--red-ui-diff-state-conflicted: #{colors.$diff-state-conflicted};
--red-ui-diff-state-moved: #{colors.$diff-state-moved};
--red-ui-diff-state-conflict: #{colors.$diff-state-conflict};
--red-ui-diff-state-conflict-background: #{colors.$diff-state-conflict-background};
--red-ui-diff-state-added-background: #{$diff-state-added-background};
--red-ui-diff-state-added-border: #{$diff-state-added-border};
--red-ui-diff-state-added-header-background: #{$diff-state-added-header-background};
--red-ui-diff-state-added-header-border: #{$diff-state-added-header-border};
--red-ui-diff-state-added-background: #{colors.$diff-state-added-background};
--red-ui-diff-state-added-border: #{colors.$diff-state-added-border};
--red-ui-diff-state-added-header-background: #{colors.$diff-state-added-header-background};
--red-ui-diff-state-added-header-border: #{colors.$diff-state-added-header-border};
--red-ui-diff-state-deleted-background: #{$diff-state-deleted-background};
--red-ui-diff-state-deleted-border: #{$diff-state-deleted-border};
--red-ui-diff-state-deleted-header-background: #{$diff-state-deleted-header-background};
--red-ui-diff-state-deleted-header-border: #{$diff-state-deleted-header-border};
--red-ui-diff-state-deleted-background: #{colors.$diff-state-deleted-background};
--red-ui-diff-state-deleted-border: #{colors.$diff-state-deleted-border};
--red-ui-diff-state-deleted-header-background: #{colors.$diff-state-deleted-header-background};
--red-ui-diff-state-deleted-header-border: #{colors.$diff-state-deleted-header-border};
--red-ui-diff-merge-header-color: #{$diff-merge-header-color};
--red-ui-diff-merge-header-background: #{$diff-merge-header-background};
--red-ui-diff-merge-header-border-color: #{$diff-merge-header-border-color};
--red-ui-diff-merge-header-color: #{colors.$diff-merge-header-color};
--red-ui-diff-merge-header-background: #{colors.$diff-merge-header-background};
--red-ui-diff-merge-header-border-color: #{colors.$diff-merge-header-border-color};
--red-ui-menuBackground: #{$menuBackground};
--red-ui-menuDivider: #{$menuDivider};
--red-ui-menuColor: #{$menuColor};
--red-ui-menuActiveColor: #{$menuActiveColor};
--red-ui-menuActiveBackground: #{$menuActiveBackground};
--red-ui-menuDisabledColor: #{$menuDisabledColor};
--red-ui-menuHoverColor: #{$menuHoverColor};
--red-ui-menuHoverBackground: #{$menuHoverBackground};
--red-ui-menuCaret: #{$menuCaret};
--red-ui-menuBackground: #{colors.$menuBackground};
--red-ui-menuDivider: #{colors.$menuDivider};
--red-ui-menuColor: #{colors.$menuColor};
--red-ui-menuActiveColor: #{colors.$menuActiveColor};
--red-ui-menuActiveBackground: #{colors.$menuActiveBackground};
--red-ui-menuDisabledColor: #{colors.$menuDisabledColor};
--red-ui-menuHoverColor: #{colors.$menuHoverColor};
--red-ui-menuHoverBackground: #{colors.$menuHoverBackground};
--red-ui-menuCaret: #{colors.$menuCaret};
--red-ui-view-navigator-background: #{$view-navigator-background};
--red-ui-view-navigator-background: #{colors.$view-navigator-background};
--red-ui-view-lasso-stroke: #{$view-lasso-stroke};
--red-ui-view-lasso-fill: #{$view-lasso-fill};
--red-ui-view-lasso-stroke: #{colors.$view-lasso-stroke};
--red-ui-view-lasso-fill: #{colors.$view-lasso-fill};
--red-ui-view-background: #{$view-background};
--red-ui-view-grid-color: #{$view-grid-color};
--red-ui-view-background: #{colors.$view-background};
--red-ui-view-grid-color: #{colors.$view-grid-color};
--red-ui-node-label-color: #{$node-label-color};
--red-ui-node-port-label-color: #{$node-port-label-color};
--red-ui-node-border: #{$node-border};
--red-ui-node-border-unknown: #{$node-border-unknown};
--red-ui-node-border-placeholder: #{$node-border-placeholder};
--red-ui-node-background-placeholder: #{$node-background-placeholder};
--red-ui-node-label-color: #{colors.$node-label-color};
--red-ui-node-port-label-color: #{colors.$node-port-label-color};
--red-ui-node-border: #{colors.$node-border};
--red-ui-node-border-unknown: #{colors.$node-border-unknown};
--red-ui-node-border-placeholder: #{colors.$node-border-placeholder};
--red-ui-node-background-placeholder: #{colors.$node-background-placeholder};
--red-ui-node-port-background: #{$node-port-background};
--red-ui-node-port-background-hover: #{$node-port-background-hover};
--red-ui-node-icon-color: #{$node-icon-color};
--red-ui-node-icon-background-color: #{$node-icon-background-color};
--red-ui-node-icon-background-color-fill: #{$node-icon-background-color-fill};
--red-ui-node-icon-background-color-opacity: #{$node-icon-background-color-opacity};
--red-ui-node-icon-border-color: #{$node-icon-border-color};
--red-ui-node-icon-border-color-opacity: #{$node-icon-border-color-opacity};
--red-ui-node-port-background: #{colors.$node-port-background};
--red-ui-node-port-background-hover: #{colors.$node-port-background-hover};
--red-ui-node-icon-color: #{colors.$node-icon-color};
--red-ui-node-icon-background-color: #{colors.$node-icon-background-color};
--red-ui-node-icon-background-color-fill: #{colors.$node-icon-background-color-fill};
--red-ui-node-icon-background-color-opacity: #{colors.$node-icon-background-color-opacity};
--red-ui-node-icon-border-color: #{colors.$node-icon-border-color};
--red-ui-node-icon-border-color-opacity: #{colors.$node-icon-border-color-opacity};
--red-ui-node-config-background: #{$node-config-background};
--red-ui-node-config-icon-container-disabled: #{$node-config-icon-container-disabled};
--red-ui-node-config-background: #{colors.$node-config-background};
--red-ui-node-config-icon-container-disabled: #{colors.$node-config-icon-container-disabled};
--red-ui-node-link-port-background: #{$node-link-port-background};
--red-ui-node-link-port-background: #{colors.$node-link-port-background};
--red-ui-node-status-error-border: #{$node-status-error-border};
--red-ui-node-status-error-background: #{$node-status-error-background};
--red-ui-node-status-changed-border: #{$node-status-changed-border};
--red-ui-node-status-changed-background: #{$node-status-changed-background};
--red-ui-node-status-error-border: #{colors.$node-status-error-border};
--red-ui-node-status-error-background: #{colors.$node-status-error-background};
--red-ui-node-status-changed-border: #{colors.$node-status-changed-border};
--red-ui-node-status-changed-background: #{colors.$node-status-changed-background};
@each $current-color in red green yellow blue grey gray {
--red-ui-node-status-colors-#{"" + $current-color}: #{map-get($node-status-colors, $current-color)};
--red-ui-node-status-colors-#{"" + $current-color}: #{map.get(colors.$node-status-colors, $current-color)};
}
--red-ui-node-selected-color: #{$node-selected-color};
--red-ui-port-selected-color: #{$port-selected-color};
--red-ui-node-selected-color: #{colors.$node-selected-color};
--red-ui-port-selected-color: #{colors.$port-selected-color};
--red-ui-link-color: #{$link-color};
--red-ui-link-link-color: #{$link-link-color};
--red-ui-link-disabled-color: #{$link-disabled-color};
--red-ui-link-link-active-color: #{$link-link-active-color};
--red-ui-link-unknown-color: #{$link-unknown-color};
--red-ui-link-color: #{colors.$link-color};
--red-ui-link-link-color: #{colors.$link-link-color};
--red-ui-link-disabled-color: #{colors.$link-disabled-color};
--red-ui-link-link-active-color: #{colors.$link-link-active-color};
--red-ui-link-unknown-color: #{colors.$link-unknown-color};
--red-ui-clipboard-textarea-background: #{$clipboard-textarea-background};
--red-ui-clipboard-textarea-background: #{colors.$clipboard-textarea-background};
--red-ui-deploy-button-color: #{$deploy-button-color};
--red-ui-deploy-button-color-active: #{$deploy-button-color-active};
--red-ui-deploy-button-color-disabled: #{$deploy-button-color-disabled};
--red-ui-deploy-button-background: #{$deploy-button-background};
--red-ui-deploy-button-background-hover: #{$deploy-button-background-hover};
--red-ui-deploy-button-background-active: #{$deploy-button-background-active};
--red-ui-deploy-button-background-disabled: #{$deploy-button-background-disabled};
--red-ui-deploy-button-background-disabled-hover: #{$deploy-button-background-disabled-hover};
--red-ui-deploy-button-color: #{colors.$deploy-button-color};
--red-ui-deploy-button-color-active: #{colors.$deploy-button-color-active};
--red-ui-deploy-button-color-disabled: #{colors.$deploy-button-color-disabled};
--red-ui-deploy-button-background: #{colors.$deploy-button-background};
--red-ui-deploy-button-background-hover: #{colors.$deploy-button-background-hover};
--red-ui-deploy-button-background-active: #{colors.$deploy-button-background-active};
--red-ui-deploy-button-background-disabled: #{colors.$deploy-button-background-disabled};
--red-ui-deploy-button-background-disabled-hover: #{colors.$deploy-button-background-disabled-hover};
--red-ui-header-background: #{$header-background};
--red-ui-header-accent: #{$header-accent};
--red-ui-header-button-background-active: #{$header-button-background-active};
--red-ui-header-menu-color: #{$header-menu-color};
--red-ui-header-menu-color-disabled: #{$header-menu-color-disabled};
--red-ui-header-menu-heading-color: #{$header-menu-heading-color};
--red-ui-header-menu-sublabel-color: #{$header-menu-sublabel-color};
--red-ui-header-menu-background: #{$header-menu-background};
--red-ui-header-menu-item-hover: #{$header-menu-item-hover};
--red-ui-header-menu-item-border-active: #{$header-menu-item-border-active};
--red-ui-headerMenuItemDivider: #{$headerMenuItemDivider};
--red-ui-headerMenuCaret: #{$headerMenuCaret};
--red-ui-header-background: #{colors.$header-background};
--red-ui-header-accent: #{colors.$header-accent};
--red-ui-header-button-background-active: #{colors.$header-button-background-active};
--red-ui-header-menu-color: #{colors.$header-menu-color};
--red-ui-header-menu-color-disabled: #{colors.$header-menu-color-disabled};
--red-ui-header-menu-heading-color: #{colors.$header-menu-heading-color};
--red-ui-header-menu-sublabel-color: #{colors.$header-menu-sublabel-color};
--red-ui-header-menu-background: #{colors.$header-menu-background};
--red-ui-header-menu-item-hover: #{colors.$header-menu-item-hover};
--red-ui-header-menu-item-border-active: #{colors.$header-menu-item-border-active};
--red-ui-headerMenuItemDivider: #{colors.$headerMenuItemDivider};
--red-ui-headerMenuCaret: #{colors.$headerMenuCaret};
--red-ui-vcCommitShaColor: #{$vcCommitShaColor};
--red-ui-vcCommitShaColor: #{colors.$vcCommitShaColor};
--red-ui-dnd-background: #{$dnd-background};
--red-ui-dnd-color: #{$dnd-color};
--red-ui-dnd-background: #{colors.$dnd-background};
--red-ui-dnd-color: #{colors.$dnd-color};
--red-ui-notification-border-default: #{$notification-border-default};
--red-ui-notification-border-success: #{$notification-border-success};
--red-ui-notification-border-warning: #{$notification-border-warning};
--red-ui-notification-border-error: #{$notification-border-error};
--red-ui-notification-border-default: #{colors.$notification-border-default};
--red-ui-notification-border-success: #{colors.$notification-border-success};
--red-ui-notification-border-warning: #{colors.$notification-border-warning};
--red-ui-notification-border-error: #{colors.$notification-border-error};
--red-ui-debug-message-background: #{$debug-message-background};
--red-ui-debug-message-background-hover: #{$debug-message-background-hover};
--red-ui-debug-message-background: #{colors.$debug-message-background};
--red-ui-debug-message-background-hover: #{colors.$debug-message-background-hover};
--red-ui-debug-message-text-color: #{$debug-message-text-color};
--red-ui-debug-message-text-color-meta: #{$debug-message-text-color-meta};
--red-ui-debug-message-text-color-object-key: #{$debug-message-text-color-object-key};
--red-ui-debug-message-text-color-msg-type-other: #{$debug-message-text-color-msg-type-other};
--red-ui-debug-message-text-color-msg-type-string: #{$debug-message-text-color-msg-type-string};
--red-ui-debug-message-text-color-msg-type-null: #{$debug-message-text-color-msg-type-null};
--red-ui-debug-message-text-color-msg-type-meta: #{$debug-message-text-color-msg-type-meta};
--red-ui-debug-message-text-color-msg-type-number: #{$debug-message-text-color-msg-type-number};
--red-ui-debug-message-text-color: #{colors.$debug-message-text-color};
--red-ui-debug-message-text-color-meta: #{colors.$debug-message-text-color-meta};
--red-ui-debug-message-text-color-object-key: #{colors.$debug-message-text-color-object-key};
--red-ui-debug-message-text-color-msg-type-other: #{colors.$debug-message-text-color-msg-type-other};
--red-ui-debug-message-text-color-msg-type-string: #{colors.$debug-message-text-color-msg-type-string};
--red-ui-debug-message-text-color-msg-type-null: #{colors.$debug-message-text-color-msg-type-null};
--red-ui-debug-message-text-color-msg-type-meta: #{colors.$debug-message-text-color-msg-type-meta};
--red-ui-debug-message-text-color-msg-type-number: #{colors.$debug-message-text-color-msg-type-number};
--red-ui-debug-message-border: #{$debug-message-border};
--red-ui-debug-message-border-hover: #{$debug-message-border-hover};
--red-ui-debug-message-border-warning: #{$debug-message-border-warning};
--red-ui-debug-message-border-error: #{$debug-message-border-error};
--red-ui-debug-message-border: #{colors.$debug-message-border};
--red-ui-debug-message-border-hover: #{colors.$debug-message-border-hover};
--red-ui-debug-message-border-warning: #{colors.$debug-message-border-warning};
--red-ui-debug-message-border-error: #{colors.$debug-message-border-error};
--red-ui-group-default-fill: #{$group-default-fill};
--red-ui-group-default-fill-opacity: #{$group-default-fill-opacity};
--red-ui-group-default-stroke: #{$group-default-stroke};
--red-ui-group-default-stroke-opacity: #{$group-default-stroke-opacity};
--red-ui-group-default-label-color: #{$group-default-label-color};
--red-ui-group-default-fill: #{colors.$group-default-fill};
--red-ui-group-default-fill-opacity: #{colors.$group-default-fill-opacity};
--red-ui-group-default-stroke: #{colors.$group-default-stroke};
--red-ui-group-default-stroke-opacity: #{colors.$group-default-stroke-opacity};
--red-ui-group-default-label-color: #{colors.$group-default-label-color};
--red-ui-tourGuide-border: #{$tourGuide-border};
--red-ui-tourGuide-heading-color: #{$tourGuide-heading-color};
--red-ui-tourGuide-border: #{colors.$tourGuide-border};
--red-ui-tourGuide-heading-color: #{colors.$tourGuide-heading-color};
--red-ui-grip-color: #{$grip-color};
--red-ui-grip-color: #{colors.$grip-color};
--red-ui-icons-flow-color: #{$icons-flow-color};
--red-ui-icons-flow-color: #{colors.$icons-flow-color};
--red-ui-spinner-color: #{$spinner-color};
--red-ui-spinner-color: #{colors.$spinner-color};
--red-ui-tab-icon-color: #{$tab-icon-color};
--red-ui-tab-icon-color: #{colors.$tab-icon-color};
@each $current-color in 1 2 3 4 5 {
--red-ui-user-profile-colors-#{"" + $current-color}: #{map-get($user-profile-colors, $current-color)};
--red-ui-user-profile-colors-#{"" + $current-color}: #{map.get(colors.$user-profile-colors, $current-color)};
}
}

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -22,7 +24,7 @@
bottom: 0px;
right: 322px;
overflow: hidden;
@include component-border;
@include mixins.component-border;
transition: left 0.1s ease-in-out;
}
@@ -40,7 +42,7 @@
}
}
#red-ui-workspace-tabs-shade {
@include shade;
@include mixins.shade;
z-index: 2;
bottom: auto;
height: 35px;
@@ -157,7 +159,7 @@
}
.red-ui-component-footer {
@include component-footer;
@include mixins.component-footer;
> .button-group {
display: inline-block;
@@ -176,12 +178,12 @@
a.red-ui-footer-button,
button.red-ui-footer-button {
@include component-footer-button;
@include mixins.component-footer-button;
}
a.red-ui-footer-button-toggle,
button.red-ui-footer-button-toggle {
@include component-footer-button-toggle;
@include mixins.component-footer-button-toggle;
}
.red-ui-statusbar-widget {

View File

@@ -1,3 +1,5 @@
@use "mixins";
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
@@ -32,7 +34,7 @@
white-space: nowrap;
transition: right 0.2s ease;
overflow: hidden;
@include disable-selection;
@include mixins.disable-selection;
label {
padding: 1px 8px;
@@ -44,12 +46,12 @@
padding: 0;
}
.button {
@include workspace-button;
@include mixins.workspace-button;
margin-right: 10px;
padding: 2px 8px;
}
.button-group {
@include disable-selection;
@include mixins.disable-selection;
.button:first-child {
margin-right: 0;

View File

@@ -0,0 +1,231 @@
export default {
version: "4.0.0",
steps: [
{
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 4.0!",
"ja": "Node-RED 4.0 へようこそ!",
"fr": "Bienvenue dans Node-RED 4.0!"
},
description: {
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
"ja": "<p>本リリースの新機能を見つけてみましょう。</p>",
"fr": "<p>Prenons un moment pour découvrir les nouvelles fonctionnalités de cette version.</p>"
}
},
{
title: {
"en-US": "Multiplayer Mode",
"ja": "複数ユーザ同時利用モード",
"fr": "Mode Multi-utilisateur"
},
image: '4.0/images/nr4-multiplayer-location.png',
description: {
"en-US": `<p>This release includes the first small steps towards making Node-RED easier
to work with when you have multiple people editing flows at the same time.</p>
<p>When this feature is enabled, you will now see who else has the editor open and some
basic information on where they are in the editor.</p>
<p>Check the release post for details on how to enable this feature in your settings file.</p>`,
"ja": `<p>本リリースには、複数ユーザが同時にフローを編集する時に、Node-REDをより使いやすくするのための最初の微修正が入っています。</p>
<p>本機能を有効にすると、誰がエディタを開いているか、その人がエディタ上のどこにいるかの基本的な情報が表示されます。</p>
<p>設定ファイルで本機能を有効化する方法の詳細は、リリースの投稿を確認してください。</p>`,
"fr": `<p>Cette version inclut les premières étapes visant à rendre Node-RED plus facile à utiliser
lorsque plusieurs personnes modifient des flux en même temps.</p>
<p>Lorsque cette fonctionnalité est activée, vous pourrez désormais voir si dautres utilisateurs ont
ouvert l'éditeur. Vous pourrez également savoir où ces utilisateurs se trouvent dans l'éditeur.</p>
<p>Consultez la note de publication pour plus de détails sur la façon d'activer cette fonctionnalité
dans votre fichier de paramètres.</p>`
}
},
{
title: {
"en-US": "Better background deploy handling",
"ja": "バックグラウンドのデプロイ処理の改善",
"fr": "Meilleure gestion du déploiement en arrière-plan"
},
image: '4.0/images/nr4-background-deploy.png',
description: {
"en-US": `<p>If another user deploys changes whilst you are editing, we now use a more discrete notification
that doesn't stop you continuing your work - especially if they are being very productive and deploying lots
of changes.</p>`,
"ja": `他のユーザが変更をデプロイした時に、特に変更が多い生産的な編集作業を妨げないように通知するようになりました。`,
"fr": `<p>Si un autre utilisateur déploie des modifications pendant que vous êtes en train de modifier, vous recevrez
une notification plus discrète qu'auparavant qui ne vous empêche pas de continuer votre travail.</p>`
}
},
{
title: {
"en-US": "Improved flow diffs",
"ja": "フローの差分表示の改善",
"fr": "Amélioration des différences de flux"
},
image: '4.0/images/nr4-diff-update.png',
description: {
"en-US": `<p>When viewing changes made to a flow, Node-RED now distinguishes between nodes that have had configuration
changes and those that have only been moved.<p>
<p>When faced with a long list of changes to look at, this makes it much easier to focus on more significant items.</p>`,
"ja": `<p>フローの変更内容を表示する時に、Node-REDは設定が変更されたードと、移動されただけのードを区別するようになりました。<p>
<p>これによって、多くの変更内容を確認する際に、重要な項目に焦点を当てることができます。</p>`,
"fr": `<p>Lors de l'affichage des modifications apportées à un flux, Node-RED fait désormais la distinction entre les
noeuds qui ont changé de configuration et ceux qui ont seulement été déplacés.<p>
<p>Face à une longue liste de changements à examiner, il est beaucoup plus facile de se concentrer sur les éléments les
plus importants.</p>`
}
},
{
title: {
"en-US": "Better Configuration Node UX",
"ja": "設定ードのUXが向上",
"fr": "Meilleure expérience utilisateur du noeud de configuration"
},
image: '4.0/images/nr4-config-select.png',
description: {
"en-US": `<p>The Configuration node selection UI has had a small update to have a dedicated 'add' button
next to the select box.</p>
<p>It's a small change, but should make it easier to work with your config nodes.</p>`,
"ja": `<p>設定ードを選択するUIが修正され、選択ボックスの隣に専用の「追加」ボタンが追加されました。</p>
<p>微修正ですが設定ノードの操作が容易になります。</p>`,
"fr": `<p>L'interface utilisateur de la sélection du noeud de configuration a fait l'objet d'une petite
mise à jour afin de disposer d'un bouton « Ajouter » à côté de la zone de sélection.</p>
<p>C'est un petit changement, mais cela devrait faciliter le travail avec vos noeuds de configuration.</p>`
}
},
{
title: {
"en-US": "Timestamp formatting options",
"ja": "タイムスタンプの形式の項目",
"fr": "Options de formatage de l'horodatage"
},
image: '4.0/images/nr4-timestamp-formatting.png',
description: {
"en-US": `<p>Nodes that let you set a timestamp now have options on what format that timestamp should be in.</p>
<p>We're keeping it simple to begin with by providing three options:<p>
<ul>
<li>Milliseconds since epoch - this is existing behaviour of the timestamp option</li>
<li>ISO 8601 - a common format used by many systems</li>
<li>JavaScript Date Object</li>
</ul>`,
"ja": `<p>タイムスタンプを設定するノードに、タイムスタンプの形式を指定できる項目が追加されました。</p>
<p>次の3つの項目を追加したことで、簡単に選択できるようになりました:<p>
<ul>
<li>エポックからのミリ秒 - 従来動作と同じになるタイムスタンプの項目</li>
<li>ISO 8601 - 多くのシステムで使用されている共通の形式</li>
<li>JavaScript日付オブジェクト</li>
</ul>`,
"fr": `<p>Les noeuds qui vous permettent de définir un horodatage disposent désormais d'options sur le format dans lequel cet horodatage peut être défini.</p>
<p>Nous gardons les choses simples en proposant trois options :<p>
<ul>
<li>Millisecondes depuis l'époque : il s'agit du comportement existant de l'option d'horodatage</li>
<li>ISO 8601 : un format commun utilisé par de nombreux systèmes</li>
<li>Objet Date JavaScript</li>
</ul>`
}
},
{
title: {
"en-US": "Auto-complete of flow/global and env types",
"ja": "フロー/グローバル、環境変数の型の自動補完",
"fr": "Saisie automatique des types de flux/global et env"
},
image: '4.0/images/nr4-auto-complete.png',
description: {
"en-US": `<p>The <code>flow</code>/<code>global</code> context inputs and the <code>env</code> input
now all include auto-complete suggestions based on the live state of your flows.</p>
`,
"ja": `<p><code>flow</code>/<code>global</code>コンテキストや<code>env</code>の入力を、現在のフローの状態をもとに自動補完で提案するようになりました。</p>
`,
"fr": `<p>Les entrées contextuelles <code>flow</code>/<code>global</code> et l'entrée <code>env</code>
incluent désormais des suggestions de saisie semi-automatique basées sur l'état actuel de vos flux.</p>
`,
}
},
{
title: {
"en-US": "Config node customisation in Subflows",
"ja": "サブフローでの設定ノードのカスタマイズ",
"fr": "Personnalisation du noeud de configuration dans les sous-flux"
},
image: '4.0/images/nr4-sf-config.png',
description: {
"en-US": `<p>Subflows can now be customised to allow each instance to use a different
config node of a selected type.</p>
<p>For example, each instance of a subflow that connects to an MQTT Broker and does some post-processing
of the messages received can be pointed at a different broker.</p>
`,
"ja": `<p>サブフローをカスタマイズして、選択した型の異なる設定ノードを各インスタンスが使用できるようになりました。</p>
<p>例えば、MQTTブローカへ接続し、メッセージ受信と後処理を行うサブフローの各インスタンスに異なるブローカを指定することも可能です。</p>
`,
"fr": `<p>Les sous-flux peuvent désormais être personnalisés pour permettre à chaque instance d'utiliser un
noeud de configuration d'un type sélectionné.</p>
<p>Par exemple, chaque instance d'un sous-flux qui se connecte à un courtier MQTT et effectue un post-traitement
des messages reçus peut être pointée vers un autre courtier.</p>
`
}
},
{
title: {
"en-US": "Remembering palette state",
"ja": "パレットの状態を維持",
"fr": "Mémorisation de l'état de la palette"
},
description: {
"en-US": `<p>The palette now remembers what categories you have hidden between reloads - as well as any
filter you have applied.</p>`,
"ja": `<p>パレット上で非表示にしたカテゴリや適用したフィルタが、リロードしても記憶されるようになりました。</p>`,
"fr": `<p>La palette se souvient désormais des catégories que vous avez masquées entre les rechargements,
ainsi que le filtre que vous avez appliqué.</p>`
}
},
{
title: {
"en-US": "Plugins shown in the Palette Manager",
"ja": "パレット管理にプラグインを表示",
"fr": "Affichage des Plugins dans le gestionnaire de palettes"
},
image: '4.0/images/nr4-plugins.png',
description: {
"en-US": `<p>The palette manager now shows any plugin modules you have installed, such as
<code>node-red-debugger</code>. Previously they would only be shown if the plugins include
nodes for the palette.</p>`,
"ja": `<p>パレットの管理に <code>node-red-debugger</code> の様なインストールしたプラグインが表示されます。以前はプラグインにパレット向けのノードが含まれている時のみ表示されていました。</p>`,
"fr": `<p>Le gestionnaire de palettes affiche désormais tous les plugins que vous avez installés,
tels que <code>node-red-debugger</code>. Auparavant, ils n'étaient affichés que s'ils contenaient
des noeuds pour la palette.</p>`
}
},
{
title: {
"en-US": "Node Updates",
"ja": "ノードの更新",
"fr": "Mises à jour des noeuds"
},
// image: "images/",
description: {
"en-US": `<p>The core nodes have received lots of minor fixes, documentation updates and
small enhancements. Check the full changelog in the Help sidebar for a full list.</p>
<ul>
<li>A fully RFC4180 compliant CSV mode</li>
<li>Customisable headers on the WebSocket node</li>
<li>Split node now can operate on any message property</li>
<li>and lots more...</li>
</ul>`,
"ja": `<p>コアノードには沢山の軽微な修正、ドキュメント更新、小さな機能拡張が入っています。全リストはヘルプサイドバーにある変更履歴を参照してください。</p>
<ul>
<li>RFC4180に完全に準拠したCSVモード</li>
<li>WebSocketードのカスタマイズ可能なヘッダ</li>
<li>Splitードは、メッセージプロパティで操作できるようになりました</li>
<li>他にも沢山あります...</li>
</ul>`,
"fr": `<p>Les noeuds principaux ont reçu de nombreux correctifs mineurs ainsi que des améliorations. La documentation a été mise à jour.
Consultez le journal des modifications dans la barre latérale d'aide pour une liste complète. Ci-dessous, les changements les plus importants :</p>
<ul>
<li>Un mode CSV entièrement conforme à la norme RFC4180</li>
<li>En-têtes personnalisables pour le noeud WebSocket</li>
<li>Le noeud Split peut désormais fonctionner sur n'importe quelle propriété de message</li>
<li>Et bien plus encore...</li>
</ul>`
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,12 +1,12 @@
export default {
version: "4.0.0",
version: "4.1.0",
steps: [
{
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 4.0!",
"ja": "Node-RED 4.0 へようこそ!",
"fr": "Bienvenue dans Node-RED 4.0!"
"en-US": "Welcome to Node-RED 4.1!",
"ja": "Node-RED 4.1 へようこそ!",
"fr": "Bienvenue dans Node-RED 4.1!"
},
description: {
"en-US": "<p>Let's take a moment to discover the new features in this release.</p>",
@@ -16,184 +16,79 @@ export default {
},
{
title: {
"en-US": "Multiplayer Mode",
"ja": "複数ユーザ同時利用モード",
"fr": "Mode Multi-utilisateur"
"en-US": "Update notifications",
"ja": "更新の通知",
"fr": "Notifications de mise à jour"
},
image: 'images/nr4-multiplayer-location.png',
image: 'images/update-notification.png',
description: {
"en-US": `<p>This release includes the first small steps towards making Node-RED easier
to work with when you have multiple people editing flows at the same time.</p>
<p>When this feature is enabled, you will now see who else has the editor open and some
basic information on where they are in the editor.</p>
<p>Check the release post for details on how to enable this feature in your settings file.</p>`,
"ja": `<p>本リリースには、複数ユーザが同時にフローを編集する時に、Node-REDをより使いやすくするのための最初の微修正が入っています。</p>
<p>本機能を有効にすると、誰がエディタを開いているか、その人がエディタ上のどこにいるかの基本的な情報が表示されます。</p>
<p>設定ファイルで本機能を有効化する方法の詳細は、リリースの投稿を確認してください。</p>`,
"fr": `<p>Cette version inclut les premières étapes visant à rendre Node-RED plus facile à utiliser
lorsque plusieurs personnes modifient des flux en même temps.</p>
<p>Lorsque cette fonctionnalité est activée, vous pourrez désormais voir si dautres utilisateurs ont
ouvert l'éditeur. Vous pourrez également savoir où ces utilisateurs se trouvent dans l'éditeur.</p>
<p>Consultez la note de publication pour plus de détails sur la façon d'activer cette fonctionnalité
dans votre fichier de paramètres.</p>`
"en-US": `<p>Stay up to date with notifications when there is a new Node-RED version available, or updates to the nodes you have installed</p>`,
"ja": `<p>新バージョンのNode-REDの提供や、インストールしたードの更新があった時に、通知を受け取ることができます。</p>`,
"fr": `<p>Désormais vous recevrez une notification lorsqu'une nouvelle version de Node-RED ou une nouvelle version relative à un des noeuds que vous avez installés est disponible</p>`
}
},
{
title: {
"en-US": "Better background deploy handling",
"ja": "バックグラウンドのデプロイ処理の改善",
"fr": "Meilleure gestion du déploiement en arrière-plan"
"en-US": "Flow documentation",
"ja": "フローのドキュメント",
"fr": "Documentation des flux"
},
image: 'images/nr4-background-deploy.png',
image: 'images/node-docs.png',
description: {
"en-US": `<p>If another user deploys changes whilst you are editing, we now use a more discrete notification
that doesn't stop you continuing your work - especially if they are being very productive and deploying lots
of changes.</p>`,
"ja": `他のユーザが変更をデプロイした時に、特に変更が多い生産的な編集作業を妨げないように通知するようになりました。`,
"fr": `<p>Si un autre utilisateur déploie des modifications pendant que vous êtes en train de modifier, vous recevrez
une notification plus discrète qu'auparavant qui ne vous empêche pas de continuer votre travail.</p>`
"en-US": `<p>Quickly see which nodes have additional documentation with the new documentation icon.</p>
<p>Clicking on the icon opens up the Description tab of the node edit dialog.</p>`,
"ja": `<p>ドキュメントアイコンによって、どのノードにドキュメントが追加されているかをすぐに確認できます。</p>
<p>アイコンをクリックすると、ノード編集ダイアログの説明タブが開きます。</p>`,
"fr": `<p>Voyez rapidement quels noeuds ont une documentation supplémentaire avec la nouvelle icône de documentation.</p>
<p>Cliquer sur l'icône ouvre l'onglet Description de la boîte de dialogue d'édition du noeud.</p>`
}
},
{
title: {
"en-US": "Improved flow diffs",
"ja": "フローの差分表示の改善",
"fr": "Amélioration des différences de flux"
"en-US": "Palette Manager Improvements",
"ja": "パレットの管理の改善",
"fr": "Améliorations du Gestionnaire de Palettes"
},
image: 'images/nr4-diff-update.png',
description: {
"en-US": `<p>When viewing changes made to a flow, Node-RED now distinguishes between nodes that have had configuration
changes and those that have only been moved.<p>
<p>When faced with a long list of changes to look at, this makes it much easier to focus on more significant items.</p>`,
"ja": `<p>フローの変更内容を表示する時に、Node-REDは設定が変更されたードと、移動されただけのードを区別するようになりました。<p>
<p>これによって、多くの変更内容を確認する際に、重要な項目に焦点を当てることができます。</p>`,
"fr": `<p>Lors de l'affichage des modifications apportées à un flux, Node-RED fait désormais la distinction entre les
noeuds qui ont changé de configuration et ceux qui ont seulement été déplacés.<p>
<p>Face à une longue liste de changements à examiner, il est beaucoup plus facile de se concentrer sur les éléments les
plus importants.</p>`
}
},
{
title: {
"en-US": "Better Configuration Node UX",
"ja": "設定ードのUXが向上",
"fr": "Meilleure expérience utilisateur du noeud de configuration"
},
image: 'images/nr4-config-select.png',
description: {
"en-US": `<p>The Configuration node selection UI has had a small update to have a dedicated 'add' button
next to the select box.</p>
<p>It's a small change, but should make it easier to work with your config nodes.</p>`,
"ja": `<p>設定ードを選択するUIが修正され、選択ボックスの隣に専用の「追加」ボタンが追加されました。</p>
<p>微修正ですが設定ノードの操作が容易になります。</p>`,
"fr": `<p>L'interface utilisateur de la sélection du noeud de configuration a fait l'objet d'une petite
mise à jour afin de disposer d'un bouton « Ajouter » à côté de la zone de sélection.</p>
<p>C'est un petit changement, mais cela devrait faciliter le travail avec vos noeuds de configuration.</p>`
}
},
{
title: {
"en-US": "Timestamp formatting options",
"ja": "タイムスタンプの形式の項目",
"fr": "Options de formatage de l'horodatage"
},
image: 'images/nr4-timestamp-formatting.png',
description: {
"en-US": `<p>Nodes that let you set a timestamp now have options on what format that timestamp should be in.</p>
<p>We're keeping it simple to begin with by providing three options:<p>
"en-US": `<p>There are lots of improvements to the palette manager:</p>
<ul>
<li>Milliseconds since epoch - this is existing behaviour of the timestamp option</li>
<li>ISO 8601 - a common format used by many systems</li>
<li>JavaScript Date Object</li>
<li>Search results are sorted by downloads to help you find the most popular nodes</li>
<li>See which nodes have been deprecated by their author and are no longer recommended for use</li>
<li>Links to node documentation for the nodes you already have installed</li>
</ul>`,
"ja": `<p>タイムスタンプを設定するノードに、タイムスタンプの形式を指定できる項目が追加されました</p>
<p>次の3つの項目を追加したことで、簡単に選択できるようになりました:<p>
"ja": `<p>パレットの管理に多くの改善が加えられました:</p>
<ul>
<li>エポックからのミリ秒 - 従来動作と同じになるタイムスタンプの項目</li>
<li>ISO 8601 - 多くのシステムで使用されている共通の形式</li>
<li>JavaScript日付オブジェクト</li>
<li>検索結果はダウンロード数順で並べられ、最も人気のあるノードを見つけやすくなりました。</li>
<li>作者によって非推奨とされ、利用が推奨されなくなったノードかを確認できるようになりました。</li>
<li>既にインストールされているノードに、ノードのドキュメントへのリンクが追加されました。</li>
</ul>`,
"fr": `<p>Les noeuds qui vous permettent de définir un horodatage disposent désormais d'options sur le format dans lequel cet horodatage peut être défini.</p>
<p>Nous gardons les choses simples en proposant trois options :<p>
"fr": `<p>Le Gestionnaire de Palettes a bénéficié de nombreuses améliorations :</p>
<ul>
<li>Millisecondes depuis l'époque : il s'agit du comportement existant de l'option d'horodatage</li>
<li>ISO 8601 : un format commun utilisé par de nombreux systèmes</li>
<li>Objet Date JavaScript</li>
<li>Les résultats de recherche sont triés par téléchargement pour vous aider à trouver les noeuds les plus populaires.</li>
<li>Indique les noeuds obsolètes par leur auteur et dont l'utilisation n'est plus recommandée.</li>
<li>Liens vers la documentation des noeuds déjà installés.</li>
</ul>`
}
},
{
title: {
"en-US": "Auto-complete of flow/global and env types",
"ja": "フロー/グローバル、環境変数の型の自動補完",
"fr": "Saisie automatique des types de flux/global et env"
"en-US": "Installing missing modules",
"ja": "不足モジュールのインストール",
"fr": "Installation des modules manquants"
},
image: 'images/nr4-auto-complete.png',
image: 'images/missing-modules.png',
description: {
"en-US": `<p>The <code>flow</code>/<code>global</code> context inputs and the <code>env</code> input
now all include auto-complete suggestions based on the live state of your flows.</p>
"en-US": `<p>Flows exported from Node-RED 4.1 now include information on what additional modules need to be installed.</p>
<p>When importing a flow with this information, the editor will let you know what is missing and help to get them installed.</p>
`,
"ja": `<p><code>flow</code>/<code>global</code>コンテキストや<code>env</code>の入力を、現在のフローの状態をもとに自動補完で提案するようになりました。</p>
"ja": `<p>Node-RED 4.1から書き出したフローには、インストールが必要な追加モジュールの情報が含まれる様になりました。</p>
<p>この情報を含むフローを読み込むと、エディタは不足しているモジュールを通知し、インストールを支援します。</p>
`,
"fr": `<p>Les entrées contextuelles <code>flow</code>/<code>global</code> et l'entrée <code>env</code>
incluent désormais des suggestions de saisie semi-automatique basées sur l'état actuel de vos flux.</p>
`,
}
},
{
title: {
"en-US": "Config node customisation in Subflows",
"ja": "サブフローでの設定ノードのカスタマイズ",
"fr": "Personnalisation du noeud de configuration dans les sous-flux"
},
image: 'images/nr4-sf-config.png',
description: {
"en-US": `<p>Subflows can now be customised to allow each instance to use a different
config node of a selected type.</p>
<p>For example, each instance of a subflow that connects to an MQTT Broker and does some post-processing
of the messages received can be pointed at a different broker.</p>
`,
"ja": `<p>サブフローをカスタマイズして、選択した型の異なる設定ノードを各インスタンスが使用できるようになりました。</p>
<p>例えば、MQTTブローカへ接続し、メッセージ受信と後処理を行うサブフローの各インスタンスに異なるブローカを指定することも可能です。</p>
`,
"fr": `<p>Les sous-flux peuvent désormais être personnalisés pour permettre à chaque instance d'utiliser un
noeud de configuration d'un type sélectionné.</p>
<p>Par exemple, chaque instance d'un sous-flux qui se connecte à un courtier MQTT et effectue un post-traitement
des messages reçus peut être pointée vers un autre courtier.</p>
"fr": `<p>Les flux exportés depuis Node-RED 4.1 incluent désormais des informations sur les modules supplémentaires à installer.</p>
<p>Lors de l'importation d'un flux contenant ces informations, l'éditeur vous indiquera les modules manquants et vous aidera à les installer.</p>
`
}
},
{
title: {
"en-US": "Remembering palette state",
"ja": "パレットの状態を維持",
"fr": "Mémorisation de l'état de la palette"
},
description: {
"en-US": `<p>The palette now remembers what categories you have hidden between reloads - as well as any
filter you have applied.</p>`,
"ja": `<p>パレット上で非表示にしたカテゴリや適用したフィルタが、リロードしても記憶されるようになりました。</p>`,
"fr": `<p>La palette se souvient désormais des catégories que vous avez masquées entre les rechargements,
ainsi que le filtre que vous avez appliqué.</p>`
}
},
{
title: {
"en-US": "Plugins shown in the Palette Manager",
"ja": "パレット管理にプラグインを表示",
"fr": "Affichage des Plugins dans le gestionnaire de palettes"
},
image: 'images/nr4-plugins.png',
description: {
"en-US": `<p>The palette manager now shows any plugin modules you have installed, such as
<code>node-red-debugger</code>. Previously they would only be shown if the plugins include
nodes for the palette.</p>`,
"ja": `<p>パレットの管理に <code>node-red-debugger</code> の様なインストールしたプラグインが表示されます。以前はプラグインにパレット向けのノードが含まれている時のみ表示されていました。</p>`,
"fr": `<p>Le gestionnaire de palettes affiche désormais tous les plugins que vous avez installés,
tels que <code>node-red-debugger</code>. Auparavant, ils n'étaient affichés que s'ils contenaient
des noeuds pour la palette.</p>`
}
},
{
title: {
"en-US": "Node Updates",
@@ -205,26 +100,26 @@ export default {
"en-US": `<p>The core nodes have received lots of minor fixes, documentation updates and
small enhancements. Check the full changelog in the Help sidebar for a full list.</p>
<ul>
<li>A fully RFC4180 compliant CSV mode</li>
<li>Customisable headers on the WebSocket node</li>
<li>Split node now can operate on any message property</li>
<li>Support for <code>node:</code> prefixed modules in the Function node</li>
<li>The ability to set a global timeout for Function nodes via the runtime settings</li>
<li>Better display of error objects in the Debug sidebar</li>
<li>and lots more...</li>
</ul>`,
"ja": `<p>コアノードには沢山の軽微な修正、ドキュメント更新、小さな機能拡張が入っています。全リストはヘルプサイドバーにある変更履歴を参照してください。</p>
<ul>
<li>RFC4180に完全に準拠したCSVモード</li>
<li>WebSocketードのカスタマイズ可能なヘッダ</li>
<li>Splitードは、メッセージプロパティで操作できるようになりました</li>
<li>他にも沢山あります...</li>
<li>Functionードで<code>node:</code>のプレフィックスモジュールをサポート</li>
<li>ランタイム設定からFunctionードのグローバルタイムアウトを設定可能</li>
<li>デバッグサイドバーでのエラーオブジェクトの表示を改善</li>
<li>その他、多数...</li>
</ul>`,
"fr": `<p>Les noeuds principaux ont reçu de nombreux correctifs mineurs ainsi que des améliorations. La documentation a été mise à jour.
Consultez le journal des modifications dans la barre latérale d'aide pour une liste complète. Ci-dessous, les changements les plus importants :</p>
<ul>
<li>Un mode CSV entièrement conforme à la norme RFC4180</li>
<li>En-têtes personnalisables pour le noeud WebSocket</li>
<li>Le noeud Split peut désormais fonctionner sur n'importe quelle propriété de message</li>
<li>Et bien plus encore...</li>
</ul>`
"fr": `<p>Les noeuds principaux ont bénéficié de nombreux correctifs mineurs, de mises à jour de documentation et d'améliorations mineures.
Consultez le journal complet des modifications dans la barre latérale d'aide pour une liste complète.</p>
<ul>
<li>Prise en charge des modules préfixés <code>node:</code> dans le noeud Fonction.</li>
<li>Possibilité de définir un délai d'expiration global pour les noeuds Fonction via les paramètres d'exécution.</li>
<li>Meilleur affichage des objets d'erreur dans la barre latérale de débogage.</li>
<li>Et bien plus encore...</li>
</ul>`
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -46,12 +46,12 @@
<div class="form-row inject-time-row hidden" id="inject-time-row-interval">
<span data-i18n="inject.every"></span>
<input id="inject-time-interval-count" class="inject-time-count" value="1"></input>
<input id="inject-time-interval-count" class="inject-time-count" value="1">
<select style="width:100px" id="inject-time-interval-units">
<option value="s" data-i18n="inject.seconds"></option>
<option value="m" data-i18n="inject.minutes"></option>
<option value="h" data-i18n="inject.hours"></option>
</select><br/>
</select><br>
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-interval-time">
@@ -68,46 +68,46 @@
<option value="20">20</option>
<option value="30">30</option>
<option value="0">60</option>
</select> <span data-i18n="inject.minutes"></span><br/>
</select> <span data-i18n="inject.minutes"></span><br>
<span data-i18n="inject.between"></span> <select id="inject-time-interval-time-start" class="inject-time-times"></select>
<span data-i18n="inject.and"></span> <select id="inject-time-interval-time-end" class="inject-time-times"></select><br/>
<span data-i18n="inject.and"></span> <select id="inject-time-interval-time-end" class="inject-time-times"></select><br>
<div id="inject-time-interval-time-days" class="inject-time-days" style="margin-top:5px">
<div style="display:inline-block; vertical-align:top; margin-right:5px;" data-i18n="inject.on">on</div>
<div style="display:inline-block;">
<div>
<label><input type='checkbox' checked value='1'/> <span data-i18n="inject.days.0"></span></label>
<label><input type='checkbox' checked value='2'/> <span data-i18n="inject.days.1"></span></label>
<label><input type='checkbox' checked value='3'/> <span data-i18n="inject.days.2"></span></label>
<label><input type='checkbox' checked value='1'> <span data-i18n="inject.days.0"></span></label>
<label><input type='checkbox' checked value='2'> <span data-i18n="inject.days.1"></span></label>
<label><input type='checkbox' checked value='3'> <span data-i18n="inject.days.2"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='4'/> <span data-i18n="inject.days.3"></span></label>
<label><input type='checkbox' checked value='5'/> <span data-i18n="inject.days.4"></span></label>
<label><input type='checkbox' checked value='6'/> <span data-i18n="inject.days.5"></span></label>
<label><input type='checkbox' checked value='4'> <span data-i18n="inject.days.3"></span></label>
<label><input type='checkbox' checked value='5'> <span data-i18n="inject.days.4"></span></label>
<label><input type='checkbox' checked value='6'> <span data-i18n="inject.days.5"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='0'/> <span data-i18n="inject.days.6"></span></label>
<label><input type='checkbox' checked value='0'> <span data-i18n="inject.days.6"></span></label>
</div>
</div>
</div>
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-time">
<span data-i18n="inject.at"></span> <input type="text" id="inject-time-time" value="12:00"></input><br/>
<span data-i18n="inject.at"></span> <input type="text" id="inject-time-time" value="12:00"><br>
<div id="inject-time-time-days" class="inject-time-days">
<div style="display:inline-block; vertical-align:top; margin-right:5px;" data-i18n="inject.on"></div>
<div style="display:inline-block;">
<div>
<label><input type='checkbox' checked value='1'/> <span data-i18n="inject.days.0"></span></label>
<label><input type='checkbox' checked value='2'/> <span data-i18n="inject.days.1"></span></label>
<label><input type='checkbox' checked value='3'/> <span data-i18n="inject.days.2"></span></label>
<label><input type='checkbox' checked value='1'> <span data-i18n="inject.days.0"></span></label>
<label><input type='checkbox' checked value='2'> <span data-i18n="inject.days.1"></span></label>
<label><input type='checkbox' checked value='3'> <span data-i18n="inject.days.2"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='4'/> <span data-i18n="inject.days.3"></span></label>
<label><input type='checkbox' checked value='5'/> <span data-i18n="inject.days.4"></span></label>
<label><input type='checkbox' checked value='6'/> <span data-i18n="inject.days.5"></span></label>
<label><input type='checkbox' checked value='4'> <span data-i18n="inject.days.3"></span></label>
<label><input type='checkbox' checked value='5'> <span data-i18n="inject.days.4"></span></label>
<label><input type='checkbox' checked value='6'> <span data-i18n="inject.days.5"></span></label>
</div>
<div>
<label><input type='checkbox' checked value='0'/> <span data-i18n="inject.days.6"></span></label>
<label><input type='checkbox' checked value='0'> <span data-i18n="inject.days.6"></span></label>
</div>
</div>
</div>

View File

@@ -11,12 +11,13 @@
RED.nodes.registerType('global-config',{
category: 'config',
defaults: {
name: { value: "" },
env: { value: [] },
modules: { value: {} }
},
credentials: {
map: { type: "map" }
},
label: 'global-config',
oneditprepare: function() {
$('#node-input-edit-env-var').on('click', function(evt) {
RED.actions.invoke('core:show-user-settings', 'envvar')

View File

@@ -1,14 +1,22 @@
<script type="text/html" data-template-name="unknown">
<div class="form-tips"><span data-i18n="[html]unknown.tip"></span></div>
<div class="form-tips">
<span data-i18n="[html]unknown.tip"></span>
<p id="unknown-module-known">
<button id="unknown-manage-dependencies" class="red-ui-button"><span data-i18n="unknown.manageModules"></span></button>
</p>
</div>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('unknown',{
RED.nodes.registerType('unknown', {
category: 'unknown',
color:"#fff0f0",
color:"#fff000",
defaults: {
name: {value:""}
name: {value:""},
modules: { value: [] }
},
inputs:1,
outputs:1,
@@ -18,6 +26,20 @@
},
labelStyle: function() {
return "node_label_unknown";
},
oneditprepare: function () {
const node = this
if (this.modules && this.modules.length > 0) {
$('#unknown-manage-dependencies').on('click', function () {
RED.actions.invoke('core:cancel-edit-tray')
RED.actions.invoke('core:manage-palette', {
view: 'install',
filter: '"' + node.modules.join('", "') + '"'
})
})
} else {
$('#unknown-module-known').hide()
}
}
});
</script>

View File

@@ -536,10 +536,22 @@ RED.debug = (function() {
e.stopPropagation();
showMessageMenu(filterMessage,debugMessage,sourceNode&&sourceNode.id);
});
$('<span class="red-ui-debug-msg-topic">'+
(o.topic?topic+' : ':'')+
(o.property?'msg.'+property:'msg')+" : "+format+
'</span>').appendTo(metaRow);
const msgInfos = `${o.topic ? " : " : ""}msg${o.property ? "." + property : ""} : ${format}`
const topicTruncated = RED.utils.truncateString((o.topic ? topic : ""), 120 - msgInfos.length);
const topicElem = $('<span class="red-ui-debug-msg-topic">' + topicTruncated + msgInfos + '</span>').appendTo(metaRow);
if (topic !== topicTruncated) {
RED.popover.create({
content: topic,
delay: { show: 750, hide: 50 },
direction: "bottom",
interactive: true,
maxWidth: 300,
target: topicElem,
trigger: "hover",
tooltip: true,
size: "small"
});
}
}
var atBottom = (sbc.scrollHeight-messageList.height()-sbc.scrollTop) < 5;

View File

@@ -162,6 +162,8 @@ module.exports = function(RED) {
console:console,
util:util,
Buffer:Buffer,
URL: URL,
URLSearchParams: URLSearchParams,
Date: Date,
RED: {
util: {
@@ -403,6 +405,8 @@ module.exports = function(RED) {
if(node.timeout>0){
finOpt.timeout = node.timeout;
finOpt.breakOnSigint = true;
} else if (RED.settings.globalFunctionTimeout > 0){
finOpt.timeout = RED.settings.globalFunctionTimeout * 1000
}
}
var promise = Promise.resolve();
@@ -419,8 +423,14 @@ module.exports = function(RED) {
var opts = {};
if (node.timeout>0){
opts = node.timeoutOptions;
} else if (RED.settings. globalFunctionTimeout > 0){
opts.timeout = RED.settings. globalFunctionTimeout * 1000
}
try {
node.script.runInContext(context,opts);
} catch (err) {
return done(err);
}
node.script.runInContext(context,opts);
context.results.then(function(results) {
sendResults(node,send,msg._msgid,results,false);
if (handleNodeDoneCall) {

View File

@@ -21,8 +21,8 @@
</div>
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="switch.label.property"></span></label>
<input type="text" id="node-input-property" style="width: calc(100% - 105px)"/>
<input type="hidden" id="node-input-outputs"/>
<input type="text" id="node-input-property" style="width: calc(100% - 105px)">
<input type="hidden" id="node-input-outputs">
</div>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
@@ -35,7 +35,7 @@
</div>
<div class="form-row">
<input type="checkbox" id="node-input-repair" style="display: inline-block; width: auto; vertical-align: top;">
<label style="width: auto;" for="node-input-repair"><span data-i18n="switch.label.repair"></span></label></input>
<label style="width: auto;" for="node-input-repair"><span data-i18n="switch.label.repair"></span></label>
</div>
</script>

View File

@@ -2,7 +2,7 @@
<script type="text/html" data-template-name="range">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:calc(70% - 1px)"/>
<input type="text" id="node-input-property" style="width:calc(70% - 1px)">
</div>
<div class="form-row">
<label for="node-input-action"><i class="fa fa-dot-circle-o"></i> <span data-i18n="range.label.action"></span></label>
@@ -13,23 +13,23 @@
<option value="drop" data-i18n="range.scale.drop"></option>
</select>
</div>
<br/>
<br>
<div class="form-row"><i class="fa fa-sign-in"></i> <span data-i18n="range.label.inputrange"></span>:</div>
<div class="form-row"><label></label>
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minin" data-i18n="[placeholder]range.placeholder.min" style="width:100px;"/>
&nbsp;&nbsp;<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxin" data-i18n="[placeholder]range.placeholder.maxin" style="width:100px;"/>
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minin" data-i18n="[placeholder]range.placeholder.min" style="width:100px;">
&nbsp;&nbsp;<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxin" data-i18n="[placeholder]range.placeholder.maxin" style="width:100px;">
</div>
<div class="form-row"><i class="fa fa-sign-out"></i> <span data-i18n="range.label.resultrange"></span>:</div>
<div class="form-row"><label></label>
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minout" data-i18n="[placeholder]range.placeholder.min" style="width:100px;"/>
&nbsp;&nbsp;<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxout" data-i18n="[placeholder]range.placeholder.maxout" style="width:100px;"/>
<span data-i18n="range.label.from"></span>: <input type="text" id="node-input-minout" data-i18n="[placeholder]range.placeholder.min" style="width:100px;">
&nbsp;&nbsp;<span data-i18n="range.label.to"></span>: <input type="text" id="node-input-maxout" data-i18n="[placeholder]range.placeholder.maxout" style="width:100px;">
</div>
<br/>
<br>
<div class="form-row"><label></label>
<input type="checkbox" id="node-input-round" style="display: inline-block; width: auto; vertical-align: top;">
<label style="width: auto;" for="node-input-round"><span data-i18n="range.label.roundresult"></span></label></input>
<label style="width: auto;" for="node-input-round"><span data-i18n="range.label.roundresult"></span></label>
</div>
<br/>
<br>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">

View File

@@ -63,7 +63,7 @@
<li><span data-i18n="trigger.label.resetPayload"></span> <input type="text" id="node-input-reset" style="width:150px" data-i18n="[placeholder]trigger.label.resetprompt"></li>
</ul>
</div>
<br/>
<br>
<div class="form-row">
<label data-i18n="trigger.for" for="node-input-bytopic"></label>
<select id="node-input-bytopic" style="width:120px;">
@@ -71,12 +71,12 @@
<option value="topic" data-i18n="trigger.bytopics"></option>
</select>
<span class="form-row" id="node-stream-topic">
<input type="text" id="node-input-topic" style="width:46%;"/>
<input type="text" id="node-input-topic" style="width:46%;">
</span>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></input>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
<input type="hidden" id="node-input-outputs" value="1">
</div>
</script>

View File

@@ -91,7 +91,13 @@ module.exports = function(RED) {
const opts = isWindows ? { ...node.spawnOpt, shell: true } : node.spawnOpt
/* istanbul ignore else */
node.debug(cmd+" ["+arg+"]");
child = spawn(cmd,arg,opts);
if (opts.shell) {
// When called with shell: true, passing in separate args is deprecated in Node 24
// so we need to join the command and args into a single string.
child = spawn([cmd].concat(arg).join(" "), opts);
} else {
child = spawn(cmd,arg,opts);
}
node.status({fill:"blue",shape:"dot",text:"pid:"+child.pid});
var unknownCommand = (child.pid === undefined);
if (node.timer !== 0) {
@@ -109,7 +115,7 @@ module.exports = function(RED) {
child.stderr.on('data', function (data) {
if (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null) {
if (isUtf8(data)) { msg.payload = data.toString(); }
else { msg.payload = Buffer.from(data); }
else { msg.payload = data; }
nodeSend([null,RED.util.cloneMessage(msg),null]);
}
});
@@ -146,7 +152,8 @@ module.exports = function(RED) {
delete msg.payload;
if (stderr) {
msg2 = RED.util.cloneMessage(msg);
msg2.payload = stderr;
msg2.payload = Buffer.from(stderr,"binary");
if (isUtf8(msg2.payload)) { msg2.payload = msg2.payload.toString(); }
}
msg.payload = Buffer.from(stdout,"binary");
if (isUtf8(msg.payload)) { msg.payload = msg.payload.toString(); }

View File

@@ -25,7 +25,7 @@
</div>
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
<input type="text" id="node-input-property" style="width:70%;">
</div>
<div class="form-row" style="margin-bottom: 0px;">
<label> </label>
@@ -34,7 +34,7 @@
</div>
<div class="form-row">
<label> </label>
<input type="text" id="node-input-topi" style="width:70%;"/>
<input type="text" id="node-input-topi" style="width:70%;">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="rbe.label.name"></span></label>

View File

@@ -477,6 +477,16 @@
}
return RED._("node-red:mqtt.errors.invalid-topic");
}
function setupTopicField(node, input) {
input.autoComplete({
minLength: 0,
completionPluginType: 'node-red-mqtt-topic-autocomplete-source',
context: {
node
}
})
}
RED.nodes.registerType('mqtt-broker',{
category: 'config',
defaults: {
@@ -852,6 +862,7 @@
},
oneditprepare: function() {
const node = this;
setupTopicField(this, $("#node-input-topic"));
const isV5Broker = function() {
var confNode = RED.nodes.node($("#node-input-broker").val());
return confNode && confNode.protocolVersion === "5";
@@ -930,6 +941,7 @@
},
oneditprepare: function() {
var that = this;
setupTopicField(this, $("#node-input-topic"));
function showHideDynamicFields() {
var confNode = RED.nodes.node($("#node-input-broker").val());

View File

@@ -25,11 +25,22 @@
<option value="patch">PATCH</option>
</select>
</div>
<div class="form-row form-row-http-in-upload hide">
<div id="form-reqBody-http-in-controller" class="form-row hide" style="display: flex;">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-upload" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-upload" style="width: 70%;" data-i18n="httpin.label.upload"></label>
<div style="display: flex; margin-left: 5px; flex-direction: column-reverse; gap: 10px; justify-content: center;">
<div id="form-row-http-in-upload" class="hide" style="display: flex; gap: 10px">
<input type="checkbox" id="node-input-upload" style="margin: 0px;">
<label for="node-input-upload" style="text-wrap: nowrap; margin-bottom: 0;" data-i18n="httpin.label.upload"></label>
</div>
<div id="form-row-http-in-parsing" class="hide" style="display: flex; gap: 10px">
<input type="checkbox" id="node-input-skipBodyParsing" style="margin: 0px;">
<label for="node-input-skipBodyParsing" style="text-wrap: nowrap; margin-bottom: 0;" data-i18n="httpin.label.parsing"></label>
</div>
</div>
</div>
<div class="form-row">
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
<input id="node-input-url" type="text" placeholder="/url">
@@ -74,6 +85,7 @@
label:RED._("node-red:httpin.label.url")},
method: {value:"get",required:true},
upload: {value:false},
skipBodyParsing: {value:false},
swaggerDoc: {type:"swagger-doc", required:false}
},
inputs:0,
@@ -115,16 +127,22 @@
$('.row-swagger-doc').hide();
}
$("#node-input-method").on("change", function() {
if ($(this).val() === "post") {
$(".form-row-http-in-upload").show();
var method = $(this).val();
if(["post", "put", "patch","delete"].includes(method)){
$("#form-reqBody-http-in-controller").show();
$("#form-row-http-in-parsing").show();
if (method === "post") {
$("#form-row-http-in-upload").show();
} else {
$("#form-row-http-in-upload").hide();
}
} else {
$(".form-row-http-in-upload").hide();
$("#form-row-http-in-parsing").hide();
$("#form-row-http-in-upload").hide();
$("#form-reqBody-http-in-controller").hide();
}
}).change();
}
});
var headerTypes = [
{value:"content-type",label:"Content-Type",hasValue: false},

View File

@@ -16,6 +16,7 @@
module.exports = function(RED) {
"use strict";
var rootApp;
var bodyParser = require("body-parser");
var multer = require("multer");
var cookieParser = require("cookie-parser");
@@ -26,10 +27,11 @@ module.exports = function(RED) {
var mediaTyper = require('media-typer');
var isUtf8 = require('is-utf8');
var hashSum = require("hash-sum");
var rawDataRoutes = new Set();
function rawBodyParser(req, res, next) {
if (req.skipRawBodyParser) { next(); } // don't parse this if told to skip
if (req._body) { return next(); }
if (req.skipRawBodyParser || req._body || req.readableEnded) return next();
req.body = "";
req._body = true;
@@ -71,7 +73,65 @@ module.exports = function(RED) {
});
}
var corsSetup = false;
/**
* This method retrieves the root app by traversing the parent hierarchy.
* @param {import('express').Application} app
* @returns {import('express').Application}
*/
function getRootApp(app) {
if (typeof app.parent === 'undefined') {
return app;
}
return getRootApp(app.parent);
}
/**
* It provide the unique route key
* @param {{method: string, url: string}} obj
* @returns
*/
function getRouteKey(obj) {
var method = obj.method.toUpperCase();
// Normalize the URL by replacing double slashes with a single slash and removing the trailing slash
var url = obj.url.replace(/\/{2,}/g, '/').replace(/\/$/, '');
return `${method}:${url}`;
}
/**
* This middleware is for capture raw body
* @param {import('express').Request} req
* @param {import('express').Response} _res
* @param {import('express').NextFunction} next
* @returns
*/
function rawBodyCapture(req, _res, next) {
var routeKey = getRouteKey({ method: req.method, url: req._parsedUrl.pathname });
// Check if routeKey exist in rawDataRoutes
if (rawDataRoutes.has(routeKey)) {
// Convert the request stream to buffer
getBody(req, {
length: req.headers['content-length'],
}, function (err, buf) {
if (err) {
return next(err);
}
req.body = buf;
// Skip the body parsing
req.skipRawBodyParser = true;
req._body = true;
next();
})
} else {
next();
}
}
if(typeof RED.httpNode === 'function' && (rootApp = getRootApp(RED.httpNode))) {
// Add middleware to the stack
rootApp.use(rawBodyCapture);
// Move the middleware to top of the stack
rootApp._router.stack.unshift(rootApp._router.stack.pop());
}
function createRequestWrapper(node,req) {
// This misses a bunch of properties (eg headers). Before we use this function
@@ -125,6 +185,7 @@ module.exports = function(RED) {
return wrapper;
}
function createResponseWrapper(node,res) {
var wrapper = {
_res: res
@@ -188,9 +249,16 @@ module.exports = function(RED) {
}
this.method = n.method;
this.upload = n.upload;
this.skipBodyParsing = n.skipBodyParsing;
this.swaggerDoc = n.swaggerDoc;
var node = this;
var routeKey = getRouteKey({method: this.method, url: RED.httpNode.path() + this.url});
// If the user enables raw body, add it to the raw data routes.
if(this.skipBodyParsing) {
rawDataRoutes.add(routeKey);
}
this.errorHandler = function(err,req,res,next) {
node.warn(err);
@@ -227,7 +295,9 @@ module.exports = function(RED) {
}
var maxApiRequestSize = RED.settings.apiMaxLength || '5mb';
var jsonParser = bodyParser.json({limit:maxApiRequestSize});
var urlencParser = bodyParser.urlencoded({limit:maxApiRequestSize,extended:true});
var metricsHandler = function(req,res,next) { next(); }
@@ -253,6 +323,7 @@ module.exports = function(RED) {
if (this.upload) {
var mp = multer({ storage: multer.memoryStorage() }).any();
multipartParser = function(req,res,next) {
if(req.readableEnded || req._body) return next();
mp(req,res,function(err) {
req._body = true;
next(err);
@@ -261,18 +332,21 @@ module.exports = function(RED) {
}
if (this.method == "get") {
RED.httpNode.get(this.url,cookieParser(),httpMiddleware,corsHandler,metricsHandler,this.callback,this.errorHandler);
RED.httpNode.get(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, this.callback, this.errorHandler);
} else if (this.method == "post") {
RED.httpNode.post(this.url,cookieParser(),httpMiddleware,corsHandler,metricsHandler,jsonParser,urlencParser,multipartParser,rawBodyParser,this.callback,this.errorHandler);
RED.httpNode.post(this.url,cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, multipartParser, rawBodyParser, this.callback, this.errorHandler);
} else if (this.method == "put") {
RED.httpNode.put(this.url,cookieParser(),httpMiddleware,corsHandler,metricsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
RED.httpNode.put(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
} else if (this.method == "patch") {
RED.httpNode.patch(this.url,cookieParser(),httpMiddleware,corsHandler,metricsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
RED.httpNode.patch(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
} else if (this.method == "delete") {
RED.httpNode.delete(this.url,cookieParser(),httpMiddleware,corsHandler,metricsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
RED.httpNode.delete(this.url, cookieParser(), httpMiddleware, corsHandler, metricsHandler, jsonParser, urlencParser, rawBodyParser, this.callback, this.errorHandler);
}
this.on("close",function() {
// Remove it from the raw data routes if the node is closed
rawDataRoutes.delete(routeKey);
var node = this;
RED.httpNode._router.stack.forEach(function(route,i,routes) {
if (route.route && route.route.path === node.url && route.route.methods[node.method]) {
@@ -284,9 +358,9 @@ module.exports = function(RED) {
this.warn(RED._("httpin.errors.not-created"));
}
}
RED.nodes.registerType("http in",HTTPIn);
function HTTPOut(n) {
RED.nodes.createNode(this,n);
var node = this;
@@ -361,5 +435,6 @@ module.exports = function(RED) {
done();
});
}
RED.nodes.registerType("http response",HTTPOut);
}

View File

@@ -431,7 +431,7 @@ in your Node-RED user directory (${RED.settings.userDir}).
normalisedHeaders[k.toLowerCase()] = response.headers[k]
})
if (normalisedHeaders['www-authenticate']) {
let authHeader = buildDigestHeader(digestCreds.user,digestCreds.password, response.request.options.method, requestUrl.pathname, normalisedHeaders['www-authenticate'])
let authHeader = buildDigestHeader(digestCreds.user,digestCreds.password, response.request.options.method, requestUrl.pathname + requestUrl.search, normalisedHeaders['www-authenticate'])
options.headers.Authorization = authHeader;
}
// response.request.options.merge(options)
@@ -599,7 +599,18 @@ in your Node-RED user directory (${RED.settings.userDir}).
}
} else {
if (msg.hasOwnProperty('rejectUnauthorized')) {
opts.https = { rejectUnauthorized: msg.rejectUnauthorized };
if (typeof msg.rejectUnauthorized === 'boolean') {
opts.https = { rejectUnauthorized: msg.rejectUnauthorized }
} else if (typeof msg.rejectUnauthorized === 'string') {
if (msg.rejectUnauthorized.toLowerCase() === 'true' || msg.rejectUnauthorized.toLowerCase() === 'false') {
opts.https = { rejectUnauthorized: (msg.rejectUnauthorized.toLowerCase() === 'true') }
} else {
node.warn(RED._("httpin.errors.rejectunauthorized-invalid"))
}
} else {
node.warn(RED._("httpin.errors.rejectunauthorized-invalid"))
}
}
}

Some files were not shown because too many files have changed in this diff Show More