feat(tui): support session deletion
This commit is contained in:
parent
96717c1a8c
commit
c0ea1a43f9
18 changed files with 563 additions and 273 deletions
|
|
@ -1068,7 +1068,7 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
|
|||
})
|
||||
|
||||
event.on("session.deleted", (evt) => {
|
||||
if (route.data.type === "session" && route.data.sessionID === evt.data.info.id) {
|
||||
if (route.data.type === "session" && route.data.sessionID === evt.data.sessionID) {
|
||||
route.navigate({ type: "home" })
|
||||
toast.show({
|
||||
variant: "info",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { createMemo, createResource, onMount } from "solid-js"
|
||||
import { createMemo, createResource, createSignal, onMount } from "solid-js"
|
||||
import path from "path"
|
||||
import type { SessionV2Info } from "@opencode-ai/sdk/v2"
|
||||
import { useDialog } from "../ui/dialog"
|
||||
|
|
@ -15,6 +15,7 @@ import { useToast } from "../ui/toast"
|
|||
import { useCommandShortcut } from "../keymap"
|
||||
import { DialogSessionRename } from "./dialog-session-rename"
|
||||
import { Spinner } from "./spinner"
|
||||
import { errorMessage } from "../util/error"
|
||||
|
||||
export function DialogSessionList() {
|
||||
const dialog = useDialog()
|
||||
|
|
@ -26,8 +27,10 @@ export function DialogSessionList() {
|
|||
const local = useLocal()
|
||||
const toast = useToast()
|
||||
const [search, setSearch] = createDebouncedSignal("", 150)
|
||||
const [toDelete, setToDelete] = createSignal<string>()
|
||||
const quickSwitch1 = useCommandShortcut("session.quick_switch.1")
|
||||
const quickSwitch9 = useCommandShortcut("session.quick_switch.9")
|
||||
const deleteHint = useCommandShortcut("session.delete")
|
||||
|
||||
const [searchResults] = createResource(search, async (query) => {
|
||||
if (!query) return
|
||||
|
|
@ -78,11 +81,13 @@ export function DialogSessionList() {
|
|||
const directory = session.location.directory
|
||||
const footer = directory !== project.data.project.mainDir ? Locale.truncate(path.basename(directory), 20) : ""
|
||||
const slot = slotByID.get(session.id)
|
||||
const deleting = toDelete() === session.id
|
||||
return {
|
||||
title: session.title,
|
||||
title: deleting ? `Press ${deleteHint()} again to confirm` : session.title,
|
||||
value: session.id,
|
||||
category,
|
||||
footer,
|
||||
bg: deleting ? theme.error : undefined,
|
||||
gutter:
|
||||
data.session.family(session.id).some((id) => data.session.status(id) === "running")
|
||||
? () => <Spinner />
|
||||
|
|
@ -104,9 +109,6 @@ export function DialogSessionList() {
|
|||
|
||||
onMount(() => dialog.setSize("large"))
|
||||
|
||||
const unavailable = (feature: string) =>
|
||||
toast.show({ message: `${feature} is not implemented for V2 sessions yet`, variant: "error", duration: 5000 })
|
||||
|
||||
return (
|
||||
<DialogSelect
|
||||
title="Sessions"
|
||||
|
|
@ -114,6 +116,7 @@ export function DialogSessionList() {
|
|||
skipFilter={true}
|
||||
current={currentSessionID()}
|
||||
onFilter={setSearch}
|
||||
onMove={() => setToDelete(undefined)}
|
||||
onSelect={(option) => {
|
||||
route.navigate({ type: "session", sessionID: option.value })
|
||||
dialog.clear()
|
||||
|
|
@ -127,7 +130,22 @@ export function DialogSessionList() {
|
|||
{
|
||||
command: "session.delete",
|
||||
title: "delete",
|
||||
onTrigger: () => unavailable("Deleting"),
|
||||
onTrigger: (option: { value: string }) => {
|
||||
if (toDelete() !== option.value) {
|
||||
setToDelete(option.value)
|
||||
return
|
||||
}
|
||||
void sdk.client.v2.session
|
||||
.remove({ sessionID: option.value }, { throwOnError: true })
|
||||
.catch((error) => {
|
||||
setToDelete(undefined)
|
||||
toast.show({
|
||||
message: `Failed to delete session: ${errorMessage(error)}`,
|
||||
variant: "error",
|
||||
duration: 5000,
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
command: "session.rename",
|
||||
|
|
|
|||
|
|
@ -213,11 +213,35 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
)
|
||||
}
|
||||
|
||||
function removeSession(sessionID: string) {
|
||||
messageIndex.delete(sessionID)
|
||||
setStore(
|
||||
"session",
|
||||
produce((draft) => {
|
||||
delete draft.info[sessionID]
|
||||
delete draft.status[sessionID]
|
||||
delete draft.compaction[sessionID]
|
||||
delete draft.message[sessionID]
|
||||
delete draft.input[sessionID]
|
||||
delete draft.permission[sessionID]
|
||||
delete draft.form[sessionID]
|
||||
for (const [rootID, family] of Object.entries(draft.family)) {
|
||||
const next = family.filter((id) => id !== sessionID)
|
||||
if (next.length === 0) delete draft.family[rootID]
|
||||
else draft.family[rootID] = next
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
function handleEvent(event: V2Event) {
|
||||
switch (event.type) {
|
||||
case "session.created":
|
||||
void result.session.refresh(event.data.sessionID)
|
||||
break
|
||||
case "session.deleted":
|
||||
removeSession(event.data.sessionID)
|
||||
break
|
||||
case "catalog.updated":
|
||||
void Promise.all([
|
||||
result.location.model.refresh(event.location),
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||
}
|
||||
|
||||
event.on("session.deleted", (evt) => {
|
||||
prune(evt.data.info.id)
|
||||
prune(evt.data.sessionID)
|
||||
})
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue