/* * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use client'; import { useEffect, useRef } from 'react'; import styles from './ResearchProgressList.module.css'; import ResearchProgressItem from './ResearchProgressItem'; import ResearchProgressFooter from './ResearchProgressFooter'; import ResearchProgressHeader from './ResearchProgressHeader'; import { ApplicationState } from '@/types/ApplicationState'; export type ResearchEventType = | 'prompt_received' | 'prompt_analysis_started' | 'prompt_analysis_completed' | 'task_analysis_completed' | 'topic_exploration_started' | 'search_started' | 'search_result_processing_started' | 'aggregation_started' | 'research_completed' | 'report_building' | 'report_formatting' | 'report_done' | 'error'; export interface ResearchEvent { id: string; type: ResearchEventType; description: string; timestamp: number; } interface ResearchProgressListProps { state: ApplicationState; onStop?: () => void; onClear?: () => void; onFinalize?: () => void; onViewError?: () => void; } export default function ResearchProgressList({ state, onStop, onClear, onFinalize, onViewError }: ResearchProgressListProps) { const listRef = useRef(null); const prevEventsLengthRef = useRef(0); const userHasScrolledRef = useRef(false); useEffect(() => { // Only scroll if we have new events, the list exists, and user hasn't scrolled if (listRef.current && state.events.length > prevEventsLengthRef.current && !userHasScrolledRef.current) { listRef.current.scrollTop = listRef.current.scrollHeight; prevEventsLengthRef.current = state.events.length; //console.log('scrolling to bottom'); } }, [state.events]); const handleScroll = (e: React.UIEvent) => { const element = e.currentTarget; // Check if we're not at the bottom if (element.scrollHeight - element.scrollTop - element.clientHeight > 10) { userHasScrolledRef.current = true; } else { // Reset the flag if user scrolls back to bottom userHasScrolledRef.current = false; //console.log('resetting scroll flag'); } }; return (
{state.type !== 'idle' && (
{state.events.map((event) => ( ))}
)}
); }