Customize the input and table of a form journal component

🟡 Intermediate

form collection dashboard

This tutorial shows how to customize the journal component in a form in order to add fields to a journal entry.

  • Create a Category collection to provide selectable values for journal entries.

  • Define a standalone journal input form with custom fields (timestamp, text, category).

  • Configure the Journal collection with a JOURNAL render column using journalSettingsOverride.

  • Use a Collection Table widget to interact with the customized journal form on a dashboard.

git checkout origin/osp-web-configuration .
git checkout origin/osp-collections-configuration .
git checkout origin/example-dashboard-form-journal-custom .

Steps

1. Create the Category collection

This collection is just here to provide a list of categories to feed to the events of the Journal collection. Therefore, this collection will only contain a field called text.

Here are the different schema files to define the collection:

root/collections/categories/schema.collections

{
    "moduleId": "modules.collections.collections-1",
    "collectionName": "categories",
    "indexes": [
        {
            "name": "text",
            "index": "{'text': 1}"
        }
    ],
    "filters": [
        {
            "id": "all",
            "query": "{}"
        }
    ]
}

root/collections/categories/schema.ospp

{
    "filters": [
        {
            "id": "all",
            "name": "All"
        }
    ],
    "schema": {
        "type": "object",
        "properties": {
            "text": {
                "type": "string"
            }
        },
        "required": [
            "text"
        ]
    }
}

root/collections/categories/schema.web

{
    "moduleId": "modules.web.web-1",
    "name": "Categories",
    "views": [
        {
            "id": "1",
            "name": "1",
            "reorderable": true,
            "isDefault": true,
            "sort": [],
            "columns": [
                {
                    "name": "text",
                    "field": "text",
                    "position": 0,
                    "render": "STRING"
                }
            ]
        }
    ]
}

In order to offer the user a way to populate this collection, we also need to define a form dedicated to this collection.

root/collections/categories/form/form.web

{
  "moduleId": [
    "modules.web.web-1"
  ],
  "name": "Fiche categorie",
  "description": "",
  "bindings": {},
  "rights": [],
  "schema": "root.collections.categories",
  "ui": {
    "type": "VerticalLayout",
    "elements": [
      {
        "type": "Control",
        "scope": "#/properties/text",
        "label": "text"
      }
    ]
  },
  "submit": {
    "destination": "Request",
    "type": "Deferred"
  }
}

2. Create the journal input form

The second step is to define a standalone form that will represent the input of the journal component present in the form of the Journal collection that we will create later.

This form will consist of the following fields:

  • timestamp: Timestamp of the journal entry

  • text: Content of the journal entry

  • cat: Category of event, from the Category collection

To define this form, we need a form.web and a schema.ospp, as defined here:

root/journal_input/schema.ospp

{
    "filters": [],
    "schema": {
        "type": "object",
        "properties": {
            "timestamp": {
                "type": "number",
                "$comment": "date"
            },
            "text": {
                "type": "string"
            },
            "cat": {
                "type": "string"
            }
        },
        "required": [
            "timestamp",
            "cat"
        ]
    }
}

root/journal_input/form.web

{
  "moduleId": [
    "modules.web.web-1"
  ],
  "name": "Journal Input form",
  "description": "",
  "schema": "root.journal_input",
  "bindings": {},
  "ui": {
    "type": "HorizontalLayout",
    "elements": [
      {
        "type": "Control",
        "scope": "#/properties/timestamp",
        "options": {
            "format": "date-time",
            "autoFill": true,
            "dateTimeFormat": "L HH:mm"
        }
      },
      {
        "type": "Collection",
        "scope": "#/properties/cat",
        "label": "Category",
        "options": {
          "schema": "root.collections.categories",
          "format": "${text}"
        }
      },
      {
        "type": "Control",
        "scope": "#/properties/text",
        "label": "text"
      }
    ]
  }
}

3. Create the Journal collection

The Journal collection will consist of a summary field and a list of events.

First, we need to define the schema files to define the collection.

root/collections/journal/schema.collections

{
    "moduleId": "modules.collections.collections-1",
    "collectionName": "journal",
    "indexes": [
        {
            "name": "summary",
            "index": "{'summary': 1}"
        }
    ],
    "filters": [
        {
            "id": "all",
            "query": "{}"
        }
    ]
}

root/collections/journal/schema.ospp

{
    "filters": [
        {
            "id": "all",
            "name": "All"
        }
    ],
    "schema": {
        "type": "object",
        "properties": {
            "summary": {
                "type": "string",
                "title": "Résumé"
            },
            "events": {
                "type": "array",
                "title": "Events",
                "items": {
                    "type": "object",
                    "properties": {
                        "id": {
                            "type": "string"
                        },
                        "user": {
                            "type": "string"
                        },
                        "text": {
                            "type": "string"
                        },
                        "cat": {
                            "type": "string"
                        },
                        "timestamp": {
                            "type": "number"
                        },
                        "meta": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "user": {
                                        "type": "string"
                                    },
                                    "timestamp": {
                                        "type": "number"
                                    },
                                    "operation": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "required": [
            "summary"
        ]
    }
}

root/collections/journal/schema.web

Here, we can define a column for the events fields with the JOURNAL render. This column will define how the journal component present on the table side panel will work. So we need to indicate which form to use for the input and how to display the data.

On the options of the column, we can set the journalSettingsOverride to define the form, the timeline text formatter (used for the timeline display of the journal) and the table configuration.

{
    "moduleId": "modules.web.web-1",
    "name": "Fiche générale Sécurité",
    "views": [
        {
            "id": "1",
            "name": "Journal complet",
            "reorderable": true,
            "isDefault": true,
            "tableRowDetail": "journal",
            "sort": [],
            "columns": [
                {
                    "name": "Summary",
                    "field": "summary",
                    "position": 0,
                    "render": "STRING"
                },
                {
                    "name": "Events",
                    "field": "events",
                    "position": 1,
                    "render": "JOURNAL",
                    "display": false,
                    "options": {
                        "summaryFormatterExpression": "${description}",
                        "inputMethod": "Message",
                        "editMode": "all",
                        "displayWithMultipleRows": false,
                        "type": "Table",
                        "journalSettingsOverride": {
                            "form": "root.journal_input",
                            "timelineTextFormatter": "**${cat}** - ${text}",
                            "tableView": {
                                "sort": [
                                  {
                                      "field": "timestamp",
                                      "direction": "desc"
                                  }
                                ],
                                "columns": [
                                  {
                                    "name": "Id",
                                    "field": "id",
                                    "position": 0,
                                    "display": false,
                                    "render": "STRING"
                                  },
                                  {
                                    "name": "Date",
                                    "field": "timestamp",
                                    "position": 1,
                                    "render": "TIMESTAMP",
                                    "options": {
                                      "formatter": "L LT"
                                    }
                                  },
                                  {
                                    "name": "Text",
                                    "field": "text",
                                    "position": 2,
                                    "render": "MARKDOWN"
                                  },
                                  {
                                    "name": "Category",
                                    "field": "cat",
                                    "position": 3,
                                    "render": "STRING"
                                  },
                                  {
                                    "name": "User",
                                    "field": "user",
                                    "position": 4,
                                    "render": "STRING"
                                  },
                                  {
                                    "name": "Meta",
                                    "field": "meta",
                                    "position": 5,
                                    "width": "auto",
                                    "display": false,
                                    "render": "JOURNAL_METADATA"
                                  }
                                ]
                              }
                        }
                    }
                }
            ]
        }
    ]
}

Now, we can define a form for the collection and apply the same settings for the journal component as for the schema column.

root/collections/journal/form/form.web

{
  "moduleId": [
    "modules.web.web-1"
  ],
  "name": "Events",
  "description": "",
  "bindings": {},
  "rights": [],
  "schema": "root.collections.journal",
  "ui": {
    "type": "VerticalLayout",
    "elements": [
      {
        "type": "Control",
        "scope": "#/properties/summary",
        "label": "Summary"
      },
      {
        "type": "Journal",
        "scope": "#/properties/events",
        "label": "Events",
        "options": {
          "height": "400px",
          "journalWidgetSettings": {
            "type": "Table",
            "inputMethod": "TimestampMessage",
            "actionsPosition": "top",
            "timestampSort": "asc",
            "autoFocus": false,
            "journalEditMode": "all",
            "journalSettingsOverride": {
              "form": "root.journal_input",
              "timelineTextFormatter": "**${cat}** - ${text}",
              "tableView": {
                "sort": [
                  {
                    "field": "timestamp",
                    "direction": "desc"
                  }
                ],
                "columns": [
                  {
                    "name": "Id",
                    "field": "id",
                    "position": 0,
                    "display": false,
                    "width": "auto",
                    "render": "STRING"
                  },
                  {
                    "name": "Date",
                    "field": "timestamp",
                    "position": 1,
                    "render": "TIMESTAMP",
                    "width": "auto",
                    "display": true,
                    "options": {
                      "formatter": "L LT"
                    }
                  },
                  {
                    "name": "Text",
                    "field": "text",
                    "position": 2,
                    "width": "auto",
                    "display": true,
                    "render": "MARKDOWN"
                  },
                  {
                    "name": "Category",
                    "field": "cat",
                    "position": 3,
                    "width": "auto",
                    "display": true,
                    "render": "STRING"
                  },
                  {
                    "name": "User",
                    "field": "user",
                    "position": 4,
                    "width": "auto",
                    "display": true,
                    "render": "STRING"
                  },
                  {
                    "name": "Meta",
                    "field": "meta",
                    "position": 5,
                    "width": "auto",
                    "display": false,
                    "render": "JOURNAL_METADATA"
                  }
                ]
              }
            }
          }
        }
      }
    ]
  },
  "initialValue": {},
  "submit": {
    "destination": "Request",
    "type": "Deferred"
  }
}

4. Use a Collection Table widget to interact with the form

To finalize this example, we will simply define a dashboard with a Collection Table that use as a default schema the Journal collection schema.

root/dashboards/journal/dashboard.view

{
  "configuration": [
    {
      "type": "CollectionTable",
      "id": "D2H2STZ3",
      "title": "",
      "menuReferences": [],
      "collectionTableWidgetSettings": {
        "defaultSchemas": ["root.collections.journal"],
        "defaultFilter": "all",
        "defaultDisplayType": "table",
        "pageSize": 100,
        "pageSizes": [
          50,
          100,
          200
        ],
        "resizeMode": "widget",
        "rowDetailHeight": 500,
        "disableToolbarTableRefresh": false,
        "disableUrlHistory": true,
        "disableSchemaUpdate": false,
        "disableViewUpdate": false,
        "disableFilterUpdate": false,
        "disableToolbar": false,
        "disableToolbarMenu": false,
        "disableSidePanel": false,
        "disableToolbarExport": false,
        "disableToolbarColumnShowHide": false,
        "disableToolbarFilterShowHide": false,
        "disableToolbarSummaryShowHide": false,
        "disableToolbarSearch": true,
        "disableToolbarColumnChooser": false,
        "disableToolbarClearFilter": false,
        "iconTableView": "import_contacts",
        "iconFormView": "description",
        "iconCreateEntry": "note_add",
        "iconSidePanel": "add_comment",
        "iconExportPanel": "file_download",
        "submitSettings": {
          "submitText": "Save and close",
          "applyText": "Save"
        }
      }
    }
  ],
  "layout": {
    "lg": [
      {
        "w": 12,
        "h": 7,
        "x": 0,
        "y": 0,
        "i": "D2H2STZ3"
      }
    ]
  },
  "breakpoints": {
    "lg": 1200,
    "md": 996,
    "sm": 768,
    "xs": 480,
    "xxs": 0
  },
  "cols": {
    "lg": 12,
    "md": 10,
    "sm": 6,
    "xs": 4,
    "xxs": 2
  },
  "rowHeight": 150
}

Upon loading the dashboard, when entering in edition mode or when displaying the table side panel, you should see your journal with the extra Category field.

../_images/osp-form-journal-custom-edition.png ../_images/osp-form-journal-custom-table.png