use client on select assets

This commit is contained in:
Nate Kelley 2025-03-04 13:52:33 -07:00
parent 2eb938f597
commit e79f1e7e05
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
24 changed files with 102 additions and 67 deletions

View File

@ -7,7 +7,7 @@ import {
} from './eventInterfaces';
export enum ChatsResponses {
'/chats/list:getThreadsList' = '/chats/list:getThreadsList',
'/chats/list:getChatsList' = '/chats/list:getChatsList',
'/chats/unsubscribe:unsubscribe' = '/chats/unsubscribe:unsubscribe',
'/chats/get:getChat' = '/chats/get:getChat',
'/chats/post:initializeChat' = '/chats/post:initializeChat',

View File

@ -4,7 +4,7 @@ import { ChatListHeader } from './_ChatsListContainer/ChatListHeader';
export default function ChatsPage() {
return (
<AppPageLayout headerVariant="list" header={<ChatListHeader />}>
<AppPageLayout headerSizeVariant="list" header={<ChatListHeader />}>
<ChatListContainer />
</AppPageLayout>
);

View File

@ -16,9 +16,17 @@ export const AppPageLayout: React.FC<
header?: React.ReactNode;
scrollable?: boolean;
className?: string;
headerVariant?: 'default' | 'list';
headerSizeVariant?: 'default' | 'list';
headerBorderVariant?: 'default' | 'ghost';
}>
> = ({ children, header, scrollable = false, className = '', headerVariant = 'default' }) => {
> = ({
children,
header,
scrollable = false,
className = '',
headerSizeVariant = 'default',
headerBorderVariant = 'default'
}) => {
return (
<div
className={cn(
@ -26,7 +34,11 @@ export const AppPageLayout: React.FC<
scrollable && 'overflow-y-auto',
className
)}>
{header && <AppPageLayoutHeader variant={headerVariant}>{header}</AppPageLayoutHeader>}
{header && (
<AppPageLayoutHeader sizeVariant={headerSizeVariant} borderVariant={headerBorderVariant}>
{header}
</AppPageLayoutHeader>
)}
<AppPageLayoutContent scrollable={scrollable}>{children}</AppPageLayoutContent>
</div>
);

View File

@ -3,13 +3,21 @@ 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 justify-between gap-x-2.5 border-b',
'bg-page-background flex max-h-[38px] min-h-[38px] items-center justify-between gap-x-2.5 ',
{
variants: {
variant: {
sizeVariant: {
default: 'px-4.5',
list: 'px-7.5'
},
borderVariant: {
default: 'border-b',
ghost: 'border-b-0'
}
},
defaultVariants: {
borderVariant: 'default',
sizeVariant: 'default'
}
}
);
@ -20,6 +28,8 @@ export const AppPageLayoutHeader: React.FC<
className?: string;
} & VariantProps<typeof headerVariants>
>
> = ({ children, className = '', variant = 'default' }) => {
return <div className={cn(headerVariants({ variant }), className)}>{children}</div>;
> = ({ children, className = '', sizeVariant = 'default', borderVariant = 'default' }) => {
return (
<div className={cn(headerVariants({ sizeVariant, borderVariant }), className)}>{children}</div>
);
};

View File

@ -16,7 +16,7 @@ export const useBusterChatListByFilter = (
route: '/chats/list',
payload: filters
},
responseEvent: '/chats/list:getThreadsList',
responseEvent: '/chats/list:getChatsList',
options: queryKeys['chatsGetList'](filters)
});

View File

@ -136,6 +136,10 @@ export const useChatStreamMessage = () => {
const _generatingResponseMessageCallback = useMemoizedFn(
(_: null, d: ChatEvent_GeneratingResponseMessage) => {
const { message_id, response_message, chat_id } = d;
console.log(response_message?.id);
if (!response_message?.id) return;
const responseMessageId = response_message.id;
const foundResponseMessage: undefined | ChatMessageResponseMessage =
chatMessageResponseMessagesRef.current[message_id]?.[responseMessageId];

View File

@ -1,4 +1,5 @@
'use client';
import React from 'react';
import { useChatIndividualContextSelector } from '@chatLayout/ChatContext';
import { ReasoningMessageContainer } from './ReasoningMessageContainer';

View File

@ -1,3 +1,5 @@
'use client';
import type { BusterChatMessageReasoning } from '@/api/asset_interfaces';
import React, { useMemo } from 'react';
import { ReasoningMessageSelector } from './ReasoningMessages';

View File

@ -19,6 +19,7 @@ export const ChatContainer = React.memo(({}: ChatContainerProps) => {
return (
<AppPageLayout
header={<ChatHeader showScrollOverflow={showScrollOverflow} />}
headerBorderVariant="ghost"
className="flex h-full w-full min-w-[295px] flex-col">
<ChatContent chatContentRef={chatContentRef} />
</AppPageLayout>

View File

@ -1,12 +1,12 @@
'use client';
import React from 'react';
import { useChatIndividualContextSelector } from '../../ChatContext';
import { ChatMessageBlock } from './ChatMessageBlock';
import { ChatInput } from './ChatInput';
import { createStyles } from 'antd-style';
export const ChatContent: React.FC<{ chatContentRef: React.RefObject<HTMLDivElement> }> =
React.memo(({ chatContentRef }) => {
const { styles } = useStyles();
const chatMessageIds = useChatIndividualContextSelector((state) => state.chatMessageIds);
// const chatMessages = useBusterChatContextSelector((state) => state.chatsMessages);
@ -17,7 +17,7 @@ export const ChatContent: React.FC<{ chatContentRef: React.RefObject<HTMLDivElem
<div ref={chatContentRef} className="h-full w-full overflow-y-auto">
<div className="pb-8">
{chatMessageIds?.map((messageId) => (
<div key={messageId} className={styles.messageBlock}>
<div key={messageId} className={'hover:bg-item-hover'}>
<div className={autoClass}>
<ChatMessageBlock key={messageId} messageId={messageId} />
</div>
@ -33,11 +33,3 @@ export const ChatContent: React.FC<{ chatContentRef: React.RefObject<HTMLDivElem
});
ChatContent.displayName = 'ChatContent';
const useStyles = createStyles(({ token, css }) => ({
messageBlock: css`
&:hover {
background-color: ${token.controlItemBgHover};
}
`
}));

View File

@ -1,10 +1,10 @@
import React from 'react';
import { Text } from '@/components/ui';
import { Text } from '@/components/ui/typography';
export const AIWarning = React.memo(() => {
return (
<div className="w-full truncate overflow-hidden text-center">
<Text size="xs" type="tertiary" className="truncate">
<Text size="xs" variant="tertiary" truncate>
Our AI may make mistakes. Check important info.
</Text>
</div>

View File

@ -3,7 +3,7 @@ import type { BusterChatMessageResponse } from '@/api/asset_interfaces';
import { createStyles } from 'antd-style';
import { ChatResponseMessageSelector } from './ChatResponseMessageSelector';
import { AnimatePresence, motion } from 'framer-motion';
import { Text } from '@/components/ui';
import { Text } from '@/components/ui/typography';
import { AppMaterialIcons } from '@/components/ui';
import pluralize from 'pluralize';
import { useMemoizedFn } from 'ahooks';

View File

@ -5,7 +5,6 @@ import { ShimmerText } from '@/components/ui/typography/ShimmerText';
import { useMemoizedFn } from 'ahooks';
import { motion } from 'framer-motion';
import { AnimatePresence } from 'framer-motion';
import { AppMaterialIcons } from '@/components/ui';
import { Stars } from '@/components/ui/icons';
import { Text } from '@/components/ui/typography';
import { createStyles } from 'antd-style';

View File

@ -1,7 +1,7 @@
import type { BusterChatMessageRequest } from '@/api/asset_interfaces';
import { createStyles } from 'antd-style';
import React from 'react';
import { Text } from '@/components/ui';
import { Text } from '@/components/ui/typography';
import { MessageContainer } from './MessageContainer';
export const ChatUserMessage: React.FC<{ requestMessage: BusterChatMessageRequest }> = React.memo(
@ -12,9 +12,7 @@ export const ChatUserMessage: React.FC<{ requestMessage: BusterChatMessageReques
return (
<MessageContainer senderName={sender_name} senderId={sender_id} senderAvatar={sender_avatar}>
<Text className="" lineHeight={undefined}>
{request}
</Text>
<Text>{request}</Text>
</MessageContainer>
);
}

View File

@ -1,9 +1,9 @@
'use client';
import React from 'react';
import { ChatHeaderOptions } from './ChatHeaderOptions';
import { ChatHeaderTitle } from './ChatHeaderTitle';
import { useChatIndividualContextSelector } from '../../ChatContext';
import { cn } from '@/lib/classMerge';
import { AppPageLayoutHeader } from '@/components/ui/layouts/AppPageLayoutHeader';
export const ChatHeader: React.FC<{
showScrollOverflow: boolean;
@ -11,19 +11,13 @@ export const ChatHeader: React.FC<{
const hasFile = useChatIndividualContextSelector((state) => state.hasFile);
const chatTitle = useChatIndividualContextSelector((state) => state.chatTitle);
if (!hasFile && !chatTitle) return null;
return (
<AppPageLayoutHeader
className={cn(
'relative z-2 flex w-full items-center justify-between space-x-2 border-b-0 px-4 transition-shadow',
showScrollOverflow && 'shadow-scroll-indicator'
)}>
{hasFile && chatTitle && (
<>
<ChatHeaderTitle />
<ChatHeaderOptions />
</>
)}
</AppPageLayoutHeader>
<>
<ChatHeaderTitle />
<ChatHeaderOptions />
</>
);
});

View File

@ -1,3 +1,5 @@
'use client';
import { AppMaterialIcons } from '@/components/ui';
import { Button } from 'antd';
import React from 'react';

View File

@ -1,4 +1,6 @@
import { Text } from '@/components/ui';
'use client';
import { Text } from '@/components/ui/typography';
import React from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { useChatIndividualContextSelector } from '../../ChatContext';

View File

@ -1,30 +1,28 @@
'use client';
import { useMessageIndividual } from '@/context/Chats';
import type { SelectedFile } from '../interfaces';
import { usePrevious } from 'ahooks';
import { useEffect } from 'react';
import { useEffect, useRef } from 'react';
export const useAutoChangeLayout = ({
lastMessageId,
onSetSelectedFile
}: {
lastMessageId: string;
onSetSelectedFile: (file: SelectedFile) => void;
}) => {
const hasSeeningReasoningPage = useRef(false); //used when there is a delay in page load
const message = useMessageIndividual(lastMessageId);
const reasoningMessagesLength = message?.reasoning?.length;
const previousReasoningMessagesLength = usePrevious(reasoningMessagesLength);
const isCompletedStream = message?.isCompletedStream;
const isLoading = !isCompletedStream;
const hasReasoning = !!reasoningMessagesLength;
const previousIsEmpty = previousReasoningMessagesLength === 0;
console.log(isLoading, previousIsEmpty, hasReasoning, message);
//change the page to reasoning file if we get a reasoning message
useEffect(() => {
if (isLoading && previousIsEmpty && hasReasoning) {
if (isLoading && !hasSeeningReasoningPage.current && hasReasoning) {
hasSeeningReasoningPage.current = true;
onSetSelectedFile({ id: lastMessageId, type: 'reasoning' });
}
}, [isLoading, hasReasoning, previousIsEmpty]);
}, [isLoading, hasReasoning]);
};

View File

@ -47,7 +47,7 @@ export const ChatLayout: React.FC<ChatSplitterProps> = React.memo(
<AppSplitter
ref={appSplitterRef}
leftChildren={<ChatContainer />}
rightChildren={<FileContainer children={children} />}
rightChildren={<FileContainer>{children}</FileContainer>}
autoSaveId="chat-splitter"
defaultLayout={defaultSplitterLayout}
rightHidden={renderViewLayoutKey === 'chat'}

View File

@ -4,7 +4,7 @@ import React from 'react';
import { useChatLayoutContextSelector } from '../../ChatLayoutContext';
import { useHotkeys } from 'react-hotkeys-hook';
import { useMemoizedFn } from 'ahooks';
import { AppTooltip } from '@/components/ui';
import { AppTooltip } from '@/components/ui/tooltip';
export const CreateChatButton = React.memo(() => {
const onCollapseFileClick = useChatLayoutContextSelector((x) => x.onCollapseFileClick);

View File

@ -1,6 +1,6 @@
import React from 'react';
import type { FileContainerSegmentProps } from './interfaces';
import type { DashboardFileView, FileView } from '../../ChatLayoutContext/useChatFileLayout';
import type { FileView } from '../../ChatLayoutContext/useChatFileLayout';
import { AppSegmented } from '@/components/ui/segmented';
import { useChatLayoutContextSelector } from '../../ChatLayoutContext';
import { useMemoizedFn } from 'ahooks';
@ -19,7 +19,14 @@ export const DashboardContainerHeaderSegment: React.FC<FileContainerSegmentProps
onSetFileView({ fileView: fileView.value });
});
return <AppSegmented options={segmentOptions} value={selectedFileView} onChange={onChange} />;
return (
<AppSegmented
type="button"
options={segmentOptions}
value={selectedFileView}
onChange={onChange}
/>
);
}
);

View File

@ -1,6 +1,8 @@
'use client';
import React from 'react';
import { CollapseFileButton } from './CollapseFileButton';
import { FileType } from '@/api/asset_interfaces';
import type { FileType } from '@/api/asset_interfaces';
import { FileContainerSegmentProps, FileContainerButtonsProps } from './interfaces';
import { DashboardContainerHeaderButtons } from './DashboardContainerHeaderButtons';
import { DashboardContainerHeaderSegment } from './DashboardContainerHeaderSegment';
@ -8,7 +10,6 @@ import { MetricContainerHeaderSegment } from './MetricContainerHeaderSegment';
import { MetricContainerHeaderButtons } from './MetricContainerHeaderButtons';
import { useChatLayoutContextSelector } from '../../ChatLayoutContext';
import { ReasoningContainerHeaderSegment } from './ReasoningContainerHeaderSegment';
import { cn } from '@/lib/utils';
export const FileContainerHeader: React.FC = React.memo(() => {
const selectedFileType = useChatLayoutContextSelector((x) => x.selectedFileType);
@ -37,11 +38,7 @@ export const FileContainerHeader: React.FC = React.memo(() => {
);
return (
<div
className={cn(
'border-b',
'flex w-full items-center justify-between space-x-1 overflow-hidden px-3'
)}>
<>
<div className="flex items-center gap-1.5">
<CollapseFileButton
collapseDirection={collapseDirection}
@ -52,7 +49,7 @@ export const FileContainerHeader: React.FC = React.memo(() => {
{selectedFileView && <SelectedFileSegment selectedFileView={selectedFileView} />}
</div>
<SelectedFileButtons selectedFileView={selectedFileView} />
</div>
</>
);
});

View File

@ -20,7 +20,14 @@ export const MetricContainerHeaderSegment: React.FC<FileContainerSegmentProps> =
onSetFileView({ fileView: fileView.value });
});
return <AppSegmented options={segmentOptions} value={selectedFileView} onChange={onChange} />;
return (
<AppSegmented
type="button"
options={segmentOptions}
value={selectedFileView}
onChange={onChange}
/>
);
}
);

View File

@ -1,3 +1,5 @@
'use client';
import React from 'react';
import { FileContainerSegmentProps } from './interfaces';
import { AppSegmented } from '@/components/ui/segmented';
@ -18,7 +20,14 @@ export const ReasoningContainerHeaderSegment: React.FC<FileContainerSegmentProps
onSetFileView({ fileView: fileView.value });
});
return <AppSegmented options={segmentOptions} value={selectedFileView} onChange={onChange} />;
return (
<AppSegmented
type="button"
options={segmentOptions}
value={selectedFileView}
onChange={onChange}
/>
);
}
);