Skip to content

jenkinsci/data-tables-api-plugin

Repository files navigation

jQuery DataTables Jenkins Plugin

Jenkins GitHub Actions GitHub pull requests

Provides jQuery DataTables for Jenkins Plugins. DataTables is a plug-in for the jQuery Javascript library. It is a highly flexible tool, built upon the foundations of progressive enhancement, that adds all of these advanced features to any HTML table:

  • Previous, next and page navigation

  • Filter results by text search

  • Sort data by multiple columns at once

  • DOM, Javascript, Ajax and server-side processing

  • Easily theme-able

  • Mobile friendly

This plugin contains JS and CSS files of the latest DataTables release and corresponding Jenkins UI elements (Java data model). It also contains some additional DataTables plugins.

How to use the plugin

A common UI element to show plugin details is a table control. Most plugins (and Jenkins core) typically use plain HTML tables. However, if the table should show a large number of rows then using a more sophisticated control like DataTables makes more sense.

In order to use DataTables in a view there are two options, you can either decorate existing static HTML tables (see Tables with static HTML content) or populate the table content using Ajax (see Tables with dynamic model based content). Both option require that you add a maven dependency to your pom:

<dependency>
  <groupId>io.jenkins.plugins</groupId>
  <artifactId>data-tables-api</artifactId>
  <version>[latest version]</version>
</dependency>

Tables with static HTML content

The easiest way of using DataTables is by creating a static HTML table that will be decorated by simply calling the constructor of the datatable. This approach involves no special handling on the Java and Jelly side, so I think it is sufficient to follow the example in the DataTables documentation. Just make sure that after building the table in your Jelly file you need to decorate the table with the following piece of code:

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" >

  <st:adjunct includes="io.jenkins.plugins.jquery3"/>
  <st:adjunct includes="io.jenkins.plugins.data-tables"/>

  [...]

    <div class="table-responsive">
        <table
          class="table table-striped display" id="id">
            [...]
        </table>
    </div>

  [...]
  <script>
     $('#id').DataTable(); (1)
  </script>

</j:jelly>
  1. replace id with the ID of your HTML table element

In the Forensics plugin no such static table is used so far, but you can have a look at the table that shows fixed warnings in the warnings plugin to see how such a table can be decorated.

Tables with dynamic model based content

While static HTML tables are easy to implement, they have several limitations. So it makes sense to follow a more sophisticating approach. Typically, tables in user interfaces are defined by using a corresponding table (and row) model. Java Swing successfully provides such a table model concept since the early days of Java. I adapted these concepts for Jenkins and DataTables as well. In order to create a table in a Jenkins view a plugin needs to provide a table model class, that provides the following information:

  • the ID of the table (since there might be several tables in the view)

  • the model of the columns (i.e., the number, type, and header labels of the columns)

  • the content of the table (i.e. the individual row objects)

You will find an example of such a table in the Forensics plugin: here a table lists the files in your Git repository combined with the corresponding commit statistics (number of authors, number of commits, last modification, first commit). A screenshot of that table is shown in Dynamic Table in the Forensics plugin.

Table example
Figure 1. Dynamic Table in the Forensics plugin

In order to create such a table in Jenkins, you need to create a table model class that derives from TableModel. In Table model of the Forensics plugin a diagram of the corresponding classes in the Forensics plugin is shown.

Tabel model
Figure 2. Table model of the Forensics plugin

Table column model

This first thing a table model class defines is a model of the available columns by creating corresponding TableColumn instances. For each column you need to specify a header label and the name of the bean property that should be shown in the corresponding column (the row elements are actually Java beans: each column will show one distinct property of such a bean, see next section). You can use any of the supported column types by simply providing a String or Integer based column.

Table rows content

Additionally, a table model class provides the content of the rows. This getRows() method will be invoked asynchronously using an Ajax call. Typically, this method simply returns a list of Java Bean instances, that provide the properties of each column (see previous section). These objects will be converted automatically to an array of JSON objects, the basic data structure required for the DataTables API. You will find a fully working example table model implementation in the Git repository of the forensics plugin in the class ForensicsTableModel.

In order to use such a table in your plugin view you need to create the table in the associated Jelly file using the new table tag:

index.jelly
<j:jelly xmlns:j="jelly:core" xmlns:dt="/data-tables" >
    [...]
    <st:adjunct includes="io.jenkins.plugins.data-tables"/>

    <dt:table model="${it.getTableModel('id')}"/> (1)
    [...]
</j:jelly>
  1. replace id with the id of your table

The only parameter you need to provide for the table is the model — it is typically part of the corresponding Jenkins view model class (this object is referenced with ${it} in the view). In order to connect the corresponding Jenkins view model class with the table, the view model class needs to implement the AsyncTableContentProvider interface. Or even simpler, let your view model class derive from DefaultAsyncTableContentProvider. This relationship is required, so that Jenkins can automatically create and bind a proxy for the Ajax calls that will automatically fill the table content after the HTML page has been created.

If we put all those pieces together, we are required to define a model similar to the model of the Forensics plugin, that is shown in Jenkins reporter design - high level view of the model for reporter plugins.

Forensics view model
Figure 3. Jenkins reporter design - high level view of the model for reporter plugins

As already described in [jenkins-reporter-model] the plugin needs to attach a BuildAction to each build. The Forensics plugin attaches a ForensicBuildAction to the build. This action stores a RepositoryStatistics instance, that contains the repository results for a given build. This action delegates all Stapler requests to a new Stapler proxy instance so we can keep the action clean of user interface code. This ForensicsViewModel class then acts as view model that provides the server side model for the corresponding Jelly view given by the file index.jelly.

While this approach looks quite complex at a first view, you will see that the actual implementation part is quite small. Most of the boilerplate code is already provided by the base classes and you need to implement only a few methods. Using this concept also provides some additional features, that are part of the DataTables plugin:

  • Ordering of columns is persisted automatically in the browser local storage.

  • Paging size is persisted automatically in the browser local storage.

  • The Ajax calls are actually invoked only if a table will become visible. So if you have several tables hidden in tabs then the content will be loaded on demand only, reducing the amount of data to be transferred.

  • There is an option available to provide an additional details row that can be expanded with a + symbol, see warnings plugin table for details.

You can find several examples of Jenkins views that use jQuery in the Warnings Next Generation plugin and in the Forensics plugin.