diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java index a850a9b1fc..b44cd1c59d 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java @@ -57,6 +57,10 @@ public interface GerritConstants extends Constants { String branchDeletionConfirmationMessage(); + String tagDeletionDialogTitle(); + + String tagDeletionConfirmationMessage(); + String newUi(); String notSignedInTitle(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties index cab988b558..9aa438886f 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties @@ -26,6 +26,9 @@ tagCreationConfirmationMessage = The following tag was successfully created: branchDeletionDialogTitle = Branch Deletion branchDeletionConfirmationMessage = Do you really want to delete the following branches? +tagDeletionDialogTitle = Tag Deletion +tagDeletionConfirmationMessage = Do you really want to delete the following tags? + newUi = New UI notSignedInTitle = Code Review - Session Expired diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java index d4b575fb33..d7fb0726e0 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java @@ -185,6 +185,8 @@ public interface AdminConstants extends Constants { String buttonAddTag(); + String buttonDeleteTag(); + String saveHeadButton(); String cancelHeadButton(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties index 404d90373e..465bcfc054 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties @@ -88,6 +88,7 @@ initialRevision = Initial Revision buttonAddBranch = Create Branch buttonAddTag = Create Tag buttonDeleteBranch = Delete +buttonDeleteTag = Delete saveHeadButton = Save cancelHeadButton = Cancel diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectTagsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectTagsScreen.java index de40a5d3bb..b89139c21f 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectTagsScreen.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectTagsScreen.java @@ -20,6 +20,7 @@ import com.google.gerrit.client.ConfirmationCallback; import com.google.gerrit.client.ConfirmationDialog; import com.google.gerrit.client.ErrorDialog; import com.google.gerrit.client.Gerrit; +import com.google.gerrit.client.VoidResult; import com.google.gerrit.client.access.AccessMap; import com.google.gerrit.client.access.ProjectAccessInfo; import com.google.gerrit.client.projects.ProjectApi; @@ -43,6 +44,8 @@ import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter; @@ -52,6 +55,7 @@ import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.InlineHTML; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; import com.google.gwtexpui.globalkey.client.NpTextBox; import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; import java.util.HashSet; @@ -62,6 +66,7 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { private Hyperlink prev; private Hyperlink next; private TagsTable tagTable; + private Button delTag; private Button addTag; private HintTextBox nameTxtBox; private HintTextBox irevTxtBox; @@ -95,6 +100,7 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { } private void updateForm() { + tagTable.updateDeleteButton(); addTag.setEnabled(true); nameTxtBox.setEnabled(true); irevTxtBox.setEnabled(true); @@ -160,8 +166,19 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { tagTable = new TagsTable(); + delTag = new Button(AdminConstants.I.buttonDeleteTag()); + delTag.setStyleName(Gerrit.RESOURCES.css().branchTableDeleteButton()); + delTag.addClickHandler( + new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + tagTable.deleteChecked(); + } + }); + HorizontalPanel buttons = new HorizontalPanel(); buttons.setStyleName(Gerrit.RESOURCES.css().branchTablePrevNextLinks()); + buttons.add(delTag); buttons.add(prev); buttons.add(next); add(tagTable); @@ -272,6 +289,8 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { } private class TagsTable extends NavigationTable { + private ValueChangeHandler updateDeleteHandler; + boolean canDelete; TagsTable() { table.setWidth(""); @@ -282,6 +301,14 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().iconHeader()); fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader()); fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader()); + + updateDeleteHandler = + new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + updateDeleteButton(); + } + }; } Set getCheckedRefs() { @@ -306,11 +333,74 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { } } + void deleteChecked() { + final Set refs = getCheckedRefs(); + + SafeHtmlBuilder b = new SafeHtmlBuilder(); + b.openElement("b"); + b.append(Gerrit.C.tagDeletionConfirmationMessage()); + b.closeElement("b"); + + b.openElement("p"); + boolean first = true; + for (String ref : refs) { + if (!first) { + b.append(",").br(); + } + b.append(ref); + first = false; + } + b.closeElement("p"); + + if (refs.isEmpty()) { + updateDeleteButton(); + return; + } + + delTag.setEnabled(false); + ConfirmationDialog confirmationDialog = + new ConfirmationDialog( + Gerrit.C.tagDeletionDialogTitle(), + b.toSafeHtml(), + new ConfirmationCallback() { + @Override + public void onOk() { + deleteTags(refs); + } + + @Override + public void onCancel() { + tagTable.updateDeleteButton(); + } + }); + confirmationDialog.center(); + } + + private void deleteTags(final Set tags) { + ProjectApi.deleteTags( + getProjectKey(), + tags, + new GerritCallback() { + @Override + public void onSuccess(VoidResult result) { + query = new Query(match).start(start).run(); + } + + @Override + public void onFailure(Throwable caught) { + query = new Query(match).start(start).run(); + super.onFailure(caught); + } + }); + } + void display(List tags) { displaySubset(tags, 0, tags.size()); } void displaySubset(List tags, int fromIndex, int toIndex) { + canDelete = false; + while (1 < table.getRowCount()) { table.removeRow(table.getRowCount() - 1); } @@ -324,7 +414,14 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { } void populate(int row, TagInfo k) { - table.setText(row, 1, ""); + if (k.canDelete()) { + CheckBox sel = new CheckBox(); + sel.addValueChangeHandler(updateDeleteHandler); + table.setWidget(row, 1, sel); + canDelete = true; + } else { + table.setText(row, 1, ""); + } table.setWidget(row, 2, new InlineHTML(highlight(k.getShortName(), match))); @@ -344,6 +441,25 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { setRowItem(row, k); } + boolean hasTagCanDelete() { + return canDelete; + } + + void updateDeleteButton() { + boolean on = false; + for (int row = 1; row < table.getRowCount(); row++) { + Widget w = table.getWidget(row, 1); + if (w != null && w instanceof CheckBox) { + CheckBox sel = (CheckBox) w; + if (sel.getValue()) { + on = true; + break; + } + } + } + delTag.setEnabled(on); + } + @Override protected void onOpenRow(int row) { if (row > 0) { @@ -421,6 +537,7 @@ public class ProjectTagsScreen extends PaginatedProjectScreen { prev.setVisible(false); } + delTag.setVisible(tagTable.hasTagCanDelete()); Set checkedRefs = tagTable.getCheckedRefs(); tagTable.setChecked(checkedRefs); updateForm(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java index 1350e1a67c..4be877ea71 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java @@ -82,6 +82,20 @@ public class ProjectApi { getRestApi(name, "tags", limit, start, match).get(cb); } + /** Delete tags. One call is fired to the server to delete all the tags. */ + public static void deleteTags( + Project.NameKey name, Set refs, AsyncCallback cb) { + if (refs.size() == 1) { + project(name).view("tags").id(refs.iterator().next()).delete(cb); + } else { + DeleteTagsInput d = DeleteTagsInput.create(); + for (String ref : refs) { + d.addTag(ref); + } + project(name).view("tags:delete").post(d, cb); + } + } + /** Create a new branch */ public static void createBranch( Project.NameKey name, String ref, String revision, AsyncCallback cb) { @@ -373,6 +387,20 @@ public class ProjectApi { final native void setRef(String r) /*-{ if(r)this.ref=r; }-*/; } + private static class DeleteTagsInput extends JavaScriptObject { + static DeleteTagsInput create() { + DeleteTagsInput d = createObject().cast(); + d.init(); + return d; + } + + protected DeleteTagsInput() {} + + final native void init() /*-{ this.tags = []; }-*/; + + final native void addTag(String b) /*-{ this.tags.push(b); }-*/; + } + private static class DeleteBranchesInput extends JavaScriptObject { static DeleteBranchesInput create() { DeleteBranchesInput d = createObject().cast(); diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/TagInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/TagInfo.java index bccac9b9c5..24487aef8b 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/TagInfo.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/TagInfo.java @@ -15,6 +15,8 @@ package com.google.gerrit.client.projects; public class TagInfo extends RefInfo { + public final native boolean canDelete() /*-{ return this['can_delete'] ? true : false; }-*/; + // TODO(dpursehouse) add extra tag-related fields (message, tagger, etc) protected TagInfo() {} }