Add support for creating lightweight tags from the web ui

Change-Id: I843edbf70acc5c5d5f01be78d5d9672e139fb389
This commit is contained in:
Paladox 2016-11-26 00:29:38 +00:00 committed by David Pursehouse
parent 5dc6f95268
commit 061573f135
7 changed files with 265 additions and 26 deletions

View File

@ -49,6 +49,10 @@ public interface GerritConstants extends Constants {
String branchCreationConfirmationMessage();
String tagCreationDialogTitle();
String tagCreationConfirmationMessage();
String branchDeletionDialogTitle();
String branchDeletionConfirmationMessage();

View File

@ -20,6 +20,9 @@ confirmationDialogCancel = Cancel
branchCreationDialogTitle = Branch Creation
branchCreationConfirmationMessage = The following branch was successfully created:
tagCreationDialogTitle = Tag Creation
tagCreationConfirmationMessage = The following tag was successfully created:
branchDeletionDialogTitle = Branch Deletion
branchDeletionConfirmationMessage = Do you really want to delete the following branches?

View File

@ -27,6 +27,8 @@ public interface AdminConstants extends Constants {
String defaultBranchName();
String defaultTagName();
String defaultRevisionSpec();
String buttonDeleteIncludedGroup();
@ -171,18 +173,22 @@ public interface AdminConstants extends Constants {
String columnBranchRevision();
String columnTagName();
String columnTagRevision();
String initialRevision();
String buttonAddBranch();
String buttonDeleteBranch();
String buttonAddTag();
String saveHeadButton();
String cancelHeadButton();
String columnTagName();
String groupItemHelp();
String groupListTitle();

View File

@ -1,6 +1,7 @@
defaultAccountName = Name or Email
defaultAccountGroupName = Group Name
defaultBranchName = Branch Name
defaultTagName = Tag Name
defaultRevisionSpec = Revision (Branch or SHA-1)
buttonDeleteIncludedGroup = Delete
@ -81,12 +82,14 @@ typeRemoved = Removed
columnBranchName = Branch Name
columnBranchRevision = Revision
columnTagName = Tag Name
columnTagRevision = Revision
initialRevision = Initial Revision
buttonAddBranch = Create Branch
buttonAddTag = Create Tag
buttonDeleteBranch = Delete
saveHeadButton = Save
cancelHeadButton = Cancel
columnTagName = Tag Name
groupItemHelp = group

View File

@ -16,32 +16,58 @@ package com.google.gerrit.client.admin;
import static com.google.gerrit.client.ui.Util.highlight;
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.access.AccessMap;
import com.google.gerrit.client.access.ProjectAccessInfo;
import com.google.gerrit.client.projects.ProjectApi;
import com.google.gerrit.client.projects.TagInfo;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.HintTextBox;
import com.google.gerrit.client.ui.Hyperlink;
import com.google.gerrit.client.ui.NavigationTable;
import com.google.gerrit.client.ui.PagingHyperlink;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
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.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
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.gwtexpui.globalkey.client.NpTextBox;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ProjectTagsScreen extends PaginatedProjectScreen {
private NpTextBox filterTxt;
private Query query;
private Hyperlink prev;
private Hyperlink next;
private TagsTable tagsTable;
private TagsTable tagTable;
private Button addTag;
private HintTextBox nameTxtBox;
private HintTextBox irevTxtBox;
private FlowPanel addPanel;
private NpTextBox filterTxt;
private Query query;
public ProjectTagsScreen(Project.NameKey toShow) {
super(toShow);
@ -52,31 +78,95 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
return PageLinks.toProjectTags(getProjectKey());
}
@Override
protected void onLoad() {
super.onLoad();
addPanel.setVisible(false);
AccessMap.get(
getProjectKey(),
new GerritCallback<ProjectAccessInfo>() {
@Override
public void onSuccess(ProjectAccessInfo result) {
addPanel.setVisible(result.canAddRefs());
}
});
query = new Query(match).start(start).run();
savedPanel = TAGS;
}
private void updateForm() {
addTag.setEnabled(true);
nameTxtBox.setEnabled(true);
irevTxtBox.setEnabled(true);
}
@Override
protected void onInitUI() {
super.onInitUI();
initPageHeader();
prev = PagingHyperlink.createPrev();
prev.setVisible(false);
next = PagingHyperlink.createNext();
next.setVisible(false);
tagsTable = new TagsTable();
addPanel = new FlowPanel();
Grid addGrid = new Grid(2, 2);
addGrid.setStyleName(Gerrit.RESOURCES.css().addBranch());
int texBoxLength = 50;
nameTxtBox = new HintTextBox();
nameTxtBox.setVisibleLength(texBoxLength);
nameTxtBox.setHintText(AdminConstants.I.defaultTagName());
nameTxtBox.addKeyPressHandler(
new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
doAddNewTag();
}
}
});
addGrid.setText(0, 0, AdminConstants.I.columnTagName() + ":");
addGrid.setWidget(0, 1, nameTxtBox);
irevTxtBox = new HintTextBox();
irevTxtBox.setVisibleLength(texBoxLength);
irevTxtBox.setHintText(AdminConstants.I.defaultRevisionSpec());
irevTxtBox.addKeyPressHandler(
new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
doAddNewTag();
}
}
});
addGrid.setText(1, 0, AdminConstants.I.initialRevision() + ":");
addGrid.setWidget(1, 1, irevTxtBox);
addTag = new Button(AdminConstants.I.buttonAddTag());
addTag.addClickHandler(
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
doAddNewTag();
}
});
addPanel.add(addGrid);
addPanel.add(addTag);
tagTable = new TagsTable();
HorizontalPanel buttons = new HorizontalPanel();
buttons.setStyleName(Gerrit.RESOURCES.css().branchTablePrevNextLinks());
buttons.add(prev);
buttons.add(next);
add(tagsTable);
add(tagTable);
add(buttons);
}
@Override
protected void onLoad() {
super.onLoad();
query = new Query(match).start(start).run();
savedPanel = TAGS;
add(addPanel);
}
private void initPageHeader() {
@ -95,8 +185,10 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
Query q = new Query(filterTxt.getValue());
if (match.equals(q.qMatch)) {
q.start(start);
} else if (query == null) {
q.run();
} else {
if (query == null) {
q.run();
}
query = q;
}
}
@ -105,16 +197,113 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
add(hp);
}
private void doAddNewTag() {
String tagName = nameTxtBox.getText().trim();
if (tagName.isEmpty()) {
nameTxtBox.setFocus(true);
return;
}
String rev = irevTxtBox.getText().trim();
if (rev.isEmpty()) {
irevTxtBox.setText("HEAD");
Scheduler.get()
.scheduleDeferred(
new ScheduledCommand() {
@Override
public void execute() {
irevTxtBox.selectAll();
irevTxtBox.setFocus(true);
}
});
return;
}
addTag.setEnabled(false);
ProjectApi.createTag(
getProjectKey(),
tagName,
rev,
new GerritCallback<TagInfo>() {
@Override
public void onSuccess(TagInfo tag) {
showAddedTag(tag);
nameTxtBox.setText("");
irevTxtBox.setText("");
query = new Query(match).start(start).run();
}
@Override
public void onFailure(Throwable caught) {
addTag.setEnabled(true);
selectAllAndFocus(nameTxtBox);
new ErrorDialog(caught.getMessage()).center();
}
});
}
void showAddedTag(TagInfo tag) {
SafeHtmlBuilder b = new SafeHtmlBuilder();
b.openElement("b");
b.append(Gerrit.C.tagCreationConfirmationMessage());
b.closeElement("b");
b.openElement("p");
b.append(tag.ref());
b.closeElement("p");
ConfirmationDialog confirmationDialog =
new ConfirmationDialog(
Gerrit.C.tagCreationDialogTitle(),
b.toSafeHtml(),
new ConfirmationCallback() {
@Override
public void onOk() {
//do nothing
}
});
confirmationDialog.center();
confirmationDialog.setCancelVisible(false);
}
private static void selectAllAndFocus(TextBox textBox) {
textBox.selectAll();
textBox.setFocus(true);
}
private class TagsTable extends NavigationTable<TagInfo> {
TagsTable() {
table.setWidth("");
table.setText(0, 1, AdminConstants.I.columnTagName());
table.setText(0, 2, AdminConstants.I.columnBranchRevision());
table.setText(0, 2, AdminConstants.I.columnTagName());
table.setText(0, 3, AdminConstants.I.columnTagRevision());
FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().dataHeader());
fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().iconHeader());
fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader());
fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader());
}
Set<String> getCheckedRefs() {
Set<String> refs = new HashSet<>();
for (int row = 1; row < table.getRowCount(); row++) {
TagInfo k = getRowItem(row);
if (k != null
&& table.getWidget(row, 1) instanceof CheckBox
&& ((CheckBox) table.getWidget(row, 1)).getValue()) {
refs.add(k.ref());
}
}
return refs;
}
void setChecked(Set<String> refs) {
for (int row = 1; row < table.getRowCount(); row++) {
TagInfo k = getRowItem(row);
if (k != null && refs.contains(k.ref()) && table.getWidget(row, 1) instanceof CheckBox) {
((CheckBox) table.getWidget(row, 1)).setValue(true);
}
}
}
void display(List<TagInfo> tags) {
@ -135,18 +324,22 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
}
void populate(int row, TagInfo k) {
table.setWidget(row, 1, new InlineHTML(highlight(k.getShortName(), match)));
table.setText(row, 1, "");
table.setWidget(row, 2, new InlineHTML(highlight(k.getShortName(), match)));
if (k.revision() != null) {
table.setText(row, 2, k.revision());
table.setText(row, 3, k.revision());
} else {
table.setText(row, 2, "");
table.setText(row, 3, "");
}
FlexCellFormatter fmt = table.getFlexCellFormatter();
String iconCellStyle = Gerrit.RESOURCES.css().iconCell();
String dataCellStyle = Gerrit.RESOURCES.css().dataCell();
fmt.addStyleName(row, 1, dataCellStyle);
fmt.addStyleName(row, 1, iconCellStyle);
fmt.addStyleName(row, 2, dataCellStyle);
fmt.addStyleName(row, 3, dataCellStyle);
setRowItem(row, k);
}
@ -216,10 +409,10 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
ProjectTagsScreen.this.start = qStart;
if (result.length() <= pageSize) {
tagsTable.display(Natives.asList(result));
tagTable.display(Natives.asList(result));
next.setVisible(false);
} else {
tagsTable.displaySubset(Natives.asList(result), 0, result.length() - 1);
tagTable.displaySubset(Natives.asList(result), 0, result.length() - 1);
setupNavigationLink(next, qMatch, qStart + pageSize);
}
if (qStart > 0) {
@ -228,6 +421,10 @@ public class ProjectTagsScreen extends PaginatedProjectScreen {
prev.setVisible(false);
}
Set<String> checkedRefs = tagTable.getCheckedRefs();
tagTable.setChecked(checkedRefs);
updateForm();
if (!isCurrentView()) {
display();
}

View File

@ -60,6 +60,14 @@ public class ProjectApi {
return call;
}
/** Create a new tag */
public static void createTag(
Project.NameKey name, String ref, String revision, AsyncCallback<TagInfo> cb) {
TagInput input = TagInput.create();
input.setRevision(revision);
project(name).view("tags").id(ref).ifNoneMatch().put(input, cb);
}
/** Retrieve all visible tags of the project */
public static void getTags(Project.NameKey name, AsyncCallback<JsArray<TagInfo>> cb) {
project(name).view("tags").get(cb);
@ -325,6 +333,16 @@ public class ProjectApi {
public final native void put(String n, ConfigParameterValue v) /*-{ this[n] = v; }-*/;
}
private static class TagInput extends JavaScriptObject {
static TagInput create() {
return (TagInput) createObject();
}
protected TagInput() {}
final native void setRevision(String r) /*-{ if(r)this.revision=r; }-*/;
}
private static class BranchInput extends JavaScriptObject {
static BranchInput create() {
return (BranchInput) createObject();

View File

@ -14,7 +14,15 @@
package com.google.gerrit.client.projects;
import com.google.gerrit.client.info.ActionInfo;
import com.google.gerrit.client.info.WebLinkInfo;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gwt.core.client.JsArray;
public class TagInfo extends RefInfo {
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions }-*/;
public final native JsArray<WebLinkInfo> webLinks() /*-{ return this.web_links; }-*/;
// TODO(dpursehouse) add extra tag-related fields (message, tagger, etc)
protected TagInfo() {}