feat(ui): add session reload action

Let users refresh a session transcript from the sidebar without reopening it. Reuse the existing forced message loading path so the reload behavior stays aligned with normal session hydration.
This commit is contained in:
Shantur
2026-03-31 14:32:45 +01:00
parent 42589464e5
commit 1d953dfe64
8 changed files with 65 additions and 1 deletions

View File

@@ -2,7 +2,7 @@ import { Component, For, Show, createSignal, createMemo, createEffect, JSX, onCl
import type { SessionStatus } from "../types/session"
import type { SessionThread } from "../stores/session-state"
import { getSessionStatus } from "../stores/session-status"
import { Bot, User, Copy, Trash2, Pencil, ShieldAlert, ChevronDown, Search, Square, CheckSquare, MinusSquare, Split } from "lucide-solid"
import { Bot, User, Copy, Trash2, Pencil, ShieldAlert, ChevronDown, Search, Square, CheckSquare, MinusSquare, Split, RotateCw } from "lucide-solid"
import KeyboardHint from "./keyboard-hint"
import SessionRenameDialog from "./session-rename-dialog"
import { keyboardRegistry } from "../lib/keyboard-registry"
@@ -14,6 +14,7 @@ import {
ensureSessionParentExpanded,
getVisibleSessionIds,
isSessionParentExpanded,
loadMessages,
loading,
renameSession,
sessions as sessionStateSessions,
@@ -53,6 +54,7 @@ const SessionList: Component<SessionListProps> = (props) => {
const normalizedQuery = createMemo(() => (props.enableFilterBar ? filterQuery().trim().toLowerCase() : ""))
const [selectedSessionIds, setSelectedSessionIds] = createSignal<Set<string>>(new Set())
const [reloadingSessionIds, setReloadingSessionIds] = createSignal<Set<string>>(new Set())
const normalizeSessionLabel = (sessionId: string) => {
const session = sessionStateSessions().get(props.instanceId)?.get(sessionId)
@@ -213,6 +215,32 @@ const SessionList: Component<SessionListProps> = (props) => {
setRenameTarget({ id: sessionId, title: session.title ?? "", label })
}
const isSessionReloading = (sessionId: string) => reloadingSessionIds().has(sessionId)
const handleReloadSession = async (event: MouseEvent, sessionId: string) => {
event.stopPropagation()
if (isSessionReloading(sessionId)) return
setReloadingSessionIds((prev) => {
const next = new Set(prev)
next.add(sessionId)
return next
})
try {
await loadMessages(props.instanceId, sessionId, true)
} catch (error) {
log.error(`Failed to reload session ${sessionId}:`, error)
showToastNotification({ message: t("sessionList.reload.error"), variant: "error" })
} finally {
setReloadingSessionIds((prev) => {
const next = new Set(prev)
next.delete(sessionId)
return next
})
}
}
const closeRenameDialog = () => {
setRenameTarget(null)
}
@@ -493,6 +521,21 @@ const SessionList: Component<SessionListProps> = (props) => {
>
<Copy class="w-3 h-3" />
</span>
<span
class={`session-item-close opacity-80 hover:opacity-100 ${isActive() ? "hover:bg-white/20" : "hover:bg-surface-hover"}`}
onClick={(event) => handleReloadSession(event, rowProps.sessionId)}
role="button"
tabIndex={0}
aria-label={t("sessionList.actions.reload.ariaLabel")}
title={t("sessionList.actions.reload.title")}
>
<Show
when={!isSessionReloading(rowProps.sessionId)}
fallback={<RotateCw class="w-3 h-3 animate-spin" />}
>
<RotateCw class="w-3 h-3" />
</Show>
</span>
<span
class={`session-item-close opacity-80 hover:opacity-100 ${isActive() ? "hover:bg-white/20" : "hover:bg-surface-hover"}`}
onClick={(event) => {