# DisplayFields

DisplayFields is a [templating API](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/config/definitions/common/DisplayFields.html) that enables integration adapters to provide nested sets of dynamic, internationalised, customisable fields (label-value pairs) to Caplin’s front end applications for display.

DisplayFields are used to display information in:

* Trade confirmations
* Blotter summaries
* Post-trade history

## DisplayFields in context

DisplayFields are sent to the front end in the `DisplayFields` field of some trade model messages and blotter records.

Message builders that support DisplayFields auto-generate a default value for the `DisplayFields` field that you are free to override.

See below a simplified example of DisplayFields being sent to the front end as part of an [RFS spot trade confirmation trade model message](fxapi-trade-model-rfs.md#ticketspottradeconfirmation) using the [`TicketSpotTradeConfirmation`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/generated/motif/fx/tradeconfirmation/TradeConfTypesDef.TicketSpotTradeConfirmation.html) message builder.

**Example TradeConfirmationProvider**

```java
public class TradeConfirmationProvider implements CachedMessageProvider<TradeSubjectInfo> {

  private SubjectMessagePublisher<TradeSubjectInfo> publisher;

  @Override
  public void initialise(final SubjectMessagePublisher<TradeSubjectInfo> publisher) {
    this.publisher = publisher;
  }

  @Override
  public void onRequest(TradeSubjectInfo subject) {
    TicketSpotTradeConfirmation tradeConfirmation =
      TicketSpotTradeConfirmation.newBuilder()
        .setDisplayFields(
          new DisplayFields()
            .displayFields(List.of(
              new DisplayField()
                .label("Account")
                .template("{{account}}")
                .arguments(Map.ofEntries(
                  Map.entry("account", new DisplayFieldArgument("User 1", DisplayFieldArgument.TypeEnum.TEXT))
                ))
            ))
        )
        .build();
    publisher.publishMessage(subject, tradeConfirmation);
  }
}
```

## Anatomy of a DisplayField

Each DisplayField is made up of a label, a template, and a set of arguments. The front end combines these attributes to render a label-value pair. Common combinations can be created using the `DefaultDisplayFields` helpers:

* FX: [`DefaultDisplayFields`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/fx/config/DefaultDisplayFields.html)
* MM: [`DefaultDisplayFields`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/mm/config/DefaultDisplayFields.html)

### Labels, templates, and arguments

Labels, templates, and arguments are the core parts of each individual DisplayField that inform the front end on how to render the text label and value of the field.

**An example DisplayField with multiple arguments**

```java
int rate = 1.125
int amount = 10000 // 10,000
int total = rate * amount;

new DisplayField()
  .label("Rate x Amount") ①
  .template("{{rate}} x {{amount}} = {{total}}") ②
  .arguments(Map.ofEntries( ③
    Map.entry("rate", new DisplayFieldArgument(rate, DisplayFieldArgument.TypeEnum.NUMBER))
    Map.entry("amount", new DisplayFieldArgument(amount, DisplayFieldArgument.TypeEnum.NUMBER))
    Map.entry("total", new DisplayFieldArgument(total, DisplayFieldArgument.TypeEnum.NUMBER))
  ))
```

1. The label to be shown in the front end.
2. A template string that becomes the value for the field. The keys surrounded by double curly brackets (e.g. `{{rate}}`) are replaced with the values of the corresponding arguments \(C).
3. A map of arguments to be interpolated into the template (B).

When template interpolation and formatting has been applied in the front end, the example above would look something like this:

* ***Rate x Amount***\
1.125 x 10,000 = 11,250

#### Translation tokens

To ensure that DisplayFields are translatable along with other content in the front end, DisplayField labels and arguments support the use of i18n tokens.

The front end automatically recognises i18n tokens in the label of a DisplayField, but arguments with i18n tokens must use the argument type [`TOKEN`](#argument-type-token) for an i18n token to be recognised.

For a full list of argument types, see [Argument types](#argument-types).

**An example DisplayField using i18n tokens**

```java
new DisplayField()
  .label("display-field-label.trade-status") ①
  .template("{{status}}") ②
  .arguments(Map.ofEntries( ③
    Map.entry("status", new DisplayFieldArgument("display-field-value.trade-status-pending", DisplayFieldArgument.TypeEnum.TOKEN)) ③
  ))
```

1. A DisplayField label using the i18n token `display-field-label.trade-status`.
2. The template uses the value of the `status` argument below (3).
3. A single argument `status` is used. The value of the argument is `display-field-value.trade-status-pending`, and it uses the argument type `TOKEN`.

If the application had i18n translations for both English and Spanish, the example above might display as:

* ***Trade Status***\
Pending

Or alternatively:

* ***Estado Comercial***\
Pendiente

Note that you must provide i18n translations for each of the languages and translation tokens you wish to support.

#### Argument types

Each DisplayField be of one of several data types. The types inform the front end how it should format and display the fields. The following types are available via [`DisplayFieldArgument.TypeEnum`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/config/definitions/common/DisplayFieldArgument.TypeEnum.html).

* **`TEXT`**\
A plaintext value that should be displayed unmodified. TOKEN is preferred for text values that need to be translatable.

* **`TOKEN`**\
An i18n translation token for text translations.
* **`NUMBER`**\
A numerical value, such as 1.0, 100, or 1,000. The front end should apply formatting appropriate to the user’s locale.
* **`DATE`**\
An ISO date (`YYYY-MM-DD`). The front end should apply formatting appropriate to the user’s locale.
* **`TIME`**\
An ISO date-time (`YYYY-MM-DD[T]HH:mm:ss.SSS`) or time (`HH:mm:ss.SSS`) with or without milliseconds. Input must be in UTC. Milliseconds will be displayed only if the input format contained milliseconds. The front end will convert the value to local time and display the time part only, formatted according to the user’s locale settings.
* **`DATETIME`**\
An ISO date-time (`YYYY-MM-DD[T]HH:mm:ss.SSS`) with or without milliseconds. Input must be in UTC. Milliseconds will be displayed only if the input format contained milliseconds. Frontend will convert to local time and display the date and time formatted according to the user’s locale settings.
* **`RATE`**\
A rate value that may be formatted with adapter-provided formatting attributes.
* **`POINTS`**\
An amount value that may be formatted with attributes provided by an adapter.
* **`AMOUNT`**\
An amount value that may be formatted with attributes provided by an adapter.

## Grouping DisplayFields into sections

DisplayFields can be grouped into sections by nesting them under other DisplayFields that act as wrappers. Headers can be added to these sections using the `template` property to interpolate a header label.

**An example of DisplayFields grouped into two sections**

```java
new DisplayFields()
  .displayFields(List.of(
    new DisplayFields() ①
      .template("{{header}}") ②
      .arguments(Map.ofEntries( ③
        Map.entry("header", new DisplayFieldArgument("User Info", DisplayFieldArgument.TypeEnum.TEXT))
      ))
      .displayFields(List.of( ④
        new DisplayField()
          .label("Account")
          .template("{{account}}")
          .arguments(Map.ofEntries(
            Map.entry("account", new DisplayFieldArgument("User 1", DisplayFieldArgument.TypeEnum.TEXT))
          ))
      )),
    new DisplayFields() ⑤
      .template("{{header}}") ⑥
      .arguments(Map.ofEntries( ⑦
        Map.entry("header", new DisplayFieldArgument("Trade Details", DisplayFieldArgument.TypeEnum.TEXT))
      ))
      .displayFields(List.of( ⑧
        new DisplayField()
          .label("Settlement Date")
          .template("{{settlement}}")
          .arguments(Map.ofEntries(
            Map.entry("settlement", new DisplayFieldArgument("2024-04-01", DisplayFieldArgument.TypeEnum.DATE))
          ))
      ))
  ));
```

1. The beginning of the first section.
2. The template uses the `header` argument. This will act as the header for the first section.
3. The `header` argument is defined, to be used in the template (2).
4. The fields for this section are added.
5. The beginning of the second section.
6. The template uses the `header` argument. This will act as the header for the second section.
7. The `header` argument is defined, to be used in the template (6).
8. The fields for this section are added.

When template interpolation and formatting has been applied in the front end, the example above would look something like this:

* **[.underline]*User Info***

  * ***Account***\
  User 1
* **[.underline]*Trade Details***

  * ***Settlement Date***\
  01/04/2024

## DisplayFields in table format

Some messages support DisplayFields in table format.

You can use the `DefaultTableFields` helpers to help you create tables for these messages.

* [com.caplin.motif.commodities.invoices.DefaultTableFields](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/commodities/invoices/DefaultTableFields.html)
* [com.caplin.motif.commodities.trading.dealbreakdown.DefaultTableFields](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/commodities/trading/dealbreakdown/DefaultTableFields.html)
* [com.caplin.motif.mm.trading.posttradehistory.DefaultTableFields](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/fx/trading/posttradehistory/DefaultTableFields.html)
* [com.caplin.motif.mm.trading.posttradehistory.MMDefaultTableFields](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/mm/trading/posttradehistory/MMDefaultTableFields.html)

See below a simplified version of a DisplayFields table being added to a `PostTradeHistory` message. For a full example, see `ExamplePostTradeHistoryProvider` in the FX Example Adapter.

**Simplified ExamplePostTradeHistoryProvider with a DisplayFields table**

```java
public class ExamplePostTradeHistoryProvider implements CachedObjectProvider<PostTradeHistory, TradeSubjectInfo> {

  @Override
  public void onRequest(final TradeSubjectInfo subjectInfo, final SubjectConsumer<PostTradeHistory> publishObject) {
    final Table postTradeHistoryTable = DefaultTableFields.createPostTradeHistoryTable();
    DefaultTableFields.addPostTradeHistoryRow(
        postTradeHistoryTable,
        LocalDate.now(),
        new FormattedAmount(new BigDecimal("1000"), "GBP", 2),
        LocalDate.now().plusDays(7),
        Tenor._1W.toString(),
        new FormattedAmount(new BigDecimal("0"), "GBP", 2),
        new PostTradeHistoryAction(TypeEnum.ROLL_FORWARD, "0987654321")
    );
    final PostTradeHistory postTradeHistory = new PostTradeHistory();
    postTradeHistory.setTable(postTradeHistoryTable);

    publishObject.onNext(postTradeHistory);
  }
}
```

### Anatomy of a DisplayFields table

DisplayFields tables are created using [`Table`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/config/definitions/common/Table.html), [`TableCell`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/config/definitions/common/TableCell.html), and [`TableRow`](https://docs.caplin.com/developer/api/fxintegration/latest/com/caplin/motif/config/definitions/common/TableRow.html) objects.

TableCell and TableRow objects use templates and arguments in the same way as regular DisplayFields. See [Labels, templates, and arguments](#labels-templates-and-arguments) for details.

```java
new Table() ①
  .headers(List.of( ②
    new TableCell()
      .template("{{header}}")
      .arguments(
        Map.ofEntries(
          Map.entry("header", new DisplayFieldArgument("Header 1", DisplayFieldArgument.TypeEnum.TEXT))
        )
      ),
    new TableCell()
      .template("{{header}}")
      .arguments(
        Map.ofEntries(
          Map.entry("header", new DisplayFieldArgument("Header 2", DisplayFieldArgument.TypeEnum.TEXT))
        )
      )
  ))
  .rows(List.of( ③
    new TableRow()
      .cells(List.of( ④
        new TableCell()
          .template("{data}}")
          .arguments(Map.ofEntries(
            Map.entry("data", new DisplayFieldArgument("Value 1", DisplayFieldArgument.TypeEnum.TEXT))
          )),
        new TableCell()
          .template("{data}}")
          .arguments(Map.ofEntries(
            Map.entry("data", new DisplayFieldArgument("Value 2", DisplayFieldArgument.TypeEnum.TEXT))
          ))
      ))
  ));
```

1. Create a `Table` object.
2. Using `Table.headers`, provide a list of `TableCell` objects. These become headers in the table.
3. Using `Table.rows`, provide a list of `TableRow` objects. These become rows in the table.
4. Each row has a list of `TableCell` objects, populating each of the columns in that row.

The example above creates a table with the following structure:

| Header 1 | Header 2 |
| --- | --- |
| Value 1 | Value 2 |
