Fluent Commerce Logo
Docs
Sign In

UX Configuration - Common Concepts

Essential knowledge

Author:

Fluent Commerce

Changed on:

12 Sept 2024

Overview

Some common types and conventions are used across many component definitions. These items are not directly configurable in the manifest but will often be referenced in other component definitions that use them.

Key points

  • The Mystique manifest configures icons, cards, and template strings. Icons come from React Icons. 
  • Cards have common fields, and template strings allow dynamic values. Dynamic attributes (standard, image, component) offer flexibility based on conditions. 
  • Additional options like TextOptions and ImageOptions provide styling choices.

Icons

There are many places where icons can be configured in the Mystique manifest, whether to represent the app itself, different routes, or within component configurations.

In most cases, the list of available icons comes from the React Icons library - specifically the Material Design and Font Awesome packages.

Card

Many content-centric components are embedded in a card and will, therefore, share some common fields.

Name

Type

Required

Description

`title`

string

no

Title text of the card

`highlight`

MystiqueThemeColour / string (hex value)

no

Show a colored highlight above the card to denote status in cases like dashboard cards.

`width`

"quarter" / "third" / "half" / "two-thirds" / "full" / number (1-12)

no

Define the width of this card on a 12-column grid. You can use the named widths for readability or numbers directly.

On mobile devices, all widths will automatically change to 12 for the best responsive experience.

The default is "full" and will take up the full width of the containing component.

Template Strings

Many string values accepted by components are Template Strings. This means you can use a Mustache syntax to create dynamic values, mapping and transforming data from GraphQL or other sources into the UI.

As an example, configuring a card to display a customer's name might look something like:

`"{{order.customer.firstName}} {{order.customer.lastName}}"`

A selection of helper functions are also available to control and transform these values as required:

Name

Body

Description

Examples

String functions




`toLowerCase`

body: single string value

Convert a string to lowercase.

`"{{toLowerCase order.type}}"`

`toUpperCase`

body: single string value

Convert a string to upper case.

`"{{toUpperCase order.customer.lastName}}"`

`humanify`

body: single string value

Convert the first letter of a string to upper-case.

`"{{humanify order.ref}}"`

`stringify`

body: single JSON object

Convert a JSON object into a string representation.

`"{{stringify order.attributes.byName.invoicePayload}}"`

`concat`

body: two string values

(Optional separator argument)

Concatenates two strings together using the specified separator. 

(Default separator = "")

`"{{concat order.customer.firstName order.customer.lastName}}"`

`"{{concat order.customer.firstName order.customer.lastName separator=' '}}"`

`partialStringMatch`

body: two string values

Returns true if the first string appears in the second string. (Case Insensitive)

`{{partialStringMatch "eM1" "item1"}} = true`

`
`
{{partialStringMatch "eM2" "item1"}} = false

Date functions




`dateFormat`


(aka
`dateStringFormatter`
)

body:

0: date object or date-formatted string

1: optional format string (ISO 8601)

2: optional boolean to show in UTC time (

`true`
) instead of the user's timezone (
`false`
). The default is
`false`
.

Format a date to the user's locale.

`"{{dateStringFormatter order.createdOn}}"`

`"{{dateStringFormatter order.createdOn 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'}}"`

`dateAdd`

body: optional date object

modifier: <period>=<amount>

Add or subtract an amount of time from a given date.

Passing a date is optional, and the default is now.

This is often used with 

`dateFormat`
 to provide a date range for GQL queries, for example, fetching all orders created in the last 24 hours.

`"expiry: {{dateAdd node.createdOn day=3}}"`


`{{dateStringFormatter (dateAdd day=-1) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'}}`

`dateRelative`

body: date object

Convert a date object into a relative format, e.g. "10 minutes ago"

`{{dateRelative node.expiryTime}}`

`dateSubtract`

body: optional date object

modifier: <period>=<amount>

Subtract an amount of time from a given date.

Passing a date is optional, and the default is now.

This is often used with 

`dateFormat`
 to provide a date range for GQL queries, for example, fetching all orders created in the last 24 hours.

`"WorkWeekStart: {{dateSubtract node.createdOn day=5}}"`


`{{dateFormat (dateSubtract day=params.filter_value) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'}}`

`dateFormatByLocale`








body:

0: date object or date-formatted string

1: optional boolean to show in UTC time (

`true`
) instead of the user's timezone (
`false`
). The default is
`false`
.

Format a date based on user's browser language: 

  • English (UK)/English(AU) and other languages - dd/mm/yyyy
  • English (US) - mm/dd/yyyy
  • English (CA)/French(CA)  - yyyy/mm/dd

`"{{dateFormatByLocale order.createdOn}}"`

Array functions




`arraySum`

body:

0: array of objects

1: JSONPath from the object root to the field to be summed.

Total up values from within an array of objects.

`"{{arraySum order.items 'node.totalPrice'}}"`

I18n functions




`i18n`

body: any number of strings that are joined together into an i18n key

_fallback: optional fallback value if the key does not exist.

Translate a value into another language.

`{{i18n 'fc.om.order.type.' node.type _fallback=node.type}}`

Logic Functions




`eq`

body: two values that are equal

Compare two values, true if equivalent.

`{{eq order.status 'BOOKED'}} // true`

`ne`

body: two values that are not equal

Compare two values, true if not equivalent.

`{{ne order.status 'BOOKED'}} // false`

`lt`

body: two values to be compared

Compare two values, true if a is less than b

`{{lt order.items.count 3}}`

`gt`

body: two values to be compared

Compare two values, true if a is more than b

`{{gt order.items.count 3}}`

`lte`

body: two values to be compared

Compare two values, true if a is less or equal to b

`{{lte order.items.count 3}}`

`gte`

body: two values to be compared

Compare two values, true if a is more than or equal to b

`{{gte order.items.count 3}}`

`and`

body: one or more values (expressions)

Compare two booleans, true if both are true.

In JavaScript, strings, numbers, and objects are 

`true`
, and null/undefined are 
`false`
.

`{{and (eq order.status 'BOOKED') (gt order.items.count 3)}}`


`{{and order.status order.items.count}}`


`{{and order.status}}`

`or`

body: one or more values (expressions)

Compare two booleans;

`true`
if either is
`true`
.

In Java Script, strings, numbers, and objects are 
`true`
, and null/undefined are 
`false`
.

`{{or (eq order.status 'BOOKED') (gt order.items.count 3)}}`


`{{or order.status order.items.count}}`


`{{or order.status}}`

`firstDefinedValue`

body: one or more values

This template returns the first valid value. Valid values are anything that isn't either

`null`
or
`undefined`
(empty).

`{{ firstDefinedValue null undefined 10 }} returns  10`

`{{ firstDefinedValue null undefined false 10 }} returns false `

`{{ firstDefinedValue null undefined null }} returns null`

`anyMatch`

The body consists of three values: the path, the function, and the value

anyMatch template is used for performing conditional checks on structured data (i.e lists, arrays), typically JSON.  More examples can be found here

`{{anyMatch "node.entity.field.subfield2" "delta" "eq"}}`

Number Functions




`Currency`

number, currency, _locale (optional), _decimalPlaces (optional, default: 2)

Convert a number to currency format; this template uses the Intl.NumberFormat function with the 4 parameters described to the left

`{{currency totalPrice items.edges.0.node.currency _locale='en-AU' _decimalPlaces=3 }} = $99.990`


`{{currency 123.586 'AUD'}} = A$123.59`


`{{currency 10000000.123 'GBP' _decimalPlaces=1}} = £10,000,000.1`


`{{currency 123.87862 'AUD' _locale='en-AU' _decimalPlaces=3}} = $123.879`


`{{currency totalPrice 'INR' _locale='hi-IN' _decimalPlaces=2}} = ₹99.99`


`{{currency 10000000.123 'EUR' _locale='es-ES'}} = 10.000.000,12 €`


`{{currency totalPrice items.edges.0.node.currency}}`


`{{currency (subtract 50.32 20.11) "AUD" _decimalPlaces=2}} = A$30.21`

`add`

body: two values to be added, _decimalPlaces (optional, default: 2)

Adds two numbers together.

`{{add 1 2}} // 3`


`{{add 2.345 1.432 _decimalPlaces=3}} // 3.777`

`subtract`

body: two values to be subtracted, _decimalPlaces (optional, default: 2)

Subtracts one number from another

`{{subtract 1 2}} // -2`


`{{subtract 2.345 1.432 _decimalPlaces=3}} // 0.913`

`multiply`

body: two values to be multiplied, _decimalPlaces (optional, default: 2)

Multiplies two numbers together

`{{multiply 3 4}} // 12`


`{{multiply 1.348 3.472 _decimalPlaces=3}} // 4.680`

`divide`

body: two values to be divided, _decimalPlaces (optional, default: 2)

Divides one number from another

`{{divide 12 4}} // 3`


`{{divide 5.298 2.252 _decimalPlaces=3}} // 2.352`

`pow`

body: raise the first value to the power of the second, _decimalPlaces (optional, default: 2)

Raises one number to the power of the second

`{{pow 3 2}} // 9`


`{{pow 3.994 3 _decimalPlaces=3}} // 63.712`

`getMetricStepByTimePeriod`

body: any number

This template calculates the step’s size by a set time period. Depending on the specified time period, the template returns different values:

  • The time period equals 480; the step size is 30 (time/16);
  • The time period equals 1440; the step size is 120 (time/12);
  • For all other cases, the set time is divided into 15.

`{{getMetricStepByTimePeriod params.filter_value}}`

Other




barcode

body: two string values and one boolean

(Optional format and displayText arguments)

Generate a barcode for a given string. 

1.If the format is not specified, it will be detected automatically.

Supported barcode formats:

  • CODE128
    • CODE128 (automatic mode switching)
    • CODE128 A/B/C (force mode)
  • EAN
    • EAN-13
    • EAN-8
    • EAN-5
    • EAN-2
    • UPC (A)
    • UPC (E)
  • CODE39
  • ITF
    • ITF
    • ITF-14
  • MSI
    • MSI10
    • MSI11
    • MSI1010
    • MSI1110
  • Pharmacode
  • Codabar

2. The

`displayText`
argument determines if the text will be rendered, defaulting to
`true`
. If not specified, the text will appear unless explicitly set to
`false`
.

`{{ barcode '1234 abc' 'CODE128B' }}`

`{{ barcode fulfilmentById.ref }}`

`{{ barcode '1234 abc' 'CODE128B' false}}`

Accessing entity attributes by name

In GraphQL, any entity attributes are returned as an array. This can make it difficult to configure a component to show a specific attribute.

To help with this, attribute arrays have a 

`byName`
 property that allows specific attributes to be directly referenced in template strings.

For example, if an Order has a custom attribute 

`vipStatus`
, you can add this attribute to a card or list with the following syntax:

`"{{order.attributes.byName.vipStatus}}"`

Plugin-specific Template Strings

Some additional templates are available only when certain plugins are loaded.

Name

Body

Description

Examples

Plugin

Array functions





`arrayFieldSum`

body:

0: array of objects

1: JSONPath from the object root to the field to be summed.

Total up values from within an array of objects. Supports summation of elements with zero value.

datasource:

`[{price: 1},{price: 2},{price: 3},]`

`"{{arraySum items 'price'}}" // 6`

OMS

`getMaxValue`

array of objects

Get the max value from an array of objects

datasource: 

No alt provided

`{{getMaxValue`
`node.updatedOn}} // '2023-12-12T00:00:00.000Z'`

Inventory

`getTotalActiveFeeds`

object

Get total active feeds from a query on the Feeds Dashboard

`{{getTotalActiveFeeds inventoryFeeds.edges}}`

Inventory

Date functions





`timeAgo`

date object 

Convert a date object or date-formatted string into a relative format:

  • less than 1 second ago - round to seconds and display 0 sec (less 499 ms) or 1 sec (500 ms or more);
  • less than 1 minute ago - “XX sec” (note: 59 sec 499 ms is rounded to 59 sec; 59 sec 500 ms is rounded to 1 min)
  • less than 1 hour ago - “XX min” (note: 5 min 29 sec is rounded to 5 min; 5 min 30 sec is rounded to 6 min)
  • less or equals 23 hours 59 min 59 sec ago  - “> XX hr” (note: 1 hr 0 min 0 sec is converted to “> 1 hr”)
  • more than 23 hours 59 min 59 sec ago - “> 1 day”

`{{timeAgo node.updatedOn}}`

Inventory

`convertMsToDate`

number

Convert milliseconds to date.

`{{convertMsToDate 1691054160}} // '1970-01-20T13:44:14.160Z'`

Inventory

Number functions





`round`

number

Round a number 

`{{round 5.4}} // 5`

Inventory

String functions





`compactNumberFormat`

string

Convert a number to a compact format

`{{compactNumberFormat 15000}} // 15k`

Inventory

Dynamic Attribute

Dynamic Attribute is a common convention used when defining key/value type information in the manifest, such as card attributes or table columns.

The "value" and "link" fields are both Template Strings (see above), which is how dynamic values can be defined. For example, a table column might be defined as:

1{
2  "label":"i18n:fc.om.orders.index.list.column.customer.heading", // "Customer" in English
3  "value": "{{customer.firstName}} {{customer.lastName}}",
4  "link": "#/customer/{{customer.id}}",
5  "condition": "{{and customer.id}}"
6}

Language: json

Name: a table column might be defined

Description:

[Warning: empty required content area]

Standard (or Text) Attribute

Name

Type

Required

Description

`type`

`"standard"`
 (or not present)

no

Choose whether the value should be displayed as text or used to render an image.

The default is "standard".

`label`

`string`

yes

String key of the key/value pair. Used as text labels in

`AttributesCard`
component and column headers in the List component. Not actually used by DynamicValue.

`value`

`string`
 (with templates)

yes

The templatised string is to be transformed into the output value.

Has access to DynamicValue context (e.g., GraphQL response data) and any available template helpers (e.g., i18n, date formatters, etc.).

`link`

`string`
 (with templates)

no

If present, render the text as a link to the location defined in the "link" value. This also has access to DynamicValue context (e.g., GraphQL response data) and any available template helpers (e.g., i18n, date formatters, etc.).

`options`

`TextOptions`

no

Type-specific configurations for the Dynamic Attribute

`condition`

`string`
 (with templates)

no

If

`true`
, render the text a link to the location defined in the "link" value. Otherwise, render defaultValue.

TextOptions

In text-based attributes, a set of optional styles can be applied.

Each style option has a 

`matches`
 condition, and for each instance of an attribute, the style options are evaluated in order until the first match is found, at which point that style is applied.

Name

Type

Required

Description

`styles`

`TextStyle[]`

no

Set of styles to apply to this text attribute.

TextStyleOption

Name

Type

Required

Description

`value`

`string`

no

Value to compare matches to. Default is the rendered value of the overall attribute itself.

`matches`

`string[]`

no

If any of these match the value, apply this style. If empty, treat this as a 

`default`
 style (and apply to all).

`icon`

`IconStyle`

no

Icon and coloring to apply to this attribute.

`text`

`TextStyle`

no

Text coloring to apply to this attribute.

IconStyle

Name

Type

Required

Description

`name`

`loading`
/
`string`
 (icon name)

yes

Name of the icon to show with this text attribute.

To show a loading spinner, use 

`loading`
; otherwise, this should be a reference to a supported icon (see Icons above).

`colour`

`string`

no

Optionally apply a color to the icon.

Named theme colors (e.g. 

`primary`
 or 
`secondary`
) are recommended, but direct CSS hex values (e.g., 
`#00FF00`
) are also supported.`

TextStyle

Name

Type

Required

Description

`colour`

`string`

no

Optionally apply a color to the text.

Named theme colors (e.g. 

`primary`
 or 
`secondary`
) are recommended, but direct CSS hex values (e.g., 
`#00FF00`
) are also supported.`

Sample usage

The following attribute is used to embed a link into a component.

1{
2    "label": "i18n:fc.products.category.label",
3    "value": "{{ref}}",
4    "link": "#/category/{{catalogue.ref}}/{{ref}}",
5    "condition": "{{and catalogue.ref ref}}"
6}
7

Language: json

Name: Attribute is used to embed a link into a component

Description:

[Warning: empty required content area]


Image Attribute

Name

Type

Required

Description

`type`

`"image"`

yes

Choose whether the value should be displayed as text or used to render an image.

`label`

`string`

yes

String key of the key/value pair. Used as text labels in

`AttributesCard`
component and column headers in the List component. Not actually used by DynamicValue.

`value`

`string`
 (with templates)

yes

The templatised string is to be used as the URL for the image.

Has access to DynamicValue context (e.g., GraphQL response data) and any available template helpers (e.g., i18n, date formatters, etc).

`link`

`string`
 (with templates)

no

If present, render the image as a link to the location defined in the "link" value. This also has access to DynamicValue context (e.g. GraphQL response data) and any template helpers that are available (e.g. i18n, date formatters, etc).

`options`

`ImageOptions`

no

Type-specific configurations for the Dynamic Attribute

`condition`

`string`
 (with templates)

no

If it returns 

`true`
, render an image. Otherwise, render defaultValue.

The Condition field can stop an image from displaying if it contains no 
`src`
.

ImageOptions

Name

Type

Required

Description

`height`

`number`

no

Height of the image (width will auto-scale)

`width`

`number`

no

Width of the image (height will auto-scale)

`alt`

`string`

no

Alt text of the image

`noModal`

`boolean`

no

True to prevent the default modal on click of an image

Sample Usage

Example 1.

In the following example:

  • the first option would be applied when the wave is in
    `CREATED`
    or
    `PICK`
    states
  • the second when the wave has a custom attribute of the value "customValue" but is not in
    `CREATED`
    or
    `PICK`
    states (as that would have stopped at the first style)
  • the third, in any other case
1{
2  "type": "image",
3  "label":"i18n:fc.om.order.status.label",
4   "value":"{{wave.status}}",
5   "options":{
6      "styles":[
7         {
8            "matches":[
9               "CREATED",
10               "PICK"
11            ],
12            "icon":{
13               "name":"MdShoppingBasket"
14            }
15         },
16         {
17            "value":"{{wave.attributes.byName.customAttribute}}",
18            "matches":[
19               "customValue"
20            ],
21            "icon":{
22               "name":"FaBoxOpen"
23            }
24         },
25         {
26            "icon":{
27               "name":"FaTruck"
28            }
29         }
30      ]
31   }
32}

Language: json

Name: Example 1

Description:

[Warning: empty required content area]

Example 2.

The following attribute is used to embed an image into a component.

1{
2  "type": "image",
3  "value": "{{node.attributes.byName.imageUrl}}",
4  "options": {
5                  "width": 50,
6                  "height": 50
7                },
8  "condition": "{{and node.attributes.byName.imageUrl}}"
9}

Language: json

Name: Example 2

Description:

[Warning: empty required content area]

`
`

Component Attribute

The component-type attribute allows you to embed components inside of other components that accept DynamicAttributes.

Please be aware that not all components will work particularly well in all positions!

Name

Type

Required

Description

`type`

`"component"`

yes

Choose whether the value should be displayed as text or used to render an image.

`label`

`string`

yes

String key of the key/value pair. Used as text labels in

`AttributesCard`
component and column headers in the List component. Not actually used by DynamicValue.

`value`

`string`

no

Not used in 

`component`
 attributes.

`link`

`string`

no

Not used in 

`component`
 attributes.

`options`

`MystiqueComponentInstance`

no

Component props, as you would define them anywhere else in the manifest.

`condition`

`string`
 (with templates)

no

If it returns 

`true`
, render an image. Otherwise, render defaultValue.

The Condition field can stop a component from displaying if it contains no data.

Sample usage

The following attribute is used to embed the print button component into a table column.

1{
2    "label": "i18n:fc.om.orders.index.list.column.orderValue.heading",
3    "type": "component",
4    "options": {
5        "component": "fc.button.print.download",
6        "props": {
7            "label": "Print",
8            "href": "api/v4/consignment/{{articleById.id}}/labelStream",
9            "filename": "pack-label.pdf"
10        }
11    },
12  "condition": "{{and articleById.id}}"
13}

Language: json

Name: Attribute is used to embed the print button component into a table column

Description:

Example of a

`DynamicAttribute`
 where the print button component is embedded into a table column. Check UX Configuration Common Concepts for details.  

Copyright © 2024 Fluent Retail Pty Ltd (trading as Fluent Commerce). All rights reserved. No materials on this docs.fluentcommerce.com site may be used in any way and/or for any purpose without prior written authorisation from Fluent Commerce. Current customers and partners shall use these materials strictly in accordance with the terms and conditions of their written agreements with Fluent Commerce or its affiliates.

Fluent Logo