fix: resolve plugin market detail mix-up for same-named plugins - #9925
fix: resolve plugin market detail mix-up for same-named plugins#9925Hayston1001 wants to merge 1 commit into
Conversation
Two market entries can share the same metadata `name` (different authors), but the detail flow used `name` as the unique key: - `openMarketPluginDetail` navigated with `plugin.name` as the route param, so both entries resolved to the same detail route; - `selectedMarketPlugin` matched `item.name === pluginId`, always returning the first same-named entry (wrong version/author/repo/README); - duplicate `v-for` keys (`plugin.name`) caused Vue to reuse wrong component instances in the market list; - the random-plugins section keyed its sampling Map by `name`, collapsing same-named entries. Introduce `getMarketPluginKey(plugin)` (`market_plugin_id || repo || name`) as the unique market identity, use it for navigation, list keys, detail lookup (name kept as fallback for legacy deep links), and the random-plugins sampling. Fixes AstrBotDevs#9924
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="dashboard/src/views/extension/useExtensionPage.js" line_range="691-700" />
<code_context>
return String(plugin?.market_plugin_id || "").trim();
};
+ // Unique identity for a market entry. Metadata `name` alone is not unique —
+ // different authors can publish plugins with the same name — so fall back to
+ // repo and finally name for legacy registry entries without an explicit id.
+ const getMarketPluginKey = (plugin) => {
+ return (
+ getMarketPluginId(plugin) ||
+ String(plugin?.repo || "").trim() ||
+ String(plugin?.name || "").trim()
+ );
+ };
+
const getMarketInstallSourcePayload = () => {
</code_context>
<issue_to_address>
**issue (bug_risk):** `market_plugin_id || repo || name` is not a globally unique key because values from different fallback levels share the same namespace; an entry whose `repo` equals another entry's `market_plugin_id` or `name` produces the same key. Duplicate or empty fallback values also collapse entries in the random-plugin `Map`, create duplicate Vue keys, and cause detail lookup to select the first entry.
**Triggers:** When a registry contains entries with colliding fallback values, duplicate repository values, or entries missing all three identity fields.
**Suggested fix:** Prefix the selected identity with its source field (for example, `id:`, `repo:`, or `name:`), and define a deterministic handling strategy for entries whose resulting identity is still not unique.
</issue_to_address>Sourcery assessment
Approval pending. 1 finding to address first.
Blocking findings: dashboard/src/views/extension/useExtensionPage.js:700
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| // Unique identity for a market entry. Metadata `name` alone is not unique — | ||
| // different authors can publish plugins with the same name — so fall back to | ||
| // repo and finally name for legacy registry entries without an explicit id. | ||
| const getMarketPluginKey = (plugin) => { | ||
| return ( | ||
| getMarketPluginId(plugin) || | ||
| String(plugin?.repo || "").trim() || | ||
| String(plugin?.name || "").trim() | ||
| ); | ||
| }; |
There was a problem hiding this comment.
issue (bug_risk): market_plugin_id || repo || name is not a globally unique key because values from different fallback levels share the same namespace; an entry whose repo equals another entry's market_plugin_id or name produces the same key. Duplicate or empty fallback values also collapse entries in the random-plugin Map, create duplicate Vue keys, and cause detail lookup to select the first entry.
Triggers: When a registry contains entries with colliding fallback values, duplicate repository values, or entries missing all three identity fields.
Suggested fix: Prefix the selected identity with its source field (for example, id:, repo:, or name:), and define a deterministic handling strategy for entries whose resulting identity is still not unique.
Motivation
Fixes #9924.
In the plugin market (WebUI), two entries can share the same metadata
name(typically plugins published by different authors). The detail flow, however, usednameas the unique key, so both entries resolved to the same detail page showing the first entry's info (version / author / repo / README / changelog), and duplicatev-forkeys made the market list render incorrectly as well. Related but distinct from #9026 (installed-vs-market name collision) — this issue is market-entry vs market-entry.Modifications
dashboard/src/views/extension/useExtensionPage.jsgetMarketPluginKey(plugin)=market_plugin_id || repo || nameas the unique identity of a market entry (three-level fallback so legacy registry entries without an explicit id still get a stable key), and expose it via the page state.Mapby the unique key instead ofname, so same-named entries no longer collapse into one.dashboard/src/views/extension/MarketPluginsTab.vueopenMarketPluginDetail()navigates with the unique key aspluginIdinstead ofplugin.name.v-for:keys (paginated list and random list) use the unique key, eliminating duplicate Vue keys.dashboard/src/views/ExtensionPage.vueselectedMarketPluginnow resolves the detail entry by the unique key first; thenamematch is kept only as a fallback for legacy deep links (/extension/<name>#market). The installed-tab branch still resolves strictly by repo URL, so the [Bug] 当本地插件与插件市场中的某个插件name相同,插件详情页会混入插件市场条目的信息 #9026 behavior is unchanged.Notes:
Route params containing
/(e.g.author/name) are safe: vue-router 4.2.4 encodes/as%2Fwhen building the path and decodes it back on parse (verified against the installed version at runtime).No backend API/schema changes, so no API client regeneration is needed.
This is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
vite buildpasses (exit 0).node --test tests/*.test.mjs→ 39/39 pass.router.push({ params: { pluginId: "authorA/astrbot_plugin_foo" } })→ URL/extension/plugins/market/authorA%2Fastrbot_plugin_foo→route.params.pluginId === "authorA/astrbot_plugin_foo"(also for a second authorauthorB/...→ distinct routes).Verification steps for reviewers:
namebut differentauthor;.../market/<authorA>%2F<name>vs.../market/<authorB>%2F<name>);/extension/<name>#marketstill resolves to a same-named entry (name fallback).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 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
Fix market plugin identity handling so entries with the same name remain distinct throughout listing, navigation, and detail views.
Bug Fixes:
Enhancements:
Tests: