fix(client): distinguish grep/glob rows from the web search row
The grep, glob, and web_search tool rows all rendered as "Search" with the same magnifier icon, so a transcript full of local searches was indistinguishable from web searches. Grep and glob now carry their own command-named titles through TOOL_TITLES, and the web_search row wears a new globe glyph (IconGlobeOutline14) while keeping its "Search" title.
This commit is contained in:
@@ -23,8 +23,13 @@ import { CONVERSATION_NS as NS } from '../../locale.ts'
|
||||
/** Full row props: the toolview runtime share plus the standard locale seat. */
|
||||
type SearchRowProps = ToolCallViewProps & PropsLocale<'conversation'>
|
||||
|
||||
const SEARCH_TITLES: Record<string, string> = {
|
||||
grep: 'Grep',
|
||||
glob: 'Glob',
|
||||
}
|
||||
|
||||
/**
|
||||
* Search row: icon + Search · {summary} in the shared ToolRow chrome, with the
|
||||
* Search row: icon + Grep/Glob · {summary} in the shared ToolRow chrome, with the
|
||||
* completed search's card as the row's collapsed-by-default card body (a capped
|
||||
* search's recovery footer rides below it, inside ToolRow). Registered under
|
||||
* both `grep` and `glob`; the derived model's `kind` decides the card shape. A
|
||||
@@ -40,7 +45,7 @@ export function SearchRow({ toolName, block, inspect, t }: SearchRowProps) {
|
||||
variant={model.variant}
|
||||
toolName={toolName}
|
||||
icon={<IconSearchOutline16 size={14} />}
|
||||
title={model.title}
|
||||
title={SEARCH_TITLES[toolName] ?? model.title}
|
||||
// The result view's replacement title outranks the args-derived summary,
|
||||
// matching the terminal card's description precedence.
|
||||
summary={search?.title ?? model.summary}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
// summary line alone.
|
||||
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import { IconBrowseOutline16, IconSearchOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import { IconBrowseOutline16, IconGlobeOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import type { ToolCallViewProps } from '../../contract/slots.ts'
|
||||
import { webCardModel } from '../models/web-card-model.ts'
|
||||
@@ -35,7 +35,8 @@ const WEB_TITLES: Record<string, string> = {
|
||||
export function WebRow({ toolName, block, inspect, t }: WebRowProps) {
|
||||
const model = toolRowModel(toolName, block)
|
||||
const web = webCardModel(block)
|
||||
const icon = toolName === 'web_fetch' ? <IconBrowseOutline16 size={14} /> : <IconSearchOutline16 size={14} />
|
||||
// Web search uses a globe; local grep/glob keep the magnifier family.
|
||||
const icon = toolName === 'web_fetch' ? <IconBrowseOutline16 size={14} /> : <IconGlobeOutline14 size={14} />
|
||||
return (
|
||||
<ToolRow
|
||||
t={t}
|
||||
|
||||
@@ -246,7 +246,8 @@ describe('SearchRow keyed card', () => {
|
||||
|
||||
it('collapses to the summary row; expanding reveals the grep card', () => {
|
||||
const view = render(<SearchRow {...rowProps(settledGrep(), 'grep')} />)
|
||||
expect(view.getByText('Search')).toBeTruthy()
|
||||
expect(view.getByText('Grep')).toBeTruthy()
|
||||
expect(view.queryByText('Search')).toBeNull()
|
||||
// Collapsed: the card is not in the DOM until the row is expanded.
|
||||
expect(searchKindOf(view.container)).toBeNull()
|
||||
expect(view.queryByText(/const foo = 1/)).toBeNull()
|
||||
@@ -259,6 +260,8 @@ describe('SearchRow keyed card', () => {
|
||||
|
||||
it('expands to the glob path card', () => {
|
||||
const view = render(<SearchRow {...rowProps(settledGlob(), 'glob')} />)
|
||||
expect(view.getByText('Glob')).toBeTruthy()
|
||||
expect(view.queryByText('Search')).toBeNull()
|
||||
expect(searchKindOf(view.container)).toBeNull()
|
||||
toggleRow(view)
|
||||
expect(view.getByText('src/a.ts')).toBeTruthy()
|
||||
|
||||
@@ -20,6 +20,7 @@ import type { ToolResultView } from '@deepseek-ai/dsh-api-remotes/client'
|
||||
import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react'
|
||||
import type { SelectionTarget } from '@deepseek-ai/dsh-client-ui-conversation/client'
|
||||
import type { ToolCallOwnerProps } from '@deepseek-ai/dsh-client-ui-tool/client'
|
||||
import { IconGlobeOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import { webCardModel } from '../src/client/tool/models/web-card-model.ts'
|
||||
import { createChatStore } from '@deepseek-ai/dsh-client-ui-conversation/src/client/stores.ts'
|
||||
import { GenericToolCard } from '../src/client/tool/toolviews/GenericToolCard.tsx'
|
||||
@@ -140,9 +141,11 @@ describe('chat row web body', () => {
|
||||
}
|
||||
|
||||
it('the WebRow collapses to the summary row, expanding to the full search card', () => {
|
||||
const globe = render(<IconGlobeOutline14 />).container.querySelector('svg')!.outerHTML
|
||||
const view = render(<WebRow {...rowProps(settledSearch(), 'web_search')} />)
|
||||
// Collapsed: the summary row alone, no card in the DOM.
|
||||
expect(view.getByText('Search')).toBeTruthy()
|
||||
expect(view.container.querySelector('svg')?.outerHTML).toBe(globe)
|
||||
expect(view.queryByText('Titled')).toBeNull()
|
||||
expect(view.container.querySelector('[data-web]')).toBeNull()
|
||||
toggleRow(view)
|
||||
|
||||
Reference in New Issue
Block a user