Client API
A BotMate plugin can interact with both the back end and the front end of the application. The Client API is about the front end part, i.e. it allows a plugin to customize the application's dashboard.
A Client API consist the following -
- an entry point which is client.tsx
- lifecycle functions
- and several custom React hooks and variables to interact with the dashboard
Entry file
The entry file for the Client API is [plugin-name]/src/client/client.tsx. This file exports a class that extends the client plugin with the following functions available:
Lifecycle functions
beforeLoad
This function runs every time the plugin is about to load.
It usually includes tasks like registering new routes or adding items to the sidebar.
When the page loads, the beforeLoad
function is called for each plugin.
load
This function runs after all the beforeLoad
functions have finished.
It can include logic that depends on other plugins being enabled.
This allows plugins to create and share plugin hooks that other plugins can use.
Available actions
The Client API provides plugins with access to various small APIs for performing actions. Refer to this table for details:
Sidebar API
The Sidebar API allows a plugin to add a new item to the main sidebar through the addToSidebar()
function with the following parameters:
Parameter | Type | Description |
---|---|---|
label | String | The text to show when hovered |
path | String | Location to open when clicked |
icon | LucideIcon | Icon to show on in sidebar |
regex? | RegEx | Regular expression for the path |
This by itself does not create a new page, but it adds a new item to the sidebar that can be clicked to open a new page. To create new pages, use the Route API.
Example:
export class MyPlugin extends Plugin {
beforeLoad() {
this.addToSidebar({
label: 'Moderation',
icon: ShieldIcon,
path: '/moderation',
regex: /^\/moderation/,
});
}
}
View screenshot
Route API
This API enables you to add register routes to the application, although it is recommended to use this API once throughout your plugin. This allows plugins to add new pages to the dashboard. Unlike the Settings API, the Route API is more flexible and can be used to create complex pages with multiple routes. Here is the list of parameters:
Parameter | Type | Description |
---|---|---|
path | String | Path to register on the dashboard |
element | ReactElement | Component to load when the path is visited |
Let's say you want to create a moderation plugin with multiple pages like Home
, Welcome
, Filters
, and Anti-Spam
. You can use the Route API to achieve this.
Here is an example:
this.addRoute({
path: '/moderation/*',
element: (
<Layout>
<Routes>
<Route index element={<HomePage />} />
<Route path="/welcome" element={<WelcomePage />} />
<Route path="/filters" element={<FiltersPage />} />
<Route path="/anti-spam" element={<AntiSpamPage />} />
</Routes>
</Layout>
),
});
But to open the moderation plugin, you need to add a sidebar item for it. You can do this by using the Sidebar API.
Settings API
The Settings API allows you to provide a settings page for your plugin. This is useful for plugins that require user configuration.
import React from 'react';
import { Plugin } from '@botmate/client';
import SettingsPage from './settings';
export class RandomNumberGenerator extends Plugin {
displayName = 'Random Number Generator';
async beforeLoad() {
this.provideSettings(<SettingsPage />);
}
}
The provideSettings
function takes a React component as an argument. This component will be rendered when the user clicks on the plugin settings.
It is recommended to use settings page for plugins that require less configuration, for more complex configuration and UI, use the Route API.
React hooks
Client API also consists several React hooks which can help you rapidy develop plugins. Here are the list of available hooks.
usePluginConfig
This hook enables the saving and loading of plugin configurations for the bot. By default, it saves configurations to the currently active bot on the dashboard using key-value pairs. These configurations can subsequently be utilized in the Server API, allowing users to customize your plugin with a variety of options.
This hook can be used inside the plugin routes or the settings page.
Example:
function SettingsPage() {
const config = usePluginConfig();
const inputRef = React.useRef < HTMLInputElement > null;
return (
<div className="space-y-2">
<Input
ref={inputRef}
defaultValue={config.get('message.start')}
placeholder="Enter start message"
/>
<Button
onClick={async () => {
const text = inputRef.current?.value;
if (text) {
await config.save('message.start', text);
toast.success('Message saved');
} else {
toast.error('Please enter start message');
}
}}
>
Save
</Button>
</div>
);
}
In the code above, we are reading text from an input field and saving in the database using the config.save
function.
This saves the value of the input fields with the key message.start
in the database.
Note: Uninstalling the plugin will remove all the configurations saved by the plugin.
createPluginRPC
This hook is used to create an RPC object that can be used to call functions defined in the server API of the plugin. It is used to call RPC functions of the plugin on the server with type safety.
Here is an example of using query -
import { createPluginRPC } from '@botmate/client';
import type { RPC } from '../server';
const rpc = createPluginRPC<RPC>();
function Page() {
const bot = useCurrentBot();
const [searchParams] = useSearchParams();
const page = searchParams.get('page') || '1';
const telegramChats = rpc.getTelegramChats.useQuery(parseInt(page));
return (
<div>
{telegramChats?.map((chat) => (
<div key={chat.id}>{chat.title}</div>
))}
</div>
);
}
usePluginRPC (deprecated)
Note: This hook is deprecated and will be removed in future versions. Use
createPluginRPC
instead.
This React hook accepts two arguments: the first is the name of the function to be called,
and the second is the parameter to pass to that function. It is used to call RPC functions of the plugin on the server.
The hook returns the result of the function call, while it's fetching, the result will be undefined
.
- Use this hook to call functions defined in the server API of the plugin.
- The function name should be the same as the function name defined in the server API.
Example:
// page.tsx
import type { RPC } from '../server';
const telegramChats = usePluginRPC<RPC>('getTelegramChats', 1);
return (
<div>
{telegramChats?.map((chat) => (
<div key={chat.id}>{chat.title}</div>
))}
</div>
);
In the code above, we are calling the getTelegramChats
function defined in the server API of the plugin.
// server.ts
export class MyPlugin extends Plugin {
rpc = getRPC(this);
displayName = 'My Plugin';
...
}
const getRPC = (plugin: Plugin) => ({
getTelegramChats: async () => {
const chats = await telegram.repository.find();
return chats;
},
});
export type RPC = ReturnType<typeof getRPC>;
usePluginRPCMutation (deprecated)
Note: This hook is deprecated and will be removed in future versions. Use
createPluginRPC
instead.
This hook is used to call RPC functions that modify the state of the plugin on the server. It can also be called dynamically based on user actions, such as on button clicks or form submissions.
- Use this hook to call functions defined in the server API of the plugin.
- The hook returns a promise that resolves when the function call is successful.
- The function name should be the same as the function name defined in the server API.
Example:
// page.tsx
import type { RPC } from '../server';
const sendMessage = usePluginRPCMutation<RPC>('sendMessage');
return (
<Button
onClick={async () => {
await sendMessage({ text: 'Hello, world!' });
}}
>
Send Message
</Button>
);
In the code above, we are calling the sendMessage
function defined in the server API of the plugin.
// server.ts
export class MyPlugin extends Plugin {
rpc = getRPC(this);
displayName = 'My Plugin';
...
}
const getRPC = (plugin: Plugin) => ({
sendMessage: async (params: { text: string }) => {
await telegram.sendMessage(params.text);
},
});
export type RPC = ReturnType<typeof getRPC>;