mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
refactor: unify restart gating and update availability sync
This commit is contained in:
@@ -17,13 +17,6 @@
|
||||
padding: 10px 16px;
|
||||
}
|
||||
|
||||
.update-banner code {
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.update-banner__btn {
|
||||
margin-left: 8px;
|
||||
border-color: var(--danger);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { GATEWAY_EVENT_UPDATE_AVAILABLE } from "../../../src/gateway/events.js";
|
||||
import { connectGateway } from "./app-gateway.ts";
|
||||
|
||||
type GatewayClientMock = {
|
||||
@@ -79,6 +80,7 @@ function createHost() {
|
||||
refreshSessionsAfterChat: new Set<string>(),
|
||||
execApprovalQueue: [],
|
||||
execApprovalError: null,
|
||||
updateAvailable: null,
|
||||
} as unknown as Parameters<typeof connectGateway>[0];
|
||||
}
|
||||
|
||||
@@ -126,6 +128,38 @@ describe("connectGateway", () => {
|
||||
expect(host.eventLogBuffer[0]?.event).toBe("presence");
|
||||
});
|
||||
|
||||
it("applies update.available only from active client", () => {
|
||||
const host = createHost();
|
||||
|
||||
connectGateway(host);
|
||||
const firstClient = gatewayClientInstances[0];
|
||||
expect(firstClient).toBeDefined();
|
||||
|
||||
connectGateway(host);
|
||||
const secondClient = gatewayClientInstances[1];
|
||||
expect(secondClient).toBeDefined();
|
||||
|
||||
firstClient.emitEvent({
|
||||
event: GATEWAY_EVENT_UPDATE_AVAILABLE,
|
||||
payload: {
|
||||
updateAvailable: { currentVersion: "1.0.0", latestVersion: "9.9.9", channel: "latest" },
|
||||
},
|
||||
});
|
||||
expect(host.updateAvailable).toBeNull();
|
||||
|
||||
secondClient.emitEvent({
|
||||
event: GATEWAY_EVENT_UPDATE_AVAILABLE,
|
||||
payload: {
|
||||
updateAvailable: { currentVersion: "1.0.0", latestVersion: "2.0.0", channel: "latest" },
|
||||
},
|
||||
});
|
||||
expect(host.updateAvailable).toEqual({
|
||||
currentVersion: "1.0.0",
|
||||
latestVersion: "2.0.0",
|
||||
channel: "latest",
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores stale client onClose callbacks after reconnect", () => {
|
||||
const host = createHost();
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
GATEWAY_EVENT_UPDATE_AVAILABLE,
|
||||
type GatewayUpdateAvailableEventPayload,
|
||||
} from "../../../src/gateway/events.js";
|
||||
import { CHAT_SESSIONS_ACTIVE_MINUTES, flushChatQueueForEvent } from "./app-chat.ts";
|
||||
import type { EventLogEntry } from "./app-events.ts";
|
||||
import {
|
||||
@@ -26,7 +30,13 @@ import type { GatewayEventFrame, GatewayHelloOk } from "./gateway.ts";
|
||||
import { GatewayBrowserClient } from "./gateway.ts";
|
||||
import type { Tab } from "./navigation.ts";
|
||||
import type { UiSettings } from "./storage.ts";
|
||||
import type { AgentsListResult, PresenceEntry, HealthSnapshot, StatusSummary } from "./types.ts";
|
||||
import type {
|
||||
AgentsListResult,
|
||||
PresenceEntry,
|
||||
HealthSnapshot,
|
||||
StatusSummary,
|
||||
UpdateAvailable,
|
||||
} from "./types.ts";
|
||||
|
||||
type GatewayHost = {
|
||||
settings: UiSettings;
|
||||
@@ -54,7 +64,7 @@ type GatewayHost = {
|
||||
refreshSessionsAfterChat: Set<string>;
|
||||
execApprovalQueue: ExecApprovalRequest[];
|
||||
execApprovalError: string | null;
|
||||
updateAvailable: { currentVersion: string; latestVersion: string; channel: string } | null;
|
||||
updateAvailable: UpdateAvailable | null;
|
||||
};
|
||||
|
||||
type SessionDefaultsSnapshot = {
|
||||
@@ -270,6 +280,12 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) {
|
||||
if (resolved) {
|
||||
host.execApprovalQueue = removeExecApproval(host.execApprovalQueue, resolved.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.event === GATEWAY_EVENT_UPDATE_AVAILABLE) {
|
||||
const payload = evt.payload as GatewayUpdateAvailableEventPayload | undefined;
|
||||
host.updateAvailable = payload?.updateAvailable ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +295,7 @@ export function applySnapshot(host: GatewayHost, hello: GatewayHelloOk) {
|
||||
presence?: PresenceEntry[];
|
||||
health?: HealthSnapshot;
|
||||
sessionDefaults?: SessionDefaultsSnapshot;
|
||||
updateAvailable?: { currentVersion: string; latestVersion: string; channel: string };
|
||||
updateAvailable?: UpdateAvailable;
|
||||
}
|
||||
| undefined;
|
||||
if (snapshot?.presence && Array.isArray(snapshot.presence)) {
|
||||
|
||||
@@ -221,7 +221,7 @@ export type AppViewState = {
|
||||
logsLimit: number;
|
||||
logsMaxBytes: number;
|
||||
logsAtBottom: boolean;
|
||||
updateAvailable: { currentVersion: string; latestVersion: string; channel: string } | null;
|
||||
updateAvailable: import("./types.js").UpdateAvailable | null;
|
||||
client: GatewayBrowserClient | null;
|
||||
refreshSessionsAfterChat: Set<string>;
|
||||
connect: () => void;
|
||||
|
||||
@@ -300,11 +300,7 @@ export class OpenClawApp extends LitElement {
|
||||
@state() cronRuns: CronRunLogEntry[] = [];
|
||||
@state() cronBusy = false;
|
||||
|
||||
@state() updateAvailable: {
|
||||
currentVersion: string;
|
||||
latestVersion: string;
|
||||
channel: string;
|
||||
} | null = null;
|
||||
@state() updateAvailable: import("./types.js").UpdateAvailable | null = null;
|
||||
|
||||
@state() skillsLoading = false;
|
||||
@state() skillsReport: SkillStatusReport | null = null;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export type UpdateAvailable = import("../../../src/infra/update-startup.js").UpdateAvailable;
|
||||
|
||||
export type ChannelsStatusSnapshot = {
|
||||
ts: number;
|
||||
channelOrder: string[];
|
||||
|
||||
Reference in New Issue
Block a user