chore: cleanup (#14113)
This commit is contained in:
@@ -1,26 +1,20 @@
|
||||
import { For, onCleanup, Show, Match, Switch, createMemo, createEffect, on } from "solid-js"
|
||||
import { createMediaQuery } from "@solid-primitives/media"
|
||||
import { createResizeObserver } from "@solid-primitives/resize-observer"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
import { useLocal } from "@/context/local"
|
||||
import { selectionFromLines, useFile, type FileSelection, type SelectedLineRange } from "@/context/file"
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
||||
import { Dialog } from "@opencode-ai/ui/dialog"
|
||||
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
||||
import { Tabs } from "@opencode-ai/ui/tabs"
|
||||
import { Select } from "@opencode-ai/ui/select"
|
||||
import { useCodeComponent } from "@opencode-ai/ui/context/code"
|
||||
import { createAutoScroll } from "@opencode-ai/ui/hooks"
|
||||
import { Mark } from "@opencode-ai/ui/logo"
|
||||
|
||||
import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, closestCenter } from "@thisbeyond/solid-dnd"
|
||||
import type { DragEvent } from "@thisbeyond/solid-dnd"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { useTerminal, type LocalPTY } from "@/context/terminal"
|
||||
import { useTerminal } from "@/context/terminal"
|
||||
import { useLayout } from "@/context/layout"
|
||||
import { checksum, base64Encode } from "@opencode-ai/util/encode"
|
||||
import { findLast } from "@opencode-ai/util/array"
|
||||
@@ -34,16 +28,14 @@ import { UserMessage } from "@opencode-ai/sdk/v2"
|
||||
import { useSDK } from "@/context/sdk"
|
||||
import { usePrompt } from "@/context/prompt"
|
||||
import { useComments } from "@/context/comments"
|
||||
import { ConstrainDragYAxis, getDraggableId } from "@/utils/solid-dnd"
|
||||
import { usePermission } from "@/context/permission"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { SessionHeader, SessionContextTab, SortableTab, FileVisual, NewSessionView } from "@/components/session"
|
||||
import { SessionHeader, NewSessionView } from "@/components/session"
|
||||
import { navMark, navParams } from "@/utils/perf"
|
||||
import { same } from "@/utils/same"
|
||||
import { createOpenReviewFile, focusTerminalById, getTabReorderIndex } from "@/pages/session/helpers"
|
||||
import { createOpenReviewFile } from "@/pages/session/helpers"
|
||||
import { createScrollSpy } from "@/pages/session/scroll-spy"
|
||||
import { createFileTabListSync } from "@/pages/session/file-tab-scroll"
|
||||
import { FileTabContent } from "@/pages/session/file-tabs"
|
||||
import {
|
||||
SessionReviewTab,
|
||||
StickyAddButton,
|
||||
@@ -51,7 +43,6 @@ import {
|
||||
type SessionReviewTabProps,
|
||||
} from "@/pages/session/review-tab"
|
||||
import { TerminalPanel } from "@/pages/session/terminal-panel"
|
||||
import { terminalTabLabel } from "@/pages/session/terminal-label"
|
||||
import { MessageTimeline } from "@/pages/session/message-timeline"
|
||||
import { useSessionCommands } from "@/pages/session/use-session-commands"
|
||||
import { SessionPromptDock } from "@/pages/session/session-prompt-dock"
|
||||
@@ -59,42 +50,13 @@ import { SessionMobileTabs } from "@/pages/session/session-mobile-tabs"
|
||||
import { SessionSidePanel } from "@/pages/session/session-side-panel"
|
||||
import { useSessionHashScroll } from "@/pages/session/use-session-hash-scroll"
|
||||
|
||||
type HandoffSession = {
|
||||
prompt: string
|
||||
files: Record<string, SelectedLineRange | null>
|
||||
}
|
||||
|
||||
const HANDOFF_MAX = 40
|
||||
|
||||
const handoff = {
|
||||
session: new Map<string, HandoffSession>(),
|
||||
terminal: new Map<string, string[]>(),
|
||||
}
|
||||
|
||||
const touch = <K, V>(map: Map<K, V>, key: K, value: V) => {
|
||||
map.delete(key)
|
||||
map.set(key, value)
|
||||
while (map.size > HANDOFF_MAX) {
|
||||
const first = map.keys().next().value
|
||||
if (first === undefined) return
|
||||
map.delete(first)
|
||||
}
|
||||
}
|
||||
|
||||
const setSessionHandoff = (key: string, patch: Partial<HandoffSession>) => {
|
||||
const prev = handoff.session.get(key) ?? { prompt: "", files: {} }
|
||||
touch(handoff.session, key, { ...prev, ...patch })
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
const layout = useLayout()
|
||||
const local = useLocal()
|
||||
const file = useFile()
|
||||
const sync = useSync()
|
||||
const globalSync = useGlobalSync()
|
||||
const terminal = useTerminal()
|
||||
const dialog = useDialog()
|
||||
const codeComponent = useCodeComponent()
|
||||
const command = useCommand()
|
||||
const language = useLanguage()
|
||||
const params = useParams()
|
||||
@@ -104,53 +66,21 @@ export default function Page() {
|
||||
const comments = useComments()
|
||||
const permission = usePermission()
|
||||
|
||||
const permRequest = createMemo(() => {
|
||||
const sessionID = params.id
|
||||
if (!sessionID) return
|
||||
return sync.data.permission[sessionID]?.[0]
|
||||
})
|
||||
|
||||
const questionRequest = createMemo(() => {
|
||||
const sessionID = params.id
|
||||
if (!sessionID) return
|
||||
return sync.data.question[sessionID]?.[0]
|
||||
})
|
||||
|
||||
const blocked = createMemo(() => !!permRequest() || !!questionRequest())
|
||||
|
||||
const [ui, setUi] = createStore({
|
||||
responding: false,
|
||||
pendingMessage: undefined as string | undefined,
|
||||
scrollGesture: 0,
|
||||
autoCreated: false,
|
||||
scroll: {
|
||||
overflow: false,
|
||||
bottom: true,
|
||||
},
|
||||
})
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => permRequest()?.id,
|
||||
() => setUi("responding", false),
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
const blocked = createMemo(() => {
|
||||
const sessionID = params.id
|
||||
if (!sessionID) return false
|
||||
return !!sync.data.permission[sessionID]?.[0] || !!sync.data.question[sessionID]?.[0]
|
||||
})
|
||||
|
||||
const decide = (response: "once" | "always" | "reject") => {
|
||||
const perm = permRequest()
|
||||
if (!perm) return
|
||||
if (ui.responding) return
|
||||
|
||||
setUi("responding", true)
|
||||
sdk.client.permission
|
||||
.respond({ sessionID: perm.sessionID, permissionID: perm.id, response })
|
||||
.catch((err: unknown) => {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
showToast({ title: language.t("common.requestFailed"), description: message })
|
||||
})
|
||||
.finally(() => setUi("responding", false))
|
||||
}
|
||||
const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
|
||||
const workspaceKey = createMemo(() => params.dir ?? "")
|
||||
const workspaceTabs = createMemo(() => layout.tabs(workspaceKey))
|
||||
@@ -323,206 +253,6 @@ export default function Page() {
|
||||
return sync.session.history.loading(id)
|
||||
})
|
||||
|
||||
const [title, setTitle] = createStore({
|
||||
draft: "",
|
||||
editing: false,
|
||||
saving: false,
|
||||
menuOpen: false,
|
||||
pendingRename: false,
|
||||
})
|
||||
let titleRef: HTMLInputElement | undefined
|
||||
|
||||
const errorMessage = (err: unknown) => {
|
||||
if (err && typeof err === "object" && "data" in err) {
|
||||
const data = (err as { data?: { message?: string } }).data
|
||||
if (data?.message) return data.message
|
||||
}
|
||||
if (err instanceof Error) return err.message
|
||||
return language.t("common.requestFailed")
|
||||
}
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
sessionKey,
|
||||
() => setTitle({ draft: "", editing: false, saving: false, menuOpen: false, pendingRename: false }),
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
const openTitleEditor = () => {
|
||||
if (!params.id) return
|
||||
setTitle({ editing: true, draft: info()?.title ?? "" })
|
||||
requestAnimationFrame(() => {
|
||||
titleRef?.focus()
|
||||
titleRef?.select()
|
||||
})
|
||||
}
|
||||
|
||||
const closeTitleEditor = () => {
|
||||
if (title.saving) return
|
||||
setTitle({ editing: false, saving: false })
|
||||
}
|
||||
|
||||
const saveTitleEditor = async () => {
|
||||
const sessionID = params.id
|
||||
if (!sessionID) return
|
||||
if (title.saving) return
|
||||
|
||||
const next = title.draft.trim()
|
||||
if (!next || next === (info()?.title ?? "")) {
|
||||
setTitle({ editing: false, saving: false })
|
||||
return
|
||||
}
|
||||
|
||||
setTitle("saving", true)
|
||||
await sdk.client.session
|
||||
.update({ sessionID, title: next })
|
||||
.then(() => {
|
||||
sync.set(
|
||||
produce((draft) => {
|
||||
const index = draft.session.findIndex((s) => s.id === sessionID)
|
||||
if (index !== -1) draft.session[index].title = next
|
||||
}),
|
||||
)
|
||||
setTitle({ editing: false, saving: false })
|
||||
})
|
||||
.catch((err) => {
|
||||
setTitle("saving", false)
|
||||
showToast({
|
||||
title: language.t("common.requestFailed"),
|
||||
description: errorMessage(err),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const navigateAfterSessionRemoval = (sessionID: string, parentID?: string, nextSessionID?: string) => {
|
||||
if (params.id !== sessionID) return
|
||||
if (parentID) {
|
||||
navigate(`/${params.dir}/session/${parentID}`)
|
||||
return
|
||||
}
|
||||
if (nextSessionID) {
|
||||
navigate(`/${params.dir}/session/${nextSessionID}`)
|
||||
return
|
||||
}
|
||||
navigate(`/${params.dir}/session`)
|
||||
}
|
||||
|
||||
async function archiveSession(sessionID: string) {
|
||||
const session = sync.session.get(sessionID)
|
||||
if (!session) return
|
||||
|
||||
const sessions = sync.data.session ?? []
|
||||
const index = sessions.findIndex((s) => s.id === sessionID)
|
||||
const nextSession = index === -1 ? undefined : (sessions[index + 1] ?? sessions[index - 1])
|
||||
|
||||
await sdk.client.session
|
||||
.update({ sessionID, time: { archived: Date.now() } })
|
||||
.then(() => {
|
||||
sync.set(
|
||||
produce((draft) => {
|
||||
const index = draft.session.findIndex((s) => s.id === sessionID)
|
||||
if (index !== -1) draft.session.splice(index, 1)
|
||||
}),
|
||||
)
|
||||
navigateAfterSessionRemoval(sessionID, session.parentID, nextSession?.id)
|
||||
})
|
||||
.catch((err) => {
|
||||
showToast({
|
||||
title: language.t("common.requestFailed"),
|
||||
description: errorMessage(err),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function deleteSession(sessionID: string) {
|
||||
const session = sync.session.get(sessionID)
|
||||
if (!session) return false
|
||||
|
||||
const sessions = (sync.data.session ?? []).filter((s) => !s.parentID && !s.time?.archived)
|
||||
const index = sessions.findIndex((s) => s.id === sessionID)
|
||||
const nextSession = index === -1 ? undefined : (sessions[index + 1] ?? sessions[index - 1])
|
||||
|
||||
const result = await sdk.client.session
|
||||
.delete({ sessionID })
|
||||
.then((x) => x.data)
|
||||
.catch((err) => {
|
||||
showToast({
|
||||
title: language.t("session.delete.failed.title"),
|
||||
description: errorMessage(err),
|
||||
})
|
||||
return false
|
||||
})
|
||||
|
||||
if (!result) return false
|
||||
|
||||
sync.set(
|
||||
produce((draft) => {
|
||||
const removed = new Set<string>([sessionID])
|
||||
|
||||
const byParent = new Map<string, string[]>()
|
||||
for (const item of draft.session) {
|
||||
const parentID = item.parentID
|
||||
if (!parentID) continue
|
||||
const existing = byParent.get(parentID)
|
||||
if (existing) {
|
||||
existing.push(item.id)
|
||||
continue
|
||||
}
|
||||
byParent.set(parentID, [item.id])
|
||||
}
|
||||
|
||||
const stack = [sessionID]
|
||||
while (stack.length) {
|
||||
const parentID = stack.pop()
|
||||
if (!parentID) continue
|
||||
|
||||
const children = byParent.get(parentID)
|
||||
if (!children) continue
|
||||
|
||||
for (const child of children) {
|
||||
if (removed.has(child)) continue
|
||||
removed.add(child)
|
||||
stack.push(child)
|
||||
}
|
||||
}
|
||||
|
||||
draft.session = draft.session.filter((s) => !removed.has(s.id))
|
||||
}),
|
||||
)
|
||||
|
||||
navigateAfterSessionRemoval(sessionID, session.parentID, nextSession?.id)
|
||||
return true
|
||||
}
|
||||
|
||||
function DialogDeleteSession(props: { sessionID: string }) {
|
||||
const title = createMemo(() => sync.session.get(props.sessionID)?.title ?? language.t("command.session.new"))
|
||||
const handleDelete = async () => {
|
||||
await deleteSession(props.sessionID)
|
||||
dialog.close()
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog title={language.t("session.delete.title")} fit>
|
||||
<div class="flex flex-col gap-4 pl-6 pr-2.5 pb-3">
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-14-regular text-text-strong">
|
||||
{language.t("session.delete.confirm", { name: title() })}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button variant="ghost" size="large" onClick={() => dialog.close()}>
|
||||
{language.t("common.cancel")}
|
||||
</Button>
|
||||
<Button variant="primary" size="large" onClick={handleDelete}>
|
||||
{language.t("session.delete.button")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const emptyUserMessages: UserMessage[] = []
|
||||
const userMessages = createMemo(
|
||||
() => messages().filter((m) => m.role === "user") as UserMessage[],
|
||||
@@ -555,8 +285,6 @@ export default function Page() {
|
||||
)
|
||||
|
||||
const [store, setStore] = createStore({
|
||||
activeDraggable: undefined as string | undefined,
|
||||
activeTerminalDraggable: undefined as string | undefined,
|
||||
messageId: undefined as string | undefined,
|
||||
turnStart: 0,
|
||||
mobileTab: "session" as "session" | "changes",
|
||||
@@ -679,43 +407,6 @@ export default function Page() {
|
||||
void sync.session.todo(id)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!view().terminal.opened()) {
|
||||
setUi("autoCreated", false)
|
||||
return
|
||||
}
|
||||
if (!terminal.ready() || terminal.all().length !== 0 || ui.autoCreated) return
|
||||
terminal.new()
|
||||
setUi("autoCreated", true)
|
||||
})
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => terminal.all().length,
|
||||
(count, prevCount) => {
|
||||
if (prevCount !== undefined && prevCount > 0 && count === 0) {
|
||||
if (view().terminal.opened()) {
|
||||
view().terminal.toggle()
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => terminal.active(),
|
||||
(activeId) => {
|
||||
if (!activeId || !view().terminal.opened()) return
|
||||
// Immediately remove focus
|
||||
if (document.activeElement instanceof HTMLElement) {
|
||||
document.activeElement.blur()
|
||||
}
|
||||
focusTerminalById(activeId)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => visibleUserMessages().at(-1)?.id,
|
||||
@@ -729,11 +420,6 @@ export default function Page() {
|
||||
)
|
||||
|
||||
const status = createMemo(() => sync.data.session_status[params.id ?? ""] ?? idle)
|
||||
const todos = createMemo(() => {
|
||||
const id = params.id
|
||||
if (!id) return []
|
||||
return globalSync.data.session_todo[id] ?? []
|
||||
})
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
@@ -741,7 +427,6 @@ export default function Page() {
|
||||
() => {
|
||||
setStore("messageId", undefined)
|
||||
setStore("changes", "session")
|
||||
setUi("autoCreated", false)
|
||||
},
|
||||
{ defer: true },
|
||||
),
|
||||
@@ -827,53 +512,6 @@ export default function Page() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDragStart = (event: unknown) => {
|
||||
const id = getDraggableId(event)
|
||||
if (!id) return
|
||||
setStore("activeDraggable", id)
|
||||
}
|
||||
|
||||
const handleDragOver = (event: DragEvent) => {
|
||||
const { draggable, droppable } = event
|
||||
if (draggable && droppable) {
|
||||
const currentTabs = tabs().all()
|
||||
const toIndex = getTabReorderIndex(currentTabs, draggable.id.toString(), droppable.id.toString())
|
||||
if (toIndex === undefined) return
|
||||
tabs().move(draggable.id.toString(), toIndex)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDragEnd = () => {
|
||||
setStore("activeDraggable", undefined)
|
||||
}
|
||||
|
||||
const handleTerminalDragStart = (event: unknown) => {
|
||||
const id = getDraggableId(event)
|
||||
if (!id) return
|
||||
setStore("activeTerminalDraggable", id)
|
||||
}
|
||||
|
||||
const handleTerminalDragOver = (event: DragEvent) => {
|
||||
const { draggable, droppable } = event
|
||||
if (draggable && droppable) {
|
||||
const terminals = terminal.all()
|
||||
const fromIndex = terminals.findIndex((t: LocalPTY) => t.id === draggable.id.toString())
|
||||
const toIndex = terminals.findIndex((t: LocalPTY) => t.id === droppable.id.toString())
|
||||
if (fromIndex !== -1 && toIndex !== -1 && fromIndex !== toIndex) {
|
||||
terminal.move(draggable.id.toString(), toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleTerminalDragEnd = () => {
|
||||
setStore("activeTerminalDraggable", undefined)
|
||||
const activeId = terminal.active()
|
||||
if (!activeId) return
|
||||
setTimeout(() => {
|
||||
focusTerminalById(activeId)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
const contextOpen = createMemo(() => tabs().active() === "context" || tabs().all().includes("context"))
|
||||
const openedTabs = createMemo(() =>
|
||||
tabs()
|
||||
@@ -1485,58 +1123,6 @@ export default function Page() {
|
||||
document.addEventListener("keydown", handleKeyDown)
|
||||
})
|
||||
|
||||
const previewPrompt = () =>
|
||||
prompt
|
||||
.current()
|
||||
.map((part) => {
|
||||
if (part.type === "file") return `[file:${part.path}]`
|
||||
if (part.type === "agent") return `@${part.name}`
|
||||
if (part.type === "image") return `[image:${part.filename}]`
|
||||
return part.content
|
||||
})
|
||||
.join("")
|
||||
.trim()
|
||||
|
||||
createEffect(() => {
|
||||
if (!prompt.ready()) return
|
||||
setSessionHandoff(sessionKey(), { prompt: previewPrompt() })
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!terminal.ready()) return
|
||||
language.locale()
|
||||
|
||||
touch(
|
||||
handoff.terminal,
|
||||
params.dir!,
|
||||
terminal.all().map((pty) =>
|
||||
terminalTabLabel({
|
||||
title: pty.title,
|
||||
titleNumber: pty.titleNumber,
|
||||
t: language.t as (key: string, vars?: Record<string, string | number | boolean>) => string,
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!file.ready()) return
|
||||
setSessionHandoff(sessionKey(), {
|
||||
files: tabs()
|
||||
.all()
|
||||
.reduce<Record<string, SelectedLineRange | null>>((acc, tab) => {
|
||||
const path = file.pathFromTab(tab)
|
||||
if (!path) return acc
|
||||
const selected = file.selectedLines(path)
|
||||
acc[path] =
|
||||
selected && typeof selected === "object" && "start" in selected && "end" in selected
|
||||
? (selected as SelectedLineRange)
|
||||
: null
|
||||
return acc
|
||||
}, {}),
|
||||
})
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
cancelTurnBackfill()
|
||||
document.removeEventListener("keydown", handleKeyDown)
|
||||
@@ -1555,7 +1141,6 @@ export default function Page() {
|
||||
reviewCount={reviewCount()}
|
||||
onSession={() => setStore("mobileTab", "session")}
|
||||
onChanges={() => setStore("mobileTab", "changes")}
|
||||
t={language.t as (key: string, vars?: Record<string, string | number | boolean>) => string}
|
||||
/>
|
||||
|
||||
{/* Session panel */}
|
||||
@@ -1595,27 +1180,7 @@ export default function Page() {
|
||||
isDesktop={isDesktop()}
|
||||
onScrollSpyScroll={scrollSpy.onScroll}
|
||||
onAutoScrollInteraction={autoScroll.handleInteraction}
|
||||
showHeader={!!(info()?.title || info()?.parentID)}
|
||||
centered={centered()}
|
||||
title={info()?.title}
|
||||
parentID={info()?.parentID}
|
||||
openTitleEditor={openTitleEditor}
|
||||
closeTitleEditor={closeTitleEditor}
|
||||
saveTitleEditor={saveTitleEditor}
|
||||
titleRef={(el) => {
|
||||
titleRef = el
|
||||
}}
|
||||
titleState={title}
|
||||
onTitleDraft={(value) => setTitle("draft", value)}
|
||||
onTitleMenuOpen={(open) => setTitle("menuOpen", open)}
|
||||
onTitlePendingRename={(value) => setTitle("pendingRename", value)}
|
||||
onNavigateParent={() => {
|
||||
navigate(`/${params.dir}/session/${info()?.parentID}`)
|
||||
}}
|
||||
sessionID={params.id!}
|
||||
onArchiveSession={(sessionID) => void archiveSession(sessionID)}
|
||||
onDeleteSession={(sessionID) => dialog.show(() => <DialogDeleteSession sessionID={sessionID} />)}
|
||||
t={language.t as (key: string, vars?: Record<string, string | number | boolean>) => string}
|
||||
setContentRef={(el) => {
|
||||
content = el
|
||||
autoScroll.contentRef(el)
|
||||
@@ -1670,15 +1235,6 @@ export default function Page() {
|
||||
|
||||
<SessionPromptDock
|
||||
centered={centered()}
|
||||
questionRequest={questionRequest}
|
||||
permissionRequest={permRequest}
|
||||
blocked={blocked()}
|
||||
todos={todos()}
|
||||
promptReady={prompt.ready()}
|
||||
handoffPrompt={handoff.session.get(sessionKey())?.prompt}
|
||||
t={language.t as (key: string, vars?: Record<string, string | number | boolean>) => string}
|
||||
responding={ui.responding}
|
||||
onDecide={decide}
|
||||
inputRef={(el) => {
|
||||
inputRef = el
|
||||
}}
|
||||
@@ -1688,7 +1244,9 @@ export default function Page() {
|
||||
comments.clear()
|
||||
resumeScroll()
|
||||
}}
|
||||
setPromptDockRef={(el) => (promptDock = el)}
|
||||
setPromptDockRef={(el) => {
|
||||
promptDock = el
|
||||
}}
|
||||
/>
|
||||
|
||||
<Show when={desktopReviewOpen()}>
|
||||
@@ -1702,64 +1260,10 @@ export default function Page() {
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<SessionSidePanel
|
||||
open={desktopSidePanelOpen()}
|
||||
reviewOpen={desktopReviewOpen()}
|
||||
language={language}
|
||||
layout={layout}
|
||||
command={command}
|
||||
dialog={dialog}
|
||||
file={file}
|
||||
comments={comments}
|
||||
hasReview={hasReview()}
|
||||
reviewCount={reviewCount()}
|
||||
reviewTab={reviewTab()}
|
||||
contextOpen={contextOpen}
|
||||
openedTabs={openedTabs}
|
||||
activeTab={activeTab}
|
||||
activeFileTab={activeFileTab}
|
||||
tabs={tabs}
|
||||
openTab={openTab}
|
||||
showAllFiles={showAllFiles}
|
||||
reviewPanel={reviewPanel}
|
||||
vm={{
|
||||
messages,
|
||||
visibleUserMessages,
|
||||
view,
|
||||
info,
|
||||
}}
|
||||
handoffFiles={() => handoff.session.get(sessionKey())?.files}
|
||||
codeComponent={codeComponent}
|
||||
addCommentToContext={addCommentToContext}
|
||||
activeDraggable={() => store.activeDraggable}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragOver={handleDragOver}
|
||||
fileTreeTab={fileTreeTab}
|
||||
setFileTreeTabValue={setFileTreeTabValue}
|
||||
diffsReady={diffsReady()}
|
||||
diffFiles={diffFiles()}
|
||||
kinds={kinds()}
|
||||
activeDiff={tree.activeDiff}
|
||||
focusReviewDiff={focusReviewDiff}
|
||||
/>
|
||||
<SessionSidePanel reviewPanel={reviewPanel} activeDiff={tree.activeDiff} focusReviewDiff={focusReviewDiff} />
|
||||
</div>
|
||||
|
||||
<TerminalPanel
|
||||
open={isDesktop() && view().terminal.opened()}
|
||||
height={layout.terminal.height()}
|
||||
resize={layout.terminal.resize}
|
||||
close={view().terminal.close}
|
||||
terminal={terminal}
|
||||
language={language}
|
||||
command={command}
|
||||
handoff={() => handoff.terminal.get(params.dir!) ?? []}
|
||||
activeTerminalDraggable={() => store.activeTerminalDraggable}
|
||||
handleTerminalDragStart={handleTerminalDragStart}
|
||||
handleTerminalDragOver={handleTerminalDragOver}
|
||||
handleTerminalDragEnd={handleTerminalDragEnd}
|
||||
onCloseTab={() => setUi("autoCreated", false)}
|
||||
/>
|
||||
<TerminalPanel />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user