mirror of
https://github.com/iamlukethedev/Claw3D.git
synced 2026-08-14 00:58:04 +00:00
fix ongoing findings issue
This commit is contained in:
@@ -5,6 +5,7 @@ import type {
|
||||
StudioFocusedPreference,
|
||||
StudioGatewaySettings,
|
||||
StudioGatewaySettingsPublic,
|
||||
StudioGatewaySettingsPatch,
|
||||
StudioOfficePreferencePatch,
|
||||
StudioSettingsPublic,
|
||||
StudioSettingsPatch,
|
||||
@@ -267,13 +268,83 @@ const mergeOfficeFloorsPatch = (
|
||||
return { ...current, ...next };
|
||||
};
|
||||
|
||||
const mergeGatewayProfilesPatch = (
|
||||
current: StudioGatewaySettingsPatch["profiles"],
|
||||
next: StudioGatewaySettingsPatch["profiles"],
|
||||
): StudioGatewaySettingsPatch["profiles"] => {
|
||||
if (next === undefined) return current;
|
||||
if (next === null) return null;
|
||||
if (!current || current === null) return { ...next };
|
||||
const merged: NonNullable<StudioGatewaySettingsPatch["profiles"]> = {
|
||||
...current,
|
||||
};
|
||||
for (const [adapterType, profilePatch] of Object.entries(next)) {
|
||||
if (profilePatch === null) {
|
||||
merged[adapterType as keyof typeof merged] = null;
|
||||
continue;
|
||||
}
|
||||
const existing = merged[adapterType as keyof typeof merged];
|
||||
merged[adapterType as keyof typeof merged] =
|
||||
existing && existing !== null
|
||||
? { ...existing, ...profilePatch }
|
||||
: { ...profilePatch };
|
||||
}
|
||||
return merged;
|
||||
};
|
||||
|
||||
const mergeGatewayConnectionPatch = (
|
||||
current: StudioGatewaySettingsPatch["lastKnownGood"],
|
||||
next: StudioGatewaySettingsPatch["lastKnownGood"],
|
||||
): StudioGatewaySettingsPatch["lastKnownGood"] => {
|
||||
if (next === undefined) return current;
|
||||
if (next === null) return null;
|
||||
if (!current || current === null) return { ...next };
|
||||
return { ...current, ...next };
|
||||
};
|
||||
|
||||
const mergeGatewayPatch = (
|
||||
current: StudioSettingsPatch["gateway"],
|
||||
next: StudioSettingsPatch["gateway"],
|
||||
): StudioSettingsPatch["gateway"] => {
|
||||
if (next === undefined) return current;
|
||||
if (next === null) return null;
|
||||
if (!current || current === null) {
|
||||
return {
|
||||
...next,
|
||||
...(next.profiles !== undefined
|
||||
? { profiles: mergeGatewayProfilesPatch(undefined, next.profiles) }
|
||||
: {}),
|
||||
...(next.lastKnownGood !== undefined
|
||||
? {
|
||||
lastKnownGood: mergeGatewayConnectionPatch(
|
||||
undefined,
|
||||
next.lastKnownGood,
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
const profiles = mergeGatewayProfilesPatch(current.profiles, next.profiles);
|
||||
const lastKnownGood = mergeGatewayConnectionPatch(
|
||||
current.lastKnownGood,
|
||||
next.lastKnownGood,
|
||||
);
|
||||
return {
|
||||
...current,
|
||||
...next,
|
||||
...(profiles !== undefined ? { profiles } : {}),
|
||||
...(lastKnownGood !== undefined ? { lastKnownGood } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
const mergeStudioPatch = (
|
||||
current: StudioSettingsPatch | null,
|
||||
next: StudioSettingsPatch
|
||||
): StudioSettingsPatch => {
|
||||
if (!current) {
|
||||
return {
|
||||
...(next.gateway !== undefined ? { gateway: next.gateway } : {}),
|
||||
...(next.gateway !== undefined ? { gateway: mergeGatewayPatch(undefined, next.gateway) } : {}),
|
||||
...(next.activeFloorId !== undefined ? { activeFloorId: next.activeFloorId } : {}),
|
||||
...(next.focused ? { focused: { ...next.focused } } : {}),
|
||||
...(next.avatars ? { avatars: { ...next.avatars } } : {}),
|
||||
@@ -297,11 +368,12 @@ const mergeStudioPatch = (
|
||||
const standup = mergeStandupPatch(current.standup, next.standup);
|
||||
const taskBoard = mergeTaskBoardPatch(current.taskBoard, next.taskBoard);
|
||||
const officeFloors = mergeOfficeFloorsPatch(current.officeFloors, next.officeFloors);
|
||||
const gateway = mergeGatewayPatch(current.gateway, next.gateway);
|
||||
return {
|
||||
...(next.gateway !== undefined
|
||||
? { gateway: next.gateway }
|
||||
: current.gateway !== undefined
|
||||
? { gateway: current.gateway }
|
||||
? { gateway }
|
||||
: gateway !== undefined
|
||||
? { gateway }
|
||||
: {}),
|
||||
...(next.activeFloorId !== undefined
|
||||
? { activeFloorId: next.activeFloorId }
|
||||
|
||||
@@ -50,6 +50,117 @@ describe("StudioSettingsCoordinator", () => {
|
||||
coordinator.dispose();
|
||||
});
|
||||
|
||||
it("merges queued gateway patches field-by-field before flushing", async () => {
|
||||
const fetchSettings = vi.fn(async () => createResponse());
|
||||
const updateSettings = vi.fn(async () => createResponse());
|
||||
const coordinator = new StudioSettingsCoordinator({ fetchSettings, updateSettings }, 300);
|
||||
|
||||
coordinator.schedulePatch(
|
||||
{
|
||||
gateway: {
|
||||
lastKnownGood: {
|
||||
url: "ws://localhost:18789",
|
||||
token: undefined,
|
||||
adapterType: "openclaw",
|
||||
},
|
||||
},
|
||||
},
|
||||
300,
|
||||
);
|
||||
coordinator.schedulePatch(
|
||||
{
|
||||
gateway: {
|
||||
url: "http://localhost:7770",
|
||||
adapterType: "local",
|
||||
profiles: {
|
||||
local: {
|
||||
url: "http://localhost:7770",
|
||||
token: undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
300,
|
||||
);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(300);
|
||||
|
||||
expect(updateSettings).toHaveBeenCalledTimes(1);
|
||||
expect(updateSettings).toHaveBeenCalledWith({
|
||||
gateway: {
|
||||
url: "http://localhost:7770",
|
||||
adapterType: "local",
|
||||
profiles: {
|
||||
local: {
|
||||
url: "http://localhost:7770",
|
||||
token: undefined,
|
||||
},
|
||||
},
|
||||
lastKnownGood: {
|
||||
url: "ws://localhost:18789",
|
||||
token: undefined,
|
||||
adapterType: "openclaw",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
coordinator.dispose();
|
||||
});
|
||||
|
||||
it("merges queued gateway profile and last-known-good subpatches", async () => {
|
||||
const fetchSettings = vi.fn(async () => createResponse());
|
||||
const updateSettings = vi.fn(async () => createResponse());
|
||||
const coordinator = new StudioSettingsCoordinator({ fetchSettings, updateSettings }, 300);
|
||||
|
||||
coordinator.schedulePatch({
|
||||
gateway: {
|
||||
profiles: {
|
||||
hermes: {
|
||||
url: "ws://localhost:18888",
|
||||
token: undefined,
|
||||
},
|
||||
},
|
||||
lastKnownGood: {
|
||||
url: "ws://localhost:18789",
|
||||
token: "stored-token",
|
||||
},
|
||||
},
|
||||
});
|
||||
coordinator.schedulePatch({
|
||||
gateway: {
|
||||
profiles: {
|
||||
hermes: {
|
||||
token: "new-token",
|
||||
},
|
||||
},
|
||||
lastKnownGood: {
|
||||
adapterType: "openclaw",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await vi.advanceTimersByTimeAsync(300);
|
||||
|
||||
expect(updateSettings).toHaveBeenCalledTimes(1);
|
||||
expect(updateSettings).toHaveBeenCalledWith({
|
||||
gateway: {
|
||||
profiles: {
|
||||
hermes: {
|
||||
url: "ws://localhost:18888",
|
||||
token: "new-token",
|
||||
},
|
||||
},
|
||||
lastKnownGood: {
|
||||
url: "ws://localhost:18789",
|
||||
token: "stored-token",
|
||||
adapterType: "openclaw",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
coordinator.dispose();
|
||||
});
|
||||
|
||||
it("flushPending persists queued patch immediately", async () => {
|
||||
const fetchSettings = vi.fn(async () => createResponse());
|
||||
const updateSettings = vi.fn(async () => createResponse());
|
||||
|
||||
Reference in New Issue
Block a user