mirror of https://github.com/buster-so/buster.git
added basic embed checks
This commit is contained in:
parent
ac19b16362
commit
88e3e1e6c5
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
export const useSelectedAssetType = () => {
|
||||
const data = assetRouteApi.useRouteContext({ select: stableCtxSelector });
|
||||
const lastMatch = findLast(matches, (match) => match.staticData?.assetType);
|
||||
if (typeof lastMatch === 'number') {
|
||||
return 'chat';
|
||||
}
|
||||
// @ts-expect-error - lastMatch is not undefined
|
||||
const data = lastMatch?.staticData?.assetType as StaticDataRouteOption['assetType'];
|
||||
const { messageId } = useParams({
|
||||
strict: false,
|
||||
});
|
||||
|
|
|
@ -5,21 +5,23 @@ import { ChatHeader } from './ChatHeader';
|
|||
|
||||
export const CHAT_CONTAINER_ID = 'chat-container-content';
|
||||
|
||||
export const ChatContainer = React.memo(({ chatId }: { chatId: string | undefined }) => {
|
||||
return (
|
||||
<AppPageLayout
|
||||
headerSizeVariant="default"
|
||||
header={<ChatHeader />}
|
||||
headerBorderVariant="ghost"
|
||||
headerClassName="bg-page-background"
|
||||
mainClassName="bg-page-background"
|
||||
scrollable
|
||||
id={CHAT_CONTAINER_ID}
|
||||
className="flex h-full w-full min-w-[295px] flex-col"
|
||||
>
|
||||
<ChatContent chatId={chatId} />
|
||||
</AppPageLayout>
|
||||
);
|
||||
});
|
||||
export const ChatContainer = React.memo(
|
||||
({ chatId, isEmbed }: { chatId: string | undefined; isEmbed: boolean }) => {
|
||||
return (
|
||||
<AppPageLayout
|
||||
headerSizeVariant="default"
|
||||
header={<ChatHeader isEmbed={isEmbed} />}
|
||||
headerBorderVariant="ghost"
|
||||
headerClassName="bg-page-background"
|
||||
mainClassName="bg-page-background"
|
||||
scrollable
|
||||
id={CHAT_CONTAINER_ID}
|
||||
className="flex h-full w-full min-w-[295px] flex-col"
|
||||
>
|
||||
<ChatContent chatId={chatId} isEmbed={isEmbed} />
|
||||
</AppPageLayout>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
ChatContainer.displayName = 'ChatContainer';
|
||||
|
|
|
@ -12,61 +12,65 @@ import { FollowUpChatInput } from './FollowupChatInput';
|
|||
|
||||
const autoClass = 'mx-auto max-w-[600px] w-full';
|
||||
|
||||
export const ChatContent: React.FC<{ chatId: string | undefined }> = React.memo(({ chatId }) => {
|
||||
const chatMessageIds = useGetChatMessageIds(chatId);
|
||||
const containerRef = useRef<HTMLElement>(null);
|
||||
export const ChatContent: React.FC<{ chatId: string | undefined; isEmbed: boolean }> = React.memo(
|
||||
({ chatId, isEmbed }) => {
|
||||
const chatMessageIds = useGetChatMessageIds(chatId);
|
||||
const containerRef = useRef<HTMLElement>(null);
|
||||
|
||||
const { isAutoScrollEnabled, isMountedAutoScrollObserver, scrollToBottom, enableAutoScroll } =
|
||||
useAutoScroll(containerRef, {
|
||||
observeSubTree: true,
|
||||
enabled: false,
|
||||
const { isAutoScrollEnabled, isMountedAutoScrollObserver, scrollToBottom, enableAutoScroll } =
|
||||
useAutoScroll(containerRef, {
|
||||
observeSubTree: true,
|
||||
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 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;
|
||||
|
||||
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 (
|
||||
<>
|
||||
<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}
|
||||
{!isEmbed && (
|
||||
<ChatInputWrapper>
|
||||
{showScrollToBottomButton && (
|
||||
<ScrollToBottomButton
|
||||
isAutoScrollEnabled={isAutoScrollEnabled}
|
||||
scrollToBottom={scrollToBottom}
|
||||
className={'absolute -top-10'}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</ClientOnly>
|
||||
</div>
|
||||
|
||||
<ChatInputWrapper>
|
||||
{showScrollToBottomButton && (
|
||||
<ScrollToBottomButton
|
||||
isAutoScrollEnabled={isAutoScrollEnabled}
|
||||
scrollToBottom={scrollToBottom}
|
||||
className={'absolute -top-10'}
|
||||
/>
|
||||
)}
|
||||
</ChatInputWrapper>
|
||||
)}
|
||||
</ChatInputWrapper>
|
||||
</>
|
||||
);
|
||||
});
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
ChatContent.displayName = 'ChatContent';
|
||||
|
||||
|
|
|
@ -89,18 +89,20 @@ export const ChatMessageOptions: React.FC<{
|
|||
/>
|
||||
</AppTooltip>
|
||||
)}
|
||||
<AppTooltip title="Report message">
|
||||
<Button
|
||||
variant="ghost"
|
||||
prefix={feedback === 'negative' ? <ThumbsDownFilled /> : <ThumbsDown />}
|
||||
onClick={() =>
|
||||
updateChatMessageFeedback({
|
||||
message_id: messageId,
|
||||
feedback: feedback === 'negative' ? null : 'negative',
|
||||
})
|
||||
}
|
||||
/>
|
||||
</AppTooltip>
|
||||
{canEditChat && (
|
||||
<AppTooltip title="Report message">
|
||||
<Button
|
||||
variant="ghost"
|
||||
prefix={feedback === 'negative' ? <ThumbsDownFilled /> : <ThumbsDown />}
|
||||
onClick={() =>
|
||||
updateChatMessageFeedback({
|
||||
message_id: messageId,
|
||||
feedback: feedback === 'negative' ? null : 'negative',
|
||||
})
|
||||
}
|
||||
/>
|
||||
</AppTooltip>
|
||||
)}
|
||||
|
||||
{postProcessingMessage && (
|
||||
<AppTooltip title="View assumptions">
|
||||
|
|
|
@ -4,7 +4,7 @@ import { ChatHeaderTitle } from '@/components/features/chat/ChatHeaderTitle';
|
|||
import { useGetActiveChatTitle, useIsStreamingMessage } from '@/context/Chats';
|
||||
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 chatTitle = useGetActiveChatTitle();
|
||||
const isStreamingMessage = useIsStreamingMessage();
|
||||
|
@ -16,7 +16,7 @@ export const ChatHeader: React.FC = React.memo(() => {
|
|||
chatId={chatId || ''}
|
||||
isStreamingMessage={isStreamingMessage}
|
||||
/>
|
||||
<ChatHeaderOptions />
|
||||
{!isEmbed && <ChatHeaderOptions />}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
type AppSplitterRef,
|
||||
type LayoutSize,
|
||||
} from '@/components/ui/layouts/AppSplitter';
|
||||
import { useIsEmbed } from '@/context/BusterAssets/useIsEmbed';
|
||||
import { useGetCurrentMessageId, useIsStreamingMessage } from '@/context/Chats';
|
||||
import { useGetChatId } from '@/context/Chats/useGetChatId';
|
||||
import type { LayoutMode } from '@/layouts/ChatLayout/config';
|
||||
|
@ -38,6 +39,7 @@ export const ChatLayout: React.FC<ChatSplitterProps> = ({
|
|||
const selectedAssetId = useSelectedAssetId();
|
||||
const currentMessageId = useGetCurrentMessageId() || '';
|
||||
const chatId = useGetChatId();
|
||||
const isEmbed = useIsEmbed();
|
||||
const isStreamingMessage = useIsStreamingMessage();
|
||||
|
||||
const leftPanelMinSize = selectedAssetId ? DEFAULT_CHAT_OPTION_SIDEBAR_SIZE : '0px';
|
||||
|
@ -57,7 +59,7 @@ export const ChatLayout: React.FC<ChatSplitterProps> = ({
|
|||
return (
|
||||
<AppSplitter
|
||||
ref={appSplitterRef}
|
||||
leftChildren={renderLeftPanel && <ChatContainer chatId={chatId} />}
|
||||
leftChildren={renderLeftPanel && <ChatContainer chatId={chatId} isEmbed={isEmbed} />}
|
||||
rightChildren={renderRightPanel && children}
|
||||
autoSaveId={autoSaveId}
|
||||
defaultLayout={defaultLayout}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Text } from '@/components/ui/typography';
|
|||
import { getSupabaseSession } from '@/integrations/supabase/getSupabaseUserClient';
|
||||
import { signInWithAnonymousUser } from '@/integrations/supabase/signIn';
|
||||
import { AppAssetCheckLayout } from '@/layouts/AppAssetCheckLayout';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
|
||||
export const Route = createFileRoute('/embed')({
|
||||
beforeLoad: async ({ context, matches }) => {
|
||||
|
@ -36,18 +37,15 @@ function RouteComponent() {
|
|||
);
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
const isChat = assetType === 'chat';
|
||||
|
||||
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}>
|
||||
<Outlet />
|
||||
</AppAssetCheckLayout>
|
||||
|
|
|
@ -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';
|
||||
|
||||
export const Route = createFileRoute('/embed/chat/$chatId')({
|
||||
...chatLayoutServerContext,
|
||||
ssr: false,
|
||||
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>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue