From cc8b4a094089dbd650afab243a41f1a8f53df425 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 9 Apr 2026 21:31:23 -0500 Subject: [PATCH] Tap-to-edit session titles, PATCH proxy, model display on replay --- app/api/sessions/[id]/route.ts | 19 +++++++++++++++++ app/history/[id]/page.tsx | 37 +++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/app/api/sessions/[id]/route.ts b/app/api/sessions/[id]/route.ts index 0ef41ad..68875ec 100644 --- a/app/api/sessions/[id]/route.ts +++ b/app/api/sessions/[id]/route.ts @@ -16,6 +16,25 @@ export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: } } +export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + const body = await req.text(); + try { + const res = await fetch(BACKEND + "/api/sessions/" + id, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body, + }); + const data = await res.text(); + return new NextResponse(data, { + status: res.status, + headers: { "content-type": "application/json" }, + }); + } catch { + return NextResponse.json({ error: "backend unreachable" }, { status: 502 }); + } +} + export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) { const { id } = await params; try { diff --git a/app/history/[id]/page.tsx b/app/history/[id]/page.tsx index 3b46681..8143e0c 100644 --- a/app/history/[id]/page.tsx +++ b/app/history/[id]/page.tsx @@ -22,6 +22,8 @@ export default function SessionReplayPage({ params }: { params: Promise<{ id: st const qc = useQueryClient(); const router = useRouter(); const [confirmDelete, setConfirmDelete] = useState(false); + const [editingTitle, setEditingTitle] = useState(false); + const [titleDraft, setTitleDraft] = useState(""); const { data: sessionData } = useSession(id); const { data: messagesData, isLoading } = useMessages(id); const [input, setInput] = useState(""); @@ -88,15 +90,44 @@ export default function SessionReplayPage({ params }: { params: Promise<{ id: st
-
- {session?.title || "Session " + id.slice(0, 8)} -
+ {editingTitle ? ( + setTitleDraft(e.target.value)} + onBlur={async () => { + if (titleDraft.trim() && titleDraft !== session?.title) { + await fetch("/api/sessions/" + id, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ title: titleDraft.trim() }), + }); + qc.invalidateQueries({ queryKey: ["session", id] }); + } + setEditingTitle(false); + }} + onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }} + className="text-[15px] font-medium w-full bg-transparent outline-none" + style={{ color: "var(--text-1)", borderBottom: "1px solid var(--accent)" }} + autoFocus + /> + ) : ( +
{ setTitleDraft(session?.title || ""); setEditingTitle(true); }} + > + {session?.title || "Session " + id.slice(0, 8)} +
+ )} {session && (
{session.source} + {session.model && {session.model.split("/").pop()}} + {session.model && " · "} {session.message_count} msgs · {formatTokens(session.input_tokens + session.output_tokens)} · {timeAgo(session.started_at)}