mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
fix(ui): report connection loss instead of silently dropping session actions (#123771)
* fix(ui): report connection loss instead of silently dropping session actions patchSession returned 'stale' with no message when the gateway dropped before a queued dialog submit (rename and similar) — the dialog closed and the edit vanished with no visible outcome. loadCheckpoint had the sibling gap: expanding a row while disconnected left the drawer claiming 'No checkpoints' beside a nonzero checkpoint badge. Both now surface the existing actionRequiresConnection message at their owning error surface. * test: widen patchSession test-support patch type for label patches
This commit is contained in:
committed by
GitHub
parent
0bdf11c9dc
commit
877f2ec083
@@ -25,6 +25,7 @@ export type TestSessionsPage = HTMLElement & {
|
||||
sessionMenu: { key: string; x: number; y: number } | null;
|
||||
sessionMenuTrigger: HTMLElement | null;
|
||||
checkpointItemsByKey: Record<string, SessionCompactionCheckpoint[]>;
|
||||
checkpointErrorByKey: Record<string, string>;
|
||||
checkpointLoadingKey: string | null;
|
||||
checkpointBusyKey: string | null;
|
||||
sessionMutationPending: boolean;
|
||||
@@ -47,7 +48,7 @@ export type TestSessionsPage = HTMLElement & {
|
||||
) => void;
|
||||
patchSession: (
|
||||
key: string,
|
||||
patch: { archived?: boolean; pinned?: boolean },
|
||||
patch: { archived?: boolean; pinned?: boolean; label?: string | null },
|
||||
scope?: unknown,
|
||||
expectedSessionId?: string,
|
||||
) => Promise<unknown>;
|
||||
|
||||
@@ -281,6 +281,35 @@ describe("sessions page lifecycle", () => {
|
||||
expect(page.transcriptSearch).toEqual({ status: "idle" });
|
||||
});
|
||||
|
||||
it("reports a connection error instead of silently dropping a patch", async () => {
|
||||
const patch = vi.fn();
|
||||
const sessions = createSessions({ patch });
|
||||
const mutableGateway = createGateway({} as GatewayBrowserClient);
|
||||
const page = await createPage(createContext(mutableGateway.gateway, sessions));
|
||||
// Gateway drops while a rename dialog is open; submit lands afterwards.
|
||||
mutableGateway.emit({ phase: "reconnecting", client: null });
|
||||
|
||||
const result = await page.patchSession("agent:main:main", { label: "renamed" });
|
||||
|
||||
expect(result).toBe("failed");
|
||||
expect(patch).not.toHaveBeenCalled();
|
||||
expect(page.error).toBe("Connect to the Gateway to change sessions.");
|
||||
});
|
||||
|
||||
it("shows a connection error in the checkpoints drawer while disconnected", async () => {
|
||||
const mutableGateway = createGateway({} as GatewayBrowserClient);
|
||||
const page = await createPage(createContext(mutableGateway.gateway, createSessions()));
|
||||
mutableGateway.emit({ phase: "reconnecting", client: null });
|
||||
|
||||
await page.loadCheckpoint("agent:main:main");
|
||||
|
||||
// Without the recorded error the drawer would render "No checkpoints"
|
||||
// beside a nonzero checkpoint badge.
|
||||
expect(page.checkpointErrorByKey["agent:main:main"]).toBe(
|
||||
"Connect to the Gateway to change sessions.",
|
||||
);
|
||||
});
|
||||
|
||||
it("drops a transcript result after the query changes while it is pending", async () => {
|
||||
const response = deferred<SessionsSearchResult>();
|
||||
const request = vi.fn(() => response.promise);
|
||||
|
||||
@@ -1144,7 +1144,10 @@ class SessionsPage extends OpenClawLightDomElement {
|
||||
expectedSessionId?: string,
|
||||
): Promise<SessionsPageMutationResult> {
|
||||
if (!scope) {
|
||||
return "stale";
|
||||
// Nothing was attempted (e.g. rename dialog submitted after the gateway
|
||||
// dropped); say so instead of silently swallowing the edit.
|
||||
this.error = t("sessionsView.actionRequiresConnection");
|
||||
return "failed";
|
||||
}
|
||||
if (typeof patch.archived === "boolean" && !expectedSessionId?.trim()) {
|
||||
this.error = "Session lifecycle action requires a durable session identity.";
|
||||
@@ -1280,6 +1283,12 @@ class SessionsPage extends OpenClawLightDomElement {
|
||||
private async loadCheckpoint(sessionKey: string) {
|
||||
const scope = this.captureRequestScope();
|
||||
if (!scope) {
|
||||
// Rows stay expandable while disconnected; without an error the drawer
|
||||
// would claim "No checkpoints" beside a nonzero checkpoint badge.
|
||||
this.checkpointErrorByKey = {
|
||||
...this.checkpointErrorByKey,
|
||||
[sessionKey]: t("sessionsView.actionRequiresConnection"),
|
||||
};
|
||||
return;
|
||||
}
|
||||
this.checkpointTaskKey = sessionKey;
|
||||
|
||||
Reference in New Issue
Block a user