node-red/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js

1683 lines
84 KiB
JavaScript

/**
* 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.settings = (function() {
var trayWidth = 700;
var settingsVisible = false;
var panes = [];
function addPane(options) {
panes.push(options);
}
// TODO: DRY - tab-info.js
function addTargetToExternalLinks(el) {
$(el).find("a").each(function(el) {
var href = $(this).attr('href');
if (/^https?:/.test(href)) {
$(this).attr('target','_blank');
}
});
return el;
}
function show(initialTab) {
if (settingsVisible) {
return;
}
if (!RED.user.hasPermission("projects.write")) {
RED.notify(RED._("user.errors.notAuthorized"),"error");
return;
}
settingsVisible = true;
var trayOptions = {
title: RED._("sidebar.project.projectSettings.title"),
buttons: [
{
id: "node-dialog-ok",
text: RED._("common.label.close"),
class: "primary",
click: function() {
RED.tray.close();
}
}
],
resize: function(dimensions) {
trayWidth = dimensions.width;
},
open: function(tray) {
var project = RED.projects.getActiveProject();
var trayBody = tray.find('.red-ui-tray-body');
var settingsContent = $('<div></div>').appendTo(trayBody);
var tabContainer = $('<div></div>',{class:"red-ui-settings-tabs-container"}).appendTo(settingsContent);
$('<ul></ul>',{id:"user-settings-tabs"}).appendTo(tabContainer);
var settingsTabs = RED.tabs.create({
id: "user-settings-tabs",
vertical: true,
onchange: function(tab) {
setTimeout(function() {
tabContents.children().hide();
$("#" + tab.id).show();
if (tab.pane.focus) {
tab.pane.focus();
}
},50);
}
});
var tabContents = $('<div></div>',{class:"red-ui-settings-tabs-content"}).appendTo(settingsContent);
panes.forEach(function(pane) {
settingsTabs.addTab({
id: "red-ui-project-settings-tab-"+pane.id,
label: pane.title,
pane: pane
});
pane.get(project).hide().appendTo(tabContents);
});
settingsContent.i18n();
settingsTabs.activateTab("red-ui-project-settings-tab-"+(initialTab||'main'))
$("#red-ui-sidebar-shade").show();
},
close: function() {
settingsVisible = false;
panes.forEach(function(pane) {
if (pane.close) {
pane.close();
}
});
$("#red-ui-sidebar-shade").hide();
},
show: function() {}
}
if (trayWidth !== null) {
trayOptions.width = trayWidth;
}
RED.tray.show(trayOptions);
}
function editDescription(activeProject, container) {
RED.editor.editMarkdown({
title: RED._('sidebar.project.editDescription'),
header: $('<span><i class="fa fa-book"></i> README.md</span>'),
value: activeProject.description,
stateId: "sidebar.project.editDescription",
complete: function(v) {
container.empty();
var spinner = utils.addSpinnerOverlay(container);
var done = function(err,res) {
if (err) {
return editDescription(activeProject, container);
}
activeProject.description = v;
updateProjectDescription(activeProject, container);
}
utils.sendRequest({
url: "projects/"+activeProject.name,
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
done(null,data);
RED.sidebar.versionControl.refresh(true);
},
400: {
'*': function(error) {
utils.reportUnexpectedError(error);
done(error,null);
}
},
}
},{description:v}).always(function() {
spinner.remove();
});
}
});
}
function updateProjectDescription(activeProject, container) {
container.empty();
var desc;
if (activeProject.description) {
desc = RED.utils.renderMarkdown(activeProject.description);
} else {
desc = '<span class="red-ui-help-info-none">' + RED._("sidebar.project.noDescriptionAvailable") + '</span>';
}
var description = addTargetToExternalLinks($('<span class="red-ui-text-bidi-aware" dir=\"'+RED.text.bidi.resolveBaseTextDir(desc)+'">'+desc+'</span>')).appendTo(container);
description.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "<span></span>" );
setTimeout(function () {
RED.editor.mermaid.render()
}, 200);
}
function editSummary(activeProject, summary, container, version, versionContainer) {
var editButton = container.prev();
editButton.hide();
container.empty();
versionContainer.empty();
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 versionInput = $('<input type="text" style="width: calc(100% - 150px); margin-right: 10px;">').val(version||"").appendTo(versionContainer);
$('<button class="red-ui-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(bg)
.on("click", function(evt) {
evt.preventDefault();
updateProjectSummary(activeProject.summary, container);
updateProjectVersion(activeProject.version, versionContainer);
editButton.show();
});
$('<button class="red-ui-button">' + RED._("common.label.save") + '</button>')
.appendTo(bg)
.on("click", function(evt) {
evt.preventDefault();
var newSummary = input.val();
var newVersion = versionInput.val();
updateProjectSummary(newSummary, container);
updateProjectVersion(newVersion, versionContainer);
var spinner = utils.addSpinnerOverlay(container).addClass('red-ui-component-spinner-contain');
var done = function(err,res) {
if (err) {
spinner.remove();
return editSummary(activeProject, summary, container, version, versionContainer);
}
activeProject.summary = newSummary;
activeProject.version = newVersion;
spinner.remove();
updateProjectSummary(activeProject.summary, container);
updateProjectVersion(activeProject.version, versionContainer);
editButton.show();
}
utils.sendRequest({
url: "projects/"+activeProject.name,
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
RED.sidebar.versionControl.refresh(true);
done(null,data);
},
400: {
'*': function(error) {
utils.reportUnexpectedError(error);
done(error,null);
}
},
}
},{summary:newSummary, version: newVersion});
});
}
function updateProjectSummary(summary, container) {
container.empty();
if (summary) {
container.text(summary).removeClass('red-ui-help-info-none');
} else {
container.text(RED._("sidebar.project.noSummaryAvailable")).addClass('red-ui-help-info-none');
}
}
function updateProjectVersion(version, container) {
container.empty();
if (version) {
container.text(version);
}
}
function createMainPane(activeProject) {
var pane = $('<div id="red-ui-project-settings-tab-main" class="red-ui-project-settings-tab-pane red-ui-help"></div>');
$('<h1>').text(activeProject.name).appendTo(pane);
var summary = $('<div style="position: relative">').appendTo(pane);
var summaryContent = $('<div></div>').appendTo(summary);
var versionContent = $('<div></div>').addClass('red-ui-help-info-none').appendTo(summary);
updateProjectSummary(activeProject.summary, summaryContent);
updateProjectVersion(activeProject.version, versionContent);
if (RED.user.hasPermission("projects.write")) {
$('<button class="red-ui-button red-ui-button-small" style="float: right;">' + RED._('sidebar.project.editDescription') + '</button>')
.prependTo(summary)
.on("click", function(evt) {
evt.preventDefault();
editSummary(activeProject, activeProject.summary, summaryContent, activeProject.version, versionContent);
});
}
$('<hr>').appendTo(pane);
var description = $('<div class="red-ui-help" style="position: relative"></div>').appendTo(pane);
var descriptionContent = $('<div>',{style:"min-height: 200px"}).appendTo(description);
updateProjectDescription(activeProject, descriptionContent);
if (RED.user.hasPermission("projects.write")) {
$('<button class="red-ui-button red-ui-button-small" style="float: right;">' + RED._('sidebar.project.editReadme') + '</button>')
.prependTo(description)
.on("click", function(evt) {
evt.preventDefault();
editDescription(activeProject, descriptionContent);
});
}
return pane;
}
function updateProjectDependencies(activeProject,depsList) {
depsList.editableList('empty');
var totalCount = 0;
var unknownCount = 0;
var unusedCount = 0;
var notInstalledCount = 0;
for (var m in modulesInUse) {
if (modulesInUse.hasOwnProperty(m)) {
depsList.editableList('addItem',{
id: modulesInUse[m].module,
version: modulesInUse[m].version,
count: modulesInUse[m].count,
known: activeProject.dependencies.hasOwnProperty(m),
installed: true
});
totalCount++;
if (modulesInUse[m].count === 0) {
unusedCount++;
}
if (!activeProject.dependencies.hasOwnProperty(m)) {
unknownCount++;
}
}
}
if (activeProject.dependencies) {
for (var m in activeProject.dependencies) {
if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) {
var installed = !!RED.nodes.registry.getModule(m);
depsList.editableList('addItem',{
id: m,
version: activeProject.dependencies[m], //RED.nodes.registry.getModule(module).version,
count: 0,
known: true,
installed: installed
});
totalCount++;
if (installed) {
unusedCount++;
} else {
notInstalledCount++;
}
}
}
}
// if (notInstalledCount > 0) {
// depsList.editableList('addItem',{index:1, label:"Missing dependencies"}); // TODO: nls
// }
// if (unknownCount > 0) {
// depsList.editableList('addItem',{index:1, label:"Unlisted dependencies"}); // TODO: nls
// }
// if (unusedCount > 0) {
// depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls
// }
if (totalCount === 0) {
depsList.editableList('addItem',{index:0, label:RED._("sidebar.project.projectSettings.none")});
}
}
function saveDependencies(depsList,container,dependencies,complete) {
var activeProject = RED.projects.getActiveProject();
var spinner = utils.addSpinnerOverlay(container).addClass('red-ui-component-spinner-contain');
var done = function(err,res) {
spinner.remove();
if (err) {
return complete(err);
}
activeProject.dependencies = dependencies;
RED.sidebar.versionControl.refresh(true);
complete();
}
utils.sendRequest({
url: "projects/"+activeProject.name,
type: "PUT",
responses: {
0: function(error) {
done(error,null);
},
200: function(data) {
RED.sidebar.versionControl.refresh(true);
done(null,data);
},
400: {
'*': function(error) {
done(error,null);
}
},
}
},{dependencies:dependencies});
}
function editDependencies(activeProject,depsJSON,container,depsList) {
var json = depsJSON||JSON.stringify(activeProject.dependencies||{},"",4);
if (json === "{}") {
json = "{\n\n}";
}
RED.editor.editJSON({
title: RED._('sidebar.project.editDependencies'),
value: json,
requireValid: true,
complete: function(v) {
try {
var parsed = JSON.parse(v);
saveDependencies(depsList,container,parsed,function(err) {
if (err) {
return editDependencies(activeProject,v,container,depsList);
}
activeProject.dependencies = parsed;
updateProjectDependencies(activeProject,depsList);
});
} catch(err) {
editDependencies(activeProject,v,container,depsList);
}
}
});
}
function createDependenciesPane(activeProject) {
var pane = $('<div id="red-ui-project-settings-tab-deps" class="red-ui-project-settings-tab-pane red-ui-help"></div>');
if (RED.user.hasPermission("projects.write")) {
$('<button class="red-ui-button red-ui-button-small" style="margin-top:10px;float: right;">' + RED._("sidebar.project.projectSettings.edit") + '</button>')
.appendTo(pane)
.on("click", function(evt) {
evt.preventDefault();
editDependencies(activeProject,null,pane,depsList)
});
}
var depsList = $("<ol>",{style:"position: absolute;top: 60px;bottom: 20px;left: 20px;right: 20px;"}).appendTo(pane);
depsList.editableList({
addButton: false,
addItem: function(row,index,entry) {
// console.log(entry);
var headerRow = $('<div>',{class:"red-ui-palette-module-header"}).appendTo(row);
if (entry.label) {
if (entry.index === 0) {
headerRow.addClass("red-ui-search-empty")
} else {
row.parent().addClass("red-ui-palette-module-section");
}
headerRow.text(entry.label);
// if (RED.user.hasPermission("projects.write")) {
// if (entry.index === 1) {
// var addButton = $('<button class="red-ui-button red-ui-button-small red-ui-palette-module-button">add to project</button>').appendTo(headerRow).on("click", function(evt) {
// evt.preventDefault();
// var deps = $.extend(true, {}, activeProject.dependencies);
// for (var m in modulesInUse) {
// if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) {
// deps[m] = modulesInUse[m].version;
// }
// }
// editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList);
// });
// } else if (entry.index === 3) {
// var removeButton = $('<button class="red-ui-button red-ui-button-small red-ui-palette-module-button">remove from project</button>').appendTo(headerRow).on("click", function(evt) {
// evt.preventDefault();
// var deps = $.extend(true, {}, activeProject.dependencies);
// for (var m in activeProject.dependencies) {
// if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) {
// delete deps[m];
// }
// }
// editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList);
// });
// }
// }
} else {
headerRow.addClass("red-ui-palette-module-header");
if (!entry.installed) {
headerRow.addClass("red-ui-palette-module-not-installed");
} else if (entry.count === 0) {
headerRow.addClass("red-ui-palette-module-unused");
} else if (!entry.known) {
headerRow.addClass("red-ui-palette-module-unknown");
}
entry.element = headerRow;
var titleRow = $('<div class="red-ui-palette-module-meta red-ui-palette-module-name"></div>').appendTo(headerRow);
var iconClass = "fa-cube";
if (!entry.installed) {
iconClass = "fa-warning";
}
var icon = $('<i class="fa '+iconClass+'"></i>').appendTo(titleRow);
entry.icon = icon;
$('<span>').text(entry.id).appendTo(titleRow);
var metaRow = $('<div class="red-ui-palette-module-meta red-ui-palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
var versionSpan = $('<span>').text(entry.version).appendTo(metaRow);
metaRow = $('<div class="red-ui-palette-module-meta"></div>').appendTo(headerRow);
var buttons = $('<div class="red-ui-palette-module-button-group"></div>').appendTo(metaRow);
if (RED.user.hasPermission("projects.write")) {
if (!entry.installed && RED.settings.get('externalModules.palette.allowInstall', true) !== false) {
$('<a href="#" class="red-ui-button red-ui-button-small">' + RED._("sidebar.project.projectSettings.install") + '</a>').appendTo(buttons)
.on("click", function(evt) {
evt.preventDefault();
RED.palette.editor.install(entry,row,function(err) {
if (!err) {
entry.installed = true;
var spinner = RED.utils.addSpinnerOverlay(row,true);
setTimeout(function() {
depsList.editableList('removeItem',entry);
refreshModuleInUseCounts();
if (modulesInUse.hasOwnProperty(entry.id)) {
entry.count = modulesInUse[entry.id].count;
} else {
entry.count = 0;
}
depsList.editableList('addItem',entry);
},500);
}
});
})
} else if (entry.known && entry.count === 0) {
$('<a href="#" class="red-ui-button red-ui-button-small">' + RED._("sidebar.project.projectSettings.removeFromProject") + '</a>').appendTo(buttons)
.on("click", function(evt) {
evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies);
delete deps[entry.id];
saveDependencies(depsList,row,deps,function(err) {
if (!err) {
row.fadeOut(200,function() {
depsList.editableList('removeItem',entry);
});
} else {
console.log(err);
}
});
});
} else if (!entry.known) {
$('<a href="#" class="red-ui-button red-ui-button-small">' + RED._("sidebar.project.projectSettings.addToProject") + '</a>').appendTo(buttons)
.on("click", function(evt) {
evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies);
deps[entry.id] = modulesInUse[entry.id].version;
saveDependencies(depsList,row,deps,function(err) {
if (!err) {
buttons.remove();
headerRow.removeClass("red-ui-palette-module-unknown");
} else {
console.log(err);
}
});
});
}
}
}
},
sort: function(A,B) {
return A.id.localeCompare(B.id);
// if (A.index && B.index) {
// return A.index - B.index;
// }
// var Acategory = A.index?A.index:(A.known?(A.count>0?0:4):2);
// var Bcategory = B.index?B.index:(B.known?(B.count>0?0:4):2);
// if (Acategory === Bcategory) {
// return A.id.localeCompare(B.id);
// } else {
// return Acategory - Bcategory;
// }
}
});
updateProjectDependencies(activeProject,depsList);
return pane;
}
function showProjectFileListing(row,activeProject,current,selectFilter,done) {
var dialog;
var dialogBody;
var filesList;
var selected;
var container = $('<div class="red-ui-projects-file-listing-container"></div>',{style:"position: relative; min-height: 175px; height: 175px;"}).hide().appendTo(row);
var spinner = utils.addSpinnerOverlay(container);
$.getJSON("projects/"+activeProject.name+"/files",function(result) {
var fileNames = Object.keys(result);
fileNames = fileNames.filter(function(fn) {
return !result[fn].status || !/D/.test(result[fn].status);
})
var files = {};
fileNames.sort();
fileNames.forEach(function(file) {
file.split("/").reduce(function(r,v,i,arr) { if (v) { if (i<arr.length-1) { r[v] = r[v]||{};} else { r[v] = true }return r[v];}},files);
});
var sortFiles = function(key,value,fullPath) {
var result = {
name: key||"/",
path: fullPath+(fullPath?"/":"")+key,
};
if (value === true) {
result.type = 'f';
return result;
}
result.type = 'd';
result.children = [];
result.path = result.path;
var files = Object.keys(value);
files.forEach(function(file) {
result.children.push(sortFiles(file,value[file],result.path));
})
result.children.sort(function(A,B) {
if (A.hasOwnProperty("children") && !B.hasOwnProperty("children")) {
return -1;
} else if (!A.hasOwnProperty("children") && B.hasOwnProperty("children")) {
return 1;
}
return A.name.localeCompare(B.name);
})
return result;
}
var files = sortFiles("",files,"")
createFileSubList(container,files.children,current,selectFilter,done,"height: 175px");
spinner.remove();
});
return container;
}
function createFileSubList(container, files, current, selectFilter, onselect, style) {
style = style || "";
var list = $('<ol>',{class:"red-ui-projects-dialog-file-list", style:style}).appendTo(container).editableList({
addButton: false,
scrollOnAdd: false,
addItem: function(row,index,entry) {
var header = $('<div></div>',{class:"red-ui-projects-dialog-file-list-entry"}).appendTo(row);
if (entry.children) {
$('<span class="red-ui-projects-dialog-file-list-entry-folder"><i class="fa fa-angle-right"></i> <i class="fa fa-folder-o"></i></span>').appendTo(header);
if (entry.children.length > 0) {
var children = $('<div></div>',{style:"padding-left: 20px;"}).appendTo(row);
if (current.indexOf(entry.path+"/") === 0) {
header.addClass("expanded");
} else {
children.hide();
}
createFileSubList(children,entry.children,current,selectFilter,onselect);
header.addClass("selectable");
header.on("click", function(e) {
if ($(this).hasClass("expanded")) {
$(this).removeClass("expanded");
children.slideUp(200);
} else {
$(this).addClass("expanded");
children.slideDown(200);
}
});
}
} else {
var fileIcon = "fa-file-o";
var fileClass = "";
if (/\.json$/i.test(entry.name)) {
fileIcon = "fa-file-code-o"
} else if (/\.md$/i.test(entry.name)) {
fileIcon = "fa-book";
} else if (/^\.git/i.test(entry.name)) {
fileIcon = "fa-code-fork";
header.addClass("red-ui-projects-dialog-file-list-entry-file-type-git");
}
$('<span class="red-ui-projects-dialog-file-list-entry-file"> <i class="fa '+fileIcon+'"></i></span>').appendTo(header);
if (selectFilter(entry)) {
header.addClass("selectable");
if (entry.path === current) {
header.addClass("selected");
}
header.on("click", function(e) {
$(".red-ui-projects-dialog-file-list-entry.selected").removeClass("selected");
$(this).addClass("selected");
onselect(entry.path,true);
})
header.on("dblclick", function(e) {
e.preventDefault();
onselect(entry.path,true);
})
} else {
header.addClass("unselectable");
}
}
$('<span class="red-ui-projects-dialog-file-list-entry-name" style=""></span>').text(entry.name).appendTo(header);
}
});
if (!style) {
list.parent().css("overflow-y","");
}
files.forEach(function(f) {
list.editableList('addItem',f);
})
}
// function editFiles(activeProject, container,flowFile, flowFileLabel) {
// var editButton = container.children().first();
// editButton.hide();
//
// var flowFileInput = $('<input id="" type="text" style="width: calc(100% - 300px);">').val(flowFile).insertAfter(flowFileLabel);
//
// var flowFileInputSearch = $('<button class="red-ui-button" style="margin-left: 10px"><i class="fa fa-folder-open-o"></i></button>')
// .insertAfter(flowFileInput)
// .on("click", function(e) {
// showProjectFileListing(activeProject,'Select flow file',flowFileInput.val(),function(result) {
// flowFileInput.val(result);
// checkFiles();
// })
// })
//
// var checkFiles = function() {
// saveButton.toggleClass('disabled',flowFileInput.val()==="");
// saveButton.prop('disabled',flowFileInput.val()==="");
// }
// flowFileInput.on("change keyup paste",checkFiles);
// flowFileLabel.hide();
//
// var bg = $('<span class="button-group" style="position: relative; float: right; margin-right:0;"></span>').prependTo(container);
// $('<button class="red-ui-button">Cancel</button>')
// .appendTo(bg)
// .on("click", function(evt) {
// evt.preventDefault();
//
// flowFileLabel.show();
// flowFileInput.remove();
// flowFileInputSearch.remove();
// bg.remove();
// editButton.show();
// });
// var saveButton = $('<button class="red-ui-button">Save</button>')
// .appendTo(bg)
// .on("click", function(evt) {
// evt.preventDefault();
// var newFlowFile = flowFileInput.val();
// var newCredsFile = credentialsFileInput.val();
// var spinner = utils.addSpinnerOverlay(container);
// var done = function(err,res) {
// if (err) {
// spinner.remove();
// return;
// }
// activeProject.summary = v;
// spinner.remove();
// flowFileLabel.text(newFlowFile);
// flowFileLabel.show();
// flowFileInput.remove();
// flowFileInputSearch.remove();
// bg.remove();
// editButton.show();
// }
// // utils.sendRequest({
// // url: "projects/"+activeProject.name,
// // type: "PUT",
// // responses: {
// // 0: function(error) {
// // done(error,null);
// // },
// // 200: function(data) {
// // done(null,data);
// // },
// // 400: {
// // 'unexpected_error': function(error) {
// // done(error,null);
// // }
// // },
// // }
// // },{summary:v});
// });
//
//
// checkFiles();
//
// }
function createFilesSection(activeProject,pane) {
var title = $('<h3></h3>').text(RED._("sidebar.project.projectSettings.files")).appendTo(pane);
var filesContainer = $('<div class="red-ui-settings-section"></div>').appendTo(pane);
if (RED.user.hasPermission("projects.write")) {
var editFilesButton = $('<button type="button" id="red-ui-project-settings-tab-settings-file-edit" class="red-ui-button red-ui-button-small" style="float: right;">' + RED._('sidebar.project.projectSettings.edit') + '</button>')
.appendTo(title)
.on("click", function(evt) {
evt.preventDefault();
formButtons.show();
editFilesButton.hide();
// packageFileLabelText.hide();
if (!activeProject.files.package) {
packageFileSubLabel.find(".red-ui-projects-edit-form-sublabel-text").text(RED._("sidebar.project.projectSettings.packageCreate"));
packageFileSubLabel.show();
}
packageFileInputSearch.show();
// packageFileInputCreate.show();
flowFileLabelText.hide();
flowFileInput.show();
flowFileInputSearch.show();
flowFileInputResize();
// credentialStateLabel.parent().hide();
credentialStateLabel.addClass("uneditable-input");
$(".red-ui-settings-row-credentials").show();
credentialStateLabel.css('height','auto');
credentialFormRows.hide();
credentialSecretButtons.show();
});
}
var row;
// Flow files
row = $('<div class="red-ui-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.package")).appendTo(row);
var packageFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
var packageFileLabelText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.files.package||"package.json").appendTo(packageFileLabel);
var packageFileInput = $('<input type="hidden">').val(activeProject.files.package||"package.json").appendTo(packageFileLabel);
var packageFileInputSearch = $('<button type="button" class="red-ui-button toggle single" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 36px; height: 34px; position: absolute; top: -1px; right: -1px;"><i class="fa fa-folder-open-o"></i></button>')
.hide()
.appendTo(packageFileLabel)
.on("click", function(e) {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
packageFileLabel.find('.red-ui-projects-file-listing-container').slideUp(200,function() {
$(this).remove();
packageFileLabel.css('height','');
});
packageFileLabel.css('color','');
} else {
$(this).addClass('selected');
packageFileLabel.css('color','inherit');
var fileList = showProjectFileListing(packageFileLabel,activeProject,packageFileInput.val(),
function(entry) { return entry.children || /package\.json$/.test(entry.path); },
function(result,close) {
if (result) {
packageFileInput.val(result);
packageFileLabelText.text(result);
var rootDir = result.substring(0,result.length - 12);
flowFileLabelPrefixText.text(rootDir);
credFileLabelPrefixText.text(rootDir);
flowFileInputResize();
packageFileSubLabel.hide();
}
if (close) {
$(packageFileInputSearch).trigger("click");
}
checkFiles();
});
packageFileLabel.css('height','auto');
setTimeout(function() {
fileList.slideDown(200);
},50);
}
})
RED.popover.tooltip(packageFileInputSearch,RED._("sidebar.project.projectSettings.selectFile"));
var packageFileSubLabel = $('<label style="margin-left: 110px" class="red-ui-projects-edit-form-sublabel"><small><span class="form-warning"><i class="fa fa-warning"></i> <span class="red-ui-projects-edit-form-sublabel-text"></span></small></label>').appendTo(row).hide();
if (!activeProject.files.package) {
packageFileSubLabel.find(".red-ui-projects-edit-form-sublabel-text").text(RED._("sidebar.project.projectSettings.fileNotExist"));
packageFileSubLabel.show();
}
var projectPackage = activeProject.files.package||"package.json";
var projectRoot = projectPackage.substring(0,projectPackage.length - 12);
// Flow files
row = $('<div class="red-ui-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.flow")).appendTo(row);
var flowFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
var flowFileLabelPrefixText = $('<span style="display:inline-block; padding: 6px 0 6px 6px">').text(projectRoot).appendTo(flowFileLabel);
var flowFileName = "flows.json";
if (activeProject.files.flow) {
if (activeProject.files.flow.indexOf(projectRoot) === 0) {
flowFileName = activeProject.files.flow.substring(projectRoot.length);
} else {
flowFileName = activeProject.files.flow;
}
}
var flowFileLabelText = $('<span style="display:inline-block; padding: 6px 6px 6px 0">').text(flowFileName).appendTo(flowFileLabel);
var flowFileInputResize = function() {
flowFileInput.css({
"width": "calc(100% - "+(flowFileInputSearch.width() + flowFileLabelPrefixText.width())+"px)"
});
}
var flowFileInput = $('<input type="text" style="padding-left:1px; margin-top: -2px; margin-bottom: 0;border: none;">').val(flowFileName).hide().appendTo(flowFileLabel);
var flowFileInputSearch = $('<button type="button" class="red-ui-button toggle single" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 36px; height: 34px; position: absolute; top: -1px; right: -1px;"><i class="fa fa-folder-open-o"></i></button>')
.hide()
.appendTo(flowFileLabel)
.on("click", function(e) {
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
flowFileLabel.find('.red-ui-projects-file-listing-container').slideUp(200,function() {
$(this).remove();
flowFileLabel.css('height','');
});
flowFileLabel.css('color','');
} else {
$(this).addClass('selected');
flowFileLabel.css('color','inherit');
var packageFile = packageFileInput.val();
var packagePrefix = packageFile.substring(0,packageFile.length - 12);
var re = new RegExp("^"+packagePrefix+".*\.json$");
var fileList = showProjectFileListing(flowFileLabel,
activeProject,
flowFileInput.val(),
function(entry) { return !/package.json$/.test(entry.path) && re.test(entry.path) && !/_cred\.json$/.test(entry.path) },
function(result,isDblClick) {
if (result) {
flowFileInput.val(result.substring(packagePrefix.length));
}
if (isDblClick) {
$(flowFileInputSearch).trigger("click");
}
checkFiles();
}
);
flowFileLabel.css('height','auto');
setTimeout(function() {
fileList.slideDown(200);
},50);
}
})
RED.popover.tooltip(flowFileInputSearch,RED._("sidebar.project.projectSettings.selectFile"));
row = $('<div class="red-ui-settings-row"></div>').appendTo(filesContainer);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.credentials")).appendTo(row);
var credFileName = "flows_cred.json";
if (activeProject.files.credentials) {
if (activeProject.files.flow.indexOf(projectRoot) === 0) {
credFileName = activeProject.files.credentials.substring(projectRoot.length);
} else {
credFileName = activeProject.files.credentials;
}
}
var credFileLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
var credFileLabelPrefixText = $('<span style="display:inline-block;padding: 6px 0 6px 6px">').text(projectRoot).appendTo(credFileLabel);
var credFileLabelText = $('<span style="display:inline-block; padding: 6px 6px 6px 0">').text(credFileName).appendTo(credFileLabel);
var credFileInput = $('<input type="hidden">').val(credFileName).insertAfter(credFileLabel);
var checkFiles = function() {
var saveDisabled;
var currentFlowValue = flowFileInput.val();
var m = /^(.+?)(\.[^.]*)?$/.exec(currentFlowValue);
if (m) {
credFileLabelText.text(m[1]+"_cred"+(m[2]||".json"));
} else if (currentFlowValue === "") {
credFileLabelText.text("");
}
credFileInput.val(credFileLabelText.text());
var isFlowInvalid = currentFlowValue==="" ||
/\.\./.test(currentFlowValue) ||
/\/$/.test(currentFlowValue);
saveDisabled = isFlowInvalid || credFileLabelText.text()==="";
if (credentialSecretExistingRow.is(":visible")) {
credentialSecretExistingInput.toggleClass("input-error", credentialSecretExistingInput.val() === "");
saveDisabled = saveDisabled || credentialSecretExistingInput.val() === "";
}
if (credentialSecretNewRow.is(":visible")) {
credentialSecretNewInput.toggleClass("input-error", credentialSecretNewInput.val() === "");
saveDisabled = saveDisabled || credentialSecretNewInput.val() === "";
}
flowFileInput.toggleClass("input-error", isFlowInvalid);
// credFileInput.toggleClass("input-error",credFileInput.text()==="");
saveButton.toggleClass('disabled',saveDisabled);
saveButton.prop('disabled',saveDisabled);
}
flowFileInput.on("change keyup paste",checkFiles);
// if (!activeProject.files.package) {
// $('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(packageFileLabelText);
// }
// if (!activeProject.files.flow) {
// $('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(flowFileLabelText);
// }
// if (!activeProject.files.credentials) {
// $('<span class="form-warning"><i class="fa fa-warning"></i> Missing</span>').appendTo(credFileLabel);
// }
row = $('<div class="red-ui-settings-row"></div>').appendTo(filesContainer);
$('<label></label>').appendTo(row);
var credentialStateLabel = $('<span><i class="user-settings-credentials-state-icon fa"></i> <span class="user-settings-credentials-state"></span></span>').appendTo(row);
var credentialSecretButtons = $('<span class="button-group" style="margin-left: -72px;">').hide().appendTo(row);
credentialStateLabel.css('color','#666');
credentialSecretButtons.css('vertical-align','top');
var credentialSecretResetButton = $('<button type="button" class="red-ui-button" style="vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-trash-o"></i></button>')
.appendTo(credentialSecretButtons)
.on("click", function(e) {
e.preventDefault();
if (!$(this).hasClass('selected')) {
credentialSecretNewInput.val("");
credentialSecretExistingRow.hide();
credentialSecretNewRow.show();
$(this).addClass("selected");
credentialSecretEditButton.removeClass("selected");
credentialResetLabel.show();
credentialResetWarning.show();
credentialSetLabel.hide();
credentialChangeLabel.hide();
credentialFormRows.show();
} else {
$(this).removeClass("selected");
credentialFormRows.hide();
}
checkFiles();
});
RED.popover.tooltip(credentialSecretResetButton,RED._("sidebar.project.projectSettings.resetTheEncryptionKey"));
var credentialSecretEditButton = $('<button type="button" class="red-ui-button" style="border-top-right-radius: 4px; border-bottom-right-radius: 4px; vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-pencil"></i></button>')
.appendTo(credentialSecretButtons)
.on("click", function(e) {
e.preventDefault();
if (!$(this).hasClass('selected')) {
credentialSecretExistingInput.val("");
credentialSecretNewInput.val("");
if (activeProject.settings.credentialSecretInvalid || !activeProject.settings.credentialsEncrypted) {
credentialSetLabel.show();
credentialChangeLabel.hide();
credentialSecretExistingRow.hide();
} else {
credentialSecretExistingRow.show();
credentialSetLabel.hide();
credentialChangeLabel.show();
}
credentialSecretNewRow.show();
credentialSecretEditButton.addClass("selected");
credentialSecretResetButton.removeClass("selected");
credentialResetLabel.hide();
credentialResetWarning.hide();
credentialFormRows.show();
} else {
$(this).removeClass("selected");
credentialFormRows.hide();
}
checkFiles();
})
RED.popover.tooltip(credentialSecretEditButton,RED._("sidebar.project.projectSettings.changeTheEncryptionKey"));
row = $('<div class="red-ui-settings-row red-ui-settings-row-credentials"></div>').hide().appendTo(filesContainer);
var credentialFormRows = $('<div>',{style:"margin-top:10px"}).hide().appendTo(credentialStateLabel);
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;">' + RED._("sidebar.project.projectSettings.changeTheEncryptionKey") + '</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="red-ui-settings-row red-ui-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.currentKey")).appendTo(credentialSecretExistingRow);
var credentialSecretExistingInput = $('<input type="text">').appendTo(credentialSecretExistingRow).typedInput({type:"cred"})
.on("change keyup paste",function() {
if (popover) {
popover.close();
popover = null;
}
checkFiles();
});
var credentialSecretNewRow = $('<div class="red-ui-settings-row red-ui-settings-row-credentials"></div>').appendTo(credentialFormRows);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.newKey")).appendTo(credentialSecretNewRow);
var credentialSecretNewInput = $('<input type="text">').appendTo(credentialSecretNewRow).typedInput({type:"cred"}).on("change keyup paste",checkFiles);
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() {
editFilesButton.show();
formButtons.hide();
// packageFileLabelText.show();
packageFileInputSearch.hide();
// packageFileInputCreate.hide();
flowFileLabelText.show();
flowFileInput.hide();
flowFileInputSearch.hide();
// credentialStateLabel.parent().show();
credentialStateLabel.removeClass("uneditable-input");
credentialStateLabel.css('height','');
flowFileInputSearch.removeClass('selected');
flowFileLabel.find('.red-ui-projects-file-listing-container').remove();
flowFileLabel.css('height','');
flowFileLabel.css('color','');
$(".red-ui-settings-row-credentials").hide();
credentialFormRows.hide();
credentialSecretButtons.hide();
credentialSecretResetButton.removeClass("selected");
credentialSecretEditButton.removeClass("selected");
}
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
$('<button type="button" class="red-ui-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(formButtons)
.on("click", function(evt) {
evt.preventDefault();
var projectPackage = activeProject.files.package||"package.json";
var projectRoot = projectPackage.substring(0,projectPackage.length - 12);
flowFileLabelPrefixText.text(projectRoot);
credFileLabelPrefixText.text(projectRoot);
packageFileLabelText.text(activeProject.files.package||"package.json");
if (!activeProject.files.package) {
packageFileSubLabel.find(".red-ui-projects-edit-form-sublabel-text").text(RED._("sidebar.project.projectSettings.fileNotExist"));
packageFileSubLabel.show();
} else {
packageFileSubLabel.hide();
}
flowFileInput.val(flowFileLabelText.text());
credFileLabelText.text(credFileName);
hideEditForm();
});
var saveButton = $('<button type="button" class="red-ui-button">' + RED._("common.label.save") + '</button>')
.appendTo(formButtons)
.on("click", function(evt) {
evt.preventDefault();
var spinner = utils.addSpinnerOverlay(filesContainer);
var done = function(err) {
spinner.remove();
if (err) {
utils.reportUnexpectedError(err);
return;
}
flowFileLabelText.text(flowFileInput.val());
credFileLabelText.text(credFileInput.val());
packageFileSubLabel.hide();
hideEditForm();
}
var rootPath = packageFileInput.val();
rootPath = rootPath.substring(0,rootPath.length-12);
var payload = {
files: {
package: packageFileInput.val(),
flow: rootPath+flowFileInput.val(),
credentials: rootPath+credFileInput.val()
}
}
if (credentialSecretResetButton.hasClass('selected')) {
payload.resetCredentialSecret = true;
}
if (credentialSecretResetButton.hasClass('selected') || credentialSecretEditButton.hasClass('selected')) {
payload.credentialSecret = credentialSecretNewInput.val();
if (credentialSecretExistingRow.is(":visible")) {
payload.currentCredentialSecret = credentialSecretExistingInput.val();
}
}
RED.deploy.setDeployInflight(true);
utils.sendRequest({
url: "projects/"+activeProject.name,
type: "PUT",
responses: {
0: function(error) {
done(error);
},
200: function(data) {
activeProject = data;
RED.sidebar.versionControl.refresh(true);
updateForm();
done();
},
400: {
'credentials_load_failed': function(error) {
done(error);
},
'missing_current_credential_key': function(error) {
credentialSecretExistingInput.addClass("input-error");
popover = RED.popover.create({
target: credentialSecretExistingInput,
direction: 'right',
size: 'small',
content: "Incorrect key",
autoClose: 3000
}).open();
done(error);
},
'*': function(error) {
done(error);
}
},
}
},payload).always(function() {
setTimeout(function() {
RED.deploy.setDeployInflight(false);
},500);
});
});
var updateForm = function() {
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").text(RED._("sidebar.project.projectSettings.invalidEncryptionKey"));
} 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").text(RED._("sidebar.project.projectSettings.encryptionEnabled"));
} else {
credentialStateLabel.find(".user-settings-credentials-state-icon").removeClass().addClass("user-settings-credentials-state-icon fa fa-unlock");
credentialStateLabel.find(".user-settings-credentials-state").text(RED._("sidebar.project.projectSettings.encryptionDisabled"));
}
credentialSecretResetButton.toggleClass('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
credentialSecretResetButton.prop('disabled',!activeProject.settings.credentialSecretInvalid && !activeProject.settings.credentialsEncrypted);
}
checkFiles();
updateForm();
}
function createLocalBranchListSection(activeProject,pane) {
var localBranchContainer = $('<div class="red-ui-settings-section"></div>').appendTo(pane);
$('<h4></h4>').text(RED._("sidebar.project.projectSettings.branches")).appendTo(localBranchContainer);
var row = $('<div class="red-ui-settings-row red-ui-projects-dialog-list"></div>').appendTo(localBranchContainer);
var branchList = $('<ol>').appendTo(row).editableList({
height: 'auto',
addButton: false,
scrollOnAdd: false,
addItem: function(row,index,entry) {
var container = $('<div class="red-ui-projects-dialog-list-entry">').appendTo(row);
if (entry.empty) {
container.addClass('red-ui-search-empty');
container.text(RED._("sidebar.project.projectSettings.noBranches"));
return;
}
if (entry.current) {
container.addClass("current");
}
$('<span class="entry-icon"><i class="fa fa-code-fork"></i></span>').appendTo(container);
var content = $('<span>').appendTo(container);
var topRow = $('<div>').appendTo(content);
$('<span class="entry-name">').text(entry.name).appendTo(topRow);
if (entry.commit) {
$('<span class="entry-detail">').text(entry.commit.sha).appendTo(topRow);
}
if (entry.remote) {
var bottomRow = $('<div>').appendTo(content);
$('<span class="entry-detail entry-remote-name">').text(entry.remote||"").appendTo(bottomRow);
if (entry.status.ahead+entry.status.behind > 0) {
$('<span class="entry-detail">'+
'<i class="fa fa-long-arrow-up"></i> <span>'+entry.status.ahead+'</span> '+
'<i class="fa fa-long-arrow-down"></i> <span>'+entry.status.behind+'</span>'+
'</span>').appendTo(bottomRow);
}
}
if (!entry.current) {
var tools = $('<span class="entry-tools">').appendTo(container);
$('<button class="red-ui-button red-ui-button-small"><i class="fa fa-trash"></i></button>')
.appendTo(tools)
.on("click", function(e) {
e.preventDefault();
var spinner = utils.addSpinnerOverlay(row).addClass('red-ui-component-spinner-contain');
var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteConfirm", { name: entry.name }), {
type: "warning",
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
spinner.remove();
notification.close();
}
},{
text: 'Delete branch',
click: function() {
notification.close();
var url = "projects/"+activeProject.name+"/branches/"+entry.name;
var options = {
url: url,
type: "DELETE",
responses: {
200: function(data) {
row.fadeOut(200,function() {
branchList.editableList('removeItem',entry);
spinner.remove();
});
},
400: {
'git_delete_branch_unmerged': function(error) {
notification = RED.notify(RED._("sidebar.project.projectSettings.unmergedConfirm", { name: entry.name }), {
type: "warning",
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
spinner.remove();
notification.close();
}
},{
text: RED._("sidebar.project.projectSettings.deleteUnmergedBranch"),
click: function() {
options.url += "?force=true";
notification.close();
utils.sendRequest(options);
}
}
]
});
},
'*': function(error) {
utils.reportUnexpectedError(error);
spinner.remove();
}
},
}
}
utils.sendRequest(options);
}
}
]
})
})
}
}
});
$.getJSON("projects/"+activeProject.name+"/branches",function(result) {
if (result.branches) {
if (result.branches.length > 0) {
result.branches.sort(function(A,B) {
if (A.current) { return -1 }
if (B.current) { return 1 }
return A.name.localeCompare(B.name);
});
result.branches.forEach(function(branch) {
branchList.editableList('addItem',branch);
})
} else {
branchList.editableList('addItem',{empty:true});
}
}
})
}
function createRemoteRepositorySection(activeProject,pane) {
$('<h3></h3>').text(RED._("sidebar.project.projectSettings.versionControl")).appendTo(pane);
createLocalBranchListSection(activeProject,pane);
var repoContainer = $('<div class="red-ui-settings-section"></div>').appendTo(pane);
var title = $('<h4></h4>').text(RED._("sidebar.project.projectSettings.gitRemotes")).appendTo(repoContainer);
var editRepoButton = $('<button class="red-ui-button red-ui-button-small" style="float: right; margin-right: 10px;">' + RED._("sidebar.project.projectSettings.addRemote") + '</button>')
.appendTo(title)
.on("click", function(evt) {
editRepoButton.attr('disabled',true);
addRemoteDialog.slideDown(200, function() {
addRemoteDialog[0].scrollIntoView();
if (isEmpty) {
remoteNameInput.val('origin');
remoteURLInput.trigger("focus");
} else {
remoteNameInput.trigger("focus");
}
validateForm();
});
});
var emptyItem = { empty: true };
var isEmpty = true;
var row = $('<div class="red-ui-settings-row"></div>').appendTo(repoContainer);
var addRemoteDialog = $('<div class="red-ui-projects-dialog-list-dialog"></div>').hide().appendTo(row);
row = $('<div class="red-ui-settings-row red-ui-projects-dialog-list"></div>').appendTo(repoContainer);
var remotesList = $('<ol>').appendTo(row);
remotesList.editableList({
addButton: false,
height: 'auto',
addItem: function(row,index,entry) {
var container = $('<div class="red-ui-projects-dialog-list-entry">').appendTo(row);
if (entry.empty) {
container.addClass('red-ui-search-empty');
container.text(RED._("sidebar.project.projectSettings.noRemotes"));
return;
} else {
$('<span class="entry-icon"><i class="fa fa-globe"></i></span>').appendTo(container);
var content = $('<span>').appendTo(container);
$('<div class="entry-name">').text(entry.name).appendTo(content);
if (entry.urls.fetch === entry.urls.push) {
$('<div class="entry-detail">').text(entry.urls.fetch).appendTo(content);
} else {
$('<div class="entry-detail">').text("fetch: "+entry.urls.fetch).appendTo(content);
$('<div class="entry-detail">').text("push: "+entry.urls.push).appendTo(content);
}
var tools = $('<span class="entry-tools">').appendTo(container);
$('<button class="red-ui-button red-ui-button-small"><i class="fa fa-trash"></i></button>')
.appendTo(tools)
.on("click", function(e) {
e.preventDefault();
var spinner = utils.addSpinnerOverlay(row).addClass('red-ui-component-spinner-contain');
var notification = RED.notify(RED._("sidebar.project.projectSettings.deleteRemoteConfrim", { name: entry.name }), {
type: "warning",
modal: true,
fixed: true,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
spinner.remove();
notification.close();
}
},{
text: RED._("sidebar.project.projectSettings.deleteRemote"),
click: function() {
notification.close();
if (activeProject.git.branches.remote && activeProject.git.branches.remote.indexOf(entry.name+"/") === 0) {
delete activeProject.git.branches.remote;
}
if (activeProject.git.branches.remoteAlt && activeProject.git.branches.remoteAlt.indexOf(entry.name+"/") === 0) {
delete activeProject.git.branches.remoteAlt;
}
var url = "projects/"+activeProject.name+"/remotes/"+entry.name;
var options = {
url: url,
type: "DELETE",
responses: {
200: function(data) {
row.fadeOut(200,function() {
remotesList.editableList('removeItem',entry);
setTimeout(spinner.remove, 100);
if (data.remotes.length === 0) {
delete activeProject.git.remotes;
isEmpty = true;
remotesList.editableList('addItem',emptyItem);
} else {
activeProject.git.remotes = {};
data.remotes.forEach(function(remote) {
var name = remote.name;
delete remote.name;
activeProject.git.remotes[name] = remote;
});
}
delete activeProject.git.branches.remoteAlt;
RED.sidebar.versionControl.refresh();
});
},
400: {
'*': function(error) {
utils.reportUnexpectedError(error);
spinner.remove();
}
},
}
}
utils.sendRequest(options);
}
}
]
})
});
}
}
});
var validateForm = function() {
var validName = /^[a-zA-Z0-9\-_]+$/.test(remoteNameInput.val());
var repo = 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);
if (/^https?:\/\/[^/]+@/i.test(repo)) {
remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule2"));
validRepo = false;
} else {
remoteURLLabel.text(RED._("sidebar.project.projectSettings.urlRule"));
}
saveButton.attr('disabled',(!validName || !validRepo))
remoteNameInput.toggleClass('input-error',remoteNameInputChanged&&!validName);
remoteURLInput.toggleClass('input-error',remoteURLInputChanged&&!validRepo);
if (popover) {
popover.close();
popover = null;
}
};
var popover;
var remoteNameInputChanged = false;
var remoteURLInputChanged = false;
$('<div class="red-ui-projects-dialog-list-dialog-header">').text(RED._('sidebar.project.projectSettings.addRemote2')).appendTo(addRemoteDialog);
row = $('<div class="red-ui-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.remoteName")).appendTo(row);
var remoteNameInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteNameInputChanged = true;
validateForm();
});
$('<label class="red-ui-projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.nameRule") + '</small></label>').appendTo(row).find("small");
row = $('<div class="red-ui-settings-row"></div>').appendTo(addRemoteDialog);
$('<label for=""></label>').text(RED._("sidebar.project.projectSettings.url")).appendTo(row);
var remoteURLInput = $('<input type="text">').appendTo(row).on("change keyup paste",function() {
remoteURLInputChanged = true;
validateForm()
});
var remoteURLLabel = $('<label class="red-ui-projects-edit-form-sublabel"><small>' + RED._("sidebar.project.projectSettings.urlRule") +'</small></label>').appendTo(row).find("small");
var hideEditForm = function() {
editRepoButton.attr('disabled',false);
addRemoteDialog.hide();
remoteNameInput.val("");
remoteURLInput.val("");
if (popover) {
popover.close();
popover = null;
}
}
var formButtons = $('<span class="button-row" style="position: relative; float: right; margin: 10px;"></span>')
.appendTo(addRemoteDialog);
$('<button class="red-ui-button">' + RED._("common.label.cancel") + '</button>')
.appendTo(formButtons)
.on("click", function(evt) {
evt.preventDefault();
hideEditForm();
});
var saveButton = $('<button class="red-ui-button">' + RED._("sidebar.project.projectSettings.addRemote2") + '</button>')
.appendTo(formButtons)
.on("click", function(evt) {
evt.preventDefault();
var spinner = utils.addSpinnerOverlay(addRemoteDialog).addClass('red-ui-component-spinner-contain');
var payload = {
name: remoteNameInput.val(),
url: remoteURLInput.val()
}
var done = function(err) {
spinner.remove();
if (err) {
return;
}
hideEditForm();
}
// console.log(JSON.stringify(payload,null,4));
RED.deploy.setDeployInflight(true);
utils.sendRequest({
url: "projects/"+activeProject.name+"/remotes",
type: "POST",
responses: {
0: function(error) {
done(error);
},
200: function(data) {
activeProject.git.remotes = {};
data.remotes.forEach(function(remote) {
var name = remote.name;
delete remote.name;
activeProject.git.remotes[name] = remote;
});
updateForm();
RED.sidebar.versionControl.refresh();
done();
},
400: {
'git_remote_already_exists': function(error) {
popover = RED.popover.create({
target: remoteNameInput,
direction: 'right',
size: 'small',
content: "Remote already exists",
autoClose: 6000
}).open();
remoteNameInput.addClass('input-error');
done(error);
},
'*': function(error) {
utils.reportUnexpectedError(error);
done(error);
}
},
}
},payload);
});
var updateForm = function() {
remotesList.editableList('empty');
var count = 0;
if (activeProject.git.hasOwnProperty('remotes')) {
for (var name in activeProject.git.remotes) {
if (activeProject.git.remotes.hasOwnProperty(name)) {
count++;
remotesList.editableList('addItem',{name:name,urls:activeProject.git.remotes[name]});
}
}
}
isEmpty = (count === 0);
if (isEmpty) {
remotesList.editableList('addItem',emptyItem);
}
}
updateForm();
}
function createSettingsPane(activeProject) {
var pane = $('<div id="red-ui-project-settings-tab-settings" class="red-ui-project-settings-tab-pane red-ui-help"></div>');
createFilesSection(activeProject,pane);
// createLocalRepositorySection(activeProject,pane);
createRemoteRepositorySection(activeProject,pane);
return pane;
}
function refreshModuleInUseCounts() {
modulesInUse = {};
RED.nodes.eachNode(_updateModulesInUse);
RED.nodes.eachConfig(_updateModulesInUse);
}
function _updateModulesInUse(n) {
if (!/^subflow:/.test(n.type)) {
var module = RED.nodes.registry.getNodeSetForType(n.type).module;
if (module !== 'node-red') {
if (!modulesInUse.hasOwnProperty(module)) {
modulesInUse[module] = {
module: module,
version: RED.nodes.registry.getModule(module).version,
count: 0,
known: false
}
}
modulesInUse[module].count++;
}
}
}
var popover;
var utils;
var modulesInUse = {};
function init(_utils) {
utils = _utils;
addPane({
id:'main',
title: RED._("sidebar.project.name"),
get: createMainPane,
close: function() { }
});
addPane({
id:'deps',
title: RED._("sidebar.project.dependencies"),
get: createDependenciesPane,
close: function() { }
});
addPane({
id:'settings',
title: RED._("sidebar.project.settings"),
get: createSettingsPane,
close: function() {
if (popover) {
popover.close();
popover = null;
}
}
});
RED.events.on('nodes:add', _updateModulesInUse);
RED.events.on('nodes:remove', function(n) {
if (!/^subflow:/.test(n.type)) {
var module = RED.nodes.registry.getNodeSetForType(n.type).module;
if (module !== 'node-red' && modulesInUse.hasOwnProperty(module)) {
modulesInUse[module].count--;
if (modulesInUse[module].count === 0) {
if (!modulesInUse[module].known) {
delete modulesInUse[module];
}
}
}
}
})
}
return {
init: init,
show: show,
switchProject: function(name) {
// TODO: not ideal way to trigger this; should there be an editor-wide event?
modulesInUse = {};
}
};
})();