mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
Merge pull request #11037 from Kilo-Org/perf-agent-manager-timeline-renderer
perf(vscode): coalesce task timeline performance optimization
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep task timelines in place while reviewing earlier activity across Kilo chat surfaces, and resume following updates from the latest bar.
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { sizes, MAX_HEIGHT } from "../../webview-ui/src/utils/timeline/sizes"
|
||||
import { sizes, pinned, MAX_HEIGHT } from "../../webview-ui/src/utils/timeline/sizes"
|
||||
import type { Part, TextPart, ToolPart, StepFinishPart } from "../../webview-ui/src/types/messages"
|
||||
|
||||
function mkText(text: string): TextPart {
|
||||
@@ -89,4 +89,10 @@ describe("timeline sizes", () => {
|
||||
expect(Number.isInteger(bar.height)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it("detects whether scrolling should follow new bars", () => {
|
||||
expect(pinned({ scrollLeft: 100, scrollWidth: 200, clientWidth: 100 })).toBe(true)
|
||||
expect(pinned({ scrollLeft: 88, scrollWidth: 200, clientWidth: 100 })).toBe(true)
|
||||
expect(pinned({ scrollLeft: 87, scrollWidth: 200, clientWidth: 100 })).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Component, Index, Show, createMemo, createEffect, createSignal, on, onC
|
||||
import { Portal } from "solid-js/web"
|
||||
import { useSession } from "../../context/session"
|
||||
import { color, label } from "../../utils/timeline/colors"
|
||||
import { sizes, MAX_HEIGHT } from "../../utils/timeline/sizes"
|
||||
import { sizes, pinned, MAX_HEIGHT } from "../../utils/timeline/sizes"
|
||||
import type { Part, Message } from "../../types/messages"
|
||||
|
||||
export interface TimelineBar {
|
||||
@@ -73,19 +73,34 @@ export const TaskTimeline: Component = () => {
|
||||
const bars = createMemo(() => collect(messages(), allParts()))
|
||||
const busy = () => session.status() === "busy"
|
||||
|
||||
// Auto-scroll to the latest bar when new bars appear
|
||||
// Reading scrollWidth and writing scrollLeft synchronously for every appended bar can
|
||||
// force repeated layout during streamed part updates. Batch those appends behind one
|
||||
// animation frame, after Solid has applied the current DOM updates. Only follow while
|
||||
// pinned so inspecting earlier activity is not interrupted by incoming bars.
|
||||
let prev = 0
|
||||
let frame: number | undefined
|
||||
let follow = true
|
||||
const onScroll = () => {
|
||||
if (ref) follow = pinned(ref)
|
||||
}
|
||||
createEffect(
|
||||
on(
|
||||
() => bars().length,
|
||||
(len) => {
|
||||
if (len > prev && ref) {
|
||||
ref.scrollLeft = ref.scrollWidth
|
||||
if (len > prev && ref && follow && frame === undefined) {
|
||||
frame = requestAnimationFrame(() => {
|
||||
frame = undefined
|
||||
if (!ref || !follow) return
|
||||
ref.scrollLeft = ref.scrollWidth
|
||||
})
|
||||
}
|
||||
prev = len
|
||||
},
|
||||
),
|
||||
)
|
||||
onCleanup(() => {
|
||||
if (frame !== undefined) cancelAnimationFrame(frame)
|
||||
})
|
||||
|
||||
const hideTip = () => {
|
||||
tipBar = undefined
|
||||
@@ -161,6 +176,7 @@ export const TaskTimeline: Component = () => {
|
||||
onPointerUp={onPointerUp}
|
||||
onPointerCancel={onPointerUp}
|
||||
onPointerLeave={hideTip}
|
||||
onScroll={onScroll}
|
||||
>
|
||||
<Index each={bars()}>
|
||||
{(bar) => {
|
||||
|
||||
@@ -20,6 +20,17 @@ export interface BarSize {
|
||||
content: number
|
||||
}
|
||||
|
||||
export interface TimelineScroll {
|
||||
scrollLeft: number
|
||||
scrollWidth: number
|
||||
clientWidth: number
|
||||
}
|
||||
|
||||
/** Keep following updates when the viewport is within one bar of the right edge. */
|
||||
export function pinned(scroll: TimelineScroll, slack = BAR_W): boolean {
|
||||
return scroll.scrollWidth - scroll.clientWidth - scroll.scrollLeft <= slack
|
||||
}
|
||||
|
||||
// ── Content length ───────────────────────────────────────────────────
|
||||
|
||||
function content(part: Part): number {
|
||||
|
||||
Reference in New Issue
Block a user