Add top menu extension point
This extension point allows plugins to contribute entries to the top menu of Gerrit's Web UI. The usage is really simple, just implement TopMenu and add @Listen annotation or bind the implementation in plugin's module using: DynamicSet.bind(binder(), TopMenu.class).to(PluginFooTopMenu.class); Currently we only allow contribute top level menu entries with given name and list of menu items with name and URL. Change-Id: Ie161e0a61fdf041340df1aa0d6945fd479f34842 Signed-off-by: Dariusz Luksza <dariusz@luksza.org>
This commit is contained in:
parent
0b7e7850e5
commit
589ba00aa3
@ -732,6 +732,53 @@ Gerrit.install(function(self) {
|
||||
});
|
||||
----
|
||||
|
||||
[[top-menu-extensions]]
|
||||
Top Menu Extensions
|
||||
-------------------
|
||||
|
||||
Plugins can contribute items to Gerrit's top menu.
|
||||
|
||||
A single top menu extension can have multiple elements and will be put as
|
||||
the last element in Gerrit's top menu.
|
||||
|
||||
Plugins define the top menu entries by implementing `TopMenu` interface:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
public class MyTopMenuExtension implements TopMenu {
|
||||
|
||||
@Override
|
||||
public List<MenuEntry> getEntries() {
|
||||
return Lists.newArrayList(
|
||||
new MenuEntry("Top Menu Entry", Lists.newArrayList(
|
||||
new MenuItem("Gerrit", "http://gerrit.googlecode.com/"))));
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
If no Guice modules are declared in the manifest, the top menu extension may use
|
||||
auto-registration by providing an `@Listen` annotation:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Listen
|
||||
public class MyTopMenuExtension implements TopMenu {
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
Otherwise the top menu extension must be bound in a plugin module:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
public class HelloWorldModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
DynamicSet.bind(binder(), TopMenu.class).to(MyTopMenuExtension.class);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[http]]
|
||||
HTTP Servlets
|
||||
-------------
|
||||
|
@ -135,6 +135,47 @@ The entries in the map are sorted by capability ID.
|
||||
}
|
||||
----
|
||||
|
||||
[[get-top-menus]]
|
||||
Get Top Menus
|
||||
~~~~~~~~~~~~~
|
||||
[verse]
|
||||
'GET /config/server/top-menus'
|
||||
|
||||
Returns the list of additional top menu entries.
|
||||
|
||||
.Request
|
||||
----
|
||||
GET /config/server/top-menus HTTP/1.0
|
||||
----
|
||||
|
||||
As response a list of the additional top menu entries as
|
||||
link:#top-menu-entry-info[TopMenuEntryInfo] entities is returned.
|
||||
|
||||
.Response
|
||||
----
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
|
||||
)]}'
|
||||
[
|
||||
{
|
||||
"name": "Top Menu Entry",
|
||||
"items": [
|
||||
{
|
||||
"url": "http://gerrit.googlecode.com/",
|
||||
"name": "Gerrit",
|
||||
"target": "_blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
----
|
||||
|
||||
|
||||
[[json-entities]]
|
||||
JSON Entities
|
||||
-------------
|
||||
|
||||
[[capability-info]]
|
||||
CapabilityInfo
|
||||
~~~~~~~~~~~~~~
|
||||
@ -148,6 +189,32 @@ The `CapabilityInfo` entity contains information about a capability.
|
||||
|`name` |capability name
|
||||
|=================================
|
||||
|
||||
[[top-menu-entry-info]]
|
||||
TopMenuEntryInfo
|
||||
~~~~~~~~~~~~~~~~
|
||||
The `TopMenuEntryInfo` entity contains information about a top menu
|
||||
entry.
|
||||
|
||||
[options="header",width="50%",cols="1,5"]
|
||||
|=================================
|
||||
|Field Name |Description
|
||||
|`name` |Name of the top menu entry.
|
||||
|`items` |List of link:#top-menu-item-info[menu items].
|
||||
|=================================
|
||||
|
||||
[[top-menu-item-info]]
|
||||
TopMenuItemInfo
|
||||
~~~~~~~~~~~~~~~
|
||||
The `TopMenuItemInfo` entity contains information about a menu item in
|
||||
a top menu entry.
|
||||
|
||||
[options="header",width="50%",cols="1,5"]
|
||||
|=================================
|
||||
|Field Name |Description
|
||||
|`url` |The URL of the menu item link.
|
||||
|`name` |The name of the menu item.
|
||||
|`target` |Target attribute of the menu item link.
|
||||
|=================================
|
||||
|
||||
GERRIT
|
||||
------
|
||||
|
@ -0,0 +1,51 @@
|
||||
// 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.annotations.ExtensionPoint;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ExtensionPoint
|
||||
public interface TopMenu {
|
||||
|
||||
public class MenuEntry {
|
||||
public final String name;
|
||||
public final List<MenuItem> items;
|
||||
|
||||
public MenuEntry(String name, List<MenuItem> items) {
|
||||
this.name = name;
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
|
||||
public class MenuItem {
|
||||
public final String url;
|
||||
public final String name;
|
||||
public final String target;
|
||||
|
||||
public MenuItem(String name, String url) {
|
||||
this(name, url, "_blank");
|
||||
}
|
||||
|
||||
public MenuItem(String name, String url, String target) {
|
||||
this.url = url;
|
||||
this.name = name;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
||||
List<MenuEntry> getEntries();
|
||||
}
|
@ -24,8 +24,13 @@ import com.google.gerrit.client.admin.ProjectScreen;
|
||||
import com.google.gerrit.client.api.ApiGlue;
|
||||
import com.google.gerrit.client.changes.ChangeConstants;
|
||||
import com.google.gerrit.client.changes.ChangeListScreen;
|
||||
import com.google.gerrit.client.config.ConfigServerApi;
|
||||
import com.google.gerrit.client.extensions.TopMenu;
|
||||
import com.google.gerrit.client.extensions.TopMenuItem;
|
||||
import com.google.gerrit.client.extensions.TopMenuList;
|
||||
import com.google.gerrit.client.patches.PatchScreen;
|
||||
import com.google.gerrit.client.rpc.GerritCallback;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.client.ui.LinkMenuBar;
|
||||
import com.google.gerrit.client.ui.LinkMenuItem;
|
||||
import com.google.gerrit.client.ui.MorphingTabPanel;
|
||||
@ -86,6 +91,7 @@ import com.google.gwtjsonrpc.common.AsyncCallback;
|
||||
import com.google.gwtorm.client.KeyUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Gerrit implements EntryPoint {
|
||||
public static final GerritConstants C = GWT.create(GerritConstants.class);
|
||||
@ -784,6 +790,18 @@ public class Gerrit implements EntryPoint {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ConfigServerApi.topMenus(new GerritCallback<TopMenuList>() {
|
||||
public void onSuccess(TopMenuList result) {
|
||||
List<TopMenu> topMenuExtensions = Natives.asList(result);
|
||||
for (TopMenu menu : topMenuExtensions) {
|
||||
LinkMenuBar bar = new LinkMenuBar();
|
||||
for (TopMenuItem item : Natives.asList(menu.getItems())) {
|
||||
addExtensionLink(bar, item);
|
||||
}
|
||||
menuLeft.add(bar, menu.getName());
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public static void applyUserPreferences() {
|
||||
@ -916,4 +934,10 @@ public class Gerrit implements EntryPoint {
|
||||
atag.setTarget("_blank");
|
||||
m.add(atag);
|
||||
}
|
||||
|
||||
private static void addExtensionLink(final LinkMenuBar m, final TopMenuItem item) {
|
||||
final Anchor atag = anchor(item.getName(), item.getUrl());
|
||||
atag.setTarget(item.getTarget());
|
||||
m.add(atag);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.client.config;
|
||||
|
||||
import com.google.gerrit.client.extensions.TopMenuList;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.client.rpc.RestApi;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
@ -27,4 +28,8 @@ public class ConfigServerApi {
|
||||
public static void capabilities(AsyncCallback<NativeMap<CapabilityInfo>> cb) {
|
||||
new RestApi("/config/server/capabilities/").get(cb);
|
||||
}
|
||||
|
||||
public static void topMenus(AsyncCallback<TopMenuList> cb) {
|
||||
new RestApi("/config/server/top-menus").get(cb);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
// 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.client.extensions;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
|
||||
public class TopMenu extends JavaScriptObject {
|
||||
|
||||
protected TopMenu() {
|
||||
}
|
||||
|
||||
public final native String getName() /*-{ return this.name; }-*/;
|
||||
|
||||
public final native JsArray<TopMenuItem> getItems() /*-{ return this.items; }-*/;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// 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.client.extensions;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
|
||||
public class TopMenuItem extends JavaScriptObject {
|
||||
public final native String getName() /*-{ return this.name; }-*/;
|
||||
public final native String getUrl() /*-{ return this.url; }-*/;
|
||||
public final native String getTarget() /*-{ return this.target; }-*/;
|
||||
|
||||
protected TopMenuItem() {
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
// 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.client.extensions;
|
||||
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
|
||||
public class TopMenuList extends JsArray<TopMenu> {
|
||||
|
||||
protected TopMenuList() {
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import com.google.gerrit.extensions.events.ProjectDeletedListener;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.extensions.webui.TopMenu;
|
||||
import com.google.gerrit.rules.PrologModule;
|
||||
import com.google.gerrit.rules.RulesCache;
|
||||
import com.google.gerrit.server.AnonymousUser;
|
||||
@ -239,6 +240,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
DynamicSet.setOf(binder(), MergeValidationListener.class);
|
||||
DynamicItem.itemOf(binder(), AvatarProvider.class);
|
||||
DynamicSet.setOf(binder(), LifecycleListener.class);
|
||||
DynamicSet.setOf(binder(), TopMenu.class);
|
||||
|
||||
bind(AnonymousUser.class);
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
// 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.server.config;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.extensions.webui.TopMenu;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class ListTopMenus implements RestReadView<ConfigResource> {
|
||||
private final DynamicSet<TopMenu> extensions;
|
||||
|
||||
@Inject
|
||||
ListTopMenus(DynamicSet<TopMenu> extensions) {
|
||||
this.extensions = extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object apply(ConfigResource resource) {
|
||||
List<TopMenu.MenuEntry> entries = Lists.newArrayList();
|
||||
for (TopMenu extension : extensions) {
|
||||
entries.addAll(extension.getEntries());
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
}
|
@ -14,8 +14,9 @@
|
||||
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
|
||||
import static com.google.gerrit.server.config.CapabilityResource.CAPABILITY_KIND;
|
||||
import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
|
||||
import static com.google.gerrit.server.config.TopMenuResource.TOP_MENU_KIND;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.RestApiModule;
|
||||
@ -24,8 +25,10 @@ public class Module extends RestApiModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
DynamicMap.mapOf(binder(), CONFIG_KIND);
|
||||
DynamicMap.mapOf(binder(), TOP_MENU_KIND);
|
||||
DynamicMap.mapOf(binder(), CAPABILITY_KIND);
|
||||
child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class);
|
||||
child(CONFIG_KIND, "top-menus").to(TopMenuCollection.class);
|
||||
get(CONFIG_KIND, "version").to(GetVersion.class);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
// 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.server.config;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.restapi.ChildCollection;
|
||||
import com.google.gerrit.extensions.restapi.IdString;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
class TopMenuCollection implements
|
||||
ChildCollection<ConfigResource, TopMenuResource> {
|
||||
private final DynamicMap<RestView<TopMenuResource>> views;
|
||||
private final Provider<ListTopMenus> list;
|
||||
|
||||
@Inject
|
||||
TopMenuCollection(DynamicMap<RestView<TopMenuResource>> views,
|
||||
Provider<ListTopMenus> list) {
|
||||
this.views = views;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestView<ConfigResource> list() throws ResourceNotFoundException {
|
||||
return list.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopMenuResource parse(ConfigResource parent, IdString id)
|
||||
throws ResourceNotFoundException {
|
||||
throw new ResourceNotFoundException(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicMap<RestView<TopMenuResource>> views() {
|
||||
return views;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
// 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.server.config;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.RestView;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
public class TopMenuResource extends ConfigResource {
|
||||
public static final TypeLiteral<RestView<TopMenuResource>> TOP_MENU_KIND =
|
||||
new TypeLiteral<RestView<TopMenuResource>>() {};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user