Chapter 6. Improving The Upcoming UI [DRAFT]

Table of Contents

6.1. This is a DRAFT! Give your opinion!
6.2. Getting the skeleton for this lesson
6.3. Add a layout
6.3.1. Reminder about building and deploying
6.4. A brief interlude about development with Nuxeo
6.5. Adding An Icon
6.5.1. The deployment fragment
6.6. nuxeo.war
6.7. The big picture, again
6.8. Exercises

Objective: To understand how to customize the web user interface for a new document type and understand the relationship between the larger Nuxeo EP server UI and the UI of a particular document type.

I was taught that the way of progress was neither swift nor easy. Marie Curie, Polish/French Physicist, twice winner of the Nobel Prize (1867-1934)

6.1. This is a DRAFT! Give your opinion!

If you have any comments, questions, or general-purpose harassment you would like give us about this book, then please use the comment form at the bottom of each page! We promise that we will try to incorporate any feedback you give (minus the profanity, of course), will respond to your questions, and credit you appropriately in section 4 below.

6.2. Getting the skeleton for this lesson

As in the last lesson, we have a prepared a skeleton for you to start from for this lesson. This skeleton contains all the code from the last lesson so we can improve the look of our new document type. To retrieve, unpack and build an eclipse project, use a set of commands like this:

[~]
$ cd /nuxeo/workspace/

[/nuxeo/workspace]
$ svn export http://svn.nuxeo.org/nuxeo/sandbox/iansmith/book/lesson-basic-ui/

[/nuxeo/workspace]
$ cd lesson-basic-ui

[/nuxeo/workspace/lesson-basic-ui]
$ mvn eclipse:eclipse

Note that we are using the same eclipse workspace as in the previous lesson, /nuxeo/workspace, and that we have created another project for Eclipse to use, this time called lesson-basic-ui. Also as before, you will need to import the project into your eclipse workspace and then verify in eclipse that your source code path is free of Maven-generated excess; you should have only src/main/java and src/test/java in your source code path.

6.3. Add a layout

We will start updating the user interface by adding the ability to actually use the fields we so carefully added in the previous lesson. To do this, we are going to use another extension point, layout, in the WebLayoutManager component. The following content should be placed in a file called layout-contrib.xml in the OSGI-INF directory.

<component name="org.nuxeo.book.component.layout">

  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="layouts">
    
    <templates>
        <template mode="any">/layouts/layout_default_template.xhtml</template>
    </templates>

    <layout name="upcoming">
      <rows>
        <row>
          <widget>upcoming_when</widget>
        </row>
        <row>
          <widget>upcoming_who</widget>
        </row>
        <row>
          <widget>upcoming_howmuch</widget>
        </row>
      </rows>


      <widget name="upcoming_when" type="datetime">
        <labels>
          <label mode="any">When?</label>
        </labels>
        <translated>false</translated>
        <fields>
          <field>up:occursOn</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
      <widget name="upcoming_who" type="text">
        <labels>
          <label mode="any">Who?</label>
        </labels>
        <translated>false</translated>
        <fields>
          <field>up:presenter</field>
        </fields>
      </widget>
      <widget name="upcoming_howmuch" type="text">
        <labels>
          <label mode="any">How much to get in?</label>
        </labels>
        <translated>false</translated>
        <fields>
          <field>up:admissionPrice</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
    </layout>

  </extension>

</component>

This is a much more substantive contribution than the prior ones have been. This contribution can be broken into three parts: the top section, surrounded by the templates tag, the middle section inside the rows tag, that defines where the items are laid out on the screen, and the bottom part, inside each of the three widget tags, which defines what is going to be laid out. We are going to defer discussing the first part of the contribution until a later time in this lesson.

The middle section defines three rows, each one with a widget in it. You can place all the widgets in one row if you want to see what happens; we just felt this was the most appropriate for our data. (If you want to use two rows and make things line up, this <widget/> can be used as a spacer.) The values in the middle section's widget nodes, such as upcoming_who, must match up with existing widget definitions (defined elsewhere in Nuxeo) or those in the remainder of the file. In our case, all three widgets we are using are defined in the lower section. We have prefixed our widgets with the the schema name of the of the data they display because we want to be sure that these are unique. It is possible to share widget definitions between layouts by using the same widget names, so it is advised that you take steps to make your widget names unique if you want to be sure.

The latter section of this contribution defines our three new widget types, one for each field in our upcoming schema. Roughly, a widget definition in this file tells Nuxeo's web interface what type of objects you want on screen. So, looking at the upcoming_when widget definition you can see that the "type" is an object capable of displaying the date and time: this will result in a calendar plus a spot to enter the time of day. Similarly, upcoming_who widget uses an object capable of entering text. Strangely, the upcoming_howmuch widget does too! This is because the widget type describes only what visual form the user will see on the screen; it is unrelated to the type of data in the schema. You should notice that each widget says what fields of the schema data in corresponds to, one widget for each field in this example. The definition of upcoming_howmuch says that it will use a text object on screen, yet the schema definition (upcoming.xsd) says that the field up:admissionPrice is a floating point number! The nuxeo server will take care of doing most of these transformations from the display representation to the stored representation for you without any help. You can also add your own, as we will see in a future lesson.

Each widget definition above declares a label and some text. This is the text that will be shown to the user just beside the value of the field in the schema. Just after the label definition, we have set <translated>false</translated> because we want the text used literally. In the next lesson, you will see how to change a layout definition to work correctly in multiple languages.

The definitions of the first and last widgets, upcoming_when and upcoming_howmuch have a properties section. There a number of properties that can be set on a widget, but we will limit ourselves to just discussing two key issues. Obviously, the first and third widget (which work out to the fields occursOn and admissionPrice on the schema) are required to be present... but under what circumstances? The attribute widgetName and its value, edit, indicate that these fields are required in when the document's meta-data can be changed, such as when you create a document or when you modify the meta-data via the web UI's Modify tab. Similarly the label tag has the attribute mode which is also referring to which state the widget is currently in; all our labels above use the mode any to indicate we always want the same text displayed. One could, for example, set the label to be "Please Enter a Date" for mode edit and "Date" for mode view. The full list of widget modes is edit, view, any (to indicate both edit and view), and hidden. The last of these is to allow a widget to be defined, but not displayed.

After adding this new contribution, do not forget to update your manifest file. Further, this new extension means that we will now need another bundle to be required so we can have access to the WebLayoutManager. Here is the updated MANIFEST.MF.

Manifest-Version: 1.0
Bundle-ManifestVersion: 1
Bundle-Name: lesson4 project
Bundle-SymbolicName: org.nuxeo.book.upcoming;singleton:=true
Bundle-Version: 0.0.1
Bundle-Vendor: YOU!
Nuxeo-Require: org.nuxeo.ecm.core,
 org.nuxeo.ecm.core.schema,
 org.nuxeo.ecm.webapp.core
Nuxeo-Component: OSGI-INF/schema-contrib.xml,
 OSGI-INF/doctype-contrib.xml,
 OSGI-INF/layout-contrib.xml,
 OSGI-INF/ui-contrib.xml

Warning

Again, the ordering of contributions is tricky in Nuxeo-Component because there is a dependency between the layout contribution and the UI contribution so our new layout contribution must come first.

We now need to inform Nuxeo that our document type, Upcoming, wants to use the layout we have constructed (sadly, also customarily called "upcoming") as part of its display. This is done by replacing the previous list of layouts with the upcoming layout; this controls which layout or layouts is used to display or edit the meta-data of the document type Upcoming. Below is a snippet from the ui-contrib.xml file showing the change:

    <type id="Upcoming" coretype="Upcoming">
      <label>Upcoming Event</label>
      <icon>/icons/upcoming.png</icon>
      <default-view>view_documents</default-view>
      <layouts mode="any">
        <layout>upcoming</layout>
      </layouts>
    </type>

The result of all this work can be seen in this screen capture of creating a new upcoming document:

The last when and how much fields have a red asterisk because they are required. Clicking on the grey button to the right of "When" opens a calendar widget.

6.3.1. Reminder about building and deploying

If you have forgotten, you should build your now updated version of lesson-simple-ui with mvn clean install in the lesson-basic-ui directory. When it completes successfully, you will find the file lesson-basic-ui.0.0.1.jar in the target subdirectory. You should make sure your Nuxeo server is not running, then copy this jar file into the plugins subdirectory inside the nuxeo.ear subdirectory of your server, this would be /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear if you have been following our instructions . Restart your server and try logging in and creating a new Upcoming document!

6.4. A brief interlude about development with Nuxeo

In general, it is bad to have your Nuxeo system have multiple different definitions for a single document type or schema while you are doing development. When this happens, you are likely to experience strange results from using the system. This also happens when you end up with multiple layout or ui contributions to the same point, but it is easier to see what is happening and realize you are running the older version of the code!

If you have not configured any database system into your nuxeo installation-and we haven't covered that yet!-you will probably want to use commands like this to destroy the databases maintained by Nuxeo like this:

[~]
$ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/data

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/data]
$ rm -rf h2/nuxeo.* hypersonic/* derby/*

Warning

Do not do this if you have content in your database you want to keep! This will also revert your Administrator password back its default setting of "Administrator". Where is administrator password stored? Does it really reset?

However, during normal software development you will find that a common sequence is to kill the running server, make some changes to your source code in Eclipse, rebuild your jar file, copy the jar file into the plugins directory, destroy the old databases, destroy the old logs, and restart the server. To make this easier, one of the authors uses multiple tabs in a shell window like this:

This makes it a bit easier to complete any of the steps listed since hitting the up arrow once or twice in any tab gets the desired effect.

Above we suggested that it is a good idea to clear the old logs (/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/logs) before any run. We suggest this because we have found it useful to turn the logging up to the maximum (DEBUG level, as shown in a previous lesson) and then use grep to find the lines of interest in the logs. Here is any example from the log tab above:

[~]
$ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/log

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/log]
$ cat *.log | grep -i upcoming
2009-01-25 21:17:12,807 INFO  [org.nuxeo.runtime.jboss.deployment.preprocessor.DeploymentPreprocessor] 
 Running custom installation for fragment: org.nuxeo.book.upcoming
2009-01-25 21:17:47,785 INFO  [org.nuxeo.osgi.BundleRegistry] Registering resolved bundle: 
 org.nuxeo.book.upcoming

This is easy way to find errors that may have occurred as the system was booting or as your bundle was being loaded.

6.5. Adding An Icon

Giving the Upcoming document its own icon is easy-and visually pleasing so the Upcoming object lines up when showing the list of document types that can be created. You can use any image you want so long as it is in any image format that a web browser understands such as jpeg, gif, or png. If you want to your icon to line up with others, use a 16 pixel by 16 pixel icon.

Start by creating a new subdirectory of src/main/resources in your Eclipse project called nuxeo.war. This will be a peer of the OSGI-INF directory both in Eclipse and in the final bundle file. Inside nuxeo.war create a subdirectory icons. Place your graphics file in this directory and then change the start of your ui-contrib.xml file to point to it with an icon tag like your existing label tag. Here is a snippet from the improved ui-contrib.xml:

    <type id="Upcoming" coretype="Upcoming">
      <label>Upcoming Event</label>
      <icon>/icons/upcoming.png</icon>
      <default-view>view_documents</default-view>

Note

The icon path should start with a '/' character.

6.5.1. The deployment fragment

In the prior lesson we noted that the deployment fragment can be used to help "deploy" resources that are part of your program into the Nuxeo EP server. Now you have a need for this functionality, since you are going to end up with your icon file inside your bundle file. Here is the updated deployment-fragment.xml that copies all the contents of the nuxeo.war part of your project into Nuxeo server.

<fragment>

  <extension target="application#MODULE">
    <module>
      <java>${bundle.fileName}</java>
    </module>
  </extension>

  <install>

    <!-- Unzip the contents of our nuxeo.war into the server -->
    <unzip from="${bundle.fileName}" to="/">
      <include>nuxeo.war/**</include>
    </unzip>

  </install>


</fragment>

Note

The notation nuxeo.war/** means to include all the files in the directory nuxeo.war in your bundle and recursively copy the contents of all subdirectories. Nuxeo deployment fragments use the same notation for included and excluded files as the Ant and Maven build tools, if you are familiar with those.

After running through the steps of section 2.1 again, when you create a new document via the web interface to Nuxeo you should see a set of document types like this, but with your chosen image:

6.6. nuxeo.war

If you studied the deployment fragment above carefully, you would have noticed that target of the unzip operation is the directory /, yet if you look in your filesystem root you will not find your icons directory! The / above is relative to the nuxeo.war directory inside the nuxeo.ear portion of your server. Here is a snippet from that directory:

[~]
$ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war]
$ ls
create_document.xhtml                        members_management.xhtml
create_domain.xhtml                          META-INF
create_file.xhtml                            nuxeo_error.jsp

[... many more lines elided...]

The nuxeo.war directory contains all the web resources for the Nuxeo server. One of the many subdirectories of nuxeo.war is icons, where the system icons are held. Thus, our deployment fragment puts our upcoming icon in among all the other icons and this is normal practice for plugin developers:

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war]
$ cd icons/

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/icons]
$ ls u*
unchecked.gif  unknown.png  upcoming.png  user.gif  user_go.png

Returning to our discussion of the layout contribution above in section 2 (layout-contrib.xml) it may now be more clear why we waited to explain the top section of the file. The layout contribution tells Nuxeo to use a template (again, starting with /) /layouts/layout_default_template.xhtml and it should not be a surprise where this file is actually located:

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war]
$ cd layouts

[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/layouts]
$ ls
layout_default_template.xhtml

6.7. The big picture, again

A crucial idea of the Nuxeo system, we reiterate, is that Nuxeo's ECM functionality is provided by bundles that are "just like yours" and there are no special, hidden mechanisms exploited by the Nuxeo "system" as you see it through the web interface. As an example, the Note document type you can create via the web UI, uses exactly the same extension points and xml configuration that we have walked through for building the Upcoming document type (although Note exploits a bit more of the functionality!). As you can see from the nuxeo.war directory, you can even re-purpose the web resources that are used to implement the Nuxeo ECM functionality.

6.8. Exercises

If you would like to practice more with the concepts in this lesson, here are some suggested exercises.

  1. Using chapter 8 of the Nuxeo Developer's Documentation (http://doc.nuxeo.org/5.2/books/nuxeo-book/html/) change the ui for Upcoming documents:

    • Use a non-editable label to display the date and time for the field occursOn when the user cannot edit the data. The user interface should continue to use the calendar widget in situations where the user can change the value of the field. It is ok if the display in non-editable situations only shows the date of the event, not the date and time.

    Solving this without duplication of code (a big no-no!) requires the use of an additional extension point in your layout-contrib.xml.

  2. If you create a document of type Upcoming now, you will notice that it is displayed with your icon but with a rather ugly title:

    This is because the title is not being set when you create a document (dublincore:title), so Nuxeo defaults to chosing a title which is a unique identifier for the document. Correct this by adding back in the support for the layout type heading.