Skip to content

Template Custom UI

gmarjoram edited this page Oct 8, 2021 · 35 revisions

By default, the user interface (UI) for configuring a toolchain service is automatically generated based on the properties specified in the service's JSON schema. The default UI is very simple: properties of type string are rendered as text input fields, `Boolean value as checkboxes, and so on.

To override the default UI, the template author can provide a JSON file containing a custom UI. The custom UI format is essentially JSON Schema augmented with additional JSON Form properties. These additional properties control how the schema is rendered visually as input fields.

The best way to demonstrate this is with a walkthrough of the sections of a custom UI JSON file.

For reference, here is a complete custom UI file used to configure a pipeline service by collecting the region, org, space and app name.

Annotated example

This section provides an annotated example of a custom UI.

Boilerplate

This boilerplate identifies the custom UI as JSON Schema.

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    ....

Messages

Refers to a locales file providing keys and translated strings for different languages. The i18n reference gets resolved to the keys and their strings in the client's preferred locale, allowing field names and labels to be translated.

See the Template-File-Format#messages-section for a complete explanation of how the messages section works.

    "messages": {
        "$i18n": "locales.yml"
    },

Optional metadata

Title, description and long description. The long description string is rendered in the UI. Title and description are not currently displayed.

    "title": "Sample Deploy Stage"
    "description": "sample toolchain"
    "longDescription": "The Delivery Pipeline automates continuous deployment."

Properties

Specify the properties that you want returned from this UI. The property's name (prod-region, prod-organization, and so on) allows it to be referenced from the form section.

    "type": "object",
    "properties": {
        "api-key": {
            "description": "IBM Cloud Api Key"
            "type": "string",
            "validator": {
                "v-type": "api-key"
            }
        },
        "prod-region": {
            "description": "IBM Cloud region",
            "type": "string",
            "validator": {
                "v-type": "cf-region",
                "params": ["api-key"]
            }
        },
        "prod-organization": {
            "description": "IBM Cloud org",
            "type": "string",
            "validator": {
                "v-type": "cf-org",
                "params": ["prod-region"]
            }        
        },
        "prod-space": {
            "description": "IBM Cloud space",
            "type": "string",
            "validator": {
                "v-type": "cf-space",
                "params": ["prod-organization"]
            }
        },
        "prod-app-name": {
            "description": "App name description",
            "type": "string",
            "pattern": "\\S"
        }
    },

For an explanation of the validator object see Validator Object.

Required fields

Adds an asterisk after all field names (for properties of type string):

    "required": ["prod-region", "prod-organization", "prod-space", "prod-app-name"],

Form

The form definition consists of an array of supported UI Types (see list here). The order of elements is preserved when rendering the UI, so order matters. For a more advanced form layout, you can make use of the table element.

Each element in the form array can either:

  • reference an element in the schema by name:

    {
      "properties": {
         ....
         "prod-space": {
            "description": "IBM Cloud space",
            "type": "string",
             "validator": {
                 "v-type": "cf-space",
                 "params": ["prod-organization"]
             }
         }
         ....
      }
      "form": [
         ....
         "items": [
            "prod-space"
         ]
      ]
    }
  • Reference the name of a schema property in a key property

    {
      "properties": {
         ....
         "prod-app-name": {
            "description": "App Name",
            "type": "string",
            "pattern": "\\S"
         }
         ....
      }
      "form": [
         ....
         "items": [
            {
                "type": "text",
                "readonly": false,
                "title": "App Name",
                "key": "prod-app-name"
            }
         ]
      ]
    }
  • not reference any element in the schema, as a standalone type

    {
      ...
      "form": [{
         "type": "validator",
         "url": "/devops/setup/bm-helper/github_helper.html"
      }]
    }

Below is a typical example of a JSON form:

    "form": [{
            "type": "validator",
            "url": "/devops/validator/validator-v1.html"
        },
        {
            "type": "text",
            "readonly": false,
            "title": {
                "$ref": "#/messages/deploy.appName"
            },
            "key": "prod-app-name"
        },
        {
            "type": "password",
            "readonly": false,
            "title": {
                "$ref": "#/messages/deploy.apiKeyTitle"
            },
            "key": "api-key"
        },
        {
            "type": "table",
            "columnCount": 3,
            "widths": [
                "33%",
                "33%",
                "33%"
            ],
            "items": [{
                    "type": "label",
                    "title": {
                        "$ref": "#/messages/region"
                    }
                },
                {
                    "type": "label",
                    "title": {
                        "$ref": "#/messages/organization"
                    }
                },
                {
                    "type": "label",
                    "title": {
                        "$ref": "#/messages/space"
                    }
                },
                {
                    "type": "select",
                    "key": "prod-region"
                },
                {
                    "type": "select",
                    "key": "prod-organization"
                },
                {
                    "type": "select",
                    "key": "prod-space",
                    "readonly": false
                }
            ]
        }
    ]

Here is the screenshot of UI generated using deploy.json:

Rendered Object

UI elements

The UI elements used in OTC templates follows the JSON forms syntax.

You define a properties object that is made up of one or more property objects. Each one must be one of the types below.

Each property object contains the following elements:

In addition, an object can contain a special property enum to define a set of named constants. The details section for UI elements explains how this property is being rendered on the UI.

"type": {
   "description": "Choose the type of repository for your Artifactory integration.",
   "title": "Repository type",
   "type": "string",
   "enum": [
     "npm",
     "maven"
   ]
}

Here are the details for the UI elements that can be used as types in the form declaration.

Note: Some of the elements have additional properties that can be set.

boolean

Renders as a checkbox by default. Uses the title attribute for a label. If description text is provided, an info help icon will be provided. The form will respect the default value if set.

"has_issues": {
   "title": "Enable GitHub Issues",
   "description": "Select this check box to enable GitHub Issues for lightweight issue tracking.",
   "type": "boolean",
   "default": true
}

A toggle control can also be used to render a boolean type:

    "key-protect": {
      "title": {
        "$ref": "#/messages/wizard.vault.keyProtect.title"
      },
      "description": {
        "$ref": "#/messages/wizard.vault.keyProtect.description"
      },
      "type": "boolean",
      "display": {
        "component": "toggle",
        "style": "card"
      }
    }

Toggle

The card style renders a border around the toggle whereas standalone does not.

string

Renders as a textbox, title appears as label.

"repo_name": {
   "title": "New repository name",
   "type": "string"
}

password

Renders as a password textbox, title appears as label.

label

Renders a label, uses title for text. Note that you are allowed to use markdown in the title property.

"label": {
   "title": "List title",
   "description": "Type a title for your list.",
   "type": "string"
}

link

Renders a button, uses label for the text; Upon a click of button, it opens up a URL in a new tab.

{ 
  “type”: “link”,
  “label”: “Test Button”,
  “url”: “https://www.google.com/
}

object

Renders a group of related elements in a form. The following example shows how the labels object is rendered on the UI:

"labels": {
   "type": "object",
   "title": "GitHub Issues use labels to track attributes. You can select which Track & Plan Work attributes",
   "properties": {
      "type": {"title": "type", "type": "boolean"},
      "severity": {"title": "severity", "type": "boolean"},
      "state": {"title": "state", "type": "boolean"},
      "priority": {"title": "priority", "type": "boolean"},
      "resolution": {"title": "resolution", "type": "boolean"},
      "filedAgainst": {"title": "filedAgainst", "type": "boolean"},
      "tags": {"title": "tags", "type": "boolean"}
   }
}

Rendered Object

selectfieldset

Renders a dropdown menu by default, with options to select different UI components. UI components are a group of related elements. The following example shows how selectfieldset with options New, Fork, Existing and Clone is rendered on the UI, along with their respective UI components.

The form defines the selectfieldset as per the type property. It contains four UI components corresponding to the enum with four constants (new, fork, clone, and link) of the type property.

{
   "properties": {
      "repo_name": {
         "title": "New repository name",
         "type": "string"
      },
      "repo_url": {
         "title": "Source repository URL",
         "description": "Type the URL of the repository that you are forking, cloning, or linking to.",
         "type": "string"
      },
      "type": {
         "title": "Repository type",
         "type": "string",
         "enum": [
            "new",
            "fork",
            "clone",
            "link"
         ]
      },
      "private_repo": {
         "title": "Make this repository private",
         "description": "Select this check box to make this repository private.",
         "type": "boolean",
         "default": false
      },
      "has_issues": {
         "title": "Enable GitHub Issues",
         "description": "Select this check box to enable GitHub Issues for lightweight issue tracking.",
         "type": "boolean",
         "default": true
      },
      "enable_traceability": {
         "title": "Track deployment of code changes",
         "description": "Select this check box to track the deployment of code changes by creating tags.",
         "type": "boolean",
         "default": false
      }
   },
   "form": [
      ....
     {
        "type": "selectfieldset",
        "key": "type",
        "titleMap": {
           "new": "New",
           "fork": "Fork",
           "link": "Existing",
           "clone": "Clone"
        },
        "items": [
           {
              "type": "section",
	      "description": "Create an empty repository.",
	      "items": [
	         "repo_name",
	         "private_repo",
	         "has_issues",
	         "enable_traceability"
	      ]
           }, 
           {
              "type": "section",
              "description": "Fork the repository that is specified in the Source repository URL field.",
              "items": [
                 {
                    "type": "select",
	            "key": "repo_url",
	            "readonly": false
	         },
	         "enable_traceability"
              ]
           }, 
           {
              "type": "section",
              "description": "Clone the repository that is specified in the Source repository URL field.",
              "items": [
                 "repo_name", 
                 {
	            "type": "select",
	            "key": "repo_url",
	            "readonly": false
	         },
	         "private_repo",
	         "has_issues",
	         "enable_traceability"
              ]
          }, 
          {
             "type": "section",
             "description": "Link to the repository that is specified in the Source repository URL field.",
             "items": [
                {
                   "type": "select",
	           "key": "repo_url",
	           "readonly": false
                },
                "enable_traceability"
             ]
          }
       ]
    }
 ]
}

Selectfieldset with option clone

Selectfieldset with option Existing

Selectfieldset with option fork

Selectfieldset with option New

A tilegroup or radiogroup can be used instead of dropdown as the base component. To do this you must add a display.component property to the definition as follows:

     {
        "type": "selectfieldset",
        "key": "type",
        "display": {
           "component": "tilegroup"
        }
        "titleMap": {
           "new": "New",
           "fork": "Fork",
           "link": "Existing",
           "clone": "Clone"
        }
        ...

table

Renders a complex table layout. The following example shows a JSON form along with the rendered UI.

It contains three columns and the width of each column is also specified. The items property defines the UI elements of each column. The first three elements are part of the first column, the next three are a part of the second column, and the last three will go to the third column.

{
        "type": "table",
        "columnCount": 3,
        "widths": ["47%", "6%", "47%"],
        "items": [
            {
              "type": "label",
              "title": "Source Repository"
            },
            {
              "type": "label",
              "title": ""
            },
            {
              "type": "label",
              "title": {
                "$ref": "Target Repository"
              }
            },
            {
              "type": "text",
              "key": "catalog-api-repo_url"
            },
            {
              "type": "icon",
              "iconType": "right_arrow"
            },
            {
              "type": "text",
              "key": "catalog-api-repo_name"
            },
            {
              "type": "text",
              "key": "orders-api-repo_url"
            },
            {
              "type": "icon",
              "iconType": "right_arrow"
            },
            {
              "type": "text",
              "key": "orders-api-repo_name"
            },  {
              "type": "text",
              "key": "ui-repo_url"
            },
            {
              "type": "icon",
              "iconType": "right_arrow"
            },
            {
              "type": "text",
              "key": "ui-repo_name"
            }
        ]
      }

Custom Github

section

Renders a group of related elements in a form.

{
   "type": "section",
   "description": "Create an empty repository.",
   "items": [
      "repo_name",
      "private_repo",
      "has_issues",
      "enable_traceability"
   ]
}

notification

A notification renders a colourful information box in three possible styles - info, warning and error.

    {
      "type": "notification",
      "display": {
        "style": "warning",
        "title": {
          "$ref": "#/messages/wizard.evidence.cos.notification.title"
        },
        "subtitle": {
          "$ref": "#/messages/wizard.evidence.cos.notification.sutitle"
        },
        "showInAdvancedMode": true,
        "advancedModePosition": "bottom",
        "controlId": "cos-warning"
      }
    }

Notification

accordion

Renders a group of controls that will be initially hidden but can be shown when the user clicks on the parent control.

    {
        "type": "accordion",
        "title": "Application access details",
        "items": [{
            "type": "text",
            "readonly": false,
            "title": {
                "$ref": "#/messages/deploy.appName"
            },
            "key": "app-name"
        }, {
            "type": "password",
            "readonly": false,
            "title": {
                "$ref": "#/messages/deploy.apikey"
            },
            "key": "api-key"
        }]
    }

Child controls hidden:
Accordion closed

Child controls revealed:
Accordion open

radiogroup

Renders a set of options as radio buttons allowing the selection of one.

    {
        "type": "radiogroup",
        "key": "deploy-option",
        "title": "Deployment options:",
        "display": {
            "orientation": "horizontal"
        },
        "enum": [{
            "name": "Rolling",
            "value": "rolling"
        }, {
            "name": "Blue green",
            "value": "blue-green"
        }]
    }

Radiogroup

tilegroup

Renders a set of options as tile buttons allowing the selection of one.

    {
        "type": "tilegroup",
        "key": "deploy-option",
        "title": "Deployment options:",
        "display": {
            "orientation": "horizontal"
        },
        "enum": [{
            "name": "Rolling",
            "value": "rolling"
        }, {
            "name": "Blue green",
            "value": "blue-green"
        }]
    }

Tilegroup

info

Used to render static markdown.

    {
      "type": "info",
      "text": {
        "$ref": "#/messages/wizard.vault.info"
      }
    }

Clone this wiki locally