Skip to content

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

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

ZXLyyds100 wants to merge 5 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 / 运行截图或测试结果

Current acceptance after master sync — 2026-10-22

Current head: 802a79718b383f0de58ad01545a2c93c99429a85. Normally merged master 1b10813c70949071fa11153cc4ec8c51421d13d0, preserving PR history.
The only merge conflict was the generated SDK's type import. Resolved it with
the official API generator, retaining both this image-preview API and master's
log-export API. The resulting PR still contains the original 20 feature files;
no workflow, dependency, permission-gate or production-restart change was added.

  • Full local Python suite (pytest -q --cov=.): 4,848 passed, 11 skipped,
    72 warnings
    . The focused dashboard API suite: 205 passed (included in
    the full count, not additive).
  • Dashboard Node suite: 78 passed, no skips.
  • Ruff format/check, normal commit hooks, API regeneration, dashboard typecheck
    and production dashboard build passed. Existing dependency, asset/font and
    async-cleanup warnings remain; this is not a warning-free run.
  • Actual tools: macOS, Python 3.12.14, Node 24.19.0, pnpm 11.25.0.
    These are this run's tools, not the historical CI-version claims below.
  • A real localhost smoke start passed using the locally built dashboard and a
    fresh synthetic data root; the task-owned process was then stopped. An earlier
    attempt waited for a remote dashboard download, so it was not counted as a
    successful start. No IM provider or paid model was invoked.

No fresh browser capture, locale check or documentation build is claimed for
this synchronization. Existing screenshots/recordings and earlier lifecycle,
locale and documentation results retain their actual historical revisions.
The private smoke log is not published because it can include synthetic
initialization credentials. Local success and Sourcery are not human review
or upstream Actions approval/success.

Historical acceptance after master sync — 2026-10-20

Head at that checkpoint: 63f30db299fe9d9d75ba8aa6b8813b51e264d440. Normally merged master
f2404c191716a64daaa422be7f3c567cace50d39 without rewriting the PR history.
The only conflict was the restart-test fixture: master now supplies its own
module-local threading mock and bounded wait. Kept that upstream test
byte-for-byte, removing the superseded fixture workaround from this PR.
The resulting diff is the original 20 feature files; no production restart,
workflow, dependency, or permission-gate changes are introduced.

  • Full repository Python CI script on macOS/Python 3.12.14:
    4720 passed, 11 skipped. No tests were deselected or newly skipped.
  • Lifecycle: 26 passed; dashboard API: 178 passed;
    dashboard Node tests: 78 passed.
  • Ruff format/lint, normal merge-commit hooks, regenerated API consistency,
    final typecheck, four-locale checks, production dashboard build, and
    English/Chinese documentation build passed. Dashboard uses CI's
    Node 24.13.0 / pnpm 10.28.2.
  • Seven skips require Windows paths/junctions, three require Linux/bubblewrap,
    and one requires optional edge_tts. Dependency deprecation warnings and
    existing build-size warnings remain.
  • Test-runner setup problems were corrected locally: precreated the pytest
    temporary parent and verified the dynamic-plugin data-root convention.
    The final complete CI-script run passed with no production or test-source
    changes to hide those setup failures.

The preview implementation and its regression tests are byte-identical to
the preceding head. The only changed feature-file blobs are the two WebUI
guides, which retain master's current navigation/settings instructions plus
the preview instructions. Existing real screenshots/recordings below keep
their explicit historical revisions; no fresh browser run or new capture
is claimed for this test-fixture-only conflict resolution
. The current
documentation path is Extensions → Plugins → Extension Config → Manage Files.

Hosted workflow authorization and human review remain separate from these
local results; neither is implied by local tests or a bot check.

Historical acceptance after master sync — 2026-10-18

Head at that checkpoint: ae728172062566bd251be143a40d9ecd79ffbdb5. Synchronized master 8774e53, resolving the generated
SDK conflict by regeneration and preserving both preview and trace endpoints.
The original 20 feature files remain in scope, plus one test-only lifecycle
fixture adjustment; production restart logic is unchanged.

  • Full Python suite on macOS: 4702 passed, 11 skipped; focused API/auth/docs/storage:
    345 passed; lifecycle: 26 passed; dashboard Node tests: 78 passed.
  • Ruff, normal commit hooks, API regeneration/consistency, typecheck, i18n,
    production dashboard build and docs build passed with CI's Node/pnpm versions.
  • A clean, unmodified 8774e53 checkout reproduces a hang in the restart test.
    Its global Thread mock also blocks the executor used by new trace cleanup.
    The fixture now mocks asyncio.to_thread and asserts the cleanup call.
    The full suite was rerun without deselecting that test or adding a skip.
  • 31 browser assertions, 29 URLs created / 29 revoked / 0 live.
    Fresh real screenshots and a 10.6-second
    interaction recording use recreated synthetic files and the real backend.
  • Skips: seven Windows-only cases, three Linux/bubblewrap cases, and one optional
    edge_tts import. Hosted Actions still await maintainer authorization; local
    success and Sourcery success are not human approval or hosted CI success.

2026-10-18 evidence and source provenance ·
2026-10-18 interaction recording

2026-10-18 synchronized-head screenshots

Synced head file manager

Synced head enlarged preview

Synced head mobile preview

Synced head image aliases

The historical before/after captures and counts below remain tied to their
explicit original revisions; they have not been relabeled as current captures.

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 \
  tests/unit/test_core_lifecycle.py
cd dashboard
pnpm generate:api
node --test tests/*.test.mjs
pnpm run i18n:check
pnpm run build
cd ../docs
pnpm run docs:build
  • Original pre-sync baseline full Python suite: 4001 passed, 4 skipped.
  • Original pre-sync 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.
  • Original pre-sync 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.

Original pre-sync 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.

Summary by Sourcery

Enable secure image previews in the plugin file configuration manager without changing upload or deletion semantics.

New Features:

  • Add authenticated image thumbnails and enlarged previews to plugin file configuration management.

Enhancements:

  • Secure previews to the selected plugin field directory with bounded, metadata-free PNG output while preserving existing file management behavior.
  • Support accessible, localized lazy-loading previews with request cancellation and refresh after same-name uploads.

Documentation:

  • Document image preview behavior, supported formats, limits, and the new authenticated API endpoint in English and Chinese documentation.

Tests:

  • Add regression coverage for authentication, path and symlink isolation, format handling, size limits, metadata and orientation, animation, storage failures, and source-file preservation.

@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 像素,动图显示首帧),不是原始文件下载;点击入口是缩略图,而非文件名。

@ZXLyyds100

ZXLyyds100 commented Oct 18, 2026 •

Copy link
Copy Markdown
Author

Updated on 2026-10-22 in 802a7971: normally merged master
1b10813c and regenerated the conflicting SDK, preserving preview and log-export
APIs. The verified resulting PR scope remains 20 feature files.

Fresh local results: 4,848 Python tests passed / 11 skipped / 72 warnings,
205 dashboard API cases (included above), and 78 dashboard Node tests.
Ruff, normal hooks, generation, typecheck and dashboard production build passed.
A real localhost startup using the local build and synthetic data also passed
and its process was stopped. The updated PR body gives actual tool versions and
warnings; no new browser capture, locale or documentation build is claimed.

Existing visual evidence keeps its original revisions. Hosted workflows still
need upstream authorization and human review remains required; no gate was
bypassed. This edits my existing update instead of posting another comment.

Historical delivery report

Updated on 2026-10-20 in 63f30db2: normally merged master f2404c19 and
resolved the restart-test conflict by keeping master's current fixture
byte-for-byte. The old test workaround is no longer in this PR, leaving the
original 20 feature files. The preview implementation itself is unchanged.

Fresh local acceptance: 4720 Python tests passed / 11 platform-or-optional
skips
, 26 lifecycle, 178 dashboard API, and 78 dashboard Node
tests
passed. Ruff, normal commit hooks, API regeneration consistency,
typecheck, i18n, production dashboard and docs builds passed. The PR body has
the commands, environment/setup caveats, skip details and exact synchronized
revisions. Existing real visual evidence remains labeled by its original
revision; this fixture-only sync does not claim new browser captures.

The pushed ref, resulting PR file list and PR body were read back and verified.
Hosted Actions authorization and human review are still separate requirements,
not local-test success. This edits my existing sync update to avoid another ping.

Previous synchronization report — 2026-10-18

Synchronized master in ae72817 and regenerated the SDK to keep both image-preview and upstream trace endpoints. GitHub now reports the PR as mergeable.

Revalidation exposed a pre-existing restart-test hang, independently reproduced on clean master 8774e53. The test-only adjustment mocks threaded trace cleanup and asserts that call; no production restart code changed.

Full local suite: 4702 passed / 11 skipped; dashboard Node: 78 passed; browser: 31 assertions, with all 29 object URLs reclaimed. Types, locales, API generation, builds, Ruff and normal hooks passed. Fresh screenshots, 10.6-second recording, skip details and provenance are also linked in the updated PR description.

Hosted GitHub Actions still require maintainer authorization; these local results and the automated Sourcery check are not hosted CI success or human approval.

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