Allow plugins to add custom settings screens
Plugins can now add custom screens which are integrated into the Gerrit user settings menu. A new entry in the user settings menu loads and displays the settings screen from the plugin. The user settings menu on the left side is automatically included into the custom settings screens. Plugins must register settings screen early at plugin module load. The way how settings screens are registered is similar to how plugins can add normal custom screens. An example settings screen was implemented in the cookbook plugin. Change-Id: I4a88e4975ff436a5cdb125ebbde276dfab280ce2 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -1730,6 +1730,31 @@ public class MyPlugin extends PluginEntryPoint {
|
||||
}
|
||||
----
|
||||
|
||||
[[user-settings-screen]]
|
||||
== Add User Settings Screen
|
||||
|
||||
A link:#gwt_ui_extension[GWT plugin] can implement a user settings
|
||||
screen that is integrated into the Gerrit user settings menu.
|
||||
|
||||
Example settings screen:
|
||||
[source,java]
|
||||
----
|
||||
public class MyPlugin extends PluginEntryPoint {
|
||||
@Override
|
||||
public void onPluginLoad() {
|
||||
Plugin.get().settingsScreen("my-preferences", "My Preferences",
|
||||
new Screen.EntryPoint() {
|
||||
@Override
|
||||
public void onLoad(Screen screen) {
|
||||
screen.setPageTitle("Settings");
|
||||
screen.add(new InlineLabel("My Preferences"));
|
||||
screen.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[settings-screen]]
|
||||
== Plugin Settings Screen
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ public class PageLinks {
|
||||
public static final String SETTINGS_CONTACT = "/settings/contact";
|
||||
public static final String SETTINGS_PROJECTS = "/settings/projects";
|
||||
public static final String SETTINGS_NEW_AGREEMENT = "/settings/new-agreement";
|
||||
public static final String SETTINGS_EXTENSION = "/settings/x/";
|
||||
public static final String REGISTER = "/register";
|
||||
|
||||
public static final String MINE = "/";
|
||||
@@ -128,6 +129,10 @@ public class PageLinks {
|
||||
return ADMIN_GROUPS + "uuid-" + uuid;
|
||||
}
|
||||
|
||||
public static String toSettings(String pluginName, String path) {
|
||||
return SETTINGS_EXTENSION + pluginName + "/" + path;
|
||||
}
|
||||
|
||||
private static String status(Status status) {
|
||||
switch (status) {
|
||||
case ABANDONED:
|
||||
|
||||
@@ -28,6 +28,7 @@ import static com.google.gerrit.common.PageLinks.REGISTER;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS_AGREEMENTS;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS_CONTACT;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS_EXTENSION;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS_HTTP_PASSWORD;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS_MYGROUPS;
|
||||
import static com.google.gerrit.common.PageLinks.SETTINGS_NEW_AGREEMENT;
|
||||
@@ -65,6 +66,7 @@ import com.google.gerrit.client.admin.ProjectInfoScreen;
|
||||
import com.google.gerrit.client.admin.ProjectListScreen;
|
||||
import com.google.gerrit.client.admin.ProjectScreen;
|
||||
import com.google.gerrit.client.api.ExtensionScreen;
|
||||
import com.google.gerrit.client.api.ExtensionSettingsScreen;
|
||||
import com.google.gerrit.client.change.ChangeScreen;
|
||||
import com.google.gerrit.client.change.FileTable;
|
||||
import com.google.gerrit.client.changes.AccountDashboardScreen;
|
||||
@@ -720,6 +722,16 @@ public class Dispatcher {
|
||||
return new NewAgreementScreen(skip(token));
|
||||
}
|
||||
|
||||
if (matchPrefix(SETTINGS_EXTENSION, token)) {
|
||||
ExtensionSettingsScreen view =
|
||||
new ExtensionSettingsScreen(skip(token));
|
||||
if (view.isFound()) {
|
||||
return view;
|
||||
} else {
|
||||
return new NotFoundScreen();
|
||||
}
|
||||
}
|
||||
|
||||
return new NotFoundScreen();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package com.google.gerrit.client.account;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.api.ExtensionSettingsScreen;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.client.ui.MenuScreen;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
|
||||
@@ -37,6 +39,13 @@ public abstract class SettingsScreen extends MenuScreen {
|
||||
if (Gerrit.info().auth().useContributorAgreements()) {
|
||||
link(Util.C.tabAgreements(), PageLinks.SETTINGS_AGREEMENTS);
|
||||
}
|
||||
|
||||
for (String pluginName : ExtensionSettingsScreen.Definition.plugins()) {
|
||||
for (ExtensionSettingsScreen.Definition def :
|
||||
Natives.asList(ExtensionSettingsScreen.Definition.get(pluginName))) {
|
||||
link(def.getMenu(), PageLinks.toSettings(pluginName, def.getPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -35,12 +35,14 @@ public class ApiGlue {
|
||||
private static native void init0() /*-{
|
||||
var serverUrl = @com.google.gwt.core.client.GWT::getHostPageBaseURL()();
|
||||
var ScreenDefinition = @com.google.gerrit.client.api.ExtensionScreen.Definition::TYPE;
|
||||
var SettingsScreenDefinition = @com.google.gerrit.client.api.ExtensionSettingsScreen.Definition::TYPE;
|
||||
var PanelDefinition = @com.google.gerrit.client.api.ExtensionPanel.Definition::TYPE;
|
||||
$wnd.Gerrit = {
|
||||
JsonString: @com.google.gerrit.client.rpc.NativeString::TYPE,
|
||||
events: {},
|
||||
plugins: {},
|
||||
screens: {},
|
||||
settingsScreens: {},
|
||||
panels: {},
|
||||
change_actions: {},
|
||||
edit_actions: {},
|
||||
@@ -87,6 +89,11 @@ public class ApiGlue {
|
||||
var s = new ScreenDefinition(r,c);
|
||||
(this.screens[p] || (this.screens[p]=[])).push(s);
|
||||
},
|
||||
settingsScreen: function(p,m,c){this._settingsScreen(this.getPluginName(),p,m,c)},
|
||||
_settingsScreen: function(n,p,m,c){
|
||||
var s = new SettingsScreenDefinition(p,m,c);
|
||||
(this.settingsScreens[n] || (this.settingsScreens[n]=[])).push(s);
|
||||
},
|
||||
panel: function(i,c){this._panel(this.getPluginName(),i,c)},
|
||||
_panel: function(n,i,c){
|
||||
var p = new PanelDefinition(n,c);
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (C) 2015 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.client.api;
|
||||
|
||||
import com.google.gerrit.client.account.SettingsScreen;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.client.rpc.NativeString;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/** SettingsScreen contributed by a plugin. */
|
||||
public class ExtensionSettingsScreen extends SettingsScreen {
|
||||
private Context ctx;
|
||||
|
||||
public ExtensionSettingsScreen(String token) {
|
||||
if (token.contains("?")) {
|
||||
token = token.substring(0, token.indexOf('?'));
|
||||
}
|
||||
String name;
|
||||
String rest;
|
||||
int s = token.indexOf('/');
|
||||
if (0 < s) {
|
||||
name = token.substring(0, s);
|
||||
rest = token.substring(s + 1);
|
||||
} else {
|
||||
name = token;
|
||||
rest = "";
|
||||
}
|
||||
ctx = create(name, rest);
|
||||
}
|
||||
|
||||
private Context create(String name, String rest) {
|
||||
for (Definition def : Natives.asList(Definition.get(name))) {
|
||||
if (def.matches(rest)) {
|
||||
return Context.create(def, this);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isFound() {
|
||||
return ctx != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
setHeaderVisible(false);
|
||||
ctx.onLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnload() {
|
||||
super.onUnload();
|
||||
for (JavaScriptObject u : Natives.asList(ctx.unload())) {
|
||||
ApiGlue.invoke(u);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Definition extends JavaScriptObject {
|
||||
static final JavaScriptObject TYPE = init();
|
||||
private static native JavaScriptObject init() /*-{
|
||||
function SettingsScreenDefinition(p, m, c) {
|
||||
this.path = p;
|
||||
this.menu = m;
|
||||
this.onLoad = c;
|
||||
};
|
||||
return SettingsScreenDefinition;
|
||||
}-*/;
|
||||
|
||||
public static native JsArray<Definition> get(String n)
|
||||
/*-{ return $wnd.Gerrit.settingsScreens[n] || [] }-*/;
|
||||
|
||||
public static final Set<String> plugins() {
|
||||
return Natives.keys(settingsScreens());
|
||||
}
|
||||
|
||||
private static final native NativeMap<NativeString> settingsScreens()
|
||||
/*-{ return $wnd.Gerrit.settingsScreens; }-*/;
|
||||
|
||||
public final native String getPath() /*-{ return this.path; }-*/;
|
||||
public final native String getMenu() /*-{ return this.menu; }-*/;
|
||||
|
||||
final native boolean matches(String t)
|
||||
/*-{ return this.path == t; }-*/;
|
||||
|
||||
protected Definition() {
|
||||
}
|
||||
}
|
||||
|
||||
static class Context extends JavaScriptObject {
|
||||
static final Context create(
|
||||
Definition def,
|
||||
ExtensionSettingsScreen view) {
|
||||
return create(TYPE, def, view, view.getBody().getElement());
|
||||
}
|
||||
|
||||
final native void onLoad() /*-{ this._d.onLoad(this) }-*/;
|
||||
final native JsArray<JavaScriptObject> unload() /*-{ return this._u }-*/;
|
||||
|
||||
private static final native Context create(
|
||||
JavaScriptObject T,
|
||||
Definition d,
|
||||
ExtensionSettingsScreen s,
|
||||
Element e)
|
||||
/*-{ return new T(d,s,e) }-*/;
|
||||
|
||||
private static final JavaScriptObject TYPE = init();
|
||||
private static final native JavaScriptObject init() /*-{
|
||||
var T = function(d,s,e) {
|
||||
this._d = d;
|
||||
this._s = s;
|
||||
this._u = [];
|
||||
this.body = e;
|
||||
};
|
||||
T.prototype = {
|
||||
setTitle: function(t){this._s.@com.google.gerrit.client.ui.Screen::setPageTitle(Ljava/lang/String;)(t)},
|
||||
setWindowTitle: function(t){this._s.@com.google.gerrit.client.ui.Screen::setWindowTitle(Ljava/lang/String;)(t)},
|
||||
show: function(){$entry(this._s.@com.google.gwtexpui.user.client.View::display()())},
|
||||
onUnload: function(f){this._u.push(f)},
|
||||
};
|
||||
return T;
|
||||
}-*/;
|
||||
|
||||
protected Context() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ final class Plugin extends JavaScriptObject {
|
||||
on: function(e,f){G.on(e,f)},
|
||||
onAction: function(t,n,c){G._onAction(this.name,t,n,c)},
|
||||
screen: function(p,c){G._screen(this.name,p,c)},
|
||||
settingsScreen: function(p,m,c){G._settingsScreen(this.name,p,m,c)},
|
||||
panel: function(i,c){G._panel(this.name,i,c)},
|
||||
|
||||
url: function (u){return G.url(this._url(u))},
|
||||
|
||||
@@ -48,6 +48,11 @@ public abstract class MenuScreen extends Screen {
|
||||
super.setToken(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FlowPanel getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void add(final Widget w) {
|
||||
body.add(w);
|
||||
|
||||
@@ -93,6 +93,19 @@ public final class Plugin extends JavaScriptObject {
|
||||
private final native void screenRegex(String p, JavaScriptObject e)
|
||||
/*-{ this.screen(new $wnd.RegExp(p), e) }-*/;
|
||||
|
||||
/**
|
||||
* Register a settings screen displayed at {@code /#/settings/x/plugin/token}.
|
||||
*
|
||||
* @param token literal anchor token appearing after the plugin name.
|
||||
* @param entry callback function invoked to create the settings screen widgets.
|
||||
*/
|
||||
public final void settingsScreen(String token, String menu, Screen.EntryPoint entry) {
|
||||
settingsScreen(token, menu, wrap(entry));
|
||||
}
|
||||
|
||||
private final native void settingsScreen(String t, String m, JavaScriptObject e)
|
||||
/*-{ this.settingsScreen(t, m, e) }-*/;
|
||||
|
||||
/**
|
||||
* Register a panel for a UI extension point.
|
||||
*
|
||||
|
||||
Submodule plugins/cookbook-plugin updated: a128968cd8...eee2781ce0
Reference in New Issue
Block a user