Skip to content

Queue filter #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9e1edfb
committing to see deleted file
isc-svelury Nov 8, 2021
eaf7f11
staged deleted file
isc-svelury Nov 8, 2021
561806b
Staging another file to delete later
isc-svelury Nov 8, 2021
b3f7105
Staging class file to see how delete works
isc-svelury Nov 8, 2021
45d1c0f
Merge branch 'main' into queue-filter
isc-svelury Nov 12, 2021
f398c63
clean up
isc-svelury Nov 12, 2021
04d9624
Commit to test delete in Uncommitted queue
isc-svelury Nov 12, 2021
213e9c0
minor refactoring
isc-svelury Nov 15, 2021
00339b5
delete class file made for testing
isc-svelury Nov 15, 2021
242f384
Add code to remove file from Uncommitted queue after commit.
isc-svelury Nov 15, 2021
c71ec39
Remove unneeded file
isc-svelury Nov 15, 2021
f77014d
Uncommitted queue now saves deleted files
isc-svelury Nov 16, 2021
49da591
Commit changes with logging statements for testing
isc-svelury Nov 16, 2021
0fad94d
Merge branch 'main' into queue-filter
isc-svelury Nov 16, 2021
7c6d9cb
Merge branch 'main' into queue-filter
isc-svelury Nov 16, 2021
35db6fa
comitting temp file
isc-svelury Nov 18, 2021
c043cc6
deleting temp file
isc-svelury Nov 18, 2021
b0340dc
Add temp file again
isc-svelury Nov 18, 2021
7d6fb96
commit delete of temp file
isc-svelury Nov 18, 2021
291ff21
Add temp file again
isc-svelury Nov 18, 2021
2050600
delete temp file
isc-svelury Nov 18, 2021
7df90e4
Remove logging; SQL code to check for deleted file in Uncommitted que…
isc-svelury Nov 18, 2021
f3ccdb8
Merging with main
isc-svelury Nov 18, 2021
298ca5c
actually saving the merge conflict resolution this time
isc-svelury Nov 18, 2021
b723293
The WebUIDriver now properly filters files that you can and can't com…
isc-svelury Nov 18, 2021
290c470
Remove logging
isc-svelury Nov 22, 2021
69b8c79
Popup now works properly
isc-svelury Nov 29, 2021
1cc7e8e
Fixed typo in method name (confirmActionForUnavailableFile)
isc-svelury Nov 30, 2021
0ec72a2
Delete testfile.md
isc-svelury Nov 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cls/SourceControl/Git/Change.cls
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ ClassMethod RemoveUncommitted(FileList, Display = 1, Revert = 0, ActiveCommit =
quit SCs
}

/// This method records a deleted file in the uncommitted queue
ClassMethod AddDeletedToUncommitted(Filename, InternalName) As %Status
{

Quit ..SetUncommitted(Filename, "delete", InternalName, $USERNAME, "", 1, "", "", 0)
}

ClassMethod IsUncommitted(Filename, ByRef ID) As %Boolean
{
&SQL(SELECT ID INTO :ID FROM SourceControl_Git.Change WHERE ItemFile = :Filename AND Committed = '0')
Expand Down
12 changes: 12 additions & 0 deletions cls/SourceControl/Git/Extension.cls
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,18 @@ Method IsInSourceControl(InternalName As %String) As %Boolean [ CodeMode = expre
InternalName'="" && ##class(Utils).IsInSourceControl(##class(Utils).NormalizeInternalName(InternalName))
}

/// Called before an item is deleted.
Method OnBeforeDelete(InternalName As %String) As %Status
{
set context = ##class(SourceControl.Git.PackageManagerContext).ForInternalName(InternalName)
set InternalName = ##class(Utils).NormalizeInternalName(InternalName)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: full classnames are preferred (though other code in the same neighborhood might not be great about that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This happens in multiple places all throughout the project. It might be better to create a separate PR for finding and refactoring all these instances.

set Filename = ##class(Utils).FullExternalName(InternalName)
if ##class(Utils).IsInSourceControl(InternalName) {
quit ##class(Change).AddDeletedToUncommitted(Filename, InternalName)
}
quit $$$OK
}

/// Called after an item is deleted.
Method OnAfterDelete(InternalName As %String) As %Status
{
Expand Down
21 changes: 16 additions & 5 deletions cls/SourceControl/Git/Utils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ ClassMethod Commit(InternalName As %String, Message As %String = "example commit
do outStream.OutputToDevice()
write !
do errStream.OutputToDevice()
$$$QuitOnError(##class(SourceControl.Git.Change).RemoveUncommitted(filename))
$$$QuitOnError(##class(SourceControl.Git.Change).RefreshUncommitted())
quit $$$OK
}

Expand Down Expand Up @@ -1161,7 +1163,7 @@ ClassMethod RunGitCommandWithInput(command As %String, inFile As %String = "", O
quit returnCode
}

ClassMethod GitStatus(ByRef files)
ClassMethod GitStatus(ByRef files, IncludeAllFiles = 0)
{
do ..RunGitCommand("status", .errStream, .outStream, "-z", "-uall")
set lines = outStream.ReadLine()
Expand All @@ -1170,12 +1172,13 @@ ClassMethod GitStatus(ByRef files)
while $listnext(list, pointer, item) {
set operation = $extract(item, 1, 2)
set externalName = $extract(item, 4, *)
///w externalName_" "
set internalName = ..NameToInternalName(externalName)
///write internalName, !
if (internalName '= "") {
set files(internalName) = $listbuild(operation, externalName)
}
} elseif IncludeAllFiles {
set externalName = $TRANSLATE(externalName, "\", "/")
set files($I(files)) = $listbuild(operation, externalName)
}
}
}

Expand Down Expand Up @@ -1261,6 +1264,7 @@ ClassMethod Name(InternalName As %String) As %String
ClassMethod NameToInternalName(Name, IgnorePercent = 1, IgnoreNonexistent = 1) As %String
{
set InternalName=""
set Deleted = 0
if ($zconvert(Name,"U")'[$zconvert($$$SourceRoot,"U")) {
set Name = ##class(%File).NormalizeFilename(..TempFolder()_Name)
}
Expand All @@ -1271,6 +1275,13 @@ ClassMethod NameToInternalName(Name, IgnorePercent = 1, IgnoreNonexistent = 1) A
//only set if a single Name was returned ... ignore multi-item files
set InternalName=outName
}
} else {
// check for file in uncommitted queue
&sql(SELECT internalName into :InternalName FROM SourceControl_Git.Change where ItemFile = :Name)
if (SQLCODE = 100) {
set InternalName = ""
}
set Deleted = 1
}
if (InternalName="") {
if ($zconvert(Name,"U")'[$zconvert($$$SourceRoot,"U")) {
Expand Down Expand Up @@ -1345,7 +1356,7 @@ ClassMethod NameToInternalName(Name, IgnorePercent = 1, IgnoreNonexistent = 1) A
}
}
if ((IgnorePercent)&&($extract(InternalName)="%")) { set InternalName = "" } // don't return a result for % items if instructed to ignore them
if ((IgnoreNonexistent)&&('##class(%RoutineMgr).Exists(InternalName))) { set InternalName = "" } // only return item names which exist in the DB
if ((IgnoreNonexistent)&&('##class(%RoutineMgr).Exists(InternalName))&&('Deleted)) { set InternalName = "" } // only return item names which exist in the DB
quit ..NormalizeInternalName(InternalName)
}

Expand Down
12 changes: 8 additions & 4 deletions cls/SourceControl/Git/WebUIDriver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ ClassMethod UserInfo() As %SystemBase
ClassMethod Uncommitted() As %SystemBase
{
// Stub
do ##class(Utils).GitStatus(.files)
do ##class(Utils).GitStatus(.files, 1)
set output = ""
set key = ""

Expand All @@ -160,13 +160,17 @@ ClassMethod Uncommitted() As %SystemBase
quit:key=""
// Check that current user has files(key) uncommitted and only %Push if they do
set filename = ##class(Utils).FullExternalName(key)
set sc=##class(SourceControl.Git.Change).GetUncommitted(filename,.tAction,.tInternalName,.UncommittedUser,.tSource,.UncommittedLastUpdated)
if $$$ISOK(sc) && ($data(tAction)&&(UncommittedUser=$username)) {
if (($ISVALIDNUM(key)) && (files(key) '= "")){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to check ISVALIDNUM?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Utils.GitStatus(), if we want to include all files, then for the files that don't have an internal name but are still tracked by git, I use $increment to generate keys. For files that have internal names, the internal names are the keys and the filepath is the value associated with the key.

So in WebUIDriver.Uncommitted(), if the key is a number and the value is not empty, then it indicates that the file is tracked by Git but not by the Uncommitted queue. Therefore, any user should be able to take action on those changes.

do array.%Push($listget(fileData,2))
}
else{
set sc=##class(SourceControl.Git.Change).GetUncommitted(filename,.tAction,.tInternalName,.UncommittedUser,.tSource,.UncommittedLastUpdated)
if ($$$ISOK(sc)) && ($data(tAction)&&(UncommittedUser=$username)) {
do array.%Push($listget(fileData,2))
}
}
}
quit array
}

}

27 changes: 25 additions & 2 deletions git-webui/release/share/git-webui/webui/css/git-webui.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,15 @@ body {
margin: 0;
font: 10pt sans-serif;
}
#confirm-branch-delete p {
#confirm-branch-delete,
#confirm-staging p {
font-size: 105%;
}
#confirm-delete,
#cancel-delete,
#confirm-force-delete {
#confirm-force-delete,
#confirm-staging,
#cancel-staging {
margin-left: 1rem;
margin-top: 0.5rem;
}
Expand Down Expand Up @@ -107,6 +110,16 @@ body {
#error-modal .modal-body {
margin-bottom: 0;
}
#confirm-unavailable-staging .form-check {
padding-left: 18%;
}
#confirm-unavailable-staging .form-check-input {
margin-top: 0;
}
#confirm-unavailable-staging .form-check-input:first-of-type,
#confirm-unavailable-staging .form-check-label:first-of-type {
margin-top: 3%;
}
#help-modal img {
display: block;
margin: 0 auto;
Expand Down Expand Up @@ -669,6 +682,16 @@ body {
white-space: nowrap;
border-radius: 0;
}
#workspace-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#commit-explorer-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#workspace-view #commit-explorer-navigator-view #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#commit-explorer-view #commit-explorer-navigator-view #working-copy-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#workspace-view #workspace-editor #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#commit-explorer-view #workspace-editor #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#workspace-view #commit-explorer-navigator-view #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill,
#commit-explorer-view #commit-explorer-navigator-view #staging-area-view .file-list-container .list-group .list-group-item svg.bi-people-fill {
margin-right: 3%;
}
#workspace-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item.available,
#commit-explorer-view #workspace-editor #working-copy-view .file-list-container .list-group .list-group-item.available,
#workspace-view #commit-explorer-navigator-view #working-copy-view .file-list-container .list-group .list-group-item.available,
Expand Down
152 changes: 132 additions & 20 deletions git-webui/release/share/git-webui/webui/js/git-webui.js
Original file line number Diff line number Diff line change
Expand Up @@ -1574,10 +1574,20 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
} else {
model = line;
}
var isForCurrentUser = true; //(uncommittedItems.indexOf(model) > -1);
var isForCurrentUser = (uncommittedItems.indexOf(model) > -1);
var cssClass = isForCurrentUser ? 'list-group-item available' : 'list-group-item unavailable';

var item = $('<a class="'+cssClass+'">').appendTo(fileList)[0];
if(isForCurrentUser){
var item = $('<a class="'+cssClass+'">').prependTo(fileList)[0];
}
else{
var item = $('<a class="'+cssClass+'">'+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-people-fill" viewBox="0 0 16 16">'+
'<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"/>'+
'<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"/>'+
'<path d="M4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/>'+
'</svg>').appendTo(fileList)[0];
}
item.model = model;
item.status = status;
item.appendChild(document.createTextNode(line));
Expand Down Expand Up @@ -1652,42 +1662,143 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
}
};

self.getFileList = function(including, excluding) {
var files = "";
function confirmActionForUnavailableFile(files, action) {
function removeUnavailableModal(popup) {
$(popup).children( ".modal-fade").modal('hide');
$(".modal-backdrop").remove();
$("#confirm-unavailable-staging").remove();
}

var popup = $( '<div class="modal fade" id="confirm-unavailable-staging" role="dialog">' +
'<div class="modal-dialog modal-md">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h5 class="modal-title">Confirm Staging</h5>' +
'<button type="button" class="btn btn-default close" data-dismiss="modal">'+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">'+
'<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"/>'+
'<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"/>'+
'</svg>'+
'</button>' +
'</div>' +
'<div class="modal-body"></div>' +
'</div>' +
'</div>' +
'</div>')[0];
$("body").append(popup);
var popupContent = $(".modal-body", popup)[0];
removeAllChildNodes(popupContent);
$('<div class="row"><div class="col-sm-1">'+
'<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">'+
'<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>'+
'</svg></div>'+
'<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);

files.forEach(function(file, index, array){
$('<div class="form-check">'+
'<input class="form-check-input" type="checkbox" value="'+ file.model+'" id="file'+index+'" checked>'+
'<label class="form-check-label" for="file'+index+'">'+file.model+
'</label>'+
'</div>').appendTo(popupContent);
});


$('<button class="btn btn-sm btn-danger float-right" id="confirm-staging">' + action.charAt(0).toUpperCase()+action.substr(1)+'</button>'+
'<button class="btn btn-sm btn-secondary float-right" id="cancel-staging">Cancel</button>').appendTo(popupContent);
$(popup).modal('show');

$("#confirm-unavailable-staging").on('click', '#confirm-staging', function(e){
var checkedFiles = $("#confirm-unavailable-staging input[type=checkbox]:checked" );
for (var i = 0; i < fileList.childElementCount; ++i) {
var newChild = fileList.children[i];
for (var j = 0 ; j < checkedFiles.length; j++) {
if(newChild.model == $(checkedFiles[j]).val()){
$(newChild).addClass("available");
$(newChild).addClass("active");
$(newChild).removeClass("unavailable");
}
}
}
removeUnavailableModal(popup);
if(action == 'discard'){
self.cancel()
}
else{
self.process();
}
});

$("#confirm-unavailable-staging").find("#cancel-staging, .close").click(function() {
removeUnavailableModal(popup);
});
}

self.getFileList = function(including, excluding, onlyUnavailable=0, stringifyFilenames = 1) {
if(stringifyFilenames)
var files = "";
else
var files = [];

for (var i = 0; i < fileList.childElementCount; ++i) {
var child = fileList.children[i];
var included = including == undefined || including.indexOf(child.status) != -1;
var excluded = excluding != undefined && excluding.indexOf(child.status) != -1;
if ($(child).hasClass("active") && $(child).hasClass("available") && included && !excluded) {
files += '"' + (child.model) + '" ';
if ($(child).hasClass("active") && ($(child).hasClass("available")^onlyUnavailable) && included && !excluded) {
if(stringifyFilenames)
files += '"' + (child.model) + '" ';
else
files.push(child);
}
}
return files;
}

self.process = function() {
prevScrollTop = fileListContainer.scrollTop;
var files = self.getFileList(undefined, "D");
var rmFiles = self.getFileList("D");
var action = type == "working-copy" ? "stage" : "unstage"
var files = self.getFileList(undefined, "D", 0);
var rmFiles = self.getFileList("D", undefined, 0);

if (files.length != 0) {
var cmd = type == "working-copy" ? "add" : "reset";
webui.git(cmd + " -- " + files, function(data) {
if (rmFiles.length != 0) {
webui.git("rm -- " + rmFiles, function(data) {
workspaceView.update(type == "working-copy" ? "stage" : "unstage");
workspaceView.update(action);
});
} else {
workspaceView.update(type == "working-copy" ? "stage" : "unstage");
workspaceView.update(action);
}
});
} else if (rmFiles.length != 0) {
var cmd = type == "working-copy" ? "rm" : "reset";
webui.git(cmd + " -- " + rmFiles, function(data) {
workspaceView.update(type == "working-copy" ? "stage" : "unstage");
workspaceView.update(action);
});
}
};

self.processByAvailability = function() {
prevScrollTop = fileListContainer.scrollTop;
self.process();

var action = type == "working-copy" ? "stage" : "unstage"
var files = self.getFileList(undefined, "D", 1, 0);
var rmFiles = self.getFileList("D", undefined, 1, 0);
var combinedFiles = files.concat(rmFiles);

if(combinedFiles.length>0)
confirmActionForUnavailableFile(combinedFiles, action);
}

self.cancelByAvailability = function() {
prevScrollTop = fileListContainer.scrollTop;

var action = "discard"
var files = self.getFileList(undefined, undefined, 1, 0);
if(files.length>0)
confirmActionForUnavailableFile(files, action);
}

self.cancel = function() {
prevScrollTop = fileListContainer.scrollTop;
var files = self.getFileList();
Expand All @@ -1712,9 +1823,9 @@ webui.ChangedFilesView = function(workspaceView, type, label) {
'</div>' +
'</div>')[0];
if (type == "working-copy") {
var buttons = [{ name: "Stage", callback: self.process }, { name: "Cancel", callback: self.cancel }];
var buttons = [{ name: "Stage", callback: self.processByAvailability }, { name: "Cancel", callback: self.cancelByAvailability }];
} else {
var buttons = [{ name: "Unstage", callback: self.process }];
var buttons = [{ name: "Unstage", callback: self.processByAvailability }];
}
var btnGroup = $(".btn-group", self.element);
buttons.forEach(function (btnData) {
Expand Down Expand Up @@ -1893,14 +2004,15 @@ $(function () {
});
});

function removeDeleteModal(popup) {
$(popup).children( ".modal-fade").modal('hide');
$(".modal-backdrop").remove();
$("#confirm-branch-delete").remove();
}

$(document).on('click', '.btn-delete-branch', function(e) {
e.preventDefault();

function removeDeleteModal(popup) {
$(popup).children( ".modal-fade").modal('hide');
$(".modal-backdrop").remove();
$("#confirm-branch-delete").remove();
}
$("#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.
var refName = $(this).parent().parent().parent().siblings(
".card-header").children("button").html();
Expand Down Expand Up @@ -2049,4 +2161,4 @@ $(function () {
e.preventDefault();
location.reload()
});
});
});
Loading