mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
wip(desktop): progress
This commit is contained in:
parent
5fbcb203f5
commit
df2ebfac7d
4 changed files with 106 additions and 4 deletions
|
|
@ -46,6 +46,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||
review: {
|
||||
state: "pane" as "pane" | "tab",
|
||||
},
|
||||
steps: {
|
||||
expanded: false,
|
||||
},
|
||||
sessionTabs: {} as Record<string, SessionTabs>,
|
||||
}),
|
||||
{
|
||||
|
|
@ -161,6 +164,18 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||
setStore("review", "state", "tab")
|
||||
},
|
||||
},
|
||||
steps: {
|
||||
expanded: createMemo(() => store.steps?.expanded ?? false),
|
||||
toggle() {
|
||||
setStore("steps", "expanded", (x) => !x)
|
||||
},
|
||||
expand() {
|
||||
setStore("steps", "expanded", true)
|
||||
},
|
||||
collapse() {
|
||||
setStore("steps", "expanded", false)
|
||||
},
|
||||
},
|
||||
tabs(sessionKey: string) {
|
||||
const tabs = createMemo(() => store.sessionTabs[sessionKey] ?? { all: [] })
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -156,6 +156,12 @@ export default function Layout(props: ParentProps) {
|
|||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
id: "provider.connect",
|
||||
title: "Connect provider",
|
||||
category: "Provider",
|
||||
onSelect: () => connectProvider(),
|
||||
},
|
||||
{
|
||||
id: "session.previous",
|
||||
title: "Previous session",
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import { Terminal } from "@/components/terminal"
|
|||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { DialogSelectFile } from "@/components/dialog-select-file"
|
||||
import { DialogSelectModel } from "@/components/dialog-select-model"
|
||||
import { useCommand } from "@/context/command"
|
||||
import { useNavigate, useParams } from "@solidjs/router"
|
||||
import { AssistantMessage, UserMessage } from "@opencode-ai/sdk/v2"
|
||||
|
|
@ -70,6 +71,25 @@ export default function Page() {
|
|||
setMessageStore("messageId", message?.id)
|
||||
}
|
||||
|
||||
function navigateMessageByOffset(offset: number) {
|
||||
const messages = userMessages()
|
||||
if (messages.length === 0) return
|
||||
|
||||
const current = activeMessage()
|
||||
const currentIndex = current ? messages.findIndex((m) => m.id === current.id) : -1
|
||||
|
||||
let targetIndex: number
|
||||
if (currentIndex === -1) {
|
||||
targetIndex = offset > 0 ? 0 : messages.length - 1
|
||||
} else {
|
||||
targetIndex = currentIndex + offset
|
||||
}
|
||||
|
||||
if (targetIndex < 0 || targetIndex >= messages.length) return
|
||||
|
||||
setActiveMessage(messages[targetIndex])
|
||||
}
|
||||
|
||||
const last = createMemo(
|
||||
() => messages().findLast((x) => x.role === "assistant" && x.tokens.output > 0) as AssistantMessage,
|
||||
)
|
||||
|
|
@ -118,7 +138,7 @@ export default function Page() {
|
|||
title: "New session",
|
||||
description: "Create a new session",
|
||||
category: "Session",
|
||||
keybind: "mod+n",
|
||||
keybind: "mod+shift+s",
|
||||
slash: "new",
|
||||
onSelect: () => navigate(`/${params.dir}/session`),
|
||||
},
|
||||
|
|
@ -163,6 +183,49 @@ export default function Page() {
|
|||
keybind: "ctrl+shift+`",
|
||||
onSelect: () => terminal.new(),
|
||||
},
|
||||
{
|
||||
id: "steps.toggle",
|
||||
title: "Toggle steps",
|
||||
description: "Show or hide the steps",
|
||||
category: "View",
|
||||
keybind: "mod+e",
|
||||
slash: "steps",
|
||||
onSelect: () => layout.steps.toggle(),
|
||||
},
|
||||
{
|
||||
id: "message.previous",
|
||||
title: "Previous message",
|
||||
description: "Go to the previous user message",
|
||||
category: "Session",
|
||||
keybind: "mod+arrowup",
|
||||
disabled: !params.id,
|
||||
onSelect: () => navigateMessageByOffset(-1),
|
||||
},
|
||||
{
|
||||
id: "message.next",
|
||||
title: "Next message",
|
||||
description: "Go to the next user message",
|
||||
category: "Session",
|
||||
keybind: "mod+arrowdown",
|
||||
disabled: !params.id,
|
||||
onSelect: () => navigateMessageByOffset(1),
|
||||
},
|
||||
{
|
||||
id: "model.choose",
|
||||
title: "Choose model",
|
||||
description: "Select a different model",
|
||||
category: "Model",
|
||||
slash: "model",
|
||||
onSelect: () => dialog.replace(() => <DialogSelectModel />),
|
||||
},
|
||||
{
|
||||
id: "agent.cycle",
|
||||
title: "Cycle agent",
|
||||
description: "Switch to the next agent",
|
||||
category: "Agent",
|
||||
slash: "agent",
|
||||
onSelect: () => local.agent.move(1),
|
||||
},
|
||||
])
|
||||
|
||||
// Handle keyboard events that aren't commands
|
||||
|
|
@ -492,6 +555,10 @@ export default function Page() {
|
|||
<SessionTurn
|
||||
sessionID={params.id!}
|
||||
messageID={activeMessage()?.id!}
|
||||
stepsExpanded={layout.steps.expanded()}
|
||||
onStepsExpandedChange={(expanded) =>
|
||||
expanded ? layout.steps.expand() : layout.steps.collapse()
|
||||
}
|
||||
classes={{
|
||||
root: "pb-20 flex-1 min-w-0",
|
||||
content: "pb-20",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ export function SessionTurn(
|
|||
props: ParentProps<{
|
||||
sessionID: string
|
||||
messageID: string
|
||||
stepsExpanded?: boolean
|
||||
onStepsExpandedChange?: (expanded: boolean) => void
|
||||
classes?: {
|
||||
root?: string
|
||||
content?: string
|
||||
|
|
@ -222,10 +224,17 @@ export function SessionTurn(
|
|||
|
||||
const [store, setStore] = createStore({
|
||||
status: rawStatus(),
|
||||
stepsExpanded: working(),
|
||||
stepsExpanded: props.stepsExpanded ?? working(),
|
||||
duration: duration(),
|
||||
})
|
||||
|
||||
// Sync with controlled prop
|
||||
createEffect(() => {
|
||||
if (props.stepsExpanded !== undefined) {
|
||||
setStore("stepsExpanded", props.stepsExpanded)
|
||||
}
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setStore("duration", duration())
|
||||
|
|
@ -262,6 +271,7 @@ export function SessionTurn(
|
|||
const isWorking = working()
|
||||
if (prev && !isWorking && !state.userScrolled) {
|
||||
setStore("stepsExpanded", false)
|
||||
props.onStepsExpandedChange?.(false)
|
||||
}
|
||||
return isWorking
|
||||
}, working())
|
||||
|
|
@ -278,7 +288,7 @@ export function SessionTurn(
|
|||
<div data-slot="session-turn-message-header">
|
||||
<div data-slot="session-turn-message-title">
|
||||
<Switch>
|
||||
<Match when={working()}>
|
||||
<Match when={working() && message().id === userMessages().at(-1)?.id}>
|
||||
<Typewriter as="h1" text={message().summary?.title} data-slot="session-turn-typewriter" />
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
|
|
@ -298,7 +308,11 @@ export function SessionTurn(
|
|||
data-slot="session-turn-collapsible-trigger-content"
|
||||
variant="ghost"
|
||||
size="small"
|
||||
onClick={() => setStore("stepsExpanded", !store.stepsExpanded)}
|
||||
onClick={() => {
|
||||
const next = !store.stepsExpanded
|
||||
setStore("stepsExpanded", next)
|
||||
props.onStepsExpandedChange?.(next)
|
||||
}}
|
||||
>
|
||||
<Show when={working()}>
|
||||
<Spinner />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue