Rewrite UI plugin action description API

Using methods on an interface that plugins/extensions implement
makes for a very brittle API. We cannot safely add a new method
without breaking all existing code or introducing another interface
for plugins to implement.

Change the UI action description to be a single method interface
that returns an instance of a concrete description object. Plugins
can populate the fields they know about and need for their use case,
and the server will do its best to honor what the plugin has given.
New methods can be added to the description without affecting the
API versioning, enabling Gerrit to add more features in the future.

The confirmation message feature has been removed. In the near
future plugins will have the ability to register JavaScript code
to be executed client-side when the button is activated and before
the RPC is started. This will allow plugins to perform more custom
logic, such as obtaining additional input.

Looking even further ahead plugins may register their own JS handler
to render a button, allowing the plugin to use a more complex widget.
The UiAction.Description type may need to be extended to allow
server side view code to pass custom data to the UI rendering logic.

Change-Id: If5e0e6b42d6d1e8a111a2d304ce54b9d8834688a
This commit is contained in:
Shawn Pearce
2013-07-15 12:20:40 -07:00
parent 3600951d0b
commit 3d57549a1d
17 changed files with 252 additions and 364 deletions

View File

@@ -20,7 +20,7 @@ import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.webui.UiCommand;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.client.ChangeMessage;
@@ -42,11 +42,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
public class Restore implements RestModifyView<ChangeResource, Input>,
UiCommand<ChangeResource> {
UiAction<ChangeResource> {
private static final Logger log = LoggerFactory.getLogger(Restore.class);
private final ChangeHooks hooks;
@@ -94,8 +92,8 @@ public class Restore implements RestModifyView<ChangeResource, Input>,
new AtomicUpdate<Change>() {
@Override
public Change update(Change change) {
if (change.getStatus() == Change.Status.ABANDONED) {
change.setStatus(Change.Status.NEW);
if (change.getStatus() == Status.ABANDONED) {
change.setStatus(Status.NEW);
ChangeUtil.updated(change);
return change;
}
@@ -132,34 +130,11 @@ public class Restore implements RestModifyView<ChangeResource, Input>,
}
@Override
public Set<Place> getPlaces() {
return EnumSet.of(Place.PATCHSET_ACTION_PANEL);
}
@Override
public String getLabel(ChangeResource resource) {
return "Restore";
}
@Override
public String getTitle(ChangeResource resource) {
return null;
}
@Override
public boolean isVisible(ChangeResource resource) {
return isEnabled(resource);
}
@Override
public boolean isEnabled(ChangeResource resource) {
return resource.getChange().getStatus() == Change.Status.ABANDONED
&& resource.getControl().canRestore();
}
@Override
public String getConfirmationMessage(ChangeResource resource) {
return null;
public UiAction.Description getDescription(ChangeResource resource) {
return new UiAction.Description()
.setLabel("Restore")
.setVisible(resource.getChange().getStatus() == Status.ABANDONED
&& resource.getControl().canRestore());
}
private ChangeMessage newMessage(Input input, IdentifiedUser caller,