added basic embed checks

This commit is contained in:
Nate Kelley 2025-10-01 14:52:11 -06:00
parent ac19b16362
commit 88e3e1e6c5
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
9 changed files with 130 additions and 96 deletions

View File

@ -0,0 +1,9 @@
import { useMatch, useMatches } from '@tanstack/react-router';
export const useIsEmbed = () => {
const match = useMatch({
from: '/embed',
});
console.log(match);
return !!match?.id;
};

View File

@ -1,10 +1,21 @@
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 matches = useMatches();
const stableCtxSelector = (ctx: RouteContext) => ctx.assetType; const lastMatch = findLast(matches, (match) => match.staticData?.assetType);
export const useSelectedAssetType = () => { if (typeof lastMatch === 'number') {
const data = assetRouteApi.useRouteContext({ select: stableCtxSelector }); return 'chat';
}
// @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,11 +5,12 @@ 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(
({ chatId, isEmbed }: { chatId: string | undefined; isEmbed: boolean }) => {
return ( return (
<AppPageLayout <AppPageLayout
headerSizeVariant="default" headerSizeVariant="default"
header={<ChatHeader />} header={<ChatHeader isEmbed={isEmbed} />}
headerBorderVariant="ghost" headerBorderVariant="ghost"
headerClassName="bg-page-background" headerClassName="bg-page-background"
mainClassName="bg-page-background" mainClassName="bg-page-background"
@ -17,9 +18,10 @@ export const ChatContainer = React.memo(({ chatId }: { chatId: string | undefine
id={CHAT_CONTAINER_ID} id={CHAT_CONTAINER_ID}
className="flex h-full w-full min-w-[295px] flex-col" className="flex h-full w-full min-w-[295px] flex-col"
> >
<ChatContent chatId={chatId} /> <ChatContent chatId={chatId} isEmbed={isEmbed} />
</AppPageLayout> </AppPageLayout>
); );
}); }
);
ChatContainer.displayName = 'ChatContainer'; ChatContainer.displayName = 'ChatContainer';

View File

@ -12,7 +12,8 @@ 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(
({ chatId, isEmbed }) => {
const chatMessageIds = useGetChatMessageIds(chatId); const chatMessageIds = useGetChatMessageIds(chatId);
const containerRef = useRef<HTMLElement>(null); const containerRef = useRef<HTMLElement>(null);
@ -55,6 +56,7 @@ export const ChatContent: React.FC<{ chatId: string | undefined }> = React.memo(
</ClientOnly> </ClientOnly>
</div> </div>
{!isEmbed && (
<ChatInputWrapper> <ChatInputWrapper>
{showScrollToBottomButton && ( {showScrollToBottomButton && (
<ScrollToBottomButton <ScrollToBottomButton
@ -64,9 +66,11 @@ export const ChatContent: React.FC<{ chatId: string | undefined }> = React.memo(
/> />
)} )}
</ChatInputWrapper> </ChatInputWrapper>
)}
</> </>
); );
}); }
);
ChatContent.displayName = 'ChatContent'; ChatContent.displayName = 'ChatContent';

View File

@ -89,6 +89,7 @@ export const ChatMessageOptions: React.FC<{
/> />
</AppTooltip> </AppTooltip>
)} )}
{canEditChat && (
<AppTooltip title="Report message"> <AppTooltip title="Report message">
<Button <Button
variant="ghost" variant="ghost"
@ -101,6 +102,7 @@ export const ChatMessageOptions: React.FC<{
} }
/> />
</AppTooltip> </AppTooltip>
)}
{postProcessingMessage && ( {postProcessingMessage && (
<AppTooltip title="View assumptions"> <AppTooltip title="View assumptions">

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

@ -5,6 +5,7 @@ import { Text } from '@/components/ui/typography';
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 }) => {
@ -36,18 +37,15 @@ function RouteComponent() {
); );
} }
if (assetType === 'chat') { const isChat = 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>
);
}
return ( return (
<main className="h-full w-full bg-page-background overflow-y-auto"> <main
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,16 @@
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: () => {
return <div>Hello "/embed/chat/$chatId"!</div>; return (
<div className="h-full w-full p-2 max-h-[100vh] ">
<div className="h-full w-full border rounded bg-background">
{chatLayoutServerContext.component()}
</div>
</div>
);
}, },
}); });