Skip to content

Commit 27e26ed

Browse files
authored
Queue filter (#82)
* committing to see deleted file * staged deleted file * Staging another file to delete later * Staging class file to see how delete works * clean up * Commit to test delete in Uncommitted queue * minor refactoring * delete class file made for testing * Add code to remove file from Uncommitted queue after commit. * Remove unneeded file * Uncommitted queue now saves deleted files * Commit changes with logging statements for testing * comitting temp file * deleting temp file * Add temp file again * commit delete of temp file * Add temp file again * delete temp file * Remove logging; SQL code to check for deleted file in Uncommitted queue; Deleted flag * actually saving the merge conflict resolution this time * The WebUIDriver now properly filters files that you can and can't commit.The UI adds a dialog for staging and unstaging edits from other users. * Remove logging * Popup now works properly * Fixed typo in method name (confirmActionForUnavailableFile) * Delete testfile.md Co-authored-by: Sarmishta Velury <[email protected]>
1 parent 7484851 commit 27e26ed

File tree

8 files changed

+349
-52
lines changed

8 files changed

+349
-52
lines changed

cls/SourceControl/Git/Change.cls

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ ClassMethod RemoveUncommitted(FileList, Display = 1, Revert = 0, ActiveCommit =
5858
quit SCs
5959
}
6060

61+
/// This method records a deleted file in the uncommitted queue
62+
ClassMethod AddDeletedToUncommitted(Filename, InternalName) As %Status
63+
{
64+
65+
Quit ..SetUncommitted(Filename, "delete", InternalName, $USERNAME, "", 1, "", "", 0)
66+
}
67+
6168
ClassMethod IsUncommitted(Filename, ByRef ID) As %Boolean
6269
{
6370
&SQL(SELECT ID INTO :ID FROM SourceControl_Git.Change WHERE ItemFile = :Filename AND Committed = '0')

cls/SourceControl/Git/Extension.cls

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,18 @@ Method IsInSourceControl(InternalName As %String) As %Boolean [ CodeMode = expre
248248
InternalName'="" && ##class(Utils).IsInSourceControl(##class(Utils).NormalizeInternalName(InternalName))
249249
}
250250

251+
/// Called before an item is deleted.
252+
Method OnBeforeDelete(InternalName As %String) As %Status
253+
{
254+
set context = ##class(SourceControl.Git.PackageManagerContext).ForInternalName(InternalName)
255+
set InternalName = ##class(Utils).NormalizeInternalName(InternalName)
256+
set Filename = ##class(Utils).FullExternalName(InternalName)
257+
if ##class(Utils).IsInSourceControl(InternalName) {
258+
quit ##class(Change).AddDeletedToUncommitted(Filename, InternalName)
259+
}
260+
quit $$$OK
261+
}
262+
251263
/// Called after an item is deleted.
252264
Method OnAfterDelete(InternalName As %String) As %Status
253265
{

cls/SourceControl/Git/Utils.cls

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ ClassMethod Commit(InternalName As %String, Message As %String = "example commit
265265
do outStream.OutputToDevice()
266266
write !
267267
do errStream.OutputToDevice()
268+
$$$QuitOnError(##class(SourceControl.Git.Change).RemoveUncommitted(filename))
269+
$$$QuitOnError(##class(SourceControl.Git.Change).RefreshUncommitted())
268270
quit $$$OK
269271
}
270272

@@ -1191,7 +1193,7 @@ ClassMethod RunGitCommandWithInput(command As %String, inFile As %String = "", O
11911193
quit returnCode
11921194
}
11931195

1194-
ClassMethod GitStatus(ByRef files)
1196+
ClassMethod GitStatus(ByRef files, IncludeAllFiles = 0)
11951197
{
11961198
do ..RunGitCommand("status", .errStream, .outStream, "-z", "-uall")
11971199
set lines = outStream.ReadLine()
@@ -1200,12 +1202,13 @@ ClassMethod GitStatus(ByRef files)
12001202
while $listnext(list, pointer, item) {
12011203
set operation = $extract(item, 1, 2)
12021204
set externalName = $extract(item, 4, *)
1203-
///w externalName_" "
12041205
set internalName = ..NameToInternalName(externalName)
1205-
///write internalName, !
12061206
if (internalName '= "") {
12071207
set files(internalName) = $listbuild(operation, externalName)
1208-
}
1208+
} elseif IncludeAllFiles {
1209+
set externalName = $TRANSLATE(externalName, "\", "/")
1210+
set files($I(files)) = $listbuild(operation, externalName)
1211+
}
12091212
}
12101213
}
12111214

@@ -1291,6 +1294,7 @@ ClassMethod Name(InternalName As %String) As %String
12911294
ClassMethod NameToInternalName(Name, IgnorePercent = 1, IgnoreNonexistent = 1) As %String
12921295
{
12931296
set InternalName=""
1297+
set Deleted = 0
12941298
if ($zconvert(Name,"U")'[$zconvert($$$SourceRoot,"U")) {
12951299
set Name = ##class(%File).NormalizeFilename(..TempFolder()_Name)
12961300
}
@@ -1301,6 +1305,13 @@ ClassMethod NameToInternalName(Name, IgnorePercent = 1, IgnoreNonexistent = 1) A
13011305
//only set if a single Name was returned ... ignore multi-item files
13021306
set InternalName=outName
13031307
}
1308+
} else {
1309+
// check for file in uncommitted queue
1310+
&sql(SELECT internalName into :InternalName FROM SourceControl_Git.Change where ItemFile = :Name)
1311+
if (SQLCODE = 100) {
1312+
set InternalName = ""
1313+
}
1314+
set Deleted = 1
13041315
}
13051316
if (InternalName="") {
13061317
if ($zconvert(Name,"U")'[$zconvert($$$SourceRoot,"U")) {
@@ -1375,7 +1386,7 @@ ClassMethod NameToInternalName(Name, IgnorePercent = 1, IgnoreNonexistent = 1) A
13751386
}
13761387
}
13771388
if ((IgnorePercent)&&($extract(InternalName)="%")) { set InternalName = "" } // don't return a result for % items if instructed to ignore them
1378-
if ((IgnoreNonexistent)&&('##class(%RoutineMgr).Exists(InternalName))) { set InternalName = "" } // only return item names which exist in the DB
1389+
if ((IgnoreNonexistent)&&('##class(%RoutineMgr).Exists(InternalName))&&('Deleted)) { set InternalName = "" } // only return item names which exist in the DB
13791390
quit ..NormalizeInternalName(InternalName)
13801391
}
13811392

cls/SourceControl/Git/WebUIDriver.cls

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ ClassMethod UserInfo() As %SystemBase
149149
ClassMethod Uncommitted() As %SystemBase
150150
{
151151
// Stub
152-
do ##class(Utils).GitStatus(.files)
152+
do ##class(Utils).GitStatus(.files, 1)
153153
set output = ""
154154
set key = ""
155155

@@ -160,13 +160,17 @@ ClassMethod Uncommitted() As %SystemBase
160160
quit:key=""
161161
// Check that current user has files(key) uncommitted and only %Push if they do
162162
set filename = ##class(Utils).FullExternalName(key)
163-
set sc=##class(SourceControl.Git.Change).GetUncommitted(filename,.tAction,.tInternalName,.UncommittedUser,.tSource,.UncommittedLastUpdated)
164-
if $$$ISOK(sc) && ($data(tAction)&&(UncommittedUser=$username)) {
163+
if (($ISVALIDNUM(key)) && (files(key) '= "")){
165164
do array.%Push($listget(fileData,2))
166165
}
166+
else{
167+
set sc=##class(SourceControl.Git.Change).GetUncommitted(filename,.tAction,.tInternalName,.UncommittedUser,.tSource,.UncommittedLastUpdated)
168+
if ($$$ISOK(sc)) && ($data(tAction)&&(UncommittedUser=$username)) {
169+
do array.%Push($listget(fileData,2))
170+
}
171+
}
167172
}
168173
quit array
169174
}
170175

171176
}
172-

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,15 @@ body {
4646
margin: 0;
4747
font: 10pt sans-serif;
4848
}
49-
#confirm-branch-delete p {
49+
#confirm-branch-delete,
50+
#confirm-staging p {
5051
font-size: 105%;
5152
}
5253
#confirm-delete,
5354
#cancel-delete,
54-
#confirm-force-delete {
55+
#confirm-force-delete,
56+
#confirm-staging,
57+
#cancel-staging {
5558
margin-left: 1rem;
5659
margin-top: 0.5rem;
5760
}
@@ -107,6 +110,16 @@ body {
107110
#error-modal .modal-body {
108111
margin-bottom: 0;
109112
}
113+
#confirm-unavailable-staging .form-check {
114+
padding-left: 18%;
115+
}
116+
#confirm-unavailable-staging .form-check-input {
117+
margin-top: 0;
118+
}
119+
#confirm-unavailable-staging .form-check-input:first-of-type,
120+
#confirm-unavailable-staging .form-check-label:first-of-type {
121+
margin-top: 3%;
122+
}
110123
#help-modal img {
111124
display: block;
112125
margin: 0 auto;
@@ -669,6 +682,16 @@ body {
669682
white-space: nowrap;
670683
border-radius: 0;
671684
}
685+
#workspace-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
686+
#commit-explorer-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
687+
#workspace-view #commit-explorer-navigator-view #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
688+
#commit-explorer-view #commit-explorer-navigator-view #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
689+
#workspace-view #workspace-editor #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
690+
#commit-explorer-view #workspace-editor #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
691+
#workspace-view #commit-explorer-navigator-view #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
692+
#commit-explorer-view #commit-explorer-navigator-view #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill {
693+
margin-right: 3%;
694+
}
672695
#workspace-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item.available,
673696
#commit-explorer-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item.available,
674697
#workspace-view #commit-explorer-navigator-view #working-copy-view .file-list-container .list-group .list-group-item.available,

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

Lines changed: 132 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,10 +1574,20 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
15741574
} else {
15751575
model = line;
15761576
}
1577-
var isForCurrentUser = true; //(uncommittedItems.indexOf(model) > -1);
1577+
var isForCurrentUser = (uncommittedItems.indexOf(model) > -1);
15781578
var cssClass = isForCurrentUser ? 'list-group-item available' : 'list-group-item unavailable';
15791579

1580-
var item = $('<a class="'+cssClass+'">').appendTo(fileList)[0];
1580+
if(isForCurrentUser){
1581+
var item = $('<a class="'+cssClass+'">').prependTo(fileList)[0];
1582+
}
1583+
else{
1584+
var item = $('<a class="'+cssClass+'">'+
1585+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-people-fill" viewBox="0 0 16 16">'+
1586+
'<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1H7zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>'+
1587+
'<path fill-rule="evenodd" d="M5.216 14A2.238 2.238 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.325 6.325 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1h4.216z"/>'+
1588+
'<path d="M4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/>'+
1589+
'</svg>').appendTo(fileList)[0];
1590+
}
15811591
item.model = model;
15821592
item.status = status;
15831593
item.appendChild(document.createTextNode(line));
@@ -1652,42 +1662,143 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
16521662
}
16531663
};
16541664

1655-
self.getFileList = function(including, excluding) {
1656-
var files = "";
1665+
function confirmActionForUnavailableFile(files, action) {
1666+
function removeUnavailableModal(popup) {
1667+
$(popup).children( ".modal-fade").modal('hide');
1668+
$(".modal-backdrop").remove();
1669+
$("#confirm-unavailable-staging").remove();
1670+
}
1671+
1672+
var popup = $( '<div class="modal fade" id="confirm-unavailable-staging" role="dialog">' +
1673+
'<div class="modal-dialog modal-md">' +
1674+
'<div class="modal-content">' +
1675+
'<div class="modal-header">' +
1676+
'<h5 class="modal-title">Confirm Staging</h5>' +
1677+
'<button type="button" class="btn btn-default close" data-dismiss="modal">'+
1678+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">'+
1679+
'<path fill-rule="evenodd" clip-rule="evenodd" d="M13.854 2.146a.5.5 0 0 1 0 .708l-11 11a.5.5 0 0 1-.708-.708l11-11a.5.5 0 0 1 .708 0Z" fill="#000"/>'+
1680+
'<path fill-rule="evenodd" clip-rule="evenodd" d="M2.146 2.146a.5.5 0 0 0 0 .708l11 11a.5.5 0 0 0 .708-.708l-11-11a.5.5 0 0 0-.708 0Z" fill="#000"/>'+
1681+
'</svg>'+
1682+
'</button>' +
1683+
'</div>' +
1684+
'<div class="modal-body"></div>' +
1685+
'</div>' +
1686+
'</div>' +
1687+
'</div>')[0];
1688+
$("body").append(popup);
1689+
var popupContent = $(".modal-body", popup)[0];
1690+
removeAllChildNodes(popupContent);
1691+
$('<div class="row"><div class="col-sm-1">'+
1692+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#dc3545" class="bi bi-exclamation-circle-fill" viewBox="0 0 16 16">'+
1693+
'<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"></path>'+
1694+
'</svg></div>'+
1695+
'<div class="col-sm-11">The following files were changed by other users. Are you sure you want to ' + action + ' them?</div></div>').appendTo(popupContent);
1696+
1697+
files.forEach(function(file, index, array){
1698+
$('<div class="form-check">'+
1699+
'<input class="form-check-input" type="checkbox" value="'+ file.model+'" id="file'+index+'" checked>'+
1700+
'<label class="form-check-label" for="file'+index+'">'+file.model+
1701+
'</label>'+
1702+
'</div>').appendTo(popupContent);
1703+
});
1704+
1705+
1706+
$('<button class="btn btn-sm btn-danger float-right" id="confirm-staging">' + action.charAt(0).toUpperCase()+action.substr(1)+'</button>'+
1707+
'<button class="btn btn-sm btn-secondary float-right" id="cancel-staging">Cancel</button>').appendTo(popupContent);
1708+
$(popup).modal('show');
1709+
1710+
$("#confirm-unavailable-staging").on('click', '#confirm-staging', function(e){
1711+
var checkedFiles = $("#confirm-unavailable-staging input[type=checkbox]:checked" );
1712+
for (var i = 0; i < fileList.childElementCount; ++i) {
1713+
var newChild = fileList.children[i];
1714+
for (var j = 0 ; j < checkedFiles.length; j++) {
1715+
if(newChild.model == $(checkedFiles[j]).val()){
1716+
$(newChild).addClass("available");
1717+
$(newChild).addClass("active");
1718+
$(newChild).removeClass("unavailable");
1719+
}
1720+
}
1721+
}
1722+
removeUnavailableModal(popup);
1723+
if(action == 'discard'){
1724+
self.cancel()
1725+
}
1726+
else{
1727+
self.process();
1728+
}
1729+
});
1730+
1731+
$("#confirm-unavailable-staging").find("#cancel-staging, .close").click(function() {
1732+
removeUnavailableModal(popup);
1733+
});
1734+
}
1735+
1736+
self.getFileList = function(including, excluding, onlyUnavailable=0, stringifyFilenames = 1) {
1737+
if(stringifyFilenames)
1738+
var files = "";
1739+
else
1740+
var files = [];
1741+
16571742
for (var i = 0; i < fileList.childElementCount; ++i) {
16581743
var child = fileList.children[i];
16591744
var included = including == undefined || including.indexOf(child.status) != -1;
16601745
var excluded = excluding != undefined && excluding.indexOf(child.status) != -1;
1661-
if ($(child).hasClass("active") && $(child).hasClass("available") && included && !excluded) {
1662-
files += '"' + (child.model) + '" ';
1746+
if ($(child).hasClass("active") && ($(child).hasClass("available")^onlyUnavailable) && included && !excluded) {
1747+
if(stringifyFilenames)
1748+
files += '"' + (child.model) + '" ';
1749+
else
1750+
files.push(child);
16631751
}
16641752
}
16651753
return files;
16661754
}
16671755

16681756
self.process = function() {
1669-
prevScrollTop = fileListContainer.scrollTop;
1670-
var files = self.getFileList(undefined, "D");
1671-
var rmFiles = self.getFileList("D");
1757+
var action = type == "working-copy" ? "stage" : "unstage"
1758+
var files = self.getFileList(undefined, "D", 0);
1759+
var rmFiles = self.getFileList("D", undefined, 0);
1760+
16721761
if (files.length != 0) {
16731762
var cmd = type == "working-copy" ? "add" : "reset";
16741763
webui.git(cmd + " -- " + files, function(data) {
16751764
if (rmFiles.length != 0) {
16761765
webui.git("rm -- " + rmFiles, function(data) {
1677-
workspaceView.update(type == "working-copy" ? "stage" : "unstage");
1766+
workspaceView.update(action);
16781767
});
16791768
} else {
1680-
workspaceView.update(type == "working-copy" ? "stage" : "unstage");
1769+
workspaceView.update(action);
16811770
}
16821771
});
16831772
} else if (rmFiles.length != 0) {
16841773
var cmd = type == "working-copy" ? "rm" : "reset";
16851774
webui.git(cmd + " -- " + rmFiles, function(data) {
1686-
workspaceView.update(type == "working-copy" ? "stage" : "unstage");
1775+
workspaceView.update(action);
16871776
});
16881777
}
16891778
};
16901779

1780+
self.processByAvailability = function() {
1781+
prevScrollTop = fileListContainer.scrollTop;
1782+
self.process();
1783+
1784+
var action = type == "working-copy" ? "stage" : "unstage"
1785+
var files = self.getFileList(undefined, "D", 1, 0);
1786+
var rmFiles = self.getFileList("D", undefined, 1, 0);
1787+
var combinedFiles = files.concat(rmFiles);
1788+
1789+
if(combinedFiles.length>0)
1790+
confirmActionForUnavailableFile(combinedFiles, action);
1791+
}
1792+
1793+
self.cancelByAvailability = function() {
1794+
prevScrollTop = fileListContainer.scrollTop;
1795+
1796+
var action = "discard"
1797+
var files = self.getFileList(undefined, undefined, 1, 0);
1798+
if(files.length>0)
1799+
confirmActionForUnavailableFile(files, action);
1800+
}
1801+
16911802
self.cancel = function() {
16921803
prevScrollTop = fileListContainer.scrollTop;
16931804
var files = self.getFileList();
@@ -1712,9 +1823,9 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
17121823
'</div>' +
17131824
'</div>')[0];
17141825
if (type == "working-copy") {
1715-
var buttons = [{ name: "Stage", callback: self.process }, { name: "Cancel", callback: self.cancel }];
1826+
var buttons = [{ name: "Stage", callback: self.processByAvailability }, { name: "Cancel", callback: self.cancelByAvailability }];
17161827
} else {
1717-
var buttons = [{ name: "Unstage", callback: self.process }];
1828+
var buttons = [{ name: "Unstage", callback: self.processByAvailability }];
17181829
}
17191830
var btnGroup = $(".btn-group", self.element);
17201831
buttons.forEach(function (btnData) {
@@ -1893,14 +2004,15 @@ $(function () {
18932004
});
18942005
});
18952006

2007+
function removeDeleteModal(popup) {
2008+
$(popup).children( ".modal-fade").modal('hide');
2009+
$(".modal-backdrop").remove();
2010+
$("#confirm-branch-delete").remove();
2011+
}
2012+
18962013
$(document).on('click', '.btn-delete-branch', function(e) {
18972014
e.preventDefault();
18982015

1899-
function removeDeleteModal(popup) {
1900-
$(popup).children( ".modal-fade").modal('hide');
1901-
$(".modal-backdrop").remove();
1902-
$("#confirm-branch-delete").remove();
1903-
}
19042016
$("#confirm-branch-delete").remove(); //removes any remaining modals. If there are more than one modals, the ids are duplicated and event listeners won't work.
19052017
var refName = $(this).parent().parent().parent().siblings(
19062018
".card-header").children("button").html();
@@ -2049,4 +2161,4 @@ $(function () {
20492161
e.preventDefault();
20502162
location.reload()
20512163
});
2052-
});
2164+
});

0 commit comments

Comments
 (0)