ErisPulse-Dashboard
ErisPulse-Dashboard は、ErisDev が直接管理する Web 管理パネルモジュール であり、ErisPulse に視覚的な実行時管理インターフェースを提供します。モジュールの起動・停止、設定の編集、ログの表示、イベントストリームの監視などが可能です。
Important
Dashboard は ErisPulse フレームワークの組み込み機能ではなく、個別にインストールする必要があります:
epsdk install Dashboard
Dashboard は、他の ErisPulse モジュールがサイドバーにカスタム管理ページを登録することもサポートしています。登録後、ユーザーは Dashboard でそのモジュールの専用ウィンドウページに切り替えることができ、追加のフロントエンド開発を必要としません。
Note
ウィンドウの登録はオプション機能です。
- Dashboard モジュールがインストールされていない、またはロードされていない場合、
sdk.Dashboard.register_view()を呼び出すと例外が発生します - 他のモジュール機能に影響を与えないように、登録コードを
try/exceptで囲むことを推奨します - 登録前に Dashboard の利用可能性を確認することを推奨します:
hasattr(sdk, 'Dashboard') and sdk.Dashboard
動作原理
モジュール on_load()
→ sdk.Dashboard.register_view(...) を呼び出す
→ Dashboard は後端にウィンドウ情報を保存
→ WebSocket でフロントエンドに通知
→ フロントエンドは動的にサイドバーのナビゲーション項目とページコンテナを作成
→ ユーザーがクリックするとモジュールのウィンドウが表示される
APIの登録
sdk.Dashboard.register_view(
id="MyModule", # 必須、一意な識別子
title="私のモジュール", # 中文名
title_en="My Module", # 英文名
icon_svg='<svg>...</svg>', # サイドバーのアイコン SVG
html_content='<div>...</div>', # ページ HTML 内容
js_content='function xxx() {}', # ページ JavaScript ロジック
css_content='.my-style {}', # オプションのカスタム CSS
iframe_url='', # iframe モードの URL(html_content と二択)
loader="loadMyModuleView", # このページに切り替わる際に呼び出される JS 関数名
group="group_extensions", # サイドバーのグループ
group_title="", # カスタムグループの中文名
group_title_en="", # カスタマグループの英文名
)
パラメータの説明
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
id |
str |
はい | ウィンドウの一意な識別子、モジュール名を使用することを推奨 |
title |
str |
いいえ | 中文表示名、デフォルトは id を使用 |
title_en |
str |
いいえ | 英文表示名、デフォルトは title を使用 |
icon_svg |
str |
いいえ | サイドバーのアイコンの完全な SVG 文字列 |
html_content |
str |
いいえ* | インジェクションモードのページ HTML 内容 |
js_content |
str |
いいえ | ページ JavaScript コード |
css_content |
str |
いいえ | ページのカスタム CSS スタイル |
iframe_url |
str |
いいえ* | iframe モードの URL、設定すると html_content は無視される |
loader |
str |
いいえ | ページがアクティブになった際に自動的に呼び出される JS 関数名 |
group |
str |
いいえ | サイドバーのグループ識別子、デフォルトは group_extensions |
group_title |
str |
いいえ | カスタムグループの中文タイトル |
group_title_en |
str |
いいえ | カスタムグループの英文タイトル |
*
html_contentとiframe_urlのどちらか一方は必ず提供する必要がある。両方指定しない場合、ページは空白になる。
2 種の注入モード
モード 1:HTML/JS 注入(推奨)
HTML、JS、CSS の文字列を直接提供し、Dashboard がページに内容を注入します。このモードでは Dashboard のスタイルと完全に一致し、Dashboard が提供する CSS クラス名の使用が推奨されます。
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",
)
API ルート、JS によるインタラクションなどを含む、完全な天気モジュールの例は、下記の 完全なモジュールの例 を参照してください。
モード 2:iframe 埋め込み
独自の HTML ページの URL を提供し(独自にルートを登録する必要があります)、Dashboard が iframe で埋め込みます。完全に独立した UI または複雑なインタラクションが必要な場合に適しています。
sdk.Dashboard.register_view(
id="MyVisualizer",
title="データ可視化", title_en="Data Visualizer",
iframe_url="/MyVisualizer/view",
group="group_tools",
)
iframe モードでは、認証のために URL に
tokenパラメータが自動的に追加されます。
サイドバーのグループ化
モジュールは、ウィンドウが所属するサイドバーのグループを指定できます。Dashboard には、以下のグループが内蔵されています:
| グループ識別子 | 中文名 | 位置 |
|---|---|---|
group_overview |
概観 | 第1グループ |
group_events |
イベント | 第2グループ |
group_extensions |
拡張機能 | 第3グループ(デフォルト) |
group_system |
システム | 第4グループ |
group_tools |
ツール | 第5グループ |
内蔵されたグループ名を指定すると、モジュールのウィンドウはそのグループの末尾に追加されます:
group="group_tools" # "ツール"グループに追加
group_ で始まらないカスタムグループ名を使用することもできます。Dashboard は自動的に新しいグループを作成します:
group="my_group",
group_title="私のグループ",
group_title_en="My Group",
一般的 CSS クラス名
モジュールウィンドウで HTML インジェクションモードを使用する場合、ダッシュボードで既に用意されている CSS クラス名を使用することで、視覚的な一貫性を保つことができます。
| クラス名 | 用途 |
|---|---|
page-title |
ページタイトル、例: <h1 class="page-title">タイトル</h1> |
card |
カードコンテナ |
card-header |
カードのタイトルバー |
card-body |
カードのコンテンツ領域 |
grid-2 |
2 列のグリッドレイアウト |
grid-3 |
3 列のグリッドレイアウト |
btn |
基本ボタン |
btn-primary |
主なボタン(青色) |
btn-secondary |
次要なボタン |
btn-icon |
アイコン付きボタン |
btn-danger |
危険な操作を表すボタン |
ダッシュボードは CSS 変数を使ってテーマカラーを制御しており、モジュールウィンドウでも直接参照することができます。
| CSS 変数 | 用途 |
|---|---|
var(--bg-p) |
主な背景色 |
var(--bg-s) |
次の背景色 |
var(--bg-t) |
3 番目の背景色(カードなど) |
var(--tx-p) |
主な文字色 |
var(--tx-s) |
次の文字色 |
var(--tx-t) |
補助的な文字色 |
var(--bd) |
ボーダー色 |
var(--accent) |
強調色 |
var(--ok-c) |
成功色 |
var(--er-c) |
エラーカラー |
これらの変数は、ダッシュボードのライト/ダークテーマに応じて自動的に切り替えられ、モジュール側で追加の処理は不要です。
認証と API 呼び出し
モジュールウィンドウの JS で、モジュール自身の API を呼び出す際には、Dashboard のトークンを付けて認証を行う必要があります:
var token = localStorage.getItem('__ep_tk__');
var resp = await fetch('/YourModule/api/data', {
headers: { 'Authorization': 'Bearer ' + token }
});
var data = await resp.json();
モジュールの API エンドポイントは、トークンの検証を行うかどうかを独自に決定できます。検証が必要な場合は、リクエストヘッダーから抽出できます:
async def _api_data(self, request):
token = request.headers.get("Authorization", "").replace("Bearer ", "")
if not token:
return {"error": "Unauthorized"}, 401
return {"data": "hello"}
完全なモジュールの例
以下は、ウィンドウの登録、APIデータの提供、およびアンロード時にリソースをクリーンアップする方法を示す、完全な天気モジュールの例です。
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("天気モジュールがロードされました")
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("天気モジュールがアンロードされました")
def _load_config(self):
config = self.sdk.config.getConfig("Weather")
if not config:
default = {"city": "北京", "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", "北京"),
"temp": 25,
"humidity": 60,
}
def _register_dashboard_view(self):
try:
dashboard = self.sdk.Dashboard
dashboard.register_view(
id="Weather",
title="天気", 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">天気照会</h1>
<p style="color:var(--tx-s);margin-bottom:16px">現在の天気情報を表示します</p>
<div class="grid-2">
<div class="card">
<div class="card-header">現在の天気</div>
<div class="card-body">
<div id="weather-info" style="font-size:14px;color:var(--tx-s)">クリックして更新</div>
</div>
</div>
<div class="card">
<div class="card-header">操作</div>
<div class="card-body">
<button class="btn btn-primary" onclick="refreshWeather()">更新</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 = '読み込み中...';
try {
var resp = await fetch('/Weather/api/current', {
headers: { 'Authorization': 'Bearer ' + localStorage.getItem('__ep_tk__') }
});
var data = await resp.json();
el.innerHTML = '<p>都市: ' + (data.city || '--') + '</p>' +
'<p>温度: ' + (data.temp || '--') + '°C</p>' +
'<p>湿度: ' + (data.humidity || '--') + '%</p>';
} catch (e) {
el.textContent = '読み込み失敗: ' + e.message;
}
}
''',
loader="loadWeatherView",
group="group_tools",
)
except Exception as e:
self.logger.warning(f"Dashboardウィンドウの登録に失敗しました: {e}")
視窗の登録解除
モジュールのアンロード時に、unregister_view() を呼び出して登録済みの視窗をクリーンアップする必要があります。
async def on_unload(self, event):
if hasattr(self.sdk, 'Dashboard') and self.sdk.Dashboard:
self.sdk.Dashboard.unregister_view("Weather")
登録解除後、Dashboard のフロントエンドは WebSocket を介してサイドバーのナビゲーション項目とページコンテンツをリアルタイムに削除します。ユーザーによるリフレッシュは不要です。
注意事項
- ロード順序 — Dashboard のロード優先度は
99999(高優先度)です。あなたのモジュールの優先度はこの値より低くする必要があります(例:50)。これにより、Dashboard が先にロード完了するようにします。 - 防御的プログラミング — Dashboard モジュールがインストールされていない、またはロードされていない可能性があるため、ウィンドウを登録する際には
try/exceptで囲んでください。 - リソースのクリーンアップ —
on_unloadでunregister_view()を呼び出し、登録されたウィンドウを削除します。 - ID の一意性 —
idパラメータは、Dashboard 全体で一意である必要があります。モジュール名を直接使用することを推奨します。 - SVG アイコン —
icon_svgは完全な<svg>タグである必要があります。推奨サイズはviewBox="0 0 24 24"です。stroke="currentColor"を使用して、Dashboard のテーマ色を継承します。 - JS 関数名 —
js_content内の関数名は一意である必要があります(例:loadWeatherView)。他のモジュールとの衝突を避けるためです。 - 動的更新 — モジュールがウィンドウを登録または解除した後、Dashboard のフロントエンドは WebSocket を使用してサイドバーをリアルタイムに更新します。ページをリフレッシュする必要はありません。