diff --git a/packages/app/src/home/sessions/controller.tsx b/packages/app/src/home/sessions/controller.tsx index 4c7bef90493..706ac244060 100644 --- a/packages/app/src/home/sessions/controller.tsx +++ b/packages/app/src/home/sessions/controller.tsx @@ -146,6 +146,10 @@ export function createHomeSessionsController(home: HomeController) { .rename({ sessionID: session.id, title: next }) .then(() => { ctx.data.session.remember({ ...(ctx.data.session.get(session.id) ?? session), title: next }) + // Rename advances time.updated server-side; re-sync the canonical + // record so date grouping and ordering do not go stale. + ctx.data.session.invalidate(session.id) + void ctx.data.session.sync(session.id) queryClient.setQueryData(["home-sessions", conn], (current) => current?.map((item) => (item.id === session.id ? { ...item, title: next } : item)), ) @@ -202,6 +206,9 @@ export function createHomeSessionsController(home: HomeController) { directory: session.location.directory, sessionIDs: ids, }) + // The pre-mutation cancel may have aborted an in-flight index fetch; + // refetch so the full server index is not left unloaded. + void queryClient.invalidateQueries({ queryKey: ["home-sessions", conn], exact: true }) return true }) .catch((cause) => { diff --git a/packages/app/src/home/sessions/view.tsx b/packages/app/src/home/sessions/view.tsx index cbd801497d6..ca08ef51bd4 100644 --- a/packages/app/src/home/sessions/view.tsx +++ b/packages/app/src/home/sessions/view.tsx @@ -447,6 +447,7 @@ function HomeSessionRow( let longPressTimer: ReturnType | undefined let longPressStart: { x: number; y: number } | undefined let suppressClick = false + let menuInteractedOutside = false const clearLongPress = () => { if (longPressTimer !== undefined) clearTimeout(longPressTimer) @@ -483,10 +484,21 @@ function HomeSessionRow( if (!current || current.renaming) return props.setRowUI("editor", { ...current, renaming: true }) const saved = await props.onRenameSession(props.server, props.record.session, current.draft) + // Disabling the input during the request drops focus to the body; restore + // it unless the user focused another control while the rename was pending. + const restore = document.activeElement === document.body || document.activeElement === titleRef props.setRowUI("editor", (value) => { if (value?.id !== sessionID()) return value return saved ? undefined : { ...value, renaming: false } }) + if (!restore) return + requestAnimationFrame(() => { + if (saved) { + rowRef?.focus() + return + } + titleRef?.focus() + }) } return ( @@ -496,8 +508,9 @@ function HomeSessionRow( class="group/session relative flex h-10 min-w-0 items-center rounded-[6px] outline-none focus:outline-none focus-visible:outline-none" classList={{ group: !!showProjectName() }} onContextMenu={(event) => { - event.preventDefault() + // While renaming, keep the native menu so paste and spelling work. if (editor()) return + event.preventDefault() openMenu(event.currentTarget, event.clientX, event.clientY) }} > @@ -531,6 +544,9 @@ function HomeSessionRow( }} onKeyDown={(event) => { event.stopPropagation() + // Enter and Escape during IME composition commit or cancel + // the composition, not the rename. + if (event.isComposing) return if (event.key === "Enter") { event.preventDefault() void saveEditor() @@ -539,6 +555,7 @@ function HomeSessionRow( if (event.key !== "Escape") return event.preventDefault() closeEditor() + requestAnimationFrame(() => rowRef?.focus()) }} onBlur={closeEditor} /> @@ -640,12 +657,18 @@ function HomeSessionRow( /> { + menuInteractedOutside = true + }} onCloseAutoFocus={(event) => { // The trigger is an invisible positioning span, so Kobalte's // default close focus restore has no useful target. Skip the - // row focus while the rename editor owns focus instead. + // row focus when the rename editor owns focus or the user + // dismissed the menu by interacting elsewhere. event.preventDefault() - if (editor()) return + const outside = menuInteractedOutside + menuInteractedOutside = false + if (outside || editor()) return requestAnimationFrame(() => rowRef?.focus()) }} >