mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-11-11 05:17:43 +08:00
Merge pull request #6594 from deepseek-harness/turtle/plugin-market-enable-stay
fix(plugin-manager): keep the selected tab when enabling a bundle
This commit is contained in:
+2
-2
@@ -9,8 +9,8 @@
|
||||
en: edefff7cd986a509
|
||||
zh: a270839fa86976a2
|
||||
/agent-note-guided-plugin-installation/decision:
|
||||
en: 30f1e636973df06a
|
||||
zh: 0f874b88a5d4d7f5
|
||||
en: 5448b9f8aaa9a569
|
||||
zh: 9024c5328c5da3bd
|
||||
/agent-note-guided-plugin-installation/alternatives-considered:
|
||||
en: be64b541f4d81e7c
|
||||
zh: 8600531c08ab4288
|
||||
|
||||
@@ -20,7 +20,7 @@ The install dialog put a spec straight into `pnpm add` and showed pnpm's termina
|
||||
|
||||
**Cancellation is the manager's, not the signal's.** The dialog generates a request id for each run; the Host streams the run's output and phases under it, and `cancelInstall` answers only after pnpm exited and the files are back. The dialog waits for that answer before offering the spec again; an aborted RPC or a lost connection is not a confirmation. Only the check takes a trailing `AbortSignal`: going back or closing drops a registry lookup, whose settlement nothing waits for.
|
||||
|
||||
**Enabling comes after the fact.** The run installs with `enabled: false`; the finished screen offers **Enable now** for the bundle it added, and the dialog closes and the list scrolls to it. Nothing is enabled before the person has seen what was installed.
|
||||
**Enabling comes after the fact.** The run installs with `enabled: false`; the finished screen offers **Enable now** for the bundle it added; the dialog closes, and the list scrolls to it when its card is on the current page. Nothing is enabled before the person has seen what was installed.
|
||||
|
||||
**Outcomes of the moment are toasts.** A change that waits for the next start, one a higher layer overrides, a cancelled run, and a refused action each toast and retire; nothing stays on the page.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Status: implemented
|
||||
|
||||
**取消属于管理器,不属于信号。** 对话框为每次运行生成一个 request id;宿主在它之下流式转发运行的输出与阶段,`cancelInstall` 只在 pnpm 退出且文件恢复后才答复。对话框等到这个答复才把 spec 重新交回;中止的 RPC 或断开的连接都不算确认。只有检查末尾接受 `AbortSignal`:返回编辑或关闭会丢掉一次注册表查询,没有人等它的结果。
|
||||
|
||||
**启用在事后。** 运行以 `enabled: false` 安装;完成画面为它新增的组合包提供**立即启用**,对话框关闭,列表滚动到它。在人看到装了什么之前,不会启用任何东西。
|
||||
**启用在事后。** 运行以 `enabled: false` 安装;完成画面为它新增的组合包提供**立即启用**,对话框关闭;其卡片在当前页面时,列表滚动到它。在人看到装了什么之前,不会启用任何东西。
|
||||
|
||||
**当下的结果是 toast。** 要等下次启动的变更、被更高层覆盖的变更、被取消的运行、被拒绝的操作,各弹一条 toast 后自行消失;页面上不留任何东西。
|
||||
|
||||
|
||||
@@ -1551,8 +1551,6 @@ export function PluginManagerPage(props: PluginManagerPageProps): ReactNode {
|
||||
// A contributed tab that left the ledger falls back to Installed, and stays there when it returns.
|
||||
const tab = tabs.some(item => item.id === selectedTab) ? selectedTab : INSTALLED_TAB
|
||||
useEffect(() => { if (tab !== selectedTab) setTab(tab) }, [tab, selectedTab, setTab])
|
||||
// A bundle an install just enabled is shown where its card is.
|
||||
useEffect(() => { if (state.highlight !== null) setTab(INSTALLED_TAB) }, [state.highlight, setTab])
|
||||
const tabsId = useId()
|
||||
const [activation, setActivation] = useState<string | null>(null)
|
||||
useEffect(() => { ensure() }, [ensure])
|
||||
@@ -1815,7 +1813,8 @@ export function PluginManagerPage(props: PluginManagerPageProps): ReactNode {
|
||||
</div>
|
||||
)
|
||||
: null}
|
||||
{showsCards && activated !== undefined && !state.install.open
|
||||
{/* Activation guidance belongs beside the Installed list that holds the enabled bundle's card. */}
|
||||
{installedCards && activated !== undefined && !state.install.open
|
||||
? renderSlot('plugins.bundle.activation', {
|
||||
packageName: activated.name,
|
||||
onDismiss: () => { setActivation(null) },
|
||||
|
||||
@@ -216,7 +216,7 @@ function renderTab(
|
||||
|
||||
describe('PluginManagerPage', () => {
|
||||
it('shows no tabs without contributions, and switches between Installed and a contributed tab', () => {
|
||||
const { actions, navigation, setTabs, set } = renderTab({ packages: [pkg()] }, {}, {
|
||||
const { actions, navigation, setTabs } = renderTab({ packages: [pkg()] }, {}, {
|
||||
'plugins.tab:discover': (_view, owner) => {
|
||||
const tab = owner as PluginTabProps
|
||||
return (
|
||||
@@ -247,13 +247,20 @@ describe('PluginManagerPage', () => {
|
||||
setTabs([])
|
||||
expect(document.querySelector('[data-plugin-group="bundles"]')).not.toBeNull()
|
||||
expect(navigation.getSnapshot().tab).toBe('installed')
|
||||
// Enabling a bundle an install added highlights its card, so the page shows Installed.
|
||||
// A contributed tab that returns can be selected again.
|
||||
setTabs([{ id: 'discover', label: 'Discover' }])
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Discover' }))
|
||||
expect(screen.getByRole('tabpanel', { name: 'Discover' })).toBeTruthy()
|
||||
})
|
||||
|
||||
it('marks the bundle an install enabled without leaving a contributed tab', () => {
|
||||
const { navigation, set } = renderTab({ packages: [pkg()] }, {}, {}, {}, [{ id: 'discover', label: 'Discover' }])
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Discover' }))
|
||||
expect(screen.getByRole('tabpanel', { name: 'Discover' })).toBeTruthy()
|
||||
// Enable now publishes the new bundle's mark; the mark scrolls to a visible card and selects no page.
|
||||
set({ highlight: 'dsh-better-sidebar' })
|
||||
expect(navigation.getSnapshot().tab).toBe('installed')
|
||||
expect(screen.getByRole('tabpanel', { name: en.installedTab })).toBeTruthy()
|
||||
expect(navigation.getSnapshot().tab).toBe('discover')
|
||||
expect(screen.getByRole('tabpanel', { name: 'Discover' })).toBeTruthy()
|
||||
})
|
||||
|
||||
it('keeps the Installed tab panel through loading and the More list out of the tabs', () => {
|
||||
@@ -2318,6 +2325,24 @@ it('dismisses activation guidance until the user enables the bundle again', () =
|
||||
expect(screen.getByText('Later')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('keeps activation guidance with the Installed list when a contributed tab enables the bundle', () => {
|
||||
const name = 'dsh-better-sidebar'
|
||||
const subject = { spec: `${name}@0.16.0`, status: 'accepted', kind: 'registry', name, bundle: true, registry: null } as const
|
||||
const { set } = renderTab({
|
||||
install: { ...IDLE_INSTALL, open: true, phase: 'done', subject, installed: name },
|
||||
}, { bundles: new Set([name]) }, {
|
||||
[`plugins.bundle.activation:${name}`]: () => <div>Enable guidance</div>,
|
||||
}, {}, [{ id: 'discover', label: 'Discover' }])
|
||||
fireEvent.click(screen.getByRole('button', { name: en.installEnableNow }))
|
||||
set({ install: IDLE_INSTALL, packages: [pkg()] })
|
||||
expect(screen.getByText('Enable guidance')).toBeTruthy()
|
||||
// A contributed tab shows its own content, not guidance for the Installed list.
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Discover' }))
|
||||
expect(screen.queryByText('Enable guidance')).toBeNull()
|
||||
fireEvent.click(screen.getByRole('tab', { name: en.installedTab }))
|
||||
expect(screen.getByText('Enable guidance')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('supplies the accepted entry values and atomic mutation action to a custom plugin page', () => {
|
||||
const mutate = vi.fn(async () => true)
|
||||
const form: ConfigPageForm = {
|
||||
|
||||
Reference in New Issue
Block a user