App Display
You can customize the structure of an app's pages, menus, navigation, panels and add custom UI components.
Display Configuration
The app's user interface is defined by a JSON5 configuration file named display.json5
. The file is in a JSON5 format which approximates native JavaScript.
The display.json5 file controls the following display items:
- Multiple display definitions for various device types
- Display color theme including dark and light modes
- Menu items and options
- UI pages
- Data tables and fields
- Device data edit property panels
- Dashboards and widgets
- Configurable Options
When imported by a main.js
file, the display.json5 file will be reformatted to a display.js
JavaScript file to it can be imported.
Here is a subset example of a display.json5 file:
{
name: 'MyApp',
version: '1.0.0',
format: '1.2.0',
displays: [ {
name: 'Desktop',
expression: 'width > 1024',
description: 'Display for MyApp',
title: 'MyApp',
features: {
dash: {
actions: true,
edit: true,
database: true,
metrics: true,
}
},
themes: {
title: 'Device App',
modes: {
dark: {
logo: '/images/ioto-logo-dark.png',
...
},
light: {
logo: '/images/ioto-logo-light.png',
...
},
}
},
views: [{
path: '/', name: 'home', redirect: 'devices'
views: [
{ path: 'login', component: 'Login' },
{
path: 'devices',
menu: 'Devices'
icon: 'devices',
component: 'GenericList',
table: {
model: 'Device',
title: 'Devices',
subtitle: 'Click on a device to explore',
fields: [
{name: 'product'},
{name: 'description'},
{name: 'model'},
{name: 'id', title: 'Device ID'},
{name: '*', launch: '/devices/:id/overview'}
],
actions: {
add: { count: 0, launch: 'claim' },
release: { 'count': 2,
invoke: 'DeviceRelease', confirm: true }
}
},
panels: [ {
name: 'claim',
component: 'DeviceClaim',
button: 'Claim Device'
} ]
}
]
}]
} ]
}
Quick tour
A minimal display.json5 will consist of some top level properties, and a set of displays.
For Example
{
name: 'MyDeviceApp',
version: '1.0.0',
format: '1.2.0',
displays: [{
expression: 'width <= 640',
title: 'Mobile App',
features: {...},
themes: {...},
views: [
{ path: '/', name: 'home', views: [
{ path: 'login', component: 'Login' },
]},
...
]
}]
}
The name
is the internal name of the app. This name is not displayed to the user. The version is your app version. The format is the version of the display format and should be set to 1.2.0.
The displays
array contains one or more display definitions. Each display definition contains a matching expression that is evaluated to determine if the display should be used.
Each display definition contains a title
that is used as the application title in the navigation bar and login panel. The features
define a set of configurable options for the display.
The views
define one or more views. If a view has menu
property set, the app sidebar will display the view icon to launch the view. Views can be nested to create a multi-level navigation hierarchy. Nested views inhert the parent view's role and parent path as a prefix.
See Display properties for a full list of display properties.
Display Expressions
The expression
property is a JavaScript (like) expression that is evaluated to determine if the display should be used.
The expression is evaluated in the context of the current device and can access the following properties:
Property | Description |
---|---|
agent | The current device agent |
desktop | true if the current device is a desktop device |
height | The height of the current device |
language | The current device language |
mobile | true if the current device is a mobile device |
width | The width of the current device |
Here are some examples of expressions:
width < 640
width >= 640 && width <= 1024
width > 1024 && language == /en/
true // always use this display
Display Themes
The themes
property within a display definition defines the light and dark mode color themes for the app. It may also specify the product logo image to use, font-sizes and default date and time formats.
Here is an example themes:
themes: {
logo: '/images/logo.png',
formats: {
mstime: 'mmm d, H:MM:ss:l',
time: 'mmm d, HH:MM:ss',
fulltime: 'ddd d mmm h:MM:ss tt',
date: 'mmm d, yyyy'
},
modes: {
dark: {
dark: true,
colors: {
background: '#111217',
surface: '#000000',
primary: '#3F51B5',
secondary: '#707070',
error: '#fb6d6d',
info: '#2196F3',
success: '#4CAF50',
warning: '#FB8C00',
accent: '#82B1FF',
'on-accent': '#FFFFFF',
none: '#000000',
sidebar: '#363636',
extra: '#00CDCD',
anchor: '#1976D2',
nav: '#3F51B5',
text: '#DBDBDB',
form: '#363636',
border: '#666666',
'none-lighten-1': '#282828',
'background-lighten-1': '#080808',
'text-lighten-1': '#808080',
'border-lighten-1': '#444444'
},
variables: {
'font-size': '15px'
}
},
light: {
dark: false,
colors: {
background: '#F7F7F7',
surface: '#FFFFFF',
primary: '#3F51B5',
secondary: '#707070',
error: '#fb6d6d',
info: '#2196F3',
success: '#4CAF50',
warning: '#FB8C00',
accent: '#82B1FF',
'on-accent': '#FFFFFF',
none: '#FFFFFF',
sidebar: '#FFFFFF',
extra: '#00CDCD',
anchor: '#1976D2',
text: '#484848',
nav: '#3F51B5',
form: '#FFFFFF',
border: '#CCCCCC',
'none-lighten-1': '#FAFAFA',
'background-lighten-1': '#F0F0F0',
'text-lighten-1': '#A0A0A0',
'border-lighten-1': '#DDDDDD'
},
variables: {
'font-size': '15px'
}
}
}
},
Navigation
The DevCore
framework provides two axes of navigation:
- Sidebar for top-level items
- Horizontal tabs below the app navigation bar
The sidebar is populated with items that have a menu
property set. The horizontal tab menu is built from child views under a parent view that defines an empty tabs
array property.
On a mobile display, the tabs navigation is placed at the bottom of the page.
Views
UI pages are created for each item defined under the views
properties. Each view is a displayable page for a specific browser URL.
The view defines a name
, navigation path
and typically a rendering component
.
{
views: [
{ name: 'Home', path: '/', redirect: '/dashboard' },
{
name: 'Fleet',
path: '/fleet',
component: 'Fleet',
},
{
name: 'account',
path: '/account',
icon: '$account',
redirect: 'profile',
menu: 'Account',
tabs: [],
views: [
{
name: 'profile',
path: 'profile',
component: 'UserProfile'
},
...
]
}
]
}
If a view defines child views under a views
property, those child views are presented as tabbed menu options under the parent view if the parent defines an empty tabs
array.
Views may define a redirect
property to redirect the browser to another target view.
Table Views
The DevCore
framework provides a GenericTable component that can be used to display device data as a table.
The table component is a flexible component that can:
- Display data in pages
- Select data items for operations
- Select data via a search box
- Resize columns
- Reorder columns with drag and drop
Table views present data items that can be selected via checkboxes or by clicking on table cells. The display.json5 table definitions can specify how to respond to item selection and cell clicks via actions
.
An actions definition will specify which panels to launch or components to run when the relevant action is invoked.
{
table: {
model: 'Device',
fields: [
{name: 'product'},
{name: 'id', title: 'Device ID'},
{name: '*', launch: '/devices/:id/overview'}
],
actions: {
add: { count: 0, launch: 'claim' },
release: { count: 2, invoke: 'DeviceRelease' }
}
}
}
In this example: when a row in the table is clicked, the wild-card field definition ("*") will cause the browser will be redirected to the /devices/ID/overview
page.
If table items are selected, depending on the count of items selected, the appropriate action will cause a panel to be "launched" or component to be "invoked" as required.
Custom Views
The DevCore
framework is a VueJS single-page app that provides core components to create responsive, interactive device management apps. Custom components will thus be VueJS components.
Instead of using the GenericList component for a tabular view, you can create custom components to extend the DevCore. Custom views can be any VueJS page of your design -- the sky's the limit.
Panels
To facilitate editing the properties of a data item, you can defines UI Panels. A parent view may define zero or more panels that can be invoked to operate on selected data items from the parent view.
The panel will animate and slide out from the right side of the screen when launched by a view action or button.
Panels are defined under a views panels
property.
{
panels: [
{
name: 'claim',
component: 'DeviceClaim',
button: 'Claim Device',
width: '500px'
}
]
}
A panel has a name
and a component
to render and operate the panel. It may specify a button
which will be added to the parent view table to launch the panel. Alternatively, panels may be launched via view table actions.
Dashboards
The DevCore has a Dash
component that can be used in any view to provide a graphical canvas to display interactive widgets connected to live device data.
Some of the supported widget types are:
- button
- event
- form
- gauge
- graph
- image
- input
- led
- numeric
- progress
- sign
- table
- text
Here is an example view:
{
name: 'Overview',
title: 'Device Overview',
menu: 'Overview',
path: '/overview',
icon: '$dashboard',
component: 'Dash',
widgets: [
{
type: 'gauge',
name: 'Network IO',
data: {
model: 'Stats',
field: 'io',
},
width: '.23',
},
]
}
Widget Data
You can connect device metric or database data to widgets via the data
property.
To connect with database data, set the model
and field
properties. The model
defines the database entity model. The field
defines the database item attribute (column).
An optional where
property defines a matching expression that is used to select the qualifying item (row).
{
data: {
model: 'Test',
field: 'cpu',
where: '${name} = {cpu}',
}
}
For metric data, define the namespace
, metric
, dimensions
, statistic
and period
properties.
{
data: {
namespace: 'Embedthis/Device',
metric: 'UpdateSuccess',
dimensions: [],
statistic: 'avg'
period: 3600,
}
}
Designing Pages and Widgets
It can be an easy and effective way to design your pages and widget layouts by using the low-code App Designer. Once the page is the way you like it, you can then export the page from the Pages list. This will export a JSON5 file that can then be modified and pasted into the display.json5.
Authorizing Access
It may be required to control access to specific views based on the authorized role of a user. For example, you may only want administrators to be able to view certain resources.
The DevCore framework allows the visibility of views, panels, table columns and panel fields to be controlled depending on the user's authorized role.
By specifying a role
property, you can require that the user have at least this capability to access the designated element.
For example, to only allow access to a view by adminstrators:
{
"name": "fleet",
"component": "Fleet",
"role": "admin",
},
Configurable Options
See the Display properties for a full list of display features.
Examples
The Ioto apps distribution includes several management applications that include display.json5 files to customize the appearance of the app.