Frontend

A plugin performs all of its modifications to the heedy frontend through the use of a single javascript module. Heedy is made aware of this module in the plugin’s heedy.conf, by setting the frontend variable in the plugin’s block. The variable is set to the module’s path relative to the public/static directory in the plugin’s folder.

plugin "myplugin" {
    frontend = "myplugin/main.mjs"
}

While not strictly required, it is recommended that you prefix the module path with your plugin name (as was done here). In this case, heedy’s frontend code will look for a javascript module file served at /static/myplugin/main.mjs. Then, for heedy’s backend to serve the file at the correct location, you need to create a main.mjs file, and place it at public/static/myplugin/main.mjs in your plugin’s folder. The minimal content of your main.mjs is the following:

function setup(frontend) {
  // Initialize your plugin's frontend here
}
export default setup;

The frontend object

Using the frontend object passed into your module’s setup function, you can tell heedy’s UI how to accommodate your plugin. The UI is built with Vue, so the frontend object allows you to directly deal with Vue components:

function setup(frontend) {
  // Register a vuex store for your plugin (optional)
  frontend.store.registerModule("myplugin", vuexModule);
  // Add a route to the ui, which will be accessibe from `/#/myplugin/myroute`
  frontend.addRoute({
    path: "/myplugin/myroute",
    component: MyComponent
  });
  // Add an item to the main menu that will redirect to the registered route
  frontend.addMenuItem({
    key: "mypluginMenuItem",
    text: "My Plugin",
    icon: "home",
    route: "/myplugin/myroute",
    location: "primary"
  });
}
export default setup;

Injected Functionality

Each heedy plugin can attach additional functionality to the frontend object (i.e. inject their own objects into the frontend). In a bare heedy install, the following registered classes extend the frontend’s functionality:

Each of these can be accessed as a property of the frontend object (ex: frontend.websocket, frontend.worker, frontend.timeseries).

Frontend API

class Frontend(Vue, appinfo, store)

The frontend object is passed to the setup functions of each plugin, and exposes the APIs necessary to augment heedy’s UI.

Examples:

function setup(frontend) {
   frontend.addRoute({
       path: "/myplugin/myroute",
       component: MyComponent
   });
}
Frontend.addMenuItem(m)

Add an item to the main app menu.

Arguments
  • m (object) – Menu item to add. It is given an object with items “key”, which is a unique ID, text, the text to display, icon, the icon to show, and route, which is the route to navigate to. Optionally also has a “location” attribute which hints at where the user might want the menu (primary,secondary,spaced_primary). Can also have “component” which is a vue component to display instead of icon. Be aware that the component must have a “state” prop, where it is told how to behave i.e. whether the menu is small, on bottom, etc.

Frontend.addRoute(r)

Routes sets up the app’s routes, one by one. It allows for overriding routes, however, it only allows overriding the base route, it does not handle child routes. To set up different routes for logged in users and the public, the plugin can check if info.user is null.

Arguments
  • r (*) – a single route element.

Frontend.info

This property contains information passed in from the server, and is used to set up the session.

Examples:

frontend.info = {
 // Whether the current session is of an admin user
 admin: true,
 // The list of plugins with frontend code,
 // as well as paths to their modules
 plugins: [
     {name: "heedy", path: "heedy/main.mjs"},
     ...
     {name: "timeseries", path: "timeseries/main.mjs"},
     {name: "myplugin", path: "myplugin/main.mjs"}
 ],
 // The currently logged in user. If no user is logged in,
 // this field is null. Checking if frontend.info.user
 // is null is the recommended way to modify plugin features
 // for logged in users.
 user: {
     username: "myuser",
     name: "My User",
     icon: "base64:...",
     public_read: false,
     users_read: false
 }
}
Frontend.inject(name, toInject)

A plugin can inject its own API into the frontend object, so that all plugins loaded after it have access to it.

Arguments
  • name (string) – the name at which to inject the object

  • toInject (*) – the object to inject into the frontend

Examples:

class MyAPI {
   constructor() {}
   myfunction() {}
}
frontend.inject("myapi", new MyAPI());
frontend.myapi.myfunction();
Frontend.notFound

The vue component to display when linked to a route that was not registered. For example, the notFound component will be displayed when the path /#/blahblah is used.

Examples:

frontend.notFound = MyNotFoundComponent
Frontend.rest(method, uri, data=null, params=null, json=true)

An async helper function that allows querying the REST API explicitly. It explicitly returns the decoded json object, or returns the error response.

Arguments
  • method (string) – HTTP verb to use (GET/POST/…)

  • uri (string) – uri to query (api/users/…)

  • data (object) – optional object to send as a json payload. If the method is GET, the data is sent as url params.

  • params (object) – params to set as url params

  • json (boolean) – whether data should be sent as standard POST url encoded or as json

Returns

object – an object with two fields, response and data. response gives a fetch query response object, and data contains the response content decoded from json.

Examples:

let username = "myuser"
let res = await frontend.rest("GET",`api/users/{username}`,{
 icon: true // urlparam to include icon with request
})
if (!res.response.ok) {
 console.log("Failed:",res.data.error_description);
} else {
 console.log("User:",res.data);
}
Frontend.router

The vue router used for the frontend. This value is only initialized after the initial setup, so it is not available when initializing plugins.

Frontend.store

The vuex store used for the frontend. A plugin can set up its own vuex modules to manage its state.

Examples:

frontend.store.registerModule("myplugin",{
 state: {count: 0},
 mutations: {
     increment(state) {state.count++}
 }
});
Frontend.theme

The vue component to use as the main theme for the frontend. The theme renders the main menu, and holds the router that shows individual pages.

Examples:

frontend.theme = MyThemeComponent
Frontend.vue

The Vue instance. This is mainly to be used to register components and plugins.

Examples:

frontend.vue.use(MyVuePlugin);
frontend.vue.component("mycomponent",MyComponent);