mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
A big projects update
Includes: - change local/remote branches - basic support for username/password handling
This commit is contained in:
parent
3745504107
commit
10057de9b3
@ -43,7 +43,9 @@
|
|||||||
$(".palette-scroll").removeClass("hide");
|
$(".palette-scroll").removeClass("hide");
|
||||||
$("#palette-search").removeClass("hide");
|
$("#palette-search").removeClass("hide");
|
||||||
loadFlows(function() {
|
loadFlows(function() {
|
||||||
RED.projects.refresh();
|
RED.projects.refresh(function() {
|
||||||
|
RED.sidebar.info.refresh()
|
||||||
|
});
|
||||||
|
|
||||||
var persistentNotifications = {};
|
var persistentNotifications = {};
|
||||||
RED.comms.subscribe("notification/#",function(topic,msg) {
|
RED.comms.subscribe("notification/#",function(topic,msg) {
|
||||||
|
@ -101,6 +101,14 @@ RED.stack = (function() {
|
|||||||
if (entry.onexpand) {
|
if (entry.onexpand) {
|
||||||
entry.onexpand.call(entry);
|
entry.onexpand.call(entry);
|
||||||
}
|
}
|
||||||
|
if (options.singleExpanded) {
|
||||||
|
entries.forEach(function(e) {
|
||||||
|
if (e !== entry) {
|
||||||
|
e.collapse();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
icon.addClass("expanded");
|
icon.addClass("expanded");
|
||||||
entry.container.addClass("palette-category-expanded");
|
entry.container.addClass("palette-category-expanded");
|
||||||
entry.contentWrap.slideDown(200);
|
entry.contentWrap.slideDown(200);
|
||||||
|
@ -1581,10 +1581,10 @@ RED.diff = (function() {
|
|||||||
if (Adiff.type === 2) {
|
if (Adiff.type === 2) {
|
||||||
cellNo.addClass('blank');
|
cellNo.addClass('blank');
|
||||||
cellLine.addClass('blank');
|
cellLine.addClass('blank');
|
||||||
} else if (Adiff.type === 1) {
|
} else if (Adiff.type === 4) {
|
||||||
cellNo.addClass('added');
|
cellNo.addClass('added');
|
||||||
cellLine.addClass('added');
|
cellLine.addClass('added');
|
||||||
} else if (Adiff.type === 4) {
|
} else if (Adiff.type === 1) {
|
||||||
cellNo.addClass('removed');
|
cellNo.addClass('removed');
|
||||||
cellLine.addClass('removed');
|
cellLine.addClass('removed');
|
||||||
}
|
}
|
||||||
@ -1593,10 +1593,10 @@ RED.diff = (function() {
|
|||||||
if (Bdiff.type === 2) {
|
if (Bdiff.type === 2) {
|
||||||
cellNo.addClass('blank');
|
cellNo.addClass('blank');
|
||||||
cellLine.addClass('blank');
|
cellLine.addClass('blank');
|
||||||
} else if (Bdiff.type === 1) {
|
} else if (Bdiff.type === 4) {
|
||||||
cellNo.addClass('added');
|
cellNo.addClass('added');
|
||||||
cellLine.addClass('added');
|
cellLine.addClass('added');
|
||||||
} else if (Bdiff.type === 4) {
|
} else if (Bdiff.type === 1) {
|
||||||
cellNo.addClass('removed');
|
cellNo.addClass('removed');
|
||||||
cellLine.addClass('removed');
|
cellLine.addClass('removed');
|
||||||
}
|
}
|
||||||
@ -1694,9 +1694,14 @@ RED.diff = (function() {
|
|||||||
var isCollapsed = diffFileRow.hasClass("collapsed");
|
var isCollapsed = diffFileRow.hasClass("collapsed");
|
||||||
diffFileRow.nextUntil(".node-text-diff-file-header").toggle(!isCollapsed);
|
diffFileRow.nextUntil(".node-text-diff-file-header").toggle(!isCollapsed);
|
||||||
})
|
})
|
||||||
var label = $('<span></span>').text(file.file).appendTo(content);
|
var label = $('<span class="filename"></span>').text(file.file).appendTo(content);
|
||||||
|
|
||||||
if (commitOptions.project.files && commitOptions.project.files.flow === file.file) {
|
var conflictHeader;
|
||||||
|
var unresolvedConflicts = 0;
|
||||||
|
var resolvedConflicts = 0;
|
||||||
|
var conflictResolutions = {};
|
||||||
|
|
||||||
|
if (!commitOptions.unmerged && commitOptions.project.files && commitOptions.project.files.flow === file.file) {
|
||||||
var tools = $('<span style="float: right;" class="button-group"></span>').appendTo(content);
|
var tools = $('<span style="float: right;" class="button-group"></span>').appendTo(content);
|
||||||
$('<button class="editor-button editor-button-small">show flow diff</button>').appendTo(tools).click(function(e) {
|
$('<button class="editor-button editor-button-small">show flow diff</button>').appendTo(tools).click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -1740,38 +1745,72 @@ RED.diff = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (var i=0;i<hunks.length;i++) {
|
hunks.forEach(function(hunk) {
|
||||||
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
var diffRow = $('<tr class="node-text-diff-header">').appendTo(codeBody);
|
||||||
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
var content = $('<td colspan="3"></td>').appendTo(diffRow);
|
||||||
var label = $('<span></span>').text(hunks[i].header).appendTo(content);
|
var label = $('<span></span>').text(hunk.header).appendTo(content);
|
||||||
|
var isConflict = hunk.conflict;
|
||||||
|
var localLine = hunk.localStartLine;
|
||||||
|
var remoteLine = hunk.remoteStartLine;
|
||||||
|
if (isConflict) {
|
||||||
|
unresolvedConflicts++;
|
||||||
|
}
|
||||||
|
|
||||||
var localLine = hunks[i].localStartLine;
|
hunk.lines.forEach(function(lineText,lineNumber) {
|
||||||
var remoteLine = hunks[i].remoteStartLine;
|
|
||||||
|
|
||||||
|
|
||||||
for (var j=0;j<hunks[i].lines.length;j++) {
|
|
||||||
var lineText = hunks[i].lines[j];
|
|
||||||
// if (lineText[0] === '\\' || lineText === "") {
|
// if (lineText[0] === '\\' || lineText === "") {
|
||||||
// // Comment line - bail out of this hunk
|
// // Comment line - bail out of this hunk
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
diffRow = $('<tr>').appendTo(codeBody);
|
|
||||||
|
var actualLineNumber = hunk.diffStart + lineNumber;
|
||||||
|
var isMergeHeader = isConflict && /^..(<<<<<<<|=======$|>>>>>>>)/.test(lineText);
|
||||||
|
var diffRow = $('<tr>').appendTo(codeBody);
|
||||||
var localLineNo = $('<td class="lineno">').appendTo(diffRow);
|
var localLineNo = $('<td class="lineno">').appendTo(diffRow);
|
||||||
var remoteLineNo = $('<td class="lineno">').appendTo(diffRow);
|
var remoteLineNo;
|
||||||
|
if (!isMergeHeader) {
|
||||||
|
remoteLineNo = $('<td class="lineno">').appendTo(diffRow);
|
||||||
|
} else {
|
||||||
|
localLineNo.attr('colspan',2);
|
||||||
|
}
|
||||||
var line = $('<td class="linetext">').appendTo(diffRow);
|
var line = $('<td class="linetext">').appendTo(diffRow);
|
||||||
$('<span class="prefix">').text(lineText[0]).appendTo(line);
|
var prefixStart = 0;
|
||||||
$('<span>').text(lineText.substring(1)).appendTo(line);
|
var prefixEnd = 1;
|
||||||
|
if (isConflict) {
|
||||||
|
prefixEnd = 2;
|
||||||
|
}
|
||||||
|
if (!isMergeHeader) {
|
||||||
|
var changeMarker = lineText[0];
|
||||||
|
if (isConflict && !commitOptions.unmerged && changeMarker === ' ') {
|
||||||
|
changeMarker = lineText[1];
|
||||||
|
}
|
||||||
|
$('<span class="prefix">').text(changeMarker).appendTo(line);
|
||||||
|
var handledlLine = false;
|
||||||
|
if (isConflict && commitOptions.unmerged) {
|
||||||
|
$('<span class="prefix">').text(lineText[1]).appendTo(line);
|
||||||
if (lineText[0] === '+') {
|
if (lineText[0] === '+') {
|
||||||
|
localLineNo.text(localLine++);
|
||||||
|
handledlLine = true;
|
||||||
|
}
|
||||||
|
if (lineText[1] === '+') {
|
||||||
|
remoteLineNo.text(remoteLine++);
|
||||||
|
handledlLine = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lineText[0] === '+' || (isConflict && lineText[1] === '+')) {
|
||||||
localLineNo.addClass("added");
|
localLineNo.addClass("added");
|
||||||
remoteLineNo.addClass("added");
|
remoteLineNo.addClass("added");
|
||||||
line.addClass("added");
|
line.addClass("added");
|
||||||
remoteLineNo.text(remoteLine++);
|
remoteLineNo.text(remoteLine++);
|
||||||
} else if (lineText[0] === '-') {
|
handledlLine = true;
|
||||||
|
} else if (lineText[0] === '-' || (isConflict && lineText[1] === '-')) {
|
||||||
localLineNo.addClass("removed");
|
localLineNo.addClass("removed");
|
||||||
remoteLineNo.addClass("removed");
|
remoteLineNo.addClass("removed");
|
||||||
line.addClass("removed");
|
line.addClass("removed");
|
||||||
localLineNo.text(localLine++);
|
localLineNo.text(localLine++);
|
||||||
} else {
|
handledlLine = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!handledlLine) {
|
||||||
line.addClass("unchanged");
|
line.addClass("unchanged");
|
||||||
if (localLine > 0 && lineText[0] !== '\\' && lineText !== "") {
|
if (localLine > 0 && lineText[0] !== '\\' && lineText !== "") {
|
||||||
localLineNo.text(localLine++);
|
localLineNo.text(localLine++);
|
||||||
@ -1780,7 +1819,69 @@ RED.diff = (function() {
|
|||||||
remoteLineNo.text(remoteLine++);
|
remoteLineNo.text(remoteLine++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$('<span>').text(lineText.substring(prefixEnd)).appendTo(line);
|
||||||
|
} else {
|
||||||
|
diffRow.addClass("mergeHeader");
|
||||||
|
var isSeparator = /^..(=======$)/.test(lineText);
|
||||||
|
if (!isSeparator) {
|
||||||
|
var isOurs = /^..<<<<<<</.test(lineText);
|
||||||
|
if (isOurs) {
|
||||||
|
$('<span>').text("<<<<<<< Local Changes").appendTo(line);
|
||||||
|
hunk.localChangeStart = actualLineNumber;
|
||||||
|
} else {
|
||||||
|
hunk.remoteChangeEnd = actualLineNumber;
|
||||||
|
$('<span>').text(">>>>>>> Remote Changes").appendTo(line);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
diffRow.addClass("mergeHeader-"+(isOurs?"ours":"theirs"));
|
||||||
|
$('<button class="editor-button editor-button-small" style="float: right; margin-right: 20px;"><i class="fa fa-angle-double-'+(isOurs?"down":"up")+'"></i> use '+(isOurs?"local":"remote")+' changes</button>')
|
||||||
|
.appendTo(line)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
resolvedConflicts++;
|
||||||
|
var addedRows;
|
||||||
|
var midRow;
|
||||||
|
if (isOurs) {
|
||||||
|
addedRows = diffRow.nextUntil(".mergeHeader-separator");
|
||||||
|
midRow = addedRows.last().next();
|
||||||
|
midRow.nextUntil(".mergeHeader").remove();
|
||||||
|
midRow.next().remove();
|
||||||
|
} else {
|
||||||
|
addedRows = diffRow.prevUntil(".mergeHeader-separator");
|
||||||
|
midRow = addedRows.last().prev();
|
||||||
|
midRow.prevUntil(".mergeHeader").remove();
|
||||||
|
midRow.prev().remove();
|
||||||
|
}
|
||||||
|
midRow.remove();
|
||||||
|
diffRow.remove();
|
||||||
|
addedRows.find(".linetext").addClass('added');
|
||||||
|
conflictHeader.empty();
|
||||||
|
$('<span><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(conflictHeader);
|
||||||
|
|
||||||
|
conflictResolutions[file.file] = conflictResolutions[file.file] || {};
|
||||||
|
conflictResolutions[file.file][hunk.localChangeStart] = {
|
||||||
|
changeStart: hunk.localChangeStart,
|
||||||
|
separator: hunk.changeSeparator,
|
||||||
|
changeEnd: hunk.remoteChangeEnd,
|
||||||
|
selection: isOurs?"A":"B"
|
||||||
|
}
|
||||||
|
if (commitOptions.resolveConflict) {
|
||||||
|
commitOptions.resolveConflict({
|
||||||
|
conflicts: unresolvedConflicts,
|
||||||
|
resolved: resolvedConflicts,
|
||||||
|
resolutions: conflictResolutions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
hunk.changeSeparator = actualLineNumber;
|
||||||
|
diffRow.addClass("mergeHeader-separator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (commitOptions.unmerged) {
|
||||||
|
conflictHeader = $('<span style="float: right;"><span>'+resolvedConflicts+'</span> of <span>'+unresolvedConflicts+'</span> conflicts resolved</span>').appendTo(content);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return diffPanel;
|
return diffPanel;
|
||||||
@ -1820,8 +1921,9 @@ RED.diff = (function() {
|
|||||||
$('<div style="float: right">').text("Commit "+commit.sha).appendTo(summary);
|
$('<div style="float: right">').text("Commit "+commit.sha).appendTo(summary);
|
||||||
$('<div>').text((commit.authorName||commit.author)+" - "+options.date).appendTo(summary);
|
$('<div>').text((commit.authorName||commit.author)+" - "+options.date).appendTo(summary);
|
||||||
|
|
||||||
|
if (commit.files) {
|
||||||
createUnifiedDiffTable(commit.files,options).appendTo(diffPanel);
|
createUnifiedDiffTable(commit.files,options).appendTo(diffPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -1837,16 +1939,30 @@ RED.diff = (function() {
|
|||||||
function showUnifiedDiff(options) {
|
function showUnifiedDiff(options) {
|
||||||
var diff = options.diff;
|
var diff = options.diff;
|
||||||
var title = options.title;
|
var title = options.title;
|
||||||
|
|
||||||
var files = parseUnifiedDiff(diff);
|
var files = parseUnifiedDiff(diff);
|
||||||
|
|
||||||
|
var currentResolution;
|
||||||
|
if (options.unmerged) {
|
||||||
|
options.resolveConflict = function(results) {
|
||||||
|
currentResolution = results;
|
||||||
|
if (results.conflicts === results.resolved) {
|
||||||
|
$("#node-diff-view-resolve-diff").removeClass('disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var trayOptions = {
|
var trayOptions = {
|
||||||
title: title||"Compare Changes", //TODO: nls
|
title: title||"Compare Changes", //TODO: nls
|
||||||
width: Infinity,
|
width: Infinity,
|
||||||
overlay: true,
|
overlay: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: RED._("common.label.close"),
|
text: RED._((options.unmerged)?"common.label.cancel":"common.label.close"),
|
||||||
click: function() {
|
click: function() {
|
||||||
|
if (options.oncancel) {
|
||||||
|
options.oncancel();
|
||||||
|
}
|
||||||
RED.tray.close();
|
RED.tray.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1858,8 +1974,6 @@ RED.diff = (function() {
|
|||||||
var trayBody = tray.find('.editor-tray-body');
|
var trayBody = tray.find('.editor-tray-body');
|
||||||
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
|
var diffPanel = $('<div class="node-text-diff"></div>').appendTo(trayBody);
|
||||||
createUnifiedDiffTable(files,options).appendTo(diffPanel);
|
createUnifiedDiffTable(files,options).appendTo(diffPanel);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
diffVisible = false;
|
diffVisible = false;
|
||||||
@ -1868,6 +1982,23 @@ RED.diff = (function() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options.unmerged) {
|
||||||
|
trayOptions.buttons.push(
|
||||||
|
{
|
||||||
|
id: "node-diff-view-resolve-diff",
|
||||||
|
text: "Save conflict resolution",
|
||||||
|
class: "primary disabled",
|
||||||
|
click: function() {
|
||||||
|
if (!$("#node-diff-view-resolve-diff").hasClass('disabled')) {
|
||||||
|
if (options.onresolve) {
|
||||||
|
options.onresolve(currentResolution);
|
||||||
|
}
|
||||||
|
RED.tray.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
RED.tray.show(trayOptions);
|
RED.tray.show(trayOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1912,6 +2043,7 @@ RED.diff = (function() {
|
|||||||
}
|
}
|
||||||
var fileHeader = /^\+\+\+ b\/(.*)\t?/;
|
var fileHeader = /^\+\+\+ b\/(.*)\t?/;
|
||||||
var hunkHeader = /^@@ -((\d+)(,(\d+))?) \+((\d+)(,(\d+))?) @@ ?(.*)$/;
|
var hunkHeader = /^@@ -((\d+)(,(\d+))?) \+((\d+)(,(\d+))?) @@ ?(.*)$/;
|
||||||
|
var conflictHunkHeader = /^@+ -((\d+)(,(\d+))?) -((\d+)(,(\d+))?) \+((\d+)(,(\d+))?) @+/;
|
||||||
var files = [];
|
var files = [];
|
||||||
var currentFile;
|
var currentFile;
|
||||||
var hunks = [];
|
var hunks = [];
|
||||||
@ -1944,9 +2076,29 @@ RED.diff = (function() {
|
|||||||
localLength: hunkLine[4]||1,
|
localLength: hunkLine[4]||1,
|
||||||
remoteStartLine: hunkLine[6],
|
remoteStartLine: hunkLine[6],
|
||||||
remoteLength: hunkLine[8]||1,
|
remoteLength: hunkLine[8]||1,
|
||||||
lines: []
|
lines: [],
|
||||||
|
conflict: false
|
||||||
}
|
}
|
||||||
} else if (currentHunk) {
|
continue;
|
||||||
|
}
|
||||||
|
hunkLine = conflictHunkHeader.exec(line);
|
||||||
|
if (hunkLine) {
|
||||||
|
if (currentHunk) {
|
||||||
|
currentFile.hunks.push(currentHunk);
|
||||||
|
}
|
||||||
|
currentHunk = {
|
||||||
|
header: line,
|
||||||
|
localStartLine: hunkLine[2],
|
||||||
|
localLength: hunkLine[4]||1,
|
||||||
|
remoteStartLine: hunkLine[6],
|
||||||
|
remoteLength: hunkLine[8]||1,
|
||||||
|
diffStart: parseInt(hunkLine[10]),
|
||||||
|
lines: [],
|
||||||
|
conflict: true
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (currentHunk) {
|
||||||
currentHunk.lines.push(line);
|
currentHunk.lines.push(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ RED.notify = (function() {
|
|||||||
window.clearTimeout(nn.timeoutid);
|
window.clearTimeout(nn.timeoutid);
|
||||||
};
|
};
|
||||||
})());
|
})());
|
||||||
n.timeoutid = window.setTimeout(n.close,timeout||3000);
|
n.timeoutid = window.setTimeout(n.close,timeout||5000);
|
||||||
}
|
}
|
||||||
currentNotifications.push(n);
|
currentNotifications.push(n);
|
||||||
c+=1;
|
c+=1;
|
||||||
|
@ -110,17 +110,13 @@ RED.projects.settings = (function() {
|
|||||||
RED.tray.show(trayOptions);
|
RED.tray.show(trayOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSpinnerOverlay(container) {
|
|
||||||
var spinner = $('<div class="projects-dialog-spinner projects-dialog-spinner-sidebar"><img src="red/images/spin.svg"/></div>').appendTo(container);
|
|
||||||
return spinner;
|
|
||||||
}
|
|
||||||
function editDescription(activeProject, container) {
|
function editDescription(activeProject, container) {
|
||||||
RED.editor.editMarkdown({
|
RED.editor.editMarkdown({
|
||||||
title: RED._('sidebar.project.editDescription'),
|
title: RED._('sidebar.project.editDescription'),
|
||||||
value: activeProject.description,
|
value: activeProject.description,
|
||||||
complete: function(v) {
|
complete: function(v) {
|
||||||
container.empty();
|
container.empty();
|
||||||
var spinner = addSpinnerOverlay(container);
|
var spinner = utils.addSpinnerOverlay(container);
|
||||||
var done = function(err,res) {
|
var done = function(err,res) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return editDescription(activeProject, container);
|
return editDescription(activeProject, container);
|
||||||
@ -176,7 +172,7 @@ RED.projects.settings = (function() {
|
|||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
var v = input.val();
|
var v = input.val();
|
||||||
updateProjectSummary(v, container);
|
updateProjectSummary(v, container);
|
||||||
var spinner = addSpinnerOverlay(container);
|
var spinner = utils.addSpinnerOverlay(container);
|
||||||
var done = function(err,res) {
|
var done = function(err,res) {
|
||||||
if (err) {
|
if (err) {
|
||||||
spinner.remove();
|
spinner.remove();
|
||||||
@ -307,7 +303,7 @@ RED.projects.settings = (function() {
|
|||||||
complete: function(v) {
|
complete: function(v) {
|
||||||
try {
|
try {
|
||||||
var parsed = JSON.parse(v);
|
var parsed = JSON.parse(v);
|
||||||
var spinner = addSpinnerOverlay(container);
|
var spinner = utils.addSpinnerOverlay(container);
|
||||||
|
|
||||||
var done = function(err,res) {
|
var done = function(err,res) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -427,9 +423,8 @@ RED.projects.settings = (function() {
|
|||||||
var dialogBody;
|
var dialogBody;
|
||||||
var filesList;
|
var filesList;
|
||||||
var selected;
|
var selected;
|
||||||
var container = $('<div class="project-file-listing-container"></div>',{style:"position: relative; min-height: 175px; height: 175px;"}).appendTo(row);
|
var container = $('<div class="project-file-listing-container"></div>',{style:"position: relative; min-height: 175px; height: 175px;"}).hide().appendTo(row);
|
||||||
var spinner = addSpinnerOverlay(container);
|
var spinner = utils.addSpinnerOverlay(container);
|
||||||
|
|
||||||
$.getJSON("/projects/"+activeProject.name+"/files",function(result) {
|
$.getJSON("/projects/"+activeProject.name+"/files",function(result) {
|
||||||
var fileNames = Object.keys(result);
|
var fileNames = Object.keys(result);
|
||||||
var files = {};
|
var files = {};
|
||||||
@ -467,7 +462,9 @@ RED.projects.settings = (function() {
|
|||||||
createFileSubList(container,files.children,current,done,"height: 175px");
|
createFileSubList(container,files.children,current,done,"height: 175px");
|
||||||
spinner.remove();
|
spinner.remove();
|
||||||
});
|
});
|
||||||
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFileSubList(container, files, current, onselect, style) {
|
function createFileSubList(container, files, current, onselect, style) {
|
||||||
style = style || "";
|
style = style || "";
|
||||||
var list = $('<ol>',{class:"projects-dialog-file-list", style:style}).appendTo(container).editableList({
|
var list = $('<ol>',{class:"projects-dialog-file-list", style:style}).appendTo(container).editableList({
|
||||||
@ -575,7 +572,7 @@ RED.projects.settings = (function() {
|
|||||||
// evt.preventDefault();
|
// evt.preventDefault();
|
||||||
// var newFlowFile = flowFileInput.val();
|
// var newFlowFile = flowFileInput.val();
|
||||||
// var newCredsFile = credentialsFileInput.val();
|
// var newCredsFile = credentialsFileInput.val();
|
||||||
// var spinner = addSpinnerOverlay(container);
|
// var spinner = utils.addSpinnerOverlay(container);
|
||||||
// var done = function(err,res) {
|
// var done = function(err,res) {
|
||||||
// if (err) {
|
// if (err) {
|
||||||
// spinner.remove();
|
// spinner.remove();
|
||||||
@ -617,12 +614,12 @@ 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("Files").appendTo(pane);
|
||||||
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
var filesContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||||
var editButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
|
var editFilesButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
|
||||||
.appendTo(title)
|
.appendTo(title)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
formButtons.show();
|
formButtons.show();
|
||||||
editButton.hide();
|
editFilesButton.hide();
|
||||||
flowFileLabelText.hide();
|
flowFileLabelText.hide();
|
||||||
flowFileInput.show();
|
flowFileInput.show();
|
||||||
flowFileInputSearch.show();
|
flowFileInputSearch.show();
|
||||||
@ -646,21 +643,21 @@ RED.projects.settings = (function() {
|
|||||||
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);
|
||||||
|
|
||||||
var flowFileInput = $('<input id="" type="text" style="margin-bottom: 0;width: 100%; border: none;">').val(activeProject.files.flow).hide().appendTo(flowFileLabel);
|
var flowFileInput = $('<input id="" type="text" style="margin-bottom: 0;width: 100%; border: none;">').val(activeProject.files.flow).hide().appendTo(flowFileLabel);
|
||||||
var flowFileInputSearch = $('<button class="editor-button" style="width: 36px; height: 36px; position: absolute; top: -1px; right: -1px;"><i class="fa fa-folder-open-o"></i></button>')
|
var flowFileInputSearch = $('<button class="editor-button" 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()
|
.hide()
|
||||||
.appendTo(flowFileLabel)
|
.appendTo(flowFileLabel)
|
||||||
.click(function(e) {
|
.click(function(e) {
|
||||||
if ($(this).hasClass('selected')) {
|
if ($(this).hasClass('selected')) {
|
||||||
$(this).removeClass('selected');
|
$(this).removeClass('selected');
|
||||||
flowFileLabel.find('.project-file-listing-container').remove();
|
flowFileLabel.find('.project-file-listing-container').slideUp(200,function() {
|
||||||
|
$(this).remove();
|
||||||
flowFileLabel.css('height','');
|
flowFileLabel.css('height','');
|
||||||
|
});
|
||||||
flowFileLabel.css('color','');
|
flowFileLabel.css('color','');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$(this).addClass('selected');
|
$(this).addClass('selected');
|
||||||
flowFileLabel.css('height','auto');
|
|
||||||
flowFileLabel.css('color','inherit');
|
flowFileLabel.css('color','inherit');
|
||||||
showProjectFileListing(flowFileLabel,activeProject,flowFileInput.val(),function(result,isDblClick) {
|
var fileList = showProjectFileListing(flowFileLabel,activeProject,flowFileInput.val(),function(result,isDblClick) {
|
||||||
if (result) {
|
if (result) {
|
||||||
flowFileInput.val(result);
|
flowFileInput.val(result);
|
||||||
}
|
}
|
||||||
@ -668,7 +665,12 @@ RED.projects.settings = (function() {
|
|||||||
$(flowFileInputSearch).click();
|
$(flowFileInputSearch).click();
|
||||||
}
|
}
|
||||||
checkFiles();
|
checkFiles();
|
||||||
})
|
});
|
||||||
|
flowFileLabel.css('height','auto');
|
||||||
|
setTimeout(function() {
|
||||||
|
fileList.slideDown(200);
|
||||||
|
},50);
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -748,7 +750,7 @@ RED.projects.settings = (function() {
|
|||||||
}
|
}
|
||||||
checkFiles();
|
checkFiles();
|
||||||
});
|
});
|
||||||
var credentialSecretEditButton = $('<button class="editor-button" style="vertical-align: top; width: 36px; margin-bottom: 10px"><i class="fa fa-pencil"></i></button>')
|
var credentialSecretEditButton = $('<button class="editor-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)
|
.appendTo(credentialSecretButtons)
|
||||||
.click(function(e) {
|
.click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -810,7 +812,7 @@ RED.projects.settings = (function() {
|
|||||||
|
|
||||||
|
|
||||||
var hideEditForm = function() {
|
var hideEditForm = function() {
|
||||||
editButton.show();
|
editFilesButton.show();
|
||||||
formButtons.hide();
|
formButtons.hide();
|
||||||
flowFileLabelText.show();
|
flowFileLabelText.show();
|
||||||
flowFileInput.hide();
|
flowFileInput.hide();
|
||||||
@ -821,6 +823,11 @@ RED.projects.settings = (function() {
|
|||||||
credentialStateLabel.removeClass("uneditable-input");
|
credentialStateLabel.removeClass("uneditable-input");
|
||||||
credentialStateLabel.css('height','');
|
credentialStateLabel.css('height','');
|
||||||
|
|
||||||
|
flowFileInputSearch.removeClass('selected');
|
||||||
|
flowFileLabel.find('.project-file-listing-container').remove();
|
||||||
|
flowFileLabel.css('height','');
|
||||||
|
flowFileLabel.css('color','');
|
||||||
|
|
||||||
$(".user-settings-row-credentials").hide();
|
$(".user-settings-row-credentials").hide();
|
||||||
credentialFormRows.hide();
|
credentialFormRows.hide();
|
||||||
credentialSecretButtons.hide();
|
credentialSecretButtons.hide();
|
||||||
@ -831,7 +838,7 @@ RED.projects.settings = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var formButtons = $('<span class="button-group" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
|
var formButtons = $('<span class="button-group" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(filesContainer);
|
||||||
var cancelButton = $('<button class="editor-button">Cancel</button>')
|
$('<button class="editor-button">Cancel</button>')
|
||||||
.appendTo(formButtons)
|
.appendTo(formButtons)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
@ -841,7 +848,7 @@ RED.projects.settings = (function() {
|
|||||||
.appendTo(formButtons)
|
.appendTo(formButtons)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
var spinner = addSpinnerOverlay(filesContainer);
|
var spinner = utils.addSpinnerOverlay(filesContainer);
|
||||||
var done = function(err) {
|
var done = function(err) {
|
||||||
spinner.remove();
|
spinner.remove();
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -927,9 +934,201 @@ RED.projects.settings = (function() {
|
|||||||
checkFiles();
|
checkFiles();
|
||||||
updateForm();
|
updateForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createLocalRepositorySection(activeProject,pane) {
|
||||||
|
var title = $('<h3></h3>').text("Local Repository").appendTo(pane);
|
||||||
|
var repoContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||||
|
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
|
||||||
|
.appendTo(title)
|
||||||
|
.click(function(evt) {
|
||||||
|
editRepoButton.hide();
|
||||||
|
localRepoSearch.show();
|
||||||
|
formButtons.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
var row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
|
||||||
|
$('<label for=""></label>').text('Branch').appendTo(row);
|
||||||
|
var localRepoLabel = $('<div class="uneditable-input" style="padding:0">').appendTo(row);
|
||||||
|
|
||||||
|
var hideLocalRepoBranchList = function() {
|
||||||
|
localRepoSearch.removeClass('selected');
|
||||||
|
localRepoLabel.css('height','');
|
||||||
|
localRepoBranchListRow.slideUp(100);
|
||||||
|
}
|
||||||
|
var localRepoText = $('<span style="display:inline-block; padding: 6px">').text(activeProject.branches.local).appendTo(localRepoLabel);
|
||||||
|
var localRepoSearch = $('<button class="editor-button" 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-code-fork"></i></button>')
|
||||||
|
.hide()
|
||||||
|
.appendTo(localRepoLabel)
|
||||||
|
.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ($(this).hasClass('selected')) {
|
||||||
|
hideLocalRepoBranchList();
|
||||||
|
} else {
|
||||||
|
$(this).addClass('selected');
|
||||||
|
localRepoLabel.css('height','auto');
|
||||||
|
localRepoBranchListRow.slideDown(100);
|
||||||
|
localRepoBranchList.refresh("/projects/"+activeProject.name+"/branches");
|
||||||
|
localRepoBranchList.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var localRepoBranchListRow = $('<div>').hide().appendTo(localRepoLabel);
|
||||||
|
var localRepoBranchList = utils.createBranchList({
|
||||||
|
current: function() {
|
||||||
|
return activeProject.branches.local
|
||||||
|
},
|
||||||
|
placeholder: "Find or create a branch",
|
||||||
|
container: localRepoBranchListRow,
|
||||||
|
onselect: function(body) {
|
||||||
|
localRepoText.text(body.name);
|
||||||
|
hideLocalRepoBranchList();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var hideEditForm = function() {
|
||||||
|
editRepoButton.show();
|
||||||
|
localRepoSearch.hide();
|
||||||
|
formButtons.hide();
|
||||||
|
localRepoBranchListRow.slideUp(100);
|
||||||
|
localRepoSearch.removeClass('selected');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var formButtons = $('<span class="button-group" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(repoContainer);
|
||||||
|
$('<button class="editor-button">Cancel</button>')
|
||||||
|
.appendTo(formButtons)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
hideEditForm();
|
||||||
|
});
|
||||||
|
var saveButton = $('<button class="editor-button">Save</button>')
|
||||||
|
.appendTo(formButtons)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
hideEditForm();
|
||||||
|
});
|
||||||
|
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("Invalid encryption key");
|
||||||
|
// } 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("Encryption enabled");
|
||||||
|
// } 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("Encryption disabled");
|
||||||
|
// }
|
||||||
|
// credentialSecretResetButton.toggleClass('disabled',!activeProject.settings.credentialsEncrypted);
|
||||||
|
// credentialSecretResetButton.prop('disabled',!activeProject.settings.credentialsEncrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRemoteRepositorySection(activeProject,pane) {
|
||||||
|
var title = $('<h3></h3>').text("Git Remotes").appendTo(pane);
|
||||||
|
var repoContainer = $('<div class="user-settings-section"></div>').appendTo(pane);
|
||||||
|
var editRepoButton = $('<button class="editor-button editor-button-small" style="float: right;">edit</button>')
|
||||||
|
.appendTo(title)
|
||||||
|
.click(function(evt) {
|
||||||
|
editRepoButton.hide();
|
||||||
|
formButtons.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
var row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
|
||||||
|
|
||||||
|
|
||||||
|
var remotesList = $("<ol>",{style:"height: 320px"}).appendTo(row);
|
||||||
|
remotesList.editableList({
|
||||||
|
addButton: "remote",
|
||||||
|
addItem: function(outer,index,entry) {
|
||||||
|
var row = $('<div class="user-settings-row"></div>').appendTo(outer);
|
||||||
|
$('<label for=""></label>').text('Name').appendTo(row);
|
||||||
|
$('<div class="uneditable-input">').text(entry.name).appendTo(row);
|
||||||
|
row = $('<div class="user-settings-row"></div>').appendTo(outer);
|
||||||
|
$('<label for=""></label>').text('Fetch URL').appendTo(row);
|
||||||
|
$('<div class="uneditable-input">').text(entry.urls.fetch).appendTo(row);
|
||||||
|
row = $('<div class="user-settings-row"></div>').appendTo(outer);
|
||||||
|
$('<label for=""></label>').text('Push URL').appendTo(row);
|
||||||
|
$('<div class="uneditable-input">').text(entry.urls.push).appendTo(row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (activeProject.hasOwnProperty('remotes')) {
|
||||||
|
for (var name in activeProject.remotes) {
|
||||||
|
if (activeProject.remotes.hasOwnProperty(name)) {
|
||||||
|
remotesList.editableList('addItem',{name:name,urls:activeProject.remotes[name]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
|
||||||
|
|
||||||
|
// if (activeProject.hasOwnProperty('remotes')) {
|
||||||
|
// $('<label for=""></label>').text('URL').appendTo(row);
|
||||||
|
// for (var name in activeProject.remotes) {
|
||||||
|
// if (activeProject.remotes.hasOwnProperty(name)) {
|
||||||
|
// var repos = activeProject.remotes[name];
|
||||||
|
// if (repos.fetch === repos.push) {
|
||||||
|
// $('<div class="uneditable-input">').text(repos.fetch).appendTo(row);
|
||||||
|
// $('<div class="projects-edit-form-sublabel"><small></small></div>').appendTo(row).find('small').text(name+" fetch/push");
|
||||||
|
// } else {
|
||||||
|
// $('<div class="uneditable-input">').text(repos.fetch).appendTo(row);
|
||||||
|
// $('<div class="projects-edit-form-sublabel"><small></small></div>').appendTo(row).find('small').text(name+" fetch");
|
||||||
|
// $('<label for=""></label>').appendTo(row);
|
||||||
|
// $('<div class="uneditable-input">').text(repos.push).appendTo(row);
|
||||||
|
// $('<div class="projects-edit-form-sublabel"><small></small></div>').appendTo(row).find('small').text(name+" push");
|
||||||
|
// // $('<span>').text(repos.fetch+" (fetch)").appendTo(repoRow);
|
||||||
|
// // $('<span>').text(repos.push+" (push)").appendTo(repoRow);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (activeProject.branches.hasOwnProperty('remote')) {
|
||||||
|
// row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
|
||||||
|
// $('<label for="" style="text-align: right;box-sizing: border-box; padding-right: 25px;">Branch</label>').appendTo(row);
|
||||||
|
// $('<div class="uneditable-input">').text(activeProject.branches.remote).appendTo(row);
|
||||||
|
//
|
||||||
|
// row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
|
||||||
|
// $('<label for="" style="text-align: right;box-sizing: border-box; padding-right: 25px;">Username</label>').appendTo(row);
|
||||||
|
// $('<div class="uneditable-input">').appendTo(row);
|
||||||
|
//
|
||||||
|
// row = $('<div class="user-settings-row"></div>').appendTo(repoContainer);
|
||||||
|
// $('<label for="" style="text-align: right;box-sizing: border-box; padding-right: 25px;">Password</label>').appendTo(row);
|
||||||
|
// $('<div class="uneditable-input">').html("• • • • • • • •").appendTo(row);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
var hideEditForm = function() {
|
||||||
|
editRepoButton.show();
|
||||||
|
formButtons.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
var formButtons = $('<span class="button-group" style="position: relative; float: right; margin-right:0;"></span>').hide().appendTo(repoContainer);
|
||||||
|
$('<button class="editor-button">Cancel</button>')
|
||||||
|
.appendTo(formButtons)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
hideEditForm();
|
||||||
|
});
|
||||||
|
var saveButton = $('<button class="editor-button">Save</button>')
|
||||||
|
.appendTo(formButtons)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
hideEditForm();
|
||||||
|
});
|
||||||
|
var updateForm = function() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function createSettingsPane(activeProject) {
|
function createSettingsPane(activeProject) {
|
||||||
var pane = $('<div id="project-settings-tab-settings" class="project-settings-tab-pane node-help"></div>');
|
var pane = $('<div id="project-settings-tab-settings" class="project-settings-tab-pane node-help"></div>');
|
||||||
createFilesSection(activeProject,pane);
|
createFilesSection(activeProject,pane);
|
||||||
|
// createLocalRepositorySection(activeProject,pane);
|
||||||
|
createRemoteRepositorySection(activeProject,pane);
|
||||||
return pane;
|
return pane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,24 +51,61 @@ RED.projects = (function() {
|
|||||||
var copyProject;
|
var copyProject;
|
||||||
var projectRepoInput;
|
var projectRepoInput;
|
||||||
var emptyProjectCredentialInput;
|
var emptyProjectCredentialInput;
|
||||||
|
var projectRepoUserInput;
|
||||||
|
var projectRepoPasswordInput;
|
||||||
|
var projectNameSublabel;
|
||||||
|
var projectRepoPassphrase;
|
||||||
|
var projectRepoRemoteName
|
||||||
|
var projectRepoBranch;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: "Create a new project", // TODO: NLS
|
title: "Create a new project", // TODO: NLS
|
||||||
content: function() {
|
content: function() {
|
||||||
|
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 container = $('<div class="projects-dialog-screen-create"></div>');
|
var container = $('<div class="projects-dialog-screen-create"></div>');
|
||||||
var row;
|
var row;
|
||||||
|
|
||||||
var validateForm = function() {
|
var validateForm = function() {
|
||||||
var projectName = projectNameInput.val();
|
var projectName = projectNameInput.val();
|
||||||
var valid = true;
|
var valid = true;
|
||||||
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName)) {
|
|
||||||
if (projectNameInputChanged) {
|
if (projectNameInputChanged) {
|
||||||
projectNameInput.addClass("input-error");
|
if (projectList === null) {
|
||||||
|
pendingFormValidation = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
projectNameStatus.empty();
|
||||||
|
if (!/^[a-zA-Z0-9\-_]+$/.test(projectName) || projectList[projectName]) {
|
||||||
|
projectNameInput.addClass("input-error");
|
||||||
|
$('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>').appendTo(projectNameStatus);
|
||||||
|
projectNameValid = false;
|
||||||
valid = false;
|
valid = false;
|
||||||
|
if (projectList[projectName]) {
|
||||||
|
projectNameSublabel.text("Project already exists");
|
||||||
|
} else {
|
||||||
|
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
projectNameInput.removeClass("input-error");
|
projectNameInput.removeClass("input-error");
|
||||||
|
$('<i style="margin-top: 8px;" class="fa fa-check"></i>').appendTo(projectNameStatus);
|
||||||
|
projectNameSublabel.text("Must contain only A-Z 0-9 _ -");
|
||||||
|
projectNameValid = true;
|
||||||
}
|
}
|
||||||
|
projectNameLastChecked = projectName;
|
||||||
|
}
|
||||||
|
valid = projectNameValid;
|
||||||
|
|
||||||
var projectType = $(".projects-dialog-screen-create-type.selected").data('type');
|
var projectType = $(".projects-dialog-screen-create-type.selected").data('type');
|
||||||
if (projectType === 'copy') {
|
if (projectType === 'copy') {
|
||||||
if (!copyProject) {
|
if (!copyProject) {
|
||||||
@ -76,19 +113,43 @@ RED.projects = (function() {
|
|||||||
}
|
}
|
||||||
} else if (projectType === 'clone') {
|
} else if (projectType === 'clone') {
|
||||||
var repo = projectRepoInput.val();
|
var repo = projectRepoInput.val();
|
||||||
if (repo.trim() === '') {
|
|
||||||
// TODO: could do more url regex checking...
|
var validRepo = /^(?:git|ssh|https?|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?[\w\.@:\/~_-]+\.git(?:\/?|\#[\d\w\.\-_]+?)$/.test(repo);
|
||||||
|
if (!validRepo) {
|
||||||
if (projectRepoChanged) {
|
if (projectRepoChanged) {
|
||||||
projectRepoInput.addClass("input-error");
|
projectRepoInput.addClass("input-error");
|
||||||
}
|
}
|
||||||
valid = false;
|
valid = false;
|
||||||
} else {
|
} else {
|
||||||
projectRepoInput.removeClass("input-error");
|
projectRepoInput.removeClass("input-error");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (/^(?:ssh|[\d\w\.\-_]+@[\w\.]+):(?:\/\/)?/.test(repo)) {
|
||||||
|
$(".projects-dialog-screen-create-row-creds").hide();
|
||||||
|
$(".projects-dialog-screen-create-row-passphrase").show();
|
||||||
|
} else if (/^https?:\/\//.test(repo)) {
|
||||||
|
$(".projects-dialog-screen-create-row-creds").show();
|
||||||
|
$(".projects-dialog-screen-create-row-passphrase").hide();
|
||||||
|
} else {
|
||||||
|
$(".projects-dialog-screen-create-row-creds").show();
|
||||||
|
$(".projects-dialog-screen-create-row-passphrase").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else if (projectType === 'empty') {
|
} else if (projectType === 'empty') {
|
||||||
projectFlowFileInput.toggleClass("input-error",projectFlowFileInput.val()==='')
|
var flowFile = projectFlowFileInput.val();
|
||||||
valid = valid && projectFlowFileInput.val()!=='';
|
if (flowFile === "" || !/\.json$/.test(flowFile)) {
|
||||||
|
valid = false;
|
||||||
|
if (!projectFlowFileInput.hasClass("input-error")) {
|
||||||
|
projectFlowFileInput.addClass("input-error");
|
||||||
|
projectFlowFileInput.next().empty().append('<i style="margin-top: 8px;" class="fa fa-exclamation-triangle"></i>');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (projectFlowFileInput.hasClass("input-error")) {
|
||||||
|
projectFlowFileInput.removeClass("input-error");
|
||||||
|
projectFlowFileInput.next().empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var encryptionState = $("input[name=projects-encryption-type]:checked").val();
|
var encryptionState = $("input[name=projects-encryption-type]:checked").val();
|
||||||
if (encryptionState === 'enabled') {
|
if (encryptionState === 'enabled') {
|
||||||
var encryptionKeyType = $("input[name=projects-encryption-key]:checked").val();
|
var encryptionKeyType = $("input[name=projects-encryption-key]:checked").val();
|
||||||
@ -103,7 +164,7 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
row = $('<div class="form-row button-group"></div>').appendTo(container);
|
row = $('<div class="form-row button-group"></div>').appendTo(container);
|
||||||
var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type toggle selected"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>Empty Project</button>').appendTo(row);
|
var createAsEmpty = $('<button data-type="empty" class="editor-button projects-dialog-screen-create-type toggle selected"><i class="fa fa-archive fa-2x"></i><i style="position: absolute;" class="fa fa-asterisk"></i><br/>Empty Project</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-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();
|
||||||
@ -116,24 +177,51 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
|
|
||||||
row = $('<div class="form-row"></div>').appendTo(container);
|
row = $('<div class="form-row"></div>').appendTo(container);
|
||||||
$('<label>Project name</label>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-name">Project name</label>').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);
|
||||||
|
var projectNameStatus = $('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||||
|
|
||||||
projectNameInput = $('<input type="text"></input>').appendTo(row);
|
|
||||||
var projectNameInputChanged = false;
|
var projectNameInputChanged = false;
|
||||||
projectNameInput.on("change keyup paste",function() { projectNameInputChanged = true; validateForm(); });
|
var projectNameLastChecked = "";
|
||||||
$('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</small></label>').appendTo(row);
|
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();
|
||||||
|
$('<img src="red/images/spin.svg"/>').appendTo(projectNameStatus);
|
||||||
|
if (projectNameInput.val() === '') {
|
||||||
|
validateForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkProjectName = setTimeout(function() {
|
||||||
|
validateForm();
|
||||||
|
checkProjectName = null;
|
||||||
|
},300)
|
||||||
|
});
|
||||||
|
projectNameSublabel = $('<label class="projects-edit-form-sublabel"><small>Must contain only A-Z 0-9 _ -</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>Description</label>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-desc">Description</label>').appendTo(row);
|
||||||
projectSummaryInput = $('<input 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>Optional</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>Flow file</label>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-file">Flow file</label>').appendTo(row);
|
||||||
projectFlowFileInput = $('<input type="text">').val("flow.json")
|
subrow = $('<div style="position:relative;"></div>').appendTo(row);
|
||||||
|
projectFlowFileInput = $('<input id="projects-dialog-screen-create-project-file" type="text">').val("flow.json")
|
||||||
.on("change keyup paste",validateForm)
|
.on("change keyup paste",validateForm)
|
||||||
.appendTo(row);
|
.appendTo(subrow);
|
||||||
|
$('<div class="projects-dialog-screen-input-status"></div>').appendTo(subrow);
|
||||||
$('<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);
|
||||||
@ -185,7 +273,7 @@ RED.projects = (function() {
|
|||||||
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="form-tips form-warning" style="padding: 15px; margin: 5px;"><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> The credentials file will not be encrypted and its contents easily read</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();
|
||||||
@ -195,29 +283,31 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
|
|
||||||
// Copy Project
|
// Copy Project
|
||||||
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-copy"></div>').appendTo(container);
|
// row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-copy"></div>').appendTo(container);
|
||||||
$('<label> Select project to copy</label>').appendTo(row);
|
// $('<label> Select project to copy</label>').appendTo(row);
|
||||||
var autoInsertedName = "";
|
// createProjectList({
|
||||||
createProjectList({
|
// height: "250px",
|
||||||
height: "250px",
|
// small: true,
|
||||||
small: true,
|
// select: function(project) {
|
||||||
select: function(project) {
|
// copyProject = project;
|
||||||
copyProject = project;
|
// var projectName = projectNameInput.val();
|
||||||
var projectName = projectNameInput.val();
|
// if (projectName === "" || projectName === autoInsertedName) {
|
||||||
if (projectName === "" || projectName === autoInsertedName) {
|
// autoInsertedName = project.name+"-copy";
|
||||||
autoInsertedName = project.name+"-copy";
|
// projectNameInput.val(autoInsertedName);
|
||||||
projectNameInput.val(autoInsertedName);
|
// }
|
||||||
}
|
// validateForm();
|
||||||
validateForm();
|
// }
|
||||||
}
|
// }).appendTo(row);
|
||||||
}).appendTo(row);
|
|
||||||
|
|
||||||
// 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>Git repository URL</label>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-repo">Git repository URL</label>').appendTo(row);
|
||||||
projectRepoInput = $('<input 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 class="projects-edit-form-sublabel"><small>https:// or ssh://</small></label>').appendTo(row);
|
||||||
|
|
||||||
var projectRepoChanged = false;
|
var projectRepoChanged = false;
|
||||||
projectRepoInput.on("change keyup paste",function() {
|
projectRepoInput.on("change keyup paste",function() {
|
||||||
|
projectRepoChanged = true;
|
||||||
var repo = $(this).val();
|
var repo = $(this).val();
|
||||||
var m = /\/([^/]+)\.git/.exec(repo);
|
var m = /\/([^/]+)\.git/.exec(repo);
|
||||||
if (m) {
|
if (m) {
|
||||||
@ -230,10 +320,35 @@ RED.projects = (function() {
|
|||||||
validateForm();
|
validateForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Secret - clone
|
row = $('<div class="hide form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone projects-dialog-screen-create-row-creds"></div>').hide().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);
|
var subrow = $('<div style="width: calc(50% - 10px); display:inline-block;"></div>').appendTo(row);
|
||||||
projectSecretInput = $('<input type="text"></input>').appendTo(row);
|
$('<label for="projects-dialog-screen-create-project-repo-user">Username</label>').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);
|
||||||
|
$('<label for="projects-dialog-screen-create-project-repo-pass">Password</label>').appendTo(subrow);
|
||||||
|
projectRepoPasswordInput = $('<input id="projects-dialog-screen-create-project-repo-pass" type="password"></input>').appendTo(subrow);
|
||||||
|
|
||||||
|
row = $('<div class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-passphrase"></div>').hide().appendTo(container);
|
||||||
|
$('<label for="projects-dialog-screen-create-project-repo-passphrase">SSH key passphrase</label>').appendTo(row);
|
||||||
|
projectRepoPassphrase = $('<input id="projects-dialog-screen-create-project-repo-passphrase" type="password" style="width: calc(100% - 250px);"></input>').appendTo(row);
|
||||||
|
|
||||||
|
// row = $('<div style="width: calc(50% - 10px); display:inline-block;" class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').hide().appendTo(container);
|
||||||
|
// $('<label for="projects-dialog-screen-create-project-repo-remote-name">Remote name</label>').appendTo(row);
|
||||||
|
// projectRepoRemoteName = $('<input id="projects-dialog-screen-create-project-repo-remote-name" type="text" style="width: 100%;"></input>').val("origin").appendTo(row);
|
||||||
|
//
|
||||||
|
// row = $('<div style="width: calc(50% - 10px); margin-left: 20px; display:inline-block;" class="form-row projects-dialog-screen-create-row projects-dialog-screen-create-row-clone"></div>').hide().appendTo(container);
|
||||||
|
// $('<label for="projects-dialog-screen-create-project-repo-branch">Branch</label>').appendTo(row);
|
||||||
|
// projectRepoBranch = $('<input id="projects-dialog-screen-create-project-repo-branch" type="text"></input>').val('master').appendTo(row);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // Secret - clone
|
||||||
|
// 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);
|
||||||
|
// projectSecretInput = $('<input type="text"></input>').appendTo(row);
|
||||||
|
|
||||||
createAsEmpty.click();
|
createAsEmpty.click();
|
||||||
|
|
||||||
@ -280,9 +395,13 @@ RED.projects = (function() {
|
|||||||
} else if (projectType === 'copy') {
|
} else if (projectType === 'copy') {
|
||||||
projectData.copy = copyProject.name;
|
projectData.copy = copyProject.name;
|
||||||
} else if (projectType === 'clone') {
|
} else if (projectType === 'clone') {
|
||||||
projectData.credentialSecret = projectSecretInput.val();
|
// projectData.credentialSecret = projectSecretInput.val();
|
||||||
projectData.remote = {
|
projectData.remote = {
|
||||||
url: projectRepoInput.val()
|
// name: projectRepoRemoteName.val()||'origin',
|
||||||
|
// branch: projectRepoBranch.val()||'master',
|
||||||
|
url: projectRepoInput.val(),
|
||||||
|
username: projectRepoUserInput.val(),
|
||||||
|
password: projectRepoPasswordInput.val()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +423,8 @@ RED.projects = (function() {
|
|||||||
console.log("git error",error);
|
console.log("git error",error);
|
||||||
},
|
},
|
||||||
'git_auth_failed': function(error) {
|
'git_auth_failed': function(error) {
|
||||||
|
projectRepoUserInput.addClass("input-error");
|
||||||
|
projectRepoPasswordInput.addClass("input-error");
|
||||||
// getRepoAuthDetails(req);
|
// getRepoAuthDetails(req);
|
||||||
console.log("git auth error",error);
|
console.log("git auth error",error);
|
||||||
},
|
},
|
||||||
@ -551,6 +672,115 @@ RED.projects = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBranchList(options) {
|
||||||
|
var branchFilterTerm = "";
|
||||||
|
var branchFilterCreateItem;
|
||||||
|
var branches = [];
|
||||||
|
var currentBranch;
|
||||||
|
var branchPrefix = "";
|
||||||
|
var container = $('<div class="projects-branch-list">').appendTo(options.container);
|
||||||
|
|
||||||
|
var branchFilter = $('<input type="text">').attr('placeholder',options.placeholder).appendTo(container).searchBox({
|
||||||
|
delay: 200,
|
||||||
|
change: function() {
|
||||||
|
branchFilterTerm = $(this).val();
|
||||||
|
if (/(\.\.|\/\.|[?*[~^: \\]|\/\/|\/.$|\/$)/.test(branchFilterTerm)) {
|
||||||
|
if (!branchFilterCreateItem.hasClass("input-error")) {
|
||||||
|
branchFilterCreateItem.addClass("input-error");
|
||||||
|
branchFilterCreateItem.find("i").addClass("fa-warning").removeClass("fa-code-fork");
|
||||||
|
}
|
||||||
|
branchFilterCreateItem.find("span").text("Invalid branch: "+branchPrefix+branchFilterTerm);
|
||||||
|
} else {
|
||||||
|
if (branchFilterCreateItem.hasClass("input-error")) {
|
||||||
|
branchFilterCreateItem.removeClass("input-error");
|
||||||
|
branchFilterCreateItem.find("i").removeClass("fa-warning").addClass("fa-code-fork");
|
||||||
|
}
|
||||||
|
branchFilterCreateItem.find(".sidebar-version-control-branch-list-entry-create-name").text(branchPrefix+branchFilterTerm);
|
||||||
|
}
|
||||||
|
branchList.editableList("filter");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var branchList = $("<ol>",{style:"height: 130px;"}).appendTo(container);
|
||||||
|
branchList.editableList({
|
||||||
|
addButton: false,
|
||||||
|
scrollOnAdd: false,
|
||||||
|
addItem: function(row,index,entry) {
|
||||||
|
var container = $('<div class="sidebar-version-control-branch-list-entry">').appendTo(row);
|
||||||
|
if (typeof entry !== "string") {
|
||||||
|
branchFilterCreateItem = container;
|
||||||
|
$('<i class="fa fa-code-fork"></i>').appendTo(container);
|
||||||
|
$('<span>').text("Create branch:").appendTo(container);
|
||||||
|
$('<div class="sidebar-version-control-branch-list-entry-create-name" style="margin-left: 10px;">').text(entry.name).appendTo(container);
|
||||||
|
} else {
|
||||||
|
$('<i class="fa fa-code-fork"></i>').appendTo(container);
|
||||||
|
$('<span>').text(entry).appendTo(container);
|
||||||
|
if (currentBranch === entry) {
|
||||||
|
container.addClass("selected");
|
||||||
|
$('<span class="current"></span>').text(options.currentLabel||"current").appendTo(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('input-error')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var body = {};
|
||||||
|
if (typeof entry !== "string") {
|
||||||
|
body.name = branchFilter.val();
|
||||||
|
body.create = true;
|
||||||
|
if (options.remote) {
|
||||||
|
body.name = options.remote()+"/"+body.name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($(this).hasClass('selected')) {
|
||||||
|
body.current = true;
|
||||||
|
}
|
||||||
|
body.name = entry;
|
||||||
|
}
|
||||||
|
if (options.onselect) {
|
||||||
|
options.onselect(body);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
filter: function(data) {
|
||||||
|
var isCreateEntry = (typeof data !=="string");
|
||||||
|
return (isCreateEntry && (branchFilterTerm !== "" && branches.indexOf(branchPrefix+branchFilterTerm) === -1) ) || (!isCreateEntry && data.indexOf(branchPrefix+branchFilterTerm) !== -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
refresh: function(url) {
|
||||||
|
branchFilter.searchBox("value","");
|
||||||
|
branchList.editableList('empty');
|
||||||
|
var start = Date.now();
|
||||||
|
var spinner = addSpinnerOverlay(container).addClass("projects-dialog-spinner-contain");
|
||||||
|
currentBranch = options.current();
|
||||||
|
if (options.remote) {
|
||||||
|
branchPrefix = options.remote()+"/";
|
||||||
|
} else {
|
||||||
|
branchPrefix = "";
|
||||||
|
}
|
||||||
|
$.getJSON(url,function(result) {
|
||||||
|
branches = result.branches;
|
||||||
|
result.branches.forEach(function(b) {
|
||||||
|
branchList.editableList('addItem',b);
|
||||||
|
});
|
||||||
|
branchList.editableList('addItem',{});
|
||||||
|
setTimeout(function() {
|
||||||
|
spinner.remove();
|
||||||
|
},Math.max(300-(Date.now() - start),0));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addItem: function(data) { branchList.editableList('addItem',data) },
|
||||||
|
filter: function() { branchList.editableList('filter') },
|
||||||
|
focus: function() { branchFilter.focus() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSpinnerOverlay(container) {
|
||||||
|
var spinner = $('<div class="projects-dialog-spinner"><img src="red/images/spin.svg"/></div>').appendTo(container);
|
||||||
|
return spinner;
|
||||||
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
dialog = $('<div id="projects-dialog" class="hide node-red-dialog projects-edit-form"><form class="form-horizontal"></form><div class="projects-dialog-spinner hide"><img src="red/images/spin.svg"/></div></div>')
|
dialog = $('<div id="projects-dialog" class="hide node-red-dialog projects-edit-form"><form class="form-horizontal"></form><div class="projects-dialog-spinner hide"><img src="red/images/spin.svg"/></div></div>')
|
||||||
.appendTo("body")
|
.appendTo("body")
|
||||||
@ -577,9 +807,13 @@ RED.projects = (function() {
|
|||||||
|
|
||||||
RED.actions.add("core:new-project",RED.projects.newProject);
|
RED.actions.add("core:new-project",RED.projects.newProject);
|
||||||
RED.actions.add("core:open-project",RED.projects.selectProject);
|
RED.actions.add("core:open-project",RED.projects.selectProject);
|
||||||
|
var projectsAPI = {
|
||||||
RED.projects.settings.init({sendRequest:sendRequest});
|
sendRequest:sendRequest,
|
||||||
RED.sidebar.versionControl.init({sendRequest:sendRequest});
|
createBranchList:createBranchList,
|
||||||
|
addSpinnerOverlay:addSpinnerOverlay
|
||||||
|
};
|
||||||
|
RED.projects.settings.init(projectsAPI);
|
||||||
|
RED.sidebar.versionControl.init(projectsAPI);
|
||||||
initScreens();
|
initScreens();
|
||||||
// initSidebar();
|
// initSidebar();
|
||||||
}
|
}
|
||||||
@ -589,6 +823,7 @@ RED.projects = (function() {
|
|||||||
$.getJSON("projects",function(data) {
|
$.getJSON("projects",function(data) {
|
||||||
if (data.active) {
|
if (data.active) {
|
||||||
$.getJSON("projects/"+data.active, function(project) {
|
$.getJSON("projects/"+data.active, function(project) {
|
||||||
|
console.log(project.branches);
|
||||||
activeProject = project;
|
activeProject = project;
|
||||||
// updateProjectSummary();
|
// updateProjectSummary();
|
||||||
// updateProjectDescription();
|
// updateProjectDescription();
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
**/
|
**/
|
||||||
RED.sidebar.versionControl = (function() {
|
RED.sidebar.versionControl = (function() {
|
||||||
|
|
||||||
var content;
|
var sidebarContent;
|
||||||
var sections;
|
var sections;
|
||||||
|
|
||||||
var allChanges = {};
|
var allChanges = {};
|
||||||
@ -27,17 +27,21 @@ RED.sidebar.versionControl = (function() {
|
|||||||
var unstagedChanges;
|
var unstagedChanges;
|
||||||
var stagedChanges;
|
var stagedChanges;
|
||||||
var bulkChangeSpinner;
|
var bulkChangeSpinner;
|
||||||
|
var unmergedContent;
|
||||||
|
var unmergedChangesList;
|
||||||
var commitButton;
|
var commitButton;
|
||||||
|
var mergeConflictNotification;
|
||||||
|
var localChanges;
|
||||||
|
|
||||||
var localCommitList;
|
var localCommitList;
|
||||||
|
var localCommitListShade;
|
||||||
|
// var remoteCommitList;
|
||||||
|
|
||||||
|
var isMerging;
|
||||||
|
|
||||||
// TODO: DRY projectSummary.js
|
// TODO: DRY projectSummary.js
|
||||||
function addSpinnerOverlay(container) {
|
|
||||||
var spinner = $('<div class="projects-dialog-spinner"><img src="red/images/spin.svg"/></div>').appendTo(container);
|
function createChangeEntry(row, entry, status, state) {
|
||||||
return spinner;
|
|
||||||
}
|
|
||||||
function createChangeEntry(row, entry, status, unstaged) {
|
|
||||||
row.addClass("sidebar-version-control-change-entry");
|
row.addClass("sidebar-version-control-change-entry");
|
||||||
var container = $('<div>').appendTo(row);
|
var container = $('<div>').appendTo(row);
|
||||||
if (entry.label) {
|
if (entry.label) {
|
||||||
@ -51,13 +55,14 @@ RED.sidebar.versionControl = (function() {
|
|||||||
var label = $('<span>').appendTo(container);
|
var label = $('<span>').appendTo(container);
|
||||||
|
|
||||||
var bg = $('<div class="button-group"></div>').appendTo(row);
|
var bg = $('<div class="button-group"></div>').appendTo(row);
|
||||||
var viewDiffButton = $('<button class="editor-button editor-button-small"><i class="fa fa-eye"></i></button>')
|
var viewDiffButton = $('<button class="editor-button editor-button-small"><i class="fa fa-'+(state==='unmerged'?'columns':'eye')+'"></i></button>')
|
||||||
.appendTo(bg)
|
.appendTo(bg)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
var diffTarget = (state === 'staged')?"index":"tree";
|
||||||
utils.sendRequest({
|
utils.sendRequest({
|
||||||
url: "projects/"+activeProject.name+"/diff/"+(unstaged?"tree":"index")+"/"+encodeURIComponent(entry.file),
|
url: "projects/"+activeProject.name+"/diff/"+diffTarget+"/"+encodeURIComponent(entry.file),
|
||||||
type: "GET",
|
type: "GET",
|
||||||
responses: {
|
responses: {
|
||||||
0: function(error) {
|
0: function(error) {
|
||||||
@ -65,17 +70,46 @@ RED.sidebar.versionControl = (function() {
|
|||||||
// done(error,null);
|
// done(error,null);
|
||||||
},
|
},
|
||||||
200: function(data) {
|
200: function(data) {
|
||||||
|
if (mergeConflictNotification) {
|
||||||
|
mergeConflictNotification.close();
|
||||||
|
mergeConflictNotification = null;
|
||||||
|
}
|
||||||
|
var title;
|
||||||
|
if (state === 'unstaged') {
|
||||||
|
title = 'Unstaged changes : '+entry.file
|
||||||
|
} else if (state === 'staged') {
|
||||||
|
title = 'Staged changes : '+entry.file
|
||||||
|
} else {
|
||||||
|
title = 'Resolve conflicts : '+entry.file
|
||||||
|
}
|
||||||
var options = {
|
var options = {
|
||||||
diff: data.diff,
|
diff: data.diff,
|
||||||
title: (unstaged?"Unstaged":"Staged")+" changes : "+entry.file,
|
title: title,
|
||||||
oldRevTitle: unstaged?(entry.indexStatus === " "?"HEAD":"Staged"):"HEAD",
|
unmerged: state === 'unmerged',
|
||||||
newRevTitle: unstaged?"Unstaged":"Staged",
|
|
||||||
oldRev: unstaged?(entry.indexStatus === " "?"@":":0"):"@",
|
|
||||||
newRev: unstaged?"_":":0",
|
|
||||||
project: activeProject
|
project: activeProject
|
||||||
}
|
}
|
||||||
RED.diff.showUnifiedDiff(options);
|
if (state == 'unstaged') {
|
||||||
// console.log(data.diff);
|
options.oldRevTitle = entry.indexStatus === " "?"HEAD":"Staged";
|
||||||
|
options.newRevTitle = "Unstaged";
|
||||||
|
options.oldRev = entry.indexStatus === " "?"@":":0";
|
||||||
|
options.newRev = "_";
|
||||||
|
} else if (state === 'staged') {
|
||||||
|
options.oldRevTitle = "HEAD";
|
||||||
|
options.newRevTitle = "Staged";
|
||||||
|
options.oldRev = "@";
|
||||||
|
options.newRev = ":0";
|
||||||
|
} else {
|
||||||
|
options.onresolve = function(resolution) {
|
||||||
|
utils.sendRequest({
|
||||||
|
url: "projects/"+activeProject.name+"/resolve/"+encodeURIComponent(entry.file),
|
||||||
|
type: "POST",
|
||||||
|
responses: {
|
||||||
|
0: function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
},
|
||||||
|
200: function(data) {
|
||||||
|
refresh(true);
|
||||||
},
|
},
|
||||||
400: {
|
400: {
|
||||||
'unexpected_error': function(error) {
|
'unexpected_error': function(error) {
|
||||||
@ -84,18 +118,32 @@ RED.sidebar.versionControl = (function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
},{resolutions:resolution.resolutions[entry.file]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options.oncancel = showMergeConflictNotification;
|
||||||
|
RED.diff.showUnifiedDiff(options);
|
||||||
|
// console.log(data.diff);
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
$('<button class="editor-button editor-button-small"><i class="fa fa-'+(unstaged?"plus":"minus")+'"></i></button>')
|
if (state !== 'unmerged') {
|
||||||
|
$('<button class="editor-button editor-button-small"><i class="fa fa-'+((state==='unstaged')?"plus":"minus")+'"></i></button>')
|
||||||
.appendTo(bg)
|
.appendTo(bg)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
entry.spinner = addSpinnerOverlay(row).addClass('projects-version-control-spinner-sidebar');
|
entry.spinner = utils.addSpinnerOverlay(row).addClass('projects-version-control-spinner-sidebar');
|
||||||
utils.sendRequest({
|
utils.sendRequest({
|
||||||
url: "projects/"+activeProject.name+"/stage/"+encodeURIComponent(entry.file),
|
url: "projects/"+activeProject.name+"/stage/"+encodeURIComponent(entry.file),
|
||||||
type: unstaged?"POST":"DELETE",
|
type: (state==='unstaged')?"POST":"DELETE",
|
||||||
responses: {
|
responses: {
|
||||||
0: function(error) {
|
0: function(error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -113,7 +161,8 @@ RED.sidebar.versionControl = (function() {
|
|||||||
}
|
}
|
||||||
},{});
|
},{});
|
||||||
});
|
});
|
||||||
entry["update"+(unstaged?"Unstaged":"Staged")] = function(entry,status) {
|
}
|
||||||
|
entry["update"+((state==='unstaged')?"Unstaged":"Staged")] = function(entry,status) {
|
||||||
container.removeClass();
|
container.removeClass();
|
||||||
var iconClass = "";
|
var iconClass = "";
|
||||||
if (status === 'A') {
|
if (status === 'A') {
|
||||||
@ -131,6 +180,9 @@ RED.sidebar.versionControl = (function() {
|
|||||||
} else if (status === 'R') {
|
} else if (status === 'R') {
|
||||||
container.addClass("node-diff-changed");
|
container.addClass("node-diff-changed");
|
||||||
iconClass = "fa-toggle-right";
|
iconClass = "fa-toggle-right";
|
||||||
|
} else if (status === 'U') {
|
||||||
|
container.addClass("node-diff-conflicted");
|
||||||
|
iconClass = "fa-exclamation-triangle";
|
||||||
} else {
|
} else {
|
||||||
iconClass = "fa-exclamation-triangle"
|
iconClass = "fa-exclamation-triangle"
|
||||||
}
|
}
|
||||||
@ -157,7 +209,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
.toggleClass('fa-eye-slash',(status === 'D' || status === '?'))
|
.toggleClass('fa-eye-slash',(status === 'D' || status === '?'))
|
||||||
|
|
||||||
}
|
}
|
||||||
entry["update"+(unstaged?"Unstaged":"Staged")](entry, status);
|
entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status);
|
||||||
}
|
}
|
||||||
var utils;
|
var utils;
|
||||||
function init(_utils) {
|
function init(_utils) {
|
||||||
@ -165,15 +217,15 @@ RED.sidebar.versionControl = (function() {
|
|||||||
|
|
||||||
RED.actions.add("core:show-version-control-tab",show);
|
RED.actions.add("core:show-version-control-tab",show);
|
||||||
|
|
||||||
content = $('<div>', {class:"sidebar-version-control"});
|
sidebarContent = $('<div>', {class:"sidebar-version-control"});
|
||||||
var stackContainer = $("<div>",{class:"sidebar-version-control-stack"}).appendTo(content);
|
var stackContainer = $("<div>",{class:"sidebar-version-control-stack"}).appendTo(sidebarContent);
|
||||||
sections = RED.stack.create({
|
sections = RED.stack.create({
|
||||||
container: stackContainer,
|
container: stackContainer,
|
||||||
fill: true,
|
fill: true,
|
||||||
singleExpanded: true
|
singleExpanded: true
|
||||||
});
|
});
|
||||||
|
|
||||||
var localChanges = sections.add({
|
localChanges = sections.add({
|
||||||
title: "Local Changes",
|
title: "Local Changes",
|
||||||
collapsible: true
|
collapsible: true
|
||||||
});
|
});
|
||||||
@ -190,7 +242,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
|
|
||||||
|
|
||||||
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">Unstaged Changes</div>').appendTo(unstagedContent);
|
var header = $('<div class="sidebar-version-control-change-header">Local files</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> all</button>')
|
||||||
.appendTo(header)
|
.appendTo(header)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
@ -206,7 +258,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
addButton: false,
|
addButton: false,
|
||||||
scrollOnAdd: false,
|
scrollOnAdd: false,
|
||||||
addItem: function(row,index,entry) {
|
addItem: function(row,index,entry) {
|
||||||
createChangeEntry(row,entry,entry.treeStatus,true);
|
createChangeEntry(row,entry,entry.treeStatus,'unstaged');
|
||||||
},
|
},
|
||||||
sort: function(A,B) {
|
sort: function(A,B) {
|
||||||
if (A.treeStatus === '?' && B.treeStatus !== '?') {
|
if (A.treeStatus === '?' && B.treeStatus !== '?') {
|
||||||
@ -219,9 +271,58 @@ RED.sidebar.versionControl = (function() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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);
|
||||||
|
bg = $('<div style="float: right"></div>').appendTo(header);
|
||||||
|
var abortMergeButton = $('<button class="editor-button editor-button-small" style="margin-right: 5px;">abort merge</button>')
|
||||||
|
.appendTo(bg)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
var spinner =u(unmergedContent);
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
utils.sendRequest({
|
||||||
|
url: "projects/"+activeProject.name+"/merge",
|
||||||
|
type: "DELETE",
|
||||||
|
responses: {
|
||||||
|
0: function(error) {
|
||||||
|
console.log(error);
|
||||||
|
},
|
||||||
|
200: function(data) {
|
||||||
|
spinner.remove();
|
||||||
|
refresh(true);
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
unmergedChangesList = $("<ol>",{style:"position: absolute; top: 30px; bottom: 0; right:0; left:0;"}).appendTo(unmergedContent);
|
||||||
|
unmergedChangesList.editableList({
|
||||||
|
addButton: false,
|
||||||
|
scrollOnAdd: false,
|
||||||
|
addItem: function(row,index,entry) {
|
||||||
|
createChangeEntry(row,entry,entry.treeStatus,'unmerged');
|
||||||
|
},
|
||||||
|
sort: function(A,B) {
|
||||||
|
if (A.treeStatus === '?' && B.treeStatus !== '?') {
|
||||||
|
return 1;
|
||||||
|
} else if (A.treeStatus !== '?' && B.treeStatus === '?') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return A.file.localeCompare(B.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
var header = $('<div class="sidebar-version-control-change-header">Staged Changes</div>').appendTo(stagedContent);
|
header = $('<div class="sidebar-version-control-change-header">Changes to commit</div>').appendTo(stagedContent);
|
||||||
|
|
||||||
bg = $('<div style="float: right"></div>').appendTo(header);
|
bg = $('<div style="float: right"></div>').appendTo(header);
|
||||||
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;">commit</button>')
|
||||||
@ -232,9 +333,16 @@ RED.sidebar.versionControl = (function() {
|
|||||||
commitMessage.val("");
|
commitMessage.val("");
|
||||||
submitCommitButton.attr("disabled",true);
|
submitCommitButton.attr("disabled",true);
|
||||||
unstagedContent.css("height","30px");
|
unstagedContent.css("height","30px");
|
||||||
|
if (unmergedContent.is(":visible")) {
|
||||||
|
unmergedContent.css("height","30px");
|
||||||
|
stagedContent.css("height","calc(100% - 60px - 175px)");
|
||||||
|
} else {
|
||||||
stagedContent.css("height","calc(100% - 30px - 175px)");
|
stagedContent.css("height","calc(100% - 30px - 175px)");
|
||||||
|
}
|
||||||
commitBox.show();
|
commitBox.show();
|
||||||
|
setTimeout(function() {
|
||||||
commitBox.css("height","175px");
|
commitBox.css("height","175px");
|
||||||
|
},10);
|
||||||
stageAllButton.attr("disabled",true);
|
stageAllButton.attr("disabled",true);
|
||||||
unstageAllButton.attr("disabled",true);
|
unstageAllButton.attr("disabled",true);
|
||||||
commitButton.attr("disabled",true);
|
commitButton.attr("disabled",true);
|
||||||
@ -258,21 +366,21 @@ RED.sidebar.versionControl = (function() {
|
|||||||
addButton: false,
|
addButton: false,
|
||||||
scrollOnAdd: false,
|
scrollOnAdd: false,
|
||||||
addItem: function(row,index,entry) {
|
addItem: function(row,index,entry) {
|
||||||
createChangeEntry(row,entry,entry.indexStatus,false);
|
createChangeEntry(row,entry,entry.indexStatus,'staged');
|
||||||
},
|
},
|
||||||
sort: function(A,B) {
|
sort: function(A,B) {
|
||||||
return A.file.localeCompare(B.file);
|
return A.file.localeCompare(B.file);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
commitBox = $('<div class="sidebar-version-control-change-commit-box"></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>')
|
var commitMessage = $('<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-change-commit-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">Cancel</button>')
|
||||||
.appendTo(commitToolbar)
|
.appendTo(commitToolbar)
|
||||||
@ -280,8 +388,9 @@ RED.sidebar.versionControl = (function() {
|
|||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
commitMessage.val("");
|
commitMessage.val("");
|
||||||
unstagedContent.css("height","");
|
unstagedContent.css("height","");
|
||||||
|
unmergedContent.css("height","");
|
||||||
stagedContent.css("height","");
|
stagedContent.css("height","");
|
||||||
commitBox.css("height","");
|
commitBox.css("height",0);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
commitBox.hide();
|
commitBox.hide();
|
||||||
},200);
|
},200);
|
||||||
@ -293,7 +402,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
.appendTo(commitToolbar)
|
.appendTo(commitToolbar)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
var spinner = addSpinnerOverlay(submitCommitButton).addClass('projects-dialog-spinner-sidebar');
|
var spinner = utils.addSpinnerOverlay(submitCommitButton).addClass('projects-dialog-spinner-sidebar');
|
||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
utils.sendRequest({
|
utils.sendRequest({
|
||||||
url: "projects/"+activeProject.name+"/commit",
|
url: "projects/"+activeProject.name+"/commit",
|
||||||
@ -336,17 +445,66 @@ RED.sidebar.versionControl = (function() {
|
|||||||
refreshLocalCommits();
|
refreshLocalCommits();
|
||||||
})
|
})
|
||||||
|
|
||||||
localCommitList = $("<ol>",{style:"position: absolute; top: 0px; bottom: 0; right:0; left:0;"}).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>')
|
||||||
|
.appendTo(localBranchToolbar)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('selected')) {
|
||||||
|
closeBranchBox();
|
||||||
|
} else {
|
||||||
|
closeRemoteBox();
|
||||||
|
localCommitListShade.show();
|
||||||
|
$(this).addClass('selected');
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
localBranchList.refresh("/projects/"+activeProject.name+"/branches");
|
||||||
|
localBranchBox.show();
|
||||||
|
setTimeout(function() {
|
||||||
|
localBranchBox.css("height","215px");
|
||||||
|
localBranchList.focus();
|
||||||
|
},100);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
var repoStatusButton = $('<button class="editor-button editor-button-small" style="margin-left: 10px;" id="sidebar-version-control-repo-status-button"><i class="fa fa-long-arrow-up"></i> <span id="sidebar-version-control-commits-ahead"></span> <i class="fa fa-long-arrow-down"></i> <span id="sidebar-version-control-commits-behind"></span></button>')
|
||||||
|
.appendTo(localBranchToolbar)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('selected')) {
|
||||||
|
closeRemoteBox();
|
||||||
|
} else {
|
||||||
|
closeBranchBox();
|
||||||
|
localCommitListShade.show();
|
||||||
|
$(this).addClass('selected');
|
||||||
|
remoteBox.show();
|
||||||
|
setTimeout(function() {
|
||||||
|
remoteBox.css("height","265px");
|
||||||
|
},100);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
localCommitList = $("<ol>",{style:"position: absolute; top: 30px; bottom: 0px; right:0; left:0;"}).appendTo(localHistory.content);
|
||||||
|
localCommitListShade = $('<div class="component-shade"></div>').css('top',"30px").hide().appendTo(localHistory.content);
|
||||||
localCommitList.editableList({
|
localCommitList.editableList({
|
||||||
addButton: false,
|
addButton: false,
|
||||||
scrollOnAdd: false,
|
scrollOnAdd: false,
|
||||||
addItem: function(row,index,entry) {
|
addItem: function(row,index,entry) {
|
||||||
row.addClass('sidebar-version-control-commit-entry');
|
row.addClass('sidebar-version-control-commit-entry');
|
||||||
|
if (entry.url) {
|
||||||
|
row.addClass('sidebar-version-control-commit-more');
|
||||||
|
row.text("+ "+(entry.total-entry.totalKnown)+" more commit(s)");
|
||||||
|
row.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
getCommits(entry.url,localCommitList,row,entry.limit,entry.before);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
row.click(function(e) {
|
row.click(function(e) {
|
||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
if (activeProject) {
|
if (activeProject) {
|
||||||
$.getJSON("/projects/"+activeProject.name+"/commits/"+entry.sha,function(result) {
|
$.getJSON("/projects/"+activeProject.name+"/commits/"+entry.sha,function(result) {
|
||||||
result.project = activeProject;
|
result.project = activeProject;
|
||||||
|
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 = "Commit "+entry.sha.substring(0,7)+"~1";
|
||||||
@ -357,24 +515,276 @@ RED.sidebar.versionControl = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
var container = $('<div>').appendTo(row);
|
var container = $('<div>').appendTo(row);
|
||||||
$('<div class="sidebar-version-control-commit-sha">').text(entry.sha.substring(0,7)).appendTo(container);
|
|
||||||
$('<div class="sidebar-version-control-commit-subject">').text(entry.subject).appendTo(container);
|
$('<div class="sidebar-version-control-commit-subject">').text(entry.subject).appendTo(container);
|
||||||
$('<div class="sidebar-version-control-commit-user">').text(entry.author).appendTo(container);
|
if (entry.refs) {
|
||||||
|
var refDiv = $('<div class="sidebar-version-control-commit-refs">').appendTo(container);
|
||||||
|
entry.refs.forEach(function(ref) {
|
||||||
|
var label = ref;
|
||||||
|
if (/HEAD -> /.test(ref)) {
|
||||||
|
label = ref.substring(8);
|
||||||
|
}
|
||||||
|
$('<span class="sidebar-version-control-commit-ref">').text(label).appendTo(refDiv);
|
||||||
|
});
|
||||||
|
row.addClass('sidebar-version-control-commit-head');
|
||||||
|
}
|
||||||
|
$('<div class="sidebar-version-control-commit-sha">').text(entry.sha.substring(0,7)).appendTo(container);
|
||||||
|
// $('<div class="sidebar-version-control-commit-user">').text(entry.author).appendTo(container);
|
||||||
$('<div class="sidebar-version-control-commit-date">').text(humanizeSinceDate(parseInt(entry.date))).appendTo(container);
|
$('<div class="sidebar-version-control-commit-date">').text(humanizeSinceDate(parseInt(entry.date))).appendTo(container);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var remoteHistory = sections.add({
|
|
||||||
title: "Remote History",
|
var closeBranchBox = function(done) {
|
||||||
collapsible: true
|
localBranchButton.removeClass('selected')
|
||||||
|
localBranchBox.css("height","0");
|
||||||
|
localCommitListShade.hide();
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
localBranchBox.hide();
|
||||||
|
if (done) { done() }
|
||||||
|
},200);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
var localBranchList = utils.createBranchList({
|
||||||
|
current: function() {
|
||||||
|
return RED.projects.getActiveProject().branches.local
|
||||||
|
},
|
||||||
|
placeholder: "Find or create a branch",
|
||||||
|
container: localBranchBox,
|
||||||
|
onselect: function(body) {
|
||||||
|
if (body.current) {
|
||||||
|
return closeBranchBox();
|
||||||
|
}
|
||||||
|
var spinner = utils.addSpinnerOverlay(localBranchBox);
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
utils.sendRequest({
|
||||||
|
url: "projects/"+activeProject.name+"/branches",
|
||||||
|
type: "POST",
|
||||||
|
responses: {
|
||||||
|
0: function(error) {
|
||||||
|
spinner.remove();
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
},
|
||||||
|
200: function(data) {
|
||||||
|
RED.projects.refresh(function() {
|
||||||
|
closeBranchBox(function() {
|
||||||
|
spinner.remove();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
spinner.remove();
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},body);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var remoteBox = $('<div class="sidebar-version-control-slide-box sidebar-version-control-slide-box-top" style="top:30px"></div>').hide().appendTo(localHistory.content);
|
||||||
|
var closeRemoteBox = function() {
|
||||||
|
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked',false);
|
||||||
|
repoStatusButton.removeClass('selected')
|
||||||
|
remoteBox.css("height","0");
|
||||||
|
localCommitListShade.hide();
|
||||||
|
setTimeout(function() {
|
||||||
|
remoteBox.hide();
|
||||||
|
closeRemoteBranchBox();
|
||||||
|
},200);
|
||||||
|
}
|
||||||
|
|
||||||
|
var closeRemoteBranchBox = function(done) {
|
||||||
|
if (remoteBranchButton.hasClass('selected')) {
|
||||||
|
remoteBranchButton.removeClass('selected');
|
||||||
|
remoteBranchSubRow.height(0);
|
||||||
|
remoteBox.css("height","265px");
|
||||||
|
setTimeout(function() {
|
||||||
|
remoteBranchSubRow.hide();
|
||||||
|
if (done) { done(); }
|
||||||
|
},200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('<div class="sidebar-version-control-slide-box-header"></div>').text("Manage remote branch").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>')
|
||||||
|
.appendTo(remoteBranchRow)
|
||||||
|
.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('selected')) {
|
||||||
|
closeRemoteBranchBox();
|
||||||
|
} else {
|
||||||
|
$(this).addClass('selected');
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
remoteBranchList.refresh("/projects/"+activeProject.name+"/branches/remote");
|
||||||
|
remoteBranchSubRow.show();
|
||||||
|
setTimeout(function() {
|
||||||
|
remoteBranchSubRow.height(180);
|
||||||
|
remoteBox.css("height","445px");
|
||||||
|
remoteBranchList.focus();
|
||||||
|
},100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('<div id="sidebar-version-control-repo-toolbar-message" class="sidebar-version-control-slide-box-header" style="min-height: 100px;"></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"> Set as upstream branch</label></div>').appendTo(remoteBox);
|
||||||
|
|
||||||
|
var remoteBranchSubRow = $('<div style="height: 0;overflow:hidden; transition: height 0.2s ease-in-out;"></div>').hide().appendTo(remoteBranchRow);
|
||||||
|
var remoteBranchList = utils.createBranchList({
|
||||||
|
current: function() {
|
||||||
|
return RED.projects.getActiveProject().branches.remote
|
||||||
|
},
|
||||||
|
placeholder: "Find or create a remote branch",
|
||||||
|
currentLabel: "upstream",
|
||||||
|
remote: function() {
|
||||||
|
var project = RED.projects.getActiveProject();
|
||||||
|
var remotes = Object.keys(project.remotes);
|
||||||
|
return remotes[0];
|
||||||
|
},
|
||||||
|
container: remoteBranchSubRow,
|
||||||
|
onselect: function(body) {
|
||||||
|
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked',false);
|
||||||
|
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('disabled',false);
|
||||||
|
$("#sidebar-version-control-remote-branch").text(body.name+(body.create?" *":""));
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
if (activeProject.branches.remote === body.name) {
|
||||||
|
delete activeProject.branches.remoteAlt;
|
||||||
|
} else {
|
||||||
|
activeProject.branches.remoteAlt = body.name;
|
||||||
|
}
|
||||||
|
$("#sidebar-version-control-repo-toolbar-set-upstream-row").toggle(!!activeProject.branches.remoteAlt);
|
||||||
|
closeRemoteBranchBox(function() {
|
||||||
|
if (!body.create) {
|
||||||
|
var start = Date.now();
|
||||||
|
var spinner = utils.addSpinnerOverlay($('#sidebar-version-control-repo-toolbar-message')).addClass("projects-dialog-spinner-contain");
|
||||||
|
$.getJSON("projects/"+activeProject.name+"/branches/remote/"+body.name+"/status", function(result) {
|
||||||
|
setTimeout(function() {
|
||||||
|
updateRemoteStatus(result.commits.ahead, result.commits.behind);
|
||||||
|
spinner.remove();
|
||||||
|
},Math.max(400-(Date.now() - start),0));
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (!activeProject.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-set-upstream").prop('checked',true);
|
||||||
|
$("#sidebar-version-control-repo-toolbar-set-upstream").prop('disabled',true);
|
||||||
|
} 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-pull").attr('disabled',true);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
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>')
|
||||||
|
.appendTo(row)
|
||||||
|
.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var spinner = utils.addSpinnerOverlay(remoteBox).addClass("projects-dialog-spinner-contain");
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
var url = "projects/"+activeProject.name+"/push";
|
||||||
|
if (activeProject.branches.remoteAlt) {
|
||||||
|
url+="/"+activeProject.branches.remoteAlt;
|
||||||
|
}
|
||||||
|
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
|
||||||
|
url+="?u=true"
|
||||||
|
}
|
||||||
|
utils.sendRequest({
|
||||||
|
url: url,
|
||||||
|
type: "POST",
|
||||||
|
responses: {
|
||||||
|
0: function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
},
|
||||||
|
200: function(data) {
|
||||||
|
refresh(true);
|
||||||
|
closeRemoteBox();
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
'git_push_failed': function(err) {
|
||||||
|
// TODO: better message + NLS
|
||||||
|
RED.notify("NLS: Push failed as the remote has more recent commits. Pull first and write a better error message!","error");
|
||||||
|
},
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},{}).always(function() {
|
||||||
|
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>')
|
||||||
|
.appendTo(row)
|
||||||
|
.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var spinner = utils.addSpinnerOverlay(remoteBox).addClass("projects-dialog-spinner-contain");
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
var url = "projects/"+activeProject.name+"/pull";
|
||||||
|
if (activeProject.branches.remoteAlt) {
|
||||||
|
url+="/"+activeProject.branches.remoteAlt;
|
||||||
|
}
|
||||||
|
if ($("#sidebar-version-control-repo-toolbar-set-upstream").prop('checked')) {
|
||||||
|
url+="?u=true"
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.sendRequest({
|
||||||
|
url: url,
|
||||||
|
type: "POST",
|
||||||
|
responses: {
|
||||||
|
0: function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
},
|
||||||
|
200: function(data) {
|
||||||
|
refresh(true);
|
||||||
|
closeRemoteBox();
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
'git_pull_overwrite': function(err) {
|
||||||
|
RED.notify("Unable to pull remote changes; your unstaged local changes would be overwritten. Commit your changes and try again."+
|
||||||
|
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show unstaged changes'+'</a></p>',"error",false,10000000);
|
||||||
|
},
|
||||||
|
'git_pull_merge_conflict': function(err) {
|
||||||
|
refresh(true);
|
||||||
|
},
|
||||||
|
'git_connection_failed': function(err) {
|
||||||
|
RED.notify("Could not connect to remote repository: "+err.toString(),"warning")
|
||||||
|
},
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},{}).always(function() {
|
||||||
|
spinner.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
RED.sidebar.addTab({
|
RED.sidebar.addTab({
|
||||||
id: "version-control",
|
id: "version-control",
|
||||||
label: "version control",
|
label: "history",
|
||||||
name: "Version Control",
|
name: "Project History",
|
||||||
content: content,
|
content: sidebarContent,
|
||||||
enableOnEdit: false,
|
enableOnEdit: false,
|
||||||
onchange: function() {
|
onchange: function() {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
@ -408,9 +818,9 @@ RED.sidebar.versionControl = (function() {
|
|||||||
function updateBulk(files,unstaged) {
|
function updateBulk(files,unstaged) {
|
||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
if (unstaged) {
|
if (unstaged) {
|
||||||
bulkChangeSpinner = addSpinnerOverlay(unstagedChangesList.parent());
|
bulkChangeSpinner = utils.addSpinnerOverlay(unstagedChangesList.parent());
|
||||||
} else {
|
} else {
|
||||||
bulkChangeSpinner = addSpinnerOverlay(stagedChangesList.parent());
|
bulkChangeSpinner = utils.addSpinnerOverlay(stagedChangesList.parent());
|
||||||
}
|
}
|
||||||
bulkChangeSpinner.addClass('projects-dialog-spinner-sidebar');
|
bulkChangeSpinner.addClass('projects-dialog-spinner-sidebar');
|
||||||
var body = unstaged?{files:files}:undefined;
|
var body = unstaged?{files:files}:undefined;
|
||||||
@ -438,41 +848,136 @@ RED.sidebar.versionControl = (function() {
|
|||||||
var refreshInProgress = false;
|
var refreshInProgress = false;
|
||||||
|
|
||||||
var emptyStagedItem = { label:"None" };
|
var emptyStagedItem = { label:"None" };
|
||||||
|
var emptyMergedItem = { label:"All conflicts resolved. Commit the changes to complete the merge." };
|
||||||
|
|
||||||
function refreshLocalCommits() {
|
function getCommits(url,targetList,spinnerTarget,limit,before) {
|
||||||
localCommitList.editableList('empty');
|
var spinner = utils.addSpinnerOverlay(spinnerTarget);
|
||||||
var spinner = addSpinnerOverlay(localCommitList);
|
var fullUrl = url+"?limit="+(limit||20);
|
||||||
var activeProject = RED.projects.getActiveProject();
|
if (before) {
|
||||||
if (activeProject) {
|
fullUrl+="&before="+before;
|
||||||
$.getJSON("/projects/"+activeProject.name+"/commits",function(result) {
|
}
|
||||||
|
utils.sendRequest({
|
||||||
|
url: fullUrl,
|
||||||
|
type: "GET",
|
||||||
|
responses: {
|
||||||
|
0: function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
},
|
||||||
|
200: function(result) {
|
||||||
|
var lastSha;
|
||||||
result.commits.forEach(function(c) {
|
result.commits.forEach(function(c) {
|
||||||
localCommitList.editableList('addItem',c);
|
targetList.editableList('addItem',c);
|
||||||
|
lastSha = c.sha;
|
||||||
})
|
})
|
||||||
|
if (targetList.loadMoreItem) {
|
||||||
|
targetList.editableList('removeItem',targetList.loadMoreItem);
|
||||||
|
delete targetList.loadMoreItem;
|
||||||
|
}
|
||||||
|
var totalKnown = targetList.editableList('length');
|
||||||
|
if (totalKnown < result.total) {
|
||||||
|
targetList.loadMoreItem = {
|
||||||
|
totalKnown: totalKnown,
|
||||||
|
total: result.total,
|
||||||
|
url: url,
|
||||||
|
before: lastSha+"~1",
|
||||||
|
limit: limit,
|
||||||
|
};
|
||||||
|
targetList.editableList('addItem',targetList.loadMoreItem);
|
||||||
|
}
|
||||||
spinner.remove();
|
spinner.remove();
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
'unexpected_error': function(error) {
|
||||||
|
console.log(error);
|
||||||
|
// done(error,null);
|
||||||
|
},
|
||||||
|
'git_auth_failed': function(error) {
|
||||||
|
RED.notify('Authentication failed against remote repository','error');
|
||||||
|
$('#sidebar-version-control-repo-toolbar-message').text("Failed to fetch remote repository status");
|
||||||
|
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||||
|
|
||||||
|
spinner.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function refreshLocalCommits() {
|
||||||
|
localCommitList.editableList('empty');
|
||||||
|
var activeProject = RED.projects.getActiveProject();
|
||||||
|
if (activeProject) {
|
||||||
|
getCommits("/projects/"+activeProject.name+"/commits",localCommitList,localCommitList.parent());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// function refreshRemoteCommits() {
|
||||||
|
// remoteCommitList.editableList('empty');
|
||||||
|
// var spinner = utils.addSpinnerOverlay(remoteCommitList);
|
||||||
|
// var activeProject = RED.projects.getActiveProject();
|
||||||
|
// if (activeProject) {
|
||||||
|
// getCommits("/projects/"+activeProject.name+"/commits/origin",remoteCommitList,remoteCommitList.parent());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
function showMergeConflictNotification() {
|
||||||
|
if (isMerging) {
|
||||||
|
mergeConflictNotification = RED.notify("NLS: Automatic merging of remote changes failed. Fix the unmerged conflicts then commit the results."+
|
||||||
|
'<p><a href="#" onclick="RED.sidebar.versionControl.showLocalChanges(); return false;">'+'Show merge conflicts'+'</a></p>',"error",true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function refreshFiles(result) {
|
function refreshFiles(result) {
|
||||||
|
var files = result.files;
|
||||||
if (bulkChangeSpinner) {
|
if (bulkChangeSpinner) {
|
||||||
bulkChangeSpinner.remove();
|
bulkChangeSpinner.remove();
|
||||||
bulkChangeSpinner = null;
|
bulkChangeSpinner = null;
|
||||||
}
|
}
|
||||||
|
isMerging = !!result.merging;
|
||||||
|
if (isMerging) {
|
||||||
|
if (!mergeConflictNotification) {
|
||||||
|
showMergeConflictNotification();
|
||||||
|
}
|
||||||
|
sidebarContent.addClass("sidebar-version-control-merging");
|
||||||
|
unmergedContent.show();
|
||||||
|
} else {
|
||||||
|
if (mergeConflictNotification) {
|
||||||
|
mergeConflictNotification.close();
|
||||||
|
mergeConflictNotification = null;
|
||||||
|
}
|
||||||
|
sidebarContent.removeClass("sidebar-version-control-merging");
|
||||||
|
unmergedContent.hide();
|
||||||
|
}
|
||||||
unstagedChangesList.editableList('removeItem',emptyStagedItem);
|
unstagedChangesList.editableList('removeItem',emptyStagedItem);
|
||||||
stagedChangesList.editableList('removeItem',emptyStagedItem);
|
stagedChangesList.editableList('removeItem',emptyStagedItem);
|
||||||
|
unmergedChangesList.editableList('removeItem',emptyMergedItem);
|
||||||
|
|
||||||
var fileNames = Object.keys(result).filter(function(f) { return result[f].type === 'f'})
|
var fileNames = Object.keys(files).filter(function(f) { return files[f].type === 'f'})
|
||||||
fileNames.sort();
|
fileNames.sort();
|
||||||
var updateIndex = Date.now()+Math.floor(Math.random()*100);
|
var updateIndex = Date.now()+Math.floor(Math.random()*100);
|
||||||
fileNames.forEach(function(fn) {
|
fileNames.forEach(function(fn) {
|
||||||
var entry = result[fn];
|
var entry = files[fn];
|
||||||
var addEntry = false;
|
var addEntry = false;
|
||||||
if (entry.status) {
|
if (entry.status) {
|
||||||
entry.file = fn;
|
entry.file = fn;
|
||||||
entry.indexStatus = entry.status[0];
|
entry.indexStatus = entry.status[0];
|
||||||
entry.treeStatus = entry.status[1];
|
entry.treeStatus = entry.status[1];
|
||||||
|
if ((entry.indexStatus === 'A' && /[AU]/.test(entry.treeStatus)) ||
|
||||||
|
(entry.indexStatus === 'U' && /[DAU]/.test(entry.treeStatus)) ||
|
||||||
|
(entry.indexStatus === 'D' && /[DU]/.test(entry.treeStatus))) {
|
||||||
|
entry.unmerged = true;
|
||||||
|
}
|
||||||
if (allChanges[fn]) {
|
if (allChanges[fn]) {
|
||||||
|
if (allChanges[fn].unmerged && !entry.unmerged) {
|
||||||
|
unmergedChangesList.editableList('removeItem', allChanges[fn])
|
||||||
|
addEntry = true;
|
||||||
|
} else if (!allChanges[fn].unmerged && entry.unmerged) {
|
||||||
|
unstagedChangesList.editableList('removeItem', allChanges[fn])
|
||||||
|
stagedChangesList.editableList('removeItem', allChanges[fn])
|
||||||
|
}
|
||||||
// Known file
|
// Known file
|
||||||
if (allChanges[fn].status !== entry.status) {
|
if (allChanges[fn].status !== entry.status) {
|
||||||
// Status changed.
|
// Status changed.
|
||||||
@ -501,12 +1006,17 @@ RED.sidebar.versionControl = (function() {
|
|||||||
allChanges[fn].indexStatus = entry.indexStatus;
|
allChanges[fn].indexStatus = entry.indexStatus;
|
||||||
allChanges[fn].treeStatus = entry.treeStatus;
|
allChanges[fn].treeStatus = entry.treeStatus;
|
||||||
allChanges[fn].oldName = entry.oldName;
|
allChanges[fn].oldName = entry.oldName;
|
||||||
|
allChanges[fn].unmerged = entry.unmerged;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
addEntry = true;
|
addEntry = true;
|
||||||
allChanges[fn] = entry;
|
allChanges[fn] = entry;
|
||||||
}
|
}
|
||||||
allChanges[fn].updateIndex = updateIndex;
|
allChanges[fn].updateIndex = updateIndex;
|
||||||
if (addEntry) {
|
if (addEntry) {
|
||||||
|
if (entry.unmerged) {
|
||||||
|
unmergedChangesList.editableList('addItem', allChanges[fn]);
|
||||||
|
} else {
|
||||||
if (entry.treeStatus !== ' ') {
|
if (entry.treeStatus !== ' ') {
|
||||||
unstagedChangesList.editableList('addItem', allChanges[fn])
|
unstagedChangesList.editableList('addItem', allChanges[fn])
|
||||||
}
|
}
|
||||||
@ -515,6 +1025,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Object.keys(allChanges).forEach(function(fn) {
|
Object.keys(allChanges).forEach(function(fn) {
|
||||||
if (allChanges[fn].updateIndex !== updateIndex) {
|
if (allChanges[fn].updateIndex !== updateIndex) {
|
||||||
@ -526,7 +1037,9 @@ RED.sidebar.versionControl = (function() {
|
|||||||
|
|
||||||
var stagedCount = stagedChangesList.editableList('length');
|
var stagedCount = stagedChangesList.editableList('length');
|
||||||
var unstagedCount = unstagedChangesList.editableList('length');
|
var unstagedCount = unstagedChangesList.editableList('length');
|
||||||
commitButton.attr('disabled',stagedCount === 0);
|
var unmergedCount = unmergedChangesList.editableList('length');
|
||||||
|
|
||||||
|
commitButton.attr('disabled',(isMerging && unmergedCount > 0)||(!isMerging && stagedCount === 0));
|
||||||
stageAllButton.attr('disabled',unstagedCount === 0);
|
stageAllButton.attr('disabled',unstagedCount === 0);
|
||||||
unstageAllButton.attr('disabled',stagedCount === 0);
|
unstageAllButton.attr('disabled',stagedCount === 0);
|
||||||
|
|
||||||
@ -536,8 +1049,9 @@ RED.sidebar.versionControl = (function() {
|
|||||||
if (unstagedCount === 0) {
|
if (unstagedCount === 0) {
|
||||||
unstagedChangesList.editableList('addItem',emptyStagedItem);
|
unstagedChangesList.editableList('addItem',emptyStagedItem);
|
||||||
}
|
}
|
||||||
|
if (unmergedCount === 0) {
|
||||||
|
unmergedChangesList.editableList('addItem',emptyMergedItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refresh(full) {
|
function refresh(full) {
|
||||||
@ -548,6 +1062,7 @@ RED.sidebar.versionControl = (function() {
|
|||||||
allChanges = {};
|
allChanges = {};
|
||||||
unstagedChangesList.editableList('empty');
|
unstagedChangesList.editableList('empty');
|
||||||
stagedChangesList.editableList('empty');
|
stagedChangesList.editableList('empty');
|
||||||
|
unmergedChangesList.editableList('empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshInProgress = true;
|
refreshInProgress = true;
|
||||||
@ -555,23 +1070,79 @@ RED.sidebar.versionControl = (function() {
|
|||||||
|
|
||||||
var activeProject = RED.projects.getActiveProject();
|
var activeProject = RED.projects.getActiveProject();
|
||||||
if (activeProject) {
|
if (activeProject) {
|
||||||
$.getJSON("/projects/"+activeProject.name+"/files",function(result) {
|
$.getJSON("/projects/"+activeProject.name+"/status",function(result) {
|
||||||
|
|
||||||
refreshFiles(result);
|
refreshFiles(result);
|
||||||
|
|
||||||
|
$('#sidebar-version-control-local-branch').text(result.branches.local);
|
||||||
|
$('#sidebar-version-control-remote-branch').text(result.branches.remote||"none");
|
||||||
|
|
||||||
|
var commitsAhead = result.commits.ahead || 0;
|
||||||
|
var commitsBehind = result.commits.behind || 0;
|
||||||
|
console.log(commitsBehind,commitsAhead);
|
||||||
|
|
||||||
|
if (activeProject.hasOwnProperty('remotes')) {
|
||||||
|
$("#sidebar-version-control-repo-status-button").show();
|
||||||
|
if (result.branches.hasOwnProperty('remote')) {
|
||||||
|
updateRemoteStatus(commitsAhead, commitsBehind);
|
||||||
|
} else {
|
||||||
|
$('#sidebar-version-control-commits-ahead').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-pull").attr('disabled',true);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$("#sidebar-version-control-repo-status-button").hide();
|
||||||
|
}
|
||||||
refreshInProgress = false;
|
refreshInProgress = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
unstagedChangesList.editableList('empty');
|
unstagedChangesList.editableList('empty');
|
||||||
stagedChangesList.editableList('empty');
|
stagedChangesList.editableList('empty');
|
||||||
|
unmergedChangesList.editableList('empty');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateRemoteStatus(commitsAhead, commitsBehind) {
|
||||||
|
$('#sidebar-version-control-commits-ahead').text(commitsAhead);
|
||||||
|
$('#sidebar-version-control-commits-behind').text(commitsBehind);
|
||||||
|
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-pull").attr('disabled',true);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||||
|
} 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-pull").attr('disabled',true);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',false);
|
||||||
|
} 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-pull").attr('disabled',false);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||||
|
} 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-pull").attr('disabled',false);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||||
|
} else if (commitsAhead === 0 && commitsBehind === 0) {
|
||||||
|
$('#sidebar-version-control-repo-toolbar-message').text("Your repository is up to date.");
|
||||||
|
$("#sidebar-version-control-repo-pull").attr('disabled',true);
|
||||||
|
$("#sidebar-version-control-repo-push").attr('disabled',true);
|
||||||
|
}
|
||||||
|
}
|
||||||
function show() {
|
function show() {
|
||||||
refresh();
|
refresh();
|
||||||
RED.sidebar.show("version-control");
|
RED.sidebar.show("version-control");
|
||||||
}
|
}
|
||||||
|
function showLocalChanges() {
|
||||||
|
RED.sidebar.show("version-control");
|
||||||
|
localChanges.expand();
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
show: show,
|
show: show,
|
||||||
refresh: refresh
|
refresh: refresh,
|
||||||
|
showLocalChanges: showLocalChanges
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -573,8 +573,8 @@
|
|||||||
td.lineno {
|
td.lineno {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: #999;
|
color: #aaa;
|
||||||
background: #fafafa;
|
background: #f6f6f6;
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
}
|
}
|
||||||
td.lineno:nth-child(3) {
|
td.lineno:nth-child(3) {
|
||||||
@ -600,6 +600,23 @@
|
|||||||
td.removed {
|
td.removed {
|
||||||
background: #fadddd;
|
background: #fadddd;
|
||||||
}
|
}
|
||||||
|
tr.mergeHeader td {
|
||||||
|
color: #800080;
|
||||||
|
background: #e5f9ff;
|
||||||
|
height: 26px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
tr.mergeHeader-separator td {
|
||||||
|
color: #800080;
|
||||||
|
background: darken(#e5f9ff, 10%);
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
tr.mergeHeader-ours td {
|
||||||
|
border-top: 2px solid darken(#e5f9ff, 10%);
|
||||||
|
}
|
||||||
|
tr.mergeHeader-theirs td {
|
||||||
|
border-bottom: 2px solid darken(#e5f9ff, 10%);
|
||||||
|
}
|
||||||
td.unchanged {
|
td.unchanged {
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
@ -613,7 +630,9 @@
|
|||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
tr.node-text-diff-file-header td {
|
tr.node-text-diff-file-header td {
|
||||||
|
.filename {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
}
|
||||||
background: #f3f3f3;
|
background: #f3f3f3;
|
||||||
padding: 5px 10px 5px 0;
|
padding: 5px 10px 5px 0;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
@ -215,6 +215,9 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
&.toggle {
|
&.toggle {
|
||||||
@include workspace-button-toggle;
|
@include workspace-button-toggle;
|
||||||
}
|
}
|
||||||
@ -223,6 +226,7 @@
|
|||||||
|
|
||||||
.editor-button-small {
|
.editor-button-small {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
min-width: 20px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
@ -243,3 +243,6 @@
|
|||||||
background: $shade-color;
|
background: $shade-color;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
.component-shade {
|
||||||
|
@include shade
|
||||||
|
}
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#project-settings-tab-settings {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
.projects-edit-form form {
|
.projects-edit-form form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
.form-row {
|
.form-row {
|
||||||
@ -28,13 +31,6 @@
|
|||||||
color: #555;
|
color: #555;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
font-weight: 500;
|
|
||||||
&.projects-edit-form-sublabel {
|
|
||||||
color: #999;
|
|
||||||
text-align: right;
|
|
||||||
margin-bottom: -15px;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
&.projects-edit-form-inline-label {
|
&.projects-edit-form-inline-label {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -51,12 +47,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.projects-edit-form-sublabel {
|
||||||
|
color: #999;
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: -15px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.project-settings-tab-pane {
|
||||||
|
& * .projects-edit-form-sublabel {
|
||||||
|
margin-right: 50px;
|
||||||
|
margin-top: -10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.projects-dialog-spinner {
|
.projects-dialog-spinner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 1px;
|
||||||
bottom: 0;
|
bottom: 1px;
|
||||||
left: 0;
|
left: 1px;
|
||||||
right: 0;
|
right: 1px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
background: white;
|
background: white;
|
||||||
@ -87,6 +96,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.projects-dialog-spinner-contain {
|
||||||
|
padding: 0;
|
||||||
|
img {
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
max-height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.projects-dialog-screen-start {
|
.projects-dialog-screen-start {
|
||||||
@ -196,6 +213,15 @@
|
|||||||
background: #fff !important;
|
background: #fff !important;
|
||||||
color: #666 !important;
|
color: #666 !important;
|
||||||
}
|
}
|
||||||
|
.projects-dialog-screen-input-status {
|
||||||
|
text-align: right;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 8px;
|
||||||
|
width: 70px;
|
||||||
|
height: 30px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-version-control {
|
.sidebar-version-control {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -278,18 +304,22 @@
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-version-control-change-container {
|
.sidebar-version-control-change-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-top: 1px solid $secondary-border-color;
|
|
||||||
transition: height 0.2s ease-in-out;
|
transition: height 0.2s ease-in-out;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
// border-bottom: 1px solid $primary-border-color;
|
// border-bottom: 1px solid $primary-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.sidebar-version-control-change-commit-box {
|
.sidebar-version-control-merging {
|
||||||
|
.sidebar-version-control-change-container {
|
||||||
|
height: 33%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sidebar-version-control-slide-box {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left:0;
|
left:0;
|
||||||
@ -299,7 +329,28 @@
|
|||||||
background: #f6f6f6;
|
background: #f6f6f6;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
&.sidebar-version-control-slide-box-top {
|
||||||
|
z-index: 10;
|
||||||
|
top: 0px;
|
||||||
|
left: auto;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 280px;
|
||||||
|
border-left: 1px solid $primary-border-color;
|
||||||
|
border-right: 1px solid $primary-border-color;
|
||||||
|
border-bottom: 1px solid $primary-border-color;
|
||||||
|
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
|
||||||
|
|
||||||
|
color: #666;
|
||||||
|
background: #f6f6f6;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
}
|
||||||
|
&.sidebar-version-control-slide-box-bottom {
|
||||||
|
bottom: 0px;
|
||||||
border-top: 1px solid $secondary-border-color;
|
border-top: 1px solid $secondary-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
height: 110px;
|
height: 110px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
@ -308,12 +359,84 @@
|
|||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
resize: none;
|
resize: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.sidebar-version-control-change-commit-toolbar {
|
|
||||||
padding: 0 20px;
|
|
||||||
text-align: right;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.projects-branch-list {
|
||||||
|
position: relative;
|
||||||
|
.red-ui-searchBox-container {
|
||||||
|
border-top: 1px solid $secondary-border-color;
|
||||||
|
border-left: 1px solid $secondary-border-color;
|
||||||
|
border-right: 1px solid $secondary-border-color;
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.red-ui-editableList {
|
||||||
|
border: 1px solid $secondary-border-color;
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
& > .red-ui-editableList-border {
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.red-ui-editableList-container {
|
||||||
|
padding: 0;
|
||||||
|
li {
|
||||||
|
padding: 0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.uneditable-input .projects-branch-list {
|
||||||
|
.red-ui-editableList {
|
||||||
|
border-left: none;
|
||||||
|
border-bottom: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
.red-ui-searchBox-container {
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sidebar-version-control-slide-box-header {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-version-control-slide-box-toolbar {
|
||||||
|
padding: 0 20px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.sidebar-version-control-branch-list-entry {
|
||||||
|
padding: 5px 8px;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
&.selected {
|
||||||
|
border-left-color:#999;
|
||||||
|
border-right-color:#999;
|
||||||
|
}
|
||||||
|
border-left: 2px solid #fff;
|
||||||
|
border-right: 2px solid #fff;
|
||||||
|
margin: 0 1px;
|
||||||
|
i { width: 16px; text-align: center}
|
||||||
|
&.input-error {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
&:not(.input-error):hover {
|
||||||
|
background: #f3f3f3;
|
||||||
|
border-left-color:#999;
|
||||||
|
border-right-color:#999;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
span.current {
|
||||||
|
float: right;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-version-control-change-entry {
|
.sidebar-version-control-change-entry {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
@ -340,6 +463,8 @@
|
|||||||
&.node-info-none {
|
&.node-info-none {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: #fefefe;
|
background: #fefefe;
|
||||||
|
white-space: normal;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,11 +473,18 @@
|
|||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sidebar-version-control-commit-more {
|
||||||
|
color: #999;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
.sidebar-version-control-commit-sha {
|
.sidebar-version-control-commit-sha {
|
||||||
float: right;
|
float: right;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
@ -364,6 +496,17 @@
|
|||||||
.sidebar-version-control-commit-subject {
|
.sidebar-version-control-commit-subject {
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
.sidebar-version-control-commit-refs {
|
||||||
|
min-height: 22px;
|
||||||
|
}
|
||||||
|
.sidebar-version-control-commit-ref {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.7em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
.sidebar-version-control-commit-date {
|
.sidebar-version-control-commit-date {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
@ -373,18 +516,44 @@
|
|||||||
color: #999;
|
color: #999;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
.sidebar-version-control-commit-head {
|
||||||
|
}
|
||||||
.sidebar-version-control-change-header {
|
.sidebar-version-control-change-header {
|
||||||
color: #666;
|
color: #666;
|
||||||
background: #f6f6f6;
|
background: #f6f6f6;
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
border-top: 1px solid $secondary-border-color;
|
||||||
border-bottom: 1px solid $secondary-border-color;
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
i {
|
i {
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sidebar-version-control-repo-toolbar {
|
||||||
|
color: #666;
|
||||||
|
background: #f6f6f6;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-version-control-repo-count {
|
||||||
|
margin-right: 8px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.sidebar-version-control-repo-action {
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.sidebar-version-control-repo-sub-action {
|
||||||
|
width: calc(50% - 5px);
|
||||||
|
margin-right: 5px;
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.project-file-listing-container > .red-ui-editableList > .red-ui-editableList-border {
|
.project-file-listing-container > .red-ui-editableList > .red-ui-editableList-border {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
label {
|
label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-top: 5px;
|
||||||
input {
|
input {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
@ -117,10 +117,27 @@ module.exports = {
|
|||||||
// Delete project
|
// Delete project
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.get("/:id/status", function(req,res) {
|
||||||
|
// Get project metadata
|
||||||
|
runtime.storage.projects.getStatus(req.params.id).then(function(data) {
|
||||||
|
if (data) {
|
||||||
|
res.json(data);
|
||||||
|
} else {
|
||||||
|
res.status(404).end();
|
||||||
|
}
|
||||||
|
}).catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Project Files
|
// Project Files
|
||||||
|
|
||||||
app.get("/:id/files", function(req,res) {
|
app.get("/:id/files", function(req,res) {
|
||||||
runtime.storage.projects.getFiles(req.params.id).then(function(data) {
|
runtime.storage.projects.getFiles(req.params.id).then(function(data) {
|
||||||
|
console.log("TODO: REMOVE /:id/files as /:id/status is better!")
|
||||||
res.json(data);
|
res.json(data);
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
@ -149,7 +166,7 @@ module.exports = {
|
|||||||
var file = req.params[0];
|
var file = req.params[0];
|
||||||
|
|
||||||
runtime.storage.projects.stageFile(projectName,file).then(function(data) {
|
runtime.storage.projects.stageFile(projectName,file).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/status");
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
@ -161,7 +178,7 @@ module.exports = {
|
|||||||
var files = req.body.files;
|
var files = req.body.files;
|
||||||
|
|
||||||
runtime.storage.projects.stageFile(projectName,files).then(function(data) {
|
runtime.storage.projects.stageFile(projectName,files).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/status");
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
@ -173,7 +190,7 @@ module.exports = {
|
|||||||
var projectName = req.params.id;
|
var projectName = req.params.id;
|
||||||
|
|
||||||
runtime.storage.projects.commit(projectName,req.body).then(function(data) {
|
runtime.storage.projects.commit(projectName,req.body).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/status");
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
@ -186,7 +203,7 @@ module.exports = {
|
|||||||
var file = req.params[0];
|
var file = req.params[0];
|
||||||
|
|
||||||
runtime.storage.projects.unstageFile(projectName,file).then(function(data) {
|
runtime.storage.projects.unstageFile(projectName,file).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/status");
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
@ -196,7 +213,7 @@ module.exports = {
|
|||||||
app.delete("/:id/stage", function(req, res) {
|
app.delete("/:id/stage", function(req, res) {
|
||||||
var projectName = req.params.id;
|
var projectName = req.params.id;
|
||||||
runtime.storage.projects.unstageFile(projectName).then(function(data) {
|
runtime.storage.projects.unstageFile(projectName).then(function(data) {
|
||||||
res.redirect(303,req.baseUrl+"/"+projectName+"/files");
|
res.redirect(303,req.baseUrl+"/"+projectName+"/status");
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
@ -221,13 +238,20 @@ module.exports = {
|
|||||||
|
|
||||||
app.get("/:id/commits", function(req, res) {
|
app.get("/:id/commits", function(req, res) {
|
||||||
var projectName = req.params.id;
|
var projectName = req.params.id;
|
||||||
var options = {};
|
var options = {
|
||||||
|
limit: req.query.limit||20,
|
||||||
|
before: req.query.before
|
||||||
|
};
|
||||||
runtime.storage.projects.getCommits(projectName,options).then(function(data) {
|
runtime.storage.projects.getCommits(projectName,options).then(function(data) {
|
||||||
res.json(data);
|
res.json(data);
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -244,6 +268,137 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/:id/push/?*", function(req,res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
var remoteBranchName = req.params[0]
|
||||||
|
var setRemote = req.query.u;
|
||||||
|
runtime.storage.projects.push(projectName,remoteBranchName,setRemote).then(function(data) {
|
||||||
|
res.status(204).end();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
app.get("/:id/pull/?*", function(req,res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
var remoteBranchName = req.params[0];
|
||||||
|
var setRemote = req.query.u;
|
||||||
|
runtime.storage.projects.pull(projectName,remoteBranchName,setRemote).then(function(data) {
|
||||||
|
res.status(204).end();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
app.delete("/:id/merge", function(req, res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
runtime.storage.projects.abortMerge(projectName).then(function(data) {
|
||||||
|
res.status(204).end();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/:id/resolve/*", function(req, res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
var file = req.params[0];
|
||||||
|
var resolution = req.body.resolutions;
|
||||||
|
runtime.storage.projects.resolveMerge(projectName,file,resolution).then(function(data) {
|
||||||
|
res.status(204).end();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/:id/branches", function(req, res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
runtime.storage.projects.getBranches(projectName,false).then(function(data) {
|
||||||
|
res.json(data);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
app.get("/:id/branches/remote", function(req, res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
runtime.storage.projects.getBranches(projectName,true).then(function(data) {
|
||||||
|
res.json(data);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/:id/branches/remote/*/status", function(req, res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
var branch = req.params[0];
|
||||||
|
runtime.storage.projects.getBranchStatus(projectName,branch).then(function(data) {
|
||||||
|
res.json(data);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.post("/:id/branches", function(req, res) {
|
||||||
|
var projectName = req.params.id;
|
||||||
|
var branchName = req.body.name;
|
||||||
|
var isCreate = req.body.create;
|
||||||
|
runtime.storage.projects.setBranch(projectName,branchName,isCreate).then(function(data) {
|
||||||
|
res.json(data);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
if (err.code) {
|
||||||
|
res.status(400).json({error:err.code, message: err.message});
|
||||||
|
} else {
|
||||||
|
res.status(400).json({error:"unexpected_error", message:err.toString()});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ Project.prototype.load = function () {
|
|||||||
|
|
||||||
this.credentialSecret = projectSettings.credentialSecret;
|
this.credentialSecret = projectSettings.credentialSecret;
|
||||||
|
|
||||||
|
this.remote = projectSettings.remote;
|
||||||
|
|
||||||
// this.paths.flowFile = fspath.join(this.path,"flow.json");
|
// this.paths.flowFile = fspath.join(this.path,"flow.json");
|
||||||
// this.paths.credentialsFile = fspath.join(this.path,"flow_cred.json");
|
// this.paths.credentialsFile = fspath.join(this.path,"flow_cred.json");
|
||||||
|
|
||||||
@ -60,6 +62,7 @@ Project.prototype.load = function () {
|
|||||||
if (missingFiles.indexOf('package.json') === -1) {
|
if (missingFiles.indexOf('package.json') === -1) {
|
||||||
project.paths['package.json'] = fspath.join(project.path,"package.json");
|
project.paths['package.json'] = fspath.join(project.path,"package.json");
|
||||||
promises.push(fs.readFile(project.paths['package.json'],"utf8").then(function(content) {
|
promises.push(fs.readFile(project.paths['package.json'],"utf8").then(function(content) {
|
||||||
|
try {
|
||||||
project.package = util.parseJSON(content);
|
project.package = util.parseJSON(content);
|
||||||
if (project.package.hasOwnProperty('node-red')) {
|
if (project.package.hasOwnProperty('node-red')) {
|
||||||
if (project.package['node-red'].hasOwnProperty('settings')) {
|
if (project.package['node-red'].hasOwnProperty('settings')) {
|
||||||
@ -70,6 +73,10 @@ Project.prototype.load = function () {
|
|||||||
// TODO: package.json doesn't have a node-red section
|
// TODO: package.json doesn't have a node-red section
|
||||||
// is that a bad thing?
|
// is that a bad thing?
|
||||||
}
|
}
|
||||||
|
} catch(err) {
|
||||||
|
// package.json isn't valid JSON... is a merge underway?
|
||||||
|
project.package = {};
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
project.package = {};
|
project.package = {};
|
||||||
@ -93,6 +100,13 @@ Project.prototype.load = function () {
|
|||||||
// project.paths.credentialsFile = fspath.join(project.path,"flow_cred.json");
|
// project.paths.credentialsFile = fspath.join(project.path,"flow_cred.json");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
promises.push(gitTools.getRemotes(project.path).then(function(remotes) {
|
||||||
|
project.remotes = remotes;
|
||||||
|
}));
|
||||||
|
promises.push(gitTools.getBranchInfo(project.path).then(function(branches) {
|
||||||
|
project.branches = branches;
|
||||||
|
}));
|
||||||
|
|
||||||
return when.settle(promises).then(function() {
|
return when.settle(promises).then(function() {
|
||||||
return project;
|
return project;
|
||||||
})
|
})
|
||||||
@ -207,7 +221,24 @@ Project.prototype.getFileDiff = function(file,type) {
|
|||||||
return gitTools.getFileDiff(this.path,file,type);
|
return gitTools.getFileDiff(this.path,file,type);
|
||||||
}
|
}
|
||||||
Project.prototype.getCommits = function(options) {
|
Project.prototype.getCommits = function(options) {
|
||||||
return gitTools.getCommits(this.path,options);
|
var self = this;
|
||||||
|
var fetchPromise;
|
||||||
|
if (this.remote) {
|
||||||
|
options.hasRemote = true;
|
||||||
|
fetchPromise = gitTools.fetch(this.path)
|
||||||
|
} else {
|
||||||
|
fetchPromise = when.resolve();
|
||||||
|
}
|
||||||
|
return fetchPromise.then(function() {
|
||||||
|
return gitTools.getCommits(self.path,options);
|
||||||
|
}).otherwise(function(e) {
|
||||||
|
if (e.code === 'git_auth_failed') {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
console.log("Fetch failed");
|
||||||
|
console.log(e);
|
||||||
|
return gitTools.getCommits(self.path,options);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Project.prototype.getCommit = function(sha) {
|
Project.prototype.getCommit = function(sha) {
|
||||||
return gitTools.getCommit(this.path,sha);
|
return gitTools.getCommit(this.path,sha);
|
||||||
@ -220,6 +251,94 @@ Project.prototype.getFile = function (filePath,treeish) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Project.prototype.status = function() {
|
||||||
|
var self = this;
|
||||||
|
var promises = [
|
||||||
|
gitTools.getStatus(this.path),
|
||||||
|
fs.exists(fspath.join(this.path,".git","MERGE_HEAD"))
|
||||||
|
]
|
||||||
|
return when.all(promises).then(function(results) {
|
||||||
|
var result = results[0];
|
||||||
|
if (results[1]) {
|
||||||
|
result.merging = true;
|
||||||
|
}
|
||||||
|
self.branches.local = result.branches.local;
|
||||||
|
self.branches.remote = result.branches.remote;
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
Project.prototype.push = function (remoteBranchName,setRemote) {
|
||||||
|
return gitTools.push(this.path, remoteBranchName, setRemote);
|
||||||
|
};
|
||||||
|
|
||||||
|
Project.prototype.pull = function (remoteBranchName,setRemote) {
|
||||||
|
if (setRemote) {
|
||||||
|
return gitTools.setUpstream(this.path, remoteBranchName).then(function() {
|
||||||
|
return gitTools.pull(this.path);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return gitTools.pull(this.path, remoteBranchName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Project.prototype.resolveMerge = function (file,resolutions) {
|
||||||
|
var filePath = fspath.join(this.path,file);
|
||||||
|
var self = this;
|
||||||
|
return fs.readFile(filePath,"utf8").then(function(content) {
|
||||||
|
var lines = content.split("\n");
|
||||||
|
var result = [];
|
||||||
|
var ignoreBlock = false;
|
||||||
|
var currentBlock;
|
||||||
|
for (var i=1;i<=lines.length;i++) {
|
||||||
|
if (resolutions.hasOwnProperty(i)) {
|
||||||
|
currentBlock = resolutions[i];
|
||||||
|
if (currentBlock.selection === "A") {
|
||||||
|
ignoreBlock = false;
|
||||||
|
} else {
|
||||||
|
ignoreBlock = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (currentBlock) {
|
||||||
|
if (currentBlock.separator === i) {
|
||||||
|
if (currentBlock.selection === "A") {
|
||||||
|
ignoreBlock = true;
|
||||||
|
} else {
|
||||||
|
ignoreBlock = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (currentBlock.changeEnd === i) {
|
||||||
|
currentBlock = null;
|
||||||
|
continue;
|
||||||
|
} else if (ignoreBlock) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(lines[i-1]);
|
||||||
|
}
|
||||||
|
var finalResult = result.join("\n");
|
||||||
|
return util.writeFile(filePath,finalResult).then(function() {
|
||||||
|
return self.stageFile(file);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Project.prototype.abortMerge = function () {
|
||||||
|
return gitTools.abortMerge(this.path);
|
||||||
|
};
|
||||||
|
|
||||||
|
Project.prototype.getBranches = function (remote) {
|
||||||
|
return gitTools.getBranches(this.path,remote);
|
||||||
|
};
|
||||||
|
Project.prototype.setBranch = function (branchName, isCreate) {
|
||||||
|
var self = this;
|
||||||
|
return gitTools.checkoutBranch(this.path, branchName, isCreate).then(function() {
|
||||||
|
return self.load();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
Project.prototype.getBranchStatus = function (branchName) {
|
||||||
|
return gitTools.getBranchStatus(this.path,branchName);
|
||||||
|
};
|
||||||
Project.prototype.getFlowFile = function() {
|
Project.prototype.getFlowFile = function() {
|
||||||
console.log("Project.getFlowFile = ",this.paths.flowFile);
|
console.log("Project.getFlowFile = ",this.paths.flowFile);
|
||||||
if (this.paths.flowFile) {
|
if (this.paths.flowFile) {
|
||||||
@ -243,14 +362,13 @@ Project.prototype.getCredentialsFileBackup = function() {
|
|||||||
return getBackupFilename(this.getCredentialsFile());
|
return getBackupFilename(this.getCredentialsFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Project.prototype.toJSON = function () {
|
Project.prototype.toJSON = function () {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
summary: this.package.description,
|
summary: this.package.description,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
dependencies: this.package.dependencies,
|
dependencies: this.package.dependencies||{},
|
||||||
settings: {
|
settings: {
|
||||||
credentialsEncrypted: (typeof this.credentialSecret === "string"),
|
credentialsEncrypted: (typeof this.credentialSecret === "string"),
|
||||||
credentialSecretInvalid: this.credentialSecretInvalid
|
credentialSecretInvalid: this.credentialSecretInvalid
|
||||||
@ -258,7 +376,9 @@ Project.prototype.toJSON = function () {
|
|||||||
files: {
|
files: {
|
||||||
flow: this.paths.flowFile,
|
flow: this.paths.flowFile,
|
||||||
credentials: this.paths.credentialsFile
|
credentials: this.paths.credentialsFile
|
||||||
}
|
},
|
||||||
|
remotes: this.remotes,
|
||||||
|
branches: this.branches
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -281,7 +401,7 @@ function checkProjectExists(project) {
|
|||||||
var projectPath = fspath.join(projectsDir,project);
|
var projectPath = fspath.join(projectsDir,project);
|
||||||
return fs.pathExists(projectPath).then(function(exists) {
|
return fs.pathExists(projectPath).then(function(exists) {
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
var e = new Error("NLD: project not found");
|
var e = new Error("NLS: project not found");
|
||||||
e.code = "project_not_found";
|
e.code = "project_not_found";
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -379,6 +499,7 @@ function createProject(metadata) {
|
|||||||
return settings.set('projects',projects);
|
return settings.set('projects',projects);
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
if (metadata.remote) {
|
if (metadata.remote) {
|
||||||
|
console.log(metadata.remote);
|
||||||
return gitTools.clone(metadata.remote,projectPath).then(function(result) {
|
return gitTools.clone(metadata.remote,projectPath).then(function(result) {
|
||||||
// Check this is a valid project
|
// Check this is a valid project
|
||||||
// If it is empty
|
// If it is empty
|
||||||
@ -415,8 +536,7 @@ function getProject(name) {
|
|||||||
}
|
}
|
||||||
currentProject = new Project(name);
|
currentProject = new Project(name);
|
||||||
return currentProject.load();
|
return currentProject.load();
|
||||||
})
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function listProjects() {
|
function listProjects() {
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var net = require("net");
|
||||||
|
var fs = require("fs-extra");
|
||||||
|
var path = require("path");
|
||||||
|
var os = require("os");
|
||||||
|
|
||||||
|
function getListenPath() {
|
||||||
|
var seed = (0x100000+Math.random()*0x999999).toString(16);
|
||||||
|
var fn = 'node-red-git-askpass-'+seed+'-sock';
|
||||||
|
var listenPath;
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
listenPath = '\\\\.\\pipe\\'+getListenPath;
|
||||||
|
} else {
|
||||||
|
listenPath = path.join(process.env['XDG_RUNTIME_DIR'] || os.tmpdir(), fn);
|
||||||
|
}
|
||||||
|
console.log(listenPath);
|
||||||
|
return listenPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var ResponseServer = function(auth) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
server = net.createServer(function(connection) {
|
||||||
|
// Stop accepting new connections
|
||||||
|
connection.setEncoding('utf8');
|
||||||
|
var parts = [];
|
||||||
|
connection.on('data', function(data) {
|
||||||
|
var m = data.indexOf("\n");
|
||||||
|
if (m !== -1) {
|
||||||
|
parts.push(data.substring(0, m));
|
||||||
|
data = data.substring(m);
|
||||||
|
var line = parts.join("");
|
||||||
|
parts = [];
|
||||||
|
if (line==='Username') {
|
||||||
|
connection.end(auth.username);
|
||||||
|
} else if (line === 'Password') {
|
||||||
|
connection.end(auth.password);
|
||||||
|
server.close();
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.length > 0) {
|
||||||
|
parts.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var listenPath = getListenPath();
|
||||||
|
|
||||||
|
server.listen(listenPath, function(ready) {
|
||||||
|
resolve({path:listenPath,close:function() { server.close(); }});
|
||||||
|
});
|
||||||
|
server.on('close', function() {
|
||||||
|
console.log("Closing response server");
|
||||||
|
fs.removeSync(listenPath);
|
||||||
|
});
|
||||||
|
server.on('error',function(err) {
|
||||||
|
console.log("ResponseServer unexpectedError:",err.toString());
|
||||||
|
server.close();
|
||||||
|
reject(err);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ResponseServer: ResponseServer
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var net = require("net");
|
||||||
|
var socket = net.connect(process.argv[2], function() {
|
||||||
|
socket.on('data', function(data) { console.log(data);});
|
||||||
|
socket.on('end', function() {
|
||||||
|
});
|
||||||
|
socket.write((process.argv[3]||"")+"\n", 'utf8');
|
||||||
|
});
|
||||||
|
socket.setEncoding('utf8');
|
@ -17,25 +17,32 @@
|
|||||||
var when = require('when');
|
var when = require('when');
|
||||||
var exec = require('child_process').exec;
|
var exec = require('child_process').exec;
|
||||||
var spawn = require('child_process').spawn;
|
var spawn = require('child_process').spawn;
|
||||||
|
var authResponseServer = require('./authServer').ResponseServer;
|
||||||
|
var clone = require('clone');
|
||||||
|
var path = require("path");
|
||||||
|
|
||||||
|
var gitCommand = "git";
|
||||||
|
var log;
|
||||||
|
|
||||||
function execCommand(command,args,cwd) {
|
// function execCommand(command,args,cwd) {
|
||||||
|
// return when.promise(function(resolve,reject) {
|
||||||
|
// var fullCommand = command+" "+args.join(" ");
|
||||||
|
// child = exec(fullCommand, {cwd: cwd, timeout:3000, killSignal: 'SIGTERM'}, function (error, stdout, stderr) {
|
||||||
|
// if (error) {
|
||||||
|
// reject(error);
|
||||||
|
// } else {
|
||||||
|
// resolve(stdout);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
function runGitCommand(args,cwd,env) {
|
||||||
|
log.trace(gitCommand + JSON.stringify(args));
|
||||||
return when.promise(function(resolve,reject) {
|
return when.promise(function(resolve,reject) {
|
||||||
var fullCommand = command+" "+args.join(" ");
|
args.unshift("credential.helper=")
|
||||||
child = exec(fullCommand, {cwd: cwd, timeout:3000, killSignal: 'SIGTERM'}, function (error, stdout, stderr) {
|
args.unshift("-c");
|
||||||
if (error) {
|
var child = spawn(gitCommand, args, {cwd:cwd, detached:true, env:env});
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
resolve(stdout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function runCommand(command,args,cwd) {
|
|
||||||
console.log(cwd,command,args);
|
|
||||||
return when.promise(function(resolve,reject) {
|
|
||||||
var child = spawn(command, args, {cwd:cwd, detached:true});
|
|
||||||
var stdout = "";
|
var stdout = "";
|
||||||
var stderr = "";
|
var stderr = "";
|
||||||
child.stdout.on('data', function(data) {
|
child.stdout.on('data', function(data) {
|
||||||
@ -49,10 +56,14 @@ function runCommand(command,args,cwd) {
|
|||||||
child.on('close', function(code) {
|
child.on('close', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
var err = new Error(stderr);
|
var err = new Error(stderr);
|
||||||
|
err.stdout = stdout;
|
||||||
|
err.stderr = stderr;
|
||||||
if (/fatal: could not read Username/.test(stderr)) {
|
if (/fatal: could not read Username/.test(stderr)) {
|
||||||
err.code = "git_auth_failed";
|
err.code = "git_auth_failed";
|
||||||
} else if(/HTTP Basic: Access denied/.test(stderr)) {
|
} else if(/HTTP Basic: Access denied/.test(stderr)) {
|
||||||
err.code = "git_auth_failed";
|
err.code = "git_auth_failed";
|
||||||
|
} else if(/Connection refused/.test(stderr)) {
|
||||||
|
err.code = "git_connection_failed";
|
||||||
} else {
|
} else {
|
||||||
err.code = "git_error";
|
err.code = "git_error";
|
||||||
}
|
}
|
||||||
@ -62,9 +73,17 @@ function runCommand(command,args,cwd) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function isAuthError(err) {
|
function runGitCommandWithAuth(args,cwd,auth) {
|
||||||
// var lines = err.toString().split("\n");
|
return authResponseServer(auth).then(function(rs) {
|
||||||
// lines.forEach(console.log);
|
var commandEnv = clone(process.env);
|
||||||
|
commandEnv.GIT_ASKPASS = path.join(__dirname,"node-red-ask-pass.sh");
|
||||||
|
commandEnv.NODE_RED_GIT_NODE_PATH = process.execPath;
|
||||||
|
commandEnv.NODE_RED_GIT_SOCK_PATH = rs.path;
|
||||||
|
commandEnv.NODE_RED_GIT_ASKPASS_PATH = path.join(__dirname,"authWriter.js");
|
||||||
|
return runGitCommand(args,cwd,commandEnv).finally(function() {
|
||||||
|
rs.close();
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanFilename(name) {
|
function cleanFilename(name) {
|
||||||
@ -85,13 +104,41 @@ function parseFilenames(name) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
function getBranchInfo(localRepo) {
|
||||||
function getFiles(localRepo) {
|
return runGitCommand(["status","--porcelain","-b"],localRepo).then(function(output) {
|
||||||
|
var lines = output.split("\n");
|
||||||
|
var unknownDirs = [];
|
||||||
|
var branchLineRE = /^## (.+?)($|\.\.\.(.+?)($| \[(ahead (\d+))?.*?(behind (\d+))?\]))/m;
|
||||||
|
var m = branchLineRE.exec(output);
|
||||||
|
var result = {}; //commits:{}};
|
||||||
|
if (m) {
|
||||||
|
result.local = m[1];
|
||||||
|
if (m[3]) {
|
||||||
|
result.remote = m[3];
|
||||||
|
}
|
||||||
|
// if (m[6] !== undefined) {
|
||||||
|
// result.commits.ahead = parseInt(m[6]);
|
||||||
|
// }
|
||||||
|
// if (m[8] !== undefined) {
|
||||||
|
// result.commits.behind = parseInt(m[8]);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getStatus(localRepo) {
|
||||||
// parseFilename('"test with space"');
|
// parseFilename('"test with space"');
|
||||||
// parseFilename('"test with space" -> knownFile.txt');
|
// parseFilename('"test with space" -> knownFile.txt');
|
||||||
// parseFilename('"test with space" -> "un -> knownFile.txt"');
|
// parseFilename('"test with space" -> "un -> knownFile.txt"');
|
||||||
var files = {};
|
var result = {
|
||||||
return runCommand(gitCommand,["ls-files","--cached","--others","--exclude-standard"],localRepo).then(function(output) {
|
files: {},
|
||||||
|
commits: {},
|
||||||
|
branches: {}
|
||||||
|
}
|
||||||
|
return runGitCommand(['rev-list', 'HEAD', '--count'],localRepo).then(function(count) {
|
||||||
|
result.commits.total = parseInt(count);
|
||||||
|
}).then(function() {
|
||||||
|
return runGitCommand(["ls-files","--cached","--others","--exclude-standard"],localRepo).then(function(output) {
|
||||||
var lines = output.split("\n");
|
var lines = output.split("\n");
|
||||||
lines.forEach(function(l) {
|
lines.forEach(function(l) {
|
||||||
if (l==="") {
|
if (l==="") {
|
||||||
@ -100,7 +147,7 @@ function getFiles(localRepo) {
|
|||||||
var fullName = cleanFilename(l);
|
var fullName = cleanFilename(l);
|
||||||
// parseFilename(l);
|
// parseFilename(l);
|
||||||
var parts = fullName.split("/");
|
var parts = fullName.split("/");
|
||||||
var p = files;
|
var p = result.files;
|
||||||
var name;
|
var name;
|
||||||
for (var i = 0;i<parts.length-1;i++) {
|
for (var i = 0;i<parts.length-1;i++) {
|
||||||
var name = parts.slice(0,i+1).join("/")+"/";
|
var name = parts.slice(0,i+1).join("/")+"/";
|
||||||
@ -110,18 +157,34 @@ function getFiles(localRepo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
files[fullName] = {
|
result.files[fullName] = {
|
||||||
type: /\/$/.test(fullName)?"d":"f"
|
type: /\/$/.test(fullName)?"d":"f"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return runCommand(gitCommand,["status","--porcelain"],localRepo).then(function(output) {
|
return runGitCommand(["status","--porcelain","-b"],localRepo).then(function(output) {
|
||||||
var lines = output.split("\n");
|
var lines = output.split("\n");
|
||||||
var unknownDirs = [];
|
var unknownDirs = [];
|
||||||
|
var branchLineRE = /^## (.+?)($|\.\.\.(.+?)($| \[(ahead (\d+))?.*?(behind (\d+))?\]))/;
|
||||||
lines.forEach(function(line) {
|
lines.forEach(function(line) {
|
||||||
if (line==="") {
|
if (line==="") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (line[0] === "#") {
|
if (line[0] === "#") {
|
||||||
|
var m = branchLineRE.exec(line);
|
||||||
|
if (m) {
|
||||||
|
result.branches.local = m[1];
|
||||||
|
if (m[3]) {
|
||||||
|
result.branches.remote = m[3];
|
||||||
|
result.commits.ahead = 0;
|
||||||
|
result.commits.behind = 0;
|
||||||
|
}
|
||||||
|
if (m[6] !== undefined) {
|
||||||
|
result.commits.ahead = parseInt(m[6]);
|
||||||
|
}
|
||||||
|
if (m[8] !== undefined) {
|
||||||
|
result.commits.behind = parseInt(m[8]);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var status = line.substring(0,2);
|
var status = line.substring(0,2);
|
||||||
@ -141,24 +204,24 @@ function getFiles(localRepo) {
|
|||||||
if (fileName.charCodeAt(0) === 34) {
|
if (fileName.charCodeAt(0) === 34) {
|
||||||
fileName = fileName.substring(1,fileName.length-1);
|
fileName = fileName.substring(1,fileName.length-1);
|
||||||
}
|
}
|
||||||
if (files.hasOwnProperty(fileName)) {
|
if (result.files.hasOwnProperty(fileName)) {
|
||||||
files[fileName].status = status;
|
result.files[fileName].status = status;
|
||||||
} else {
|
} else {
|
||||||
files[fileName] = {
|
result.files[fileName] = {
|
||||||
type: "f",
|
type: "f",
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (names.length > 1) {
|
if (names.length > 1) {
|
||||||
files[fileName].oldName = names[0];
|
result.files[fileName].oldName = names[0];
|
||||||
}
|
}
|
||||||
if (status === "??" && fileName[fileName.length-1] === '/') {
|
if (status === "??" && fileName[fileName.length-1] === '/') {
|
||||||
unknownDirs.push(fileName);
|
unknownDirs.push(fileName);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var allFilenames = Object.keys(files);
|
var allFilenames = Object.keys(result.files);
|
||||||
allFilenames.forEach(function(f) {
|
allFilenames.forEach(function(f) {
|
||||||
var entry = files[f];
|
var entry = result.files[f];
|
||||||
if (!entry.hasOwnProperty('status')) {
|
if (!entry.hasOwnProperty('status')) {
|
||||||
unknownDirs.forEach(function(uf) {
|
unknownDirs.forEach(function(uf) {
|
||||||
if (f.startsWith(uf)) {
|
if (f.startsWith(uf)) {
|
||||||
@ -168,56 +231,185 @@ function getFiles(localRepo) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
// console.log(files);
|
// console.log(files);
|
||||||
return files;
|
return result;
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseLog(log) {
|
function parseLog(log) {
|
||||||
var lines = log.split("\n");
|
var lines = log.split("\n");
|
||||||
var currentCommit = null;
|
var currentCommit = {};
|
||||||
var commits = [];
|
var commits = [];
|
||||||
lines.forEach(function(l) {
|
lines.forEach(function(l) {
|
||||||
if (/^sha: /.test(l)) {
|
if (l === "-----") {
|
||||||
if (currentCommit) {
|
|
||||||
commits.push(currentCommit);
|
commits.push(currentCommit);
|
||||||
}
|
|
||||||
currentCommit = {}
|
currentCommit = {}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
var m = /^(.*): (.*)$/.exec(l);
|
var m = /^(.*): (.*)$/.exec(l);
|
||||||
if (m) {
|
if (m) {
|
||||||
|
if (m[1] === 'refs' && m[2]) {
|
||||||
|
currentCommit[m[1]] = m[2].split(",").map(function(v) { return v.trim() });
|
||||||
|
} else {
|
||||||
|
if (m[1] === 'parents') {
|
||||||
|
currentCommit[m[1]] = m[2].split(" ");
|
||||||
|
} else {
|
||||||
currentCommit[m[1]] = m[2];
|
currentCommit[m[1]] = m[2];
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (currentCommit) {
|
|
||||||
commits.push(currentCommit);
|
|
||||||
}
|
}
|
||||||
return {commits: commits};
|
}
|
||||||
|
});
|
||||||
|
return commits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// function getCommitCounts(cwd, options) {
|
||||||
|
// var commands = [
|
||||||
|
// runGitCommand(['rev-list', 'HEAD', '--count'],cwd), // #commits on master
|
||||||
|
// ];
|
||||||
|
// if (options.hasRemote) {
|
||||||
|
// commands.push(runGitCommand(['rev-list', 'master','^origin/master', '--count'],cwd)); // #commits master ahead
|
||||||
|
// commands.push(runGitCommand(['rev-list', '^master','origin/master', '--count'],cwd)); // #commits master behind
|
||||||
|
// }
|
||||||
|
// return when.all(commands).then(function(results) {
|
||||||
|
// var result = {
|
||||||
|
// total: parseInt(results[0])
|
||||||
|
// }
|
||||||
|
// if (options.hasRemote) {
|
||||||
|
// result.ahead = parseInt(results[1]);
|
||||||
|
// result.behind = parseInt(results[2]);
|
||||||
|
// }
|
||||||
|
// return result;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
function getRemotes(cwd) {
|
||||||
|
return runGitCommand(['remote','-v'],cwd).then(function(output) {
|
||||||
|
var result;
|
||||||
|
if (output.length > 0) {
|
||||||
|
result = {};
|
||||||
|
var remoteRE = /^(.+)\t(.+) \((.+)\)$/gm;
|
||||||
|
var m;
|
||||||
|
while ((m = remoteRE.exec(output)) !== null) {
|
||||||
|
result[m[1]] = result[m[1]]||{};
|
||||||
|
result[m[1]][m[3]] = m[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBranches(cwd, remote) {
|
||||||
|
var args = ['branch','--no-color'];
|
||||||
|
if (remote) {
|
||||||
|
args.push('-r');
|
||||||
|
}
|
||||||
|
return runGitCommand(args,cwd).then(function(output) {
|
||||||
|
var branches = [];
|
||||||
|
var lines = output.split("\n");
|
||||||
|
branches = lines.map(function(l) { return l.substring(2)})
|
||||||
|
.filter(function(l) {
|
||||||
|
return !/HEAD ->/.test(l) && (l.length > 0)
|
||||||
|
});
|
||||||
|
return {branches:branches};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function getBranchStatus(cwd,remoteBranch) {
|
||||||
|
var commands = [
|
||||||
|
// #commits master ahead
|
||||||
|
runGitCommand(['rev-list', 'HEAD','^'+remoteBranch, '--count'],cwd),
|
||||||
|
// #commits master behind
|
||||||
|
runGitCommand(['rev-list', '^HEAD',remoteBranch, '--count'],cwd)
|
||||||
|
];
|
||||||
|
return when.all(commands).then(function(results) {
|
||||||
|
return {
|
||||||
|
commits: {
|
||||||
|
ahead: parseInt(results[0]),
|
||||||
|
behind: parseInt(results[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitCommand = "git";
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
init: function(_settings,_runtime) {
|
||||||
|
log = _runtime.log
|
||||||
|
},
|
||||||
initRepo: function(cwd) {
|
initRepo: function(cwd) {
|
||||||
return runCommand(gitCommand,["init"],cwd);
|
return runGitCommand(["init"],cwd);
|
||||||
},
|
},
|
||||||
pull: function(repo, cwd) {
|
setUpstream: function(cwd,remoteBranch) {
|
||||||
if (repo.url) {
|
var args = ["branch","--set-upstream-to",remoteBranch];
|
||||||
repo = repo.url;
|
return runGitCommand(args,cwd);
|
||||||
|
},
|
||||||
|
pull: function(cwd,remoteBranch) {
|
||||||
|
var args = ["pull"];
|
||||||
|
var m = /^(.*?)\/(.*)$/.exec(remoteBranch);
|
||||||
|
if (m) {
|
||||||
|
args.push(m[1]);
|
||||||
|
args.push(m[2])
|
||||||
}
|
}
|
||||||
var args = ["pull",repo,"master"];
|
return runGitCommand(args,cwd).otherwise(function(err) {
|
||||||
return runCommand(gitCommand,args,cwd);
|
if (/CONFLICT/.test(err.stdout)) {
|
||||||
},
|
var e = new Error("NLS: pull failed - merge conflict");
|
||||||
clone: function(repo, cwd) {
|
e.code = "git_pull_merge_conflict";
|
||||||
if (repo.url) {
|
throw e;
|
||||||
repo = repo.url;
|
} else if (/Please commit your changes or stash/.test(err.message)) {
|
||||||
|
var e = new Error("NLS: Pull failed - local changes would be overwritten");
|
||||||
|
e.code = "git_pull_overwrite";
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
var args = ["clone",repo,"."];
|
throw err;
|
||||||
return runCommand(gitCommand,args,cwd);
|
});
|
||||||
},
|
},
|
||||||
getFiles: getFiles,
|
push: function(cwd,remoteBranch,setUpstream) {
|
||||||
|
var args = ["push"];
|
||||||
|
var m = /^(.*?)\/(.*)$/.exec(remoteBranch);
|
||||||
|
if (m) {
|
||||||
|
if (setUpstream) {
|
||||||
|
args.push("-u");
|
||||||
|
}
|
||||||
|
args.push(m[1]);
|
||||||
|
args.push("HEAD:"+m[2]);
|
||||||
|
} else {
|
||||||
|
args.push("origin");
|
||||||
|
}
|
||||||
|
args.push("--porcelain");
|
||||||
|
return runGitCommand(args,cwd).otherwise(function(err) {
|
||||||
|
if (err.code === 'git_error') {
|
||||||
|
if (/^!.*non-fast-forward/m.test(err.stdout)) {
|
||||||
|
err.code = 'git_push_failed';
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clone: function(remote, cwd) {
|
||||||
|
var args = ["clone",remote.url];
|
||||||
|
if (remote.name) {
|
||||||
|
args.push("-o");
|
||||||
|
args.push(remote.name);
|
||||||
|
}
|
||||||
|
if (remote.branch) {
|
||||||
|
args.push("-b");
|
||||||
|
args.push(remote.branch);
|
||||||
|
}
|
||||||
|
args.push(".");
|
||||||
|
if (remote.hasOwnProperty("username") && remote.hasOwnProperty("password")) {
|
||||||
|
return runGitCommandWithAuth(args,cwd,remote);
|
||||||
|
} else {
|
||||||
|
return runGitCommand(args,cwd);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getStatus: getStatus,
|
||||||
getFile: function(cwd, filePath, treeish) {
|
getFile: function(cwd, filePath, treeish) {
|
||||||
var args = ["show",treeish+":"+filePath];
|
var args = ["show",treeish+":"+filePath];
|
||||||
return runCommand(gitCommand,args,cwd);
|
return runGitCommand(args,cwd);
|
||||||
|
},
|
||||||
|
getFiles: function(cwd) {
|
||||||
|
return getStatus(cwd).then(function(status) {
|
||||||
|
return status.files;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
stageFile: function(cwd,file) {
|
stageFile: function(cwd,file) {
|
||||||
var args = ["add"];
|
var args = ["add"];
|
||||||
@ -226,18 +418,18 @@ module.exports = {
|
|||||||
} else {
|
} else {
|
||||||
args.push(file);
|
args.push(file);
|
||||||
}
|
}
|
||||||
return runCommand(gitCommand,args,cwd);
|
return runGitCommand(args,cwd);
|
||||||
},
|
},
|
||||||
unstageFile: function(cwd, file) {
|
unstageFile: function(cwd, file) {
|
||||||
var args = ["reset","--"];
|
var args = ["reset","--"];
|
||||||
if (file) {
|
if (file) {
|
||||||
args.push(file);
|
args.push(file);
|
||||||
}
|
}
|
||||||
return runCommand(gitCommand,args,cwd);
|
return runGitCommand(args,cwd);
|
||||||
},
|
},
|
||||||
commit: function(cwd, message) {
|
commit: function(cwd, message) {
|
||||||
var args = ["commit","-m",message];
|
var args = ["commit","-m",message];
|
||||||
return runCommand(gitCommand,args,cwd);
|
return runGitCommand(args,cwd);
|
||||||
},
|
},
|
||||||
getFileDiff(cwd,file,type) {
|
getFileDiff(cwd,file,type) {
|
||||||
var args = ["diff"];
|
var args = ["diff"];
|
||||||
@ -247,14 +439,53 @@ module.exports = {
|
|||||||
args.push("--cached");
|
args.push("--cached");
|
||||||
}
|
}
|
||||||
args.push(file);
|
args.push(file);
|
||||||
return runCommand(gitCommand,args,cwd);
|
return runGitCommand(args,cwd);
|
||||||
|
},
|
||||||
|
fetch: function(cwd) {
|
||||||
|
return runGitCommand(["fetch"],cwd);
|
||||||
},
|
},
|
||||||
getCommits: function(cwd,options) {
|
getCommits: function(cwd,options) {
|
||||||
var args = ["log", "--format=sha: %H%nauthor: %an%ndate: %ct%nsubject: %s","-n 10"];
|
var args = ["log", "--format=sha: %H%nparents: %p%nrefs: %D%nauthor: %an%ndate: %ct%nsubject: %s%n-----"];
|
||||||
return runCommand(gitCommand,args,cwd).then(parseLog);
|
var limit = parseInt(options.limit) || 20;
|
||||||
|
args.push("-n "+limit);
|
||||||
|
var before = options.before;
|
||||||
|
if (before) {
|
||||||
|
args.push(before);
|
||||||
|
}
|
||||||
|
var commands = [
|
||||||
|
runGitCommand(['rev-list', 'HEAD', '--count'],cwd),
|
||||||
|
runGitCommand(args,cwd).then(parseLog)
|
||||||
|
];
|
||||||
|
return when.all(commands).then(function(results) {
|
||||||
|
var result = results[0];
|
||||||
|
result.count = results[1].length;
|
||||||
|
result.before = before;
|
||||||
|
result.commits = results[1];
|
||||||
|
return {
|
||||||
|
count: results[1].length,
|
||||||
|
commits: results[1],
|
||||||
|
before: before,
|
||||||
|
total: parseInt(results[0])
|
||||||
|
};
|
||||||
|
})
|
||||||
},
|
},
|
||||||
getCommit: function(cwd,sha) {
|
getCommit: function(cwd,sha) {
|
||||||
var args = ["show",sha];
|
var args = ["show",sha];
|
||||||
return runCommand(gitCommand,args,cwd);
|
return runGitCommand(args,cwd);
|
||||||
|
},
|
||||||
|
abortMerge: function(cwd) {
|
||||||
|
return runGitCommand(['merge','--abort'],cwd);
|
||||||
|
},
|
||||||
|
getRemotes: getRemotes,
|
||||||
|
getBranches: getBranches,
|
||||||
|
getBranchInfo: getBranchInfo,
|
||||||
|
checkoutBranch: function(cwd, branchName, isCreate) {
|
||||||
|
var args = ['checkout'];
|
||||||
|
if (isCreate) {
|
||||||
|
args.push('-b');
|
||||||
}
|
}
|
||||||
|
args.push(branchName);
|
||||||
|
return runGitCommand(args,cwd);
|
||||||
|
},
|
||||||
|
getBranchStatus: getBranchStatus
|
||||||
}
|
}
|
||||||
|
1
red/runtime/storage/localfilesystem/projects/git/node-red-ask-pass.sh
Executable file
1
red/runtime/storage/localfilesystem/projects/git/node-red-ask-pass.sh
Executable file
@ -0,0 +1 @@
|
|||||||
|
"$NODE_RED_GIT_NODE_PATH" "$NODE_RED_GIT_ASKPASS_PATH" "$NODE_RED_GIT_SOCK_PATH" $@
|
@ -36,6 +36,7 @@ function init(_settings, _runtime) {
|
|||||||
settings = _settings;
|
settings = _settings;
|
||||||
runtime = _runtime;
|
runtime = _runtime;
|
||||||
log = runtime.log;
|
log = runtime.log;
|
||||||
|
gitTools.init(_settings, _runtime);
|
||||||
|
|
||||||
Projects.init(settings,runtime);
|
Projects.init(settings,runtime);
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ function getProject(name) {
|
|||||||
function checkActiveProject(project) {
|
function checkActiveProject(project) {
|
||||||
if (!activeProject || activeProject.name !== project) {
|
if (!activeProject || activeProject.name !== project) {
|
||||||
//TODO: throw better err
|
//TODO: throw better err
|
||||||
throw new Error("Cannot operate on inactive project");
|
throw new Error("Cannot operate on inactive project wanted:"+project+" current:"+(activeProject&&activeProject.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function getFiles(project) {
|
function getFiles(project) {
|
||||||
@ -157,7 +158,38 @@ function getFile(project,filePath,sha) {
|
|||||||
checkActiveProject(project);
|
checkActiveProject(project);
|
||||||
return activeProject.getFile(filePath,sha);
|
return activeProject.getFile(filePath,sha);
|
||||||
}
|
}
|
||||||
|
function push(project,remoteBranchName,setRemote) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.push(remoteBranchName,setRemote);
|
||||||
|
}
|
||||||
|
function pull(project,remoteBranchName,setRemote) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.pull(remoteBranchName,setRemote).then(reloadActiveProject);
|
||||||
|
}
|
||||||
|
function getStatus(project) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.status();
|
||||||
|
}
|
||||||
|
function resolveMerge(project,file,resolution) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.resolveMerge(file,resolution);
|
||||||
|
}
|
||||||
|
function abortMerge(project) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.abortMerge().then(reloadActiveProject);
|
||||||
|
}
|
||||||
|
function getBranches(project,remote) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.getBranches(remote);
|
||||||
|
}
|
||||||
|
function setBranch(project,branchName,isCreate) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.setBranch(branchName,isCreate).then(reloadActiveProject);
|
||||||
|
}
|
||||||
|
function getBranchStatus(project,branchName) {
|
||||||
|
checkActiveProject(project);
|
||||||
|
return activeProject.getBranchStatus(branchName);
|
||||||
|
}
|
||||||
function getActiveProject() {
|
function getActiveProject() {
|
||||||
return activeProject;
|
return activeProject;
|
||||||
}
|
}
|
||||||
@ -347,6 +379,14 @@ module.exports = {
|
|||||||
getFileDiff: getFileDiff,
|
getFileDiff: getFileDiff,
|
||||||
getCommits: getCommits,
|
getCommits: getCommits,
|
||||||
getCommit: getCommit,
|
getCommit: getCommit,
|
||||||
|
push: push,
|
||||||
|
pull: pull,
|
||||||
|
getStatus:getStatus,
|
||||||
|
resolveMerge: resolveMerge,
|
||||||
|
abortMerge: abortMerge,
|
||||||
|
getBranches: getBranches,
|
||||||
|
setBranch: setBranch,
|
||||||
|
getBranchStatus:getBranchStatus,
|
||||||
|
|
||||||
getFlows: getFlows,
|
getFlows: getFlows,
|
||||||
saveFlows: saveFlows,
|
saveFlows: saveFlows,
|
||||||
|
Loading…
Reference in New Issue
Block a user