Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 2 additions & 53 deletions browser/src/components/AssistantFooter/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import { CheckOutlined } from '@ant-design/icons';
import { Button, Flex, Spin } from 'antd';
import { Button, Flex } from 'antd';
import { useEffect, useState } from 'react';
import { useSnapshot } from 'valtio';
import { useClipboard } from '@/hooks/useClipboard';
import CopyIcon from '@/icons/copy.svg?react';
import DislikeIcon from '@/icons/dislike.svg?react';
import LikeIcon from '@/icons/like.svg?react';
import RefreshIcon from '@/icons/refresh.svg?react';
import type { AppStatus } from '@/state/chat';
import { state } from '@/state/sender';
import type { Message } from '@/types/chat';
import ActivityIndicator from '../ActivityIndicator';
import styles from './index.module.css';

interface AssistantFooterProps {
message: Message;
status: AppStatus;
}

const AssistantFooter: React.FC<AssistantFooterProps> = ({
message,
status,
}) => {
const { mode } = useSnapshot(state);
const AssistantFooter: React.FC<AssistantFooterProps> = ({ message }) => {
const { writeText } = useClipboard();
const [isCopySuccess, setIsCopySuccess] = useState(false);

Expand Down Expand Up @@ -57,48 +48,6 @@ const AssistantFooter: React.FC<AssistantFooterProps> = ({
}
}, [isCopySuccess]);

if (mode === 'plan' && status === 'idle') {
// const lastMessage = message;
// if (
// lastMessage?.type === UIMessageType.Text &&
// lastMessage.mode === 'plan'
// ) {
// return (
// <div className="w-full p-2 border-t border-gray-100 bg-gray-50/50">
// <Flex justify="space-between" align="center" className="w-full">
// <Text
// type="secondary"
// className="text-sm text-gray-600 flex-1 mr-4"
// >
// {t('plan.approveDescription')}
// </Text>
// <Button
// type="primary"
// size="middle"
// icon={<RefreshIcon />}
// className="shrink-0"
// onClick={async () => {
// actions.updateMode('agent');
// console.log('approvePlan', message);
// }}
// >
// {t('plan.approve')}
// </Button>
// </Flex>
// </div>
// );
// }
}

if (status !== 'idle') {
return (
<div className="flex items-center space-x-2 pt-2">
<Spin size="small" />
<ActivityIndicator />
</div>
);
}

return (
<Flex className={styles.assistantFooter}>
<Button
Expand Down
52 changes: 41 additions & 11 deletions browser/src/components/ChatContent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Bubble } from '@ant-design/x';
import { type GetProp, Skeleton } from 'antd';
import { type GetProp, Skeleton, Spin } from 'antd';
import { useSnapshot } from 'valtio';
import AssistantFooter from '@/components/AssistantFooter';
import AssistantMessage from '@/components/AssistantMessage';
Expand All @@ -10,26 +10,56 @@ import Welcome from '@/components/Welcome';
import { state } from '@/state/chat';
import type { Message } from '@/types/chat';
import styles from './index.module.css';
import ActivityIndicator from '../ActivityIndicator';

const ChatContent: React.FC = () => {
const { messages, status } = useSnapshot(state);

// Check if assistant loading needs to be displayed
const shouldShowAssistantLoading =
status !== 'idle' &&
messages &&
messages.length > 0 &&
messages[messages.length - 1].role === 'user';

const items = messages?.map((message, index) => {
const isLastMessage = index === messages.length - 1;

const footer = () => {
// If it's the last message and it's an assistant message, show the assistant footer
if (isLastMessage && message.role === 'assistant') {
return <AssistantFooter message={message as Message} />;
}
// Otherwise, show the normal user message footer
return <UserMessageFooter message={message as Message} />;
};

return {
...message,
content: message,
// typing: status === 'processing' ? { step: 20, interval: 150 } : false,
// loading: status === 'processing_stream' && isLastMessage,
footer:
isLastMessage && message.role === 'assistant'
? () => (
<AssistantFooter message={message as Message} status={status} />
)
: () => <UserMessageFooter message={message as Message} />,
footer: footer,
};
});

// If assistant loading needs to be displayed, add a loading item
const finalItems =
shouldShowAssistantLoading && items
? [
...items,
{
role: 'assistant',
content: '',
loading: true,
footer: () => (
<div className="flex items-center space-x-2 pt-2">
<Spin size="small" />
<ActivityIndicator />
</div>
),
},
]
: items;

const roles: GetProp<typeof Bubble.List, 'roles'> = {
user: {
placement: 'end',
Expand Down Expand Up @@ -67,9 +97,9 @@ const ChatContent: React.FC = () => {
return (
<div className={styles.chat}>
<div className={styles.chatList}>
{items?.length ? (
{finalItems?.length ? (
<Bubble.List
items={items}
items={finalItems}
className={styles.bubbleList}
roles={roles}
/>
Expand Down
3 changes: 1 addition & 2 deletions browser/src/components/Sider/Conversations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const useStyle = createStyles(({ token, css }) => {

&:hover {
background: ${token.colorBgTextHover};
transform: translateX(4px);

.ant-conversations-item-content {
color: ${token.colorPrimary};
Expand Down Expand Up @@ -90,7 +89,7 @@ const useStyle = createStyles(({ token, css }) => {
conversationsContent: css`
width: 100%;
flex: 1;
overflow-y: auto;
overflow-y: scroll;
overflow-x: hidden;
min-height: 0;
padding-right: 4px;
Expand Down
Loading