diff --git a/web/src/api/buster_rest/chats/queryRequests.ts b/web/src/api/buster_rest/chats/queryRequests.ts index 8378d467b..b23796dc9 100644 --- a/web/src/api/buster_rest/chats/queryRequests.ts +++ b/web/src/api/buster_rest/chats/queryRequests.ts @@ -77,6 +77,7 @@ export const useGetChat = ( if (lastMessage) { Object.values(lastMessage.response_messages).forEach((responseMessage) => { if (responseMessage.type === 'file' && responseMessage.file_type === 'metric') { + console.log('prefetching metric', responseMessage.id); prefetchGetMetricDataClient({ id: responseMessage.id }, queryClient); } }); diff --git a/web/src/api/buster_rest/dashboards/queryRequests.ts b/web/src/api/buster_rest/dashboards/queryRequests.ts index 3a3deb32f..8f96609ea 100644 --- a/web/src/api/buster_rest/dashboards/queryRequests.ts +++ b/web/src/api/buster_rest/dashboards/queryRequests.ts @@ -54,6 +54,7 @@ const useGetDashboardAndInitializeMetrics = () => { const prevMetric = queryClient.getQueryData(queryKeys.metricsGetMetric(metric.id).queryKey); const upgradedMetric = upgradeMetricToIMetric(metric, prevMetric); queryClient.setQueryData(queryKeys.metricsGetMetric(metric.id).queryKey, upgradedMetric); + console.log('prefetching metric', metric.id); prefetchGetMetricDataClient({ id: metric.id }, queryClient); } }); diff --git a/web/src/api/buster_rest/metrics/queryReqestsServer.ts b/web/src/api/buster_rest/metrics/queryReqestsServer.ts index cbc8f6489..06961a6e0 100644 --- a/web/src/api/buster_rest/metrics/queryReqestsServer.ts +++ b/web/src/api/buster_rest/metrics/queryReqestsServer.ts @@ -3,6 +3,9 @@ import { upgradeMetricToIMetric } from '@/lib/metrics'; import { QueryClient } from '@tanstack/react-query'; import { getMetric_server, listMetrics, listMetrics_server } from './requests'; +/* + + */ export const prefetchGetMetric = async ( params: Parameters[0], queryClientProp?: QueryClient diff --git a/web/src/api/buster_rest/metrics/queryRequests.ts b/web/src/api/buster_rest/metrics/queryRequests.ts index a8cae1293..f91e1b793 100644 --- a/web/src/api/buster_rest/metrics/queryRequests.ts +++ b/web/src/api/buster_rest/metrics/queryRequests.ts @@ -22,7 +22,6 @@ import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsPro import { useGetUserFavorites } from '../users'; import type { IBusterMetric } from '@/api/asset_interfaces/metric'; import { create } from 'mutative'; -import { isServer } from '@tanstack/react-query'; import { useAddAssetToCollection, useRemoveAssetFromCollection @@ -106,7 +105,6 @@ export const useGetMetricData = ({ version_number?: number; }) => { const searchParams = useSearchParams(); - const queryClient = useQueryClient(); const queryVersionNumber = searchParams.get('metric_version_number'); const version_number = useMemo(() => { @@ -114,12 +112,9 @@ export const useGetMetricData = ({ }, [version_number_prop, queryVersionNumber]); const queryFn = useMemoizedFn(() => { - console.log('hit!', isServer, metricsQueryKeys.metricsGetData(id, version_number).queryKey); return getMetricData({ id, version_number }); }); - console.log('data here!'); - return useQuery({ ...metricsQueryKeys.metricsGetData(id, version_number), queryFn diff --git a/web/src/app/app/(primary_layout)/(chat_experience)/metrics/[metricId]/page.tsx b/web/src/app/app/(primary_layout)/(chat_experience)/metrics/[metricId]/page.tsx index 610151ac4..2b483a24c 100644 --- a/web/src/app/app/(primary_layout)/(chat_experience)/metrics/[metricId]/page.tsx +++ b/web/src/app/app/(primary_layout)/(chat_experience)/metrics/[metricId]/page.tsx @@ -1,8 +1,11 @@ +'use server'; + import { MetricController } from '@/controllers/MetricController'; import { AppAssetCheckLayout } from '@/layouts/AppAssetCheckLayout'; export default async function MetricPage(props: { params: Promise<{ metricId: string }> }) { - const [params] = await Promise.all([props.params]); + const params = await props.params; + const { metricId } = params; return ( diff --git a/web/src/app/app/(settings_layout)/settings/(restricted-width)/(admin-only)/datasources/(admin-restricted-space)/add/page.tsx b/web/src/app/app/(settings_layout)/settings/(restricted-width)/(admin-only)/datasources/(admin-restricted-space)/add/page.tsx index 7b99fdb6b..e650495c6 100644 --- a/web/src/app/app/(settings_layout)/settings/(restricted-width)/(admin-only)/datasources/(admin-restricted-space)/add/page.tsx +++ b/web/src/app/app/(settings_layout)/settings/(restricted-width)/(admin-only)/datasources/(admin-restricted-space)/add/page.tsx @@ -34,7 +34,7 @@ export default function Page({ const onClearSelectedDataSource = useMemoizedFn(() => { setSelectedDataSource(null); - onChangePage(createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD })); + onChangePage({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD }); }); useEffect(() => { diff --git a/web/src/components/features/modal/NewDatasetModal.tsx b/web/src/components/features/modal/NewDatasetModal.tsx index 7e23a1548..3d3575765 100644 --- a/web/src/components/features/modal/NewDatasetModal.tsx +++ b/web/src/components/features/modal/NewDatasetModal.tsx @@ -55,7 +55,7 @@ export const NewDatasetModal: React.FC<{ }); const onAddDataSourceClick = useMemoizedFn(() => { - onChangePage(createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD })); + onChangePage({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD }); setTimeout(() => { onClose(); }, 450); diff --git a/web/src/components/features/versionHistory/VersionHistoryPanel.tsx b/web/src/components/features/versionHistory/VersionHistoryPanel.tsx index d5e13bc53..996e2749e 100644 --- a/web/src/components/features/versionHistory/VersionHistoryPanel.tsx +++ b/web/src/components/features/versionHistory/VersionHistoryPanel.tsx @@ -38,7 +38,6 @@ export const VersionHistoryPanel = React.memo( return ( ( diff --git a/web/src/components/ui/layouts/AppPageLayout.tsx b/web/src/components/ui/layouts/AppPageLayout.tsx index 0e5b6c563..7093607e9 100644 --- a/web/src/components/ui/layouts/AppPageLayout.tsx +++ b/web/src/components/ui/layouts/AppPageLayout.tsx @@ -40,10 +40,7 @@ export const AppPageLayout: React.FC< )}> {header && ( {header} diff --git a/web/src/components/ui/layouts/AppPageLayoutHeader.tsx b/web/src/components/ui/layouts/AppPageLayoutHeader.tsx index a1de95cd3..7b88d7a6e 100644 --- a/web/src/components/ui/layouts/AppPageLayoutHeader.tsx +++ b/web/src/components/ui/layouts/AppPageLayoutHeader.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; const headerVariants = cva( - 'bg-page-background flex max-h-[38px] min-h-[38px] items-center z-10 justify-between gap-x-2.5 relative', + 'bg-page-background flex max-h-[38px] min-h-[38px] items-center justify-between gap-x-2.5 relative', { variants: { sizeVariant: { diff --git a/web/src/components/ui/streaming/StreamingMessage_File.stories.tsx b/web/src/components/ui/streaming/StreamingMessage_File.stories.tsx index 1b490f007..e1aac5f0b 100644 --- a/web/src/components/ui/streaming/StreamingMessage_File.stories.tsx +++ b/web/src/components/ui/streaming/StreamingMessage_File.stories.tsx @@ -48,8 +48,7 @@ export const Default: Story = { args: { isSelectedFile: false, isCompletedStream: true, - responseMessage: mockResponseMessage, - onClick: fn() + responseMessage: mockResponseMessage } }; @@ -57,8 +56,7 @@ export const Selected: Story = { args: { isSelectedFile: true, isCompletedStream: true, - responseMessage: mockResponseMessage, - onClick: fn() + responseMessage: mockResponseMessage } }; @@ -66,8 +64,7 @@ export const Streaming: Story = { args: { isSelectedFile: false, isCompletedStream: false, - responseMessage: mockResponseMessage, - onClick: fn() + responseMessage: mockResponseMessage } }; @@ -78,7 +75,6 @@ export const LongFileName: Story = { responseMessage: { ...mockResponseMessage, file_name: 'very_long_file_name_that_should_truncate_in_the_ui.txt' - }, - onClick: fn() + } } }; diff --git a/web/src/components/ui/streaming/StreamingMessage_File.tsx b/web/src/components/ui/streaming/StreamingMessage_File.tsx index 1f2187bfe..efe5efa8c 100644 --- a/web/src/components/ui/streaming/StreamingMessage_File.tsx +++ b/web/src/components/ui/streaming/StreamingMessage_File.tsx @@ -12,10 +12,9 @@ import { cn } from '@/lib/classMerge'; export const StreamingMessage_File: React.FC<{ isSelectedFile: boolean; - onClick: () => void; responseMessage: BusterChatResponseMessage_file; isCompletedStream: boolean; -}> = React.memo(({ isCompletedStream, responseMessage, onClick, isSelectedFile }) => { +}> = React.memo(({ isCompletedStream, responseMessage, isSelectedFile }) => { const { file_name, version_number, @@ -28,7 +27,6 @@ export const StreamingMessage_File: React.FC<{ { const queryClient = useQueryClient(); @@ -62,7 +62,20 @@ export const useChatStreamMessage = () => { const queryKey = options.queryKey; queryClient.setQueryData(queryKey, message); chatRefMessages.current[message.id] = message; - prefetchGetMetricDataClient({ id: message.id }, queryClient); + } + } + ); + + const prefetchLastMessageMetricData = useMemoizedFn( + (iChat: IBusterChat, iChatMessages: Record) => { + const lastMessageId = iChat.message_ids[iChat.message_ids.length - 1]; + const lastMessage = iChatMessages[lastMessageId]; + if (lastMessage?.response_message_ids) { + Object.values(lastMessage.response_messages).forEach((responseMessage) => { + if (responseMessage.type === 'file' && responseMessage.file_type === 'metric') { + prefetchGetMetricDataClient({ id: responseMessage.id }, queryClient); + } + }); } } ); @@ -73,6 +86,7 @@ export const useChatStreamMessage = () => { normalizeChatMessage(iChatMessages); onUpdateChat(iChat); removeBlackBoxMessage({ messageId: iChat.message_ids[iChat.message_ids.length - 1] }); + prefetchLastMessageMetricData(iChat, iChatMessages); }); const stopChatCallback = useMemoizedFn((chatId: string) => { diff --git a/web/src/controllers/MetricController/MetricController.tsx b/web/src/controllers/MetricController/MetricController.tsx index 86f4d7ebc..3aa6f13d3 100644 --- a/web/src/controllers/MetricController/MetricController.tsx +++ b/web/src/controllers/MetricController/MetricController.tsx @@ -10,6 +10,11 @@ import { FileIndeterminateLoader } from '@/components/features/FileIndeterminate import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics'; import { MetricViewError } from './MetricViewError'; +/* +TODO: consider makiing this a server component that fetches the metric and metric data? +As long as we have a loading.tsx component that can handle the loading state, this should work? +*/ + export const MetricController: React.FC<{ metricId: string; }> = React.memo(({ metricId }) => { diff --git a/web/src/controllers/MetricController/MetricViewError/MetricViewError.tsx b/web/src/controllers/MetricController/MetricViewError/MetricViewError.tsx index f036ca39d..b602199ba 100644 --- a/web/src/controllers/MetricController/MetricViewError/MetricViewError.tsx +++ b/web/src/controllers/MetricController/MetricViewError/MetricViewError.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Text, Title } from '@/components/ui/typography'; import { StatusCard } from '@/components/ui/card/StatusCard'; export const MetricViewError: React.FC<{ error: string | undefined }> = ({ diff --git a/web/src/controllers/ReasoningController/ReasoningController.tsx b/web/src/controllers/ReasoningController/ReasoningController.tsx index eb93321f0..086f2cbb3 100644 --- a/web/src/controllers/ReasoningController/ReasoningController.tsx +++ b/web/src/controllers/ReasoningController/ReasoningController.tsx @@ -13,7 +13,6 @@ interface ReasoningControllerProps { export const ReasoningController: React.FC = ({ chatId, messageId }) => { const { data: hasChat } = useGetChat({ id: chatId || '' }, (x) => !!x.id); - const reasoningMessageIds = useGetChatMessage(messageId, (x) => x?.reasoning_message_ids); const isCompletedStream = useGetChatMessage(messageId, (x) => x?.isCompletedStream); diff --git a/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_Files/ReasoningFileButtons.tsx b/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_Files/ReasoningFileButtons.tsx index 539e954be..317d117f7 100644 --- a/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_Files/ReasoningFileButtons.tsx +++ b/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_Files/ReasoningFileButtons.tsx @@ -2,31 +2,46 @@ import type { FileType } from '@/api/asset_interfaces'; import { AppTooltip } from '@/components/ui/tooltip'; import { ArrowUpRight } from '@/components/ui/icons'; import { Button } from '@/components/ui/buttons'; -import React from 'react'; +import React, { useMemo } from 'react'; import { useChatLayoutContextSelector } from '@/layouts/ChatLayout/ChatLayoutContext'; import { useMemoizedFn } from '@/hooks'; +import Link from 'next/link'; +import { createChatAssetRoute } from '@/layouts/ChatLayout/ChatLayoutContext/helpers'; export const ReasoningFileButtons = React.memo( - ({ fileType, fileId, type }: { fileType: FileType; fileId: string; type: 'file' | 'status' }) => { - const onSetSelectedFile = useChatLayoutContextSelector((state) => state.onSetSelectedFile); - - const onOpenFile = useMemoizedFn((e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - onSetSelectedFile({ - id: fileId, + ({ + fileType, + fileId, + type, + chatId + }: { + fileType: FileType; + fileId: string; + type: 'file' | 'status'; + chatId: string; + }) => { + const href = useMemo(() => { + return createChatAssetRoute({ + chatId: chatId, + assetId: fileId, type: fileType }); - }); + }, [chatId, fileId, fileType]); if (type === 'status') return null; return ( -
- - - -
+ + { + e.preventDefault(); + e.stopPropagation(); + }}> + - + ); }; diff --git a/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessagePillsContainer.tsx b/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessagePillsContainer.tsx index 527b1aa7e..94492955a 100644 --- a/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessagePillsContainer.tsx +++ b/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessagePillsContainer.tsx @@ -32,8 +32,9 @@ export const ReasoningMessagePillsContainer: React.FC< BusterChatMessageReasoning_pills & { status: NonNullable; isCompletedStream: boolean; + chatId: string; } -> = ({ pill_containers, status, isCompletedStream }) => { +> = ({ pill_containers, status, isCompletedStream, chatId }) => { const hasPills = !!pill_containers && pill_containers.length > 0; if (!hasPills) return null; @@ -50,6 +51,7 @@ export const ReasoningMessagePillsContainer: React.FC< key={index} pillContainer={pill_container} isCompletedStream={isCompletedStream} + chatId={chatId} />
))} diff --git a/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessage_PillsContainer.tsx b/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessage_PillsContainer.tsx index 2369f75b2..775e5f4ae 100644 --- a/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessage_PillsContainer.tsx +++ b/web/src/controllers/ReasoningController/ReasoningMessages/ReasoningMessage_PillContainers/ReasoningMessage_PillsContainer.tsx @@ -5,7 +5,7 @@ import { useGetChatMessage } from '@/api/buster_rest/chats'; import { ReasoningMessagePillsContainer } from './ReasoningMessagePillsContainer'; export const ReasoningMessage_PillsContainer: React.FC = React.memo( - ({ reasoningMessageId, messageId, isCompletedStream }) => { + ({ reasoningMessageId, messageId, isCompletedStream, chatId }) => { const reasoningMessage = useGetChatMessage( messageId, (x) => x?.reasoning_messages[reasoningMessageId] @@ -19,6 +19,7 @@ export const ReasoningMessage_PillsContainer: React.FC = {...reasoningMessagePills} status={status} isCompletedStream={isCompletedStream} + chatId={chatId} /> ); } diff --git a/web/src/layouts/AppAssetCheckLayout.tsx b/web/src/layouts/AppAssetCheckLayout.tsx index 74b3c428f..98182b44d 100644 --- a/web/src/layouts/AppAssetCheckLayout.tsx +++ b/web/src/layouts/AppAssetCheckLayout.tsx @@ -1,10 +1,11 @@ +'use server'; + import React from 'react'; import { ShareAssetType } from '@/api/asset_interfaces'; import { AppPasswordAccess } from '@/controllers/AppPasswordAccess'; import { AppNoPageAccess } from '@/controllers/AppNoPageAccess'; import { prefetchAssetCheck } from '@/api/buster_rest/assets'; import { dehydrate, HydrationBoundary } from '@tanstack/react-query'; -import { queryKeys } from '@/api/query_keys'; export type AppAssetCheckLayoutProps = { assetId: string; diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessage_File/ChatResponseMessage_File.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessage_File/ChatResponseMessage_File.tsx index 79409c33d..83e0371a1 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessage_File/ChatResponseMessage_File.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessage_File/ChatResponseMessage_File.tsx @@ -55,13 +55,6 @@ export const ChatResponseMessage_File: React.FC = Reac return ''; }, [chatId, file_type, id]); - const onClick = useMemoizedFn(() => { - onSetSelectedFile({ - id, - type: file_type - }); - }); - useMount(() => { if (href) { router.prefetch(href); @@ -69,11 +62,10 @@ export const ChatResponseMessage_File: React.FC = Reac }); return ( - + onSetSelectedFile({ id, type: file_type })}> diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx index 43da023cb..97eac903b 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseMessages.tsx @@ -27,6 +27,7 @@ export const ChatResponseMessages: React.FC = React.m finalReasoningMessage={finalReasoningMessage} isCompletedStream={isCompletedStream} messageId={messageId} + chatId={chatId} /> {responseMessageIds.map((responseMessageId, index) => ( diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseReasoning.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseReasoning.tsx index 501cc1a2c..87198cb85 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseReasoning.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatResponseMessages/ChatResponseReasoning.tsx @@ -10,6 +10,8 @@ import { useChatLayoutContextSelector } from '../../../ChatLayoutContext'; import { useGetChatMessage } from '@/api/buster_rest/chats'; import { useQuery } from '@tanstack/react-query'; import { queryKeys } from '@/api/query_keys'; +import Link from 'next/link'; +import { BusterRoutes, createBusterRoute } from '@/routes'; const animations = { initial: { opacity: 0 }, @@ -23,7 +25,8 @@ export const ChatResponseReasoning: React.FC<{ finalReasoningMessage: string | undefined | null; isCompletedStream: boolean; messageId: string; -}> = React.memo(({ reasoningMessageId, isCompletedStream, messageId }) => { + chatId: string; +}> = React.memo(({ reasoningMessageId, isCompletedStream, messageId, chatId }) => { const lastMessageTitle = useGetChatMessage( messageId, (x) => x?.reasoning_messages?.[reasoningMessageId ?? '']?.title @@ -46,29 +49,31 @@ export const ChatResponseReasoning: React.FC<{ return lastMessageTitle || 'Thinking...'; }, [lastMessageTitle, finalReasoningMessage, blackBoxMessage]); - const onClickReasoning = useMemoizedFn(() => { - onSetSelectedFile({ - type: 'reasoning', - id: messageId + const href = useMemo(() => { + return createBusterRoute({ + route: BusterRoutes.APP_CHAT_ID_REASONING_ID, + messageId, + chatId }); - }); + }, [isReasonginFileSelected, messageId]); return ( - - - {!showShimmerText ? ( - - {text} - - ) : ( - - )} - - + + + + {!showShimmerText ? ( + + {text} + + ) : ( + + )} + + + ); }); diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx index 13a519942..20779565e 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatHeader/ChatHeaderOptions/ChatHeaderDropdown.tsx @@ -28,7 +28,7 @@ export const ChatContainerHeaderDropdown: React.FC<{ chatId && deleteChat([chatId], { onSuccess: () => { - onChangePage(createBusterRoute({ route: BusterRoutes.APP_CHAT })); + onChangePage({ route: BusterRoutes.APP_CHAT }); } }) }, diff --git a/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx b/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx index 6435552ec..c541762b9 100644 --- a/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx +++ b/web/src/layouts/ChatLayout/ChatContext/ChatContext.tsx @@ -50,7 +50,8 @@ const useChatIndividualContext = ({ useAutoChangeLayout({ lastMessageId: currentMessageId, onSetSelectedFile, - selectedFileId + selectedFileId, + chatId }); return React.useMemo( diff --git a/web/src/layouts/ChatLayout/ChatContext/useAutoChangeLayout.ts b/web/src/layouts/ChatLayout/ChatContext/useAutoChangeLayout.ts index c6299dcc7..4328e8ae5 100644 --- a/web/src/layouts/ChatLayout/ChatContext/useAutoChangeLayout.ts +++ b/web/src/layouts/ChatLayout/ChatContext/useAutoChangeLayout.ts @@ -5,15 +5,19 @@ import type { SelectedFile } from '../interfaces'; import { useEffect, useRef } from 'react'; import findLast from 'lodash/findLast'; import { BusterChatResponseMessage_file } from '@/api/asset_interfaces/chat'; +import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; +import { BusterRoutes } from '@/routes'; export const useAutoChangeLayout = ({ lastMessageId, onSetSelectedFile, - selectedFileId + selectedFileId, + chatId }: { lastMessageId: string; onSetSelectedFile: (file: SelectedFile) => void; selectedFileId: string | undefined; + chatId: string | undefined; }) => { const previousLastMessageId = useRef(null); const reasoningMessagesLength = useGetChatMessage( @@ -27,9 +31,12 @@ export const useAutoChangeLayout = ({ //change the page to reasoning file if we get a reasoning message useEffect(() => { - // console.log(isCompletedStream, hasReasoning, lastMessageId, previousLastMessageId.current); - if (!isCompletedStream && hasReasoning && previousLastMessageId.current !== lastMessageId) { - // hasSeeningReasoningPage.current = true; + if ( + !isCompletedStream && + hasReasoning && + previousLastMessageId.current !== lastMessageId && + chatId + ) { onSetSelectedFile({ id: lastMessageId, type: 'reasoning' }); previousLastMessageId.current = lastMessageId; } @@ -48,5 +55,5 @@ export const useAutoChangeLayout = ({ onSetSelectedFile({ id: lastFileId, type: lastFile.file_type }); } } - }, [isCompletedStream, hasReasoning, lastMessageId]); + }, [isCompletedStream, chatId, hasReasoning, lastMessageId]); }; diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/helpers.ts b/web/src/layouts/ChatLayout/ChatLayoutContext/helpers.ts index 8a6c72aca..054dee7cc 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/helpers.ts +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/helpers.ts @@ -57,6 +57,6 @@ export const createChatAssetRoute = ({ type: FileType; }) => { const routeBuilder = chatRouteRecord[type]; - if (!routeBuilder) return ''; + if (!routeBuilder) return null; return routeBuilder(chatId, assetId); }; diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts b/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts index 535fa5c70..c32850f74 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts @@ -6,6 +6,9 @@ import { useMemoizedFn } from '@/hooks'; import { createSelectedFile } from './createSelectedFile'; import type { useGetChatParams } from '../useGetChatParams'; import type { AppSplitterRef } from '@/components/ui/layouts/AppSplitter'; +import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; +import { BusterRoutes, createBusterRoute } from '@/routes'; +import { createChatAssetRoute } from '../helpers'; export const useSelectedFile = ({ animateOpenSplitter, @@ -17,6 +20,7 @@ export const useSelectedFile = ({ chatParams: ReturnType; }) => { const { metricVersionNumber, dashboardVersionNumber } = chatParams; + const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage); const selectedFile: SelectedFile | null = useMemo(() => { return createSelectedFile(chatParams); @@ -29,13 +33,24 @@ export const useSelectedFile = ({ }, [selectedFile?.type, metricVersionNumber, dashboardVersionNumber]); /** - * @description Opens the splitter if the file is not already open. If the file is already open, it will collapse the splitter. This does NOT set the selected file. You should do that with a Link + * @description Opens the splitter if the file is not already open. + * If the file is already open, it will collapse the splitter. + * You should do try to set the selected file with a Link! * @param file */ const onSetSelectedFile = useMemoizedFn(async (file: SelectedFile | null) => { const handleFileCollapse = !file || (file?.id === selectedFile?.id && !appSplitterRef.current?.isSideClosed('right')); + if (file && chatParams.chatId) { + const link = createChatAssetRoute({ + chatId: chatParams.chatId, + assetId: file?.id, + type: file?.type + }); + if (link) onChangePage(link); + } + if (handleFileCollapse) { animateOpenSplitter('left'); return; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx index adcd26050..f26510de0 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx @@ -90,7 +90,7 @@ export const FileContainer: React.FC = ({ children }) => { ), [] )} - headerClassName="border-l"> + headerClassName=""> , onClick: async () => { await deleteDashboard({ dashboardId }); - onChangePage(createBusterRoute({ route: BusterRoutes.APP_DASHBOARDS })); + onChangePage({ route: BusterRoutes.APP_DASHBOARDS }); } }), [dashboardId]