fix(mobile): gate the tool detail panel on having detail (STA-3333)

The Tools toggle opens every row at once, bypassing the row's tap guard,
so a row with nothing to expand rendered its own label again underneath
itself — and the tap that would dismiss it is a no-op. Matches desktop.
This commit is contained in:
Brennan Benson
2026-08-04 03:45:39 -07:00
parent 27fe90a6f2
commit 6b43b51711
2 changed files with 16 additions and 2 deletions
@@ -141,4 +141,14 @@ describe('MobileNativeChatMessage', () => {
'{\n "cmd": "git status",\n "description": "Inspect changes"\n}'
)
})
it('does not echo the row label as detail when a row has nothing to expand', () => {
// The Tools toggle opens every row at once, bypassing the tap guard — a row
// whose formatted input is its own label would echo itself in a panel that
// no tap can dismiss.
const tree = render(toolMessage([{ type: 'tool-call', name: 'ListTodos', input: '{}' }]), {
toolsExpanded: true
})
expect(textIn(tree.root).filter((text) => text === '{}')).toHaveLength(1)
})
})
@@ -109,6 +109,10 @@ function ToolLine({
result !== undefined ||
preview.length > 40 ||
(call !== undefined && isStructuredToolInput(call.input))
// The group toggle opens every line at once, bypassing the tap guard, so the
// panel has to consult it too — else a detail-less row echoes its own label
// under itself and no tap can dismiss it.
const showDetail = hasDetail && expanded
// A tool that targets a file (Read/Edit/Write…) renders its preview as a
// tappable link that opens the file, independent of the line's expand tap.
const filePath = call ? toolFilePath(call.input) : null
@@ -120,7 +124,7 @@ function ToolLine({
onPress={() => hasDetail && setExpanded((v) => !v)}
hitSlop={6}
>
{expanded ? (
{showDetail ? (
<ChevronDown size={15} color={colors.textMuted} strokeWidth={2} />
) : (
<SquareChevronRight size={15} color={colors.textMuted} strokeWidth={2} />
@@ -137,7 +141,7 @@ function ToolLine({
</Text>
) : null}
</Pressable>
{expanded ? (
{showDetail ? (
<View style={styles.toolDetail}>
{callDiff ? <DiffView lines={callDiff} /> : null}
{callDetail ? <Text style={styles.mono}>{callDetail}</Text> : null}