Document UI Extension feature
Change-Id: I12877b51c81bc473a0590e51c3d2be609ba7edfc
This commit is contained in:
committed by
David Pursehouse
parent
be31cd4ea5
commit
f86bae579d
@@ -328,7 +328,7 @@ abstract class:
|
||||
}
|
||||
====
|
||||
|
||||
If no Guice modules are declared in the manifest, UI commands may
|
||||
If no Guice modules are declared in the manifest, UI actions may
|
||||
use auto-registration by providing an `@Export` annotation:
|
||||
|
||||
====
|
||||
@@ -351,7 +351,7 @@ Otherwise the capability must be bound in a plugin module:
|
||||
====
|
||||
|
||||
With a plugin-owned capability defined in this way, it is possible to restrict
|
||||
usage of an SSH command or UiAction to members of the group that were granted
|
||||
usage of an SSH command or `UiAction` to members of the group that were granted
|
||||
this capability in the usual way, using the `RequiresCapability` annotation:
|
||||
|
||||
====
|
||||
@@ -361,7 +361,7 @@ this capability in the usual way, using the `RequiresCapability` annotation:
|
||||
...
|
||||
====
|
||||
|
||||
Or with UiAction:
|
||||
Or with `UiAction`:
|
||||
|
||||
====
|
||||
@RequiresCapability("printHello")
|
||||
@@ -390,6 +390,186 @@ this can be specified by setting `scope = CapabilityScope.CORE`:
|
||||
...
|
||||
====
|
||||
|
||||
[[ui_extension]]
|
||||
UI Extension
|
||||
------------
|
||||
|
||||
Plugins can contribute their own UI commands on core Gerrit pages.
|
||||
This is useful for workflow customization or exposing plugin functionality
|
||||
through the UI in addition to SSH commands and the REST API.
|
||||
|
||||
For instance a plugin to integrate Jira with Gerrit changes may contribute its
|
||||
own "File bug" button to allow filing a bug from the change page or plugins to
|
||||
integrate continuous integration systems may contribute a "Schedule" button to
|
||||
allow a CI build to be scheduled manually from the patch set panel.
|
||||
|
||||
Two different places on core Gerrit pages are currently supported:
|
||||
|
||||
* Change screen
|
||||
* Project info screen
|
||||
|
||||
Plugins contribute UI actions by implementing the `UiAction` interface:
|
||||
|
||||
====
|
||||
@RequiresCapability("printHello")
|
||||
class HelloWorldAction implements UiAction<RevisionResource>,
|
||||
RestModifyView<RevisionResource, HelloWorldAction.Input> {
|
||||
static class Input {
|
||||
boolean french;
|
||||
String message;
|
||||
}
|
||||
|
||||
private Provider<CurrentUser> cu;
|
||||
|
||||
@Inject
|
||||
HelloWorldAction(Provider<CurrentUser> user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(RevisionResource rev, Input input) {
|
||||
final String greeting = input.french
|
||||
? "Bonjour"
|
||||
: "Hello";
|
||||
return String.format("%s %s from change %s, patch set %d!",
|
||||
greeting,
|
||||
Strings.isNullOrEmpty(input.message)
|
||||
? Objects.firstNonNull(user.get().getUserName(), "world")
|
||||
: input.message,
|
||||
rev.getChange().getId().toString(),
|
||||
rev.getPatchSet().getPatchSetId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description getDescription(
|
||||
RevisionResource resource) {
|
||||
return new Description()
|
||||
.setLabel("Say hello")
|
||||
.setTitle("Say hello in different languages");
|
||||
}
|
||||
}
|
||||
====
|
||||
|
||||
`UiAction` must be bound in a plugin module:
|
||||
|
||||
====
|
||||
public class Module extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
install(new RestApiModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
post(REVISION_KIND, "say-hello")
|
||||
.to(HelloWorldAction.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
====
|
||||
|
||||
The module above must be declared in pom.xml for Maven driven plugins:
|
||||
|
||||
====
|
||||
<manifestEntries>
|
||||
<Gerrit-Module>com.googlesource.gerrit.plugins.cookbook.Module</Gerrit-Module>
|
||||
</manifestEntries>
|
||||
====
|
||||
|
||||
or in the BUCK configuration file for Buck driven plugins:
|
||||
|
||||
====
|
||||
manifest_entries = [
|
||||
'Gerrit-Module: com.googlesource.gerrit.plugins.cookbook.Module',
|
||||
]
|
||||
====
|
||||
|
||||
In some use cases more user input must be gathered, for that `UiAction` can be
|
||||
combined with the JavaScript API. This would display a small popup near the
|
||||
activation button to gather additional input from the user. The JS file is
|
||||
typically put in the `static` folder within the plugin's directory:
|
||||
|
||||
====
|
||||
Gerrit.install(function(self) {
|
||||
function onSayHello(c) {
|
||||
var f = c.textfield();
|
||||
var t = c.checkbox();
|
||||
var b = c.button('Say hello', {onclick: function(){
|
||||
c.call(
|
||||
{message: f.value, french: t.checked},
|
||||
function(r) {
|
||||
c.hide();
|
||||
window.alert(r);
|
||||
c.refresh();
|
||||
});
|
||||
}});
|
||||
c.popup(c.div(
|
||||
c.prependLabel('Greeting message', f),
|
||||
c.br(),
|
||||
c.label(t, 'french'),
|
||||
c.br(),
|
||||
b));
|
||||
f.focus();
|
||||
}
|
||||
self.onAction('revision', 'say-hello', onSayHello);
|
||||
});
|
||||
====
|
||||
|
||||
The JS module must be exposed as a `WebUiPlugin` and bound as
|
||||
an HTTP Module:
|
||||
|
||||
====
|
||||
public class HttpModule extends HttpPluginModule {
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
DynamicSet.bind(binder(), WebUiPlugin.class)
|
||||
.toInstance(new JavaScriptPlugin("hello.js"));
|
||||
}
|
||||
}
|
||||
====
|
||||
|
||||
The HTTP module above must be declared in pom.xml for Maven driven plugins:
|
||||
|
||||
====
|
||||
<manifestEntries>
|
||||
<Gerrit-HttpModule>com.googlesource.gerrit.plugins.cookbook.HttpModule</Gerrit-HttpModule>
|
||||
</manifestEntries>
|
||||
====
|
||||
|
||||
or in the BUCK configuration file for Buck driven plugins
|
||||
|
||||
====
|
||||
manifest_entries = [
|
||||
'Gerrit-HttpModule: com.googlesource.gerrit.plugins.cookbook.HttpModule',
|
||||
]
|
||||
====
|
||||
|
||||
If `UiAction` is annotated with the `@RequiresCapability` annotation, then the
|
||||
capability check is done during the `UiAction` gathering, so the plugin author
|
||||
doesn't have to set `UiAction.Description.setVisible()` explicitly in this
|
||||
case.
|
||||
|
||||
The following prerequisities must be met, to satisfy the capability check:
|
||||
|
||||
* user is authenticated
|
||||
* user is a member of the Administrators group, or
|
||||
* user is a member of a group which has the required capability
|
||||
|
||||
The `apply` method is called when the button is clicked. If `UiAction` is
|
||||
combined with JavaScript API (its own JavaScript function is provided),
|
||||
then a popup dialog is normally opened to gather additional user input.
|
||||
A new button is placed on the popup dialog to actually send the request.
|
||||
|
||||
Every `UiAction` exposes a REST API endpoint. The endpoint from the example above
|
||||
can be accessed from any REST client, i. e.:
|
||||
|
||||
====
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{message: "François", french: true}' \
|
||||
--digest --user joe:secret \
|
||||
http://host:port/a/changes/1/revisions/1/cookbook~say-hello
|
||||
"Bonjour François from change 1, patch set 1!"
|
||||
====
|
||||
|
||||
[[http]]
|
||||
HTTP Servlets
|
||||
-------------
|
||||
@@ -573,6 +753,12 @@ command can be used.
|
||||
Disabled plugins can be re-enabled using the
|
||||
link:cmd-plugin-enable.html[plugin enable] command.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
* link:js-api.html[JavaScript API]
|
||||
* link:dev-rest-api.html[REST API Developers' Notes]
|
||||
|
||||
GERRIT
|
||||
------
|
||||
Part of link:index.html[Gerrit Code Review]
|
||||
|
||||
Reference in New Issue
Block a user