feat(desktop): keep deleted home sessions gone and slide rows up (#55349)

This commit is contained in:
usrnk1
2026-10-22 10:39:04 +02:00
committed by GitHub
Unverified
parent ab6ac0099f
commit eafec096c3
2 changed files with 39 additions and 7 deletions
+35 -3
View File
@@ -231,9 +231,16 @@ export function createHomeSessionsController(home: HomeController) {
if (!conn || !ctx) return false
const ids = sessionTreeIDs(ctx.data.session.list(), session.id)
const rows = homeRowTops()
// session.deleted clears the local hide mutation before the refetch lands,
// so the cached index must drop the row now or it briefly reappears.
queryClient.setQueryData<SessionInfo[]>(["home-sessions", conn], (current) =>
current?.filter((item) => item.id !== session.id),
)
const request = ctx.data.session.remove(session.id)
animateHomeRowsUp(rows)
return ctx.data.session
.remove(session.id)
return request
.then(() => {
notifySessionTabsRemoved({
server: ServerConnection.key(conn),
@@ -260,8 +267,8 @@ export function createHomeSessionsController(home: HomeController) {
const name = () => sessionTitle(props.session.title) ?? language.t("command.session.new")
const confirm = async () => {
await remove(props.server, props.session)
dialog.close()
await remove(props.server, props.session)
}
return (
@@ -381,6 +388,31 @@ function directories(project: LocalProject) {
return [project.worktree, ...(project.sandboxes ?? [])]
}
const HOME_ROW_SELECTOR = '[data-component="home-session-row-container"]'
function homeRowTops() {
return new Map(
Array.from(document.querySelectorAll<HTMLElement>(HOME_ROW_SELECTOR), (row) => {
return [row.dataset.sessionId, row.getBoundingClientRect().top] as const
}),
)
}
// FLIP: rows below a removed row jump up in layout; play the difference back as a short transform.
function animateHomeRowsUp(tops: Map<string | undefined, number>) {
if (matchMedia("(prefers-reduced-motion: reduce)").matches) return
document.querySelectorAll<HTMLElement>(HOME_ROW_SELECTOR).forEach((row) => {
const before = tops.get(row.dataset.sessionId)
const delta = before === undefined ? 0 : before - row.getBoundingClientRect().top
if (delta === 0) return
row.animate([{ transform: `translateY(${delta}px)` }, { transform: "translateY(0)" }], {
duration: 180,
easing: "cubic-bezier(0.645, 0.045, 0.355, 1)",
})
})
}
export function homeSessionSearchKey(record: HomeSessionRecord) {
return `${pathKey(record.session.location.directory)}:${record.session.id}`
}
+4 -4
View File
@@ -620,8 +620,8 @@ function HomeSessionRow(
fallback={
<div
data-slot="home-session-editor"
class="flex h-10 min-w-0 w-full flex-1 items-center py-3 ps-1.5 pe-3 md:ps-3 md:pe-10"
classList={{ "gap-1.5": props.desktop, "gap-2": !props.desktop }}
class="flex h-10 min-w-0 w-full flex-1 items-center py-3 ps-1.5 pe-3 md:ps-3"
classList={{ "gap-1.5": props.desktop, "gap-2": !props.desktop, "md:pe-10": SHOW_HOME_SESSION_ARCHIVE }}
>
<HomeSessionLeadingController server={props.server} isOpenTab={props.isOpenTab} record={props.record} />
<div data-slot="home-session-labels" class="contents">
@@ -678,11 +678,11 @@ function HomeSessionRow(
aria-expanded={!!menu()}
class={`
flex h-10 min-w-0 w-full flex-1 shrink-0 cursor-default items-center rounded-[6px] border-0
bg-transparent py-3 ps-1.5 pe-3 md:ps-3 md:pe-10 text-start text-v2-text-text-muted [font-weight:530]
bg-transparent py-3 ps-1.5 pe-3 md:ps-3 text-start text-v2-text-text-muted [font-weight:530]
transition-[background-color,color,box-shadow] duration-[120ms] ease-in-out
hover:bg-v2-overlay-simple-overlay-hover focus-visible:bg-v2-overlay-simple-overlay-hover focus-visible:outline-none
`}
classList={{ "gap-1.5": props.desktop, "gap-2": !props.desktop }}
classList={{ "gap-1.5": props.desktop, "gap-2": !props.desktop, "md:pe-10": SHOW_HOME_SESSION_ARCHIVE }}
onMouseDown={(event) => {
if (event.button === 1) event.preventDefault()
}}