mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
Control UI: guard deferred bootstrap connect after disconnect
This commit is contained in:
@@ -41,6 +41,7 @@ function createHost() {
|
||||
return {
|
||||
basePath: "",
|
||||
client: null,
|
||||
connectGeneration: 0,
|
||||
connected: false,
|
||||
tab: "chat",
|
||||
assistantName: "OpenClaw",
|
||||
@@ -79,4 +80,24 @@ describe("handleConnected", () => {
|
||||
await Promise.resolve();
|
||||
expect(connectGatewayMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("skips deferred connect when disconnected before bootstrap resolves", async () => {
|
||||
let resolveBootstrap!: () => void;
|
||||
loadBootstrapMock.mockReturnValueOnce(
|
||||
new Promise<void>((resolve) => {
|
||||
resolveBootstrap = resolve;
|
||||
}),
|
||||
);
|
||||
connectGatewayMock.mockReset();
|
||||
const host = createHost();
|
||||
|
||||
handleConnected(host as never);
|
||||
expect(connectGatewayMock).not.toHaveBeenCalled();
|
||||
|
||||
host.connectGeneration += 1;
|
||||
resolveBootstrap();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(connectGatewayMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ function createHost() {
|
||||
return {
|
||||
basePath: "",
|
||||
client: { stop: vi.fn() },
|
||||
connectGeneration: 0,
|
||||
connected: true,
|
||||
tab: "chat",
|
||||
assistantName: "OpenClaw",
|
||||
@@ -35,6 +36,7 @@ describe("handleDisconnected", () => {
|
||||
handleDisconnected(host as unknown as Parameters<typeof handleDisconnected>[0]);
|
||||
|
||||
expect(removeSpy).toHaveBeenCalledWith("popstate", host.popStateHandler);
|
||||
expect(host.connectGeneration).toBe(1);
|
||||
expect(host.client).toBeNull();
|
||||
expect(host.connected).toBe(false);
|
||||
expect(disconnectSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -22,6 +22,7 @@ import type { Tab } from "./navigation.ts";
|
||||
type LifecycleHost = {
|
||||
basePath: string;
|
||||
client?: { stop: () => void } | null;
|
||||
connectGeneration: number;
|
||||
connected?: boolean;
|
||||
tab: Tab;
|
||||
assistantName: string;
|
||||
@@ -42,6 +43,7 @@ type LifecycleHost = {
|
||||
};
|
||||
|
||||
export function handleConnected(host: LifecycleHost) {
|
||||
const connectGeneration = ++host.connectGeneration;
|
||||
host.basePath = inferBasePath();
|
||||
const bootstrapReady = loadControlUiBootstrapConfig(host);
|
||||
applySettingsFromUrl(host as unknown as Parameters<typeof applySettingsFromUrl>[0]);
|
||||
@@ -49,9 +51,12 @@ export function handleConnected(host: LifecycleHost) {
|
||||
syncThemeWithSettings(host as unknown as Parameters<typeof syncThemeWithSettings>[0]);
|
||||
attachThemeListener(host as unknown as Parameters<typeof attachThemeListener>[0]);
|
||||
window.addEventListener("popstate", host.popStateHandler);
|
||||
void bootstrapReady.finally(() =>
|
||||
connectGateway(host as unknown as Parameters<typeof connectGateway>[0]),
|
||||
);
|
||||
void bootstrapReady.finally(() => {
|
||||
if (host.connectGeneration !== connectGeneration) {
|
||||
return;
|
||||
}
|
||||
connectGateway(host as unknown as Parameters<typeof connectGateway>[0]);
|
||||
});
|
||||
startNodesPolling(host as unknown as Parameters<typeof startNodesPolling>[0]);
|
||||
if (host.tab === "logs") {
|
||||
startLogsPolling(host as unknown as Parameters<typeof startLogsPolling>[0]);
|
||||
@@ -66,6 +71,7 @@ export function handleFirstUpdated(host: LifecycleHost) {
|
||||
}
|
||||
|
||||
export function handleDisconnected(host: LifecycleHost) {
|
||||
host.connectGeneration += 1;
|
||||
window.removeEventListener("popstate", host.popStateHandler);
|
||||
stopNodesPolling(host as unknown as Parameters<typeof stopNodesPolling>[0]);
|
||||
stopLogsPolling(host as unknown as Parameters<typeof stopLogsPolling>[0]);
|
||||
|
||||
@@ -111,6 +111,7 @@ function resolveOnboardingMode(): boolean {
|
||||
export class OpenClawApp extends LitElement {
|
||||
private i18nController = new I18nController(this);
|
||||
clientInstanceId = generateUUID();
|
||||
connectGeneration = 0;
|
||||
@state() settings: UiSettings = loadSettings();
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
Reference in New Issue
Block a user