Repository navigation
Fix resolve plugin view titles on the detail page and view iframe - #10506
Open
lingyun14beta wants to merge 5 commits into
Open
lingyun14beta wants to merge 5 commits into
lingyun14beta wants to merge 5 commits into
Conversation
AstrBotDevs#10502 made the sidebar resolve view titles, but the plugin detail page and the pageTitle handed to plugin view iframes go through pluginI18n.js, which was still hardcoded to the legacy "pages" namespace. A plugin that follows the docs and writes "views.<view>.title" therefore showed its localized title in the sidebar and the raw view directory name everywhere else. - Resolve both namespaces in pluginI18n.js, preferring "views", and derive the view name from whichever prefix the API reported so the client keeps working against older backends - Emit the canonical "views.<name>" i18n_key from the plugin page service - Report a plugin that ships both views/ and pages/: discovery stops at the first directory that exists, so every view under pages/ is silently ignored. Report pages/-only plugins once as well, so authors get a migration hint instead of nothing
- Add an old to new mapping for the view directory, the i18n namespace, the bridge global, and the v1 API routes to the plugin view guide (zh/en) - Warn that "views/" wins when both directories exist and that the log points it out, and that a "views:" entry in metadata.yaml only feeds plugin metadata instead of affecting view discovery
Contributor
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="tests/unit/test_plugin_view_layout.py" line_range="71" />
<code_context>
+ assert await service.resolve_plugin_pages_root(plugin) == plugin_root / "pages"
+ second_pass = [record.getMessage() for record in caplog.records]
+
+ assert len(first_pass) == 1
+ assert "pages/" in first_pass[0] and "views/" in first_pass[0]
+ # Discovery runs on every plugin list request, so it must stay quiet after
</code_context>
<issue_to_address>
**Warning tests miss emitted logs**
When the new layout-warning tests run with AstrBot’s configured logger, `caplog` captures records through pytest’s logging handler, but `logger` is AstrBot’s logger with `propagate=False`; the warning never reaches that handler, so `first_pass` is empty and the new assertion fails. The same capture issue breaks the shadowed-directory assertion.
Capture the AstrBot logger with a dedicated test handler or mock the warning call instead of relying on root-level `caplog` capture.
</issue_to_address>
### Comment 2
<location path="astrbot/dashboard/services/plugin_page_service.py" line_range="485-497" />
<code_context>
+ plugin_root: Path,
+ selected_dir: str,
+ ) -> None:
+ """Warn once when a plugin keeps views in a directory that gets ignored.
+
+ Args:
+ plugin: Plugin metadata owning the view directory.
+ plugin_root: Plugin root directory.
+ selected_dir: The view directory name discovery selected.
+
+ Note:
+ View discovery stops at the first directory in
+ ``PLUGIN_PAGE_ROOT_DIR_NAMES`` that exists, so a plugin shipping
+ both ``views/`` and ``pages/`` silently loses every view that only
+ lives under the shadowed directory.
+ """
+ warn_key = f"{plugin.name}:{selected_dir}"
+ if warn_key in _WARNED_VIEW_LAYOUTS:
</code_context>
<issue_to_address>
**Legacy warning docstring is inaccurate**
The docstring says this helper warns when a view directory is ignored, but the `pages/`-only branch also warns even though that directory remains supported and is scanned. Maintainers reading the helper description get the wrong account of when it warns.
Update the docstring to describe both shadowed-directory warnings and migration hints for legacy-only layouts.
</issue_to_address>Sourcery assessment
Approval pending. 1 finding to address first.
Blocking findings: tests/unit/test_plugin_view_layout.py:71
astrbot.core.logger sets propagate = False, so pytest's caplog only sees these warnings through the indirect loguru bridge. Attach the collecting handler to that logger directly and pin its level for the duration of the test, so the assertions no longer depend on the root logger or on the order the rest of the suite leaves the logging configuration in.
The summary only described the shadowed-directory case, but the helper also reports plugins that keep their views in pages/ only. Those still work and get a migration hint rather than a warning about lost views; say so.
Soulter
reviewed
Oct 11, 2026
| return pages_root | ||
| raise FileNotFoundError("Plugin views root directory does not exist") | ||
|
|
||
| async def _warn_legacy_view_layout( |
Member
There was a problem hiding this comment.
unnecessary, this can be removed
Soulter asked for this to go. It fires for every plugin that still keeps its views in pages/, which is noise for a layout that is supported and works. Removes the helper, the once-per-plugin guard, the logger import it needed, the unit tests that only existed to cover it, and the changelog and docs lines that mentioned the log output. The Pages to Views migration notes and the i18n namespace fix stay.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #10497. Follow-up to the sidebar fix in #10502.
#10502 made the sidebar resolve view titles, and the field table it added to
docs/zh/dev/star/guides/plugin-pages.md(and the English mirror) states thattitleis used by the sidebar, the WebUI shell and the plugin detail page.The plugin detail page and the
pageTitlehanded to plugin view iframes do not go through that path though. They resolve throughdashboard/src/utils/pluginI18n.js, which is still hardcoded to the legacypagesnamespace:So a plugin that follows the docs and writes
views.<view>.titleshows its localized title in the sidebar and the raw view directory name everywhere else — the sidebar says设置while the plugin detail page sayssettings. A plugin still using the legacypages.<view>.titlenamespace resolves correctly on every surface, which makes following the documentation the worse choice.Modifications / 改动点
dashboard/src/utils/pluginI18n.jsviews.<view>.<attr>first and fall back topages.<view>.<attr>, deriving the view name from whichever prefix the API reported, so the client keeps working against older backends that reportpages.<name>.astrbot/dashboard/services/plugin_page_service.pyviews.<name>i18n_keyinstead ofpages.<name>, matching what the docs describe as canonical.views/andpages/. View discovery stops at the first directory inPLUGIN_PAGE_ROOT_DIR_NAMESthat exists, so every view living only underpages/is currently discarded without a word. Plugins that still keep their views inpages/are reported once as well, so authors get a migration hint instead of nothing. Discovery runs again on every plugin list request, so both reports are guarded by_WARNED_VIEW_LAYOUTSand fire at most once per plugin per process.Tests
tests/unit/test_plugin_view_layout.py(new):views/alone stays silent, apages/-only plugin is reported exactly once and stays quiet on the second discovery pass, a shadowedpages/directory is reported as ignored, and a plugin without view directories still raisesFileNotFoundError.tests/test_dashboard.py: the two plugin page component assertions now expect theviews.prefix.Docs (
docs/zh,docs/en)views/wins when both directories exist and that the log points it out, and that aviews:entry inmetadata.yamlonly feeds plugin metadata instead of affecting discovery.changelogs/unreleased.md.This PR intentionally does not touch the sidebar (
usePluginSidebarItems.ts,NavItem.vue,sidebarItem.ts) — #10502 already covers that path, including the dual-namespace lookup and the grouped/ungrouped fallback. Nor does it touch the##视图国际化heading, which #10502 replaced with## 视图元数据与国际化.Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
📚 I checked the affected WebUI instructions and screenshots in
docs/zhanddocs/enagainst the changed navigation, page structure, and labels, and updated them in this PR (or explained why no documentation update is needed). For renamed, moved, or merged entry points, I included an old entry → new entry mapping in the documentation and changelog./ 我已对照变化后的 WebUI 入口、页面结构和术语,核对并在本 PR 中更新
docs/zh和docs/en的相关操作说明与截图(或说明无需更新文档的原因)。入口改名、移动或合并时,已在文档和 changelog 中补充 旧入口 → 新入口 对照。🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Resolve plugin view titles consistently across the detail page and iframe while preserving compatibility with legacy plugin layouts and translations.
Bug Fixes:
views.<view>.*translations while retaining compatibility with the legacypages.<view>.*namespace.Enhancements:
viewsi18n namespace and document migration from Pages to Views, including directory discovery behavior and compatibility aliases.Documentation:
Tests: