Add a Custom Report to the Content Reports Application
Introduction
Goal
Add a custom reporting plugin to the CMS.
Background
Insights > Content reports is a separate application in the CMS. It is similar to the Setup > System application and provides an overview of icons / portals with a breadcrumb behaviour. Each icon represents a configurable group of plugins which gets shown if an icon is clicked. The following example will describe a basic setup to add a custom portal group with one panel.
The Content reports application is based on Ext JS and Wicket, for further information have a look at the wicket-extjs project source code.
Create a PortalPanelPlugin
To create a Portal Panel which represents a group of plugins with an icon, title and description create the following class in the cms module of your project:
HelloWorldPortalPanel.java:
package com.onehippo.cms7.reports.plugins; import org.apache.wicket.request.resource.ResourceReference; import org.apache.wicket.request.resource.PackageResourceReference; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.hippoecm.frontend.plugin.IPluginContext; import org.hippoecm.frontend.plugin.config.IPluginConfig; import org.onehippo.cms7.reports.ReportsPerspective; import org.onehippo.cms7.reports.plugins.PortalPanelPlugin; public class HelloWorldPortalPanel extends PortalPanelPlugin { public static final String HELLO_WORLD_PANEL_SERVICE = "service.reports.helloworld"; public HelloWorldPortalPanel(final IPluginContext context, final IPluginConfig config) { super(context, config); } @Override public ResourceReference getImage() { return new PackageResourceReference(HelloWorldPortalPanel.class, "hello-world-48.png"); } @Override public IModel<String> getTitle() { return new Model<String>("Hello World"); } @Override public IModel<String> getHelp() { return new Model<String>("Hello World Help"); } @Override public String getPanelServiceId() { // the service id of the perspective this plugin should be rendered // in, here the reports perspective return ReportsPerspective.REPORTING_SERVICE; } @Override public String getPortalPanelServiceId() { // the service id of the portal panel, to associate plugins to // the panel return HELLO_WORLD_PANEL_SERVICE; } }
The important functions which register and connect everything are getPanelServiceId() and getPortalPanelServiceId().
Note the reference to the image hello-world-48.png. Add a 48x48 icon (e.g. this copy of the 'buzz' icon) with that name to the cms module, under src/main/resources, in the package com.onehippo.cms7.reports.plugins.
Create an ExtPlugin
To render a plugin within the portal you must create another class (also in the cms module) which adds a Javascript resources header contribution and generates the Ext JS Javascript code to instantiate the class. It is a bridge between Wicket and Ext JS which initialises the config object passed to the constructor of the Ext JS javascript class. The annotation @ExtClass maps the java class to the custom javascript Ext JS class Hippo.Reports.HelloWorldPluginPanel which is defined in the file referenced by the head contribution Hippo.Reports.HelloWorldPluginPanel.js. @ExtProperty passes / converts class member variables to the javascript config object ( Hippo.Reports.HelloWorldPluginPanel.js).
HelloWorldPlugin.java:
package com.onehippo.cms7.reports.plugins; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.request.resource.JavaScriptResourceReference; import org.hippoecm.frontend.plugin.IPluginContext; import org.hippoecm.frontend.plugin.config.IPluginConfig; import org.onehippo.cms7.reports.AbstractExtRenderPlugin; import org.onehippo.cms7.reports.plugins.ReportPanel; import org.wicketstuff.js.ext.ExtComponent; import org.wicketstuff.js.ext.util.ExtClass; import org.wicketstuff.js.ext.util.ExtProperty; public class HelloWorldPlugin extends AbstractExtRenderPlugin { private static final JavaScriptResourceReference PANEL_JS = new JavaScriptResourceReference(HelloWorldPlugin.class, "Hippo.Reports.HelloWorldPluginPanel.js"); private ExtComponent helloWorldPluginPanel; @ExtClass("Hippo.Reports.HelloWorldPluginPanel") public class HelloWorldPluginPanel extends ReportPanel { @ExtProperty public String helloWorldText; public HelloWorldPluginPanel(final IPluginContext context, final IPluginConfig config) { super(context, config); helloWorldText = config.getString("helloworld.text"); } @Override public void renderHead(IHeaderResponse response) { super.renderHead(response); response.render(JavaScriptHeaderItem.forReference(PANEL_JS)); } } public HelloWorldPlugin(IPluginContext context, IPluginConfig config) { super(context, config); helloWorldPluginPanel = new HelloWorldPluginPanel(context, config); add(helloWorldPluginPanel); } @Override public ExtComponent getExtComponent() { return helloWorldPluginPanel; } }
For this example create a custom Ext JS class and simply display a property which was defined in the configuration of the plugin in the repository (see next XML code snippets for more details).
Create the following Javascript file in the cms module (in the same package as the Java classes):
Hippo.Reports.HelloWorldPluginPanel.js:
(function(Ext) { // define the namespace Ext.ns('Hippo.Reports'); // custom javascript class which gets initialised due to the annotations // in HelloWorldPlugin.java Hippo.Reports.HelloWorldPluginPanel = Ext.extend(Hippo.Reports.Portlet, { // config.helloWorldText holds the value of the @ExtProperty annotated // helloWorldText class member variable constructor : function(config) { // set the Ext html panel property to render the hello world text // in the panel config = Ext.apply(config, { html : config.helloWorldText }); // call the super constructor Hippo.Reports.HelloWorldPluginPanel.superclass.constructor.call( this, config); } }); // register the class as xtype Ext.reg('Hippo.Reports.HelloWorldPluginPanel', Hippo.Reports.HelloWorldPluginPanel); })(Ext);
Configuration of the plugins
The reporting dashboard is configured under the path /hippo:configuration/hippo:frontend/cms/hippo-reports. For this example, you need two YAML source definitions which bootstrap the configuration for the two plugins. These YAML representations can be imported through the Console:
definitions: config: /hippo:configuration/hippo:frontend/cms/hippo-reports/hello-world-portal-panel: jcr:primaryType: frontend:plugin plugin.class: com.onehippo.cms7.reports.plugins.HelloWorldPortalPanel
definitions: config: /hippo:configuration/hippo:frontend/cms/hippo-reports/hello-world-plugin: jcr:primaryType: frontend:plugin background: true height: 600 helloworld.text: Hello World! plugin.class: com.onehippo.cms7.reports.plugins.HelloWorldPlugin wicket.id: service.reports.helloworld width: 0.5
Important is the reference by the property wicket.id. It references the previous defined service string constant HELLO_WORLD_PANEL_SERVICE in HelloWorldPortalPanel.java to associate the plugin with the plugin HelloWorldPlugin.
Layout and appearance
The layout of the plugins is dynamic to the browser size and can be influenced with the properties width ( Double) and height ( Long). width is defined in relative percentage and height in absolute pixels. To give the plugin a light grey gradient background you can set the boolean property background.