Allow RestApiView<RevisionResource> to add buttons on patch sets
RestApiViews that accept a RevisionResource may now also describe buttons that should appear on a patch set. Description is given to Gerrit by implementing the UiCommand interface and returning useful information from the getter methods. Change-Id: I2b9445e73448968f1e3234812cc28b57e9ec7250
This commit is contained in:
parent
878b5a5544
commit
b313bfe17f
@ -19,6 +19,7 @@ import com.google.gerrit.reviewdb.client.PatchSet;
|
|||||||
import com.google.gerrit.reviewdb.client.PatchSetInfo;
|
import com.google.gerrit.reviewdb.client.PatchSetInfo;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PatchSetDetail {
|
public class PatchSetDetail {
|
||||||
@ -26,6 +27,7 @@ public class PatchSetDetail {
|
|||||||
protected PatchSetInfo info;
|
protected PatchSetInfo info;
|
||||||
protected List<Patch> patches;
|
protected List<Patch> patches;
|
||||||
protected Project.NameKey project;
|
protected Project.NameKey project;
|
||||||
|
protected List<UiCommandDetail> commands;
|
||||||
|
|
||||||
public PatchSetDetail() {
|
public PatchSetDetail() {
|
||||||
}
|
}
|
||||||
@ -61,4 +63,15 @@ public class PatchSetDetail {
|
|||||||
public void setProject(final Project.NameKey p) {
|
public void setProject(final Project.NameKey p) {
|
||||||
project = p;
|
project = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<UiCommandDetail> getCommands() {
|
||||||
|
if (commands != null) {
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommands(List<UiCommandDetail> cmds) {
|
||||||
|
commands = cmds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (C) 2013 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.common.data;
|
||||||
|
|
||||||
|
/** Detail necessary to display an action. */
|
||||||
|
public class UiCommandDetail {
|
||||||
|
public String id;
|
||||||
|
public String method;
|
||||||
|
public String label;
|
||||||
|
public String title;
|
||||||
|
public boolean enabled;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) 2013 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.extensions.webui;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.restapi.RestResource;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
|
|
||||||
|
public interface UiCommand<R extends RestResource> extends RestView<R> {
|
||||||
|
public static enum Place {
|
||||||
|
PATCHSET_ACTION_PANEL;
|
||||||
|
};
|
||||||
|
|
||||||
|
Place getPlace();
|
||||||
|
String getLabel(R resource);
|
||||||
|
String getTitle(R resource);
|
||||||
|
boolean isVisible(R resource);
|
||||||
|
boolean isEnabled(R resource);
|
||||||
|
}
|
@ -14,12 +14,15 @@
|
|||||||
|
|
||||||
package com.google.gerrit.client.changes;
|
package com.google.gerrit.client.changes;
|
||||||
import com.google.gerrit.client.Dispatcher;
|
import com.google.gerrit.client.Dispatcher;
|
||||||
|
import com.google.gerrit.client.ErrorDialog;
|
||||||
import com.google.gerrit.client.FormatUtil;
|
import com.google.gerrit.client.FormatUtil;
|
||||||
import com.google.gerrit.client.Gerrit;
|
import com.google.gerrit.client.Gerrit;
|
||||||
import com.google.gerrit.client.GitwebLink;
|
import com.google.gerrit.client.GitwebLink;
|
||||||
import com.google.gerrit.client.download.DownloadPanel;
|
import com.google.gerrit.client.download.DownloadPanel;
|
||||||
import com.google.gerrit.client.patches.PatchUtil;
|
import com.google.gerrit.client.patches.PatchUtil;
|
||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.rpc.NativeString;
|
||||||
|
import com.google.gerrit.client.rpc.RestApi;
|
||||||
import com.google.gerrit.client.ui.AccountLinkPanel;
|
import com.google.gerrit.client.ui.AccountLinkPanel;
|
||||||
import com.google.gerrit.client.ui.ActionDialog;
|
import com.google.gerrit.client.ui.ActionDialog;
|
||||||
import com.google.gerrit.client.ui.CherryPickDialog;
|
import com.google.gerrit.client.ui.CherryPickDialog;
|
||||||
@ -28,6 +31,7 @@ import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
|
|||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
import com.google.gerrit.common.data.ChangeDetail;
|
import com.google.gerrit.common.data.ChangeDetail;
|
||||||
import com.google.gerrit.common.data.PatchSetDetail;
|
import com.google.gerrit.common.data.PatchSetDetail;
|
||||||
|
import com.google.gerrit.common.data.UiCommandDetail;
|
||||||
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
||||||
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
|
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
|
||||||
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
|
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
|
||||||
@ -35,10 +39,13 @@ import com.google.gerrit.reviewdb.client.Change;
|
|||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSetInfo;
|
import com.google.gerrit.reviewdb.client.PatchSetInfo;
|
||||||
import com.google.gerrit.reviewdb.client.UserIdentity;
|
import com.google.gerrit.reviewdb.client.UserIdentity;
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
import com.google.gwt.event.dom.client.ClickEvent;
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
import com.google.gwt.event.dom.client.ClickHandler;
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||||
|
import com.google.gwt.user.client.Window;
|
||||||
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
import com.google.gwt.user.client.ui.Anchor;
|
import com.google.gwt.user.client.ui.Anchor;
|
||||||
import com.google.gwt.user.client.ui.Button;
|
import com.google.gwt.user.client.ui.Button;
|
||||||
import com.google.gwt.user.client.ui.DisclosurePanel;
|
import com.google.gwt.user.client.ui.DisclosurePanel;
|
||||||
@ -169,6 +176,7 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel
|
|||||||
if (changeDetail.isCurrentPatchSet(detail)) {
|
if (changeDetail.isCurrentPatchSet(detail)) {
|
||||||
populateActions(detail);
|
populateActions(detail);
|
||||||
}
|
}
|
||||||
|
populateCommands(detail);
|
||||||
}
|
}
|
||||||
if (detail.getPatchSet().isDraft()) {
|
if (detail.getPatchSet().isDraft()) {
|
||||||
if (changeDetail.canPublish()) {
|
if (changeDetail.canPublish()) {
|
||||||
@ -535,6 +543,45 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void populateCommands(final PatchSetDetail detail) {
|
||||||
|
for (final UiCommandDetail cmd : detail.getCommands()) {
|
||||||
|
final Button b = new Button(cmd.label);
|
||||||
|
b.setEnabled(cmd.enabled);
|
||||||
|
b.setTitle(cmd.title);
|
||||||
|
b.addClickHandler(new ClickHandler() {
|
||||||
|
@Override
|
||||||
|
public void onClick(final ClickEvent event) {
|
||||||
|
b.setEnabled(false);
|
||||||
|
AsyncCallback<NativeString> cb =
|
||||||
|
new AsyncCallback<NativeString>() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
b.setEnabled(true);
|
||||||
|
new ErrorDialog(caught).center();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(NativeString msg) {
|
||||||
|
b.setEnabled(true);
|
||||||
|
if (msg != null) {
|
||||||
|
Window.alert(msg.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
RestApi api = ChangeApi.revision(patchSet.getId()).view(cmd.id);
|
||||||
|
if ("PUT".equalsIgnoreCase(cmd.method)) {
|
||||||
|
api.put(JavaScriptObject.createObject(), cb);
|
||||||
|
} else if ("DELETE".equalsIgnoreCase(cmd.method)) {
|
||||||
|
api.delete(cb);
|
||||||
|
} else {
|
||||||
|
api.post(JavaScriptObject.createObject(), cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
actionsPanel.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void populateReviewAction() {
|
private void populateReviewAction() {
|
||||||
final Button b = new Button(Util.C.buttonReview());
|
final Button b = new Button(Util.C.buttonReview());
|
||||||
b.addClickHandler(new ClickHandler() {
|
b.addClickHandler(new ClickHandler() {
|
||||||
|
@ -14,20 +14,28 @@
|
|||||||
|
|
||||||
package com.google.gerrit.httpd.rpc.changedetail;
|
package com.google.gerrit.httpd.rpc.changedetail;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gerrit.common.data.PatchSetDetail;
|
import com.google.gerrit.common.data.PatchSetDetail;
|
||||||
|
import com.google.gerrit.common.data.UiCommandDetail;
|
||||||
import com.google.gerrit.common.errors.NoSuchEntityException;
|
import com.google.gerrit.common.errors.NoSuchEntityException;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
|
import com.google.gerrit.extensions.webui.UiCommand;
|
||||||
import com.google.gerrit.httpd.rpc.Handler;
|
import com.google.gerrit.httpd.rpc.Handler;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
||||||
|
import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
|
||||||
import com.google.gerrit.reviewdb.client.AccountPatchReview;
|
import com.google.gerrit.reviewdb.client.AccountPatchReview;
|
||||||
import com.google.gerrit.reviewdb.client.Patch;
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
|
|
||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.change.ChangeResource;
|
||||||
|
import com.google.gerrit.server.change.RevisionResource;
|
||||||
|
import com.google.gerrit.server.change.Revisions;
|
||||||
import com.google.gerrit.server.patch.PatchList;
|
import com.google.gerrit.server.patch.PatchList;
|
||||||
import com.google.gerrit.server.patch.PatchListCache;
|
import com.google.gerrit.server.patch.PatchListCache;
|
||||||
import com.google.gerrit.server.patch.PatchListKey;
|
import com.google.gerrit.server.patch.PatchListKey;
|
||||||
@ -44,6 +52,8 @@ import org.eclipse.jgit.lib.ObjectId;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -67,6 +77,7 @@ class PatchSetDetailFactory extends Handler<PatchSetDetail> {
|
|||||||
private final ReviewDb db;
|
private final ReviewDb db;
|
||||||
private final PatchListCache patchListCache;
|
private final PatchListCache patchListCache;
|
||||||
private final ChangeControl.Factory changeControlFactory;
|
private final ChangeControl.Factory changeControlFactory;
|
||||||
|
private final Revisions revisions;
|
||||||
|
|
||||||
private Project.NameKey projectKey;
|
private Project.NameKey projectKey;
|
||||||
private final PatchSet.Id psIdBase;
|
private final PatchSet.Id psIdBase;
|
||||||
@ -83,6 +94,7 @@ class PatchSetDetailFactory extends Handler<PatchSetDetail> {
|
|||||||
PatchSetDetailFactory(final PatchSetInfoFactory psif, final ReviewDb db,
|
PatchSetDetailFactory(final PatchSetInfoFactory psif, final ReviewDb db,
|
||||||
final PatchListCache patchListCache,
|
final PatchListCache patchListCache,
|
||||||
final ChangeControl.Factory changeControlFactory,
|
final ChangeControl.Factory changeControlFactory,
|
||||||
|
final Revisions revisions,
|
||||||
@Assisted("psIdBase") @Nullable final PatchSet.Id psIdBase,
|
@Assisted("psIdBase") @Nullable final PatchSet.Id psIdBase,
|
||||||
@Assisted("psIdNew") final PatchSet.Id psIdNew,
|
@Assisted("psIdNew") final PatchSet.Id psIdNew,
|
||||||
@Assisted @Nullable final AccountDiffPreference diffPrefs) {
|
@Assisted @Nullable final AccountDiffPreference diffPrefs) {
|
||||||
@ -90,6 +102,7 @@ class PatchSetDetailFactory extends Handler<PatchSetDetail> {
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
this.patchListCache = patchListCache;
|
this.patchListCache = patchListCache;
|
||||||
this.changeControlFactory = changeControlFactory;
|
this.changeControlFactory = changeControlFactory;
|
||||||
|
this.revisions = revisions;
|
||||||
|
|
||||||
this.psIdBase = psIdBase;
|
this.psIdBase = psIdBase;
|
||||||
this.psIdNew = psIdNew;
|
this.psIdNew = psIdNew;
|
||||||
@ -164,9 +177,57 @@ class PatchSetDetailFactory extends Handler<PatchSetDetail> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RevisionResource rev =
|
||||||
|
new RevisionResource(new ChangeResource(control), patchSet);
|
||||||
|
detail.setCommands(buildCommands(rev));
|
||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<UiCommandDetail> buildCommands(RevisionResource rev) {
|
||||||
|
List<UiCommandDetail> all = Lists.newArrayList();
|
||||||
|
for (DynamicMap.Entry<RestView<RevisionResource>> e : revisions.views()) {
|
||||||
|
int d = e.getExportName().indexOf('.');
|
||||||
|
if (d < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String method = e.getExportName().substring(0, d);
|
||||||
|
String name = e.getExportName().substring(d + 1);
|
||||||
|
RestView<RevisionResource> view;
|
||||||
|
try {
|
||||||
|
view = e.getProvider().get();
|
||||||
|
} catch (RuntimeException err) {
|
||||||
|
log.error(String.format(
|
||||||
|
"error in view %s.%s",
|
||||||
|
e.getPluginName(), e.getExportName()), err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(view instanceof UiCommand)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UiCommand<RevisionResource> cmd = (UiCommand<RevisionResource>) view;
|
||||||
|
if (cmd.getPlace() != UiCommand.Place.PATCHSET_ACTION_PANEL
|
||||||
|
|| !cmd.isVisible(rev)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UiCommandDetail dsc = new UiCommandDetail();
|
||||||
|
dsc.id = e.getPluginName() + '~' + name;
|
||||||
|
dsc.method = method;
|
||||||
|
dsc.label = cmd.getLabel(rev);
|
||||||
|
dsc.title = cmd.getTitle(rev);
|
||||||
|
dsc.enabled = cmd.isEnabled(rev);
|
||||||
|
all.add(dsc);
|
||||||
|
}
|
||||||
|
Collections.sort(all, new Comparator<UiCommandDetail>() {
|
||||||
|
@Override
|
||||||
|
public int compare(UiCommandDetail a, UiCommandDetail b) {
|
||||||
|
return a.id.compareTo(b.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return all.isEmpty() ? null : all;
|
||||||
|
}
|
||||||
|
|
||||||
private ObjectId toObjectId(final PatchSet.Id psId) throws OrmException,
|
private ObjectId toObjectId(final PatchSet.Id psId) throws OrmException,
|
||||||
NoSuchEntityException {
|
NoSuchEntityException {
|
||||||
final PatchSet ps = db.patchSets().get(psId);
|
final PatchSet ps = db.patchSets().get(psId);
|
||||||
|
Loading…
Reference in New Issue
Block a user