TFDi Design Icon
TFDi Design

Making a plugin

A simple guide of the basic steps behind creating your own plugin

Setting Up

First, create the folder for your plugin in the %localappdata%\TFDi Design\smartCARS\resources\app\dist\plugins folder. In there, create a plugin.json file and fill it out as described below.

For a full source example of a working plugin, refer to the TFDi Design Flight Center plugin on GitHub.

The plugin.json

{
    "id": "com.example.pluginname",
    "name": "Plugin Name",
    "organization": "",
    "allowedCommunities": ["1"],
    "version": "0.0.1",
    "type": "user",
    "description": "An example plugin",
    "availableSettings": {
        "some_setting": {
            "name": "Enable some feature?",
            "description": "Do you want to have this feature do its tasks?",
            "type": "boolean",
            "default": false
        }
    }
}

In the above example, the fields are as follows.

  • id: The package name of the plugin. This should typically be the TLD of the organization, the common name, and the name of the plugin separated by dots (i.e. com.tfdidesign.chat)
  • name: This is the name of the plugin to be displayed to the user
  • organization: An organization name to be displayed as the author - this is an optional field
  • allowedCommunities: This an optional field consisting of an array of numeric community IDs formatted as strings that this plugin is available to - this can be used to limit access during testing or create community-specific features.
  • version: The version string of the plugin
  • type: Specifies whether this plugin is installed by a user or a community - options are user or airline
  • description: The textual description of the plugin to display to a user
  • availableSettings: An array of plugin settings (see below)

Consider security!

The allowedCommunities field serves primarily as a filter and should not be considered a security measure or protection system.

Settings

The availableSettings field of the plugin.json is an array of settings, as described below.

The settings are stored as a key-value-pair, where the key is the setting key (to be used to find the value later) and the value is the object describing the setting.

A barebones setting is as follows:

"some_setting": {
	"name": "Enable some feature?",
	"description": "Do you want to have this feature do its tasks?",
	"type": "boolean"
}

The possible settings and all of their possible configuration options are listed below. All settings can have an optional required field specifying that it must be checked and/or filled.

Boolean (Toggle)

"my_setting": {
  "type": "boolean"
}

Range (Slider)

"my_setting": {
  "type": "range",
  "min": 0,
  "max": 10,
  "step": 1
}

List (Combobox)

"my_setting": {
  "type": "list",
  "options": {
  	"option_1": "Option 1",
  	"option_2": "Some other option"
	}
}

Number

"my_setting": {
  "type": "number",
  "min": 0,
  "max": 10,
  "step": 1
}

Number

"my_setting": {
  "type": "number",
  "min": 0,
  "max": 10,
  "step": 1
}

Date

"my_setting": {
  "type": "date"
}

JSON

"my_setting": {
  "type": "json",
  "minLength": 0,
  "maxLength": 4096
}

Long Text

"my_setting": {
  "type": "longtext",
  "minLength": 0,
  "maxLength": 4096
}

Radio Button

"my_setting": {
  "type": "radio",
  "options": {
  	"option_1": "Option 1",
  	"option_2": "Some other option"
	}
}

Text

"my_setting": {
  "type": "text",
  "minLength": 0,
  "maxLength": 4096,
  "pattern": "[A-Aa-z]*",
}

Creating the UI

This is not a complete guide on creating a web interface and assumes you have at least basic experience coding in HTML, CSS, and JavaScript.

Getting Started

To start creating a plugin UI, we must first create a web application. As mentioned, we recommend using React. To get started with a React web application, see https://create-react-app.dev/docs/getting-started.

Using the UI SDK

The UI SDK contains helper functions and the UI styling. To install it, run npm install @tfdidesign/smartcars3-ui-sdk

Once your project is initialized, you may add your UI code as needed.

Once your UI is built, the output must be placed in the ui folder within your plugin.

Some web application systems require that a homepage be specified. The homepage URL of the web app will be /plugins/{your plugin ID}.

Styling

smartCARS uses Tailwind CSS as the foundation of its UI styling. Tailwind, although technically not absolutely required, is strongly recommended as the default styling is based on its presence.

All plugins should include the smartcars.css file as it will apply the default smartCARS styling to all controls and classes. We encourage developers to review the classes within this CSS file to better understand it.

Responding to Theme Customization

As each community can change its theme colors and the user can toggle light or dark mode, it is important for a UI plugin to respond to these changes. The community foreground color, background color, and current UI mode are sent as URL parameters to the plugin.

Additionally, the smartCARS UI SDK provides "applyVAColor" and "applyAppColor" functions that accept the parameters directly as given by the URL and update the CSS variables for you. This means that to support color customization and themes, you simply must use the provided classes and call the color application function. The rest is handled by smartCARS for you.

An example of how this is done in React is given below.

/*Toward the top of the file*/
import { request, applyAppColor, applyVAColor } from "@tfdidesign/smartcars3-background-sdk";


const MyComponent = () => {
  const urlParams = new URLSearchParams(window.location.search);
  const darkMode = urlParams.get("darkmode") === "true";
  const foreColor = urlParams.get("forecolor");
  const backColor = urlParams.get("backcolor");

  applyAppColor(document, darkMode);
  applyVAColor(document, foreColor, backColor);

	/* ...Other ui work */
	return (...);
};

A plugin must include two icon files in its root directory. The first must be named menu_icon_dark.png for use in dark mode, and menu_icon_light.png. If using React, this can be achieved in react by placing the two icons in the public folder within your project.

Creating a Background

To create a background plugin, a JavaScript index.js file containing the plugin entry point must be created.

Using the background SDK

A background SDK with helper functions is also available on NPM. To install it, run npm install @tfdidesign/smartcars3-background-sdk

A plugin may export onStart, acceptNotification, and onEnd function and a routes array to be used by smartCARS.

This is helpful if you want a notification to be conditionally silenced but cannot restrict the notification when it is generated. The data field of the notification is also forwarded to this function, meaning custom information added to your notification can be used to make this decision.

A full example of a barebones index.js is as follows:

module.exports = {
    onStart: (identity) => {
        //do setup
    },
    acceptNotification: (notification) => {
        return "ACCEPT";
    },
    routes: {
        get: {
            somedata: {
                description: "Endpoint to retrieve certain data. Returns object with data, takes no parameters.",
                handler: async (request, response) => {
                  return response.status(200).json({});
                },
            },
        },
    },
    onEnd: () => {
        //do cleanup
    },
};

Startup and Shutdown

The onStart function is given an identity object. It is the same as the response from the api/identity call; it is simply provided here for ease and efficiency. The onStart and onEnd calls are performed sequentially and are blocking, meaning the UI cannot continue until they have returned.

Routes

The routes object may have a get and post sub-object, both a collection of key-value-pairs that create plugin API routes. Plugins exporting routes this way is what populates the routes returned by the api/plugins call.

Accepting Notifications

Finally, the acceptNotification function will be called by smartCARS when a notification sent by (or on behalf of) that plugin is about to be displayed. This function can then return ACCEPT, QUIET, or REJECT, indicating that smartCARS should display the notification normally, quietly, or not at all, respectively.


Deployment

Once a plugin is developed, it must be deployed. To deploy a plugin, visit the Developer Center in smartCARS Central.

dev_center.png

Preparing to Upload

A packaged plugin is simply a zip file of the contents of the plugin. The plugin.json file must be at the root of the zip file (as pictured below).

files.png

Once ready, upload the plugin via the "Upload New Plugin" button in the Developer Center. This will create a new plugin based on the information in the plugin.json.

smartCARS Central will give relatively verbose error messages should a plugin not be accepted, making resolving issues easier.

To update a plugin, click the "Update" button and select the zip file containing the new plugin data.