1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge branch '0.19' into runtime-api

This commit is contained in:
Nick O'Leary 2018-06-06 21:59:46 +01:00
commit 0835fdd0d1
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
35 changed files with 1277 additions and 464 deletions

View File

@ -4,7 +4,7 @@ matrix:
include: include:
- node_js: "10" - node_js: "10"
script: script:
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage - ./node_modules/.bin/grunt && istanbul report text && ( cat coverage/lcov.info | $(npm get prefix)/bin/coveralls || true ) && rm -rf coverage
before_script: before_script:
- npm install -g istanbul coveralls - npm install -g istanbul coveralls
- node_js: "8" - node_js: "8"

View File

@ -1,3 +1,20 @@
#### 0.18.7: Maintenance Release
Editor Fixes
- Do not trim wires if node declares outputs in defaults but misses value Fixes #1737
Node Fixes
- Relax twitter node version ready for major version bump
- Pass Date into the Function node sandbox to fix instanceof tests
- let TCP in node report remote ip and port when in single packet mode
- typo fix in node help (#1735)
Other Fixes
- Tidy up default grunt task and fixup test break due to reorder Fixes #1738
- Bump jsonata version
#### 0.18.6: Maintenance Release #### 0.18.6: Maintenance Release
Editor Fixes Editor Fixes

View File

@ -55,7 +55,7 @@ module.exports = function(grunt) {
reportFormats: ['lcov','html'], reportFormats: ['lcov','html'],
print: 'both' print: 'both'
}, },
all: { src: ['test/**/*_spec.js'] }, all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] },
core: { src: ["test/_spec.js","test/red/**/*_spec.js"]}, core: { src: ["test/_spec.js","test/red/**/*_spec.js"]},
nodes: { src: ["test/nodes/**/*_spec.js"]} nodes: { src: ["test/nodes/**/*_spec.js"]}
}, },
@ -495,7 +495,7 @@ module.exports = function(grunt) {
grunt.registerTask('default', grunt.registerTask('default',
'Builds editor content then runs code style checks and unit tests on all components', 'Builds editor content then runs code style checks and unit tests on all components',
['build','test-core','test-editor','test-nodes']); ['build','jshint:editor','mocha_istanbul:all']);
grunt.registerTask('test-core', grunt.registerTask('test-core',
'Runs code style check and unit tests on core runtime code', 'Runs code style check and unit tests on core runtime code',

View File

@ -1033,15 +1033,31 @@ RED.nodes = (function() {
node.type = "unknown"; node.type = "unknown";
} }
if (node._def.category != "config") { if (node._def.category != "config") {
node.inputs = n.inputs||node._def.inputs; if (n.hasOwnProperty('inputs')) {
node.outputs = n.outputs||node._def.outputs; node.inputs = n.inputs;
// If 'wires' is longer than outputs, clip wires node._config.inputs = JSON.stringify(n.inputs);
} else {
node.inputs = node._def.inputs;
}
if (n.hasOwnProperty('outputs')) {
node.outputs = n.outputs;
node._config.outputs = JSON.stringify(n.outputs);
} else {
node.outputs = node._def.outputs;
}
if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) { if (node.hasOwnProperty('wires') && node.wires.length > node.outputs) {
if (!node._def.defaults.hasOwnProperty("outputs") || !isNaN(parseInt(n.outputs))) {
// If 'wires' is longer than outputs, clip wires
console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs); console.log("Warning: node.wires longer than node.outputs - trimming wires:",node.id," wires:",node.wires.length," outputs:",node.outputs);
node.wires = node.wires.slice(0,node.outputs); node.wires = node.wires.slice(0,node.outputs);
} else {
// The node declares outputs in its defaults, but has not got a valid value
// Defer to the length of the wires array
node.outputs = node.wires.length;
}
} }
for (d in node._def.defaults) { for (d in node._def.defaults) {
if (node._def.defaults.hasOwnProperty(d)) { if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
node[d] = n[d]; node[d] = n[d];
node._config[d] = JSON.stringify(n[d]); node._config[d] = JSON.stringify(n[d]);
} }

View File

@ -176,13 +176,13 @@ var RED = (function() {
loadFlows(function() { loadFlows(function() {
var project = RED.projects.getActiveProject(); var project = RED.projects.getActiveProject();
var message = { var message = {
"change-branch":"Change to local branch '"+project.git.branches.local+"'", "change-branch": RED._("notification.project.change-branch", {project: project.git.branches.local}),
"merge-abort":"Git merge aborted", "merge-abort": RED._("notification.project.merge-abort"),
"loaded":"Project '"+msg.project+"' loaded", "loaded": RED._("notification.project.loaded", {project: msg.project}),
"updated":"Project '"+msg.project+"' updated", "updated": RED._("notification.project.updated", {project: msg.project}),
"pull":"Project '"+msg.project+"' reloaded", "pull": RED._("notification.project.pull", {project: msg.project}),
"revert": "Project '"+msg.project+"' reloaded", "revert": RED._("notification.project.revert", {project: msg.project}),
"merge-complete":"Git merge completed" "merge-complete": RED._("notification.project.merge-complete")
}[msg.action]; }[msg.action];
RED.notify("<p>"+message+"</p>"); RED.notify("<p>"+message+"</p>");
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
@ -206,7 +206,7 @@ var RED = (function() {
if (!!RED.projects.getActiveProject()) { if (!!RED.projects.getActiveProject()) {
options.buttons = [ options.buttons = [
{ {
text: "Manage project dependencies", text: RED._("notification.label.manage-project-dep"),
click: function() { click: function() {
persistentNotifications[notificationId].hideNotification(); persistentNotifications[notificationId].hideNotification();
RED.projects.settings.show('deps'); RED.projects.settings.show('deps');
@ -217,7 +217,7 @@ var RED = (function() {
} else { } else {
options.buttons = [ options.buttons = [
{ {
text: "Close", text: RED._("common.label.close"),
click: function() { click: function() {
persistentNotifications[notificationId].hideNotification(); persistentNotifications[notificationId].hideNotification();
} }

View File

@ -1233,7 +1233,7 @@ RED.diff = (function() {
// currentDiff = diff; // currentDiff = diff;
var trayOptions = { var trayOptions = {
title: options.title||"Review Changes", //TODO: nls title: options.title||RED._("diff.reviewChanges"),
width: Infinity, width: Infinity,
overlay: true, overlay: true,
buttons: [ buttons: [
@ -1416,7 +1416,7 @@ RED.diff = (function() {
function showTextDiff(textA,textB) { function showTextDiff(textA,textB) {
var trayOptions = { var trayOptions = {
title: "Compare Changes", //TODO: nls title: RED._("diff.compareChanges"),
width: Infinity, width: Infinity,
overlay: true, overlay: true,
buttons: [ buttons: [
@ -1747,7 +1747,7 @@ RED.diff = (function() {
try { try {
commonFlow = JSON.parse(commonVersion.content||"[]"); commonFlow = JSON.parse(commonVersion.content||"[]");
} catch(err) { } catch(err) {
console.log("Common Version doesn't contain valid JSON:",commonVersionUrl); console.log(RED._("diff.commonVersionError"),commonVersionUrl);
console.log(err); console.log(err);
return; return;
} }
@ -1755,7 +1755,7 @@ RED.diff = (function() {
try { try {
oldFlow = JSON.parse(oldVersion.content||"[]"); oldFlow = JSON.parse(oldVersion.content||"[]");
} catch(err) { } catch(err) {
console.log("Old Version doesn't contain valid JSON:",oldVersionUrl); console.log(RED._("diff.oldVersionError"),oldVersionUrl);
console.log(err); console.log(err);
return; return;
} }
@ -1765,7 +1765,7 @@ RED.diff = (function() {
try { try {
newFlow = JSON.parse(newVersion.content||"[]"); newFlow = JSON.parse(newVersion.content||"[]");
} catch(err) { } catch(err) {
console.log("New Version doesn't contain valid JSON:",newFlow); console.log(RED._("diff.newVersionError"),newFlow);
console.log(err); console.log(err);
return; return;
} }
@ -1797,11 +1797,11 @@ RED.diff = (function() {
if (isBinary) { if (isBinary) {
var diffBinaryRow = $('<tr class="node-text-diff-header">').appendTo(codeBody); var diffBinaryRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
var binaryContent = $('<td colspan="3"></td>').appendTo(diffBinaryRow); var binaryContent = $('<td colspan="3"></td>').appendTo(diffBinaryRow);
$('<span></span>').text("Cannot show binary file contents").appendTo(binaryContent); $('<span></span>').text(RED._("diff.noBinaryFileShowed")).appendTo(binaryContent);
} else { } else {
if (commitOptions.unmerged) { if (commitOptions.unmerged) {
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content); conflictHeader = $('<span style="float: right;">'+RED._("diff.conflictHeader",{resolved:resolvedConflicts, unresolved:unresolvedConflicts})+'</span>').appendTo(content);
} }
hunks.forEach(function(hunk) { hunks.forEach(function(hunk) {
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody); var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
@ -1914,7 +1914,7 @@ RED.diff = (function() {
diffRow.remove(); diffRow.remove();
addedRows.find(".linetext").addClass('added'); addedRows.find(".linetext").addClass('added');
conflictHeader.empty(); conflictHeader.empty();
$('<span><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(conflictHeader); $('<span>'+RED._("diff.conflictHeader",{resolved:resolvedConflicts, unresolved:unresolvedConflicts})+'</span>').appendTo(conflictHeader);
conflictResolutions[file.file] = conflictResolutions[file.file] || {}; conflictResolutions[file.file] = conflictResolutions[file.file] || {};
conflictResolutions[file.file][hunk.localChangeStart] = { conflictResolutions[file.file][hunk.localChangeStart] = {
@ -1946,7 +1946,7 @@ RED.diff = (function() {
function showCommitDiff(options) { function showCommitDiff(options) {
var commit = parseCommitDiff(options.commit); var commit = parseCommitDiff(options.commit);
var trayOptions = { var trayOptions = {
title: "View Commit Changes", //TODO: nls title: RED._("diff.viewCommitDiff"),
width: Infinity, width: Infinity,
overlay: true, overlay: true,
buttons: [ buttons: [
@ -2008,7 +2008,7 @@ RED.diff = (function() {
} }
var trayOptions = { var trayOptions = {
title: title||"Compare Changes", //TODO: nls title: title|| RED._("diff.compareChanges"),
width: Infinity, width: Infinity,
overlay: true, overlay: true,
buttons: [ buttons: [
@ -2041,7 +2041,7 @@ RED.diff = (function() {
trayOptions.buttons.push( trayOptions.buttons.push(
{ {
id: "node-diff-view-resolve-diff", id: "node-diff-view-resolve-diff",
text: "Save conflict resolution", text: RED._("diff.saveConflict"),
class: "primary disabled", class: "primary disabled",
click: function() { click: function() {
if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) { if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) {

View File

@ -49,7 +49,7 @@ RED.projects.settings = (function() {
var tabContainer; var tabContainer;
var trayOptions = { var trayOptions = {
title: "Project Settings",// RED._("menu.label.userSettings"),, // TODO: nls title: RED._("menu.label.userSettings"),
buttons: [ buttons: [
{ {
id: "node-dialog-ok", id: "node-dialog-ok",
@ -173,14 +173,14 @@ RED.projects.settings = (function() {
container.empty(); container.empty();
var bg = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').appendTo(container); var bg = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').appendTo(container);
var input = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(summary||"").appendTo(container); var input = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(summary||"").appendTo(container);
$('<button class="editor-button">Cancel</button>') $('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(bg) .appendTo(bg)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
updateProjectSummary(activeProject.summary, container); updateProjectSummary(activeProject.summary, container);
editButton.show(); editButton.show();
}); });
$('<button class="editor-button">Save</button>') $('<button class="editor-button">' + RED._("common.label.save") + '</button>')
.appendTo(bg) .appendTo(bg)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -223,7 +223,7 @@ RED.projects.settings = (function() {
if (summary) { if (summary) {
container.text(summary).removeClass('node-info-node'); container.text(summary).removeClass('node-info-node');
} else { } else {
container.text("No summary available").addClass('node-info-none');// TODO: nls container.text(RED._("sidebar.project.projectSettings.noSummaryAvailable")).addClass('node-info-none');
} }
} }
@ -235,7 +235,7 @@ RED.projects.settings = (function() {
var summaryContent = $('<div></div>',{style:"color: #999"}).appendTo(summary); var summaryContent = $('<div></div>',{style:"color: #999"}).appendTo(summary);
updateProjectSummary(activeProject.summary, summaryContent); updateProjectSummary(activeProject.summary, summaryContent);
if (RED.user.hasPermission("projects.write")) { if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="float: right;">edit description</button>') $('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.editDescription') + '</button>')
.prependTo(summary) .prependTo(summary)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -250,7 +250,7 @@ RED.projects.settings = (function() {
updateProjectDescription(activeProject, descriptionContent); updateProjectDescription(activeProject, descriptionContent);
if (RED.user.hasPermission("projects.write")) { if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="float: right;">edit README.md</button>') $('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.editReadme') + '</button>')
.prependTo(description) .prependTo(description)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -316,7 +316,7 @@ RED.projects.settings = (function() {
// depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls // depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls
// } // }
if (totalCount === 0) { if (totalCount === 0) {
depsList.editableList('addItem',{index:0, label:"None"}); // TODO: nls depsList.editableList('addItem',{index:0, label:RED._("sidebar.project.projectSettings.none")});
} }
} }
@ -381,7 +381,7 @@ RED.projects.settings = (function() {
function createDependenciesPane(activeProject) { function createDependenciesPane(activeProject) {
var pane = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>'); var pane = $('<div id="project-settings-tab-deps" class="project-settings-tab-pane node-help"></div>');
if (RED.user.hasPermission("projects.write")) { if (RED.user.hasPermission("projects.write")) {
$('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">edit</button>') $('<button class="editor-button editor-button-small" style="margin-top:10px;float: right;">' + RED._("sidebar.project.projectSettings.edit") + '</button>')
.appendTo(pane) .appendTo(pane)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -451,7 +451,7 @@ RED.projects.settings = (function() {
var buttons = $('<div class="palette-module-button-group"></div>').appendTo(metaRow); var buttons = $('<div class="palette-module-button-group"></div>').appendTo(metaRow);
if (RED.user.hasPermission("projects.write")) { if (RED.user.hasPermission("projects.write")) {
if (!entry.installed && RED.settings.theme('palette.editable') !== false) { if (!entry.installed && RED.settings.theme('palette.editable') !== false) {
$('<a href="#" class="editor-button editor-button-small">install</a>').appendTo(buttons) $('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.install") + '</a>').appendTo(buttons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
RED.palette.editor.install(entry,row,function(err) { RED.palette.editor.install(entry,row,function(err) {
@ -468,7 +468,7 @@ RED.projects.settings = (function() {
}); });
}) })
} else if (entry.known && entry.count === 0) { } else if (entry.known && entry.count === 0) {
$('<a href="#" class="editor-button editor-button-small">remove from project</a>').appendTo(buttons) $('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.removeFromProject") + '</a>').appendTo(buttons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies); var deps = $.extend(true, {}, activeProject.dependencies);
@ -484,7 +484,7 @@ RED.projects.settings = (function() {
}); });
}); });
} else if (!entry.known) { } else if (!entry.known) {
$('<a href="#" class="editor-button editor-button-small">add to project</a>').appendTo(buttons) $('<a href="#" class="editor-button editor-button-small">' + RED._("sidebar.project.projectSettings.addToProject") + '</a>').appendTo(buttons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies); var deps = $.extend(true, {}, activeProject.dependencies);
@ -723,10 +723,10 @@ RED.projects.settings = (function() {
// } // }
function createFilesSection(activeProject,pane) { function createFilesSection(activeProject,pane) {
var title = $('<h3></h3>').text("Files").appendTo(pane); var title = $('<h3></h3>').text(RED._("sidebar.project.projectSettings.files")).appendTo(pane);
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane); var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
if (RED.user.hasPermission("projects.write")) { if (RED.user.hasPermission("projects.write")) {
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>') var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">' + RED._('sidebar.project.projectSettings.edit') + '</button>')
.appendTo(title) .appendTo(title)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -750,7 +750,7 @@ RED.projects.settings = (function() {
// Flow files // Flow files
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer); row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text('Flow').appendTo(row); $('<label for=""></label>').text(RED._("sidebar.project.projectSettings.flow")).appendTo(row);
var flowFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row); var flowFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
var flowFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.flow).appendTo(flowFileLabel); var flowFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.flow).appendTo(flowFileLabel);
@ -787,7 +787,7 @@ RED.projects.settings = (function() {
}) })
row = $('<div class="user-settings-row"></div>').appendTo(filesContainer); row = $('<div class="user-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text('Credentials').appendTo(row); $('<label for=""></label>').text(RED._("sidebar.project.projectSettings.credentials")).appendTo(row);
var credFileLabel = $('<div class="uneditable-input">').text(activeProject.files.credentials).appendTo(row); var credFileLabel = $('<div class="uneditable-input">').text(activeProject.files.credentials).appendTo(row);
var credFileInput = $('<div class="uneditable-input">').text(activeProject.files.credentials).hide().insertAfter(credFileLabel); var credFileInput = $('<div class="uneditable-input">').text(activeProject.files.credentials).hide().insertAfter(credFileLabel);
@ -899,12 +899,12 @@ RED.projects.settings = (function() {
var credentialFormRows = $('<div>',{style:"margin-top:10px"}).hide().appendTo(credentialStateLabel); var credentialFormRows = $('<div>',{style:"margin-top:10px"}).hide().appendTo(credentialStateLabel);
var credentialSetLabel = $('<div style="margin: 20px 0 10px 5px;">Set the encryption key:</div>').hide().appendTo(credentialFormRows); var credentialSetLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.setTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
var credentialChangeLabel = $('<div style="margin: 20px 0 10px 5px;">Change the encryption key:</div>').hide().appendTo(credentialFormRows); var credentialChangeLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.changeTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
var credentialResetLabel = $('<div style="margin: 20px 0 10px 5px;">Reset the encryption key:</div>').hide().appendTo(credentialFormRows); var credentialResetLabel = $('<div style="margin: 20px 0 10px 5px;">' + RED._("sidebar.project.projectSettings.resetTheEncryptionKey") + '</div>').hide().appendTo(credentialFormRows);
var credentialSecretExistingRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows); var credentialSecretExistingRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text('Current key').appendTo(credentialSecretExistingRow); $('<label for=""></label>').text(RED._("sidebar.project.projectSettings.currentKey")).appendTo(credentialSecretExistingRow);
var credentialSecretExistingInput = $('<input type="password">').appendTo(credentialSecretExistingRow) var credentialSecretExistingInput = $('<input type="password">').appendTo(credentialSecretExistingRow)
.on("change keyup paste",function() { .on("change keyup paste",function() {
if (popover) { if (popover) {
@ -917,10 +917,10 @@ RED.projects.settings = (function() {
var credentialSecretNewRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows); var credentialSecretNewRow = $('<div class="user-settings-row user-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text('New key').appendTo(credentialSecretNewRow); $('<label for=""></label>').text(RED._("sidebar.project.projectSettings.newKey")).appendTo(credentialSecretNewRow);
var credentialSecretNewInput = $('<input type="password">').appendTo(credentialSecretNewRow).on("change keyup paste",checkFiles); var credentialSecretNewInput = $('<input type="password">').appendTo(credentialSecretNewRow).on("change keyup paste",checkFiles);
var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i> This will delete all existing credentials</div>').hide().appendTo(credentialFormRows); var credentialResetWarning = $('<div class="form-tips form-warning" style="margin: 10px;"><i class="fa fa-warning"></i>' + RED._("sidebar.project.projectSettings.credentialsAlert") + '</div>').hide().appendTo(credentialFormRows);
var hideEditForm = function() { var hideEditForm = function() {
@ -950,13 +950,13 @@ RED.projects.settings = (function() {
} }
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer); var formButtons = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
$('<button class="editor-button">Cancel</button>') $('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
hideEditForm(); hideEditForm();
}); });
var saveButton = $('<button class="editor-button">Save</button>') var saveButton = $('<button class="editor-button">' + RED._("common.label.save") + '</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -1032,13 +1032,13 @@ RED.projects.settings = (function() {
var updateForm = function() { var updateForm = function() {
if (activeProject.settings.credentialSecretInvalid) { if (activeProject.settings.credentialSecretInvalid) {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-warning"); credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-warning");
credentialStateLabel.find(".user-settings-credentials-state").text("Invalid encryption key"); credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.invalidEncryptionKey"));
} else if (activeProject.settings.credentialsEncrypted) { } else if (activeProject.settings.credentialsEncrypted) {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-lock"); credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-lock");
credentialStateLabel.find(".user-settings-credentials-state").text("Encryption enabled"); credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionEnabled"));
} else { } else {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-unlock"); credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-unlock");
credentialStateLabel.find(".user-settings-credentials-state").text("Encryption disabled"); credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionDisabled"));
} }
credentialSecretResetButton.toggleClass('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted); credentialSecretResetButton.toggleClass('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
credentialSecretResetButton.prop('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted); credentialSecretResetButton.prop('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
@ -1050,7 +1050,7 @@ RED.projects.settings = (function() {
function createLocalBranchListSection(activeProject,pane) { function createLocalBranchListSection(activeProject,pane) {
var localBranchContainer = $('<div class="user-settings-section"></div>').appendTo(pane); var localBranchContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
$('<h4></h4>').text("Branches").appendTo(localBranchContainer); $('<h4></h4>').text(RED._("sidebar.project.projectSettings.branches")).appendTo(localBranchContainer);
var row = $('<div class="user-settings-row projects-dialog-list"></div>').appendTo(localBranchContainer); var row = $('<div class="user-settings-row projects-dialog-list"></div>').appendTo(localBranchContainer);
@ -1063,7 +1063,7 @@ RED.projects.settings = (function() {
var container = $('<div class="projects-dialog-list-entry">').appendTo(row); var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
if (entry.empty) { if (entry.empty) {
container.addClass('red-ui-search-empty'); container.addClass('red-ui-search-empty');
container.text("No branches"); container.text(RED._("sidebar.project.projectSettings.noBranches"));
return; return;
} }
if (entry.current) { if (entry.current) {
@ -1095,7 +1095,7 @@ RED.projects.settings = (function() {
.click(function(e) { .click(function(e) {
e.preventDefault(); e.preventDefault();
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain'); var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to delete the local branch '"+entry.name+"'? This cannot be undone.", { var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteConfirm", { name: entry.name }), {
type: "warning", type: "warning",
modal: true, modal: true,
fixed: true, fixed: true,
@ -1123,7 +1123,7 @@ RED.projects.settings = (function() {
}, },
400: { 400: {
'git_delete_branch_unmerged': function(error) { 'git_delete_branch_unmerged': function(error) {
notification = RED.notify("The local branch '"+entry.name+"' has unmerged changes that will be lost. Are you sure you want to delete it?", { notification = RED.notify(RED._("sidebar.project.projectSettings.unmergedConfirm", { name: entry.name }), {
type: "warning", type: "warning",
modal: true, modal: true,
fixed: true, fixed: true,
@ -1135,7 +1135,7 @@ RED.projects.settings = (function() {
notification.close(); notification.close();
} }
},{ },{
text: 'Delete unmerged branch', text: RED._("sidebar.project.projectSettings.deleteUnmergedBranch"),
click: function() { click: function() {
options.url += "?force=true"; options.url += "?force=true";
notification.close(); notification.close();
@ -1183,14 +1183,14 @@ RED.projects.settings = (function() {
} }
function createRemoteRepositorySection(activeProject,pane) { function createRemoteRepositorySection(activeProject,pane) {
$('<h3></h3>').text("Version Control").appendTo(pane); $('<h3></h3>').text(RED._("sidebar.project.projectSettings.versionControl")).appendTo(pane);
createLocalBranchListSection(activeProject,pane); createLocalBranchListSection(activeProject,pane);
var repoContainer = $('<div class="user-settings-section"></div>').appendTo(pane); var repoContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
var title = $('<h4></h4>').text("Git remotes").appendTo(repoContainer); var title = $('<h4></h4>').text(RED._("sidebar.project.projectSettings.gitRemotes")).appendTo(repoContainer);
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right; margin-right: 10px;">add remote</button>') var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right; margin-right: 10px;">' + RED._("sidebar.project.projectSettings.addRemote") + '</button>')
.appendTo(title) .appendTo(title)
.click(function(evt) { .click(function(evt) {
editRepoButton.attr('disabled',true); editRepoButton.attr('disabled',true);
@ -1221,7 +1221,7 @@ RED.projects.settings = (function() {
var container = $('<div class="projects-dialog-list-entry">').appendTo(row); var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
if (entry.empty) { if (entry.empty) {
container.addClass('red-ui-search-empty'); container.addClass('red-ui-search-empty');
container.text("No remotes"); container.text(RED._("sidebar.project.projectSettings.noRemotes"));
return; return;
} else { } else {
$('<span class="entry-icon"><i class="fa fa-globe"></i></span>').appendTo(container); $('<span class="entry-icon"><i class="fa fa-globe"></i></span>').appendTo(container);
@ -1240,7 +1240,7 @@ RED.projects.settings = (function() {
.click(function(e) { .click(function(e) {
e.preventDefault(); e.preventDefault();
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain'); var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to delete the remote '"+entry.name+"'?", { var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteRemoteConfrim", { name: entry.name }), {
type: "warning", type: "warning",
modal: true, modal: true,
fixed: true, fixed: true,
@ -1252,7 +1252,7 @@ RED.projects.settings = (function() {
notification.close(); notification.close();
} }
},{ },{
text: 'Delete remote', text: RED._("sidebar.project.projectSettings.deleteRemote"),
click: function() { click: function() {
notification.close(); notification.close();
@ -1315,10 +1315,10 @@ RED.projects.settings = (function() {
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\.git)?(?:\/?|\#[\d\w\.\-_]+?)$/.test(remoteURLInput.val()); // var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\.git)?(?:\/?|\#[\d\w\.\-_]+?)$/.test(remoteURLInput.val());
var validRepo = repo.length > 0 && !/\s/.test(repo); var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) { if (/^https?:\/\/[^/]+@/i.test(repo)) {
remoteURLLabel.text("Do not include the username/password in the url"); remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule2"));
validRepo = false; validRepo = false;
} else { } else {
remoteURLLabel.text("https://, ssh:// or file://"); remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule"));
} }
saveButton.attr('disabled',(!validName || !validRepo)) saveButton.attr('disabled',(!validName || !validRepo))
remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName); remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName);
@ -1332,22 +1332,22 @@ RED.projects.settings = (function() {
var remoteNameInputChanged = false; var remoteNameInputChanged = false;
var remoteURLInputChanged = false; var remoteURLInputChanged = false;
$('<div class="projects-dialog-list-dialog-header">').text('Add remote').appendTo(addRemoteDialog); $('<div class="projects-dialog-list-dialog-header">').text(RED._('sidebar.project.projectSettings.addRemote2')).appendTo(addRemoteDialog);
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog); row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text('Remote name').appendTo(row); $('<label for=""></label>').text(RED._("sidebar.project.projectSettings.remoteName")).appendTo(row);
var remoteNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() { var remoteNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteNameInputChanged = true; remoteNameInputChanged = true;
validateForm(); validateForm();
}); });
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small"); $('<label class="projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.nameRule") + '</small></label>').appendTo(row).find("small");
row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog); row = $('<div class="user-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text('URL').appendTo(row); $('<label for=""></label>').text(RED._("sidebar.project.projectSettings.url")).appendTo(row);
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() { var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteURLInputChanged = true; remoteURLInputChanged = true;
validateForm() validateForm()
}); });
var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row).find("small"); var remoteURLLabel = $('<label class="projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.urlRule") +'</small></label>').appendTo(row).find("small");
var hideEditForm = function() { var hideEditForm = function() {
editRepoButton.attr('disabled',false); editRepoButton.attr('disabled',false);
@ -1361,13 +1361,13 @@ RED.projects.settings = (function() {
} }
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>') var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>')
.appendTo(addRemoteDialog); .appendTo(addRemoteDialog);
$('<button class="editor-button">Cancel</button>') $('<button class="editor-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
hideEditForm(); hideEditForm();
}); });
var saveButton = $('<button class="editor-button">Add remote</button>') var saveButton = $('<button class="editor-button">' + RED._("sidebar.project.projectSettings.addRemote2") + '</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -1484,19 +1484,19 @@ RED.projects.settings = (function() {
utils = _utils; utils = _utils;
addPane({ addPane({
id:'main', id:'main',
title: "Project", // TODO: nls title: RED._("sidebar.project.name"),
get: createMainPane, get: createMainPane,
close: function() { } close: function() { }
}); });
addPane({ addPane({
id:'deps', id:'deps',
title: "Dependencies", // TODO: nls title: RED._("sidebar.project.dependencies"),
get: createDependenciesPane, get: createDependenciesPane,
close: function() { } close: function() { }
}); });
addPane({ addPane({
id:'settings', id:'settings',
title: "Settings", // TODO: nls title: RED._("sidebar.project.settings"),
get: createSettingsPane, get: createSettingsPane,
close: function() { close: function() {
if (popover) { if (popover) {

View File

@ -24,18 +24,18 @@ RED.projects.userSettings = (function() {
var currentGitSettings = RED.settings.get('git') || {}; var currentGitSettings = RED.settings.get('git') || {};
currentGitSettings.user = currentGitSettings.user || {}; currentGitSettings.user = currentGitSettings.user || {};
var title = $('<h3></h3>').text("Committer Details").appendTo(pane); var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.committerDetail")).appendTo(pane);
var gitconfigContainer = $('<div class="user-settings-section"></div>').appendTo(pane); var gitconfigContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
$('<div style="color:#aaa;"></div>').appendTo(gitconfigContainer).text("Leave blank to use system default"); $('<div style="color:#aaa;"></div>').appendTo(gitconfigContainer).text(RED._("editor:sidebar.project.userSettings.committerTip"));
var row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer); var row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for=""></label>').text('Username').appendTo(row); $('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.userName")).appendTo(row);
gitUsernameInput = $('<input type="text">').appendTo(row); gitUsernameInput = $('<input type="text">').appendTo(row);
gitUsernameInput.val(currentGitSettings.user.name||""); gitUsernameInput.val(currentGitSettings.user.name||"");
row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer); row = $('<div class="user-settings-row"></div>').appendTo(gitconfigContainer);
$('<label for=""></label>').text('Email').appendTo(row); $('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.email")).appendTo(row);
gitEmailInput = $('<input type="text">').appendTo(row); gitEmailInput = $('<input type="text">').appendTo(row);
gitEmailInput.val(currentGitSettings.user.email||""); gitEmailInput.val(currentGitSettings.user.email||"");
} }
@ -44,10 +44,10 @@ RED.projects.userSettings = (function() {
function createSSHKeySection(pane) { function createSSHKeySection(pane) {
var container = $('<div class="user-settings-section"></div>').appendTo(pane); var container = $('<div class="user-settings-section"></div>').appendTo(pane);
var popover; var popover;
var title = $('<h3></h3>').text("SSH Keys").appendTo(container); var title = $('<h3></h3>').text(RED._("editor:sidebar.project.userSettings.sshKeys")).appendTo(container);
var subtitle = $('<div style="color:#aaa;"></div>').appendTo(container).text("Allows you to create secure connections to remote git repositories."); var subtitle = $('<div style="color:#aaa;"></div>').appendTo(container).text(RED._("editor:sidebar.project.userSettings.sshKeysTip"));
var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="editor-button editor-button-small" style="float: right; margin-right: 10px;">add key</button>') var addKeyButton = $('<button id="user-settings-gitconfig-add-key" class="editor-button editor-button-small" style="float: right; margin-right: 10px;">'+RED._("editor:sidebar.project.userSettings.add")+'</button>')
.appendTo(subtitle) .appendTo(subtitle)
.click(function(evt) { .click(function(evt) {
addKeyButton.attr('disabled',true); addKeyButton.attr('disabled',true);
@ -72,9 +72,9 @@ RED.projects.userSettings = (function() {
var validPassphrase = passphrase.length === 0 || passphrase.length >= 8; var validPassphrase = passphrase.length === 0 || passphrase.length >= 8;
passphraseInput.toggleClass('input-error',!validPassphrase); passphraseInput.toggleClass('input-error',!validPassphrase);
if (!validPassphrase) { if (!validPassphrase) {
passphraseInputSubLabel.text("Passphrase too short"); passphraseInputSubLabel.text(RED._("editor:sidebar.project.userSettings.passphraseShort"));
} else if (passphrase.length === 0) { } else if (passphrase.length === 0) {
passphraseInputSubLabel.text("Optional"); passphraseInputSubLabel.text(RED._("editor:sidebar.project.userSettings.optional"));
} else { } else {
passphraseInputSubLabel.text(""); passphraseInputSubLabel.text("");
} }
@ -91,11 +91,11 @@ RED.projects.userSettings = (function() {
var row = $('<div class="user-settings-row"></div>').appendTo(container); var row = $('<div class="user-settings-row"></div>').appendTo(container);
var addKeyDialog = $('<div class="projects-dialog-list-dialog"></div>').hide().appendTo(row); var addKeyDialog = $('<div class="projects-dialog-list-dialog"></div>').hide().appendTo(row);
$('<div class="projects-dialog-list-dialog-header">').text('Add SSH Key').appendTo(addKeyDialog); $('<div class="projects-dialog-list-dialog-header">').text(RED._("editor:sidebar.project.userSettings.addSshKey")).appendTo(addKeyDialog);
var addKeyDialogBody = $('<div>').appendTo(addKeyDialog); var addKeyDialogBody = $('<div>').appendTo(addKeyDialog);
row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody); row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody);
$('<div style="color:#aaa;"></div>').appendTo(row).text("Generate a new public/private key pair"); $('<div style="color:#aaa;"></div>').appendTo(row).text(RED._("editor:sidebar.project.userSettings.addSshKeyTip"));
// var bg = $('<div></div>',{class:"button-group", style:"text-align: center"}).appendTo(row); // var bg = $('<div></div>',{class:"button-group", style:"text-align: center"}).appendTo(row);
// var addLocalButton = $('<button class="editor-button toggle selected">use local key</button>').appendTo(bg); // var addLocalButton = $('<button class="editor-button toggle selected">use local key</button>').appendTo(bg);
// var uploadButton = $('<button class="editor-button toggle">upload key</button>').appendTo(bg); // var uploadButton = $('<button class="editor-button toggle">upload key</button>').appendTo(bg);
@ -125,19 +125,19 @@ RED.projects.userSettings = (function() {
row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody); row = $('<div class="user-settings-row"></div>').appendTo(addKeyDialogBody);
$('<label for=""></label>').text('Name').appendTo(row); $('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.name")).appendTo(row);
var keyNameInputChanged = false; var keyNameInputChanged = false;
var keyNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() { var keyNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
keyNameInputChanged = true; keyNameInputChanged = true;
validateForm(); validateForm();
}); });
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small"); $('<label class="projects-edit-form-sublabel"><small>'+RED._("editor:sidebar.project.userSettings.nameRule")+'</small></label>').appendTo(row).find("small");
var generateKeyPane = $('<div>').appendTo(addKeyDialogBody); var generateKeyPane = $('<div>').appendTo(addKeyDialogBody);
row = $('<div class="user-settings-row"></div>').appendTo(generateKeyPane); row = $('<div class="user-settings-row"></div>').appendTo(generateKeyPane);
$('<label for=""></label>').text('Passphrase').appendTo(row); $('<label for=""></label>').text(RED._("editor:sidebar.project.userSettings.passphrase")).appendTo(row);
var passphraseInput = $('<input type="password">').appendTo(row).on("change keyup paste",validateForm); var passphraseInput = $('<input type="password">').appendTo(row).on("change keyup paste",validateForm);
var passphraseInputSubLabel = $('<label class="projects-edit-form-sublabel"><small>Optional</small></label>').appendTo(row).find("small"); var passphraseInputSubLabel = $('<label class="projects-edit-form-sublabel"><small>'+RED._("editor:sidebar.project.userSettings.optional")+'</small></label>').appendTo(row).find("small");
// var addLocalKeyPane = $('<div>').hide().appendTo(addKeyDialogBody); // var addLocalKeyPane = $('<div>').hide().appendTo(addKeyDialogBody);
// row = $('<div class="user-settings-row"></div>').appendTo(addLocalKeyPane); // row = $('<div class="user-settings-row"></div>').appendTo(addLocalKeyPane);
@ -179,13 +179,13 @@ RED.projects.userSettings = (function() {
} }
} }
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(addKeyDialog); var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(addKeyDialog);
$('<button class="editor-button">Cancel</button>') $('<button class="editor-button">'+RED._("editor:sidebar.project.userSettings.cancel")+'</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
hideEditForm(); hideEditForm();
}); });
var saveButton = $('<button class="editor-button">Generate key</button>') var saveButton = $('<button class="editor-button">'+RED._("editor:sidebar.project.userSettings.generate")+'</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -264,7 +264,7 @@ RED.projects.userSettings = (function() {
utils.sendRequest(options); utils.sendRequest(options);
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(row); var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>').appendTo(row);
$('<button class="editor-button editor-button-small">Copy public key to clipboard</button>') $('<button class="editor-button editor-button-small">'+RED._("editor:sidebar.project.userSettings.copyPublicKey")+'</button>')
.appendTo(formButtons) .appendTo(formButtons)
.click(function(evt) { .click(function(evt) {
try { try {
@ -289,7 +289,7 @@ RED.projects.userSettings = (function() {
var container = $('<div class="projects-dialog-list-entry">').appendTo(row); var container = $('<div class="projects-dialog-list-entry">').appendTo(row);
if (entry.empty) { if (entry.empty) {
container.addClass('red-ui-search-empty'); container.addClass('red-ui-search-empty');
container.text("No SSH keys"); container.text(RED._("editor:sidebar.project.userSettings.noSshKeys"));
return; return;
} }
var topRow = $('<div class="projects-dialog-ssh-key-header">').appendTo(container); var topRow = $('<div class="projects-dialog-ssh-key-header">').appendTo(container);
@ -313,7 +313,7 @@ RED.projects.userSettings = (function() {
.click(function(e) { .click(function(e) {
e.stopPropagation(); e.stopPropagation();
var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain'); var spinner = utils.addSpinnerOverlay(row).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to delete the SSH key '"+entry.name+"'? This cannot be undone.", { var notification = RED.notify(RED._("editor:sidebar.project.userSettings.deleteConfirm", {name:entry.name}), {
type: 'warning', type: 'warning',
modal: true, modal: true,
fixed: true, fixed: true,
@ -326,7 +326,7 @@ RED.projects.userSettings = (function() {
} }
}, },
{ {
text: "Delete key", text: RED._("editor:sidebar.project.userSettings.delete"),
click: function() { click: function() {
notification.close(); notification.close();
var url = "settings/user/keys/"+entry.name; var url = "settings/user/keys/"+entry.name;
@ -400,7 +400,7 @@ RED.projects.userSettings = (function() {
utils = _utils; utils = _utils;
RED.userSettings.add({ RED.userSettings.add({
id:'gitconfig', id:'gitconfig',
title: "Git config", // TODO: nls title: RED._("editor:sidebar.project.userSettings.gitConfig"),
get: createSettingsPane, get: createSettingsPane,
close: function() { close: function() {
var currentGitSettings = RED.settings.get('git') || {}; var currentGitSettings = RED.settings.get('git') || {};

View File

@ -22,18 +22,18 @@ RED.projects = (function() {
function reportUnexpectedError(error) { function reportUnexpectedError(error) {
var notification; var notification;
if (error.error === 'git_missing_user') { if (error.error === 'git_missing_user') {
notification = RED.notify("<p>You Git client is not configured with a username/email.</p>",{ notification = RED.notify("<p>"+RED._("projects.errors.no-username-email")+"</p>",{
fixed: true, fixed: true,
type:'error', type:'error',
buttons: [ buttons: [
{ {
text: "Cancel", text: RED._("common.label.cancel"),
click: function() { click: function() {
notification.close(); notification.close();
} }
}, },
{ {
text: "Configure Git client", text: RED._("projects.config-git"),
click: function() { click: function() {
RED.userSettings.show('gitconfig'); RED.userSettings.show('gitconfig');
notification.close(); notification.close();
@ -43,13 +43,13 @@ RED.projects = (function() {
}) })
} else { } else {
console.log(error); console.log(error);
notification = RED.notify("<p>An unexpected error occurred:</p><p>"+error.message+"</p><small>code: "+error.error+"</small>",{ notification = RED.notify("<p>"+RED._("projects.errors.unexpected")+":</p><p>"+error.message+"</p><small>"+RED._("projects.errors.code")+": "+error.error+"</small>",{
fixed: true, fixed: true,
modal: true, modal: true,
type: 'error', type: 'error',
buttons: [ buttons: [
{ {
text: "Close", text: RED._("common.label.close"),
click: function() { click: function() {
notification.close(); notification.close();
} }
@ -75,14 +75,14 @@ RED.projects = (function() {
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Hello! We have introduced 'projects' to Node-RED.").appendTo(body); $('<p>').text(RED._("projects.welcome.hello")).appendTo(body);
$('<p>').text("This is a new way for you to manage your flow files and includes version control of your flows.").appendTo(body); $('<p>').text(RED._("projects.welcome.desc0")).appendTo(body);
$('<p>').text("To get started you can create your first project or clone an existing project from a git repository.").appendTo(body); $('<p>').text(RED._("projects.welcome.desc1")).appendTo(body);
$('<p>').text("If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.").appendTo(body); $('<p>').text(RED._("projects.welcome.desc2")).appendTo(body);
var row = $('<div style="text-align: center"></div>').appendTo(body); var row = $('<div style="text-align: center"></div>').appendTo(body);
var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>Create Project</button>').appendTo(row); var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.welcome.create")+'</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>Clone Repository</button>').appendTo(row); var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.welcome.clone")+'</button>').appendTo(row);
createAsEmpty.click(function(e) { createAsEmpty.click(function(e) {
e.preventDefault(); e.preventDefault();
@ -105,7 +105,7 @@ RED.projects = (function() {
buttons: [ buttons: [
{ {
// id: "clipboard-dialog-cancel", // id: "clipboard-dialog-cancel",
text: "Not right now", text: RED._("projects.welcome.not-right-now"),
click: function() { click: function() {
createProjectOptions = {}; createProjectOptions = {};
$( this ).dialog( "close" ); $( this ).dialog( "close" );
@ -139,23 +139,23 @@ RED.projects = (function() {
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Setup your version control client").appendTo(body); $('<p>').text(RED._("projects.git-config.setup")).appendTo(body);
$('<p>').text("Node-RED uses the open source tool Git for version control. It tracks changes to your project files and lets you push them to remote repositories.").appendTo(body); $('<p>').text(RED._("projects.git-config.desc0")).appendTo(body);
$('<p>').text("When you commit a set of changes, Git records who made the changes with a username and email address. The Username can be anything you want - it does not need to be your real name.").appendTo(body); $('<p>').text(RED._("projects.git-config.desc1")).appendTo(body);
if (isGlobalConfig) { if (isGlobalConfig) {
$('<p>').text("Your Git client is already configured with the details below.").appendTo(body); $('<p>').text(RED._("projects.git-config.desc2")).appendTo(body);
} }
$('<p>').text("You can change these settings later under the 'Git config' tab of the settings dialog.").appendTo(body); $('<p>').text(RED._("projects.git-config.desc3")).appendTo(body);
var row = $('<div class="form-row"></div>').appendTo(body); var row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="">Username</label>').appendTo(row); $('<label for="">'+RED._("projects.git-config.username")+'</label>').appendTo(row);
gitUsernameInput = $('<input type="text">').val((existingGitSettings&&existingGitSettings.name)||"").appendTo(row); gitUsernameInput = $('<input type="text">').val((existingGitSettings&&existingGitSettings.name)||"").appendTo(row);
// $('<div style="position:relative;"></div>').text("This does not need to be your real name").appendTo(row); // $('<div style="position:relative;"></div>').text("This does not need to be your real name").appendTo(row);
gitUsernameInput.on("change keyup paste",validateForm); gitUsernameInput.on("change keyup paste",validateForm);
row = $('<div class="form-row"></div>').appendTo(body); row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="">Email</label>').appendTo(row); $('<label for="">'+RED._("projects.git-config.email")+'</label>').appendTo(row);
gitEmailInput = $('<input type="text">').val((existingGitSettings&&existingGitSettings.email)||"").appendTo(row); gitEmailInput = $('<input type="text">').val((existingGitSettings&&existingGitSettings.email)||"").appendTo(row);
gitEmailInput.on("change keyup paste",validateForm); gitEmailInput.on("change keyup paste",validateForm);
// $('<div style="position:relative;"></div>').text("Something something email").appendTo(row); // $('<div style="position:relative;"></div>').text("Something something email").appendTo(row);
@ -168,14 +168,14 @@ RED.projects = (function() {
buttons: [ buttons: [
{ {
// id: "clipboard-dialog-cancel", // id: "clipboard-dialog-cancel",
text: "Back", text: RED._("common.label.back"),
click: function() { click: function() {
show('welcome'); show('welcome');
} }
}, },
{ {
id: "projects-dialog-git-config", id: "projects-dialog-git-config",
text: "Next", // TODO: nls text: RED._("common.label.next"),
class: "primary", class: "primary",
click: function() { click: function() {
var currentGitSettings = RED.settings.get('git') || {}; var currentGitSettings = RED.settings.get('git') || {};
@ -216,10 +216,10 @@ RED.projects = (function() {
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Create your project").appendTo(body); $('<p>').text(RED._("projects.project-details.create")).appendTo(body);
$('<p>').text("A project is maintained as a Git repository. It makes it much easier to share your flows with others and to collaborate on them.").appendTo(body); $('<p>').text(RED._("projects.project-details.desc0")).appendTo(body);
$('<p>').text("You can create multiple projects and quickly switch between them from the editor.").appendTo(body); $('<p>').text(RED._("projects.project-details.desc1")).appendTo(body);
$('<p>').text("To begin, your project needs a name and an optional description.").appendTo(body); $('<p>').text(RED._("projects.project-details.desc2")).appendTo(body);
var validateForm = function() { var validateForm = function() {
var projectName = projectNameInput.val(); var projectName = projectNameInput.val();
@ -236,14 +236,14 @@ RED.projects = (function() {
projectNameValid = false; projectNameValid = false;
valid = false; valid = false;
if (projectList[projectName]) { if (projectList[projectName]) {
projectNameSublabel.text("Project already exists"); projectNameSublabel.text(RED._("projects.project-details.already-exists"));
} else { } else {
projectNameSublabel.text("Must contain only A-Z 0-9 _ -"); projectNameSublabel.text(RED._("projects.project-details.must-contain"));
} }
} else { } else {
projectNameInput.removeClass("input-error"); projectNameInput.removeClass("input-error");
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus); $('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
projectNameSublabel.text("Must contain only A-Z 0-9 _ -"); projectNameSublabel.text(RED._("projects.project-details.must-contain"));
projectNameValid = true; projectNameValid = true;
} }
projectNameLastChecked = projectName; projectNameLastChecked = projectName;
@ -253,7 +253,7 @@ RED.projects = (function() {
} }
var row = $('<div class="form-row"></div>').appendTo(body); var row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-name">Project name</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-name">'+RED._("projects.project-details.project-name")+'</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row); var subrow = $('<div style="position:relative;"></div>').appendTo(row);
projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').val(createProjectOptions.name||"").appendTo(subrow); projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').val(createProjectOptions.name||"").appendTo(subrow);
@ -283,13 +283,13 @@ RED.projects = (function() {
checkProjectName = null; checkProjectName = null;
},300) },300)
}); });
projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small"); projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>'+RED._("projects.project-details.must-contain")+'</small></label>').appendTo(row).find("small");
// Empty Project // Empty Project
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(body); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-desc">Description</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-desc">'+RED._("projects.project-details.desc")+'</label>').appendTo(row);
projectSummaryInput = $('<input id="projects-dialog-screen-create-project-desc" type="text">').val(createProjectOptions.summary||"").appendTo(row); projectSummaryInput = $('<input id="projects-dialog-screen-create-project-desc" type="text">').val(createProjectOptions.summary||"").appendTo(row);
$('<label class="projects-edit-form-sublabel"><small>Optional</small></label>').appendTo(row); $('<label class="projects-edit-form-sublabel"><small>'+RED._("projects.project-details.opt")+'</small></label>').appendTo(row);
setTimeout(function() { setTimeout(function() {
projectNameInput.focus(); projectNameInput.focus();
@ -300,7 +300,7 @@ RED.projects = (function() {
buttons: function(options) { buttons: function(options) {
return [ return [
{ {
text: "Back", text: RED._("common.label.back"),
click: function() { click: function() {
show('git-config'); show('git-config');
} }
@ -308,7 +308,7 @@ RED.projects = (function() {
{ {
id: "projects-dialog-create-name", id: "projects-dialog-create-name",
disabled: true, disabled: true,
text: "Next", // TODO: nls text: RED._("common.label.next"),
class: "primary disabled", class: "primary disabled",
click: function() { click: function() {
createProjectOptions.name = projectNameInput.val(); createProjectOptions.name = projectNameInput.val();
@ -344,8 +344,8 @@ RED.projects = (function() {
var container = $('<div class="projects-dialog-screen-start"></div>'); var container = $('<div class="projects-dialog-screen-start"></div>');
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Clone a project").appendTo(body); $('<p>').text(RED._("projects.clone-project.clone")).appendTo(body);
$('<p>').text("If you already have a git repository containing a project, you can clone it to get started.").appendTo(body); $('<p>').text(RED._("projects.clone-project.desc0")).appendTo(body);
var projectList = null; var projectList = null;
var pendingFormValidation = false; var pendingFormValidation = false;
@ -376,14 +376,14 @@ RED.projects = (function() {
projectNameValid = false; projectNameValid = false;
valid = false; valid = false;
if (projectList[projectName]) { if (projectList[projectName]) {
projectNameSublabel.text("Project already exists"); projectNameSublabel.text(RED._("projects.clone-project.already-exists"));
} else { } else {
projectNameSublabel.text("Must contain only A-Z 0-9 _ -"); projectNameSublabel.text(RED._("projects.clone-project.must-contain"));
} }
} else { } else {
projectNameInput.removeClass("input-error"); projectNameInput.removeClass("input-error");
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus); $('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
projectNameSublabel.text("Must contain only A-Z 0-9 _ -"); projectNameSublabel.text(RED._("projects.clone-project.must-contain"));
projectNameValid = true; projectNameValid = true;
} }
projectNameLastChecked = projectName; projectNameLastChecked = projectName;
@ -395,7 +395,7 @@ RED.projects = (function() {
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo); // var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
var validRepo = repo.length > 0 && !/\s/.test(repo); var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) { if (/^https?:\/\/[^/]+@/i.test(repo)) {
$("#projects-dialog-screen-create-project-repo-label small").text("Do not include the username/password in the url"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.clone-project.no-info-in-url"));
validRepo = false; validRepo = false;
} }
if (!validRepo) { if (!validRepo) {
@ -426,7 +426,7 @@ RED.projects = (function() {
var row; var row;
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(body); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-name">Project name</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-name">'+RED._("projects.clone-project.project-name")+'</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row); var subrow = $('<div style="position:relative;"></div>').appendTo(row);
projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').appendTo(subrow); projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').appendTo(subrow);
@ -456,19 +456,19 @@ RED.projects = (function() {
checkProjectName = null; checkProjectName = null;
},300) },300)
}); });
projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small"); projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>'+RED._("projects.clone-project.must-contain")+'</small></label>').appendTo(row).find("small");
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-repo">Git repository URL</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-repo">'+RED._("projects.clone-project.git-url")+'</label>').appendTo(row);
projectRepoInput = $('<input id="projects-dialog-screen-create-project-repo" type="text" placeholder="https://git.example.com/path/my-project.git"></input>').appendTo(row); projectRepoInput = $('<input id="projects-dialog-screen-create-project-repo" type="text" placeholder="https://git.example.com/path/my-project.git"></input>').appendTo(row);
$('<label id="projects-dialog-screen-create-project-repo-label" class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row); $('<label id="projects-dialog-screen-create-project-repo-label" class="projects-edit-form-sublabel"><small>'+RED._("projects.clone-project.protocols")+'</small></label>').appendTo(row);
var projectRepoChanged = false; var projectRepoChanged = false;
var lastProjectRepo = ""; var lastProjectRepo = "";
projectRepoInput.on("change keyup paste",function() { projectRepoInput.on("change keyup paste",function() {
projectRepoChanged = true; projectRepoChanged = true;
var repo = $(this).val(); var repo = $(this).val();
if (lastProjectRepo !== repo) { if (lastProjectRepo !== repo) {
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.clone-project.protocols"));
} }
lastProjectRepo = repo; lastProjectRepo = repo;
@ -486,24 +486,24 @@ RED.projects = (function() {
var cloneAuthRows = $('<div class="projects-dialog-screen-create-row"></div>').appendTo(body); var cloneAuthRows = $('<div class="projects-dialog-screen-create-row"></div>').appendTo(body);
row = $('<div class="form-row projects-dialog-screen-create-row-auth-error"></div>').hide().appendTo(cloneAuthRows); row = $('<div class="form-row projects-dialog-screen-create-row-auth-error"></div>').hide().appendTo(cloneAuthRows);
$('<div><i class="fa fa-warning"></i> Authentication failed</div>').appendTo(row); $('<div><i class="fa fa-warning"></i> '+RED._("projects.clone-project.auth-failed")+'</div>').appendTo(row);
// Repo credentials - username/password ---------------- // Repo credentials - username/password ----------------
row = $('<div class="hide form-row projects-dialog-screen-create-row-creds"></div>').hide().appendTo(cloneAuthRows); row = $('<div class="hide form-row projects-dialog-screen-create-row-creds"></div>').hide().appendTo(cloneAuthRows);
var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row); var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-user">Username</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-user">'+RED._("projects.clone-project.username")+'</label>').appendTo(subrow);
projectRepoUserInput = $('<input id="projects-dialog-screen-create-project-repo-user" type="text"></input>').appendTo(subrow); projectRepoUserInput = $('<input id="projects-dialog-screen-create-project-repo-user" type="text"></input>').appendTo(subrow);
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row); subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-pass">Password</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-pass">'+RED._("projects.clone-project.passwd")+'</label>').appendTo(subrow);
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow); projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
// ----------------------------------------------------- // -----------------------------------------------------
// Repo credentials - key/passphrase ------------------- // Repo credentials - key/passphrase -------------------
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(cloneAuthRows); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(cloneAuthRows);
subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row); subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH Key</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.clone-project.ssh-key")+'</label>').appendTo(subrow);
projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow); projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow);
$.getJSON("settings/user/keys", function(data) { $.getJSON("settings/user/keys", function(data) {
@ -523,14 +523,14 @@ RED.projects = (function() {
} }
}); });
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row); subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-passphrase">Passphrase</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.clone-project.passphrase")+'</label>').appendTo(subrow);
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow); projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
subrow = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows); subrow = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
var sshwarningRow = $('<div class="projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow); var sshwarningRow = $('<div class="projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> Before you can clone a repository over ssh you must add an SSH key to access it.</div>').appendTo(sshwarningRow); $('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.clone-project.ssh-key-desc")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow); subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="editor-button">Add an ssh key</button>').appendTo(subrow).click(function(e) { $('<button class="editor-button">'+RED._("projects.clone-project.ssh-key-add")+'</button>').appendTo(subrow).click(function(e) {
e.preventDefault(); e.preventDefault();
$('#projects-dialog-cancel').click(); $('#projects-dialog-cancel').click();
RED.userSettings.show('gitconfig'); RED.userSettings.show('gitconfig');
@ -543,7 +543,7 @@ RED.projects = (function() {
// Secret - clone // Secret - clone
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(body);
$('<label>Credentials encryption key</label>').appendTo(row); $('<label>'+RED._("projects.clone-project.credential-key")+'</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row); projectSecretInput = $('<input type="password"></input>').appendTo(row);
@ -553,7 +553,7 @@ RED.projects = (function() {
buttons: function(options) { buttons: function(options) {
return [ return [
{ {
text: "Back", text: RED._("common.label.back"),
click: function() { click: function() {
show('git-config'); show('git-config');
} }
@ -561,7 +561,7 @@ RED.projects = (function() {
{ {
id: "projects-dialog-clone-project", id: "projects-dialog-clone-project",
disabled: true, disabled: true,
text: "Clone project", // TODO: nls text: RED._("common.label.clone"),
class: "primary disabled", class: "primary disabled",
click: function() { click: function() {
var projectType = $(".projects-dialog-screen-create-type.selected").data('type'); var projectType = $(".projects-dialog-screen-create-type.selected").data('type');
@ -585,7 +585,7 @@ RED.projects = (function() {
}; };
} }
else { else {
console.log("Error! Can't get selected SSH key path."); console.log(RED._("projects.clone-project.cant-get-ssh-key"));
return; return;
} }
} }
@ -602,7 +602,7 @@ RED.projects = (function() {
} }
$(".projects-dialog-screen-create-row-auth-error").hide(); $(".projects-dialog-screen-create-row-auth-error").hide();
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.clone-project.protocols"));
projectRepoUserInput.removeClass("input-error"); projectRepoUserInput.removeClass("input-error");
projectRepoPasswordInput.removeClass("input-error"); projectRepoPasswordInput.removeClass("input-error");
@ -622,22 +622,22 @@ RED.projects = (function() {
}, },
400: { 400: {
'project_exists': function(error) { 'project_exists': function(error) {
console.log("already exists"); console.log(RED._("projects.clone-project.already-exists"));
}, },
'git_error': function(error) { 'git_error': function(error) {
console.log("git error",error); console.log(RED._("projects.clone-project.git-error"),error);
}, },
'git_connection_failed': function(error) { 'git_connection_failed': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Connection failed"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.clone-project.connection-failed"));
}, },
'git_not_a_repository': function(error) { 'git_not_a_repository': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Not a git repository"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.clone-project.not-git-repo"));
}, },
'git_repository_not_found': function(error) { 'git_repository_not_found': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Repository not found"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.clone-project.repo-not-found"));
}, },
'git_auth_failed': function(error) { 'git_auth_failed': function(error) {
$(".projects-dialog-screen-create-row-auth-error").show(); $(".projects-dialog-screen-create-row-auth-error").show();
@ -689,11 +689,11 @@ RED.projects = (function() {
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Create your project files").appendTo(body); $('<p>').text(RED._("projects.default-files.create")).appendTo(body);
$('<p>').text("A project contains your flow files, a README file and a package.json file.").appendTo(body); $('<p>').text(RED._("projects.default-files.desc0")).appendTo(body);
$('<p>').text("It can contain any other files you want to maintain in the Git repository.").appendTo(body); $('<p>').text(RED._("projects.default-files.desc1")).appendTo(body);
if (!options.existingProject && RED.settings.files) { if (!options.existingProject && RED.settings.files) {
$('<p>').text("Your existing flow and credential files will be copied into the project.").appendTo(body); $('<p>').text(RED._("projects.default-files.desc2")).appendTo(body);
} }
var validateForm = function() { var validateForm = function() {
@ -724,7 +724,7 @@ RED.projects = (function() {
$("#projects-dialog-create-default-files").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid); $("#projects-dialog-create-default-files").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
} }
var row = $('<div class="form-row"></div>').appendTo(body); var row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-file">Flow file</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-file">'+RED._("projects.default-files.flow-file")+'</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row); var subrow = $('<div style="position:relative;"></div>').appendTo(row);
var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || (RED.settings.files && RED.settings.files.flow)||"flow.json"; var defaultFlowFile = (createProjectOptions.files &&createProjectOptions.files.flow) || (RED.settings.files && RED.settings.files.flow)||"flow.json";
projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val(defaultFlowFile) projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val(defaultFlowFile)
@ -735,7 +735,7 @@ RED.projects = (function() {
var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || (RED.settings.files && RED.settings.files.credentials)||"flow_cred.json"; var defaultCredentialsFile = (createProjectOptions.files &&createProjectOptions.files.credentials) || (RED.settings.files && RED.settings.files.credentials)||"flow_cred.json";
row = $('<div class="form-row"></div>').appendTo(body); row = $('<div class="form-row"></div>').appendTo(body);
$('<label for="projects-dialog-screen-create-project-credfile">Credentials file</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-credfile">'+RED._("projects.default-files.credentials-file")+'</label>').appendTo(row);
subrow = $('<div style="position:relative;"></div>').appendTo(row); subrow = $('<div style="position:relative;"></div>').appendTo(row);
projectCredentialFileInput = $('<div style="width: 100%" class="uneditable-input" id="projects-dialog-screen-create-project-credentials">').text(defaultCredentialsFile) projectCredentialFileInput = $('<div style="width: 100%" class="uneditable-input" id="projects-dialog-screen-create-project-credentials">').text(defaultCredentialsFile)
.appendTo(subrow); .appendTo(subrow);
@ -752,7 +752,7 @@ RED.projects = (function() {
return [ return [
{ {
// id: "clipboard-dialog-cancel", // id: "clipboard-dialog-cancel",
text: options.existingProject?"Cancel":"Back", text: RED._(options.existingProject ? "common.label.cancel": "common.label.back"),
click: function() { click: function() {
if (options.existingProject) { if (options.existingProject) {
$(this).dialog('close'); $(this).dialog('close');
@ -763,7 +763,7 @@ RED.projects = (function() {
}, },
{ {
id: "projects-dialog-create-default-files", id: "projects-dialog-create-default-files",
text: "Next", // TODO: nls text: RED._("common.label.next"),
class: "primary", class: "primary",
click: function() { click: function() {
createProjectOptions.files = { createProjectOptions.files = {
@ -789,22 +789,22 @@ RED.projects = (function() {
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("Setup encryption of your credentials file").appendTo(body); $('<p>').text(RED._("projects.encryption-config.setup")).appendTo(body);
if (options.existingProject) { if (options.existingProject) {
$('<p>').text("Your flow credentials file can be encrypted to keep its contents secure.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc0")).appendTo(body);
$('<p>').text("If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc1")).appendTo(body);
} else { } else {
if (RED.settings.flowEncryptionType === 'disabled') { if (RED.settings.flowEncryptionType === 'disabled') {
$('<p>').text("Your flow credentials file is not currently encrypted.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc2")).appendTo(body);
$('<p>').text("That means its contents, such as passwords and access tokens, can be read by anyone with access to the file.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc3")).appendTo(body);
$('<p>').text("If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc4")).appendTo(body);
} else { } else {
if (RED.settings.flowEncryptionType === 'user') { if (RED.settings.flowEncryptionType === 'user') {
$('<p>').text("Your flow credentials file is currently encrypted using the credentialSecret property from your settings file as the key.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc5")).appendTo(body);
} else if (RED.settings.flowEncryptionType === 'system') { } else if (RED.settings.flowEncryptionType === 'system') {
$('<p>').text("Your flow credentials file is currently encrypted using a system-generated key. You should provide a new secret key for this project.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc6")).appendTo(body);
} }
$('<p>').text("The key will be stored separately from your project files. You will need to provide the key to use this project in another instance of Node-RED.").appendTo(body); $('<p>').text(RED._("projects.encryption-config.desc7")).appendTo(body);
} }
} }
@ -832,16 +832,16 @@ RED.projects = (function() {
var row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(body); var row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(body);
$('<label>Credentials</label>').appendTo(row); $('<label>'+RED._("projects.encryption-config.credentials")+'</label>').appendTo(row);
var credentialsBox = $('<div style="width: 550px">').appendTo(row); var credentialsBox = $('<div style="width: 550px">').appendTo(row);
var credentialsRightBox = $('<div style="min-height:150px; box-sizing: border-box; float: right; vertical-align: top; width: 331px; margin-left: -1px; padding: 15px; margin-top: -15px; border: 1px solid #ccc; border-radius: 3px; display: inline-block">').appendTo(credentialsBox); var credentialsRightBox = $('<div style="min-height:150px; box-sizing: border-box; float: right; vertical-align: top; width: 331px; margin-left: -1px; padding: 15px; margin-top: -15px; border: 1px solid #ccc; border-radius: 3px; display: inline-block">').appendTo(credentialsBox);
var credentialsLeftBox = $('<div style="vertical-align: top; width: 220px; display: inline-block">').appendTo(credentialsBox); var credentialsLeftBox = $('<div style="vertical-align: top; width: 220px; display: inline-block">').appendTo(credentialsBox);
var credentialsEnabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid #ccc;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: white;"></div>').appendTo(credentialsLeftBox); var credentialsEnabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid #ccc;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: white;"></div>').appendTo(credentialsLeftBox);
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="enabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-lock"></i> <span style="vertical-align: middle;">Enable encryption</span></label>').appendTo(credentialsEnabledBox); $('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="enabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-lock"></i> <span style="vertical-align: middle;">'+RED._("projects.encryption-config.enable")+'</span></label>').appendTo(credentialsEnabledBox);
var credentialsDisabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid white;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: #ccc; "></div>').appendTo(credentialsLeftBox); var credentialsDisabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid white;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: #ccc; "></div>').appendTo(credentialsLeftBox);
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="disabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-unlock"></i> <span style="vertical-align: middle;">Disable encryption</span></label>').appendTo(credentialsDisabledBox); $('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="disabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-unlock"></i> <span style="vertical-align: middle;">'+RED._("projects.encryption-config.disable")+'</span></label>').appendTo(credentialsDisabledBox);
credentialsLeftBox.find("input[name=projects-encryption-type]").click(function(e) { credentialsLeftBox.find("input[name=projects-encryption-type]").click(function(e) {
var val = $(this).val(); var val = $(this).val();
@ -876,15 +876,15 @@ RED.projects = (function() {
}) })
row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox); row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
$('<label class="projects-edit-form-inline-label '+((RED.settings.flowEncryptionType !== 'user')?'disabled':'')+'" style="margin-left: 5px"><input '+((RED.settings.flowEncryptionType !== 'user')?'disabled':'')+' type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="default" name="projects-encryption-key"> <span style="vertical-align: middle;">Copy over existing key</span></label>').appendTo(row); $('<label class="projects-edit-form-inline-label '+((RED.settings.flowEncryptionType !== 'user')?'disabled':'')+'" style="margin-left: 5px"><input '+((RED.settings.flowEncryptionType !== 'user')?RED._("projects.encryption-config.disabled"):'')+' type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="default" name="projects-encryption-key"> <span style="vertical-align: middle;">'+RED._("projects.encryption-config.copy")+'</span></label>').appendTo(row);
row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox); row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="custom" name="projects-encryption-key"> <span style="vertical-align: middle;">Use custom key</span></label>').appendTo(row); $('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" value="custom" name="projects-encryption-key"> <span style="vertical-align: middle;">'+RED._("projects.encryption-config.use-custom")+'</span></label>').appendTo(row);
row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox); row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
emptyProjectCredentialInput = $('<input disabled type="password" style="margin-left: 25px; width: calc(100% - 30px);"></input>').appendTo(row); emptyProjectCredentialInput = $('<input disabled type="password" style="margin-left: 25px; width: calc(100% - 30px);"></input>').appendTo(row);
emptyProjectCredentialInput.on("change keyup paste", validateForm); emptyProjectCredentialInput.on("change keyup paste", validateForm);
row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox); row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox);
$('<div class="" style="padding: 5px 20px;"><i class="fa fa-warning"></i> The credentials file will not be encrypted and its contents easily read</div>').appendTo(row); $('<div class="" style="padding: 5px 20px;"><i class="fa fa-warning"></i> '+RED._("projects.encryption-config.desc8")+'</div>').appendTo(row);
credentialsRightBox.find("input[name=projects-encryption-key]").click(function() { credentialsRightBox.find("input[name=projects-encryption-key]").click(function() {
var val = $(this).val(); var val = $(this).val();
@ -911,14 +911,14 @@ RED.projects = (function() {
return [ return [
{ {
// id: "clipboard-dialog-cancel", // id: "clipboard-dialog-cancel",
text: "Back", text: RED._("common.label.back"),
click: function() { click: function() {
show('default-files',options); show('default-files',options);
} }
}, },
{ {
id: "projects-dialog-create-encryption", id: "projects-dialog-create-encryption",
text: options.existingProject?"Create project files":"Create project", // TODO: nls text: RED._(options.existingProject?"projects.encryption-config.create-project-files":"projects.encryption-config.create-project"),
class: "primary disabled", class: "primary disabled",
disabled: true, disabled: true,
click: function() { click: function() {
@ -966,10 +966,10 @@ RED.projects = (function() {
}, },
400: { 400: {
'project_exists': function(error) { 'project_exists': function(error) {
console.log("already exists"); console.log(RED._("projects.encryption-config.already-exists"));
}, },
'git_error': function(error) { 'git_error': function(error) {
console.log("git error",error); console.log(RED._("projects.encryption-config.git-error"),error);
}, },
'git_connection_failed': function(error) { 'git_connection_failed': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
@ -978,7 +978,7 @@ RED.projects = (function() {
projectRepoUserInput.addClass("input-error"); projectRepoUserInput.addClass("input-error");
projectRepoPasswordInput.addClass("input-error"); projectRepoPasswordInput.addClass("input-error");
// getRepoAuthDetails(req); // getRepoAuthDetails(req);
console.log("git auth error",error); console.log(RED._("projects.encryption-config.git-auth-error"),error);
}, },
'*': function(error) { '*': function(error) {
reportUnexpectedError(error); reportUnexpectedError(error);
@ -1004,19 +1004,16 @@ RED.projects = (function() {
migrateProjectHeader.appendTo(container); migrateProjectHeader.appendTo(container);
var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container); var body = $('<div class="projects-dialog-screen-start-body"></div>').appendTo(container);
$('<p>').text("You have successfully created your first project!").appendTo(body); $('<p>').text(RED._("projects.create-success.success")).appendTo(body);
$('<p>').text("You can now continue to use Node-RED just as you always have.").appendTo(body); $('<p>').text(RED._("projects.create-success.desc0")).appendTo(body);
$('<p>').text("The 'info' tab in the sidebar shows you what your current active project is. "+ $('<p>').text(RED._("projects.create-success.desc1")).appendTo(body);
"The button next to the name can be used to access the project settings view.").appendTo(body); $('<p>').text(RED._("projects.create-success.desc2")).appendTo(body);
$('<p>').text("The 'history' tab in the sidebar can be used to view files that have changed "+
"in your project and to commit them. It shows you a complete history of your commits and "+
"allows you to push your changes to a remote repository.").appendTo(body);
return container; return container;
}, },
buttons: [ buttons: [
{ {
text: "Done", text: RED._("common.label.done"),
click: function() { click: function() {
$( this ).dialog( "close" ); $( this ).dialog( "close" );
} }
@ -1043,7 +1040,7 @@ RED.projects = (function() {
var selectedProject; var selectedProject;
return { return {
title: "Projects", // TODO: NLS title: RED._("projects.create.projects"),
content: function(options) { content: function(options) {
var projectList = null; var projectList = null;
selectedProject = null; selectedProject = null;
@ -1077,14 +1074,14 @@ RED.projects = (function() {
projectNameValid = false; projectNameValid = false;
valid = false; valid = false;
if (projectList[projectName]) { if (projectList[projectName]) {
projectNameSublabel.text("Project already exists"); projectNameSublabel.text(RED._("projects.create.already-exists"));
} else { } else {
projectNameSublabel.text("Must contain only A-Z 0-9 _ -"); projectNameSublabel.text(RED._("projects.create.must-contain"));
} }
} else { } else {
projectNameInput.removeClass("input-error"); projectNameInput.removeClass("input-error");
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus); $('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
projectNameSublabel.text("Must contain only A-Z 0-9 _ -"); projectNameSublabel.text(RED._("projects.create.must-contain"));
projectNameValid = true; projectNameValid = true;
} }
projectNameLastChecked = projectName; projectNameLastChecked = projectName;
@ -1102,7 +1099,7 @@ RED.projects = (function() {
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo); // var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
var validRepo = repo.length > 0 && !/\s/.test(repo); var validRepo = repo.length > 0 && !/\s/.test(repo);
if (/^https?:\/\/[^/]+@/i.test(repo)) { if (/^https?:\/\/[^/]+@/i.test(repo)) {
$("#projects-dialog-screen-create-project-repo-label small").text("Do not include the username/password in the url"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.create.no-info-in-url"));
validRepo = false; validRepo = false;
} }
if (!validRepo) { if (!validRepo) {
@ -1159,10 +1156,10 @@ RED.projects = (function() {
row = $('<div class="form-row button-group"></div>').appendTo(container); row = $('<div class="form-row button-group"></div>').appendTo(container);
var openProject = $('<button data-type="open" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>Open Project</button>').appendTo(row); var openProject = $('<button data-type="open" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-folder-open"></i><br/>'+RED._("projects.create.open")+'</button>').appendTo(row);
var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>Create Project</button>').appendTo(row); var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>'+RED._("projects.create.create")+'</button>').appendTo(row);
// var createAsCopy = $('<button data-type="copy" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row); // var createAsCopy = $('<button data-type="copy" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i class="fa fa-long-arrow-right fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Copy existing</button>').appendTo(row);
var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>Clone Repository</button>').appendTo(row); var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-git"></i><br/>'+RED._("projects.create.clone")+'</button>').appendTo(row);
// var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row); // var createAsClone = $('<button data-type="clone" class="editor-button projects-dialog-screen-create-type toggle"><i class="fa fa-git fa-2x"></i><i class="fa fa-arrows-h fa-2x"></i><i class="fa fa-archive fa-2x"></i><br/>Clone Repository</button>').appendTo(row);
row.find(".projects-dialog-screen-create-type").click(function(evt) { row.find(".projects-dialog-screen-create-type").click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -1173,9 +1170,9 @@ RED.projects = (function() {
validateForm(); validateForm();
projectNameInput.focus(); projectNameInput.focus();
switch ($(this).data('type')) { switch ($(this).data('type')) {
case "open": $("#projects-dialog-create").text("Open project"); break; case "open": $("#projects-dialog-create").text(RED._("projects.create.open")); break;
case "empty": $("#projects-dialog-create").text("Create project"); break; case "empty": $("#projects-dialog-create").text(RED._("projects.create.create")); break;
case "clone": $("#projects-dialog-create").text("Clone project"); break; case "clone": $("#projects-dialog-create").text(RED._("projects.create.clone")); break;
} }
}) })
@ -1201,7 +1198,7 @@ RED.projects = (function() {
}).appendTo(row); }).appendTo(row);
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(container); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label for="projects-dialog-screen-create-project-name">Project name</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-name">'+RED._("projects.create.project-name")+'</label>').appendTo(row);
var subrow = $('<div style="position:relative;"></div>').appendTo(row); var subrow = $('<div style="position:relative;"></div>').appendTo(row);
projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').appendTo(subrow); projectNameInput = $('<input id="projects-dialog-screen-create-project-name" type="text"></input>').appendTo(subrow);
@ -1231,16 +1228,16 @@ RED.projects = (function() {
checkProjectName = null; checkProjectName = null;
},300) },300)
}); });
projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row).find("small"); projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>'+RED._("projects.create.must-contain")+'</small></label>').appendTo(row).find("small");
// Empty Project // Empty Project
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
$('<label for="projects-dialog-screen-create-project-desc">Description</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-desc">'+RED._("projects.create.desc")+'</label>').appendTo(row);
projectSummaryInput = $('<input id="projects-dialog-screen-create-project-desc" type="text">').appendTo(row); projectSummaryInput = $('<input id="projects-dialog-screen-create-project-desc" type="text">').appendTo(row);
$('<label class="projects-edit-form-sublabel"><small>Optional</small></label>').appendTo(row); $('<label class="projects-edit-form-sublabel"><small>'+RED._("projects.create.opt")+'</small></label>').appendTo(row);
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
$('<label for="projects-dialog-screen-create-project-file">Flow file</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-file">'+RED._("projects.create.flow-file")+'</label>').appendTo(row);
subrow = $('<div style="position:relative;"></div>').appendTo(row); subrow = $('<div style="position:relative;"></div>').appendTo(row);
projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val("flow.json") projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val("flow.json")
.on("change keyup paste",validateForm) .on("change keyup paste",validateForm)
@ -1249,16 +1246,16 @@ RED.projects = (function() {
$('<label class="projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row); $('<label class="projects-edit-form-sublabel"><small>*.json</small></label>').appendTo(row);
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-empty"></div>').appendTo(container);
$('<label>Credentials</label>').appendTo(row); $('<label>'+RED._("projects.create.credentials")+'</label>').appendTo(row);
var credentialsBox = $('<div style="width: 550px">').appendTo(row); var credentialsBox = $('<div style="width: 550px">').appendTo(row);
var credentialsRightBox = $('<div style="min-height:150px; box-sizing: border-box; float: right; vertical-align: top; width: 331px; margin-left: -1px; padding: 15px; margin-top: -15px; border: 1px solid #ccc; border-radius: 3px; display: inline-block">').appendTo(credentialsBox); var credentialsRightBox = $('<div style="min-height:150px; box-sizing: border-box; float: right; vertical-align: top; width: 331px; margin-left: -1px; padding: 15px; margin-top: -15px; border: 1px solid #ccc; border-radius: 3px; display: inline-block">').appendTo(credentialsBox);
var credentialsLeftBox = $('<div style="vertical-align: top; width: 220px; display: inline-block">').appendTo(credentialsBox); var credentialsLeftBox = $('<div style="vertical-align: top; width: 220px; display: inline-block">').appendTo(credentialsBox);
var credentialsEnabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid #ccc;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: white;"></div>').appendTo(credentialsLeftBox); var credentialsEnabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid #ccc;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: white;"></div>').appendTo(credentialsLeftBox);
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" checked style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="enabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-lock"></i> <span style="vertical-align: middle;">Enable encryption</span></label>').appendTo(credentialsEnabledBox); $('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" checked style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="enabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-lock"></i> <span style="vertical-align: middle;">'+RED._("projects.create.enable-encryption")+'</span></label>').appendTo(credentialsEnabledBox);
var credentialsDisabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid white;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: #ccc; "></div>').appendTo(credentialsLeftBox); var credentialsDisabledBox = $('<div class="form-row" style="padding: 7px 8px 3px 8px;border: 1px solid white;border-radius: 4px;border-top-right-radius: 0;border-bottom-right-radius: 0;border-right-color: #ccc; "></div>').appendTo(credentialsLeftBox);
$('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="disabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-unlock"></i> <span style="vertical-align: middle;">Disable encryption</span></label>').appendTo(credentialsDisabledBox); $('<label class="projects-edit-form-inline-label" style="margin-left: 5px"><input type="radio" style="vertical-align: middle; margin-top:0; margin-right: 10px;" name="projects-encryption-type" value="disabled"> <i style="font-size: 1.4em; margin-right: 8px; vertical-align: middle; color: #888;" class="fa fa-unlock"></i> <span style="vertical-align: middle;">'+RED._("projects.create.disable-encryption")+'</span></label>').appendTo(credentialsDisabledBox);
credentialsLeftBox.find("input[name=projects-encryption-type]").click(function(e) { credentialsLeftBox.find("input[name=projects-encryption-type]").click(function(e) {
var val = $(this).val(); var val = $(this).val();
@ -1292,15 +1289,15 @@ RED.projects = (function() {
}) })
row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox); row = $('<div class="form-row projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
$('<label class="projects-edit-form-inline-label">Encryption key</label>').appendTo(row); $('<label class="projects-edit-form-inline-label">'+RED._("projects.create.encryption-key")+'</label>').appendTo(row);
// row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox); // row = $('<div class="projects-encryption-enabled-row"></div>').appendTo(credentialsRightBox);
emptyProjectCredentialInput = $('<input type="password"></input>').appendTo(row); emptyProjectCredentialInput = $('<input type="password"></input>').appendTo(row);
emptyProjectCredentialInput.on("change keyup paste", validateForm); emptyProjectCredentialInput.on("change keyup paste", validateForm);
$('<label class="projects-edit-form-sublabel"><small>A phrase to secure your credentials with</small></label>').appendTo(row); $('<label class="projects-edit-form-sublabel"><small>'+RED._("projects.create.desc0")+'</small></label>').appendTo(row);
row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox); row = $('<div class="form-row projects-encryption-disabled-row"></div>').hide().appendTo(credentialsRightBox);
$('<div class="" style="padding: 5px 20px;"><i class="fa fa-warning"></i> The credentials file will not be encrypted and its contents easily read</div>').appendTo(row); $('<div class="" style="padding: 5px 20px;"><i class="fa fa-warning"></i> '+RED._("projects.create.desc1")+'</div>').appendTo(row);
credentialsRightBox.find("input[name=projects-encryption-key]").click(function() { credentialsRightBox.find("input[name=projects-encryption-key]").click(function() {
var val = $(this).val(); var val = $(this).val();
@ -1313,9 +1310,9 @@ RED.projects = (function() {
// Clone Project // Clone Project
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container); row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label for="projects-dialog-screen-create-project-repo">Git repository URL</label>').appendTo(row); $('<label for="projects-dialog-screen-create-project-repo">'+RED._("projects.create.git-url")+'</label>').appendTo(row);
projectRepoInput = $('<input id="projects-dialog-screen-create-project-repo" type="text" placeholder="https://git.example.com/path/my-project.git"></input>').appendTo(row); projectRepoInput = $('<input id="projects-dialog-screen-create-project-repo" type="text" placeholder="https://git.example.com/path/my-project.git"></input>').appendTo(row);
$('<label id="projects-dialog-screen-create-project-repo-label" class="projects-edit-form-sublabel"><small>https://, ssh:// or file://</small></label>').appendTo(row); $('<label id="projects-dialog-screen-create-project-repo-label" class="projects-edit-form-sublabel"><small>'+RED._("projects.create.protocols")+'</small></label>').appendTo(row);
var projectRepoChanged = false; var projectRepoChanged = false;
var lastProjectRepo = ""; var lastProjectRepo = "";
@ -1323,7 +1320,7 @@ RED.projects = (function() {
projectRepoChanged = true; projectRepoChanged = true;
var repo = $(this).val(); var repo = $(this).val();
if (lastProjectRepo !== repo) { if (lastProjectRepo !== repo) {
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.create.protocols"));
} }
lastProjectRepo = repo; lastProjectRepo = repo;
@ -1342,24 +1339,24 @@ RED.projects = (function() {
var cloneAuthRows = $('<div class="hide projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').hide().appendTo(container); var cloneAuthRows = $('<div class="hide projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').hide().appendTo(container);
row = $('<div class="form-row projects-dialog-screen-create-row-auth-error"></div>').hide().appendTo(cloneAuthRows); row = $('<div class="form-row projects-dialog-screen-create-row-auth-error"></div>').hide().appendTo(cloneAuthRows);
$('<div><i class="fa fa-warning"></i> Authentication failed</div>').appendTo(row); $('<div><i class="fa fa-warning"></i> '+RED._("projects.create.auth-failed")+'</div>').appendTo(row);
// Repo credentials - username/password ---------------- // Repo credentials - username/password ----------------
row = $('<div class="hide form-row projects-dialog-screen-create-row-creds"></div>').hide().appendTo(cloneAuthRows); row = $('<div class="hide form-row projects-dialog-screen-create-row-creds"></div>').hide().appendTo(cloneAuthRows);
var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row); var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-user">Username</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-user">'+RED._("projects.create.username")+'</label>').appendTo(subrow);
projectRepoUserInput = $('<input id="projects-dialog-screen-create-project-repo-user" type="text"></input>').appendTo(subrow); projectRepoUserInput = $('<input id="projects-dialog-screen-create-project-repo-user" type="text"></input>').appendTo(subrow);
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row); subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-pass">Password</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-pass">'+RED._("projects.create.password")+'</label>').appendTo(subrow);
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow); projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
// ----------------------------------------------------- // -----------------------------------------------------
// Repo credentials - key/passphrase ------------------- // Repo credentials - key/passphrase -------------------
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(cloneAuthRows); row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').hide().appendTo(cloneAuthRows);
subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row); subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH Key</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.create.ssh-key")+'</label>').appendTo(subrow);
projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow); projectRepoSSHKeySelect = $("<select>",{style:"width: 100%"}).appendTo(subrow);
$.getJSON("settings/user/keys", function(data) { $.getJSON("settings/user/keys", function(data) {
@ -1379,14 +1376,14 @@ RED.projects = (function() {
} }
}); });
subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row); subrow = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;"></div>').appendTo(row);
$('<label for="projects-dialog-screen-create-project-repo-passphrase">Passphrase</label>').appendTo(subrow); $('<label for="projects-dialog-screen-create-project-repo-passphrase">'+RED._("projects.create.passphrase")+'</label>').appendTo(subrow);
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow); projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password"></input>').appendTo(subrow);
subrow = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows); subrow = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-sshkey"></div>').appendTo(cloneAuthRows);
var sshwarningRow = $('<div class="projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow); var sshwarningRow = $('<div class="projects-dialog-screen-create-row-auth-error-no-keys"></div>').hide().appendTo(subrow);
$('<div class="form-row"><i class="fa fa-warning"></i> Before you can clone a repository over ssh you must add an SSH key to access it.</div>').appendTo(sshwarningRow); $('<div class="form-row"><i class="fa fa-warning"></i> '+RED._("projects.create.desc2")+'</div>').appendTo(sshwarningRow);
subrow = $('<div style="text-align: center">').appendTo(sshwarningRow); subrow = $('<div style="text-align: center">').appendTo(sshwarningRow);
$('<button class="editor-button">Add an ssh key</button>').appendTo(subrow).click(function(e) { $('<button class="editor-button">'+RED._("projects.create.add-ssh-key")+'</button>').appendTo(subrow).click(function(e) {
e.preventDefault(); e.preventDefault();
$('#projects-dialog-cancel').click(); $('#projects-dialog-cancel').click();
RED.userSettings.show('gitconfig'); RED.userSettings.show('gitconfig');
@ -1399,7 +1396,7 @@ RED.projects = (function() {
// Secret - clone // Secret - clone
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container); row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').appendTo(container);
$('<label>Credentials encryption key</label>').appendTo(row); $('<label>'+RED._("projects.create.credentials-encryption-key")+'</label>').appendTo(row);
projectSecretInput = $('<input type="password"></input>').appendTo(row); projectSecretInput = $('<input type="password"></input>').appendTo(row);
@ -1421,9 +1418,9 @@ RED.projects = (function() {
buttons: function(options) { buttons: function(options) {
var initialLabel; var initialLabel;
switch (options.screen||"empty") { switch (options.screen||"empty") {
case "open": initialLabel = "Open project"; break; case "open": initialLabel = RED._("projects.create.open"); break;
case "empty": initialLabel = "Create project"; break; case "empty": initialLabel = RED._("projects.create.create"); break;
case "clone": initialLabel = "Clone project"; break; case "clone": initialLabel = RED._("projects.create.clone"); break;
} }
return [ return [
{ {
@ -1477,7 +1474,7 @@ RED.projects = (function() {
}; };
} }
else { else {
console.log("Error! Can't get selected SSH key path."); console.log(RED._("projects.create.cant-get-ssh-key-path"));
return; return;
} }
} }
@ -1497,14 +1494,14 @@ RED.projects = (function() {
dialog.dialog( "close" ); dialog.dialog( "close" );
if (err) { if (err) {
if (err.error !== 'credentials_load_failed') { if (err.error !== 'credentials_load_failed') {
console.log("unexpected_error",err) console.log(RED._("projects.create.unexpected_error"),err)
} }
} }
}) })
} }
$(".projects-dialog-screen-create-row-auth-error").hide(); $(".projects-dialog-screen-create-row-auth-error").hide();
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.create.protocols"));
projectRepoUserInput.removeClass("input-error"); projectRepoUserInput.removeClass("input-error");
projectRepoPasswordInput.removeClass("input-error"); projectRepoPasswordInput.removeClass("input-error");
@ -1524,22 +1521,22 @@ RED.projects = (function() {
}, },
400: { 400: {
'project_exists': function(error) { 'project_exists': function(error) {
console.log("already exists"); console.log(RED._("projects.create.already-exists-2"));
}, },
'git_error': function(error) { 'git_error': function(error) {
console.log("git error",error); console.log(RED._("projects.create.git-error"),error);
}, },
'git_connection_failed': function(error) { 'git_connection_failed': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Connection failed"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.create.con-failed"));
}, },
'git_not_a_repository': function(error) { 'git_not_a_repository': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Not a git repository"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.create.not-git"));
}, },
'git_repository_not_found': function(error) { 'git_repository_not_found': function(error) {
projectRepoInput.addClass("input-error"); projectRepoInput.addClass("input-error");
$("#projects-dialog-screen-create-project-repo-label small").text("Repository not found"); $("#projects-dialog-screen-create-project-repo-label small").text(RED._("projects.create.no-resource"));
}, },
'git_auth_failed': function(error) { 'git_auth_failed': function(error) {
$(".projects-dialog-screen-create-row-auth-error").show(); $(".projects-dialog-screen-create-row-auth-error").show();
@ -1619,15 +1616,15 @@ RED.projects = (function() {
whitespace: "nowrap", whitespace: "nowrap",
width:"1000px" width:"1000px"
}).click(function(evt) { evt.stopPropagation(); }).appendTo(row); }).click(function(evt) { evt.stopPropagation(); }).appendTo(row);
$('<span>').css({"lineHeight":"40px"}).text("Are you sure you want to delete this project?").appendTo(cover); $('<span>').css({"lineHeight":"40px"}).text(RED._("projects.delete.confirm")).appendTo(cover);
$('<button style="margin-left:20px" class="editor-button">Cancel</button>') $('<button style="margin-left:20px" class="editor-button">'+RED._("common.label.cancel")+'</button>')
.appendTo(cover) .appendTo(cover)
.click(function(e) { .click(function(e) {
e.stopPropagation(); e.stopPropagation();
cover.remove(); cover.remove();
done(true); done(true);
}); });
$('<button style="margin-left:20px" class="editor-button primary">Delete</button>') $('<button style="margin-left:20px" class="editor-button primary">'+RED._("common.label.delete")+'</button>')
.appendTo(cover) .appendTo(cover)
.click(function(e) { .click(function(e) {
e.stopPropagation(); e.stopPropagation();
@ -1681,7 +1678,7 @@ RED.projects = (function() {
var filterTerm = ""; var filterTerm = "";
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(container); var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(container);
var searchInput = $('<input id="projects-dialog-project-list-search" type="text" placeholder="search your projects">').appendTo(searchDiv).searchBox({ var searchInput = $('<input id="projects-dialog-project-list-search" type="text" placeholder="'+RED._("projects.create-project-list.search")+'">').appendTo(searchDiv).searchBox({
//data-i18n="[placeholder]menu.label.searchInput" //data-i18n="[placeholder]menu.label.searchInput"
delay: 200, delay: 200,
change: function() { change: function() {
@ -1790,7 +1787,7 @@ RED.projects = (function() {
$('<span class="projects-dialog-project-list-entry-name" style=""></span>').text(entry.name).appendTo(header); $('<span class="projects-dialog-project-list-entry-name" style=""></span>').text(entry.name).appendTo(header);
if (activeProject && activeProject.name === entry.name) { if (activeProject && activeProject.name === entry.name) {
header.addClass("projects-list-entry-current"); header.addClass("projects-list-entry-current");
$('<span class="projects-dialog-project-list-entry-current">current</span>').appendTo(header); $('<span class="projects-dialog-project-list-entry-current">'+RED._("projects.create-project-list.current")+'</span>').appendTo(header);
if (options.canSelectActive === false) { if (options.canSelectActive === false) {
// active project cannot be selected; so skip the rest // active project cannot be selected; so skip the rest
return return
@ -1852,7 +1849,7 @@ RED.projects = (function() {
function requireCleanWorkspace(done) { function requireCleanWorkspace(done) {
if (RED.nodes.dirty()) { if (RED.nodes.dirty()) {
var message = '<p>You have undeployed changes that will be lost.</p><p>Do you want to continue?</p>'; var message = RED._("projects.require-clean.confirm");
var cleanNotification = RED.notify(message,{ var cleanNotification = RED.notify(message,{
type:"info", type:"info",
fixed: true, fixed: true,
@ -1867,7 +1864,7 @@ RED.projects = (function() {
done(true); done(true);
} }
},{ },{
text: 'Continue', text: RED._("common.label.cont"),
click: function() { click: function() {
cleanNotification.close(); cleanNotification.close();
done(false); done(false);
@ -1945,14 +1942,14 @@ RED.projects = (function() {
var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch; var url = activeProject.git.remotes[xhr.responseJSON.remote||options.remote||'origin'].fetch;
var message = $('<div>'+ var message = $('<div>'+
'<div class="form-row">Authentication required for repository:</div>'+ '<div class="form-row">'+RED._("projects.send-req.auth-req")+':</div>'+
'<div class="form-row"><div style="margin-left: 20px;">'+url+'</div></div>'+ '<div class="form-row"><div style="margin-left: 20px;">'+url+'</div></div>'+
'</div>'); '</div>');
var isSSH = false; var isSSH = false;
if (/^https?:\/\//.test(url)) { if (/^https?:\/\//.test(url)) {
$('<div class="form-row"><label for="projects-user-auth-username">Username</label><input id="projects-user-auth-username" type="text"></input></div>'+ $('<div class="form-row"><label for="projects-user-auth-username">'+RED._("projects.send-req.username")+'</label><input id="projects-user-auth-username" type="text"></input></div>'+
'<div class="form-row"><label for=projects-user-auth-password">Password</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message); '<div class="form-row"><label for=projects-user-auth-password">'+RED._("projects.send-req.password")+'</label><input id="projects-user-auth-password" type="password"></input></div>').appendTo(message);
} else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) { } else if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(url)) {
isSSH = true; isSSH = true;
var row = $('<div class="form-row"></div>').appendTo(message); var row = $('<div class="form-row"></div>').appendTo(message);
@ -1969,7 +1966,7 @@ RED.projects = (function() {
} }
}); });
row = $('<div class="form-row"></div>').appendTo(message); row = $('<div class="form-row"></div>').appendTo(message);
$('<label for="projects-user-auth-passphrase">Passphrase</label>').appendTo(row); $('<label for="projects-user-auth-passphrase">'+RED._("projects.send-req.passphrase")+'</label>').appendTo(row);
$('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row); $('<input id="projects-user-auth-passphrase" type="password"></input>').appendTo(row);
} }
@ -1999,7 +1996,7 @@ RED.projects = (function() {
} }
var done = function(err) { var done = function(err) {
if (err) { if (err) {
console.log("Failed to update auth"); console.log(RED._("projects.send-req.update-failed"));
console.log(err); console.log(err);
} else { } else {
sendRequest(options,body); sendRequest(options,body);
@ -2039,7 +2036,7 @@ RED.projects = (function() {
return; return;
} }
} }
console.log("Unhandled error response:"); console.log(RED._("projects.send-req.unhandled")+":");
console.log(xhr); console.log(xhr);
console.log(textStatus); console.log(textStatus);
console.log(err); console.log(err);
@ -2073,7 +2070,7 @@ RED.projects = (function() {
branchFilterCreateItem.addClass("input-error"); branchFilterCreateItem.addClass("input-error");
branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork"); branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork");
} }
branchFilterCreateItem.find("span").text("Invalid branch: "+branchPrefix+branchFilterTerm); branchFilterCreateItem.find("span").text(RED._("projects.create-branch-list.invalid")+": "+branchPrefix+branchFilterTerm);
} else { } else {
if (branchFilterCreateItem.hasClass("input-error")) { if (branchFilterCreateItem.hasClass("input-error")) {
branchFilterCreateItem.removeClass("input-error"); branchFilterCreateItem.removeClass("input-error");
@ -2093,14 +2090,14 @@ RED.projects = (function() {
if (!entry.hasOwnProperty('commit')) { if (!entry.hasOwnProperty('commit')) {
branchFilterCreateItem = container; branchFilterCreateItem = container;
$('<i class="fa fa-code-fork"></i>').appendTo(container); $('<i class="fa fa-code-fork"></i>').appendTo(container);
$('<span>').text("Create branch:").appendTo(container); $('<span>').text(RED._("projects.create-branch-list.create")+":").appendTo(container);
$('<div class="sidebar-version-control-branch-list-entry-create-name" style="margin-left: 10px;">').text(entry.name).appendTo(container); $('<div class="sidebar-version-control-branch-list-entry-create-name" style="margin-left: 10px;">').text(entry.name).appendTo(container);
} else { } else {
$('<i class="fa fa-code-fork"></i>').appendTo(container); $('<i class="fa fa-code-fork"></i>').appendTo(container);
$('<span>').text(entry.name).appendTo(container); $('<span>').text(entry.name).appendTo(container);
if (entry.current) { if (entry.current) {
container.addClass("selected"); container.addClass("selected");
$('<span class="current"></span>').text(options.currentLabel||"current").appendTo(container); $('<span class="current"></span>').text(options.currentLabel||RED._("projects.create-branch-list.current")).appendTo(container);
} }
} }
container.click(function(evt) { container.click(function(evt) {
@ -2240,9 +2237,9 @@ RED.projects = (function() {
function createDefaultFileSet() { function createDefaultFileSet() {
if (!activeProject) { if (!activeProject) {
throw new Error("Cannot create default file set without an active project"); throw new Error(RED._("projects.create-default-file-set.no-active"));
} else if (!activeProject.empty) { } else if (!activeProject.empty) {
throw new Error("Cannot create default file set on a non-empty project"); throw new Error(RED._("projects.create-default-file-set.no-empty"));
} }
if (!RED.user.hasPermission("projects.write")) { if (!RED.user.hasPermission("projects.write")) {
RED.notify(RED._("user.errors.notAuthorized"),"error"); RED.notify(RED._("user.errors.notAuthorized"),"error");
@ -2269,7 +2266,7 @@ RED.projects = (function() {
200: function(data) { }, 200: function(data) { },
400: { 400: {
'git_error': function(error) { 'git_error': function(error) {
console.log("git error",error); console.log(RED._("projects.create-default-file-set.git-error"),error);
}, },
'missing_flow_file': function(error) { 'missing_flow_file': function(error) {
// This is a natural next error - but let the runtime event // This is a natural next error - but let the runtime event

View File

@ -52,11 +52,11 @@ RED.sidebar.versionControl = (function() {
200: function(data) { 200: function(data) {
var title; var title;
if (state === 'unstaged') { if (state === 'unstaged') {
title = 'Unstaged changes : '+entry.file title = RED._("sidebar.project.versionControl.unstagedChanges")+' : '+entry.file
} else if (state === 'staged') { } else if (state === 'staged') {
title = 'Staged changes : '+entry.file title = RED._("sidebar.project.versionControl.stagedChanges")+' : '+entry.file
} else { } else {
title = 'Resolve conflicts : '+entry.file title = RED._("sidebar.project.versionControl.resolveConflicts")+' : '+entry.file
} }
var options = { var options = {
diff: data.diff, diff: data.diff,
@ -65,18 +65,18 @@ RED.sidebar.versionControl = (function() {
project: activeProject project: activeProject
} }
if (state == 'unstaged') { if (state == 'unstaged') {
options.oldRevTitle = entry.indexStatus === " "?"HEAD":"Staged"; options.oldRevTitle = entry.indexStatus === " "?RED._("sidebar.project.versionControl.head"):RED._("sidebar.project.versionControl.staged");
options.newRevTitle = "Unstaged"; options.newRevTitle = RED._("sidebar.project.versionControl.unstaged");
options.oldRev = entry.indexStatus === " "?"@":":0"; options.oldRev = entry.indexStatus === " "?"@":":0";
options.newRev = "_"; options.newRev = "_";
} else if (state === 'staged') { } else if (state === 'staged') {
options.oldRevTitle = "HEAD"; options.oldRevTitle = RED._("sidebar.project.versionControl.head");
options.newRevTitle = "Staged"; options.newRevTitle = RED._("sidebar.project.versionControl.staged");
options.oldRev = "@"; options.oldRev = "@";
options.newRev = ":0"; options.newRev = ":0";
} else { } else {
options.oldRevTitle = "Local"; options.oldRevTitle = RED._("sidebar.project.versionControl.local");
options.newRevTitle = "Remote"; options.newRevTitle = RED._("sidebar.project.versionControl.remote");
options.commonRev = ":1"; options.commonRev = ":1";
options.oldRev = ":2"; options.oldRev = ":2";
options.newRev = ":3"; options.newRev = ":3";
@ -156,7 +156,7 @@ RED.sidebar.versionControl = (function() {
evt.preventDefault(); evt.preventDefault();
var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain'); var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain');
var notification = RED.notify("Are you sure you want to revert the changes to '"+entry.file+"'? This cannot be undone.", { var notification = RED.notify(RED._("sidebar.project.versionControl.revert",{file:entry.file}), {
type: "warning", type: "warning",
modal: true, modal: true,
fixed: true, fixed: true,
@ -168,7 +168,7 @@ RED.sidebar.versionControl = (function() {
notification.close(); notification.close();
} }
},{ },{
text: 'Revert changes', text: RED._("sidebar.project.versionControl.revertChanges"),
click: function() { click: function() {
notification.close(); notification.close();
var activeProject = RED.projects.getActiveProject(); var activeProject = RED.projects.getActiveProject();
@ -281,6 +281,8 @@ RED.sidebar.versionControl = (function() {
entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status); entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status);
} }
var utils; var utils;
var emptyStagedItem;
var emptyMergedItem;
function init(_utils) { function init(_utils) {
utils = _utils; utils = _utils;
@ -312,7 +314,7 @@ RED.sidebar.versionControl = (function() {
}); });
localChanges = sections.add({ localChanges = sections.add({
title: "Local Changes", title: RED._("sidebar.project.versionControl.localChanges"),
collapsible: true collapsible: true
}); });
localChanges.expand(); localChanges.expand();
@ -326,10 +328,12 @@ RED.sidebar.versionControl = (function() {
refresh(true); refresh(true);
}) })
emptyStagedItem = { label: RED._("sidebar.project.versionControl.none") };
emptyMergedItem = { label: RED._("sidebar.project.versionControl.conflictResolve") };
var unstagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content); var unstagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
var header = $('<div class="sidebar-version-control-change-header">Local files</div>').appendTo(unstagedContent); var header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.localFiles")+'</div>').appendTo(unstagedContent);
stageAllButton = $('<button class="editor-button editor-button-small" style="float: right"><i class="fa fa-plus"></i> all</button>') stageAllButton = $('<button class="editor-button editor-button-small" style="float: right"><i class="fa fa-plus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
.appendTo(header) .appendTo(header)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -359,9 +363,9 @@ RED.sidebar.versionControl = (function() {
unmergedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content); unmergedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
header = $('<div class="sidebar-version-control-change-header">Unmerged changes</div>').appendTo(unmergedContent); header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.unmergedChanges")+'</div>').appendTo(unmergedContent);
bg = $('<div style="float: right"></div>').appendTo(header); bg = $('<div style="float: right"></div>').appendTo(header);
var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">abort merge</button>') var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.abortMerge")+'</button>')
.appendTo(bg) .appendTo(bg)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -399,7 +403,7 @@ RED.sidebar.versionControl = (function() {
addItem: function(row,index,entry) { addItem: function(row,index,entry) {
if (entry === emptyMergedItem) { if (entry === emptyMergedItem) {
entry.button = { entry.button = {
label: 'commit', label: RED._("sidebar.project.versionControl.commit"),
click: function(evt) { click: function(evt) {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
@ -423,7 +427,7 @@ RED.sidebar.versionControl = (function() {
var stagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content); var stagedContent = $('<div class="sidebar-version-control-change-container"></div>').appendTo(localChanges.content);
header = $('<div class="sidebar-version-control-change-header">Changes to commit</div>').appendTo(stagedContent); header = $('<div class="sidebar-version-control-change-header">'+RED._("sidebar.project.versionControl.changeToCommit")+'</div>').appendTo(stagedContent);
bg = $('<div style="float: right"></div>').appendTo(header); bg = $('<div style="float: right"></div>').appendTo(header);
var showCommitBox = function() { var showCommitBox = function() {
@ -446,14 +450,14 @@ RED.sidebar.versionControl = (function() {
abortMergeButton.attr("disabled",true); abortMergeButton.attr("disabled",true);
commitMessage.focus(); commitMessage.focus();
} }
commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">commit</button>') commitButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">'+RED._("sidebar.project.versionControl.commit")+'</button>')
.appendTo(bg) .appendTo(bg)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
showCommitBox(); showCommitBox();
}); });
unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> all</button>') unstageAllButton = $('<button class="editor-button editor-button-small"><i class="fa fa-minus"></i> '+RED._("sidebar.project.versionControl.all")+'</button>')
.appendTo(bg) .appendTo(bg)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -480,14 +484,14 @@ RED.sidebar.versionControl = (function() {
commitBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-bottom"></div>').hide().appendTo(localChanges.content); commitBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-bottom"></div>').hide().appendTo(localChanges.content);
var commitMessage = $('<textarea placeholder="Enter your commit message"></textarea>') var commitMessage = $('<textarea placeholder='+RED._("sidebar.project.versionControl.commitPlaceholder")+'></textarea>')
.appendTo(commitBox) .appendTo(commitBox)
.on("change keyup paste",function() { .on("change keyup paste",function() {
submitCommitButton.attr('disabled',$(this).val().trim()===""); submitCommitButton.attr('disabled',$(this).val().trim()==="");
}); });
var commitToolbar = $('<div class="sidebar-version-control-slide-box-toolbar button-group">').appendTo(commitBox); var commitToolbar = $('<div class="sidebar-version-control-slide-box-toolbar button-group">').appendTo(commitBox);
var cancelCommitButton = $('<button class="editor-button">Cancel</button>') var cancelCommitButton = $('<button class="editor-button">'+RED._("sidebar.project.versionControl.cancelCapital")+'</button>')
.appendTo(commitToolbar) .appendTo(commitToolbar)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -505,7 +509,7 @@ RED.sidebar.versionControl = (function() {
abortMergeButton.attr("disabled",false); abortMergeButton.attr("disabled",false);
}) })
var submitCommitButton = $('<button class="editor-button">Commit</button>') var submitCommitButton = $('<button class="editor-button">'+RED._("sidebar.project.versionControl.commitCapital")+'</button>')
.appendTo(commitToolbar) .appendTo(commitToolbar)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -541,7 +545,7 @@ RED.sidebar.versionControl = (function() {
var localHistory = sections.add({ var localHistory = sections.add({
title: "Commit History", title: RED._("sidebar.project.versionControl.commitHistory"),
collapsible: true collapsible: true
}); });
@ -555,7 +559,7 @@ RED.sidebar.versionControl = (function() {
var localBranchToolbar = $('<div class="sidebar-version-control-change-header" style="text-align: right;"></div>').appendTo(localHistory.content); var localBranchToolbar = $('<div class="sidebar-version-control-change-header" style="text-align: right;"></div>').appendTo(localHistory.content);
var localBranchButton = $('<button class="editor-button editor-button-small"><i class="fa fa-code-fork"></i> Branch: <span id="sidebar-version-control-local-branch"></span></button>') var localBranchButton = $('<button class="editor-button editor-button-small"><i class="fa fa-code-fork"></i> '+RED._("sidebar.project.versionControl.branch")+' <span id="sidebar-version-control-local-branch"></span></button>')
.appendTo(localBranchToolbar) .appendTo(localBranchToolbar)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -612,7 +616,7 @@ RED.sidebar.versionControl = (function() {
row.addClass('sidebar-version-control-commit-entry'); row.addClass('sidebar-version-control-commit-entry');
if (entry.url) { if (entry.url) {
row.addClass('sidebar-version-control-commit-more'); row.addClass('sidebar-version-control-commit-more');
row.text("+ "+(entry.total-entry.totalKnown)+" more commit(s)"); row.text("+ "+(entry.total-entry.totalKnown)+RED._("sidebar.project.versionControl.moreCommits"));
row.click(function(e) { row.click(function(e) {
e.preventDefault(); e.preventDefault();
getCommits(entry.url,localCommitList,row,entry.limit,entry.before); getCommits(entry.url,localCommitList,row,entry.limit,entry.before);
@ -626,8 +630,8 @@ RED.sidebar.versionControl = (function() {
result.parents = entry.parents; result.parents = entry.parents;
result.oldRev = entry.sha+"~1"; result.oldRev = entry.sha+"~1";
result.newRev = entry.sha; result.newRev = entry.sha;
result.oldRevTitle = "Commit "+entry.sha.substring(0,7)+"~1"; result.oldRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7)+"~1";
result.newRevTitle = "Commit "+entry.sha.substring(0,7); result.newRevTitle = RED._("sidebar.project.versionControl.commitCapital")+" "+entry.sha.substring(0,7);
result.date = humanizeSinceDate(parseInt(entry.date)); result.date = humanizeSinceDate(parseInt(entry.date));
RED.diff.showCommitDiff(result); RED.diff.showCommitDiff(result);
}); });
@ -666,10 +670,10 @@ RED.sidebar.versionControl = (function() {
} }
var localBranchBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-top" style="top:30px;"></div>').hide().appendTo(localHistory.content); var localBranchBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-top" style="top:30px;"></div>').hide().appendTo(localHistory.content);
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Change local branch").appendTo(localBranchBox); $('<div class="sidebar-version-control-slide-box-header"></div>').text(RED._("sidebar.project.versionControl.changeLocalBranch")).appendTo(localBranchBox);
var localBranchList = utils.createBranchList({ var localBranchList = utils.createBranchList({
placeholder: "Find or create a branch", placeholder: RED._("sidebar.project.versionControl.createBranchPlaceholder"),
container: localBranchBox, container: localBranchBox,
onselect: function(body) { onselect: function(body) {
if (body.current) { if (body.current) {
@ -701,7 +705,7 @@ RED.sidebar.versionControl = (function() {
400: { 400: {
'git_local_overwrite': function(error) { 'git_local_overwrite': function(error) {
spinner.remove(); spinner.remove();
RED.notify("You have local changes that would be overwritten by changing the branch. You must either commit or undo those changes first.",{ RED.notify(RED._("sidebar.project.versionControl.localOverwrite"),{
type:'error', type:'error',
timeout: 8000 timeout: 8000
}); });
@ -744,10 +748,10 @@ RED.sidebar.versionControl = (function() {
},200); },200);
} }
} }
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Manage remote branch").appendTo(remoteBox); $('<div class="sidebar-version-control-slide-box-header"></div>').text(RED._("sidebar.project.versionControl.manageRemoteBranch")).appendTo(remoteBox);
var remoteBranchRow = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox); var remoteBranchRow = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox);
var remoteBranchButton = $('<button id="sidebar-version-control-repo-branch" class="sidebar-version-control-repo-action editor-button"><i class="fa fa-code-fork"></i> Remote: <span id="sidebar-version-control-remote-branch"></span></button>') var remoteBranchButton = $('<button id="sidebar-version-control-repo-branch" class="sidebar-version-control-repo-action editor-button"><i class="fa fa-code-fork"></i> '+RED._("sidebar.project.versionControl.remote")+': <span id="sidebar-version-control-remote-branch"></span></button>')
.appendTo(remoteBranchRow) .appendTo(remoteBranchRow)
.click(function(evt) { .click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@ -770,9 +774,9 @@ RED.sidebar.versionControl = (function() {
var errorMessage = $('<div id="sidebar-version-control-repo-toolbar-error-message" class="sidebar-version-control-slide-box-header" style="min-height: 100px;"></div>').hide().appendTo(remoteBox); var errorMessage = $('<div id="sidebar-version-control-repo-toolbar-error-message" class="sidebar-version-control-slide-box-header" style="min-height: 100px;"></div>').hide().appendTo(remoteBox);
$('<div style="margin-top: 10px;"><i class="fa fa-warning"></i> Unable to access remote repository</div>').appendTo(errorMessage) $('<div style="margin-top: 10px;"><i class="fa fa-warning"></i> '+RED._("sidebar.project.versionControl.unableToAccess")+'</div>').appendTo(errorMessage)
var buttonRow = $('<div style="margin: 10px 30px; text-align: center"></div>').appendTo(errorMessage); var buttonRow = $('<div style="margin: 10px 30px; text-align: center"></div>').appendTo(errorMessage);
$('<button class="editor-button" style="width: 80%;"><i class="fa fa-refresh"></i> Retry</button>') $('<button class="editor-button" style="width: 80%;"><i class="fa fa-refresh"></i> '+RED._("sidebar.project.versionControl.retry")+'</button>')
.appendTo(buttonRow) .appendTo(buttonRow)
.click(function(e) { .click(function(e) {
e.preventDefault(); e.preventDefault();
@ -810,12 +814,12 @@ RED.sidebar.versionControl = (function() {
}); });
}) })
$('<div class="sidebar-version-control-slide-box-header" style="height: 20px;"><label id="sidebar-version-control-repo-toolbar-set-upstream-row" for="sidebar-version-control-repo-toolbar-set-upstream" class="hide"><input type="checkbox" id="sidebar-version-control-repo-toolbar-set-upstream"> Set as upstream branch</label></div>').appendTo(remoteBox); $('<div class="sidebar-version-control-slide-box-header" style="height: 20px;"><label id="sidebar-version-control-repo-toolbar-set-upstream-row" for="sidebar-version-control-repo-toolbar-set-upstream" class="hide"><input type="checkbox" id="sidebar-version-control-repo-toolbar-set-upstream"> '+RED._("sidebar.project.versionControl.setUpstreamBranch")+'</label></div>').appendTo(remoteBox);
var remoteBranchSubRow = $('<div style="height: 0;overflow:hidden; transition: height 0.2s ease-in-out;"></div>').hide().appendTo(remoteBranchRow); var remoteBranchSubRow = $('<div style="height: 0;overflow:hidden; transition: height 0.2s ease-in-out;"></div>').hide().appendTo(remoteBranchRow);
var remoteBranchList = utils.createBranchList({ var remoteBranchList = utils.createBranchList({
placeholder: "Find or create a remote branch", placeholder: RED._("sidebar.project.versionControl.createRemoteBranchPlaceholder"),
currentLabel: "upstream", currentLabel: RED._("sidebar.project.versionControl.upstream"),
remote: function() { remote: function() {
var project = RED.projects.getActiveProject(); var project = RED.projects.getActiveProject();
var remotes = Object.keys(project.git.remotes); var remotes = Object.keys(project.git.remotes);
@ -845,11 +849,11 @@ RED.sidebar.versionControl = (function() {
}) })
} else { } else {
if (!activeProject.git.branches.remote) { if (!activeProject.git.branches.remote) {
$('#sidebar-version-control-repo-toolbar-message').text("The created branch will be set as the tracked upstream branch."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.trackedUpstreamBranch"));
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked',true); $("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked',true);
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('disabled',true); $("#sidebar-version-control-repo-toolbar-set-upstream").prop('disabled',true);
} else { } else {
$('#sidebar-version-control-repo-toolbar-message').text("The branch will be created. Select below to set it as the tracked upstream branch."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.selectUpstreamBranch"));
} }
$("#sidebar-version-control-repo-pull").attr('disabled',true); $("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',false); $("#sidebar-version-control-repo-push").attr('disabled',false);
@ -861,7 +865,7 @@ RED.sidebar.versionControl = (function() {
var row = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox); var row = $('<div style="margin-bottom: 5px;"></div>').appendTo(remoteBox);
$('<button id="sidebar-version-control-repo-push" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-up"></i> <span>push</span></button>') $('<button id="sidebar-version-control-repo-push" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-up"></i> <span data-i18n="sidebar.project.versionControl.push"></span></button>')
.appendTo(row) .appendTo(row)
.click(function(e) { .click(function(e) {
e.preventDefault(); e.preventDefault();
@ -893,8 +897,8 @@ RED.sidebar.versionControl = (function() {
}, },
400: { 400: {
'git_push_failed': function(err) { 'git_push_failed': function(err) {
// TODO: better message + NLS // TODO: better message
RED.notify("NLS: Push failed as the remote has more recent commits. Pull first and write a better error message!","error"); RED.notify(RED._("sidebar.project.versionControl.pushFailed"),"error");
}, },
'unexpected_error': function(error) { 'unexpected_error': function(error) {
console.log(error); console.log(error);
@ -945,18 +949,18 @@ RED.sidebar.versionControl = (function() {
}, },
400: { 400: {
'git_local_overwrite': function(err) { 'git_local_overwrite': function(err) {
RED.notify("<p>Unable to pull remote changes; your unstaged local changes would be overwritten.</p><p>Commit your changes and try again.</p>"+ RED.notify(RED._("sidebar.project.versionControl.unablePull")+
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000); '<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+RED._("sidebar.project.versionControl.showUnstagedChanges")+'</a></p>',"error",false,10000000);
}, },
'git_pull_merge_conflict': function(err) { 'git_pull_merge_conflict': function(err) {
refresh(true); refresh(true);
closeRemoteBox(); closeRemoteBox();
}, },
'git_connection_failed': function(err) { 'git_connection_failed': function(err) {
RED.notify("Could not connect to remote repository: "+err.toString(),"warning") RED.notify(RED._("sidebar.project.versionControl.connectionFailed")+err.toString(),"warning")
}, },
'git_pull_unrelated_history': function(error) { 'git_pull_unrelated_history': function(error) {
var notification = RED.notify("<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",{ var notification = RED.notify(RED._("sidebar.project.versionControl.pullUnrelatedHistory"),{
type: 'error', type: 'error',
modal: true, modal: true,
fixed: true, fixed: true,
@ -967,7 +971,7 @@ RED.sidebar.versionControl = (function() {
notification.close(); notification.close();
} }
},{ },{
text: 'Pull changes', text: RED._("sidebar.project.versionControl.pullChanges"),
click: function() { click: function() {
notification.close(); notification.close();
options.allowUnrelatedHistories = true; options.allowUnrelatedHistories = true;
@ -986,7 +990,7 @@ RED.sidebar.versionControl = (function() {
spinner.remove(); spinner.remove();
}); });
} }
$('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span>pull</span></button>') $('<button id="sidebar-version-control-repo-pull" class="sidebar-version-control-repo-sub-action editor-button"><i class="fa fa-long-arrow-down"></i> <span data-i18n="sidebar.project.versionControl.pull"></span></button>')
.appendTo(row) .appendTo(row)
.click(function(e) { .click(function(e) {
e.preventDefault(); e.preventDefault();
@ -999,7 +1003,7 @@ RED.sidebar.versionControl = (function() {
RED.sidebar.addTab({ RED.sidebar.addTab({
id: "version-control", id: "version-control",
label: "history", label: RED._("sidebar.project.versionControl.history"),
name: "Project History", name: "Project History",
content: sidebarContent, content: sidebarContent,
enableOnEdit: false, enableOnEdit: false,
@ -1021,17 +1025,17 @@ RED.sidebar.versionControl = (function() {
if (daysDelta > 30) { if (daysDelta > 30) {
return (new Date(date*1000)).toLocaleDateString(); return (new Date(date*1000)).toLocaleDateString();
} else if (daysDelta > 0) { } else if (daysDelta > 0) {
return daysDelta+" day"+(daysDelta>1?"s":"")+" ago"; return RED._("sidebar.project.versionControl.daysAgo", {count:daysDelta})
} }
var hoursDelta = Math.floor(delta / (60*60)); var hoursDelta = Math.floor(delta / (60*60));
if (hoursDelta > 0) { if (hoursDelta > 0) {
return hoursDelta+" hour"+(hoursDelta>1?"s":"")+" ago"; return RED._("sidebar.project.versionControl.hoursAgo", {count:hoursDelta})
} }
var minutesDelta = Math.floor(delta / 60); var minutesDelta = Math.floor(delta / 60);
if (minutesDelta > 0) { if (minutesDelta > 0) {
return minutesDelta+" minute"+(minutesDelta>1?"s":"")+" ago"; return RED._("sidebar.project.versionControl.minsAgo", {count:minutesDelta})
} }
return "Seconds ago"; return RED._("sidebar.project.versionControl.secondsAgo");
} }
function updateBulk(files,unstaged) { function updateBulk(files,unstaged) {
@ -1066,9 +1070,6 @@ RED.sidebar.versionControl = (function() {
var refreshInProgress = false; var refreshInProgress = false;
var emptyStagedItem = { label:"None" };
var emptyMergedItem = { label:"All conflicts resolved. Commit the changes to complete the merge." };
function getCommits(url,targetList,spinnerTarget,limit,before) { function getCommits(url,targetList,spinnerTarget,limit,before) {
var spinner = utils.addSpinnerOverlay(spinnerTarget); var spinner = utils.addSpinnerOverlay(spinnerTarget);
var fullUrl = url+"?limit="+(limit||20); var fullUrl = url+"?limit="+(limit||20);
@ -1276,7 +1277,7 @@ RED.sidebar.versionControl = (function() {
refreshFiles(result); refreshFiles(result);
$('#sidebar-version-control-local-branch').text(result.branches.local); $('#sidebar-version-control-local-branch').text(result.branches.local);
$('#sidebar-version-control-remote-branch').text(result.branches.remote||"none"); $('#sidebar-version-control-remote-branch').text(result.branches.remote||RED._("sidebar.project.versionControl.none"));
var commitsAhead = result.commits.ahead || 0; var commitsAhead = result.commits.ahead || 0;
var commitsBehind = result.commits.behind || 0; var commitsBehind = result.commits.behind || 0;
@ -1306,7 +1307,7 @@ RED.sidebar.versionControl = (function() {
$('#sidebar-version-control-commits-ahead').text(""); $('#sidebar-version-control-commits-ahead').text("");
$('#sidebar-version-control-commits-behind').text(""); $('#sidebar-version-control-commits-behind').text("");
$('#sidebar-version-control-repo-toolbar-message').text("Your local branch is not currently tracking a remote branch."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.notTracking"));
$("#sidebar-version-control-repo-pull").attr('disabled',true); $("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',true); $("#sidebar-version-control-repo-push").attr('disabled',true);
} }
@ -1332,23 +1333,26 @@ RED.sidebar.versionControl = (function() {
$('#sidebar-version-control-commits-ahead').text(commitsAhead); $('#sidebar-version-control-commits-ahead').text(commitsAhead);
$('#sidebar-version-control-commits-behind').text(commitsBehind); $('#sidebar-version-control-commits-behind').text(commitsBehind);
if (isMerging) { if (isMerging) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository has unmerged changes. You need to fix the conflicts and commit the result."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.statusUnmergedChanged"));
$("#sidebar-version-control-repo-pull").attr('disabled',true); $("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',true); $("#sidebar-version-control-repo-push").attr('disabled',true);
} else if (commitsAhead > 0 && commitsBehind === 0) { } else if (commitsAhead > 0 && commitsBehind === 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsAhead+" commit"+(commitsAhead===1?'':'s')+" ahead of the remote. You can push "+(commitsAhead===1?'this commit':'these commits')+" now."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.commitsAhead", {count:commitsAhead}));
$("#sidebar-version-control-repo-pull").attr('disabled',true); $("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',false); $("#sidebar-version-control-repo-push").attr('disabled',false);
} else if (commitsAhead === 0 && commitsBehind > 0) { } else if (commitsAhead === 0 && commitsBehind > 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsBehind+" commit"+(commitsBehind===1?'':'s')+" behind of the remote. You can pull "+(commitsBehind===1?'this commit':'these commits')+" now."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.commitsBehind",{ count: commitsBehind }));
$("#sidebar-version-control-repo-pull").attr('disabled',false); $("#sidebar-version-control-repo-pull").attr('disabled',false);
$("#sidebar-version-control-repo-push").attr('disabled',true); $("#sidebar-version-control-repo-push").attr('disabled',true);
} else if (commitsAhead > 0 && commitsBehind > 0) { } else if (commitsAhead > 0 && commitsBehind > 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is "+commitsBehind+" commit"+(commitsBehind===1?'':'s')+" behind and "+commitsAhead+" commit"+(commitsAhead===1?'':'s')+" ahead of the remote. You must pull the remote commit"+(commitsBehind===1?'':'s')+" down before pushing."); $('#sidebar-version-control-repo-toolbar-message').text(
RED._("sidebar.project.versionControl.commitsAheadAndBehind1",{ count:commitsBehind })+
RED._("sidebar.project.versionControl.commitsAheadAndBehind2",{ count:commitsAhead })+
RED._("sidebar.project.versionControl.commitsAheadAndBehind3",{ count:commitsBehind }));
$("#sidebar-version-control-repo-pull").attr('disabled',false); $("#sidebar-version-control-repo-pull").attr('disabled',false);
$("#sidebar-version-control-repo-push").attr('disabled',true); $("#sidebar-version-control-repo-push").attr('disabled',true);
} else if (commitsAhead === 0 && commitsBehind === 0) { } else if (commitsAhead === 0 && commitsBehind === 0) {
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is up to date."); $('#sidebar-version-control-repo-toolbar-message').text(RED._("sidebar.project.versionControl.repositoryUpToDate"));
$("#sidebar-version-control-repo-pull").attr('disabled',true); $("#sidebar-version-control-repo-pull").attr('disabled',true);
$("#sidebar-version-control-repo-push").attr('disabled',true); $("#sidebar-version-control-repo-push").attr('disabled',true);
} }

View File

@ -23,5 +23,6 @@ RED.state = {
EXPORT: 6, EXPORT: 6,
IMPORT: 7, IMPORT: 7,
IMPORT_DRAGGING: 8, IMPORT_DRAGGING: 8,
QUICK_JOINING: 9 QUICK_JOINING: 9,
PANNING: 10
} }

View File

@ -58,7 +58,8 @@ RED.view = (function() {
lastClickNode = null, lastClickNode = null,
dblClickPrimed = null, dblClickPrimed = null,
clickTime = 0, clickTime = 0,
clickElapsed = 0; clickElapsed = 0,
scroll_position;
var clipboard = ""; var clipboard = "";
@ -73,6 +74,8 @@ RED.view = (function() {
var PORT_TYPE_INPUT = 1; var PORT_TYPE_INPUT = 1;
var PORT_TYPE_OUTPUT = 0; var PORT_TYPE_OUTPUT = 0;
var chart = $("#chart");
var outer = d3.select("#chart") var outer = d3.select("#chart")
.append("svg:svg") .append("svg:svg")
.attr("width", space_width) .attr("width", space_width)
@ -94,6 +97,16 @@ RED.view = (function() {
.on("mousemove", canvasMouseMove) .on("mousemove", canvasMouseMove)
.on("mousedown", canvasMouseDown) .on("mousedown", canvasMouseDown)
.on("mouseup", canvasMouseUp) .on("mouseup", canvasMouseUp)
.on("mouseenter", function() {
if (lasso) {
if (d3.event.buttons !== 1) {
lasso.remove();
lasso = null;
}
} else if (mouse_mode === RED.state.PANNING && d3.event.buttons !== 4) {
resetMouseVars();
}
})
.on("touchend", function() { .on("touchend", function() {
clearTimeout(touchStartTime); clearTimeout(touchStartTime);
touchStartTime = null; touchStartTime = null;
@ -283,7 +296,6 @@ RED.view = (function() {
function init() { function init() {
RED.events.on("workspace:change",function(event) { RED.events.on("workspace:change",function(event) {
var chart = $("#chart");
if (event.old !== 0) { if (event.old !== 0) {
workspaceScrollPositions[event.old] = { workspaceScrollPositions[event.old] = {
left:chart.scrollLeft(), left:chart.scrollLeft(),
@ -526,6 +538,15 @@ RED.view = (function() {
function canvasMouseDown() { function canvasMouseDown() {
var point; var point;
if (d3.event.button === 1) {
// Middle Click pan
mouse_mode = RED.state.PANNING;
mouse_position = [d3.event.pageX,d3.event.pageY]
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
return;
}
if (!mousedown_node && !mousedown_link) { if (!mousedown_node && !mousedown_link) {
selected_link = null; selected_link = null;
updateSelection(); updateSelection();
@ -644,7 +665,6 @@ RED.view = (function() {
function canvasMouseMove() { function canvasMouseMove() {
var i; var i;
var node; var node;
mouse_position = d3.touches(this)[0]||d3.mouse(this);
// Prevent touch scrolling... // Prevent touch scrolling...
//if (d3.touches(this)[0]) { //if (d3.touches(this)[0]) {
// d3.event.preventDefault(); // d3.event.preventDefault();
@ -655,6 +675,22 @@ RED.view = (function() {
//if (point[0]-container.scrollLeft < 30 && container.scrollLeft > 0) { container.scrollLeft -= 15; } //if (point[0]-container.scrollLeft < 30 && container.scrollLeft > 0) { container.scrollLeft -= 15; }
//console.log(d3.mouse(this),container.offsetWidth,container.offsetHeight,container.scrollLeft,container.scrollTop); //console.log(d3.mouse(this),container.offsetWidth,container.offsetHeight,container.scrollLeft,container.scrollTop);
if (mouse_mode === RED.state.PANNING) {
var pos = [d3.event.pageX,d3.event.pageY];
var deltaPos = [
mouse_position[0]-pos[0],
mouse_position[1]-pos[1]
];
chart.scrollLeft(scroll_position[0]+deltaPos[0])
chart.scrollTop(scroll_position[1]+deltaPos[1])
return
}
mouse_position = d3.touches(this)[0]||d3.mouse(this);
if (lasso) { if (lasso) {
var ox = parseInt(lasso.attr("ox")); var ox = parseInt(lasso.attr("ox"));
var oy = parseInt(lasso.attr("oy")); var oy = parseInt(lasso.attr("oy"));
@ -906,6 +942,10 @@ RED.view = (function() {
function canvasMouseUp() { function canvasMouseUp() {
var i; var i;
var historyEvent; var historyEvent;
if (mouse_mode === RED.state.PANNING) {
resetMouseVars();
return
}
if (mouse_mode === RED.state.QUICK_JOINING) { if (mouse_mode === RED.state.QUICK_JOINING) {
return; return;
} }

View File

@ -156,7 +156,7 @@
toolbar: uiComponents.footer, toolbar: uiComponents.footer,
enableOnEdit: true, enableOnEdit: true,
pinned: true, pinned: true,
iconClass: "fa fa-wrench" iconClass: "fa fa-list-alt"
}); });
RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); }); RED.actions.add("core:show-debug-tab",function() { RED.sidebar.show('debug'); });

View File

@ -82,6 +82,7 @@ module.exports = function(RED) {
console:console, console:console,
util:util, util:util,
Buffer:Buffer, Buffer:Buffer,
Date: Date,
RED: { RED: {
util: RED.util util: RED.util
}, },

View File

@ -41,7 +41,7 @@
<dt>payload <span class="property-type">string | buffer</span></dt> <dt>payload <span class="property-type">string | buffer</span></dt>
<dd>a string unless detected as a binary buffer.</dd> <dd>a string unless detected as a binary buffer.</dd>
<dt>topic <span class="property-type">string</span></dt> <dt>topic <span class="property-type">string</span></dt>
<dd>the MQTT topic, uses / as a heirarchy separator.</dd> <dd>the MQTT topic, uses / as a hierarchy separator.</dd>
<dt>qos <span class="property-type">number</span> </dt> <dt>qos <span class="property-type">number</span> </dt>
<dd>0, fire and forget - 1, at least once - 2, once and once only.</dd> <dd>0, fire and forget - 1, at least once - 2, once and once only.</dd>
<dt>retain <span class="property-type">boolean</span></dt> <dt>retain <span class="property-type">boolean</span></dt>

View File

@ -21,8 +21,6 @@ module.exports = function(RED) {
var cookieParser = require("cookie-parser"); var cookieParser = require("cookie-parser");
var getBody = require('raw-body'); var getBody = require('raw-body');
var cors = require('cors'); var cors = require('cors');
var jsonParser = bodyParser.json();
var urlencParser = bodyParser.urlencoded({extended:true});
var onHeaders = require('on-headers'); var onHeaders = require('on-headers');
var typer = require('media-typer'); var typer = require('media-typer');
var isUtf8 = require('is-utf8'); var isUtf8 = require('is-utf8');
@ -212,6 +210,10 @@ module.exports = function(RED) {
} }
} }
var maxApiRequestSize = RED.settings.apiMaxLength || '5mb';
var jsonParser = bodyParser.json({limit:maxApiRequestSize});
var urlencParser = bodyParser.urlencoded({limit:maxApiRequestSize,extended:true});
var metricsHandler = function(req,res,next) { next(); } var metricsHandler = function(req,res,next) { next(); }
if (this.metric()) { if (this.metric()) {
metricsHandler = function(req, res, next) { metricsHandler = function(req, res, next) {

View File

@ -16,9 +16,7 @@
module.exports = function(RED) { module.exports = function(RED) {
"use strict"; "use strict";
var http = require("follow-redirects").http; var request = require("request");
var https = require("follow-redirects").https;
var urllib = require("url");
var mustache = require("mustache"); var mustache = require("mustache");
var querystring = require("querystring"); var querystring = require("querystring");
var cookie = require("cookie"); var cookie = require("cookie");
@ -78,9 +76,13 @@ module.exports = function(RED) {
if (msg.method && n.method && (n.method === "use")) { if (msg.method && n.method && (n.method === "use")) {
method = msg.method.toUpperCase(); // use the msg parameter method = msg.method.toUpperCase(); // use the msg parameter
} }
var opts = urllib.parse(url); var opts = {};
opts.url = url;
opts.timeout = node.reqTimeout;
opts.method = method; opts.method = method;
opts.headers = {}; opts.headers = {};
opts.encoding = null; // Force NodeJs to return a Buffer (instead of a string)
opts.maxRedirects = 21;
var ctSet = "Content-Type"; // set default camel case var ctSet = "Content-Type"; // set default camel case
var clSet = "Content-Length"; var clSet = "Content-Length";
if (msg.headers) { if (msg.headers) {
@ -109,7 +111,7 @@ module.exports = function(RED) {
} }
} }
if (msg.hasOwnProperty('followRedirects')) { if (msg.hasOwnProperty('followRedirects')) {
opts.followRedirects = msg.followRedirects; opts.followRedirect = msg.followRedirects;
} }
if (msg.cookies) { if (msg.cookies) {
var cookies = []; var cookies = [];
@ -134,7 +136,10 @@ module.exports = function(RED) {
} }
} }
if (this.credentials && this.credentials.user) { if (this.credentials && this.credentials.user) {
opts.auth = this.credentials.user+":"+(this.credentials.password||""); opts.auth = {
user: this.credentials.user,
pass: this.credentials.password||""
};
} }
var payload = null; var payload = null;
@ -160,6 +165,7 @@ module.exports = function(RED) {
opts.headers[clSet] = Buffer.byteLength(payload); opts.headers[clSet] = Buffer.byteLength(payload);
} }
} }
opts.body = payload;
} }
// revert to user supplied Capitalisation if needed. // revert to user supplied Capitalisation if needed.
if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) { if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) {
@ -170,7 +176,6 @@ module.exports = function(RED) {
opts.headers[clSet] = opts.headers['content-length']; opts.headers[clSet] = opts.headers['content-length'];
delete opts.headers['content-length']; delete opts.headers['content-length'];
} }
var urltotest = url;
var noproxy; var noproxy;
if (noprox) { if (noprox) {
for (var i in noprox) { for (var i in noprox) {
@ -180,23 +185,12 @@ module.exports = function(RED) {
if (prox && !noproxy) { if (prox && !noproxy) {
var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i); var match = prox.match(/^(http:\/\/)?(.+)?:([0-9]+)?/i);
if (match) { if (match) {
//opts.protocol = "http:"; opts.proxy = prox;
//opts.host = opts.hostname = match[2]; } else {
//opts.port = (match[3] != null ? match[3] : 80); node.warn("Bad proxy url: "+ prox);
opts.headers['Host'] = opts.host; opts.proxy = null;
var heads = opts.headers;
var path = opts.pathname = opts.href;
opts = urllib.parse(prox);
opts.path = opts.pathname = path;
opts.headers = heads;
opts.method = method;
urltotest = match[0];
if (opts.auth) {
opts.headers['Proxy-Authorization'] = "Basic "+new Buffer(opts.auth).toString('Base64')
} }
} }
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
}
if (tlsNode) { if (tlsNode) {
tlsNode.addTLSOptions(opts); tlsNode.addTLSOptions(opts);
} else { } else {
@ -204,16 +198,23 @@ module.exports = function(RED) {
opts.rejectUnauthorized = msg.rejectUnauthorized; opts.rejectUnauthorized = msg.rejectUnauthorized;
} }
} }
var req = ((/^https/.test(urltotest))?https:http).request(opts,function(res) { request(opts, function(err, res, body) {
// Force NodeJs to return a Buffer (instead of a string) if(err){
// See https://github.com/nodejs/node/issues/6038 if(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') {
res.setEncoding(null); node.error(RED._("common.notification.errors.no-response"), msg);
delete res._readableState.decoder; node.status({fill:"red", shape:"ring", text:"common.notification.errors.no-response"});
}else{
node.error(err,msg);
node.status({fill:"red", shape:"ring", text:err.code});
}
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
node.send(msg);
}else{
msg.statusCode = res.statusCode; msg.statusCode = res.statusCode;
msg.headers = res.headers; msg.headers = res.headers;
msg.responseUrl = res.responseUrl; msg.responseUrl = res.request.uri.href;
msg.payload = []; msg.payload = body;
if (msg.headers.hasOwnProperty('set-cookie')) { if (msg.headers.hasOwnProperty('set-cookie')) {
msg.responseCookies = {}; msg.responseCookies = {};
@ -224,22 +225,10 @@ module.exports = function(RED) {
parsedCookie.value = parsedCookie[key]; parsedCookie.value = parsedCookie[key];
delete parsedCookie[key]; delete parsedCookie[key];
msg.responseCookies[key] = parsedCookie; msg.responseCookies[key] = parsedCookie;
});
})
} }
msg.headers['x-node-red-request-node'] = hashSum(msg.headers); msg.headers['x-node-red-request-node'] = hashSum(msg.headers);
// msg.url = url; // revert when warning above finally removed // msg.url = url; // revert when warning above finally removed
res.on('data',function(chunk) {
if (!Buffer.isBuffer(chunk)) {
// if the 'setEncoding(null)' fix above stops working in
// a new Node.js release, throw a noisy error so we know
// about it.
throw new Error("HTTP Request data chunk not a Buffer");
}
msg.payload.push(chunk);
});
res.on('end',function() {
if (node.metric()) { if (node.metric()) {
// Calculate request time // Calculate request time
var diff = process.hrtime(preRequestTimestamp); var diff = process.hrtime(preRequestTimestamp);
@ -251,13 +240,7 @@ module.exports = function(RED) {
} }
} }
// Check that msg.payload is an array - if the req error
// handler has been called, it will have been set to a string
// and the error already handled - so no further action should
// be taken. #1344
if (Array.isArray(msg.payload)) {
// Convert the payload to the required return type // Convert the payload to the required return type
msg.payload = Buffer.concat(msg.payload); // bin
if (node.ret !== "bin") { if (node.ret !== "bin") {
msg.payload = msg.payload.toString('utf8'); // txt msg.payload = msg.payload.toString('utf8'); // txt
@ -271,25 +254,6 @@ module.exports = function(RED) {
} }
}); });
}); });
req.setTimeout(node.reqTimeout, function() {
node.error(RED._("common.notification.errors.no-response"),msg);
setTimeout(function() {
node.status({fill:"red",shape:"ring",text:"common.notification.errors.no-response"});
},10);
req.abort();
});
req.on('error',function(err) {
node.error(err,msg);
msg.payload = err.toString() + " : " + url;
msg.statusCode = err.code;
node.status({fill:"red",shape:"ring",text:err.code});
node.send(msg);
});
if (payload) {
req.write(payload);
}
req.end();
});
this.on("close",function() { this.on("close",function() {
node.status({}); node.status({});

View File

@ -130,6 +130,8 @@ module.exports = function(RED) {
socket.setKeepAlive(true,120000); socket.setKeepAlive(true,120000);
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); } if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = (1+Math.random()*4294967295).toString(16); var id = (1+Math.random()*4294967295).toString(16);
var fromi;
var fromp;
connectionPool[id] = socket; connectionPool[id] = socket;
count++; count++;
node.status({text:RED._("tcpin.status.connections",{count:count})}); node.status({text:RED._("tcpin.status.connections",{count:count})});
@ -155,18 +157,21 @@ module.exports = function(RED) {
msg._session = {type:"tcp",id:id}; msg._session = {type:"tcp",id:id};
node.send(msg); node.send(msg);
} }
} else { }
else {
if ((typeof data) === "string") { if ((typeof data) === "string") {
buffer = buffer+data; buffer = buffer+data;
} else { } else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length); buffer = Buffer.concat([buffer,data],buffer.length+data.length);
} }
fromi = socket.remoteAddress;
fromp = socket.remotePort;
} }
}); });
socket.on('end', function() { socket.on('end', function() {
if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) { if (!node.stream || (node.datatype === "utf8" && node.newline !== "")) {
if (buffer.length > 0) { if (buffer.length > 0) {
var msg = {topic:node.topic, payload:buffer, ip:socket.remoteAddress, port:socket.remotePort}; var msg = {topic:node.topic, payload:buffer, ip:fromi, port:fromp};
msg._session = {type:"tcp",id:id}; msg._session = {type:"tcp",id:id};
node.send(msg); node.send(msg);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "node-red", "name": "node-red",
"version": "0.18.6", "version": "0.18.7",
"description": "A visual tool for wiring the Internet of Things", "description": "A visual tool for wiring the Internet of Things",
"homepage": "http://nodered.org", "homepage": "http://nodered.org",
"license": "Apache-2.0", "license": "Apache-2.0",
@ -45,7 +45,6 @@
"cron": "1.3.0", "cron": "1.3.0",
"express": "4.16.3", "express": "4.16.3",
"express-session": "1.15.6", "express-session": "1.15.6",
"follow-redirects": "1.4.1",
"fs-extra": "5.0.0", "fs-extra": "5.0.0",
"fs.notify": "0.0.4", "fs.notify": "0.0.4",
"hash-sum": "1.0.2", "hash-sum": "1.0.2",
@ -54,7 +53,7 @@
"is-utf8": "0.2.1", "is-utf8": "0.2.1",
"js-yaml": "3.11.0", "js-yaml": "3.11.0",
"json-stringify-safe": "5.0.1", "json-stringify-safe": "5.0.1",
"jsonata": "1.5.3", "jsonata": "1.5.4",
"media-typer": "0.3.0", "media-typer": "0.3.0",
"memorystore": "1.6.0", "memorystore": "1.6.0",
"mime": "1.4.1", "mime": "1.4.1",
@ -64,7 +63,7 @@
"node-red-node-email": "0.1.*", "node-red-node-email": "0.1.*",
"node-red-node-feedparser": "0.1.*", "node-red-node-feedparser": "0.1.*",
"node-red-node-rbe": "0.2.*", "node-red-node-rbe": "0.2.*",
"node-red-node-twitter": "0.1.*", "node-red-node-twitter": "*",
"nopt": "4.0.1", "nopt": "4.0.1",
"oauth2orize": "1.11.0", "oauth2orize": "1.11.0",
"on-headers": "1.0.1", "on-headers": "1.0.1",
@ -72,6 +71,7 @@
"passport-http-bearer": "1.0.1", "passport-http-bearer": "1.0.1",
"passport-oauth2-client-password": "0.1.2", "passport-oauth2-client-password": "0.1.2",
"raw-body": "2.3.3", "raw-body": "2.3.3",
"request": "2.87.0",
"semver": "5.5.0", "semver": "5.5.0",
"sentiment": "2.1.0", "sentiment": "2.1.0",
"uglify-js": "3.3.25", "uglify-js": "3.3.25",

View File

@ -86,6 +86,10 @@ function init(config) {
} else { } else {
api.authenticate = authenticate; api.authenticate = authenticate;
} }
} else {
api.get = get;
api.authenticate = authenticate;
api.default = api.default;
} }
if (config.default) { if (config.default) {
if (typeof config.default === "function") { if (typeof config.default === "function") {

View File

@ -10,7 +10,11 @@
"load": "Load", "load": "Load",
"save": "Save", "save": "Save",
"import": "Import", "import": "Import",
"export": "Export" "export": "Export",
"back": "Back",
"next": "Next",
"clone": "Clone project",
"cont": "Continue"
} }
}, },
"workspace": { "workspace": {
@ -67,7 +71,11 @@
"editPalette":"Manage palette", "editPalette":"Manage palette",
"other": "Other", "other": "Other",
"showTips": "Show tips", "showTips": "Show tips",
"help": "Node-RED website" "help": "Node-RED website",
"projects": "Projects",
"projects-new": "New",
"projects-open": "Open",
"projects-settings": "Project Settings"
} }
}, },
"user": { "user": {
@ -108,6 +116,24 @@
"cannotAddCircularReference": "Cannot add subflow - circular reference detected", "cannotAddCircularReference": "Cannot add subflow - circular reference detected",
"unsupportedVersion": "<p>Using an unsupported version of Node.js</p><p>You should upgrade to the latest Node.js LTS release</p>", "unsupportedVersion": "<p>Using an unsupported version of Node.js</p><p>You should upgrade to the latest Node.js LTS release</p>",
"failedToAppendNode": "<p>Failed to load '__module__'</p><p>__error__</p>" "failedToAppendNode": "<p>Failed to load '__module__'</p><p>__error__</p>"
},
"project": {
"change-branch": "Change to local branch '__project__'",
"merge-abort": "Git merge aborted",
"loaded": "Project '__project__' loaded",
"updated": "Project '__project__' updated",
"pull": "Project '__project__' reloaded",
"revert": "Project '__project__' reloaded",
"merge-complete": "Git merge completed"
},
"label": {
"manage-project-dep": "Manage project dependencies",
"setup-cred": "Setup credentials",
"setup-project": "Setup project files",
"create-default-package": "Create default package file",
"no-thanks": "No thanks",
"create-default-project": "Create default project files",
"show-merge-conflicts": "Show merge conflicts"
} }
}, },
"clipboard": { "clipboard": {
@ -193,8 +219,16 @@
"nodeCount": "__count__ node", "nodeCount": "__count__ node",
"nodeCount_plural": "__count__ nodes", "nodeCount_plural": "__count__ nodes",
"local":"Local changes", "local":"Local changes",
"remote":"Remote changes" "remote":"Remote changes",
"reviewChanges": "Review Changes",
"noBinaryFileShowed": "Cannot show binary file contents",
"viewCommitDiff": "View Commit Changes",
"compareChanges": "Compare Changes",
"saveConflict": "Save conflict resolution",
"conflictHeader": "<span>__resolved__</span> of <span>__unresolved__</span> conflicts resolved",
"commonVersionError": "Common Version doesn't contain valid JSON:",
"oldVersionError": "Old Version doesn't contain valid JSON:",
"newVersionError": "New Version doesn't contain valid JSON:"
}, },
"subflow": { "subflow": {
"editSubflow": "Edit flow template: __name__", "editSubflow": "Edit flow template: __name__",
@ -433,8 +467,137 @@
"description": "Description", "description": "Description",
"dependencies": "Dependencies", "dependencies": "Dependencies",
"settings": "Settings", "settings": "Settings",
"noSummaryAvailable": "No summary available",
"editDescription": "Edit project description", "editDescription": "Edit project description",
"editDependencies": "Edit project dependencies" "editDependencies": "Edit project dependencies",
"editReadme": "Edit README.md",
"projectSettings": {
"edit": "edit",
"none": "None",
"install": "install",
"removeFromProject": "remove from project",
"addToProject": "add to project",
"none": "None",
"files": "Files",
"flow": "Flow",
"credentials": "Credentials",
"invalidEncryptionKey": "Invalid encryption key",
"encryptionEnabled": "Encryption enabled",
"encryptionDisabled": "Encryption disabled",
"resetTheEncryptionKey": "Reset the encryption key:",
"setTheEncryptionKey": "Set the encryption key:",
"changeTheEncryptionKey": "Change the encryption key:",
"currentKey": "Current key",
"newKey": "New key",
"credentialsAlert": "This will delete all existing credentials",
"versionControl": "Version Control",
"branches": "Branches",
"noBranches": "No branches",
"deleteConfirm": "Are you sure you want to delete the local branch '__name__'? This cannot be undone.",
"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",
"addRemote": "add remote",
"addRemote2": "Add remote",
"remoteName": "Remote name",
"nameRule": "Must contain only A-Z 0-9 _ -",
"url": "URL",
"urlRule": "https://, ssh:// or file://",
"urlRule2": "Do not include the username/password in the URL",
"noRemotes": "No remotes",
"deleteRemoteConfrim": "Are you sure you want to delete the remote '__name__'?",
"deleteRemote": "Delete remote"
},
"userSettings": {
"committerDetail": "Committer Details",
"committerTip": "Leave blank to use system default",
"userName": "Username",
"email": "Email",
"sshKeys": "SSH Keys",
"sshKeysTip": "Allows you to create secure connections to remote git repositories.",
"add": "add key",
"addSshKey": "Add SSH Key",
"addSshKeyTip": "Generate a new public/private key pair",
"name": "Name",
"nameRule": "Must contain only A-Z 0-9 _ -",
"passphrase": "Passphrase",
"passphraseShort": "Passphrase too short",
"optional": "Optional",
"cancel": "Cancel",
"generate": "Generate key",
"noSshKeys": "No SSH keys",
"copyPublicKey": "Copy public key to clipboard",
"delete": "Delete key",
"gitConfig": "Git config",
"deleteConfirm": "Are you sure you want to delete the SSH key __name__? This cannot be undone."
},
"versionControl": {
"unstagedChanges": "Unstaged changes",
"stagedChanges": "Staged changes",
"resolveConflicts": "Resolve conflicts",
"head": "HEAD",
"staged": "Staged",
"unstaged": "Unstaged",
"local": "Local",
"remote": "Remote",
"revert": "Are you sure you want to revert the changes to '__file__'? This cannot be undone.",
"revertChanges": "Revert changes",
"localChanges": "Local Changes",
"none": "None",
"conflictResolve": "All conflicts resolved. Commit the changes to complete the merge.",
"localFiles": "Local files",
"all": "all",
"unmergedChanges": "Unmerged changes",
"abortMerge": "abort merge",
"commit": "commit",
"changeToCommit": "Changes to commit",
"commitPlaceholder": "Enter your commit message",
"cancelCapital": "Cancel",
"commitCapital": "Commit",
"commitHistory": "Commit History",
"branch": "Branch:",
"moreCommits": " more commit(s)",
"changeLocalBranch": "Change local branch",
"createBranchPlaceholder": "Find or create a branch",
"upstream": "upstream",
"localOverwrite": "You have local changes that would be overwritten by changing the branch. You must either commit or undo those changes first.",
"manageRemoteBranch": "Manage remote branch",
"unableToAccess": "Unable to access remote repository",
"retry": "Retry",
"setUpstreamBranch": "Set as upstream branch",
"createRemoteBranchPlaceholder": "Find or create a remote branch",
"trackedUpstreamBranch": "The created branch will be set as the tracked upstream branch.",
"selectUpstreamBranch": "The branch will be created. Select below to set it as the tracked upstream branch.",
"pushFailed": "Push failed as the remote has more recent commits. Pull and merge first, then push again.",
"push": "push",
"pull": "pull",
"unablePull": "<p>Unable to pull remote changes; your unstaged local changes would be overwritten.</p><p>Commit your changes and try again.</p>",
"showUnstagedChanges": "Show unstaged changes",
"connectionFailed": "Could not connect to remote repository: ",
"pullUnrelatedHistory": "<p>The remote has an unrelated history of commits.</p><p>Are you sure you want to pull the changes into your local repository?</p>",
"pullChanges": "Pull changes",
"history": "history",
"daysAgo": "__count__ day ago",
"daysAgo_plural": "__count__ days ago",
"hoursAgo": "__count__ hour ago",
"hoursAgo_plural": "__count__ hours ago",
"minsAgo": "__count__ min ago",
"minsAgo_plural": "__count__ mins ago",
"secondsAgo": "Seconds ago",
"notTracking": "Your local branch is not currently tracking a remote branch.",
"statusUnmergedChanged": "Your repository has unmerged changes. You need to fix the conflicts and commit the result.",
"repositoryUpToDate": "Your repository is up to date.",
"commitsAhead": "Your repository is __count__ commit ahead of the remote. You can push this commit now.",
"commitsAhead_plural": "Your repository is __count__ commits ahead of the remote. You can push these commits now.",
"commitsBehind": "Your repository is __count__ commit behind of the remote. You can pull this commit now.",
"commitsBehind_plural": "Your repository is __count__ commits behind of the remote. You can pull these commits now.",
"commitsAheadAndBehind1": "Your repository is __count__ commit behind and ",
"commitsAheadAndBehind1_plural": "Your repository is __count__ commits behind and ",
"commitsAheadAndBehind2": "__count__ commit ahead of the remote. ",
"commitsAheadAndBehind2_plural": "__count__ commits ahead of the remote. ",
"commitsAheadAndBehind3": "You must pull the remote commit down before pushing.",
"commitsAheadAndBehind3_plural": "You must pull the remote commits down before pushing."
}
} }
}, },
"typedInput": { "typedInput": {
@ -486,5 +649,167 @@
"modeString": "Handle as UTF-8 String", "modeString": "Handle as UTF-8 String",
"modeArray": "Handle as JSON array", "modeArray": "Handle as JSON array",
"modeDesc":"<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>" "modeDesc":"<h3>Buffer editor</h3><p>The Buffer type is stored as a JSON array of byte values. The editor will attempt to parse the entered value as a JSON array. If it is not valid JSON, it will be treated as a UTF-8 String and converted to an array of the individual character code points.</p><p>For example, a value of <code>Hello World</code> will be converted to the JSON array:<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
},
"projects": {
"config-git": "Configure Git client",
"welcome": {
"hello": "Hello! We have introduced 'projects' to Node-RED.",
"desc0": "This is a new way for you to manage your flow files and includes version control of your flows.",
"desc1": "To get started you can create your first project or clone an existing project from a git repository.",
"desc2": "If you are not sure, you can skip this for now. You will still be able to create your first project from the 'Projects' menu at any time.",
"create": "Create Project",
"clone": "Clone Repository",
"not-right-now": "Not right now"
},
"git-config": {
"setup": "Setup your version control client",
"desc0": "Node-RED uses the open source tool Git for version control. It tracks changes to your project files and lets you push them to remote repositories.",
"desc1": "When you commit a set of changes, Git records who made the changes with a username and email address. The Username can be anything you want - it does not need to be your real name.",
"desc2": "Your Git client is already configured with the details below.",
"desc3": "You can change these settings later under the 'Git config' tab of the settings dialog.",
"username": "Username",
"email": "Email"
},
"project-details": {
"create": "Create your project",
"desc0": "A project is maintained as a Git repository. It makes it much easier to share your flows with others and to collaborate on them.",
"desc1": "You can create multiple projects and quickly switch between them from the editor.",
"desc2": "To begin, your project needs a name and an optional description.",
"already-exists": "Project already exists",
"must-contain": "Must contain only A-Z 0-9 _ -",
"project-name": "Project name",
"desc": "Description",
"opt": "Optional"
},
"clone-project": {
"clone": "Clone a project",
"desc0": "If you already have a git repository containing a project, you can clone it to get started.",
"already-exists": "Project already exists",
"must-contain": "Must contain only A-Z 0-9 _ -",
"project-name": "Project name",
"no-info-in-url": "Do not include the username/password in the url",
"git-url": "Git repository URL",
"protocols": "https://, ssh:// or file://",
"auth-failed": "Authentication failed",
"username": "Username",
"passwd": "Password",
"ssh-key": "SSH Key",
"passphrase": "Passphrase",
"ssh-key-desc": "Before you can clone a repository over ssh you must add an SSH key to access it.",
"ssh-key-add": "Add an ssh key",
"credential-key": "Credentials encryption key",
"cant-get-ssh-key": "Error! Can't get selected SSH key path.",
"already-exists": "already exists",
"git-error": "git error",
"connection-failed": "Connection failed",
"not-git-repo": "Not a git repository",
"repo-not-found": "Repository not found"
},
"default-files": {
"create": "Create your project files",
"desc0": "A project contains your flow files, a README file and a package.json file.",
"desc1": "It can contain any other files you want to maintain in the Git repository.",
"desc2": "Your existing flow and credential files will be copied into the project.",
"flow-file": "Flow file",
"credentials-file": "Credentials file"
},
"encryption-config": {
"setup": "Setup encryption of your credentials file",
"desc0": "Your flow credentials file can be encrypted to keep its contents secure.",
"desc1": "If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.",
"desc2": "Your flow credentials file is not currently encrypted.",
"desc3": "That means its contents, such as passwords and access tokens, can be read by anyone with access to the file.",
"desc4": "If you want to store these credentials in a public Git repository, you must encrypt them by providing a secret key phrase.",
"desc5": "Your flow credentials file is currently encrypted using the credentialSecret property from your settings file as the key.",
"desc6": "Your flow credentials file is currently encrypted using a system-generated key. You should provide a new secret key for this project.",
"desc7": "The key will be stored separately from your project files. You will need to provide the key to use this project in another instance of Node-RED.",
"credentials": "Credentials",
"enable": "Enable encryption",
"disable": "Disable encryption",
"disabled": "disabled",
"copy": "Copy over existing key",
"use-custom": "Use custom key",
"desc8": "The credentials file will not be encrypted and its contents easily read",
"create-project-files": "Create project files",
"create-project": "Create project",
"already-exists": "already exists",
"git-error": "git error",
"git-auth-error": "git auth error"
},
"create-success": {
"success": "You have successfully created your first project!",
"desc0": "You can now continue to use Node-RED just as you always have.",
"desc1": "The 'info' tab in the sidebar shows you what your current active project is. The button next to the name can be used to access the project settings view.",
"desc2": "The 'history' tab in the sidebar can be used to view files that have changed in your project and to commit them. It shows you a complete history of your commits and allows you to push your changes to a remote repository."
},
"create": {
"projects": "Projects",
"already-exists": "Project already exists",
"must-contain": "Must contain only A-Z 0-9 _ -",
"no-info-in-url": "Do not include the username/password in the url",
"open": "Open Project",
"create": "Create Project",
"clone": "Clone Repository",
"project-name": "Project name",
"desc": "Description",
"opt": "Optional",
"flow-file": "Flow file",
"credentials": "Credentials",
"enable-encryption": "Enable encryption",
"disable-encryption": "Disable encryption",
"encryption-key": "Encryption key",
"desc0": "A phrase to secure your credentials with",
"desc1": "The credentials file will not be encrypted and its contents easily read",
"git-url": "Git repository URL",
"protocols": "https://, ssh:// or file://",
"auth-failed": "Authentication failed",
"username": "Username",
"password": "Password",
"ssh-key": "SSH Key",
"passphrase": "Passphrase",
"desc2": "Before you can clone a repository over ssh you must add an SSH key to access it.",
"add-ssh-key": "Add an ssh key",
"credentials-encryption-key": "Credentials encryption key",
"already-exists-2": "already exists",
"git-error": "git error",
"con-failed": "Connection failed",
"not-git": "Not a git repository",
"no-resource": "Repository not found",
"cant-get-ssh-key-path": "Error! Can't get selected SSH key path.",
"unexpected_error": "unexpected_error"
},
"delete": {
"confirm": "Are you sure you want to delete this project?"
},
"create-project-list": {
"search": "search your projects",
"current": "current"
},
"require-clean": {
"confirm": "<p>You have undeployed changes that will be lost.</p><p>Do you want to continue?</p>"
},
"send-req": {
"auth-req": "Authentication required for repository",
"username": "Username",
"password": "Password",
"passphrase": "Passphrase",
"update-failed": "Failed to update auth",
"unhandled": "Unhandled error response"
},
"create-branch-list": {
"invalid": "Invalid branch",
"create": "Create branch",
"current": "current"
},
"create-default-file-set": {
"no-active": "Cannot create default file set without an active project",
"no-empty": "Cannot create default file set on a non-empty project",
"git-error": "git error"
},
"errors" : {
"no-username-email": "Your Git client is not configured with a username/email.",
"unexpected": "An unexpected error occurred",
"code": "code"
}
} }
} }

View File

@ -10,7 +10,11 @@
"load": "読み込み", "load": "読み込み",
"save": "保存", "save": "保存",
"import": "読み込み", "import": "読み込み",
"export": "書き出し" "export": "書き出し",
"back": "戻る",
"next": "進む",
"clone": "プロジェクトをクローン",
"cont": "続ける"
} }
}, },
"workspace": { "workspace": {
@ -67,7 +71,11 @@
"editPalette": "パレットの管理", "editPalette": "パレットの管理",
"other": "その他", "other": "その他",
"showTips": "ヒントを表示", "showTips": "ヒントを表示",
"help": "Node-REDウェブサイト" "help": "Node-REDウェブサイト",
"projects": "プロジェクト",
"projects-new": "新規",
"projects-open": "開く",
"projects-settings": "設定"
} }
}, },
"user": { "user": {
@ -102,7 +110,26 @@
"lostConnectionTry": "すぐに接続", "lostConnectionTry": "すぐに接続",
"cannotAddSubflowToItself": "サブフロー自身を追加できません", "cannotAddSubflowToItself": "サブフロー自身を追加できません",
"cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません", "cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません",
"unsupportedVersion": "サポートされていないバージョンのNode.jsを使用しています。<br/>最新のNode.js LTSに更新してください。" "unsupportedVersion": "サポートされていないバージョンのNode.jsを使用しています。<br/>最新のNode.js LTSに更新してください。",
"failedToAppendNode": "<p>'__module__'がロードできませんでした。</p><p>__error__</p>"
},
"project": {
"change-branch": "ローカルブランチ'__project__'に変更しました",
"merge-abort": "Gitマージを中止しました",
"loaded": "プロジェクト'__project__'をロードしました",
"updated": "プロジェクト'__project__'を更新しました",
"pull": "プロジェクト'__project__'を再ロードしました",
"revert": "プロジェクト'__project__'を再ロードしました",
"merge-complete": "Gitマージが完了しました"
},
"label": {
"manage-project-dep": "プロジェクトの依存関係の管理",
"setup-cred": "認証情報の設定",
"setup-project": "プロジェクトファイルの設定",
"create-default-package": "デフォルトパッケージファイルの作成",
"no-thanks": "不要",
"create-default-project": "デフォルトプロジェクトファイルの作成",
"show-merge-conflicts": "マージ競合を表示"
} }
}, },
"clipboard": { "clipboard": {
@ -188,7 +215,16 @@
"nodeCount": "__count__ 個のノード", "nodeCount": "__count__ 個のノード",
"nodeCount_plural": "__count__ 個のノード", "nodeCount_plural": "__count__ 個のノード",
"local": "ローカルの変更", "local": "ローカルの変更",
"remote": "リモートの変更" "remote": "リモートの変更",
"reviewChanges": "変更を表示",
"noBinaryFileShowed": "バイナリファイルの中身は表示することができません",
"viewCommitDiff": "コミットの内容を表示",
"compareChanges": "変更を比較",
"saveConflict": "解決して保存",
"conflictHeader": "<span>__unresolved__</span> 個中 <span>__resolved__</span> 個のコンフリクトを解決",
"commonVersionError": "共通バージョンは正しいJSON形式ではありません:",
"oldVersionError": "古いバージョンは正しいJSON形式ではありません:",
"newVersionError": "新しいバージョンは正しいJSON形式ではありません:"
}, },
"subflow": { "subflow": {
"editSubflow": "フローのテンプレートを編集: __name__", "editSubflow": "フローのテンプレートを編集: __name__",
@ -423,8 +459,137 @@
"description": "詳細", "description": "詳細",
"dependencies": "依存関係", "dependencies": "依存関係",
"settings": "設定", "settings": "設定",
"noSummaryAvailable": "サマリが存在しません",
"editDescription": "プロジェクトの詳細を編集", "editDescription": "プロジェクトの詳細を編集",
"editDependencies": "プロジェクトの依存関係を編集" "editDependencies": "プロジェクトの依存関係を編集",
"editReadme": "README.mdを編集",
"projectSettings": {
"edit": "編集",
"none": "なし",
"install": "インストール",
"removeFromProject": "プロジェクトから削除",
"addToProject": "プロジェクトへ追加",
"files": "ファイル",
"flow": "フロー",
"credentials": "認証情報",
"invalidEncryptionKey": "不正な暗号化キー",
"encryptionEnabled": "暗号化が有効になっています",
"encryptionDisabled": "暗号化が無効になっています",
"setTheEncryptionKey": "暗号化キーを設定:",
"resetTheEncryptionKey": "暗号化キーを初期化:",
"changeTheEncryptionKey": "暗号化キーを変更:",
"currentKey": "現在のキー",
"newKey": "新規のキー",
"credentialsAlert": "既存の認証情報は全て削除されます",
"versionControl": "バージョン管理",
"branches": "ブランチ",
"noBranches": "ブランチなし",
"deleteConfirm": "本当にローカルブランチ'__name__'を削除しますか?削除すると元に戻すことはできません。",
"unmergedConfirm": "ローカルブランチ'__name__'にはマージされていない変更があります。この変更は削除されます。本当に削除しますか?",
"deleteUnmergedBranch": "マージされていないブランチを削除",
"gitRemotes": "Gitリモート",
"addRemote": "リモートを追加",
"addRemote2": "リモートを追加",
"remoteName": "リモート名",
"nameRule": "A-Z 0-9 _ - のみを含む",
"url": "URL",
"urlRule": "https://、ssh:// または file://",
"urlRule2": "URLにユーザ名、パスワードを含んではいけません",
"noRemotes": "リモートなし",
"deleteRemoteConfrim": "本当にリモート'__name__'を削除しますか?",
"deleteRemote": "リモートを削除"
},
"userSettings": {
"committerDetail": "コミッター詳細",
"committerTip": "システムのデフォルトを使用する場合、空白のままにしてください",
"userName": "ユーザ名",
"email": "メールアドレス",
"sshKeys": "SSH キー",
"sshKeysTip": "gitリポジトリへのセキュアな接続を作成できます。",
"add": "キーを追加",
"addSshKey": "SSHキーを追加",
"addSshKeyTip": "新しい公開鍵/秘密鍵ペアを生成します",
"name": "名前",
"nameRule": "A-Z 0-9 _ - のみを含む",
"passphrase": "パスフレーズ",
"passphraseShort": "パスフレーズが短すぎます",
"optional": "任意",
"cancel": "中止",
"generate": "キーを生成",
"noSshKeys": "SSHキーがありません",
"copyPublicKey": "公開鍵をクリップボードにコピー",
"delete": "キーを削除",
"gitConfig": "Git設定",
"deleteConfirm": "SSHキー __name__ を削除してもよいですか? 削除したSSHキーを元に戻すことはできません。"
},
"versionControl": {
"unstagedChanges": "ステージングされていない変更",
"stagedChanges": "ステージングされた変更",
"resolveConflicts": "コンフリクトの解決",
"head": "最新",
"staged": "ステージング",
"unstaged": "未ステージング",
"local": "ローカル",
"remote": "リモート",
"revert": "'__file__'への変更を本当に戻しますか?この操作は元に戻せません。",
"revertChanges": "変更を戻す",
"localChanges": "ローカルの変更",
"none": "なし",
"conflictResolve": "全てのコンフリクトが解消されました。マージを完了するため、変更をコミットしてください。",
"localFiles": "ローカルファイル",
"all": "全て",
"unmergedChanges": "マージされていない変更",
"abortMerge": "マージ中止",
"commit": "コミット",
"changeToCommit": "コミット対象とする変更",
"commitPlaceholder": "コミットメッセージを入力してください。",
"cancelCapital": "キャンセル",
"commitCapital": "コミット",
"commitHistory": "コミット履歴",
"branch": "ブランチ:",
"moreCommits": "個のコミット",
"changeLocalBranch": "ローカルブランチの変更",
"createBranchPlaceholder": "ブランチの検索または作成",
"upstream": "アップストリーム",
"localOverwrite": "ブランチの変更によって上書きされたローカルの変更があります。これらの変更を先にコミットするか、あるいは元に戻さなければなりません。",
"manageRemoteBranch": "リモートブランチの管理",
"unableToAccess": "リモートのリポジトリにアクセスできません。",
"retry": "リトライ",
"setUpstreamBranch": "アップストリームとして設定する",
"createRemoteBranchPlaceholder": "リモートブランチの検索または作成",
"trackedUpstreamBranch": "作成されたブランチは、トラッキングされたアップストリームブランチとなります。",
"selectUpstreamBranch": "ブランチが作成されました。トラッキングするアップストリームブランチを選択してください。",
"pushFailed": "リモートに新しいコミットがあるため、プッシュに失敗しました。プルしてマージしてから、再度プッシュしてください。",
"push": "プッシュ",
"pull": "プル",
"unablePull": "<p>リモートの変更のプル失敗:ステージングされていないローカルの変更を上書きされてしまいます。</p><p>変更をコミットしてから再度実行してください。</p>",
"showUnstagedChanges": "ステージングされていない変更を表示",
"connectionFailed": "リモートリポジトリに接続できません: ",
"pullUnrelatedHistory": "<p>リモートに関連のないコミット履歴があります。</p><p>本当に変更をプルしてローカルリポジトリに反映しますか?</p>",
"pullChanges": "プル変更",
"history": "履歴",
"plural": "",
"daysAgo": "__count__ 日前",
"daysAgo_plural": "__count__ 日前",
"hoursAgo": "__count__ 時間前",
"hoursAgo_plural": "__count__ 時間前",
"minsAgo": "__count__ 分前",
"minsAgo_plural": "__count__ 分前",
"secondsAgo": "数秒前",
"notTracking": "ローカルブランチは現在リモートブランチをトラッキングしていません。",
"statusUnmergedChanged": "リポジトリ内にマージされていない変更があります。コンフリクトを解決してコミットしてください。",
"repositoryUpToDate": "リポジトリは最新です。",
"commitsAhead": "あなたのリポジトリはリモートより__count__コミット進んでいます。現在のコミットをプッシュできます。",
"commitsAhead_plural": "あなたのリポジトリはリモートより__count__コミット進んでいます。現在のコミットをプッシュできます。",
"commitsBehind": "あなたのリポジトリはリモートより__count__コミット遅れています。現在のコミットをプルできます。",
"commitsBehind_plural": "あなたのリポジトリはリモートより__count__コミット遅れています。現在のコミットをプルできます。",
"commitsAheadAndBehind1": "あなたのリポジトリはリモートより__count__コミット遅れており、かつ",
"commitsAheadAndBehind1_plural": "あなたのリポジトリはリモートより__count__コミット遅れており、かつ",
"commitsAheadAndBehind2": "__count__コミット進んでいます。 ",
"commitsAheadAndBehind2_plural": "__count__コミット進んでいます。 ",
"commitsAheadAndBehind3": "プッシュする前にリモートのコミットをプルしてください。",
"commitsAheadAndBehind3_plural": "プッシュする前にリモートのコミットをプルしてください。"
}
} }
}, },
"typedInput": { "typedInput": {
@ -476,5 +641,167 @@
"modeString": "UTF-8文字列として処理", "modeString": "UTF-8文字列として処理",
"modeArray": "JSON配列として処理", "modeArray": "JSON配列として処理",
"modeDesc": "<h3>バッファエディタ</h3><p>バッファ型は、バイト値から成るJSON配列として格納されます。このエディタは、入力値をJSON配列として構文解析します。もし不正なJSON配列の場合、UTF-8文字列として扱い、各文字コード番号から成る配列へ変換します。</p><p>例えば、 <code>Hello World</code> という値を、以下のJSON配列へ変換します。<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>" "modeDesc": "<h3>バッファエディタ</h3><p>バッファ型は、バイト値から成るJSON配列として格納されます。このエディタは、入力値をJSON配列として構文解析します。もし不正なJSON配列の場合、UTF-8文字列として扱い、各文字コード番号から成る配列へ変換します。</p><p>例えば、 <code>Hello World</code> という値を、以下のJSON配列へ変換します。<pre>[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]</pre></p>"
},
"projects": {
"config-git": "Gitクライアントの設定",
"welcome": {
"hello": "こんにちは! Node-REDで「プロジェクト」機能が利用できるようになりました。",
"desc0": "フローファイルの管理方法が刷新され、バージョン管理も可能です。",
"desc1": "まず最初にプロジェクトを作成するか、既存のGitリポジトリからプロジェクトをクローンしてください。",
"desc2": "とりあえずこの処理をスキップしてもかまいません。「プロジェクト」メニューから、いつでもプロジェクトの作成を開始できます。",
"create": "プロジェクトの作成",
"clone": "プロジェクトのクローン",
"not-right-now": "後にする"
},
"git-config": {
"setup": "バージョン管理クライアントの設定",
"desc0": "Node-REDはオープンソースツールのGitを使ってバージョン管理を行います。Gitによりプロジェクトファイルに対する変化を記録し、外部リポジトリに保存することができます。",
"desc1": "変更をコミットする際、変更を行った人物の情報としてユーザ名とEmailアドレスをGitが記憶します。ユーザ名は本名でなくても構いません。好きな名前を使ってください。",
"desc2": "Gitクライアントの現在の設定は以下の通りです。",
"desc3": "設定ダイアログの「Git設定」タブから別途変更することもできます。",
"username": "ユーザ名",
"email": "Email"
},
"project-details": {
"create": "プロジェクトの作成",
"desc0": "プロジェクトはGitリポジトリとして管理します。Gitリポジトリを使ってフローの共有やコラボレーションが簡単にできます。",
"desc1": "複数のプロジェクトを作成し、エディタから即座に変更できます。",
"desc2": "まず、プロジェクト名と説明(任意)を指定してください。",
"already-exists": "既に存在するプロジェクトです",
"must-contain": "A-Z 0-9 _ - のみ指定可能",
"project-name": "プロジェクト名",
"desc": "説明",
"opt": "任意"
},
"clone-project": {
"clone": "プロジェクトをクローン",
"desc0": "プロジェクトを含んだGitリポジトリを作成済みの場合、クローンを作成することができます。",
"already-exists": "既に存在するプロジェクトです",
"must-contain": "A-Z 0-9 _ - のみ指定可能",
"project-name": "プロジェクト名",
"no-info-in-url": "URLにユーザ名/パスワードを含めないようにしてください",
"git-url": "GitリポジトリのURL",
"protocols": "https://, ssh:// もしくは file://",
"auth-failed": "認証に失敗しました",
"username": "ユーザ名",
"passwd": "パスワード",
"ssh-key": "SSHキー",
"passphrase": "パスフレーズ",
"ssh-key-desc": "SSHでリポジトリをクローンする前にSSHキーを追加してください。",
"ssh-key-add": "SSHキーの追加",
"credential-key": "認証情報の暗号化キー",
"cant-get-ssh-key": "エラー! 選択したSSHキーのパスを取得できません。",
"already-exists": "既に存在します",
"git-error": "Gitエラー",
"connection-failed": "接続に失敗しました",
"not-git-repo": "Gitリポジトリではありません",
"repo-not-found": "リポジトリが見つかりません"
},
"default-files": {
"create": "プロジェクト関連ファアイルの作成",
"desc0": "プロジェクトはフローファイル、README、package.jsonを含みます。",
"desc1": "その他、Gitリポジトリで管理したいファイルを含めても構いません。",
"desc2": "既存のフローと認証情報ファイルをプロジェクトにコピーします。",
"flow-file": "フローファイル",
"credentials-file": "認証情報ファイル"
},
"encryption-config": {
"setup": "認証情報ファイルの暗号化設定",
"desc0": "フロー認証情報ファイルを暗号化して内容の安全性を担保できます。",
"desc1": "認証情報を公開Gitリポジトリに保存する際には、秘密キーフレーズによって暗号化します。",
"desc2": "認証情報ファイルは暗号化されていません。",
"desc3": "パスワードやアクセストークンといった認証情報を他人が参照できます。",
"desc4": "認証情報を公開Gitリポジトリに保存する際には、秘密キーフレーズによって暗号化します。",
"desc5": "フロー認証情報ファイルはsettingsファイルのcredentialSecretプロパティで暗号化されています。",
"desc6": "フロー認証情報ファイルはシステムが生成したキーによって暗号化されています。このプロジェクト用に新しい秘密キーを指定してください。",
"desc7": "キーはプロジェクトファイルとば別に保存されます。他のNode-REDでこのプロジェクトを利用するには、このプロジェクトのキーが必要です。",
"credentials": "認証情報",
"enable": "暗号化を有効にする",
"disable": "暗号化を無効にする",
"disabled": "無効",
"copy": "既存のキーをコピー",
"use-custom": "カスタムキーを使用",
"desc8": "認証情報ファイルが暗号化されないため、簡単に読み出すことができます。",
"create-project-files": "プロジェクト関連ファイル作成",
"create-project": "プロジェクト作成",
"already-exists": "既に存在",
"git-error": "Gitエラー",
"git-auth-error": "Git認証エラー"
},
"create-success": {
"success": "最初のプロジェクトの作成が成功しました!",
"desc0": "以降は、これまでと同様にNode-REDを利用できます。",
"desc1": "サイドバーの「情報」タブに現在選択されたプロジェクトを表示します。プロジェクト名の隣のボタンでプロジェクト設定画面を呼び出すことができます。",
"desc2": "サイドバーの「履歴」タブで変更が加えられたプロジェクト内のファイルを確認しコミットできます。このサイドバーでは、全てのコミット履歴を確認し、変更を外部リポジトリにプッシュすることが可能です。"
},
"create": {
"projects": "プロジェクト",
"already-exists": "プロジェクトは既に存在します",
"must-contain": "A-Z 0-9 _ - のみ指定可能",
"no-info-in-url": "URLにユーザ名/パスワードを含めないようにしてください",
"open": "プロジェクトを開く",
"create": "プロジェクトを作成",
"clone": "プロジェクトをクローン",
"project-name": "プロジェクト名",
"desc": "説明",
"opt": "任意",
"flow-file": "フローファイル",
"credentials": "認証情報",
"enable-encryption": "暗号化を有効にする",
"disable-encryption": "暗号化を無効にする",
"encryption-key": "暗号化キー",
"desc0": "認証情報をセキュアにするためのフレーズ",
"desc1": "認証情報ファイルが暗号化されないため、簡単に読み出すことができます",
"git-url": "GitリポジトリのURL",
"protocols": "https://, ssh:// もしくは file://",
"auth-failed": "認証に失敗しました",
"username": "ユーザ名",
"password": "パスワード",
"ssh-key": "SSHキー",
"passphrase": "パスフレーズ",
"desc2": "SSHでリポジトリをクローンする前にSSHキーを追加してください。",
"add-ssh-key": "SSHキーの追加",
"credentials-encryption-key": "認証情報の暗号化キー",
"already-exists-2": "既に存在します",
"git-error": "Gitエラー",
"con-failed": "接続に失敗しました",
"not-git": "Gitリポジトリではありません",
"no-resource": "リポジトリが見つかりません",
"cant-get-ssh-key-path": "エラー! 選択したSSHキーのパスを取得できません。",
"unexpected_error": "予期しないエラー"
},
"delete": {
"confirm": "プロジェクトを削除しても良いですか?"
},
"create-project-list": {
"search": "プロジェクトを検索",
"current": "有効"
},
"require-clean": {
"confirm": "<p>デプロイされていない変更は失われます。</p><p>続けますか?</p>"
},
"send-req": {
"auth-req": "リポジトリ対する認証が必要です",
"username": "ユーザ名",
"password": "パスワード",
"passphrase": "パスフレーズ",
"update-failed": "認証の更新に失敗しました",
"unhandled": "エラー応答が処理されませんでした"
},
"create-branch-list": {
"invalid": "不正なブランチ",
"create": "ブランチの作成",
"current": "有効"
},
"create-default-file-set": {
"no-active": "有効なプロジェクトが無い場合、デフォルトのファイル群を作成できません。",
"no-empty": "デフォルトのファイル群を空でないプロジェクトに作成することはできません。",
"git-error": "Gitエラー"
},
"errors" : {
"no-username-email": "Gitクライアントのユーザ名/emailが設定されていません。",
"unexpected": "予期しないエラーが発生しました",
"code": "コード"
}
} }
} }

View File

@ -150,7 +150,9 @@
"disabled": "Projects disabled : editorTheme.projects.enabled=false", "disabled": "Projects disabled : editorTheme.projects.enabled=false",
"disabledNoFlag": "Projects disabled : set editorTheme.projects.enabled=true to enable", "disabledNoFlag": "Projects disabled : set editorTheme.projects.enabled=true to enable",
"git-not-found": "Projects disabled : git command not found", "git-not-found": "Projects disabled : git command not found",
"git-version-old": "Projects disabled : git __version__ not supported. Requires 2.x" "git-version-old": "Projects disabled : git __version__ not supported. Requires 2.x",
"summary": "A Node-RED Project",
"readme": "### About\n\nThis is your project's README.md file. It helps users understand what your\nproject does, how to use it and anything else they may need to know."
} }
} }
} }

View File

@ -0,0 +1,10 @@
{
"storage": {
"localfilesystem": {
"projects": {
"summary": "Node-REDプロジェクト",
"readme": "### 説明\nこれはプロジェクトのREADME.mdファイルです。このファイルには、\nプロジェクトの説明、利用方法、その他の情報を記載します。"
}
}
}
}

View File

@ -480,11 +480,19 @@ function addFlow(flow) {
} }
flow.id = redUtil.generateId(); flow.id = redUtil.generateId();
var nodes = [{ var tabNode = {
type:'tab', type:'tab',
label:flow.label, label:flow.label,
id:flow.id id:flow.id
}]; }
if (flow.hasOwnProperty('info')) {
tabNode.info = flow.info;
}
if (flow.hasOwnProperty('disabled')) {
tabNode.disabled = flow.disabled;
}
var nodes = [tabNode];
for (i=0;i<flow.nodes.length;i++) { for (i=0;i<flow.nodes.length;i++) {
node = flow.nodes[i]; node = flow.nodes[i];
@ -537,6 +545,12 @@ function getFlow(id) {
if (flow.label) { if (flow.label) {
result.label = flow.label; result.label = flow.label;
} }
if (flow.disabled) {
result.disabled = flow.disabled;
}
if (flow.hasOwnProperty('info')) {
result.info = flow.info;
}
if (id !== 'global') { if (id !== 'global') {
result.nodes = []; result.nodes = [];
} }
@ -626,6 +640,13 @@ function updateFlow(id,newFlow) {
label:newFlow.label, label:newFlow.label,
id:id id:id
} }
if (newFlow.hasOwnProperty('info')) {
tabNode.info = newFlow.info;
}
if (newFlow.hasOwnProperty('disabled')) {
tabNode.disabled = newFlow.disabled;
}
nodes = [tabNode].concat(newFlow.nodes||[]).concat(newFlow.configs||[]); nodes = [tabNode].concat(newFlow.nodes||[]).concat(newFlow.configs||[]);
nodes.forEach(function(n) { nodes.forEach(function(n) {
n.z = id; n.z = id;

View File

@ -25,6 +25,8 @@ var storageModule;
var settingsAvailable; var settingsAvailable;
var sessionsAvailable; var sessionsAvailable;
var libraryFlowsCachedResult = null;
function moduleSelector(aSettings) { function moduleSelector(aSettings) {
var toReturn; var toReturn;
if (aSettings.storageModule) { if (aSettings.storageModule) {
@ -156,7 +158,14 @@ var storageModuleInterface = {
if (storageModule.hasOwnProperty("getAllFlows")) { if (storageModule.hasOwnProperty("getAllFlows")) {
return storageModule.getAllFlows(); return storageModule.getAllFlows();
} else { } else {
return listFlows("/"); if (libraryFlowsCachedResult) {
return Promise.resolve(libraryFlowsCachedResult);
} else {
return listFlows("/").then(function(result) {
libraryFlowsCachedResult = result;
return result;
});
}
} }
}, },
getFlow: function(fn) { getFlow: function(fn) {
@ -178,6 +187,7 @@ var storageModuleInterface = {
err.code = "forbidden"; err.code = "forbidden";
return when.reject(err); return when.reject(err);
} }
libraryFlowsCachedResult = null;
if (storageModule.hasOwnProperty("saveFlow")) { if (storageModule.hasOwnProperty("saveFlow")) {
return storageModule.saveFlow(fn, data); return storageModule.saveFlow(fn, data);
} else { } else {

View File

@ -162,7 +162,7 @@ Project.prototype.initialise = function(user,data) {
if (defaultFileSet.hasOwnProperty(file)) { if (defaultFileSet.hasOwnProperty(file)) {
var path = fspath.join(project.path,file); var path = fspath.join(project.path,file);
if (!fs.existsSync(path)) { if (!fs.existsSync(path)) {
promises.push(util.writeFile(path,defaultFileSet[file](project))); promises.push(util.writeFile(path,defaultFileSet[file](project, runtime)));
} }
} }
@ -850,7 +850,7 @@ function createDefaultProject(user, project) {
} }
for (var file in defaultFileSet) { for (var file in defaultFileSet) {
if (defaultFileSet.hasOwnProperty(file)) { if (defaultFileSet.hasOwnProperty(file)) {
promises.push(util.writeFile(fspath.join(projectPath,file),defaultFileSet[file](project))); promises.push(util.writeFile(fspath.join(projectPath,file),defaultFileSet[file](project, runtime)));
} }
} }

View File

@ -15,10 +15,11 @@
**/ **/
module.exports = { module.exports = {
"package.json": function(project) { "package.json": function(project, runtime) {
var i18n = runtime.i18n;
var package = { var package = {
"name": project.name, "name": project.name,
"description": project.summary||"A Node-RED Project", "description": project.summary||i18n._("storage.localfilesystem.projects.summary"),
"version": "0.0.1", "version": "0.0.1",
"dependencies": {}, "dependencies": {},
"node-red": { "node-red": {
@ -34,13 +35,13 @@ module.exports = {
} }
return JSON.stringify(package,"",4); return JSON.stringify(package,"",4);
}, },
"README.md": function(project) { "README.md": function(project, runtime) {
var i18n = runtime.i18n;
var content = project.name+"\n"+("=".repeat(project.name.length))+"\n\n"; var content = project.name+"\n"+("=".repeat(project.name.length))+"\n\n";
if (project.summary) { if (project.summary) {
content += project.summary+"\n\n"; content += project.summary+"\n\n";
} }
content += "### About\n\nThis is your project's README.md file. It helps users understand what your\nproject does, how to use it and anything else they may need to know."; content += i18n._("storage.localfilesystem.projects.readme");
return content; return content;
}, },
".gitignore": function() { return "*.backup" ;} ".gitignore": function() { return "*.backup" ;}

View File

@ -84,17 +84,33 @@ var MessageFileLoader = {
} }
function getCurrentLocale() {
var env = process.env;
for (var name of ['LC_ALL', 'LC_MESSAGES', 'LANG']) {
if (name in env) {
var val = env[name];
return val.substring(0, 2);
}
}
return undefined;
}
function init() { function init() {
if (!initPromise) { if (!initPromise) {
initPromise = when.promise(function(resolve,reject) { initPromise = when.promise(function(resolve,reject) {
i18n.backend(MessageFileLoader); i18n.backend(MessageFileLoader);
i18n.init({ var opt = {
ns: { ns: {
namespaces: [], namespaces: [],
defaultNs: "runtime" defaultNs: "runtime"
}, },
fallbackLng: [defaultLang] fallbackLng: [defaultLang]
},function() { };
var lang = getCurrentLocale();
if (lang) {
opt.lng = lang;
}
i18n.init(opt,function() {
resolve(); resolve();
}); });
}); });

View File

@ -536,6 +536,21 @@ describe('function node', function() {
}); });
}); });
it('should use the same Date object from outside the sandbox', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.get('typeTest')(new Date());return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().global.set("typeTest",function(d) { return d instanceof Date });
n2.on("input", function(msg) {
msg.should.have.property('payload', true);
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
describe('Logger', function () { describe('Logger', function () {
it('should log an Info Message', function (done) { it('should log an Info Message', function (done) {
var flow = [{id: "n1", type: "function", wires: [["n2"]], func: "node.log('test');"}]; var flow = [{id: "n1", type: "function", wires: [["n2"]], func: "node.log('test');"}];

View File

@ -428,13 +428,14 @@ describe('trigger node', function() {
n2.on("input", function(msg) { n2.on("input", function(msg) {
try { try {
if (c === 0) { if (c === 0) {
console.log(c,Date.now() - ss,msg);
msg.should.have.a.property("payload", "Hello"); msg.should.have.a.property("payload", "Hello");
c += 1; c += 1;
} }
else { else {
console.log(c,Date.now() - ss,msg);
msg.should.have.a.property("payload", "World"); msg.should.have.a.property("payload", "World");
//console.log(Date.now() - ss); (Date.now() - ss).should.be.greaterThan(150);
(Date.now() - ss).should.be.greaterThan(140);
done(); done();
} }
} }
@ -444,7 +445,7 @@ describe('trigger node', function() {
n1.emit("input", {payload:"Hello"}); n1.emit("input", {payload:"Hello"});
setTimeout( function() { setTimeout( function() {
n1.emit("input", {payload:"Error"}); n1.emit("input", {payload:"Error"});
},20); },30);
setTimeout( function() { setTimeout( function() {
n1.emit("input", {payload:"World"}); n1.emit("input", {payload:"World"});
},150); },150);

View File

@ -796,6 +796,25 @@ describe('HTTP Request Node', function() {
}); });
}); });
it('should prevent following redirect when msg.followRedirects is false', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"txt",url:getTestURL('/redirectToText')},
{id:"n2", type:"helper"}];
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('statusCode',302);
msg.should.have.property('responseUrl', getTestURL('/redirectToText'));
done();
} catch(err) {
done(err);
}
});
n1.receive({payload:"foo",followRedirects:false});
});
});
it('shuold output an error when request timeout occurred', function(done) { it('shuold output an error when request timeout occurred', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/timeout')}, var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/timeout')},
{id:"n2", type:"helper"}]; {id:"n2", type:"helper"}];
@ -806,7 +825,13 @@ describe('HTTP Request Node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
n2.on("input", function(msg) { n2.on("input", function(msg) {
try { try {
msg.should.have.property('statusCode','ECONNRESET'); msg.should.have.property('statusCode','ESOCKETTIMEDOUT');
var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == 'http request';
});
logEvents.should.have.length(1);
var tstmp = logEvents[0][0].timestamp;
logEvents[0][0].should.eql({level:helper.log().ERROR, id:'n1',type:'http request',msg:'common.notification.errors.no-response', timestamp:tstmp});
done(); done();
} catch(err) { } catch(err) {
done(err); done(err);

View File

@ -197,8 +197,7 @@ describe("api/auth/users", function() {
it('should fail to return user fred',function(done) { it('should fail to return user fred',function(done) {
Users.get("fred").then(function(userf) { Users.get("fred").then(function(userf) {
try { try {
userf.should.not.have.a.property("username","fred"); should.not.exist(userf);
userf.should.not.have.a.property("permissions","*");
done(); done();
} catch(err) { } catch(err) {
done(err); done(err);
@ -215,6 +214,9 @@ describe("api/auth/users", function() {
default: function() { return("Done"); } default: function() { return("Done"); }
}); });
}); });
after(function() {
Users.init({});
});
describe('#default',function() { describe('#default',function() {
it('handles api.default being a function',function(done) { it('handles api.default being a function',function(done) {
Users.should.have.property('default').which.is.a.Function(); Users.should.have.property('default').which.is.a.Function();

View File

@ -540,7 +540,7 @@ describe("red/nodes/registry/registry",function() {
} }
},icons: [{path:testIcon,icons:['test_icon.png']}]}); },icons: [{path:testIcon,icons:['test_icon.png']}]});
var iconPath = typeRegistry.getNodeIconPath('test-module','test_icon.png'); var iconPath = typeRegistry.getNodeIconPath('test-module','test_icon.png');
iconPath.should.eql(testIcon+"/test_icon.png"); iconPath.should.eql(path.resolve(testIcon+"/test_icon.png"));
}); });
it('returns the debug icon when getting an unknown module', function() { it('returns the debug icon when getting an unknown module', function() {

View File

@ -19,6 +19,13 @@ var should = require("should");
var defaultFileSet = require("../../../../../../red/runtime/storage/localfilesystem/projects/defaultFileSet"); var defaultFileSet = require("../../../../../../red/runtime/storage/localfilesystem/projects/defaultFileSet");
describe('storage/localfilesystem/projects/defaultFileSet', function() { describe('storage/localfilesystem/projects/defaultFileSet', function() {
var runtime = {
i18n: {
"_": function(name) {
return name;
}
}
};
it('generates package.json for a project', function() { it('generates package.json for a project', function() {
var generated = defaultFileSet["package.json"]({ var generated = defaultFileSet["package.json"]({
name: "A TEST NAME", name: "A TEST NAME",
@ -27,7 +34,7 @@ describe('storage/localfilesystem/projects/defaultFileSet', function() {
flow: "MY FLOW FILE", flow: "MY FLOW FILE",
credentials: "MY CREDENTIALS FILE" credentials: "MY CREDENTIALS FILE"
} }
}); }, runtime);
var parsed = JSON.parse(generated); var parsed = JSON.parse(generated);
parsed.should.have.property('name',"A TEST NAME"); parsed.should.have.property('name',"A TEST NAME");
@ -42,7 +49,7 @@ describe('storage/localfilesystem/projects/defaultFileSet', function() {
var generated = defaultFileSet["README.md"]({ var generated = defaultFileSet["README.md"]({
name: "A TEST NAME", name: "A TEST NAME",
summary: "A TEST SUMMARY" summary: "A TEST SUMMARY"
}); }, runtime);
generated.should.match(/A TEST NAME/); generated.should.match(/A TEST NAME/);
generated.should.match(/A TEST SUMMARY/); generated.should.match(/A TEST SUMMARY/);
}); });
@ -50,7 +57,7 @@ describe('storage/localfilesystem/projects/defaultFileSet', function() {
var generated = defaultFileSet[".gitignore"]({ var generated = defaultFileSet[".gitignore"]({
name: "A TEST NAME", name: "A TEST NAME",
summary: "A TEST SUMMARY" summary: "A TEST SUMMARY"
}); }, runtime);
generated.length.should.be.greaterThan(0); generated.length.should.be.greaterThan(0);
}); });
}); });