|
|
@@ -12,7 +12,6 @@ import { AssistantParts, Message, MessageDivider, PART_MAPPING, type UserActions
|
|
|
import { Card } from "./card"
|
|
|
import { Accordion } from "./accordion"
|
|
|
import { StickyAccordionHeader } from "./sticky-accordion-header"
|
|
|
-import { Collapsible } from "./collapsible"
|
|
|
import { DiffChanges } from "./diff-changes"
|
|
|
import { Icon } from "./icon"
|
|
|
import { TextShimmer } from "./text-shimmer"
|
|
|
@@ -241,23 +240,20 @@ export function SessionTurn(
|
|
|
}, [])
|
|
|
.reverse()
|
|
|
})
|
|
|
+ const MAX_FILES = 10
|
|
|
const edited = createMemo(() => diffs().length)
|
|
|
const [state, setState] = createStore({
|
|
|
- open: false,
|
|
|
+ showAll: false,
|
|
|
expanded: [] as string[],
|
|
|
})
|
|
|
- const open = () => state.open
|
|
|
+ const showAll = () => state.showAll
|
|
|
const expanded = () => state.expanded
|
|
|
-
|
|
|
- createEffect(
|
|
|
- on(
|
|
|
- open,
|
|
|
- (value, prev) => {
|
|
|
- if (!value && prev) setState("expanded", [])
|
|
|
- },
|
|
|
- { defer: true },
|
|
|
- ),
|
|
|
- )
|
|
|
+ const overflow = createMemo(() => Math.max(0, edited() - MAX_FILES))
|
|
|
+ const visible = createMemo(() => (showAll() ? diffs() : diffs().slice(0, MAX_FILES)))
|
|
|
+ const toggleAll = () => {
|
|
|
+ autoScroll.pause()
|
|
|
+ setState("showAll", !showAll())
|
|
|
+ }
|
|
|
|
|
|
const assistantMessages = createMemo(
|
|
|
() => {
|
|
|
@@ -425,101 +421,100 @@ export function SessionTurn(
|
|
|
</Show>
|
|
|
<SessionRetry status={status()} show={active()} />
|
|
|
<Show when={edited() > 0 && !working()}>
|
|
|
- <div data-slot="session-turn-diffs">
|
|
|
- <Collapsible open={open()} onOpenChange={(value) => setState("open", value)} variant="ghost">
|
|
|
- <Collapsible.Trigger>
|
|
|
- <div data-component="session-turn-diffs-trigger">
|
|
|
- <div data-slot="session-turn-diffs-title">
|
|
|
- <span data-slot="session-turn-diffs-label">{i18n.t("ui.sessionReview.change.modified")}</span>
|
|
|
- <span data-slot="session-turn-diffs-count">
|
|
|
- {edited()} {i18n.t(edited() === 1 ? "ui.common.file.one" : "ui.common.file.other")}
|
|
|
- </span>
|
|
|
- <div data-slot="session-turn-diffs-meta">
|
|
|
- <DiffChanges changes={diffs()} variant="bars" />
|
|
|
- <Collapsible.Arrow />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </Collapsible.Trigger>
|
|
|
- <Collapsible.Content>
|
|
|
- <Show when={open()}>
|
|
|
- <div data-component="session-turn-diffs-content">
|
|
|
- <Accordion
|
|
|
- multiple
|
|
|
- style={{ "--sticky-accordion-offset": "40px" }}
|
|
|
- value={expanded()}
|
|
|
- onChange={(value) =>
|
|
|
- setState("expanded", Array.isArray(value) ? value : value ? [value] : [])
|
|
|
- }
|
|
|
- >
|
|
|
- <For each={diffs()}>
|
|
|
- {(diff) => {
|
|
|
- const active = createMemo(() => expanded().includes(diff.file))
|
|
|
- const [visible, setVisible] = createSignal(false)
|
|
|
-
|
|
|
- createEffect(
|
|
|
- on(
|
|
|
- active,
|
|
|
- (value) => {
|
|
|
- if (!value) {
|
|
|
- setVisible(false)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- requestAnimationFrame(() => {
|
|
|
- if (!active()) return
|
|
|
- setVisible(true)
|
|
|
- })
|
|
|
- },
|
|
|
- { defer: true },
|
|
|
- ),
|
|
|
- )
|
|
|
-
|
|
|
- return (
|
|
|
- <Accordion.Item value={diff.file}>
|
|
|
- <StickyAccordionHeader>
|
|
|
- <Accordion.Trigger>
|
|
|
- <div data-slot="session-turn-diff-trigger">
|
|
|
- <span data-slot="session-turn-diff-path">
|
|
|
- <Show when={diff.file.includes("/")}>
|
|
|
- <span data-slot="session-turn-diff-directory">
|
|
|
- {`\u202A${getDirectory(diff.file)}\u202C`}
|
|
|
- </span>
|
|
|
- </Show>
|
|
|
- <span data-slot="session-turn-diff-filename">{getFilename(diff.file)}</span>
|
|
|
- </span>
|
|
|
- <div data-slot="session-turn-diff-meta">
|
|
|
- <span data-slot="session-turn-diff-changes">
|
|
|
- <DiffChanges changes={diff} />
|
|
|
- </span>
|
|
|
- <span data-slot="session-turn-diff-chevron">
|
|
|
- <Icon name="chevron-down" size="small" />
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </Accordion.Trigger>
|
|
|
- </StickyAccordionHeader>
|
|
|
- <Accordion.Content>
|
|
|
- <Show when={visible()}>
|
|
|
- <div data-slot="session-turn-diff-view" data-scrollable>
|
|
|
- <Dynamic
|
|
|
- component={fileComponent}
|
|
|
- mode="diff"
|
|
|
- before={{ name: diff.file, contents: diff.before }}
|
|
|
- after={{ name: diff.file, contents: diff.after }}
|
|
|
- />
|
|
|
- </div>
|
|
|
+ <div
|
|
|
+ data-slot="session-turn-diffs"
|
|
|
+ data-component="session-turn-diffs-group"
|
|
|
+ data-show-all={showAll() || undefined}
|
|
|
+ >
|
|
|
+ <div data-slot="session-turn-diffs-header">
|
|
|
+ <span data-slot="session-turn-diffs-label">
|
|
|
+ {edited()} {i18n.t("ui.sessionTurn.diffs.changed")}{" "}
|
|
|
+ {i18n.t(edited() === 1 ? "ui.common.file.one" : "ui.common.file.other")}
|
|
|
+ </span>
|
|
|
+ <DiffChanges changes={diffs()} />
|
|
|
+ <Show when={overflow() > 0}>
|
|
|
+ <span data-slot="session-turn-diffs-toggle" onClick={toggleAll}>
|
|
|
+ {showAll() ? i18n.t("ui.sessionTurn.diffs.showLess") : i18n.t("ui.sessionTurn.diffs.showAll")}
|
|
|
+ </span>
|
|
|
+ </Show>
|
|
|
+ </div>
|
|
|
+ <div data-component="session-turn-diffs-content">
|
|
|
+ <Accordion
|
|
|
+ multiple
|
|
|
+ style={{ "--sticky-accordion-offset": "40px" }}
|
|
|
+ value={expanded()}
|
|
|
+ onChange={(value) => setState("expanded", Array.isArray(value) ? value : value ? [value] : [])}
|
|
|
+ >
|
|
|
+ <For each={visible()}>
|
|
|
+ {(diff) => {
|
|
|
+ const active = createMemo(() => expanded().includes(diff.file))
|
|
|
+ const [shown, setShown] = createSignal(false)
|
|
|
+
|
|
|
+ createEffect(
|
|
|
+ on(
|
|
|
+ active,
|
|
|
+ (value) => {
|
|
|
+ if (!value) {
|
|
|
+ setShown(false)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ if (!active()) return
|
|
|
+ setShown(true)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ { defer: true },
|
|
|
+ ),
|
|
|
+ )
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Accordion.Item value={diff.file}>
|
|
|
+ <StickyAccordionHeader>
|
|
|
+ <Accordion.Trigger>
|
|
|
+ <div data-slot="session-turn-diff-trigger">
|
|
|
+ <span data-slot="session-turn-diff-path">
|
|
|
+ <Show when={diff.file.includes("/")}>
|
|
|
+ <span data-slot="session-turn-diff-directory">
|
|
|
+ {`\u202A${getDirectory(diff.file)}\u202C`}
|
|
|
+ </span>
|
|
|
</Show>
|
|
|
- </Accordion.Content>
|
|
|
- </Accordion.Item>
|
|
|
- )
|
|
|
- }}
|
|
|
- </For>
|
|
|
- </Accordion>
|
|
|
- </div>
|
|
|
- </Show>
|
|
|
- </Collapsible.Content>
|
|
|
- </Collapsible>
|
|
|
+ <span data-slot="session-turn-diff-filename">{getFilename(diff.file)}</span>
|
|
|
+ </span>
|
|
|
+ <div data-slot="session-turn-diff-meta">
|
|
|
+ <span data-slot="session-turn-diff-changes">
|
|
|
+ <DiffChanges changes={diff} />
|
|
|
+ </span>
|
|
|
+ <span data-slot="session-turn-diff-chevron">
|
|
|
+ <Icon name="chevron-down" size="small" />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Accordion.Trigger>
|
|
|
+ </StickyAccordionHeader>
|
|
|
+ <Accordion.Content>
|
|
|
+ <Show when={shown()}>
|
|
|
+ <div data-slot="session-turn-diff-view" data-scrollable>
|
|
|
+ <Dynamic
|
|
|
+ component={fileComponent}
|
|
|
+ mode="diff"
|
|
|
+ before={{ name: diff.file, contents: diff.before }}
|
|
|
+ after={{ name: diff.file, contents: diff.after }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </Show>
|
|
|
+ </Accordion.Content>
|
|
|
+ </Accordion.Item>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ </For>
|
|
|
+ </Accordion>
|
|
|
+ <Show when={!showAll() && overflow() > 0}>
|
|
|
+ <div data-slot="session-turn-diffs-more" onClick={toggleAll}>
|
|
|
+ {i18n.t("ui.sessionTurn.diffs.more", { count: String(overflow()) })}
|
|
|
+ </div>
|
|
|
+ </Show>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</Show>
|
|
|
<Show when={error()}>
|