Merge branch 'node-red:master' into master

pull/4986/head
mschlgl 2025-08-21 11:54:52 +02:00 committed by GitHub
commit a2d530bc81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
203 changed files with 6229 additions and 2564 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 }}

1
.gitignore vendored
View File

@ -28,3 +28,4 @@ docs
.nyc_output
sync.ffs_db
package-lock.json
.editorconfig

View File

@ -1,3 +1,140 @@
#### 4.1.0: Milestone Release
- Fix: multipart form data upload issue (#5228) @debadutta98
- Update help document of filter node (#5210) @kazuhitoyokoi
- Fix inject node validation to support binary and hexadecimal numbers (#5212) @ZJvandeWeg
- Do not select a nearest node if move is active (#5199) @GogoVega
#### 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
- Add details for the dynamic subscription to match the English docs (#5050) @aikitori
- Fix tooltip snapping based on `typedInput` type (#5051) @GogoVega
- Prevent symbol usage warning in monaco (#5049) @Steve-Mcl
- Show subflow flow context under node section of sidebar (#5025) @knolleary
- feat: Add custom label for default deploy button in settings.editorTheme (#5030) @matiseni51
- Handle long auto-complete suggests (#5042) @knolleary
- Handle undefined username when generating user icon (#5043) @knolleary
- Handle dragging node into group and splicing link at same time (#5027) @knolleary
- Remember context sidebar tree state when refreshing (#5021) @knolleary
- Update sf instance env vars when removed from template (#5023) @knolleary
- Do not select group when triggering quick-add within it (#5022) @knolleary
- Fix library icon handling within library browser component (#5017) @knolleary
Runtime
- Allow env var access to context (#5016) @knolleary
- fix debug status reporting if null (#5018) @dceejay
- Fix grunt dev via better ndoemon ignore rules (#5015) @knolleary
- Fix typo in CHANGELOG (4.0.7-->4.0.8) (#5007) @natcl
Nodes
- Switch: Avoid exceeding call stack when draining message group in Switch (#5014) @knolleary
#### 4.0.8: 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.8",
"version": "4.1.0",
"description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org",
"license": "Apache-2.0",
@ -26,13 +26,14 @@
}
],
"dependencies": {
"acorn": "8.12.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": "2.4.3",
"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,51 +43,51 @@
"cronosjs": "1.7.1",
"denque": "2.1.0",
"express": "4.21.2",
"express-session": "1.18.1",
"form-data": "4.0.0",
"fs-extra": "11.2.0",
"express-session": "1.18.2",
"form-data": "4.0.4",
"fs-extra": "11.3.0",
"got": "12.6.1",
"hash-sum": "2.0.0",
"hpagent": "1.2.0",
"https-proxy-agent": "5.0.1",
"i18next": "21.10.0",
"i18next": "24.2.3",
"iconv-lite": "0.6.3",
"is-utf8": "0.2.1",
"js-yaml": "4.1.0",
"json-stringify-safe": "5.0.1",
"jsonata": "2.0.5",
"jsonata": "2.0.6",
"lodash.clonedeep": "^4.5.0",
"media-typer": "1.1.0",
"memorystore": "1.6.7",
"mime": "3.0.0",
"moment": "2.30.1",
"moment-timezone": "0.5.46",
"mqtt": "5.7.0",
"multer": "1.4.5-lts.1",
"moment-timezone": "0.5.48",
"mqtt": "5.11.0",
"multer": "2.0.2",
"mustache": "4.2.0",
"node-red-admin": "^4.0.1",
"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",
"raw-body": "3.0.0",
"rfdc": "^1.3.1",
"semver": "7.6.3",
"semver": "7.7.1",
"tar": "7.4.3",
"tough-cookie": "^5.0.0",
"uglify-js": "3.17.4",
"tough-cookie": "5.1.2",
"uglify-js": "3.19.3",
"uuid": "9.0.1",
"ws": "7.5.10",
"xml2js": "0.6.2"
},
"optionalDependencies": {
"@node-rs/bcrypt": "1.10.4"
"@node-rs/bcrypt": "1.10.7"
},
"devDependencies": {
"dompurify": "2.5.7",
"dompurify": "3.2.6",
"grunt": "1.6.1",
"grunt-chmod": "~1.1.1",
"grunt-cli": "~1.5.0",
@ -110,11 +111,11 @@
"jquery-i18next": "1.2.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "4.3.0",
"mermaid": "11.3.0",
"mermaid": "11.9.0",
"minami": "1.2.3",
"mocha": "9.2.2",
"node-red-node-test-helper": "^0.3.3",
"nodemon": "3.1.7",
"nodemon": "3.1.9",
"proxy": "^1.0.2",
"sass": "1.62.1",
"should": "13.2.3",

View File

@ -185,13 +185,12 @@ module.exports = {
}
if (theme.deployButton) {
themeSettings.deployButton = {};
if (theme.deployButton.label) {
themeSettings.deployButton.label = theme.deployButton.label;
}
if (theme.deployButton.type == "simple") {
themeSettings.deployButton = {
type: "simple"
}
if (theme.deployButton.label) {
themeSettings.deployButton.label = theme.deployButton.label;
}
themeSettings.deployButton.type = theme.deployButton.type;
if (theme.deployButton.icon) {
url = serveFile(themeApp,"/deploy/",theme.deployButton.icon);
if (url) {

View File

@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "4.0.8",
"version": "4.1.0",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@ -16,17 +16,17 @@
}
],
"dependencies": {
"@node-red/util": "4.0.8",
"@node-red/editor-client": "4.0.8",
"bcryptjs": "2.4.3",
"@node-red/util": "4.1.0",
"@node-red/editor-client": "4.1.0",
"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.1",
"multer": "2.0.2",
"mustache": "4.2.0",
"oauth2orize": "1.12.0",
"passport-http-bearer": "1.0.1",
@ -35,6 +35,6 @@
"ws": "7.5.10"
},
"optionalDependencies": {
"@node-rs/bcrypt": "1.10.4"
"@node-rs/bcrypt": "1.10.7"
}
}

View File

@ -58,7 +58,6 @@
"confirmDelete": "Confirm delete",
"delete": "Are you sure you want to delete '__label__'?",
"dropFlowHere": "Drop the flow here",
"dropImageHere": "Drop the image here",
"addFlow": "Add flow",
"addFlowToRight": "Add flow to the right",
"closeFlow": "Close flow",
@ -112,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",
@ -265,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",
@ -571,6 +573,7 @@
"filter": "filter nodes",
"search": "search modules",
"addCategory": "Add new...",
"loadingSuggestions": "Loading suggestions...",
"label": {
"subflows": "subflows",
"network": "network",
@ -624,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",
@ -639,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",
@ -649,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>",
@ -1274,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

@ -58,7 +58,6 @@
"confirmDelete": "Confirmar eliminación",
"delete": "¿Estás seguro de que quieres eliminar '__label__'?",
"dropFlowHere": "Suelta el flujo aquí",
"dropImageHere": "Suelta la imagen aquí",
"addFlow": "Añadir flujo",
"addFlowToRight": "Añadir flujo a la derecha",
"closeFlow": "Cerrar flujo",

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

@ -58,7 +58,6 @@
"confirmDelete": "Confirmer la suppression",
"delete": "Êtes-vous sûr de vouloir supprimer '__label__' ?",
"dropFlowHere": "Lâchez le flux ici",
"dropImageHere": "Lâchez l'image ici",
"addFlow": "Ajouter un flux",
"addFlowToRight": "Ajouter un flux à droite",
"closeFlow": "Fermer le flux",
@ -112,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",
@ -265,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",
@ -624,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",
@ -639,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",
@ -649,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>",
@ -1263,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

@ -58,7 +58,6 @@
"confirmDelete": "削除の確認",
"delete": "本当に '__label__' を削除しますか?",
"dropFlowHere": "ここにフローをドロップしてください",
"dropImageHere": "ここに画像ファイルをドロップしてください",
"addFlow": "フローの追加",
"addFlowToRight": "右側にフローを追加",
"closeFlow": "フローを閉じる",
@ -112,6 +111,7 @@
"userSettings": "ユーザ設定",
"nodes": "ノード",
"displayStatus": "ノードのステータスを表示",
"displayInfoIcon": "ノード情報のアイコンを表示",
"displayConfig": "設定ノード",
"import": "読み込み",
"importExample": "フロー例を読み込み",
@ -265,6 +265,8 @@
"download": "ダウンロード",
"importUnrecognised": "認識できない型が読み込まれました:",
"importUnrecognised_plural": "認識できない型が読み込まれました:",
"importWithModuleInfo": "必要なモジュールが不足",
"importWithModuleInfoDesc": "以下のノードは現在パレットにインストールされていませんが、読み込んだフローには必要なノードです:",
"importDuplicate": "重複したノードを読み込みました:",
"importDuplicate_plural": "重複したノードを読み込みました:",
"nodesExported": "クリップボードへフローを書き出しました",
@ -571,6 +573,7 @@
"filter": "ノードを検索",
"search": "ノードを検索",
"addCategory": "新規追加...",
"loadingSuggestions": "提案を読み込み中...",
"label": {
"subflows": "サブフロー",
"network": "ネットワーク",
@ -624,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": "全て無効化",
@ -639,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": "ノードを追加",
@ -649,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>",
@ -1263,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の説明を表示",
@ -1303,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": "上スクロール",
@ -1415,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.8",
"version": "4.1.0",
"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

@ -490,6 +490,13 @@ RED.history = (function() {
}
}
});
} else if (i === "color" && ev.node.type === "subflow") {
// Handle the Subflow definition color change
RED.utils.clearNodeColorCache();
const subflowDef = RED.nodes.getType("subflow:" + ev.node.id);
if (subflowDef) {
subflowDef.color = ev.changes[i] || "#DDAA99";
}
}
if (i === "credentials" && ev.changes[i]) {
// Reset - Only want to keep the changes
@ -556,6 +563,10 @@ RED.history = (function() {
if (node) {
node.changed = n.changed;
node.dirty = true;
if (ev.changes && ev.changes.hasOwnProperty('color')) {
node._colorChanged = true;
}
}
});
}

View File

@ -27,7 +27,6 @@ RED.i18n = (function() {
apiRootUrl = options.apiRootUrl||"";
var preferredLanguage = localStorage.getItem("editor-language") || detectLanguage();
var opts = {
compatibilityJSON: 'v3',
backend: {
loadPath: apiRootUrl+'locales/__ns__?lng=__lng__',
},

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

@ -398,14 +398,13 @@ RED.multiplayer = (function () {
anonIconBody.setAttribute("d",`M ${radius/2} ${radius/2 + 5} h -2.5 c -2 1 -2 -5 0.5 -4.5 c 2 1 2 1 4 0 c 2.5 -0.5 2.5 5.5 0 4.5 z`);
group.appendChild(anonIconBody)
} else {
const labelText = user.username ? user.username.substring(0,2) : user
const label = document.createElementNS("http://www.w3.org/2000/svg","text");
if (user.username) {
if (user.username || user.email) {
label.setAttribute("class","red-ui-multiplayer-annotation-label");
label.textContent = user.username.substring(0,2)
label.textContent = (user.username || user.email).substring(0,2)
} else {
label.setAttribute("class","red-ui-multiplayer-annotation-label red-ui-multiplayer-user-count")
label.textContent = user
label.textContent = 'nr'
}
label.setAttribute("text-anchor", "middle")
label.setAttribute("x",radius/2);

View File

@ -44,6 +44,51 @@ RED.nodes = (function() {
var dirty = false;
const internalProperties = [
"changed",
"dirty",
"id",
"inputLabels",
"moved",
"outputLabels",
"selected",
"type",
"users",
"valid",
"validationErrors",
"wires",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"_",
"_config",
"_def",
"_orig"
];
function setDirty(d) {
dirty = d;
if (!d) {
@ -231,7 +276,6 @@ RED.nodes = (function() {
def.type = nt;
nodeDefinitions[nt] = def;
if (def.defaults) {
for (var d in def.defaults) {
if (def.defaults.hasOwnProperty(d)) {
@ -242,6 +286,11 @@ RED.nodes = (function() {
console.warn(err);
}
}
if (internalProperties.includes(d)) {
console.warn(`registerType: ${nt}: the property "${d}" is internal and cannot be used.`);
delete def.defaults[d];
}
}
}
}
@ -689,7 +738,7 @@ RED.nodes = (function() {
}
}
function addNode(n) {
function addNode(n, opt) {
let newNode
if (!n.__isProxy__) {
newNode = new Proxy(n, nodeProxyHandler)
@ -728,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) {
@ -1494,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 || {};
@ -1529,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);
}
}
@ -1564,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;
@ -1608,6 +1677,9 @@ RED.nodes = (function() {
RED.nodes.eachNode(function(n) {
nns.push(convertNode(n, opts));
})
if (opts?.includeModuleConfig) {
updateGlobalConfigModuleList(nns);
}
return nns;
}
@ -1835,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;
@ -1970,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();
@ -2175,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])
@ -2403,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") {
@ -2412,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")) {
@ -2442,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]);
}
}
@ -2629,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]
}
@ -2695,7 +2861,8 @@ RED.nodes = (function() {
workspaces:new_workspaces,
subflows:new_subflows,
missingWorkspace: missingWorkspace,
removedNodes: removedNodes
removedNodes: removedNodes,
nodeMap: node_map
}
}
@ -3099,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) {
@ -3180,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) {
@ -61,7 +120,7 @@
}
this.menu = RED.popover.menu({
tabSelect: true,
width: 300,
width: Math.max(300, this.element.width()),
maxHeight: 200,
class: "red-ui-autoComplete-container",
options: completions,
@ -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

@ -63,6 +63,7 @@
pre: value.substring(0,idx),
match: value.substring(idx,idx+len),
post: value.substring(idx+len),
exact: idx === 0 && value.length === searchValue.length
}
}
function generateSpans(match) {
@ -83,7 +84,7 @@
const srcMatch = getMatch(optSrc, val);
if (valMatch.found || srcMatch.found) {
const element = $('<div>',{style: "display: flex"});
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
const valEl = $('<div/>',{ class: "red-ui-autoComplete-completion" });
valEl.append(generateSpans(valMatch));
valEl.appendTo(element);
if (optSrc) {
@ -159,7 +160,7 @@
if (valMatch.found) {
const optSrc = envVarsMap[v]
const element = $('<div>',{style: "display: flex"});
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
const valEl = $('<div/>',{ class: "red-ui-autoComplete-completion" });
valEl.append(generateSpans(valMatch))
valEl.appendTo(element)
@ -201,7 +202,7 @@
const that = this
const getContextKeysFromRuntime = function(scope, store, searchKey, done) {
contextKnownKeys[scope] = contextKnownKeys[scope] || {}
contextKnownKeys[scope][store] = contextKnownKeys[scope][store] || new Set()
contextKnownKeys[scope][store] = contextKnownKeys[scope][store] || new Map()
if (searchKey.length > 0) {
try {
RED.utils.normalisePropertyExpression(searchKey)
@ -223,11 +224,12 @@
const result = data[store] || {}
const keys = result.keys || []
const keyPrefix = searchKey + (searchKey.length > 0 ? '.' : '')
keys.forEach(key => {
keys.forEach(keyInfo => {
const key = keyInfo.key
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(key)) {
contextKnownKeys[scope][store].add(keyPrefix + key)
contextKnownKeys[scope][store].set(keyPrefix + key, keyInfo)
} else {
contextKnownKeys[scope][store].add(searchKey + "[\""+key.replace(/"/,"\\\"")+"\"]")
contextKnownKeys[scope][store].set(searchKey + "[\""+key.replace(/"/,"\\\"")+"\"]", keyInfo)
}
})
done()
@ -242,14 +244,14 @@
// Get the flow id of the node we're editing
const editStack = RED.editor.getEditStack()
if (editStack.length === 0) {
done([])
done(new Map())
return
}
const editingNode = editStack.pop()
if (editingNode.z) {
scope = `${scope}/${editingNode.z}`
} else {
done([])
done(new Map())
return
}
}
@ -269,17 +271,29 @@
return function(val, done) {
getContextKeys(val, function (keys) {
const matches = []
keys.forEach(v => {
keys.forEach((keyInfo, v) => {
let optVal = v
let valMatch = getMatch(optVal, val);
if (!valMatch.found && val.length > 0 && val.endsWith('.')) {
// Search key ends in '.' - but doesn't match. Check again
// with [" at the end instead so we match bracket notation
valMatch = getMatch(optVal, val.substring(0, val.length - 1) + '["')
if (!valMatch.found && val.length > 0) {
if (val.endsWith('.')) {
// Search key ends in '.' - but doesn't match. Check again
// with [" at the end instead so we match bracket notation
valMatch = getMatch(optVal, val.substring(0, val.length - 1) + '["')
// } else if (val.endsWith('[') && /^array/.test(keyInfo.format)) {
// console.log('this case')
}
}
if (valMatch.found) {
const element = $('<div>',{style: "display: flex"});
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
const valEl = $('<div/>',{ class: "red-ui-autoComplete-completion" });
// if (keyInfo.format) {
// valMatch.post += ' ' + keyInfo.format
// }
if (valMatch.exact && /^array/.test(keyInfo.format)) {
valMatch.post += `[0-${keyInfo.length}]`
optVal += '['
}
valEl.append(generateSpans(valMatch))
valEl.appendTo(element)
matches.push({
@ -505,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);
@ -1567,7 +1596,8 @@
if (tooltip) {
tooltip.setContent(valid);
} else {
tooltip = RED.popover.tooltip(this.elementDiv, valid);
const target = this.typeMap[type]?.options ? this.optionSelectLabel : this.elementDiv;
tooltip = RED.popover.tooltip(target, valid);
this.element.data("tooltip", tooltip);
}
}

View File

@ -46,10 +46,20 @@ RED.contextMenu = (function () {
hasEnabledNode = true;
}
}
if (n.l === undefined || n.l) {
hasLabeledNode = true;
if (n.l === undefined) {
// Check if the node sets showLabel in the defaults
// as that determines the default behaviour for the node
if (n._def.showLabel !== false) {
hasLabeledNode = true;
} else {
hasUnlabeledNode = true;
}
} else {
hasUnlabeledNode = true;
if (n.l) {
hasLabeledNode = true;
} else {
hasUnlabeledNode = true;
}
}
}
}

View File

@ -44,6 +44,7 @@ RED.deploy = (function() {
/**
* options:
* type: "default" - Button with drop-down options - no further customisation available
* label: the text to display - default: "Deploy"
* type: "simple" - Button without dropdown. Customisations:
* label: the text to display - default: "Deploy"
* icon : the icon to use. Null removes the icon. default: "red/images/deploy-full-o.svg"
@ -51,13 +52,14 @@ RED.deploy = (function() {
function init(options) {
options = options || {};
var type = options.type || "default";
var label = options.label || RED._("deploy.deploy");
if (type == "default") {
$('<li><span class="red-ui-deploy-button-group button-group">'+
'<a id="red-ui-header-button-deploy" class="red-ui-deploy-button disabled" href="#">'+
'<span class="red-ui-deploy-button-content">'+
'<img id="red-ui-header-button-deploy-icon" src="red/images/deploy-full-o.svg"> '+
'<span>'+RED._("deploy.deploy")+'</span>'+
'<span>'+label+'</span>'+
'</span>'+
'<span class="red-ui-deploy-button-spinner hide">'+
'<img src="red/images/spin.svg"/>'+
@ -78,7 +80,6 @@ RED.deploy = (function() {
mainMenuItems.push({id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"})
RED.menu.init({id:"red-ui-header-button-deploy-options", options: mainMenuItems });
} else if (type == "simple") {
var label = options.label || RED._("deploy.deploy");
var icon = 'red/images/deploy-full-o.svg';
if (options.hasOwnProperty('icon')) {
icon = options.icon;
@ -424,11 +425,15 @@ RED.deploy = (function() {
const unknownNodes = [];
const invalidNodes = [];
const isDisabled = function (node) {
return (node.d || RED.nodes.workspace(node.z)?.disabled);
};
RED.nodes.eachConfig(function (node) {
if (node.valid === undefined) {
RED.editor.validateNode(node);
}
if (!node.valid && !node.d) {
if (!node.valid && !isDisabled(node)) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
@ -438,7 +443,7 @@ RED.deploy = (function() {
}
});
RED.nodes.eachNode(function (node) {
if (!node.valid && !node.d) {
if (!node.valid && !isDisabled(node)) {
invalidNodes.push(getNodeInfo(node));
}
if (node.type === "unknown") {
@ -452,7 +457,7 @@ RED.deploy = (function() {
const unusedConfigNodes = [];
RED.nodes.eachConfig(function (node) {
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
if ((node._def.hasUsers !== false) && (node.users.length === 0) && !isDisabled(node)) {
unusedConfigNodes.push(getNodeInfo(node));
hasUnusedConfig = true;
}

View File

@ -295,8 +295,8 @@ RED.editor = (function() {
* Called when the node's properties have changed.
* Marks the node as dirty and needing a size check.
* Removes any links to non-existant outputs.
* @param node - the node that has been updated
* @param outputMap - (optional) a map of old->new port numbers if wires should be moved
* @param {object} node - the node that has been updated
* @param {object} [outputMap] - (optional) a map of old->new port numbers if wires should be moved
* @returns {array} the links that were removed due to this update
*/
function updateNodeProperties(node, outputMap) {
@ -1017,6 +1017,7 @@ RED.editor = (function() {
function showEditDialog(node, defaultTab) {
if (buildingEditDialog) { return }
if (editStack.includes(node)) { return }
buildingEditDialog = true;
if (node.z && RED.workspaces.isLocked(node.z)) { return }
var editing_node = node;
@ -1334,6 +1335,7 @@ RED.editor = (function() {
var editing_config_node = RED.nodes.node(id);
var activeEditPanes = [];
if (editStack.includes(editing_config_node)) { return }
if (editing_config_node && editing_config_node.z && RED.workspaces.isLocked(editing_config_node.z)) { return }
var configNodeScope = ""; // default to global
@ -1777,18 +1779,21 @@ RED.editor = (function() {
function showEditSubflowDialog(subflow, defaultTab) {
if (buildingEditDialog) { return }
if (editStack.includes(subflow)) { return }
buildingEditDialog = true;
var editing_node = subflow;
var activeEditPanes = [];
editStack.push(subflow);
RED.view.state(RED.state.EDITING);
var trayOptions = {
let editingNode = subflow;
let activeEditPanes = [];
const trayOptions = {
title: getEditStackTitle(),
buttons: [
{
id: "node-dialog-cancel",
text: RED._("common.label.cancel"),
click: function() {
click: function () {
RED.tray.close();
}
},
@ -1796,39 +1801,32 @@ RED.editor = (function() {
id: "node-dialog-ok",
class: "primary",
text: RED._("common.label.done"),
click: function() {
var i;
var editState = {
click: function () {
const wasDirty = RED.nodes.dirty();
const editState = {
changes: {},
changed: false,
outputMap: null
}
var wasDirty = RED.nodes.dirty();
};
activeEditPanes.forEach(function(pane) {
// Search for changes in edit boxes (panes)
// NOTE: no `oneditsave` for Subflow def
activeEditPanes.forEach(function (pane) {
if (pane.apply) {
pane.apply.call(pane, editState);
}
})
});
var newName = $("#subflow-input-name").val();
// Search for env changes (not handled in properties pane)
const oldEnv = editingNode.env;
const newEnv = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
if (newName != editing_node.name) {
editState.changes['name'] = editing_node.name;
editing_node.name = newName;
editState.changed = true;
}
var old_env = editing_node.env;
var new_env = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
if (new_env && new_env.length > 0) {
new_env.forEach(function(prop) {
if (newEnv && newEnv.length > 0) {
newEnv.forEach(function (prop) {
if (prop.type === "cred") {
editing_node.credentials = editing_node.credentials || {_:{}};
editing_node.credentials[prop.name] = prop.value;
editing_node.credentials['has_'+prop.name] = (prop.value !== "");
editingNode.credentials = editingNode.credentials || { _: {} };
editingNode.credentials[prop.name] = prop.value;
editingNode.credentials['has_' + prop.name] = (prop.value !== "");
if (prop.value !== '__PWRD__') {
editState.changed = true;
}
@ -1836,51 +1834,59 @@ RED.editor = (function() {
}
});
}
let envToRemove = new Set()
if (!isSameObj(old_env, new_env)) {
const envToRemove = new Set();
if (!isSameObj(oldEnv, newEnv)) {
// Get a list of env properties that have been removed
// by comparing old_env and new_env
if (old_env) {
old_env.forEach(env => { envToRemove.add(env.name) })
// by comparing oldEnv and newEnv
if (oldEnv) {
oldEnv.forEach((env) => { envToRemove.add(env.name) });
}
if (new_env) {
new_env.forEach(env => {
if (newEnv) {
newEnv.forEach((env) => {
envToRemove.delete(env.name)
})
});
}
editState.changes.env = editing_node.env;
editing_node.env = new_env;
editState.changes.env = oldEnv;
editingNode.env = newEnv;
editState.changed = true;
}
if (editState.changed) {
let wasChanged = editing_node.changed;
editing_node.changed = true;
validateNode(editing_node);
let subflowInstances = [];
let instanceHistoryEvents = []
RED.nodes.eachNode(function(n) {
if (n.type == "subflow:"+editing_node.id) {
const wasChanged = editingNode.changed;
const subflowInstances = [];
const instanceHistoryEvents = [];
// Marks the Subflow has changed and validate it
editingNode.changed = true;
validateNode(editingNode);
// Update each Subflow instances
RED.nodes.eachNode(function (n) {
if (n.type == "subflow:" + editingNode.id) {
subflowInstances.push({
id:n.id,
changed:n.changed
})
n._def.color = editing_node.color;
id: n.id,
changed: n.changed
});
n.changed = true;
n.dirty = true;
if (editState.changes.hasOwnProperty("color")) {
// Redraw the node color
n._colorChanged = true;
}
if (n.env) {
const oldEnv = n.env
const newEnv = []
let envChanged = false
const oldEnv = n.env;
const newEnv = [];
let envChanged = false;
n.env.forEach((env, index) => {
if (envToRemove.has(env.name)) {
envChanged = true
envChanged = true;
} else {
newEnv.push(env)
newEnv.push(env);
}
})
});
if (envChanged) {
instanceHistoryEvents.push({
t: 'edit',
@ -1888,104 +1894,109 @@ RED.editor = (function() {
changes: { env: oldEnv },
dirty: n.dirty,
changed: n.changed
})
n.env = newEnv
});
n.env = newEnv;
}
}
updateNodeProperties(n);
validateNode(n);
}
});
RED.events.emit("subflows:change",editing_node);
RED.nodes.dirty(true);
let historyEvent = {
t:'edit',
node:editing_node,
changes:editState.changes,
dirty:wasDirty,
changed:wasChanged,
t: 'edit',
node: editingNode,
changes: editState.changes,
dirty: wasDirty,
changed: wasChanged,
subflow: {
instances:subflowInstances
instances: subflowInstances
}
};
if (instanceHistoryEvents.length > 0) {
historyEvent = {
t: 'multi',
events: [ historyEvent, ...instanceHistoryEvents ],
dirty: wasDirty
}
};
}
RED.events.emit("subflows:change", editingNode);
RED.history.push(historyEvent);
RED.nodes.dirty(true);
}
editing_node.dirty = true;
editingNode.dirty = true;
RED.tray.close();
}
}
],
resize: function(dimensions) {
resize: function (dimensions) {
$(".red-ui-tray-content").height(dimensions.height - 50);
var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
var size = {width:form.width(),height:form.height()};
activeEditPanes.forEach(function(pane) {
const form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
const size = { width: form.width(), height: form.height() };
activeEditPanes.forEach(function (pane) {
if (pane.resize) {
pane.resize.call(pane, size);
}
})
});
},
open: function(tray, done) {
var trayFooter = tray.find(".red-ui-tray-footer");
var trayFooterLeft = $("<div/>", {
class: "red-ui-tray-footer-left"
}).appendTo(trayFooter)
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
open: function (tray, done) {
const trayBody = tray.find('.red-ui-tray-body');
const trayFooter = tray.find(".red-ui-tray-footer");
trayBody.parent().css('overflow', 'hidden');
const trayFooterLeft = $("<div/>", { class: "red-ui-tray-footer-left" }).appendTo(trayFooter);
$('<span style="margin-left: 10px"><i class="fa fa-info-circle"></i> <i id="red-ui-editor-subflow-user-count"></i></span>').appendTo(trayFooterLeft);
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
if (editingNode) {
RED.sidebar.info.refresh(editingNode);
}
var nodeEditPanes = [
const nodeEditPanes = [
'editor-tab-properties',
'editor-tab-subflow-module',
'editor-tab-description',
'editor-tab-appearance'
];
prepareEditDialog(trayBody, nodeEditPanes, subflow, subflow._def, "node-input", defaultTab, function(_activeEditPanes) {
prepareEditDialog(trayBody, nodeEditPanes, subflow, subflow._def, "subflow-input", defaultTab, function (_activeEditPanes) {
activeEditPanes = _activeEditPanes;
$("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name"));
trayBody.i18n();
trayFooter.i18n();
buildingEditDialog = false;
done();
});
},
close: function() {
close: function () {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(editing_node);
RED.sidebar.info.refresh(editingNode);
RED.workspaces.refresh();
activeEditPanes.forEach(function(pane) {
activeEditPanes.forEach(function (pane) {
if (pane.close) {
pane.close.call(pane);
}
})
});
editStack.pop();
editing_node = null;
// TODO: useless?
editingNode = null;
},
show: function() {
}
show: function () {}
}
RED.tray.show(trayOptions);
}
function showEditGroupDialog(group, defaultTab) {
if (buildingEditDialog) { return }
if (editStack.includes(group)) { return }
buildingEditDialog = true;
if (group.z && RED.workspaces.isLocked(group.z)) { return }
var editing_node = group;
@ -2100,6 +2111,7 @@ RED.editor = (function() {
function showEditFlowDialog(workspace, defaultTab) {
if (buildingEditDialog) { return }
if (editStack.includes(workspace)) { return }
buildingEditDialog = true;
var activeEditPanes = [];
RED.view.state(RED.state.EDITING);

View File

@ -46,8 +46,8 @@
initialised = selectedCodeEditor.init();
}
$('<div id="red-ui-image-drop-target"><div data-i18n="[append]workspace.dropImageHere"><i class="fa fa-download"></i><br></div></div>').appendTo('#red-ui-editor');
$("#red-ui-image-drop-target").hide();
$('<div id="red-ui-drop-target-markdown-editor"><div><i class="fa fa-download"></i><br></div></div>').appendTo('#red-ui-editor');
$("#red-ui-drop-target-markdown-editor").hide();
}
function create(options) {

View File

@ -691,6 +691,7 @@ RED.editor.codeEditor.monaco = (function() {
2322, //Type 'unknown' is not assignable to type 'string'
2339, //property does not exist on
2345, //Argument of type xxx is not assignable to parameter of type 'DateTimeFormatOptions'
2538, //Ignore symbols as index property error.
7043, //i forget what this one is,
80001, //Convert to ES6 module
80004, //JSDoc types may be moved to TypeScript types.
@ -1425,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;
}
@ -1434,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

@ -27,6 +27,12 @@
reader.readAsDataURL(file);
}
function file2Text(file,cb) {
file.arrayBuffer().then(d => {
cb( new TextDecoder().decode(d) )
}).catch(ex => { cb(`error: ${ex}`) })
}
var initialized = false;
var currentEditor = null;
/**
@ -35,16 +41,22 @@
function initImageDrag(elem, editor) {
$(elem).on("dragenter", function (ev) {
ev.preventDefault();
$("#red-ui-image-drop-target").css({display:'table'}).focus();
$("#red-ui-drop-target-markdown-editor").css({
display:'table',
top: $(elem).offset().top,
left: $(elem).offset().left,
width: $(elem).width(),
height: $(elem).height()
}).focus();
currentEditor = editor;
});
if (!initialized) {
initialized = true;
$("#red-ui-image-drop-target").on("dragover", function (ev) {
$("#red-ui-drop-target-markdown-editor").on("dragover", function (ev) {
ev.preventDefault();
}).on("dragleave", function (ev) {
$("#red-ui-image-drop-target").hide();
$("#red-ui-drop-target-markdown-editor").hide();
}).on("drop", function (ev) {
ev.preventDefault();
if ($.inArray("Files",ev.originalEvent.dataTransfer.types) != -1) {
@ -52,20 +64,43 @@
if (files.length === 1) {
var file = files[0];
var name = file.name.toLowerCase();
var fileType = file.type.toLowerCase();
if (name.match(/\.(apng|avif|gif|jpeg|png|svg|webp)$/)) {
file2base64Image(file, function (image) {
var session = currentEditor.getSession();
var img = `<img src="${image}"/>\n`;
var pos = session.getCursorPosition();
session.insert(pos, img);
$("#red-ui-image-drop-target").hide();
$("#red-ui-drop-target-markdown-editor").hide();
});
return;
}
if ( fileType.startsWith("text/") ) {
file2Text(file, function (txt) {
var session = currentEditor.getSession();
var pos = session.getCursorPosition();
session.insert(pos, txt);
$("#red-ui-drop-target-markdown-editor").hide();
});
return;
}
}
} else if ($.inArray("text/plain", ev.originalEvent.dataTransfer.types) != -1) {
let item = Object.values(ev.originalEvent.dataTransfer.items).filter(d => d.type == "text/plain")[0]
if (item) {
item.getAsString(txt => {
var session = currentEditor.getSession();
var pos = session.getCursorPosition();
session.insert(pos, txt);
$("#red-ui-drop-target-markdown-editor").hide();
})
return
}
}
$("#red-ui-image-drop-target").hide();
$("#red-ui-drop-target-markdown-editor").hide();
});
}
}

View File

@ -44,7 +44,7 @@ RED.editor.mermaid = (function () {
nodes.forEach(async node => {
if (!node.getAttribute('mermaid-processed')) {
const mermaidContent = node.innerText
const mermaidContent = atob($(node).data('c64'))
node.setAttribute('mermaid-processed', true)
try {
const { svg } = await mermaid.render('mermaid-render-'+Date.now()+'-'+(diagramIds++), mermaidContent);

View File

@ -26,6 +26,8 @@
if (node._def.category === "config" && nodeType !== "group") {
this.inputClass = "node-config-input";
formStyle = "node-config-dialog-edit-form";
} else if (node.type === "subflow") {
this.inputClass = "subflow-input";
}
RED.editor.buildEditForm(container,formStyle,nodeType,i18nNamespace,node);
},

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

File diff suppressed because it is too large Load Diff

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
}
@ -401,7 +401,7 @@ RED.palette = (function() {
} else {
// Firefox doesn't do getIntersectionList and that
// makes us sad
nodes = RED.view.getLinksAtPoint(mouseX,mouseY);
nodes = RED.view.getLinksAtPoint(mouseX / RED.view.scale(), mouseY / RED.view.scale());
}
var mx = mouseX / RED.view.scale();
var my = mouseY / RED.view.scale();
@ -562,7 +562,7 @@ RED.palette = (function() {
}
}
paletteNode.css("backgroundColor", sf.color);
paletteNode.css("backgroundColor", RED.utils.getNodeColor("subflow", sf._def));
}
function refreshFilter() {
@ -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

@ -52,11 +52,21 @@ RED.sidebar.config = (function() {
if (label) {
lockIcon = $('<span style="margin-right: 5px"><i class="fa fa-lock"/></span>').appendTo(header)
lockIcon.toggle(!!isLocked)
$('<span class="red-ui-sidebar-config-category-disabled-icon" style="margin-right: 5px"><i class="fa fa-ban"/></span>').appendTo(header)
$('<span class="red-ui-palette-node-config-label"/>').text(label).appendTo(header);
} else {
$('<span class="red-ui-palette-node-config-label" data-i18n="sidebar.config.'+name+'">').appendTo(header);
}
$('<span class="red-ui-sidebar-node-config-filter-info"></span>').appendTo(header);
const changeBadgeContainer = $('<svg class="red-ui-sidebar-config-category-changed red-ui-flow-node-changed" width="10" height="10" viewBox="-1 -1 12 12"></svg>').appendTo(header);
const changeBadge = document.createElementNS("http://www.w3.org/2000/svg", "circle");
changeBadge.setAttribute("cx", "5");
changeBadge.setAttribute("cy", "5");
changeBadge.setAttribute("r", "5");
changeBadgeContainer.append(changeBadge);
category = $('<ul class="red-ui-palette-content red-ui-sidebar-node-config-list"></ul>').appendTo(container);
category.on("click", function(e) {
$(content).find(".red-ui-palette-node").removeClass("selected");
@ -150,9 +160,6 @@ RED.sidebar.config = (function() {
$('<li class="red-ui-palette-node-config-type">'+node.type+'</li>').appendTo(list);
currentType = node.type;
}
if (node.changed) {
labelText += "!!"
}
var entry = $('<li class="red-ui-palette-node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
var nodeDiv = $('<div class="red-ui-palette-node-config red-ui-palette-node"></div>').appendTo(entry);
entry.data('node',node.id);
@ -181,15 +188,29 @@ RED.sidebar.config = (function() {
}
}
if (node.changed) {
const nodeDivAnnotations = $('<svg class="red-ui-palette-node-annotations red-ui-flow-node-changed" width="10" height="10" viewBox="-1 -1 12 12"></svg>').appendTo(nodeDiv);
const changeBadge = document.createElementNS("http://www.w3.org/2000/svg", "circle");
changeBadge.setAttribute("cx", "5");
changeBadge.setAttribute("cy", "5");
changeBadge.setAttribute("r", "5");
nodeDivAnnotations.append($(changeBadge));
const categoryHeader = list.parent().find(".red-ui-sidebar-config-tray-header.red-ui-palette-header");
categoryHeader.addClass("red-ui-sidebar-config-changed");
nodeDiv.addClass("red-ui-palette-node-config-changed");
}
if (!node.valid) {
nodeDiv.addClass("red-ui-palette-node-config-invalid")
const nodeDivAnnotations = $('<svg class="red-ui-palette-node-annotations red-ui-flow-node-error" width="10" height="10"></svg>').appendTo(nodeDiv)
const errorBadge = document.createElementNS("http://www.w3.org/2000/svg","path");
errorBadge.setAttribute("d","M 0,9 l 10,0 -5,-8 z");
nodeDivAnnotations.append($(errorBadge))
const nodeDivAnnotations = $('<svg class="red-ui-palette-node-annotations red-ui-flow-node-error" width="10" height="10"></svg>').appendTo(nodeDiv);
const errorBadge = document.createElementNS("http://www.w3.org/2000/svg", "path");
errorBadge.setAttribute("d", "M 0,9 l 10,0 -5,-8 z");
nodeDivAnnotations.append($(errorBadge));
nodeDiv.addClass("red-ui-palette-node-config-invalid");
RED.popover.tooltip(nodeDivAnnotations, function () {
if (node.validationErrors && node.validationErrors.length > 0) {
return RED._("editor.errors.invalidProperties")+"<br> - "+node.validationErrors.join("<br> - ")
return RED._("editor.errors.invalidProperties") + "<br> - " + node.validationErrors.join("<br> - ");
}
})
}
@ -251,7 +272,13 @@ RED.sidebar.config = (function() {
if (!validList[id]) {
$(this).remove();
delete categories[id];
} else if (RED.nodes.workspace(id)) {
$(this).toggleClass("red-ui-sidebar-config-category-disabled", RED.nodes.workspace(id).disabled);
}
// Remove the `changed` badge from the category header
const categoryHeader = $(this).find(".red-ui-sidebar-config-tray-header.red-ui-palette-header");
categoryHeader.removeClass("red-ui-sidebar-config-changed");
})
var globalConfigNodes = [];
var configList = {};

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

@ -101,7 +101,7 @@ RED.utils = (function() {
renderer.code = function (code, lang) {
if(lang === "mermaid") {
return `<pre class='mermaid'>${code}</pre>`;
return `<pre style='word-break: unset;' data-c64='${btoa(code)}' class='mermaid'>${code}</pre>`;
} else {
return "<pre><code>" +code +"</code></pre>";
}
@ -121,17 +121,32 @@ RED.utils = (function() {
function renderMarkdown(txt) {
var rendered = _marked.parse(txt);
var cleaned = DOMPurify.sanitize(rendered, {SAFE_FOR_JQUERY: true})
const cleaned = DOMPurify.sanitize(rendered);
return cleaned;
}
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);
}
@ -1285,7 +1303,6 @@ RED.utils = (function() {
payload = JSON.parse(payload);
} else if (/error/i.test(format)) {
payload = JSON.parse(payload);
payload = (payload.name?payload.name+": ":"")+payload.message;
} else if (format === 'null') {
payload = null;
} else if (format === 'undefined') {
@ -1514,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

@ -176,8 +176,8 @@ RED.view.tools = (function() {
}
nodes.forEach(function(n) {
var modified = false;
var oldValue = n.l === undefined?true:n.l;
var showLabel = n._def.hasOwnProperty("showLabel")?n._def.showLabel:true;
var showLabel = n._def.hasOwnProperty("showLabel") ? n._def.showLabel : true;
var oldValue = n.l === undefined ? showLabel : n.l;
if (labelShown) {
if (n.l === false || (!showLabel && !n.hasOwnProperty('l'))) {
@ -368,6 +368,8 @@ RED.view.tools = (function() {
function gotoNearestNode(direction) {
// Do not select a nearest node if move is active
if (RED.view.state() === RED.state.MOVING_ACTIVE) { return }
var selection = RED.view.selection();
if (selection.nodes && selection.nodes.length === 1) {
var origin = selection.nodes[0];
@ -1147,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

@ -767,6 +767,7 @@ RED.workspaces = (function() {
RED.history.push(historyEvent);
RED.events.emit("flows:change",workspace);
RED.nodes.dirty(true);
RED.sidebar.config.refresh();
RED.nodes.filterNodes({z:workspace.id}).forEach(n => n.dirty = true)
RED.view.redraw(true);
}

View File

@ -351,10 +351,10 @@ RED.user = (function() {
userIcon.css({
backgroundImage: "url("+user.image+")",
})
} else if (user.anonymous) {
} else if (user.anonymous || (!user.username && !user.email)) {
$('<i class="fa fa-user"></i>').appendTo(userIcon);
} else {
$('<span>').text(user.username.substring(0,2)).appendTo(userIcon);
$('<span>').text((user.username || user.email).substring(0,2)).appendTo(userIcon);
}
if (user.profileColor !== undefined) {
userIcon.addClass('red-ui-user-profile-color-' + user.profileColor)

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,
@ -206,12 +208,10 @@ body {
}
img {
width: auto\9;
height: auto;
max-width: 100%;
vertical-align: middle;
border: 0;
-ms-interpolation-mode: bicubic;
}
blockquote {

View File

@ -38,12 +38,13 @@
}
}
#red-ui-image-drop-target {
#red-ui-drop-target-markdown-editor {
position: absolute;
top: 0; bottom: 0;
left: 0; right: 0;
background: var(--red-ui-dnd-background);
display:table;
border-radius: 3px;
width: 100%;
height: 100%;
display: none;

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

@ -216,14 +216,11 @@
.uneditable-input:focus {
border-color: var(--red-ui-form-input-focus-color);
outline: 0;
outline: thin dotted \9;
}
input[type="radio"],
input[type="checkbox"] {
margin: 4px 0 0;
margin-top: 1px \9;
*margin-top: 0;
line-height: normal;
}
@ -285,12 +282,6 @@
color: var(--red-ui-form-placeholder-color);
}
input:-ms-input-placeholder,
div[contenteditable="true"]:-ms-input-placeholder,
textarea:-ms-input-placeholder {
color: var(--red-ui-form-placeholder-color);
}
input::-webkit-input-placeholder,
div[contenteditable="true"]::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
@ -568,11 +559,7 @@
input.search-query {
padding-right: 14px;
padding-right: 4px \9;
padding-left: 14px;
padding-left: 4px \9;
/* IE7-8 doesn't have border-radius, so don't indent the padding */
margin-bottom: 0;
border-radius: 15px;
}

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

@ -18,7 +18,6 @@
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@ -26,7 +25,6 @@
-webkit-user-select: auto;
-khtml-user-select: auto;
-moz-user-select: auto;
-ms-user-select: auto;
user-select: auto;
}

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
*
@ -14,12 +16,31 @@
* limitations under the License.
**/
.red-ui-sidebar-config-category-disabled-icon {
display: none;
}
.red-ui-sidebar-config-category-disabled {
.red-ui-sidebar-config-tray-header {
font-style: italic;
color: var(--red-ui-tab-text-color-disabled-inactive) !important;
.red-ui-sidebar-config-category-disabled-icon {
display: inline;
}
}
.red-ui-sidebar-node-config-list {
.red-ui-palette-node-config {
@extend .red-ui-palette-node-config-disabled;
}
}
}
.red-ui-sidebar-node-config {
position: relative;
background: var(--red-ui-secondary-background);
height: 100%;
overflow-y:auto;
@include disable-selection;
@include mixins.disable-selection;
&:focus {
outline: none;
@ -84,6 +105,11 @@ ul.red-ui-sidebar-node-config-list {
background: var(--red-ui-node-config-background);
color: var(--red-ui-primary-text-color);
cursor: pointer;
&.red-ui-palette-node-config-invalid.red-ui-palette-node-config-changed {
.red-ui-palette-node-annotations.red-ui-flow-node-error {
left: calc(100% - 28px);
}
}
}
ul.red-ui-sidebar-node-config-list li.red-ui-palette-node-config-type {
color: var(--red-ui-secondary-text-color);
@ -115,6 +141,15 @@ ul.red-ui-sidebar-node-config-list li.red-ui-palette-node-config-type {
.red-ui-palette-node-config-invalid {
border-color: var(--red-ui-form-input-border-error-color)
}
.red-ui-sidebar-config-tray-header.red-ui-palette-header:not(.red-ui-sidebar-config-changed) .red-ui-flow-node-changed {
display: none;
}
.red-ui-sidebar-config-tray-header.red-ui-palette-header.red-ui-sidebar-config-changed .red-ui-flow-node-changed {
display: inline-block;
position: absolute;
top: 1px;
right: 1px;
}
.red-ui-palette-node-annotations {
position: absolute;
left: calc(100% - 15px);

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

@ -2,4 +2,15 @@
&.red-ui-popover-panel {
border-top: none;
}
}
.red-ui-autoComplete-completion {
font-family: var(--red-ui-monospace-font);
white-space: nowrap;
overflow: hidden;
flex-grow: 1;
text-overflow: ellipsis;
direction: rtl;
text-align: left;
}

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);
@ -198,6 +200,7 @@ button.red-ui-typedInput-option-expand {
}
button.red-ui-typedInput-option-trigger {
border-left: 1px solid var(--red-ui-form-input-border-color);
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
border-top-right-radius: 4px;

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

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