chore: cleanup (#14113)
This commit is contained in:
@@ -1,35 +1,105 @@
|
||||
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup } from "solid-js"
|
||||
import type { QuestionRequest, Todo } from "@opencode-ai/sdk/v2"
|
||||
import type { PermissionRequest, QuestionRequest, Todo } from "@opencode-ai/sdk/v2"
|
||||
import { useParams } from "@solidjs/router"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
import { DockPrompt } from "@opencode-ai/ui/dock-prompt"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { PromptInput } from "@/components/prompt-input"
|
||||
import { QuestionDock } from "@/components/question-dock"
|
||||
import { SessionTodoDock } from "@/components/session-todo-dock"
|
||||
import { useGlobalSync } from "@/context/global-sync"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { usePrompt } from "@/context/prompt"
|
||||
import { useSDK } from "@/context/sdk"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { getSessionHandoff, setSessionHandoff } from "@/pages/session/handoff"
|
||||
|
||||
export function SessionPromptDock(props: {
|
||||
centered: boolean
|
||||
questionRequest: () => QuestionRequest | undefined
|
||||
permissionRequest: () => { patterns: string[]; permission: string } | undefined
|
||||
blocked: boolean
|
||||
todos: Todo[]
|
||||
promptReady: boolean
|
||||
handoffPrompt?: string
|
||||
t: (key: string, vars?: Record<string, string | number | boolean>) => string
|
||||
responding: boolean
|
||||
onDecide: (response: "once" | "always" | "reject") => void
|
||||
inputRef: (el: HTMLDivElement) => void
|
||||
newSessionWorktree: string
|
||||
onNewSessionWorktreeReset: () => void
|
||||
onSubmit: () => void
|
||||
setPromptDockRef: (el: HTMLDivElement) => void
|
||||
}) {
|
||||
const done = createMemo(
|
||||
() =>
|
||||
props.todos.length > 0 && props.todos.every((todo) => todo.status === "completed" || todo.status === "cancelled"),
|
||||
const params = useParams()
|
||||
const sdk = useSDK()
|
||||
const sync = useSync()
|
||||
const globalSync = useGlobalSync()
|
||||
const prompt = usePrompt()
|
||||
const language = useLanguage()
|
||||
|
||||
const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`)
|
||||
const handoffPrompt = createMemo(() => getSessionHandoff(sessionKey())?.prompt)
|
||||
|
||||
const todos = createMemo((): Todo[] => {
|
||||
const id = params.id
|
||||
if (!id) return []
|
||||
return globalSync.data.session_todo[id] ?? []
|
||||
})
|
||||
|
||||
const questionRequest = createMemo((): QuestionRequest | undefined => {
|
||||
const sessionID = params.id
|
||||
if (!sessionID) return
|
||||
return sync.data.question[sessionID]?.[0]
|
||||
})
|
||||
|
||||
const permissionRequest = createMemo((): PermissionRequest | undefined => {
|
||||
const sessionID = params.id
|
||||
if (!sessionID) return
|
||||
return sync.data.permission[sessionID]?.[0]
|
||||
})
|
||||
|
||||
const blocked = createMemo(() => !!permissionRequest() || !!questionRequest())
|
||||
|
||||
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() })
|
||||
})
|
||||
|
||||
const [responding, setResponding] = createSignal(false)
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => permissionRequest()?.id,
|
||||
() => setResponding(false),
|
||||
{ defer: true },
|
||||
),
|
||||
)
|
||||
|
||||
const [dock, setDock] = createSignal(props.todos.length > 0)
|
||||
const decide = (response: "once" | "always" | "reject") => {
|
||||
const perm = permissionRequest()
|
||||
if (!perm) return
|
||||
if (responding()) return
|
||||
|
||||
setResponding(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(() => setResponding(false))
|
||||
}
|
||||
|
||||
const done = createMemo(
|
||||
() => todos().length > 0 && todos().every((todo) => todo.status === "completed" || todo.status === "cancelled"),
|
||||
)
|
||||
|
||||
const [dock, setDock] = createSignal(todos().length > 0)
|
||||
const [closing, setClosing] = createSignal(false)
|
||||
const [opening, setOpening] = createSignal(false)
|
||||
let timer: number | undefined
|
||||
@@ -46,7 +116,7 @@ export function SessionPromptDock(props: {
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => [props.todos.length, done()] as const,
|
||||
() => [todos().length, done()] as const,
|
||||
([count, complete], prev) => {
|
||||
if (raf) cancelAnimationFrame(raf)
|
||||
raf = undefined
|
||||
@@ -113,7 +183,7 @@ export function SessionPromptDock(props: {
|
||||
"md:max-w-200 md:mx-auto 2xl:max-w-[1000px]": props.centered,
|
||||
}}
|
||||
>
|
||||
<Show when={props.questionRequest()} keyed>
|
||||
<Show when={questionRequest()} keyed>
|
||||
{(req) => {
|
||||
return (
|
||||
<div>
|
||||
@@ -123,11 +193,11 @@ export function SessionPromptDock(props: {
|
||||
}}
|
||||
</Show>
|
||||
|
||||
<Show when={props.permissionRequest()} keyed>
|
||||
<Show when={permissionRequest()} keyed>
|
||||
{(perm) => {
|
||||
const toolDescription = () => {
|
||||
const key = `settings.permissions.tool.${perm.permission}.description`
|
||||
const value = props.t(key)
|
||||
const value = language.t(key as Parameters<typeof language.t>[0])
|
||||
if (value === key) return ""
|
||||
return value
|
||||
}
|
||||
@@ -141,36 +211,26 @@ export function SessionPromptDock(props: {
|
||||
<span data-slot="permission-icon">
|
||||
<Icon name="warning" size="normal" />
|
||||
</span>
|
||||
<div data-slot="permission-header-title">{props.t("notification.permission.title")}</div>
|
||||
<div data-slot="permission-header-title">{language.t("notification.permission.title")}</div>
|
||||
</div>
|
||||
}
|
||||
footer={
|
||||
<>
|
||||
<div />
|
||||
<div data-slot="permission-footer-actions">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="normal"
|
||||
onClick={() => props.onDecide("reject")}
|
||||
disabled={props.responding}
|
||||
>
|
||||
{props.t("ui.permission.deny")}
|
||||
<Button variant="ghost" size="normal" onClick={() => decide("reject")} disabled={responding()}>
|
||||
{language.t("ui.permission.deny")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="normal"
|
||||
onClick={() => props.onDecide("always")}
|
||||
disabled={props.responding}
|
||||
onClick={() => decide("always")}
|
||||
disabled={responding()}
|
||||
>
|
||||
{props.t("ui.permission.allowAlways")}
|
||||
{language.t("ui.permission.allowAlways")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="normal"
|
||||
onClick={() => props.onDecide("once")}
|
||||
disabled={props.responding}
|
||||
>
|
||||
{props.t("ui.permission.allowOnce")}
|
||||
<Button variant="primary" size="normal" onClick={() => decide("once")} disabled={responding()}>
|
||||
{language.t("ui.permission.allowOnce")}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
@@ -199,12 +259,12 @@ export function SessionPromptDock(props: {
|
||||
}}
|
||||
</Show>
|
||||
|
||||
<Show when={!props.blocked}>
|
||||
<Show when={!blocked()}>
|
||||
<Show
|
||||
when={props.promptReady}
|
||||
when={prompt.ready()}
|
||||
fallback={
|
||||
<div class="w-full min-h-32 md:min-h-40 rounded-md border border-border-weak-base bg-background-base/50 px-4 py-3 text-text-weak whitespace-pre-wrap pointer-events-none">
|
||||
{props.handoffPrompt || props.t("prompt.loading")}
|
||||
{handoffPrompt() || language.t("prompt.loading")}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@@ -219,10 +279,10 @@ export function SessionPromptDock(props: {
|
||||
}}
|
||||
>
|
||||
<SessionTodoDock
|
||||
todos={props.todos}
|
||||
title={props.t("session.todo.title")}
|
||||
collapseLabel={props.t("session.todo.collapse")}
|
||||
expandLabel={props.t("session.todo.expand")}
|
||||
todos={todos()}
|
||||
title={language.t("session.todo.title")}
|
||||
collapseLabel={language.t("session.todo.collapse")}
|
||||
expandLabel={language.t("session.todo.expand")}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
Reference in New Issue
Block a user