fix(web): drop a pre-#2001 selectedToolName on OAuth resume
A resume snapshot written before this change carries `selectedToolName` where `ToolsUiState` now expects `selectedToolKey`. The blind cast in `restoreTabUiFromSnapshot` carried it through as a stray field that would be re-serialized on the next redirect. Route the Tools entry through a `normalizeToolsUi` that drops it explicitly instead. The name is deliberately not migrated to a row key: a snapshot lives for one redirect (so this only arises when the app is upgraded mid-flight), and the tools list is fetched after reconnect, long after restore — there is nothing to resolve the name against. The selection is lost; search, form values, and the run-as-task toggle restore intact. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
ab40fb621a
commit
63b37e05ec
2 changed files with 52 additions and 3 deletions
|
|
@ -123,6 +123,40 @@ describe("oauthResume", () => {
|
||||||
expect(setToolsUi).toHaveBeenCalledWith(toolsUi);
|
expect(setToolsUi).toHaveBeenCalledWith(toolsUi);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("drops a pre-#2001 selectedToolName from a legacy snapshot, keeping the rest", () => {
|
||||||
|
// A redirect begun on a build that keyed tool selection by name, restored
|
||||||
|
// on one that keys it by row identity (the app upgraded mid-redirect).
|
||||||
|
// The name can't be mapped to a row key here — the tools list is fetched
|
||||||
|
// after reconnect — so the selection is dropped, not carried through as a
|
||||||
|
// stray field, and everything else survives.
|
||||||
|
const setToolsUi = vi.fn();
|
||||||
|
restoreTabUiFromSnapshot(
|
||||||
|
{
|
||||||
|
Tools: {
|
||||||
|
formValues: { city: "NYC" },
|
||||||
|
search: "get",
|
||||||
|
runAsTask: false,
|
||||||
|
selectedToolName: "get_temp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
setToolsUi,
|
||||||
|
setPromptsUi: vi.fn(),
|
||||||
|
setResourcesUi: vi.fn(),
|
||||||
|
setAppsUi: vi.fn(),
|
||||||
|
setTasksUi: vi.fn(),
|
||||||
|
setLogsUi: vi.fn(),
|
||||||
|
setProtocolUi: vi.fn(),
|
||||||
|
setNetworkUi: vi.fn(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(setToolsUi).toHaveBeenCalledWith({
|
||||||
|
formValues: { city: "NYC" },
|
||||||
|
search: "get",
|
||||||
|
runAsTask: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("falls back to legacy pending server key", () => {
|
it("falls back to legacy pending server key", () => {
|
||||||
storage.set(OAUTH_PENDING_SERVER_KEY, "legacy-srv");
|
storage.set(OAUTH_PENDING_SERVER_KEY, "legacy-srv");
|
||||||
const snapshot = readOAuthResumeSnapshot();
|
const snapshot = readOAuthResumeSnapshot();
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,23 @@ export function buildTabUiSnapshot(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A snapshot written before #2001 carries `selectedToolName` (a tool's name)
|
||||||
|
* where {@link ToolsUiState} now expects `selectedToolKey` (its `index:name`
|
||||||
|
* row identity). A snapshot only lives for the length of one OAuth redirect,
|
||||||
|
* so this matters exactly when the app is upgraded mid-redirect — and the name
|
||||||
|
* cannot be mapped to a row key here, since the tools list is fetched after
|
||||||
|
* reconnect, long after restore. So the stale selection is dropped rather than
|
||||||
|
* carried as a stray field that would be re-serialized on the next redirect;
|
||||||
|
* the rest of the tab state (search text, form values) is restored intact and
|
||||||
|
* the screen opens on its "select a tool" placeholder.
|
||||||
|
*/
|
||||||
|
function normalizeToolsUi(value: unknown): ToolsUiState {
|
||||||
|
const ui = { ...((value as ToolsUiState | undefined) ?? EMPTY_TOOLS_UI) };
|
||||||
|
delete (ui as ToolsUiState & { selectedToolName?: string }).selectedToolName;
|
||||||
|
return ui;
|
||||||
|
}
|
||||||
|
|
||||||
export function restoreTabUiFromSnapshot(
|
export function restoreTabUiFromSnapshot(
|
||||||
tabUi: Partial<Record<InspectorTabId, unknown>> | undefined,
|
tabUi: Partial<Record<InspectorTabId, unknown>> | undefined,
|
||||||
setters: TabUiSetters,
|
setters: TabUiSetters,
|
||||||
|
|
@ -110,9 +127,7 @@ export function restoreTabUiFromSnapshot(
|
||||||
const value = tabUi[tabId];
|
const value = tabUi[tabId];
|
||||||
switch (tabId) {
|
switch (tabId) {
|
||||||
case "Tools":
|
case "Tools":
|
||||||
setters.setToolsUi(
|
setters.setToolsUi(normalizeToolsUi(value));
|
||||||
(value as ToolsUiState | undefined) ?? EMPTY_TOOLS_UI,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case "Prompts":
|
case "Prompts":
|
||||||
setters.setPromptsUi(
|
setters.setPromptsUi(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue