feat: refresh shared chat and server workflows

This commit is contained in:
2026-05-26 12:26:33 +09:00
parent 51e0099bea
commit c1d0f4c1db
82 changed files with 18604 additions and 12461 deletions

View File

@@ -1,6 +1,6 @@
import { Button, Empty, Input, List, Spin, Typography } from 'antd';
import type { ChatConversationSummary } from '../../mainChatPanel/types';
import { shouldShowConversationForMode } from '../../isolatedChatRooms';
import { shouldShowPrimaryConversation } from '../../chatSessionRouting';
const { Text } = Typography;
@@ -26,7 +26,7 @@ export function ConversationListPane({
onSelectSession,
onCreateConversation,
}: ConversationListPaneProps) {
const visibleItems = items.filter((item) => shouldShowConversationForMode(item.sessionId, 'live'));
const visibleItems = items.filter((item) => shouldShowPrimaryConversation(item.sessionId));
return (
<section className="chat-v2__pane chat-v2__pane--list">

View File

@@ -5,6 +5,11 @@ import type {
ChatRuntimeSnapshot,
} from '../../mainChatPanel/types';
const SCROLL_JUMP_HIDE_THRESHOLD = 24;
const SCROLL_JUMP_MIN_OVERFLOW = 48;
const SCROLL_JUMP_DIRECTION_THRESHOLD = 6;
const SCROLL_JUMP_IDLE_HIDE_DELAY_MS = 900;
type UseConversationViewportControllerOptions = {
activeConversation: ChatConversationSummary | null;
activeQueuedComposerRequestsCount: number;
@@ -50,6 +55,7 @@ export function useConversationViewportController({
const systemStatusTimerRef = useRef<number | null>(null);
const restoreAutoScrollFrameRef = useRef<number | null>(null);
const showScrollToBottomRef = useRef(false);
const scrollJumpIdleTimerRef = useRef<number | null>(null);
const shouldStickToBottomRef = useRef(true);
const lastViewportScrollTopRef = useRef(0);
const autoScrollSuspendedUntilRef = useRef(0);
@@ -74,6 +80,13 @@ export function useConversationViewportController({
}
}, []);
const clearScrollJumpIdleTimer = useCallback(() => {
if (scrollJumpIdleTimerRef.current !== null) {
window.clearTimeout(scrollJumpIdleTimerRef.current);
scrollJumpIdleTimerRef.current = null;
}
}, []);
const syncShowScrollToBottom = useCallback((nextValue: boolean) => {
if (showScrollToBottomRef.current === nextValue) {
return;
@@ -144,8 +157,11 @@ export function useConversationViewportController({
}
const remainingDistance = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
const isNearBottom = remainingDistance <= 24;
const isScrollingUp = viewport.scrollTop < lastViewportScrollTopRef.current - 2;
const maxScrollDistance = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
const currentScrollTop = viewport.scrollTop;
const scrollDelta = currentScrollTop - lastViewportScrollTopRef.current;
const isNearBottom = remainingDistance <= SCROLL_JUMP_HIDE_THRESHOLD;
const isScrollingUp = scrollDelta < -2;
if (isNearBottom) {
releaseAutoScrollSuspension();
@@ -155,9 +171,30 @@ export function useConversationViewportController({
const shouldStickToBottom = isNearBottom && !isAutoScrollSuspended();
shouldStickToBottomRef.current = shouldStickToBottom;
lastViewportScrollTopRef.current = viewport.scrollTop;
syncShowScrollToBottom(!shouldStickToBottom);
}, [isAutoScrollSuspended, releaseAutoScrollSuspension, syncShowScrollToBottom, viewportRef]);
lastViewportScrollTopRef.current = currentScrollTop;
if (maxScrollDistance < SCROLL_JUMP_MIN_OVERFLOW || shouldStickToBottom) {
clearScrollJumpIdleTimer();
syncShowScrollToBottom(false);
return;
}
if (Math.abs(scrollDelta) >= SCROLL_JUMP_DIRECTION_THRESHOLD) {
clearScrollJumpIdleTimer();
scrollJumpIdleTimerRef.current = window.setTimeout(() => {
scrollJumpIdleTimerRef.current = null;
syncShowScrollToBottom(false);
}, SCROLL_JUMP_IDLE_HIDE_DELAY_MS);
}
syncShowScrollToBottom(true);
}, [
clearScrollJumpIdleTimer,
isAutoScrollSuspended,
releaseAutoScrollSuspension,
syncShowScrollToBottom,
viewportRef,
]);
const captureViewportRestoreSnapshot = useCallback((options?: { forceStickToBottom?: boolean }) => {
if (options?.forceStickToBottom) {
@@ -491,12 +528,13 @@ export function useConversationViewportController({
useEffect(() => {
return () => {
clearSystemStatusTimer();
clearScrollJumpIdleTimer();
if (restoreAutoScrollFrameRef.current !== null) {
window.cancelAnimationFrame(restoreAutoScrollFrameRef.current);
}
};
}, [clearSystemStatusTimer]);
}, [clearScrollJumpIdleTimer, clearSystemStatusTimer]);
return {
activeSystemStatus,