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.
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>
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>
-
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.
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.
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.
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.
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:
<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>
-
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.
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.