@clusterio/web_ui
Version:
Clusterio web interface implementation
217 lines (205 loc) • 6.59 kB
text/typescript
import type React from "react";
import type { AccountRole, FieldDefinition, Logger, PluginWebpackEnvInfo } from "@clusterio/lib";
import type { Control } from "./util/websocket";
/**
* Plugin supplied login form
*/
export interface PluginLoginForm {
/**
* Internal name of the login form, this should start with the
* plugin name followed by a dot.
*/
name: string;
/** Name displayed above this form in the login window. */
title: string;
/**
* React component that's rendered for this login form. This is
* supplied the setToken function via its props which should be called
* when an authentication token is aquired via this form.
*/
Component: React.ComponentType<{ setToken(token: string): void }>;
}
export interface InputComponentProps {
disabled?: boolean,
fieldDefinition: FieldDefinition,
value: null | boolean | number | string,
onChange: (value: null | boolean | number | string) => void,
}
export type InputComponent = React.ComponentType<InputComponentProps>;
export type UserAccount = {
/** Name of the currently logged in account. */
name: string;
/** Roles of the corrently logged in account. */
roles: AccountRole[];
/** Check if the currently logged in account has the given permission. */
hasPermission: (permission: string) => boolean | null;
/** Check if the currently logged in account has any of the given permissions. */
hasAnyPermission: (...permissions: string[]) => boolean | null;
/** Check if the currently logged in account has all of given permissions. */
hasAllPermission: (...permissions: string[]) => boolean | null;
/** Logs out of the web interface. */
logOut: () => void;
};
/**
* Plugin supplied pages
*/
export interface PluginPage {
/** URL path to this page. */
path: string;
/**
* If present and this path matches one of the pages in the sidebar it
* will cause that sidebar entry to be highlighted as active.
*/
sidebarPath?: string;
/**
* If present group this entry under a group of the given name in the
* sidebar.
*/
sidebarGroup?: string;
/**
* If present creates an entry in the sidebar for this page with the
* given text.
*/
sidebarName?: string;
/**
* A react node which is rendered when this page is navigated to.
* Should render a PageLayout.
*/
content?: React.ReactElement;
/**
* Permission to access page. function are expected to throw an error if access is deny.
*/
permission?: string | ((account: UserAccount) => (boolean|null));
};
/**
* Base class for web interface plugins
*/
export default class BaseWebPlugin {
/**
* Contents of the plugin's package.json file
*/
package: any;
/**
* Logger for this plugin
*
* Instance of winston Logger for sending log messages from this
* plugin. Supported methods and their corresponding log levels are
* `error`, `warn`, `audit`, `info` and `verbose`.
*/
logger: Logger;
/**
* List of login forms provided by this plugin
*/
loginForms: PluginLoginForm[] = [];
/**
* List of pages provided by this plugin
*/
pages: PluginPage[] = [];
/**
* Additional Config inputComponent types available to render config
* entries with.
*/
inputComponents: Record<string, InputComponent> = {};
/**
* Extra react component to add to core components
*
* Interface to augment core components of the web UI. Setting a
* component as one of the supported properties of this object will
* cause the web UI to render it when displaying that component,
* usually at the end. Each component will receive a `plugin` param
* which is the instance of the web plugin that contained the
* component extra.
*/
componentExtra: {
/** Placed at the end of the controller page. */
ControllerPage?: React.ComponentType,
/** Placed at the end of the hosts list page. */
HostsPage?: React.ComponentType,
/**
* Placed at the end of each host page. Takes a `host` param which
* is the host the page is displayed for.
*/
HostViewPage?: React.ComponentType,
/** Placed at the end of the instance list page. */
InstancesPage?: React.ComponentType,
/**
* Placed at the end of each instance page. Takes an `instance`
* param which is the instance the page is displayed for.
*/
InstanceViewPage?: React.ComponentType,
/** Placed at the end of the users list page. */
UsersPage?: React.ComponentType,
/**
* Placed at the end of each user page. Takes a `user` param which
* is the user object the page is displayed for.
*/
UserViewPage?: React.ComponentType,
/** Placed at the end of the roles list page. */
RolesPage?: React.ComponentType,
/**
* Placed at the end of each role page. Takes a `role` param which
* is the role object the page is displayed for.
*/
RoleViewPage?: React.ComponentType,
} = {};
constructor(
/**
* Webpack container for this plugin
*/
public container: any,
packageData: any,
/**
* The plugin's own info module
*/
public info: PluginWebpackEnvInfo,
/**
* Control link to the controller
*
* Not connected at the time init is invoked.
*/
public control: Control,
logger: Logger,
) {
this.package = packageData;
this.logger = logger.child({ plugin: this.info.name }) as unknown as Logger;
}
/**
* Called immediately after the class is instantiated.
*/
async init() { }
/**
* Called when an event on the controller connection happens
*
* The event param may be one of connect, drop, resume and close and has
* the following meaning:
*
* ##### connect
*
* Invoked when a new connection to the controller has been established.
*
* ##### drop
*
* Invoked when a connection loss is detected between the control link
* and the controller. Plugins should respond to this event by throtteling
* messages it is sending to the controller to an absolute minimum.
*
* Messages sent over a dropped controller connection will get queued up in
* memory in the browser and sent all in one go when the connection is
* re-established again.
*
* ##### resume
*
* Invoked when the connection that had previously dropped is
* re-established.
*
* ##### close
*
* Invoked when the connection to the controller has been closed. This
* typically means the controller has shut down. Plugins should not
* send any messages that goes to or via the controller after the
* connection has been closed and before a new one is established.
*
* @param event - one of connect, drop, resume and close
*/
onControllerConnectionEvent(event: "connect" | "drop" | "resume" | "close") { }
}