mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(ui): archived sessions leave sidebar after navigation (#122876)
* oc-ad0.1: fix archived child session retention * oc-37c: evict archived child on navigation
This commit is contained in:
@@ -110,7 +110,7 @@ export function preserveActiveSessionLineageRows(
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
preserved[parent[0]] = parent[1];
|
||||
preserved[parent[0]] = parent[1].filter((row) => areUiSessionKeysEquivalent(row.key, childKey));
|
||||
childKey = parent[0];
|
||||
}
|
||||
return preserved;
|
||||
@@ -205,6 +205,14 @@ export function evictArchivedSessionLineage(
|
||||
row != null && areUiSessionKeysEquivalent(row.key, sessionKey),
|
||||
);
|
||||
if (selectedRow?.archived === true) {
|
||||
// Navigation has ended the archived row's temporary presentation lease.
|
||||
// Remove it from the child cache before the next canonical list refresh.
|
||||
owner.childSessionRowsByParent = Object.fromEntries(
|
||||
Object.entries(owner.childSessionRowsByParent).map(([parentKey, rows]) => [
|
||||
parentKey,
|
||||
rows.filter((row) => !areUiSessionKeysEquivalent(row.key, sessionKey)),
|
||||
]),
|
||||
);
|
||||
owner.context?.sessions.reconcile(selectedRow, owner.sessionsResult?.defaults, {
|
||||
archivedFilter: "active",
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
controlUiSessionUrl,
|
||||
createSessionManagementE2eSuite,
|
||||
installMockGateway,
|
||||
navigateToControlUiSession,
|
||||
requireRecord,
|
||||
sessionRow,
|
||||
sessionsListResponse,
|
||||
@@ -564,13 +563,27 @@ suite.define(() => {
|
||||
const page = await context.newPage();
|
||||
const baseTime = Date.parse("2026-07-01T16:00:00.000Z");
|
||||
const main = sessionRow("agent:main:main", "Main", baseTime);
|
||||
const target = {
|
||||
...sessionRow(
|
||||
"agent:main:dashboard:navigation-target",
|
||||
"Navigation target",
|
||||
baseTime - 1_000,
|
||||
),
|
||||
parentSessionKey: main.key,
|
||||
sessionId: "navigation-target",
|
||||
};
|
||||
const archived = {
|
||||
...sessionRow("agent:main:navigation-archive", "Navigation archive", baseTime - 1_000),
|
||||
...sessionRow(
|
||||
"agent:main:dashboard:navigation-archive",
|
||||
"Navigation archive",
|
||||
baseTime - 2_000,
|
||||
),
|
||||
parentSessionKey: main.key,
|
||||
sessionId: "navigation-archive",
|
||||
};
|
||||
const gateway = await installMockGateway(page, {
|
||||
methodResponses: {
|
||||
"sessions.list": sessionsListResponse([main, archived]),
|
||||
"sessions.list": sessionsListResponse([main, target, archived]),
|
||||
"sessions.patch": {},
|
||||
},
|
||||
sessionKey: main.key,
|
||||
@@ -599,35 +612,36 @@ suite.define(() => {
|
||||
.locator(".agent-chat__disabled-banner");
|
||||
await archivedNotice.waitFor({ state: "visible", timeout: 10_000 });
|
||||
|
||||
await navigateToControlUiSession(page, main.key);
|
||||
await expect.poll(() => new URL(page.url()).pathname).toBe(controlUiSessionPath(main.key));
|
||||
await rowFor(target.key).click();
|
||||
await expect.poll(() => new URL(page.url()).pathname).toBe(controlUiSessionPath(target.key));
|
||||
await archivedRow.waitFor({ state: "detached", timeout: 10_000 });
|
||||
|
||||
await gateway.setMethodResponse("sessions.list", sessionsListResponse([main]));
|
||||
await gateway.setMethodResponse("sessions.list", sessionsListResponse([main, target]));
|
||||
let listRequestCount = (await gateway.getRequests("sessions.list")).length;
|
||||
await gateway.emitGatewayEvent("sessions.changed", {
|
||||
...main,
|
||||
...target,
|
||||
updatedAt: baseTime + 1_000,
|
||||
reason: "update",
|
||||
sessionKey: main.key,
|
||||
sessionKey: target.key,
|
||||
});
|
||||
await expect
|
||||
.poll(async () => (await gateway.getRequests("sessions.list")).length)
|
||||
.toBeGreaterThan(listRequestCount);
|
||||
await archivedRow.waitFor({ state: "detached", timeout: 10_000 });
|
||||
|
||||
await gateway.setMethodResponse(
|
||||
"sessions.list",
|
||||
sessionsListResponse([
|
||||
{ ...main, updatedAt: baseTime + 2_000 },
|
||||
{ ...target, updatedAt: baseTime + 3_000 },
|
||||
{ ...archived, archived: false, updatedAt: baseTime + 3_000 },
|
||||
]),
|
||||
);
|
||||
listRequestCount = (await gateway.getRequests("sessions.list")).length;
|
||||
await gateway.emitGatewayEvent("sessions.changed", {
|
||||
...main,
|
||||
...target,
|
||||
updatedAt: baseTime + 2_000,
|
||||
reason: "update",
|
||||
sessionKey: main.key,
|
||||
sessionKey: target.key,
|
||||
});
|
||||
await expect
|
||||
.poll(async () => (await gateway.getRequests("sessions.list")).length)
|
||||
|
||||
@@ -7,20 +7,13 @@ import {
|
||||
controlUiSessionPath,
|
||||
controlUiSessionUrl,
|
||||
installMockGateway,
|
||||
navigateToControlUiSession,
|
||||
waitForConfirmModal,
|
||||
type MockGatewayControls,
|
||||
type MockGatewayRequest,
|
||||
} from "../test-helpers/control-ui-e2e.ts";
|
||||
import { createControlUiE2eSuite } from "./control-ui-e2e-suite.test-support.ts";
|
||||
|
||||
export {
|
||||
controlUiSessionPath,
|
||||
controlUiSessionUrl,
|
||||
installMockGateway,
|
||||
navigateToControlUiSession,
|
||||
waitForConfirmModal,
|
||||
};
|
||||
export { controlUiSessionPath, controlUiSessionUrl, installMockGateway, waitForConfirmModal };
|
||||
|
||||
export const collapsedSessionSectionsStorageKey = "openclaw:sidebar:sessions:collapsed-sections";
|
||||
export const captureUiProofEnabled = process.env.OPENCLAW_CAPTURE_UI_PROOF === "1";
|
||||
|
||||
Reference in New Issue
Block a user