mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
106 Commits
4396-fix-g
...
4508
Author | SHA1 | Date | |
---|---|---|---|
|
58e2fcbeee | ||
|
282bb6c414 | ||
|
ce5b6a8024 | ||
|
0773edcaff | ||
|
68dcf7bceb | ||
|
d876146ea5 | ||
|
50627cd697 | ||
|
6a4d293352 | ||
|
1ad4fe44e2 | ||
|
59ea7a4f70 | ||
|
6c64ba45c2 | ||
|
c68cc4ac19 | ||
|
84ed88c8dd | ||
|
d7345d5bc6 | ||
|
f0a9b0cf69 | ||
|
26ddb5c1b7 | ||
|
82f8b64599 | ||
|
7f24de442f | ||
|
8365310ca7 | ||
|
aaed9882b8 | ||
|
8f5ebfcede | ||
|
74ff0599d1 | ||
|
1828d8a279 | ||
|
70ea5c839a | ||
|
e1f2e0656b | ||
|
d287b8867b | ||
|
0e8d312794 | ||
|
c584d51432 | ||
|
2366b4508f | ||
|
2f1565fbc9 | ||
|
7fd0ecf721 | ||
|
37d1539fda | ||
|
1e518396d6 | ||
|
617b98ed49 | ||
|
6d2a870812 | ||
|
2963f3f1b8 | ||
|
17e4bdbff1 | ||
|
f3dd5770d9 | ||
|
eebab4a921 | ||
|
b06494c5be | ||
|
a0562bef81 | ||
|
eff063a748 | ||
|
94abaaff1e | ||
|
03732869e4 | ||
|
41868e2652 | ||
|
81bfba3cea | ||
|
8a04eb2e29 | ||
|
1777fc749d | ||
|
fd32ee09ff | ||
|
4bb2157cab | ||
|
47f20cc86a | ||
|
5fc4526c70 | ||
|
9fe653f821 | ||
|
55da21ed15 | ||
|
7ebf84f38c | ||
|
d42e75ebd0 | ||
|
28825049fe | ||
|
1c3644e338 | ||
|
2dfabb523b | ||
|
3e2d20e536 | ||
|
ee7ee083b0 | ||
|
fb54c05d9f | ||
|
21f807aa66 | ||
|
6b088bda12 | ||
|
a32ee869ae | ||
|
a2d7772958 | ||
|
6ec052be18 | ||
|
9c71d52d69 | ||
|
171c146ec5 | ||
|
bc6afa2164 | ||
|
3c036257ef | ||
|
6633730bf1 | ||
|
2964a4da5e | ||
|
a55554193b | ||
|
d2a8338d4a | ||
|
e945deeab6 | ||
|
722fe02933 | ||
|
3dec609459 | ||
|
e73b9f646d | ||
|
3cea6400d1 | ||
|
c6a8eee73d | ||
|
74d431ea36 | ||
|
409a559a13 | ||
|
6829535350 | ||
|
6488111f79 | ||
|
923339c1d8 | ||
|
3f4d96f4cd | ||
|
c52985d245 | ||
|
88e6c71aa0 | ||
|
4d08e297c4 | ||
|
ad2b30691f | ||
|
369bad01b8 | ||
|
b6ecc6d9ea | ||
|
0117df0960 | ||
|
6ac905f264 | ||
|
e5307f6604 | ||
|
8d9b6dd859 | ||
|
01821ead0f | ||
|
1451fb9e2f | ||
|
245751bb23 | ||
|
f07519c705 | ||
|
60593fed4a | ||
|
fae3a5c26a | ||
|
1a52c0adfc | ||
|
44c0bbc61e | ||
|
5ac50fae3a |
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -27,12 +27,12 @@ jobs:
|
||||
with:
|
||||
repository: 'node-red/node-red.github.io'
|
||||
path: 'node-red.github.io'
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: node ./node-red/.github/scripts/update-node-red-docker.js
|
||||
- name: Create Docker Pull Request
|
||||
uses: peter-evans/create-pull-request@v2
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.NR_REPO_TOKEN }}
|
||||
committer: GitHub <noreply@github.com>
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
This PR was auto-generated by a GitHub Action. Any questions, speak to @knolleary
|
||||
- run: node ./node-red/.github/scripts/update-node-red-website.js
|
||||
- name: Create Website Pull Request
|
||||
uses: peter-evans/create-pull-request@v2
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.NR_REPO_TOKEN }}
|
||||
committer: GitHub <noreply@github.com>
|
||||
|
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
|
74
CHANGELOG.md
74
CHANGELOG.md
@@ -1,3 +1,77 @@
|
||||
#### 3.1.3: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Add missing en-us messages (#4475) @knolleary
|
||||
|
||||
#### 3.1.2: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Relax some node validators to allow undefined value (#4471) @knolleary
|
||||
- Fix switch validation of typeof field (#4465) @knolleary
|
||||
- Use move cursor when hovering on group border (#4467) @knolleary
|
||||
- Added action list Chinese (Simplified and Traditional) translation + v3.1.1 changes (#4470) @wangyiyi2056
|
||||
- Add French translation of `action-list` + v3.1.1 changes (#4466) @GogoVega
|
||||
|
||||
Runtime
|
||||
|
||||
- Ensure nested groups inside subflows have their g props remapped (#4472) @knolleary
|
||||
|
||||
#### 3.1.1: Maintenance Release
|
||||
|
||||
Editor
|
||||
|
||||
- Fix debug filter (#4461) @knolleary
|
||||
- Fix various issues with debug pop-out window (#4459) @knolleary
|
||||
- Ensure subflow instances keep track of their groups (#4457) @knolleary
|
||||
- Fix `validateNodeProperty` without validator provided (#4455) @GogoVega
|
||||
- Debounce node-removed notifications (#4453) @knolleary
|
||||
- Don't try to load the parents of the first commit (#4448) @bonanitech
|
||||
- Allow a theme to specifiy which theme mermaid should use (#4441) @knolleary
|
||||
- Update browser title with flow name if set (#4427) @knolleary
|
||||
- Ensure typeSearch handles undefined node definitions (#4423) @knolleary
|
||||
- Ensure group w/h are imported if present (#4426) @knolleary
|
||||
- Hide node status background when there is no status to show (#4425) @knolleary
|
||||
- Add a close button to the restart-required notification (#4407) @knolleary
|
||||
- Extend typedInput "num" type validity check to NaN, binary, octal & hex (#4371) @ralphwetzel
|
||||
- Fix unintended new line in node name (#4399) @kazuhitoyokoi
|
||||
- Ctrl-Enter does not close tray (Monaco) #4377 (#4382) @hazymat
|
||||
- fix buffer viewer to handle 0b style binary (#4393) @dceejay
|
||||
- Rework mermaid integration to support off-DOM rendering (#4364) @knolleary
|
||||
- Add missing nls labels to context menu (#4365) @knolleary
|
||||
|
||||
Runtime
|
||||
|
||||
- Bump the github-actions group with 2 updates (#4404) @app/dependabot
|
||||
- Handle unknown node reference inside subflow module (#4460) @knolleary
|
||||
- Add modules.install audit event when external module installed (#4452) @knolleary
|
||||
- Allow import of modules with subpath in specifier (#4451) @knolleary
|
||||
- Update node-red-admin version (#4438) @knolleary
|
||||
- Handle false-like env vars properly (#4411) @knolleary
|
||||
- Only save settings once during node load process (#4409) @knolleary
|
||||
- Ensure global-config nodes lookup cred values properly (#4405) @knolleary
|
||||
- Handle credential env var evaluation when no value set (#4362) @knolleary
|
||||
- Don't commit package-lock.json (#4354) @bonanitech
|
||||
- Fix env evaluation when one env references another in the same object (#4361) @knolleary
|
||||
- Add dependabot for Github Actions (#4312) @Rotzbua
|
||||
- Update outdated Github Actions (#4311) @Rotzbua
|
||||
- github: Request `npm run test` in PR template (#4348) @ZJvandeWeg
|
||||
- Add French translation of v3.1.0-beta.4 changes + slight improvements (#4329) @GogoVega
|
||||
- Handle nodes with multiple input handlers properly (#4332) @knolleary
|
||||
- Soften the language around unrequited PRs (#4351) @knolleary
|
||||
|
||||
Nodes
|
||||
|
||||
- CSV: make CSV export way faster by not re-allocating and handling huge string (#4349) @Fadoli
|
||||
- Delay: Fix regression in delay node to not pass on msg.reset (#4350) @dceejay
|
||||
- Link Call: Handle undefined linkType value for existing link-call nodes (#4331) @knolleary
|
||||
- MQTT: Guard against node.broker being undefined (#4454) @knolleary
|
||||
- MQTT: check topic length > 0 before publish (#4416) @dceejay
|
||||
- Switch/Change: Improve validation of switch/change node rules (#4368) @knolleary
|
||||
- Template: Fix height of description editor in template node (#4346) @kazuhitoyokoi
|
||||
- Various: Add validators to any fields using msg-typed Input (#4440) @knolleary
|
||||
|
||||
#### 3.1.0: Milestone Release
|
||||
|
||||
Editor
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -64,7 +64,7 @@
|
||||
"mqtt": "4.3.7",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"mustache": "4.2.0",
|
||||
"node-red-admin": "^3.1.0",
|
||||
"node-red-admin": "^3.1.1",
|
||||
"node-watch": "0.7.4",
|
||||
"nopt": "5.0.0",
|
||||
"oauth2orize": "1.11.1",
|
||||
|
@@ -51,7 +51,7 @@ module.exports = {
|
||||
|
||||
var ui = require("./ui");
|
||||
|
||||
ui.init(runtimeAPI);
|
||||
ui.init(settings, runtimeAPI);
|
||||
|
||||
const editorApp = apiUtil.createExpressApp(settings)
|
||||
|
||||
|
@@ -339,6 +339,8 @@ module.exports = {
|
||||
}
|
||||
theme.codeEditor = theme.codeEditor || {}
|
||||
theme.codeEditor.options = Object.assign({}, themePlugin.monacoOptions, theme.codeEditor.options);
|
||||
|
||||
theme.mermaid = Object.assign({}, themePlugin.mermaid, theme.mermaid)
|
||||
}
|
||||
activeThemeInitialised = true;
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
const crypto = require('crypto')
|
||||
var express = require('express');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
@@ -24,13 +25,16 @@ var apiUtils = require("../util");
|
||||
var theme = require("./theme");
|
||||
|
||||
var runtimeAPI;
|
||||
let settings;
|
||||
var editorClientDir = path.dirname(require.resolve("@node-red/editor-client"));
|
||||
var defaultNodeIcon = path.join(editorClientDir,"public","red","images","icons","arrow-in.svg");
|
||||
var editorTemplatePath = path.join(editorClientDir,"templates","index.mst");
|
||||
var editorTemplate;
|
||||
let cacheBuster
|
||||
|
||||
module.exports = {
|
||||
init: function(_runtimeAPI) {
|
||||
init: function(_settings, _runtimeAPI) {
|
||||
settings = _settings;
|
||||
runtimeAPI = _runtimeAPI;
|
||||
editorTemplate = fs.readFileSync(editorTemplatePath,"utf8");
|
||||
Mustache.parse(editorTemplate);
|
||||
@@ -91,6 +95,12 @@ module.exports = {
|
||||
},
|
||||
|
||||
editor: async function(req,res) {
|
||||
if (!cacheBuster) {
|
||||
// settings.instanceId is set asynchronously to the editor-api
|
||||
// being initiaised. So we defer calculating the cacheBuster hash
|
||||
// until the first load of the editor
|
||||
cacheBuster = crypto.createHash('md5').update(`${settings.version || 'version'}-${settings.instanceId || 'instanceId'}`).digest("hex").substring(0,12)
|
||||
}
|
||||
|
||||
let sessionMessages;
|
||||
if (req.session && req.session.messages) {
|
||||
@@ -99,6 +109,7 @@ module.exports = {
|
||||
}
|
||||
res.send(Mustache.render(editorTemplate,{
|
||||
sessionMessages,
|
||||
cacheBuster,
|
||||
...await theme.context()
|
||||
}));
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-api",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.1.0",
|
||||
"@node-red/editor-client": "3.1.0",
|
||||
"@node-red/util": "3.1.3",
|
||||
"@node-red/editor-client": "3.1.3",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "1.20.2",
|
||||
"clone": "2.1.2",
|
||||
|
@@ -109,7 +109,6 @@
|
||||
"selectionToSubflow": "Auswahl in Subflow umwandeln",
|
||||
"flows": "Flow",
|
||||
"add": "Hinzufügen",
|
||||
"rename": "Umbenennen",
|
||||
"delete": "Löschen",
|
||||
"keyboardShortcuts": "Tastenkürzel",
|
||||
"login": "Anmelden",
|
||||
|
@@ -113,7 +113,7 @@
|
||||
"displayStatus": "Show node status",
|
||||
"displayConfig": "Configuration nodes",
|
||||
"import": "Import",
|
||||
"importExample": "Import Example Flow",
|
||||
"importExample": "Import example flow",
|
||||
"export": "Export",
|
||||
"search": "Search flows",
|
||||
"searchInput": "search your flows",
|
||||
@@ -122,7 +122,6 @@
|
||||
"selectionToSubflow": "Selection to Subflow",
|
||||
"flows": "Flows",
|
||||
"add": "Add",
|
||||
"rename": "Rename",
|
||||
"delete": "Delete",
|
||||
"keyboardShortcuts": "Keyboard shortcuts",
|
||||
"login": "Login",
|
||||
@@ -130,6 +129,11 @@
|
||||
"editPalette": "Manage palette",
|
||||
"other": "Other",
|
||||
"showTips": "Show tips",
|
||||
"showNodeHelp": "Show node help",
|
||||
"enableSelectedNodes": "Enable selected nodes",
|
||||
"disableSelectedNodes": "Disable selected nodes",
|
||||
"showSelectedNodeLabels": "Show selected node labels",
|
||||
"hideSelectedNodeLabels": "Hide selected node labels",
|
||||
"showWelcomeTours": "Show guided tours for new versions",
|
||||
"help": "Node-RED website",
|
||||
"projects": "Projects",
|
||||
@@ -511,8 +515,8 @@
|
||||
"selectAllConnected": "Select connected",
|
||||
"addRemoveNode": "Add/remove node from selection",
|
||||
"editSelected": "Edit selected node",
|
||||
"deleteSelected": "Delete selected nodes or link",
|
||||
"deleteReconnect": "Delete and Reconnect",
|
||||
"deleteSelected": "Delete selection",
|
||||
"deleteReconnect": "Delete and reconnect",
|
||||
"importNode": "Import nodes",
|
||||
"exportNode": "Export nodes",
|
||||
"nudgeNode": "Move selected nodes (1px)",
|
||||
@@ -1218,6 +1222,7 @@
|
||||
"invalid-expr": "Invalid JSONata expression: __error__",
|
||||
"invalid-prop": "Invalid property expression",
|
||||
"invalid-num": "Invalid number",
|
||||
"invalid-num-prop": "__prop__: invalid number",
|
||||
"invalid-regexp": "Invalid input pattern",
|
||||
"invalid-regex-prop": "__prop__: invalid input pattern",
|
||||
"missing-required-prop": "__prop__: property value missing",
|
||||
@@ -1227,6 +1232,7 @@
|
||||
}
|
||||
},
|
||||
"contextMenu": {
|
||||
"showActionList": "Show action list",
|
||||
"insert": "Insert",
|
||||
"node": "Node",
|
||||
"junction": "Junction",
|
||||
|
@@ -122,7 +122,6 @@
|
||||
"selectionToSubflow": "Convertir en sous-flux",
|
||||
"flows": "Flux",
|
||||
"add": "Ajouter",
|
||||
"rename": "Renommer",
|
||||
"delete": "Supprimer",
|
||||
"keyboardShortcuts": "Raccourcis clavier",
|
||||
"login": "Se connecter",
|
||||
@@ -1215,8 +1214,10 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "Données JSON invalides : __error__",
|
||||
"invalid-prop": "Expression de propriété non valide",
|
||||
"invalid-expr": "Expression JSONata invalide : __error__",
|
||||
"invalid-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",
|
||||
@@ -1235,5 +1236,159 @@
|
||||
"environment": "Environment",
|
||||
"header": "Variables d'environnement globales",
|
||||
"revert": "Rétablir"
|
||||
},
|
||||
"action-list": {
|
||||
"toggle-show-tips": "Basculer l'affichage des astuces",
|
||||
"show-about": "Afficher la description de Node-RED",
|
||||
"show-welcome-tour": "Afficher la visite de bienvenue",
|
||||
"show-next-tab": "Afficher l'onglet suivant",
|
||||
"show-previous-tab": "Afficher l'onglet précédent",
|
||||
"add-flow": "Ajouter un flux",
|
||||
"add-flow-to-right": "Ajouter un flux à droite",
|
||||
"edit-flow": "Modifier le flux",
|
||||
"remove-flow": "Supprimer le flux",
|
||||
"enable-flow": "Activer le flux",
|
||||
"disable-flow": "Désactiver le flux",
|
||||
"hide-flow": "Masquer le flux",
|
||||
"hide-other-flows": "Masquer les autres flux",
|
||||
"hide-all-flows": "Masquer tous les flux",
|
||||
"show-all-flows": "Afficher tous les flux",
|
||||
"show-last-hidden-flow": "Afficher le dernier flux masqué",
|
||||
"list-modified-nodes": "Afficher les flux modifiés",
|
||||
"list-hidden-flows": "Afficher les flux cachés",
|
||||
"list-flows": "Lister les flux",
|
||||
"list-subflows": "Liste les sous-flux",
|
||||
"go-to-previous-location": "Aller à l'emplacement précédent",
|
||||
"go-to-next-location": "Aller à l'emplacement suivant",
|
||||
"copy-selection-to-internal-clipboard": "Copier la sélection dans le presse-papiers",
|
||||
"cut-selection-to-internal-clipboard": "Couper la sélection dans le presse-papiers",
|
||||
"paste-from-internal-clipboard": "Coller depuis le presse-papiers",
|
||||
"detach-selected-nodes": "Détacher les noeuds sélectionnés",
|
||||
"delete-selection": "Supprimer la sélection",
|
||||
"delete-selection-and-reconnect": "Supprimer la sélection et reconnecter",
|
||||
"edit-selected-node": "Modifier le noeud sélectionné",
|
||||
"go-to-selection": "Aller à la sélection",
|
||||
"undo": "Annuler les modifications",
|
||||
"redo": "Rétablir les modifications",
|
||||
"select-all-nodes": "Sélectionner tous les noeuds",
|
||||
"select-none": "Sélectionner un noeud",
|
||||
"enable-selected-nodes": "Activer les noeuds sélectionnés",
|
||||
"disable-selected-nodes": "Désactiver les noeuds sélectionnés",
|
||||
"toggle-show-grid": "Basculer l'affichage de la grille",
|
||||
"toggle-snap-grid": "Basculer l'aide au placement des noeuds",
|
||||
"toggle-status": "Commuter l'état",
|
||||
"show-selected-node-labels": "Afficher les étiquettes des noeuds sélectionnés",
|
||||
"hide-selected-node-labels": "Masquer les étiquettes des noeuds sélectionnés",
|
||||
"scroll-view-up": "Faire défiler vers le haut",
|
||||
"scroll-view-right": "Faire défiler vers la droite",
|
||||
"scroll-view-down": "Faire défiler vers le bas",
|
||||
"scroll-view-left": "Faire défiler vers la gauche",
|
||||
"step-view-up": "Faire défiler d'une unité vers le haut",
|
||||
"step-view-right": "Faire défiler d'une unité vers la droite",
|
||||
"step-view-down": "Faire défiler d'une unité vers le bas",
|
||||
"step-view-left": "Faire défiler d'une unité vers la gauche",
|
||||
"move-selection-up": "Déplacer la sélection vers le haut",
|
||||
"move-selection-right": "Déplacer la sélection vers la droite",
|
||||
"move-selection-down": "Déplacer la sélection vers le bas",
|
||||
"move-selection-left": "Déplacer la sélection vers la gauche",
|
||||
"move-selection-forwards": "Avancer la sélection",
|
||||
"move-selection-backwards": "Reculer la sélection",
|
||||
"move-selection-to-front": "Déplacer la sélection vers l'avant",
|
||||
"move-selection-to-back": "Déplacer la sélection vers l'arrière",
|
||||
"step-selection-up": "Déplacer la sélection d'une unité vers le haut",
|
||||
"step-selection-right": "Déplacer la sélection d'une unité vers la droite",
|
||||
"step-selection-down": "Déplacer la sélection d'une unité vers le bas",
|
||||
"step-selection-left": "Déplacer la sélection d'une unité vers la gauche",
|
||||
"select-connected-nodes": "Sélectionner les noeuds connectés",
|
||||
"select-downstream-nodes": "Sélectionner les noeuds connectés en aval",
|
||||
"select-upstream-nodes": "Sélectionner les noeuds connectés en amont",
|
||||
"go-to-next-node": "Aller au noeud suivant",
|
||||
"go-to-previous-node": "Aller au noeud précédent",
|
||||
"go-to-next-sibling": "Aller au noeud frère suivant",
|
||||
"go-to-previous-sibling": "Aller au noeud frère précédent",
|
||||
"go-to-nearest-node-on-left": "Aller au noeud gauche le plus proche",
|
||||
"go-to-nearest-node-on-right": "Aller au noeud droit le plus proche",
|
||||
"go-to-nearest-node-above": "Aller au noeud supérieur le plus proche",
|
||||
"go-to-nearest-node-below": "Aller au noeud le plus proche ci-dessous",
|
||||
"align-selection-to-grid": "Aligner la sélection",
|
||||
"align-selection-to-left": "Aligner la sélection à gauche",
|
||||
"align-selection-to-right": "Aligner la sélection à droite",
|
||||
"align-selection-to-top": "Aligner la sélection en haut",
|
||||
"align-selection-to-bottom": "Aligner la sélection vers le bas",
|
||||
"align-selection-to-middle": "Aligner la sélection au centre verticalement",
|
||||
"align-selection-to-center": "Aligner la sélection au centre horizontalement",
|
||||
"distribute-selection-horizontally": "Distribuer la sélection horizontalement",
|
||||
"distribute-selection-vertical": "Distribuer la sélection verticalement",
|
||||
"wire-series-of-nodes": "Connecter les noeuds en série",
|
||||
"wire-node-to-multiple": "Connecter les noeuds à plusieurs",
|
||||
"wire-multiple-to-node": "Connecter plusieurs au noeud",
|
||||
"split-wire-with-link-nodes": "Diviser le fil avec des noeuds de liaison",
|
||||
"generate-node-names": "Générer les noms de noeuds",
|
||||
"show-user-settings": "Afficher les paramètres utilisateur",
|
||||
"show-help": "Afficher l'aide",
|
||||
"toggle-palette": "Basculer l'affichage de la palette",
|
||||
"show-event-log": "Afficher le journal des événements",
|
||||
"manage-palette": "Gérer la palette",
|
||||
"toggle-sidebar": "Basculer l'affichage de la barre latérale",
|
||||
"show-info-tab": "Afficher l'onglet d'informations sur le noeud",
|
||||
"show-help-tab": "Afficher l'onglet d'aide du noeud",
|
||||
"show-config-tab": "Afficher l'onglet du noeud de configuration",
|
||||
"select-all-config-nodes": "Sélectionner tous les noeuds de configuration",
|
||||
"delete-config-selection": "Supprimer le noeud de configuration sélectionné",
|
||||
"show-context-tab": "Afficher l'onglet des données contextuelles",
|
||||
"create-subflow": "Créer un sous-flux",
|
||||
"convert-to-subflow": "Convertir la sélection en sous-flux",
|
||||
"group-selection": "Grouper la sélection",
|
||||
"ungroup-selection": "Dissocier la sélection",
|
||||
"merge-selection-to-group": "Fusionner la sélection dans le groupe",
|
||||
"remove-selection-from-group": "Supprimer la sélection du groupe",
|
||||
"copy-group-style": "Copier le style du groupe",
|
||||
"paste-group-style": "Coller le style du groupe",
|
||||
"show-export-dialog": "Afficher la boîte de dialogue d'exportation",
|
||||
"show-import-dialog": "Afficher la boîte de dialogue d'importation",
|
||||
"show-library-export-dialog": "Afficher la boîte de dialogue d'exportation de la bibliothèque",
|
||||
"show-library-import-dialog": "Afficher la boîte de dialogue d'importation de bibliothèque",
|
||||
"show-examples-import-dialog": "Afficher la boîte de dialogue d'importation d'exemples",
|
||||
"search": "Rechercher",
|
||||
"search-previous": "Recherche précédente",
|
||||
"search-next": "Recherche suivante",
|
||||
"show-action-list": "Afficher la liste d'actions",
|
||||
"confirm-edit-tray": "Confirmer la modification",
|
||||
"cancel-edit-tray": "Annuler la modification",
|
||||
"show-remote-diff": "Afficher les différences avec les modifications distantes",
|
||||
"deploy-flows": "Déployer des flux",
|
||||
"restart-flows": "Redémarrer les flux",
|
||||
"set-deploy-type-to-full": "Définir le déploiement sur 'tout'",
|
||||
"set-deploy-type-to-modified-flows": "Définir le déploiement sur 'flux modifiés'",
|
||||
"set-deploy-type-to-modified-nodes": "Définir le déploiement sur 'noeuds modifiés'",
|
||||
"show-debug-tab": "Afficher l'onglet de débogage",
|
||||
"clear-debug-messages": "Supprimer les messages de débogage",
|
||||
"clear-filtered-debug-messages": "Supprimer les messages de débogage filtrés",
|
||||
"activate-selected-debug-nodes": "Activer les noeuds de débogage sélectionnés",
|
||||
"activate-all-debug-nodes": "Activer tous les noeuds de débogage",
|
||||
"activate-all-flow-debug-nodes": "Activer tous les noeuds de débogage dans un flux",
|
||||
"deactivate-selected-debug-nodes": "Désactiver les noeuds de débogage sélectionnés",
|
||||
"deactivate-all-debug-nodes": "Désactiver tous les noeuds de débogage",
|
||||
"deactivate-all-flow-debug-nodes": "Désactiver tous les noeuds de débogage dans un flux",
|
||||
"zoom-in": "Zoomer",
|
||||
"zoom-out": "Dézoomer",
|
||||
"zoom-reset": "Réinitialiser le zoom",
|
||||
"toggle-navigator": "Basculer l'affichage du navigateur",
|
||||
"show-system-info": "Afficher les informations système",
|
||||
"split-wires-with-junctions": "Diviser les fils avec des jonctions",
|
||||
"new-project": "Nouveau projet",
|
||||
"open-project": "Ouvrir le projet",
|
||||
"show-project-settings": "Afficher les paramètres du projet",
|
||||
"show-version-control-tab": "Afficher l'onglet de contrôle de version",
|
||||
"start-flows": "Démarrer les flux",
|
||||
"stop-flows": "Arrêter les flux",
|
||||
"copy-item-url": "Copier l'URL de l'élément",
|
||||
"copy-item-edit-url": "Copier l'URL de modification de l'élément",
|
||||
"move-flow-to-start": "Déplacer le flux jusqu'au début",
|
||||
"move-flow-to-end": "Déplacer le flux jusqu'à la fin",
|
||||
"show-global-env": "Afficher les variables d'environnement globales",
|
||||
"lock-flow": "Verrouiller le flux",
|
||||
"unlock-flow": "Déverrouiller le flux",
|
||||
"show-node-help": "Afficher l'aide du noeud"
|
||||
}
|
||||
}
|
||||
|
@@ -122,7 +122,6 @@
|
||||
"selectionToSubflow": "選択部分をサブフロー化",
|
||||
"flows": "フロー",
|
||||
"add": "フローを新規追加",
|
||||
"rename": "フロー名を変更",
|
||||
"delete": "フローを削除",
|
||||
"keyboardShortcuts": "ショートカットキーの説明",
|
||||
"login": "ログイン",
|
||||
@@ -130,6 +129,11 @@
|
||||
"editPalette": "パレットの管理",
|
||||
"other": "その他",
|
||||
"showTips": "ヒントを表示",
|
||||
"showNodeHelp": "ノードのヘルプを表示",
|
||||
"enableSelectedNodes": "選択したノードを有効化",
|
||||
"disableSelectedNodes": "選択したノードを無効化",
|
||||
"showSelectedNodeLabels": "選択したノードのラベル表示",
|
||||
"hideSelectedNodeLabels": "選択したノードのラベル非表示",
|
||||
"showWelcomeTours": "新バージョンのガイドツアーを表示",
|
||||
"help": "Node-REDウェブサイト",
|
||||
"projects": "プロジェクト",
|
||||
@@ -511,7 +515,7 @@
|
||||
"selectAllConnected": "接続されたノードを選択",
|
||||
"addRemoveNode": "ノードの選択、選択解除",
|
||||
"editSelected": "選択したノードを編集",
|
||||
"deleteSelected": "選択したノードや接続を削除",
|
||||
"deleteSelected": "選択部分を削除",
|
||||
"deleteReconnect": "削除と再接続",
|
||||
"importNode": "フローの読み込み",
|
||||
"exportNode": "フローの書き出し",
|
||||
@@ -1215,8 +1219,10 @@
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "JSONデータが不正: __error__",
|
||||
"invalid-expr": "不正なJSONata式: __error__",
|
||||
"invalid-prop": "プロパティ式が不正",
|
||||
"invalid-num": "数値が不正",
|
||||
"invalid-num-prop": "__prop__: 数値が不正",
|
||||
"invalid-regexp": "入力パターンが不正",
|
||||
"invalid-regex-prop": "__prop__: 入力パターンが不正",
|
||||
"missing-required-prop": "__prop__: プロパティが未設定",
|
||||
@@ -1226,6 +1232,7 @@
|
||||
}
|
||||
},
|
||||
"contextMenu": {
|
||||
"showActionList": "動作一覧を表示",
|
||||
"insert": "挿入",
|
||||
"node": "ノード",
|
||||
"junction": "分岐点",
|
||||
|
@@ -79,7 +79,6 @@
|
||||
"selectionToSubflow": "서브 플로우 선택",
|
||||
"flows": "플로우",
|
||||
"add": "추가",
|
||||
"rename": "이름변경",
|
||||
"delete": "삭제",
|
||||
"keyboardShortcuts": "단축키",
|
||||
"login": "로그인",
|
||||
|
@@ -109,7 +109,6 @@
|
||||
"selectionToSubflow": "Seleção para subfluxo",
|
||||
"flows": "Fluxos",
|
||||
"add": "Adicionar",
|
||||
"rename": "Renomear",
|
||||
"delete": "Apagar",
|
||||
"keyboardShortcuts": "Atalhos do teclado",
|
||||
"login": "Ingressar",
|
||||
@@ -1188,6 +1187,7 @@
|
||||
"invalid-json": "Dados JSON inválidos: __error__",
|
||||
"invalid-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",
|
||||
|
@@ -95,7 +95,6 @@
|
||||
"selectionToSubflow": "Выделение в подпоток",
|
||||
"flows": "Потоки",
|
||||
"add": "Добавить",
|
||||
"rename": "Переименовать",
|
||||
"delete": "Удалить",
|
||||
"keyboardShortcuts": "Сочетания клавиш",
|
||||
"login": "Войти",
|
||||
|
@@ -23,7 +23,11 @@
|
||||
"position": "位置",
|
||||
"enable": "启用",
|
||||
"disable": "禁用",
|
||||
"upload": "上传"
|
||||
"upload": "上传",
|
||||
"lock": "锁定",
|
||||
"unlock": "解锁",
|
||||
"locked": "锁定",
|
||||
"unlocked": "解锁"
|
||||
},
|
||||
"type": {
|
||||
"string": "字符串",
|
||||
@@ -68,7 +72,13 @@
|
||||
"enabled": "有效",
|
||||
"disabled": "无效",
|
||||
"info": "详细描述",
|
||||
"selectNodes": "点击节点来选择"
|
||||
"selectNodes": "点击节点来选择",
|
||||
"enableFlow": "启用流程",
|
||||
"disableFlow": "禁用流程",
|
||||
"lockFlow": "锁定流程",
|
||||
"unlockFlow": "解除锁定",
|
||||
"moveToStart": "移动到起始",
|
||||
"moveToEnd": "移动到末尾"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
@@ -101,6 +111,7 @@
|
||||
"displayStatus": "显示节点状态",
|
||||
"displayConfig": "修改节点配置",
|
||||
"import": "导入",
|
||||
"importExample": "导入示例流程",
|
||||
"export": "导出",
|
||||
"search": "查找流程",
|
||||
"searchInput": "查找流程",
|
||||
@@ -109,7 +120,6 @@
|
||||
"selectionToSubflow": "将选择部分更改为子流程",
|
||||
"flows": "流程",
|
||||
"add": "增加",
|
||||
"rename": "重命名",
|
||||
"delete": "删除",
|
||||
"keyboardShortcuts": "键盘快捷方式",
|
||||
"login": "登录",
|
||||
@@ -142,7 +152,12 @@
|
||||
"moveToBack": "置于底层",
|
||||
"moveToFront": "置于顶层",
|
||||
"moveBackwards": "向后移动",
|
||||
"moveForwards": "向前移动"
|
||||
"moveForwards": "向前移动",
|
||||
"showNodeHelp":"显示节点帮助",
|
||||
"enableSelectedNodes":"启用当前选中节点",
|
||||
"disableSelectedNodes":"禁用当前选中节点",
|
||||
"showSelectedNodeLabels":"显示选中的节点标签",
|
||||
"hideSelectedNodeLabels":"隐藏选中的节点标签"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
@@ -403,6 +418,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点",
|
||||
"acrossMultipleGroups": "无法跨多个组创建子流",
|
||||
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"
|
||||
}
|
||||
},
|
||||
@@ -491,12 +507,14 @@
|
||||
"unassigned": "未分配",
|
||||
"global": "全局",
|
||||
"workspace": "工作区",
|
||||
"editor": "编辑对话框",
|
||||
"selectAll": "选择所有节点",
|
||||
"selectNone": "取消所有选择",
|
||||
"selectAllConnected": "选择所有连接的节点",
|
||||
"addRemoveNode": "从选择中添加/删除节点",
|
||||
"editSelected": "编辑选定节点",
|
||||
"deleteSelected": "删除选定节点或链接",
|
||||
"deleteReconnect": "删除并重新连接",
|
||||
"importNode": "导入节点",
|
||||
"exportNode": "导出节点",
|
||||
"nudgeNode": "移动所选节点(1px)",
|
||||
@@ -571,6 +589,7 @@
|
||||
"editor": {
|
||||
"title": "面板管理",
|
||||
"palette": "控制板",
|
||||
"allCatalogs": "所有目录",
|
||||
"times": {
|
||||
"seconds": "秒前",
|
||||
"minutes": "分前",
|
||||
@@ -610,6 +629,7 @@
|
||||
"tab-nodes": "节点",
|
||||
"tab-install": "安装",
|
||||
"sort": "排序:",
|
||||
"sortRelevance": "关联",
|
||||
"sortAZ": "a-z顺序",
|
||||
"sortRecent": "日期顺序",
|
||||
"more": "增加 __count__ 个",
|
||||
@@ -683,7 +703,11 @@
|
||||
"empty": "空的",
|
||||
"globalConfig": "全局配置节点",
|
||||
"triggerAction": "触发动作",
|
||||
"find": "在工作区中查找"
|
||||
"find": "在工作区中查找",
|
||||
"copyItemUrl": "复制地址",
|
||||
"copyURL2Clipboard": "复制地址到剪贴板",
|
||||
"showFlow": "显示流程",
|
||||
"hideFlow": "隐藏流程"
|
||||
},
|
||||
"help": {
|
||||
"name": "帮助",
|
||||
@@ -984,7 +1008,10 @@
|
||||
"quote": "引用",
|
||||
"link": "链接",
|
||||
"horizontal-rule": "水平线",
|
||||
"toggle-preview": "切换预览"
|
||||
"toggle-preview": "切换预览",
|
||||
"mermaid": {
|
||||
"summary": "美人鱼图"
|
||||
}
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "Buffer 编辑器",
|
||||
@@ -1147,17 +1174,6 @@
|
||||
"create": "创建分支",
|
||||
"current": "当前的"
|
||||
},
|
||||
"languages": {
|
||||
"de": "德语",
|
||||
"en-US": "英文",
|
||||
"fr": "法语",
|
||||
"ja": "日语",
|
||||
"ko": "韩文",
|
||||
"pt-BR":"葡萄牙语",
|
||||
"ru":"俄語",
|
||||
"zh-CN": "简体中文",
|
||||
"zh-TW": "繁体中文"
|
||||
},
|
||||
"create-default-file-set": {
|
||||
"no-active": "没有活动项目就无法创建默认文件集",
|
||||
"no-empty": "无法在非空项目上创建默认文件集",
|
||||
@@ -1188,19 +1204,23 @@
|
||||
"title": "系统信息"
|
||||
},
|
||||
"languages": {
|
||||
"de": "德语-Deutsch",
|
||||
"en-US": "英文-English",
|
||||
"ja": "日语-日本",
|
||||
"ko": "韩文-한국인",
|
||||
"ru": "俄语-Русский",
|
||||
"de": "德语",
|
||||
"en-US": "英文",
|
||||
"fr": "法语",
|
||||
"ja": "日语",
|
||||
"ko": "韩文",
|
||||
"pt-BR":"葡萄牙语",
|
||||
"ru":"俄語",
|
||||
"zh-CN": "简体中文",
|
||||
"zh-TW": "繁體中文"
|
||||
"zh-TW": "繁体中文"
|
||||
},
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "无效的 JSON 数据: __error__",
|
||||
"invalid-expr": "无效的 JSONata 表达式: __error__",
|
||||
"invalid-prop": "无效的属性表达式",
|
||||
"invalid-num": "无效的数字",
|
||||
"invalid-num-prop": "__prop__: 无效的数字",
|
||||
"invalid-regexp": "输入格式无效",
|
||||
"invalid-regex-prop": "__prop__: 输入格式无效",
|
||||
"missing-required-prop": "__prop__: 缺少属性值",
|
||||
@@ -1210,9 +1230,15 @@
|
||||
}
|
||||
},
|
||||
"contextMenu": {
|
||||
"showActionList":"显示动作列表",
|
||||
"insert": "插入",
|
||||
"node": "节点",
|
||||
"junction": "连接点",
|
||||
"linkNodes": "链接节点"
|
||||
},
|
||||
"env-var": {
|
||||
"environment": "环境配置",
|
||||
"header": "全局环境变量",
|
||||
"revert": "重置"
|
||||
}
|
||||
}
|
||||
|
@@ -270,5 +270,9 @@
|
||||
"$moment": {
|
||||
"args": "[str]",
|
||||
"desc": "使用Moment库获取日期对象。"
|
||||
},
|
||||
"$clone": {
|
||||
"args": "value",
|
||||
"desc": "安全克隆对象."
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,11 @@
|
||||
"position": "位置",
|
||||
"enable": "啟用",
|
||||
"disable": "禁用",
|
||||
"upload": "上傳"
|
||||
"upload": "上傳",
|
||||
"lock": "鎖定",
|
||||
"unlock": "解鎖",
|
||||
"locked": "鎖定",
|
||||
"unlocked": "解鎖"
|
||||
},
|
||||
"type": {
|
||||
"string": "字符串",
|
||||
@@ -38,11 +42,14 @@
|
||||
}
|
||||
},
|
||||
"event": {
|
||||
"loadPlugins": "加載插件",
|
||||
"loadPalette": "加載控制板",
|
||||
"loadNodeCatalogs": "加載節點目錄",
|
||||
"loadNodes": "加載 __count__ 個節點",
|
||||
"loadFlows": "加載流程",
|
||||
"importFlows": "往工作區中加載流程"
|
||||
"importFlows": "往工作區中加載流程",
|
||||
"importError": "<p>加載流程錯誤</p><p>__message__</p>",
|
||||
"loadingProject": "加載項目"
|
||||
},
|
||||
"workspace": {
|
||||
"defaultName": "流程__number__",
|
||||
@@ -51,18 +58,35 @@
|
||||
"delete": "確定想要刪除 '__label__'?",
|
||||
"dropFlowHere": "把流程放到這裡",
|
||||
"addFlow": "新增流程",
|
||||
"listFlows": "流程列表",
|
||||
"addFlowToRight": "在右側新增流程",
|
||||
"hideFlow": "隱藏流程",
|
||||
"hideOtherFlows": "隱藏其它流程",
|
||||
"showAllFlows": "顯示所有流程",
|
||||
"hideAllFlows": "隱藏所有流程",
|
||||
"hiddenFlows": "列出 __count__ 個隱藏流程",
|
||||
"hiddenFlows_plural": "列出 __count__ 個隱藏流程",
|
||||
"showLastHiddenFlow": "顯示最後一個隱藏流程",
|
||||
" ": "流程列表",
|
||||
"listSubflows": "列出子流程",
|
||||
"status": "狀態",
|
||||
"enabled": "有效",
|
||||
"disabled": "無效",
|
||||
"info": "詳細描述",
|
||||
"selectNodes": "點擊節點用於選擇"
|
||||
"selectNodes": "點擊節點用於選擇",
|
||||
"enableFlow": "啟用流程",
|
||||
"disableFlow": "禁用流程",
|
||||
"lockFlow": "鎖定流程",
|
||||
"unlockFlow": "解除鎖定",
|
||||
"moveToStart": "移動到起始",
|
||||
"moveToEnd": "移動到末尾"
|
||||
},
|
||||
"menu": {
|
||||
"label": {
|
||||
"view": {
|
||||
"view": "顯示",
|
||||
"grid": "格線",
|
||||
"storeZoom": "加載時還原縮放尺寸",
|
||||
"storePosition": "加載時還原滾動位置",
|
||||
"showGrid": "顯示格線",
|
||||
"snapGrid": "對齊格線",
|
||||
"gridSize": "格線尺寸",
|
||||
@@ -80,12 +104,14 @@
|
||||
"palette": {
|
||||
"show": "顯示控制板"
|
||||
},
|
||||
"edit": "編輯",
|
||||
"settings": "設置",
|
||||
"userSettings": "使用者設置",
|
||||
"nodes": "節點",
|
||||
"displayStatus": "顯示節點狀態",
|
||||
"displayConfig": "修改節點配置",
|
||||
"import": "匯入",
|
||||
"importExample": "導入示例流程",
|
||||
"export": "匯出",
|
||||
"search": "搜尋流程",
|
||||
"searchInput": "搜尋流程",
|
||||
@@ -94,7 +120,6 @@
|
||||
"selectionToSubflow": "將選擇部分更改為子流程",
|
||||
"flows": "流程",
|
||||
"add": "增加",
|
||||
"rename": "重新命名",
|
||||
"delete": "刪除",
|
||||
"keyboardShortcuts": "鍵盤快速鍵",
|
||||
"login": "登入",
|
||||
@@ -102,24 +127,48 @@
|
||||
"editPalette": "節點管理",
|
||||
"other": "其他",
|
||||
"showTips": "顯示小提示",
|
||||
"help": "Node-RED website",
|
||||
"showWelcomeTours": "顯示新版本向導",
|
||||
"help": "Node-RED 文檔主頁",
|
||||
"projects": "專案",
|
||||
"projects-new": "新專案",
|
||||
"projects-open": "開啟專案",
|
||||
"projects-settings": "專案設定",
|
||||
"showNodeLabelDefault": "顯示新添加節點的標籤",
|
||||
"codeEditor": "代碼編輯器",
|
||||
"groups": "組",
|
||||
"groupSelection": "選擇組",
|
||||
"ungroupSelection": "取消選擇組",
|
||||
"groupMergeSelection": "合并選擇",
|
||||
"groupRemoveSelection": "從組中移除"
|
||||
"groupRemoveSelection": "從組中移除",
|
||||
"arrange": "布局",
|
||||
"alignLeft": "左對齊",
|
||||
"alignCenter": "居中對齊",
|
||||
"alignRight": "右對齊",
|
||||
"alignTop": "頂部對齊",
|
||||
"alignMiddle": "垂直居中對齊",
|
||||
"alignBottom": "底部對齊",
|
||||
"distributeHorizontally": "横向分布",
|
||||
"distributeVertically": "垂直分布",
|
||||
"moveToBack": "置於底層",
|
||||
"moveToFront": "置於頂層",
|
||||
"moveBackwards": "向後移動",
|
||||
"moveForwards": "向前移動",
|
||||
"showNodeHelp":"顯示節點幫助",
|
||||
"enableSelectedNodes":"啟用當前選中節點",
|
||||
"disableSelectedNodes":"禁用當前選中節點",
|
||||
"showSelectedNodeLabels":"顯示選中的節點標簽",
|
||||
"hideSelectedNodeLabels":"隱藏選中的節點標簽"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "切換導航器",
|
||||
"zoom-out": "縮小",
|
||||
"zoom-reset": "重置縮放",
|
||||
"zoom-in": "放大"
|
||||
"zoom-in": "放大",
|
||||
"search-flows": "搜索流程",
|
||||
"search-prev": "上一個",
|
||||
"search-next": "下一個",
|
||||
"search-counter": "\"__term__\" __result__ of __count__"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "作為 __name__ 登入",
|
||||
@@ -135,12 +184,17 @@
|
||||
}
|
||||
},
|
||||
"notification": {
|
||||
"state": {
|
||||
"flowsStopped": "流程已停止",
|
||||
"flowsStarted": "流程已啟動"
|
||||
},
|
||||
"warning": "<strong>警告</strong>: __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "節點中存在未部署的更改",
|
||||
"nodeActionDisabled": "節點動作在子流程中被禁用",
|
||||
"nodeActionDisabledSubflow": "子流程中禁用了節點操作",
|
||||
"missing-types": "流程由於缺少節點類型而停止。請檢查日誌的詳細資訊",
|
||||
"missing-modules": "<p>流程因缺少模塊而停止。</p>",
|
||||
"safe-mode": "<p>流程在安全模式下停止。</p><p>您可以修改流程並部署更改以重新啟動。</p>",
|
||||
"restartRequired": "Node-RED必須重新啟動,以啟用升級的模組",
|
||||
"credentials_load_failed": "<p>流程由於無法解密證書而停止。</p> <p>流程證書文件已加密,但是項目的加密密鑰丟失或無效。</p>",
|
||||
@@ -151,7 +205,7 @@
|
||||
"project_not_found": "<p>找不到項目的'__project__'</p>",
|
||||
"git_merge_conflict": "<p>自動合併更改失敗。</p><p>修復未合併的衝突,然後提交結果。</p>"
|
||||
},
|
||||
"error": "<strong>Error</strong>: __message__",
|
||||
"error": "<strong>錯誤</strong>: __message__",
|
||||
"errors": {
|
||||
"lostConnection": "丟失與伺服器的連接,重新連接...",
|
||||
"lostConnectionReconnect": "丟失與伺服器的連接,__time__ 秒後重新連接",
|
||||
@@ -208,6 +262,8 @@
|
||||
"download": "下載",
|
||||
"importUnrecognised": "匯入了無法識別的類型:",
|
||||
"importUnrecognised_plural": "匯入了無法識別的類型:",
|
||||
"importDuplicate": "導入了重復節點:",
|
||||
"importDuplicate_plural": "導入了重復節點:",
|
||||
"nodesExported": "節點匯出到了剪貼簿",
|
||||
"nodesImported": "已匯入:",
|
||||
"nodeCopied": "已複製 __count__ 個節點",
|
||||
@@ -259,6 +315,10 @@
|
||||
"modifiedFlowsDesc": "只部署包含已更改節點的流程",
|
||||
"modifiedNodes": "已更改的節點",
|
||||
"modifiedNodesDesc": "只部署已經更改的節點",
|
||||
"startFlows": "啟動",
|
||||
"startFlowsDesc": "啟動流程",
|
||||
"stopFlows": "停止",
|
||||
"stopFlowsDesc": "停止流程",
|
||||
"restartFlows": "重新啟動流程",
|
||||
"restartFlowsDesc": "重新啟動當前部署的流程",
|
||||
"successfulDeploy": "部署成功",
|
||||
@@ -337,14 +397,28 @@
|
||||
"output": "輸出:",
|
||||
"status": "狀態節點",
|
||||
"deleteSubflow": "刪除子流程",
|
||||
"confirmDelete": "您確定要刪除此子流程?",
|
||||
"info": "詳細描述",
|
||||
"category": "類別",
|
||||
"module": "模塊",
|
||||
"license": "許可",
|
||||
"licenseNone": "無",
|
||||
"licenseOther": "其它",
|
||||
"type": "節點類型",
|
||||
"version": "版本",
|
||||
"versionPlaceholder": "x.y.z",
|
||||
"keys": "關鍵字",
|
||||
"keysPlaceholder": "使用英文逗號分隔關鍵字",
|
||||
"author": "作者",
|
||||
"authorPlaceholder": "名字 <email@example.com>",
|
||||
"desc": "描述",
|
||||
"env": {
|
||||
"restore": "恢復為默認子流程",
|
||||
"remove": "類別刪除環境變量"
|
||||
},
|
||||
"errors": {
|
||||
"noNodesSelected": "<strong>無法創建子流程</strong>: 未選擇節點",
|
||||
"acrossMultipleGroups": "無法跨多個組創建子流",
|
||||
"multipleInputsToSelection": "<strong>無法創建子流程</strong>: 多個輸入到了選擇"
|
||||
}
|
||||
},
|
||||
@@ -367,12 +441,12 @@
|
||||
"editConfig": "編輯 __type__ 配置",
|
||||
"addNewType": "添加新的 __type__ 節點",
|
||||
"nodeProperties": "節點屬性",
|
||||
"label": "Label",
|
||||
"label": "標簽",
|
||||
"color": "顏色",
|
||||
"portLabels": "埠標籤",
|
||||
"labelInputs": "輸入",
|
||||
"labelOutputs": "輸出",
|
||||
"settingIcon": "Icon",
|
||||
"settingIcon": "圖標",
|
||||
"default": "默認",
|
||||
"noDefaultLabel": "無",
|
||||
"defaultLabel": "使用默認標籤",
|
||||
@@ -385,6 +459,7 @@
|
||||
"icon": "圖標",
|
||||
"inputType": "輸入類型",
|
||||
"selectType": "選擇類型...",
|
||||
"loadCredentials": "加載節點憑證",
|
||||
"inputs": {
|
||||
"input": "輸入",
|
||||
"select": "選擇",
|
||||
@@ -419,7 +494,8 @@
|
||||
},
|
||||
"errors": {
|
||||
"scopeChange": "更改範圍將使其他流程中的節點無法使用",
|
||||
"invalidProperties": "無效的屬性:"
|
||||
"invalidProperties": "無效的屬性:",
|
||||
"credentialLoadFailed": "無法加載節點憑據"
|
||||
}
|
||||
},
|
||||
"keyboard": {
|
||||
@@ -431,11 +507,14 @@
|
||||
"unassigned": "未分配",
|
||||
"global": "全局",
|
||||
"workspace": "工作區",
|
||||
"editor": "編輯對話框",
|
||||
"selectAll": "選擇所有節點",
|
||||
"selectNone": "取消所有選擇",
|
||||
"selectAllConnected": "選擇所有連接的節點",
|
||||
"addRemoveNode": "從選擇中添加/刪除節點",
|
||||
"editSelected": "編輯選定節點",
|
||||
"deleteSelected": "刪除選定節點或連結",
|
||||
"deleteReconnect": "刪除並重新連接",
|
||||
"importNode": "匯入節點",
|
||||
"exportNode": "匯出節點",
|
||||
"nudgeNode": "移動所選節點(1px)",
|
||||
@@ -445,10 +524,14 @@
|
||||
"copyNode": "複製所選節點",
|
||||
"cutNode": "剪切所選節點",
|
||||
"pasteNode": "粘貼節點",
|
||||
"copyGroupStyle": "復製組樣式",
|
||||
"pasteGroupStyle": "粘貼組樣式",
|
||||
"undoChange": "撤銷上次執行的更改",
|
||||
"redoChange": "重做",
|
||||
"searchBox": "打開搜尋框",
|
||||
"managePalette": "管理面板",
|
||||
"actionList": "動作列表"
|
||||
"actionList": "動作列表",
|
||||
"splitWireWithLinks": "使用Link節點拆分已選項"
|
||||
},
|
||||
"library": {
|
||||
"library": "庫",
|
||||
@@ -466,12 +549,11 @@
|
||||
"types": {
|
||||
"local": "本地",
|
||||
"examples": "例子"
|
||||
},
|
||||
"exportToLibrary": "將節點匯出到庫"
|
||||
}
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "無可用資訊",
|
||||
"filter": "過濾節點",
|
||||
"filter": "過濾已安裝模組",
|
||||
"search": "搜尋模組",
|
||||
"addCategory": "添加新的...",
|
||||
"label": {
|
||||
@@ -501,11 +583,13 @@
|
||||
"nodeEnabled_plural": "啟用多個節點:",
|
||||
"nodeDisabled": "禁用節點:",
|
||||
"nodeDisabled_plural": "禁用多個節點:",
|
||||
"nodeUpgraded": "節點模組__module__升級到__version__版本"
|
||||
"nodeUpgraded": "節點模組__module__升級到__version__版本",
|
||||
"unknownNodeRegistered": "加載節點錯誤: <ul><li>__type__<br>__error__</li></ul>"
|
||||
},
|
||||
"editor": {
|
||||
"title": "面板管理",
|
||||
"palette": "Palette",
|
||||
"palette": "控製板",
|
||||
"allCatalogs": "所有目錄",
|
||||
"times": {
|
||||
"seconds": "秒前",
|
||||
"minutes": "分前",
|
||||
@@ -545,10 +629,12 @@
|
||||
"tab-nodes": "節點",
|
||||
"tab-install": "安裝",
|
||||
"sort": "排序:",
|
||||
"sortRelevance": "關聯",
|
||||
"sortAZ": "a-z順序",
|
||||
"sortRecent": "日期順序",
|
||||
"more": "增加 __count__ 個",
|
||||
"upload": "上傳模塊tgz文件",
|
||||
"refresh": "更新模塊列表",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "無法載入節點目錄。<br>查看瀏覽器控制臺瞭解更多資訊",
|
||||
"installFailed": "無法安裝: __module__<br>__message__<br>查看日誌瞭解更多資訊",
|
||||
@@ -617,7 +703,11 @@
|
||||
"empty": "空的",
|
||||
"globalConfig": "全局配置節點",
|
||||
"triggerAction": "觸發動作",
|
||||
"find": "在工作區中查找"
|
||||
"find": "在工作區中查找",
|
||||
"copyItemUrl": "復製地址",
|
||||
"copyURL2Clipboard": "復製地址到剪貼板",
|
||||
"showFlow": "顯示流程",
|
||||
"hideFlow": "隱藏流程"
|
||||
},
|
||||
"help": {
|
||||
"name": "幫助",
|
||||
@@ -627,7 +717,8 @@
|
||||
"showHelp": "顯示幫助",
|
||||
"showInOutline": "在大綱中顯示",
|
||||
"showTopics": "顯示主題",
|
||||
"noHelp": "未選擇幫助主題"
|
||||
"noHelp": "未選擇幫助主題",
|
||||
"changeLog": "更新日誌"
|
||||
},
|
||||
"config": {
|
||||
"name": "配置節點",
|
||||
@@ -828,31 +919,37 @@
|
||||
"json": "JSON",
|
||||
"bin": "二進位流",
|
||||
"date": "時間戳記",
|
||||
"jsonata": "expression",
|
||||
"env": "env variable",
|
||||
"jsonata": "表達式",
|
||||
"env": "環境變量",
|
||||
"cred": "證書"
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
"add": "添加"
|
||||
"add": "添加",
|
||||
"addTitle": "添加項"
|
||||
},
|
||||
"search": {
|
||||
"empty": "找不到匹配",
|
||||
"history": "搜索歷史",
|
||||
"clear": "清除所有",
|
||||
"empty": "找不到匹配項",
|
||||
"addNode": "添加一個節點...",
|
||||
"options": {
|
||||
"configNodes": "配置節點",
|
||||
"unusedConfigNodes": "未使用的配置節點",
|
||||
"invalidNodes": "無效的節點",
|
||||
"uknownNodes": "未知的節點",
|
||||
"unusedSubflows": "未使用的子流程"
|
||||
"unusedSubflows": "未使用的子流程",
|
||||
"hiddenFlows": "隱藏的流程",
|
||||
"modifiedNodes": "已修改的節點或流程",
|
||||
"thisFlow": "當前流程"
|
||||
}
|
||||
},
|
||||
"expressionEditor": {
|
||||
"functions": "功能",
|
||||
"functionReference": "Function reference",
|
||||
"functionReference": "功能參考",
|
||||
"insert": "插入",
|
||||
"title": "JSONata運算式編輯器",
|
||||
"test": "Test",
|
||||
"test": "測試",
|
||||
"data": "示例消息",
|
||||
"result": "結果",
|
||||
"format": "格式表達方法",
|
||||
@@ -863,20 +960,28 @@
|
||||
"invalid-expr": "無效的JSONata運算式:\n __message__",
|
||||
"invalid-msg": "無效的示例JSON消息:\n __message__",
|
||||
"context-unsupported": "無法測試上下文函數\n $flowContext 或 $globalContext",
|
||||
"env-unsupported": "無法測試 $env 函數",
|
||||
"moment-unsupported": "無法測試 $moment 函數",
|
||||
"clone-unsupported": "無法測試 $clone 函數",
|
||||
"eval": "評估運算式錯誤:\n __message__"
|
||||
}
|
||||
},
|
||||
"monaco": {
|
||||
"setTheme": "設置主題"
|
||||
},
|
||||
"jsEditor": {
|
||||
"title": "JavaScript 編輯器"
|
||||
},
|
||||
"textEditor": {
|
||||
"title": "Text 編輯器"
|
||||
"title": "文本編輯器"
|
||||
},
|
||||
"jsonEditor": {
|
||||
"title": "JSON編輯器",
|
||||
"format": "格式化JSON",
|
||||
"rawMode": "編輯 JSON",
|
||||
"uiMode": "Visual編輯器",
|
||||
"uiMode": "可視化編輯器",
|
||||
"rawMode-readonly": "原始JSON",
|
||||
"uiMode-readonly": "可視化",
|
||||
"insertAbove": "在上方插入",
|
||||
"insertBelow": "在下方插入",
|
||||
"addItem": "添加項目",
|
||||
@@ -892,9 +997,9 @@
|
||||
"title": "Markdown 編輯器",
|
||||
"expand": "展開",
|
||||
"format": "F使用markdown格式化",
|
||||
"heading1": "Heading 1",
|
||||
"heading2": "Heading 2",
|
||||
"heading3": "Heading 3",
|
||||
"heading1": "標題 1",
|
||||
"heading2": "標題 2",
|
||||
"heading3": "標題 3",
|
||||
"bold": "粗體",
|
||||
"italic": "斜體",
|
||||
"code": "程式碼",
|
||||
@@ -903,7 +1008,10 @@
|
||||
"quote": "引用",
|
||||
"link": "連結",
|
||||
"horizontal-rule": "分隔線",
|
||||
"toggle-preview": "預覽"
|
||||
"toggle-preview": "切換預覽",
|
||||
"mermaid": {
|
||||
"summary": "美人魚圖"
|
||||
}
|
||||
},
|
||||
"bufferEditor": {
|
||||
"title": "緩衝區編輯器",
|
||||
@@ -1038,7 +1146,8 @@
|
||||
"not-git": "不是git倉庫",
|
||||
"no-resource": "找不到存儲庫",
|
||||
"cant-get-ssh-key-path": "錯誤! 無法獲取所選的SSH密鑰路徑。",
|
||||
"unexpected_error": "意外的錯誤"
|
||||
"unexpected_error": "意外的錯誤",
|
||||
"clearContext": "更改項目時清除上下文"
|
||||
},
|
||||
"delete": {
|
||||
"confirm": "您確定要刪除此項目嗎?"
|
||||
@@ -1068,7 +1177,7 @@
|
||||
"create-default-file-set": {
|
||||
"no-active": "沒有活動項目就無法創建默認文件集",
|
||||
"no-empty": "無法在非空項目上創建默認文件集",
|
||||
"git-error": "git error"
|
||||
"git-error": "git錯誤"
|
||||
},
|
||||
"errors": {
|
||||
"no-username-email": "您的Git客戶端未配置用戶名/電子郵件。",
|
||||
@@ -1079,11 +1188,20 @@
|
||||
"editor-tab": {
|
||||
"properties": "屬性",
|
||||
"envProperties": "環境變量",
|
||||
"module": "模塊屬性",
|
||||
"description": "描述",
|
||||
"appearance": "外觀",
|
||||
"preview": "UI預覽",
|
||||
"defaultValue": "默認值",
|
||||
"env": "環境變量"
|
||||
"defaultValue": "默認值"
|
||||
},
|
||||
"tourGuide": {
|
||||
"takeATour": "查看更新內容",
|
||||
"start": "開始",
|
||||
"next": "下一個",
|
||||
"welcomeTours": "歡迎使用 Node-RED"
|
||||
},
|
||||
"diagnostics": {
|
||||
"title": "系统信息"
|
||||
},
|
||||
"languages": {
|
||||
"de": "德語",
|
||||
@@ -1095,5 +1213,31 @@
|
||||
"ru":"俄語",
|
||||
"zh-CN": "簡體中文",
|
||||
"zh-TW": "繁體中文"
|
||||
},
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "無效的 JSON 數據: __error__",
|
||||
"invalid-expr": "無效的 JSONata 表達式: __error__",
|
||||
"invalid-prop": "無效的屬性表達式",
|
||||
"invalid-num": "無效的數字",
|
||||
"invalid-regexp": "輸入格式無效",
|
||||
"invalid-regex-prop": "__prop__: 輸入格式無效",
|
||||
"missing-required-prop": "__prop__: 缺少屬性值",
|
||||
"invalid-config": "__prop__: 無效的配置節點",
|
||||
"missing-config": "__prop__: 缺少配置節點",
|
||||
"validation-error": "__prop__: 驗證錯誤: __node__, __id__: __error__"
|
||||
}
|
||||
},
|
||||
"contextMenu": {
|
||||
"showActionList":"顯示動作列表",
|
||||
"insert": "插入",
|
||||
"node": "節點",
|
||||
"junction": "連接點",
|
||||
"linkNodes": "鏈接節點"
|
||||
},
|
||||
"env-var": {
|
||||
"environment": "環境配置",
|
||||
"header": "全局環境變量",
|
||||
"revert": "重置"
|
||||
}
|
||||
}
|
||||
|
@@ -270,5 +270,9 @@
|
||||
"$moment": {
|
||||
"args": "[str]",
|
||||
"desc": "使用Moment庫獲取日期對象。"
|
||||
},
|
||||
"$clone": {
|
||||
"args": "value",
|
||||
"desc": "安全克隆對象."
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -39,15 +39,16 @@
|
||||
console.warn(evt,args);
|
||||
}
|
||||
if (handlers[evt]) {
|
||||
for (var i=0;i<handlers[evt].length;i++) {
|
||||
let cpyHandlers = [...handlers[evt]];
|
||||
|
||||
for (var i=0;i<cpyHandlers.length;i++) {
|
||||
try {
|
||||
handlers[evt][i].apply(null, args);
|
||||
cpyHandlers[i].apply(null, args);
|
||||
} catch(err) {
|
||||
console.warn("RED.events.emit error: ["+evt+"] "+(err.toString()));
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
@@ -2198,6 +2198,12 @@ RED.nodes = (function() {
|
||||
}
|
||||
node._config.x = node.x;
|
||||
node._config.y = node.y;
|
||||
if (n.hasOwnProperty('w')) {
|
||||
node.w = n.w
|
||||
}
|
||||
if (n.hasOwnProperty('h')) {
|
||||
node.h = n.h
|
||||
}
|
||||
} else if (n.type.substring(0,7) === "subflow") {
|
||||
var parentId = n.type.split(":")[1];
|
||||
var subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
||||
|
@@ -498,6 +498,15 @@ var RED = (function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
} else if (notificationId === 'restart-required') {
|
||||
options.buttons = [
|
||||
{
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
if (!persistentNotifications.hasOwnProperty(notificationId)) {
|
||||
persistentNotifications[notificationId] = RED.notify(text,options);
|
||||
@@ -525,6 +534,10 @@ var RED = (function() {
|
||||
RED.view.redrawStatus(node);
|
||||
}
|
||||
});
|
||||
|
||||
let pendingNodeRemovedNotifications = []
|
||||
let pendingNodeRemovedTimeout
|
||||
|
||||
RED.comms.subscribe("notification/node/#",function(topic,msg) {
|
||||
var i,m;
|
||||
var typeList;
|
||||
@@ -562,8 +575,15 @@ var RED = (function() {
|
||||
m = msg[i];
|
||||
info = RED.nodes.removeNodeSet(m.id);
|
||||
if (info.added) {
|
||||
typeList = "<ul><li>"+m.types.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success");
|
||||
pendingNodeRemovedNotifications = pendingNodeRemovedNotifications.concat(m.types.map(RED.utils.sanitize))
|
||||
if (pendingNodeRemovedTimeout) {
|
||||
clearTimeout(pendingNodeRemovedTimeout)
|
||||
}
|
||||
pendingNodeRemovedTimeout = setTimeout(function () {
|
||||
typeList = "<ul><li>"+pendingNodeRemovedNotifications.join("</li><li>")+"</li></ul>";
|
||||
RED.notify(RED._("palette.event.nodeRemoved", {count:pendingNodeRemovedNotifications.length})+typeList,"success");
|
||||
pendingNodeRemovedNotifications = []
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
loadIconList();
|
||||
@@ -702,7 +722,7 @@ var RED = (function() {
|
||||
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:"core:show-config-tab"});
|
||||
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
|
||||
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:"core:add-flow"},
|
||||
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:"core:edit-flow"},
|
||||
{id:"menu-item-workspace-edit",label:RED._("menu.label.edit"),onselect:"core:edit-flow"},
|
||||
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:"core:remove-flow"}
|
||||
]});
|
||||
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
|
||||
|
@@ -182,7 +182,9 @@
|
||||
valueLabel: contextLabel
|
||||
},
|
||||
str: {value:"str",label:"string",icon:"red/images/typedInput/az.svg"},
|
||||
num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate:/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/},
|
||||
num: {value:"num",label:"number",icon:"red/images/typedInput/09.svg",validate: function(v) {
|
||||
return (true === RED.utils.validateTypedProperty(v, "num"));
|
||||
} },
|
||||
bool: {value:"bool",label:"boolean",icon:"red/images/typedInput/bool.svg",options:["true","false"]},
|
||||
json: {
|
||||
value:"json",
|
||||
|
@@ -30,8 +30,26 @@ RED.contextMenu = (function () {
|
||||
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
|
||||
let hasGroup, isAllGroups = true, hasDisabledNode, hasEnabledNode, hasLabeledNode, hasUnlabeledNode;
|
||||
if (hasSelection) {
|
||||
selection.nodes.forEach(n => {
|
||||
if (n.type === 'group') {
|
||||
hasGroup = true;
|
||||
} else {
|
||||
isAllGroups = false;
|
||||
}
|
||||
if (n.d) {
|
||||
hasDisabledNode = true;
|
||||
} else {
|
||||
hasEnabledNode = true;
|
||||
}
|
||||
if (n.l === undefined || n.l) {
|
||||
hasLabeledNode = true;
|
||||
} else {
|
||||
hasUnlabeledNode = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
const offset = $("#red-ui-workspace-chart").offset()
|
||||
|
||||
let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()
|
||||
@@ -44,7 +62,7 @@ RED.contextMenu = (function () {
|
||||
}
|
||||
|
||||
menuItems.push(
|
||||
{ onselect: 'core:show-action-list', onpostselect: function () { } }
|
||||
{ onselect: 'core:show-action-list', label: RED._("contextMenu.showActionList"), onpostselect: function () { } }
|
||||
)
|
||||
|
||||
const insertOptions = []
|
||||
@@ -55,7 +73,7 @@ RED.contextMenu = (function () {
|
||||
onselect: function () {
|
||||
RED.view.showQuickAddDialog({
|
||||
position: [addX, addY],
|
||||
touchTrigger: true,
|
||||
touchTrigger: 'ontouchstart' in window,
|
||||
splice: isSingleLink ? selection.links[0] : undefined,
|
||||
// spliceMultiple: isMultipleLinks
|
||||
})
|
||||
@@ -108,16 +126,16 @@ RED.contextMenu = (function () {
|
||||
const nodeOptions = []
|
||||
if (!hasMultipleSelection && !isGroup) {
|
||||
nodeOptions.push(
|
||||
{ onselect: 'core:show-node-help' },
|
||||
{ onselect: 'core:show-node-help', label: RED._('menu.label.showNodeHelp') },
|
||||
null
|
||||
)
|
||||
}
|
||||
nodeOptions.push(
|
||||
{ onselect: 'core:enable-selected-nodes' },
|
||||
{ onselect: 'core:disable-selected-nodes' },
|
||||
{ onselect: 'core:enable-selected-nodes', label: RED._('menu.label.enableSelectedNodes'), disabled: !hasDisabledNode },
|
||||
{ onselect: 'core:disable-selected-nodes', label: RED._('menu.label.disableSelectedNodes'), disabled: !hasEnabledNode },
|
||||
null,
|
||||
{ onselect: 'core:show-selected-node-labels' },
|
||||
{ onselect: 'core:hide-selected-node-labels' }
|
||||
{ onselect: 'core:show-selected-node-labels', label: RED._('menu.label.showSelectedNodeLabels'), disabled: !hasUnlabeledNode },
|
||||
{ onselect: 'core:hide-selected-node-labels', label: RED._('menu.label.hideSelectedNodeLabels'), disabled: !hasLabeledNode }
|
||||
)
|
||||
menuItems.push({
|
||||
label: RED._('sidebar.info.node'),
|
||||
@@ -126,8 +144,8 @@ RED.contextMenu = (function () {
|
||||
menuItems.push({
|
||||
label: RED._('sidebar.info.group'),
|
||||
options: [
|
||||
{ onselect: 'core:group-selection' },
|
||||
{ onselect: 'core:ungroup-selection', disabled: !hasGroup },
|
||||
{ onselect: 'core:group-selection', label: RED._("menu.label.groupSelection") },
|
||||
{ onselect: 'core:ungroup-selection', label: RED._("menu.label.ungroupSelection"), disabled: !hasGroup },
|
||||
]
|
||||
})
|
||||
if (hasGroup) {
|
||||
@@ -143,8 +161,8 @@ RED.contextMenu = (function () {
|
||||
}
|
||||
menuItems[menuItems.length - 1].options.push(
|
||||
null,
|
||||
{ onselect: 'core:copy-group-style', disabled: !hasGroup },
|
||||
{ onselect: 'core:paste-group-style', disabled: !hasGroup}
|
||||
{ onselect: 'core:copy-group-style', label: RED._("keyboard.copyGroupStyle"), disabled: !hasGroup },
|
||||
{ onselect: 'core:paste-group-style', label: RED._("keyboard.pasteGroupStyle"), disabled: !hasGroup}
|
||||
)
|
||||
}
|
||||
if (canEdit && hasMultipleSelection) {
|
||||
@@ -174,7 +192,7 @@ RED.contextMenu = (function () {
|
||||
{ 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', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete },
|
||||
{ onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete },
|
||||
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
|
||||
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") },
|
||||
|
@@ -182,6 +182,17 @@ RED.editor = (function() {
|
||||
error: err.message
|
||||
});
|
||||
}
|
||||
} else if (valid) {
|
||||
// If the validator is not provided in node property => Check if the input has a validator
|
||||
if ("category" in node._def) {
|
||||
const isConfig = node._def.category === "config";
|
||||
const prefix = isConfig ? "node-config-input" : "node-input";
|
||||
const input = $("#"+prefix+"-"+property);
|
||||
const isTypedInput = input.length > 0 && input.next(".red-ui-typedInput-container").length > 0;
|
||||
if (isTypedInput) {
|
||||
valid = input.typedInput("validate");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid && definition[property].type && RED.nodes.getType(definition[property].type) && !("validate" in definition[property])) {
|
||||
if (!value || value == "_ADD_") {
|
||||
|
@@ -121,7 +121,7 @@
|
||||
var i=0,l=bufferBinValue.length;
|
||||
var c = 0;
|
||||
for(i=0;i<l;i++) {
|
||||
var d = parseInt(bufferBinValue[i]);
|
||||
var d = parseInt(Number(bufferBinValue[i]));
|
||||
if (!isString && (isNaN(d) || d < 0 || d > 255)) {
|
||||
valid = false;
|
||||
break;
|
||||
|
@@ -966,12 +966,10 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
|
||||
//Unbind ctrl-Enter (default action is to insert a newline in editor) This permits the shortcut to close the tray.
|
||||
try {
|
||||
ed._standaloneKeybindingService.addDynamicKeybinding(
|
||||
'-editor.action.insertLineAfter', // command ID prefixed by '-'
|
||||
null, // keybinding
|
||||
() => {} // need to pass an empty handler
|
||||
);
|
||||
} catch (error) { }
|
||||
monaco.editor.addKeybindingRule({keybinding: 0, command: "-editor.action.insertLineAfter"});
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
|
||||
ed.nodered = {
|
||||
refreshModuleLibs: refreshModuleLibs //expose this for function node externalModules refresh
|
||||
|
@@ -15,7 +15,8 @@ RED.editor.mermaid = (function () {
|
||||
'vendor/mermaid/mermaid.min.js',
|
||||
function (data, stat, jqxhr) {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false
|
||||
startOnLoad: false,
|
||||
theme: RED.settings.get('mermaid', {}).theme
|
||||
})
|
||||
loaded = true
|
||||
while(pendingEvals.length > 0) {
|
||||
|
@@ -71,7 +71,7 @@ RED.envVar = (function() {
|
||||
};
|
||||
if (item.name.trim() !== "") {
|
||||
new_env.push(item);
|
||||
if ((item.type === "cred") && (item.value !== "__PWRD__")) {
|
||||
if (item.type === "cred") {
|
||||
credentials.map[item.name] = item.value;
|
||||
credentials.map["has_"+item.name] = (item.value !== "");
|
||||
item.value = "__PWRD__";
|
||||
|
@@ -484,7 +484,7 @@ RED.palette = (function() {
|
||||
var currentLabel = paletteNode.attr("data-palette-label");
|
||||
var currentInfo = paletteNode.attr("data-palette-info");
|
||||
|
||||
if (currentLabel !== sf.name || currentInfo !== sf.info) {
|
||||
if (currentLabel !== sf.name || currentInfo !== sf.info || sf.in.length > 0 || sf.out.length > 0) {
|
||||
paletteNode.attr("data-palette-info",sf.info);
|
||||
setLabel(sf.type+":"+sf.id,paletteNode,sf.name,RED.utils.renderMarkdown(sf.info||""));
|
||||
}
|
||||
|
@@ -647,9 +647,9 @@ RED.sidebar.versionControl = (function() {
|
||||
$.getJSON("projects/"+activeProject.name+"/commits/"+entry.sha,function(result) {
|
||||
result.project = activeProject;
|
||||
result.parents = entry.parents;
|
||||
result.oldRev = entry.sha+"~1";
|
||||
result.oldRev = entry.parents[0].length !== 0 ? entry.sha+"~1" : entry.sha;
|
||||
result.newRev = entry.sha;
|
||||
result.oldRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7)+"~1";
|
||||
result.oldRevTitle = entry.parents[0].length !== 0 ? RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7)+"~1" : " ";
|
||||
result.newRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7);
|
||||
result.date = humanizeSinceDate(parseInt(entry.date));
|
||||
RED.diff.showCommitDiff(result);
|
||||
|
@@ -186,8 +186,15 @@ RED.typeSearch = (function() {
|
||||
var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv);
|
||||
RED.utils.createIconElement(icon_url, iconContainer, false);
|
||||
|
||||
|
||||
if (!/^_action_:/.test(object.type) && object.type !== "junction") {
|
||||
if (/^subflow:/.test(object.type)) {
|
||||
var sf = RED.nodes.subflow(object.type.substring(8));
|
||||
if (sf.in.length > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
||||
}
|
||||
if (sf.out.length > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port red-ui-search-result-node-output"}).appendTo(nodeDiv);
|
||||
}
|
||||
} else if (!/^_action_:/.test(object.type) && object.type !== "junction") {
|
||||
if (def.inputs > 0) {
|
||||
$('<div/>',{class:"red-ui-search-result-node-port"}).appendTo(nodeDiv);
|
||||
}
|
||||
@@ -323,7 +330,7 @@ RED.typeSearch = (function() {
|
||||
}
|
||||
}
|
||||
function applyFilter(filter,type,def) {
|
||||
return !filter ||
|
||||
return !def || !filter ||
|
||||
(
|
||||
(!filter.spliceMultiple) &&
|
||||
(!filter.type || type === filter.type) &&
|
||||
|
@@ -921,7 +921,7 @@ RED.utils = (function() {
|
||||
error = RED._("validator.errors.invalid-prop")
|
||||
}
|
||||
} else if (propertyType === 'num') {
|
||||
if (!/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(propertyValue)) {
|
||||
if (!/^NaN$|^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$|^[+-]?(0b|0B)[01]+$|^[+-]?(0o|0O)[0-7]+$|^[+-]?(0x|0X)[0-9a-fA-F]+$/.test(propertyValue)) {
|
||||
error = RED._("validator.errors.invalid-num")
|
||||
}
|
||||
} else if (propertyType === 'jsonata') {
|
||||
|
@@ -4187,7 +4187,7 @@ RED.view = (function() {
|
||||
nodeEl.__statusGroup__.style.display = "none";
|
||||
} else {
|
||||
nodeEl.__statusGroup__.style.display = "inline";
|
||||
let backgroundWidth = 12
|
||||
let backgroundWidth = 15
|
||||
var fill = status_colours[d.status.fill]; // Only allow our colours for now
|
||||
if (d.status.shape == null && fill == null) {
|
||||
backgroundWidth = 0
|
||||
@@ -4207,7 +4207,11 @@ RED.view = (function() {
|
||||
nodeEl.__statusLabel__.textContent = "";
|
||||
}
|
||||
const textSize = nodeEl.__statusLabel__.getBBox()
|
||||
nodeEl.__statusBackground__.setAttribute('width', backgroundWidth + textSize.width + 6)
|
||||
backgroundWidth += textSize.width
|
||||
if (backgroundWidth > 0 && textSize.width > 0) {
|
||||
backgroundWidth += 6
|
||||
}
|
||||
nodeEl.__statusBackground__.setAttribute('width', backgroundWidth)
|
||||
}
|
||||
delete d.dirtyStatus;
|
||||
}
|
||||
@@ -4619,8 +4623,8 @@ RED.view = (function() {
|
||||
statusBackground.setAttribute("y",-1);
|
||||
statusBackground.setAttribute("width",200);
|
||||
statusBackground.setAttribute("height",13);
|
||||
statusBackground.setAttribute("rx",1);
|
||||
statusBackground.setAttribute("ry",1);
|
||||
statusBackground.setAttribute("rx",2);
|
||||
statusBackground.setAttribute("ry",2);
|
||||
|
||||
statusEl.appendChild(statusBackground);
|
||||
node[0][0].__statusBackground__ = statusBackground;
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
RED.workspaces = (function() {
|
||||
|
||||
const documentTitle = document.title;
|
||||
|
||||
var activeWorkspace = 0;
|
||||
var workspaceIndex = 0;
|
||||
|
||||
@@ -339,12 +341,18 @@ RED.workspaces = (function() {
|
||||
$("#red-ui-workspace-chart").show();
|
||||
activeWorkspace = tab.id;
|
||||
window.location.hash = 'flow/'+tab.id;
|
||||
if (tab.label) {
|
||||
document.title = `${documentTitle} : ${tab.label}`
|
||||
} else {
|
||||
document.title = documentTitle
|
||||
}
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-disabled", !!tab.disabled);
|
||||
$("#red-ui-workspace").toggleClass("red-ui-workspace-locked", !!tab.locked);
|
||||
} else {
|
||||
$("#red-ui-workspace-chart").hide();
|
||||
activeWorkspace = 0;
|
||||
window.location.hash = '';
|
||||
document.title = documentTitle
|
||||
}
|
||||
event.workspace = activeWorkspace;
|
||||
RED.events.emit("workspace:change",event);
|
||||
|
@@ -40,9 +40,25 @@ RED.validators = {
|
||||
return opt ? RED._("validator.errors.invalid-regexp") : false;
|
||||
};
|
||||
},
|
||||
typedInput: function(ptypeName,isConfig,mopt) {
|
||||
typedInput: function(ptypeName, isConfig, mopt) {
|
||||
let options = ptypeName
|
||||
if (typeof ptypeName === 'string' ) {
|
||||
options = {}
|
||||
options.typeField = ptypeName
|
||||
options.isConfig = isConfig
|
||||
options.allowBlank = false
|
||||
}
|
||||
return function(v, opt) {
|
||||
var ptype = $("#node-"+(isConfig?"config-":"")+"input-"+ptypeName).val() || this[ptypeName];
|
||||
let ptype = options.type
|
||||
if (!ptype && options.typeField) {
|
||||
ptype = $("#node-"+(options.isConfig?"config-":"")+"input-"+options.typeField).val() || this[options.typeField];
|
||||
}
|
||||
if (options.allowBlank && v === '') {
|
||||
return true
|
||||
}
|
||||
if (options.allowUndefined && v === undefined) {
|
||||
return true
|
||||
}
|
||||
const result = RED.utils.validateTypedProperty(v, ptype, opt)
|
||||
if (result === true || opt) {
|
||||
// Valid, or opt provided - return result as-is
|
||||
|
@@ -114,6 +114,7 @@
|
||||
pointer-events: stroke;
|
||||
}
|
||||
.red-ui-flow-group-outline-select {
|
||||
cursor: move;
|
||||
fill: none;
|
||||
stroke: var(--red-ui-node-selected-color);
|
||||
pointer-events: none;
|
||||
|
@@ -24,24 +24,24 @@
|
||||
<title>{{ page.title }}</title>
|
||||
<link rel="icon" type="image/png" href="{{ page.favicon }}">
|
||||
<link rel="mask-icon" href="{{ page.tabicon.icon }}" color="{{ page.tabicon.colour }}">
|
||||
<link rel="stylesheet" href="vendor/jquery/css/base/jquery-ui.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="red/style.min.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="vendor/jquery/css/base/jquery-ui.min.css?v={{ cacheBuster }}">
|
||||
<link rel="stylesheet" href="vendor/font-awesome/css/font-awesome.min.css?v={{ cacheBuster }}">
|
||||
<link rel="stylesheet" href="red/style.min.css?v={{ cacheBuster }}">
|
||||
{{#page.css}}
|
||||
<link rel="stylesheet" href="{{.}}">
|
||||
{{/page.css}}
|
||||
{{#asset.vendorMonaco}}
|
||||
<link rel="stylesheet" href="vendor/monaco/style.css?v={{ page.version }}">
|
||||
<link rel="stylesheet" href="vendor/monaco/style.css?v={{ cacheBuster }}">
|
||||
{{/asset.vendorMonaco}}
|
||||
</head>
|
||||
<body spellcheck="false">
|
||||
<div id="red-ui-editor"></div>
|
||||
<script src="vendor/vendor.js?v={{ page.version }}"></script>
|
||||
<script src="vendor/vendor.js?v={{ cacheBuster }}"></script>
|
||||
{{#asset.vendorMonaco}}
|
||||
<script src="{{ asset.vendorMonaco }}?v={{ page.version }}"></script>
|
||||
<script src="{{ asset.vendorMonaco }}?v={{ cacheBuster }}"></script>
|
||||
{{/asset.vendorMonaco}}
|
||||
<script src="{{ asset.red }}?v={{ page.version }}"></script>
|
||||
<script src="{{ asset.main }}?v={{ page.version }}"></script>
|
||||
<script src="{{ asset.red }}?v={{ cacheBuster }}"></script>
|
||||
<script src="{{ asset.main }}?v={{ cacheBuster }}"></script>
|
||||
{{# page.scripts }}
|
||||
<script src="{{.}}"></script>
|
||||
{{/ page.scripts }}
|
||||
|
@@ -320,7 +320,7 @@
|
||||
}
|
||||
// but replace with repeat one if set to repeat
|
||||
if ((this.repeat && this.repeat != 0) || this.crontab) {
|
||||
suffix = " ↻";
|
||||
suffix = "\t↻";
|
||||
}
|
||||
if (this.name) {
|
||||
return this.name+suffix;
|
||||
|
@@ -109,9 +109,8 @@ module.exports = function(RED) {
|
||||
}
|
||||
const p = props.shift()
|
||||
const property = p.p;
|
||||
const value = p.v ? p.v : '';
|
||||
const valueType = p.vt ? p.vt : 'str';
|
||||
|
||||
const value = p.v !== undefined ? p.v : '';
|
||||
const valueType = p.vt !== undefined ? p.vt : 'str';
|
||||
if (property) {
|
||||
if (valueType === "jsonata") {
|
||||
if (p.v) {
|
||||
|
@@ -86,7 +86,7 @@
|
||||
},
|
||||
label: function() {
|
||||
var suffix = "";
|
||||
if (this.console === true || this.console === "true") { suffix = " ⇲"; }
|
||||
if (this.console === true || this.console === "true") { suffix = "\t⇲"; }
|
||||
if (this.targetType === "jsonata") {
|
||||
return (this.name || "JSONata") + suffix;
|
||||
}
|
||||
@@ -195,6 +195,119 @@
|
||||
node.dirty = true;
|
||||
});
|
||||
RED.view.redraw();
|
||||
},
|
||||
requestDebugNodeList: function(filteredNodes) {
|
||||
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
||||
var workspaceOrderMap = {};
|
||||
workspaceOrder.forEach(function(ws,i) {
|
||||
workspaceOrderMap[ws] = i;
|
||||
});
|
||||
|
||||
var candidateNodes = [];
|
||||
var candidateSFs = [];
|
||||
var subflows = {};
|
||||
RED.nodes.eachNode(function (n) {
|
||||
var nt = n.type;
|
||||
if (nt === "debug") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateNodes.push(n);
|
||||
}
|
||||
else {
|
||||
var sf = RED.nodes.subflow(n.z);
|
||||
if (sf) {
|
||||
subflows[sf.id] = {
|
||||
debug: true,
|
||||
subflows: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nt.substring(0, 8) === "subflow:") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateSFs.push(n);
|
||||
}
|
||||
else {
|
||||
var psf = RED.nodes.subflow(n.z);
|
||||
if (psf) {
|
||||
var sid = nt.substring(8);
|
||||
var item = subflows[psf.id];
|
||||
if (!item) {
|
||||
item = {
|
||||
debug: undefined,
|
||||
subflows: {}
|
||||
};
|
||||
subflows[psf.id] = item;
|
||||
}
|
||||
item.subflows[sid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
candidateSFs.forEach(function (sf) {
|
||||
var sid = sf.type.substring(8);
|
||||
if (containsDebug(sid, subflows)) {
|
||||
candidateNodes.push(sf);
|
||||
}
|
||||
});
|
||||
|
||||
candidateNodes.sort(function(A,B) {
|
||||
var wsA = workspaceOrderMap[A.z];
|
||||
var wsB = workspaceOrderMap[B.z];
|
||||
if (wsA !== wsB) {
|
||||
return wsA-wsB;
|
||||
}
|
||||
var labelA = RED.utils.getNodeLabel(A,A.id);
|
||||
var labelB = RED.utils.getNodeLabel(B,B.id);
|
||||
return labelA.localeCompare(labelB);
|
||||
});
|
||||
var currentWs = null;
|
||||
var data = [];
|
||||
var currentFlow;
|
||||
var currentSelectedCount = 0;
|
||||
candidateNodes.forEach(function(node) {
|
||||
if (currentWs !== node.z) {
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
currentSelectedCount = 0;
|
||||
currentWs = node.z;
|
||||
var parent = RED.nodes.workspace(currentWs) || RED.nodes.subflow(currentWs);
|
||||
currentFlow = {
|
||||
label: RED.utils.getNodeLabel(parent, currentWs),
|
||||
}
|
||||
if (!parent.disabled) {
|
||||
currentFlow.children = [];
|
||||
currentFlow.checkbox = true;
|
||||
} else {
|
||||
currentFlow.class = "disabled"
|
||||
}
|
||||
data.push(currentFlow);
|
||||
}
|
||||
if (currentFlow.children) {
|
||||
if (!filteredNodes[node.id]) {
|
||||
currentSelectedCount++;
|
||||
}
|
||||
currentFlow.children.push({
|
||||
label: RED.utils.getNodeLabel(node,node.id),
|
||||
node: {
|
||||
id: node.id
|
||||
},
|
||||
checkbox: true,
|
||||
selected: !filteredNodes[node.id]
|
||||
});
|
||||
}
|
||||
});
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
if (subWindow) {
|
||||
try {
|
||||
subWindow.postMessage({event:"refreshDebugNodeList", nodes:data},"*");
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
RED.debug.refreshDebugNodeList(data)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -396,6 +509,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
function containsDebug(sid, map) {
|
||||
var item = map[sid];
|
||||
if (item) {
|
||||
if (item.debug === undefined) {
|
||||
var sfs = Object.keys(item.subflows);
|
||||
var contain = false;
|
||||
for (var i = 0; i < sfs.length; i++) {
|
||||
var sf = sfs[i];
|
||||
if (containsDebug(sf, map)) {
|
||||
contain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item.debug = contain;
|
||||
}
|
||||
return item.debug;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$("#red-ui-sidebar-debug-open").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
subWindow = window.open(document.location.toString().replace(/[?#].*$/,"")+"debug/view/view.html"+document.location.search,"nodeREDDebugView","menubar=no,location=no,toolbar=no,chrome,height=500,width=600");
|
||||
@@ -427,6 +560,8 @@
|
||||
options.messageSourceClick(msg.id,msg._alias,msg.path);
|
||||
} else if (msg.event === "clear") {
|
||||
options.clear();
|
||||
} else if (msg.event === "requestDebugNodeList") {
|
||||
options.requestDebugNodeList(msg.filteredNodes)
|
||||
}
|
||||
};
|
||||
window.addEventListener('message',this.handleWindowMessage);
|
||||
|
@@ -167,19 +167,13 @@ RED.debug = (function() {
|
||||
var menu = RED.popover.menu({
|
||||
options: options,
|
||||
onselect: function(item) {
|
||||
if (item.value !== filterType) {
|
||||
filterType = item.value;
|
||||
$('#red-ui-sidebar-debug-filter span').text(RED._('node-red:debug.sidebar.'+filterType));
|
||||
refreshMessageList();
|
||||
RED.settings.set("debug.filter",filterType)
|
||||
}
|
||||
setFilterType(item.value)
|
||||
if (filterType === 'filterSelected') {
|
||||
refreshDebugNodeList();
|
||||
config.requestDebugNodeList(filteredNodes);
|
||||
filterDialog.slideDown(200);
|
||||
filterDialogShown = true;
|
||||
debugNodeTreeList.focus();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
menu.show({
|
||||
@@ -254,131 +248,7 @@ RED.debug = (function() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function containsDebug(sid, map) {
|
||||
var item = map[sid];
|
||||
if (item) {
|
||||
if (item.debug === undefined) {
|
||||
var sfs = Object.keys(item.subflows);
|
||||
var contain = false;
|
||||
for (var i = 0; i < sfs.length; i++) {
|
||||
var sf = sfs[i];
|
||||
if (containsDebug(sf, map)) {
|
||||
contain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item.debug = contain;
|
||||
}
|
||||
return item.debug;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function refreshDebugNodeList() {
|
||||
var workspaceOrder = RED.nodes.getWorkspaceOrder();
|
||||
var workspaceOrderMap = {};
|
||||
workspaceOrder.forEach(function(ws,i) {
|
||||
workspaceOrderMap[ws] = i;
|
||||
});
|
||||
|
||||
var candidateNodes = [];
|
||||
var candidateSFs = [];
|
||||
var subflows = {};
|
||||
RED.nodes.eachNode(function (n) {
|
||||
var nt = n.type;
|
||||
if (nt === "debug") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateNodes.push(n);
|
||||
}
|
||||
else {
|
||||
var sf = RED.nodes.subflow(n.z);
|
||||
if (sf) {
|
||||
subflows[sf.id] = {
|
||||
debug: true,
|
||||
subflows: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(nt.substring(0, 8) === "subflow:") {
|
||||
if (n.z in workspaceOrderMap) {
|
||||
candidateSFs.push(n);
|
||||
}
|
||||
else {
|
||||
var psf = RED.nodes.subflow(n.z);
|
||||
if (psf) {
|
||||
var sid = nt.substring(8);
|
||||
var item = subflows[psf.id];
|
||||
if (!item) {
|
||||
item = {
|
||||
debug: undefined,
|
||||
subflows: {}
|
||||
};
|
||||
subflows[psf.id] = item;
|
||||
}
|
||||
item.subflows[sid] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
candidateSFs.forEach(function (sf) {
|
||||
var sid = sf.type.substring(8);
|
||||
if (containsDebug(sid, subflows)) {
|
||||
candidateNodes.push(sf);
|
||||
}
|
||||
});
|
||||
|
||||
candidateNodes.sort(function(A,B) {
|
||||
var wsA = workspaceOrderMap[A.z];
|
||||
var wsB = workspaceOrderMap[B.z];
|
||||
if (wsA !== wsB) {
|
||||
return wsA-wsB;
|
||||
}
|
||||
var labelA = RED.utils.getNodeLabel(A,A.id);
|
||||
var labelB = RED.utils.getNodeLabel(B,B.id);
|
||||
return labelA.localeCompare(labelB);
|
||||
});
|
||||
var currentWs = null;
|
||||
var data = [];
|
||||
var currentFlow;
|
||||
var currentSelectedCount = 0;
|
||||
candidateNodes.forEach(function(node) {
|
||||
if (currentWs !== node.z) {
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
currentSelectedCount = 0;
|
||||
currentWs = node.z;
|
||||
var parent = RED.nodes.workspace(currentWs) || RED.nodes.subflow(currentWs);
|
||||
currentFlow = {
|
||||
label: RED.utils.getNodeLabel(parent, currentWs),
|
||||
}
|
||||
if (!parent.disabled) {
|
||||
currentFlow.children = [];
|
||||
currentFlow.checkbox = true;
|
||||
} else {
|
||||
currentFlow.class = "disabled"
|
||||
}
|
||||
data.push(currentFlow);
|
||||
}
|
||||
if (currentFlow.children) {
|
||||
if (!filteredNodes[node.id]) {
|
||||
currentSelectedCount++;
|
||||
}
|
||||
currentFlow.children.push({
|
||||
label: RED.utils.getNodeLabel(node,node.id),
|
||||
node: node,
|
||||
checkbox: true,
|
||||
selected: !filteredNodes[node.id]
|
||||
});
|
||||
}
|
||||
});
|
||||
if (currentFlow && currentFlow.checkbox) {
|
||||
currentFlow.selected = currentSelectedCount === currentFlow.children.length
|
||||
}
|
||||
|
||||
function refreshDebugNodeList(data) {
|
||||
debugNodeTreeList.treeList("data", data);
|
||||
}
|
||||
|
||||
@@ -401,7 +271,7 @@ RED.debug = (function() {
|
||||
},200);
|
||||
}
|
||||
function _refreshMessageList(_activeWorkspace) {
|
||||
if (_activeWorkspace) {
|
||||
if (typeof _activeWorkspace === 'string') {
|
||||
activeWorkspace = _activeWorkspace.replace(/\./g,"_");
|
||||
}
|
||||
if (filterType === "filterAll") {
|
||||
@@ -479,12 +349,12 @@ RED.debug = (function() {
|
||||
filteredNodes[n.id] = true;
|
||||
});
|
||||
delete filteredNodes[sourceId];
|
||||
$("#red-ui-sidebar-debug-filterSelected").trigger("click");
|
||||
RED.settings.set('debug.filteredNodes',Object.keys(filteredNodes))
|
||||
setFilterType('filterSelected')
|
||||
refreshMessageList();
|
||||
}},
|
||||
{id:"red-ui-debug-msg-menu-item-clear-filter",label:RED._("node-red:debug.messageMenu.clearFilter"),onselect:function(){
|
||||
$("#red-ui-sidebar-debug-filterAll").trigger("click");
|
||||
clearFilterSettings()
|
||||
refreshMessageList();
|
||||
}}
|
||||
);
|
||||
@@ -713,9 +583,17 @@ RED.debug = (function() {
|
||||
if (!!clearFilter) {
|
||||
clearFilterSettings();
|
||||
}
|
||||
refreshDebugNodeList();
|
||||
config.requestDebugNodeList(filteredNodes);
|
||||
}
|
||||
|
||||
function setFilterType(type) {
|
||||
if (type !== filterType) {
|
||||
filterType = type;
|
||||
$('#red-ui-sidebar-debug-filter span').text(RED._('node-red:debug.sidebar.'+filterType));
|
||||
refreshMessageList();
|
||||
RED.settings.set("debug.filter",filterType)
|
||||
}
|
||||
}
|
||||
function clearFilterSettings() {
|
||||
filteredNodes = {};
|
||||
filterType = 'filterAll';
|
||||
@@ -728,6 +606,7 @@ RED.debug = (function() {
|
||||
init: init,
|
||||
refreshMessageList:refreshMessageList,
|
||||
handleDebugMessage: handleDebugMessage,
|
||||
clearMessageList: clearMessageList
|
||||
clearMessageList: clearMessageList,
|
||||
refreshDebugNodeList: refreshDebugNodeList
|
||||
}
|
||||
})();
|
||||
|
@@ -12,6 +12,9 @@ $(function() {
|
||||
},
|
||||
clear: function() {
|
||||
window.opener.postMessage({event:"clear"},'*');
|
||||
},
|
||||
requestDebugNodeList: function(filteredNodes) {
|
||||
window.opener.postMessage({event: 'requestDebugNodeList', filteredNodes},'*')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +29,8 @@ $(function() {
|
||||
RED.debug.refreshMessageList(evt.data.activeWorkspace);
|
||||
} else if (evt.data.event === "projectChange") {
|
||||
RED.debug.clearMessageList(true);
|
||||
} else if (evt.data.event === "refreshDebugNodeList") {
|
||||
RED.debug.refreshDebugNodeList(evt.data.nodes)
|
||||
}
|
||||
},false);
|
||||
} catch(err) {
|
||||
|
@@ -176,14 +176,16 @@
|
||||
for (var i=0;i<rules.length;i++) {
|
||||
const opt = { label: RED._('node-red:switch.label.rule')+' '+(i+1) }
|
||||
const r = rules[i];
|
||||
if (r.hasOwnProperty('v')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v,r.vt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
if (r.t !== 'istype') {
|
||||
if (r.hasOwnProperty('v')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v,r.vt,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (r.hasOwnProperty('v2')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v2,r.v2t,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
if (r.hasOwnProperty('v2')) {
|
||||
if ((msg = RED.utils.validateTypedProperty(r.v2,r.v2t,opt)) !== true) {
|
||||
errors.push(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,9 @@
|
||||
action: {value:"scale"},
|
||||
round: {value:false},
|
||||
property: {value:"payload",required:true,
|
||||
label:RED._("node-red:common.label.property")},
|
||||
label:RED._("node-red:common.label.property"),
|
||||
validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })
|
||||
},
|
||||
name: {value:""}
|
||||
},
|
||||
inputs: 1,
|
||||
|
@@ -56,7 +56,7 @@
|
||||
color:"darksalmon",
|
||||
defaults: {
|
||||
command: {value:""},
|
||||
addpay: {value:""},
|
||||
addpay: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })},
|
||||
append: {value:""},
|
||||
useSpawn: {value:"false"},
|
||||
timer: {value:""},
|
||||
|
@@ -56,9 +56,11 @@
|
||||
inout: {value:"out"},
|
||||
septopics: {value:true},
|
||||
property: {value:"payload", required:true,
|
||||
label:RED._("node-red:rbe.label.property")},
|
||||
label:RED._("node-red:rbe.label.property"),
|
||||
validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true })},
|
||||
topi: {value:"topic", required:true,
|
||||
label:RED._("node-red:rbe.label.topic")}
|
||||
label:RED._("node-red:rbe.label.topic"),
|
||||
validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true })}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
|
@@ -104,6 +104,7 @@ module.exports = function(RED) {
|
||||
* @returns `true` if it is a valid topic
|
||||
*/
|
||||
function isValidPublishTopic(topic) {
|
||||
if (topic.length === 0) return false;
|
||||
return !/[\+#\b\f\n\r\t\v\0]/.test(topic);
|
||||
}
|
||||
|
||||
@@ -219,8 +220,8 @@ module.exports = function(RED) {
|
||||
*/
|
||||
function subscriptionHandler(node, datatype ,topic, payload, packet) {
|
||||
const msg = {topic:topic, payload:null, qos:packet.qos, retain:packet.retain};
|
||||
const v5 = (node && node.brokerConn)
|
||||
? node.brokerConn.v5()
|
||||
const v5 = (node && node.brokerConn)
|
||||
? node.brokerConn.v5()
|
||||
: Object.prototype.hasOwnProperty.call(packet, "properties");
|
||||
if(v5 && packet.properties) {
|
||||
setStrProp(packet.properties, msg, "responseTopic");
|
||||
@@ -451,7 +452,7 @@ module.exports = function(RED) {
|
||||
|
||||
/**
|
||||
* Perform the disconnect action
|
||||
* @param {MQTTInNode|MQTTOutNode} node
|
||||
* @param {MQTTInNode|MQTTOutNode} node
|
||||
* @param {Function} done
|
||||
*/
|
||||
function handleDisconnectAction(node, done) {
|
||||
@@ -611,7 +612,7 @@ module.exports = function(RED) {
|
||||
node.brokerurl = node.url;
|
||||
} else {
|
||||
// if the broker is ws:// or wss:// or tcp://
|
||||
if (node.broker.indexOf("://") > -1) {
|
||||
if ((typeof node.broker === 'string') && node.broker.indexOf("://") > -1) {
|
||||
node.brokerurl = node.broker;
|
||||
// Only for ws or wss, check if proxy env var for additional configuration
|
||||
if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
|
||||
@@ -865,7 +866,7 @@ module.exports = function(RED) {
|
||||
* Call end and wait for the client to end (or timeout)
|
||||
* @param {mqtt.MqttClient} client The broker client
|
||||
* @param {number} ms The time to wait for the client to end
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
let waitEnd = (client, ms) => {
|
||||
return new Promise( (resolve, reject) => {
|
||||
@@ -905,7 +906,7 @@ module.exports = function(RED) {
|
||||
node.subid = 1;
|
||||
|
||||
//typedef for subscription object:
|
||||
/**
|
||||
/**
|
||||
* @typedef {Object} Subscription
|
||||
* @property {String} topic - topic to subscribe to
|
||||
* @property {Object} [options] - options object
|
||||
@@ -933,7 +934,7 @@ module.exports = function(RED) {
|
||||
const ref = _ref || 0;
|
||||
let options
|
||||
let qos = 1 // default to QoS 1 (AWS and several other brokers don't support QoS 2)
|
||||
|
||||
|
||||
// if options is an object, then clone it
|
||||
if (typeof _options == "object") {
|
||||
options = RED.util.cloneMessage(_options || {})
|
||||
@@ -947,7 +948,7 @@ module.exports = function(RED) {
|
||||
if (typeof qos === "number" && qos >= 0 && qos <= 2) {
|
||||
options.qos = qos;
|
||||
}
|
||||
|
||||
|
||||
subscription.topic = _topic;
|
||||
subscription.qos = qos;
|
||||
subscription.options = RED.util.cloneMessage(options);
|
||||
@@ -957,16 +958,16 @@ module.exports = function(RED) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If topic is a subscription object, then use that, otherwise look up the topic in
|
||||
* If topic is a subscription object, then use that, otherwise look up the topic in
|
||||
* the subscriptions object. If the topic is not found, then create a new subscription
|
||||
* object and add it to the subscriptions object.
|
||||
* @param {Subscription|String} topic
|
||||
* @param {*} options
|
||||
* @param {*} callback
|
||||
* @param {*} ref
|
||||
* @param {Subscription|String} topic
|
||||
* @param {*} options
|
||||
* @param {*} callback
|
||||
* @param {*} ref
|
||||
*/
|
||||
node.subscribe = function (topic, options, callback, ref) {
|
||||
/** @type {Subscription} */
|
||||
/** @type {Subscription} */
|
||||
let subscription
|
||||
let doCompare = false
|
||||
let changesFound = false
|
||||
@@ -1004,7 +1005,7 @@ module.exports = function(RED) {
|
||||
_brokerConn.unsubscribe(sub.topic, sub.ref, true)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// if subscription is found (or sent in as a parameter), then check for changes.
|
||||
// if there are any changes requested, tidy up the old subscription
|
||||
if (subscription) {
|
||||
@@ -1091,7 +1092,7 @@ module.exports = function(RED) {
|
||||
delete sub[ref]
|
||||
}
|
||||
}
|
||||
// if instructed to remove the actual MQTT client subscription
|
||||
// if instructed to remove the actual MQTT client subscription
|
||||
if (unsub) {
|
||||
// if there are no more subscriptions for the topic, then remove the topic
|
||||
if (Object.keys(sub).length === 0) {
|
||||
|
@@ -41,8 +41,8 @@
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload"},
|
||||
outproperty: {value:"payload"},
|
||||
property: {value:"payload", validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true }) },
|
||||
outproperty: {value:"payload", validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true }) },
|
||||
tag: {value:""},
|
||||
ret: {value:"html"},
|
||||
as: {value:"single"}
|
||||
|
@@ -32,6 +32,7 @@
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true,
|
||||
validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true}),
|
||||
label:RED._("node-red:json.label.property")},
|
||||
action: {value:""},
|
||||
pretty: {value:false}
|
||||
|
@@ -27,7 +27,8 @@
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value:"payload",required:true,
|
||||
label:RED._("node-red:common.label.property")},
|
||||
label:RED._("node-red:common.label.property"),
|
||||
validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true })},
|
||||
attr: {value:""},
|
||||
chr: {value:""}
|
||||
},
|
||||
|
@@ -16,6 +16,7 @@
|
||||
color:"#DEBD5C",
|
||||
defaults: {
|
||||
property: {value:"payload",required:true,
|
||||
validate: RED.validators.typedInput({ type: 'msg', allowUndefined: true }),
|
||||
label:RED._("node-red:common.label.property")},
|
||||
name: {value:""}
|
||||
},
|
||||
|
@@ -57,7 +57,7 @@
|
||||
arraySplt: {value:1},
|
||||
arraySpltType: {value:"len"},
|
||||
stream: {value:false},
|
||||
addname: {value:""}
|
||||
addname: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
@@ -208,7 +208,22 @@
|
||||
validate:RED.validators.typedInput("propertyType", false)
|
||||
},
|
||||
propertyType: { value:"msg"},
|
||||
key: {value:"topic"},
|
||||
key: {value:"topic", validate: (function () {
|
||||
const typeValidator = RED.validators.typedInput({ type: 'msg' })
|
||||
return function(v, opt) {
|
||||
const joinMode = $("#node-input-mode").val() || this.mode
|
||||
if (joinMode !== 'custom') {
|
||||
return true
|
||||
}
|
||||
const buildType = $("#node-input-build").val() || this.build
|
||||
if (buildType !== 'object') {
|
||||
return true
|
||||
} else {
|
||||
return typeValidator(v, opt)
|
||||
}
|
||||
}
|
||||
})()
|
||||
},
|
||||
joiner: { value:"\\n"},
|
||||
joinerType: { value:"str"},
|
||||
accumulate: { value:"false" },
|
||||
|
@@ -198,7 +198,7 @@
|
||||
category: 'storage',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:""},
|
||||
filename: {value:"", validate: RED.validators.typedInput({ typeField: 'filenameType' })},
|
||||
filenameType: {value:"str"},
|
||||
appendNewline: {value:true},
|
||||
createDir: {value:false},
|
||||
@@ -297,7 +297,7 @@
|
||||
category: 'storage',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:""},
|
||||
filename: {value:"", validate: RED.validators.typedInput({ typeField: 'filenameType' }) },
|
||||
filenameType: {value:"str"},
|
||||
format: {value:"utf8"},
|
||||
chunk: {value:false},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/nodes",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -98,7 +98,7 @@ function requireModule(module) {
|
||||
const parsedModule = parseModuleName(module);
|
||||
|
||||
if (BUILTIN_MODULES.indexOf(parsedModule.module) !== -1) {
|
||||
return require(parsedModule.module);
|
||||
return require(parsedModule.module + parsedModule.subpath);
|
||||
}
|
||||
if (!knownExternalModules[parsedModule.module]) {
|
||||
const e = new Error("Module not allowed");
|
||||
@@ -131,7 +131,7 @@ function importModule(module) {
|
||||
const parsedModule = parseModuleName(module);
|
||||
|
||||
if (BUILTIN_MODULES.indexOf(parsedModule.module) !== -1) {
|
||||
return import(parsedModule.module);
|
||||
return import(parsedModule.module + parsedModule.subpath);
|
||||
}
|
||||
if (!knownExternalModules[parsedModule.module]) {
|
||||
const e = new Error("Module not allowed");
|
||||
@@ -152,12 +152,13 @@ function importModule(module) {
|
||||
}
|
||||
|
||||
function parseModuleName(module) {
|
||||
var match = /((?:@[^/]+\/)?[^/@]+)(?:@([\s\S]+))?/.exec(module);
|
||||
var match = /((?:@[^/]+\/)?[^/@]+)(\/[^/@]+)?(?:@([\s\S]+))?/.exec(module);
|
||||
if (match) {
|
||||
return {
|
||||
spec: module,
|
||||
module: match[1],
|
||||
version: match[2],
|
||||
subpath: match[2] || '',
|
||||
version: match[3],
|
||||
builtin: BUILTIN_MODULES.indexOf(match[1]) !== -1,
|
||||
known: !!knownExternalModules[match[1]]
|
||||
}
|
||||
@@ -283,6 +284,7 @@ async function installModule(moduleDetails) {
|
||||
const runtimeInstalledModules = settings.get("modules") || {};
|
||||
runtimeInstalledModules[moduleDetails.module] = moduleDetails;
|
||||
settings.set("modules",runtimeInstalledModules)
|
||||
log.audit({event: "modules.install",module:moduleDetails.module, version:moduleDetails.version});
|
||||
}).catch(result => {
|
||||
var output = result.stderr || result.toString();
|
||||
var e;
|
||||
|
@@ -143,6 +143,12 @@ function loadModuleFiles(modules) {
|
||||
return loadNodeSetList(pluginList);
|
||||
}).then(function() {
|
||||
return loadNodeSetList(nodeList);
|
||||
}).then(function () {
|
||||
if (settings.available()) {
|
||||
return registry.saveNodeList();
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -436,7 +442,7 @@ async function loadPlugin(plugin) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
|
||||
let invocation = 0
|
||||
function loadNodeSetList(nodes) {
|
||||
var promises = [];
|
||||
nodes.forEach(function(node) {
|
||||
@@ -451,13 +457,7 @@ function loadNodeSetList(nodes) {
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(function() {
|
||||
if (settings.available()) {
|
||||
return registry.saveNodeList();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
return Promise.all(promises)
|
||||
}
|
||||
|
||||
function addModule(module) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/registry",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/util": "3.1.0",
|
||||
"@node-red/util": "3.1.3",
|
||||
"clone": "2.1.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"semver": "7.5.4",
|
||||
|
@@ -99,6 +99,9 @@ var api = module.exports = {
|
||||
safeSettings.markdownEditor = runtime.settings.editorTheme.markdownEditor || {};
|
||||
safeSettings.markdownEditor.mermaid = safeSettings.markdownEditor.mermaid || { enabled: true };
|
||||
}
|
||||
if (runtime.settings.editorTheme.mermaid) {
|
||||
safeSettings.mermaid = runtime.settings.editorTheme.mermaid
|
||||
}
|
||||
}
|
||||
safeSettings.libraries = runtime.library.getLibraries();
|
||||
if (util.isArray(runtime.settings.paletteCategories)) {
|
||||
|
@@ -73,9 +73,20 @@ class Subflow extends Flow {
|
||||
id: subflowInstance.id,
|
||||
configs: {},
|
||||
nodes: {},
|
||||
groups: {},
|
||||
subflows: {}
|
||||
}
|
||||
|
||||
if (subflowDef.groups) {
|
||||
// Clone all of the subflow group definitions and give them new IDs
|
||||
for (i in subflowDef.groups) {
|
||||
if (subflowDef.groups.hasOwnProperty(i)) {
|
||||
node = createNodeInSubflow(subflowInstance.id,subflowDef.groups[i]);
|
||||
node_map[node._alias] = node;
|
||||
subflowInternalFlowConfig.groups[node.id] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (subflowDef.configs) {
|
||||
// Clone all of the subflow config node definitions and give them new IDs
|
||||
for (i in subflowDef.configs) {
|
||||
@@ -101,6 +112,7 @@ class Subflow extends Flow {
|
||||
|
||||
remapSubflowNodes(subflowInternalFlowConfig.configs,node_map);
|
||||
remapSubflowNodes(subflowInternalFlowConfig.nodes,node_map);
|
||||
remapSubflowNodes(subflowInternalFlowConfig.groups,node_map);
|
||||
|
||||
// console.log("Instance config\n",JSON.stringify(subflowInternalFlowConfig,"",2));
|
||||
|
||||
@@ -237,7 +249,7 @@ class Subflow extends Flow {
|
||||
for (j=0;j<wires.length;j++) {
|
||||
if (wires[j].id != self.subflowDef.id) {
|
||||
node = self.node_map[wires[j].id];
|
||||
if (node._originalWires) {
|
||||
if (node && node._originalWires) {
|
||||
node.wires = clone(node._originalWires);
|
||||
}
|
||||
}
|
||||
@@ -254,8 +266,10 @@ class Subflow extends Flow {
|
||||
subflowInstanceModified = true;
|
||||
} else {
|
||||
node = self.node_map[wires[j].id];
|
||||
node.wires[wires[j].port] = node.wires[wires[j].port].concat(newWires[i]);
|
||||
modifiedNodes[node.id] = node;
|
||||
if (node) {
|
||||
node.wires[wires[j].port] = node.wires[wires[j].port].concat(newWires[i]);
|
||||
modifiedNodes[node.id] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,10 +297,14 @@ class Subflow extends Flow {
|
||||
this.node._updateWires(subflowInstanceConfig.wires);
|
||||
} else {
|
||||
var node = self.node_map[wires[j].id];
|
||||
if (!node._originalWires) {
|
||||
node._originalWires = clone(node.wires);
|
||||
if (node) {
|
||||
if (!node._originalWires) {
|
||||
node._originalWires = clone(node.wires);
|
||||
}
|
||||
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]).concat(this.subflowInstance.wires[i]);
|
||||
} else {
|
||||
this.error("Unknown node referenced inside subflow: " + wires[j].id)
|
||||
}
|
||||
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]).concat(this.subflowInstance.wires[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,11 +320,15 @@ class Subflow extends Flow {
|
||||
this.node._updateWires(subflowInstanceConfig.wires);
|
||||
} else {
|
||||
var node = self.node_map[wires[j].id];
|
||||
if (!node._originalWires) {
|
||||
node._originalWires = clone(node.wires);
|
||||
if (node) {
|
||||
if (!node._originalWires) {
|
||||
node._originalWires = clone(node.wires);
|
||||
}
|
||||
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
|
||||
node.wires[wires[j].port].push(subflowStatusId);
|
||||
} else {
|
||||
this.error("Unknown node referenced inside subflow: " + wires[j].id)
|
||||
}
|
||||
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
|
||||
node.wires[wires[j].port].push(subflowStatusId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -57,18 +57,20 @@ var EnvVarPropertyRE = /^\${(\S+)}$/;
|
||||
|
||||
|
||||
function mapEnvVarProperties(obj,prop,flow,config) {
|
||||
var v = obj[prop];
|
||||
const v = obj[prop];
|
||||
if (Buffer.isBuffer(v)) {
|
||||
return;
|
||||
} else if (Array.isArray(v)) {
|
||||
for (var i=0;i<v.length;i++) {
|
||||
for (let i=0;i<v.length;i++) {
|
||||
mapEnvVarProperties(v,i,flow,config);
|
||||
}
|
||||
} else if (typeof obj[prop] === 'string') {
|
||||
if (obj[prop][0] === "$" && (EnvVarPropertyRE_old.test(v) || EnvVarPropertyRE.test(v)) ) {
|
||||
var envVar = v.substring(2,v.length-1);
|
||||
var r = redUtil.getSetting(config, envVar, flow);
|
||||
obj[prop] = r ? r : obj[prop];
|
||||
const envVar = v.substring(2,v.length-1);
|
||||
const r = redUtil.getSetting(config, envVar, flow);
|
||||
if (r !== undefined && r !== '') {
|
||||
obj[prop] = r
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var p in v) {
|
||||
|
@@ -27,6 +27,7 @@ var express = require("express");
|
||||
var path = require('path');
|
||||
var fs = require("fs");
|
||||
var os = require("os");
|
||||
const crypto = require("crypto")
|
||||
|
||||
const {log,i18n,events,exec,util,hooks} = require("@node-red/util");
|
||||
|
||||
@@ -51,7 +52,7 @@ var adminApi = {
|
||||
var nodeApp;
|
||||
var adminApp;
|
||||
var server;
|
||||
|
||||
let userSettings;
|
||||
|
||||
/**
|
||||
* Initialise the runtime module.
|
||||
@@ -61,8 +62,9 @@ var server;
|
||||
* better abstracted.
|
||||
* @memberof @node-red/runtime
|
||||
*/
|
||||
function init(userSettings,httpServer,_adminApi) {
|
||||
function init(_userSettings,httpServer,_adminApi) {
|
||||
server = httpServer;
|
||||
userSettings = _userSettings
|
||||
|
||||
if (server && server.on) {
|
||||
// Add a listener to the upgrade event so that we can properly timeout connection
|
||||
@@ -134,7 +136,12 @@ function start() {
|
||||
.then(function() { return settings.load(storage)})
|
||||
.then(function() { return library.init(runtime)})
|
||||
.then(function() {
|
||||
|
||||
if (settings.available()) {
|
||||
if (settings.get('instanceId') === undefined) {
|
||||
settings.set('instanceId', crypto.randomBytes(8).toString('hex'))
|
||||
}
|
||||
userSettings.instanceId = settings.get('instanceId') || ''
|
||||
}
|
||||
if (log.metric()) {
|
||||
runtimeMetricInterval = setInterval(function() {
|
||||
reportMetrics();
|
||||
|
@@ -384,10 +384,27 @@ var api = module.exports = {
|
||||
}
|
||||
}
|
||||
} else if (nodeType === "global-config") {
|
||||
if (JSON.stringify(savedCredentials.map) !== JSON.stringify(newCreds.map)) {
|
||||
savedCredentials.map = newCreds.map;
|
||||
dirty = true;
|
||||
}
|
||||
const existingCredentialKeys = Object.keys(savedCredentials?.map || [])
|
||||
const newCredentialKeys = Object.keys(newCreds?.map || [])
|
||||
existingCredentialKeys.forEach(key => {
|
||||
if (!newCreds.map?.[key]) {
|
||||
// This key doesn't exist in the new credentials list - remove
|
||||
delete savedCredentials.map[key]
|
||||
delete savedCredentials.map[`has_${key}`]
|
||||
dirty = true
|
||||
}
|
||||
})
|
||||
newCredentialKeys.forEach(key => {
|
||||
if (!/^has_/.test(key)) {
|
||||
if (!savedCredentials.map?.[key] || newCreds.map[key] !== '__PWRD__') {
|
||||
// This key either doesn't exist in current saved, or the
|
||||
// value has been changed
|
||||
savedCredentials.map[key] = newCreds.map[key]
|
||||
savedCredentials.map[`has_${key}`] = newCreds.map[`has_${key}`]
|
||||
dirty = true
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
var dashedType = nodeType.replace(/\s+/g, '-');
|
||||
var definition = credentialsDef[dashedType];
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/runtime",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"main": "./lib/index.js",
|
||||
"repository": {
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/registry": "3.1.0",
|
||||
"@node-red/util": "3.1.0",
|
||||
"@node-red/registry": "3.1.3",
|
||||
"@node-red/util": "3.1.3",
|
||||
"async-mutex": "0.4.0",
|
||||
"clone": "2.1.2",
|
||||
"express": "4.18.2",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/util",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
12
packages/node_modules/node-red/package.json
vendored
12
packages/node_modules/node-red/package.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "node-red",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.3",
|
||||
"description": "Low-code programming for event-driven applications",
|
||||
"homepage": "https://nodered.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,15 +31,15 @@
|
||||
"flow"
|
||||
],
|
||||
"dependencies": {
|
||||
"@node-red/editor-api": "3.1.0",
|
||||
"@node-red/runtime": "3.1.0",
|
||||
"@node-red/util": "3.1.0",
|
||||
"@node-red/nodes": "3.1.0",
|
||||
"@node-red/editor-api": "3.1.3",
|
||||
"@node-red/runtime": "3.1.3",
|
||||
"@node-red/util": "3.1.3",
|
||||
"@node-red/nodes": "3.1.3",
|
||||
"basic-auth": "2.0.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"express": "4.18.2",
|
||||
"fs-extra": "11.1.1",
|
||||
"node-red-admin": "^3.1.0",
|
||||
"node-red-admin": "^3.1.1",
|
||||
"nopt": "5.0.0",
|
||||
"semver": "7.5.4"
|
||||
},
|
||||
|
@@ -29,7 +29,7 @@ describe("api/editor/ui", function() {
|
||||
var app;
|
||||
|
||||
before(function() {
|
||||
ui.init({
|
||||
ui.init({}, {
|
||||
nodes: {
|
||||
getIcon: function(opts) {
|
||||
return new Promise(function(resolve,reject) {
|
||||
|
Reference in New Issue
Block a user