Skip to content

Commit

Permalink
feat(chat): add new, rename and delete functionality to chat channels (
Browse files Browse the repository at this point in the history
…#320)

* fix: Resolve mention dropdown issue in @ agent selection for light mode

* feat(chat): add rename and delete functionality to chat channels

Summary:
- Add rename and delete icons to chat channels with hover effects
- Implement channel rename functionality with inline editing
- Implement channel delete functionality with confirmation
- Update channel header to display current channel name
- Convert numeric IDs to string format for message handling
- Add blue and red color indicators for rename and delete actions
  • Loading branch information
XiangZhang-zx authored Nov 17, 2024
1 parent 467f138 commit a68b0b4
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 63 deletions.
2 changes: 2 additions & 0 deletions agenthub/app/agents/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface DatasetItem {
favorites: string
}

export type DatasetsTabItem = 'Recommended' | 'Writing' | 'Entertainment' | 'Programming' | 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other';

export type AgentTabItem = 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other'


Expand Down
113 changes: 67 additions & 46 deletions agenthub/app/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,11 @@ import { AgentCommand } from '@/components/chat/body/message-box';
import { baseUrl, serverUrl } from '@/lib/env';
import { generateSixDigitId } from '@/lib/utils';



const updateChatName = (chatId: number, newName: string) => {
// setChats(prevChats =>
// prevChats.map(chat =>
// chat.id === chatId ? { ...chat, name: newName } : chat
// )
// );
};








const ChatInterface: React.FC = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [darkMode, setDarkMode] = useState<boolean>(true);
const [chats, setChats] = useState<Chat[]>([{ id: 1, name: 'General' }]);
const [chats, setChats] = useState<Chat[]>([
{ id: 1, name: 'General', messages: [] }
]);
const [activeChat, setActiveChat] = useState<number>(1);
const messagesEndRef = useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -62,7 +46,6 @@ const ChatInterface: React.FC = () => {
content: string;
}


function parseNamedContent(inputString: string) {
// Regular expression to match the pattern ?>>Name/?>>\s*Content
const regex = /\?>>(.*?)\/?>>([^?]*)/g;
Expand All @@ -85,53 +68,65 @@ const ChatInterface: React.FC = () => {
return results;
}

// Ex


useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
}, [chats]);

const handleSend = async (content: string, attachments: File[]) => {
if (content.trim() || attachments.length > 0) {
const newMessage: Message = {
id: generateSixDigitId(),
id: generateSixDigitId().toString(),
text: content,
sender: 'user',
timestamp: new Date(),
attachments: attachments.map(file => file.name),
thinking: false
};
setMessages([...messages, newMessage]);

const messageId = generateSixDigitId();
setChats(prevChats => prevChats.map(chat =>
chat.id === activeChat
? { ...chat, messages: [...chat.messages, newMessage] }
: chat
));

// Handle file uploads here (e.g., to a server)
const messageId = generateSixDigitId().toString();
const botMessage: Message = {
id: messageId,
text: ``,
text: '',
sender: 'bot',
timestamp: new Date(),
thinking: true
};

setMessages(prevMessages => [...prevMessages, botMessage]);

const res = await processAgentCommand(parseNamedContent(parseText(content))[0] as AgentCommand)

setMessages(prevMessages => [...prevMessages].map(message => {
if (message.id == messageId) {
return { ...message, thinking: false, text: res.content };
}
// return res.content;
return message;
}));
setChats(prevChats => prevChats.map(chat =>
chat.id === activeChat
? { ...chat, messages: [...chat.messages, botMessage] }
: chat
));

const res = await processAgentCommand(parseNamedContent(parseText(content))[0] as AgentCommand);

setChats(prevChats => prevChats.map(chat =>
chat.id === activeChat
? {
...chat,
messages: chat.messages.map(message =>
message.id === messageId
? { ...message, thinking: false, text: res.content }
: message
)
}
: chat
));
}

};

const addChat = () => {
const newChat: Chat = { id: Date.now(), name: `Chat ${chats.length + 1}` };
const newChat: Chat = {
id: Date.now(),
name: `Chat ${chats.length + 1}`,
messages: []
};
setChats([...chats, newChat]);
setActiveChat(newChat.id);
};
Expand Down Expand Up @@ -178,7 +173,6 @@ const ChatInterface: React.FC = () => {
recent_response = "Agent Had Difficulty Thinking"
}


//return recent_response
return {
name: command.name,
Expand All @@ -188,6 +182,29 @@ const ChatInterface: React.FC = () => {

const mounted = useMounted();

const activeMessages = chats.find(chat => chat.id === activeChat)?.messages || [];

// Add updateChatName function
const updateChatName = (chatId: number, newName: string) => {
setChats(prevChats =>
prevChats.map(chat =>
chat.id === chatId ? { ...chat, name: newName } : chat
)
);
};

// Add deleteChat function
const deleteChat = (chatId: number) => {
setChats(prevChats => {
const filteredChats = prevChats.filter(chat => chat.id !== chatId);
// If the deleted chat is the active one, switch to the first chat
if (chatId === activeChat && filteredChats.length > 0) {
setActiveChat(filteredChats[0].id);
}
return filteredChats;
});
};

return (
<div className={`flex h-screen ${darkMode ? 'bg-gray-900' : 'bg-gray-50'}`}>
<Sidebar
Expand All @@ -196,11 +213,16 @@ const ChatInterface: React.FC = () => {
setActiveChat={setActiveChat}
addChat={addChat}
updateChatName={updateChatName}
deleteChat={deleteChat}
darkMode={darkMode}
/>
<div className="flex flex-col flex-grow pb-4">
<Header darkMode={darkMode} setDarkMode={setDarkMode} />
<MessageList messages={messages} darkMode={darkMode} />
<Header
darkMode={darkMode}
setDarkMode={setDarkMode}
title={chats.find(chat => chat.id === activeChat)?.name || 'Chat'}
/>
<MessageList messages={activeMessages} darkMode={darkMode} />
<div className='w-full flex h-fit justify-center'>
{mounted && <ChatEditor onSend={handleSend} darkMode={darkMode} />}
</div>
Expand All @@ -211,5 +233,4 @@ const ChatInterface: React.FC = () => {
);
};


export default ChatInterface;
7 changes: 4 additions & 3 deletions agenthub/components/agentchat/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import { Sun, Moon, Hash } from 'lucide-react';

export interface HeaderProps {
darkMode: boolean;
setDarkMode: React.Dispatch<React.SetStateAction<boolean>>;
setDarkMode: (value: boolean) => void;
title: string;
}

export const Header: React.FC<HeaderProps> = ({ darkMode, setDarkMode }) => {
export const Header: React.FC<HeaderProps> = ({ darkMode, setDarkMode, title }) => {
const theme = useMantineTheme();
return (
<div className={`flex justify-between items-center p-3 border-b ${darkMode ? 'bg-gray-900 text-white border-gray-800' : 'bg-white text-black border-gray-200'}`}>
<div className="flex items-center space-x-2">
<Hash size={20} className="text-gray-500" />
<h1 className="text-lg font-medium">General</h1>
<h1 className="text-lg font-medium">{title}</h1>
</div>
<div className="flex items-center space-x-2">
<Sun size={16} className={darkMode ? 'text-gray-400' : 'text-yellow-500'} />
Expand Down
60 changes: 46 additions & 14 deletions agenthub/components/agentchat/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from 'react';

import { TextInput, ActionIcon, Tooltip } from '@mantine/core';
import { Plus, Hash, Check, Edit2, X } from 'lucide-react';
import { Plus, Hash, Check, Edit2, X, Trash2 } from 'lucide-react';
import { Chat } from '@/interfaces/agentchat';


Expand All @@ -11,10 +11,11 @@ export interface SidebarProps {
setActiveChat: (id: number) => void;
addChat: () => void;
updateChatName: (chatId: number, newName: string) => void;
deleteChat: (chatId: number) => void;
darkMode: boolean;
}

export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveChat, addChat, updateChatName, darkMode }) => {
export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveChat, addChat, updateChatName, deleteChat, darkMode }) => {
const [editingId, setEditingId] = useState<number | null>(null);
const [editingName, setEditingName] = useState('');

Expand All @@ -40,6 +41,13 @@ export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveCh
}
};

const handleDelete = (chatId: number, e: React.MouseEvent) => {
e.stopPropagation();
if (window.confirm('Are you sure you want to delete this channel?')) {
deleteChat(chatId);
}
};

return (
<div className={`w-60 flex-shrink-0 ${darkMode ? 'bg-gray-800' : 'bg-gray-100'} p-3 flex flex-col`}>
<div className={`p-4 ${darkMode ? 'bg-gray-700' : 'bg-gray-200'} rounded-lg mb-4`}>
Expand All @@ -54,7 +62,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveCh
onClick={addChat}
variant="subtle"
color={darkMode ? "gray" : "dark"}
className="hover:bg-gray-600 pointer-events-none hover:pointer-events-none"
className="hover:bg-gray-600 cursor-pointer"
>
<Plus size={16} />
</ActionIcon>
Expand All @@ -63,7 +71,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveCh
{chats.map((chat) => (
<div
key={chat.id}
className={`${channelStyle} ${chat.id === activeChat ? activeChannelStyle : inactiveChannelStyle}`}
className={`${channelStyle} group ${chat.id === activeChat ? activeChannelStyle : inactiveChannelStyle}`}
>
{editingId === chat.id ? (
<div className="flex items-center w-full">
Expand All @@ -89,16 +97,38 @@ export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveCh
<Hash size={16} className="mr-2 flex-shrink-0" />
<span className="truncate">{chat.name}</span>
</div>
<Tooltip label="Rename Channel" position="right">
<ActionIcon
onClick={() => startEditing(chat)}
variant="subtle"
color={darkMode ? "gray" : "dark"}
className="opacity-0 group-hover:opacity-100 transition-opacity duration-200"
>
<Edit2 size={14} />
</ActionIcon>
</Tooltip>
<div className="flex items-center">
<Tooltip label="Rename Channel" position="right">
<ActionIcon
onClick={(e) => {
e.stopPropagation();
startEditing(chat);
}}
variant="subtle"
color={darkMode ? "gray" : "dark"}
size="sm"
className="ml-1"
>
<Edit2
size={14}
className={darkMode ? "text-blue-400 hover:text-blue-300" : "text-blue-600 hover:text-blue-500"}
/>
</ActionIcon>
</Tooltip>
<Tooltip label="Delete Channel" position="right">
<ActionIcon
onClick={(e) => handleDelete(chat.id, e)}
variant="subtle"
size="sm"
className="ml-1"
>
<Trash2
size={14}
className="text-red-400 hover:text-red-300"
/>
</ActionIcon>
</Tooltip>
</div>
</>
)}
</div>
Expand All @@ -107,3 +137,5 @@ export const Sidebar: React.FC<SidebarProps> = ({ chats, activeChat, setActiveCh
</div>
);
};

export default Sidebar;
14 changes: 14 additions & 0 deletions agenthub/interfaces/agentchat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface Message {
id: string;
text: string;
sender: 'user' | 'bot';
timestamp: Date;
attachments?: string[];
thinking?: boolean;
}

export interface Chat {
id: number;
name: string;
messages: Message[];
}

0 comments on commit a68b0b4

Please sign in to comment.