mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-09 05:39:12 +00:00
Change overall architecure of how information is flowing for better statefulness
This commit is contained in:
@@ -19,7 +19,7 @@ import { Label } from "@/components/ui/label"
|
|||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
|
||||||
export function TextareaWithLabel() {
|
function TextareaWithLabel() {
|
||||||
return (
|
return (
|
||||||
<div className="grid w-full gap-1.5">
|
<div className="grid w-full gap-1.5">
|
||||||
{/* <Label htmlFor="message">Your message</Label> */}
|
{/* <Label htmlFor="message">Your message</Label> */}
|
||||||
@@ -36,7 +36,7 @@ const styleClassOptions = ['pink', 'blue', 'green', 'yellow', 'purple'];
|
|||||||
interface ChatBodyDataProps {
|
interface ChatBodyDataProps {
|
||||||
chatOptionsData: ChatOptions | null;
|
chatOptionsData: ChatOptions | null;
|
||||||
setTitle: (title: string) => void;
|
setTitle: (title: string) => void;
|
||||||
setConversationID?: (conversationId: string) => void;
|
onConversationIdChange?: (conversationId: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -44,9 +44,11 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const conversationId = searchParams.get('conversationId');
|
const conversationId = searchParams.get('conversationId');
|
||||||
|
|
||||||
if (conversationId && props.setConversationID) {
|
useEffect(() => {
|
||||||
props.setConversationID(conversationId);
|
if (conversationId) {
|
||||||
}
|
props.onConversationIdChange?.(conversationId);
|
||||||
|
}
|
||||||
|
}, [conversationId, props.onConversationIdChange]);
|
||||||
|
|
||||||
if (!conversationId) {
|
if (!conversationId) {
|
||||||
return (
|
return (
|
||||||
@@ -65,9 +67,25 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={false ? styles.chatBody : styles.chatBodyFull}>
|
<>
|
||||||
<ChatHistory conversationId={conversationId} setTitle={props.setTitle} />
|
<div className={false ? styles.chatBody : styles.chatBodyFull}>
|
||||||
</div>
|
<ChatHistory conversationId={conversationId} setTitle={props.setTitle} />
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.inputBox} bg-background align-middle items-center justify-center`}>
|
||||||
|
<Button variant={'ghost'} className="!bg-none p-1 h-auto text-3xl rounded-full !hover:bg-accent ">
|
||||||
|
<FileArrowUp fill="hsl(var(--accent-foreground))" />
|
||||||
|
</Button>
|
||||||
|
<TextareaWithLabel />
|
||||||
|
<Button variant={'ghost'} className="!bg-none p-1 h-auto text-3xl rounded-full !hover:bg-accent">
|
||||||
|
<Microphone fill="hsl(var(--accent-foreground))" />
|
||||||
|
</Button>
|
||||||
|
<Button className="bg-orange-300 hover:bg-orange-500 rounded-full p-0 h-auto text-3xl">
|
||||||
|
<ArrowCircleUp />
|
||||||
|
</Button>
|
||||||
|
{/* <input className={styles.inputBox} type="text" placeholder="Type / to see a list of commands" onInput={(e) => handleChatInput(e)} /> */}
|
||||||
|
{/* <button className={styles.inputBox}>Send</button> */}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +128,10 @@ export default function Chat() {
|
|||||||
})();
|
})();
|
||||||
}, [conversationId]);
|
}, [conversationId]);
|
||||||
|
|
||||||
|
const handleConversationIdChange = (newConversationId: string) => {
|
||||||
|
setConversationID(newConversationId);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
@@ -118,42 +140,23 @@ export default function Chat() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.main + " " + styles.chatLayout}>
|
<div className={styles.main + " " + styles.chatLayout}>
|
||||||
<div className={styles.sidePanel}>
|
|
||||||
<SidePanel webSocketConnected={chatWS !== null} />
|
|
||||||
</div>
|
|
||||||
<title>
|
<title>
|
||||||
Khoj AI - Chat
|
{title}
|
||||||
</title>
|
</title>
|
||||||
<div className={styles.chatBox}>
|
<Suspense fallback={<Loading />}>
|
||||||
<NavMenu selected="Chat" title={title} />
|
<div className={styles.sidePanel}>
|
||||||
<div className={styles.chatBoxBody}>
|
<SidePanel webSocketConnected={chatWS !== null} />
|
||||||
<div>
|
</div>
|
||||||
<Suspense fallback={<Loading />}>
|
<div className={styles.chatBox}>
|
||||||
<ChatBodyData chatOptionsData={chatOptionsData} setTitle={setTitle} setConversationID={setConversationID} />
|
<NavMenu selected="Chat" title={title} />
|
||||||
</Suspense>
|
<div className={styles.chatBoxBody}>
|
||||||
</div>
|
<ChatBodyData
|
||||||
{/* <div className={styles.agentIndicator}>
|
chatOptionsData={chatOptionsData}
|
||||||
<a className='no-underline' href="/agents?agent=khoj" target="_blank" rel="noreferrer">
|
setTitle={setTitle}
|
||||||
<Lightbulb color='var(--khoj-orange)' weight='fill' />
|
onConversationIdChange={handleConversationIdChange} />
|
||||||
<span className='text-neutral-600'>Khoj</span>
|
|
||||||
</a>
|
|
||||||
</div> */}
|
|
||||||
<div className={`${styles.inputBox} bg-background align-middle items-center justify-center`}>
|
|
||||||
<Button className="!bg-transparent !hover:bg-transparent p-0 h-auto text-3xl">
|
|
||||||
<FileArrowUp fill="hsla(var(--secondary-foreground))"/>
|
|
||||||
</Button>
|
|
||||||
<TextareaWithLabel />
|
|
||||||
<Button className="!bg-transparent !hover:bg-transparent p-0 h-auto text-3xl">
|
|
||||||
<Microphone fill="hsla(var(--secondary-foreground))"/>
|
|
||||||
</Button>
|
|
||||||
<Button className="bg-orange-300 hover:bg-orange-500 rounded-full p-0 h-auto text-3xl">
|
|
||||||
<ArrowCircleUp/>
|
|
||||||
</Button>
|
|
||||||
{/* <input className={styles.inputBox} type="text" placeholder="Type / to see a list of commands" onInput={(e) => handleChatInput(e)} /> */}
|
|
||||||
{/* <button className={styles.inputBox}>Send</button> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ interface ChatSessionsModalProps {
|
|||||||
data: GroupedChatHistory | null;
|
data: GroupedChatHistory | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// function ConversationList()
|
||||||
|
|
||||||
function ChatSessionsModal({ data }: ChatSessionsModalProps) {
|
function ChatSessionsModal({ data }: ChatSessionsModalProps) {
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog>
|
||||||
@@ -188,6 +191,49 @@ function ChatSessionsModal({ data }: ChatSessionsModalProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UserProfileProps {
|
||||||
|
userProfile: UserProfile;
|
||||||
|
webSocketConnected?: boolean;
|
||||||
|
collapsed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function UserProfileComponent(props: UserProfileProps) {
|
||||||
|
if (props.collapsed) {
|
||||||
|
return (
|
||||||
|
<div className={styles.profile}>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage src={props.userProfile.photo} alt="user profile" />
|
||||||
|
<AvatarFallback>
|
||||||
|
{props.userProfile.username[0]}
|
||||||
|
</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.profile}>
|
||||||
|
<Avatar>
|
||||||
|
<AvatarImage src={props.userProfile.photo} alt="user profile" />
|
||||||
|
<AvatarFallback>
|
||||||
|
{props.userProfile.username[0]}
|
||||||
|
</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div className={styles.profileDetails}>
|
||||||
|
<p>{props.userProfile?.username}</p>
|
||||||
|
{/* Connected Indicator */}
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
|
<div className={`inline-flex h-4 w-4 rounded-full opacity-75 ${props.webSocketConnected ? 'bg-green-500' : 'bg-rose-500'}`}></div>
|
||||||
|
<p className="text-muted-foreground text-sm">
|
||||||
|
{props.webSocketConnected ? "Connected" : "Disconnected"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const fetchChatHistory = async (url: string) => {
|
const fetchChatHistory = async (url: string) => {
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -303,38 +349,14 @@ export default function SidePanel(props: SidePanelProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
{userProfile &&
|
{userProfile &&
|
||||||
<div className={styles.profile}>
|
<UserProfileComponent userProfile={userProfile} webSocketConnected={props.webSocketConnected} collapsed={false} />
|
||||||
<Avatar>
|
|
||||||
<AvatarImage src={userProfile.photo} alt="user profile" />
|
|
||||||
<AvatarFallback>
|
|
||||||
{userProfile.username[0]}
|
|
||||||
</AvatarFallback>
|
|
||||||
</Avatar>
|
|
||||||
<div className={styles.profileDetails}>
|
|
||||||
<p>{userProfile?.username}</p>
|
|
||||||
{/* Connected Indicator */}
|
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
<div className={`inline-flex h-4 w-4 rounded-full opacity-75 ${props.webSocketConnected ? 'bg-green-500' : 'bg-rose-500'}`}></div>
|
|
||||||
<p className="text-muted-foreground text-sm">
|
|
||||||
{props.webSocketConnected ? "Connected" : "Disconnected"}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div>
|
<div>
|
||||||
<div className={`${styles.collapsed}`}>
|
<div className={`${styles.collapsed}`}>
|
||||||
{userProfile &&
|
{ userProfile &&
|
||||||
<div className={styles.profile}>
|
<UserProfileComponent userProfile={userProfile} webSocketConnected={props.webSocketConnected} collapsed={true} />
|
||||||
<Avatar className="max-w-6 max-h-6 rounded-full">
|
|
||||||
<AvatarImage src={userProfile.photo} alt="user profile" />
|
|
||||||
<AvatarFallback>
|
|
||||||
{userProfile.username[0]}
|
|
||||||
</AvatarFallback>
|
|
||||||
</Avatar>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
<button className={styles.button} onClick={() => setEnabled(true)}>
|
<button className={styles.button} onClick={() => setEnabled(true)}>
|
||||||
{/* Pull Open Icon */}
|
{/* Pull Open Icon */}
|
||||||
|
|||||||
Reference in New Issue
Block a user