fix(client): restore built Tool presentation snapshots
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
/* Shared Tool calls disclosure header: [16px leading] gap 6 [title 14/24]. */
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.row[data-expandable] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.leading {
|
||||
position: relative;
|
||||
flex: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 6px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--dsw-alias-label-tertiary);
|
||||
}
|
||||
|
||||
button.leading {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.iconIdle {
|
||||
display: inline-flex;
|
||||
opacity: 1;
|
||||
transition: opacity 100ms ease;
|
||||
}
|
||||
|
||||
.chevronHover {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
opacity: 0;
|
||||
transition: opacity 100ms ease;
|
||||
}
|
||||
|
||||
.row:hover .iconIdle {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.row:hover .chevronHover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: none;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
color: var(--dsw-alias-label-secondary);
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import { type KeyboardEvent, type MouseEvent, type ReactNode } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import css from './DisclosureRow.module.css'
|
||||
|
||||
/** Shared 24px disclosure chrome for conversation flow rows. */
|
||||
export interface DisclosureRowProps {
|
||||
icon: ReactNode
|
||||
title: string
|
||||
open: boolean
|
||||
expandable: boolean
|
||||
onToggle: () => void
|
||||
/** Makes the complete title row the disclosure target. */
|
||||
expandOnRowClick?: boolean | undefined
|
||||
/** Replaces the collapsed icon with a chevron while the row is hovered. */
|
||||
previewChevron?: boolean | undefined
|
||||
/** Keeps `collapsedContent` inline while open (ToolRow's summary stays readable next to the expanded card). */
|
||||
keepContentWhenOpen?: boolean | undefined
|
||||
collapsedContent?: ReactNode
|
||||
children?: ReactNode
|
||||
className?: string | undefined
|
||||
rowClassName?: string | undefined
|
||||
leadingClassName?: string | undefined
|
||||
chevronClassName?: string | undefined
|
||||
titleClassName?: string | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Render one disclosure header and its controlled expanded content.
|
||||
* @param props - Visual content, controlled state, and interaction policy.
|
||||
* @returns The disclosure row.
|
||||
*/
|
||||
export function DisclosureRow({
|
||||
icon,
|
||||
title,
|
||||
open,
|
||||
expandable,
|
||||
onToggle,
|
||||
expandOnRowClick = false,
|
||||
previewChevron = expandable,
|
||||
keepContentWhenOpen = false,
|
||||
collapsedContent,
|
||||
children,
|
||||
className,
|
||||
rowClassName,
|
||||
leadingClassName,
|
||||
chevronClassName,
|
||||
titleClassName,
|
||||
}: DisclosureRowProps) {
|
||||
const rowExpands = expandable && expandOnRowClick
|
||||
const toggleFromLeading = (event: MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation()
|
||||
onToggle()
|
||||
}
|
||||
const toggleFromKeyboard = (event: KeyboardEvent<HTMLDivElement>) => {
|
||||
if (!rowExpands || (event.key !== 'Enter' && event.key !== ' ')) return
|
||||
event.preventDefault()
|
||||
onToggle()
|
||||
}
|
||||
const collapsedLeading = previewChevron
|
||||
? (
|
||||
<>
|
||||
<span className={css.iconIdle}>{icon}</span>
|
||||
<IconChevronDownOutline14 className={clsx(chevronClassName, css.chevronHover)} />
|
||||
</>
|
||||
)
|
||||
: icon
|
||||
const leading = open
|
||||
? <IconChevronDownOutline14 className={chevronClassName} />
|
||||
: collapsedLeading
|
||||
|
||||
return (
|
||||
<div className={clsx(css.root, className)} data-open={open || undefined}>
|
||||
<div
|
||||
className={clsx(css.row, rowClassName)}
|
||||
data-disclosure-row
|
||||
data-expandable={rowExpands || undefined}
|
||||
role={rowExpands ? 'button' : undefined}
|
||||
tabIndex={rowExpands ? 0 : undefined}
|
||||
aria-expanded={rowExpands ? open : undefined}
|
||||
onClick={rowExpands ? onToggle : undefined}
|
||||
onKeyDown={rowExpands ? toggleFromKeyboard : undefined}
|
||||
>
|
||||
{expandable && !rowExpands ? (
|
||||
<button
|
||||
type="button"
|
||||
className={clsx(css.leading, leadingClassName)}
|
||||
aria-expanded={open}
|
||||
onClick={toggleFromLeading}
|
||||
>
|
||||
{leading}
|
||||
</button>
|
||||
) : (
|
||||
<span className={clsx(css.leading, leadingClassName)}>
|
||||
{leading}
|
||||
</span>
|
||||
)}
|
||||
<span className={clsx(css.title, titleClassName)}>{title}</span>
|
||||
{(keepContentWhenOpen || !open) && collapsedContent}
|
||||
</div>
|
||||
{open && children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
import { useState, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import {
|
||||
CodeBlock, DiffBlock, IconInspectOutline12, ReadBlock, SearchBlock, StateDot, TerminalBlock, WebBlock,
|
||||
CodeBlock, DiffBlock, DisclosureRow, IconInspectOutline12, ReadBlock, SearchBlock, StateDot, TerminalBlock, WebBlock,
|
||||
} from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { WebBlockProps } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
@@ -29,7 +29,6 @@ import { CHAT_READ_MAX_LINES, type ReadCardModel } from '../models/read-card-mod
|
||||
import { CHAT_SEARCH_MAX_LINES, type SearchCardModel } from '../models/search-card-model.ts'
|
||||
import { terminalBlockLabels, type TerminalCardModel } from '../models/terminal-card-model.ts'
|
||||
import type { ToolRowState, ToolRowVariant } from '../models/tool-call-model.ts'
|
||||
import { DisclosureRow } from './DisclosureRow.tsx'
|
||||
import css from './ToolRow.module.css'
|
||||
|
||||
export interface ToolRowProps {
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
* are derived once.
|
||||
* @module
|
||||
*/
|
||||
import { resolveWorkspacePath } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import type { TerminalBlockLabels, TerminalBlockProps } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import { resolveToolPath, type ToolCallBlock } from './tool-call-model.ts'
|
||||
import type { ToolCallBlock } from './tool-call-model.ts'
|
||||
|
||||
/**
|
||||
* Build the TerminalBlock display copy from the conversation locale seat —
|
||||
@@ -88,7 +89,7 @@ export function terminalFailed(model: TerminalCardModel): boolean {
|
||||
function resolveTerminalCwd(viewCwd: string | undefined, sessionCwd: string | undefined): string | undefined {
|
||||
if (viewCwd === undefined || viewCwd === '') return sessionCwd
|
||||
if (sessionCwd === undefined || sessionCwd === '') return normalizeSegments(viewCwd)
|
||||
return normalizeSegments(resolveToolPath(sessionCwd, viewCwd))
|
||||
return normalizeSegments(resolveWorkspacePath(sessionCwd, viewCwd))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,21 +172,6 @@ function deriveFilePath(variant: ToolRowVariant, argsRaw: string): string | unde
|
||||
return picked === undefined ? undefined : firstLine(picked)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a tool-arg path against the session cwd for host.openPath.
|
||||
* Absolute POSIX/Windows paths pass through; relative paths join under cwd.
|
||||
* @param cwd - session working directory (may be absent for ungrouped sessions).
|
||||
* @param path - path as carried in tool args.
|
||||
* @returns a host-facing path string.
|
||||
*/
|
||||
export function resolveToolPath(cwd: string | undefined, path: string): string {
|
||||
if (path.startsWith('/') || /^[A-Za-z]:[/\\]/.test(path) || path.startsWith('\\\\')) return path
|
||||
if (cwd === undefined || cwd === '') return path
|
||||
const base = cwd.replace(/[/\\]+$/, '')
|
||||
const rel = path.replace(/^[/\\]+/, '')
|
||||
return `${base}/${rel}`
|
||||
}
|
||||
|
||||
function deriveBody(variant: ToolRowVariant, argsRaw: string): string | null {
|
||||
if (argsRaw === '') return null
|
||||
const parsed = parseArgs(argsRaw)
|
||||
|
||||
Reference in New Issue
Block a user