Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Table of Contents

...

Motivation

...

Often , especially when an exhibit requires some form of presets, an exhibit the developer needs will need a way to represent many instances of identically structured groups of settings. For example, imagine a simple exhibit that controls a lighting system where the goal is to change the state of the lights with different presets. Sounds simple enough; just use a DROPDOWN Dropdown setting type where the user can select one of the many preconfigured presets:

Code Block
{
    "manifest": {
        "statuses": [ ... ],
        "controls": [ ... ],
        "settings": [
			{
                "id": "lighting-presets",
                "type": "Dropdown",
                "display": "Lighting Preset",
                "items": [
                    {
                      "id": "presetId1morning",
                      "display": "My Preset Name 1Morning",
                      "order": 0
                    },
                    {
                      "id": "presetId2afternoon",
                      "display": "My Preset Name 2afternoon"
                    },
                    {
                      "id": "presetId3evening",
                      "display": "My Preset Name 3Evening"
                    }
                ]
            }
        ]
    }
}  

But what if an additional preset is added to the lighting system after the exhibit is installed? Then the exhibit developer must manually add this preset to the manifest:

Code Block
{
    "manifest": {
        "statuses": [ ... ],
        "controls": [ ... ],
        "settings": [
			{
                "id": "lighting-presets",
                "type": "Dropdown",
                "display": "Lighting Preset",
                "items": [
                    [...]
                    {
                      "id": "newPresetIdafter-hours",
                      "display": "MyAfter New PresetHours"
                    }
                ]
            }
        ]
    }
}

So if more presets need to be added post-installation, this setup will increase the technical expertise needed requires a considerable effort to update an the exhibit over its lifecycle.

Settings Lists solve this problem by allowing a developer to define groups of settings that can be dynamically created and modified after exhibit installation.

...

Setting Lists enable the dynamic creation of settings in the Gumband UI by following a predefined pre-defined schema in the manifest. The schema of the Setting List is essentially its class definition, and it defines what settings which defines the Setting fields and types that should be present in each new setting list itemSetting List instance. Once the schema is defined in the manifest, setting items, each of which contains each new setting defined in the schema, can be created Setting List instances can be manipulated through the Gumband UI. When these instances are created, modified, or deleted, the Gumband platform sends signals to the exhibit’s NodeJS SDK with the updated changes.

...

In-Depth Usage

For this example, imagine an exhibit that takes a few pieces of data to configure different presets for a screenDigital Signage display.

...

Manifest Setting List Implementation

Settings Lists are defined in the Manifest file in a similar manner to top-level settings. The only difference is that they require an additional entry property to define the schema, which is just another ; an array of settings.

Code Block
languagejson
{
    "manifest": {
        "statuses": [ ... ],
        "controls": [ ... ],
        "settings": [
			{
				"id": "screens",
				"type": "SettingsList",
				"display": "Screens",
				"order": 0, // optional
				"schema": [ // any Gumband setting types can be included
					{
                        "id": "bkg_img",
                        "type": "FileSelection",
                        "display": "Background Image",
                        "order": 0
					},
					{
                        "id": "header",
                        "type": "TextInput",
                        "display": "Header",
                        "order": 1
					},
					{
                        "id": "body",
                        "type": "TextInput",
                        "display": "Body",
                        "order": 2
					}
				]
			},
        ],
    }
}

...

Once added to the manifest and with the exhibit running, the Settings List will appear as its own setting on the Settings Page. The (0) indicates that there are currently no instances of list items in the Screens SettingList SettingsList. Click it to view, create, and modify list items.

...

It is also possible to retrieve SettingList SettingsList instances manually.

With two setting list items in the Screens SettingList SettingsList, the following code will deliver JSON-formatted data of the SettingsList schema followed by the items themselves with all associated data.

...

Individual Settings within each setting list item can be retrieved and modified manually as well:

Expand
titleNot-Working due to a Bug
Code Block
languagejs
const health_header = await gb.getSetting("screens/\"Health\"/header");
console.log(health_header);
// Prints out:
Code Block
languagejson
{
    "id": 1612,
    "manifestId": "screens/\"Health\"/header",
    "exhibitId": 146,
    "type": "TextInput",
    "display": "Header",
    "enabledOpMode": null,
    "value": "Health",
    "default": "",
    "order": 1,
    "touchless": null,
    "listId": 67,
    "items": [],
    "read": true,
    "write": true
}
Code Block
languagejs
// To update the setting's value property
await gb.setSetting("screens/\"Health\"/header", "Health: System Operational Stats");

Expand
titleCurrent Workaround

The current method for retrieving and saving a SettingsList item is to first get its id value, as listed in the previous gb.getAllSettingLists() example, above. With this id, you can retrieve or save the Setting value through a modified command: gb.exhibit.getSetting(<setting-item-id>).

Code Block
languagejs
const sl = await gb.getAllSettingLists();
const elems = sl[0].settinglistitems.find(setting => setting.listName.endsWith("Health")); // Pull out the SettingList called "Health"
const elem_id = elems.items.find(s => s.manifestId.endsWith("screens/\"Health\"/header")).id; // Narrow down to the List element with the manifestId we're looking for, get it's (database) "id" value
retrieval = await gb.exhibit.getSetting(elem_id); // elem_id = 1612
console.log(retrieval);
// Prints out:
Code Block
languagejson
{
    "id": 1612,
    "manifestId": "screens/\"Health\"/header",
    "exhibitId": 146,
    "type": "TextInput",
    "display": "Header",
    "enabledOpMode": null,
    "value": "Health",
    "default": "",
    "order": 1,
    "touchless": null,
    "listId": 67,
    "items": [],
    "read": true,
    "write": true
}

You can also update the Setting value through a similar mechanism:

Code Block
languagejs
// (see above JS example, lines 1-3)
await gb.exhibit.setSetting(elem_id, "Health: System Operational Stats")

With these callbacks and access functions provided by the NodeJS SDK, it becomes a breeze to respond to setting changes in real time or retrieve and update the List elements as a single-point-of-truth. To provide a robust means of storing intricate data, it’s possible to nest a SettingsList inside the schema of another in the Manifest. Currently up to Two levels of SettingsList nesting are supported. For example, the following modification to our original Manifest would allow any number of Images to be added to any particular Screen SettingsList instance.

Code Block
languagejson
{
    "manifest": {
        "statuses": [ ... ],
        "controls": [ ... ],
        "settings": [
			{
				"id": "screens",
				"type": "SettingsList",
				"display": "Screens",
				"order": 0, // optional
				"schema": [ // any Gumband setting types can be included
					{
                        "id": "screen_images",
						"type": "SettingsList",
						"display": "Screen Images",
						"order": 0, // optional
						"schema": [
							{
                              "id": "imgs",
                              "type": "FileSelection",
                              "display": "Images",
                              "order": 0
							}
						]
					},
					{
                        "id": "header",
                        "type": "TextInput",
                        "display": "Header",
                        "order": 1
					},
					{
                        "id": "body",
                        "type": "TextInput",
                        "display": "Body",
                        "order": 2
					}
				]
			},
        ],
    }
}