mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 03:45:46 -06:00
fix(ui): prevent dashboard chat messages from overlapping (#123713)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -31,10 +31,12 @@ suite.define(() => {
|
||||
|
||||
await page.goto(`${suite.server.baseUrl}skills`);
|
||||
await gateway.waitForRequest("skills.status");
|
||||
await expect
|
||||
.poll(() => gateway.getRequests("skills.status"))
|
||||
.toEqual([expect.objectContaining({ params: { agentId: "main" } })]);
|
||||
await page.getByText("No skills found.").waitFor();
|
||||
const requests = await gateway.getRequests("skills.status");
|
||||
expect(requests.length).toBeGreaterThan(0);
|
||||
expect(requests.map((request) => request.params)).toEqual(
|
||||
requests.map(() => ({ agentId: "main" })),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -51,6 +51,27 @@ describe("chat transcript controller", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("measures newly inserted rows after Lit connects them", async () => {
|
||||
// Lit invokes ref callbacks while a new row is still detached. Browsers
|
||||
// report a zero offsetHeight there, which must not become the row's
|
||||
// durable virtual size before the following user bubble is positioned.
|
||||
transcriptDomState.detachedRowHeight = 0;
|
||||
const transcript = createTestTranscript();
|
||||
const container = document.body.appendChild(document.createElement("div"));
|
||||
const props = threadProps("pane-commentary-insert", "agent:main:session-a", [
|
||||
{ role: "assistant", content: "commentary", timestamp: 1_000 },
|
||||
{ role: "user", content: "next turn", timestamp: 2_000 },
|
||||
]);
|
||||
|
||||
render(renderChatThread(props, transcript), container);
|
||||
transcript.hostConnected();
|
||||
transcript.hostUpdated();
|
||||
await flushDeferredRowPrune();
|
||||
render(renderChatThread(props, transcript), container);
|
||||
|
||||
expect(transcriptRows(container)[1]?.style.transform).toBe("translateY(100px)");
|
||||
});
|
||||
|
||||
it("pauses an unmeasurable restore until loading commits an empty transcript", () => {
|
||||
const transcript = createTestTranscript();
|
||||
const container = document.body.appendChild(document.createElement("div"));
|
||||
|
||||
@@ -132,7 +132,22 @@ class ChatSessionVirtualizerHost implements ReactiveControllerHost, ChatTranscri
|
||||
if (!callback) {
|
||||
callback = (element?: Element) => {
|
||||
if (element instanceof HTMLElement) {
|
||||
this.virtualizerController.getVirtualizer().measureElement(element);
|
||||
if (element.isConnected) {
|
||||
this.virtualizerController.getVirtualizer().measureElement(element);
|
||||
} else {
|
||||
// Lit invokes refs before the row is connected. Measuring a new
|
||||
// key there records offsetHeight=0, so a following row can share
|
||||
// its transform and paint over it until ResizeObserver catches up.
|
||||
queueMicrotask(() => {
|
||||
if (
|
||||
element.isConnected &&
|
||||
element.dataset.virtualRowKey === key &&
|
||||
this.rowIndexesByKey.has(key)
|
||||
) {
|
||||
this.virtualizerController.getVirtualizer().measureElement(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Re-stamps (e.g. the chat<->dashboard face switch) re-invoke each
|
||||
|
||||
@@ -4,7 +4,7 @@ import { resetThreadPresentation } from "./chat-thread-interactions.ts";
|
||||
|
||||
export const observedElements = new Set<Element>();
|
||||
export const resizeObservers = new Set<RecordingResizeObserver>();
|
||||
export const transcriptDomState = { measuredRowHeight: 100 };
|
||||
export const transcriptDomState = { measuredRowHeight: 100, detachedRowHeight: 100 };
|
||||
|
||||
class RecordingResizeObserver implements ResizeObserver {
|
||||
private readonly targets = new Set<Element>();
|
||||
@@ -95,9 +95,14 @@ export function installTranscriptDomMocks(): void {
|
||||
observedElements.clear();
|
||||
resizeObservers.clear();
|
||||
transcriptDomState.measuredRowHeight = 100;
|
||||
transcriptDomState.detachedRowHeight = 100;
|
||||
vi.stubGlobal("ResizeObserver", RecordingResizeObserver);
|
||||
vi.spyOn(HTMLElement.prototype, "offsetHeight", "get").mockImplementation(
|
||||
() => transcriptDomState.measuredRowHeight,
|
||||
function (this: HTMLElement) {
|
||||
return this.isConnected
|
||||
? transcriptDomState.measuredRowHeight
|
||||
: transcriptDomState.detachedRowHeight;
|
||||
},
|
||||
);
|
||||
vi.spyOn(Element.prototype, "getBoundingClientRect").mockReturnValue({
|
||||
x: 0,
|
||||
|
||||
Reference in New Issue
Block a user