Skip to content

Commit 1622f6a

Browse files
authored
feat: replace dashboard with Solid SPA
Replace the legacy dashboard with the Solid.js SPA, add frontend build fallback support, and add required PR checks.
1 parent da0b30c commit 1622f6a

107 files changed

Lines changed: 7558 additions & 9976 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/codeql.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: CodeQL
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
push:
7+
branches: [main]
8+
schedule:
9+
- cron: "24 3 * * 1"
10+
11+
permissions:
12+
actions: read
13+
contents: read
14+
security-events: write
15+
16+
jobs:
17+
analyze:
18+
name: Analyze (python)
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
24+
- name: Initialize CodeQL
25+
uses: github/codeql-action/init@v4
26+
with:
27+
languages: python
28+
29+
- name: Perform CodeQL analysis
30+
uses: github/codeql-action/analyze@v4
31+
with:
32+
category: "/language:python"

.github/workflows/dashboard-ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Dashboard CI
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
build:
12+
name: build
13+
runs-on: ubuntu-latest
14+
defaults:
15+
run:
16+
working-directory: web_src
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
21+
- name: Set up pnpm
22+
uses: pnpm/action-setup@v4
23+
with:
24+
version: 10
25+
26+
- name: Set up Node.js
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: "22"
30+
cache: pnpm
31+
cache-dependency-path: web_src/pnpm-lock.yaml
32+
33+
- name: Install dashboard dependencies
34+
run: pnpm install --frozen-lockfile
35+
36+
- name: Type-check dashboard
37+
run: pnpm typecheck
38+
39+
- name: Test dashboard
40+
run: pnpm test
41+
42+
- name: Build dashboard
43+
run: pnpm build
44+
45+
- name: Verify committed dashboard artifacts
46+
working-directory: .
47+
run: git diff --exit-code -- web_res/static/dashboard

.github/workflows/format-check.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Code Format Check
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
format-check:
12+
name: format-check
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout repository
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Check whitespace formatting
21+
run: git diff --check "${{ github.event.pull_request.base.sha }}" "${{ github.sha }}"

.github/workflows/smoke-test.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Smoke Test
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
smoke-test:
12+
name: Smoke test (${{ matrix.os }}, Python ${{ matrix.python-version }})
13+
runs-on: ${{ matrix.os }}
14+
env:
15+
PYTHONPATH: ${{ github.workspace }}/..
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
os: [ubuntu-latest, windows-latest]
20+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Expose legacy package import path
26+
if: runner.os != 'Windows'
27+
run: ln -sfn "$GITHUB_WORKSPACE" "$(dirname "$GITHUB_WORKSPACE")/self_learning_EterU"
28+
29+
- name: Expose legacy package import path on Windows
30+
if: runner.os == 'Windows'
31+
shell: pwsh
32+
run: |
33+
$aliasPath = Join-Path (Split-Path $env:GITHUB_WORKSPACE -Parent) "self_learning_EterU"
34+
if (-not (Test-Path $aliasPath)) {
35+
New-Item -ItemType Junction -Path $aliasPath -Target $env:GITHUB_WORKSPACE | Out-Null
36+
}
37+
38+
- name: Set up Python
39+
uses: actions/setup-python@v5
40+
with:
41+
python-version: ${{ matrix.python-version }}
42+
cache: pip
43+
cache-dependency-path: requirements-test.txt
44+
45+
- name: Install smoke test dependencies
46+
if: matrix.python-version != '3.14'
47+
run: |
48+
python -m pip install --upgrade pip
49+
python -m pip install -r requirements-test.txt
50+
python -m pip install "astrbot>=4.14,<4.15" aiohttp "emoji==2.14.1" "hypercorn==0.17.3" jieba quart "quart_cors==0.8.0" pydantic "sqlalchemy[asyncio]" aiosqlite asyncpg "cachetools>=5.3.0" apscheduler "defusedxml>=0.7.1"
51+
52+
- name: Install smoke test dependencies for Python 3.14
53+
if: matrix.python-version == '3.14'
54+
run: |
55+
python -m pip install --upgrade pip
56+
python -m pip install -r requirements-test.txt
57+
python -m pip install "astrbot>=4.24,<5" aiohttp "emoji==2.14.1" "hypercorn==0.17.3" jieba quart "quart_cors==0.8.0" pydantic "sqlalchemy[asyncio]" aiosqlite asyncpg "cachetools>=5.3.0" apscheduler "defusedxml>=0.7.1"
58+
59+
- name: Compile Python files
60+
run: python -m compileall .
61+
62+
- name: Run smoke tests
63+
run: python -m pytest tests/integration/test_package_imports.py tests/integration/test_webui_static_assets.py --no-cov

.github/workflows/unit-tests.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Unit Tests
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
pytest:
12+
name: Run pytest suite
13+
runs-on: ubuntu-latest
14+
env:
15+
PYTHONPATH: ${{ github.workspace }}/..
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
20+
- name: Expose legacy package import path
21+
run: ln -sfn "$GITHUB_WORKSPACE" "$(dirname "$GITHUB_WORKSPACE")/self_learning_EterU"
22+
23+
- name: Set up Python
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: "3.11"
27+
cache: pip
28+
cache-dependency-path: requirements-test.txt
29+
30+
- name: Install test dependencies
31+
run: |
32+
python -m pip install --upgrade pip
33+
python -m pip install -r requirements-test.txt
34+
python -m pip install "astrbot>=4.14,<4.15" aiohttp "emoji==2.14.1" "hypercorn==0.17.3" jieba quart "quart_cors==0.8.0" pydantic "sqlalchemy[asyncio]" aiosqlite asyncpg "cachetools>=5.3.0" apscheduler "defusedxml>=0.7.1" psutil aiomysql "prometheus_client>=0.20.0" "prometheus-async>=22.2.0" "networkx>=3.2,<3.5" "numpy>=1.26,<2.3" "pandas>=2.1,<2.4" "scikit_learn>=1.4,<1.8"
35+
36+
- name: Run pytest suite
37+
run: python -m pytest --no-cov

main.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ def __init__(self, context: Context, config: AstrBotConfig = None) -> None:
178178
self.plugin_config, self.context, self.group_id_to_unified_origin
179179
)
180180
self._register_official_page_api_if_available()
181+
self._trigger_dashboard_autobuild()
181182

182183
logger.info(StatusMessages.PLUGIN_INITIALIZED)
183184

@@ -202,6 +203,35 @@ def _register_official_page_api_if_available(self) -> None:
202203
self.page_api = None
203204
logger.warning(f"官方插件页面 API 注册失败,已跳过: {exc}", exc_info=True)
204205

206+
def _trigger_dashboard_autobuild(self) -> None:
207+
"""后台检测并自动构建 Dashboard 前端(仅在产物缺失时触发)。
208+
209+
- 产物已就绪则直接跳过(生产环境随仓库分发,开箱即用)。
210+
- 缺失时以 ``asyncio.create_task`` 后台执行,绝不阻塞插件启动,
211+
任何异常仅记录日志,不影响插件加载。
212+
"""
213+
try:
214+
plugin_root = os.path.dirname(os.path.abspath(__file__))
215+
from .webui.frontend_builder import (
216+
dashboard_artifact_exists,
217+
ensure_dashboard_built,
218+
)
219+
220+
if dashboard_artifact_exists(plugin_root):
221+
return
222+
223+
loop = asyncio.get_running_loop()
224+
_t = loop.create_task(ensure_dashboard_built(plugin_root))
225+
bg = getattr(self, "background_tasks", None)
226+
if bg is not None:
227+
bg.add(_t)
228+
_t.add_done_callback(bg.discard)
229+
except Exception as exc:
230+
logger.warning(
231+
f"[WebUI] Dashboard 自动构建触发失败(不影响插件运行):{exc}",
232+
exc_info=True,
233+
)
234+
205235
async def initialize(self):
206236
"""AstrBot 在完成 handler 绑定后调用此方法"""
207237
await self._lifecycle.on_load()

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ markers =
5050
config: Configuration tests
5151
utils: Utility module tests
5252
quality: Quality monitoring tests
53+
security: Security-related tests
5354

5455
# Log output
5556
log_cli = true

statics/messages.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ class FileNames:
240240
class TemplateNames:
241241
"""HTML 模板名称"""
242242
LOGIN = "login.html"
243-
INDEX = "index.html"
244243
CHANGE_PASSWORD = "change_password.html"
245244

246245

0 commit comments

Comments
 (0)