From 7983ae9d5c8f44ebe79a08c69cb447d8c7a5e943 Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Mon, 19 Oct 2026 08:14:08 -0700 Subject: [PATCH] feat: open recommended plugin details from conversation cards --- apps/web/tests/plugin-recommendations.e2e.ts | 5 ++++- .../README.i18n.yaml | 4 ++-- .../README.md | 2 +- .../README.zh.md | 2 +- .../package.json | 6 ++++-- .../src/client/Card.module.css | 5 +++++ .../src/client/Card.tsx | 13 ++++++++---- .../src/client/index.ts | 4 +++- .../src/client/locales.ts | 2 ++ .../tests/browser-plugin.client.spec.ts | 4 ++++ .../tests/card.client.spec.tsx | 21 +++++++++++++------ .../tsconfig.json | 3 +++ .../plugin-recommendations/README.i18n.yaml | 4 ++-- .../plugin-recommendations/README.md | 2 +- .../plugin-recommendations/README.zh.md | 2 +- pnpm-lock.yaml | 3 +++ .../dismissed.expected.md | 6 +++--- .../offered.expected.md | 6 +++--- 18 files changed, 66 insertions(+), 28 deletions(-) diff --git a/apps/web/tests/plugin-recommendations.e2e.ts b/apps/web/tests/plugin-recommendations.e2e.ts index 81ce54869c..ee683e6fbe 100644 --- a/apps/web/tests/plugin-recommendations.e2e.ts +++ b/apps/web/tests/plugin-recommendations.e2e.ts @@ -63,9 +63,12 @@ describe('official plugin recommendation in a conversation', () => { await card.getByRole('status').getByText('Dismissed', { exact: true }).waitFor() acknowledgeReloadConnectionLoss(tripwire, warnings) expect(await card.count()).toBe(1) - expect(await card.getByRole('button').count()).toBe(0) + expect(await card.getByRole('button').count()).toBe(1) expect((await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === '@deepseek-ai/dsh-experimental-session-search')?.enabled).toBe(false) await compareOrRefreshGolden(join(directory, 'dismissed.expected.md'), await captureStableAria(page, '[data-plugin-recommendation]', scaffold.workspaceCwd), scaffold.mode) + await card.getByRole('button', { name: 'View details: Session search', exact: true }).click() + await page.locator('[data-plugin-detail="@deepseek-ai/dsh-experimental-session-search"]').waitFor({ state: 'visible' }) + expect((await scaffold.ctx.pluginManager.listBundles()).find(bundle => bundle.name === '@deepseek-ai/dsh-experimental-session-search')?.enabled).toBe(false) expect(tripwire.pageErrors).toEqual([]) expect(tripwire.warnings).toEqual([]) if (scaffold.mode === 'replay') await assertFixtureInventory(directory, [ diff --git a/packages/experimental/client-ui-plugin-recommendations/README.i18n.yaml b/packages/experimental/client-ui-plugin-recommendations/README.i18n.yaml index 77c8ae470e..50cc76558e 100644 --- a/packages/experimental/client-ui-plugin-recommendations/README.i18n.yaml +++ b/packages/experimental/client-ui-plugin-recommendations/README.i18n.yaml @@ -9,8 +9,8 @@ en: f0fc11779f589f44 zh: e6f828ecaa30460b /deepseek-ai-dsh-experimental-client-ui-plugin-recommendations/summary: - en: c7a8e86d94161c24 - zh: cbc4f532a57f804e + en: 5c22b43888c4eaa7 + zh: 33c341ab607da2f4 /deepseek-ai-dsh-experimental-client-ui-plugin-recommendations/table-of-contents: en: d152484eb41ac6b4 zh: dbb94479b1334720 diff --git a/packages/experimental/client-ui-plugin-recommendations/README.md b/packages/experimental/client-ui-plugin-recommendations/README.md index 61f4273699..cba344efb0 100644 --- a/packages/experimental/client-ui-plugin-recommendations/README.md +++ b/packages/experimental/client-ui-plugin-recommendations/README.md @@ -9,7 +9,7 @@ English | [中文](README.zh.md) ## Summary -Users see one plugin recommendation below the completed answer. Enable and Not now are explicit choices. Decisions remain visible after reconnecting. +Users see one plugin recommendation below the completed answer. Clicking its title or description opens that plugin's details in Plugins without enabling it or changing the current Session. Enable and Not now remain separate choices. Decisions and the details link remain available after reconnecting. ## Table of Contents diff --git a/packages/experimental/client-ui-plugin-recommendations/README.zh.md b/packages/experimental/client-ui-plugin-recommendations/README.zh.md index bdba240818..af35e34a34 100644 --- a/packages/experimental/client-ui-plugin-recommendations/README.zh.md +++ b/packages/experimental/client-ui-plugin-recommendations/README.zh.md @@ -9,7 +9,7 @@ kind: "package-reference" ## 概述 -用户在完整回答下方看到一张插件推荐卡片。启用和暂不需要均由用户选择。重新连接后仍能看到之前的选择。 +用户在完整回答下方看到一张插件推荐卡片。点击标题或描述可打开插件页中的对应详情,不会启用插件或改变当前 Session。启用和暂不需要仍是独立操作。重新连接后仍能看到之前的选择并打开详情。 ## 目录 diff --git a/packages/experimental/client-ui-plugin-recommendations/package.json b/packages/experimental/client-ui-plugin-recommendations/package.json index 52cd09fbb5..4fb9f4658c 100644 --- a/packages/experimental/client-ui-plugin-recommendations/package.json +++ b/packages/experimental/client-ui-plugin-recommendations/package.json @@ -34,7 +34,8 @@ "@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-conversation", "@deepseek-ai/dsh-client-ui-chat", - "@deepseek-ai/dsh-client-ui-session" + "@deepseek-ai/dsh-client-ui-session", + "@deepseek-ai/dsh-client-ui-plugin-manager" ] } }, @@ -55,7 +56,8 @@ "@deepseek-ai/dsh-client-ui-primitives": "workspace:*", "react": "^18.2.0", "@deepseek-ai/dsh-experimental-plugin-recommendations": "workspace:*", - "@deepseek-ai/dsh-client-store": "workspace:*" + "@deepseek-ai/dsh-client-store": "workspace:*", + "@deepseek-ai/dsh-client-ui-plugin-manager": "workspace:*" }, "files": [ "lib/index.js", diff --git a/packages/experimental/client-ui-plugin-recommendations/src/client/Card.module.css b/packages/experimental/client-ui-plugin-recommendations/src/client/Card.module.css index 9d43e870f9..d876489ba5 100644 --- a/packages/experimental/client-ui-plugin-recommendations/src/client/Card.module.css +++ b/packages/experimental/client-ui-plugin-recommendations/src/client/Card.module.css @@ -2,6 +2,11 @@ .header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; background: var(--dsw-alias-bg-module-platform); font-size: 12px; color: var(--dsw-alias-label-secondary); } .badge { font-size: 11px; } .body { padding: 16px; } +.details { display: block; width: 100%; padding: 0; border: 0; background: none; color: inherit; text-align: start; cursor: pointer; } +.details:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: var(--dsw-radius-sm); } +.details:hover .title { text-decoration: underline; } +.detailHint { display: block; margin-top: 8px; font-size: 12px; color: var(--dsw-alias-label-secondary); } +.reason, .description { display: block; } .title { font-size: 14px; font-weight: 500; overflow-wrap: anywhere; } .reason { margin: 8px 0 4px; font-size: 13px; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; } .description { margin: 0; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); overflow-wrap: anywhere; } diff --git a/packages/experimental/client-ui-plugin-recommendations/src/client/Card.tsx b/packages/experimental/client-ui-plugin-recommendations/src/client/Card.tsx index 805583db9b..bae3058c9a 100644 --- a/packages/experimental/client-ui-plugin-recommendations/src/client/Card.tsx +++ b/packages/experimental/client-ui-plugin-recommendations/src/client/Card.tsx @@ -12,6 +12,7 @@ import css from './Card.module.css' /** Session-bound callbacks and language, without a service in the component. */ export interface CardInjected { act: (callId: ToolCallId, action: 'enable' | 'dismiss') => Promise + openDetails: (packageName: string) => void hooks: { chinese: HostObservable } } @@ -37,7 +38,7 @@ export function RecommendationTail({ turn, useRecommendations, ...props }: Pick< * @param props - Session-bound recommendation, actions and locale. * @returns the card below its completed answer. */ -export function RecommendationCard({ recommendation, useProjection, useChinese, act, t }: CardProps) { +export function RecommendationCard({ recommendation, useProjection, useChinese, act, openDetails, t }: CardProps) { const chinese = useChinese(value => value) const decisions = useProjection('pluginRecommendations') const outcome = decisions?.decisions[recommendation.callId] @@ -59,9 +60,13 @@ export function RecommendationCard({ recommendation, useProjection, useChinese, return
{t('heading')}{t('official')}
- {chinese ? recommendation.titleZh : recommendation.titleEn} -

{recommendation.reason}

-

{chinese ? recommendation.descriptionZh : recommendation.descriptionEn}

+ {outcome !== undefined &&

{t(outcome)}

} {error !== undefined &&

{t(error)}

} {open &&