Skip to content

feat(extension): support list view and persisted page size in plugin market#6727

Open
RhoninSeiei wants to merge 1 commit intoAstrBotDevs:masterfrom
RhoninSeiei:codex/market-page-size-selector
Open

feat(extension): support list view and persisted page size in plugin market#6727
RhoninSeiei wants to merge 1 commit intoAstrBotDevs:masterfrom
RhoninSeiei:codex/market-page-size-selector

Conversation

@RhoninSeiei
Copy link
Contributor

@RhoninSeiei RhoninSeiei commented Mar 20, 2026

参考 #6664#6650 中的需求

背景

当前插件市场仅支持卡片视图,且每页固定显示 9 个插件。随着插件数量增加,浏览与筛选成本会明显上升。Issue #6664 提出希望补充列表视图,#6650 支持记住每页显示数量。

Modifications / 改动点

  • 为插件市场新增列表视图,可在卡片视图与列表视图之间切换
  • 在插件市场分页区域增加每页显示数量选择器,支持 9 / 25 / 50 / 100
  • 将插件市场视图模式与每页显示数量持久化到 localStorage
  • 将插件市场的视图状态与“已安装插件”页面的视图状态分开存储,避免互相影响
  • 补充中英文文案

设计说明

  • 继续使用现有 Vue 与 Vuetify 组件实现,未新增前端或后端依赖
  • 每页数量变化时自动回到第一页,避免页码越界导致空白列表
  • 分页区域在窄屏下自动换行,保持移动端与小分辨率窗口可用
  • 随机插件区域继续保留卡片形式,仅全量插件列表支持列表视图

影响范围

改动仅涉及 Dashboard 前端插件市场页面,不影响插件市场接口、插件安装逻辑以及各消息平台适配器行为。

Screenshots or Test Results / 运行截图或测试结果(过曝是因为HDR还请见谅)

列表视图25格
image

切换选项
image

持久化后调节器的每页格数刷新后也能保存下来
动画

image 一页25格 image 一页100格 longCapture

运行验证

  • 已在实际运行中的 AstrBot 容器中验证插件市场页面可以正常打开和与之前一样使用
  • 列表视图与卡片视图可以正常切换
  • 每页显示数量切换后会立即生效,刷新页面后仍保持上次选择
  • 分页区域与每页显示控件在当前页面布局下显示正常
  • 验证过程中同步修正了列表视图安装按钮的前端调用错误,页面脚本已恢复正常

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ 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.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

Add a list view and configurable, persisted page size to the plugin market, improving discoverability and usability without changing backend behavior.

New Features:

  • Introduce a switchable list view alongside the existing card view for the plugin market.
  • Allow users to configure the number of plugins shown per page in the market and persist this preference in localStorage.

Bug Fixes:

  • Fix the install action wiring for plugins in the list view so installations trigger correctly.

Enhancements:

  • Refine plugin market pagination layout for better responsiveness across screen sizes.
  • Display additional plugin metadata (platforms, version, author, stars, updated time) in the new list view table.

Documentation:

  • Update English and Chinese UI copy for the plugin market to cover the new views, table headers, and pagination controls.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 20, 2026
@dosubot dosubot bot added area:webui The bug / feature is about webui(dashboard) of astrbot. feature:plugin The bug / feature is about AstrBot plugin system. labels Mar 20, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the plugin market by adding a list view and allowing users to customize the number of plugins displayed per page. It also persists these preferences using localStorage. The changes improve the browsing and filtering experience for users as the number of plugins grows.

Highlights

  • List View Support: Added a list view option to the plugin market, allowing users to switch between card and list views.
  • Items Per Page Selection: Implemented a selector for the number of plugins displayed per page, with options for 9, 25, 50, and 100 items.
  • Persistence: Persisted the selected view mode and items per page in localStorage, ensuring user preferences are remembered.
  • Independent View States: Ensured that the view state of the plugin market and the 'Installed Plugins' page are stored separately to avoid conflicts.
  • i18n: Added i18n support for the new features.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • Consider extracting the repeated window.localStorage access logic (for list view mode and items-per-page) into a small utility/composable to centralize key names, default values, and environment checks instead of duplicating this pattern in useExtensionPage.
  • The list view table currently formats updated time with new Date(item.updated_at).toLocaleDateString() and labels stars as Star {{ item.stars }} directly in the template; it would be more consistent with the rest of the page to move this into i18n-aware helpers/computed properties (including localized date formatting and translatable labels).
  • Since v-data-table is already driven by paginatedPlugins, passing :items-per-page="marketItemsPerPage" is redundant and may be confusing; either rely on items-per-page for paging or keep all pagination in the paginatedPlugins computed, but avoid mixing both mechanisms.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider extracting the repeated `window.localStorage` access logic (for list view mode and items-per-page) into a small utility/composable to centralize key names, default values, and environment checks instead of duplicating this pattern in `useExtensionPage`.
- The list view table currently formats updated time with `new Date(item.updated_at).toLocaleDateString()` and labels stars as `Star {{ item.stars }}` directly in the template; it would be more consistent with the rest of the page to move this into i18n-aware helpers/computed properties (including localized date formatting and translatable labels).
- Since `v-data-table` is already driven by `paginatedPlugins`, passing `:items-per-page="marketItemsPerPage"` is redundant and may be confusing; either rely on `items-per-page` for paging or keep all pagination in the `paginatedPlugins` computed, but avoid mixing both mechanisms.

## Individual Comments

### Comment 1
<location path="dashboard/src/views/extension/useExtensionPage.js" line_range="253-247" />
<code_context>
+    }
+    return 9;
+  };
+  const marketItemsPerPageOptions = [9, 25, 50, 100];
+  const marketItemsPerPage = ref(getInitialMarketItemsPerPage());
   const sortBy = ref("default"); // default, stars, author, updated
</code_context>
<issue_to_address>
**suggestion:** Use the `marketItemsPerPageOptions` constant instead of duplicating the literal array.

In `getInitialMarketItemsPerPage`, the valid values `[9, 25, 50, 100]` are duplicated instead of using `marketItemsPerPageOptions`. This can cause the validation list to drift from the actual options if only one is updated. Referencing `marketItemsPerPageOptions` (e.g. `marketItemsPerPageOptions.includes(rawValue)`) will keep them aligned.

Suggested implementation:

```javascript
  const marketIsListView = ref(getInitialMarketListViewMode());
  const marketItemsPerPageOptions = [9, 25, 50, 100];
  const getInitialMarketItemsPerPage = () => {

```

```javascript
      const rawValue = Number(localStorage.getItem("pluginMarketItemsPerPage"));
      if (marketItemsPerPageOptions.includes(rawValue)) {

```

```javascript
  };
  const marketItemsPerPage = ref(getInitialMarketItemsPerPage());

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

const getInitialMarketItemsPerPage = () => {
if (typeof window !== "undefined" && window.localStorage) {
const rawValue = Number(localStorage.getItem("pluginMarketItemsPerPage"));
if ([9, 25, 50, 100].includes(rawValue)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Use the marketItemsPerPageOptions constant instead of duplicating the literal array.

In getInitialMarketItemsPerPage, the valid values [9, 25, 50, 100] are duplicated instead of using marketItemsPerPageOptions. This can cause the validation list to drift from the actual options if only one is updated. Referencing marketItemsPerPageOptions (e.g. marketItemsPerPageOptions.includes(rawValue)) will keep them aligned.

Suggested implementation:

  const marketIsListView = ref(getInitialMarketListViewMode());
  const marketItemsPerPageOptions = [9, 25, 50, 100];
  const getInitialMarketItemsPerPage = () => {
      const rawValue = Number(localStorage.getItem("pluginMarketItemsPerPage"));
      if (marketItemsPerPageOptions.includes(rawValue)) {
  };
  const marketItemsPerPage = ref(getInitialMarketItemsPerPage());

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

此拉取请求成功地为插件市场引入了列表视图和可配置的每页显示数量功能。代码实现清晰,逻辑合理,并且考虑到了用户体验,例如在切换每页显示数量时自动回到第一页,以及将用户偏好持久化到 localStorage。响应式布局和国际化支持也做得很好。这是一个高质量的改进,显著提升了插件市场的可用性。

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

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. feature:plugin The bug / feature is about AstrBot plugin system. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant