Parcourir la source

fix(app): patch tool renders like edit tool

Adam il y a 8 mois
Parent
commit
9c5bbba6ea
1 fichiers modifiés avec 145 ajouts et 92 suppressions
  1. 145 92
      packages/ui/src/components/message-part.tsx

+ 145 - 92
packages/ui/src/components/message-part.tsx

@@ -1603,6 +1603,12 @@ ToolRegistry.register({
     const i18n = useI18n()
     const diffComponent = useDiffComponent()
     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[]>([])
     let seeded = false
 
@@ -1621,100 +1627,147 @@ ToolRegistry.register({
     })
 
     return (
-      <div data-component="apply-patch-tool">
-        <BasicTool
-          {...props}
-          icon="code-lines"
-          defer
-          trigger={{
-            title: i18n.t("ui.tool.patch"),
-            subtitle: subtitle(),
-          }}
-        >
-          <Show when={files().length > 0}>
-            <Accordion
-              multiple
-              data-scope="apply-patch"
-              style={{ "--sticky-accordion-offset": "40px" }}
-              value={expanded()}
-              onChange={(value) => setExpanded(Array.isArray(value) ? value : value ? [value] : [])}
+      <Show
+        when={single()}
+        fallback={
+          <div data-component="apply-patch-tool">
+            <BasicTool
+              {...props}
+              icon="code-lines"
+              defer
+              trigger={{
+                title: i18n.t("ui.tool.patch"),
+                subtitle: subtitle(),
+              }}
             >
-              <For each={files()}>
-                {(file) => {
-                  const active = createMemo(() => expanded().includes(file.filePath))
-                  const [visible, setVisible] = createSignal(false)
-
-                  createEffect(() => {
-                    if (!active()) {
-                      setVisible(false)
-                      return
-                    }
-
-                    requestAnimationFrame(() => {
-                      if (!active()) return
-                      setVisible(true)
-                    })
-                  })
-
-                  return (
-                    <Accordion.Item value={file.filePath} data-type={file.type}>
-                      <StickyAccordionHeader>
-                        <Accordion.Trigger>
-                          <div data-slot="apply-patch-trigger-content">
-                            <div data-slot="apply-patch-file-info">
-                              <FileIcon node={{ path: file.relativePath, type: "file" }} />
-                              <div data-slot="apply-patch-file-name-container">
-                                <Show when={file.relativePath.includes("/")}>
-                                  <span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span>
-                                </Show>
-                                <span data-slot="apply-patch-filename">{getFilename(file.relativePath)}</span>
+              <Show when={files().length > 0}>
+                <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()}>
+                    {(file) => {
+                      const active = createMemo(() => expanded().includes(file.filePath))
+                      const [visible, setVisible] = createSignal(false)
+
+                      createEffect(() => {
+                        if (!active()) {
+                          setVisible(false)
+                          return
+                        }
+
+                        requestAnimationFrame(() => {
+                          if (!active()) return
+                          setVisible(true)
+                        })
+                      })
+
+                      return (
+                        <Accordion.Item value={file.filePath} data-type={file.type}>
+                          <StickyAccordionHeader>
+                            <Accordion.Trigger>
+                              <div data-slot="apply-patch-trigger-content">
+                                <div data-slot="apply-patch-file-info">
+                                  <FileIcon node={{ path: file.relativePath, type: "file" }} />
+                                  <div data-slot="apply-patch-file-name-container">
+                                    <Show when={file.relativePath.includes("/")}>
+                                      <span data-slot="apply-patch-directory">{`\u202A${getDirectory(file.relativePath)}\u202C`}</span>
+                                    </Show>
+                                    <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 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>
-                        </Accordion.Trigger>
-                      </StickyAccordionHeader>
-                      <Accordion.Content>
-                        <Show when={visible()}>
-                          <div data-component="apply-patch-file-diff">
-                            <Dynamic
-                              component={diffComponent}
-                              before={{ name: file.filePath, contents: file.before }}
-                              after={{ name: file.movePath ?? file.filePath, contents: file.after }}
-                            />
-                          </div>
-                        </Show>
-                      </Accordion.Content>
-                    </Accordion.Item>
-                  )
-                }}
-              </For>
-            </Accordion>
-          </Show>
-        </BasicTool>
-      </div>
+                            </Accordion.Trigger>
+                          </StickyAccordionHeader>
+                          <Accordion.Content>
+                            <Show when={visible()}>
+                              <div data-component="apply-patch-file-diff">
+                                <Dynamic
+                                  component={diffComponent}
+                                  before={{ name: file.filePath, contents: file.before }}
+                                  after={{ name: file.movePath ?? file.filePath, contents: file.after }}
+                                />
+                              </div>
+                            </Show>
+                          </Accordion.Content>
+                        </Accordion.Item>
+                      )
+                    }}
+                  </For>
+                </Accordion>
+              </Show>
+            </BasicTool>
+          </div>
+        }
+      >
+        {(file) => (
+          <BasicTool
+            {...props}
+            icon="code-lines"
+            defer
+            trigger={
+              <div data-component="edit-trigger">
+                <div data-slot="message-part-title-area">
+                  <div data-slot="message-part-title">
+                    <span data-slot="message-part-title-text">
+                      <Show when={pending()} fallback={i18n.t("ui.tool.patch")}>
+                        <TextShimmer text={i18n.t("ui.tool.patch")} />
+                      </Show>
+                    </span>
+                    <Show when={!pending()}>
+                      <span data-slot="message-part-title-filename">{getFilename(file().relativePath)}</span>
+                    </Show>
+                  </div>
+                  <Show when={!pending() && file().relativePath.includes("/")}>
+                    <div data-slot="message-part-path">
+                      <span data-slot="message-part-directory">{getDirectory(file().relativePath)}</span>
+                    </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>
     )
   },
 })