mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge branch 'gg-changes' into validate-users-in-history
This commit is contained in:
@@ -375,7 +375,10 @@
|
||||
"flowAdded": "flow added",
|
||||
"moved": "moved",
|
||||
"movedTo": "moved to __id__",
|
||||
"movedFrom": "moved from __id__"
|
||||
"movedFrom": "moved from __id__",
|
||||
"none": "none",
|
||||
"position": "position",
|
||||
"wires": "wires"
|
||||
},
|
||||
"nodeCount": "__count__ node",
|
||||
"nodeCount_plural": "__count__ nodes",
|
||||
@@ -384,9 +387,14 @@
|
||||
"reviewChanges": "Review Changes",
|
||||
"noBinaryFileShowed": "Cannot show binary file contents",
|
||||
"viewCommitDiff": "View Commit Changes",
|
||||
"commit": "Commit",
|
||||
"compareChanges": "Compare Changes",
|
||||
"saveConflict": "Save conflict resolution",
|
||||
"conflictHeader": "<span>__resolved__</span> of <span>__unresolved__</span> conflicts resolved",
|
||||
"localChanges": "Local Changes",
|
||||
"remoteChanges": "Remote Changes",
|
||||
"useLocalChanges": "use local changes",
|
||||
"useRemoteChanges": "use remote changes",
|
||||
"commonVersionError": "Common Version doesn't contain valid JSON:",
|
||||
"oldVersionError": "Old Version doesn't contain valid JSON:",
|
||||
"newVersionError": "New Version doesn't contain valid JSON:"
|
||||
@@ -554,7 +562,9 @@
|
||||
"types": {
|
||||
"local": "Local",
|
||||
"examples": "Examples"
|
||||
}
|
||||
},
|
||||
"type": "Type",
|
||||
"name": "Name"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "no information available",
|
||||
@@ -803,6 +813,7 @@
|
||||
"branches": "Branches",
|
||||
"noBranches": "No branches",
|
||||
"deleteConfirm": "Are you sure you want to delete the local branch '__name__'? This cannot be undone.",
|
||||
"deleteBranch": "Delete branch",
|
||||
"unmergedConfirm": "The local branch '__name__' has unmerged changes that will be lost. Are you sure you want to delete it?",
|
||||
"deleteUnmergedBranch": "Delete unmerged branch",
|
||||
"gitRemotes": "Git remotes",
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"lock": "Bloquear",
|
||||
"unlock": "Desbloquear",
|
||||
"locked": "Bloqueado",
|
||||
"unlocked": "Desbloqueado"
|
||||
"unlocked": "Desbloqueado",
|
||||
"format": "Formato"
|
||||
},
|
||||
"type": {
|
||||
"string": "texto",
|
||||
@@ -303,7 +304,8 @@
|
||||
"missingType": "La entrada no es un flujo válido - elemento __index__ falta la propiedad 'type'"
|
||||
},
|
||||
"conflictNotification1": "Algunos de los nodos que estás importando ya existen en tu espacio de trabajo.",
|
||||
"conflictNotification2": "Selecciona qué nodos importar y si reemplazar los nodos existentes o importar una copia de los mismos."
|
||||
"conflictNotification2": "Selecciona qué nodos importar y si reemplazar los nodos existentes o importar una copia de los mismos.",
|
||||
"alreadyExists": "Este nodo ya existe"
|
||||
},
|
||||
"copyMessagePath": "Ruta copiada",
|
||||
"copyMessageValue": "Valor copiado",
|
||||
@@ -371,8 +373,12 @@
|
||||
"deleted": "eliminado",
|
||||
"flowDeleted": "flujo eliminado",
|
||||
"flowAdded": "flujo añadido",
|
||||
"moved": "movido",
|
||||
"movedTo": "movido a __id__",
|
||||
"movedFrom": "movido desde __id__"
|
||||
"movedFrom": "movido desde __id__",
|
||||
"none": "ninguno",
|
||||
"position": "posición",
|
||||
"wires": "conectores"
|
||||
},
|
||||
"nodeCount": "__count__ nodo",
|
||||
"nodeCount_plural": "__count__ nodos",
|
||||
@@ -381,9 +387,14 @@
|
||||
"reviewChanges": "Revisar Cambios",
|
||||
"noBinaryFileShowed": "No se puede mostrar el contenido del archivo binario",
|
||||
"viewCommitDiff": "Ver cambios de commit",
|
||||
"commit": "Commit",
|
||||
"compareChanges": "Comparar Cambios",
|
||||
"saveConflict": "Guardar resolución de conflictos",
|
||||
"conflictHeader": "<span>__resolved__</span> de <span>__unresolved__</span> conflictos resueltos",
|
||||
"localChanges": "Cambios Locales",
|
||||
"remoteChanges": "Cambios Remotos",
|
||||
"useLocalChanges": "utilizar cambios locales",
|
||||
"useRemoteChanges": "utilizar cambios remotos",
|
||||
"commonVersionError": "La versión común no contiene JSON válido:",
|
||||
"oldVersionError": "La versión anterior no contiene JSON válido:",
|
||||
"newVersionError": "La versión nueva no contiene JSON válido:"
|
||||
@@ -551,7 +562,9 @@
|
||||
"types": {
|
||||
"local": "Local",
|
||||
"examples": "Ejemplos"
|
||||
}
|
||||
},
|
||||
"type": "Tipo",
|
||||
"name": "Nombre"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "no hay información disponible",
|
||||
@@ -613,6 +626,8 @@
|
||||
},
|
||||
"nodeCount": "__label__ nodo",
|
||||
"nodeCount_plural": "__label__ nodos",
|
||||
"pluginCount": "__count__ extensión",
|
||||
"pluginCount_plural": "__count__ extensiones",
|
||||
"moduleCount": "__count__ módulo disponible",
|
||||
"moduleCount_plural": "__count__ módulos disponibles",
|
||||
"inuse": "en uso",
|
||||
@@ -640,6 +655,7 @@
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>La carga del catálogo de nodos ha fallado</p><p>Revise la consola del navegador para mas información</p>",
|
||||
"installFailed": "<p>Fallo al instalar: __module__</p><p>__message__</p><p>Revise el log para mas información</p>",
|
||||
"installTimeout": "<p>La instalación continúa en segundo plano.</p><p>Los nodos aparecerán en la paleta cuando finalice. Consulta el registro para obtener más información.</p>",
|
||||
"removeFailed": "<p>Fallo al eliminar: __module__</p><p>__message__</p><p>Revise el log para mas información</p>",
|
||||
"updateFailed": "<p>Fallo al actualizar: __module__</p><p>__message__</p><p>Revise el log para mas información</p>",
|
||||
"enableFailed": "<p>Fallo al activar: __module__</p><p>__message__</p><p>Revise el log para mas información</p>",
|
||||
@@ -654,6 +670,9 @@
|
||||
"body":"<p>Eliminando '__module__'</p><p>La eliminación del nodo lo desinstalará de Node-RED. Es posible que el nodo siga utilizando recursos hasta que Node-RED sea reiniciado.</p>",
|
||||
"title": "Eliminar nodos"
|
||||
},
|
||||
"removePlugin": {
|
||||
"body": "<p>Extensión __module__ eliminada. Vuelve a cargar el editor para borrar los elementos sobrantes.</p>"
|
||||
},
|
||||
"update": {
|
||||
"body":"<p>Actualizando '__module__'</p><p>La actualización del nodo requerirá un reinicio manual de Node-RED para completarse. Debe ser reiniciado manualmente.</p>",
|
||||
"title": "Actualizar nodos"
|
||||
@@ -665,7 +684,8 @@
|
||||
"review": "Abrir información del nodo",
|
||||
"install": "Instalar",
|
||||
"remove": "Eliminar",
|
||||
"update": "Actualizar"
|
||||
"update": "Actualizar",
|
||||
"understood": "Entendido"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -718,6 +738,7 @@
|
||||
"nodeHelp": "Ayuda de nodo",
|
||||
"showHelp": "Mostrar ayuda",
|
||||
"showInOutline": "Mostrar en controno",
|
||||
"hideTopics": "Esconder temas",
|
||||
"showTopics": "Mostrar temas",
|
||||
"noHelp": "No hay ningun tema de ayuda seleccionado",
|
||||
"changeLog": "Registro de Cambios"
|
||||
@@ -792,6 +813,7 @@
|
||||
"branches": "Ramas",
|
||||
"noBranches": "Sin ramas",
|
||||
"deleteConfirm": "¿Estás seguro de que quieres eliminar la rama local '__name__'? Esta acción no puede deshacerse.",
|
||||
"deleteBranch": "Eliminar rama",
|
||||
"unmergedConfirm": "La rama local '__name__' tiene cambios no fusionados que se perderán. ¿Estás seguro de que quieres eliminarla?",
|
||||
"deleteUnmergedBranch": "Eliminar rama no fusionada",
|
||||
"gitRemotes": "Git remotes",
|
||||
@@ -913,6 +935,8 @@
|
||||
}
|
||||
},
|
||||
"typedInput": {
|
||||
"selected": "__count__ seleccionado",
|
||||
"selected_plural": "__count__ seleccionados",
|
||||
"type": {
|
||||
"str": "texto",
|
||||
"num": "número",
|
||||
@@ -923,7 +947,14 @@
|
||||
"date": "marca tiempo",
|
||||
"jsonata": "expresión",
|
||||
"env": "variable de entorno",
|
||||
"cred": "credencial"
|
||||
"cred": "credencial",
|
||||
"conf-types": "nodo configuración"
|
||||
},
|
||||
"date": {
|
||||
"format": {
|
||||
"timestamp": "milisegundos desde epoch",
|
||||
"object": "Objeto de fecha de JavaScript"
|
||||
}
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
@@ -1205,6 +1236,18 @@
|
||||
"diagnostics": {
|
||||
"title": "Información Sistema"
|
||||
},
|
||||
"languages": {
|
||||
"de": "Deutsch",
|
||||
"en-US": "English",
|
||||
"es-ES": "Español (España)",
|
||||
"fr": "Français",
|
||||
"ja": "日本語",
|
||||
"ko": "Korean",
|
||||
"pt-BR": "Português (Brasil)",
|
||||
"ru": "Русский",
|
||||
"zh-CN": "简体中文",
|
||||
"zh-TW": "繁體中文"
|
||||
},
|
||||
"validator": {
|
||||
"errors": {
|
||||
"invalid-json": "Datos JSON inválidos: __error__",
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"lock": "Verrouiller",
|
||||
"unlock": "Déverrouiller",
|
||||
"locked": "Verrouillé",
|
||||
"unlocked": "Déverrouillé"
|
||||
"unlocked": "Déverrouillé",
|
||||
"format": "Format"
|
||||
},
|
||||
"type": {
|
||||
"string": "chaîne de caractères",
|
||||
@@ -54,10 +55,10 @@
|
||||
"workspace": {
|
||||
"defaultName": "Flux __number__",
|
||||
"editFlow": "Modifier le flux : __name__",
|
||||
"confirmDelete": "Confirmation de la suppression",
|
||||
"delete": "Etes-vous sûr de vouloir supprimer '__label__'?",
|
||||
"dropFlowHere": "Déposer le flux ici",
|
||||
"dropImageHere": "Déposer l'image ici",
|
||||
"confirmDelete": "Confirmer la suppression",
|
||||
"delete": "Êtes-vous sûr de vouloir supprimer '__label__' ?",
|
||||
"dropFlowHere": "Lâchez le flux ici",
|
||||
"dropImageHere": "Lâchez l'image ici",
|
||||
"addFlow": "Ajouter un flux",
|
||||
"addFlowToRight": "Ajouter un flux à droite",
|
||||
"closeFlow": "Fermer le flux",
|
||||
@@ -74,7 +75,7 @@
|
||||
"enabled": "Activé",
|
||||
"disabled": "Désactivé",
|
||||
"info": "Description",
|
||||
"selectNodes": "Cliquer sur les noeuds pour sélectionner",
|
||||
"selectNodes": "Cliquer pour sélectionner",
|
||||
"enableFlow": "Activer le flux",
|
||||
"disableFlow": "Désactiver le flux",
|
||||
"lockFlow": "Verrouiller le flux",
|
||||
@@ -98,7 +99,7 @@
|
||||
"rtl": "De droite à gauche",
|
||||
"auto": "Contextuel",
|
||||
"language": "Langue",
|
||||
"browserDefault": "Navigateur par défaut"
|
||||
"browserDefault": "Par défaut du Navigateur"
|
||||
},
|
||||
"sidebar": {
|
||||
"show": "Afficher la barre latérale"
|
||||
@@ -134,7 +135,7 @@
|
||||
"disableSelectedNodes": "Désactiver les noeuds sélectionnés",
|
||||
"showSelectedNodeLabels": "Afficher les étiquettes des noeuds sélectionnés",
|
||||
"hideSelectedNodeLabels": "Masquer les étiquettes des noeuds sélectionnés",
|
||||
"showWelcomeTours": "Afficher les visites guidées pour les nouvelles versions",
|
||||
"showWelcomeTours": "Afficher les visites guidées des nouvelles versions",
|
||||
"help": "Site web de Node-RED",
|
||||
"projects": "Projets",
|
||||
"projects-new": "Nouveau projet",
|
||||
@@ -143,7 +144,7 @@
|
||||
"showNodeLabelDefault": "Afficher l'étiquette des noeuds nouvellement ajoutés",
|
||||
"codeEditor": "Éditeur de code",
|
||||
"groups": "Groupes",
|
||||
"groupSelection": "Grouper cette sélection",
|
||||
"groupSelection": "Grouper la sélection",
|
||||
"ungroupSelection": "Dégrouper la sélection",
|
||||
"groupMergeSelection": "Fusionner la sélection",
|
||||
"groupRemoveSelection": "Supprimer du groupe",
|
||||
@@ -155,7 +156,7 @@
|
||||
"alignMiddle": "Aligner au milieu",
|
||||
"alignBottom": "Aligner en bas",
|
||||
"distributeHorizontally": "Répartir horizontalement",
|
||||
"distributeVertically": "Distribuer verticalement",
|
||||
"distributeVertically": "Répartir verticalement",
|
||||
"moveToBack": "Déplacer vers l'arrière",
|
||||
"moveToFront": "Déplacer vers l'avant",
|
||||
"moveBackwards": "Reculer",
|
||||
@@ -163,21 +164,21 @@
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"toggle-navigator": "Basculer de navigateur",
|
||||
"zoom-out": "Dézoomer",
|
||||
"zoom-reset": "Réinitialiser le zoom",
|
||||
"toggle-navigator": "Basculer l'affichage du navigateur",
|
||||
"zoom-out": "Réduire",
|
||||
"zoom-reset": "Réinitialiser",
|
||||
"zoom-in": "Agrandir",
|
||||
"search-flows": "Rechercher le flux",
|
||||
"search-prev": "Précédent",
|
||||
"search-next": "Suivant",
|
||||
"search-counter": "\"__term__\" __result__ de __count__"
|
||||
"search-counter": "\"__term__\" __result__ sur __count__"
|
||||
},
|
||||
"user": {
|
||||
"loggedInAs": "Connecté en tant que __name__",
|
||||
"username": "Nom d'utilisateur",
|
||||
"password": "Mot de passe",
|
||||
"login": "Connexion",
|
||||
"loginFailed": "Échec de la connexion",
|
||||
"login": "Se connecter",
|
||||
"loginFailed": "Échec de connexion",
|
||||
"notAuthorized": "Pas autorisé",
|
||||
"errors": {
|
||||
"settings": "Vous devez être connecté pour accéder aux paramètres",
|
||||
@@ -193,16 +194,16 @@
|
||||
"warning": "<strong>Attention</strong> : __message__",
|
||||
"warnings": {
|
||||
"undeployedChanges": "Le noeud a des modifications non déployées",
|
||||
"nodeActionDisabled": "Actions de noeud désactivées",
|
||||
"nodeActionDisabledSubflow": "Actions de noeud désactivées dans le sous-flux",
|
||||
"nodeActionDisabled": "Les actions du noeud sont désactivées",
|
||||
"nodeActionDisabledSubflow": "Les actions de noeud sont désactivées à l'intérieur du sous-flux",
|
||||
"missing-types": "<p>Flux arrêtés en raison de types de noeuds manquants.</p>",
|
||||
"missing-modules": "<p>Flux arrêtés en raison de modules manquants.</p>",
|
||||
"safe-mode": "<p>Flux arrêtés en mode sans échec.</p><p>Vous pouvez modifier vos flux et déployer les changements pour redémarrer.</p>",
|
||||
"safe-mode": "<p>Flux arrêtés en mode sans échec.</p><p>Vous pouvez modifier vos flux et déployer ensuite les changements afin de démarrer vos flux.</p>",
|
||||
"restartRequired": "Node-RED doit être redémarré pour mettre à jour les modules",
|
||||
"credentials_load_failed": "<p>Les flux se sont arrêtés car les informations d'identification n'ont pas pu être déchiffrées.</p><p>Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.</p>",
|
||||
"credentials_load_failed_reset": "<p>Les informations d'identification n'ont pas pu être déchiffrées</p><p>Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.</p><p>Le fichier d'informations d'identification du flux sera réinitialisé lors du prochain déploiement. Toutes les informations d'identification de flux existantes seront perdues.</p>",
|
||||
"credentials_load_failed": "<p>Les flux se sont arrêtés car les informations d'identification n'ont pas pu être déchiffrées.</p><p>Le fichier d'informations d'identification du flux est chiffré mais la clé de chiffrement du projet est manquante ou invalide.</p>",
|
||||
"credentials_load_failed_reset": "<p>Les informations d'identification n'ont pas pu être déchiffrées</p><p>Le fichier d'informations d'identification du flux est chiffré mais la clé de chiffrement du projet est manquante ou invalide.</p><p>Le fichier d'informations d'identification du flux sera réinitialisé lors du prochain déploiement. Toutes les informations d'identification des flux existants seront perdues.</p>",
|
||||
"missing_flow_file": "<p>Fichier contenant les flux introuvable.</p><p>Le projet n'est pas configuré avec un fichier de flux.</p>",
|
||||
"missing_package_file": "<p>Fichier de paquetage du projet introuvable.</p><p>Il manque au projet un fichier package.json.</p>",
|
||||
"missing_package_file": "<p>Fichier de paquetage du projet introuvable.</p><p>Il manque au projet le fichier <code>package.json</code>.</p>",
|
||||
"project_empty": "<p>Le projet est vide.</p><p>Voulez-vous créer un ensemble de fichiers de projet par défaut ?<br/>Sinon, vous devrez ajouter manuellement des fichiers au projet (en dehors de l'éditeur).</p>",
|
||||
"project_not_found": "<p>Le projet '__project__' est introuvable.</p>",
|
||||
"git_merge_conflict": "<p>La fusion automatique des modifications a échoué.</p><p>Corriger les conflits non fusionnés, puis valider le résultat.</p>"
|
||||
@@ -219,7 +220,7 @@
|
||||
},
|
||||
"project": {
|
||||
"change-branch": "Changer pour une branche locale '__project__'",
|
||||
"merge-abort": "Git fusion abandonnée",
|
||||
"merge-abort": "Fusion Git abandonnée",
|
||||
"loaded": "Projet '__project__' chargé",
|
||||
"updated": "Projet '__project__' mis à jour",
|
||||
"pull": "Projet '__project__' rechargé",
|
||||
@@ -352,7 +353,7 @@
|
||||
"backgroundUpdate": "Les flux sur le serveur ont été mis à jour.",
|
||||
"conflictChecking": "Vérifier si les modifications peuvent être fusionnées automatiquement",
|
||||
"conflictAutoMerge": "Les modifications n'incluent aucun conflit et peuvent être fusionnées automatiquement.",
|
||||
"conflictManualMerge": "Les changements incluent des conflits qui doivent être résolus avant de pouvoir être déployés.",
|
||||
"conflictManualMerge": "Les modifications incluent des conflits qui doivent être résolus avant de pouvoir être déployées.",
|
||||
"plusNMore": "+ __count__ en plus"
|
||||
}
|
||||
},
|
||||
@@ -372,19 +373,28 @@
|
||||
"deleted": "supprimé",
|
||||
"flowDeleted": "flux supprimé",
|
||||
"flowAdded": "flux ajouté",
|
||||
"moved": "déplacé",
|
||||
"movedTo": "déplacé vers __id__",
|
||||
"movedFrom": "déplacé depuis __id__"
|
||||
"movedFrom": "déplacé depuis __id__",
|
||||
"none": "aucun",
|
||||
"position": "position",
|
||||
"wires": "câbles"
|
||||
},
|
||||
"nodeCount": "__count__ noeud",
|
||||
"nodeCount_plural": "__count__ noeuds",
|
||||
"local": "Changements locaux",
|
||||
"remote": "Modifications à distance",
|
||||
"remote": "Changements distants",
|
||||
"reviewChanges": "Examiner les modifications",
|
||||
"noBinaryFileShowed": "Impossible d'afficher le contenu du fichier binaire",
|
||||
"viewCommitDiff": "Afficher les modifications de validation",
|
||||
"viewCommitDiff": "Afficher les modifications de la validation",
|
||||
"commit": "Validation",
|
||||
"compareChanges": "Comparer les modifications",
|
||||
"saveConflict": "Enregistrer la résolution des conflits",
|
||||
"conflictHeader": "<span>__resolved__</span> sur <span>__unresolved__</span> conflit(s) résolu(s)",
|
||||
"localChanges": "Modifications locales",
|
||||
"remoteChanges": "Modifications distantes",
|
||||
"useLocalChanges": "utiliser les modifications locales",
|
||||
"useRemoteChanges": "utiliser les modifications distantes",
|
||||
"commonVersionError": "La version commune ne contient pas de JSON valide :",
|
||||
"oldVersionError": "L'ancienne version ne contient pas de JSON valide :",
|
||||
"newVersionError": "La nouvelle version ne contient pas de JSON valide :"
|
||||
@@ -395,9 +405,9 @@
|
||||
"edit": "Modifier le modèle du sous-flux",
|
||||
"subflowInstances": "Il existe __count__ instance de ce modèle de sous-flux",
|
||||
"subflowInstances_plural": "Il existe __count__ instances de ce modèle de sous-flux",
|
||||
"editSubflowProperties": "modifier les propriétés",
|
||||
"input": "Entrées:",
|
||||
"output": "Sorties:",
|
||||
"editSubflowProperties": "Modifier les propriétés",
|
||||
"input": "Entrées :",
|
||||
"output": "Sorties :",
|
||||
"status": "Statut du noeud",
|
||||
"deleteSubflow": "Supprimer le sous-flux",
|
||||
"confirmDelete": "Voulez-vous vraiment supprimer ce sous-flux ?",
|
||||
@@ -411,7 +421,7 @@
|
||||
"version": "Version",
|
||||
"versionPlaceholder": "x.y.z",
|
||||
"keys": "Mots clés",
|
||||
"keysPlaceholder": "Mots clés séparés par des virgules",
|
||||
"keysPlaceholder": "Mots clés séparés par une virgule",
|
||||
"author": "Auteur",
|
||||
"authorPlaceholder": "Votre nom <email@exemple.com>",
|
||||
"desc": "Description",
|
||||
@@ -468,7 +478,7 @@
|
||||
"select": "sélection",
|
||||
"checkbox": "case à cocher",
|
||||
"spinner": "valeurs à défiler",
|
||||
"none": "aucune",
|
||||
"none": "aucun",
|
||||
"hidden": "masquer la propriété"
|
||||
},
|
||||
"types": {
|
||||
@@ -496,7 +506,7 @@
|
||||
"max": "Maximum"
|
||||
},
|
||||
"errors": {
|
||||
"scopeChange": "La modification de la portée la rendra indisponible pour les noeuds d'autres flux qui l'utilisent",
|
||||
"scopeChange": "La modification de la portée rendra indisponible ce noeud de configuration aux noeuds d'autres flux qui l'utilisent",
|
||||
"invalidProperties": "Propriétés invalides :",
|
||||
"credentialLoadFailed": "Échec du chargement des identifiants du noeud"
|
||||
}
|
||||
@@ -510,7 +520,7 @@
|
||||
"unassigned": "Non attribué",
|
||||
"global": "Global",
|
||||
"workspace": "Espace de travail",
|
||||
"editor": "Boîte de dialogue d'édition",
|
||||
"editor": "Boîte d'édition",
|
||||
"selectAll": "Tout sélectionner",
|
||||
"selectNone": "Ne rien sélectionner",
|
||||
"selectAllConnected": "Sélectionner tous les éléments connectés",
|
||||
@@ -541,7 +551,7 @@
|
||||
"openLibrary": "Ouvrir la bibliothèque...",
|
||||
"saveToLibrary": "Enregistrer dans la bibliothèque...",
|
||||
"typeLibrary": "__type__ bibliothèque",
|
||||
"unnamedType": "Innomé __type__",
|
||||
"unnamedType": "Sans nom __type__",
|
||||
"exportedToLibrary": "Noeuds exportés vers la bibliothèque",
|
||||
"dialogSaveOverwrite": "Une __libraryType__ appelée __libraryName__ existe déjà. Écraser ?",
|
||||
"invalidFilename": "Nom de fichier non valide",
|
||||
@@ -552,13 +562,15 @@
|
||||
"types": {
|
||||
"local": "Local",
|
||||
"examples": "Exemples"
|
||||
}
|
||||
},
|
||||
"type": "Type",
|
||||
"name": "Nom"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "Pas d'information disponible",
|
||||
"filter": "Rechercher le noeud",
|
||||
"search": "Rechercher les modules",
|
||||
"addCategory": "Ajouter un nouveau...",
|
||||
"addCategory": "Ajouter une nouvelle...",
|
||||
"label": {
|
||||
"subflows": "Sous-flux",
|
||||
"network": "Réseau",
|
||||
@@ -638,7 +650,7 @@
|
||||
"sortAZ": "A-Z",
|
||||
"sortRecent": "Récent",
|
||||
"more": "+ __count__ en plus",
|
||||
"upload": "Charger le fichier tgz du module",
|
||||
"upload": "Charger le fichier .tgz du module",
|
||||
"refresh": "Actualiser la liste des modules",
|
||||
"errors": {
|
||||
"catalogLoadFailed": "<p>Échec du chargement du catalogue de noeuds.</p><p>Vérifier la console du navigateur pour plus d'informations</p>",
|
||||
@@ -651,7 +663,7 @@
|
||||
},
|
||||
"confirm": {
|
||||
"install": {
|
||||
"body": "<p>Installation de '__module__'</p><p>Avant l'installation, veuiller lire la documentation du noeud. Certains noeuds ont des dépendances qui ne peuvent pas être résolues automatiquement et peuvent nécessiter un redémarrage de Node-RED.</p>",
|
||||
"body": "<p>Installation de '__module__'</p><p>Avant l'installation, veuillez lire la documentation du noeud. Certains noeuds ont des dépendances qui ne peuvent pas être résolues automatiquement et peuvent nécessiter un redémarrage de Node-RED.</p>",
|
||||
"title": "Installer les noeuds"
|
||||
},
|
||||
"remove": {
|
||||
@@ -666,7 +678,7 @@
|
||||
"title": "Mettre à jour les noeuds"
|
||||
},
|
||||
"cannotUpdate": {
|
||||
"body": "Une mise à jour pour ce noeud est disponible, mais il n'est pas installé dans un emplacement que le gestionnaire de palette peut mettre à jour.<br/><br/>Veuiller vous référer à la documentation pour savoir comment mettre à jour ce noeud."
|
||||
"body": "Une mise à jour pour ce noeud est disponible, mais il n'est pas installé dans un emplacement que le gestionnaire de palette peut mettre à jour.<br/><br/>Veuillez vous référer à la documentation pour savoir comment mettre à jour ce noeud."
|
||||
},
|
||||
"button": {
|
||||
"review": "Ouvrir la documentation",
|
||||
@@ -708,8 +720,8 @@
|
||||
"nodeHelp": "Aide sur les noeuds",
|
||||
"none": "Aucun",
|
||||
"arrayItems": "__count__ éléments",
|
||||
"showTips": "Vous pouvez ouvrir les astuces à partir du panneau des paramètres",
|
||||
"outline": "Plan",
|
||||
"showTips": "Vous pouvez afficher les astuces à partir du panneau des paramètres",
|
||||
"outline": "Contour",
|
||||
"empty": "Vide",
|
||||
"globalConfig": "Noeuds de configuration globale",
|
||||
"triggerAction": "Déclencher une action",
|
||||
@@ -722,7 +734,7 @@
|
||||
"help": {
|
||||
"name": "Aide",
|
||||
"label": "Aide",
|
||||
"search": "Aide à la recherche",
|
||||
"search": "Rechercher l'aide",
|
||||
"nodeHelp": "Aide sur les noeuds",
|
||||
"showHelp": "Afficher l'aide",
|
||||
"showInOutline": "Afficher dans les grandes lignes",
|
||||
@@ -801,7 +813,8 @@
|
||||
"branches": "Branches",
|
||||
"noBranches": "Pas de branche",
|
||||
"deleteConfirm": "Êtes-vous sûr de vouloir supprimer la branche locale '__name__' ? Ça ne peut pas être annulé.",
|
||||
"unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Etes-vous sûr de vouloir la supprimer?",
|
||||
"deleteBranch": "Supprimer la branche",
|
||||
"unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Êtes-vous sûr de vouloir la supprimer?",
|
||||
"deleteUnmergedBranch": "Supprimer la branche non fusionnée",
|
||||
"gitRemotes": "Git distant",
|
||||
"addRemote": "Ajout distant",
|
||||
@@ -845,17 +858,17 @@
|
||||
"deleteConfirm": "Êtes-vous sûr de vouloir supprimer la clé SSH __name__ ? Ça ne peut pas être annulé."
|
||||
},
|
||||
"versionControl": {
|
||||
"unstagedChanges": "Abandon des changements",
|
||||
"stagedChanges": "Changement mis en place",
|
||||
"unstageChange": "Ne pas mettre en place le changement",
|
||||
"stageChange": "Mettre en place le changement",
|
||||
"unstageAllChange": "Ne pas mettre en place tous les changements",
|
||||
"stageAllChange": "Mettre en place tous les changements",
|
||||
"unstagedChanges": "Changements non indexés",
|
||||
"stagedChanges": "Changements indexés",
|
||||
"unstageChange": "Annuler l'indexation des changements",
|
||||
"stageChange": "Indexer les changements",
|
||||
"unstageAllChange": "Annuler l'indexation de tous les changements",
|
||||
"stageAllChange": "Indexer tous les changements",
|
||||
"commitChanges": "Valider les changements",
|
||||
"resolveConflicts": "Résoudre les conflits",
|
||||
"head": "En-tête",
|
||||
"staged": "Mis en place",
|
||||
"unstaged": "Non mis en place",
|
||||
"staged": "Indexé",
|
||||
"unstaged": "Non indexé",
|
||||
"local": "Local",
|
||||
"remote": "Distant",
|
||||
"revert": "Voulez-vous vraiment annuler les modifications apportées à '__file__' ? Ça ne peut pas être annulé.",
|
||||
@@ -889,11 +902,11 @@
|
||||
"pushFailed": "L'envoi a échoué car la branche a des validations plus récentes. Tirer et fusionner d'abord, puis envoyer à nouveau.",
|
||||
"push": "Envoyer",
|
||||
"pull": "Tirer",
|
||||
"unablePull": "<p>Impossible d'extraire les modifications à distance ; vos modifications locales non mises en place seraient écrasées.</p><p>Valider vos modifications et réessayer.</p>",
|
||||
"showUnstagedChanges": "Afficher les modifications non mise en place",
|
||||
"unablePull": "<p>Impossible d'extraire les modifications à distance; vos modifications locales non mises en place seraient écrasées.</p><p>Valider vos modifications et réessayer.</p>",
|
||||
"showUnstagedChanges": "Afficher les modifications non indexées",
|
||||
"connectionFailed": "Impossible de se connecter au référentiel distant: ",
|
||||
"pullUnrelatedHistory": "<p>Le réferentiel distant a un historique de validations sans rapport.</p><p>Êtes-vous sûr de vouloir extraire les modifications dans votre référentiel local ?</p>",
|
||||
"pullChanges": "Tirer les changements",
|
||||
"pullChanges": "Tirer les changements distants",
|
||||
"history": "Historique",
|
||||
"projectHistory": "Historique du projet",
|
||||
"daysAgo": "il y a __count__ jour",
|
||||
@@ -974,7 +987,7 @@
|
||||
"result": "Résultat",
|
||||
"format": "Format",
|
||||
"compatMode": "Mode de compatibilité activé",
|
||||
"compatModeDesc": "<h3>Mode de compatibilité JSONata</h3><p> L'expression actuelle semble toujours faire référence à <code>msg</code> et sera donc évaluée en mode de compatibilité. Veuiller mettre à jour l'expression pour ne pas utiliser <code>msg</code> car ce mode sera supprimé à l'avenir.</p><p> Lorsque la prise en charge de JSONata a été ajoutée pour la première fois à Node-RED, il fallait que l'expression référencie l'objet <code>msg</code>. Par exemple, <code>msg.payload</code> serait utilisé pour accéder à la charge utile.</p><p> Cela n'est plus nécessaire car l'expression sera évaluée directement par rapport au message. Pour accéder à la charge utile, l'expression doit être simplement <code>charge utile</code>.</p>",
|
||||
"compatModeDesc": "<h3>Mode de compatibilité JSONata</h3><p> L'expression actuelle semble toujours faire référence à <code>msg</code> et sera donc évaluée en mode de compatibilité. Veuillez mettre à jour l'expression pour ne pas utiliser <code>msg</code> car ce mode sera supprimé à l'avenir.</p><p> Lorsque la prise en charge de JSONata a été ajoutée pour la première fois à Node-RED, il fallait que l'expression référencie l'objet <code>msg</code>. Par exemple, <code>msg.payload</code> serait utilisé pour accéder à la charge utile.</p><p> Cela n'est plus nécessaire car l'expression sera évaluée directement par rapport au message. Pour accéder à la charge utile, l'expression doit être simplement <code>charge utile</code>.</p>",
|
||||
"noMatch": "Aucun résultat correspondant",
|
||||
"errors": {
|
||||
"invalid-expr": "Expression JSONata non valide :\n __message__",
|
||||
@@ -997,7 +1010,7 @@
|
||||
},
|
||||
"jsonEditor": {
|
||||
"title": "Éditeur JSON",
|
||||
"format": "Format JSON",
|
||||
"format": "Formatter JSON",
|
||||
"rawMode": "Modifier JSON",
|
||||
"uiMode": "Afficher l'éditeur",
|
||||
"rawMode-readonly": "JSON",
|
||||
@@ -1016,7 +1029,7 @@
|
||||
"markdownEditor": {
|
||||
"title": "Éditeur Markdown",
|
||||
"expand": "Développer",
|
||||
"format": "Formaté avec Markdown",
|
||||
"format": "Formatter avec Markdown",
|
||||
"heading1": "Rubrique 1",
|
||||
"heading2": "Rubrique 2",
|
||||
"heading3": "Rubrique 3",
|
||||
@@ -1090,7 +1103,7 @@
|
||||
"credential-key": "Clé de chiffrement des identifiants",
|
||||
"cant-get-ssh-key": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.",
|
||||
"already-exists2": "Existe déjà",
|
||||
"git-error": "Erreur git",
|
||||
"git-error": "Erreur Git",
|
||||
"connection-failed": "La connexion a échoué",
|
||||
"not-git-repo": "Ce n'est pas un dépôt Git",
|
||||
"repo-not-found": "Référentiel introuvable"
|
||||
@@ -1104,7 +1117,7 @@
|
||||
"credentials-file": "Fichier d'identifiants"
|
||||
},
|
||||
"encryption-config": {
|
||||
"setup": "Configuration du chiffrage de votre fichier d'informations d'identification",
|
||||
"setup": "Configuration du chiffrement de votre fichier d'informations d'identification",
|
||||
"desc0": "Votre fichier d'informations d'identification de flux peut être chiffré pour sécuriser son contenu.",
|
||||
"desc1": "Si vous souhaitez stocker ces identifiants dans un référentiel Git public, vous devez les chiffrer en fournissant une phrase clé secrète.",
|
||||
"desc2": "Votre fichier d'identifiants de flux n'est actuellement pas chiffré.",
|
||||
@@ -1161,9 +1174,9 @@
|
||||
"add-ssh-key": "Ajouter une clé ssh",
|
||||
"credentials-encryption-key": "Clé de chiffrement des identifiants",
|
||||
"already-exists-2": "Existe déjà",
|
||||
"git-error": "Erreur git",
|
||||
"git-error": "Erreur Git",
|
||||
"con-failed": "La connexion a échoué",
|
||||
"not-git": "Ce n'est pas un dépôt git",
|
||||
"not-git": "Ce n'est pas un dépôt Git",
|
||||
"no-resource": "Référentiel introuvable",
|
||||
"cant-get-ssh-key-path": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.",
|
||||
"unexpected_error": "Erreur inattendue",
|
||||
@@ -1201,7 +1214,7 @@
|
||||
},
|
||||
"errors": {
|
||||
"no-username-email": "Votre client Git n'est pas configuré avec un nom d'utilisateur/e-mail.",
|
||||
"unexpected": "Une erreur inattendue est apparue",
|
||||
"unexpected": "Une erreur inattendue est survenue",
|
||||
"code": "Code"
|
||||
}
|
||||
},
|
||||
@@ -1270,7 +1283,7 @@
|
||||
"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",
|
||||
"list-subflows": "Lister 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",
|
||||
@@ -1330,8 +1343,8 @@
|
||||
"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",
|
||||
"distribute-selection-horizontally": "Répartir la sélection horizontalement",
|
||||
"distribute-selection-vertical": "Répartir 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",
|
||||
|
||||
@@ -375,7 +375,10 @@
|
||||
"flowAdded": "追加されたフロー",
|
||||
"moved": "移動",
|
||||
"movedTo": "__id__ へ移動",
|
||||
"movedFrom": "__id__ から移動"
|
||||
"movedFrom": "__id__ から移動",
|
||||
"none": "なし",
|
||||
"position": "位置",
|
||||
"wires": "ワイヤー"
|
||||
},
|
||||
"nodeCount": "__count__ 個のノード",
|
||||
"nodeCount_plural": "__count__ 個のノード",
|
||||
@@ -384,9 +387,14 @@
|
||||
"reviewChanges": "変更を表示",
|
||||
"noBinaryFileShowed": "バイナリファイルの中身は表示することができません",
|
||||
"viewCommitDiff": "コミットの内容を表示",
|
||||
"commit": "コミット",
|
||||
"compareChanges": "変更を比較",
|
||||
"saveConflict": "解決して保存",
|
||||
"conflictHeader": "<span>__unresolved__</span> 個中 <span>__resolved__</span> 個のコンフリクトを解決",
|
||||
"localChanges": "ローカルの変更",
|
||||
"remoteChanges": "リモートの変更",
|
||||
"useLocalChanges": "ローカルの変更を使用",
|
||||
"useRemoteChanges": "リモートの変更を使用",
|
||||
"commonVersionError": "共通バージョンは正しいJSON形式ではありません:",
|
||||
"oldVersionError": "古いバージョンは正しいJSON形式ではありません:",
|
||||
"newVersionError": "新しいバージョンは正しいJSON形式ではありません:"
|
||||
@@ -554,7 +562,9 @@
|
||||
"types": {
|
||||
"local": "ローカル",
|
||||
"examples": "サンプル"
|
||||
}
|
||||
},
|
||||
"type": "型",
|
||||
"name": "名前"
|
||||
},
|
||||
"palette": {
|
||||
"noInfo": "情報がありません",
|
||||
@@ -803,6 +813,7 @@
|
||||
"branches": "ブランチ",
|
||||
"noBranches": "ブランチなし",
|
||||
"deleteConfirm": "本当にローカルブランチ'__name__'を削除しますか?削除すると元に戻すことはできません。",
|
||||
"deleteBranch": "ブランチを削除",
|
||||
"unmergedConfirm": "ローカルブランチ'__name__'にはマージされていない変更があります。この変更は削除されます。本当に削除しますか?",
|
||||
"deleteUnmergedBranch": "マージされていないブランチを削除",
|
||||
"gitRemotes": "Gitリモート",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@node-red/editor-client",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.5",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -100,16 +100,36 @@ RED.multiplayer = (function () {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (isInWorkspace) {
|
||||
const chart = $('#red-ui-workspace-chart')
|
||||
const chartOffset = chart.offset()
|
||||
const scaleFactor = RED.view.scale()
|
||||
location.cursor = {
|
||||
x: (lastPosition[0] - chartOffset.left + chart.scrollLeft()) / scaleFactor,
|
||||
y: (lastPosition[1] - chartOffset.top + chart.scrollTop()) / scaleFactor
|
||||
}
|
||||
}
|
||||
return location
|
||||
}
|
||||
|
||||
let publishLocationTimeout
|
||||
let lastPosition = [0,0]
|
||||
let isInWorkspace = false
|
||||
|
||||
function publishLocation () {
|
||||
const location = getLocation()
|
||||
if (location.workspace !== 0) {
|
||||
log('send', 'multiplayer/location', location)
|
||||
RED.comms.send('multiplayer/location', location)
|
||||
if (!publishLocationTimeout) {
|
||||
publishLocationTimeout = setTimeout(() => {
|
||||
const location = getLocation()
|
||||
if (location.workspace !== 0) {
|
||||
log('send', 'multiplayer/location', location)
|
||||
RED.comms.send('multiplayer/location', location)
|
||||
}
|
||||
publishLocationTimeout = null
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function revealUser(location, skipWorkspace) {
|
||||
if (location.node) {
|
||||
// Need to check if this is a known node, so we can fall back to revealing
|
||||
@@ -271,7 +291,16 @@ RED.multiplayer = (function () {
|
||||
|
||||
function removeUserLocation (sessionId) {
|
||||
updateUserLocation(sessionId, {})
|
||||
removeUserCursor(sessionId)
|
||||
}
|
||||
function removeUserCursor (sessionId) {
|
||||
// return
|
||||
if (sessions[sessionId]?.cursor) {
|
||||
sessions[sessionId].cursor.parentNode.removeChild(sessions[sessionId].cursor)
|
||||
delete sessions[sessionId].cursor
|
||||
}
|
||||
}
|
||||
|
||||
function updateUserLocation (sessionId, location) {
|
||||
let viewTouched = false
|
||||
const oldLocation = sessions[sessionId].location
|
||||
@@ -291,6 +320,28 @@ RED.multiplayer = (function () {
|
||||
// console.log(`updateUserLocation sessionId:${sessionId} oldWS:${oldLocation?.workspace} newWS:${location.workspace}`)
|
||||
if (location.workspace) {
|
||||
getWorkspaceTray(location.workspace).addUser(sessionId)
|
||||
if (location.cursor && location.workspace === RED.workspaces.active()) {
|
||||
if (!sessions[sessionId].cursor) {
|
||||
const user = sessions[sessionId].user
|
||||
const cursorIcon = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
cursorIcon.setAttribute("class", "red-ui-multiplayer-annotation")
|
||||
cursorIcon.appendChild(createAnnotationUser(user, true))
|
||||
$(cursorIcon).css({
|
||||
transform: `translate( ${location.cursor.x}px, ${location.cursor.y}px)`,
|
||||
transition: 'transform 0.1s linear'
|
||||
})
|
||||
$("#red-ui-workspace-chart svg").append(cursorIcon)
|
||||
sessions[sessionId].cursor = cursorIcon
|
||||
} else {
|
||||
const cursorIcon = sessions[sessionId].cursor
|
||||
$(cursorIcon).css({
|
||||
transform: `translate( ${location.cursor.x}px, ${location.cursor.y}px)`
|
||||
})
|
||||
|
||||
}
|
||||
} else if (sessions[sessionId].cursor) {
|
||||
removeUserCursor(sessionId)
|
||||
}
|
||||
}
|
||||
if (location.node) {
|
||||
addUserToNode(sessionId, location.node)
|
||||
@@ -309,67 +360,69 @@ RED.multiplayer = (function () {
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
function createAnnotationUser(user, pointer = false) {
|
||||
const radius = 20
|
||||
const halfRadius = radius/2
|
||||
const group = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
const badge = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
let shapePath
|
||||
if (!pointer) {
|
||||
shapePath = `M 0 ${halfRadius} a ${halfRadius} ${halfRadius} 0 1 1 ${radius} 0 a ${halfRadius} ${halfRadius} 0 1 1 -${radius} 0 z`
|
||||
} else {
|
||||
shapePath = `M 0 0 h ${halfRadius} a ${halfRadius} ${halfRadius} 0 1 1 -${halfRadius} ${halfRadius} z`
|
||||
}
|
||||
badge.setAttribute('d', shapePath)
|
||||
badge.setAttribute("class", "red-ui-multiplayer-annotation-background")
|
||||
group.appendChild(badge)
|
||||
if (user && user.profileColor !== undefined) {
|
||||
badge.setAttribute("class", "red-ui-multiplayer-annotation-background red-ui-user-profile-color-" + user.profileColor)
|
||||
}
|
||||
if (user && user.image) {
|
||||
const image = document.createElementNS("http://www.w3.org/2000/svg","image");
|
||||
image.setAttribute("width", radius)
|
||||
image.setAttribute("height", radius)
|
||||
image.setAttribute("href", user.image)
|
||||
image.setAttribute("clip-path", "circle("+Math.floor(radius/2)+")")
|
||||
group.appendChild(image)
|
||||
} else if (user && user.anonymous) {
|
||||
const anonIconHead = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||
anonIconHead.setAttribute("cx", radius/2)
|
||||
anonIconHead.setAttribute("cy", radius/2 - 2)
|
||||
anonIconHead.setAttribute("r", 2.4)
|
||||
anonIconHead.setAttribute("class","red-ui-multiplayer-annotation-anon-label");
|
||||
group.appendChild(anonIconHead)
|
||||
const anonIconBody = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
anonIconBody.setAttribute("class","red-ui-multiplayer-annotation-anon-label");
|
||||
// anonIconBody.setAttribute("d",`M ${radius/2 - 4} ${radius/2 + 1} h 8 v4 h -8 z`);
|
||||
anonIconBody.setAttribute("d",`M ${radius/2} ${radius/2 + 5} h -2.5 c -2 1 -2 -5 0.5 -4.5 c 2 1 2 1 4 0 c 2.5 -0.5 2.5 5.5 0 4.5 z`);
|
||||
group.appendChild(anonIconBody)
|
||||
} else {
|
||||
const labelText = user.username ? user.username.substring(0,2) : user
|
||||
const label = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
if (user.username) {
|
||||
label.setAttribute("class","red-ui-multiplayer-annotation-label");
|
||||
label.textContent = user.username.substring(0,2)
|
||||
} else {
|
||||
label.setAttribute("class","red-ui-multiplayer-annotation-label red-ui-multiplayer-user-count")
|
||||
label.textContent = user
|
||||
}
|
||||
label.setAttribute("text-anchor", "middle")
|
||||
label.setAttribute("x",radius/2);
|
||||
label.setAttribute("y",radius/2 + 3);
|
||||
group.appendChild(label)
|
||||
}
|
||||
const border = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
border.setAttribute('d', shapePath)
|
||||
border.setAttribute("class", "red-ui-multiplayer-annotation-border")
|
||||
group.appendChild(border)
|
||||
return group
|
||||
}
|
||||
|
||||
return {
|
||||
init: function () {
|
||||
|
||||
function createAnnotationUser(user) {
|
||||
|
||||
const group = document.createElementNS("http://www.w3.org/2000/svg","g");
|
||||
const badge = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||
const radius = 20
|
||||
badge.setAttribute("cx",radius/2);
|
||||
badge.setAttribute("cy",radius/2);
|
||||
badge.setAttribute("r",radius/2);
|
||||
badge.setAttribute("class", "red-ui-multiplayer-annotation-background")
|
||||
group.appendChild(badge)
|
||||
if (user && user.profileColor !== undefined) {
|
||||
badge.setAttribute("class", "red-ui-multiplayer-annotation-background red-ui-user-profile-color-" + user.profileColor)
|
||||
}
|
||||
if (user && user.image) {
|
||||
const image = document.createElementNS("http://www.w3.org/2000/svg","image");
|
||||
image.setAttribute("width", radius)
|
||||
image.setAttribute("height", radius)
|
||||
image.setAttribute("href", user.image)
|
||||
image.setAttribute("clip-path", "circle("+Math.floor(radius/2)+")")
|
||||
group.appendChild(image)
|
||||
} else if (user && user.anonymous) {
|
||||
const anonIconHead = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||
anonIconHead.setAttribute("cx", radius/2)
|
||||
anonIconHead.setAttribute("cy", radius/2 - 2)
|
||||
anonIconHead.setAttribute("r", 2.4)
|
||||
anonIconHead.setAttribute("class","red-ui-multiplayer-annotation-anon-label");
|
||||
group.appendChild(anonIconHead)
|
||||
const anonIconBody = document.createElementNS("http://www.w3.org/2000/svg","path");
|
||||
anonIconBody.setAttribute("class","red-ui-multiplayer-annotation-anon-label");
|
||||
// anonIconBody.setAttribute("d",`M ${radius/2 - 4} ${radius/2 + 1} h 8 v4 h -8 z`);
|
||||
anonIconBody.setAttribute("d",`M ${radius/2} ${radius/2 + 5} h -2.5 c -2 1 -2 -5 0.5 -4.5 c 2 1 2 1 4 0 c 2.5 -0.5 2.5 5.5 0 4.5 z`);
|
||||
group.appendChild(anonIconBody)
|
||||
} else {
|
||||
const labelText = user.username ? user.username.substring(0,2) : user
|
||||
const label = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
if (user.username) {
|
||||
label.setAttribute("class","red-ui-multiplayer-annotation-label");
|
||||
label.textContent = user.username.substring(0,2)
|
||||
} else {
|
||||
label.setAttribute("class","red-ui-multiplayer-annotation-label red-ui-multiplayer-user-count")
|
||||
label.textContent = user
|
||||
}
|
||||
label.setAttribute("text-anchor", "middle")
|
||||
label.setAttribute("x",radius/2);
|
||||
label.setAttribute("y",radius/2 + 3);
|
||||
group.appendChild(label)
|
||||
}
|
||||
const border = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
||||
border.setAttribute("cx",radius/2);
|
||||
border.setAttribute("cy",radius/2);
|
||||
border.setAttribute("r",radius/2);
|
||||
border.setAttribute("class", "red-ui-multiplayer-annotation-border")
|
||||
group.appendChild(border)
|
||||
|
||||
|
||||
|
||||
return group
|
||||
}
|
||||
|
||||
|
||||
RED.view.annotations.register("red-ui-multiplayer",{
|
||||
type: 'badge',
|
||||
@@ -479,6 +532,24 @@ RED.multiplayer = (function () {
|
||||
RED.comms.send('multiplayer/disconnect', disconnectInfo)
|
||||
RED.settings.removeLocal('multiplayer:sessionId')
|
||||
})
|
||||
|
||||
const chart = $('#red-ui-workspace-chart')
|
||||
chart.on('mousemove', function (evt) {
|
||||
lastPosition[0] = evt.clientX
|
||||
lastPosition[1] = evt.clientY
|
||||
publishLocation()
|
||||
})
|
||||
chart.on('scroll', function (evt) {
|
||||
publishLocation()
|
||||
})
|
||||
chart.on('mouseenter', function () {
|
||||
isInWorkspace = true
|
||||
publishLocation()
|
||||
})
|
||||
chart.on('mouseleave', function () {
|
||||
isInWorkspace = false
|
||||
publishLocation()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,13 @@ RED.nodes = (function() {
|
||||
|
||||
var exports = {
|
||||
setModulePendingUpdated: function(module,version) {
|
||||
moduleList[module].pending_version = version;
|
||||
if (!!RED.plugins.getModule(module)) {
|
||||
// The module updated is a plugin
|
||||
RED.plugins.getModule(module).pending_version = version;
|
||||
} else {
|
||||
moduleList[module].pending_version = version;
|
||||
}
|
||||
|
||||
RED.events.emit("registry:module-updated",{module:module,version:version});
|
||||
},
|
||||
getModule: function(module) {
|
||||
@@ -1032,23 +1038,34 @@ RED.nodes = (function() {
|
||||
return {nodes:removedNodes,links:removedLinks, groups: removedGroups, junctions: removedJunctions};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Subflow to the Workspace
|
||||
*
|
||||
* @param {object} sf The Subflow to add.
|
||||
* @param {boolean|undefined} createNewIds Whether to update the name.
|
||||
*/
|
||||
function addSubflow(sf, createNewIds) {
|
||||
if (createNewIds) {
|
||||
var subflowNames = Object.keys(subflows).map(function(sfid) {
|
||||
return subflows[sfid].name;
|
||||
});
|
||||
// Update the Subflow name to highlight that this is a copy
|
||||
const subflowNames = Object.keys(subflows).map(function (sfid) {
|
||||
return subflows[sfid].name || "";
|
||||
})
|
||||
subflowNames.sort()
|
||||
|
||||
subflowNames.sort();
|
||||
var copyNumber = 1;
|
||||
var subflowName = sf.name;
|
||||
let copyNumber = 1;
|
||||
let subflowName = sf.name;
|
||||
subflowNames.forEach(function(name) {
|
||||
if (subflowName == name) {
|
||||
subflowName = sf.name + " (" + copyNumber + ")";
|
||||
copyNumber++;
|
||||
subflowName = sf.name+" ("+copyNumber+")";
|
||||
}
|
||||
});
|
||||
|
||||
sf.name = subflowName;
|
||||
}
|
||||
|
||||
sf.instances = [];
|
||||
|
||||
subflows[sf.id] = sf;
|
||||
allNodes.addTab(sf.id);
|
||||
linkTabMap[sf.id] = [];
|
||||
@@ -1101,7 +1118,7 @@ RED.nodes = (function() {
|
||||
module: "node-red"
|
||||
}
|
||||
});
|
||||
sf.instances = [];
|
||||
|
||||
sf._def = RED.nodes.getType("subflow:"+sf.id);
|
||||
RED.events.emit("subflows:add",sf);
|
||||
}
|
||||
@@ -1743,7 +1760,8 @@ RED.nodes = (function() {
|
||||
// Remove the old subflow definition - but leave the instances in place
|
||||
var removalResult = RED.subflow.removeSubflow(n.id, true);
|
||||
// Create the list of nodes for the new subflow def
|
||||
var subflowNodes = [n].concat(zMap[n.id]);
|
||||
// Need to sort the list in order to remove missing nodes
|
||||
var subflowNodes = [n].concat(zMap[n.id]).filter((s) => !!s);
|
||||
// Import the new subflow - no clashes should occur as we've removed
|
||||
// the old version
|
||||
var result = importNodes(subflowNodes);
|
||||
@@ -2023,6 +2041,8 @@ RED.nodes = (function() {
|
||||
if (matchingSubflow) {
|
||||
subflow_denylist[n.id] = matchingSubflow;
|
||||
} else {
|
||||
const oldId = n.id;
|
||||
|
||||
subflow_map[n.id] = n;
|
||||
if (createNewIds || options.importMap[n.id] === "copy") {
|
||||
nid = getID();
|
||||
@@ -2050,7 +2070,7 @@ RED.nodes = (function() {
|
||||
n.status.id = getID();
|
||||
}
|
||||
new_subflows.push(n);
|
||||
addSubflow(n,createNewIds || options.importMap[n.id] === "copy");
|
||||
addSubflow(n,createNewIds || options.importMap[oldId] === "copy");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2170,7 +2190,7 @@ RED.nodes = (function() {
|
||||
x:parseFloat(n.x || 0),
|
||||
y:parseFloat(n.y || 0),
|
||||
z:n.z,
|
||||
type:0,
|
||||
type: n.type,
|
||||
info: n.info,
|
||||
changed:false,
|
||||
_config:{}
|
||||
@@ -2231,7 +2251,6 @@ RED.nodes = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
node.type = n.type;
|
||||
node._def = def;
|
||||
if (node.type === "group") {
|
||||
node._def = RED.group.def;
|
||||
@@ -2261,6 +2280,15 @@ RED.nodes = (function() {
|
||||
outputs: n.outputs|| (n.wires && n.wires.length) || 0,
|
||||
set: registry.getNodeSet("node-red/unknown")
|
||||
}
|
||||
var orig = {};
|
||||
for (var p in n) {
|
||||
if (n.hasOwnProperty(p) && p!="x" && p!="y" && p!="z" && p!="id" && p!="wires") {
|
||||
orig[p] = n[p];
|
||||
}
|
||||
}
|
||||
node._orig = orig;
|
||||
node.name = n.type;
|
||||
node.type = "unknown";
|
||||
} else {
|
||||
if (subflow_denylist[parentId] || createNewIds || options.importMap[n.id] === "copy") {
|
||||
parentId = subflow.id;
|
||||
@@ -2406,11 +2434,28 @@ RED.nodes = (function() {
|
||||
} else {
|
||||
delete n.g
|
||||
}
|
||||
// If importing into a subflow, ensure an outbound-link doesn't get added
|
||||
if (activeSubflow && /^link /.test(n.type) && n.links) {
|
||||
// If importing a link node, ensure both ends of each link are either:
|
||||
// - not in a subflow
|
||||
// - both in the same subflow (not for link call node)
|
||||
if (/^link /.test(n.type) && n.links) {
|
||||
n.links = n.links.filter(function(id) {
|
||||
const otherNode = node_map[id] || RED.nodes.node(id);
|
||||
return (otherNode && otherNode.z === activeWorkspace);
|
||||
if (!otherNode) {
|
||||
// Cannot find other end - remove the link
|
||||
return false
|
||||
}
|
||||
if (otherNode.z === n.z) {
|
||||
// Both ends in the same flow/subflow
|
||||
return true
|
||||
} else if (n.type === "link call" && !getSubflow(otherNode.z)) {
|
||||
// Link call node can call out of a subflow as long as otherNode is
|
||||
// not in a subflow
|
||||
return true
|
||||
} else if (!!getSubflow(n.z) || !!getSubflow(otherNode.z)) {
|
||||
// One end is in a subflow - remove the link
|
||||
return false
|
||||
}
|
||||
return true
|
||||
});
|
||||
}
|
||||
for (var d3 in n._def.defaults) {
|
||||
@@ -2441,9 +2486,11 @@ RED.nodes = (function() {
|
||||
n = new_subflows[i];
|
||||
n.in.forEach(function(input) {
|
||||
input.wires.forEach(function(wire) {
|
||||
var link = {source:input, sourcePort:0, target:node_map[wire.id]};
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
if (node_map.hasOwnProperty(wire.id)) {
|
||||
var link = {source:input, sourcePort:0, target:node_map[wire.id]};
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
}
|
||||
});
|
||||
delete input.wires;
|
||||
});
|
||||
@@ -2452,11 +2499,13 @@ RED.nodes = (function() {
|
||||
var link;
|
||||
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
|
||||
link = {source:n.in[wire.port], sourcePort:wire.port,target:output};
|
||||
} else {
|
||||
} else if (node_map.hasOwnProperty(wire.id) || subflow_map.hasOwnProperty(wire.id)) {
|
||||
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:output};
|
||||
}
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
if (link) {
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
}
|
||||
});
|
||||
delete output.wires;
|
||||
});
|
||||
@@ -2465,11 +2514,13 @@ RED.nodes = (function() {
|
||||
var link;
|
||||
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
|
||||
link = {source:n.in[wire.port], sourcePort:wire.port,target:n.status};
|
||||
} else {
|
||||
} else if (node_map.hasOwnProperty(wire.id) || subflow_map.hasOwnProperty(wire.id)) {
|
||||
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:n.status};
|
||||
}
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
if (link) {
|
||||
addLink(link);
|
||||
new_links.push(link);
|
||||
}
|
||||
});
|
||||
delete n.status.wires;
|
||||
}
|
||||
|
||||
@@ -205,7 +205,9 @@ RED.actionList = (function() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
RED.actions.add("core:show-action-list",show);
|
||||
if (RED.settings.theme("menu.menu-item-action-list", true)) {
|
||||
RED.actions.add("core:show-action-list",show);
|
||||
}
|
||||
|
||||
RED.events.on("editor:open",function() { disabled = true; });
|
||||
RED.events.on("editor:close",function() { disabled = false; });
|
||||
|
||||
@@ -32,24 +32,28 @@ RED.contextMenu = (function () {
|
||||
const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g
|
||||
let hasGroup, isAllGroups = true, hasDisabledNode, hasEnabledNode, hasLabeledNode, hasUnlabeledNode;
|
||||
if (hasSelection) {
|
||||
selection.nodes.forEach(n => {
|
||||
const nodes = selection.nodes.slice();
|
||||
while (nodes.length) {
|
||||
const n = nodes.shift();
|
||||
if (n.type === 'group') {
|
||||
hasGroup = true;
|
||||
nodes.push(...n.nodes);
|
||||
} else {
|
||||
isAllGroups = false;
|
||||
}
|
||||
if (n.d) {
|
||||
hasDisabledNode = true;
|
||||
} else {
|
||||
hasEnabledNode = true;
|
||||
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()
|
||||
@@ -61,10 +65,11 @@ RED.contextMenu = (function () {
|
||||
addY = gridSize * Math.floor(addY / gridSize)
|
||||
}
|
||||
|
||||
menuItems.push(
|
||||
{ onselect: 'core:show-action-list', label: RED._("contextMenu.showActionList"), onpostselect: function () { } }
|
||||
)
|
||||
|
||||
if (RED.settings.theme("menu.menu-item-action-list", true)) {
|
||||
menuItems.push(
|
||||
{ onselect: 'core:show-action-list', label: RED._("contextMenu.showActionList"), onpostselect: function () { } }
|
||||
)
|
||||
}
|
||||
const insertOptions = []
|
||||
menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions })
|
||||
insertOptions.push(
|
||||
|
||||
@@ -589,7 +589,9 @@ RED.deploy = (function() {
|
||||
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
||||
}
|
||||
const flowsToLock = new Set()
|
||||
// Node's properties cannot be modified if its workspace is locked.
|
||||
function ensureUnlocked(id) {
|
||||
// TODO: `RED.nodes.subflow` is useless
|
||||
const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null);
|
||||
const isLocked = flow ? flow.locked : false;
|
||||
if (flow && isLocked) {
|
||||
@@ -642,6 +644,7 @@ RED.deploy = (function() {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
// Subflow cannot be locked
|
||||
RED.nodes.eachSubflow(function (subflow) {
|
||||
if (subflow.changed) {
|
||||
subflow.changed = false;
|
||||
@@ -650,12 +653,18 @@ RED.deploy = (function() {
|
||||
});
|
||||
RED.nodes.eachWorkspace(function (ws) {
|
||||
if (ws.changed || ws.added) {
|
||||
ensureUnlocked(ws.z)
|
||||
// Ensure the Workspace is unlocked to modify its properties.
|
||||
ensureUnlocked(ws.id);
|
||||
ws.changed = false;
|
||||
delete ws.added
|
||||
if (flowsToLock.has(ws)) {
|
||||
ws.locked = true;
|
||||
flowsToLock.delete(ws);
|
||||
}
|
||||
RED.events.emit("flows:change", ws)
|
||||
}
|
||||
});
|
||||
// Ensures all workspaces to be locked have been locked.
|
||||
flowsToLock.forEach(flow => {
|
||||
flow.locked = true
|
||||
})
|
||||
|
||||
@@ -497,7 +497,7 @@ RED.diff = (function() {
|
||||
}
|
||||
})
|
||||
if (c === 0) {
|
||||
result.text("none");
|
||||
result.text(RED._("diff.type.none"));
|
||||
} else {
|
||||
list.appendTo(result);
|
||||
}
|
||||
@@ -821,7 +821,7 @@ RED.diff = (function() {
|
||||
conflict = true;
|
||||
}
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"red-ui-diff-list-cell-label"}).text("position").appendTo(row);
|
||||
$("<td>",{class:"red-ui-diff-list-cell-label"}).text(RED._("diff.type.position")).appendTo(row);
|
||||
localCell = $("<td>",{class:"red-ui-diff-list-cell red-ui-diff-list-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
localCell.addClass("red-ui-diff-status-"+(localChanged?"moved":"unchanged"));
|
||||
@@ -899,7 +899,7 @@ RED.diff = (function() {
|
||||
conflict = true;
|
||||
}
|
||||
row = $("<tr>").appendTo(nodePropertiesTableBody);
|
||||
$("<td>",{class:"red-ui-diff-list-cell-label"}).text("wires").appendTo(row);
|
||||
$("<td>",{class:"red-ui-diff-list-cell-label"}).text(RED._("diff.type.wires")).appendTo(row);
|
||||
localCell = $("<td>",{class:"red-ui-diff-list-cell red-ui-diff-list-node-local"}).appendTo(row);
|
||||
if (localNode) {
|
||||
if (!conflict) {
|
||||
@@ -2029,15 +2029,14 @@ RED.diff = (function() {
|
||||
if (!isSeparator) {
|
||||
var isOurs = /^..<<<<<<</.test(lineText);
|
||||
if (isOurs) {
|
||||
$('<span>').text("<<<<<<< Local Changes").appendTo(line);
|
||||
$('<span>').text("<<<<<<< " + RED._("diff.localChanges")).appendTo(line);
|
||||
hunk.localChangeStart = actualLineNumber;
|
||||
} else {
|
||||
hunk.remoteChangeEnd = actualLineNumber;
|
||||
$('<span>').text(">>>>>>> Remote Changes").appendTo(line);
|
||||
|
||||
$('<span>').text(">>>>>>> " + RED._("diff.remoteChanges")).appendTo(line);
|
||||
}
|
||||
diffRow.addClass("mergeHeader-"+(isOurs?"ours":"theirs"));
|
||||
$('<button class="red-ui-button red-ui-button-small" style="float: right; margin-right: 20px;"><i class="fa fa-angle-double-'+(isOurs?"down":"up")+'"></i> use '+(isOurs?"local":"remote")+' changes</button>')
|
||||
$('<button class="red-ui-button red-ui-button-small" style="float: right; margin-right: 20px;"><i class="fa fa-angle-double-'+(isOurs?"down":"up")+'"></i> '+RED._(isOurs?"diff.useLocalChanges":"diff.useRemoteChanges")+'</button>')
|
||||
.appendTo(line)
|
||||
.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
@@ -2119,7 +2118,7 @@ RED.diff = (function() {
|
||||
$("<h3>").text(commit.title).appendTo(content);
|
||||
$('<div class="commit-body"></div>').text(commit.comment).appendTo(content);
|
||||
var summary = $('<div class="commit-summary"></div>').appendTo(content);
|
||||
$('<div style="float: right">').text("Commit "+commit.sha).appendTo(summary);
|
||||
$('<div style="float: right">').text(RED._('diff.commit')+" "+commit.sha).appendTo(summary);
|
||||
$('<div>').text((commit.authorName||commit.author)+" - "+options.date).appendTo(summary);
|
||||
|
||||
if (commit.files) {
|
||||
|
||||
@@ -808,6 +808,17 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
const oldCreds = {};
|
||||
if (editing_node._def.credentials) {
|
||||
for (const prop in editing_node._def.credentials) {
|
||||
if (Object.prototype.hasOwnProperty.call(editing_node._def.credentials, prop)) {
|
||||
if (prop in editing_node.credentials) {
|
||||
oldCreds[prop] = editing_node.credentials[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const rc = editing_node._def.oneditsave.call(editing_node);
|
||||
if (rc === true) {
|
||||
@@ -839,6 +850,21 @@ RED.editor = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (editing_node._def.credentials) {
|
||||
for (const prop in editing_node._def.credentials) {
|
||||
if (Object.prototype.hasOwnProperty.call(editing_node._def.credentials, prop)) {
|
||||
if (oldCreds[prop] !== editing_node.credentials[prop]) {
|
||||
if (editing_node.credentials[prop] === '__PWRD__') {
|
||||
continue;
|
||||
}
|
||||
editState.changes.credentials = editState.changes.credentials || {};
|
||||
editState.changes.credentials[prop] = oldCreds[prop];
|
||||
editState.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +925,7 @@ RED.editor = (function() {
|
||||
const labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"] || tenv.name, locale)
|
||||
const config = {
|
||||
env: tenv,
|
||||
id: '${' + parentEnv[0].name + '}',
|
||||
id: '${' + tenv.name + '}',
|
||||
type: type,
|
||||
label: labelText,
|
||||
__label__: `[env] ${labelText}`
|
||||
@@ -1481,134 +1507,181 @@ RED.editor = (function() {
|
||||
},
|
||||
{
|
||||
id: "node-config-dialog-ok",
|
||||
text: adding?RED._("editor.configAdd"):RED._("editor.configUpdate"),
|
||||
text: adding ? RED._("editor.configAdd") : RED._("editor.configUpdate"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
var editState = {
|
||||
// TODO: Already defined
|
||||
const configProperty = name;
|
||||
const configType = type;
|
||||
const configTypeDef = RED.nodes.getType(configType);
|
||||
|
||||
const wasChanged = editing_config_node.changed;
|
||||
const editState = {
|
||||
changes: {},
|
||||
changed: false,
|
||||
outputMap: null
|
||||
};
|
||||
var configProperty = name;
|
||||
var configId = editing_config_node.id;
|
||||
var configType = type;
|
||||
var configAdding = adding;
|
||||
var configTypeDef = RED.nodes.getType(configType);
|
||||
var d;
|
||||
var input;
|
||||
|
||||
// Call `oneditsave` and search for changes
|
||||
handleEditSave(editing_config_node, editState);
|
||||
|
||||
if (configTypeDef.oneditsave) {
|
||||
try {
|
||||
configTypeDef.oneditsave.call(editing_config_node);
|
||||
} catch(err) {
|
||||
console.warn("oneditsave",editing_config_node.id,editing_config_node.type,err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
for (d in configTypeDef.defaults) {
|
||||
if (configTypeDef.defaults.hasOwnProperty(d)) {
|
||||
var newValue;
|
||||
input = $("#node-config-input-"+d);
|
||||
if (input.attr('type') === "checkbox") {
|
||||
newValue = input.prop('checked');
|
||||
} else if ("format" in configTypeDef.defaults[d] && configTypeDef.defaults[d].format !== "" && input[0].nodeName === "DIV") {
|
||||
newValue = input.text();
|
||||
} else {
|
||||
newValue = input.val();
|
||||
}
|
||||
if (newValue != null && newValue !== editing_config_node[d]) {
|
||||
if (editing_config_node._def.defaults[d].type) {
|
||||
if (newValue == "_ADD_") {
|
||||
newValue = "";
|
||||
}
|
||||
// Change to a related config node
|
||||
var configNode = RED.nodes.node(editing_config_node[d]);
|
||||
if (configNode) {
|
||||
var users = configNode.users;
|
||||
users.splice(users.indexOf(editing_config_node),1);
|
||||
RED.events.emit("nodes:change",configNode);
|
||||
}
|
||||
configNode = RED.nodes.node(newValue);
|
||||
if (configNode) {
|
||||
configNode.users.push(editing_config_node);
|
||||
RED.events.emit("nodes:change",configNode);
|
||||
}
|
||||
}
|
||||
editing_config_node[d] = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activeEditPanes.forEach(function(pane) {
|
||||
// Search for changes in the edit box (panes)
|
||||
activeEditPanes.forEach(function (pane) {
|
||||
if (pane.apply) {
|
||||
pane.apply.call(pane, editState);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
editing_config_node.label = configTypeDef.label;
|
||||
|
||||
var scope = $("#red-ui-editor-config-scope").val();
|
||||
editing_config_node.z = scope;
|
||||
// TODO: Why?
|
||||
editing_config_node.label = configTypeDef.label
|
||||
|
||||
// Check if disabled has changed
|
||||
if ($("#node-config-input-node-disabled").prop('checked')) {
|
||||
if (editing_config_node.d !== true) {
|
||||
editState.changes.d = editing_config_node.d;
|
||||
editState.changed = true;
|
||||
editing_config_node.d = true;
|
||||
}
|
||||
} else {
|
||||
if (editing_config_node.d === true) {
|
||||
editState.changes.d = editing_config_node.d;
|
||||
editState.changed = true;
|
||||
delete editing_config_node.d;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: must be undefined if no scope used
|
||||
const scope = $("#red-ui-editor-config-scope").val() || undefined;
|
||||
|
||||
// Check if the scope has changed
|
||||
if (editing_config_node.z !== scope) {
|
||||
editState.changes.z = editing_config_node.z;
|
||||
editState.changed = true;
|
||||
editing_config_node.z = scope;
|
||||
}
|
||||
|
||||
// Search for nodes that use this config node that are no longer
|
||||
// in scope, so must be removed
|
||||
const historyEvents = [];
|
||||
if (scope) {
|
||||
// Search for nodes that use this one that are no longer
|
||||
// in scope, so must be removed
|
||||
editing_config_node.users = editing_config_node.users.filter(function(n) {
|
||||
var keep = true;
|
||||
for (var d in n._def.defaults) {
|
||||
if (n._def.defaults.hasOwnProperty(d)) {
|
||||
if (n._def.defaults[d].type === editing_config_node.type &&
|
||||
n[d] === editing_config_node.id &&
|
||||
n.z !== scope) {
|
||||
keep = false;
|
||||
// Remove the reference to this node
|
||||
// and revalidate
|
||||
n[d] = null;
|
||||
n.dirty = true;
|
||||
n.changed = true;
|
||||
validateNode(n);
|
||||
const newUsers = editing_config_node.users.filter(function (node) {
|
||||
let keepNode = false;
|
||||
let nodeModified = null;
|
||||
|
||||
for (const d in node._def.defaults) {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
if (node._def.defaults[d].type === editing_config_node.type) {
|
||||
if (node[d] === editing_config_node.id) {
|
||||
if (node.z === editing_config_node.z) {
|
||||
// The node is kept only if at least one property uses
|
||||
// this config node in the correct scope.
|
||||
keepNode = true;
|
||||
} else {
|
||||
if (!nodeModified) {
|
||||
nodeModified = {
|
||||
t: "edit",
|
||||
node: node,
|
||||
changes: { [d]: node[d] },
|
||||
changed: node.changed,
|
||||
dirty: node.dirty
|
||||
};
|
||||
} else {
|
||||
nodeModified.changes[d] = node[d];
|
||||
}
|
||||
|
||||
// Remove the reference to the config node
|
||||
node[d] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return keep;
|
||||
});
|
||||
}
|
||||
|
||||
if (configAdding) {
|
||||
RED.nodes.add(editing_config_node);
|
||||
}
|
||||
|
||||
validateNode(editing_config_node);
|
||||
var validatedNodes = {};
|
||||
validatedNodes[editing_config_node.id] = true;
|
||||
|
||||
var userStack = editing_config_node.users.slice();
|
||||
while(userStack.length > 0) {
|
||||
var user = userStack.pop();
|
||||
if (!validatedNodes[user.id]) {
|
||||
validatedNodes[user.id] = true;
|
||||
if (user.users) {
|
||||
userStack = userStack.concat(user.users);
|
||||
// Add the node modified to the history
|
||||
if (nodeModified) {
|
||||
historyEvents.push(nodeModified);
|
||||
}
|
||||
validateNode(user);
|
||||
|
||||
// Mark as changed and revalidate this node
|
||||
if (!keepNode) {
|
||||
node.changed = true;
|
||||
node.dirty = true;
|
||||
validateNode(node);
|
||||
RED.events.emit("nodes:change", node);
|
||||
}
|
||||
|
||||
return keepNode;
|
||||
});
|
||||
|
||||
// Check if users are changed
|
||||
if (editing_config_node.users.length !== newUsers.length) {
|
||||
editState.changes.users = editing_config_node.users;
|
||||
editState.changed = true;
|
||||
editing_config_node.users = newUsers;
|
||||
}
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
if (!configAdding) {
|
||||
RED.events.emit("editor:save",editing_config_node);
|
||||
RED.events.emit("nodes:change",editing_config_node);
|
||||
|
||||
if (editState.changed) {
|
||||
// Set the congig node as changed
|
||||
editing_config_node.changed = true;
|
||||
}
|
||||
|
||||
// Now, validate the config node
|
||||
validateNode(editing_config_node);
|
||||
|
||||
// And validate nodes using this config node too
|
||||
const validatedNodes = new Set();
|
||||
const userStack = editing_config_node.users.slice();
|
||||
|
||||
validatedNodes.add(editing_config_node.id);
|
||||
while (userStack.length) {
|
||||
const node = userStack.pop();
|
||||
if (!validatedNodes.has(node.id)) {
|
||||
validatedNodes.add(node.id);
|
||||
if (node.users) {
|
||||
userStack.push(...node.users);
|
||||
}
|
||||
validateNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
let historyEvent = {
|
||||
t: "edit",
|
||||
node: editing_config_node,
|
||||
changes: editState.changes,
|
||||
changed: wasChanged,
|
||||
dirty: RED.nodes.dirty()
|
||||
};
|
||||
|
||||
if (historyEvents.length) {
|
||||
// Need a multi events
|
||||
historyEvent = {
|
||||
t: "multi",
|
||||
events: [historyEvent].concat(historyEvents),
|
||||
dirty: historyEvent.dirty
|
||||
};
|
||||
}
|
||||
|
||||
if (!adding) {
|
||||
// This event is triggered when the edit box is saved,
|
||||
// regardless of whether there are any modifications.
|
||||
RED.events.emit("editor:save", editing_config_node);
|
||||
}
|
||||
|
||||
if (editState.changed) {
|
||||
if (adding) {
|
||||
RED.history.push({ t: "add", nodes: [editing_config_node.id], dirty: RED.nodes.dirty() });
|
||||
// Add the new config node and trigger the `nodes:add` event
|
||||
RED.nodes.add(editing_config_node);
|
||||
} else {
|
||||
RED.history.push(historyEvent);
|
||||
RED.events.emit("nodes:change", editing_config_node);
|
||||
}
|
||||
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
RED.tray.close(function() {
|
||||
var filter = null;
|
||||
// when editing a config via subflow edit panel, the `configProperty` will not
|
||||
|
||||
@@ -165,7 +165,13 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
//Handles orphaned models
|
||||
//ensure loaded models that are not explicitly destroyed by a call to .destroy() are disposed
|
||||
RED.events.on("editor:close",function() {
|
||||
let models = window.monaco ? monaco.editor.getModels() : null;
|
||||
if (!window.monaco) { return; }
|
||||
const editors = window.monaco.editor.getEditors()
|
||||
const orphanEditors = editors.filter(editor => editor && !document.body.contains(editor.getDomNode()))
|
||||
orphanEditors.forEach(editor => {
|
||||
editor.dispose();
|
||||
});
|
||||
let models = monaco.editor.getModels()
|
||||
if(models && models.length) {
|
||||
console.warn("Cleaning up monaco models left behind. Any node that calls createEditor() should call .destroy().")
|
||||
for (let index = 0; index < models.length; index++) {
|
||||
@@ -1124,6 +1130,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
|
||||
$(el).remove();
|
||||
$(toolbarRow).remove();
|
||||
ed.dispose();
|
||||
}
|
||||
|
||||
ed.resize = function resize() {
|
||||
|
||||
@@ -131,7 +131,7 @@ RED.editor.envVarList = (function() {
|
||||
nameField.trigger('change');
|
||||
}
|
||||
},
|
||||
sortable: ".red-ui-editableList-item-handle",
|
||||
sortable: true,
|
||||
removable: false
|
||||
});
|
||||
var parentEnv = {};
|
||||
|
||||
@@ -839,10 +839,10 @@ RED.library = (function() {
|
||||
if (file && file.label && !file.children) {
|
||||
$.get("library/"+file.library+"/"+file.type+"/"+file.path, function(data) {
|
||||
//TODO: nls + sanitize
|
||||
var propRow = $('<tr class="red-ui-help-info-row"><td>Type</td><td></td></tr>').appendTo(table);
|
||||
var propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("library.type")+'</td><td></td></tr>').appendTo(table);
|
||||
$(propRow.children()[1]).text(activeLibrary.type);
|
||||
if (file.props.hasOwnProperty('name')) {
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>Name</td><td>'+file.props.name+'</td></tr>').appendTo(table);
|
||||
propRow = $('<tr class="red-ui-help-info-row"><td>'+RED._("library.name")+'</td><td>'+file.props.name+'</td></tr>').appendTo(table);
|
||||
$(propRow.children()[1]).text(file.props.name);
|
||||
}
|
||||
for (var p in file.props) {
|
||||
|
||||
@@ -308,7 +308,7 @@ RED.projects.settings = (function() {
|
||||
if (activeProject.dependencies) {
|
||||
for (var m in activeProject.dependencies) {
|
||||
if (activeProject.dependencies.hasOwnProperty(m)) {
|
||||
var installed = !!RED.nodes.registry.getModule(m) && activeProject.dependencies[m] === modulesInUse[m].version;
|
||||
var installed = !!RED.nodes.registry.getModule(m) && activeProject.dependencies[m] === modulesInUse[m]?.version;
|
||||
depsList.editableList('addItem',{
|
||||
id: m,
|
||||
version: activeProject.dependencies[m], //RED.nodes.registry.getModule(module).version,
|
||||
@@ -1256,7 +1256,7 @@ RED.projects.settings = (function() {
|
||||
notification.close();
|
||||
}
|
||||
},{
|
||||
text: 'Delete branch',
|
||||
text: RED._("sidebar.project.projectSettings.deleteBranch"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
var url = "projects/"+activeProject.name+"/branches/"+entry.name;
|
||||
|
||||
@@ -204,7 +204,7 @@ RED.sidebar.info = (function() {
|
||||
|
||||
propertiesPanelHeaderIcon.empty();
|
||||
RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon);
|
||||
propertiesPanelHeaderLabel.text("Selection");
|
||||
propertiesPanelHeaderLabel.text(RED._("sidebar.info.selection"));
|
||||
propertiesPanelHeaderReveal.hide();
|
||||
propertiesPanelHeaderHelp.hide();
|
||||
propertiesPanelHeaderCopyLink.hide();
|
||||
|
||||
@@ -279,6 +279,11 @@ RED.typeSearch = (function() {
|
||||
if ($("#red-ui-main-container").height() - opts.y - 195 < 0) {
|
||||
opts.y = opts.y - 275;
|
||||
}
|
||||
const dialogWidth = dialog.width() || 300 // default is 300 (defined in class .red-ui-search)
|
||||
const workspaceWidth = $('#red-ui-workspace').width()
|
||||
if (workspaceWidth > dialogWidth && workspaceWidth - opts.x - dialogWidth < 0) {
|
||||
opts.x = opts.x - (dialogWidth - RED.view.node_width)
|
||||
}
|
||||
dialog.css({left:opts.x+"px",top:opts.y+"px"}).show();
|
||||
searchResultsDiv.slideDown(300);
|
||||
setTimeout(function() {
|
||||
@@ -330,13 +335,25 @@ RED.typeSearch = (function() {
|
||||
}
|
||||
}
|
||||
function applyFilter(filter,type,def) {
|
||||
return !def || !filter ||
|
||||
(
|
||||
(!filter.spliceMultiple) &&
|
||||
(!filter.type || type === filter.type) &&
|
||||
(!filter.input || type === 'junction' || def.inputs > 0) &&
|
||||
(!filter.output || type === 'junction' || def.outputs > 0)
|
||||
)
|
||||
if (!filter) {
|
||||
// No filter; allow everything
|
||||
return true
|
||||
}
|
||||
if (type === 'junction') {
|
||||
// Only allow Junction is there's no specific type filter
|
||||
return !filter.type
|
||||
}
|
||||
if (filter.type) {
|
||||
// Handle explicit type filter
|
||||
return filter.type === type
|
||||
}
|
||||
if (!def) {
|
||||
// No node definition available - allow it
|
||||
return true
|
||||
}
|
||||
// Check if the filter is for input/outputs and apply
|
||||
return (!filter.input || def.inputs > 0) &&
|
||||
(!filter.output || def.outputs > 0)
|
||||
}
|
||||
function refreshTypeList(opts) {
|
||||
var i;
|
||||
@@ -365,7 +382,7 @@ RED.typeSearch = (function() {
|
||||
var items = [];
|
||||
RED.nodes.registry.getNodeTypes().forEach(function(t) {
|
||||
var def = RED.nodes.getType(t);
|
||||
if (def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
|
||||
if (def.set?.enabled !== false && def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
|
||||
items.push({type:t,def: def, label:getTypeLabel(t,def)});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1102,18 +1102,27 @@ RED.view.tools = (function() {
|
||||
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
|
||||
const defaultNodeNameRE = new RegExp('^'+paletteLabel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')+' (\\d+)$')
|
||||
if (!typeIndex.hasOwnProperty(n.type)) {
|
||||
const existingNodes = RED.nodes.filterNodes({type: n.type})
|
||||
let maxNameNumber = 0;
|
||||
existingNodes.forEach(n => {
|
||||
let match = defaultNodeNameRE.exec(n.name)
|
||||
const existingNodes = RED.nodes.filterNodes({ type: n.type });
|
||||
const existingIds = existingNodes.reduce((ids, node) => {
|
||||
let match = defaultNodeNameRE.exec(node.name);
|
||||
if (match) {
|
||||
let nodeNumber = parseInt(match[1])
|
||||
if (nodeNumber > maxNameNumber) {
|
||||
maxNameNumber = nodeNumber
|
||||
const nodeNumber = parseInt(match[1], 10);
|
||||
if (!ids.includes(nodeNumber)) {
|
||||
ids.push(nodeNumber);
|
||||
}
|
||||
}
|
||||
})
|
||||
typeIndex[n.type] = maxNameNumber + 1
|
||||
return ids;
|
||||
}, []).sort((a, b) => a - b);
|
||||
|
||||
let availableNameNumber = 1;
|
||||
for (let i = 0; i < existingIds.length; i++) {
|
||||
if (existingIds[i] !== availableNameNumber) {
|
||||
break;
|
||||
}
|
||||
availableNameNumber++;
|
||||
}
|
||||
|
||||
typeIndex[n.type] = availableNameNumber;
|
||||
}
|
||||
if ((options.renameBlank && n.name === '') || (options.renameClash && defaultNodeNameRE.test(n.name))) {
|
||||
if (generateHistory) {
|
||||
|
||||
@@ -288,7 +288,7 @@ RED.view = (function() {
|
||||
}
|
||||
selectedLinks.clearUnselected()
|
||||
},
|
||||
length: () => groups.length,
|
||||
length: () => groups.size,
|
||||
forEach: (func) => { groups.forEach(func) },
|
||||
toArray: () => [...groups],
|
||||
clear: function () {
|
||||
@@ -1209,7 +1209,10 @@ RED.view = (function() {
|
||||
lasso = null;
|
||||
}
|
||||
if (d3.event.touches || d3.event.button === 0) {
|
||||
if ((mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) {
|
||||
if (
|
||||
(mouse_mode === 0 && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) ||
|
||||
mouse_mode === RED.state.QUICK_JOINING
|
||||
) {
|
||||
// Trigger quick add dialog
|
||||
d3.event.stopPropagation();
|
||||
clearSelection();
|
||||
@@ -1285,7 +1288,6 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
var mainPos = $("#red-ui-main-container").position();
|
||||
|
||||
if (mouse_mode !== RED.state.QUICK_JOINING) {
|
||||
mouse_mode = RED.state.QUICK_JOINING;
|
||||
$(window).on('keyup',disableQuickJoinEventHandler);
|
||||
@@ -2687,22 +2689,21 @@ RED.view = (function() {
|
||||
addToRemovedLinks(reconnectResult.removedLinks)
|
||||
}
|
||||
|
||||
var startDirty = RED.nodes.dirty();
|
||||
var startChanged = false;
|
||||
var selectedGroups = [];
|
||||
const startDirty = RED.nodes.dirty();
|
||||
let movingSelectedGroups = [];
|
||||
if (movingSet.length() > 0) {
|
||||
|
||||
for (var i=0;i<movingSet.length();i++) {
|
||||
node = movingSet.get(i).n;
|
||||
if (node.type === "group") {
|
||||
selectedGroups.push(node);
|
||||
movingSelectedGroups.push(node);
|
||||
}
|
||||
}
|
||||
// Make sure we have identified all groups about to be deleted
|
||||
for (i=0;i<selectedGroups.length;i++) {
|
||||
selectedGroups[i].nodes.forEach(function(n) {
|
||||
if (n.type === "group" && selectedGroups.indexOf(n) === -1) {
|
||||
selectedGroups.push(n);
|
||||
for (i=0;i<movingSelectedGroups.length;i++) {
|
||||
movingSelectedGroups[i].nodes.forEach(function(n) {
|
||||
if (n.type === "group" && movingSelectedGroups.indexOf(n) === -1) {
|
||||
movingSelectedGroups.push(n);
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -2719,7 +2720,7 @@ RED.view = (function() {
|
||||
addToRemovedLinks(removedEntities.links);
|
||||
if (node.g) {
|
||||
var group = RED.nodes.group(node.g);
|
||||
if (selectedGroups.indexOf(group) === -1) {
|
||||
if (movingSelectedGroups.indexOf(group) === -1) {
|
||||
// Don't use RED.group.removeFromGroup as that emits
|
||||
// a change event on the node - but we're deleting it
|
||||
var index = group.nodes.indexOf(node);
|
||||
@@ -2733,7 +2734,7 @@ RED.view = (function() {
|
||||
removedLinks = removedLinks.concat(result.links);
|
||||
if (node.g) {
|
||||
var group = RED.nodes.group(node.g);
|
||||
if (selectedGroups.indexOf(group) === -1) {
|
||||
if (movingSelectedGroups.indexOf(group) === -1) {
|
||||
// Don't use RED.group.removeFromGroup as that emits
|
||||
// a change event on the node - but we're deleting it
|
||||
var index = group.nodes.indexOf(node);
|
||||
@@ -2755,8 +2756,8 @@ RED.view = (function() {
|
||||
|
||||
// Groups must be removed in the right order - from inner-most
|
||||
// to outermost.
|
||||
for (i = selectedGroups.length-1; i>=0; i--) {
|
||||
var g = selectedGroups[i];
|
||||
for (i = movingSelectedGroups.length-1; i>=0; i--) {
|
||||
var g = movingSelectedGroups[i];
|
||||
removedGroups.push(g);
|
||||
RED.nodes.removeGroup(g);
|
||||
}
|
||||
@@ -3057,8 +3058,8 @@ RED.view = (function() {
|
||||
}
|
||||
|
||||
function disableQuickJoinEventHandler(evt) {
|
||||
// Check for ctrl (all browsers), "Meta" (Chrome/FF), keyCode 91 (Safari)
|
||||
if (evt.keyCode === 17 || evt.key === "Meta" || evt.keyCode === 91) {
|
||||
// Check for ctrl (all browsers), "Meta" (Chrome/FF), keyCode 91 (Safari), or Escape
|
||||
if (evt.keyCode === 17 || evt.key === "Meta" || evt.keyCode === 91 || evt.keyCode === 27) {
|
||||
resetMouseVars();
|
||||
hideDragLines();
|
||||
redraw();
|
||||
@@ -3189,27 +3190,59 @@ RED.view = (function() {
|
||||
|
||||
for (i=0;i<drag_lines.length;i++) {
|
||||
if (portType != drag_lines[i].portType && mouseup_node !== drag_lines[i].node) {
|
||||
var drag_line = drag_lines[i];
|
||||
var src,dst,src_port;
|
||||
let drag_line = drag_lines[i];
|
||||
let src,dst,src_port;
|
||||
let oldDst;
|
||||
let oldSrc;
|
||||
if (drag_line.portType === PORT_TYPE_OUTPUT) {
|
||||
src = drag_line.node;
|
||||
src_port = drag_line.port;
|
||||
dst = mouseup_node;
|
||||
oldSrc = src;
|
||||
if (drag_line.link) {
|
||||
oldDst = drag_line.link.target;
|
||||
}
|
||||
} else if (drag_line.portType === PORT_TYPE_INPUT) {
|
||||
src = mouseup_node;
|
||||
dst = drag_line.node;
|
||||
src_port = portIndex || 0;
|
||||
oldSrc = dst;
|
||||
if (drag_line.link) {
|
||||
oldDst = drag_line.link.source
|
||||
}
|
||||
}
|
||||
var link = {source: src, sourcePort:src_port, target: dst};
|
||||
if (drag_line.virtualLink) {
|
||||
if (/^link (in|out)$/.test(src.type) && /^link (in|out)$/.test(dst.type) && src.type !== dst.type) {
|
||||
if (src.links.indexOf(dst.id) === -1 && dst.links.indexOf(src.id) === -1) {
|
||||
var oldSrcLinks = $.extend(true,{},{v:src.links}).v
|
||||
var oldDstLinks = $.extend(true,{},{v:dst.links}).v
|
||||
var oldSrcLinks = [...src.links]
|
||||
var oldDstLinks = [...dst.links]
|
||||
|
||||
src.links.push(dst.id);
|
||||
dst.links.push(src.id);
|
||||
|
||||
if (oldDst) {
|
||||
src.links = src.links.filter(id => id !== oldDst.id)
|
||||
dst.links = dst.links.filter(id => id !== oldDst.id)
|
||||
var oldOldDstLinks = [...oldDst.links]
|
||||
oldDst.links = oldDst.links.filter(id => id !== oldSrc.id)
|
||||
oldDst.dirty = true;
|
||||
modifiedNodes.push(oldDst);
|
||||
linkEditEvents.push({
|
||||
t:'edit',
|
||||
node: oldDst,
|
||||
dirty: RED.nodes.dirty(),
|
||||
changed: oldDst.changed,
|
||||
changes: {
|
||||
links:oldOldDstLinks
|
||||
}
|
||||
});
|
||||
oldDst.changed = true;
|
||||
}
|
||||
|
||||
src.dirty = true;
|
||||
dst.dirty = true;
|
||||
|
||||
modifiedNodes.push(src);
|
||||
modifiedNodes.push(dst);
|
||||
|
||||
@@ -3237,6 +3270,7 @@ RED.view = (function() {
|
||||
links:oldDstLinks
|
||||
}
|
||||
});
|
||||
|
||||
src.changed = true;
|
||||
dst.changed = true;
|
||||
}
|
||||
|
||||
@@ -183,25 +183,29 @@ RED.workspaces = (function() {
|
||||
},
|
||||
null)
|
||||
}
|
||||
menuItems.push(
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
}
|
||||
)
|
||||
if (isMenuButton || !!tab) {
|
||||
if (RED.settings.theme("menu.menu-item-workspace-add", true)) {
|
||||
menuItems.push(
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:add-flow-to-right", tab)
|
||||
}
|
||||
},
|
||||
null
|
||||
id:"red-ui-tabs-menu-option-add-flow",
|
||||
label: RED._("workspace.addFlow"),
|
||||
onselect: "core:add-flow"
|
||||
}
|
||||
)
|
||||
}
|
||||
if (isMenuButton || !!tab) {
|
||||
if (RED.settings.theme("menu.menu-item-workspace-add", true)) {
|
||||
menuItems.push(
|
||||
{
|
||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||
label: RED._("workspace.addFlowToRight"),
|
||||
shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"),
|
||||
onselect: function() {
|
||||
RED.actions.invoke("core:add-flow-to-right", tab)
|
||||
}
|
||||
},
|
||||
null
|
||||
)
|
||||
}
|
||||
if (activeWorkspace && activeWorkspace.type === 'tab') {
|
||||
menuItems.push(
|
||||
isFlowDisabled ? {
|
||||
@@ -255,7 +259,9 @@ RED.workspaces = (function() {
|
||||
}
|
||||
)
|
||||
}
|
||||
menuItems.push(null)
|
||||
if (menuItems.length > 0) {
|
||||
menuItems.push(null)
|
||||
}
|
||||
if (isMenuButton || !!tab) {
|
||||
menuItems.push(
|
||||
{
|
||||
@@ -299,19 +305,24 @@ RED.workspaces = (function() {
|
||||
}
|
||||
)
|
||||
if (tab) {
|
||||
menuItems.push(null)
|
||||
|
||||
if (RED.settings.theme("menu.menu-item-workspace-delete", true)) {
|
||||
menuItems.push(
|
||||
{
|
||||
label: RED._("common.label.delete"),
|
||||
onselect: function() {
|
||||
if (tab.type === 'tab') {
|
||||
RED.workspaces.delete(tab)
|
||||
} else if (tab.type === 'subflow') {
|
||||
RED.subflow.delete(tab.id)
|
||||
}
|
||||
},
|
||||
disabled: isCurrentLocked || (workspaceTabCount === 1)
|
||||
}
|
||||
)
|
||||
}
|
||||
menuItems.push(
|
||||
null,
|
||||
{
|
||||
label: RED._("common.label.delete"),
|
||||
onselect: function() {
|
||||
if (tab.type === 'tab') {
|
||||
RED.workspaces.delete(tab)
|
||||
} else if (tab.type === 'subflow') {
|
||||
RED.subflow.delete(tab.id)
|
||||
}
|
||||
},
|
||||
disabled: isCurrentLocked || (workspaceTabCount === 1)
|
||||
},
|
||||
{
|
||||
label: RED._("menu.label.export"),
|
||||
shortcut: RED.keyboard.getShortcut("core:show-export-dialog"),
|
||||
@@ -468,7 +479,7 @@ RED.workspaces = (function() {
|
||||
},
|
||||
minimumActiveTabWidth: 150,
|
||||
scrollable: true,
|
||||
addButton: "core:add-flow",
|
||||
addButton: RED.settings.theme("menu.menu-item-workspace-add", true) ? "core:add-flow" : undefined,
|
||||
addButtonCaption: RED._("workspace.addFlow"),
|
||||
menu: function() { return getMenuItems(true) },
|
||||
contextmenu: function(tab) { return getMenuItems(false, tab) }
|
||||
@@ -525,19 +536,24 @@ RED.workspaces = (function() {
|
||||
$(window).on("resize", function() {
|
||||
workspace_tabs.resize();
|
||||
});
|
||||
|
||||
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
||||
RED.actions.add("core:add-flow-to-right",function(workspace) {
|
||||
let index
|
||||
if (workspace) {
|
||||
index = workspace_tabs.getTabIndex(workspace.id)+1
|
||||
} else {
|
||||
index = workspace_tabs.activeIndex()+1
|
||||
}
|
||||
addWorkspace(undefined,undefined,index)
|
||||
});
|
||||
RED.actions.add("core:edit-flow",editWorkspace);
|
||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||
if (RED.settings.theme("menu.menu-item-workspace-add", true)) {
|
||||
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
||||
RED.actions.add("core:add-flow-to-right",function(workspace) {
|
||||
let index
|
||||
if (workspace) {
|
||||
index = workspace_tabs.getTabIndex(workspace.id)+1
|
||||
} else {
|
||||
index = workspace_tabs.activeIndex()+1
|
||||
}
|
||||
addWorkspace(undefined,undefined,index)
|
||||
});
|
||||
}
|
||||
if (RED.settings.theme("menu.menu-item-workspace-edit", true)) {
|
||||
RED.actions.add("core:edit-flow",editWorkspace);
|
||||
}
|
||||
if (RED.settings.theme("menu.menu-item-workspace-delete", true)) {
|
||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||
}
|
||||
RED.actions.add("core:enable-flow",enableWorkspace);
|
||||
RED.actions.add("core:disable-flow",disableWorkspace);
|
||||
RED.actions.add("core:lock-flow",lockWorkspace);
|
||||
@@ -904,6 +920,17 @@ RED.workspaces = (function() {
|
||||
}
|
||||
},
|
||||
refresh: function() {
|
||||
var workspace = RED.nodes.workspace(RED.workspaces.active());
|
||||
if (workspace) {
|
||||
document.title = `${documentTitle} : ${workspace.label}`;
|
||||
} else {
|
||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||
if (subflow) {
|
||||
document.title = `${documentTitle} : ${subflow.name}`;
|
||||
} else {
|
||||
document.title = documentTitle
|
||||
}
|
||||
}
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
workspace_tabs.renameTab(ws.id,ws.label);
|
||||
$("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label)
|
||||
|
||||
@@ -259,7 +259,7 @@ $deploy-button-background-disabled-hover: #555;
|
||||
|
||||
$header-background: #000;
|
||||
$header-button-background-active: #121212;
|
||||
$header-accent: #d41313;
|
||||
$header-accent: #C02020;
|
||||
$header-menu-color: #eee;
|
||||
$header-menu-color-disabled: #666;
|
||||
$header-menu-heading-color: #fff;
|
||||
|
||||
@@ -151,8 +151,9 @@
|
||||
&.red-ui-tabs-add {
|
||||
padding-right: 29px;
|
||||
}
|
||||
&.red-ui-tabs-add.red-ui-tabs-scrollable {
|
||||
padding-right: 53px;
|
||||
&.red-ui-tabs-add.red-ui-tabs-scrollable,
|
||||
&.red-ui-tabs-menu.red-ui-tabs-scrollable {
|
||||
padding-right: 53px;
|
||||
}
|
||||
&.red-ui-tabs-add.red-ui-tabs-menu.red-ui-tabs-scrollable,
|
||||
&.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-scrollable {
|
||||
@@ -310,8 +311,9 @@
|
||||
}
|
||||
|
||||
}
|
||||
.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right {
|
||||
right: 32px;
|
||||
.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right,
|
||||
.red-ui-tabs.red-ui-tabs-menu .red-ui-tab-scroll-right {
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.red-ui-tabs.red-ui-tabs-add.red-ui-tabs-menu .red-ui-tab-scroll-right,
|
||||
|
||||
Reference in New Issue
Block a user