fix(chat): speed up history switch
This commit is contained in:
@@ -59,11 +59,13 @@ export function HistorySidebar({
|
|||||||
const bodyRef = useRef<HTMLDivElement>(null);
|
const bodyRef = useRef<HTMLDivElement>(null);
|
||||||
const [visibleCount, setVisibleCount] = useState(appConfig.sessionPageSize);
|
const [visibleCount, setVisibleCount] = useState(appConfig.sessionPageSize);
|
||||||
const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);
|
const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null);
|
||||||
|
const [pendingSelectId, setPendingSelectId] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
setVisibleCount(appConfig.sessionPageSize);
|
setVisibleCount(appConfig.sessionPageSize);
|
||||||
setPendingDeleteId(null);
|
setPendingDeleteId(null);
|
||||||
|
setPendingSelectId(null);
|
||||||
}
|
}
|
||||||
}, [open, sessions.length]);
|
}, [open, sessions.length]);
|
||||||
|
|
||||||
@@ -77,6 +79,7 @@ export function HistorySidebar({
|
|||||||
}, [visibleCount, sessions.length]);
|
}, [visibleCount, sessions.length]);
|
||||||
|
|
||||||
const handleDeleteClick = useCallback((sessionId: string) => {
|
const handleDeleteClick = useCallback((sessionId: string) => {
|
||||||
|
setPendingSelectId(null);
|
||||||
setPendingDeleteId(sessionId);
|
setPendingDeleteId(sessionId);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -92,6 +95,24 @@ export function HistorySidebar({
|
|||||||
setPendingDeleteId(null);
|
setPendingDeleteId(null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleSelectClick = useCallback(
|
||||||
|
(sessionId: string) => {
|
||||||
|
if (pendingDeleteId === sessionId) return;
|
||||||
|
if (activeSessionId === sessionId) {
|
||||||
|
setPendingSelectId(null);
|
||||||
|
onSelect(sessionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pendingSelectId === sessionId) {
|
||||||
|
setPendingSelectId(null);
|
||||||
|
onSelect(sessionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setPendingSelectId(sessionId);
|
||||||
|
},
|
||||||
|
[activeSessionId, onSelect, pendingDeleteId, pendingSelectId],
|
||||||
|
);
|
||||||
|
|
||||||
if (!open) return null;
|
if (!open) return null;
|
||||||
|
|
||||||
const visibleSessions = sessions.slice(0, visibleCount);
|
const visibleSessions = sessions.slice(0, visibleCount);
|
||||||
@@ -130,17 +151,21 @@ export function HistorySidebar({
|
|||||||
{group.sessions.map((item) => {
|
{group.sessions.map((item) => {
|
||||||
const label = getSessionListLabel(item);
|
const label = getSessionListLabel(item);
|
||||||
const isPending = pendingDeleteId === item.id;
|
const isPending = pendingDeleteId === item.id;
|
||||||
|
const isPendingSelect = pendingSelectId === item.id;
|
||||||
return (
|
return (
|
||||||
<li key={item.id} className={`sidebar-item-wrap${isPending ? ' sidebar-item-confirming' : ''}`}>
|
<li key={item.id} className={`sidebar-item-wrap${isPending ? ' sidebar-item-confirming' : ''}`}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`sidebar-item ${item.id === activeSessionId ? 'sidebar-item-active' : ''}`}
|
className={`sidebar-item ${item.id === activeSessionId ? 'sidebar-item-active' : ''}${isPendingSelect ? ' sidebar-item-pending' : ''}`}
|
||||||
onClick={() => { if (!isPending) onSelect(item.id); }}
|
onClick={() => handleSelectClick(item.id)}
|
||||||
>
|
>
|
||||||
<span className="sidebar-item-title">{label}</span>
|
<span className="sidebar-item-title">{label}</span>
|
||||||
<span className="sidebar-item-meta">
|
<span className="sidebar-item-meta">
|
||||||
{formatSessionTime(item.updated_at ?? item.created_at)}
|
{formatSessionTime(item.updated_at ?? item.created_at)}
|
||||||
</span>
|
</span>
|
||||||
|
{isPendingSelect && item.id !== activeSessionId ? (
|
||||||
|
<span className="sidebar-item-hint">轻点打开</span>
|
||||||
|
) : null}
|
||||||
</button>
|
</button>
|
||||||
{isPending ? (
|
{isPending ? (
|
||||||
<div className="sidebar-item-confirm">
|
<div className="sidebar-item-confirm">
|
||||||
|
|||||||
@@ -610,22 +610,24 @@ export function useTKMindChat(
|
|||||||
setPendingTool(null);
|
setPendingTool(null);
|
||||||
activeRequestId.current = null;
|
activeRequestId.current = null;
|
||||||
|
|
||||||
const resumed = options?.skipResume
|
|
||||||
? (options.seedSession ?? null)
|
|
||||||
: await resumeSession(sessionId);
|
|
||||||
if (token !== connectTokenRef.current) return;
|
|
||||||
|
|
||||||
const knownSession = sessionsRef.current.find((s) => s.id === sessionId);
|
const knownSession = sessionsRef.current.find((s) => s.id === sessionId);
|
||||||
const hints = knownSession
|
const hints = knownSession
|
||||||
? { messageCount: knownSession.message_count, updatedAt: knownSession.updated_at }
|
? { messageCount: knownSession.message_count, updatedAt: knownSession.updated_at }
|
||||||
: undefined;
|
: undefined;
|
||||||
const { session: detail, messages: history } = await loadSessionDetail(sessionId, hints);
|
const detailPromise = loadSessionDetail(sessionId, hints);
|
||||||
|
const resumedPromise = options?.skipResume
|
||||||
|
? Promise.resolve(options.seedSession ?? null)
|
||||||
|
: resumeSession(sessionId);
|
||||||
|
const { session: detail, messages: history } = await detailPromise;
|
||||||
if (token !== connectTokenRef.current) return;
|
if (token !== connectTokenRef.current) return;
|
||||||
|
|
||||||
writeStoredSessionId(userRef.current?.id, sessionId);
|
writeStoredSessionId(userRef.current?.id, sessionId);
|
||||||
setSession({ ...detail, ...(resumed ?? {}), id: sessionId });
|
setSession((current) => (current?.id === sessionId ? { ...detail, ...current, id: sessionId } : { ...detail, id: sessionId }));
|
||||||
messagesRef.current = history;
|
messagesRef.current = history;
|
||||||
setMessages(history);
|
setMessages(history);
|
||||||
|
const resumed = await resumedPromise;
|
||||||
|
if (token !== connectTokenRef.current) return;
|
||||||
|
setSession({ ...detail, ...(resumed ?? {}), id: sessionId });
|
||||||
setChatState('idle');
|
setChatState('idle');
|
||||||
setSessions((prev) => prependUnique(prev, { ...detail, ...resumed, id: sessionId }));
|
setSessions((prev) => prependUnique(prev, { ...detail, ...resumed, id: sessionId }));
|
||||||
|
|
||||||
|
|||||||
@@ -253,6 +253,10 @@ body,
|
|||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-item-pending {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-item-title {
|
.sidebar-item-title {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -269,6 +273,13 @@ body,
|
|||||||
color: var(--color-text-faint);
|
color: var(--color-text-faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-item-hint {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-item-confirming .sidebar-item {
|
.sidebar-item-confirming .sidebar-item {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
|
|||||||
Reference in New Issue
Block a user