scope the pane rename by cwd, and show the renamed title
Two faults, and the visible symptom of both was the same: type a new title, press enter, watch it snap back unchanged. The rename 404'd. `useClaudeSessions()` was called with no cwd, so the PATCH went without `?cwd=` and the server searched the default group — `findTranscript(email, cwd, id)` scopes by directory, so every conversation living in a project was unfindable. Only chats in the default group could ever have been renamed. The pane now passes the session's own cwd, as the list already did. And the title it displayed could not have changed even on success. It came from `selected.title`, which rides the `chat:selected-session` channel — published once when a row is clicked and never updated — so the invalidation refreshed the row underneath while the header kept the old name. The title is now resolved once in `ChatDetailPanel` from the sessions query and passed down, so the pane, the page title and the row are one source. Renaming from the list's pencil retitles an open pane too, which it never did before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,12 @@ type ChatLocationState = {
|
||||
|
||||
type DetailBarProps = {
|
||||
sessionTitle: string | undefined;
|
||||
/**
|
||||
* The session's own directory. Not decoration — every `/chat/sessions` call is scoped by it, because
|
||||
* the server resolves a transcript by searching that cwd's project dir (`findTranscript`). Renaming
|
||||
* without it searches the default group and 404s for any conversation living in a project.
|
||||
*/
|
||||
cwd?: string | null;
|
||||
/** Transcripts behind this conversation; `> 1` when `/clear` parts have been merged into it. */
|
||||
partCount?: number;
|
||||
isConnected: boolean;
|
||||
@@ -50,7 +56,7 @@ type DetailBarProps = {
|
||||
onDisconnect?: () => void;
|
||||
};
|
||||
|
||||
function DetailBar({ sessionTitle, partCount, isConnected, isGenerating, onDisconnect }: DetailBarProps) {
|
||||
function DetailBar({ sessionTitle, cwd, partCount, isConnected, isGenerating, onDisconnect }: DetailBarProps) {
|
||||
// The id to rename comes from the URL, not from `resumeSessionId`. They are the same for an ordinary
|
||||
// conversation and not for a merged `/clear` chain, where the resume target is the tail transcript
|
||||
// while the list, the links and the server all address the chain by its head. Renaming the tail would
|
||||
@@ -61,7 +67,7 @@ function DetailBar({ sessionTitle, partCount, isConnected, isGenerating, onDisco
|
||||
|
||||
// The same rename the list's pencil calls, so both surfaces write one place and the invalidation that
|
||||
// follows refreshes the row too. A failure toasts rather than reverting silently, matching `SessionList`.
|
||||
const { renameSession } = useClaudeSessions();
|
||||
const { renameSession } = useClaudeSessions(cwd);
|
||||
const commitRename = useCallback(
|
||||
async (next: string) => {
|
||||
if (!sessionId) return;
|
||||
@@ -176,6 +182,7 @@ function NewChat(props: NewChatProps) {
|
||||
// comes from the same place the list gets it, which is also what makes the `/clear` numbering
|
||||
// agree in both views instead of only in the row.
|
||||
sessionTitle={props.sessionTitle ?? undefined}
|
||||
cwd={props.sessionCwd}
|
||||
partCount={props.partCount}
|
||||
isConnected={chat.isConnected}
|
||||
isGenerating={chat.isGenerating}
|
||||
@@ -205,7 +212,16 @@ export const ChatDetailPanel = () => {
|
||||
// the browser tab strip is the only place the name shows, which is exactly what tells two side-by-side
|
||||
// windows apart. Tiled, the same value fills the header's centre. One rule, both states.
|
||||
const { sessionId } = useParams<{ sessionId: string }>();
|
||||
usePublishPageTitle(sessionId ? (selected?.title ?? null) : null);
|
||||
|
||||
// The list's copy of the title wins over the one handed down at selection time. `selected.title` rides
|
||||
// the `chat:selected-session` channel, which is published once when a row is clicked and never updated
|
||||
// — so a rename reached the server, refreshed the row, and left this pane and the page title showing
|
||||
// the old name, which reads exactly like the rename having failed. Resolved here, once, and passed
|
||||
// down: renaming from either surface now retitles both, and the list's own pencil retitles an open pane.
|
||||
const { sessions } = useClaudeSessions(selected?.cwd);
|
||||
const title = sessions.find((session) => session.id === sessionId)?.title ?? selected?.title ?? null;
|
||||
|
||||
usePublishPageTitle(sessionId ? title : null);
|
||||
|
||||
if (!selected) {
|
||||
return (
|
||||
@@ -224,7 +240,7 @@ export const ChatDetailPanel = () => {
|
||||
total={selected.total}
|
||||
initialOffset={selected.initialOffset}
|
||||
sessionCwd={selected.cwd}
|
||||
sessionTitle={selected.title}
|
||||
sessionTitle={title}
|
||||
partCount={selected.partCount}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user