Merge "Enhance plugin extension panels to allow ordering per a config"
This commit is contained in:
@@ -1209,6 +1209,7 @@ public class MyPlugin extends PluginEntryPoint {
|
||||
@Override
|
||||
public void onPluginLoad() {
|
||||
Plugin.get().panel(GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK,
|
||||
"my_panel_name",
|
||||
new Panel.EntryPoint() {
|
||||
@Override
|
||||
public void onLoad(Panel panel) {
|
||||
@@ -1220,6 +1221,23 @@ public class MyPlugin extends PluginEntryPoint {
|
||||
}
|
||||
----
|
||||
|
||||
Change Screen panel ordering may be specified in the
|
||||
project config. Values may be either "plugin name" or
|
||||
"plugin name"."panel name".
|
||||
Panels not specified in the config will be added
|
||||
to the end in load order. Panels specified in the config that
|
||||
are not found will be ignored.
|
||||
|
||||
Example config:
|
||||
----
|
||||
[extension-panels "CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK"]
|
||||
panel = helloworld.change_id
|
||||
panel = myotherplugin
|
||||
panel = myplugin.my_panel_name
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[actions]]
|
||||
=== Actions
|
||||
|
||||
|
@@ -41,6 +41,8 @@ public class ConfigInfo {
|
||||
public Map<String, CommentLinkInfo> commentlinks;
|
||||
public ThemeInfo theme;
|
||||
|
||||
public Map<String, List<String>> extensionPanelNames;
|
||||
|
||||
public static class InheritedBooleanInfo {
|
||||
public Boolean value;
|
||||
public InheritableBoolean configuredValue;
|
||||
|
@@ -100,9 +100,9 @@ public class ApiGlue {
|
||||
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);
|
||||
panel: function(i,c,n){this._panel(this.getPluginName(),i,c,n)},
|
||||
_panel: function(n,i,c,x){
|
||||
var p = new PanelDefinition(n,c,x);
|
||||
(this.panels[i] || (this.panels[i]=[])).push(p);
|
||||
},
|
||||
|
||||
|
@@ -22,7 +22,10 @@ import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -32,13 +35,18 @@ public class ExtensionPanel extends FlowPanel {
|
||||
private final List<Context> contexts;
|
||||
|
||||
public ExtensionPanel(GerritUiExtensionPoint extensionPoint) {
|
||||
this.extensionPoint = extensionPoint;
|
||||
this.contexts = create();
|
||||
this(extensionPoint, new ArrayList<String>());
|
||||
}
|
||||
|
||||
private List<Context> create() {
|
||||
List<Context> contexts = new ArrayList<>();
|
||||
for (Definition def : Natives.asList(Definition.get(extensionPoint.name()))) {
|
||||
public ExtensionPanel(GerritUiExtensionPoint extensionPoint,
|
||||
List<String> panelNames) {
|
||||
this.extensionPoint = extensionPoint;
|
||||
this.contexts = create(panelNames);
|
||||
}
|
||||
|
||||
private List<Context> create(List<String> panelNames) {
|
||||
List<Context> contexts = new ArrayList<Context>();
|
||||
for (Definition def : getOrderedDefs(panelNames)) {
|
||||
SimplePanel p = new SimplePanel();
|
||||
add(p);
|
||||
contexts.add(Context.create(def, p));
|
||||
@@ -46,6 +54,45 @@ public class ExtensionPanel extends FlowPanel {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
private List<Definition> getOrderedDefs(List<String> panelNames) {
|
||||
if (panelNames == null) {
|
||||
panelNames = Collections.emptyList();
|
||||
}
|
||||
Map<String, List<Definition>> defsOrderedByName =
|
||||
new LinkedHashMap<String, List<Definition>>();
|
||||
for (String name : panelNames) {
|
||||
defsOrderedByName.put(name, new ArrayList<Definition>());
|
||||
}
|
||||
for (Definition def : Natives.asList(
|
||||
Definition.get(extensionPoint.name()))) {
|
||||
addDef(def, defsOrderedByName);
|
||||
}
|
||||
List<Definition> orderedDefs = new ArrayList<Definition>();
|
||||
for (List<Definition> defList : defsOrderedByName.values()) {
|
||||
orderedDefs.addAll(defList);
|
||||
}
|
||||
return orderedDefs;
|
||||
}
|
||||
|
||||
private static void addDef(Definition def,
|
||||
Map<String, List<Definition>> defsOrderedByName) {
|
||||
String panelName = def.getPanelName();
|
||||
if (panelName.equals(def.getPluginName() + ".undefined")) {
|
||||
/* Handle a partially undefined panel name from the
|
||||
javascript layer by generating a random panel name.
|
||||
This maintains support for panels that do not provide a name. */
|
||||
panelName = def.getPluginName() + "." + Long.toHexString(
|
||||
Double.doubleToLongBits(Math.random()));
|
||||
}
|
||||
if (defsOrderedByName.containsKey(panelName)) {
|
||||
defsOrderedByName.get(panelName).add(def);
|
||||
} else if (defsOrderedByName.containsKey(def.getPluginName())) {
|
||||
defsOrderedByName.get(def.getPluginName()).add(def);
|
||||
} else {
|
||||
defsOrderedByName.put(panelName, Collections.singletonList(def));
|
||||
}
|
||||
}
|
||||
|
||||
public void put(GerritUiExtensionPoint.Key key, String value) {
|
||||
for (Context ctx : contexts) {
|
||||
ctx.put(key.name(), value);
|
||||
@@ -103,9 +150,10 @@ public class ExtensionPanel extends FlowPanel {
|
||||
static final JavaScriptObject TYPE = init();
|
||||
|
||||
private static native JavaScriptObject init() /*-{
|
||||
function PanelDefinition(n, c) {
|
||||
function PanelDefinition(n, c, x) {
|
||||
this.pluginName = n;
|
||||
this.onLoad = c;
|
||||
this.name = x;
|
||||
};
|
||||
return PanelDefinition;
|
||||
}-*/;
|
||||
@@ -113,6 +161,9 @@ public class ExtensionPanel extends FlowPanel {
|
||||
static native JsArray<Definition> get(String i) /*-{ return $wnd.Gerrit.panels[i] || [] }-*/;
|
||||
|
||||
protected Definition() {}
|
||||
|
||||
public final native String getPanelName() /*-{ return this.pluginName + "." + this.name; }-*/;
|
||||
public final native String getPluginName() /*-{ return this.pluginName; }-*/;
|
||||
}
|
||||
|
||||
static class Context extends JavaScriptObject {
|
||||
|
@@ -68,7 +68,7 @@ final class Plugin extends JavaScriptObject {
|
||||
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)},
|
||||
panel: function(i,c,n){G._panel(this.name,i,c,n)},
|
||||
|
||||
url: function (u){return G.url(this._url(u))},
|
||||
get: function(u,b){@com.google.gerrit.client.api.ActionContext::get(
|
||||
|
@@ -309,8 +309,7 @@ public class ChangeScreen extends Screen {
|
||||
@Override
|
||||
public void onSuccess(final ChangeInfo info) {
|
||||
info.init();
|
||||
addExtensionPoints(info, initCurrentRevision(info));
|
||||
|
||||
initCurrentRevision(info);
|
||||
final RevisionInfo rev = info.revision(revision);
|
||||
CallbackGroup group = new CallbackGroup();
|
||||
loadCommit(rev, group);
|
||||
@@ -379,7 +378,8 @@ public class ChangeScreen extends Screen {
|
||||
return resolveRevisionToDisplay(info);
|
||||
}
|
||||
|
||||
private void addExtensionPoints(ChangeInfo change, RevisionInfo rev) {
|
||||
private void addExtensionPoints(ChangeInfo change, RevisionInfo rev,
|
||||
Entry result) {
|
||||
addExtensionPoint(GerritUiExtensionPoint.CHANGE_SCREEN_HEADER, headerExtension, change, rev);
|
||||
addExtensionPoint(
|
||||
GerritUiExtensionPoint.CHANGE_SCREEN_HEADER_RIGHT_OF_BUTTONS,
|
||||
@@ -392,7 +392,10 @@ public class ChangeScreen extends Screen {
|
||||
change,
|
||||
rev);
|
||||
addExtensionPoint(
|
||||
GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK, changeExtension, change, rev);
|
||||
GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK,
|
||||
changeExtension, change, rev,
|
||||
result.getExtensionPanelNames(
|
||||
GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK.toString()));
|
||||
addExtensionPoint(
|
||||
GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_RELATED_INFO_BLOCK,
|
||||
relatedExtension,
|
||||
@@ -408,13 +411,19 @@ public class ChangeScreen extends Screen {
|
||||
}
|
||||
|
||||
private void addExtensionPoint(
|
||||
GerritUiExtensionPoint extensionPoint, Panel p, ChangeInfo change, RevisionInfo rev) {
|
||||
ExtensionPanel extensionPanel = new ExtensionPanel(extensionPoint);
|
||||
GerritUiExtensionPoint extensionPoint, Panel p, ChangeInfo change,
|
||||
RevisionInfo rev, List<String> panelNames) {
|
||||
ExtensionPanel extensionPanel = new ExtensionPanel(extensionPoint, panelNames);
|
||||
extensionPanel.putObject(GerritUiExtensionPoint.Key.CHANGE_INFO, change);
|
||||
extensionPanel.putObject(GerritUiExtensionPoint.Key.REVISION_INFO, rev);
|
||||
p.add(extensionPanel);
|
||||
}
|
||||
|
||||
private void addExtensionPoint(
|
||||
GerritUiExtensionPoint extensionPoint, Panel p, ChangeInfo change, RevisionInfo rev) {
|
||||
addExtensionPoint(extensionPoint, p, change, rev, Collections.emptyList());
|
||||
}
|
||||
|
||||
private boolean enableSignedPush() {
|
||||
return Gerrit.info().receive().enableSignedPush();
|
||||
}
|
||||
@@ -1031,6 +1040,14 @@ public class ChangeScreen extends Screen {
|
||||
loadRevisionInfo();
|
||||
}
|
||||
});
|
||||
ConfigInfoCache.get(
|
||||
info.projectNameKey(),
|
||||
new GerritCallback<Entry>() {
|
||||
@Override
|
||||
public void onSuccess(Entry entry) {
|
||||
addExtensionPoints(info, rev, entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateToken(ChangeInfo info, DiffObject base, RevisionInfo rev) {
|
||||
|
@@ -116,6 +116,8 @@ public class ConfigInfo extends JavaScriptObject {
|
||||
|
||||
final native ThemeInfo theme() /*-{ return this.theme; }-*/;
|
||||
|
||||
final native NativeMap<JsArrayString> extensionPanelNames() /*-{ return this.extension_panel_names; }-*/;
|
||||
|
||||
protected ConfigInfo() {}
|
||||
|
||||
static class CommentLinkInfo extends JavaScriptObject {
|
||||
|
@@ -16,12 +16,16 @@ package com.google.gerrit.client.projects;
|
||||
|
||||
import com.google.gerrit.client.changes.ChangeApi;
|
||||
import com.google.gerrit.client.info.ChangeInfo;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.client.ui.CommentLinkProcessor;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Cache of {@link ConfigInfo} objects by project name. */
|
||||
@@ -48,6 +52,10 @@ public class ConfigInfoCache {
|
||||
public ThemeInfo getTheme() {
|
||||
return info.theme();
|
||||
}
|
||||
|
||||
public List<String> getExtensionPanelNames(String extensionPoint) {
|
||||
return Natives.asList(info.extensionPanelNames().get(extensionPoint));
|
||||
}
|
||||
}
|
||||
|
||||
public static void get(Project.NameKey name, AsyncCallback<Entry> cb) {
|
||||
|
@@ -121,12 +121,16 @@ public final class Plugin extends JavaScriptObject {
|
||||
*
|
||||
* @param extensionPoint the UI extension point for which the panel should be registered.
|
||||
* @param entry callback function invoked to create the panel widgets.
|
||||
* @param name the name of the panel which can be used to specify panel
|
||||
* ordering via project config
|
||||
*/
|
||||
public void panel(GerritUiExtensionPoint extensionPoint, Panel.EntryPoint entry) {
|
||||
panel(extensionPoint.name(), wrap(entry));
|
||||
public final void panel(GerritUiExtensionPoint extensionPoint,
|
||||
Panel.EntryPoint entry, String name) {
|
||||
panel(extensionPoint.name(), wrap(entry), name);
|
||||
}
|
||||
|
||||
private native void panel(String i, JavaScriptObject e) /*-{ this.panel(i, e) }-*/;
|
||||
private native void panel(String i, JavaScriptObject e, String n)
|
||||
/*-{ this.panel(i, e, n) }-*/;
|
||||
|
||||
protected Plugin() {}
|
||||
|
||||
|
@@ -166,6 +166,9 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
||||
private static final SubmitType DEFAULT_SUBMIT_ACTION = SubmitType.MERGE_IF_NECESSARY;
|
||||
private static final ProjectState DEFAULT_STATE_VALUE = ProjectState.ACTIVE;
|
||||
|
||||
private static final String EXTENSION_PANELS = "extension-panels";
|
||||
private static final String KEY_PANEL = "panel";
|
||||
|
||||
private Project.NameKey projectName;
|
||||
private Project project;
|
||||
private AccountsSection accountsSection;
|
||||
@@ -186,6 +189,7 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
||||
private Set<String> sectionsWithUnknownPermissions;
|
||||
private boolean hasLegacyPermissions;
|
||||
private boolean enableReviewerByEmail;
|
||||
private Map<String, List<String>> extensionPanelSections;
|
||||
|
||||
public static ProjectConfig read(MetaDataUpdate update)
|
||||
throws IOException, ConfigInvalidException {
|
||||
@@ -201,6 +205,10 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
||||
return r;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getExtensionPanelSections() {
|
||||
return extensionPanelSections;
|
||||
}
|
||||
|
||||
public static CommentLinkInfoImpl buildCommentLink(Config cfg, String name, boolean allowRaw)
|
||||
throws IllegalArgumentException {
|
||||
String match = cfg.getString(COMMENTLINK, name, KEY_MATCH);
|
||||
@@ -541,6 +549,7 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
||||
loadPluginSections(rc);
|
||||
loadReceiveSection(rc);
|
||||
loadReviewerSection(rc);
|
||||
loadExtensionPanelSections(rc);
|
||||
}
|
||||
|
||||
private void loadAccountsSection(Config rc, Map<String, GroupReference> groupsByName) {
|
||||
@@ -549,6 +558,23 @@ public class ProjectConfig extends VersionedMetaData implements ValidationError.
|
||||
loadPermissionRules(rc, ACCOUNTS, null, KEY_SAME_GROUP_VISIBILITY, groupsByName, false));
|
||||
}
|
||||
|
||||
private void loadExtensionPanelSections(Config rc) throws IOException {
|
||||
Map<String, String> lowerNames = Maps.newHashMapWithExpectedSize(2);
|
||||
extensionPanelSections = Maps.newLinkedHashMap();
|
||||
for (String name : rc.getSubsections(EXTENSION_PANELS)) {
|
||||
String lower = name.toLowerCase();
|
||||
if (lowerNames.containsKey(lower)) {
|
||||
error(new ValidationError(PROJECT_CONFIG, String.format(
|
||||
"Extension Panels \"%s\" conflicts with \"%s\"",
|
||||
name, lowerNames.get(lower))));
|
||||
}
|
||||
lowerNames.put(lower, name);
|
||||
extensionPanelSections.put(name,
|
||||
new ArrayList<String>(Arrays.asList(
|
||||
rc.getStringList(EXTENSION_PANELS, name, KEY_PANEL))));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadContributorAgreements(Config rc, Map<String, GroupReference> groupsByName) {
|
||||
contributorAgreements = new HashMap<>();
|
||||
for (String name : rc.getSubsections(CONTRIBUTOR_AGREEMENT)) {
|
||||
|
@@ -131,6 +131,8 @@ public class ConfigInfoImpl extends ConfigInfo {
|
||||
actions.put(d.getId(), new ActionInfo(d));
|
||||
}
|
||||
this.theme = projectState.getTheme();
|
||||
|
||||
this.extensionPanelNames = projectState.getConfig().getExtensionPanelSections();
|
||||
}
|
||||
|
||||
private Map<String, Map<String, ConfigParameterInfo>> getPluginConfig(
|
||||
|
Reference in New Issue
Block a user