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

Allow unstaged files to be reverted

This commit is contained in:
Nick O'Leary 2017-12-11 17:05:12 +00:00
parent 604e3068b2
commit bb59cd5742
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
8 changed files with 180 additions and 81 deletions

View File

@ -72,8 +72,9 @@
"abort-merge":"Git merge aborted", "abort-merge":"Git merge aborted",
"loaded":"Project '"+msg.project+"' loaded", "loaded":"Project '"+msg.project+"' loaded",
"updated":"Project '"+msg.project+"' updated", "updated":"Project '"+msg.project+"' updated",
"pull":"Project '"+msg.project+"' reloaded" "pull":"Project '"+msg.project+"' reloaded",
}[msg.action] "revert": "Project '"+msg.project+"' reloaded"
}[msg.action];
RED.notify(message); RED.notify(message);
RED.sidebar.info.refresh() RED.sidebar.info.refresh()
}); });

View File

@ -134,6 +134,7 @@ RED.projects.settings = (function() {
}, },
200: function(data) { 200: function(data) {
done(null,data); done(null,data);
RED.sidebar.versionControl.refresh(true);
}, },
400: { 400: {
'unexpected_error': function(error) { 'unexpected_error': function(error) {
@ -197,6 +198,7 @@ RED.projects.settings = (function() {
done(error,null); done(error,null);
}, },
200: function(data) { 200: function(data) {
RED.sidebar.versionControl.refresh(true);
done(null,data); done(null,data);
}, },
400: { 400: {
@ -326,6 +328,7 @@ RED.projects.settings = (function() {
done(error,null); done(error,null);
}, },
200: function(data) { 200: function(data) {
RED.sidebar.versionControl.refresh(true);
done(null,data); done(null,data);
}, },
400: { 400: {
@ -900,6 +903,7 @@ RED.projects.settings = (function() {
}, },
200: function(data) { 200: function(data) {
activeProject = data; activeProject = data;
RED.sidebar.versionControl.refresh(true);
updateForm(); updateForm();
done(); done();
}, },

View File

@ -39,7 +39,82 @@ RED.sidebar.versionControl = (function() {
var isMerging; var isMerging;
// TODO: DRY projectSummary.js function viewFileDiff(entry,state) {
var activeProject = RED.projects.getActiveProject();
var diffTarget = (state === 'staged')?"index":"tree";
utils.sendRequest({
url: "projects/"+activeProject.name+"/diff/"+diffTarget+"/"+encodeURIComponent(entry.file),
type: "GET",
responses: {
0: function(error) {
console.log(error);
// done(error,null);
},
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 = {
diff: data.diff,
title: title,
unmerged: state === 'unmerged',
project: activeProject
}
if (state == 'unstaged') {
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: {
'unexpected_error': function(error) {
console.log(error);
// done(error,null);
}
},
}
},{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);
}
}
}
})
}
function createChangeEntry(row, entry, status, state) { function createChangeEntry(row, entry, status, state) {
row.addClass("sidebar-version-control-change-entry"); row.addClass("sidebar-version-control-change-entry");
@ -52,88 +127,67 @@ RED.sidebar.versionControl = (function() {
var icon = $('<i class=""></i>').appendTo(container); var icon = $('<i class=""></i>').appendTo(container);
var label = $('<span>').appendTo(container); var entryLink = $('<a href="#">')
.appendTo(container)
.click(function(e) {
e.preventDefault();
viewFileDiff(entry,state);
});
var label = $('<span>').appendTo(entryLink);
var bg = $('<div class="button-group"></div>').appendTo(row); var entryTools = $('<div class="sidebar-version-control-change-entry-tools">').appendTo(row);
var viewDiffButton = $('<button class="editor-button editor-button-small"><i class="fa fa-'+(state==='unmerged'?'columns':'eye')+'"></i></button>') var bg;
.appendTo(bg) var revertButton;
.click(function(evt) { if (state === 'unstaged') {
evt.preventDefault(); bg = $('<span class="button-group" style="margin-right: 5px;"></span>').appendTo(entryTools);
var activeProject = RED.projects.getActiveProject(); revertButton = $('<button class="editor-button editor-button-small"><i class="fa fa-reply"></i></button>')
var diffTarget = (state === 'staged')?"index":"tree"; .appendTo(bg)
utils.sendRequest({ .click(function(evt) {
url: "projects/"+activeProject.name+"/diff/"+diffTarget+"/"+encodeURIComponent(entry.file), evt.preventDefault();
type: "GET", var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain');
responses: { var notification = RED.notify("Are you sure you want to revert the changes to '"+entry.file+"'? This cannot be undone.", {
0: function(error) { type: "warning",
console.log(error); modal: true,
// done(error,null); fixed: true,
}, buttons: [
200: function(data) { {
if (mergeConflictNotification) { text: RED._("common.label.cancel"),
mergeConflictNotification.close(); click: function() {
mergeConflictNotification = null; spinner.remove();
} notification.close();
var title; }
if (state === 'unstaged') { },{
title = 'Unstaged changes : '+entry.file text: 'Revert changes',
} else if (state === 'staged') { click: function() {
title = 'Staged changes : '+entry.file notification.close();
} else { var activeProject = RED.projects.getActiveProject();
title = 'Resolve conflicts : '+entry.file var url = "projects/"+activeProject.name+"/files/_/"+entry.file;
} var options = {
var options = { url: url,
diff: data.diff, type: "DELETE",
title: title,
unmerged: state === 'unmerged',
project: activeProject
}
if (state == 'unstaged') {
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: { responses: {
0: function(error) {
console.log(error);
// done(error,null);
},
200: function(data) { 200: function(data) {
refresh(true); spinner.remove();
}, },
400: { 400: {
'unexpected_error': function(error) { 'unexpected_error': function(error) {
spinner.remove();
console.log(error); console.log(error);
// done(error,null); // done(error,null);
} }
}, }
} }
},{resolutions:resolution.resolutions[entry.file]}); }
utils.sendRequest(options);
} }
} }
options.oncancel = showMergeConflictNotification;
RED.diff.showUnifiedDiff(options); ]
// console.log(data.diff); })
},
400: { });
'unexpected_error': function(error) { }
console.log(error); bg = $('<span class="button-group"></span>').appendTo(entryTools);
// done(error,null);
}
}
}
})
})
if (state !== 'unmerged') { if (state !== 'unmerged') {
$('<button class="editor-button editor-button-small"><i class="fa fa-'+((state==='unstaged')?"plus":"minus")+'"></i></button>') $('<button class="editor-button editor-button-small"><i class="fa fa-'+((state==='unstaged')?"plus":"minus")+'"></i></button>')
.appendTo(bg) .appendTo(bg)
@ -203,11 +257,10 @@ RED.sidebar.versionControl = (function() {
delete entry.spinner; delete entry.spinner;
} }
viewDiffButton.attr("disabled",(status === 'D' || status === '?')); if (revertButton) {
viewDiffButton.find("i") revertButton.toggle(status !== '?');
.toggleClass('fa-eye',!(status === 'D' || status === '?')) }
.toggleClass('fa-eye-slash',(status === 'D' || status === '?')) entryLink.toggleClass("disabled",(status === 'D' || status === '?'));
} }
entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status); entry["update"+((state==='unstaged')?"Unstaged":"Staged")](entry, status);
} }

View File

@ -444,7 +444,13 @@
span { span {
margin: 0 6px; margin: 0 6px;
} }
.button-group { a {
color: currentColor;
&.disabled {
pointer-events: none;
}
}
.sidebar-version-control-change-entry-tools {
position: absolute; position: absolute;
top: 4px; top: 4px;
right: 4px; right: 4px;
@ -455,7 +461,7 @@
} }
&:hover { &:hover {
.button-group { .sidebar-version-control-change-entry-tools {
display: block; display: block;
} }
} }

View File

@ -170,6 +170,22 @@ module.exports = {
}) })
}); });
// Revert a file
app.delete("/:id/files/_/*", needsPermission("projects.write"), function(req,res) {
var projectId = req.params.id;
var filePath = req.params[0];
runtime.storage.projects.revertFile(req.user, projectId,filePath).then(function() {
res.status(204).end();
})
.catch(function(err) {
console.log(err.stack);
res.status(400).json({error:"unexpected_error", message:err.toString()});
})
});
// Stage a file // Stage a file
app.post("/:id/stage/*", needsPermission("projects.write"), function(req,res) { app.post("/:id/stage/*", needsPermission("projects.write"), function(req,res) {
var projectName = req.params.id; var projectName = req.params.id;

View File

@ -329,6 +329,14 @@ Project.prototype.getFile = function (filePath,treeish) {
return fs.readFile(fspath.join(this.path,filePath),"utf8"); return fs.readFile(fspath.join(this.path,filePath),"utf8");
} }
}; };
Project.prototype.revertFile = function (filePath) {
var self = this;
return gitTools.revertFile(this.path, filePath).then(function() {
return self.load();
});
};
Project.prototype.status = function(user) { Project.prototype.status = function(user) {
var self = this; var self = this;

View File

@ -421,6 +421,10 @@ module.exports = {
return status.files; return status.files;
}) })
}, },
revertFile: function(cwd, filePath) {
var args = ["checkout",filePath];
return runGitCommand(args,cwd);
},
stageFile: function(cwd,file) { stageFile: function(cwd,file) {
var args = ["add"]; var args = ["add"];
if (Array.isArray(file)) { if (Array.isArray(file)) {

View File

@ -173,7 +173,7 @@ function getFileDiff(user, project,file,type) {
} }
function getCommits(user, project,options) { function getCommits(user, project,options) {
checkActiveProject(project); checkActiveProject(project);
return activeProject.getCommits(options); return activeProject.getCommits(options);
} }
function getCommit(user, project,sha) { function getCommit(user, project,sha) {
checkActiveProject(project); checkActiveProject(project);
@ -184,6 +184,12 @@ function getFile(user, project,filePath,sha) {
checkActiveProject(project); checkActiveProject(project);
return activeProject.getFile(filePath,sha); return activeProject.getFile(filePath,sha);
} }
function revertFile(user, project,filePath) {
checkActiveProject(project);
return activeProject.revertFile(filePath).then(function() {
return reloadActiveProject("revert");
})
}
function push(user, project,remoteBranchName,setRemote) { function push(user, project,remoteBranchName,setRemote) {
checkActiveProject(project); checkActiveProject(project);
return activeProject.push(user,remoteBranchName,setRemote); return activeProject.push(user,remoteBranchName,setRemote);
@ -413,6 +419,7 @@ module.exports = {
updateProject: updateProject, updateProject: updateProject,
getFiles: getFiles, getFiles: getFiles,
getFile: getFile, getFile: getFile,
revertFile: revertFile,
stageFile: stageFile, stageFile: stageFile,
unstageFile: unstageFile, unstageFile: unstageFile,
commit: commit, commit: commit,