Merge pull request #1237 from buster-so/big-nate-bus-1988-view-only-chat-ui

Big nate bus 1988 view only chat UI
This commit is contained in:
Nate Kelley 2025-10-01 15:48:07 -06:00 committed by GitHub
commit a33477a093
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 834 additions and 725 deletions

View File

@ -158,13 +158,19 @@ const useCheckIfWeHaveAFollowupDashboard = (messageId: string) => {
return useMemoizedFn(method); return useMemoizedFn(method);
}; };
export const useTrackAndUpdateNewMessages = ({ chatId }: { chatId: string | undefined }) => { export const useTrackAndUpdateNewMessages = ({
chatId,
isEmbed,
}: {
chatId: string | undefined;
isEmbed: boolean;
}) => {
const { onUpdateChat } = useChatUpdate(); const { onUpdateChat } = useChatUpdate();
const getChatMemoized = useGetChatMemoized(); const getChatMemoized = useGetChatMemoized();
const getChatMessageMemoized = useGetChatMessageMemoized(); const getChatMessageMemoized = useGetChatMessageMemoized();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const subscribe = !!chatId; const subscribe = !!chatId && !isEmbed;
const shape = useMemo(() => { const shape = useMemo(() => {
return messagesShape({ chatId: chatId || '', columns: ['id'] }); return messagesShape({ chatId: chatId || '', columns: ['id'] });

View File

@ -3,11 +3,11 @@ import { SelectableButton } from '@/components/ui/buttons/SelectableButton';
import { useGetChatId } from '@/context/Chats/useGetChatId'; import { useGetChatId } from '@/context/Chats/useGetChatId';
import { Xmark } from '../../ui/icons'; import { Xmark } from '../../ui/icons';
export const ClosePageButton = () => { export const ClosePageButton = ({ isEmbed }: { isEmbed: boolean }) => {
const chatId = useGetChatId() || ''; const chatId = useGetChatId() || '';
return ( return (
<Link to="/app/chats/$chatId" params={{ chatId }}> <Link to={isEmbed ? '/embed/chat/$chatId' : '/app/chats/$chatId'} params={{ chatId }}>
<SelectableButton selected={false} tooltipText="Close" icon={<Xmark />} /> <SelectableButton selected={false} tooltipText="Close" icon={<Xmark />} />
</Link> </Link>
); );

View File

@ -4,7 +4,7 @@ import { Card, CardContent, CardFooter } from '@/components/ui/card/CardBase';
// Displays a full-screen, visually polished 404 not found state // Displays a full-screen, visually polished 404 not found state
// inspired by GlobalErrorCard with consistent styling and components. // inspired by GlobalErrorCard with consistent styling and components.
export const NotFoundCard: NotFoundRouteComponent = () => { export const NotFoundCard = () => {
return ( return (
<section <section
className="flex flex-col items-center z-[999] absolute inset-0 top-0 left-0 right-0 bottom-0 justify-center h-full w-full p-8 bg-background" className="flex flex-col items-center z-[999] absolute inset-0 top-0 left-0 right-0 bottom-0 justify-center h-full w-full p-8 bg-background"

View File

@ -1,23 +1,23 @@
import { createFileRoute } from '@tanstack/react-router';
import { ClosePageButton } from '@/components/features/chat/ClosePageButton'; import { ClosePageButton } from '@/components/features/chat/ClosePageButton';
import { AppSegmented } from '@/components/ui/segmented'; import { AppSegmented } from '@/components/ui/segmented';
import { ReasoningController } from '@/controllers/ReasoningController/ReasoningController'; import { useGetChatId } from '@/context/Chats/useGetChatId';
import { ReasoningController } from '@/controllers/ReasoningController';
import { AssetContainer } from '@/layouts/AssetContainer/AssetContainer'; import { AssetContainer } from '@/layouts/AssetContainer/AssetContainer';
import { useGetReasoningMessageId } from '../useGetReasoningMessageId';
import { useIsEmbed } from '../useIsEmbed';
export const Route = createFileRoute('/embed/chats/$chatId/reasoning/$messageId/')({ export const component = () => {
component: RouteComponent, const chatId = useGetChatId() || '';
}); const messageId = useGetReasoningMessageId() || '';
function RouteComponent() {
const { chatId, messageId } = Route.useParams();
return ( return (
<AssetContainer header={<ReasoningControllerHeader />} headerBorderVariant="ghost" scrollable> <AssetContainer header={<ReasoningControllerHeader />} headerBorderVariant="ghost" scrollable>
<ReasoningController chatId={chatId} messageId={messageId} /> <ReasoningController chatId={chatId} messageId={messageId} />
</AssetContainer> </AssetContainer>
); );
} };
const ReasoningControllerHeader: React.FC = () => { const ReasoningControllerHeader: React.FC = () => {
const isEmbed = useIsEmbed();
return ( return (
<div className="w-full flex items-center justify-between"> <div className="w-full flex items-center justify-between">
<AppSegmented <AppSegmented
@ -29,7 +29,7 @@ const ReasoningControllerHeader: React.FC = () => {
}, },
]} ]}
/> />
<ClosePageButton /> <ClosePageButton isEmbed={isEmbed} />
</div> </div>
); );
}; };

View File

@ -0,0 +1,6 @@
import { useParams } from '@tanstack/react-router';
export const useGetReasoningMessageId = () => {
const params = useParams({ strict: false });
return params?.messageId;
};

View File

@ -0,0 +1,11 @@
import { useMatchRoute } from '@tanstack/react-router';
import { Route as EmbedRoute } from '@/routes/embed';
export const useIsEmbed = () => {
const matchRoute = useMatchRoute();
const matches = matchRoute({
to: EmbedRoute.id,
fuzzy: true,
});
return !!matches;
};

View File

@ -1,10 +1,24 @@
import { getRouteApi, type RouteContext, useParams, useSearch } from '@tanstack/react-router'; import type { AssetType } from '@buster/server-shared/assets';
import {
type StaticDataRouteOption,
useMatches,
useParams,
useSearch,
} from '@tanstack/react-router';
import findLast from 'lodash/findLast';
const assetRouteApi = getRouteApi('/app/_app/_asset'); export const useSelectedAssetType = (): NonNullable<StaticDataRouteOption['assetType']> => {
const lastMatch = useMatches({
select: (matches) => {
return findLast(matches, (match) => match.staticData?.assetType);
},
});
const stableCtxSelector = (ctx: RouteContext) => ctx.assetType; if (typeof lastMatch === 'number') {
export const useSelectedAssetType = () => { return 'chat';
const data = assetRouteApi.useRouteContext({ select: stableCtxSelector }); }
// @ts-expect-error - lastMatch is not undefined
const data = lastMatch?.staticData?.assetType as StaticDataRouteOption['assetType'];
const { messageId } = useParams({ const { messageId } = useParams({
strict: false, strict: false,
}); });

View File

@ -5,6 +5,7 @@ import { CreateChatButton } from '@/components/features/AssetLayout/CreateChatBu
import { ShareDashboardButton } from '@/components/features/buttons/ShareDashboardButton'; import { ShareDashboardButton } from '@/components/features/buttons/ShareDashboardButton';
import { ClosePageButton } from '@/components/features/chat/ClosePageButton'; import { ClosePageButton } from '@/components/features/chat/ClosePageButton';
import { DashboardThreeDotMenu } from '@/components/features/dashboard/DashboardThreeDotMenu'; import { DashboardThreeDotMenu } from '@/components/features/dashboard/DashboardThreeDotMenu';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { useIsChatMode, useIsFileMode } from '@/context/Chats/useMode'; import { useIsChatMode, useIsFileMode } from '@/context/Chats/useMode';
import { useIsDashboardReadOnly } from '@/context/Dashboards/useIsDashboardReadOnly'; import { useIsDashboardReadOnly } from '@/context/Dashboards/useIsDashboardReadOnly';
import { canEdit, getIsEffectiveOwner } from '@/lib/share'; import { canEdit, getIsEffectiveOwner } from '@/lib/share';
@ -17,6 +18,7 @@ export const DashboardContainerHeaderButtons: React.FC<{
}> = React.memo(({ dashboardId, dashboardVersionNumber }) => { }> = React.memo(({ dashboardId, dashboardVersionNumber }) => {
const isChatMode = useIsChatMode(); const isChatMode = useIsChatMode();
const isFileMode = useIsFileMode(); const isFileMode = useIsFileMode();
const isEmbed = useIsEmbed();
const { isViewingOldVersion } = useIsDashboardReadOnly({ const { isViewingOldVersion } = useIsDashboardReadOnly({
dashboardId: dashboardId || '', dashboardId: dashboardId || '',
}); });
@ -36,15 +38,17 @@ export const DashboardContainerHeaderButtons: React.FC<{
dashboardVersionNumber={dashboardVersionNumber} dashboardVersionNumber={dashboardVersionNumber}
/> />
)} )}
<DashboardThreeDotMenu {!isEmbed && (
dashboardId={dashboardId} <DashboardThreeDotMenu
isViewingOldVersion={isViewingOldVersion} dashboardId={dashboardId}
dashboardVersionNumber={dashboardVersionNumber} isViewingOldVersion={isViewingOldVersion}
/> dashboardVersionNumber={dashboardVersionNumber}
/>
)}
<HideButtonContainer show={isFileMode && isEditor}> <HideButtonContainer show={isFileMode && isEditor}>
<CreateChatButton assetId={dashboardId} assetType="dashboard_file" /> <CreateChatButton assetId={dashboardId} assetType="dashboard_file" />
</HideButtonContainer> </HideButtonContainer>
{isChatMode && <ClosePageButton />} {isChatMode && <ClosePageButton isEmbed={isEmbed} />}
</FileButtonContainer> </FileButtonContainer>
); );
}); });

View File

@ -9,6 +9,7 @@ import { ClosePageButton } from '@/components/features/chat/ClosePageButton';
import { MetricThreeDotMenuButton } from '@/components/features/metrics/MetricThreeDotMenu'; import { MetricThreeDotMenuButton } from '@/components/features/metrics/MetricThreeDotMenu';
import { SelectableButton } from '@/components/ui/buttons/SelectableButton'; import { SelectableButton } from '@/components/ui/buttons/SelectableButton';
import { SquareChartPen } from '@/components/ui/icons'; import { SquareChartPen } from '@/components/ui/icons';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { useIsChatMode, useIsFileMode } from '@/context/Chats/useMode'; import { useIsChatMode, useIsFileMode } from '@/context/Chats/useMode';
import { useIsMetricReadOnly } from '@/context/Metrics/useIsMetricReadOnly'; import { useIsMetricReadOnly } from '@/context/Metrics/useIsMetricReadOnly';
import { canEdit, getIsEffectiveOwner } from '@/lib/share'; import { canEdit, getIsEffectiveOwner } from '@/lib/share';
@ -22,6 +23,7 @@ export const MetricContainerHeaderButtons: React.FC<{
}> = React.memo(({ metricId, metricVersionNumber }) => { }> = React.memo(({ metricId, metricVersionNumber }) => {
const isChatMode = useIsChatMode(); const isChatMode = useIsChatMode();
const isFileMode = useIsFileMode(); const isFileMode = useIsFileMode();
const isEmbed = useIsEmbed();
const { isViewingOldVersion } = useIsMetricReadOnly({ const { isViewingOldVersion } = useIsMetricReadOnly({
metricId: metricId || '', metricId: metricId || '',
}); });
@ -42,15 +44,17 @@ export const MetricContainerHeaderButtons: React.FC<{
{isEffectiveOwner && !isViewingOldVersion && ( {isEffectiveOwner && !isViewingOldVersion && (
<ShareMetricButton metricId={metricId} metricVersionNumber={metricVersionNumber} /> <ShareMetricButton metricId={metricId} metricVersionNumber={metricVersionNumber} />
)} )}
<MetricThreeDotMenuButton {!isEmbed && (
metricId={metricId} <MetricThreeDotMenuButton
isViewingOldVersion={isViewingOldVersion} metricId={metricId}
versionNumber={metricVersionNumber} isViewingOldVersion={isViewingOldVersion}
/> versionNumber={metricVersionNumber}
/>
)}
<HideButtonContainer show={isFileMode && isEditor}> <HideButtonContainer show={isFileMode && isEditor}>
<CreateChatButton assetId={metricId} assetType="metric_file" /> <CreateChatButton assetId={metricId} assetType="metric_file" />
</HideButtonContainer> </HideButtonContainer>
{isChatMode && <ClosePageButton />} {isChatMode && <ClosePageButton isEmbed={isEmbed} />}
</FileButtonContainer> </FileButtonContainer>
); );
}); });

View File

@ -6,6 +6,7 @@ import { CreateChatButton } from '@/components/features/AssetLayout/CreateChatBu
import { ShareReportButton } from '@/components/features/buttons/ShareReportButton'; import { ShareReportButton } from '@/components/features/buttons/ShareReportButton';
import { ClosePageButton } from '@/components/features/chat/ClosePageButton'; import { ClosePageButton } from '@/components/features/chat/ClosePageButton';
import { ReportThreeDotMenu } from '@/components/features/reports/ReportThreeDotMenu'; import { ReportThreeDotMenu } from '@/components/features/reports/ReportThreeDotMenu';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { useIsChatMode, useIsFileMode } from '@/context/Chats/useMode'; import { useIsChatMode, useIsFileMode } from '@/context/Chats/useMode';
import { useIsReportReadOnly } from '@/context/Reports/useIsReportReadOnly'; import { useIsReportReadOnly } from '@/context/Reports/useIsReportReadOnly';
import { canEdit, getIsEffectiveOwner } from '@/lib/share'; import { canEdit, getIsEffectiveOwner } from '@/lib/share';
@ -23,6 +24,7 @@ export const ReportContainerHeaderButtons: React.FC<ReportContainerHeaderButtons
}) => { }) => {
const isChatMode = useIsChatMode(); const isChatMode = useIsChatMode();
const isFileMode = useIsFileMode(); const isFileMode = useIsFileMode();
const isEmbed = useIsEmbed();
const { isViewingOldVersion } = useIsReportReadOnly({ const { isViewingOldVersion } = useIsReportReadOnly({
reportId: reportId || '', reportId: reportId || '',
}); });
@ -38,16 +40,18 @@ export const ReportContainerHeaderButtons: React.FC<ReportContainerHeaderButtons
<FileButtonContainer> <FileButtonContainer>
{isEffectiveOwner && <ShareReportButton reportId={reportId} />} {isEffectiveOwner && <ShareReportButton reportId={reportId} />}
<ReportThreeDotMenu {!isEmbed && (
reportId={reportId} <ReportThreeDotMenu
reportVersionNumber={reportVersionNumber} reportId={reportId}
isViewingOldVersion={isViewingOldVersion} reportVersionNumber={reportVersionNumber}
/> isViewingOldVersion={isViewingOldVersion}
/>
)}
<HideButtonContainer show={isFileMode && isEditor}> <HideButtonContainer show={isFileMode && isEditor}>
<CreateChatButton assetId={reportId} assetType="report_file" /> <CreateChatButton assetId={reportId} assetType="report_file" />
</HideButtonContainer> </HideButtonContainer>
{isChatMode && <ClosePageButton />} {isChatMode && <ClosePageButton isEmbed={isEmbed} />}
</FileButtonContainer> </FileButtonContainer>
); );
}; };

View File

@ -5,21 +5,23 @@ import { ChatHeader } from './ChatHeader';
export const CHAT_CONTAINER_ID = 'chat-container-content'; export const CHAT_CONTAINER_ID = 'chat-container-content';
export const ChatContainer = React.memo(({ chatId }: { chatId: string | undefined }) => { export const ChatContainer = React.memo(
return ( ({ chatId, isEmbed }: { chatId: string | undefined; isEmbed: boolean }) => {
<AppPageLayout return (
headerSizeVariant="default" <AppPageLayout
header={<ChatHeader />} headerSizeVariant="default"
headerBorderVariant="ghost" header={<ChatHeader isEmbed={isEmbed} />}
headerClassName="bg-page-background" headerBorderVariant="ghost"
mainClassName="bg-page-background" headerClassName="bg-page-background"
scrollable mainClassName="bg-page-background"
id={CHAT_CONTAINER_ID} scrollable
className="flex h-full w-full min-w-[295px] flex-col" id={CHAT_CONTAINER_ID}
> className="flex h-full w-full min-w-[295px] flex-col"
<ChatContent chatId={chatId} /> >
</AppPageLayout> <ChatContent chatId={chatId} isEmbed={isEmbed} />
); </AppPageLayout>
}); );
}
);
ChatContainer.displayName = 'ChatContainer'; ChatContainer.displayName = 'ChatContainer';

View File

@ -12,61 +12,65 @@ import { FollowUpChatInput } from './FollowupChatInput';
const autoClass = 'mx-auto max-w-[600px] w-full'; const autoClass = 'mx-auto max-w-[600px] w-full';
export const ChatContent: React.FC<{ chatId: string | undefined }> = React.memo(({ chatId }) => { export const ChatContent: React.FC<{ chatId: string | undefined; isEmbed: boolean }> = React.memo(
const chatMessageIds = useGetChatMessageIds(chatId); ({ chatId, isEmbed }) => {
const containerRef = useRef<HTMLElement>(null); const chatMessageIds = useGetChatMessageIds(chatId);
const containerRef = useRef<HTMLElement>(null);
const { isAutoScrollEnabled, isMountedAutoScrollObserver, scrollToBottom, enableAutoScroll } = const { isAutoScrollEnabled, isMountedAutoScrollObserver, scrollToBottom, enableAutoScroll } =
useAutoScroll(containerRef, { useAutoScroll(containerRef, {
observeSubTree: true, observeSubTree: true,
enabled: false, enabled: false,
});
useMount(() => {
const container = document
.getElementById(CHAT_CONTAINER_ID)
?.querySelector(`.${SCROLL_AREA_VIEWPORT_CLASS}`) as HTMLElement;
if (!container) return;
containerRef.current = container;
enableAutoScroll();
}); });
useMount(() => { const showScrollToBottomButton = isMountedAutoScrollObserver && containerRef.current;
const container = document
.getElementById(CHAT_CONTAINER_ID)
?.querySelector(`.${SCROLL_AREA_VIEWPORT_CLASS}`) as HTMLElement;
if (!container) return;
containerRef.current = container;
enableAutoScroll();
});
const showScrollToBottomButton = isMountedAutoScrollObserver && containerRef.current; return (
<>
<div
className={cn(
'mb-48 flex h-full w-full flex-col',
!isMountedAutoScrollObserver && 'invisible'
)}
>
<ClientOnly>
{chatMessageIds?.map((messageId, index) => (
<div key={messageId} className={autoClass}>
<ChatMessageBlock
key={messageId}
messageId={messageId}
chatId={chatId || ''}
messageIndex={index}
/>
</div>
))}
</ClientOnly>
</div>
return ( {!isEmbed && (
<> <ChatInputWrapper>
<div {showScrollToBottomButton && (
className={cn( <ScrollToBottomButton
'mb-48 flex h-full w-full flex-col', isAutoScrollEnabled={isAutoScrollEnabled}
!isMountedAutoScrollObserver && 'invisible' scrollToBottom={scrollToBottom}
)} className={'absolute -top-10'}
>
<ClientOnly>
{chatMessageIds?.map((messageId, index) => (
<div key={messageId} className={autoClass}>
<ChatMessageBlock
key={messageId}
messageId={messageId}
chatId={chatId || ''}
messageIndex={index}
/> />
</div> )}
))} </ChatInputWrapper>
</ClientOnly>
</div>
<ChatInputWrapper>
{showScrollToBottomButton && (
<ScrollToBottomButton
isAutoScrollEnabled={isAutoScrollEnabled}
scrollToBottom={scrollToBottom}
className={'absolute -top-10'}
/>
)} )}
</ChatInputWrapper> </>
</> );
); }
}); );
ChatContent.displayName = 'ChatContent'; ChatContent.displayName = 'ChatContent';

View File

@ -89,18 +89,20 @@ export const ChatMessageOptions: React.FC<{
/> />
</AppTooltip> </AppTooltip>
)} )}
<AppTooltip title="Report message"> {canEditChat && (
<Button <AppTooltip title="Report message">
variant="ghost" <Button
prefix={feedback === 'negative' ? <ThumbsDownFilled /> : <ThumbsDown />} variant="ghost"
onClick={() => prefix={feedback === 'negative' ? <ThumbsDownFilled /> : <ThumbsDown />}
updateChatMessageFeedback({ onClick={() =>
message_id: messageId, updateChatMessageFeedback({
feedback: feedback === 'negative' ? null : 'negative', message_id: messageId,
}) feedback: feedback === 'negative' ? null : 'negative',
} })
/> }
</AppTooltip> />
</AppTooltip>
)}
{postProcessingMessage && ( {postProcessingMessage && (
<AppTooltip title="View assumptions"> <AppTooltip title="View assumptions">

View File

@ -1,6 +1,7 @@
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import type { BusterChatMessage, BusterChatResponseMessage_file } from '@/api/asset_interfaces'; import type { BusterChatMessage, BusterChatResponseMessage_file } from '@/api/asset_interfaces';
import { useGetChatMessage } from '@/api/buster_rest/chats'; import { useGetChatMessage } from '@/api/buster_rest/chats';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { createChatAssetRoute } from '@/lib/routes/createSimpleAssetRoute'; import { createChatAssetRoute } from '@/lib/routes/createSimpleAssetRoute';
import type { ILinkProps } from '@/types/routes'; import type { ILinkProps } from '@/types/routes';
import type { ChatResponseMessageProps } from '../ChatResponseMessageSelector'; import type { ChatResponseMessageProps } from '../ChatResponseMessageSelector';
@ -21,12 +22,14 @@ export const ChatResponseMessage_File: React.FC<ChatResponseMessageProps> = Reac
const { file_type } = responseMessage; const { file_type } = responseMessage;
const { isSelectedFile } = useGetIsSelectedFile({ responseMessage }); const { isSelectedFile } = useGetIsSelectedFile({ responseMessage });
const isEmbed = useIsEmbed();
const linkParams = createChatAssetRoute({ const linkParams = createChatAssetRoute({
asset_type: file_type, asset_type: file_type,
id: responseMessage.id, id: responseMessage.id,
chatId, chatId,
versionNumber: responseMessage.version_number, versionNumber: responseMessage.version_number,
isEmbed,
}) as unknown as ILinkProps; }) as unknown as ILinkProps;
const SelectedComponent = useMemo(() => { const SelectedComponent = useMemo(() => {

View File

@ -7,6 +7,7 @@ import { Text } from '@/components/ui/typography';
import { ShimmerText } from '@/components/ui/typography/ShimmerText'; import { ShimmerText } from '@/components/ui/typography/ShimmerText';
import { useGetBlackBoxMessage } from '@/context/BlackBox/blackbox-store'; import { useGetBlackBoxMessage } from '@/context/BlackBox/blackbox-store';
import { BLACK_BOX_INITIAL_THOUGHT } from '@/context/BlackBox/useBlackboxMessage'; import { BLACK_BOX_INITIAL_THOUGHT } from '@/context/BlackBox/useBlackboxMessage';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { useSelectedAssetType } from '@/context/BusterAssets/useSelectedAssetType'; import { useSelectedAssetType } from '@/context/BusterAssets/useSelectedAssetType';
import { useGetCurrentMessageId } from '@/context/Chats'; import { useGetCurrentMessageId } from '@/context/Chats';
@ -31,6 +32,7 @@ export const ChatResponseReasoning: React.FC<{
const { data: lastMessageTitle } = useGetChatMessage(messageId, { const { data: lastMessageTitle } = useGetChatMessage(messageId, {
select: stableLastMessageTitleSelector, select: stableLastMessageTitleSelector,
}); });
const isEmbed = useIsEmbed();
const selectedFileType = useSelectedAssetType(); const selectedFileType = useSelectedAssetType();
const isReasonginFileSelected = selectedFileType === 'reasoning' && urlMessageId === messageId; const isReasonginFileSelected = selectedFileType === 'reasoning' && urlMessageId === messageId;
const showShimmerText = isReasonginFileSelected const showShimmerText = isReasonginFileSelected
@ -49,7 +51,11 @@ export const ChatResponseReasoning: React.FC<{
return ( return (
<Link <Link
to={ to={
isReasonginFileSelected ? '/app/chats/$chatId' : '/app/chats/$chatId/reasoning/$messageId' isEmbed
? '/embed/chat/$chatId/reasoning/$messageId'
: isReasonginFileSelected
? '/app/chats/$chatId'
: '/app/chats/$chatId/reasoning/$messageId'
} }
params={{ params={{
chatId, chatId,

View File

@ -4,7 +4,7 @@ import { ChatHeaderTitle } from '@/components/features/chat/ChatHeaderTitle';
import { useGetActiveChatTitle, useIsStreamingMessage } from '@/context/Chats'; import { useGetActiveChatTitle, useIsStreamingMessage } from '@/context/Chats';
import { useGetChatId } from '@/context/Chats/useGetChatId'; import { useGetChatId } from '@/context/Chats/useGetChatId';
export const ChatHeader: React.FC = React.memo(() => { export const ChatHeader: React.FC<{ isEmbed: boolean }> = React.memo(({ isEmbed }) => {
const chatId = useGetChatId(); const chatId = useGetChatId();
const chatTitle = useGetActiveChatTitle(); const chatTitle = useGetActiveChatTitle();
const isStreamingMessage = useIsStreamingMessage(); const isStreamingMessage = useIsStreamingMessage();
@ -16,7 +16,7 @@ export const ChatHeader: React.FC = React.memo(() => {
chatId={chatId || ''} chatId={chatId || ''}
isStreamingMessage={isStreamingMessage} isStreamingMessage={isStreamingMessage}
/> />
<ChatHeaderOptions /> {!isEmbed && <ChatHeaderOptions />}
</> </>
); );
}); });

View File

@ -5,6 +5,7 @@ import {
type AppSplitterRef, type AppSplitterRef,
type LayoutSize, type LayoutSize,
} from '@/components/ui/layouts/AppSplitter'; } from '@/components/ui/layouts/AppSplitter';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { useGetCurrentMessageId, useIsStreamingMessage } from '@/context/Chats'; import { useGetCurrentMessageId, useIsStreamingMessage } from '@/context/Chats';
import { useGetChatId } from '@/context/Chats/useGetChatId'; import { useGetChatId } from '@/context/Chats/useGetChatId';
import type { LayoutMode } from '@/layouts/ChatLayout/config'; import type { LayoutMode } from '@/layouts/ChatLayout/config';
@ -38,6 +39,7 @@ export const ChatLayout: React.FC<ChatSplitterProps> = ({
const selectedAssetId = useSelectedAssetId(); const selectedAssetId = useSelectedAssetId();
const currentMessageId = useGetCurrentMessageId() || ''; const currentMessageId = useGetCurrentMessageId() || '';
const chatId = useGetChatId(); const chatId = useGetChatId();
const isEmbed = useIsEmbed();
const isStreamingMessage = useIsStreamingMessage(); const isStreamingMessage = useIsStreamingMessage();
const leftPanelMinSize = selectedAssetId ? DEFAULT_CHAT_OPTION_SIDEBAR_SIZE : '0px'; const leftPanelMinSize = selectedAssetId ? DEFAULT_CHAT_OPTION_SIDEBAR_SIZE : '0px';
@ -57,7 +59,7 @@ export const ChatLayout: React.FC<ChatSplitterProps> = ({
return ( return (
<AppSplitter <AppSplitter
ref={appSplitterRef} ref={appSplitterRef}
leftChildren={renderLeftPanel && <ChatContainer chatId={chatId} />} leftChildren={renderLeftPanel && <ChatContainer chatId={chatId} isEmbed={isEmbed} />}
rightChildren={renderRightPanel && children} rightChildren={renderRightPanel && children}
autoSaveId={autoSaveId} autoSaveId={autoSaveId}
defaultLayout={defaultLayout} defaultLayout={defaultLayout}

View File

@ -11,6 +11,7 @@ import {
import { chatQueryKeys } from '@/api/query_keys/chat'; import { chatQueryKeys } from '@/api/query_keys/chat';
import { metricsQueryKeys } from '@/api/query_keys/metric'; import { metricsQueryKeys } from '@/api/query_keys/metric';
import { useBlackboxMessage } from '@/context/BlackBox/useBlackboxMessage'; import { useBlackboxMessage } from '@/context/BlackBox/useBlackboxMessage';
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
import { useMemoizedFn } from '@/hooks/useMemoizedFn'; import { useMemoizedFn } from '@/hooks/useMemoizedFn';
import { updateChatToIChat } from '@/lib/chat'; import { updateChatToIChat } from '@/lib/chat';
@ -105,8 +106,9 @@ export const useChatStreaming = ({
}); });
//HOOKS FOR TRACKING CHAT AND MESSAGE CHANGES //HOOKS FOR TRACKING CHAT AND MESSAGE CHANGES
const isEmbed = useIsEmbed();
useTrackAndUpdateChatChanges({ chatId, isStreamingMessage }); useTrackAndUpdateChatChanges({ chatId, isStreamingMessage });
useTrackAndUpdateNewMessages({ chatId }); useTrackAndUpdateNewMessages({ chatId, isEmbed });
useTrackAndUpdateMessageChanges({ chatId, messageId, isStreamingMessage }, (c) => { useTrackAndUpdateMessageChanges({ chatId, messageId, isStreamingMessage }, (c) => {
const { const {
reasoning_messages, reasoning_messages,

View File

@ -59,8 +59,16 @@ export const createChatAssetRoute = (asset: {
id: string | undefined; id: string | undefined;
chatId: string; chatId: string;
versionNumber?: number; versionNumber?: number;
isEmbed: boolean;
}) => { }) => {
if (asset.asset_type === 'chat' || !asset.asset_type || !asset.id) { if (asset.asset_type === 'chat' || !asset.asset_type || !asset.id) {
if (asset.isEmbed) {
return defineLink({
to: '/embed/chat/$chatId',
params: { chatId: asset.chatId },
});
}
return defineLink({ return defineLink({
to: '/app/chats/$chatId', to: '/app/chats/$chatId',
params: { chatId: asset.chatId }, params: { chatId: asset.chatId },
@ -68,6 +76,13 @@ export const createChatAssetRoute = (asset: {
} }
if (asset.asset_type === 'metric_file') { if (asset.asset_type === 'metric_file') {
if (asset.isEmbed) {
return defineLink({
to: '/embed/chat/$chatId/metrics/$metricId',
params: { metricId: asset.id || '', chatId: asset.chatId },
search: { metric_version_number: asset.versionNumber },
});
}
return defineLink({ return defineLink({
to: '/app/chats/$chatId/metrics/$metricId', to: '/app/chats/$chatId/metrics/$metricId',
params: { metricId: asset.id || '', chatId: asset.chatId }, params: { metricId: asset.id || '', chatId: asset.chatId },
@ -76,6 +91,13 @@ export const createChatAssetRoute = (asset: {
} }
if (asset.asset_type === 'dashboard_file') { if (asset.asset_type === 'dashboard_file') {
if (asset.isEmbed) {
return defineLink({
to: '/embed/chat/$chatId/dashboards/$dashboardId',
params: { dashboardId: asset.id || '', chatId: asset.chatId },
search: { dashboard_version_number: asset.versionNumber },
});
}
return defineLink({ return defineLink({
to: '/app/chats/$chatId/dashboards/$dashboardId', to: '/app/chats/$chatId/dashboards/$dashboardId',
params: { dashboardId: asset.id || '', chatId: asset.chatId }, params: { dashboardId: asset.id || '', chatId: asset.chatId },
@ -84,6 +106,13 @@ export const createChatAssetRoute = (asset: {
} }
if (asset.asset_type === 'report_file') { if (asset.asset_type === 'report_file') {
if (asset.isEmbed) {
return defineLink({
to: '/embed/chat/$chatId/reports/$reportId',
params: { reportId: asset.id || '', chatId: asset.chatId },
search: { report_version_number: asset.versionNumber },
});
}
return defineLink({ return defineLink({
to: '/app/chats/$chatId/reports/$reportId', to: '/app/chats/$chatId/reports/$reportId',
params: { reportId: asset.id || '', chatId: asset.chatId }, params: { reportId: asset.id || '', chatId: asset.chatId },
@ -92,6 +121,12 @@ export const createChatAssetRoute = (asset: {
} }
if (asset.asset_type === 'reasoning') { if (asset.asset_type === 'reasoning') {
if (asset.isEmbed) {
return defineLink({
to: '/embed/chat/$chatId/reasoning/$messageId',
params: { messageId: asset.id || '', chatId: asset.chatId },
});
}
return defineLink({ return defineLink({
to: '/app/chats/$chatId/reasoning/$messageId', to: '/app/chats/$chatId/reasoning/$messageId',
params: { chatId: asset.chatId, messageId: asset.id || '' }, params: { chatId: asset.chatId, messageId: asset.id || '' },
@ -99,6 +134,12 @@ export const createChatAssetRoute = (asset: {
} }
if (asset.asset_type === 'collection') { if (asset.asset_type === 'collection') {
if (asset.isEmbed) {
console.warn('collection is actually not supported for embeds...', asset.id);
return defineLink({
to: '/auth/login',
});
}
return defineLink({ return defineLink({
to: '/app/collections/$collectionId', to: '/app/collections/$collectionId',
params: { collectionId: asset.id || '' }, params: { collectionId: asset.id || '' },

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import { ClosePageButton } from '@/components/features/chat/ClosePageButton'; import * as reportContent from '@/context/BusterAssets/reasoning-server/reasoningContent';
import { AppSegmented } from '@/components/ui/segmented';
import { ReasoningController } from '@/controllers/ReasoningController/ReasoningController';
import { AssetContainer } from '@/layouts/AssetContainer/AssetContainer';
export const Route = createFileRoute('/app/_app/_asset/chats/$chatId/reasoning/$messageId/')({ export const Route = createFileRoute('/app/_app/_asset/chats/$chatId/reasoning/$messageId/')({
component: RouteComponent, ...reportContent,
}); });
function RouteComponent() {
const { chatId, messageId } = Route.useParams();
return (
<AssetContainer header={<ReasoningControllerHeader />} headerBorderVariant="ghost" scrollable>
<ReasoningController chatId={chatId} messageId={messageId} />
</AssetContainer>
);
}
const ReasoningControllerHeader: React.FC = () => {
return (
<div className="w-full flex items-center justify-between">
<AppSegmented
type="button"
options={[
{
value: 'reasoning',
label: 'Reasoning',
},
]}
/>
<ClosePageButton />
</div>
);
};

View File

@ -1,10 +1,12 @@
import type { AssetType } from '@buster/server-shared/assets'; import type { AssetType } from '@buster/server-shared/assets';
import { createFileRoute, Outlet, type RouteContext } from '@tanstack/react-router'; import { createFileRoute, Outlet, type RouteContext } from '@tanstack/react-router';
import { prefetchGetMyUserInfo } from '@/api/buster_rest/users'; import { prefetchGetMyUserInfo } from '@/api/buster_rest/users';
import { Text } from '@/components/ui/typography'; import { NotFoundCard } from '@/components/features/global/NotFoundCard';
import { useGetChatId } from '@/context/Chats/useGetChatId';
import { getSupabaseSession } from '@/integrations/supabase/getSupabaseUserClient'; import { getSupabaseSession } from '@/integrations/supabase/getSupabaseUserClient';
import { signInWithAnonymousUser } from '@/integrations/supabase/signIn'; import { signInWithAnonymousUser } from '@/integrations/supabase/signIn';
import { AppAssetCheckLayout } from '@/layouts/AppAssetCheckLayout'; import { AppAssetCheckLayout } from '@/layouts/AppAssetCheckLayout';
import { cn } from '@/lib/classMerge';
export const Route = createFileRoute('/embed')({ export const Route = createFileRoute('/embed')({
beforeLoad: async ({ context, matches }) => { beforeLoad: async ({ context, matches }) => {
@ -14,6 +16,7 @@ export const Route = createFileRoute('/embed')({
const assetType = [...matches].reverse().find(({ staticData }) => staticData?.assetType) const assetType = [...matches].reverse().find(({ staticData }) => staticData?.assetType)
?.staticData?.assetType as AssetType; ?.staticData?.assetType as AssetType;
return { return {
assetType, assetType,
}; };
@ -29,25 +32,26 @@ export const Route = createFileRoute('/embed')({
const stableCtxSelector = (ctx: RouteContext) => ctx.assetType; const stableCtxSelector = (ctx: RouteContext) => ctx.assetType;
function RouteComponent() { function RouteComponent() {
const assetType = Route.useLoaderData({ select: stableCtxSelector }); const assetType = Route.useLoaderData({ select: stableCtxSelector });
const chatId = useGetChatId();
if (!assetType) { if (!assetType) {
return ( return (
<div className="flex h-full w-full items-center justify-center">No asset type found</div> <div className="flex flex-col gap-3 h-full w-full items-center justify-center">
); <NotFoundCard />
}
if (assetType === 'chat') {
return (
<div className="flex h-full w-full items-center justify-center">
<Text className="text-lg">
Sharing a chat is not supported yet... But it is on our roadmap!
</Text>
</div> </div>
); );
} }
const isChat = assetType === 'chat' || !!chatId;
return ( return (
<main className="h-full w-full bg-page-background overflow-y-auto"> <main
data-testid={`embed-main-${assetType}`}
className={cn(
'h-full w-full bg-page-background overflow-y-auto',
isChat && 'overflow-y-hidden bg-background-secondary'
)}
>
<AppAssetCheckLayout assetType={assetType}> <AppAssetCheckLayout assetType={assetType}>
<Outlet /> <Outlet />
</AppAssetCheckLayout> </AppAssetCheckLayout>

View File

@ -1,10 +1,18 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute, Outlet } from '@tanstack/react-router';
import * as chatLayoutServerContext from '@/context/BusterAssets/chat-server/chatLayoutServer'; import * as chatLayoutServerContext from '@/context/BusterAssets/chat-server/chatLayoutServer';
export const Route = createFileRoute('/embed/chat/$chatId')({ export const Route = createFileRoute('/embed/chat/$chatId')({
...chatLayoutServerContext, ...chatLayoutServerContext,
ssr: false, ssr: false,
component: () => { component: RouteComponent,
return <div>Hello "/embed/chat/$chatId"!</div>;
},
}); });
function RouteComponent() {
return (
<div className="h-full w-full p-2 max-h-[100vh]" data-testid="embed-chat-container">
<div className="h-full w-full border rounded bg-background">
{chatLayoutServerContext.component()}
</div>
</div>
);
}

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as dashboardLayoutServerAssetContext from '@/context/BusterAssets/dashboard-server/dashboardLayoutServerAssetContext'; import * as dashboardLayoutServerAssetContext from '@/context/BusterAssets/dashboard-server/dashboardLayoutServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/dashboards/$dashboardId/_layout')({ export const Route = createFileRoute('/embed/chat/$chatId/dashboards/$dashboardId/_layout')({
...dashboardLayoutServerAssetContext, ...dashboardLayoutServerAssetContext,
}); });

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as dashboardContentServerContext from '@/context/BusterAssets/dashboard-server/dashboardContentContext'; import * as dashboardContentServerContext from '@/context/BusterAssets/dashboard-server/dashboardContentContext';
export const Route = createFileRoute('/embed/chats/$chatId/dashboards/$dashboardId/_layout/')({ export const Route = createFileRoute('/embed/chat/$chatId/dashboards/$dashboardId/_layout/')({
...dashboardContentServerContext, ...dashboardContentServerContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricLayoutServerContext from '@/context/BusterAssets/metric-server/metricLayoutServerAssetContext'; import * as metricLayoutServerContext from '@/context/BusterAssets/metric-server/metricLayoutServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/dashboards/$dashboardId/metrics/$metricId/_content' '/embed/chat/$chatId/dashboards/$dashboardId/metrics/$metricId/_content'
)({ )({
...metricLayoutServerContext, ...metricLayoutServerContext,
loader: metricLayoutServerContext.loader<{ metricId: string; dashboardId: string }>, loader: metricLayoutServerContext.loader<{ metricId: string; dashboardId: string }>,

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricChartServerAssetContext from '@/context/BusterAssets/metric-server/metricChartServerAssetContext'; import * as metricChartServerAssetContext from '@/context/BusterAssets/metric-server/metricChartServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/chart' '/embed/chat/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/chart'
)({ )({
...metricChartServerAssetContext, ...metricChartServerAssetContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricIndexServerContext from '@/context/BusterAssets/metric-server/metricIndexServerAssetContext'; import * as metricIndexServerContext from '@/context/BusterAssets/metric-server/metricIndexServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/' '/embed/chat/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/'
)({ )({
...metricIndexServerContext, ...metricIndexServerContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricResultsServerAssetContext from '@/context/BusterAssets/metric-server/metricResultsServerAssetContext'; import * as metricResultsServerAssetContext from '@/context/BusterAssets/metric-server/metricResultsServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/results' '/embed/chat/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/results'
)({ )({
...metricResultsServerAssetContext, ...metricResultsServerAssetContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricSQLServerAsssetContext from '@/context/BusterAssets/metric-server/metricSQLServerAsssetContext'; import * as metricSQLServerAsssetContext from '@/context/BusterAssets/metric-server/metricSQLServerAsssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/sql' '/embed/chat/$chatId/dashboards/$dashboardId/metrics/$metricId/_content/sql'
)({ )({
...metricSQLServerAsssetContext, ...metricSQLServerAsssetContext,
}); });

View File

@ -1,7 +1,10 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/embed/chats/$chatId/')({ export const Route = createFileRoute('/embed/chat/$chatId/')({
component: RouteComponent, component: RouteComponent,
staticData: {
assetType: 'chat',
},
}); });
function RouteComponent() { function RouteComponent() {

View File

@ -1,7 +1,7 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as metricLayoutServerContext from '@/context/BusterAssets/metric-server/metricLayoutServerAssetContext'; import * as metricLayoutServerContext from '@/context/BusterAssets/metric-server/metricLayoutServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/metrics/$metricId/_layout')({ export const Route = createFileRoute('/embed/chat/$chatId/metrics/$metricId/_layout')({
...metricLayoutServerContext, ...metricLayoutServerContext,
loader: metricLayoutServerContext.loader<{ metricId: string }>, loader: metricLayoutServerContext.loader<{ metricId: string }>,
}); });

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as metricChartServerAssetContext from '@/context/BusterAssets/metric-server/metricChartServerAssetContext'; import * as metricChartServerAssetContext from '@/context/BusterAssets/metric-server/metricChartServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/metrics/$metricId/_layout/chart')({ export const Route = createFileRoute('/embed/chat/$chatId/metrics/$metricId/_layout/chart')({
...metricChartServerAssetContext, ...metricChartServerAssetContext,
}); });

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as metricIndexServerContext from '@/context/BusterAssets/metric-server/metricIndexServerAssetContext'; import * as metricIndexServerContext from '@/context/BusterAssets/metric-server/metricIndexServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/metrics/$metricId/_layout/')({ export const Route = createFileRoute('/embed/chat/$chatId/metrics/$metricId/_layout/')({
...metricIndexServerContext, ...metricIndexServerContext,
}); });

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as metricResultsServerAssetContext from '@/context/BusterAssets/metric-server/metricResultsServerAssetContext'; import * as metricResultsServerAssetContext from '@/context/BusterAssets/metric-server/metricResultsServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/metrics/$metricId/_layout/results')({ export const Route = createFileRoute('/embed/chat/$chatId/metrics/$metricId/_layout/results')({
...metricResultsServerAssetContext, ...metricResultsServerAssetContext,
}); });

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as metricSQLServerAsssetContext from '@/context/BusterAssets/metric-server/metricSQLServerAsssetContext'; import * as metricSQLServerAsssetContext from '@/context/BusterAssets/metric-server/metricSQLServerAsssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/metrics/$metricId/_layout/sql')({ export const Route = createFileRoute('/embed/chat/$chatId/metrics/$metricId/_layout/sql')({
...metricSQLServerAsssetContext, ...metricSQLServerAsssetContext,
}); });

View File

@ -0,0 +1,6 @@
import { createFileRoute } from '@tanstack/react-router';
import * as reportContent from '@/context/BusterAssets/reasoning-server/reasoningContent';
export const Route = createFileRoute('/embed/chat/$chatId/reasoning/$messageId/')({
...reportContent,
});

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as reportLayoutServerAssetContext from '@/context/BusterAssets/report-server/reportLayoutServerAssetContext'; import * as reportLayoutServerAssetContext from '@/context/BusterAssets/report-server/reportLayoutServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/reports/$reportId/_layout')({ export const Route = createFileRoute('/embed/chat/$chatId/reports/$reportId/_layout')({
...reportLayoutServerAssetContext, ...reportLayoutServerAssetContext,
}); });

View File

@ -2,6 +2,6 @@ import { createFileRoute } from '@tanstack/react-router';
import * as reportContentServerContext from '@/context/BusterAssets/report-server/reportContentServerAssetContext'; import * as reportContentServerContext from '@/context/BusterAssets/report-server/reportContentServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/reports/$reportId/_layout/content')({ export const Route = createFileRoute('/embed/chat/$chatId/reports/$reportId/_layout/content')({
...reportContentServerContext, ...reportContentServerContext,
}); });

View File

@ -1,6 +1,6 @@
import { createFileRoute } from '@tanstack/react-router'; import { createFileRoute } from '@tanstack/react-router';
import * as reportIndexServerAssetContext from '@/context/BusterAssets/report-server/reportContentServerAssetContext'; import * as reportIndexServerAssetContext from '@/context/BusterAssets/report-server/reportContentServerAssetContext';
export const Route = createFileRoute('/embed/chats/$chatId/reports/$reportId/_layout/')({ export const Route = createFileRoute('/embed/chat/$chatId/reports/$reportId/_layout/')({
...reportIndexServerAssetContext, ...reportIndexServerAssetContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricLayoutServerContext from '@/context/BusterAssets/metric-server/metricLayoutServerAssetContext'; import * as metricLayoutServerContext from '@/context/BusterAssets/metric-server/metricLayoutServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/reports/$reportId/metrics/$metricId/_content' '/embed/chat/$chatId/reports/$reportId/metrics/$metricId/_content'
)({ )({
...metricLayoutServerContext, ...metricLayoutServerContext,
loader: metricLayoutServerContext.loader<{ metricId: string }>, loader: metricLayoutServerContext.loader<{ metricId: string }>,

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricChartServerAssetContext from '@/context/BusterAssets/metric-server/metricChartServerAssetContext'; import * as metricChartServerAssetContext from '@/context/BusterAssets/metric-server/metricChartServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/reports/$reportId/metrics/$metricId/_content/chart' '/embed/chat/$chatId/reports/$reportId/metrics/$metricId/_content/chart'
)({ )({
...metricChartServerAssetContext, ...metricChartServerAssetContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricIndexServerContext from '@/context/BusterAssets/metric-server/metricIndexServerAssetContext'; import * as metricIndexServerContext from '@/context/BusterAssets/metric-server/metricIndexServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/reports/$reportId/metrics/$metricId/_content/' '/embed/chat/$chatId/reports/$reportId/metrics/$metricId/_content/'
)({ )({
...metricIndexServerContext, ...metricIndexServerContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricResultsServerAssetContext from '@/context/BusterAssets/metric-server/metricResultsServerAssetContext'; import * as metricResultsServerAssetContext from '@/context/BusterAssets/metric-server/metricResultsServerAssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/reports/$reportId/metrics/$metricId/_content/results' '/embed/chat/$chatId/reports/$reportId/metrics/$metricId/_content/results'
)({ )({
...metricResultsServerAssetContext, ...metricResultsServerAssetContext,
}); });

View File

@ -2,7 +2,7 @@ import { createFileRoute } from '@tanstack/react-router';
import * as metricSQLServerAsssetContext from '@/context/BusterAssets/metric-server/metricSQLServerAsssetContext'; import * as metricSQLServerAsssetContext from '@/context/BusterAssets/metric-server/metricSQLServerAsssetContext';
export const Route = createFileRoute( export const Route = createFileRoute(
'/embed/chats/$chatId/reports/$reportId/metrics/$metricId/_content/sql' '/embed/chat/$chatId/reports/$reportId/metrics/$metricId/_content/sql'
)({ )({
...metricSQLServerAsssetContext, ...metricSQLServerAsssetContext,
}); });