Essentials Plugin Front End

Essentials plugins can contribute HTML and JavaScript to the Dashboard so users can set installation options and configure features and tools. How that integration works depends on which Dashboard generation your Bloomreach Experience Manager (XM) release uses.

  • Before XM 17.0.0: the Dashboard was an AngularJS application. Plugins registered controllers on the hippo.essentials module and used Plugin SDK AngularJS services and directives.
  • XM 17.0.0 and later: the Dashboard is an Angular application. Bloomreach ships first-party plugin UIs as Angular components inside the Dashboard. Customer and third-party plugins are not registered in Angular; instead, their configuration UI is loaded in a sandboxed iframe, and the Dashboard exposes a small JavaScript API over a postMessage bridge (implemented with Penpal).

Static assets (HTML, CSS, JS) are still packaged with the Servlet 3.0+ web fragment mechanism; only the way the running Dashboard loads and talks to that UI changed for external plugins.


Part A — Before XM 17.0.0 (AngularJS Essentials Dashboard)

Use Cases

Essentials plugins typically contribute to the Dashboard in two scenarios:

  1. Feature plugin installation requires user-controlled installation parameters. The Plugin SDK API provides the AngularJS directive <essentials-simple-install-plugin>, which plugins can use to manage built-in installation parameters. See the directive details below.

  2. The plugin offers configuration options that require a user interface fragment. This is required for plugins of type tool and optional for plugins of type feature.

Packaging

To add HTML fragments or JavaScript code to the Dashboard, a plugin must package these resources using the Servlet 3.0 Web fragment mechanism. Essentials expects each plugin JAR to include a META-INF/web-fragment.xml file. All resources requested by the front-end must be placed under META-INF/resources. For details on icons and images, refer to the Plugin Descriptor.

To prevent namespace conflicts and to enable automatic detection and loading, Essentials enforces a convention: Dashboard contributions must be located at <pluginType>/<pluginId>/<pluginId>.[html|js] within the web fragment.

For example, a feature plugin with the ID myPluginId should place its JavaScript resource at:

src/main/resources/META-INF/resources/feature/myPluginId/myPluginId.js

Functionality

The Dashboard is an AngularJS single-page application. To contribute functionality, an Essentials plugin must register a controller with the hippo.essentials AngularJS module. Each controller name must be unique, typically by appending Ctrl to the plugin ID.

Controllers can request standard AngularJS services such as $scope (for HTML interaction) and $http (for REST communication with the back-end). The Dashboard also provides Essentials-specific services, included as web fragments in the Plugin SDK API JAR. The table below summarizes these services. For detailed documentation, review the Plugin SDK's META-INF/resources/dashboard/api/services.js.

ServiceDescription
essentialsRestServiceSupplies the base URL for accessing dynamic REST endpoints on the back-end.
essentialsPluginServiceProvides a front-end representation of the plugin, including its current installation state.
essentialsProjectServiceSupplies current project settings, including global installation parameter preferences.
essentialsContentTypeServiceOffers access to project content types, content type instances (documents), and template queries for creating new documents.

The following example shows a plugin controller that exposes a function to the HTML fragment. This function calls the plugin's dynamic REST endpoint to retrieve plugin-specific data. For plugins of type tool, or plugins with hasConfiguration set, and with JavaScript resources packaged as described above, the Dashboard will automatically detect, load, and register the controller.

(function () { 'use strict'; angular.module('hippo.essentials') .controller('myPluginCtrl', function ($scope, $http, essentialsRestService) { $scope.getMyStuff = function () { $http.get(essentialsRestService.baseUrl + '/myPlugin').success(function (data) { $scope.data = data; }); }; }); })();

Presentation

The AngularJS controller manages the plugin's front-end logic. The presentation layer is defined by an HTML fragment, which can use AngularJS directives from the Plugin SDK API and interact with the controller. The controller is only instantiated if the HTML fragment explicitly requires it. If the HTML fragment does not require a controller, you do not need to package a JavaScript resource with the plugin.

Like JavaScript resources, the HTML fragment must be packaged as a web fragment. The Dashboard loads the fragment as needed. If a feature plugin has no installation parameters and no configuration, it does not need to include an HTML fragment.

The Plugin SDK API provides several Essentials-specific directives for use in HTML fragments. The table below summarizes these directives. For more details, review the AngularJS code in the Plugin SDK's META-INF/resources/dashboard/api/directives.js.

DirectiveDescription
<essentials-simple-install-plugin>Renders a form to specify installation parameters for the plugin. Requires a plugin ID. Optionally, the fragment can indicate whether the plugin has sample data or extra templates to display the relevant input fields. See the installation parameters section for details.
<essentials-cms-document-type-deep-link>Renders a link to the CMS document type editor for a specific document type. Specify the document type and a label for the link.
<essentials-draft-warning>Displays an alert box listing document types currently in draft mode (being edited in the CMS document type editor). Document types should not be edited in both CMS and Essentials simultaneously. This directive does not require parameters.

The following example shows a plugin HTML fragment that renders the installation form, allowing the user to specify whether to install sample data. No extra templates are available in this example.

<div ng-controller="myPluginCtrl"> <essentials-simple-install-plugin plugin-id="myPluginId" has-sample-data="true"> </essentials-simple-install-plugin> <button ng-click="getMyStuff()">Load data</button> <pre>{{ data | json }}</pre> </div>

The Essentials Dashboard application uses bootstrap-like styling.


Part B — XM 17.0.0 and later (Angular Dashboard and iframe bridge)

From XM 17.0.0, first-party Essentials plugins increasingly ship as Angular components embedded in the Dashboard. Additional plugins (for example customer JARs) that are not wired into the Dashboard code use static HTML (and optional CSS/JS) under the same web-fragment paths, loaded inside an iframe, and communicate with the host through EssentialsPluginSdk.connect().

When is the iframe shown?

For a given plugin descriptor:

  • Bloomreach built-ins — plugins that have dedicated Angular components in the Dashboard do not use this iframe path; the Dashboard renders those components directly.
  • Your plugin — set hasConfiguration to true if the plugin provides a configuration UI that should load in the iframe using the default URL convention (below).
  • customUiUrl — optional. If set, the Dashboard loads that URL in the iframe instead of the convention path.
    • Must be same-origin: either an absolute path on the Essentials webapp (for example /essentials/custom/my-plugin.html) or an http/https URL whose origin matches the Dashboard. Cross-origin URLs are not supported in this version.

If customUiUrl is omitted and the Dashboard chooses the iframe for your plugin, the default document URL is:

{essentialsContextPath}/{type}/{pluginId}/{pluginId}.html

Example: Essentials mounted at /essentials, feature myPluginId:

/essentials/feature/myPluginId/myPluginId.html

Tools: third-party tool plugins need a resolvable iframe URL (customUiUrl and/or hasConfiguration with the conventional HTML), or the Dashboard cannot show your UI for that tool.

Packaging

Unchanged in principle: place HTML and supporting assets under:

src/main/resources/META-INF/resources/{type}/{pluginId}/

Reference CSS and JS with paths relative to that HTML file. Essentials still expects each plugin JAR to include a META-INF/web-fragment.xml file. For details on icons and images, refer to the Plugin Descriptor.

Essentials Plugin SDK (browser script)

The Dashboard serves a bundled script for iframe pages:

{essentialsContextPath}/sdk/essentials-plugin-sdk.js

From the conventional HTML path …/{type}/{pluginId}/{pluginId}.html, a typical script tag is:

<script src="../../sdk/essentials-plugin-sdk.js"></script>

The global EssentialsPluginSdk exposes:

EssentialsPluginSdk.connect()

It returns a Promise that resolves to an API object with methods that mirror the legacy AngularJS services in a promise-based form:

MethodDescription
getRestBaseUrl()Resolves to the base URL for plugin dynamic REST endpoints (for example {contextPath}/rest/dynamic when the Dashboard REST API is under {contextPath}/rest). Append your plugin-specific segment when calling your dynamic REST resource.
getPlugin(id)GET plugin descriptor for the given id.
getProjectSettings()GET project settings.
getContentTypes()GET document types (same general contract as the legacy content-type service).
getContentTypeInstances(jcrType)GET instances for a JCR type name (for example namespace:documenttype).
getTemplateQueries()GET template queries.
install(pluginId, params?)POST install for the plugin; params is an optional object for installation options.
navigate(path)Client-side navigation in the Dashboard Angular router. Only internal application paths are allowed; the host validates the path (must start with /, not //).

Example — minimal HTML and script

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>My plugin UI</title> <script src="../../sdk/essentials-plugin-sdk.js"></script> </head> <body> <button type="button" id="load">Load plugin info</button> <pre id="out"></pre> <script> (function () { var out = document.getElementById('out'); EssentialsPluginSdk.connect().then(function (api) { document.getElementById('load').onclick = function () { api.getPlugin('myPluginId').then(function (data) { out.textContent = JSON.stringify(data, null, 2); }); }; }).catch(function (e) { out.textContent = 'Connect failed: ' + e; }); })(); </script> </body> </html>

connect() retries briefly if the iframe loads before the host finishes registering the bridge; if it still fails, handle the rejected Promise (for example show an error in the iframe).

Back-end REST

The REST surface used by the Dashboard (plugins list, install, project settings, documents, dynamic plugin endpoints) is conceptually the same as before. Prefer calling it through the bridge from the iframe so authentication, cookies, and context paths stay aligned. Avoid crafting ad hoc REST URLs inside the iframe unless you deliberately align sessions, CORS, and paths yourself. See also Plugin Back-End.

AngularJS directives and the simple install form

Legacy directives (essentials-simple-install-plugin, and so on) are not available inside arbitrary iframe HTML. For installation-parameter flows, build the equivalent controls in your page and call install() through the SDK, or follow the plugin installation documentation for feature flows.


Summary

EraDashboardCustomer plugin UI
Before 17.0.0AngularJShippo.essentials controllers, web-fragment assets, Plugin SDK AngularJS services and directives.
17.0.0+AngularWeb-fragment assets and essentials-plugin-sdk.js with EssentialsPluginSdk.connect(); optional customUiUrl (same-origin only).

Further reading

Share Feedback
Page: /build/plugins/core-plugins/plugin-front-end
Section: Build
Category *