简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

ErisPulse-Dashboard

ErisPulse-Dashboard is a web management panel module directly maintained by ErisDev, providing a visual runtime management interface for ErisPulse: module start/stop, configuration editing, log viewing, event stream monitoring, and more.

Important

Dashboard is not a built-in feature of the ErisPulse framework and must be installed separately:

epsdk install Dashboard

The Dashboard also supports other ErisPulse modules registering custom management pages to the sidebar. After registration, users can directly switch to the dedicated view page of that module within the Dashboard, without needing to develop an additional standalone frontend interface.

Note

View registration is an optional feature.

  • If the Dashboard module is not installed or not loaded, calling sdk.Dashboard.register_view() will raise an exception
  • Be sure to wrap registration code with try/except to ensure other features of the module are not affected
  • It is recommended to check if Dashboard is available before registering: hasattr(sdk, 'Dashboard') and sdk.Dashboard

How It Works

Module on_load()
  → Calls sdk.Dashboard.register_view(...)
  → Dashboard backend stores view information
  → WebSocket notifies frontend
  → Frontend dynamically creates sidebar navigation item + page container
  → User clicks to view module view

Register API

sdk.Dashboard.register_view(
    id="MyModule",                    # Required, unique identifier
    title="我的模块",                  # Chinese name
    title_en="My Module",             # English name
    icon_svg='<svg>...</svg>',        # SVG icon for sidebar
    html_content='<div>...</div>',     # HTML content for the page
    js_content='function xxx() {}',    # JavaScript logic for the page
    css_content='.my-style {}',        # Optional custom CSS
    iframe_url='',                     # URL for iframe mode (either this or html_content)
    loader="loadMyModuleView",         # JS function name called when switching to this page
    group="group_extensions",          # Sidebar group
    group_title="",                    # Custom group Chinese title
    group_title_en="",                 # Custom group English title
)

Parameter Description

Parameter Type Required Description
id str Yes Unique identifier for the view, recommended to use the module name
title str No Chinese display name, defaults to id
title_en str No English display name, defaults to title
icon_svg str No Full SVG string for the sidebar icon
html_content str No* HTML content for the injected mode page
js_content str No JavaScript code for the page
css_content str No Custom CSS styles for the page
iframe_url str No* URL for iframe mode, if set, html_content is ignored
loader str No Name of the JS function automatically called when the page is activated
group str No Sidebar group identifier, default is group_extensions
group_title str No Custom Chinese title for the group
group_title_en str No Custom English title for the group

*Either html_content or iframe_url must be provided; otherwise, the page will be blank.


Two Injection Modes

Directly provide HTML, JS, and CSS strings. The Dashboard will inject the content into the page. This mode is fully consistent with the Dashboard's styling, and it is recommended to use the CSS class names provided by the Dashboard.

sdk.Dashboard.register_view(
    id="HelloPage",
    title="你好页面", title_en="Hello",
    icon_svg='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/></svg>',
    html_content='<h1 class="page-title">Hello World</h1><div class="card"><div class="card-body">这是一个示例页面</div></div>',
    group="group_tools",
)

For a complete weather module example (including API routes, JS interactions, etc.), see the Complete Module Example below.

Mode 2: iframe Embedding

The module provides its own HTML page URL (which needs to be registered separately), and the Dashboard embeds it using an iframe. This mode is suitable for scenarios requiring a completely independent UI or complex interactions.

sdk.Dashboard.register_view(
    id="MyVisualizer",
    title="数据可视化", title_en="Data Visualizer",
    iframe_url="/MyVisualizer/view",
    group="group_tools",
)

In iframe mode, a token parameter is automatically appended to the URL for authentication purposes.

Modules can specify which sidebar group the window belongs to. Dashboard provides the following built-in groups:

Group Identifier Chinese Name Position
group_overview Overview Group 1
group_events Events Group 2
group_extensions Extensions Group 3 (Default)
group_system System Group 4
group_tools Tools Group 5

Specify a built-in group name, and the module window will be appended to the end of that group:

group="group_tools"  # Appends to the "Tools" group

You can also use a custom group name (not starting with group_), and Dashboard will automatically create a new group:

group="my_group",
group_title="我的分组",
group_title_en="My Group",

Common CSS Class Names

When using the HTML injection mode in module windows, you can directly use the existing CSS class names from Dashboard to maintain visual consistency:

Class Name Purpose
page-title Page title, e.g., <h1 class="page-title">Title</h1>
card Card container
card-header Card header bar
card-body Card content area
grid-2 Two-column grid layout
grid-3 Three-column grid layout
btn Basic button
btn-primary Primary button (blue)
btn-secondary Secondary button
btn-icon Icon button
btn-danger Button for dangerous operations

Dashboard uses CSS variables to control theme colors. You can directly reference these variables in module windows:

CSS Variable Purpose
var(--bg-p) Primary background color
var(--bg-s) Secondary background color
var(--bg-t) Tertiary background color (for cards, etc.)
var(--tx-p) Primary text color
var(--tx-s) Secondary text color
var(--tx-t) Auxiliary text color
var(--bd) Border color
var(--accent) Accent color
var(--ok-c) Success color
var(--er-c) Error color

These variables automatically switch based on Dashboard's light/dark theme, so modules do not need additional handling.

Authentication and API Calls

When calling the module's own API from the JavaScript in the module window, you need to include the Dashboard's Token for authentication:

var token = localStorage.getItem('__ep_tk__');
var resp = await fetch('/YourModule/api/data', {
    headers: { 'Authorization': 'Bearer ' + token }
});
var data = await resp.json();

The module's API endpoint can decide whether to validate the Token. If validation is required, you can extract it from the request headers:

async def _api_data(self, request):
    token = request.headers.get("Authorization", "").replace("Bearer ", "")
    if not token:
        return {"error": "Unauthorized"}, 401
    return {"data": "hello"}

Complete Module Example

The following is a complete weather module example, demonstrating how to register a window, provide API data, and clean up resources upon unloading:

from ErisPulse import sdk
from ErisPulse.Core.Bases import BaseModule
from ErisPulse.Core.Event import command


class Main(BaseModule):
    def __init__(self):
        self.sdk = sdk
        self.logger = sdk.logger.get_child("Weather")
        self.config = self._load_config()

    @staticmethod
    def get_load_strategy():
        from ErisPulse.loaders import ModuleLoadStrategy
        return ModuleLoadStrategy(lazy_load=False, priority=50)

    async def on_load(self, event):
        self._register_routes()
        self._register_dashboard_view()
        self.logger.info("Weather module loaded")

    async def on_unload(self, event):
        self._unregister_routes()
        if hasattr(self.sdk, 'Dashboard') and self.sdk.Dashboard:
            self.sdk.Dashboard.unregister_view("Weather")
        self.logger.info("Weather module unloaded")

    def _load_config(self):
        config = self.sdk.config.getConfig("Weather")
        if not config:
            default = {"city": "Beijing", "api_key": ""}
            self.sdk.config.setConfig("Weather", default)
            return default
        return config

    def _register_routes(self):
        r = self.sdk.router
        r.register_http_route("Weather", "/api/current",
                              handler=self._api_current, methods=["GET"])

    def _unregister_routes(self):
        r = self.sdk.router
        try:
            r.unregister_http_route("Weather", "/api/current")
        except Exception:
            pass

    async def _api_current(self, request):
        return {
            "city": self.config.get("city", "Beijing"),
            "temp": 25,
            "humidity": 60,
        }

    def _register_dashboard_view(self):
        try:
            dashboard = self.sdk.Dashboard
            dashboard.register_view(
                id="Weather",
                title="Weather", title_en="Weather",
                icon_svg='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>',
                html_content='''
                    <h1 class="page-title">Weather Query</h1>
                    <p style="color:var(--tx-s);margin-bottom:16px">View current weather information</p>
                    <div class="grid-2">
                        <div class="card">
                            <div class="card-header">Current Weather</div>
                            <div class="card-body">
                                <div id="weather-info" style="font-size:14px;color:var(--tx-s)">Click to refresh and load</div>
                            </div>
                        </div>
                        <div class="card">
                            <div class="card-header">Actions</div>
                            <div class="card-body">
                                <button class="btn btn-primary" onclick="refreshWeather()">Refresh</button>
                            </div>
                        </div>
                    </div>
                ''',
                js_content='''
                    async function loadWeatherView() { await refreshWeather(); }
                    async function refreshWeather() {
                        var el = document.getElementById('weather-info');
                        if (!el) return;
                        el.textContent = 'Loading...';
                        try {
                            var resp = await fetch('/Weather/api/current', {
                                headers: { 'Authorization': 'Bearer ' + localStorage.getItem('__ep_tk__') }
                            });
                            var data = await resp.json();
                            el.innerHTML = '<p>City: ' + (data.city || '--') + '</p>' +
                                           '<p>Temperature: ' + (data.temp || '--') + '°C</p>' +
                                           '<p>Humidity: ' + (data.humidity || '--') + '%</p>';
                        } catch (e) {
                            el.textContent = 'Failed to load: ' + e.message;
                        }
                    }
                ''',
                loader="loadWeatherView",
                group="group_tools",
            )
        except Exception as e:
            self.logger.warning(f"Failed to register Dashboard view: {e}")

Unregistering Views

When the module is unloaded, unregister_view() should be called to clean up registered views:

async def on_unload(self, event):
    if hasattr(self.sdk, 'Dashboard') and self.sdk.Dashboard:
        self.sdk.Dashboard.unregister_view("Weather")

After unregistration, the Dashboard frontend will remove the sidebar navigation item and page content in real-time via WebSocket, without requiring a user refresh.


Notes

  1. Load Order — The Dashboard's load priority is 99999 (high priority). Your module's priority should be lower than this value (e.g., 50), ensuring the Dashboard loads first.
  2. Defensive Programming — Use try/except to wrap window registration, as the Dashboard module may not be installed or loaded.
  3. Resource Cleanup — Call unregister_view() in on_unload to remove registered windows.
  4. ID Uniqueness — The id parameter must be unique throughout the Dashboard. It is recommended to use the module name directly.
  5. SVG Icon — icon_svg should be a complete <svg> tag. It is recommended to use viewBox="0 0 24 24" and stroke="currentColor" to inherit the Dashboard's main theme color.
  6. JS Function Naming — The function names in js_content should be unique (e.g., loadWeatherView), to avoid conflicts with other modules.
  7. Dynamic Updates — After registering or unregistering windows, the Dashboard frontend will update the sidebar in real time via WebSocket, without requiring a page refresh.