diff --git a/community-chatbot/.gitignore b/community-chatbot/.gitignore
index f398c97d..e7fbc9c1 100644
--- a/community-chatbot/.gitignore
+++ b/community-chatbot/.gitignore
@@ -31,3 +31,4 @@ next-env.d.ts
__pycache__/
*.sql
*.py
+Jira/
\ No newline at end of file
diff --git a/community-chatbot/app/globals.css b/community-chatbot/app/globals.css
index ac684423..86d0524e 100644
--- a/community-chatbot/app/globals.css
+++ b/community-chatbot/app/globals.css
@@ -92,3 +92,44 @@ body {
@apply bg-background text-foreground;
}
}
+
+@layer utilities {
+
+ /* Minimal aesthetic scrollbar */
+ .scrollbar-aesthetic {
+ overflow-y: auto;
+ scrollbar-width: thin;
+ scrollbar-color: rgba(0, 0, 0, 0.8) transparent;
+ }
+
+ /* Chrome / Edge / Safari */
+ .scrollbar-aesthetic::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ .scrollbar-aesthetic::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ .scrollbar-aesthetic::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.5);
+ border-radius: 9999px;
+ }
+
+ .scrollbar-aesthetic::-webkit-scrollbar-thumb:hover {
+ background: rgba(0, 0, 0, 1);
+ }
+
+ /* Dark mode */
+ .dark .scrollbar-aesthetic {
+ scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
+ }
+
+ .dark .scrollbar-aesthetic::-webkit-scrollbar-thumb {
+ background: rgba(255, 255, 255, 0.3);
+ }
+
+ .dark .scrollbar-aesthetic::-webkit-scrollbar-thumb:hover {
+ background: rgba(255, 255, 255, 0.5);
+ }
+}
\ No newline at end of file
diff --git a/community-chatbot/components/agent/Mode/Chat/InputBox.tsx b/community-chatbot/components/agent/Mode/Chat/InputBox.tsx
index 774c9add..9a34ad07 100644
--- a/community-chatbot/components/agent/Mode/Chat/InputBox.tsx
+++ b/community-chatbot/components/agent/Mode/Chat/InputBox.tsx
@@ -1,8 +1,11 @@
+import {
+ MessageInput,
+} from '@/components/agent/Mode/Chat/InputBox/MessageInput';
+import {
+ SubmitButton,
+} from '@/components/agent/Mode/Chat/InputBox/SubmitButton';
import { useSendMessage } from '@/hooks/agent/Mode/Chat/useSendMessage';
-import { MessageInput } from './InputBox/MessageInput';
-import { SubmitButton } from './InputBox/SubmitButton';
-
export function InputBox() {
const { handleSendMessage } = useSendMessage();
const handleSubmit = async (event?: React.FormEvent) => {
@@ -13,11 +16,11 @@ export function InputBox() {
return (
);
-}
\ No newline at end of file
+}
diff --git a/community-chatbot/components/agent/Mode/Chat/InputBox/MessageInput.tsx b/community-chatbot/components/agent/Mode/Chat/InputBox/MessageInput.tsx
index e10a0de9..3f74d580 100644
--- a/community-chatbot/components/agent/Mode/Chat/InputBox/MessageInput.tsx
+++ b/community-chatbot/components/agent/Mode/Chat/InputBox/MessageInput.tsx
@@ -1,28 +1,42 @@
import { usePathname } from 'next/navigation';
+import Textarea from 'react-textarea-autosize';
-import { Input } from '@/components/ui/input';
+import { useSendMessage } from '@/hooks/agent/Mode/Chat/useSendMessage';
import { integrationModes } from '@/lib/constants/chat';
import { useAgentStore } from '@/lib/store/agent/agentStore';
export function MessageInput() {
const { input, setInput, status } = useAgentStore();
+ const { handleSendMessage } = useSendMessage();
const pathname = usePathname();
const currentMode = pathname.split('/')[1];
const name = integrationModes.find((m) => m.id === currentMode)?.name;
- const handleInputChange = (e: React.ChangeEvent) => {
+ const handleInputChange = (e: React.ChangeEvent) => {
setInput(e.target.value);
};
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter' && !e.shiftKey) {
+ e.preventDefault();
+ if (input.trim()) {
+ handleSendMessage();
+ }
+ }
+ };
+
return (
-
-
+
);
diff --git a/community-chatbot/components/agent/Mode/Chat/InputBox/SubmitButton.tsx b/community-chatbot/components/agent/Mode/Chat/InputBox/SubmitButton.tsx
index cffbd9fd..8ff4fc49 100644
--- a/community-chatbot/components/agent/Mode/Chat/InputBox/SubmitButton.tsx
+++ b/community-chatbot/components/agent/Mode/Chat/InputBox/SubmitButton.tsx
@@ -19,7 +19,7 @@ export function SubmitButton() {
type="submit"
size="icon"
disabled={!input.trim() || status !== "ready"}
- className="bg-blue-600 hover:bg-blue-700"
+ className="bg-blue-600 hover:bg-blue-700 mb-2 text-white"
>
diff --git a/community-chatbot/components/agent/Mode/Chat/Panel/ChatAvatar.tsx b/community-chatbot/components/agent/Mode/Chat/Panel/ChatAvatar.tsx
deleted file mode 100644
index 5f0ce12d..00000000
--- a/community-chatbot/components/agent/Mode/Chat/Panel/ChatAvatar.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Bot, User } from 'lucide-react';
-
-import { Avatar, AvatarFallback } from '@/components/ui/avatar';
-
-interface ChatAvatarProps {
- role: "user" | "assistant"
-}
-
-export function ChatAvatar({ role }: ChatAvatarProps) {
- if (role === "user") {
- return (
-
-
-
-
-
- )
- } else {
- return (
-
-
-
-
-
- )
- }
-}
diff --git a/community-chatbot/components/agent/Mode/Chat/Panel/CopyButton.tsx b/community-chatbot/components/agent/Mode/Chat/Panel/CopyButton.tsx
new file mode 100644
index 00000000..d67ae642
--- /dev/null
+++ b/community-chatbot/components/agent/Mode/Chat/Panel/CopyButton.tsx
@@ -0,0 +1,41 @@
+'use client';
+
+import { useState } from 'react';
+import { Check, Copy } from 'lucide-react';
+
+import { Button } from '@/components/ui/button';
+import { cn } from '@/lib/utils';
+
+interface CopyButtonProps {
+ textToCopy: string;
+ className?: string;
+}
+
+export function CopyButton({ textToCopy, className }: CopyButtonProps) {
+ const [isCopied, setIsCopied] = useState(false);
+
+ const handleCopy = async () => {
+ try {
+ await navigator.clipboard.writeText(textToCopy);
+ setIsCopied(true);
+ setTimeout(() => setIsCopied(false), 2000); // Reset after 2 seconds
+ } catch (err) {
+ console.error('Failed to copy text: ', err);
+ }
+ };
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/community-chatbot/components/agent/Mode/Chat/Panel/MessageList.tsx b/community-chatbot/components/agent/Mode/Chat/Panel/MessageList.tsx
index 911119b1..ccf88edc 100644
--- a/community-chatbot/components/agent/Mode/Chat/Panel/MessageList.tsx
+++ b/community-chatbot/components/agent/Mode/Chat/Panel/MessageList.tsx
@@ -1,23 +1,26 @@
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
-import { ChatAvatar } from '@/components/agent/Mode/Chat/Panel/ChatAvatar';
import { Message } from '@/types/chat/types';
+import { CopyButton } from '@/components/agent/Mode/Chat/Panel/CopyButton';
interface MessageListProps {
- messages:Message[]
+ messages: Message[];
}
export function MessageList({ messages }: MessageListProps) {
return (
- <>
+
{messages.map((message) => (
-
- {message.role === "assistant" &&
}
+
@@ -26,9 +29,12 @@ export function MessageList({ messages }: MessageListProps) {
- {message.role === "user" &&
}
+
))}
- >
+
);
-}
+}
\ No newline at end of file
diff --git a/community-chatbot/package.json b/community-chatbot/package.json
index 5cbdf6bc..dfe050ce 100644
--- a/community-chatbot/package.json
+++ b/community-chatbot/package.json
@@ -62,6 +62,7 @@
"react-hook-form": "^7.54.1",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^2.1.7",
+ "react-textarea-autosize": "^8.5.9",
"recharts": "2.15.0",
"remark-gfm": "^4.0.1",
"sonner": "^1.7.1",
diff --git a/community-chatbot/pnpm-lock.yaml b/community-chatbot/pnpm-lock.yaml
index 03c676e3..5dbe5f4a 100644
--- a/community-chatbot/pnpm-lock.yaml
+++ b/community-chatbot/pnpm-lock.yaml
@@ -164,6 +164,9 @@ importers:
react-resizable-panels:
specifier: ^2.1.7
version: 2.1.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react-textarea-autosize:
+ specifier: ^8.5.9
+ version: 8.5.9(@types/react@18.3.24)(react@18.3.1)
recharts:
specifier: 2.15.0
version: 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -3623,6 +3626,12 @@ packages:
'@types/react':
optional: true
+ react-textarea-autosize@8.5.9:
+ resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
react-transition-group@4.4.5:
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
peerDependencies:
@@ -3973,6 +3982,33 @@ packages:
'@types/react':
optional: true
+ use-composed-ref@1.4.0:
+ resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ use-isomorphic-layout-effect@1.2.1:
+ resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ use-latest@1.3.0:
+ resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
use-sidecar@1.1.3:
resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
engines: {node: '>=10'}
@@ -8122,6 +8158,15 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.24
+ react-textarea-autosize@8.5.9(@types/react@18.3.24)(react@18.3.1):
+ dependencies:
+ '@babel/runtime': 7.28.4
+ react: 18.3.1
+ use-composed-ref: 1.4.0(@types/react@18.3.24)(react@18.3.1)
+ use-latest: 1.3.0(@types/react@18.3.24)(react@18.3.1)
+ transitivePeerDependencies:
+ - '@types/react'
+
react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.28.4
@@ -8519,6 +8564,25 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.24
+ use-composed-ref@1.4.0(@types/react@18.3.24)(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.24
+
+ use-isomorphic-layout-effect@1.2.1(@types/react@18.3.24)(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.24
+
+ use-latest@1.3.0(@types/react@18.3.24)(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ use-isomorphic-layout-effect: 1.2.1(@types/react@18.3.24)(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.24
+
use-sidecar@1.1.3(@types/react@18.3.24)(react@18.3.1):
dependencies:
detect-node-es: 1.1.0