Skip to content

Commit 2b8bbf1

Browse files
authored
Stash list, pop, apply, drop; stash files from workspace (#95)
* Add tab to view stash; List changes in the stash; Display changes in each stashed commit. * Applying/Popping from Stash is now possible * Stash changed files from workspace * Drop selected stash * Message if stash is empty Co-authored-by: Sarmishta Velury <[email protected]>
1 parent 67c8612 commit 2b8bbf1

File tree

6 files changed

+508
-8
lines changed

6 files changed

+508
-8
lines changed

git-webui/release/share/git-webui/webui/css/git-webui.css

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ body {
187187
#sidebar #sidebar-content #sidebar-workspace h4:before {
188188
content: url(../img/computer.svg);
189189
}
190+
#sidebar #sidebar-content #sidebar-stash h4:before {
191+
content: url(../img/inboxes.svg);
192+
}
190193
#sidebar #sidebar-content #sidebar-remote h4:before {
191194
content: url(../img/daemon.svg);
192195
}
@@ -257,14 +260,18 @@ body {
257260
font-size: 36pt;
258261
margin-top: 0;
259262
}
260-
#history-view {
263+
#history-view,
264+
#stash-view {
261265
display: flex;
262266
display: -webkit-flex;
263267
min-height: 0;
264268
min-width: 0;
265269
flex: 1 1 0px;
266270
-webkit-flex: 1 1 0px;
267271
}
272+
.empty-stash {
273+
text-align: center;
274+
}
268275
#log-view {
269276
flex: 1 1 0px;
270277
-webkit-flex: 1 1 0px;
@@ -311,6 +318,9 @@ body {
311318
align-items: baseline;
312319
-webkit-align-items: baseline;
313320
}
321+
#log-view .log-entry header .stash-list-index {
322+
display: none !important;
323+
}
314324
#log-view .log-entry header h6 {
315325
font-weight: bold;
316326
margin-top: 0;
Lines changed: 3 additions & 0 deletions
Loading

git-webui/release/share/git-webui/webui/js/git-webui.js

Lines changed: 239 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ webui.SideBarView = function(mainView) {
398398
'<section id="sidebar-workspace">' +
399399
'<h4>Workspace</h4>' +
400400
'</section>' +
401+
'<section id="sidebar-stash">' +
402+
'<h4>Stash</h4>' +
403+
'</section>' +
401404
'<section id="sidebar-local-branches">' +
402405
'<h4 class="mt-3">Local Branches' +
403406
'<button type="button" class="btn btn-default btn-sidebar-icon btn-add shadow-none" >' +
@@ -430,6 +433,13 @@ webui.SideBarView = function(mainView) {
430433
workspaceElement.addClass("active");
431434
self.mainView.workspaceView.update("stage");
432435
});
436+
437+
var stashElement = $("#sidebar-stash h4", self.element);
438+
stashElement.click(function (event) {
439+
$("*", self.element).removeClass("active");
440+
stashElement.addClass("active");
441+
self.mainView.stashView.update(0);
442+
});
433443
}
434444

435445
self.fetchSection($("#sidebar-local-branches", self.element)[0], "Local Branches", "local-branches", "branch");
@@ -723,10 +733,168 @@ webui.LogView = function(historyView) {
723733
var streamColor = 0;
724734
};
725735

736+
webui.StashView = function(mainView) {
737+
738+
var self = this;
739+
740+
self.show = function() {
741+
mainView.switchTo(self.element);
742+
};
743+
744+
self.update = function(stashIndex) {
745+
self.show();
746+
self.stashListView.update(stashIndex);
747+
};
748+
749+
self.element = $('<div id="stash-view">')[0];
750+
751+
self.stashListView = new webui.StashListView(self);
752+
self.element.appendChild(self.stashListView.element);
753+
self.commitView = new webui.StashCommitView(self);
754+
self.element.appendChild(self.commitView.element);
755+
self.mainView = mainView;
756+
}
757+
758+
webui.StashListView = function(stashView) {
759+
var self = this;
760+
761+
self.update = function(stashIndex){
762+
$(svg).empty();
763+
$(content).empty();
764+
self.populate();
765+
}
766+
767+
self.populate = function() {
768+
webui.git("stash list --format='%gd::%ch::%cL::%cN::%gs'", function(data) {
769+
var start = 0;
770+
var count = 0;
771+
while (true) {
772+
var end = data.indexOf("\n", start);
773+
if (end != -1) {
774+
var len = end - start;
775+
} else {
776+
break;
777+
}
778+
var entry = new Entry(self, data.substring(start, start+len));
779+
if(start == 0){
780+
entry.select();
781+
}
782+
content.appendChild(entry.element);
783+
784+
start = end + 1;
785+
++count;
786+
}
787+
if(count == 0){
788+
var emptyStash = $('<h4 class="empty-stash">You have no stashed changes.</h4>');
789+
var emptyDiv = $('<h1 class="empty-stash">&nbsp<br>&nbsp</h1>');
790+
$("#log-view div").append(emptyDiv);
791+
$("#log-view div").append(emptyStash);
792+
}
793+
svg.setAttribute("height", $(content).outerHeight());
794+
svg.setAttribute("width", $(content).outerWidth());
795+
});
796+
}
797+
798+
function Entry(stashListView, data) {
799+
var self = this;
800+
801+
self.abbrevMessage = function() {
802+
var end = self.message.indexOf("\n");
803+
if (end == -1) {
804+
return self.message
805+
} else {
806+
return self.message.substring(0, end);
807+
}
808+
};
809+
810+
self.createElement = function() {
811+
self.element = $('<a class="log-entry list-group-item">' +
812+
'<header>' +
813+
'<h6></h6>' +
814+
'<p class="stash-list-index">' + self.stashIndex + '</p>' +
815+
'<span class="log-entry-date">' + self.date + '&nbsp;</span> ' +
816+
'<span class="badge">' + self.commit + '</span>' +
817+
'</header>' +
818+
'<p class="list-group-item-text"></p>' +
819+
'</a>')[0];
820+
$('<a target="_blank" href="mailto:' + self.authorEmail + '">' + self.authorName + '</a>').appendTo($("h6", self.element));
821+
$(".list-group-item-text", self.element)[0].appendChild(document.createTextNode(self.commitMessage));
822+
823+
self.element.model = self;
824+
var model = self;
825+
$(self.element).click(function (event) {
826+
model.select();
827+
});
828+
return self.element;
829+
};
830+
831+
self.select = function() {
832+
if (currentSelection != self) {
833+
if (currentSelection) {
834+
$(currentSelection.element).removeClass("active");
835+
}
836+
$(self.element).addClass("active");
837+
currentSelection = self;
838+
stashListView.stashView.commitView.update(self);
839+
}
840+
};
841+
842+
self.parents = [];
843+
self.message = ""
844+
845+
var pieces = data.split(/::|:\s/gm);
846+
self.stashIndex = pieces[0].substring(pieces[0].indexOf('{')+1, pieces[0].indexOf('}'));
847+
self.date = pieces[1];
848+
self.authorEmail = pieces[2];
849+
self.authorName = pieces[3];
850+
self.branchName = pieces[4];
851+
self.commit = pieces[5].substring(0, pieces[5].indexOf(" "));
852+
self.commitMessage = pieces[5].substring(pieces[5].indexOf(" ")).trim();
853+
854+
self.createElement();
855+
};
856+
857+
self.element = $('<div id="log-view" class="list-group"><svg xmlns="http://www.w3.org/2000/svg"></svg><div></div></div>')[0];
858+
var svg = self.element.children[0];
859+
var content = self.element.children[1];
860+
var currentSelection = null;
861+
// var lineHeight = null;
862+
// var streams = [];
863+
// var streamColor = 0;
864+
self.stashView = stashView
865+
}
866+
867+
webui.StashCommitView = function(stashView) {
868+
var self = this;
869+
870+
self.update = function(entry) {
871+
if (currentCommit == entry.commit) {
872+
// We already display the right data. No need to update.
873+
return;
874+
875+
}
876+
currentCommit = entry.commit;
877+
self.showDiff();
878+
diffView.update("stash show -p stash@{"+entry.stashIndex+"}");
879+
};
880+
881+
self.showDiff = function() {
882+
webui.detachChildren(commitViewContent);
883+
commitViewContent.appendChild(diffView.element);
884+
};
885+
886+
self.stashView = stashView;
887+
var currentCommit = null;
888+
self.element = $('<div id="commit-view">')[0];
889+
var commitViewContent = $('<div id="commit-view-content">')[0];
890+
self.element.appendChild(commitViewContent);
891+
var diffView = new webui.DiffView(undefined, false, self, true);
892+
};
893+
726894
/*
727895
* == DiffView ================================================================
728896
*/
729-
webui.DiffView = function(sideBySide, hunkSelectionAllowed, parent) {
897+
webui.DiffView = function(sideBySide, hunkSelectionAllowed, parent, stashedCommit) {
730898

731899
var self = this;
732900

@@ -1080,6 +1248,38 @@ webui.DiffView = function(sideBySide, hunkSelectionAllowed, parent) {
10801248
commitExplorerView.show();
10811249
};
10821250

1251+
self.applySelectedStash = function() {
1252+
if(! self.currentDiff) {
1253+
return;
1254+
}
1255+
var stashIndex = parseInt($(".log-entry.active .stash-list-index").text());
1256+
webui.git("stash apply stash@{"+stashIndex+"}", function(output){
1257+
webui.showSuccess(output);
1258+
});
1259+
}
1260+
1261+
self.popSelectedStash = function() {
1262+
if(! self.currentDiff) {
1263+
return;
1264+
}
1265+
var stashIndex = parseInt($(".log-entry.active .stash-list-index").text());
1266+
webui.git("stash pop stash@{"+stashIndex+"}", function(output){
1267+
webui.showSuccess(output);
1268+
parent.stashView.update(0);
1269+
});
1270+
}
1271+
1272+
self.dropSelectedStash = function() {
1273+
if(! self.currentDiff) {
1274+
return;
1275+
}
1276+
var stashIndex = parseInt($(".log-entry.active .stash-list-index").text());
1277+
webui.git("stash drop stash@{"+stashIndex+"}", function(output){
1278+
webui.showSuccess(output.substring(output.indexOf("Dropped")));
1279+
parent.stashView.update(0);
1280+
});
1281+
}
1282+
10831283
var html = '<div class="diff-view-container panel panel-default">';
10841284
if (! (parent instanceof webui.CommitExplorerView)) {
10851285
html +=
@@ -1096,7 +1296,10 @@ webui.DiffView = function(sideBySide, hunkSelectionAllowed, parent) {
10961296
'<button type="button" class="btn btn-default diff-cancel" style="display:none">Cancel</button>' +
10971297
'<button type="button" class="btn btn-default diff-unstage" style="display:none">Unstage</button>' +
10981298
'</div>' +
1099-
(sideBySide ? '' : '<button type="button" class="btn btn-sm btn-default diff-explore">Explore</button>') +
1299+
((sideBySide || stashedCommit) ? '' : '<button type="button" class="btn btn-sm btn-default diff-explore">Explore</button>') +
1300+
(stashedCommit ? '<button type="button" class="btn btn-sm btn-default apply-stash">Apply</button>':'')+
1301+
(stashedCommit ? '<button type="button" class="btn btn-sm btn-default pop-stash">Pop</button>':'')+
1302+
(stashedCommit ? '<button type="button" class="btn btn-sm btn-default drop-stash">Drop</button>':'')+
11001303
'</div>';
11011304
}
11021305
html += '<div class="panel-body"></div></div>'
@@ -1135,6 +1338,9 @@ webui.DiffView = function(sideBySide, hunkSelectionAllowed, parent) {
11351338
$(".diff-unstage", self.element).click(function() { self.applySelection(true, true); });
11361339

11371340
$(".diff-explore", self.element).click(function() { self.switchToExploreView(); });
1341+
$(".apply-stash", self.element).click(function() { self.applySelectedStash(); });
1342+
$(".pop-stash", self.element).click(function() { self.popSelectedStash(); });
1343+
$(".drop-stash", self.element).click(function() { self.popSelectedStash(); });
11381344

11391345
self.context = 3;
11401346
self.complete = false;
@@ -1820,6 +2026,35 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
18202026
}
18212027
}
18222028

2029+
self.stashByAvailability = function() {
2030+
prevScrollTop = fileListContainer.scrollTop;
2031+
self.stash();
2032+
2033+
var action = "stash";
2034+
2035+
var files = self.getFileList(undefined, "D", 1, 0);
2036+
var rmFiles = self.getFileList("D", undefined, 1, 0);
2037+
var combinedFiles = files.concat(rmFiles);
2038+
2039+
if(combinedFiles.length>0)
2040+
confirmActionForUnavailableFile(combinedFiles, action);
2041+
2042+
}
2043+
2044+
self.stash = function() {
2045+
var files = self.getFileList(undefined, "D", 0, 1);
2046+
var rmFiles = self.getFileList("D", undefined, 0, 1);
2047+
var combinedFiles = files+" "+rmFiles;
2048+
2049+
console.log(combinedFiles);
2050+
2051+
if(combinedFiles.length != 0){
2052+
webui.git("stash push -- " + combinedFiles, function(output){
2053+
webui.showSuccess(output);
2054+
});
2055+
}
2056+
}
2057+
18232058
self.getSelectedItemsCount = function() {
18242059
return $(".active", fileList).length;
18252060
}
@@ -1834,7 +2069,7 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
18342069
'</div>' +
18352070
'</div>')[0];
18362071
if (type == "working-copy") {
1837-
var buttons = [{ name: "Stage", callback: self.processByAvailability }, { name: "Cancel", callback: self.cancelByAvailability }];
2072+
var buttons = [{ name: "Stage", callback: self.processByAvailability }, { name: "Stash", callback: self.stash }, { name: "Cancel", callback: self.cancelByAvailability }];
18382073
} else {
18392074
var buttons = [{ name: "Unstage", callback: self.processByAvailability }];
18402075
}
@@ -1939,6 +2174,7 @@ function MainUi() {
19392174
self.historyView = new webui.HistoryView(self);
19402175
if (!webui.viewonly) {
19412176
self.workspaceView = new webui.WorkspaceView(self);
2177+
self.stashView = new webui.StashView(self);
19422178
}
19432179
});
19442180
});

git-webui/src/share/git-webui/webui/css/git-webui.less

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ body {
268268
content: url(../img/computer.svg);
269269
}
270270

271+
#sidebar-stash h4:before {
272+
content: url(../img/inboxes.svg);
273+
}
274+
271275
#sidebar-remote h4:before {
272276
content: url(../img/daemon.svg);
273277
}
@@ -348,11 +352,15 @@ body {
348352
}
349353
}
350354

351-
#history-view {
355+
#history-view, #stash-view {
352356
.display-flex();
353357
.flex(1);
354358
}
355359

360+
.empty-stash{
361+
text-align: center;
362+
}
363+
356364
#log-view {
357365
.flex(1);
358366
overflow-y: auto;
@@ -402,6 +410,10 @@ body {
402410
header {
403411
.display-flex();
404412
.align-items(baseline);
413+
414+
.stash-list-index{
415+
display: none !important;
416+
}
405417

406418
h6 {
407419
font-weight: bold;
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)