diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b7f54c5f1..27b1f683f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14, 16] + node-version: [16, 18] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} @@ -30,7 +30,7 @@ jobs: run: | npm run test - name: Publish to coveralls.io - if: ${{ matrix.node-version == 14 }} + if: ${{ matrix.node-version == 16 }} uses: coverallsapp/github-action@v1.1.2 with: github-token: ${{ github.token }} diff --git a/.jshintrc b/.jshintrc index 719eecb49..0886c1dc0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -15,5 +15,5 @@ "shadow": true, // allow variable shadowing (re-use of names...) "sub": true, // don't warn that foo['bar'] should be written as foo.bar "proto": true, // allow setting of __proto__ in node < v0.12, - "esversion": 6 // allow es6 + "esversion": 11 // allow es11(ES2020) } diff --git a/CHANGELOG.md b/CHANGELOG.md index 630d91b4b..04fd110ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,94 @@ +#### 3.1.0-beta.1: Beta Release + + +Editor + + - NEW: Locking Flows (#3938) @knolleary + - NEW: Improve UX around hiding flows via context menu (#3930) @knolleary + - NEW: Add support for inline image in markdown editor by drag and drop of an image file (#4006) @HiroyasuNishiyama + - NEW: Add support for mermaid diagram to markdown editor (#4007) @HiroyasuNishiyama + - NEW: Support uri fragments for nodes and groups including edit support (#3870) @knolleary + - NEW: Add global environment variable feature (#3941) @HiroyasuNishiyama + + - Remember compact/pretty flow export user choice (#3974) @Steve-Mcl + - fix .red-ui-notification class (#4035) @xiaobinqt + - Fix border radius on Modules list header (#4038) @bonanitech + - fix workspace reference error in case of empty tabs (#4029) @HiroyasuNishiyama + - Disable delete tab menu when single tab exists (#4030) @HiroyasuNishiyama + - Disable hide all menu if all tabs hidden (#4031) @HiroyasuNishiyama + - fix hide subflow tooltip (#4033) @HiroyasuNishiyama + - Fix disabled menu items in project feature (#4027) @kazuhitoyokoi + - Let themes change radialMenu text colors (#3995) @bonanitech + - Add Japanese translations for v3.0.3 (#4012) @kazuhitoyokoi + - Add Japanese translation for v3.1.0-beta.0 (#3997) @kazuhitoyokoi + - Add Japanese translation for v3.1.0-beta.0 (#3916) @kazuhitoyokoi + - Hide subflow category after deleting subflow (#3980) @kazuhitoyokoi + - Prevent dbl-click opening node edit dialog with text selected (#3970) @knolleary + - Handle replacing unknown node inside group or subflow (#3921) @knolleary + - Fix #3939, red border red-ui-typedInput-container (#3949) @Steveorevo + - i18n item URL copy notification & add Japanese message (#3946) @HiroyasuNishiyama + - add Japanese message for item url copy actions (#3947) @HiroyasuNishiyama + - Fix autocomplete entry for responseUrl (#3884) @knolleary + - Fix Japanese translation for JSONata editor (#3872) @HiroyasuNishiyama + - Fix search type with spaces (#3841) @Steve-Mcl + - Fix error hanndling of JSONata expression editor for extended functions (#3871) @HiroyasuNishiyama + - Add button type to the adding SSH key button (#3866) @kazuhitoyokoi + - Check radio button as default in project dialog (#3879) @kazuhitoyokoi + - Add $clone as supported function (#3874) @HiroyasuNishiyama + - Env var jsonata (#3807) @HiroyasuNishiyama + - Add Japanese translation for v3.0.2 (#3852) @kazuhitoyokoi + +Runtime + + - Force IPv4 name resolution to have priority (#4019) @dceejay + - Fix async loading of modules containing both nodes and plugins (#3999) @knolleary + - Use main branch as default in project feature (#4036) @kazuhitoyokoi + - Rename package var to avoid strict mode error (#4020) @knolleary + - Fix typos in settings.js (#4013) @ypid + - Ensure credentials object is removed before returning node in getFlow request (#3971) @knolleary + - Ignore commit error in project feature (#3987) @kazuhitoyokoi + - Update dependencies (#3969) @knolleary + - Add check that node sends object rather than primitive type (#3909) @knolleary + - Ensure key_path is quoted in GIT_SSH_COMMAND in case of spaces in pathname (#3912) @knolleary + - Fix nodesDir scan when node package has js/html in sub dir to package.json (#3867) @Steve-Mcl + - Fix file permissions (#3917) @kazuhitoyokoi + - ci: add minimum GitHub token permissions for workflows (#3907) @boahc077 + +Nodes + + - Catch: fix typo in catch.html (#3965) @we11adam + - Change: Fix change node overwriting msg with itself (#3899) @dceejay + - Comment node: Clarify where the text will appear (#4004) @dirkjanfaber + - CSV: change replace to replaceAll (#3990) @dceejay + - CSV node: check header properties for ' and " (#3920) @dceejay + - CSV: Fix for CSV undefined property (#3906) @dceejay + - Delay: let delay node handle both flush then reset (#3898) @dceejay + - Function: Limit number of ports in function node (#3886) @kazuhitoyokoi + - Function: Remove dot from variable name for external module in function node (#3880) @kazuhitoyokoi + - Function: add function node monaco types util and promisify (#3868) @Steve-Mcl + - HTTP In: Ensure msg.req.headers is enumerable (#3908) @knolleary + - HTTP Request: Support form-data arrays (#3991) @hardillb + - HTTP Request: Fix httprequest tests to be more lenient on error message (#3922) @knolleary + - HTTP Request: Add missing property to node object HTTPRequest (#3842) @hardillb + - HTTP Request/Response: Support sortable list on property UI of http request and http response nodes (#3857) @kazuhitoyokoi + - HTTP Response: Ensure statusCode is a number (#3894) @hardillb + - Inject: Allow Inject node to work with async context stores (#4021) @knolleary + - Join/Batch: Add count to join and batch node labels (#4028) @dceejay + - MQTT: Fix birth topic handling in MQTT node (#3905) @Steve-Mcl + - MQTT: Fix pull-down menus of MQTT configuration node (#3890) @kazuhitoyokoi + - MQTT: Prevent invalid mqtt birth topic crashing node-red (#3869) @Steve-Mcl + - MQTT: ensure sessionExpiry(Interval) is applied (#3840) @Steve-Mcl + - MQTT: Fix mqtt nodes not reconnecting on modified-flows deploy (#3992) @knolleary + - MQTT: fix single subscription mqtt node status (#3966) @Steve-Mcl + - Range: Add drop mode to range node (#3935) @dceejay + - Remove done from describe (#3873) @HiroyasuNishiyama + - Split node: avoid duplicate done call for buffer split (#4000) @knolleary + - Status: Fix typo in 25-status.html (#3981) @kazuhitoyokoi + - TCP Node: ensure newline substitution applies to whole message (#4009) @dceejay + - Template: Add information about environment variable to template node (#3882) @kazuhitoyokoi + - Trigger: Hide trigger node repeat send option if sending nothing (#4023) @dceejay + - Watch: fix watch node test on MacOS/ARM (#3942) @HiroyasuNishiyama + #### 3.0.2: Maintenance Release Editor diff --git a/Gruntfile.js b/Gruntfile.js index 2f81da923..44f4c97f6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -151,6 +151,7 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js", "packages/node_modules/@node-red/editor-client/src/js/history.js", "packages/node_modules/@node-red/editor-client/src/js/validators.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js", "packages/node_modules/@node-red/editor-client/src/js/ui/utils.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js", @@ -169,6 +170,7 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js", "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js", "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js", "packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js", "packages/node_modules/@node-red/editor-client/src/js/ui/view.js", @@ -224,7 +226,7 @@ module.exports = function(grunt) { "node_modules/jsonata/jsonata-es5.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js", "packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js", - "packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js", + "packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js" ], // "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [ // // TODO: resolve relative resource paths in @@ -233,6 +235,9 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [ "node_modules/jsonata/jsonata-es5.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js" + ], + "packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js": [ + "node_modules/mermaid/dist/mermaid.min.js" ] } } @@ -403,7 +408,7 @@ module.exports = function(grunt) { { cwd: 'packages/node_modules/@node-red/editor-client/src', src: [ - 'types/node/*.ts', + 'types/node/**/*.ts', 'types/node-red/*.ts', ], expand: true, diff --git a/package.json b/package.json index a57de03c5..baa9734a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "3.0.2", + "version": "3.1.0-beta.1", "description": "Low-code programming for event-driven applications", "homepage": "http://nodered.org", "license": "Apache-2.0", @@ -26,30 +26,30 @@ } ], "dependencies": { - "acorn": "8.7.1", + "acorn": "8.8.2", "acorn-walk": "8.2.0", - "ajv": "8.11.0", - "async-mutex": "0.3.2", + "ajv": "8.12.0", + "async-mutex": "0.4.0", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", - "body-parser": "1.20.0", + "body-parser": "1.20.2", "cheerio": "1.0.0-rc.10", "clone": "2.1.2", - "content-type": "1.0.4", + "content-type": "1.0.5", "cookie": "0.5.0", "cookie-parser": "1.4.6", "cors": "2.8.5", "cronosjs": "1.7.1", "denque": "2.1.0", - "express": "4.18.1", + "express": "4.18.2", "express-session": "1.17.3", "form-data": "4.0.0", "fs-extra": "10.1.0", - "got": "11.8.5", + "got": "11.8.6", "hash-sum": "2.0.0", - "hpagent": "1.0.0", + "hpagent": "1.2.0", "https-proxy-agent": "5.0.1", - "i18next": "21.8.16", + "i18next": "21.10.0", "iconv-lite": "0.6.3", "is-utf8": "0.2.1", "js-yaml": "4.1.0", @@ -60,7 +60,7 @@ "memorystore": "1.6.7", "mime": "3.0.0", "moment": "2.29.4", - "moment-timezone": "0.5.34", + "moment-timezone": "0.5.41", "mqtt": "4.3.7", "multer": "1.4.5-lts.1", "mustache": "4.2.0", @@ -72,21 +72,21 @@ "passport": "0.6.0", "passport-http-bearer": "1.0.1", "passport-oauth2-client-password": "0.1.2", - "raw-body": "2.5.1", - "semver": "7.3.7", - "tar": "6.1.11", - "tough-cookie": "4.0.0", - "uglify-js": "3.16.3", - "uuid": "8.3.2", + "raw-body": "2.5.2", + "semver": "7.3.8", + "tar": "6.1.13", + "tough-cookie": "4.1.2", + "uglify-js": "3.17.4", + "uuid": "9.0.0", "ws": "7.5.6", "xml2js": "0.4.23" }, "optionalDependencies": { - "bcrypt": "5.0.1" + "bcrypt": "5.1.0" }, "devDependencies": { - "dompurify": "2.3.10", - "grunt": "1.5.3", + "dompurify": "2.4.1", + "grunt": "1.6.1", "grunt-chmod": "~1.1.1", "grunt-cli": "~1.4.3", "grunt-concurrent": "3.0.0", @@ -108,17 +108,18 @@ "i18next-http-backend": "1.4.1", "jquery-i18next": "1.2.1", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", - "marked": "4.0.18", + "marked": "4.2.12", + "mermaid": "^9.3.0", "minami": "1.2.3", "mocha": "9.2.2", "node-red-node-test-helper": "^0.3.0", - "nodemon": "2.0.19", + "nodemon": "2.0.20", "proxy": "^1.0.2", - "sass": "1.54.2", + "sass": "1.58.3", "should": "13.2.3", "sinon": "11.1.2", "stoppable": "^1.1.0", - "supertest": "6.2.4" + "supertest": "6.3.3" }, "engines": { "node": ">=14" diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index e2c53fe84..5afcfead2 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-api", - "version": "3.0.2", + "version": "3.1.0-beta.1", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,14 +16,14 @@ } ], "dependencies": { - "@node-red/util": "3.0.2", - "@node-red/editor-client": "3.0.2", + "@node-red/util": "3.1.0-beta.1", + "@node-red/editor-client": "3.1.0-beta.1", "bcryptjs": "2.4.3", - "body-parser": "1.20.0", + "body-parser": "1.20.2", "clone": "2.1.2", "cors": "2.8.5", "express-session": "1.17.3", - "express": "4.18.1", + "express": "4.18.2", "memorystore": "1.6.7", "mime": "3.0.0", "multer": "1.4.5-lts.1", @@ -35,6 +35,6 @@ "ws": "7.5.6" }, "optionalDependencies": { - "bcrypt": "5.0.1" + "bcrypt": "5.1.0" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/de/editor.json b/packages/node_modules/@node-red/editor-client/locales/de/editor.json old mode 100755 new mode 100644 index 93a2f5946..f2955c266 --- a/packages/node_modules/@node-red/editor-client/locales/de/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/de/editor.json @@ -1175,8 +1175,10 @@ "languages": { "de": "Deutsch", "en-US": "Englisch", + "fr": "Französisch", "ja": "Japanisch", "ko": "Koreanisch", + "pt-BR":"Portugiesisch", "ru": "Russisch", "zh-CN": "Chinesisch (Vereinfacht)", "zh-TW": "Chinesisch (Traditionell)" diff --git a/packages/node_modules/@node-red/editor-client/locales/de/infotips.json b/packages/node_modules/@node-red/editor-client/locales/de/infotips.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/de/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/de/jsonata.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json old mode 100755 new mode 100644 index 0300a220f..a5fad8443 --- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json @@ -23,7 +23,11 @@ "position": "Position", "enable": "Enable", "disable": "Disable", - "upload": "Upload" + "upload": "Upload", + "lock": "Lock", + "unlock": "Unlock", + "locked": "Locked", + "unlocked": "Unlocked" }, "type": { "string": "string", @@ -53,22 +57,30 @@ "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", "hideFlow": "Hide flow", "hideOtherFlows": "Hide other flows", - "showAllFlows": "Show all flows", + "showAllFlows": "Show all flows (__count__ hidden)", "hideAllFlows": "Hide all flows", "hiddenFlows": "List __count__ hidden flow", "hiddenFlows_plural": "List __count__ hidden flows", - "showLastHiddenFlow": "Show last hidden flow", + "showLastHiddenFlow": "Reopen hidden flow", "listFlows": "List flows", "listSubflows": "List subflows", "status": "Status", "enabled": "Enabled", "disabled": "Disabled", "info": "Description", - "selectNodes": "Click nodes to select" + "selectNodes": "Click nodes to select", + "enableFlow": "Enable flow", + "disableFlow": "Disable flow", + "lockFlow": "Lock flow", + "unlockFlow": "Unlock flow", + "moveToStart": "Move flow to start", + "moveToEnd": "Move flow to end" }, "menu": { "label": { @@ -101,6 +113,7 @@ "displayStatus": "Show node status", "displayConfig": "Configuration nodes", "import": "Import", + "importExample": "Import Example Flow", "export": "Export", "search": "Search flows", "searchInput": "search your flows", @@ -497,6 +510,7 @@ "addRemoveNode": "Add/remove node from selection", "editSelected": "Edit selected node", "deleteSelected": "Delete selected nodes or link", + "deleteReconnect": "Delete and Reconnect", "importNode": "Import nodes", "exportNode": "Export nodes", "nudgeNode": "Move selected nodes (1px)", @@ -683,7 +697,11 @@ "empty": "empty", "globalConfig": "Global Configuration Nodes", "triggerAction": "Trigger action", - "find": "Find in workspace" + "find": "Find in workspace", + "copyItemUrl": "Copy item url", + "copyURL2Clipboard": "Copied url to clipboard", + "showFlow": "Show", + "hideFlow": "Hide" }, "help": { "name": "Help", @@ -984,7 +1002,10 @@ "quote": "Quote", "link": "Link", "horizontal-rule": "Horizontal rule", - "toggle-preview": "Toggle preview" + "toggle-preview": "Toggle preview", + "mermaid": { + "summary": "Mermaid Diagram" + } }, "bufferEditor": { "title": "Buffer editor", @@ -1179,8 +1200,10 @@ "languages": { "de": "German", "en-US": "English", + "fr": "French", "ja": "Japanese", "ko": "Korean", + "pt-BR":"Portuguese", "ru": "Russian", "zh-CN": "Chinese(Simplified)", "zh-TW": "Chinese(Traditional)" @@ -1206,5 +1229,10 @@ "node": "Node", "junction": "Junction", "linkNodes": "Link Nodes" + }, + "env-var": { + "environment": "Environment", + "header": "Global Environment Variables", + "revert": "Revert" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json b/packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/editor.json b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json new file mode 100644 index 000000000..a80c9160e --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json @@ -0,0 +1,1238 @@ +{ + "common": { + "label": { + "name": "Nom", + "ok": "Ok", + "done": "Terminer", + "cancel": "Annuler", + "delete": "Supprimer", + "close": "Fermer", + "load": "Ouvrir", + "save": "Sauver", + "import": "Importer", + "export": "Exporter", + "back": "Retour", + "next": "Suivant", + "clone": "Cloner", + "cont": "Continuer", + "style": "Style", + "line": "Bordure", + "fill": "Remplissage", + "label": "Etiquette", + "color": "Couleur", + "position": "Position", + "enable": "Activer", + "disable": "Désactiver", + "upload": "Charger", + "lock": "Verrouiller", + "unlock": "Déverrouiller", + "locked": "Verrouillé", + "unlocked": "Déverrouillé" + }, + "type": { + "string": "chaîne de caractères", + "number": "nombre", + "boolean": "booléen", + "array": "tableau", + "buffer": "tampon", + "object": "objet", + "jsonString": "chaîne JSON", + "undefined": "indéfini", + "null": "nul" + } + }, + "event": { + "loadPlugins": "Chargement des extensions", + "loadPalette": "Chargement de la palette", + "loadNodeCatalogs": "Chargement des catalogues de noeuds", + "loadNodes": "Chargement des noeuds __count__", + "loadFlows": "Chargement des flux", + "importFlows": "Ajout de flux à l'espace de travail", + "importError": "

Erreur lors de l'ajout du flux

__message__

", + "loadingProject": "Chargement du projet" + }, + "workspace": { + "defaultName": "Flux __number__", + "editFlow": "Modifier le flux : __name__", + "confirmDelete": "Confirmation de la suppression", + "delete": "Etes-vous sûr de vouloir supprimer '__label__'?", + "dropFlowHere": "Déposer le flux ici", + "dropImageHere": "Déposer l'image ici", + "addFlow": "Ajouter un flux", + "addFlowToRight": "Ajouter un flux à droite", + "closeFlow": "Fermer le flux", + "hideFlow": "Masquer le flux", + "hideOtherFlows": "Masquer les autres flux", + "showAllFlows": "Afficher tous les flux", + "hideAllFlows": "Masquer tous les flux", + "hiddenFlows": "Répertorier le flux masqué __count__", + "hiddenFlows_plural": "Répertorier les flux masqués __count__", + "showLastHiddenFlow": "Afficher le dernier flux masqué", + "listFlows": "Répertorier les flux", + "listSubflows": "Répertorier les sous-flux", + "status": "Statut", + "enabled": "Activé", + "disabled": "Désactivé", + "info": "Description", + "selectNodes": "Cliquer sur les noeuds pour sélectionner", + "enableFlow": "Activer le flux", + "disableFlow": "Désactiver le flux", + "lockFlow": "Verrouiller le flux", + "unlockFlow": "Déverrouiller le flux", + "moveToStart": "Déplacer le flux au début", + "moveToEnd": "Déplacer le flux vers la fin" + }, + "menu": { + "label": { + "view": { + "view": "Affichage", + "grid": "Grille", + "storeZoom": "Restaurer le niveau de zoom au chargement", + "storePosition": "Restaurer la position de défilement au chargement", + "showGrid": "Afficher la grille", + "snapGrid": "Aligner sur la grille", + "gridSize": "Taille de la grille", + "textDir": "Sens du texte", + "defaultDir": "Sens par défaut", + "ltr": "De gauche à droite", + "rtl": "De droite à gauche", + "auto": "Contextuel", + "language": "Langue", + "browserDefault": "Navigateur par défaut" + }, + "sidebar": { + "show": "Afficher la barre latérale" + }, + "palette": { + "show": "Afficher la palette" + }, + "edit": "Éditer", + "settings": "Paramètres", + "userSettings": "Paramètres de l'utilisateur", + "nodes": "Noeuds", + "displayStatus": "Afficher l'état du noeud", + "displayConfig": "Noeuds de configuration", + "import": "Importer", + "importExample": "Importer un exemple de flux", + "export": "Exporter", + "search": "Rechercher les flux", + "searchInput": "Rechercher vos flux", + "subflows": "Sous-flux", + "createSubflow": "Créer un sous-flux", + "selectionToSubflow": "Selection d'un sous-flux", + "flows": "Flux", + "add": "Ajouter", + "rename": "Renommer", + "delete": "Supprimer", + "keyboardShortcuts": "Raccourcis clavier", + "login": "Se connecter", + "logout": "Se déconnecter", + "editPalette": "Gérer la palette", + "other": "Autre", + "showTips": "Afficher les astuces", + "showWelcomeTours": "Afficher les visites guidées pour les nouvelles versions", + "help": "Site web de Node-RED", + "projects": "Projets", + "projects-new": "Nouveau projet", + "projects-open": "Ouvrir le projet", + "projects-settings": "Paramètres du projet", + "showNodeLabelDefault": "Afficher l'étiquette des noeuds nouvellement ajoutés", + "codeEditor": "Éditeur de code", + "groups": "Groupes", + "groupSelection": "Grouper cette sélection", + "ungroupSelection": "Dégrouper la sélection", + "groupMergeSelection": "Fusionner la sélection", + "groupRemoveSelection": "Supprimer du groupe", + "arrange": "Organiser", + "alignLeft": "Aligner à gauche", + "alignCenter": "Aligner au centre", + "alignRight": "Aligner à droite", + "alignTop": "Aligner en haut", + "alignMiddle": "Aligner au milieu", + "alignBottom": "Aligner en bas", + "distributeHorizontally": "Répartir horizontalement", + "distributeVertically": "Distribuer verticalement", + "moveToBack": "Déplacer vers l'arrière", + "moveToFront": "Déplacer vers l'avant", + "moveBackwards": "Reculer", + "moveForwards": "Avancer" + } + }, + "actions": { + "toggle-navigator": "Basculer de navigateur", + "zoom-out": "Dézoomer", + "zoom-reset": "Réinitialiser le zoom", + "zoom-in": "Agrandir", + "search-flows": "Rechercher le flux", + "search-prev": "Précédent", + "search-next": "Suivant", + "search-counter": "\"__term__\" __result__ de __count__" + }, + "user": { + "loggedInAs": "Connecté en tant que __name__", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "login": "Connexion", + "loginFailed": "Échec de la connexion", + "notAuthorized": "Pas autorisé", + "errors": { + "settings": "Vous devez être connecté pour accéder aux paramètres", + "deploy": "Vous devez être connecté pour déployer les modifications", + "notAuthorized": "Vous devez être connecté pour effectuer cette action" + } + }, + "notification": { + "state": { + "flowsStopped": "Flux arrêtés", + "flowsStarted": "Flux démarrés" + }, + "warning": "Attention : __message__", + "warnings": { + "undeployedChanges": "Le noeud a des modifications non déployées", + "nodeActionDisabled": "Actions de noeud désactivées", + "nodeActionDisabledSubflow": "Actions de noeud désactivées dans le sous-flux", + "missing-types": "

Flux arrêtés en raison de types de noeuds manquants.

", + "missing-modules": "

Flux arrêtés en raison de modules manquants.

", + "safe-mode": "

Flux arrêtés en mode sans échec.

Vous pouvez modifier vos flux et déployer les changements pour redémarrer.

", + "restartRequired": "Node-RED doit être redémarré pour mettre à jour les modules", + "credentials_load_failed": "

Les flux se sont arrêtés car les informations d'identification n'ont pas pu être déchiffrées.

Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.

", + "credentials_load_failed_reset": "

Les informations d'identification n'ont pas pu être déchiffrées

Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.

Le fichier d'informations d'identification du flux sera réinitialisé lors du prochain déploiement. Toutes les informations d'identification de flux existantes seront perdues.

", + "missing_flow_file": "

Fichier contenant les flux introuvable.

Le projet n'est pas configuré avec un fichier de flux.

", + "missing_package_file": "

Fichier de paquetage du projet introuvable.

Il manque au projet un fichier package.json.

", + "project_empty": "

Le projet est vide.

Voulez-vous créer un ensemble de fichiers de projet par défaut ?
Sinon, vous devrez ajouter manuellement des fichiers au projet (en dehors de l'éditeur).

", + "project_not_found": "

Le projet '__project__' est introuvable.

", + "git_merge_conflict": "

La fusion automatique des modifications a échoué.

Corriger les conflits non fusionnés, puis valider le résultat.

" + }, + "error": "Erreur : __message__", + "errors": { + "lostConnection": "Connexion avec le serveur perdue, reconnexion...", + "lostConnectionReconnect": "Connexion avec le serveur perdue, reconnexion dans __time__s.", + "lostConnectionTry": "Essayer maintenant", + "cannotAddSubflowToItself": "Impossible d'ajouter un sous-flux à lui-même", + "cannotAddCircularReference": "Impossible d'ajouter un sous-flux - référence circulaire détectée", + "unsupportedVersion": "

Utilisation d'une version non prise en charge de Node.js

Vous devez effectuer une mise à jour vers la dernière version de Node.js LTS

", + "failedToAppendNode": "

Échec du chargement du module '__module__'

__error__

" + }, + "project": { + "change-branch": "Changer pour une branche locale '__project__'", + "merge-abort": "Git fusion abandonnée", + "loaded": "Projet '__project__' chargé", + "updated": "Projet '__project__' mis à jour", + "pull": "Projet '__project__' rechargé", + "revert": "Projet '__project__' annulé", + "merge-complete": "Fusion Git terminée", + "setupCredentials": "Configuration des identifiants", + "setupProjectFiles": "Configuration des fichiers du projet", + "no": "Non merci", + "createDefault": "Créer des fichiers de projet par défaut", + "mergeConflict": "Afficher les conflits de fusion" + }, + "label": { + "manage-project-dep": "Gérer les dépendances du projet", + "setup-cred": "Configuration des identifiants", + "setup-project": "Configuration des fichiers du projet", + "create-default-package": "Créer un fichier de paquetage par défaut", + "no-thanks": "Non merci", + "create-default-project": "Créer des fichiers de projet par défaut", + "show-merge-conflicts": "Afficher les conflits de fusion", + "unknownNodesButton": "Rechercher les noeuds inconnus" + } + }, + "clipboard": { + "clipboard": "Presse-papiers", + "nodes": "Noeuds", + "node": "__count__ noeud", + "node_plural": "__count__ noeuds", + "configNode": "__count__ noeud de configuration", + "configNode_plural": "__count__ noeuds de configuration", + "group": "__count__ groupe", + "group_plural": "__count__ groupes", + "flow": "__count__ flux", + "flow_plural": "__count__ flux", + "subflow": "__count__ sous-flux", + "subflow_plural": "__count__ sous-flux", + "replacedNodes": "__count__ noeud remplacé", + "replacedNodes_plural": "__count__ noeuds remplacés", + "pasteNodes": "Coller le flux JSON ou", + "selectFile": "Sélectionner un fichier à importer", + "importNodes": "Importer des noeuds", + "exportNodes": "Exporter des noeuds", + "download": "Télécharger", + "importUnrecognised": "Importation d'un type inconnu :", + "importUnrecognised_plural": "Importation de plusieurs types inconnus :", + "importDuplicate": "Noeud en double importé :", + "importDuplicate_plural": "Noeuds en double importés :", + "nodesExported": "Noeuds exportés vers le presse-papiers", + "nodesImported": "Noeuds importés :", + "nodeCopied": "__count__ noeud copié", + "nodeCopied_plural": "__count__ noeuds copiés", + "groupCopied": "__count__ groupe copié", + "groupCopied_plural": "__count__ groupes copiés", + "groupStyleCopied": "Style de groupe copié", + "invalidFlow": "Flux invalide : __message__", + "recoveredNodes": "Noeuds récupérés", + "recoveredNodesInfo": "Les noeuds importés sur ce flux contiennent un mauvais identifiant de flux. Ces noeuds ont été ajoutés à ce flux afin que vous puissiez les restaurer ou les supprimer.", + "recoveredNodesNotification": "

Noeuds importés sans identifiant de flux valide

Ils ont été ajoutés à un nouveau flux appelé '__flowName__'.

", + "export": { + "selected": "noeuds sélectionnés", + "current": "flux actuel", + "all": "tous les flux", + "compact": "condensé", + "formatted": "formaté", + "copy": "Copier dans le presse-papier", + "export": "Exporter vers la bibliothèque", + "exportAs": "Exporter en tant que", + "overwrite": "Remplacer", + "exists": "

\"__file__\" existe déjà.

Voulez-vous le remplacer ?

" + }, + "import": { + "import": "Importer vers", + "importSelected": "Importation sélectionnée", + "importCopy": "Importer une copie", + "viewNodes": "Afficher les noeuds...", + "newFlow": "Nouveau flux", + "replace": "Remplacer", + "errors": { + "notArray": "L'entrée n'est pas un tableau JSON", + "itemNotObject": "L'entrée n'est pas un flux valide - l'élément '__index__' n'est pas un objet du noeud", + "missingId": "L'entrée n'est pas un flux valide - l'élément '__index__' n'a pas de propriété 'id'", + "missingType": "L'entrée n'est pas un flux valide - l'élément '__index__' n'a pas de propriété 'type'" + }, + "conflictNotification1": "Certains des noeuds que vous avez importés existent déjà dans votre espace de travail.", + "conflictNotification2": "Sélectionner les noeuds à importer et choisir s'il faut remplacer les noeuds existants ou en importer une copie." + }, + "copyMessagePath": "Chemin copié", + "copyMessageValue": "Valeur copiée", + "copyMessageValue_truncated": "Valeur tronquée (coupée) copiée" + }, + "deploy": { + "deploy": "Déployer", + "full": "Tout", + "fullDesc": "Déploie tout l'espace de travail", + "modifiedFlows": "Flux modifiés", + "modifiedFlowsDesc": "Déploie uniquement les flux contenant des noeuds modifiés", + "modifiedNodes": "Noeuds modifiés", + "modifiedNodesDesc": "Déploie uniquement les noeuds qui ont changés", + "startFlows": "Démarrer", + "startFlowsDesc": "Démarrer les flux", + "stopFlows": "Arrêter", + "stopFlowsDesc": "Arrêter les flux", + "restartFlows": "Redémarrer les flux", + "restartFlowsDesc": "Redémarrer les flux actuellement déployés", + "successfulDeploy": "Déployé avec succès", + "successfulRestart": "Flux redémarrés avec succès", + "deployFailed": "Échec du déploiement : __message__", + "unusedConfigNodes": "Vous avez des noeuds de configuration inutilisés.", + "unusedConfigNodesButton": "Rechercher les noeuds de configuration inutilisés", + "unknownNodesButton": "Rechercher les noeuds inconnus", + "invalidNodesButton": "Rechercher les noeuds invalides", + "errors": { + "noResponse": "Pas de réponse du serveur" + }, + "confirm": { + "button": { + "ignore": "Ignorer", + "confirm": "Confirmer", + "review": "Examiner les modifications", + "cancel": "Annuler", + "merge": "Fusionner", + "overwrite": "Ignorer et déployer" + }, + "undeployedChanges": "Vous avez des modifications non déployées.\n\nSi vous quittez cette page, ces modifications seront perdues.", + "improperlyConfigured": "L'espace de travail contient des noeuds qui ne sont pas correctement configurés :", + "unknown": "L'espace de travail contient des types de noeuds inconnus :", + "confirm": "Êtes-vous sûr de vouloir déployer ?", + "doNotWarn": "Ne plus m'avertir à ce sujet", + "conflict": "Le serveur exécute un ensemble de flux plus récent.", + "backgroundUpdate": "Les flux sur le serveur ont été mis à jour.", + "conflictChecking": "Vérifier si les modifications peuvent être fusionnées automatiquement", + "conflictAutoMerge": "Les modifications n'incluent aucun conflit et peuvent être fusionnées automatiquement.", + "conflictManualMerge": "Les changements incluent des conflits qui doivent être résolus avant de pouvoir être déployés.", + "plusNMore": "+ __count__ en plus" + } + }, + "eventLog": { + "title": "Journal des événements", + "view": "Afficher le journal" + }, + "diff": { + "unresolvedCount": "__count__ conflit non résolu", + "unresolvedCount_plural": "__count__ conflits non résolus", + "globalNodes": "noeuds globaux", + "flowProperties": "Propriétés du flux", + "type": { + "added": "ajouté", + "changed": "modifié", + "unchanged": "inchangé", + "deleted": "supprimé", + "flowDeleted": "flux supprimé", + "flowAdded": "flux ajouté", + "movedTo": "déplacé vers __id__", + "movedFrom": "déplacé depuis __id__" + }, + "nodeCount": "__count__ noeud", + "nodeCount_plural": "__count__ noeuds", + "local": "Changements locaux", + "remote": "Modifications à distance", + "reviewChanges": "Examiner les modifications", + "noBinaryFileShowed": "Impossible d'afficher le contenu du fichier binaire", + "viewCommitDiff": "Afficher les modifications de validation", + "compareChanges": "Comparer les modifications", + "saveConflict": "Enregistrer la résolution des conflits", + "conflictHeader": "__resolved__ sur __unresolved__ conflit(s) résolu(s)", + "commonVersionError": "La version commune ne contient pas de JSON valide :", + "oldVersionError": "L'ancienne version ne contient pas de JSON valide :", + "newVersionError": "La nouvelle version ne contient pas de JSON valide :" + }, + "subflow": { + "editSubflowInstance": "Modifier l'instance du sous-flux : __name__", + "editSubflow": "Modifier le modèle du sous-flux : __name__", + "edit": "Modifier le modèle du sous-flux", + "subflowInstances": "Il existe __count__ instance de ce modèle de sous-flux", + "subflowInstances_plural": "Il existe __count__ instances de ce modèle de sous-flux", + "editSubflowProperties": "modifier les propriétés", + "input": "entrées:", + "output": "sorties:", + "status": "statut du noeud", + "deleteSubflow": "supprimer le sous-flux", + "confirmDelete": "Voulez-vous vraiment supprimer ce sous-flux ?", + "info": "Description", + "category": "Catégorie", + "module": "Module", + "license": "Licence", + "licenseNone": "Aucune", + "licenseOther": "Autre", + "type": "Type de noeud", + "version": "Version", + "versionPlaceholder": "x.y.z", + "keys": "Mots clés", + "keysPlaceholder": "Mots clés séparés par des virgules", + "author": "Auteur", + "authorPlaceholder": "Votre nom ", + "desc": "Description", + "env": { + "restore": "Restaurer le sous-flux par défaut", + "remove": "Supprimer la variable d'environnement" + }, + "errors": { + "noNodesSelected": "Impossible de créer un sous-flux : aucun noeud sélectionné", + "multipleInputsToSelection": "Impossible de créer un sous-flux : plusieurs entrées pour la sélection" + } + }, + "group": { + "editGroup": "Modifier le groupe : __name__", + "errors": { + "cannotCreateDiffGroups": "Impossible de créer un groupe de noeuds provenant de différents groupes", + "cannotAddSubflowPorts": "Impossible d'ajouter des ports à un groupe de sous-flux" + } + }, + "editor": { + "configEdit": "Modifier", + "configAdd": "Ajouter", + "configUpdate": "Sauver", + "configDelete": "Supprimer", + "nodesUse": "__count__ noeud utilise cette configuration", + "nodesUse_plural": "__count__ noeuds utilisent cette configuration", + "addNewConfig": "Ajouter un nouveau noeud de configuration __type__", + "editNode": "Modifier le noeud __type__", + "editConfig": "Modifier le noeud de configuration __type__", + "addNewType": "Ajouter un nouveau __type__...", + "nodeProperties": "Propriétés du noeud", + "label": "Étiquette", + "color": "Couleur", + "portLabels": "Étiquettes des ports", + "labelInputs": "Entrées", + "labelOutputs": "Sorties", + "settingIcon": "Icône", + "default": "Par défaut", + "noDefaultLabel": "Aucune", + "defaultLabel": "Utiliser l'étiquette par défaut", + "searchIcons": "Icônes de recherche", + "useDefault": "Utilisation par défaut", + "description": "Description", + "show": "Afficher", + "hide": "Masquer", + "locale": "Sélectionner la langue", + "icon": "Icône", + "inputType": "Type d'entrée", + "selectType": "Sélectionner les types...", + "loadCredentials": "Chargement des identifiants du noeud", + "inputs": { + "input": "entrée", + "select": "sélection", + "checkbox": "case à cocher", + "spinner": "valeurs à défiler", + "none": "aucune", + "hidden": "masquer la propriété" + }, + "types": { + "str": "chaîne de caractères", + "num": "nombre", + "bool": "booléen", + "json": "JSON", + "bin": "tampon", + "env": "variable d'environnement", + "cred": "identifiant" + }, + "menu": { + "input": "entrée", + "select": "sélection", + "checkbox": "case à cocher", + "spinner": "valeurs à défiler", + "hidden": "étiquette seulement" + }, + "select": { + "label": "Etiquette", + "value": "Valeur" + }, + "spinner": { + "min": "Minimum", + "max": "Maximum" + }, + "errors": { + "scopeChange": "La modification de la portée la rendra indisponible pour les noeuds d'autres flux qui l'utilisent", + "invalidProperties": "Propriétés invalides :", + "credentialLoadFailed": "Échec du chargement des identifiants du noeud" + } + }, + "keyboard": { + "title": "Raccourcis clavier", + "keyboard": "Clavier", + "filterActions": "Actions de filtrage", + "shortcut": "raccourci", + "scope": "portée", + "unassigned": "Non attribué", + "global": "global", + "workspace": "espace de travail", + "selectAll": "Tout sélectionner", + "selectNone": "Ne rien sélectionner", + "selectAllConnected": "Sélectionner tous les éléments connectés", + "addRemoveNode": "Ajouter/supprimer un noeud de la sélection", + "editSelected": "Modifier le noeud sélectionné", + "deleteSelected": "Supprimer les noeuds ou le lien sélectionné(s)", + "deleteReconnect": "Supprimer et reconnecter", + "importNode": "Importer les noeuds", + "exportNode": "Exporter les noeuds", + "nudgeNode": "Déplacer les noeuds sélectionnés (1px)", + "moveNode": "Déplacer les noeuds sélectionnés (20px)", + "toggleSidebar": "Basculer la barre latérale", + "togglePalette": "Basculer la palette", + "copyNode": "Copier les noeuds sélectionnés", + "cutNode": "Couper les noeuds sélectionnés", + "pasteNode": "Coller les noeuds", + "copyGroupStyle": "Copier le style de groupe", + "pasteGroupStyle": "Coller le style de groupe", + "undoChange": "Annuler", + "redoChange": "Rétablir", + "searchBox": "Ouvrir le champ de recherche", + "managePalette": "Gérer la palette", + "actionList": "Liste d'action", + "splitWireWithLinks": "Ajouter des liens à la sélection" + }, + "library": { + "library": "Bibliothèque", + "openLibrary": "Ouvrir la bibliothèque...", + "saveToLibrary": "Enregistrer dans la bibliothèque...", + "typeLibrary": "__type__ bibliothèque", + "unnamedType": "Innomé __type__", + "exportedToLibrary": "Noeuds exportés vers la bibliothèque", + "dialogSaveOverwrite": "Une __libraryType__ appelée __libraryName__ existe déjà. Écraser ?", + "invalidFilename": "Nom de fichier non valide", + "savedNodes": "Noeuds enregistrés", + "savedType": "__type__ enregistré", + "saveFailed": "Échec de la sauvegarde : __message__", + "newFolder": "Nouveau dossier", + "types": { + "local": "Local", + "examples": "Exemples" + } + }, + "palette": { + "noInfo": "Pas d'information disponible", + "filter": "Filtrer les noeuds", + "search": "Rechercher les modules", + "addCategory": "Ajouter un nouveau...", + "label": { + "subflows": "sous-flux", + "network": "réseau", + "common": "commun", + "input": "entrée", + "output": "sortie", + "function": "fonction", + "sequence": "séquence", + "parser": "analyseur", + "social": "social", + "storage": "stockage", + "analysis": "analyse", + "advanced": "avancé" + }, + "actions": { + "collapse-all": "Réduire toutes les catégories", + "expand-all": "Développer toutes les catégories" + }, + "event": { + "nodeAdded": "Noeud ajouté à la palette :", + "nodeAdded_plural": "Noeuds ajoutés à la palette :", + "nodeRemoved": "Noeud supprimé de la palette :", + "nodeRemoved_plural": "Noeuds supprimés de la palette :", + "nodeEnabled": "Noeud activé :", + "nodeEnabled_plural": "Noeuds activés :", + "nodeDisabled": "Noeud désactivé :", + "nodeDisabled_plural": "Noeuds désactivés :", + "nodeUpgraded": "Les noeuds du module __module__ ont été mis à jour vers la version __version__", + "unknownNodeRegistered": "Erreur lors du chargement du noeud : " + }, + "editor": { + "title": "Gérer la palette", + "palette": "Palette", + "times": { + "seconds": "il y a quelques secondes", + "minutes": "il y a quelques minutes", + "minutesV": "il y a __count__ minutes", + "hoursV": "il y a __count__ heure", + "hoursV_plural": "il y a __count__ heures", + "daysV": "il y a __count__ jour", + "daysV_plural": "il y a __count__ jours", + "weeksV": "il y a __count__ semaine", + "weeksV_plural": "il y a __count__ semaines", + "monthsV": "il y a __count__ mois", + "monthsV_plural": "il y a __count__ mois", + "yearsV": "il y a __count__ an", + "yearsV_plural": "il y a __count__ ans", + "yearMonthsV": "il y a __y__ an, __count__ mois", + "yearMonthsV_plural": "il y a __y__ an, __count__ mois", + "yearsMonthsV": "il y a __y__ ans, __count__ mois", + "yearsMonthsV_plural": "il y a __y__ ans, __count__ mois" + }, + "nodeCount": "__label__ noeud", + "nodeCount_plural": "__label__ noeuds", + "moduleCount": "__count__ module disponible", + "moduleCount_plural": "__count__ modules disponibles", + "inuse": "en cours d'utilisation", + "enableall": "activer tout", + "disableall": "désactiver tout", + "enable": "activer", + "disable": "désactiver", + "remove": "supprimer", + "update": "mettre à jour vers __version__", + "updated": "mis à jour", + "install": "installer", + "installed": "installé", + "conflict": "conflit", + "conflictTip": "

Ce module ne peut pas être installé car il inclut un
type de noeud qui a déjà été installé

Conflits avec __module__

", + "loading": "Chargement des catalogues...", + "tab-nodes": "Noeuds", + "tab-install": "Installer", + "sort": "trier:", + "sortAZ": "a-z", + "sortRecent": "récent", + "more": "+ __count__ en plus", + "upload": "Charger le fichier tgz du module", + "refresh": "Actualiser la liste des modules", + "errors": { + "catalogLoadFailed": "

Échec du chargement du catalogue de noeuds.

Vérifier la console du navigateur pour plus d'informations

", + "installFailed": "

Échec lors de l'installation : __module__

__message__

Consulter le journal pour plus d'informations

", + "removeFailed": "

Échec lors de la suppression : __module__

__message__

Consulter le journal pour plus d'informations

", + "updateFailed": "

Échec lors de la mise à jour : __module__

__message__

Consulter le journal pour plus d'informations

", + "enableFailed": "

Échec lors de l'activation : __module__

__message__

Consulter le journal pour plus d'informations

", + "disableFailed": "

Échec lors de la désactivation : __module__

__message__

Consulter le journal pour plus d'informations

" + }, + "confirm": { + "install": { + "body": "

Installation de '__module__'

Avant l'installation, veuiller lire la documentation du noeud. Certains noeuds ont des dépendances qui ne peuvent pas être résolues automatiquement et peuvent nécessiter un redémarrage de Node-RED.

", + "title": "Installer les noeuds" + }, + "remove": { + "body": "

Suppression de '__module__'

La suppression du noeud le désinstallera de Node-RED. Le noeud peut continuer à utiliser des ressources jusqu'au redémarrage de Node-RED.

", + "title": "Supprimer les noeuds" + }, + "update": { + "body": "

Mise à jour de '__module__'

La mise à jour du noeud nécessitera un redémarrage de Node-RED pour terminer la mise à jour. Cela doit être fait manuellement.

", + "title": "Mettre à jour les noeuds" + }, + "cannotUpdate": { + "body": "Une mise à jour pour ce noeud est disponible, mais il n'est pas installé dans un emplacement que le gestionnaire de palette peut mettre à jour.

Veuiller vous référer à la documentation pour savoir comment mettre à jour ce noeud." + }, + "button": { + "review": "Ouvrir la documentation", + "install": "Installer", + "remove": "Supprimer", + "update": "Mettre à jour" + } + } + } + }, + "sidebar": { + "info": { + "name": "Information", + "tabName": "Nom", + "label": "info", + "node": "Noeud", + "type": "Type", + "group": "Groupe", + "module": "Module", + "id": "ID (identifiant)", + "status": "Statut", + "enabled": "Activé", + "disabled": "Désactivé", + "subflow": "Sous-flux", + "instances": "Instances", + "properties": "Propriétés", + "info": "Information", + "desc": "Description", + "blank": "vide", + "null": "nul", + "showMore": "afficher en plus", + "showLess": "afficher en moins", + "flow": "Flux", + "selection": "Sélection", + "nodes": "__count__ noeuds", + "flowDesc": "Description du flux", + "subflowDesc": "Description du sous-flux", + "nodeHelp": "Aide sur les noeuds", + "none": "Aucun", + "arrayItems": "__count__ éléments", + "showTips": "Vous pouvez ouvrir les astuces à partir du panneau des paramètres", + "outline": "Plan", + "empty": "vide", + "globalConfig": "Noeuds de configuration globale", + "triggerAction": "Déclencher une action", + "find": "Rechercher dans l'espace de travail", + "copyItemUrl": "Copier l'URL de l'élément", + "copyURL2Clipboard": "URL copiée dans le presse-papiers", + "showFlow": "Afficher", + "hideFlow": "Masquer" + }, + "help": { + "name": "Aide", + "label": "aide", + "search": "Aide à la recherche", + "nodeHelp": "Aide sur les noeuds", + "showHelp": "Afficher l'aide", + "showInOutline": "Afficher dans les grandes lignes", + "showTopics": "Afficher les sujets", + "noHelp": "Aucune rubrique d'aide sélectionnée", + "changeLog": "Journal des modifications" + }, + "config": { + "name": "Noeuds de configuration", + "label": "configuration", + "global": "Tous les flux", + "none": "aucun", + "subflows": "sous-flux", + "flows": "flux", + "filterAll": "tout", + "showAllConfigNodes": "Afficher tous les noeuds de configuration", + "filterUnused": "inutilisé", + "showAllUnusedConfigNodes": "Afficher tous les noeuds de configuration inutilisés", + "filtered": "__count__ caché(s)" + }, + "context": { + "name": "Données contextuelles", + "label": "contexte", + "none": "aucune sélection", + "refresh": "actualiser pour charger", + "empty": "vide", + "node": "Noeud", + "flow": "Flux", + "global": "Global", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer cet élément ?", + "autoRefresh": "Rafraîchir si la sélection change", + "refrsh": "Rafraîchir", + "delete": "Supprimer" + }, + "palette": { + "name": "Gestion des palettes", + "label": "palette" + }, + "project": { + "label": "projet", + "name": "Projet", + "description": "Description", + "dependencies": "Dépendances", + "settings": "Paramètres", + "noSummaryAvailable": "Aucun résumé disponible", + "editDescription": "Modifier la description du projet", + "editDependencies": "Modifier les dépendances du projet", + "noDescriptionAvailable": "Pas de description disponible", + "editReadme": "Modifier le fichier README.md", + "showProjectSettings": "Afficher les paramètres du projet", + "projectSettings": { + "title": "Paramètres du projet", + "edit": "modifier", + "none": "Vide", + "install": "installer", + "removeFromProject": "supprimer du projet", + "addToProject": "ajouter au projet", + "files": "Fichiers", + "flow": "Flux", + "credentials": "Identifiants", + "package": "Paquets", + "packageCreate": "Le fichier sera créé lorsque les modifications seront enregistrées", + "fileNotExist": "Le fichier n'existe pas", + "selectFile": "Choisir le dossier", + "invalidEncryptionKey": "Clé de chiffrement invalide", + "encryptionEnabled": "Chiffrement activé", + "encryptionDisabled": "Chiffrement désactivé", + "setTheEncryptionKey": "Définir la clé de chiffrement", + "resetTheEncryptionKey": "Réinitialiser la clé de chiffrement", + "changeTheEncryptionKey": "Changer la clé de chiffrement", + "currentKey": "Clé actuelle", + "newKey": "Nouvelle clé", + "credentialsAlert": "Cela supprimera tous les identifiants existants", + "versionControl": "Contrôle de version", + "branches": "Branches", + "noBranches": "Pas de branche", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la branche locale '__name__' ? Ça ne peut pas être annulé.", + "unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Etes-vous sûr de vouloir la supprimer?", + "deleteUnmergedBranch": "Supprimer la branche non fusionnée", + "gitRemotes": "Git distant", + "addRemote": "Ajout distant", + "addRemote2": "Ajout distant", + "remoteName": "Nom distant", + "nameRule": "Doit contenir uniquement A-Z 0-9 _ -", + "url": "URL", + "urlRule": "https://, ssh:// ou file://", + "urlRule2": "Ne pas inclure le nom d'utilisateur/mot de passe dans l'URL", + "noRemotes": "Pas distant", + "deleteRemoteConfrim": "Êtes-vous sûr de vouloir supprimer '__name__' distant ?", + "deleteRemote": "Supprimer distant" + }, + "userSettings": { + "committerDetail": "Détails de l'auteur de la validation (commit)", + "committerTip": "Laisser vide pour utiliser la valeur par défaut du système", + "userName": "Nom d'utilisateur", + "email": "e-mail", + "workflow": "Flux de travail", + "workfowTip": "Choisisser votre flux de travail Git préféré", + "workflowManual": "Manuel", + "workflowManualTip": "Toutes les modifications doivent être validées manuellement dans la barre latérale 'historique'", + "workflowAuto": "Automatique", + "workflowAutoTip": "Les modifications sont validées automatiquement à chaque déploiement", + "sshKeys": "Clés SSH", + "sshKeysTip": "Vous permet de créer des connexions sécurisées aux référentiels Git distants.", + "add": "ajouter une clé", + "addSshKey": "Ajouter une clé SSH", + "addSshKeyTip": "Générer une nouvelle paire de clés publique/privée", + "name": "Nom", + "nameRule": "Doit contenir uniquement A-Z 0-9 _ -", + "passphrase": "Phrase de mot de passe", + "passphraseShort": "Phrase de mot de passe trop courte", + "optional": "Facultatif", + "cancel": "Annuler", + "generate": "Générer une clé", + "noSshKeys": "Pas de clé SSH", + "copyPublicKey": "Copier la clé publique dans le presse-papiers", + "delete": "Supprimer une clé", + "gitConfig": "Configuration Git", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la clé SSH __nom__ ? Ça ne peut pas être annulé." + }, + "versionControl": { + "unstagedChanges": "Abandon des changements", + "stagedChanges": "Changement mis en place", + "unstageChange": "Ne pas mettre en place le changement", + "stageChange": "Mettre en place le changement", + "unstageAllChange": "Ne pas mettre en place tous les changements", + "stageAllChange": "Mettre en place tous les changements", + "commitChanges": "Valider les changements", + "resolveConflicts": "Résoudre les conflits", + "head": "En-tête", + "staged": "Mis en place", + "unstaged": "Non mis en place", + "local": "Local", + "remote": "Distant", + "revert": "Voulez-vous vraiment annuler les modifications apportées à '__file__' ? Ça ne peut pas être annulé.", + "revertChanges": "Rétablir les changements", + "localChanges": "Modifications locales", + "none": "Vide", + "conflictResolve": "Tous les conflits ont été résolus. Valider les modifications pour terminer la fusion.", + "localFiles": "Fichiers locaux", + "all": "tout", + "unmergedChanges": "Modifications non fusionnées", + "abortMerge": "Abandonner la fusion", + "commit": "Valider", + "changeToCommit": "Modifications à valider", + "commitPlaceholder": "Entrer votre message de validation", + "cancelCapital": "Annuler", + "commitCapital": "Valider", + "commitHistory": "Historique des validations", + "branch": "Branche :", + "moreCommits": "Davantage de validations", + "changeLocalBranch": "Changer de branche locale", + "createBranchPlaceholder": "Trouver où créer une branche", + "upstream": "en amont", + "localOverwrite": "Vous avez des modifications locales qui seraient écrasées en changeant la branche. Vous devez d'abord valider ou annuler ces modifications.", + "manageRemoteBranch": "Gérer une branche distante", + "unableToAccess": "Impossible d'accéder au référentiel distant", + "retry": "Recommencer", + "setUpstreamBranch": "Définir comme branche en amont", + "createRemoteBranchPlaceholder": "Trouver ou créer une branche distante", + "trackedUpstreamBranch": "La branche créée sera définie comme la branche en amont suivie.", + "selectUpstreamBranch": "La branche sera créée. Sélectionner ci-dessous pour la définir comme branche en amont suivie.", + "pushFailed": "L'envoi a échoué car la branche a des validations plus récentes. Tirer et fusionner d'abord, puis envoyer à nouveau.", + "push": "Envoyer", + "pull": "Tirer", + "unablePull": "

Impossible d'extraire les modifications à distance ; vos modifications locales non mises en place seraient écrasées.

Valider vos modifications et réessayer.

", + "showUnstagedChanges": "Afficher les modifications non mise en place", + "connectionFailed": "Impossible de se connecter au référentiel distant: ", + "pullUnrelatedHistory": "

Le réferentiel distant a un historique de validations sans rapport.

Êtes-vous sûr de vouloir extraire les modifications dans votre référentiel local ?

", + "pullChanges": "Tirer les changements", + "history": "Historique", + "projectHistory": "Historique du projet", + "daysAgo": "il y a __count__ jour", + "daysAgo_plural": "il y a __count__ jours", + "hoursAgo": "il y a __count__ heure", + "hoursAgo_plural": "il y a __count__ heures", + "minsAgo": "il y a __count__ minute", + "minsAgo_plural": "il y a __count__ minutes", + "secondsAgo": "Il y a quelques instants", + "notTracking": "Votre branche locale ne suit pas actuellement une branche distante.", + "statusUnmergedChanged": "Votre référentiel contient des modifications non fusionnées. Vous devez résoudre les conflits et valider le résultat.", + "repositoryUpToDate": "Votre référentiel est à jour.", + "commitsAhead": "Votre référentiel a __count__ validation d'avance sur le référentiel distant. Vous pouvez pousser cette validation maintenant.", + "commitsAhead_plural": "Votre référentiel a __count__ validations d'avance sur le référentiel distant. Vous pouvez pousser ces validations maintenant.", + "commitsBehind": "Votre référentiel a __count__ validation de retard sur le référentiel distant. Vous pouvez pousser cette validation maintenant.", + "commitsBehind_plural": "Votre référentiel a __count__ validations de retard sur le référentiel distant. Vous pouvez pousser ces validations maintenant.", + "commitsAheadAndBehind1": "Votre référentiel a __count__ validation derrière et ", + "commitsAheadAndBehind1_plural": "Votre référentiel est __count__ validations derrière et ", + "commitsAheadAndBehind2": "__count__ validation avant le référentiel distant. ", + "validationsAheadAndBehind2_plural": "__count__ commits avant le référentiel distant. ", + "commitsAheadAndBehind3": "Vous devez retirer la validation à distance avant de pousser la modification.", + "commitsAheadAndBehind3_plural": "Vous devez retirer les validations à distance avant de pousser les modifications.", + "refreshCommitHistory": "Actualiser l'historique des validations", + "refreshChanges": "Actualiser les modifications" + } + } + }, + "typedInput": { + "type": { + "str": "chaîne de caractères", + "num": "nombre", + "re": "expression régulière", + "bool": "booléen", + "json": "JSON", + "bin": "tampon", + "date": "horodatage", + "jsonata": "expression", + "env": "variable d'environnement", + "cred": "identifiant" + } + }, + "editableList": { + "add": "Ajouter", + "addTitle": "Ajouter un élément" + }, + "search": { + "history": "Historique des recherches", + "clear": "Tout effacer", + "empty": "Aucun résultat", + "addNode": "Ajouter un noeud...", + "options": { + "configNodes": "Noeuds de configuration", + "unusedConfigNodes": "Noeuds de configuration inutilisés", + "invalidNodes": "Noeuds invalides", + "uknownNodes": "Noeuds inconnus", + "unusedSubflows": "Sous-flux inutilisés", + "hiddenFlows": "Flux cachés", + "modifiedNodes": "Noeuds et flux modifiés", + "thisFlow": "Flux courant" + } + }, + "expressionEditor": { + "functions": "Fonctions", + "functionReference": "Fonction de référence", + "insert": "Insérer", + "title": "Éditeur d'expressions JSONata", + "test": "Test", + "data": "Exemple de message", + "result": "Résultat", + "format": "Format", + "compatMode": "Mode de compatibilité activé", + "compatModeDesc": "

Mode de compatibilité JSONata

L'expression actuelle semble toujours faire référence à msg et sera donc évaluée en mode de compatibilité. Veuiller mettre à jour l'expression pour ne pas utiliser msg car ce mode sera supprimé à l'avenir.

Lorsque la prise en charge de JSONata a été ajoutée pour la première fois à Node-RED, il fallait que l'expression référencie l'objet msg. Par exemple, msg.payload serait utilisé pour accéder à la charge utile.

Cela n'est plus nécessaire car l'expression sera évaluée directement par rapport au message. Pour accéder à la charge utile, l'expression doit être simplement charge utile.

", + "noMatch": "Aucun résultat correspondant", + "errors": { + "invalid-expr": "Expression JSONata non valide :\n __message__", + "invalid-msg": "Exemple de message JSON non valide :\n __message__", + "context-unsupported": "Impossible de tester les fonctions de contexte\n $flowContext ou $globalContext", + "env-unsupported": "Impossible de tester la fonction $env", + "moment-unsupported": "Impossible de tester la fonction $moment", + "clone-unsupported": "Impossible de tester la fonction $clone", + "eval": "Erreur lors de l'évaluation de l'expression :\n __message__" + } + }, + "monaco": { + "setTheme": "Définir le thème" + }, + "jsEditor": { + "title": "Éditeur JavaScript" + }, + "textEditor": { + "title": "Éditeur de texte" + }, + "jsonEditor": { + "title": "Éditeur JSON", + "format": "Format JSON", + "rawMode": "Modifier JSON", + "uiMode": "Afficher l'éditeur", + "rawMode-readonly": "JSON", + "uiMode-readonly": "Visualiser", + "insertAbove": "Insérer ci-dessus", + "insertBelow": "Insérer ci-dessous", + "addItem": "Ajouter un élément", + "copyPath": "Copier le chemin vers l'élément", + "expandItems": "Développer les éléments", + "collapseItems": "Réduire les éléments", + "duplicate": "Dupliquer", + "error": { + "invalidJSON": "JSON invalide : " + } + }, + "markdownEditor": { + "title": "Éditeur Markdown", + "expand": "Développer", + "format": "Formaté avec Markdown", + "heading1": "Rubrique 1", + "heading2": "Rubrique 2", + "heading3": "Rubrique 3", + "bold": "Gras", + "italic": "Italic", + "code": "Code", + "ordered-list": "Liste ordonnée", + "unordered-list": "Liste non ordonnée", + "quote": "Citation", + "link": "Lien", + "horizontal-rule": "Règle horizontale", + "toggle-preview": "Basculer l'aperçu", + "mermaid": { + "summary": "Diagramme Mermaid" + } + }, + "bufferEditor": { + "title": "Éditeur de tampon", + "modeString": "Gérer comme une chaîne UTF-8", + "modeArray": "Gérer en tant que tableau JSON", + "modeDesc": "

Éditeur de tampon

Le type de tampon est stocké sous la forme d'un tableau JSON de valeurs d'octets. L'éditeur tentera d'analyser la valeur saisie en tant que tableau JSON. S'il ne s'agit pas d'un JSON valide, il sera traité comme une chaîne UTF-8 et converti en un tableau de points de code de caractères individuels.

Par exemple, une valeur de Hello World sera converti en tableau JSON :

[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

" + }, + "projects": { + "config-git": "Configurer le client Git", + "welcome": { + "hello": "Bonjour! Nous avons introduit des 'projets' dans Node-RED.", + "desc0": "Il s'agit d'une nouvelle façon pour vous de gérer vos fichiers de flux, cela inclut le contrôle de version de vos flux.", + "desc1": "Pour commencer, vous pouvez créer votre premier projet ou cloner un projet existant à partir d'un référentiel git.", + "desc2": "Si vous n'êtes pas sûr, vous pouvez ignorer ceci pour le moment. Vous pourrez toujours créer votre premier projet à partir du menu 'Projets' à tout moment.", + "create": "Créer un projet", + "clone": "Cloner un référentiel", + "openExistingProject": "Ouvrir un projet existant", + "not-right-now": "Pas maintenant" + }, + "git-config": { + "setup": "Configurer votre version du client Git", + "desc0": "Node-RED utilise l'outil open source Git pour le contrôle de version. Il suit les modifications apportées à vos fichiers de projet et vous permet de les transférer vers des référentiels distants.", + "desc1": "Lorsque vous validez un ensemble de modifications, Git enregistre l'auteur qui a effectué les modifications avec un nom d'utilisateur et une adresse e-mail. Le nom d'utilisateur peut être ce que vous voulez - il n'est pas nécessaire que ce soit votre vrai nom.", + "desc2": "Votre client Git est déjà configuré avec les détails ci-dessous.", + "desc3": "Vous pouvez modifier ces paramètres ultérieurement sous l'onglet 'Configuration Git' de la boîte de dialogue des paramètres.", + "username": "Nom d'utilisateur", + "email": "e-mail" + }, + "project-details": { + "create": "Créer votre projet", + "desc0": "Un projet est maintenu en tant que référentiel Git. Il est beaucoup plus facile de partager vos flux et de collaborer avec les autres grâce à ce référentiel.", + "desc1": "Vous pouvez créer plusieurs projets et basculer rapidement entre eux depuis l'éditeur.", + "desc2": "Pour commencer, votre projet a besoin d'un nom et facultativement d'une description.", + "already-exists": "Le projet existe déjà", + "must-contain": "Doit contenir uniquement A-Z 0-9 _ -", + "project-name": "Nom du projet", + "desc": "Description", + "opt": "Facultatif" + }, + "clone-project": { + "clone": "Cloner un projet", + "desc0": "Si vous avez déjà un dépôt Git contenant un projet, vous pouvez le cloner pour commencer.", + "already-exists": "Le projet existe déjà", + "must-contain": "Doit contenir uniquement A-Z 0-9 _ -", + "project-name": "Nom du projet", + "no-info-in-url": "Ne pas inclure le nom d'utilisateur/mot de passe dans l'URL", + "git-url": "URL du dépôt Git", + "protocols": "https://, ssh:// ou file://", + "auth-failed": "L'authentification a échoué", + "username": "Nom d'utilisateur", + "passwd": "Mot de passe", + "ssh-key": "Clé SSH", + "passphrase": "Phrase de mot de passe", + "ssh-key-desc": "Avant de pouvoir cloner un référentiel avec ssh, vous devez ajouter une clé SSH pour y accéder.", + "ssh-key-add": "Ajouter une clé ssh", + "credential-key": "Clé de chiffrement des identifiants", + "cant-get-ssh-key": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.", + "already-exists2": "Existe déjà", + "git-error": "Erreur git", + "connection-failed": "La connexion a échoué", + "not-git-repo": "Ce n'est pas un dépôt Git", + "repo-not-found": "Référentiel introuvable" + }, + "default-files": { + "create": "Créer vos fichiers de projet", + "desc0": "Un projet contient vos fichiers de flux, un fichier README et un fichier package.json.", + "desc1": "Il peut contenir tous les autres fichiers que vous souhaitez conserver dans le référentiel Git.", + "desc2": "Vos fichiers de flux et identifiants existants seront copiés dans le projet.", + "flow-file": "Fichier de flux", + "credentials-file": "Fichier d'identifiants" + }, + "encryption-config": { + "setup": "Configuration du chiffrage de votre fichier d'informations d'identification", + "desc0": "Votre fichier d'informations d'identification de flux peut être chiffré pour sécuriser son contenu.", + "desc1": "Si vous souhaitez stocker ces identifiants dans un référentiel Git public, vous devez les chiffrer en fournissant une phrase clé secrète.", + "desc2": "Votre fichier d'identifiants de flux n'est actuellement pas chiffré.", + "desc3": "Cela signifie que son contenu, tel que les mots de passe et les jetons d'accès, peut être lu par toute personne ayant accès au fichier.", + "desc4": "Si vous souhaitez stocker ces identifiants dans un référentiel Git public, vous devez les chiffrer en fournissant une phrase clé secrète.", + "desc5": "Votre fichier contenant les identifiants de flux est actuellement chiffré à l'aide de la propriété credentialSecret de votre fichier de paramètres comme clé.", + "desc6": "Votre fichier contenant les identifiants de flux est actuellement chiffré à l'aide d'une clé générée par le système. Vous devez fournir une nouvelle clé secrète pour ce projet.", + "desc7": "La clé sera stockée séparément de vos fichiers de projet. Vous devrez fournir la clé pour utiliser ce projet dans une autre instance de Node-RED.", + "credentials": "Identifiants", + "enable": "Activer le chiffrement", + "disable": "Désactiver le chiffrement", + "disabled": "Désactivé", + "copy": "Remplacer la clé existante", + "use-custom": "Utiliser la clé personnalisée", + "desc8": "Le fichier contenant les identifiants ne sera pas crypté et son contenu sera facilement lisible", + "create-project-files": "Créer des fichiers de projet", + "create-project": "Créer un projet", + "already-exists": "existe déjà", + "git-error": "Erreur Git", + "git-auth-error": "erreur d'authentification Git" + }, + "create-success": { + "success": "Vous avez créé avec succès votre premier projet !", + "desc0": "Vous pouvez maintenant continuer à utiliser Node-RED comme vous l'avez toujours fait.", + "desc1": "L'onglet 'info' dans la barre latérale vous montre quel est votre projet actif actuel. Le bouton à côté du nom peut être utilisé pour accéder à la vue des paramètres du projet.", + "desc2": "L'onglet 'historique' dans la barre latérale peut être utilisé pour afficher les fichiers qui ont changé dans votre projet et pour les valider. Il vous montre un historique complet de vos validations (commits) et vous permet de pousser vos modifications vers un référentiel distant." + }, + "create": { + "projects": "Projets", + "already-exists": "Le projet existe déjà", + "must-contain": "Doit contenir uniquement A-Z 0-9 _ -", + "no-info-in-url": "Ne pas inclure le nom d'utilisateur/mot de passe dans l'URL", + "open": "Projet ouvert", + "create": "Créer un projet", + "clone": "Cloner un référentiel", + "project-name": "Nom du projet", + "desc": "Description", + "opt": "Facultatif", + "flow-file": "Fichier de flux", + "credentials": "Identifiants", + "enable-encryption": "Activer le chiffrement", + "disable-encryption": "Désactiver le chiffrement", + "encryption-key": "Clé de chiffrement", + "desc0": "Une phrase pour sécuriser vos identifiants", + "desc1": "Le fichier contenant les identifiants ne sera pas crypté et son contenu sera facilement lisible", + "git-url": "URL du dépôt Git", + "protocols": "https://, ssh:// ou file://", + "auth-failed": "L'authentification a échoué", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "ssh-key": "Clé SSH", + "passphrase": "Phrase de mot de passe", + "desc2": "Avant de pouvoir cloner un référentiel sur ssh, vous devez ajouter une clé SSH pour y accéder.", + "add-ssh-key": "Ajouter une clé ssh", + "credentials-encryption-key": "Clé de chiffrement des identifiants", + "already-exists-2": "existe déjà", + "git-error": "erreur git", + "con-failed": "La connexion a échoué", + "not-git": "Ce n'est pas un dépôt git", + "no-resource": "Référentiel introuvable", + "cant-get-ssh-key-path": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.", + "unexpected_error": "Erreur inattendue", + "clearContext": "Effacer le contexte lors du changement de projet" + }, + "delete": { + "confirm": "Voulez-vous vraiment supprimer ce projet ?" + }, + "create-project-list": { + "search": "rechercher vos projets", + "current": "actuel" + }, + "require-clean": { + "confirm": "

Vous avez des modifications non déployées qui seront perdues.

Voulez-vous continuer ?

" + }, + "send-req": { + "auth-req": "Authentification requise pour le référentiel", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "passphrase": "Phrase de mot de passe", + "retry": "Recommencer", + "update-failed": "La mise à jour a échoué", + "unhandled": "Code d'erreur non géré", + "host-key-verify-failed": "

La vérification de la clé d'hôte a échoué.

La clé d'hôte du référentiel n'a pas pu être vérifiée. Veuillez mettre à jour votre fichier known_hosts et réessayer.

" + }, + "create-branch-list": { + "invalid": "Branche invalide", + "create": "Créer une branche", + "current": "Actuelle" + }, + "create-default-file-set": { + "no-active": "Impossible de créer un ensemble de fichiers par défaut sans projet actif", + "no-empty": "Impossible de créer un ensemble de fichiers par défaut sur un projet non vide", + "git-error": "Erreur Git" + }, + "errors": { + "no-username-email": "Votre client Git n'est pas configuré avec un nom d'utilisateur/e-mail.", + "unexpected": "Une erreur inattendue est apparue", + "code": "Code" + } + }, + "editor-tab": { + "properties": "Propriétés", + "envProperties": "Variables d'environnement", + "module": "Propriétés des modules", + "description": "Description", + "appearance": "Apparence", + "preview": "Aperçu de l'interface utilisateur", + "defaultValue": "Valeur par défaut" + }, + "tourGuide": { + "takeATour": "Aperçu", + "start": "Commencer", + "next": "Suivant", + "welcomeTours": "Visite de bienvenue" + }, + "diagnostics": { + "title": "Information système" + }, + "languages": { + "de": "Allemand", + "en-US": "Anglais", + "fr": "Français", + "ja": "Japonais", + "ko": "Coréen", + "pt-BR": "Portugais brésilien", + "ru": "Russe", + "zh-CN": "Chinois (Simplifié)", + "zh-TW": "Chinois (Traditionnel)" + }, + "validator": { + "errors": { + "invalid-json": "Données JSON invalides : __error__", + "invalid-json-prop": "__prop__: données JSON invalides : __error__", + "invalid-prop": "Expression de propriété non valide", + "invalid-prop-prop": "__prop__: expression de propriété invalide", + "invalid-num": "Numéro invalide", + "invalid-num-prop": "__prop__: numéro invalide", + "invalid-regexp": "Modèle d'entrée non valide", + "invalid-regex-prop": "__prop__: modèle d'entrée non valide", + "missing-required-prop": "__prop__: valeur de la propriété manquante", + "invalid-config": "__prop__: noeud de configuration invalide", + "missing-config": "__prop__: noeud de configuration manquant", + "validation-error": "__prop__: erreur de validation: __node__, __id__: __error__" + } + }, + "contextMenu": { + "insert": "Insérer", + "node": "Noeud", + "junction": "Jonction", + "linkNodes": "Liens entre les noeuds" + }, + "env-var": { + "environment": "Environment", + "header": "Variables d'environnement globales", + "revert": "Rétablir" + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/infotips.json b/packages/node_modules/@node-red/editor-client/locales/fr/infotips.json new file mode 100755 index 000000000..449be751b --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/fr/infotips.json @@ -0,0 +1,23 @@ +{ + "info": { + "tip0": "Vous pouvez supprimer les noeuds ou les liens sélectionnés avec {{core:delete-selection}}", + "tip1": "Rechercher des noeuds à l'aide de {{core:search}}", + "tip2": "{{core:toggle-sidebar}} basculera l'affichage de cette barre latérale", + "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", + "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}}", + "tip10": "[majuscule] [clic] et faites glisser sur un port de noeud pour déplacer tous les fils attachés ou seulement celui sélectionné", + "tip11": "Afficher l'onglet Infos avec {{core:show-info-tab}} ou l'onglet Débogage avec {{core:show-debug-tab}}", + "tip12": "[ctrl] [clic] dans l'espace de travail pour ouvrir la boîte de dialogue d'ajout rapide", + "tip13": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un port de noeud pour activer le câblage rapide", + "tip14": "Maintenir la touche [shift] enfoncée lorsque vous [cliquez] sur un noeud pour sélectionner également tous ses noeuds connectés", + "tip15": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un noeud pour l'ajouter ou le supprimer de la sélection actuelle", + "tip16": "Changer d'onglet de flux avec {{core:show-previous-tab}} et {{core:show-next-tab}}", + "tip17": "Vous pouvez confirmer vos modifications dans le panneau d'édition du noeud avec {{core:confirm-edit-tray}} ou les annuler avec {{core:cancel-edit-tray}}", + "tip18": "Appuyer sur {{core:edit-selected-node}} modifiera le premier noeud de la sélection actuelle" + } +} \ No newline at end of file diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json new file mode 100755 index 000000000..8fd65bf72 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json @@ -0,0 +1,274 @@ +{ + "$string": { + "args": "arg[, prettify]", + "desc": "Convertit le paramètre `arg` en une chaîne de caractères en utilisant les règles de typage suivantes :\n\n - Les chaînes de caractères sont inchangées\n - Les fonctions sont converties en une chaîne vide\n - L'infini numérique et NaN renvoient une erreur car ils ne peuvent pas être représentés comme un Numéro JSON\n - Toutes les autres valeurs sont converties en une chaîne JSON à l'aide de la fonction `JSON.stringify`. Si `prettify` est vrai, alors le JSON \"prettified\" est produit. c'est-à-dire une ligne par champ et les lignes seront en retrait en fonction de la profondeur du champ." + }, + "$length": { + "args": "str", + "desc": "Renvoie le nombre de caractères dans la chaîne `str`. Une erreur est renvoyée si `str` n'est pas une chaîne de caractères." + }, + "$substring": { + "args": "str, start[, length]", + "desc": "Renvoie une chaîne contenant les caractères du premier paramètre `str` commençant à la position `start` (pas de décalage). Si `length` est spécifié, alors la sous-chaîne contiendra un maximum de caractères `length`. Si `start` est négatif alors il indique le nombre de caractères à partir de la fin de `str`." + }, + "$substringBefore": { + "args": "str, chars", + "desc": "Renvoie la sous-chaîne avant la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`." + }, + "$substringAfter": { + "args": "str, chars", + "desc": "Renvoie la sous-chaîne après la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`." + }, + "$uppercase": { + "args": "str", + "desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en majuscules." + }, + "$lowercase": { + "args": "str", + "desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en minuscules." + }, + "$trim": { + "args": "str", + "desc": "Normalise et supprime tous les caractères d'espacement dans `str` en appliquant les étapes suivantes :\n\n - Toutes les tabulations, retours à la ligne et sauts de ligne sont remplacés par des espaces.\n- Les séquences contiguës d'espaces sont réduites à un seul espace.\n- Les espaces de fin et de début sont supprimés.\n\n Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée sans argument), alors la valeur de contexte est utilisée comme valeur de `str`. Une erreur est renvoyée si `str` n'est pas une chaîne." + }, + "$contains": { + "args": "str, pattern", + "desc": "Renvoie `true` si `str` correspond à `pattern`, sinon il renvoie `false`. Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée avec un argument), alors la valeur de contexte est utilisée comme valeur de `str`. Le paramètre `pattern` peut être une chaîne ou une expression régulière." + }, + "$split": { + "args": "str[, separator][, limit]", + "desc": "Divise le paramètre `str` en un tableau de sous-chaînes. C'est une erreur si `str` n'est pas une chaîne. Le paramètre facultatif `separator` spécifie les caractères à l'intérieur de `str` à propos desquels il doit être divisé en chaîne ou en expression régulière. Si `separator` n'est pas spécifié, la chaîne vide est supposée et `str` sera divisé en un tableau de caractères uniques. C'est une erreur si `separator` n'est pas une chaîne. Le paramètre facultatif `limit` est un nombre qui spécifie le nombre maximum de sous-chaînes à inclure dans le tableau résultant. Toutes les sous-chaînes supplémentaires sont ignorées. Si `limit` n'est pas spécifié, alors `str` est entièrement divisé sans limite à la taille du tableau résultant. C'est une erreur si `limit` n'est pas un nombre non négatif." + }, + "$join": { + "args": "array[, separator]", + "desc": "Joint un tableau de chaînes de composants en une seule chaîne concaténée, chaque chaîne de composants étant séparée par le paramètre facultatif `separator`. C'est une erreur si l'entrée `array` contient un élément qui n'est pas une chaîne. Si `séparateur` n'est pas spécifié, il est supposé être la chaîne vide, c'est-à-dire qu'il n'y a pas de `séparateur` entre les chaînes de composants. C'est une erreur si `separator` n'est pas une chaîne." + }, + "$match": { + "args": "str, pattern [, limit]", + "desc": "Applique la chaîne `str` à l'expression régulière `pattern` et renvoie un tableau d'objets, chaque objet contenant des informations sur chaque occurrence d'une correspondance dans `str`." + }, + "$replace": { + "args": "str, pattern, replacement [, limit]", + "desc": "Trouve les occurrences de `pattern` dans `str` et les remplace par `replacement`.\n\nLe paramètre facultatif `limit` est le nombre maximum de remplacements." + }, + "$now": { + "args": "$[picture [, timezone]]", + "desc": "Génère un horodatage au format compatible ISO 8601 et le renvoie sous forme de chaîne. Si les paramètres optionnels d'image et de fuseau horaire sont fournis, alors l'horodatage actuel est formaté comme décrit par la fonction `$fromMillis()`" + }, + "$base64encode": { + "args": "string", + "desc": "Convertit une chaîne ASCII en une représentation en base 64. Chaque caractère de la chaîne est traité comme un octet de données binaires. Cela nécessite que tous les caractères de la chaîne se trouvent dans la plage 0x00 à 0xFF, qui inclut tous les caractères des chaînes encodées en URI. Les caractères Unicode en dehors de cette plage ne sont pas pris en charge." + }, + "$base64decode": { + "args": "string", + "desc": "Convertit les octets encodés en base 64 en une chaîne, à l'aide d'une page de codes Unicode UTF-8." + }, + "$number": { + "args": "arg", + "desc": "Convertit le paramètre `arg` en un nombre en utilisant les règles de conversion suivantes :\n\n - Les nombres sont inchangés\n - Les chaînes qui contiennent une séquence de caractères représentant un nombre JSON légal sont converties en ce nombre\n - Toutes les autres valeurs provoquer l'envoi d'une erreur." + }, + "$abs": { + "args": "number", + "desc": "Renvoie la valeur absolue du paramètre `nombre`." + }, + "$floor": { + "args": "number", + "desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche inférieur ou égal à `number`." + }, + "$ceil": { + "args": "number", + "desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche supérieur ou égal à `number`." + }, + "$round": { + "args": "number [, precision]", + "desc": "Renvoie la valeur du paramètre `number` arrondie au nombre de décimales spécifié par le paramètre facultatif `precision`." + }, + "$power": { + "args": "base, exponent", + "desc": "Renvoie la valeur de `base` élevée à la puissance de `exponent`." + }, + "$sqrt": { + "args": "number", + "desc": "Renvoie la racine carrée de la valeur du paramètre `number`." + }, + "$random": { + "args": "", + "desc": "Renvoie un nombre pseudo-aléatoire supérieur ou égal à zéro et inférieur à un." + }, + "$millis": { + "args": "", + "desc": "Renvoie le nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Tous les appels de `$millis()` dans une évaluation d'une expression renverront toutes la même valeur." + }, + "$sum": { + "args": "array", + "desc": "Renvoie la somme arithmétique d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$max": { + "args": "array", + "desc": "Renvoie le nombre maximal dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$min": { + "args": "array", + "desc": "Renvoie le nombre minimum dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$average": { + "args": "array", + "desc": "Renvoie la valeur moyenne d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$boolean": { + "args": "arg", + "desc": "Transforme l'argument en booléen en utilisant les règles suivantes :\n\n - `Boolean` : inchangé\n - `string` : vide : `false`\n - `string` : non vide : `true`\n - `number` : `0` : `false`\n - `number` : non nul : `true`\n - `null` : `false`\n - `array` : vide : `false`\n - `array` : contient un membre qui convertit en `true` : `true`\n - `array` : tous les membres sont transformés en `false` : `false`\n - `object` : vide : `false`\n - `object` : non vide : `true`\n - `function` : `false`" + }, + "$not": { + "args": "arg", + "desc": "Renvoie un booléen résultat de la négation logique de l'argument" + }, + "$exists": { + "args": "arg", + "desc": "Renvoie la valeur booléenne `true` si l'expression `arg` est évaluée à une valeur, ou `false` si l'expression ne correspond à rien (par exemple, un chemin vers une référence de champ inexistante)." + }, + "$count": { + "args": "array", + "desc": "Renvoie le nombre d'éléments du tableau" + }, + "$append": { + "args": "array, array", + "desc": "Combine deux tableaux" + }, + "$sort": { + "args": "array [, function]", + "desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais triées dans l'ordre.\n\nSi un comparateur `function` est fourni, alors il doit s'agir d'une fonction qui prend deux paramètres :\n\n`function(left , droite)`\n\nCette fonction est invoquée par l'algorithme de tri pour comparer deux valeurs à gauche et à droite. Si la valeur de left doit être placée après la valeur de right dans l'ordre de tri souhaité, la fonction doit renvoyer un booléen `true` pour indiquer un échange. Sinon, il doit renvoyer `false`." + }, + "$reverse": { + "args": "array", + "desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais dans l'ordre inverse." + }, + "$shuffle": { + "args": "array", + "desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais mélangées dans un ordre aléatoire." + }, + "$zip": { + "args": "array, ...", + "desc": "Renvoie un tableau convolué (zippé) contenant des tableaux groupés de valeurs des arguments `array1`...`arrayN` d'index 0, 1, 2...." + }, + "$keys": { + "args": "object", + "desc": "Renvoie un tableau contenant les clés de l'objet. Si l'argument est un tableau d'objets, le tableau renvoyé contient une liste dédupliquée de toutes les clés de tous les objets." + }, + "$lookup": { + "args": "object, key", + "desc": "Renvoie la valeur associée à la clé dans l'objet. Si le premier argument est un tableau d'objets, tous les objets du tableau sont recherchés et les valeurs associées à toutes les occurrences de key sont renvoyées." + }, + "$spread": { + "args": "object", + "desc": "Divise un objet contenant des paires clé/valeur en un tableau d'objets, chacun ayant une seule paire clé/valeur de l'objet d'entrée. Si le paramètre est un tableau d'objets, alors le tableau résultant contient un objet pour chaque paire clé/valeur dans chaque objet du tableau fourni." + }, + "$merge": { + "args": "array<object>", + "desc": "Fusionne un tableau d'`objets` en un seul `objet` contenant toutes les paires clé/valeur de chacun des objets du tableau d'entrée. Si l'un des objets d'entrée contient la même clé, alors l'`objet` renvoyé contiendra la valeur du dernier dans le tableau. C'est une erreur si le tableau d'entrée contient un élément qui n'est pas un objet." + }, + "$sift": { + "args": "object, function", + "desc": "Renvoie un objet qui contient uniquement les paires clé/valeur du paramètre `object` qui satisfont le prédicat `function` transmis comme second paramètre.\n\nLa `function` qui est fournie comme second paramètre doit avoir la signature suivante :\n\n`fonction(valeur [, clé [, objet]])`" + }, + "$each": { + "args": "object, function", + "desc": "Renvoie un tableau contenant les valeurs renvoyées par la `fonction` lorsqu'elle est appliquée à chaque paire clé/valeur dans l'`objet`." + }, + "$map": { + "args": "array, function", + "desc": "Renvoie un tableau contenant les résultats de l'application du paramètre `function` à chaque valeur du paramètre `array`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function( valeur [, indice [, tableau]])`" + }, + "$filter": { + "args": "array, function", + "desc": "Renvoie un tableau contenant uniquement les valeurs du paramètre `array` qui satisfont le prédicat `function`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function(value [ , indice [, tableau]])`" + }, + "$reduce": { + "args": "array, function [, init]", + "desc": "Renvoie une valeur agrégée dérivée de l'application successive du paramètre `function` à chaque valeur de `array` en combinaison avec le résultat de l'application précédente de la fonction.\n\nLa fonction doit accepter deux arguments et se comporte comme un opérateur infixe entre chaque valeur dans le `tableau`. La signature de `function` doit être de la forme : `myfunc($accumulator, $value[, $index[, $array]])`\n\nLe paramètre facultatif `init` est utilisé comme valeur initiale dans l'agrégation ." + }, + "$flowContext": { + "args": "string[, string]", + "desc": "Récupère une propriété de contexte de flux.\n\nCeci est une fonction définie par Node-RED." + }, + "$globalContext": { + "args": "string[, string]", + "desc": "Récupère une propriété de contexte globale.\n\nCeci est une fonction définie par Node-RED." + }, + "$pad": { + "args": "string, width [, char]", + "desc": "Renvoie une copie de la `chaîne` avec un rembourrage supplémentaire, si nécessaire, de sorte que son nombre total de caractères corresponde au moins à la valeur absolue du paramètre `width`.\n\nSi `width` est un nombre positif, alors la chaîne est rembourré à droite; s'il est négatif, il est rempli vers la gauche.\n\nL'argument optionnel `char` spécifie le(s) caractère(s) de remplissage à utiliser. S'il n'est pas spécifié, la valeur par défaut est le caractère espace." + }, + "$fromMillis": { + "args": "number, [, picture [, timezone]]", + "desc": "Convertisser le « nombre » représentant les millisecondes depuis l'époque Unix (1er janvier 1970 UTC) en une représentation sous forme de chaîne formatée de l'horodatage tel que spécifié par la chaîne d'image.\n\nSi le paramètre facultatif « image » est omis, l'horodatage est formaté au format ISO 8601.\n\nSi la chaîne facultative `image` est fournie, l'horodatage est formaté selon la représentation spécifiée dans cette chaîne. Le comportement de cette fonction est cohérent avec la version à deux arguments de la fonction XPath/XQuery `format-dateTime` telle que définie dans la spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont l'horodatage est formaté et a la même syntaxe que `format-dateTime`.\n\nSi la chaîne facultative `timezone` est fournie, alors l'horodatage formaté sera dans ce fuseau horaire. La chaîne `timezone` doit être au format '±HHMM', où ± est le signe plus ou moins et HHMM est le décalage en heures et minutes par rapport à UTC. Décalage positif pour les fuseaux horaires à l'est de UTC, décalage négatif pour les fuseaux horaires à l'ouest de UTC." + }, + "$formatNumber": { + "args": "number, picture [, options]", + "desc": "Convertit le `number` en une chaîne et le formate en une représentation décimale comme spécifié par la chaîne `picture`.\n\n Le comportement de cette fonction est cohérent avec la fonction XPath/XQuery fn:format-number telle que définie dans le Spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que fn:format-number.\n\nLe troisième argument facultatif `options` est utilisé pour remplacer les caractères de formatage spécifiques aux paramètres régionaux par défaut, tels que le séparateur décimal. S'il est fourni, cet argument doit être un objet contenant des paires nom/valeur spécifiées dans la section de format décimal de la spécification XPath F&O 3.1." + }, + "$formatBase": { + "args": "number [, radix]", + "desc": "Convertit le `number` en une chaîne et le formate en un entier représenté dans la base numérique spécifiée par l'argument `radix`. Si `radix` n'est pas spécifié, la valeur par défaut est la base 10. `radix` peut être compris entre 2 et 36, sinon une erreur est renvoyée." + }, + "$toMillis": { + "args": "timestamp", + "desc": "Convertit une chaîne `timestamp` au format ISO 8601 en nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Une erreur est renvoyée si la chaîne n'est pas au format correct." + }, + "$env": { + "args": "arg", + "desc": "Renvoie la valeur d'une variable d'environnement.\n\nCeci est une fonction définie par Node-RED." + }, + "$eval": { + "args": "expr [, context]", + "desc": "Analyse et évalue la chaîne `expr` qui contient un JSON littéral ou une expression JSONata en utilisant le contexte actuel comme contexte d'évaluation." + }, + "$formatInteger": { + "args": "number, picture", + "desc": "Transforme le `nombre` en une chaîne et le formate en une représentation entière comme spécifié par la chaîne `image`. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-integer` de la spécification XPath F&O 3.1." + }, + "$parseInteger": { + "args": "string, picture", + "desc": "Analyse le contenu du paramètre `string` en un entier (comme un nombre JSON) en utilisant le format spécifié par la chaîne `picture`. Le paramètre de chaîne `picture` a le même format que `$formatInteger`." + }, + "$error": { + "args": "[str]", + "desc": "Génère une erreur avec un message. Le `str` facultatif remplacera le message par défaut de la fonction `$error() évaluée`" + }, + "$assert": { + "args": "arg, str", + "desc": "Si `arg` est vrai, la fonction renvoie undefined. Si `arg` est faux, une exception est lancée avec `str` comme message de l'exception." + }, + "$single": { + "args": "array, function", + "desc": "Renvoie la seule et unique valeur du paramètre `array` qui satisfait le prédicat `function` (c'est-à-dire que la `function` renvoie la valeur booléenne `true` lorsqu'elle est transmise à la valeur). Lève une exception si le nombre de valeurs correspondantes n'est pas exactement un.\n\nLa fonction doit être fournie dans la signature suivante : `function(value [, index [, array]])` où value est chaque entrée du tableau, index est la position de cette valeur et le tableau entier est passé comme troisième argument" + }, + "$encodeUrlComponent": { + "args": "str", + "desc": "Encode un composant URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère.\n\nExemple : `$encodeUrlComponent(\"?x =test\")` => `\"%3Fx%3Dtest\"`" + }, + "$encodeUrl": { + "args": "str", + "desc": "Encode une URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère. \n\nExemple : `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0% B5%D0%BB%D0%BB%D1%8B\"`" + }, + "$decodeUrlComponent": { + "args": "str", + "desc": "Décode un composant URL (Uniform Resource Locator) précédemment créé par encodeUrlComponent. \n\nExemple : `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" + }, + "$decodeUrl": { + "args": "str", + "desc": "Décode une URL (Uniform Resource Locator) précédemment créée par encodeUrl. \n\nExemple : `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" + }, + "$distinct": { + "args": "array", + "desc": "Renvoie un tableau avec les valeurs en double supprimées de `array`" + }, + "$type": { + "args": "value", + "desc": "Renvoie le type de `value` sous forme de chaîne. Si `value` n'est pas défini, cela renverra `undefined`" + }, + "$moment": { + "args": "[str]", + "desc": "Obtient un objet de date à l'aide de la bibliothèque Moment." + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json index b07b8e583..84a1f4dad 100644 --- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json @@ -23,7 +23,11 @@ "position": "配置", "enable": "有効", "disable": "無効", - "upload": "アップロード" + "upload": "アップロード", + "lock": "固定", + "unlock": "固定を解除", + "locked": "固定済み", + "unlocked": "固定なし" }, "type": { "string": "文字列", @@ -53,8 +57,10 @@ "confirmDelete": "削除の確認", "delete": "本当に '__label__' を削除しますか?", "dropFlowHere": "ここにフローをドロップしてください", + "dropImageHere": "ここに画像ファイルをドロップしてください", "addFlow": "フローの追加", "addFlowToRight": "右側にフローを追加", + "closeFlow": "フローを閉じる", "hideFlow": "フローを非表示", "hideOtherFlows": "他のフローを非表示", "showAllFlows": "全てのフローを表示", @@ -68,7 +74,13 @@ "enabled": "有効", "disabled": "無効", "info": "詳細", - "selectNodes": "ノードをクリックして選択" + "selectNodes": "ノードをクリックして選択", + "enableFlow": "フローを有効化", + "disableFlow": "フローを無効化", + "lockFlow": "フローを固定", + "unlockFlow": "フローの固定を解除", + "moveToStart": "フローを先頭へ移動", + "moveToEnd": "フローを最後へ移動" }, "menu": { "label": { @@ -101,6 +113,7 @@ "displayStatus": "ノードのステータスを表示", "displayConfig": "設定ノード", "import": "読み込み", + "importExample": "フロー例を読み込み", "export": "書き出し", "search": "ノードを検索", "searchInput": "ノードを検索", @@ -497,6 +510,7 @@ "addRemoveNode": "ノードの選択、選択解除", "editSelected": "選択したノードを編集", "deleteSelected": "選択したノードや接続を削除", + "deleteReconnect": "削除と再接続", "importNode": "フローの読み込み", "exportNode": "フローの書き出し", "nudgeNode": "選択したノードを移動(移動量小)", @@ -683,7 +697,11 @@ "empty": "空", "globalConfig": "グローバル設定ノード", "triggerAction": "アクションを実行", - "find": "ワークスペース内を検索" + "find": "ワークスペース内を検索", + "copyItemUrl": "要素のURLをコピー", + "copyURL2Clipboard": "URLをクリップボードにコピーしました", + "showFlow": "表示", + "hideFlow": "非表示" }, "help": { "name": "ヘルプ", @@ -984,7 +1002,10 @@ "quote": "引用", "link": "リンク", "horizontal-rule": "区切り線", - "toggle-preview": "プレビュー表示切替え" + "toggle-preview": "プレビュー表示切替え", + "mermaid": { + "summary": "Mermaid図" + } }, "bufferEditor": { "title": "バッファエディタ", @@ -1179,8 +1200,10 @@ "languages": { "de": "ドイツ語", "en-US": "英語", + "fr": "フランス語", "ja": "日本語", "ko": "韓国語", + "pt-BR":"ポルトガル語", "ru": "ロシア語", "zh-CN": "中国語(簡体)", "zh-TW": "中国語(繁体)" @@ -1207,6 +1230,11 @@ "junction": "分岐点", "linkNodes": "Linkノード" }, + "env-var": { + "environment": "環境変数", + "header": "大域環境変数", + "revert": "破棄" + }, "action-list": { "toggle-show-tips": "ヒント表示切替", "show-about": "Node-REDの説明を表示", @@ -1291,6 +1319,7 @@ "distribute-selection-vertically": "選択を上下に整列", "wire-series-of-nodes": "ノードを一続きに接続", "wire-node-to-multiple": "ノードを複数に接続", + "wire-multiple-to-node": "複数からノードへ接続", "split-wire-with-link-nodes": "ワイヤーをlinkノードで分割", "generate-node-names": "ノード名を生成", "show-user-settings": "ユーザ設定を表示", @@ -1350,6 +1379,14 @@ "show-project-settings": "プロジェクト設定を表示", "show-version-control-tab": "バージョンコントロールタブを表示", "start-flows": "フローを開始", - "stop-flows": "フローを停止" + "stop-flows": "フローを停止", + "copy-item-url": "要素のURLをコピー", + "copy-item-edit-url": "要素の編集URLをコピー", + "move-flow-to-start": "フローを先頭に移動", + "move-flow-to-end": "フローを末尾に移動", + "show-global-env": "大域環境変数を表示", + "lock-flow": "フローを固定", + "unlock-flow": "フローの固定を解除", + "show-node-help": "ノードのヘルプを表示" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/ko/editor.json b/packages/node_modules/@node-red/editor-client/locales/ko/editor.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/ko/infotips.json b/packages/node_modules/@node-red/editor-client/locales/ko/infotips.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/ko/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/ko/jsonata.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json b/packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json new file mode 100644 index 000000000..6e20bc32d --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json @@ -0,0 +1,1208 @@ +{ + "common": { + "label": { + "name": "Nome", + "ok": "O.K.", + "done": "Feito", + "cancel": "Cancelar", + "delete": "Deletar", + "close": "Fechar", + "load": "Carregar", + "save": "Salvar", + "import": "Importar", + "export": "Exportar", + "back": "Voltar", + "next": "Próximo", + "clone": "Clonar", + "cont": "Continuar", + "style": "Estilo", + "line": "Contorno", + "fill": "Preenchido", + "label": "Etiqueta", + "color": "Cor", + "position": "Posição", + "enable": "Habilitado", + "disable": "Desabilitado", + "upload": "Subir" + }, + "type": { + "string": "cadeia de caracteres", + "number": "numero", + "boolean": "booliano", + "array": "matriz", + "buffer": "armazenamento temporário", + "object": "objeto", + "jsonString": "cadeia de caracteres JSON", + "undefined": "indefinido", + "null": "nulo" + } + }, + "event": { + "loadPlugins": "Carregando programas adicionais", + "loadPalette": "Carregando Paleta", + "loadNodeCatalogs": "Carregando Catálogo de Nós", + "loadNodes": "Carregando Nós __count__", + "loadFlows": "Carregando Fluxos", + "importFlows": "Adicionar Fluxos ao espaço de trabalho", + "importError": "

Erro ao adicionar fluxos

__message__

", + "loadingProject": "Carregando projeto" + }, + "workspace": { + "defaultName": "Fluxo __number__", + "editFlow": "Editar Fluxo: __name__", + "confirmDelete": "Confirmar exclusão", + "delete": "Tem certeza de que deseja excluir '__label__'?", + "dropFlowHere": "Solte o fluxo aqui", + "addFlow": "Adicionar fluxo", + "addFlowToRight": "Adicionar fluxo à direita", + "hideFlow": "Esconder fluxo", + "hideOtherFlows": "Esconder outros fluxos", + "showAllFlows": "Mostrar todos os fluxos", + "hideAllFlows": "Esconder todos os fluxos", + "hiddenFlows": "Listar __count__ fluxo escondido", + "hiddenFlows_plural": "Listar __count__ fluxos escondidos", + "showLastHiddenFlow": "Mostrar último fluxo escondido", + "listFlows": "Listar Fluxos", + "listSubflows": "Listar subfluxos", + "status": "Estado", + "enabled": "Habilitar", + "disabled": "Desabilitar", + "info": "Descrição", + "selectNodes": "Clique em nós para selecionar" + }, + "menu": { + "label": { + "view": { + "view": "Visão", + "grid": "Grade", + "storeZoom": "Restaura nível do zoom ao carregar", + "storePosition": "Restaura posição de rolamento ao carregar", + "showGrid": "Mostre as grades", + "snapGrid": "Ajustar à grade", + "gridSize": "Tamanho da grade", + "textDir": "Direção do texto", + "defaultDir": "Padrão", + "ltr": "Esquerta-para-direita", + "rtl": "Direita-para-esquerda", + "auto": "Contextual", + "language": "Linguagem", + "browserDefault": "Padrão do navegador" + }, + "sidebar": { + "show": "Mostrar barra lateral" + }, + "palette": { + "show": "Mostrar paleta" + }, + "edit": "Editar", + "settings": "Configurações", + "userSettings": "Configurações do usuário", + "nodes": "Nós", + "displayStatus": "Mostrar estados do nó", + "displayConfig": "Configuração dos nós", + "import": "Importar", + "export": "Exportar", + "search": "Procurar fluxos", + "searchInput": "procure seus fluxos", + "subflows": "subfluxos", + "createSubflow": "Criar Subfluxo", + "selectionToSubflow": "Seleção para subfluxo", + "flows": "Fluxos", + "add": "Adicionar", + "rename": "Renomear", + "delete": "Apagar", + "keyboardShortcuts": "Atalhos do teclado", + "login": "Ingressar", + "logout": "Sair", + "editPalette": "Gerenciar paleta", + "other": "Outro", + "showTips": "Mostre as dicas", + "showWelcomeTours": "Mostrar excursão guiada para novas versões", + "help": "sítio do Node-RED", + "projects": "Projetos", + "projects-new": "Novo", + "projects-open": "Abrir", + "projects-settings": "Configurações do projeto", + "showNodeLabelDefault": "Mostrar rótulo de nós recém-adicionados", + "codeEditor": "Editor de código", + "groups": "Grupos", + "groupSelection": "Agrupar seleção", + "ungroupSelection": "Desagrupar seleção", + "groupMergeSelection": "Mesclar seleção", + "groupRemoveSelection": "Remover do grupo", + "arrange": "Organizar", + "alignLeft": "Alinhar à esquerda", + "alignCenter": "Alinhar ao centro", + "alignRight": "Alinhar à direita", + "alignTop": "Alinhar ao início", + "alignMiddle": "Alinhar ao meio", + "alignBottom": "Alinhar ao final ", + "distributeHorizontally": "Distribuir horizontalmente", + "distributeVertically": "Distribuir verticalmente", + "moveToBack": "Mover para detrás", + "moveToFront": "Mover para a frente", + "moveBackwards": "Volta", + "moveForwards": "Avança" + } + }, + "actions": { + "toggle-navigator": "Alternar navegador", + "zoom-out": "Diminuir zoom ", + "zoom-reset": "Reiniciar zoom", + "zoom-in": "Aumentar zoom", + "search-flows": "Procura fluxos", + "search-prev": "Anterior", + "search-next": "Próximo", + "search-counter": "\"__term__\" __result__ of __count__" + }, + "user": { + "loggedInAs": "Acessado como __name__", + "username": "Nome do Usuário", + "password": "Senha", + "login": "Ingressar", + "loginFailed": "Falha ao ingressar", + "notAuthorized": "Não autorizado", + "errors": { + "settings": "Você deve ingressar para acessar as configurações", + "deploy": "Você deve ingressar para implementar mudanças", + "notAuthorized": "Você precisa ter ingressado para realizar esta ação" + } + }, + "notification": { + "state": { + "flowsStopped": "Fluxos parados", + "flowsStarted": "Fluxos iniciados" + }, + "warning": "Aviso: __message__", + "warnings": { + "undeployedChanges": "o nó tem mudanças não implementadas", + "nodeActionDisabled": "ações do nó desabilitadas", + "nodeActionDisabledSubflow": "ações do nó desabilitadas dentro do subfluxo", + "missing-types": "

Fluxos parados devido a tipos de nós ausentes.

", + "missing-modules": "

Os fluxos pararam devido à falta de módulos.

", + "safe-mode": "

Fluxos parados no modo de segurança.

Você pode modificar seus fluxos e implementar as mudanças para reiniciar.

", + "restartRequired": "O Node-RED deve ser reiniciado para habilitar os módulos atualizados", + "credentials_load_failed": "

Os fluxos pararam porque as credenciais não puderam ser descriptografadas.

O arquivo de credencial de fluxo está criptografado, mas a chave de criptografia do projeto está ausente ou é inválida.

", + "credentials_load_failed_reset": "

As credenciais não puderam ser descriptografadas

O arquivo de credencial do fluxo está criptografado, mas a chave de criptografia do projeto está ausente ou é inválida.

O arquivo de credencial de fluxo será redefinido na próxima implantação. Todas as credenciais de fluxo existentes serão apagadas.

", + "missing_flow_file": "

Arquivo de fluxo de projeto não encontrado.

O projeto não está configurado com um arquivo de fluxo.

", + "missing_package_file": "

Arquivo de pacote de projeto não encontrado.

O projeto está sem um arquivo package.json.

", + "project_empty": "

O projeto está vazio.

Você deseja criar um conjunto padrão de arquivos de projeto?
Caso contrário, você terá que adicionar arquivos manualmente ao projeto fora do editor.

", + "project_not_found": "

Projeto '__project__' não encontrado.

", + "git_merge_conflict": "

A mesclagem automática de alterações falhou.

Corrija os conflitos não mesclados e confirme os resultados.

" + }, + "error": "Erro: __message__", + "errors": { + "lostConnection": "Conexão perdida com o servidor, reconectando...", + "lostConnectionReconnect": "Conexão perdida com o servidor, reconectando em __time__s.", + "lostConnectionTry": "Tentar novamente", + "cannotAddSubflowToItself": "Não é possível adicionar subfluxo a si mesmo", + "cannotAddCircularReference": "Não é possível adicionar subfluxo - referência circular detectada", + "unsupportedVersion": "

Usando uma versão não suportada do Node.js

Você deve atualizar para a versão mais recente do Node.js LTS

", + "failedToAppendNode": "

Falha ao carregar '__module__'

__error__

" + }, + "project": { + "change-branch": "Mudar para ramo local'__project__'", + "merge-abort": "Mesclagem Git abortada", + "loaded": "Projeto '__project__' carregado", + "updated": "Projeto '__project__' atualizado", + "pull": "Projeto '__project__' recarregado", + "revert": "Projeto '__project__' revertido", + "merge-complete": "Mesclagem Git completa", + "setupCredentials": "Configurar credenciais", + "setupProjectFiles": "Configurar arquivos de projeto", + "no": "Não obrigado", + "createDefault": "Criar arquivos de projeto padrão", + "mergeConflict": "Mostrar conflitos de mesclagem" + }, + "label": { + "manage-project-dep": "Gerenciar dependências do projeto", + "setup-cred": "Configurar credenciais", + "setup-project": "Arquivos de projeto de instalação", + "create-default-package": "Criar arquivo de pacote padrão", + "no-thanks": "Não obrigado", + "create-default-project": "Crie arquivos de projeto padrão", + "show-merge-conflicts": "Mostrar conflitos de mesclagem", + "unknownNodesButton": "Procura por nós desconhecidos" + } + }, + "clipboard": { + "clipboard": "Área de transferência", + "nodes": "Nós", + "node": "__count__ nó", + "node_plural": "__count__ nós", + "configNode": "__count__ nó de configuração", + "configNode_plural": "__count__ nós de configuração", + "group": "__count__ grupo", + "group_plural": "__count__ grupos", + "flow": "__count__ fluxo", + "flow_plural": "__count__ fluxos", + "subflow": "__count__ subfluxo", + "subflow_plural": "__count__ subfluxos", + "replacedNodes": "__count__ nó substituído", + "replacedNodes_plural": "__count__ nós substituídos", + "pasteNodes": "Colar fluxo JSON ou", + "selectFile": "selecione um arquivo para importar", + "importNodes": "Importar nós", + "exportNodes": "Exportar nós", + "download": "Baixar", + "importUnrecognised": "Tipo não reconhecido importado:", + "importUnrecognised_plural": "Tipos não reconhecidos importados:", + "importDuplicate": "Nó duplicado importado:", + "importDuplicate_plural": "Nós duplicados importados:", + "nodesExported": "Nós exportados para a área de transferência", + "nodesImported": "Importado:", + "nodeCopied": "__count__ nó copiado", + "nodeCopied_plural": "__count__ nós copiados", + "groupCopied": "__count__ grupo copiado", + "groupCopied_plural": "__count__ grupos copiados", + "groupStyleCopied": "Estilo de grupo copiado", + "invalidFlow": "Fluxo inválido: __message__", + "recoveredNodes": "Nós recuperados", + "recoveredNodesInfo": "Os nós neste fluxo não tinham um ID de fluxo válido quando foram importados. Eles foram adicionados a este fluxo para que você possa restaurá-los ou excluí-los.", + "recoveredNodesNotification": "

Nós importados sem um ID de fluxo válido

Eles foram adicionados a um novo fluxo chamado '__flowName__'.

", + "export": { + "selected": "nós selecionados", + "current": "fluxo corrente", + "all": "todos os fluxos", + "compact": "compactar", + "formatted": "formatado", + "copy": "Copiar para área de transferência", + "export": "Exportar biblioteca", + "exportAs": "Exportar como", + "overwrite": "Substituir", + "exists": "

\"__file__\" já existe.

Deseja substituir?

" + }, + "import": { + "import": "Importar para", + "importSelected": "Importar selecionado", + "importCopy": "Importar cópia", + "viewNodes": "Ver nós...", + "newFlow": "novo fluxo", + "replace": "substituir", + "errors": { + "notArray": "A entrada não é uma matriz JSON", + "itemNotObject": "A entrada não é um fluxo válido - o item __index__ não é um objeto de nó", + "missingId": "A entrada não é um fluxo válido - item __index__ faltando propriedade 'id'", + "missingType": "A entrada não é um fluxo válido - item __index__ faltando propriedade 'type'" + }, + "conflictNotification1": "Alguns dos nós que você está importando já existem em sua área de trabalho.", + "conflictNotification2": "Selecione quais nós importar e se deseja substituir os nós existentes ou importar uma cópia deles." + }, + "copyMessagePath": "Caminho copiado", + "copyMessageValue": "Valor copiado", + "copyMessageValue_truncated": "Valor truncado copiado" + }, + "deploy": { + "deploy": "implementar", + "full": "Cheio", + "fullDesc": "Implementar tudo no espaço de trabalho", + "modifiedFlows": "Fluxos Modificados", + "modifiedFlowsDesc": "Implantar apenas fluxos que contêm nós alterados", + "modifiedNodes": "Nós Modificados", + "modifiedNodesDesc": "Implantar apenas nós que mudaram", + "startFlows": "Iniciar", + "startFlowsDesc": "Iniciar Fluxos", + "stopFlows": "Parar", + "stopFlowsDesc": "Parar Fluxos", + "restartFlows": "Reiniciar Fluxos", + "restartFlowsDesc": "Reinicia os fluxos atuais implantados", + "successfulDeploy": "Implementado com sucesso", + "successfulRestart": "Fluxos reiniciados com sucesso", + "deployFailed": "Implementação falhou: __message__", + "unusedConfigNodes": "Você tem alguns nós de configuração não utilizados.", + "unusedConfigNodesButton": "Procurar por nós de configuração não utilizados", + "unknownNodesButton": "Procurar por nós desconhecidos", + "invalidNodesButton": "Procurar por nós inválidos", + "errors": { + "noResponse": "sem resposta do servidor" + }, + "confirm": { + "button": { + "ignore": "Ignorar", + "confirm": "Confirmar implantação", + "review": "Rever alterações", + "cancel": "Cancelar", + "merge": "Mesclar", + "overwrite": "Ignorar e implantar" + }, + "undeployedChanges": "Você tem alterações não implementadas. \n\n Se sair desta página, essas alterações serão perdidas.", + "improperlyConfigured": "O espaço de trabalho contém alguns nós que não estão configurados corretamente:", + "unknown": "O espaço de trabalho contém alguns tipos de nós desconhecidos:", + "confirm": "Tem certeza que deseja implantar?", + "doNotWarn": "não avisar sobre isso de novo ", + "conflict": "O servidor está executando um conjunto de fluxos mais recente.", + "backgroundUpdate": "Os fluxos no servidor foram atualizados.", + "conflictChecking": "Verificando se as alterações podem ser mescladas automaticamente", + "conflictAutoMerge": "As alterações não incluem conflitos e podem ser mescladas automaticamente.", + "conflictManualMerge": "As mudanças incluem conflitos que devem ser resolvidos antes de serem implantados.", + "plusNMore": "+ __count__ mais" + } + }, + "eventLog": { + "title": "Registro de Eventos", + "view": "Registro de visão" + }, + "diff": { + "unresolvedCount": "__count__ conflito não resolvido ", + "unresolvedCount_plural": "__count__ conflitos não resolvidos ", + "globalNodes": "Nós globais ", + "flowProperties": "Propriedades de fluxo ", + "type": { + "added": "adicionado", + "changed": "alterado", + "unchanged": "inalterado ", + "deleted": "Excluído", + "flowDeleted": "fluxo excluído ", + "flowAdded": "fluxo adicionado ", + "movedTo": "movido para __id__ ", + "movedFrom": "movido de __id__" + }, + "nodeCount": "__count__ nó", + "nodeCount_plural": "__count__ nós", + "local": "Mudanças locais ", + "remote": "Mudanças remotas ", + "reviewChanges": "Rever alterações ", + "noBinaryFileShowed": "Não é possível mostrar o conteúdo do arquivo binário ", + "viewCommitDiff": "Ver alterações de confirmação ", + "compareChanges": "Compare as alterações ", + "saveConflict": "Salvar resolução de conflito ", + "conflictHeader": "__resolved__ of __unresolved__ conflitos resolvidos", + "commonVersionError": "A versão comum não contém JSON válido: ", + "oldVersionError": "A versão antiga não contém JSON válido: ", + "newVersionError": "A nova versão não contém JSON válido: " + }, + "subflow": { + "editSubflowInstance": "Editar instância de subfluxo: __name__", + "editSubflow": "Editar modelo de subfluxo: __name__", + "edit": "Editar modelo de subfluxo", + "subflowInstances": "Existe uma instância __count__ deste modelo de subfluxo", + "subflowInstances_plural": "Existem __count__ instâncias deste modelo de subfluxo", + "editSubflowProperties": "editar propriedades", + "input": "entradas:", + "output": "saídas:", + "status": "estados do nó", + "deleteSubflow": "excluir subfluxo", + "confirmDelete": "Tem certeza de que deseja excluir este subfluxo?", + "info": "Descrição", + "category": "Categoria", + "module": "Módulo", + "license": "Licença", + "licenseNone": "Nenhum", + "licenseOther": "Outro", + "type": "Tipo de nó", + "version": "Versão", + "versionPlaceholder": "x.y.z", + "keys": "Palavras-chave", + "keysPlaceholder": "Palavras-chave separadas por vírgulas", + "author": "Autor", + "authorPlaceholder": "Seu nome ", + "desc": "Descrição", + "env": { + "restore": "Restaurar para o subfluxo padrão", + "remove": "Remover variável de ambiente" + }, + "errors": { + "noNodesSelected": "Não é possível criar subfluxo : nenhum nó selecionado", + "multipleInputsToSelection": "Não é possível criar subfluxo : várias entradas para seleção" + } + }, + "group": { + "editGroup": "Editar grupo: __name__", + "errors": { + "cannotCreateDiffGroups": "Não é possível criar grupo usando nós de grupos diferentes", + "cannotAddSubflowPorts": "Não é possível adicionar portas de subfluxo a um grupo" + } + }, + "editor": { + "configEdit": "Editar", + "configAdd": "Adicionar", + "configUpdate": "Atualizar", + "configDelete": "Excluir", + "nodesUse": "__count__ o nó usa esta configuração", + "nodesUse_plural": "__count__ os nós usam esta configuração", + "addNewConfig": "Adicionar novo __type__ configuração de nó", + "editNode": "Editar __type__ nó", + "editConfig": "Editar __type__ configuração de nó", + "addNewType": "Adicionar novo __type__...", + "nodeProperties": "propriedades do nó", + "label": "Etiqueta", + "color": "Cor", + "portLabels": "Rótulo da porta", + "labelInputs": "Entradas", + "labelOutputs": "Saídas", + "settingIcon": "Ícone", + "default": "padrão", + "noDefaultLabel": "nenhum", + "defaultLabel": "usar etiqueta padrão", + "searchIcons": "Procurar ícones", + "useDefault": "usar padrão", + "description": "Descrição", + "show": "Mostrar", + "hide": "Esconder", + "locale": "Selecione o idioma da interface", + "icon": "Ícone", + "inputType": "Tipo de entrada", + "selectType": "selecione os tipos...", + "loadCredentials": "Carregando credenciais de nó", + "inputs": { + "input": "entrada", + "select": "seleção", + "checkbox": "caixa de seleção", + "spinner": "caixa de mostruário giratório", + "none": "nenhum", + "hidden": "ocultar propriedade" + }, + "types": { + "str": "cadeia de caracteres", + "num": "numero", + "bool": "booliano", + "json": "JSON", + "bin": "armazenamento temporário", + "env": "variável de ambiente", + "cred": "credencial" + }, + "menu": { + "input": "entrada", + "select": "seleção", + "checkbox": "caixa de seleção", + "spinner": "roleta", + "hidden": "Somente etiqueta" + }, + "select": { + "label": "Etiqueta", + "value": "Valor" + }, + "spinner": { + "min": "Mínimo", + "max": "Máximo" + }, + "errors": { + "scopeChange": "Alterar o escopo o tornará indisponível para nós em outros fluxos que o utilizam", + "invalidProperties": "Propriedades inválidas:", + "credentialLoadFailed": "Falha ao carregar credenciais de nó" + } + }, + "keyboard": { + "title": "Atalhos do teclado", + "keyboard": "Teclado", + "filterActions": "ações de filtro", + "shortcut": "atalho", + "scope": "escopo", + "unassigned": "Não atribuído", + "global": "global", + "workspace": "área de trabalho", + "selectAll": "Selecionar todos", + "selectNone": "Selecionar nenhum", + "selectAllConnected": "Selecione todos os nós conectados", + "addRemoveNode": "Adicionar / remover nó da seleção", + "editSelected": "Editar nó selecionado", + "deleteSelected": "Excluir nós selecionados ou link", + "importNode": "Importar nós", + "exportNode": "Exportar nós", + "nudgeNode": "Mover nós selecionados (1px)", + "moveNode": "Mover nós selecionados (20px)", + "toggleSidebar": "Alternar barra lateral", + "togglePalette": "Alternar paleta", + "copyNode": "Copiar nós selecionados", + "cutNode": "Cortar nós selecionados", + "pasteNode": "Colar nós", + "copyGroupStyle": "Copiar estilo de grupo", + "pasteGroupStyle": "Colar estilo de grupo", + "undoChange": "Desfazer", + "redoChange": "Refazer", + "searchBox": "Abrir caixa de pesquisa", + "managePalette": "Gerenciar paleta", + "actionList": "Lista de Ação", + "splitWireWithLinks": "Separa a seleção com os nós de ligação" + }, + "library": { + "library": "Biblioteca", + "openLibrary": "Biblioteca aberta ...", + "saveToLibrary": "Salvar na biblioteca ...", + "typeLibrary": "__type__ biblioteca", + "unnamedType": "Sem nome __tipo__", + "exportedToLibrary": "Nós exportados para a biblioteca", + "dialogSaveOverwrite": "Já existe um __libraryType__ chamado __libraryName__. Substituir?", + "invalidFilename": "Nome de arquivo inválido", + "savedNodes": "Nós salvos", + "savedType": "Salvo __tipo__", + "saveFailed": "Falha ao salvar: __message__", + "newFolder": "Nova pasta", + "types": { + "local": "Local", + "examples": "Exemplos" + } + }, + "palette": { + "noInfo": "sem informação disponível", + "filter": "filtrar nós", + "search": "procurar módulos", + "addCategory": "Adicionar novo...", + "label": { + "subflows": "subfluxos", + "network": "rede", + "common": "comum", + "input": "entrada", + "output": "saída", + "function": "função", + "sequence": "sequencia", + "parser": "analisador sintático", + "social": "social", + "storage": "armazenar", + "analysis": "análise", + "advanced": "avançado" + }, + "actions": { + "collapse-all": "Recolher todas as categorias", + "expand-all": "Expandir todas as categorias" + }, + "event": { + "nodeAdded": "Nó adicionado à paleta:", + "nodeAdded_plural": "Nós adicionados à paleta:", + "nodeRemoved": "Nó removido da paleta:", + "nodeRemoved_plural": "Nós removidos da paleta:", + "nodeEnabled": "Nó habilitado:", + "nodeEnabled_plural": "Nós habilitados:", + "nodeDisabled": "Nó desativado:", + "nodeDisabled_plural": "Nós desativados:", + "nodeUpgraded": "Módulo de nó __module__ atualizado para a versão __version__", + "unknownNodeRegistered": "Erro carregando o nó: " + }, + "editor": { + "title": "Gerenciar paleta", + "palette": "Paleta", + "times": { + "seconds": "segundos atrás", + "minutes": "minutos atrás", + "minutesV": "__count__ minutos atrás", + "hoursV": "__count__ hora atrás", + "hoursV_plural": "__count__ horas atrás", + "daysV": "__count__ dia atrás", + "daysV_plural": "__count__ dias atrás", + "weeksV": "__count__ semana atrás", + "weeksV_plural": "__count__ semanas atrás", + "monthsV": "__count__ mês atrás", + "monthsV_plural": "__count__ meses atrás", + "yearsV": "__count__ ano atrás", + "yearsV_plural": "__count__ anos atrás", + "yearMonthsV": "__y__ ano, __count__ mês atrás", + "yearMonthsV_plural": "__y__ ano, __count__ meses atrás", + "yearsMonthsV": "__y__ anos, __count__ mês atrás", + "yearsMonthsV_plural": "__y__ anos, __count__ meses atrás" + }, + "nodeCount": "__label__ node", + "nodeCount_plural": "__label__ nodes", + "moduleCount": "módulo __count__ disponível", + "moduleCount_plural": "__count__ módulos disponíveis", + "inuse": "em uso", + "enableall": "habilitar todos", + "disableall": "desabilitar todos", + "enable": "habilitar", + "disable": "desabilitar", + "remove": "remover", + "update": "atualizar para __version__", + "updated": "atualizado", + "install": "instalar", + "installed": "instalado", + "conflict": "conflito", + "conflictTip": "

Este módulo não pode ser instalado porque inclui um
tipo de nó que já foi instalado

Conflitos com __module__

" , + "loading": "Carregando catálogos ...", + "tab-nodes": "Nós", + "tab-install": "Instalar", + "sort": "ordenar:", + "sortAZ": "a-z", + "sortRecent": "recente", + "more": "+ __count__ mais", + "upload": "Carregar arquivo tgz do módulo", + "refresh": "Atualizar lista de módulos", + "errors": { + "catalogLoadFailed": "

Falha ao carregar o catálogo de nós.

Verifique o console do navegador para obter mais informações

", + "installFailed": "

Falha ao instalar: __module__

__message__

Verifique o log para obter mais informações

", + "removeFailed": "

Falha ao remover: __module__

__message__

Verifique o log para obter mais informações

", + "updateFailed": "

Falha ao atualizar: __module__

__message__

Verifique o log para obter mais informações

", + "enableFailed": "

Falha ao ativar: __module__

__message__

Verifique o log para obter mais informações

", + "disableFailed": "

Falha ao desativar: __module__

__message__

Verifique o log para obter mais informações

" + }, + "confirm": { + "install": { + "body": "

Instalando '__module__'

Antes de instalar, leia a documentação do nó. Alguns nós têm dependências que não podem ser resolvidas automaticamente e podem exigir a reinicialização do Node-RED.

", + "title": "Instalar nós" + }, + "remove": { + "body": "

Remover '__module__'

Remover o nó irá desinstalá-lo do Node-RED. O nó pode continuar a usar recursos até que o Node-RED seja reiniciado.

", + "title": "Remover nós" + }, + "update": { + "body": "

Atualizar '__module__'

Atualizar o nó exigirá a reinicialização do Node-RED para concluir a atualização. Isso deve ser feito manualmente.

", + "title": "Atualizar nós" + }, + "cannotUpdate": { + "body": "Uma atualização para este nó está disponível, mas não está instalada em um local que o gerenciador de paletas possa atualizar.

Consulte a documentação para saber como atualizar este nó." + }, + "button": { + "review": "Abrir informação do nó", + "install": "Instalar", + "remove": "Remover", + "update": "Atualizar" + } + } + } + }, + "sidebar": { + "info": { + "name": "Informação", + "tabName": "Nome", + "label": "informações", + "node": "Nó", + "type": "Tipo", + "group": "Grupo", + "module": "Módulo", + "id": "ID", + "status": "Estado", + "enabled": "Habilitado", + "disabled": "Desabilitado", + "subflow": "Subfluxo", + "instances": "Instâncias", + "properties": "Propriedades", + "info": "Informação", + "desc": "Descrição", + "blank": "branco", + "null": "nulo", + "showMore": "mostrar mais", + "showLess": "mostrar menos", + "flow": "Fluxo", + "selection": "Seleção", + "nodes": "__count__ nós", + "flowDesc": "Descrição do Fluxo", + "subflowDesc": "Descrição do Subfluxo", + "nodeHelp": "Ajuda do Nó", + "none": "Nenhum", + "arrayItems": "__count__ items", + "showTips": "Você pode abrir as dicas a partir do painel de configurações", + "outline": "Contorno", + "empty": "vazio", + "globalConfig": "Nós de configuração global", + "triggerAction": "Ação de gatilho", + "find": "Encontre no espaço de trabalho" + }, + "help": { + "name": "Ajuda", + "label": "ajuda", + "search": "Ajuda sobre a procura", + "nodeHelp": "Ajuda sobre o nó", + "showHelp": "Mostrar ajuda", + "showInOutline": "Mostrar no contorno", + "showTopics": "Mostrar tópicos", + "noHelp": "Nenhum tópico de ajuda selecionado", + "changeLog": "Log de alteração" + }, + "config": { + "name": "Configuração dos nós", + "label": "configuração", + "global": "Em todos os fluxos", + "none": "nenhum", + "subflows": "subfluxos", + "flows": "fluxos", + "filterAll": "todos", + "showAllConfigNodes": "Ver todas as configurações dos nós", + "filterUnused": "não utilizados", + "showAllUnusedConfigNodes": "Mostrar todas os nós de configuração não usados", + "filtered": "__count__ hidden" + }, + "context": { + "name": "Contexto dos Dados", + "label": "contexto", + "none": "nenhum selecionado", + "refresh": "atualize para carregar", + "empty": "vazio", + "node": "Nó", + "flow": "Fluxo", + "global": "Global", + "deleteConfirm": "Você tem certeza que deseja remover este item?", + "autoRefresh": "Atualizar na mudança de seleção", + "refrsh": "Atualizar", + "delete": "Remover" + }, + "palette": { + "name": "Gerenciamento de paleta", + "label": "paleta" + }, + "project": { + "label": "projeto", + "name": "Projeto", + "description": "Descrição", + "dependencies": "Dependências", + "settings": "Configurações", + "noSummaryAvailable": "Nenhum resumo disponível", + "editDescription": "Editar a descrição do projeto", + "editDependencies": "Editar dependências do projeto", + "noDescriptionAvailable": "Descrição não disponível", + "editReadme": "Editar README.md", + "showProjectSettings": "Mostrar configurações do projeto", + "projectSettings": { + "title": "Configurações do Projeto", + "edit": "editar", + "none": "Nenhum", + "install": "instalar", + "removeFromProject": "remover do projeto", + "addToProject": "adicionar ao projeto", + "files": "Arquivos", + "flow": "Fluxos", + "credentials": "Credenciais", + "package": "Pacote", + "packageCreate": "O arquivo será criado quando as alterações forem salvas", + "fileNotExist": "Arquivo não existe", + "selectFile": "Selecione o arquivo", + "invalidEncryptionKey": "Chave de criptografia inválida", + "encryptionEnabled": "Criptografia habilitada", + "encryptionDisabled": "Criptografia desabilitada", + "setTheEncryptionKey": "Defina a chave de criptografia", + "resetTheEncryptionKey": "Redefina a chave de criptografia", + "changeTheEncryptionKey": "Troque a chave de criptografia", + "currentKey": "Chave atual", + "newKey": "Nova chave", + "credentialsAlert": "Isso excluirá todas as credenciais existentes", + "versionControl": "Controle de versão", + "branches": "Ramos", + "noBranches": "Sem ramos", + "deleteConfirm": "Tem certeza de que deseja excluir o ramo local '__name__'? Isto não pode ser desfeito.", + "unmergedConfirm": "O ramo local '__name__' tem alterações não mescladas que serão perdidas. Tem certeza que deseja excluir?", + "deleteUnmergedBranch": "Excluir ramo não mesclado", + "gitRemotes": "Git remoto", + "addRemote": "adicionar remoto", + "addRemote2": "Adicionar remoto", + "remoteName": "Nome do remoto", + "nameRule": "Deve conter apenas A-Z 0-9 _ -", + "url": "URL", + "urlRule": "https://, ssh:// ou file://", + "urlRule2": "Não inclua o nome de usuário / senha na URL", + "noRemotes": "Sem remotos", + "deleteRemoteConfrim": "Tem certeza de que deseja excluir o remoto '__name__'?", + "deleteRemote": "Excluir remoto" + }, + "userSettings": { + "committerDetail": "Detalhes do Cometedor", + "committerTip": "Deixe em branco para usar o padrão do sistema", + "userName": "Nome de usuário", + "email": "Email", + "workflow": "Fluxo de trabalho", + "workfowTip": "Escolha seu fluxo de trabalho git preferido", + "workflowManual": "Manual", + "workflowManualTip": "Todas as alterações devem ser confirmadas manualmente na barra lateral 'histórico'", + "workflowAuto": "Automático", + "workflowAutoTip": "As alterações são confirmadas automaticamente a cada implantação", + "sshKeys": "Chaves SSH", + "sshKeysTip": "Permite que você crie conexões seguras para repositórios git remotos.", + "add": "adicionar chave", + "addSshKey": "Adicionar chave SSH", + "addSshKeyTip": "Gerar um novo par de chaves públicas / privadas", + "name": "Nome", + "nameRule": "Deve conter apenas A-Z 0-9 _ -", + "passphrase": "Frase de passe", + "passphraseShort": "Frase de passe muito curta", + "optional": "Opcional", + "cancel": "Cancelar", + "generate": "Gerar chave", + "noSshKeys": "Sem chaves SSH", + "copyPublicKey": "Copiar chave pública para a área de transferência", + "delete": "Excluir chave key", + "gitConfig": "Configuração do Git", + "deleteConfirm": "Tem certeza de que deseja excluir a chave SSH __name__? Isso não pode ser desfeito." + }, + "versionControl": { + "unstagedChanges": "Alterações não realizadas", + "stagedChanges": "Alterações realizadas", + "unstageChange": "Desfazer alteração", + "stageChange": "Realizar alteração", + "unstageAllChange": "Desfazer todas as alterações", + "stageAllChange": "Realizar todas as alterações", + "commitChanges": "Cometer alterações", + "resolveConflicts": "Resolver conflitos", + "head": "CABEÇA", + "staged": "Alterado", + "unstaged": "Desfeita Alteração", + "local": "Local", + "remote": "Remoto", + "revert": "Tem certeza de que deseja reverter as alterações para '__file__'? Essa ação não poderá ser desfeita.", + "revertChanges": "Reverter alterações", + "localChanges": "Mudanças locais", + "none": "Nenhum", + "conflictResolve": "Todos os conflitos resolvidos. Cometa as alterações para concluir a mesclagem.", + "localFiles": "Arquivos locais", + "all": "todos", + "unmergedChanges": "Alterações não mescladas", + "abortMerge": "interromper mesclagem", + "commit": "cometer", + "changeToCommit": "Alterações para cometer", + "commitPlaceholder": "Digite sua mensagem de cometimento", + "cancelCapital": "Cancelar", + "commitCapital": "Cometer", + "commitHistory": "Histórico do cometimento", + "branch": "Ramo:", + "moreCommits": "mais cometimentos", + "changeLocalBranch": "Alterar ramo local", + "createBranchPlaceholder": "Encontrar ou criar um ramo", + "upstream": "subir do cliente ao servidor", + "localOverwrite": "Você tem alterações locais que seriam sobrescritas alterando o ramo. Você deve cometer ou desfazer essas alterações primeiro.", + "manageRemoteBranch": "Gerenciar ramo remoto", + "unableToAccess": "Incapaz de acessar o repositório remoto", + "retry": "Tentar novamente", + "setUpstreamBranch": "Definir como ramo de subida do cliente para o servidor", + "createRemoteBranchPlaceholder": "Encontrar ou criar um ramo remoto", + "trackedUpstreamBranch": "O ramo criado será definido como o ramo de subida do cliente para o servidor rastreado.", + "selectUpstreamBranch": "O ramo será criado. Selecione abaixo para defini-lo como o ramo de subida do cliente para o servidor rastreado.", + "pushFailed": "falha ao empurrar porque o remoto tem cometimentos mais recentes. Puxe e mescle primeiro, depois empurre novamente.", + "push": "empurrar", + "pull": "puxar", + "unablePull": "

Incapaz de puxar as alterações remotas; suas alterações locais não realizadas seriam sobrescritas.

Cometa suas alterações e tente novamente.

", + "showUnstagedChanges": "Mostrar alterações não realizadas", + "connectionFailed": "Não foi possível conectar ao repositório remoto:", + "pullUnrelatedHistory": "

O remoto tem um histórico não relacionado de cometimentos.

Tem certeza que deseja puxar as mudanças para o seu repositório local?

", + "pullChanges": "Puxar modificações", + "history": "histórico", + "projectHistory": "Histórico do Projeto", + "daysAgo": "__count__ dia atrás", + "daysAgo_plural": "__count__ dias atrás", + "hoursAgo": "__count__ hora atrás", + "hoursAgo_plural": "__count__ horas atrás", + "minsAgo": "__count__ min ago", + "minsAgo_plural": "__count__ minutos atrás", + "secondsAgo": "Segundos atrás", + "notTracking": "Seu ramo local não está atualmente rastreando um ramo remoto.", + "statusUnmergedChanged": "Seu repositório tem alterações não mescladas. Você precisa corrigir os conflitos e enviar o resultado.", + "repositoryUpToDate": "Seu repositório está atualizado.", + "commitsAhead": "Seu repositório está __count__ cometimento à frente do remoto. Você pode empurrar este cometimento agora.", + "commitsAhead_plural": "Seu repositório está __count__ cometimentos à frente do remoto. Você pode empurrar estes cometimentos agora.", + "commitsBehind": "Seu repositório está __count__ cometimento atrás do remoto. Você pode puxar este cometimento agora.", + "commitsBehind_plural": "Seu repositório está __count__ cometimentos atrás do remoto. Você pode puxar esses cometimentos agora.", + "commitsAheadAndBehind1": "Seu repositório está __count__ cometimento atrás e", + "commitsAheadAndBehind1_plural": "Seu repositório está __count__ cometimentos atrás e", + "commitsAheadAndBehind2": "__count__ cometimento à frente do remoto.", + "commitsAheadAndBehind2_plural": "__count__ cometimentos à frente do remoto.", + "commitsAheadAndBehind3": "Você deve baixar o cometimento remoto antes de empurrar.", + "commitsAheadAndBehind3_plural": "Você deve baixar os cometimentos remotos antes de empurrar.", + "refreshCommitHistory": "Atualizar histórico de cometimentos", + "refreshChanges": "Atualizar alterações" + } + } + }, + "typedInput": { + "type": { + "str": "cadeia de caracteres", + "num": "número", + "re": "expressão regular", + "bool": "booliano", + "json": "JSON", + "bin": "armazenamento temporário", + "date": "registro de tempo", + "jsonata": "expressão", + "env": "variável de ambiente", + "cred": "credencial" + } + }, + "editableList": { + "add": "adicionar", + "addTitle": "adicionar um item" + }, + "search": { + "history": "Histórico da procura", + "clear": "limpar tudo", + "empty": "Nenhuma equivalência encontrada", + "addNode": "adicionar um nó...", + "options": { + "configNodes": "Configuração de nós", + "unusedConfigNodes": "Configuração de nós não utilizadas", + "invalidNodes": "Nós inválidos", + "uknownNodes": "Nós desconhecidos", + "unusedSubflows": "Subfluxos não utilizados", + "hiddenFlows": "Flux escondidos", + "modifiedNodes": "Nós e Fluxos Modificados", + "thisFlow": "Fluxo atual" + } + }, + "expressionEditor": { + "functions": "Funções", + "functionReference": "Referência de função", + "insert": "Inserir", + "title": "Editor de Expressões JSONata", + "test": "Teste", + "data": "Mensagem de exemplo", + "result": "Resultado", + "format": "expressão de formato", + "compatMode": "Modo de compatibilidade habilitado", + "compatModeDesc": "

Modo de compatibilidade JSONata

A expressão atual parece ainda fazer referência a msg , então será avaliada no modo de compatibilidade. Atualize a expressão para não usar msg , pois este modo será removido no futuro.

Quando o suporte JSONata foi adicionado pela primeira vez ao Node-RED, era necessária a expressão para fazer referência ao objeto msg . Por exemplo, msg.payload seria usado para acessar a carga útil.

Isso não é mais necessário, pois a expressão será avaliada em relação à mensagem diretamente. Para acessar a carga útil, a expressão deve ser apenas payload.

", + "noMatch": "Nenhum resultado correspondente", + "errors": { + "invalid-expr": "Expressão JSONata inválida:\n __message__", + "invalid-msg": "Exemplo de mensagem JSON inválida:\n __message__", + "context-unsupported": "Não é possível testar funções de contexto\n $flowContext or $globalContext", + "eval": "Erro ao avaliar a expressão:\n __message__" + } + }, + "monaco": { + "setTheme": "Definir tema" + }, + "jsEditor": { + "title": "Editor JavaScript" + }, + "textEditor": { + "title": "Editor de texto" + }, + "jsonEditor": { + "title": "editor JSON", + "format": "formatar JSON", + "rawMode": "Editar JSON", + "uiMode": "Editor visual", + "rawMode-readonly": "JSON", + "uiMode-readonly": "Visual", + "insertAbove": "Inserir acima", + "insertBelow": "Inserir abaixo", + "addItem": "Adicionar item", + "copyPath": "Copiar caminho para o item", + "expandItems": "Expandir itens", + "collapseItems": "Recolher itens", + "duplicate": "Duplicar", + "error": { + "invalidJSON": "JSON inválido: " + } + }, + "markdownEditor": { + "title": "Editor de Remarcação", + "expand": "Expandir", + "format": "Formatado com Remarcação", + "heading1": "Cabeçalho 1", + "heading2": "Cabeçalho 2", + "heading3": "Cabeçalho 3", + "bold": "Negrito", + "italic": "Itálico", + "code": "Código", + "ordered-list": "Lista ordenada", + "unordered-list": "Lista não-ordenada", + "quote": "Citar", + "link": "criar atalho", + "horizontal-rule": "Régua Horizontal", + "toggle-preview": "Alternar visualização" + }, + "bufferEditor": { + "title": "Editor de armazenamento temporário", + "modeString": "Tratar como cadeia de caracteres UTF-8", + "modeArray": "Manipular como matriz JSON", + "modeDesc": "

Editor de armazenamento temporário

O tipo de armazenamento temporário é armazenado como uma matriz JSON de valores de bytes. O editor tentará analisar o valor inserido como uma matriz JSON. Se não for um JSON válido, será tratada como uma cadeia de caracteres UTF-8 e convertida em uma matriz de pontos de código de caractere individual.

Por exemplo, um valor de Hello World será convertido na matriz JSON:

 [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100] 

" + }, + "projects": { + "config-git": "Configurar cliente Git", + "welcome": { + "hello": "Olá! Introduzimos 'projetos' no Node-RED.", + "desc0": "Esta é uma nova maneira de gerenciar seus arquivos de fluxo e incluir controle de versão de seus fluxos.", + "desc1": "Para começar, você pode criar seu primeiro projeto ou clonar um projeto existente de um repositório git.", + "desc2": "Se você não tiver certeza, pode pular isso por enquanto. Você ainda poderá criar seu primeiro projeto a partir do menu 'Projetos' a qualquer momento.", + "create": "Criar Projeto", + "clone": "Repositório de clones", + "openExistingProject": "Abrir projeto existente", + "not-right-now": "Não nesse exato momento" + }, + "git-config": { + "setup": "Configure seu cliente de controle de versão", + "desc0": "O Node-RED usa a ferramenta de código aberto Git para controle de versão. Ele rastreia as alterações em seus arquivos de projeto e permite enviá-los para repositórios remotos.", + "desc1": "Quando você confirma um conjunto de alterações, o Git registra quem fez as alterações com um nome de usuário e endereço de e-mail. O nome de usuário pode ser o que você quiser - não precisa ser seu nome real.", + "desc2": "Seu cliente Git já está configurado com os detalhes abaixo.", + "desc3": "Você pode alterar essas configurações mais tarde na guia 'Git config' da caixa de diálogo de configurações.", + "username": "Nome do usuário", + "email": "E-mail" + }, + "project-details": { + "create": "Crie seu projeto", + "desc0": "Um projeto é mantido como um repositório Git. Isso torna muito mais fácil compartilhar seus fluxos com outras pessoas e colaborar neles.", + "desc1": "Você pode criar vários projetos e alternar rapidamente entre eles no editor.", + "desc2": "Para começar, seu projeto precisa de um nome e uma descrição opcional.", + "already-exists": "Projeto já existe", + "must-contain": "Deve conter apenas A-Z 0-9 _ -", + "project-name": "Nome do Projeto", + "desc": "Descrição", + "opt": "Opcional" + }, + "clone-project": { + "clone": "Clonar um projeto", + "desc0": "Se você já tem um repositório git contendo um projeto, pode cloná-lo para começar.", + "already-exists": "Projeto já existe", + "must-contain": "Deve conter apenas A-Z 0-9 _ -", + "project-name": "Nome do projeto", + "no-info-in-url": "Não inclua o nome de usuário / senha no url", + "git-url": "Git repository URL", + "protocols": "https: //, ssh: // ou file://", + "auth-failed": "Autenticação falhou", + "username": "Nome de usuário", + "passwd": "Senha", + "ssh-key": "Chave SSH", + "passphrase": "Frase de Passe", + "ssh-key-desc": "Antes de clonar um repositório usando ssh, você deve adicionar uma chave SSH para acessá-lo.", + "ssh-key-add": "Adicionar uma chave ssh", + "credential-key": "Chave de criptografia de credenciais", + "cant-get-ssh-key": "Erro! Não é possível obter o caminho da chave SSH selecionada.", + "already-exists2": "já existe", + "git-error": "git error", + "connection-failed": "Conexão falhou", + "not-git-repo": "Não é um repositório git", + "repo-not-found": "Repositório não encontrado" + }, + "default-files": { + "create": "Crie seus arquivos de projeto", + "desc0": "Um projeto contém seus arquivos de fluxo, um arquivo README e um arquivo package.json.", + "desc1": "Pode conter quaisquer outros arquivos que você deseja manter no repositório Git.", + "desc2": "Seus arquivos de fluxo e credenciais existentes serão copiados para o projeto.", + "flow-file": "Arquivo de fluxo", + "credentials-file": "Arquivo de credenciais" + }, + "encryption-config": { + "setup": "Configure a criptografia do seu arquivo de credenciais", + "desc0": "Seu arquivo de credenciais de fluxo pode ser criptografado para manter seu conteúdo seguro.", + "desc1": "Se você deseja armazenar essas credenciais em um repositório Git público, deve criptografá-las fornecendo uma frase-chave secreta.", + "desc2": "Seu arquivo de credenciais de fluxo não está criptografado no momento.", + "desc3": "Isso significa que seu conteúdo, como senhas e fichas de acesso, pode ser lido por qualquer pessoa com acesso ao arquivo.", + "desc4": "Se você deseja armazenar essas credenciais em um repositório Git público, deve criptografá-las fornecendo uma frase-chave secreta.", + "desc5": "Seu arquivo de credenciais de fluxo está atualmente criptografado usando a propriedade credentialSecret de seu arquivo de configurações como a chave.", + "desc6": "Seu arquivo de credenciais de fluxo está criptografado usando uma chave gerada pelo sistema. Você deve fornecer uma nova chave secreta para este projeto.", + "desc7": "A chave será armazenada separadamente dos arquivos do seu projeto. Você precisará fornecer a chave para usar este projeto em outra instância do Node-RED.", + "credentials": "Credenciais", + "enable": "Habilitar criptografia", + "disable": "Desabilitar criptografia", + "disabled": "desabilitado", + "copy": "Copiar sobre a chave existente", + "use-custom": "Usar chave personalizada", + "desc8": "O arquivo de credenciais não será criptografado e seu conteúdo será lido facilmente", + "create-project-files": "Criar arquivos de projeto", + "create-project": "Criar projeto", + "already-exists": "já existe", + "git-error": "erro no git", + "git-auth-error": "git erro de autenticação" + }, + "create-success": { + "success": "Você criou com sucesso o seu primeiro projeto!", + "desc0": "Agora você pode continuar usando o Node-RED como sempre fez.", + "desc1": "A guia 'informações' na barra lateral mostra qual é o seu projeto ativo atual. O botão ao lado do nome pode ser usado para acessar a visualização das configurações do projeto.", + "desc2": "A guia 'histórico' na barra lateral pode ser usada para ver os arquivos que foram alterados no seu projeto e para submetê-los. Ela mostra um histórico completo de seus cometimentos e permite que você envie suas alterações para um repositório remoto . " + }, + "create": { + "projects": "Projetos", + "already-exists": "Projeto já existe", + "must-contain": "Deve conter apenas A-Z 0-9 _ -", + "no-info-in-url": "Não inclua o nome de usuário/senha no url", + "open": "Abrir projeto", + "create": "Criar Projeto", + "clone": "Clone Repositório", + "project-name": "Nome do projeto", + "desc": "Descrição", + "opt": "Opcional", + "flow-file": "Arquivo de fluxo", + "credentials": "Credenciais", + "enable-encryption": "Habilitar criptografia", + "disable-encryption": "Desabilitar criptografia", + "encryption-key": "Chave de criptografia", + "desc0": "Uma frase para proteger suas credenciais com", + "desc1": "O arquivo de credenciais não será criptografado e seu conteúdo poderá ser lido facilmente", + "git-url": "URL do repositório Git", + "protocols": "https://, ssh:// or file://", + "auth-failed": "Falha na autenticação", + "username": "Nome do usuário", + "password": "Senha", + "ssh-key": "Chave SSH", + "passphrase": "Frase de Passe", + "desc2": "Antes de clonar um repositório usando ssh, você deve adicionar uma chave SSH para acessá-lo.", + "add-ssh-key": "Adicionar uma chave ssh", + "credentials-encryption-key": "Chave de criptografia de credenciais", + "already-exists-2": "já existe", + "git-error": "erro de git", + "con-failed": "Conexão falhou", + "not-git": "Não é um repositório git", + "no-resource": "Repositório não encontrado", + "cant-get-ssh-key-path": "Erro! Não é possível obter o caminho da chave SSH selecionado.", + "unexpected_error": "erro_inesperado", + "clearContext": "Limpar contexto quando ocorrer troca de projetos" + }, + "delete": { + "confirm": "Tem certeza de que deseja excluir este projeto?" + }, + "create-project-list": { + "search": "procure seus projetos", + "current": "atual" + }, + "require-clean": { + "confirm": "

Você tem alterações não implantadas que serão perdidas.

Deseja continuar?

" + }, + "send-req": { + "auth-req": "Autenticação necessária para repositório", + "username": "Nome do usuário", + "password": "Senha", + "passphrase": "Frase de Passe", + "retry": "Tentar novamente", + "update-failed": "Falha ao atualizar autenticação", + "unhandled": "Resposta de erro não tratada", + "host-key-verify-failed": "

Falha na verificação da chave do servidor anfitrião.

A chave do servidor anfitrião do repositório não pôde ser verificada. Atualize seu arquivo known_hosts e tente novamente.

" + }, + "create-branch-list": { + "invalid": "Ramo inválido", + "create": "Criar ramo", + "current": "atual" + }, + "create-default-file-set": { + "no-active": "Não é possível criar um conjunto de arquivos padrão sem um projeto ativo", + "no-empty": "Não é possível criar um arquivo padrão definido em um projeto não vazio", + "git-error": "erro no git" + }, + "errors": { + "no-username-email": "Seu cliente Git não está configurado com um nome de usuário / e-mail.", + "unexpected": "Um erro inesperado ocorreu", + "code": "código" + } + }, + "editor-tab": { + "properties": "Propriedades", + "envProperties": "Variáveis de Ambiente", + "module": "Propriedades do Módulo", + "description": "Descrição", + "appearance": "Aparência", + "preview": "Visualização da IU", + "defaultValue": "Valor padrão" + }, + "tourGuide": { + "takeATour": "Faça um tour", + "start": "Inicio", + "next": "Próximo", + "welcomeTours": "Tour de Boas-vindas" + }, + "diagnostics": { + "title": "informações do Sistema" + }, + "languages": { + "de": "Alemão", + "en-US": "Inglês", + "ja": "Japonês", + "ko": "Coreano", + "pt-BR": "Português(Brasil)", + "ru": "Russo", + "zh-CN": "Chinês(Simplificado)", + "zh-TW": "Chinês(Tradicional)" + }, + "validator": { + "errors": { + "invalid-json": "Dados JSON inválidos: __error__", + "invalid-json-prop": "__prop__: dados JSON inválidos: __error__", + "invalid-prop": "Expressão de propriedade inválida", + "invalid-prop-prop": "__prop__: expressão de propriedade inválida", + "invalid-num": "Número inválido", + "invalid-num-prop": "__prop__: número inválido", + "invalid-regexp": "Padrão de entrada inválido", + "invalid-regex-prop": "__prop__: Padrão de entrada inválido", + "missing-required-prop": "__prop__: valor de propriedade ausente", + "invalid-config": "__prop__: nó de configuração inválido", + "missing-config": "__prop__: nó de Configuração ausente", + "validation-error": "__prop__: erro de validação: __node__, __id__: __error__" + } + }, + "contextMenu": { + "insert": "Inserir", + "node": "Nó", + "junction": "Junção", + "linkNodes": "Nós de Ligação" + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json b/packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json new file mode 100755 index 000000000..7ac7502c1 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json @@ -0,0 +1,23 @@ +{ + "info": { + "tip0": "Você pode remover os nós ou links selecionados com {{core:delete-selection}}", + "tip1": "Procure por nós usando {{core:search}}", + "tip2": "{{core:toggle-sidebar}} irá alternar a visualização desta barra lateral", + "tip3": "Você pode gerenciar sua paleta de nós com {{core:manage-palette}}", + "tip4": "Seus nós de configuração de fluxo são listados no painel da barra lateral. Pode ser acessado a partir do menu ou com{{core:show-config-tab}}", + "tip5": "Habilite ou desabilite essas dicas na opção nas configurações", + "tip6": "Mova os nós selecionados usando o [left] [up] [down] e [right] chaves. Segure [shift] para empurrá-los ainda mais", + "tip7": "Arrastar um nó para um fio o unirá no link", + "tip8": "Exporte os nós selecionados ou a guia atual com {{core:show-export-dialog}}", + "tip9": "Importe um fluxo arrastando seu JSON para o editor ou com {{core:show-import-dialog}}", + "tip10": "[shift] [click] e arraste em uma porta de nó para mover todos os fios conectados ou apenas o selecionado", + "tip11": "Mostre a guia Informações com {{core:show-info-tab}} ou a guia Depurar com {{core:show-debug-tab}}", + "tip12": "[ctrl] [click] na área de trabalho para abrir a caixa de diálogo de adição rápida", + "tip13": "Mantenha pressionado [ctrl] enquanto você [click] em uma porta de nó para habilitar a ligação rápida", + "tip14": "Mantenha pressionado [shift] enquanto você [click] em um nó para também selecionar todos os seus nós conectados", + "tip15": "Mantenha pressionado [ctrl] enquanto você [click] em um nó para adicioná-lo ou removê-lo da seleção atual", + "tip16": "Alternar guias de fluxo com {{core:show-previous-tab}} e {{core:show-next-tab}}", + "tip17": "Você pode confirmar suas alterações na bandeja de edição do nó com {{core:confirm-edit-tray}} ou cancele-os com {{core:cancel-edit-tray}}", + "tip18": "Pressionando {{core:edit-selected-node}} irá editar o primeiro nó na seleção atual" + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json new file mode 100755 index 000000000..18d0e78c1 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json @@ -0,0 +1,274 @@ +{ + "$string": { + "args": "arg[, prettify]", + "desc": "Converte o tipo do parâmetro `arg` em uma cadeia de caracteres usando as seguintes regras de conversão de tipo:\n\n - Cadeia de caracteres não são alteradas\n - As funções são convertidas para uma cadeia de caracteres vazia\n - os tipos numérico infinito e NaN geram um erro porque não podem ser representados como um número JSON\n - Todos os outros valores são convertidos para uma cadeia de caracteres JSON usando a função `JSON.stringify`. Se `prettify` for verdadeira, então o JSON \"prettified\" é produzido. Isto é, uma linha por campo e as linhas serão indentadas com base na profundidade do campo." + }, + "$length": { + "args": "str", + "desc": "Retorna o número de caracteres na cadeia de caracteres `str`. Um erro é gerado se `str` não for uma cadeia de caracteres." + }, + "$substring": { + "args": "str, start[, length]", + "desc": "Retorna uma cadeia de caracteres contendo os caracteres no primeiro parâmetro `str` começando na posição `start` (deslocamento zero). Se` length` for especificado, então a sub cadeia de caracteres conterá o máximo `length` de caracteres. Se` start` for negativo isso indica o número de caracteres a partir do fim de `str`." + }, + "$substringBefore": { + "args": "str, chars", + "desc": "Retorna a sub cadeia de caracteres antes da primeira ocorrência da sequência de caracteres `chars` em `string`. Se` string` não contiver `chars`, então retorna `str`. " + }, + "$substringAfter": { + "args": "str, chars", + "desc": "Retorna a sub cadeia de caracteres após a primeira ocorrência da sequência de caracteres `chars` em `string`. Se `string` não contiver `chars`, então retorna `str`. " + }, + "$uppercase": { + "args": "str", + "desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em maiúsculas. " + }, + "$lowercase": { + "args": "str", + "desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em minúsculas. " + }, + "$trim": { + "args": "str", + "desc": "Normaliza e retira todos os caracteres de espaço em branco em `str` aplicando as seguintes etapas:\n\n - Todas as tabulações, retornos de carro e avanços de linha são substituídos por espaços.\n- Sequências contíguas de espaços são reduzidas a um único espaço.\n- Espaços à direita e à esquerda são removidos.\n\n Se `str` não for especificado (isto é, esta função é chamada sem argumentos), então o valor do contexto é usado como o valor de `str`. Um erro é gerado se `str` não for uma cadeia de caracteres." + }, + "$contains": { + "args": "str, pattern", + "desc": "Retorna `true` se `str` tiver correspondente em `pattern`, caso contrário, retorna `false`. Se `str` não for especificado (isto é, esta função é chamada com um argumento), então o valor do contexto é usado como o valor de `str`. O parâmetro `pattern` pode ser uma cadeia de caracteres ou uma expressão regular. " + }, + "$split": { + "args": "str[, separator][, limit]", + "desc": "Divide o parâmetro `str` em uma matriz de sub cadeia de caracteres. É um erro se `str` não for uma cadeia de caracteres. O parâmetro opcional `separator` especifica os caracteres dentro de `str` sobre os quais devem ser divididos como uma cadeia de caracteres ou expressão regular. Se `separator` não for especificado, a cadeia de caracteres vazia será assumida e `str` será dividido em uma matriz de caracteres únicos. É um erro se `separador` não for uma cadeia de caracteres. O parâmetro opcional `limit` é um número que especifica o número máximo de sub cadeia de caracteres a serem incluídas na matriz resultante. Quaisquer sub cadeia de caracteres adicionais são descartadas. Se `limit` não for especificado, então `str` será totalmente dividido sem limite para o tamanho da matriz resultante . É um erro se `limit` não for um número não negativo." + }, + "$join": { + "args": "array[, separator]", + "desc": "Une uma matriz de cadeias de caracteres de componentes em uma única cadeia de caracteres concatenada com cada cadeia de caracteres de componente separada pelo parâmetro opcional `separator`. É um erro se a `matriz` de entrada contiver um item que não seja uma cadeia de caracteres. Se `separator` for não especificado, assume-se que é uma cadeia de caracteres vazia, ou seja, nenhum `separator` entre as cadeias de caracteres do componente. É um erro se `separator` não for uma cadeia de caracteres. " + }, + "$match": { + "args": "str, pattern [, limit]", + "desc": "Aplica a cadeia de caracteres `str` à expressão regular `pattern` e retorna uma matriz de objetos, com cada objeto contendo informações sobre cada ocorrência de uma correspondência dentro de `str`. " + }, + "$replace": { + "args": "str, pattern, replacement [, limit]", + "desc": "Encontra ocorrências de `pattern` dentro de `str` e as substitui por `replacement`.\n\nO parâmetro opcional `limit` é o número máximo de substituições." + }, + "$now": { + "args":"$[picture [, timezone]]", + "desc":"Gera um carimbo de data/hora em formato compatível com ISO 8601 e o retorna como uma cadeia de caracteres. Se os parâmetros opcionais de imagem e fuso horário forem fornecidos, o carimbo de data/hora atual é formatado conforme descrito pela função `$ fromMillis ()`" + }, + "$base64encode": { + "args":"string", + "desc":"Converte uma cadeia de caracteres ASCII em uma representação de base 64. Cada caractere na cadeia de caracteres é tratado como um byte de dados binários. Isso requer que todos os caracteres na cadeia de caracteres estejam no intervalo de 0x00 a 0xFF, o que inclui todos os caracteres em cadeias de caracteres codificadas em URI. Caracteres Unicode fora desse intervalo não são suportados." + }, + "$base64decode": { + "args":"string", + "desc":"Converte bytes codificados de base 64 em uma cadeia de caracteres, usando uma página de código UTF-8 Unicode." + }, + "$number": { + "args": "arg", + "desc": "Converte o parâmetro `arg` em um número usando as seguintes regras de conversão:\n\n - Os números permanecem inalterados\n - Cadeias de caracteres que contêm uma sequência de caracteres que representam um número JSON válido são convertidos para esse número\n - Todos os outros valores causam a geração de um erro." + }, + "$abs": { + "args":"number", + "desc":"Retorna o valor absoluto do parâmetro `number`." + }, + "$floor": { + "args":"number", + "desc":"Retorna o valor de `number` arredondado para baixo para o inteiro mais próximo que seja menor ou igual a `number`." + }, + "$ceil": { + "args":"number", + "desc":"Retorna o valor de `number` arredondado para o número inteiro mais próximo que é maior ou igual a `number`." + }, + "$round": { + "args":"number [, precision]", + "desc":"Retorna o valor do parâmetro `number` arredondado para o número de casas decimais especificado pelo parâmetro opcional `precision`." + }, + "$power": { + "args":"base, exponent", + "desc":"Retorna o valor de `base` elevado à potência de `exponent`." + }, + "$sqrt": { + "args":"number", + "desc":"Retorna a raiz quadrada do valor do parâmetro `number`." + }, + "$random": { + "args":"", + "desc":"Retorna um número pseudoaleatório maior ou igual a zero e menor que um." + }, + "$millis": { + "args":"", + "desc":"Retorna o número de milissegundos desde o Unix Epoch (1º de janeiro de 1970 UTC) como um número. Todas as invocações de `$ millis ()` dentro de uma avaliação de uma expressão retornarão todas o mesmo valor." + }, + "$sum": { + "args": "array", + "desc": "Retorna a soma aritmética de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$max": { + "args": "array", + "desc": "Retorna o número máximo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$min": { + "args": "array", + "desc": "Retorna o número mínimo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$average": { + "args": "array", + "desc": "Retorna o valor médio de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$boolean": { + "args": "arg", + "desc": "Converte o argumento em um booliano usando as seguintes regras:\n\n - `Boolean` : inalterado\n - `string`: vazio : `false`\n - `string`: não-vazio : `true`\n - `number`: `0` : `false`\n - `number`: não-zero : `true`\n - `null` : `false`\n - `array`: vazio : `false`\n - `array`: contém um membro que converte de tipo para `true` : `true`\n - `array`: todos os membros convertidos de tipo para `false` : `false`\n - `object`: vazio : `false`\n - `object`: não-vazio : `true`\n - `function` : `false`" + }, + "$not": { + "args": "arg", + "desc": "Retorna booliano NOT no argumento. `Arg` é convertido de tipo primeiro para um booliano " + }, + "$exists": { + "args": "arg", + "desc": "Retorna booliano `true` se a expressão `arg` for avaliada como um valor, ou `false` se a expressão não corresponder a nada (por exemplo, um caminho para uma referência de campo inexistente)." + }, + "$count": { + "args": "array", + "desc": "Retorna o número de itens na matriz" + }, + "$append": { + "args": "array, array", + "desc": "Anexa duas matrizes" + }, + "$sort": { + "args":"array [, function]", + "desc":"Retorna uma matriz contendo todos os valores no parâmetro `array`, mas classificados em ordem.\n\nSe um comparador `function` for fornecido, então deve ser uma função que leva dois parâmetros:\n\n`function(left, right)`\n\nEsta função é invocada pelo algoritmo de classificação para comparar dois valores à esquerda e à direita. Se o valor de esquerda deve ser colocado após o valor de direita na ordem de classificação desejada, a função deve retornar o booliano `true` para indicar uma troca. Caso contrário, deve retornar `false`." + }, + "$reverse": { + "args":"array", + "desc":"Retorna uma matriz contendo todos os valores do parâmetro `array`, mas na ordem reversa. " + }, + "$shuffle": { + "args":"array", + "desc":"Retorna uma matriz contendo todos os valores do parâmetro `array`, mas misturados em ordem aleatória. " + }, + "$zip": { + "args":"array, ...", + "desc":"Retorna uma matriz convolucional (compactada) contendo matrizes agrupadas de valores dos argumentos `array1`… `arrayN` do índice 0, 1, 2 ...." + }, + "$keys": { + "args": "object", + "desc": "Retorna uma matriz contendo as chaves do objeto. Se o argumento for uma matriz de objetos, então a matriz retornada contém uma lista não duplicada de todas as chaves em todos os objetos." + }, + "$lookup": { + "args": "object, key", + "desc": "Retorna o valor associado à chave no objeto. Se o primeiro argumento for uma matriz de objetos, todos os objetos na matriz são pesquisados e os valores associados a todas as ocorrências da chave são retornados." + }, + "$spread": { + "args": "object", + "desc": "Divide um objeto que contém pares de chave/valor em uma matriz de objetos, cada um com um único par de chave/valor do objeto de entrada. Se o parâmetro for uma matriz de objetos, a matriz resultante conterá um objeto para cada par de chave/valor em todo objeto na matriz fornecida. " + }, + "$merge": { + "args": "array<object>", + "desc": "Mescla uma matriz de `objects` em um único `object` contendo todos os pares de chave/valor de cada um dos objetos na matriz de entrada. Se qualquer um dos objetos de entrada contiver a mesma chave, então o `object` retornado conterá o valor do último na matriz. É um erro se a matriz de entrada contiver um item que não seja um objeto." + }, + "$sift": { + "args":"object, function", + "desc": "Retorna um objeto que contém apenas os pares de chave/valor do parâmetro `object` que satisfazem o predicado `function` passado como o segundo parâmetro.\n\nA `function` que é fornecida como o segundo parâmetro deve ter o seguinte assinatura:\n\n`function(value [, key [, object]])`" + }, + "$each": { + "args":"object, function", + "desc":"Retorna uma matriz contendo os valores retornados por `function` quando aplicado a cada par chave/valor no `object`." + }, + "$map": { + "args":"array, function", + "desc":"Retorna uma matriz contendo os resultados da aplicação do parâmetro `function` a cada valor no parâmetro `array`.\n\nA `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`" + }, + "$filter": { + "args":"array, function", + "desc":"Retorna uma matriz contendo apenas os valores no parâmetro `array` que satisfazem o predicado `function`.\n\nThe `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`" + }, + "$reduce": { + "args":"array, function [, init]", + "desc":"Retorna um valor agregado derivado da aplicação do parâmetro `function` sucessivamente a cada valor em `array` em combinação com o resultado da aplicação anterior da função.\n\nA função deve aceitar dois argumentos e se comportar como um operador inserido entre cada valor dentro de `array`. A assinatura da `function` deve estar no formato: `myfunc($accumulator, $value[, $index[, $array]])`\n\nO parâmetro opcional `init` é usado como o valor inicial na agregação." + }, + "$flowContext": { + "args": "string[, string]", + "desc": "Recupera uma propriedade de contexto de fluxo.\n\nEsta é uma função definida pelo Node-RED. " + }, + "$globalContext": { + "args": "string[, string]", + "desc": "Recupera uma propriedade de contexto global.\n\nEsta é uma função definida pelo Node-RED. " + }, + "$pad": { + "args": "string, width [, char]", + "desc": "Retorna uma cópia da `string` com preenchimento extra, se necessário, de forma que seu número total de caracteres seja pelo menos o valor absoluto do parâmetro `width`.\n\nSe `width` for um número positivo, a cadeia de caracteres será preenchida à direita; se negativo, é preenchida à esquerda.\n\nO argumento opcional `char` especifica os caracteres de preenchimento a serem usados. Se não for especificado, o padrão é o caractere de espaço. " + }, + "$fromMillis": { + "args": "number, [, picture [, timezone]]", + "desc": "Converta o `number` que representa os milissegundos desde a época do Unix (1 January, 1970 UTC) em uma representação de cadeia de caracteres formatada do carimbo de data/hora conforme especificado pela cadeia de caracteres de imagem.\n\nSe o parâmetro opcional `image` for omitido, o carimbo de data/hora será formatado no formato ISO 8601.\n\nSe a cadeia de caracteresopcional `picture` for fornecida, o carimbo de data/hora é formatado de acordo com a representação especificada nessa cadeia de caracteres. O comportamento desta função é consistente com a versão de dois argumentos da função XPath/XQuery `format-dateTime` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o carimbo de data/hora é formatado e tem a mesma sintaxe de `format-dateTime`.\n\nSe a cadeia de caracteres opcional `timezone` for fornecida, o carimbo de data/hora formatado estará nesse fuso horário. A cadeia de caracteres `timezone` deve estar no formato '± HHMM', onde ± é o sinal de mais ou menos e HHMM é o deslocamento em horas e minutos do UTC. Deslocamento positivo para fusos horários a leste do UTC, deslocamento negativo para fusos horários a oeste do UTC. " + }, + "$formatNumber": { + "args": "number, picture [, options]", + "desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação decimal conforme especificado pela cadeia de caracteres `picture`.\n\n O comportamento desta função é consistente com a função XPath/XQuery fn: format-number conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de fn: format-number.\n\nO terceiro argumento opcional `options` é usado para substituir os caracteres de formatação específicos da localidade padrão, como o separador decimal. Se fornecido, este argumento deve ser um objeto contendo pares de nome/valor especificados na seção de formato decimal da especificação XPath F&O 3.1." + }, + "$formatBase": { + "args": "number [, radix]", + "desc": "Converte o `number` em uma cadeia de caracteres e o formata em um inteiro representado na base do número especificada pelo argumento `radix`. Se `radix` não for especificado, o padrão é a base 10. `radix` pode estar entre 2 e 36, caso contrário, um erro será gerado. " + }, + "$toMillis": { + "args": "timestamp", + "desc": "Converta o tipo de uma cadeia de caracteres `timestamp` no formato ISO 8601 para o número de milissegundos desde a época do Unix (1 January, 1970 UTC) como um número. Um erro é gerado se a cadeia de caracteres não estiver no formato correto. " + }, + "$env": { + "args": "arg", + "desc": "Retorna o valor de uma variável de ambiente.\n\nEsta é uma função definida pelo Node-RED." + }, + "$eval": { + "args": "expr [, context]", + "desc": "Analisa e avalia a cadeia de caracteres `expr` que contém um JSON literal ou uma expressão JSONata usando o contexto atual como o contexto para avaliação. " + }, + "$formatInteger": { + "args": "number, picture", + "desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação inteira conforme especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn: format-integer` do Especificação XPath F&O 3.1. " + }, + "$parseInteger": { + "args": "string, picture", + "desc": "Examina e troca o conteúdo do parâmetro `string` para um inteiro (como um número JSON) usando o formato especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres `picture` tem o mesmo formato que `$ formatInteger`." + }, + "$error": { + "args": "[str]", + "desc": "Gera um erro com uma mensagem. O (parâmetro) opcional `str` substituirá a mensagem padrão de `$error() function evaluated`" + }, + "$assert": { + "args": "arg, str", + "desc": "Se `arg` for verdadeiro, a função retorna indefinido. Se `arg` for falso, uma exceção é gerada com `str` como a mensagem da exceção. " + }, + "$single": { + "args": "array, function", + "desc": "Retorna o único valor no parâmetro `array` que satisfaz o predicado `function` (isto é, O (parâmetro) `function` retorna o booliano `true` quando passado o valor). Gera uma exceção se o número de valores correspondentes não for exatamente um .\n\nA função deve ser fornecida na seguinte assinatura: `function(value [, index [, array]])` onde 'value' é cada entrada da matriz, 'index' é a posição desse valor e toda a matriz é passada como o terceiro argumento" + }, + "$encodeUrlComponent": { + "args": "str", + "desc": "Codifica um componente Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere.\n\nExemplo: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" + }, + "$encodeUrl": { + "args": "str", + "desc": "Codifica um Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere. \n\nExemplo: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" + }, + "$decodeUrlComponent": { + "args": "str", + "desc": "Decodifica um componente Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrlComponent. \n\nExemplo: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" + }, + "$decodeUrl": { + "args": "str", + "desc": "Decodifica um Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrl. \n\nExemplo: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" + }, + "$distinct": { + "args": "array", + "desc": "Retorna uma matriz com valores duplicados removidos da `array` " + }, + "$type": { + "args": "value", + "desc": "Retorna o tipo de `value` como uma cadeia de caracteres. Se `value` for indefinido, retornará `undefined` " + }, + "$moment": { + "args": "[str]", + "desc": "Obtém um objeto de dados usando a biblioteca 'Moment'." + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/ru/editor.json b/packages/node_modules/@node-red/editor-client/locales/ru/editor.json old mode 100755 new mode 100644 index d669b3f09..8cfea1bde --- a/packages/node_modules/@node-red/editor-client/locales/ru/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ru/editor.json @@ -1133,8 +1133,10 @@ "languages" : { "de": "Немецкий", "en-US": "Английский", + "fr": "Французский", "ja": "Японский", "ko": "Корейский", + "pt-BR":"португальский", "ru": "Русский", "zh-CN": "Китайский (упрощенный)", "zh-TW": "Китайский (традиционный)" diff --git a/packages/node_modules/@node-red/editor-client/locales/ru/infotips.json b/packages/node_modules/@node-red/editor-client/locales/ru/infotips.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/ru/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/ru/jsonata.json old mode 100755 new mode 100644 diff --git a/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json index 0565d75ba..e55240cc5 100644 --- a/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json @@ -1147,6 +1147,17 @@ "create": "创建分支", "current": "当前的" }, + "languages": { + "de": "德语", + "en-US": "英文", + "fr": "法语", + "ja": "日语", + "ko": "韩文", + "pt-BR":"葡萄牙语", + "ru":"俄語", + "zh-CN": "简体中文", + "zh-TW": "繁体中文" + }, "create-default-file-set": { "no-active": "没有活动项目就无法创建默认文件集", "no-empty": "无法在非空项目上创建默认文件集", diff --git a/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json b/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json index 42316176f..3646f0c9e 100644 --- a/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json @@ -1088,8 +1088,11 @@ "languages": { "de": "德語", "en-US": "英語", + "fr": "法語", "ja": "日語", "ko": "韓語", + "pt-BR":"葡萄牙语", + "ru":"俄語", "zh-CN": "簡體中文", "zh-TW": "繁體中文" } diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json index 0ef939fb3..2fcd5950b 100644 --- a/packages/node_modules/@node-red/editor-client/package.json +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-client", - "version": "3.0.2", + "version": "3.1.0-beta.1", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/editor-client/src/js/history.js b/packages/node_modules/@node-red/editor-client/src/js/history.js index b23071239..c3a966890 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/history.js +++ b/packages/node_modules/@node-red/editor-client/src/js/history.js @@ -14,7 +14,7 @@ * limitations under the License. **/ -/** +/** * An API for undo / redo history buffer * @namespace RED.history */ @@ -378,7 +378,8 @@ RED.history = (function() { if (ev.addToGroup) { RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false); inverseEv.removeFromGroup = ev.addToGroup; - } else if (ev.removeFromGroup) { + } + if (ev.removeFromGroup) { RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n })); inverseEv.addToGroup = ev.removeFromGroup; } @@ -421,6 +422,9 @@ RED.history = (function() { ev.node[i] = ev.changes[i]; } } + ev.node.dirty = true; + ev.node.changed = ev.changed; + var eventType; switch(ev.node.type) { case 'tab': eventType = "flows"; break; @@ -434,7 +438,9 @@ RED.history = (function() { if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) { $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled); - $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled); + } + if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('locked')) { + $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!ev.node.locked); } if (ev.subflow) { inverseEv.subflow = {}; @@ -509,8 +515,6 @@ RED.history = (function() { inverseEv.links.push(ev.createdLinks[i]); } } - ev.node.dirty = true; - ev.node.changed = ev.changed; } else if (ev.t == "createSubflow") { inverseEv = { t: "deleteSubflow", @@ -646,6 +650,12 @@ RED.history = (function() { ev.groups[i].nodes = []; RED.nodes.addGroup(ev.groups[i]); RED.group.addToGroup(ev.groups[i],nodes); + if (ev.groups[i].g) { + const parentGroup = RED.nodes.group(ev.groups[i].g) + if (parentGroup) { + RED.group.addToGroup(parentGroup, ev.groups[i]) + } + } } } } else if (ev.t == "addToGroup") { diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index d387f01b3..08333777e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -19,7 +19,6 @@ * @namespace RED.nodes */ RED.nodes = (function() { - var PORT_TYPE_INPUT = 1; var PORT_TYPE_OUTPUT = 0; @@ -47,6 +46,9 @@ RED.nodes = (function() { function setDirty(d) { dirty = d; + if (!d) { + allNodes.clearState() + } RED.events.emit("workspace:dirty",{dirty:dirty}); } @@ -63,12 +65,12 @@ RED.nodes = (function() { defaults: { label: {value:""}, disabled: {value: false}, + locked: {value: false}, info: {value: ""}, env: {value: []} } }; - var exports = { setModulePendingUpdated: function(module,version) { moduleList[module].pending_version = version; @@ -238,22 +240,72 @@ RED.nodes = (function() { // allNodes holds information about the Flow nodes. var allNodes = (function() { + // Map node.id -> node var nodes = {}; + // Map tab.id -> Array of nodes on that tab var tabMap = {}; + // Map tab.id -> Set of dirty object ids on that tab + var tabDirtyMap = {}; + // Map tab.id -> Set of object ids of things deleted from the tab that weren't otherwise dirty + var tabDeletedNodesMap = {}; + // Set of object ids of things added to a tab after initial import + var addedDirtyObjects = new Set() + + function changeCollectionDepth(tabNodes, toMove, direction, singleStep) { + const result = [] + const moved = new Set(); + const startIndex = direction ? tabNodes.length - 1 : 0 + const endIndex = direction ? -1 : tabNodes.length + const step = direction ? -1 : 1 + let target = startIndex // Only used for all-the-way moves + for (let i = startIndex; i != endIndex; i += step) { + if (toMove.size === 0) { + break; + } + const n = tabNodes[i] + if (toMove.has(n)) { + if (singleStep) { + if (i !== startIndex && !moved.has(tabNodes[i - step])) { + tabNodes.splice(i, 1) + tabNodes.splice(i - step, 0, n) + n._reordered = true + result.push(n) + } + } else { + if (i !== target) { + tabNodes.splice(i, 1) + tabNodes.splice(target, 0, n) + n._reordered = true + result.push(n) + } + target += step + } + toMove.delete(n); + moved.add(n); + } + } + return result + } + var api = { addTab: function(id) { tabMap[id] = []; + tabDirtyMap[id] = new Set(); + tabDeletedNodesMap[id] = new Set(); }, hasTab: function(z) { return tabMap.hasOwnProperty(z) }, removeTab: function(id) { delete tabMap[id]; + delete tabDirtyMap[id]; + delete tabDeletedNodesMap[id]; }, addNode: function(n) { nodes[n.id] = n; if (tabMap.hasOwnProperty(n.z)) { tabMap[n.z].push(n); + api.addObjectToWorkspace(n.z, n.id, n.changed || n.moved) } else { console.warn("Node added to unknown tab/subflow:",n); tabMap["_"] = tabMap["_"] || []; @@ -267,8 +319,37 @@ RED.nodes = (function() { if (i > -1) { tabMap[n.z].splice(i,1); } + api.removeObjectFromWorkspace(n.z, n.id) } }, + /** + * Add an object to our dirty/clean tracking state + * @param {String} z + * @param {String} id + * @param {Boolean} isDirty + */ + addObjectToWorkspace: function (z, id, isDirty) { + if (isDirty) { + addedDirtyObjects.add(id) + } + if (tabDeletedNodesMap[z].has(id)) { + tabDeletedNodesMap[z].delete(id) + } + api.markNodeDirty(z, id, isDirty) + }, + /** + * Remove an object from our dirty/clean tracking state + * @param {String} z + * @param {String} id + */ + removeObjectFromWorkspace: function (z, id) { + if (!addedDirtyObjects.has(id)) { + tabDeletedNodesMap[z].add(id) + } else { + addedDirtyObjects.delete(id) + } + api.markNodeDirty(z, id, false) + }, hasNode: function(id) { return nodes.hasOwnProperty(id); }, @@ -280,152 +361,54 @@ RED.nodes = (function() { n.z = newZ; api.addNode(n) }, - moveNodesForwards: function(nodes) { - var result = []; + /** + * @param {array} nodes + * @param {boolean} direction true:forwards false:back + * @param {boolean} singleStep true:single-step false:all-the-way + */ + changeDepth: function(nodes, direction, singleStep) { if (!Array.isArray(nodes)) { nodes = [nodes] } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var moved = new Set(); - for (var i = tabNodes.length-1; i >= 0; i--) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i < tabNodes.length-1 && !moved.has(tabNodes[i+1])) { - // Remove from current position - tabNodes.splice(i,1); - // Add it back one position higher - tabNodes.splice(i+1,0,n); - n._reordered = true; - result.push(n); - } - toMove.delete(n); - moved.add(n); + let result = [] + const tabNodes = tabMap[nodes[0].z]; + const toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); + if (toMove.size > 0) { + result = result.concat(changeCollectionDepth(tabNodes, toMove, direction, singleStep)) + if (result.length > 0) { + RED.events.emit('nodes:reorder',{ + z: nodes[0].z, + nodes: result + }); } } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); + + const groupNodes = groupsByZ[nodes[0].z] || [] + const groupsToMove = new Set(nodes.filter(function(n) { return n.type === 'group'})) + if (groupsToMove.size > 0) { + const groupResult = changeCollectionDepth(groupNodes, groupsToMove, direction, singleStep) + if (groupResult.length > 0) { + result = result.concat(groupResult) + RED.events.emit('groups:reorder',{ + z: nodes[0].z, + nodes: groupResult + }); + } } - return result; + RED.view.redraw(true) + return result + }, + moveNodesForwards: function(nodes) { + return api.changeDepth(nodes, true, true) }, moveNodesBackwards: function(nodes) { - var result = []; - if (!Array.isArray(nodes)) { - nodes = [nodes] - } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var moved = new Set(); - for (var i = 0; i < tabNodes.length; i++) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i > 0 && !moved.has(tabNodes[i-1])) { - // Remove from current position - tabNodes.splice(i,1); - // Add it back one position lower - tabNodes.splice(i-1,0,n); - n._reordered = true; - result.push(n); - } - toMove.delete(n); - moved.add(n); - } - } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); - } - return result; + return api.changeDepth(nodes, false, true) }, moveNodesToFront: function(nodes) { - var result = []; - if (!Array.isArray(nodes)) { - nodes = [nodes] - } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var target = tabNodes.length-1; - for (var i = tabNodes.length-1; i >= 0; i--) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i < target) { - // Remove from current position - tabNodes.splice(i,1); - tabNodes.splice(target,0,n); - n._reordered = true; - result.push(n); - } - target--; - toMove.delete(n); - } - } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); - } - return result; + return api.changeDepth(nodes, true, false) }, moveNodesToBack: function(nodes) { - var result = []; - if (!Array.isArray(nodes)) { - nodes = [nodes] - } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var target = 0; - for (var i = 0; i < tabNodes.length; i++) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i > target) { - // Remove from current position - tabNodes.splice(i,1); - // Add it back one position lower - tabNodes.splice(target,0,n); - n._reordered = true; - result.push(n); - } - target++; - toMove.delete(n); - } - } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); - } - return result; + return api.changeDepth(nodes, false, false) }, getNodes: function(z) { return tabMap[z]; @@ -433,6 +416,33 @@ RED.nodes = (function() { clear: function() { nodes = {}; tabMap = {}; + tabDirtyMap = {}; + tabDeletedNodesMap = {}; + addedDirtyObjects = new Set(); + }, + /** + * Clear all internal state on what is dirty. + */ + clearState: function () { + // Called when a deploy happens, we can forget about added/remove + // items as they have now been deployed. + addedDirtyObjects = new Set() + const flowsToCheck = new Set() + for (const [z, set] of Object.entries(tabDeletedNodesMap)) { + if (set.size > 0) { + set.clear() + flowsToCheck.add(z) + } + } + for (const [z, set] of Object.entries(tabDirtyMap)) { + if (set.size > 0) { + set.clear() + flowsToCheck.add(z) + } + } + for (const z of flowsToCheck) { + api.checkTabState(z) + } }, eachNode: function(cb) { var nodeList,i,j; @@ -498,7 +508,7 @@ RED.nodes = (function() { return result; }, getNodeOrder: function(z) { - return tabMap[z].map(function(n) { return n.id }) + return (groupsByZ[z] || []).concat(tabMap[z]).map(n => n.id) }, setNodeOrder: function(z, order) { var orderMap = {}; @@ -510,6 +520,41 @@ RED.nodes = (function() { B._reordered = true; return orderMap[A.id] - orderMap[B.id]; }) + if (groupsByZ[z]) { + groupsByZ[z].sort(function(A,B) { + return orderMap[A.id] - orderMap[B.id]; + }) + } + }, + /** + * Update our records if an object is dirty or not + * @param {String} z tab id + * @param {String} id object id + * @param {Boolean} dirty whether the object is dirty or not + */ + markNodeDirty: function(z, id, dirty) { + if (tabDirtyMap[z]) { + if (dirty) { + tabDirtyMap[z].add(id) + } else { + tabDirtyMap[z].delete(id) + } + api.checkTabState(z) + } + }, + /** + * Check if a tab should update its contentsChange flag + * @param {String} z tab id + */ + checkTabState: function (z) { + const ws = workspaces[z] + if (ws) { + const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0 + if (Boolean(ws.contentsChanged) !== contentsChanged) { + ws.contentsChanged = contentsChanged + RED.events.emit("flows:change", ws); + } + } } } return api; @@ -575,15 +620,53 @@ RED.nodes = (function() { } } + const nodeProxyHandler = { + get(node, prop) { + if (prop === '__isProxy__') { + return true + } else if (prop == '__node__') { + return node + } + return node[prop] + }, + set(node, prop, value) { + if (node.z && (RED.nodes.workspace(node.z)?.locked || RED.nodes.subflow(node.z)?.locked)) { + if ( + node._def.defaults[prop] || + prop === 'z' || + prop === 'l' || + prop === 'd' || + (prop === 'changed' && (!!node.changed) !== (!!value)) || // jshint ignore:line + ((prop === 'x' || prop === 'y') && !node.resize && node.type !== 'group') + ) { + throw new Error(`Cannot modified property '${prop}' of locked object '${node.type}:${node.id}'`) + } + } + if (node.z && (prop === 'changed' || prop === 'moved')) { + setTimeout(() => { + allNodes.markNodeDirty(node.z, node.id, node.changed || node.moved) + }, 0) + } + node[prop] = value; + return true + } + } function addNode(n) { + let newNode + if (!n.__isProxy__) { + newNode = new Proxy(n, nodeProxyHandler) + } else { + newNode = n + } + if (n.type.indexOf("subflow") !== 0) { n["_"] = n._def._; } else { var subflowId = n.type.substring(8); var sf = RED.nodes.subflow(subflowId); if (sf) { - sf.instances.push(sf); + sf.instances.push(newNode); } n["_"] = RED._; } @@ -600,12 +683,13 @@ RED.nodes = (function() { }); n.i = nextId+1; } - allNodes.addNode(n); + allNodes.addNode(newNode); if (!nodeLinks[n.id]) { nodeLinks[n.id] = {in:[],out:[]}; } } - RED.events.emit('nodes:add',n); + RED.events.emit('nodes:add',newNode); + return newNode } function addLink(l) { if (nodeLinks[l.source.id]) { @@ -632,10 +716,16 @@ RED.nodes = (function() { } if (l.source.z === l.target.z && linkTabMap[l.source.z]) { linkTabMap[l.source.z].push(l); + allNodes.addObjectToWorkspace(l.source.z, getLinkId(l), true) } RED.events.emit("links:add",l); } + function getLinkId(link) { + return link.source.id + ':' + link.sourcePort + ':' + link.target.id + } + + function getNode(id) { if (id in configNodes) { return configNodes[id]; @@ -830,6 +920,7 @@ RED.nodes = (function() { if (index !== -1) { linkTabMap[l.source.z].splice(index,1) } + allNodes.removeObjectFromWorkspace(l.source.z, getLinkId(l)) } } RED.events.emit("links:remove",l); @@ -999,6 +1090,11 @@ RED.nodes = (function() { return false; } + function getDownstreamNodes(node) { + const downstreamLinks = nodeLinks[node.id].out + const downstreamNodes = new Set(downstreamLinks.map(l => l.target)) + return Array.from(downstreamNodes) + } function getAllDownstreamNodes(node) { return getAllFlowNodes(node,'down').filter(function(n) { return n !== node }); } @@ -1046,6 +1142,9 @@ RED.nodes = (function() { node.type = n.type; for (var d in n._def.defaults) { if (n._def.defaults.hasOwnProperty(d)) { + if (d === 'locked' && !n.locked) { + continue + } node[d] = n[d]; } } @@ -1651,6 +1750,7 @@ RED.nodes = (function() { * Options: * - generateIds - whether to replace all node ids * - addFlow - whether to import nodes to a new tab + * - markChanged - whether to set changed=true on all newly imported objects * - reimport - if node has a .z property, dont overwrite it * Only applicible when `generateIds` is false * - importMap - how to resolve any conflicts. @@ -1659,7 +1759,7 @@ RED.nodes = (function() { * - id:replace - import over the top of existing */ function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) { - const defOpts = { generateIds: false, addFlow: false, reimport: false, importMap: {} } + const defOpts = { generateIds: false, addFlow: false, markChanged: false, reimport: false, importMap: {} } options = Object.assign({}, defOpts, options) options.importMap = options.importMap || {} const createNewIds = options.generateIds; @@ -1685,7 +1785,7 @@ RED.nodes = (function() { newNodes = newNodesObj; } - if (!$.isArray(newNodes)) { + if (!Array.isArray(newNodes)) { newNodes = [newNodes]; } @@ -1965,7 +2065,7 @@ RED.nodes = (function() { } } } else { - const keepNodesCurrentZ = reimport && n.z && RED.workspaces.contains(n.z) + const keepNodesCurrentZ = reimport && n.z && (RED.workspaces.contains(n.z) || RED.nodes.subflow(n.z)) if (!keepNodesCurrentZ && n.z && !workspace_map[n.z] && !subflow_map[n.z]) { n.z = activeWorkspace; } @@ -1983,6 +2083,9 @@ RED.nodes = (function() { if (!n.z) { delete configNode.z; } + if (options.markChanged) { + configNode.changed = true + } if (n.hasOwnProperty('d')) { configNode.d = n.d; } @@ -2045,6 +2148,9 @@ RED.nodes = (function() { if (n.hasOwnProperty('g')) { node.g = n.g; } + if (options.markChanged) { + node.changed = true + } if (createNewIds || options.importMap[n.id] === "copy") { if (subflow_denylist[n.z]) { continue; @@ -2067,7 +2173,7 @@ RED.nodes = (function() { node.id = getID(); } else { node.id = n.id; - const keepNodesCurrentZ = reimport && node.z && RED.workspaces.contains(node.z) + const keepNodesCurrentZ = reimport && node.z && (RED.workspaces.contains(node.z) || RED.nodes.subflow(node.z)) if (!keepNodesCurrentZ && (node.z == null || (!workspace_map[node.z] && !subflow_map[node.z]))) { if (createMissingWorkspace) { if (missingWorkspace === null) { @@ -2265,7 +2371,7 @@ RED.nodes = (function() { // get added if (activeSubflow && /^link /.test(n.type) && n.links) { n.links = n.links.filter(function(id) { - var otherNode = RED.nodes.node(id); + const otherNode = node_map[id] || RED.nodes.node(id); return (otherNode && otherNode.z === activeWorkspace) }); } @@ -2315,19 +2421,6 @@ RED.nodes = (function() { if (n.g && !new_group_set.has(n.g)) { delete n.g; } - n.nodes = n.nodes.map(function(id) { - return node_map[id]; - }) - // Just in case the group references a node that doesn't exist for some reason - n.nodes = n.nodes.filter(function(v) { - if (v) { - // Repair any nodes that have forgotten they are in this group - if (v.g !== n.id) { - v.g = n.id; - } - } - return !!v - }); if (!n.g) { groupDepthMap[n.id] = 0; } @@ -2350,21 +2443,22 @@ RED.nodes = (function() { return groupDepthMap[A.id] - groupDepthMap[B.id]; }); for (i=0;i { + const mappedNode = node_map[id] + if (!mappedNode) { + return null + } + if (mappedNode.__isProxy__) { + return mappedNode + } else { + return node_map[mappedNode.id] + } + } + // Update groups to reference proxy node objects + for (i=0;i g.id) + } function addJunction(junction) { + if (!junction.__isProxy__) { + junction = new Proxy(junction, nodeProxyHandler) + } junctionsByZ[junction.z] = junctionsByZ[junction.z] || [] junctionsByZ[junction.z].push(junction) junctions[junction.id] = junction; if (!nodeLinks[junction.id]) { nodeLinks[junction.id] = {in:[],out:[]}; } + allNodes.addObjectToWorkspace(junction.z, junction.id, junction.changed || junction.moved) RED.events.emit("junctions:add", junction) + return junction } function removeJunction(junction) { var i = junctionsByZ[junction.z].indexOf(junction) @@ -2565,6 +2712,7 @@ RED.nodes = (function() { } delete junctions[junction.id] delete nodeLinks[junction.id]; + allNodes.removeObjectFromWorkspace(junction.z, junction.id) RED.events.emit("junctions:remove", junction) var removedLinks = links.filter(function(l) { return (l.source === junction) || (l.target === junction); }); @@ -2740,6 +2888,7 @@ RED.nodes = (function() { } }); + const nodeGroupMap = {} var replaceNodeIds = Object.keys(replaceNodes); if (replaceNodeIds.length > 0) { var reimportList = []; @@ -2750,6 +2899,12 @@ RED.nodes = (function() { } else { allNodes.removeNode(n); } + if (n.g) { + // reimporting a node *without* including its group object + // will cause the g property to be cleared. Cache it + // here so we can restore it + nodeGroupMap[n.id] = n.g + } reimportList.push(convertNode(n)); RED.events.emit('nodes:remove',n); }); @@ -2771,6 +2926,18 @@ RED.nodes = (function() { var newNodeMap = {}; result.nodes.forEach(function(n) { newNodeMap[n.id] = n; + if (nodeGroupMap[n.id]) { + // This node is in a group - need to substitute the + // node reference inside the group + n.g = nodeGroupMap[n.id] + const group = RED.nodes.group(n.g) + if (group) { + var index = group.nodes.findIndex(gn => gn.id === n.id) + if (index > -1) { + group.nodes[index] = n + } + } + } }); RED.nodes.eachLink(function(l) { if (newNodeMap.hasOwnProperty(l.source.id)) { @@ -2783,6 +2950,9 @@ RED.nodes = (function() { RED.view.redraw(true); } }); + RED.events.on('deploy', function () { + allNodes.clearState() + }) }, registry:registry, setNodeList: registry.setNodeList, @@ -2831,7 +3001,7 @@ RED.nodes = (function() { }, addWorkspace: addWorkspace, removeWorkspace: removeWorkspace, - getWorkspaceOrder: function() { return workspacesOrder }, + getWorkspaceOrder: function() { return [...workspacesOrder] }, setWorkspaceOrder: function(order) { workspacesOrder = order; }, workspace: getWorkspace, @@ -2885,6 +3055,20 @@ RED.nodes = (function() { } } }, + eachGroup: function(cb) { + for (var group of Object.values(groups)) { + if (cb(group) === false) { + break + } + } + }, + eachJunction: function(cb) { + for (var junction of Object.values(junctions)) { + if (cb(junction) === false) { + break + } + } + }, node: getNode, @@ -2907,6 +3091,7 @@ RED.nodes = (function() { getAllFlowNodes: getAllFlowNodes, getAllUpstreamNodes: getAllUpstreamNodes, getAllDownstreamNodes: getAllDownstreamNodes, + getDownstreamNodes: getDownstreamNodes, getNodeIslands: getNodeIslands, createExportableNodeSet: createExportableNodeSet, createCompleteNodeSet: createCompleteNodeSet, diff --git a/packages/node_modules/@node-red/editor-client/src/js/red.js b/packages/node_modules/@node-red/editor-client/src/js/red.js index 7544434b7..ce3b439e4 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/red.js +++ b/packages/node_modules/@node-red/editor-client/src/js/red.js @@ -249,8 +249,35 @@ var RED = (function() { RED.nodes.import(nodes.flows); RED.nodes.dirty(false); RED.view.redraw(true); - if (/^#flow\/.+$/.test(currentHash)) { - RED.workspaces.show(currentHash.substring(6),true); + if (/^#(flow|node|group)\/.+$/.test(currentHash)) { + const hashParts = currentHash.split('/') + const showEditDialog = hashParts.length > 2 && hashParts[2] === 'edit' + if (hashParts[0] === '#flow') { + RED.workspaces.show(hashParts[1], true); + if (showEditDialog) { + RED.workspaces.edit() + } + } else if (hashParts[0] === '#node') { + const nodeToShow = RED.nodes.node(hashParts[1]) + if (nodeToShow) { + setTimeout(() => { + RED.view.reveal(nodeToShow.id) + window.location.hash = currentHash + if (showEditDialog) { + RED.editor.edit(nodeToShow) + } + }, 50) + } + } else if (hashParts[0] === '#group') { + const nodeToShow = RED.nodes.group(hashParts[1]) + if (nodeToShow) { + RED.view.reveal(nodeToShow.id) + window.location.hash = currentHash + if (showEditDialog) { + RED.editor.editGroup(nodeToShow) + } + } + } } if (RED.workspaces.count() > 0) { const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}"); @@ -321,6 +348,8 @@ var RED = (function() { loader.end() RED.notify($("

").text(message)); RED.sidebar.info.refresh() + RED.menu.setDisabled('menu-item-projects-open',false); + RED.menu.setDisabled('menu-item-projects-settings',false); }); }); return; @@ -641,11 +670,6 @@ var RED = (function() { ]}); menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [ - {id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"}, - {id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"}, - {id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"}, - {id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"}, - null, {id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"}, {id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"}, {id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"}, @@ -655,7 +679,12 @@ var RED = (function() { {id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"}, null, {id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"}, - {id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"} + {id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"}, + null, + {id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"}, + {id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"}, + {id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"}, + {id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"} ]}); menuOptions.push(null); @@ -748,6 +777,7 @@ var RED = (function() { RED.deploy.init(RED.settings.theme("deployButton",null)); RED.keyboard.init(buildMainMenu); + RED.envVar.init(); RED.nodes.init(); RED.runtime.init() diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js index f547203d4..dd1ca7074 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js @@ -423,11 +423,10 @@ RED.clipboard = (function() { } } - function showImportNodes(mode) { + function showImportNodes(library = 'clipboard') { if (disabled) { return; } - mode = mode || "clipboard"; dialogContainer.empty(); dialogContainer.append($(importNodesDialog)); @@ -504,7 +503,7 @@ RED.clipboard = (function() { $("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport); $("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)}); - if (RED.workspaces.active() === 0) { + if (RED.workspaces.active() === 0 || RED.workspaces.isLocked()) { $("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected"); $("#red-ui-clipboard-dialog-import-opt-new").addClass("selected"); } else { @@ -533,8 +532,8 @@ RED.clipboard = (function() { $("#red-ui-clipboard-dialog-import-file-upload").trigger("click"); }) - tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode); - if (mode === 'clipboard') { + tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+library); + if (library === 'clipboard') { setTimeout(function() { $("#red-ui-clipboard-dialog-import-text").trigger("focus"); },100) @@ -558,13 +557,16 @@ RED.clipboard = (function() { }); } - function showExportNodes(mode) { + /** + * Show the export dialog + * @params library which export destination to show + * @params mode whether to default to 'auto' (default) or 'flow' + **/ + function showExportNodes(library = 'clipboard', mode = 'auto' ) { if (disabled) { return; } - mode = mode || "clipboard"; - dialogContainer.empty(); dialogContainer.append($(exportNodesDialog)); @@ -654,7 +656,12 @@ RED.clipboard = (function() { $("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select(); dialogContainer.i18n(); + var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini"; + const userFormat = RED.settings.get("editor.dialog.export.pretty") + if (userFormat === false || userFormat === true) { + format = userFormat ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini"; + } $("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) { evt.preventDefault(); @@ -670,7 +677,8 @@ RED.clipboard = (function() { var nodes = JSON.parse(flow); format = $(this).attr('id'); - if (format === 'red-ui-clipboard-dialog-export-fmt-full') { + const pretty = format === "red-ui-clipboard-dialog-export-fmt-full"; + if (pretty) { flow = JSON.stringify(nodes,null,4); } else { flow = JSON.stringify(nodes); @@ -679,6 +687,7 @@ RED.clipboard = (function() { setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50); $("#red-ui-clipboard-dialog-export-text").trigger("focus"); + RED.settings.set("editor.dialog.export.pretty", pretty) } }); @@ -766,12 +775,15 @@ RED.clipboard = (function() { } } } + if (mode === 'flow' && !$("#red-ui-clipboard-dialog-export-rng-flow").hasClass('disabled')) { + $("#red-ui-clipboard-dialog-export-rng-flow").trigger("click"); + } if (format === "red-ui-clipboard-dialog-export-fmt-full") { $("#red-ui-clipboard-dialog-export-fmt-full").trigger("click"); } else { $("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click"); } - tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode); + tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+library); var dialogHeight = 400; var winHeight = $(window).height(); @@ -1266,15 +1278,17 @@ RED.clipboard = (function() { RED.keyboard.add("#red-ui-drop-target", "escape" ,hideDropTarget); $('#red-ui-workspace-chart').on("dragenter",function(event) { - if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || - $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { + if (!RED.workspaces.isLocked() && ( + $.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || + $.inArray("Files",event.originalEvent.dataTransfer.types) != -1)) { $("#red-ui-drop-target").css({display:'table'}).focus(); } }); $('#red-ui-drop-target').on("dragover",function(event) { if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || - $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { + $.inArray("Files",event.originalEvent.dataTransfer.types) != -1 || + RED.workspaces.isLocked()) { event.preventDefault(); } }) @@ -1282,27 +1296,29 @@ RED.clipboard = (function() { hideDropTarget(); }) .on("drop",function(event) { - try { - if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { - var data = event.originalEvent.dataTransfer.getData("text/plain"); - data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); - importNodes(data); - } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { - var files = event.originalEvent.dataTransfer.files; - if (files.length === 1) { - var file = files[0]; - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - importNodes(e.target.result); - }; - })(file); - reader.readAsText(file); + if (!RED.workspaces.isLocked()) { + try { + if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { + var data = event.originalEvent.dataTransfer.getData("text/plain"); + data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); + importNodes(data); + } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { + var files = event.originalEvent.dataTransfer.files; + if (files.length === 1) { + var file = files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + importNodes(e.target.result); + }; + })(file); + reader.readAsText(file); + } } + } catch(err) { + // Ensure any errors throw above doesn't stop the drop target from + // being hidden. } - } catch(err) { - // Ensure any errors throw above doesn't stop the drop target from - // being hidden. } hideDropTarget(); event.preventDefault(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js index f308614d7..8ee1f0e29 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js @@ -417,6 +417,9 @@ } else { return null; } + }, + cancel: function() { + this.element.sortable("cancel"); } }); })(jQuery); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js index 2d95f894a..8d0f1dbd3 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js @@ -94,8 +94,8 @@ RED.menu = (function() { var link = $(linkContent).appendTo(item); opt.link = link; - if (typeof opt.onselect === 'string') { - var shortcut = RED.keyboard.getShortcut(opt.onselect); + if (typeof opt.onselect === 'string' || opt.shortcut) { + var shortcut = opt.shortcut || RED.keyboard.getShortcut(opt.onselect); if (shortcut && shortcut.key) { opt.shortcutSpan = $(''+RED.keyboard.formatKey(shortcut.key, true)+'').appendTo(link.find(".red-ui-menu-label")); } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js index 8901cf11f..abb76e622 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js @@ -141,7 +141,29 @@ RED.tabs = (function() { }) } - + if (options.contextmenu) { + wrapper.on('contextmenu', function(evt) { + let clickedTab + let target = evt.target + while(target.nodeName !== 'A' && target.nodeName !== 'UL' && target.nodeName !== 'BODY') { + target = target.parentNode + } + if (target.nodeName === 'A') { + const href = target.getAttribute('href') + if (href) { + clickedTab = tabs[href.slice(1)] + } + } + evt.preventDefault() + evt.stopPropagation() + RED.contextMenu.show({ + x:evt.clientX-5, + y:evt.clientY-5, + options: options.contextmenu(clickedTab) + }) + return false + }) + } var scrollLeft; var scrollRight; @@ -161,7 +183,7 @@ RED.tabs = (function() { // Assume this is wheel event which might not trigger // the scroll event, so do things manually var sl = scrollContainer.scrollLeft(); - sl -= evt.originalEvent.deltaY; + sl += evt.originalEvent.deltaY; scrollContainer.scrollLeft(sl); } }) @@ -807,23 +829,22 @@ RED.tabs = (function() { event.preventDefault(); removeTab(tab.id); }); - RED.popover.tooltip(closeLink,RED._("workspace.hideFlow")); - } - if (tab.hideable) { - li.addClass("red-ui-tabs-closeable") - var closeLink = $("",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li); - closeLink.append(''); - closeLink.append(''); - closeLink.on("click",function(event) { - event.preventDefault(); - hideTab(tab.id); - }); - RED.popover.tooltip(closeLink,RED._("workspace.hideFlow")); + RED.popover.tooltip(closeLink,RED._("workspace.closeFlow")); } + // if (tab.hideable) { + // li.addClass("red-ui-tabs-closeable") + // var closeLink = $("",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li); + // closeLink.append(''); + // closeLink.append(''); + // closeLink.on("click",function(event) { + // event.preventDefault(); + // hideTab(tab.id); + // }); + // RED.popover.tooltip(closeLink,RED._("workspace.hideFlow")); + // } var badges = $('').appendTo(li); if (options.onselect) { - $('').appendTo(badges); $('').appendTo(badges); } @@ -938,6 +959,9 @@ RED.tabs = (function() { activeIndex: function() { return ul.find("li.active").index() }, + getTabIndex: function (id) { + return ul.find("a[href='#"+id+"']").parent().index() + }, contains: function(id) { return ul.find("a[href='#"+id+"']").length > 0; }, diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js index a1fdb402a..b63cdc1a2 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js @@ -1,21 +1,6 @@ RED.contextMenu = (function () { let menu; - function createMenu() { - // menu = RED.popover.menu({ - // options: [ - // { - // label: 'delete selection', - // onselect: function() { - // RED.actions.invoke('core:delete-selection') - // RED.view.focus() - // } - // }, - // { label: 'world' } - // ], - // width: 200, - // }) - } function disposeMenu() { $(document).off("mousedown.red-ui-workspace-context-menu"); @@ -28,114 +13,172 @@ RED.contextMenu = (function () { if (menu) { menu.remove() } + let menuItems = [] + if (options.options) { + menuItems = options.options + } else if (options.type === 'workspace') { + const selection = RED.view.selection() + const noSelection = !selection || Object.keys(selection).length === 0 + const hasSelection = (selection.nodes && selection.nodes.length > 0); + const hasMultipleSelection = hasSelection && selection.nodes.length > 1; + const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || []; + const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || []; + const hasLinks = wireLinks.length > 0; + const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1 + const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1 + const canDelete = hasSelection || hasLinks + const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group' + const canEdit = !RED.workspaces.isLocked() + const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g + const isAllGroups = hasSelection && selection.nodes.filter(n => n.type !== 'group').length === 0 + const hasGroup = hasSelection && selection.nodes.filter(n => n.type === 'group' ).length > 0 + const offset = $("#red-ui-workspace-chart").offset() - const selection = RED.view.selection() - const noSelection = !selection || Object.keys(selection).length === 0 - const hasSelection = (selection.nodes && selection.nodes.length > 0); - const hasMultipleSelection = hasSelection && selection.nodes.length > 1; - const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || []; - const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || []; - const hasLinks = wireLinks.length > 0; - const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1 - const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1 - const canDelete = hasSelection || hasLinks - const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group' - - const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g - const offset = $("#red-ui-workspace-chart").offset() - - // addX/addY must be the position in the workspace accounting for both scroll and scale - // The +5 is because we display the contextMenu -5,-5 to actual click position - let addX = (options.x + 5 - offset.left + $("#red-ui-workspace-chart").scrollLeft()) / RED.view.scale() - let addY = (options.y + 5 - offset.top + $("#red-ui-workspace-chart").scrollTop()) / RED.view.scale() - - const menuItems = [ - { onselect: 'core:show-action-list', onpostselect: function () { } }, - { - label: RED._("contextMenu.insert"), - options: [ - { - label: RED._("contextMenu.node"), - onselect: function () { - RED.view.showQuickAddDialog({ - position: [addX, addY], - touchTrigger: true, - splice: isSingleLink ? selection.links[0] : undefined, - // spliceMultiple: isMultipleLinks - }) - }, - onpostselect: function() { - // ensure quick add dialog search input has focus - $('#red-ui-type-search-input').trigger('focus') - } - }, - (hasLinks) ? { // has least 1 wire selected - label: RED._("contextMenu.junction"), - onselect: 'core:split-wires-with-junctions', - disabled: !hasLinks - } : { - label: RED._("contextMenu.junction"), - onselect: function () { - const nn = { - _def: { defaults: {} }, - type: 'junction', - z: RED.workspaces.active(), - id: RED.nodes.id(), - x: addX, - y: addY, - w: 0, h: 0, - outputs: 1, - inputs: 1, - dirty: true - } - const historyEvent = { - dirty: RED.nodes.dirty(), - t: 'add', - junctions: [nn] - } - RED.nodes.addJunction(nn); - RED.history.push(historyEvent); - RED.nodes.dirty(true); - RED.view.select({nodes: [nn] }); - RED.view.redraw(true) - } - }, - { - label: RED._("contextMenu.linkNodes"), - onselect: 'core:split-wire-with-link-nodes', - disabled: !hasLinks - } - ] - - + let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft() + let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop() + if (RED.view.snapGrid) { + const gridSize = RED.view.gridSize() + addX = gridSize * Math.floor(addX / gridSize) + addY = gridSize * Math.floor(addY / gridSize) + } + + menuItems.push( + { onselect: 'core:show-action-list', onpostselect: function () { } } + ) + + const insertOptions = [] + menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions }) + insertOptions.push( + { + label: RED._("contextMenu.node"), + onselect: function () { + RED.view.showQuickAddDialog({ + position: [addX, addY], + touchTrigger: true, + splice: isSingleLink ? selection.links[0] : undefined, + // spliceMultiple: isMultipleLinks + }) + }, + disabled: !canEdit + }, + (hasLinks) ? { // has least 1 wire selected + label: RED._("contextMenu.junction"), + onselect: 'core:split-wires-with-junctions', + disabled: !canEdit || !hasLinks + } : { + label: RED._("contextMenu.junction"), + onselect: function () { + const nn = { + _def: { defaults: {} }, + type: 'junction', + z: RED.workspaces.active(), + id: RED.nodes.id(), + x: addX, + y: addY, + w: 0, h: 0, + outputs: 1, + inputs: 1, + dirty: true, + moved: true + } + const junction = RED.nodes.addJunction(nn); + const historyEvent = { + dirty: RED.nodes.dirty(), + t: 'add', + junctions: [junction] + } + RED.history.push(historyEvent); + RED.nodes.dirty(true); + RED.view.select({nodes: [junction] }); + RED.view.redraw(true) + }, + disabled: !canEdit + }, + { + label: RED._("contextMenu.linkNodes"), + onselect: 'core:split-wire-with-link-nodes', + disabled: !canEdit || !hasLinks + }, + null, + { onselect: 'core:show-import-dialog', label: RED._('common.label.import')}, + { onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') } + ) + if (hasSelection && canEdit) { + const nodeOptions = [] + if (!hasMultipleSelection && !isGroup) { + nodeOptions.push( + { onselect: 'core:show-node-help' }, + null + ) + } + nodeOptions.push( + { onselect: 'core:enable-selected-nodes' }, + { onselect: 'core:disable-selected-nodes' }, + null, + { onselect: 'core:show-selected-node-labels' }, + { onselect: 'core:hide-selected-node-labels' } + ) + menuItems.push({ + label: RED._('sidebar.info.node'), + options: nodeOptions + }) + menuItems.push({ + label: RED._('sidebar.info.group'), + options: [ + { onselect: 'core:group-selection' }, + { onselect: 'core:ungroup-selection', disabled: !hasGroup }, + ] + }) + if (hasGroup) { + menuItems[menuItems.length - 1].options.push( + { onselect: 'core:merge-selection-to-group', label: RED._("menu.label.groupMergeSelection") } + ) + + } + if (canRemoveFromGroup) { + menuItems[menuItems.length - 1].options.push( + { onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") } + ) + } + menuItems[menuItems.length - 1].options.push( + null, + { onselect: 'core:copy-group-style', disabled: !hasGroup }, + { onselect: 'core:paste-group-style', disabled: !hasGroup} + ) + } + if (canEdit && hasMultipleSelection) { + menuItems.push({ + label: RED._('menu.label.arrange'), + options: [ + { label:RED._("menu.label.alignLeft"), onselect: "core:align-selection-to-left"}, + { label:RED._("menu.label.alignCenter"), onselect: "core:align-selection-to-center"}, + { label:RED._("menu.label.alignRight"), onselect: "core:align-selection-to-right"}, + null, + { label:RED._("menu.label.alignTop"), onselect: "core:align-selection-to-top"}, + { label:RED._("menu.label.alignMiddle"), onselect: "core:align-selection-to-middle"}, + { label:RED._("menu.label.alignBottom"), onselect: "core:align-selection-to-bottom"}, + null, + { label:RED._("menu.label.distributeHorizontally"), onselect: "core:distribute-selection-horizontally"}, + { label:RED._("menu.label.distributeVertically"), onselect: "core:distribute-selection-vertically"} + ] + }) } - ] - menuItems.push( - null, - { onselect: 'core:undo', disabled: RED.history.list().length === 0 }, - { onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 }, - null, - { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection }, - { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection }, - { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() }, - { onselect: 'core:delete-selection', disabled: !canDelete }, - { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, - { onselect: 'core:select-all-nodes' } - ) - if (hasSelection) { menuItems.push( null, - isGroup ? - { onselect: 'core:ungroup-selection', disabled: !isGroup } - : { onselect: 'core:group-selection', disabled: !hasSelection } + { onselect: 'core:undo', disabled: RED.history.list().length === 0 }, + { onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 }, + null, + { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !canEdit || !hasSelection }, + { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection }, + { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() }, + { onselect: 'core:delete-selection', disabled: !canEdit || !canDelete }, + { onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete }, + { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, + { onselect: 'core:select-all-nodes' }, ) - if (canRemoveFromGroup) { - menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") }) - } - } var direction = "right"; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js index 8a8df6837..a09fdeb01 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js @@ -557,7 +557,17 @@ RED.deploy = (function() { } else { RED.notify('

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

', "success"); } + const flowsToLock = new Set() + function ensureUnlocked(id) { + const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null); + const isLocked = flow ? flow.locked : false; + if (flow && isLocked) { + flow.locked = false; + flowsToLock.add(flow) + } + } RED.nodes.eachNode(function (node) { + ensureUnlocked(node.z) if (node.changed) { node.dirty = true; node.changed = false; @@ -570,7 +580,32 @@ RED.deploy = (function() { delete node.credentials; } }); + RED.nodes.eachGroup(function (node) { + ensureUnlocked(node.z) + if (node.changed) { + node.dirty = true; + node.changed = false; + } + if (node.moved) { + node.dirty = true; + node.moved = false; + } + }) + RED.nodes.eachJunction(function (node) { + ensureUnlocked(node.z) + if (node.changed) { + node.dirty = true; + node.changed = false; + } + if (node.moved) { + node.dirty = true; + node.moved = false; + } + }) RED.nodes.eachConfig(function (confNode) { + if (confNode.z) { + ensureUnlocked(confNode.z) + } confNode.changed = false; if (confNode.credentials) { delete confNode.credentials; @@ -580,8 +615,16 @@ RED.deploy = (function() { subflow.changed = false; }); RED.nodes.eachWorkspace(function (ws) { - ws.changed = false; + if (ws.changed || ws.added) { + ensureUnlocked(ws.z) + ws.changed = false; + delete ws.added + RED.events.emit("flows:change", ws) + } }); + flowsToLock.forEach(flow => { + flow.locked = true + }) // Once deployed, cannot undo back to a clean state RED.history.markAllDirty(); RED.view.redraw(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index be114c4a8..45f2068d9 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -238,6 +238,7 @@ RED.editor = (function() { var valid = validateNodeProperty(node, defaults, property,value); if (((typeof valid) === "string") || !valid) { input.addClass("input-error"); + input.next(".red-ui-typedInput-container").addClass("input-error"); if ((typeof valid) === "string") { var tooltip = input.data("tooltip"); if (tooltip) { @@ -250,6 +251,7 @@ RED.editor = (function() { } } else { input.removeClass("input-error"); + input.next(".red-ui-typedInput-container").removeClass("input-error"); var tooltip = input.data("tooltip"); if (tooltip) { input.data("tooltip", null); @@ -858,6 +860,7 @@ RED.editor = (function() { function showEditDialog(node, defaultTab) { if (buildingEditDialog) { return } buildingEditDialog = true; + if (node.z && RED.workspaces.isLocked(node.z)) { return } var editing_node = node; var removeInfoEditorOnClose = false; var skipInfoRefreshOnClose = false; @@ -1043,6 +1046,13 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) + var helpButton = $('').on("click", function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.sidebar.help.show(editing_node.type); + }).appendTo(trayFooterLeft); + RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp")); + $('').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({ enabledIcon: "fa-circle-thin", disabledIcon: "fa-ban", @@ -1146,6 +1156,8 @@ RED.editor = (function() { var editing_config_node = RED.nodes.node(id); var activeEditPanes = []; + if (editing_config_node && editing_config_node.z && RED.workspaces.isLocked(editing_config_node.z)) { return } + var configNodeScope = ""; // default to global var activeSubflow = RED.nodes.subflow(RED.workspaces.active()); if (activeSubflow) { @@ -1188,6 +1200,13 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) + var helpButton = $('').on("click", function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.sidebar.help.show(editing_config_node.type); + }).appendTo(trayFooterLeft); + RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp")); + $('').prop("checked",!!editing_config_node.d).appendTo(trayFooterLeft).toggleButton({ enabledIcon: "fa-circle-thin", disabledIcon: "fa-ban", @@ -1692,6 +1711,7 @@ RED.editor = (function() { function showEditGroupDialog(group, defaultTab) { if (buildingEditDialog) { return } buildingEditDialog = true; + if (group.z && RED.workspaces.isLocked(group.z)) { return } var editing_node = group; editStack.push(group); RED.view.state(RED.state.EDITING); @@ -1851,11 +1871,15 @@ RED.editor = (function() { workspace.disabled = disabled; $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled); - if (workspace.id === RED.workspaces.active()) { - $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled); - } } + var locked = $("#node-input-locked").prop("checked"); + if (workspace.locked !== locked) { + editState.changes.locked = workspace.locked; + editState.changed = true; + workspace.locked = locked; + $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked); + } if (editState.changed) { var historyEvent = { t: "edit", @@ -1896,6 +1920,7 @@ RED.editor = (function() { var trayBody = tray.find('.red-ui-tray-body'); trayBody.parent().css('overflow','hidden'); var trayFooterLeft = $('').appendTo(trayFooter) + var trayFooterRight = $('').appendTo(trayFooter) var nodeEditPanes = [ 'editor-tab-flow-properties', @@ -1910,6 +1935,18 @@ RED.editor = (function() { disabledIcon: "fa-ban", invertState: true }) + + if (!workspace.hasOwnProperty("locked")) { + workspace.locked = false; + } + $('').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({ + enabledLabel: RED._("common.label.unlocked"), + enabledIcon: "fa-unlock-alt", + disabledLabel: RED._("common.label.locked"), + disabledIcon: "fa-lock", + invertState: true + }) + prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) { activeEditPanes = _activeEditPanes; trayBody.i18n(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js index 7cee2026b..b92881764 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js @@ -45,6 +45,9 @@ selectedCodeEditor = RED.editor.codeEditor[defaultEditor]; initialised = selectedCodeEditor.init(); } + + $('

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