# PDA Plugin Technical Guide

This page explores PDA plugin structure and functionality in greater detail. The sample code and linked resources instruct the user in the versatility and usability of:

  • Task Forms
  • Widgets
  • Code Style
  • Sonar

# Task Forms

Widgets employ JSON schema to dynamically create any forms they contain. The JSON schemas are converted into React components using the react-jsonshema-form library. Entando's initial implementation utilizes Material UI components derived from the Material UI theme library (rjsf-material-ui) as a baseline, and includes templates, widgets and fields (react-jsonshema-form terms for forms components) that are specific to Entando.

This section will introduce the basic form configuration, but if you would like to learn more, please refer to the react-jsonshema-form documentation (opens new window).

The themed JSON Form is created using the withTheme() method from the react-jsonschema-form package:

import { withTheme } from 'react-jsonschema-form';
import { Theme as MuiRJSForm } from 'rjsf-material-ui';

const JSONForm = props => {

  const ThemedForm = withTheme(MuiRJSForm);

  // ...

  return (
    <ThemedForm
    schema={formSchema}
    uiSchema={uiSchema}
    {...customTemplates}
    widgets={customWidgets}
    formData={formData}
    onSubmit={e => onSubmitForm(e)}
    >
  );
};

export default JSONForm;

A form schema provides the JSON definition of the form’s structure and is mandatory for a JSON Form to function. Users can supply form data via the formData variable, which should follow the structure of JSON schema. UI schema can be supplied via the uiSchema variable, which allows users to customize the form’s UI (e.g. components, rules, types).

You can test the JSON schema, UI schema and form data in the react-jsonschema-form sandbox environment. Entando templates, widgets, and fields allow customization of form layout using Grid components. The size parameter in the UI schema’s ui:options object specifies the fill area of a field or subform.

Size refers to the Material UI’s grid column widths (see the Material UI documentation), where the area the form can occupy is divided into 12 columns. A value of 12 (the default value if size is not provided) means the field or subform should take up all 12 columns. If two adjacent fields have size values of 8 and 4, respectively, they will share one row and the first field will be twice as wide as the second.

In addition, the user can provide an innerSize parameter to scale the input fields inside the columns. This helps with formatting when a user wants to make nonuniform adjustments to sizing.

Multicolumn layout can also be achieved via generateColumnedOFT (columnSize) functionality, which assigns the default columnSize to the created form. The function generateColumnedOFT returns an ObjectFieldTemplate that is used as a template for all object fields (fields that contain properties).

To explain the mapping between JSON schema and UI schema let's define an example schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://entando.org/schemas/pda-form.json",
  "title": "Mortgage Application Form",
  "type": "object",
  "properties": {
    "Application": {
      "title": "Application",
    "type": "object",
    "required": [],
    "properties": {
        "mortgageamount": {
          "type": "integer",
          "title": "Mortgage amount",
          "description": "Mortgage amount"
        },
        "downpayment": {
          "type": "integer",
          "title": "Down Payment",
          "description": "Down Payment"
        },
        "applicant": {
          "title": "Applicant",
          "type": "object",
          "required": [],
          "properties": {
            "name": {
              "type": "string",
              "title": "Name",
              "description": "Name",
              "maxLength": 100
            },
            "annualincome": {
              "type": "integer",
              "title": "Annual Income",
              "description": "Annual Income"
            }
          }
        },
        "property": {
          "title": "Property",
          "type": "object",
          "required": [],
          "properties": {
            "age": {
              "type": "integer",
              "title": "Age of property",
              "description": "Age of property"
            },
            "address": {
              "type": "string",
              "title": "Address of property",
              "description": "Address of property",
              "maxLength": 100
                }
          }
        }
      }
    },
    "inlimit": {
      "type": "boolean",
    "title": "Is mortgage application in limit?"
    }
  }
}

From this JSON (you can copy & paste it into the react-jsonschema-form sandbox) we can see that there is a main form with a title “Mortgage Application Form." The root form Mortgage Application Form has two properties: one is a subform called Application and the other is a checkbox field (field ID is inlimit).

The Application subform contains two fields: Mortgage Amount with field ID mortgageamount and Down Payment with field ID downpayment. It also contains two subforms: Applicant with field ID applicant and Property with field ID property.

The Applicant subform contains two fields: Name with field ID name and Annual Income with field ID annualincome. The Property subform also contains two fields: Age of property with field ID age and Address of property with field ID address.

By default (without providing UI schema), these are listed as one field per row. To use Entando’s implementation of Grid layout, users have to provide UI schema with details about each field. For example, if we would like to have a layout that looks like this (fields are marked [ field name ]):

+----------------------------------------------------------------------------+
| Mortgage Application Form                                                  |
+----------------------------------------------------------------------------+
| Application                                                                |
+----------------------------------+-----------------------------------------+
| [Mortgage amount]                | [Down Payment]                          |
+----------------------------------+-----------------+-----------------------+
| Applicant                                          | Property              |
+----------------------------------+-----------------+-----------------------+
| [Name]                           | [Annual Income] | [Age of property]     |
+----------------------------------+-----------------+-----------------------+
|                                                    | [Address of property] |
+----------------------------------------------------+-----------------------+

To set up the UI schema, you need to use field IDs to define each field you want to customize. For example, to add options to the Name field, create an object tree beginning at the root: Application —> Applicant —> Name (equivalent to Application.Applicant.Name). The UI schema for the table layout defined above looks like this:

{
  Application: {
    'ui:options': {
      size: 12, // <-- this value is not mandatory; size is 12  columns wide by default
    },
    mortgageamount: {
      'ui:disabled': true, // <-- user can define fields disabled at UI schema level
      'ui:options': {
        size: 6, // <-- Mortgage Amount field should take up half of the row
      },
    },
    downpayment: {
      'ui:options': {
         size: 4, // <-- Down Payment field should take up the other half of the row
       },
    },
    applicant: {
      'ui:options': {
         size: 8, // <-- Applicant subform should take up 8 out of 12 columns
      },
      name: {
        'ui:options': {
          size: 8, // <-- Applicant Name field should take up 8 of the 8 columns that Applicant subform occupies
        },
      },
      annualincome: {
        'ui:options': {
           size: 4, // <-- Annual Income field should take up the remaining 4 columns
        },
      },
    },
     property: {
      'ui:options': {
        size: 4, // <-- Property subform should take up the remaining 4 out of 12 columns
      },
      // note that Property field occupancy is not specified, defaulting to use all 12 of the columns available
    },
  },
};

As Material UI components are used for field templates, there might be a need to pass some Material UI options into the field. This can be done by adding the muiProps object to ui:options.

For example, if you would like to make the down payment field resizable, you can add multiline: true to the muiProps option. If you want the field to take up multiple rows by default, add the fields rows and rowsMax. The latter limits how many rows can be added until the scroll bar is shown.

downpayment: {
  'ui:options': {
    size: 4,
    muiProps: {
      multiline: true,
      rows: 2,
      rowsMax: 4
    }
  }
}

# Widgets

Different types of widgets can be applied by passing the type via ui:widget. This property specifies the widget to use when the form renders a UI field. See the documentation to learn about widgets supported by the react-jsonschema-form.

# Code Style

Refer to: https://github.com/entando/entando-code-style (opens new window)

# Sonar

Refer to: https://sonarcloud.io/organizations/entando/projects (opens new window)