/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.projects = (function() {
var dialog;
var dialogBody;
var activeProject;
function reportUnexpectedError(error) {
var notification;
if (error.error === 'git_missing_user') {
notification = RED.notify("
You Git client is not configured with a username/email.
code: "+error.error+"",{
fixed: true,
modal: true,
type: 'error',
buttons: [
{
text: "Close",
click: function() {
notification.close();
}
}
]
})
}
}
var screens = {};
function initScreens() {
var migrateProjectHeader = $('');
$('').appendTo(migrateProjectHeader)
$('').appendTo(migrateProjectHeader);
var createProjectOptions = {};
screens = {
'welcome': {
content: function(options) {
var container = $('');
migrateProjectHeader.appendTo(container);
var body = $('').appendTo(container);
$('
').text("Hello! We have introduced 'projects' to Node-RED.").appendTo(body);
$('
').text("This is a new way for you to manage your flow files and includes version control of your flows.").appendTo(body);
$('
').text("To get started you can create your first project or clone an existing project from a git repository.").appendTo(body);
$('
').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);
var row = $('
').appendTo(body);
var createAsEmpty = $('').appendTo(row);
var createAsClone = $('').appendTo(row);
createAsEmpty.click(function(e) {
e.preventDefault();
createProjectOptions = {
action: "create"
}
show('git-config');
})
createAsClone.click(function(e) {
e.preventDefault();
createProjectOptions = {
action: "clone"
}
show('git-config');
})
return container;
},
buttons: [
{
// id: "clipboard-dialog-cancel",
text: "Not right now",
click: function() {
createProjectOptions = {};
$( this ).dialog( "close" );
}
}
]
},
'git-config': (function() {
var gitUsernameInput;
var gitEmailInput;
return {
content: function(options) {
var isGlobalConfig = false;
var existingGitSettings = RED.settings.get('git');
if (existingGitSettings && existingGitSettings.user) {
existingGitSettings = existingGitSettings.user;
} else if (RED.settings.git && RED.settings.git.globalUser) {
isGlobalConfig = true;
existingGitSettings = RED.settings.git.globalUser;
}
var validateForm = function() {
var name = gitUsernameInput.val().trim();
var email = gitEmailInput.val().trim();
var valid = name.length > 0 && email.length > 0;
$("#projects-dialog-git-config").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
}
var container = $('');
migrateProjectHeader.appendTo(container);
var body = $('').appendTo(container);
$('
').text("Setup your version control client").appendTo(body);
$('
').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);
$('
').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);
if (isGlobalConfig) {
$('
').text("Your Git client is already configured with the details below.").appendTo(body);
}
$('
').text("You can change these settings later under the 'Git config' tab of the settings dialog.").appendTo(body);
var row = $('
').appendTo(body);
$('').appendTo(row);
gitUsernameInput = $('').val((existingGitSettings&&existingGitSettings.name)||"").appendTo(row);
// $('').text("This does not need to be your real name").appendTo(row);
gitUsernameInput.on("change keyup paste",validateForm);
row = $('').appendTo(body);
$('').appendTo(row);
gitEmailInput = $('').val((existingGitSettings&&existingGitSettings.email)||"").appendTo(row);
gitEmailInput.on("change keyup paste",validateForm);
// $('').text("Something something email").appendTo(row);
setTimeout(function() {
gitUsernameInput.focus();
validateForm();
},50);
return container;
},
buttons: [
{
// id: "clipboard-dialog-cancel",
text: "Back",
click: function() {
show('welcome');
}
},
{
id: "projects-dialog-git-config",
text: "Next", // TODO: nls
class: "primary",
click: function() {
var currentGitSettings = RED.settings.get('git') || {};
currentGitSettings.user = currentGitSettings.user || {};
currentGitSettings.user.name = gitUsernameInput.val();
currentGitSettings.user.email = gitEmailInput.val();
RED.settings.set('git', currentGitSettings);
if (createProjectOptions.action === "create") {
show('project-details');
} else if (createProjectOptions.action === "clone") {
show('clone-project');
}
}
}
]
};
})(),
'project-details': (function() {
var projectNameInput;
var projectSummaryInput;
return {
content: function(options) {
var projectList = null;
var projectNameValid;
var pendingFormValidation = false;
$.getJSON("projects", function(data) {
projectList = {};
data.projects.forEach(function(p) {
projectList[p] = true;
if (pendingFormValidation) {
pendingFormValidation = false;
validateForm();
}
})
});
var container = $('');
migrateProjectHeader.appendTo(container);
var body = $('').appendTo(container);
$('
').text("Create your project").appendTo(body);
$('
').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);
$('
').text("You can create multiple projects and quickly switch between them from the editor.").appendTo(body);
$('
').text("To begin, your project needs a name and an optional description.").appendTo(body);
var validateForm = function() {
var projectName = projectNameInput.val();
var valid = true;
if (projectNameInputChanged) {
if (projectList === null) {
pendingFormValidation = true;
return;
}
projectNameStatus.empty();
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName) || projectList[projectName]) {
projectNameInput.addClass("input-error");
$('').appendTo(projectNameStatus);
projectNameValid = false;
valid = false;
if (projectList[projectName]) {
projectNameSublabel.text("Project already exists");
} else {
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
}
} else {
projectNameInput.removeClass("input-error");
$('').appendTo(projectNameStatus);
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
projectNameValid = true;
}
projectNameLastChecked = projectName;
}
valid = projectNameValid;
$("#projects-dialog-create-name").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
}
var row = $('
').appendTo(body);
$('').appendTo(row);
var subrow = $('').appendTo(row);
projectNameInput = $('').val(createProjectOptions.name||"").appendTo(subrow);
var projectNameStatus = $('').appendTo(subrow);
var projectNameInputChanged = false;
var projectNameLastChecked = "";
var projectNameValid;
var checkProjectName;
var autoInsertedName = "";
projectNameInput.on("change keyup paste",function() {
projectNameInputChanged = (projectNameInput.val() !== projectNameLastChecked);
if (checkProjectName) {
clearTimeout(checkProjectName);
} else if (projectNameInputChanged) {
projectNameStatus.empty();
$('').appendTo(projectNameStatus);
if (projectNameInput.val() === '') {
validateForm();
return;
}
}
checkProjectName = setTimeout(function() {
validateForm();
checkProjectName = null;
},300)
});
projectNameSublabel = $('').appendTo(row).find("small");
// Empty Project
row = $('').appendTo(body);
$('').appendTo(row);
projectSummaryInput = $('').val(createProjectOptions.summary||"").appendTo(row);
$('').appendTo(row);
setTimeout(function() {
projectNameInput.focus();
projectNameInput.change();
},50);
return container;
},
buttons: function(options) {
return [
{
text: "Back",
click: function() {
show('git-config');
}
},
{
id: "projects-dialog-create-name",
disabled: true,
text: "Next", // TODO: nls
class: "primary disabled",
click: function() {
createProjectOptions.name = projectNameInput.val();
createProjectOptions.summary = projectSummaryInput.val();
show('default-files', options);
}
}
]
}
};
})(),
'clone-project': (function() {
var projectNameInput;
var projectSummaryInput;
var projectFlowFileInput;
var projectSecretInput;
var projectSecretSelect;
var copyProject;
var projectRepoInput;
var projectCloneSecret;
var emptyProjectCredentialInput;
var projectRepoUserInput;
var projectRepoPasswordInput;
var projectNameSublabel;
var projectRepoSSHKeySelect;
var projectRepoPassphrase;
var projectRepoRemoteName
var projectRepoBranch;
var selectedProject;
return {
content: function(options) {
var container = $('');
migrateProjectHeader.appendTo(container);
var body = $('').appendTo(container);
$('
').text("Clone a project").appendTo(body);
$('
').text("If you already have a git repository containing a project, you can clone it to get started.").appendTo(body);
var projectList = null;
var pendingFormValidation = false;
$.getJSON("projects", function(data) {
projectList = {};
data.projects.forEach(function(p) {
projectList[p] = true;
if (pendingFormValidation) {
pendingFormValidation = false;
validateForm();
}
})
});
var validateForm = function() {
var projectName = projectNameInput.val();
var valid = true;
if (projectNameInputChanged) {
if (projectList === null) {
pendingFormValidation = true;
return;
}
projectNameStatus.empty();
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName) || projectList[projectName]) {
projectNameInput.addClass("input-error");
$('').appendTo(projectNameStatus);
projectNameValid = false;
valid = false;
if (projectList[projectName]) {
projectNameSublabel.text("Project already exists");
} else {
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
}
} else {
projectNameInput.removeClass("input-error");
$('').appendTo(projectNameStatus);
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
projectNameValid = true;
}
projectNameLastChecked = projectName;
}
valid = projectNameValid;
var repo = projectRepoInput.val();
// var validRepo = /^(?:file|git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
var validRepo = repo.length > 0 && !/\s/.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");
validRepo = false;
}
if (!validRepo) {
if (projectRepoChanged) {
projectRepoInput.addClass("input-error");
}
valid = false;
} else {
projectRepoInput.removeClass("input-error");
}
if (/^https?:\/\//.test(repo)) {
$(".projects-dialog-screen-create-row-creds").show();
$(".projects-dialog-screen-create-row-sshkey").hide();
} else if (/^(?:ssh|[\S]+?@[\S]+?):(?:\/\/)?/.test(repo)) {
$(".projects-dialog-screen-create-row-creds").hide();
$(".projects-dialog-screen-create-row-sshkey").show();
// if ( !getSelectedSSHKey(projectRepoSSHKeySelect) ) {
// valid = false;
// }
} else {
$(".projects-dialog-screen-create-row-creds").hide();
$(".projects-dialog-screen-create-row-sshkey").hide();
}
$("#projects-dialog-clone-project").prop('disabled',!valid).toggleClass('disabled ui-button-disabled ui-state-disabled',!valid);
}
var row;
row = $('
').appendTo(body);
$('').appendTo(row);
var subrow = $('').appendTo(row);
projectNameInput = $('').appendTo(subrow);
var projectNameStatus = $('').appendTo(subrow);
var projectNameInputChanged = false;
var projectNameLastChecked = "";
var projectNameValid;
var checkProjectName;
var autoInsertedName = "";
projectNameInput.on("change keyup paste",function() {
projectNameInputChanged = (projectNameInput.val() !== projectNameLastChecked);
if (checkProjectName) {
clearTimeout(checkProjectName);
} else if (projectNameInputChanged) {
projectNameStatus.empty();
$('').appendTo(projectNameStatus);
if (projectNameInput.val() === '') {
validateForm();
return;
}
}
checkProjectName = setTimeout(function() {
validateForm();
checkProjectName = null;
},300)
});
projectNameSublabel = $('').appendTo(row).find("small");
row = $('').appendTo(body);
$('').appendTo(row);
projectRepoInput = $('').appendTo(row);
$('').appendTo(row);
var projectRepoChanged = false;
var lastProjectRepo = "";
projectRepoInput.on("change keyup paste",function() {
projectRepoChanged = true;
var repo = $(this).val();
if (lastProjectRepo !== repo) {
$("#projects-dialog-screen-create-project-repo-label small").text("https://, ssh:// or file://");
}
lastProjectRepo = repo;
var m = /\/([^/]+?)(?:\.git)?$/.exec(repo);
if (m) {
var projectName = projectNameInput.val();
if (projectName === "" || projectName === autoInsertedName) {
autoInsertedName = m[1];
projectNameInput.val(autoInsertedName);
projectNameInput.change();
}
}
validateForm();
});
var cloneAuthRows = $('').appendTo(body);
row = $('').hide().appendTo(cloneAuthRows);
$('