Web UI

Web UI Customization Tutorial

Updated: December 2, 2024

In this tutorial we'll guide you through customizing Nuxeo Web UI and deploying your customization. We're going to address to different customization approaches: by overriding dynamic layouts and via slots. In the former case we'll edit a view layout for a popular document type, whereas in the latter we're going to contribute a new Document Action.

Setup

Before we start customizing the Web UI we need to create an empty Nuxeo bundle. Make sure you go through the following resources to understand how to create and deploy a bundle:

Creating an Empty Bundle

To make our life easier, we'll use Nuxeo CLI. Please make sure to follow the respective guide before proceeding.

Let's start by installing Nuxeo CLI and scaffolding a new bundle:

$ npm install -g nuxeo-cli
$ mkdir -p nuxeo-customization-sample && cd $_
$ nuxeo bootstrap

Nuxeo CLI will then ask you a few questions (for which the default values will suffice). We'll assume that the parent ID is nuxeo-customization-sample, the project ID is nuxeo-customization-sample-core and the project version is 1.0-SNAPSHOT, and that the following folder hierarchy was generated:

nuxeo-customization-sample
├── nuxeo-customization-sample-core
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   └── resources
│       └── test
│           ├── java
│           └── resources
└── pom.xml

Our customizations will be contributed to the nuxeo-customization-sample-core/src/main/resources folder, hereafter referred to as just the resources folder.

Building and Deploying

We must now create the folder in our bundle under which our customized Web UI content will be placed: resources/web/nuxeo.war/ui/. In order to instruct this content to be copied when the server is run, we must add a new deployment-fragment.xml file to resources/OSGI-INF:

resources/OSGI-INF/deployment-fragment.xml

<?xml version="1.0"?>
<fragment version="1">

  <require>org.nuxeo.web.ui</require>

  <install>
    <unzip from="${bundle.fileName}" to="/" prefix="web">
      <include>web/nuxeo.war/**</include>
    </unzip>
  </install>

</fragment>

Our bundle can be built simply by running mvn install, and it can be deployed by copying the resulting jar file, in this case nuxeo-customization-sample-core/target/nuxeo-customization-sample-core-1.0-SNAPSHOT.jar, to $NUXEO_HOME/nxserver/bundles. For more information about building and deploying bundles, please check the documentation.

Contributing Dynamic Layouts

One of the most common cases of customization of the Web UI is to contribute new or modify already existing dynamic layouts. For example, one might want to change the layout to create a user or add layouts for a new document type. In this section we are going to change the view layout for the File document type, so that it displays the file's blob mime type.

To override or contribute new layouts for a document type, we must add a file with the name of the layout that needs to be created or overridden to the document/{type} folder. In this case, we need to create the folder resources/web/nuxeo.war/ui/document/file and take the original nuxeo-file-view-layout.html and add a new div element to hold some file details, specifically the blob's mime type, which is the piece of information we wanted to add:

resources/web/nuxeo.war/ui/document/file/nuxeo-file-view-layout.html

<nuxeo-card heading="Details">
  <div>
    <b>Mime Type: </b>
    <span>[[document.properties.file:content.mime-type]]</span>
  </div>
</nuxeo-card>

Extending the Web UI
Please check the deployment documentation for more information on how to extend the Web UI.

You can now build your bundle and deploy it. Then, by navigating to a file that contains a blob, you'll see its mime type.

Contributing to a Nuxeo Slot

Nuxeo Slots are an important mechanism to extend Nuxeo Web UI. Here we're going to contribute a new action to the DOCUMENT_ACTIONS slot, which will be displayed whenever a user browses to a document.

Nuxeo Slots
Please refer to the Nuxeo Slots documentation for information about slots and how to contribute to them.

Our action will consist of an element that receives a document and that is composed of a button which, when clicked, displays a popup with the list of facets of the document. So, let's start by creating a folder inside resources/web/nuxeo.war/ui (e.g. resources/web/nuxeo.war/ui/sample/) and add a new element to it named my-document-action, which will hold a button, a tooltip for that button, and a dialog:

resources/web/nuxeo.war/ui/sample/my-document-action.html

<dom-module id="my-document-action">
  <template>
    <style>
      :host {
        display: inline-block;
      }
    </style>

    <template is="dom-if" if="[[_isAvailable(document)]]">
      <paper-icon-button icon="icons:extension" on-tap="_toggleDialog" noink></paper-icon-button>
      <paper-tooltip>Display Facets</paper-tooltip>
    </template>

    <paper-dialog id="dialog" with-backdrop>
      <h2>Facets</h2>
      <div>
        <ul>
          <template is="dom-repeat" items="[[document.facets]]" as="facet">
            <li>[[facet]]</li>
          </template>
        </ul>
      </div>
      <div class="buttons">
        <paper-button dialog-dismiss>Close</paper-button>
      </div>
    </paper-dialog>

  </template>

  <script>
    Polymer({
      is: 'my-document-action',
      properties: {
        document: Object
      },

      _isAvailable: function(document) {
        return !!document;
      },

      _toggleDialog: function() {
        this.$.dialog.toggle();
      }

    });
  </script>

</dom-module>

Our new element must now be added to the DOCUMENT_ACTIONS slot. To achieve this, we must create a another file (e.g. sample.html) that will import my-document-action and declare it in a template inside a nuxeo-slot-content:

resources/web/nuxeo.war/ui/sample/sample.html

<link rel="import" href="my-document-action.html">

<nuxeo-slot-content name="mySampleAction" slot="DOCUMENT_ACTIONS">
  <template>
    <my-document-action document="[[document]]"></my-document-action>
  </template>
</nuxeo-slot-content>

Note that the document property of our element is bound to the document property provided by the action context. For more information about what property are available in this slot, please check the DOCUMENT_ACTIONS documentation .

From within a bundle, content for a Nuxeo Slot must be contributed as a WebResource. Therefore, we must add a new xml file to the resources/OSGI-INF folder, contributing sample.html as a web resource:

resources/OSGI-INF/sample-webresources-contrib.xml

<?xml version="1.0"?>

<component name="org.nuxeo.ecm.distribution.sample.resources.contrib">

  <require>org.nuxeo.web.ui.resources</require>

  <extension target="org.nuxeo.ecm.platform.WebResources" point="resources">
    <resource name="sample.html" type="import" shrinkable="false">
      <uri>/ui/sample/sample.html</uri>
    </resource>
  </extension>

  <extension target="org.nuxeo.ecm.platform.WebResources" point="bundles">
    <bundle name="web-ui">
      <resources append="true">
        <resource>sample.html</resource>
      </resources>
    </bundle>
  </extension>

</component>

Finally, we must add the aforementioned contribution file, as a nuxeo component, to the end of the manifest file:

resources/META-INF/MANIFEST.MF

...
Nuxeo-Component: OSGI-INF/sample-webresources-contrib.xml

And we're good to go! You just need to build and deploy your bundle and we'll now have a new action to display the facets of any document.