Table to div layout migration

This is documentation for a new feature in Jenkins core. See JENKINS-56109: Change Jenkins configuration UI from tables to divs for details.

Jenkins core changed its form layout from <table> to <div> in 2.264 (weekly) and 2.277.1 (LTS). Jenkins 2.263.x (LTS) releases did not change their form layout from <table> to <div>.

All core taglibs and views were updated in jenkinsci/jenkins#3895 as part of JENKINS-56109.

The vast majority of plugins do not require any changes at all because they use the standard Jelly tags in Jenkins for their forms, such as <f:entry>, <f:textbox>, and <f:checkbox>.

Debugging

If you are experiencing configuration form problems (e.g., form controls not working, the save button not working, etc.):

  1. Verify that you followed the instructions in the Jenkins 2.277.1 upgrade guide, including updating plugins after installing Jenkins 2.277.1.

  2. Refer to the known broken plugins dashboard; if you are using a plugin that is known to be broken, disable it and upvote the issue.

  3. Disable any plugins that are no longer in use, particularly if those plugins are no longer distributed on the Jenkins update site (including Team Foundation Server and Perforce).

Identifying the broken plugin

If the problem persists, perform bisection to identify the broken plugin.

  1. If you are uncomfortable using your production Jenkins installation, set up a minimal Jenkins installation:

    JENKINS_HOST=username:password@myhost.com:port
    curl -sSL "http://$JENKINS_HOST/pluginManager/api/xml?depth=1&xpath=/*/*/shortName|/*/*/version&wrapper=plugins" | perl -pe 's/.*?<shortName>([\w-]+).*?<version>([^<]+)()(<\/\w+>)+/\1 \2\n/g'| sed 's/ /:/' | cut -d ':' -f 1 | sort > plugins.txt
    wget https://github.com/jenkinsci/plugin-installation-manager-tool/releases/download/2.9.0/jenkins-plugin-manager-2.9.0.jar
    wget https://get.jenkins.io/war-stable/2.277.1/jenkins.war
    export JENKINS_HOME=~/.jenkins-tables-to-div
    java -jar jenkins-plugin-manager-2.9.0.jar -f plugins.txt -d $JENKINS_HOME/plugins --war jenkins.war
    java -jar jenkins.war
  2. Create a "freestyle" job to reproduce the issue.

  3. Generally disable plugins in groups of 10, recording which plugins you have disabled.

  4. Restart Jenkins.

  5. If the problem persists, keep disabling plugins.

  6. Once the problem is resolved, enable plugins one at a time to identify the broken plugin.

Reporting issues

When reporting an issue, include the following information:

  1. Provide the complete list of installed plugins as suggested in the bug reporting guidelines.

  2. Provide a screenshot.

  3. Provide steps to reproduce the problem on a minimal Jenkins installation; the scenario should fail when the broken plugin is enabled and pass when the broken plugin is disabled.

  4. Use the tables-to-divs-regression label.

Examples of area which may require changes

Below are some areas that may require you to adjust the form layout or JavaScript in your plugin:

  • Adding td / tr elements directly instead of using the f:entry tag, e.g. config-rotator-plugin#2

  • Custom JavaScript that is brittle to the Jenkins form UI layout. We’ve done our best to introduce shims, to not cause breakage here, but if you have written JavaScript that is reliant on the DOM structure you may need to make adjustments, take a look at the JavaScript changes in jenkins#3895.

  • Forking jelly taglibs from core and extending them, e.g. multiple-scms-plugin#25, it would be good to contribute fixes or enhancements to core rather than doing this where possible.

  • Using tables in the plugin for layout, e.g. jenkins-artifactory-plugin#266 and matrix-auth-plugin#83.

Maintaining support for tables and div layout

Maintaining such support is preferred where it is easily possible, to allow plugins to be updated and used on Jenkins deployments with older core versions (including current LTS 2.263.x at the time of this writing).

There is a jelly property set on Jenkins instances that use div’s for form layout called divBasedFormLayout, so you can adapt your plugin UI based on the presence of this property.

Note: This property is only set if the form tag uses the f:form jelly tag, and not the HTML form tag, this will be done automatically for you in form sections but not in actions or custom views.

Jelly example:

<j:jelly xmlns:j="jelly:core" xmlns:d="jelly:define" xmlns:local="local">
  <d:taglib uri="local">
    <d:tag name="blockWrapper">
          <j:choose>
              <j:when test="${divBasedFormLayout}">
                  <div>
                      <d:invokeBody/>
                  </div>
              </j:when>
              <j:otherwise>
                  <table style="width:100%">
                      <d:invokeBody/>
                  </table>
              </j:otherwise>
          </j:choose>
      </d:tag>
  </d:taglib>

  <local:blockWrapper>
  ...
  </local:blockWrapper>
</j:jelly>

This will use a table on Jenkins instances that don’t have divBasedFormLayout and will use a div when it is set.

Note: You will likely need more tags to adapt the tr and td tags to divs see multiple-scms-plugin#25 for a full example, or notification-plugin#40 for an even more extensive example of different wrapper types (note they are shipped in separate files, included from the jelly files to edit with references like xmlns:p="/lib/notification" with a path part relative to src/main/resources/ directory).

Groovy example:

blockWrapper {
    p('Hello, World!')
}

def blockWrapper(Closure closure) {
    if (context.getVariableWithDefaultValue("divBasedFormLayout", false) == true) {
        div() {
            closure.call()
        }
    } else {
        table(style: "width: 100%") {
            closure.call()
        }
    }
}

I still need more help?

Contact the UX sig on Gitter.