fix(app): prevent pane flicker across worktrees
This commit is contained in:
parent
b751e26565
commit
368f2c8433
6 changed files with 118 additions and 68 deletions
|
|
@ -4,6 +4,7 @@ import { mockOpenCodeServer } from "../utils/mock-server"
|
||||||
import { expectAppVisible, expectSessionTitle } from "../utils/waits"
|
import { expectAppVisible, expectSessionTitle } from "../utils/waits"
|
||||||
|
|
||||||
const directory = "C:/OpenCode/ReviewTabSwitch"
|
const directory = "C:/OpenCode/ReviewTabSwitch"
|
||||||
|
const otherDirectory = "C:/OpenCode/ReviewTabSwitchOther"
|
||||||
const projectID = "proj_review_tab_switch"
|
const projectID = "proj_review_tab_switch"
|
||||||
const sessionA = "ses_review_tab_a"
|
const sessionA = "ses_review_tab_a"
|
||||||
const sessionB = "ses_review_tab_b"
|
const sessionB = "ses_review_tab_b"
|
||||||
|
|
@ -58,6 +59,23 @@ test("keeps the v2 review pane mounted when switching session tabs in a workspac
|
||||||
await expect(page.getByRole("button", { name: "generated-2739.ts" })).toBeVisible()
|
await expect(page.getByRole("button", { name: "generated-2739.ts" })).toBeVisible()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("keeps the v2 review pane mounted when switching session tabs across worktrees", async ({ page }) => {
|
||||||
|
await setup(page, otherDirectory)
|
||||||
|
|
||||||
|
await page.goto(sessionHref(sessionA))
|
||||||
|
await expectSessionTitle(page, titleA)
|
||||||
|
|
||||||
|
await page.getByRole("button", { name: "Toggle review" }).click()
|
||||||
|
const review = page.locator('#review-panel [data-component="session-review-v2"]')
|
||||||
|
await expectAppVisible(review)
|
||||||
|
await writeProbe(page)
|
||||||
|
|
||||||
|
await switchTab(page, titleB)
|
||||||
|
await expectSessionTitle(page, titleB)
|
||||||
|
await expectAppVisible(review)
|
||||||
|
expect(await readProbe(page)).toBe(PROBE)
|
||||||
|
})
|
||||||
|
|
||||||
type Probed = HTMLElement & { __e2eProbe?: string }
|
type Probed = HTMLElement & { __e2eProbe?: string }
|
||||||
|
|
||||||
async function switchTab(page: Page, title: string) {
|
async function switchTab(page: Page, title: string) {
|
||||||
|
|
@ -74,7 +92,7 @@ async function readProbe(page: Page) {
|
||||||
return page.locator('#review-panel [data-component="session-review-v2"]').evaluate((el) => (el as Probed).__e2eProbe)
|
return page.locator('#review-panel [data-component="session-review-v2"]').evaluate((el) => (el as Probed).__e2eProbe)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setup(page: Page) {
|
async function setup(page: Page, destinationDirectory = directory) {
|
||||||
await mockOpenCodeServer(page, {
|
await mockOpenCodeServer(page, {
|
||||||
directory,
|
directory,
|
||||||
project: {
|
project: {
|
||||||
|
|
@ -96,19 +114,22 @@ async function setup(page: Page) {
|
||||||
connected: ["opencode"],
|
connected: ["opencode"],
|
||||||
default: { providerID: "opencode", modelID: "test" },
|
default: { providerID: "opencode", modelID: "test" },
|
||||||
},
|
},
|
||||||
sessions: [session(sessionA, titleA, 1700000000000), session(sessionB, titleB, 1700000001000)],
|
sessions: [
|
||||||
|
session(sessionA, titleA, 1700000000000, directory),
|
||||||
|
session(sessionB, titleB, 1700000001000, destinationDirectory),
|
||||||
|
],
|
||||||
vcsDiff: diffs,
|
vcsDiff: diffs,
|
||||||
pageMessages: () => ({ items: [] }),
|
pageMessages: () => ({ items: [] }),
|
||||||
})
|
})
|
||||||
|
|
||||||
await page.addInitScript(
|
await page.addInitScript(
|
||||||
({ directory, server, sessions }) => {
|
({ directories, server, sessions }) => {
|
||||||
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"opencode.global.dat:server",
|
"opencode.global.dat:server",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
projects: { local: [{ worktree: directory, expanded: true }] },
|
projects: { local: directories.map((worktree: string) => ({ worktree, expanded: true })) },
|
||||||
lastProject: { local: directory },
|
lastProject: { local: directories[0] },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
|
|
@ -116,16 +137,16 @@ async function setup(page: Page) {
|
||||||
JSON.stringify(sessions.map((sessionId: string) => ({ type: "session", server, sessionId }))),
|
JSON.stringify(sessions.map((sessionId: string) => ({ type: "session", server, sessionId }))),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{ directory, server, sessions: [sessionA, sessionB] },
|
{ directories: [...new Set([directory, destinationDirectory])], server, sessions: [sessionA, sessionB] },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function session(id: string, title: string, created: number) {
|
function session(id: string, title: string, created: number, worktree: string) {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
slug: id,
|
slug: id,
|
||||||
projectID,
|
projectID,
|
||||||
directory,
|
directory: worktree,
|
||||||
title,
|
title,
|
||||||
version: "dev",
|
version: "dev",
|
||||||
time: { created, updated: created },
|
time: { created, updated: created },
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { mockOpenCodeServer } from "../utils/mock-server"
|
||||||
import { expectSessionTitle } from "../utils/waits"
|
import { expectSessionTitle } from "../utils/waits"
|
||||||
|
|
||||||
const directory = "C:/OpenCode/TerminalTabSwitch"
|
const directory = "C:/OpenCode/TerminalTabSwitch"
|
||||||
|
const otherDirectory = "C:/OpenCode/TerminalTabSwitchOther"
|
||||||
const projectID = "proj_terminal_tab_switch"
|
const projectID = "proj_terminal_tab_switch"
|
||||||
const sessionA = "ses_terminal_tab_a"
|
const sessionA = "ses_terminal_tab_a"
|
||||||
const sessionB = "ses_terminal_tab_b"
|
const sessionB = "ses_terminal_tab_b"
|
||||||
|
|
@ -44,6 +45,29 @@ test("keeps the terminal session alive when switching session tabs in a workspac
|
||||||
expect(connections.length).toBe(1)
|
expect(connections.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("keeps the terminal pane mounted when switching session tabs across worktrees", async ({ page }) => {
|
||||||
|
await setup(page, otherDirectory)
|
||||||
|
|
||||||
|
await page.goto(sessionHref(sessionB))
|
||||||
|
await expectSessionTitle(page, titleB)
|
||||||
|
await page.keyboard.press("Control+Backquote")
|
||||||
|
await expect(page.locator("#terminal-panel")).toBeVisible()
|
||||||
|
|
||||||
|
await switchTab(page, titleA)
|
||||||
|
await expectSessionTitle(page, titleA)
|
||||||
|
await page.keyboard.press("Control+Backquote")
|
||||||
|
|
||||||
|
const panel = page.locator("#terminal-panel")
|
||||||
|
await expect(panel).toBeVisible()
|
||||||
|
await panel.evaluate((el, probe) => {
|
||||||
|
;(el as Probed).__e2eProbe = probe
|
||||||
|
}, PROBE)
|
||||||
|
|
||||||
|
await switchTab(page, titleB)
|
||||||
|
await expectSessionTitle(page, titleB)
|
||||||
|
expect(await panel.evaluate((el) => (el as Probed).__e2eProbe)).toBe(PROBE)
|
||||||
|
})
|
||||||
|
|
||||||
type Probed = HTMLElement & { __e2eProbe?: string }
|
type Probed = HTMLElement & { __e2eProbe?: string }
|
||||||
|
|
||||||
async function switchTab(page: Page, title: string) {
|
async function switchTab(page: Page, title: string) {
|
||||||
|
|
@ -60,7 +84,7 @@ async function readProbe(page: Page) {
|
||||||
return page.locator('[data-component="terminal"]').evaluate((el) => (el as Probed).__e2eProbe)
|
return page.locator('[data-component="terminal"]').evaluate((el) => (el as Probed).__e2eProbe)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setup(page: Page) {
|
async function setup(page: Page, destinationDirectory = directory) {
|
||||||
await mockOpenCodeServer(page, {
|
await mockOpenCodeServer(page, {
|
||||||
directory,
|
directory,
|
||||||
project: {
|
project: {
|
||||||
|
|
@ -82,7 +106,10 @@ async function setup(page: Page) {
|
||||||
connected: ["opencode"],
|
connected: ["opencode"],
|
||||||
default: { providerID: "opencode", modelID: "test" },
|
default: { providerID: "opencode", modelID: "test" },
|
||||||
},
|
},
|
||||||
sessions: [session(sessionA, titleA, 1700000000000), session(sessionB, titleB, 1700000001000)],
|
sessions: [
|
||||||
|
session(sessionA, titleA, 1700000000000, directory),
|
||||||
|
session(sessionB, titleB, 1700000001000, destinationDirectory),
|
||||||
|
],
|
||||||
pageMessages: () => ({ items: [] }),
|
pageMessages: () => ({ items: [] }),
|
||||||
})
|
})
|
||||||
await page.route("**/pty", (route) =>
|
await page.route("**/pty", (route) =>
|
||||||
|
|
@ -109,13 +136,13 @@ async function setup(page: Page) {
|
||||||
})
|
})
|
||||||
|
|
||||||
await page.addInitScript(
|
await page.addInitScript(
|
||||||
({ directory, server, sessions }) => {
|
({ directories, server, sessions }) => {
|
||||||
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } }))
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
"opencode.global.dat:server",
|
"opencode.global.dat:server",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
projects: { local: [{ worktree: directory, expanded: true }] },
|
projects: { local: directories.map((worktree: string) => ({ worktree, expanded: true })) },
|
||||||
lastProject: { local: directory },
|
lastProject: { local: directories[0] },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
|
|
@ -123,17 +150,17 @@ async function setup(page: Page) {
|
||||||
JSON.stringify(sessions.map((sessionId: string) => ({ type: "session", server, sessionId }))),
|
JSON.stringify(sessions.map((sessionId: string) => ({ type: "session", server, sessionId }))),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{ directory, server, sessions: [sessionA, sessionB] },
|
{ directories: [...new Set([directory, destinationDirectory])], server, sessions: [sessionA, sessionB] },
|
||||||
)
|
)
|
||||||
return connections
|
return connections
|
||||||
}
|
}
|
||||||
|
|
||||||
function session(id: string, title: string, created: number) {
|
function session(id: string, title: string, created: number, worktree: string) {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
slug: id,
|
slug: id,
|
||||||
projectID,
|
projectID,
|
||||||
directory,
|
directory: worktree,
|
||||||
title,
|
title,
|
||||||
version: "dev",
|
version: "dev",
|
||||||
time: { created, updated: created },
|
time: { created, updated: created },
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||||
import { base64Encode } from "@opencode-ai/core/util/encode"
|
import { base64Encode } from "@opencode-ai/core/util/encode"
|
||||||
import { useParams } from "@solidjs/router"
|
import { useParams } from "@solidjs/router"
|
||||||
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
import { batch, createEffect, createMemo, createRoot, onCleanup, startTransition } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { useModels } from "@/context/models"
|
import { useModels } from "@/context/models"
|
||||||
import { useSettings } from "@/context/settings"
|
import { useSettings } from "@/context/settings"
|
||||||
|
|
@ -26,6 +26,13 @@ type Saved = {
|
||||||
session: Record<string, State | undefined>
|
session: Record<string, State | undefined>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SavedEntry = {
|
||||||
|
saved: Saved
|
||||||
|
setSaved: ReturnType<typeof createStore<Saved>>[1]
|
||||||
|
ready: ReturnType<typeof persisted<Saved>>[3]
|
||||||
|
dispose: VoidFunction
|
||||||
|
}
|
||||||
|
|
||||||
const WORKSPACE_KEY = "__workspace__"
|
const WORKSPACE_KEY = "__workspace__"
|
||||||
const handoff = new Map<string, State>()
|
const handoff = new Map<string, State>()
|
||||||
|
|
||||||
|
|
@ -71,15 +78,29 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
const agentsVisible = createMemo(() => settings.visibility.customAgents() || hasCustomAgent(list()))
|
const agentsVisible = createMemo(() => settings.visibility.customAgents() || hasCustomAgent(list()))
|
||||||
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
||||||
|
|
||||||
const [saved, setSaved, , savedReady] = persisted(
|
const savedCache = new Map<string, SavedEntry>()
|
||||||
{
|
const loadSaved = (serverScope: ServerScope, directory: string) => {
|
||||||
...Persist.serverWorkspace(serverSDK().scope, sdk().directory, "model-selection", ["model-selection.v1"]),
|
const key = ScopedKey.from(serverScope, directory, "model-selection")
|
||||||
migrate,
|
const existing = savedCache.get(key)
|
||||||
},
|
if (existing) return existing
|
||||||
createStore<Saved>({
|
const entry = createRoot((dispose) => {
|
||||||
session: {},
|
const [saved, setSaved, , ready] = persisted(
|
||||||
}),
|
{
|
||||||
)
|
...Persist.serverWorkspace(serverScope, directory, "model-selection", ["model-selection.v1"]),
|
||||||
|
migrate,
|
||||||
|
},
|
||||||
|
createStore<Saved>({ session: {} }),
|
||||||
|
)
|
||||||
|
return { saved, setSaved, ready, dispose }
|
||||||
|
})
|
||||||
|
savedCache.set(key, entry)
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
const saved = createMemo(() => loadSaved(serverSDK().scope, sdk().directory))
|
||||||
|
onCleanup(() => {
|
||||||
|
for (const entry of savedCache.values()) entry.dispose()
|
||||||
|
savedCache.clear()
|
||||||
|
})
|
||||||
|
|
||||||
const [store, setStore] = createStore<{
|
const [store, setStore] = createStore<{
|
||||||
current?: string
|
current?: string
|
||||||
|
|
@ -127,7 +148,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
const scope = createMemo<State | undefined>(() => {
|
const scope = createMemo<State | undefined>(() => {
|
||||||
const session = id()
|
const session = id()
|
||||||
if (!session) return store.draft ?? store.promoting
|
if (!session) return store.draft ?? store.promoting
|
||||||
return saved.session[session] ?? handoff.get(handoffKey(serverSDK().scope, sdk().directory, session))
|
return saved().saved.session[session] ?? handoff.get(handoffKey(serverSDK().scope, sdk().directory, session))
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -137,13 +158,13 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
const key = handoffKey(serverSDK().scope, sdk().directory, session)
|
const key = handoffKey(serverSDK().scope, sdk().directory, session)
|
||||||
const next = handoff.get(key)
|
const next = handoff.get(key)
|
||||||
if (!next) return
|
if (!next) return
|
||||||
if (saved.session[session] !== undefined) {
|
if (saved().saved.session[session] !== undefined) {
|
||||||
handoff.delete(key)
|
handoff.delete(key)
|
||||||
setStore("promoting", undefined)
|
setStore("promoting", undefined)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setSaved("session", session, clone(next))
|
saved().setSaved("session", session, clone(next))
|
||||||
handoff.delete(key)
|
handoff.delete(key)
|
||||||
setStore("promoting", undefined)
|
setStore("promoting", undefined)
|
||||||
})
|
})
|
||||||
|
|
@ -209,7 +230,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
} satisfies State
|
} satisfies State
|
||||||
const session = id()
|
const session = id()
|
||||||
if (session) {
|
if (session) {
|
||||||
setSaved("session", session, next)
|
saved().setSaved("session", session, next)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setStore("draft", next)
|
setStore("draft", next)
|
||||||
|
|
@ -270,7 +291,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
|
|
||||||
const session = id()
|
const session = id()
|
||||||
if (session) {
|
if (session) {
|
||||||
setSaved("session", session, state)
|
saved().setSaved("session", session, state)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setStore("draft", state)
|
setStore("draft", state)
|
||||||
|
|
@ -378,7 +399,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
model,
|
model,
|
||||||
agent,
|
agent,
|
||||||
session: {
|
session: {
|
||||||
ready: savedReady,
|
ready: () => saved().ready(),
|
||||||
reset() {
|
reset() {
|
||||||
setStore({ draft: undefined, promoting: undefined })
|
setStore({ draft: undefined, promoting: undefined })
|
||||||
},
|
},
|
||||||
|
|
@ -389,7 +410,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
handoff.set(key, next)
|
handoff.set(key, next)
|
||||||
|
|
||||||
if (dir === sdk().directory) {
|
if (dir === sdk().directory) {
|
||||||
setSaved("session", session, next)
|
saved().setSaved("session", session, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
setStore("promoting", next)
|
setStore("promoting", next)
|
||||||
|
|
@ -399,10 +420,10 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
const session = id()
|
const session = id()
|
||||||
if (!session) return
|
if (!session) return
|
||||||
if (msg.sessionID !== session) return
|
if (msg.sessionID !== session) return
|
||||||
if (saved.session[session] !== undefined) return
|
if (saved().saved.session[session] !== undefined) return
|
||||||
if (handoff.has(handoffKey(serverSDK().scope, sdk().directory, session))) return
|
if (handoff.has(handoffKey(serverSDK().scope, sdk().directory, session))) return
|
||||||
|
|
||||||
setSaved("session", session, {
|
saved().setSaved("session", session, {
|
||||||
agent: msg.agent,
|
agent: msg.agent,
|
||||||
model: msg.model,
|
model: msg.model,
|
||||||
variant: msg.model?.variant ?? null,
|
variant: msg.model?.variant ?? null,
|
||||||
|
|
|
||||||
|
|
@ -58,18 +58,14 @@ export function DirectoryDataProvider(
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={directory()} keyed>
|
<DataProvider
|
||||||
{(directory) => (
|
data={sync().data}
|
||||||
<DataProvider
|
directory={directory}
|
||||||
data={sync().data}
|
onNavigateToSession={(sessionID: string) => navigate(href(sessionID))}
|
||||||
directory={directory}
|
onSessionHref={href}
|
||||||
onNavigateToSession={(sessionID: string) => navigate(href(sessionID))}
|
>
|
||||||
onSessionHref={href}
|
<LocalProvider>{props.children}</LocalProvider>
|
||||||
>
|
</DataProvider>
|
||||||
<LocalProvider>{props.children}</LocalProvider>
|
|
||||||
</DataProvider>
|
|
||||||
)}
|
|
||||||
</Show>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ function ResolvedTargetSessionRoute() {
|
||||||
() => params.id,
|
() => params.id,
|
||||||
() => sync().session.lineage,
|
() => sync().session.lineage,
|
||||||
)
|
)
|
||||||
const directory = createMemo(() => current()?.session.directory)
|
const directory = createMemo<string | undefined>((previous) => current()?.session.directory ?? previous)
|
||||||
const targetDirectory = () => directory()!
|
const targetDirectory = () => directory()!
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -264,33 +264,17 @@ function ResolvedTargetSessionRoute() {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// Non-keyed: closes only while the target's directory is unknown (uncached
|
// Keep the previous workspace mounted while an uncached target resolves.
|
||||||
// lineage mid-resolution), which tears down the workspace subtree including
|
|
||||||
// the terminal. Same-workspace tab switches keep it open because warm
|
|
||||||
// targets resolve synchronously from the sync cache.
|
|
||||||
<Show when={directory()}>
|
<Show when={directory()}>
|
||||||
<SDKProvider directory={targetDirectory}>
|
<SDKProvider directory={targetDirectory}>
|
||||||
<DirectoryDataProvider directory={targetDirectory} server={serverKey}>
|
<DirectoryDataProvider directory={targetDirectory} server={serverKey}>
|
||||||
<TargetSessionPage />
|
<SessionPage />
|
||||||
</DirectoryDataProvider>
|
</DirectoryDataProvider>
|
||||||
</SDKProvider>
|
</SDKProvider>
|
||||||
</Show>
|
</Show>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Owns the workspace-identity remount. Must not include the session ID in the
|
|
||||||
// key: SessionPage handles session changes reactively, and remounting here
|
|
||||||
// destroys workspace-scoped state (terminal PTYs, file/prompt providers).
|
|
||||||
function TargetSessionPage() {
|
|
||||||
const sdk = useSDK()
|
|
||||||
const serverSDK = useServerSDK()
|
|
||||||
return (
|
|
||||||
<Show when={`${serverSDK().scope}\0${sdk().directory}`} keyed>
|
|
||||||
<SessionPage />
|
|
||||||
</Show>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function TargetServerScopedProviders(
|
function TargetServerScopedProviders(
|
||||||
props: ParentProps<{ directory?: () => string | undefined; sessionID?: () => string | undefined }>,
|
props: ParentProps<{ directory?: () => string | undefined; sessionID?: () => string | undefined }>,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import type { Message, Session, Part, SnapshotFileDiff, SessionStatus, Provider } from "@opencode-ai/sdk/v2"
|
import type { Message, Session, Part, SnapshotFileDiff, SessionStatus, Provider } from "@opencode-ai/sdk/v2"
|
||||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||||
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
||||||
|
import type { Accessor } from "solid-js"
|
||||||
|
|
||||||
export type NormalizedProviderListResponse = {
|
export type NormalizedProviderListResponse = {
|
||||||
all: Map<string, Provider>
|
all: Map<string, Provider>
|
||||||
|
|
@ -45,7 +46,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||||
name: "Data",
|
name: "Data",
|
||||||
init: (props: {
|
init: (props: {
|
||||||
data: Data
|
data: Data
|
||||||
directory: string
|
directory: string | Accessor<string>
|
||||||
onNavigateToSession?: NavigateToSessionFn
|
onNavigateToSession?: NavigateToSessionFn
|
||||||
onSessionHref?: SessionHrefFn
|
onSessionHref?: SessionHrefFn
|
||||||
}) => {
|
}) => {
|
||||||
|
|
@ -54,7 +55,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
||||||
return props.data
|
return props.data
|
||||||
},
|
},
|
||||||
get directory() {
|
get directory() {
|
||||||
return props.directory
|
return typeof props.directory === "function" ? props.directory() : props.directory
|
||||||
},
|
},
|
||||||
navigateToSession: props.onNavigateToSession,
|
navigateToSession: props.onNavigateToSession,
|
||||||
sessionHref: props.onSessionHref,
|
sessionHref: props.onSessionHref,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue