Skip to content

feat(dashboard): preview images in plugin file configuration - #10596

Open
ZXLyyds100 wants to merge 2 commits into
AstrBotDevs:masterfrom
ZXLyyds100:feat/10595-config-image-preview
Open

ZXLyyds100 wants to merge 2 commits into
AstrBotDevs:masterfrom
ZXLyyds100:feat/10595-config-image-preview

Conversation

@ZXLyyds100

@ZXLyyds100 ZXLyyds100 commented Oct 17, 2026 •

Copy link
Copy Markdown

Closes #10595.

The plugin file-configuration manager lists uploaded images by name only. This
adds thumbnails and a larger preview within the existing manager, without
changing plugin configuration or upload/delete semantics.

Modifications / 改动点

  • Reuse plugin authentication for a field-scoped image-preview endpoint. Resolve
    and reject path/symlink escapes; bound input to 10 MiB and 20 million pixels;
    return a metadata-free PNG thumbnail (maximum edge 1024). Animated images
    preview their first frame. Original files are not modified.

  • Lazy-load previews through the authenticated API client and object URLs, never
    login tokens in image URLs. Cancel requests and revoke URLs when closing,
    removing or switching files. Refresh previews after same-name uploads.

  • Preserve management of non-image, missing, corrupt and oversized files. Add
    accessible preview buttons, keyboard operation and translations for all four
    existing locales.

  • Update Chinese/English WebUI and plugin-configuration instructions, OpenAPI,
    the generated client and public API/scope documentation. No navigation
    entry was renamed or moved.

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

Actual dashboard screenshots using the same synthetic fixture files in an
isolated data root. Before: unmodified de898af backend and production build.
After: e80a91e backend and production build. These are not mockups.

Before After
Names only Image thumbnails

10-second actual browser recording
· Evidence and reproducible fixture

Larger preview and mobile screenshots

Larger preview

Mobile image preview

Verification steps

From the repository's development environment:

ruff format --check .
ruff check .
bash scripts/run_pytests_ci.sh ./tests
pre-commit run --files astrbot/dashboard/api/plugins.py \
  astrbot/dashboard/services/config_service.py tests/test_fastapi_v1_dashboard.py
cd dashboard
pnpm generate:api
node --test tests/*.test.mjs
pnpm run i18n:check
pnpm run build
cd ../docs
pnpm run docs:build
  • Baseline full Python suite: 4001 passed, 4 skipped.
  • Final full Python suite: 4035 passed, 4 skipped; 34 added regression cases
    in the existing API test module. Includes JWT/API-key scope, path/field/symlink
    isolation, invalid/missing images, limits, formats, orientation, metadata,
    first-frame behavior and source-file preservation.
  • Existing dashboard Node tests: 66 passed. Typecheck, locale-key validation,
    production build, API-generation consistency, docs build, full Ruff checks and
    normal changed-file commit hooks passed. Final build uses CI's
    Node 24.13.0 / pnpm 10.28.2.
  • Real-browser acceptance: 31 assertions passed (21 initial + 10 review regressions), covering keyboard/ESC,
    desktop/mobile bounds, same-name overwrite/restore, unconfigured images,
    add/delete, field isolation, repeated open/close and cancellation of delayed
    real requests, actual image-extension aliases, sanitized failure logging and
    expected-error suppression. Instrumented 29 URLs created / 29 revoked / 0 live.
  • Checked Plugins → Installed → plugin gear icon → Manage Files against the
    updated docs. Evidence is on a separate fork branch, not in the product diff.

Manual reproduction: use a plugin file setting accepting images, upload a
landscape/portrait image and a non-image file, open Manage Files, click a
thumbnail, and close it with Escape or its close button. Repeat on mobile,
overwrite an image with the same filename, and reopen the manager.

Validation boundaries: the four Python skips also occur on the base. No live
IM platform or paid-model execution is claimed. The deliberate invalid PNG gets
the expected 415/fallback; baseline Vuetify list warnings remain. Repository-wide
pre-commit --all-files rewrites two unrelated baseline files through pyupgrade;
those incidental changes were reverted and are excluded. Normal commit hooks
on this PR pass without any bypass.

Automated review follow-up

Both Sourcery findings were addressed in e80a91e: log unexpected failures
without Axios credentials, distinguish storage failures (503) from decoder
failures (415), and support .jfif/.jpe/.dib/.apng aliases including real DIB
decoding. The supplemental review before/after evidence
reproduces the old frontend's zero alias thumbnails/zero 500 warnings and
verifies the corrected behavior. Browser 500/network/415/wrong-MIME scenarios
are explicitly controlled fault injection, not real deployment outage claims.
Sourcery's automated review does not replace a human reviewer.


Checklist / 检查清单

  • 😊 New feature discussed through an issue: implementation scope was posted
    in [Feature] 增加插件配置的管理文件的已上传图片可视图化 #10595 and the issue reporter invited implementation. This is not a claim
    of maintainer design approval.
  • 👀 Changes tested; verification steps and actual screenshots are above.
  • 📚 Affected Chinese/English WebUI instructions and terminology checked and
    updated. Navigation is unchanged, so no old-to-new entry mapping is needed.
  • 🤓 No new dependency introduced; Pillow was already a project dependency.
  • 😮 No malicious code introduced.

Disclosure: investigation, implementation, tests, self-review and evidence were
produced with OpenAI Codex assistance. No independent human review, maintainer
approval or completed upstream CI is implied.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="dashboard/src/components/shared/ConfigImagePreview.vue" line_range="69" />
<code_context>
+        objectUrl = URL.createObjectURL(response.data)
+        imageUrl.value = objectUrl
+      }
+    } catch {
+      // Unsupported, missing, or oversized images must not block file management.
+    } finally {
</code_context>
<issue_to_address>
**Preview failures go unnoticed**

When the preview API fails because of a transient service, storage, or network error, the catch suppresses every request failure, so a backend or storage outage is rendered as the same unavailable icon as an unsupported image, with no log or operator-visible indication that previews are failing.

Keep unsupported-image failures quiet but log or otherwise surface unexpected preview request failures.
</issue_to_address>

### Comment 2
<location path="dashboard/src/components/shared/FileConfigItem.vue" line_range="29" />
<code_context>
               <template #prepend>
-                <v-icon size="18">mdi-file</v-icon>
+                <div class="file-thumbnail mr-3">
+                  <v-lazy v-if="dialog && item.status !== 'missing' && /\.(png|jpe?g|webp|gif|bmp|tiff?|ico)$/i.test(item.path)"
+                    :key="`${pluginName}:${configKey}:${item.path}:${previewRevision}`" min-height="48" width="56">
+                    <ConfigImagePreview :plugin-name="pluginName" :config-key="configKey" :path="item.path" />
</code_context>
<issue_to_address>
**Supported images show generic icons**

When a supported image uses an extension omitted from the frontend allowlist, such as `.jfif`, `.jpe`, or `.dib`, the extension check prevents `ConfigImagePreview` from calling the endpoint, so users see a generic file icon instead of a preview even though the backend accepts the image.

Include all supported image extensions in the frontend allowlist or avoid filtering previews by filename extension.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and the new authenticated endpoint returns image content from plugin storage; if its field-directory or symlink checks fail, a user with plugin scope could retrieve images outside the selected field. Reverting removes the endpoint, but cannot undo images already accessed.

Blocking findings: dashboard/src/components/shared/ConfigImagePreview.vue:69, dashboard/src/components/shared/FileConfigItem.vue:29


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread dashboard/src/components/shared/ConfigImagePreview.vue Outdated
Comment thread dashboard/src/components/shared/FileConfigItem.vue Outdated
@mjy1113451

Copy link
Copy Markdown

你好,这个可以点进去一项看图片吗?

@ZXLyyds100

Copy link
Copy Markdown
Author

@mjy1113451 你好,可以的。在「插件 → 已安装 → 插件配置(齿轮)→ 管理文件」里,点击每项左侧的图片缩略图,就会弹出较大的图片预览;可以用 Esc 或右上角关闭按钮退出,键盘聚焦缩略图后按 Enter 也可以打开。

刚在当前提交 e80a91e 的真实 WebUI 和后端重新核对了鼠标点击、Enter/Esc 及手机宽度,交互正常。测试使用隔离的合成图片,没有连接真实 IM 或调用模型。

PR 已附有放大预览截图和10 秒操作录像,可以直接看效果。

补充说明:这里是经过安全处理的图片预览(最长边 1024 像素,动图显示首帧),不是原始文件下载;点击入口是缩略图,而非文件名。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 增加插件配置的管理文件的已上传图片可视图化

2 participants