fix(app): patch tool renders like edit tool

This commit is contained in:
Adam
2026-02-20 09:13:13 -06:00
parent ce17f9dd94
commit 9c5bbba6ea

View File

@@ -1603,6 +1603,12 @@ ToolRegistry.register({
const i18n = useI18n() const i18n = useI18n()
const diffComponent = useDiffComponent() const diffComponent = useDiffComponent()
const files = createMemo(() => (props.metadata.files ?? []) as ApplyPatchFile[]) const files = createMemo(() => (props.metadata.files ?? []) as ApplyPatchFile[])
const pending = createMemo(() => props.status === "pending" || props.status === "running")
const single = createMemo(() => {
const list = files()
if (list.length !== 1) return
return list[0]
})
const [expanded, setExpanded] = createSignal<string[]>([]) const [expanded, setExpanded] = createSignal<string[]>([])
let seeded = false let seeded = false
@@ -1621,100 +1627,147 @@ ToolRegistry.register({
}) })
return ( return (
<div data-component="apply-patch-tool"> <Show
<BasicTool when={single()}
{...props} fallback={
icon="code-lines" <div data-component="apply-patch-tool">
defer <BasicTool
trigger={{ {...props}
title: i18n.t("ui.tool.patch"), icon="code-lines"
subtitle: subtitle(), defer
}} trigger={{
> title: i18n.t("ui.tool.patch"),
<Show when={files().length > 0}> subtitle: subtitle(),
<Accordion }}
multiple
data-scope="apply-patch"
style={{ "--sticky-accordion-offset": "40px" }}
value={expanded()}
onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
> >
<For each={files()}> <Show when={files().length > 0}>
{(file) => { <Accordion
const active = createMemo(() => expanded().includes(file.filePath)) multiple
const [visible, setVisible] = createSignal(false) data-scope="apply-patch"
style={{ "--sticky-accordion-offset": "40px" }}
value={expanded()}
onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
>
<For each={files()}>
{(file) => {
const active = createMemo(() => expanded().includes(file.filePath))
const [visible, setVisible] = createSignal(false)
createEffect(() => { createEffect(() => {
if (!active()) { if (!active()) {
setVisible(false) setVisible(false)
return return
} }
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (!active()) return if (!active()) return
setVisible(true) setVisible(true)
}) })
}) })
return ( return (
<Accordion.Item value={file.filePath} data-type={file.type}> <Accordion.Item value={file.filePath} data-type={file.type}>
<StickyAccordionHeader> <StickyAccordionHeader>
<Accordion.Trigger> <Accordion.Trigger>
<div data-slot="apply-patch-trigger-content"> <div data-slot="apply-patch-trigger-content">
<div data-slot="apply-patch-file-info"> <div data-slot="apply-patch-file-info">
<FileIcon node={{ path: file.relativePath, type: "file" }} /> <FileIcon node={{ path: file.relativePath, type: "file" }} />
<div data-slot="apply-patch-file-name-container"> <div data-slot="apply-patch-file-name-container">
<Show when={file.relativePath.includes("/")}> <Show when={file.relativePath.includes("/")}>
<span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span> <span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span>
</Show> </Show>
<span data-slot="apply-patch-filename">{getFilename(file.relativePath)}</span> <span data-slot="apply-patch-filename">{getFilename(file.relativePath)}</span>
</div>
</div>
<div data-slot="apply-patch-trigger-actions">
<Switch>
<Match when={file.type === "add"}>
<span data-slot="apply-patch-change" data-type="added">
{i18n.t("ui.patch.action.created")}
</span>
</Match>
<Match when={file.type === "delete"}>
<span data-slot="apply-patch-change" data-type="removed">
{i18n.t("ui.patch.action.deleted")}
</span>
</Match>
<Match when={file.type === "move"}>
<span data-slot="apply-patch-change" data-type="modified">
{i18n.t("ui.patch.action.moved")}
</span>
</Match>
<Match when={true}>
<DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} />
</Match>
</Switch>
<Icon name="chevron-grabber-vertical" size="small" />
</div>
</div> </div>
</div> </Accordion.Trigger>
<div data-slot="apply-patch-trigger-actions"> </StickyAccordionHeader>
<Switch> <Accordion.Content>
<Match when={file.type === "add"}> <Show when={visible()}>
<span data-slot="apply-patch-change" data-type="added"> <div data-component="apply-patch-file-diff">
{i18n.t("ui.patch.action.created")} <Dynamic
</span> component={diffComponent}
</Match> before={{ name: file.filePath, contents: file.before }}
<Match when={file.type === "delete"}> after={{ name: file.movePath ?? file.filePath, contents: file.after }}
<span data-slot="apply-patch-change" data-type="removed"> />
{i18n.t("ui.patch.action.deleted")} </div>
</span> </Show>
</Match> </Accordion.Content>
<Match when={file.type === "move"}> </Accordion.Item>
<span data-slot="apply-patch-change" data-type="modified"> )
{i18n.t("ui.patch.action.moved")} }}
</span> </For>
</Match> </Accordion>
<Match when={true}> </Show>
<DiffChanges changes={{ additions: file.additions, deletions: file.deletions }} /> </BasicTool>
</Match> </div>
</Switch> }
<Icon name="chevron-grabber-vertical" size="small" /> >
</div> {(file) => (
</div> <BasicTool
</Accordion.Trigger> {...props}
</StickyAccordionHeader> icon="code-lines"
<Accordion.Content> defer
<Show when={visible()}> trigger={
<div data-component="apply-patch-file-diff"> <div data-component="edit-trigger">
<Dynamic <div data-slot="message-part-title-area">
component={diffComponent} <div data-slot="message-part-title">
before={{ name: file.filePath, contents: file.before }} <span data-slot="message-part-title-text">
after={{ name: file.movePath ?? file.filePath, contents: file.after }} <Show when={pending()} fallback={i18n.t("ui.tool.patch")}>
/> <TextShimmer text={i18n.t("ui.tool.patch")} />
</div> </Show>
</Show> </span>
</Accordion.Content> <Show when={!pending()}>
</Accordion.Item> <span data-slot="message-part-title-filename">{getFilename(file().relativePath)}</span>
) </Show>
}} </div>
</For> <Show when={!pending() && file().relativePath.includes("/")}>
</Accordion> <div data-slot="message-part-path">
</Show> <span data-slot="message-part-directory">{getDirectory(file().relativePath)}</span>
</BasicTool> </div>
</div> </Show>
</div>
<div data-slot="message-part-actions">
<Show when={!pending()}>
<DiffChanges changes={{ additions: file().additions, deletions: file().deletions }} />
</Show>
</div>
</div>
}
>
<div data-component="edit-content">
<Dynamic
component={diffComponent}
before={{ name: file().filePath, contents: file().before }}
after={{ name: file().movePath ?? file().filePath, contents: file().after }}
/>
</div>
</BasicTool>
)}
</Show>
) )
}, },
}) })