fix(app): repair malformed persisted tabs (#39645)
This commit is contained in:
parent
c08350b83e
commit
ac5380614f
3 changed files with 48 additions and 7 deletions
23
packages/app/src/context/tab-migration.ts
Normal file
23
packages/app/src/context/tab-migration.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import type { ServerConnection } from "./server"
|
||||
import type { Tab } from "./tabs"
|
||||
|
||||
export function migrateTabs(value: unknown, fallback: ServerConnection.Key): Tab[] {
|
||||
if (!Array.isArray(value)) return []
|
||||
return value.flatMap<Tab>((tab) => {
|
||||
if (!tab || typeof tab !== "object") return []
|
||||
if ("server" in tab && typeof tab.server !== "string") return []
|
||||
const server = ("server" in tab ? tab.server : fallback) as ServerConnection.Key
|
||||
if (tab.type === "session" && typeof tab.sessionId === "string") {
|
||||
return [{ type: tab.type, server, sessionId: tab.sessionId }]
|
||||
}
|
||||
if (
|
||||
tab.type === "draft" &&
|
||||
typeof tab.draftID === "string" &&
|
||||
typeof tab.directory === "string" &&
|
||||
(tab.worktree === undefined || typeof tab.worktree === "string")
|
||||
) {
|
||||
return [{ type: tab.type, server, draftID: tab.draftID, directory: tab.directory, worktree: tab.worktree }]
|
||||
}
|
||||
return []
|
||||
})
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import { createRoot, getOwner, onCleanup } from "solid-js"
|
|||
import { createTabMemory } from "./tab-memory"
|
||||
import { nextTabAfterClose, pushClosedTab, removeClosedTabs, takeClosedTab, type ClosedTab } from "./closed-tabs"
|
||||
import type { SessionTab, Tab } from "./tabs"
|
||||
import { migrateTabs } from "./tab-migration"
|
||||
import type { ServerConnection } from "./server"
|
||||
|
||||
const server = "local\nhttp://localhost:4096" as ServerConnection.Key
|
||||
|
|
@ -11,6 +12,28 @@ function sessionTab(sessionId: string): SessionTab {
|
|||
return { type: "session", server, sessionId }
|
||||
}
|
||||
|
||||
describe("tab migration", () => {
|
||||
test("drops null and malformed persisted tabs", () => {
|
||||
expect(
|
||||
migrateTabs(
|
||||
[null, sessionTab("a"), { type: "session", server }, { type: "unknown", server }, "invalid"],
|
||||
server,
|
||||
),
|
||||
).toEqual([sessionTab("a")])
|
||||
})
|
||||
|
||||
test("adds the fallback server to valid legacy tabs", () => {
|
||||
expect(migrateTabs([{ type: "session", sessionId: "a", dirBase64: "legacy" }], server)).toEqual([
|
||||
sessionTab("a"),
|
||||
])
|
||||
})
|
||||
|
||||
test("replaces invalid top-level persisted data", () => {
|
||||
expect(migrateTabs(null, server)).toEqual([])
|
||||
expect(migrateTabs({}, server)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe("tab memory", () => {
|
||||
test("keeps state until its tab is removed", () => {
|
||||
createRoot((dispose) => {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { sessionHref } from "@/utils/session-route"
|
|||
import { createTabMemory } from "./tab-memory"
|
||||
import { nextTabAfterClose, pushClosedTab, removeClosedTabs, takeClosedTab, type ClosedTab } from "./closed-tabs"
|
||||
import { createDraftPromptSession, type PromptModel } from "./prompt-state"
|
||||
import { migrateTabs } from "./tab-migration"
|
||||
|
||||
export type SessionTab = {
|
||||
type: "session"
|
||||
|
|
@ -59,13 +60,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
|||
const [store, setStore, _, ready] = persisted(
|
||||
{
|
||||
...Persist.window("tabs"),
|
||||
migrate: (value: unknown) => {
|
||||
if (!Array.isArray(value)) return value
|
||||
return value.map((tab) => {
|
||||
if (!tab || typeof tab !== "object" || "server" in tab) return tab
|
||||
return { ...tab, server: fallback }
|
||||
})
|
||||
},
|
||||
migrate: (value: unknown) => migrateTabs(value, fallback),
|
||||
},
|
||||
createStore<Tab[]>([]),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue