diff --git a/packages/client/ui-primitives/src/icons/index.tsx b/packages/client/ui-primitives/src/icons/index.tsx index 972e0ec14d..2606f54e62 100644 --- a/packages/client/ui-primitives/src/icons/index.tsx +++ b/packages/client/ui-primitives/src/icons/index.tsx @@ -31,6 +31,18 @@ export const IconSearchOutline16 = ({ size = 16, className }: IconProps) => ( ) +/** ic_ds_globe_outline_14 — meridian globe (harness-only figma extract). */ +export const IconGlobeOutline14 = ({ size = 14, className }: IconProps) => ( + + + +) + /** ic_ds_settings_outline_14 */ export const IconSettingsOutline14 = ({ size = 14, className }: IconProps) => ( diff --git a/packages/client/ui-primitives/tests/icons.client.spec.tsx b/packages/client/ui-primitives/tests/icons.client.spec.tsx index f6560a4cc1..41f8caad47 100644 --- a/packages/client/ui-primitives/tests/icons.client.spec.tsx +++ b/packages/client/ui-primitives/tests/icons.client.spec.tsx @@ -16,8 +16,8 @@ const icons = Object.fromEntries( const iconNames = Object.keys(icons) describe('ic_ds_ icon set', () => { - it('exports the full icon set (46 deepsuite + 19 figma extracts + three product glyphs outside those sets)', () => { - expect(iconNames.length).toBe(68) + it('exports the full icon set (46 deepsuite + 20 figma extracts + three product glyphs outside those sets)', () => { + expect(iconNames.length).toBe(69) }) it.each(iconNames)('%s renders an svg with currentColor fills and no hardcoded palette', (name) => { diff --git a/packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx b/packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx index 47b17b6fa8..e49189d6d4 100644 --- a/packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx +++ b/packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx @@ -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 = { + 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={} - 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} diff --git a/packages/client/ui-tool/src/client/tool/toolviews/web-row.tsx b/packages/client/ui-tool/src/client/tool/toolviews/web-row.tsx index c0e546f071..3dab222e95 100644 --- a/packages/client/ui-tool/src/client/tool/toolviews/web-row.tsx +++ b/packages/client/ui-tool/src/client/tool/toolviews/web-row.tsx @@ -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 = { export function WebRow({ toolName, block, inspect, t }: WebRowProps) { const model = toolRowModel(toolName, block) const web = webCardModel(block) - const icon = toolName === 'web_fetch' ? : + // Web search uses a globe; local grep/glob keep the magnifier family. + const icon = toolName === 'web_fetch' ? : return ( { it('collapses to the summary row; expanding reveals the grep card', () => { const view = render() - 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() + expect(view.getByText('Glob')).toBeTruthy() + expect(view.queryByText('Search')).toBeNull() expect(searchKindOf(view.container)).toBeNull() toggleRow(view) expect(view.getByText('src/a.ts')).toBeTruthy() diff --git a/packages/client/ui-tool/tests/web-card.client.spec.tsx b/packages/client/ui-tool/tests/web-card.client.spec.tsx index 8a3efd2627..3b5a7ebf32 100644 --- a/packages/client/ui-tool/tests/web-card.client.spec.tsx +++ b/packages/client/ui-tool/tests/web-card.client.spec.tsx @@ -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().container.querySelector('svg')!.outerHTML const view = render() // 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)