@plurid/bluefig-server
v0.0.0-4
Published
Bluefig Server for Device Configuration
Downloads
3
Readme
bluefig
is intended for the configuration of devices without input/output mechanisms.
The bluefig-server
runs on the device and the user connects to it through the bluefig-client
, running on a common user terminal.
The user then interacts with the bluefig-client
, effectively changing the internal state of the bluefig-server
machine, within the limits of the views
(elements
and actions
) specified by the bluefig-server
.
Contents
Usage
The bluefig-server
will load at start a list of views
and hooks
which will determine the bluefig-client
user interface and the bluefig-server
behavior.
A bluefig view
is comprised of elements
and actions
.
The elements
will be sent by the bluefig-server
to be rendered by the bluefig-client
.
The elements
used for input (input-x
, button
) can have an action
field. When the user interacts with the element
on the bluefig-client
, the established action
will run accordingly on the bluefig-server
.
An action
is an async function
which can return another view
; either one already defined in the views
object, or something dynamically computed based on the functions payload
, the object containing all the arguments
passed from the store
.
Any action
will also have as the second argument a notify
function which will push a notification to the bluefig-client
, and as the third argument an event
function which can be used to trigger a bluefig-server
event, such as set-token
to set the access token.
Example
Considering the simple view
import {
ViewsServer,
} from '@plurid/bluefig-server';
const views: ViewsServer = {
'/': {
title: 'Index View',
elements: [
{
type: 'text',
value: 'this is a simple view',
},
{
type: 'input-text',
title: 'Input Text',
store: 'inputTextStore',
},
{
type: 'button',
title: 'Click Me',
action: 'clickAction',
},
],
actions: {
'clickAction': {
arguments: [
'inputTextStore',
],
execution: async (
payload,
) => {
console.log('Click action called', payload.inputTextStore);
},
},
},
},
};
the bluefig-client
will then render an interface with a text input field which will listen for changes and store
the content in a variable named inputTextStore
which can then be passed to the action
clickAction
, triggerable by clicking on the button
.
The bluefig-server
will output at click
> Click action called input text
Configuration
The bluefig-server
will by default load the views
and hooks
from ~/.bluefig
.
Custom views
and hooks
paths can be provided using the environment variables BLUEFIG_VIEWS_PATH
and BLUEFIG_HOOKS_PATH
.
The environment variable BLUEFIG_SERVICE_NAME
can be used to set the name appearing in the bluefig-client
scan list.
Use Cases
bluefig
can be used to:
- connect a device to Wi-Fi, by selecting from a
bluefig-server
provided list and entering the passkey; - set an administrator password on the device;
- reset device to factory settings;
- abstract the execution of complex logic, e.g. starting/stopping a process line with one button;
- read/export device analytics;
- read/write custom configuration files†;
- execute custom shell commands†;
† In order to ensure the device security, the interaction with configuration files/shell commands should be done indirectly, the bluefig-server
exposing only a limited interaction mode to the bluefig-client
.
In Use
bluefig
is used to configure:
- deserver: admin setup, user generation, Wi-Fi selection, disk formatting, docker/processes lifecycle (setup-stop-restart).
Elements
The elements
of a view
are comprised of ViewElement
s.
export type ViewElement =
| ViewText
| ViewInputText
| ViewInputSelect
| ViewInputSwitch
| ViewInputSlider
| ViewButton
| ViewImage
| ViewFile
| ViewDivider
| ViewList;
Any field of an element
, except the type
, can receive a static value (string
, boolean
, etc.), or an async function
which will be evaluated at view-request time.
Helper types
export type PromiseOf<T> = () => Promise<T>;
export type TypeOrPromiseOf<T> = T | PromiseOf<T>;
export type StringOrPromiseOf = TypeOrPromiseOf<string>;
export type StringArrayOrPromiseOf = TypeOrPromiseOf<string[]>;
export type NumberOrPromiseOf = TypeOrPromiseOf<number>;
export type BooleanOrPromiseOf = TypeOrPromiseOf<boolean>;
export type StringOrNumberOrPromiseOf = TypeOrPromiseOf<string | number>;
export type StringOrNumberOrStringNumberArrayOrPromiseOf = TypeOrPromiseOf<string | number | (string | number)[]>;
export type ViewElementsOrPromiseOf = TypeOrPromiseOf<ViewElement[]>;
text
export interface ViewText {
type: 'text';
value: StringOrPromiseOf;
selectable?: BooleanOrPromiseOf;
}
// tests/example.all.js
'/text': {
title: 'text',
elements: [
{
type: 'text',
value: 'Text',
},
],
},
input-text
export interface ViewInputText {
type: 'input-text';
title?: StringOrPromiseOf;
store: StringOrPromiseOf;
initial?: StringOrPromiseOf;
secure?: BooleanOrPromiseOf;
}
// tests/example.all.js
'/input-text': {
title: 'input text',
elements: [
{
type: 'input-text',
title: 'Input Text',
store: 'inputText',
},
],
},
input-select
export interface ViewInputSelect {
type: 'input-select';
title?: StringOrPromiseOf;
/**
* Select from the options list.
*/
options: StringArrayOrPromiseOf;
store: StringOrPromiseOf;
initial?: StringOrNumberOrStringNumberArrayOrPromiseOf;
/**
* Allow for multiple selection.
*/
multiple?: BooleanOrPromiseOf;
/**
* Set initial value, index of `options`.
*/
action?: StringOrPromiseOf;
}
// tests/example.all.js
'/input-select': {
title: 'input select',
elements: [
{
type: 'input-select',
title: 'Input Select',
store: 'inputSelect',
options: [
'one',
'two',
'three',
],
initial: 1,
},
],
},
input-switch
export interface ViewInputSwitch {
type: 'input-switch';
title: StringOrPromiseOf;
store: StringOrPromiseOf;
initial?: BooleanOrPromiseOf;
action?: StringOrPromiseOf;
}
// tests/example.all.js
'/input-switch': {
title: 'input switch',
elements: [
{
type: 'input-switch',
title: 'Input Switch',
store: 'inputSwitch',
},
],
},
input-slider
export interface ViewInputSlider {
type: 'input-slider';
title: StringOrPromiseOf;
store: StringOrPromiseOf;
initial?: NumberOrPromiseOf;
action?: StringOrPromiseOf;
maximum?: NumberOrPromiseOf;
minimum?: NumberOrPromiseOf;
step?: NumberOrPromiseOf;
}
// tests/example.all.js
'/input-slider': {
title: 'input slider',
elements: [
{
type: 'input-slider',
title: 'Input Slider',
store: 'inputSlider',
},
],
},
button
export interface ViewButton {
type: 'button';
title: StringOrPromiseOf;
action: StringOrPromiseOf;
}
// tests/example.all.js
'/button': {
title: 'button',
elements: [
{
type: 'button',
title: 'Button',
action: 'actionButton',
},
],
},
image
export type ViewImageAlignment = 'left' | 'right' | 'center';
export interface ViewImage {
type: 'image';
source: StringOrPromiseOf;
contentType?: StringOrPromiseOf;
height?: NumberOrPromiseOf;
width?: NumberOrPromiseOf;
alignment?: ViewImageAlignment | PromiseOf<ViewImageAlignment>;
}
// tests/example.all.js
'/image': {
title: 'image',
elements: [
{
type: 'image',
source: 'bluefig-logo-128x128.jpg',
},
],
},
file
export interface ViewFile {
type: 'file';
title: StringOrPromiseOf;
source: StringOrPromiseOf;
contentType?: StringOrPromiseOf;
}
// tests/example.all.js
'/file': {
title: 'file',
elements: [
{
type: 'file',
title: 'Sample File.png',
source: 'a-file.txt',
},
],
},
divider
export interface ViewDivider {
type: 'divider';
}
// tests/example.all.js
'/divider': {
title: 'divider',
elements: [
{
type: 'divider',
},
],
},
list
export interface ViewList {
type: 'list';
items: ViewElementsOrPromiseOf;
}
// tests/example.all.js
'/list': {
title: 'list',
elements: [
{
type: 'list',
items: [
{
type: 'text',
value: 'Text In List',
},
{
type: 'input-text',
title: 'Input Text In List',
store: 'inputTextInList',
},
],
},
],
},
Packages
@plurid/bluefig-server • server