Upgrade: New Home Screen for Khoj (#860)

* V1 of the new automations page
Implemented:
- Shareable
- Editable
- Suggested Cards
- Create new cards
- added side panel new conversation button
- Implement mobile-friendly view for homepage
- Fix issue of new conversations being created when selected agent is changed
- Improve center of the homepage experience
- Fix showing agent during first chat experience
- dark mode gradient updates

---------

Co-authored-by: sabaimran <narmiabas@gmail.com>
This commit is contained in:
Raghav Tirumale
2024-07-24 03:46:19 -04:00
committed by GitHub
parent 9cf52bb7e4
commit 3e4325edab
23 changed files with 10964 additions and 1039 deletions

View File

@@ -4,10 +4,14 @@ div.main {
}
.suggestions {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
display: flex;
overflow-x: none;
height: 50%;
padding: 10px;
white-space: nowrap;
/* grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); */
gap: 1rem;
justify-content: center;
/* justify-content: center; */
}
div.inputBox {
@@ -124,3 +128,33 @@ div.agentIndicator {
}
}
#pink {
background-color: #f8d1f8;
color: #000000;
background-image: linear-gradient(to top, #f8d1f8 1%, white 100%);
}
#blue {
background-color: #d1f8f8;
color: #000000;
background-image: linear-gradient(to top, #d1f8f8 1%, white 100%);
}
#green {
background-color: #d1f8d1;
color: #000000;
background-image: linear-gradient(to top, #d1f8d1 1%, white 100%);
}
#purple {
background-color: #f8d1f8;
color: #000000;
background-image: linear-gradient(to top, #f8d1f8 1%, white 100%);
}
#yellow {
background-color: #f8f8d1;
color: #000000;
background-image: linear-gradient(to top, #f8f8d1 1%, white 100%);
}

View File

@@ -3,7 +3,6 @@
import styles from './chat.module.css';
import React, { Suspense, useEffect, useState } from 'react';
import SuggestionCard from '../components/suggestions/suggestionCard';
import SidePanel from '../components/sidePanel/chatHistorySidePanel';
import ChatHistory from '../components/chatHistory/chatHistory';
import NavMenu from '../components/navMenu/navMenu';
@@ -19,9 +18,6 @@ import { welcomeConsole } from '../common/utils';
import ChatInputArea, { ChatOptions } from '../components/chatInputArea/chatInputArea';
import { useAuthenticatedData } from '../common/auth';
const styleClassOptions = ['pink', 'blue', 'green', 'yellow', 'purple'];
interface ChatBodyDataProps {
chatOptionsData: ChatOptions | null;
setTitle: (title: string) => void;
@@ -40,43 +36,38 @@ function ChatBodyData(props: ChatBodyDataProps) {
const [processingMessage, setProcessingMessage] = useState(false);
useEffect(() => {
if (conversationId) {
props.onConversationIdChange?.(conversationId);
const storedMessage = localStorage.getItem("message");
if (storedMessage) {
setMessage(storedMessage);
}
}, [conversationId, props.onConversationIdChange]);
}, []);
useEffect(() => {
if (message) {
if(message){
setProcessingMessage(true);
props.setQueryToProcess(message);
}
}, [message]);
useEffect(() => {
if (conversationId) {
props.onConversationIdChange?.(conversationId);
}
}, [conversationId]);
useEffect(() => {
if (props.streamedMessages &&
props.streamedMessages.length > 0 &&
props.streamedMessages[props.streamedMessages.length - 1].completed) {
setProcessingMessage(false);
} else {
setMessage('');
}
}, [props.streamedMessages]);
if (!conversationId) {
return (
<div className={styles.suggestions}>
{props.chatOptionsData && Object.entries(props.chatOptionsData).map(([key, value]) => (
<SuggestionCard
key={key}
title={`/${key}`}
body={value}
link='#' // replace with actual link if available
styleClass={styleClassOptions[Math.floor(Math.random() * styleClassOptions.length)]}
/>
))}
</div>
);
if(!conversationId) {
window.location.href = '/';
return;
}
return (
@@ -88,7 +79,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
pendingMessage={processingMessage ? message : ''}
incomingMessages={props.streamedMessages} />
</div>
<div className={`${styles.inputBox} bg-background align-middle items-center justify-center px-3`}>
<div className={`${styles.inputBox} bg-background align-middle items-center justify-center px-3 dark:bg-neutral-700 dark:border-0 dark:shadow-sm`}>
<ChatInputArea
isLoggedIn={props.isLoggedIn}
sendMessage={(message) => setMessage(message)}
@@ -121,7 +112,6 @@ export default function Chat() {
const handleWebSocketMessage = (event: MessageEvent) => {
let chunk = event.data;
let currentMessage = messages.find(message => !message.completed);
if (!currentMessage) {
console.error("No current message found");
return;
@@ -205,51 +195,72 @@ export default function Chat() {
}, []);
useEffect(() => {
if (chatWS && queryToProcess) {
// Add a new object to the state
const newStreamMessage: StreamMessage = {
rawResponse: "",
trainOfThought: [],
context: [],
onlineContext: {},
completed: false,
timestamp: (new Date()).toISOString(),
rawQuery: queryToProcess || "",
}
setMessages(prevMessages => [...prevMessages, newStreamMessage]);
setProcessQuerySignal(true);
} else {
if (!chatWS) {
console.error("No WebSocket connection available");
}
if (!queryToProcess) {
console.error("No query to process");
}
}
}, [queryToProcess]);
if (chatWS) {
chatWS.onmessage = handleWebSocketMessage;
}
}, [chatWS, messages]);
//same as ChatBodyData for local storage message
useEffect(() => {
const storedMessage = localStorage.getItem("message");
setQueryToProcess(storedMessage || '');
}, []);
useEffect(() => {
if (processQuerySignal && chatWS) {
if (chatWS && queryToProcess) {
const newStreamMessage: StreamMessage = {
rawResponse: "",
trainOfThought: [],
context: [],
onlineContext: {},
completed: false,
timestamp: (new Date()).toISOString(),
rawQuery: queryToProcess || "",
};
setMessages(prevMessages => [...prevMessages, newStreamMessage]);
if (chatWS.readyState === WebSocket.OPEN) {
chatWS.send(queryToProcess);
setProcessQuerySignal(true);
}
else {
console.error("WebSocket is not open. ReadyState:", chatWS.readyState);
}
setQueryToProcess('');
}
}, [queryToProcess, chatWS]);
useEffect(() => {
if (processQuerySignal && chatWS && chatWS.readyState === WebSocket.OPEN) {
setProcessQuerySignal(false);
chatWS.onmessage = handleWebSocketMessage;
chatWS?.send(queryToProcess);
chatWS.send(queryToProcess);
localStorage.removeItem("message");
}
}, [processQuerySignal]);
}, [processQuerySignal, chatWS]);
useEffect(() => {
(async () => {
if (conversationId) {
const setupWebSocketConnection = async () => {
if (conversationId && (!chatWS || chatWS.readyState === WebSocket.CLOSED)) {
if(queryToProcess) {
const newWS = await setupWebSocket(conversationId, queryToProcess);
localStorage.removeItem("message");
setChatWS(newWS);
}
else {
const newWS = await setupWebSocket(conversationId);
setChatWS(newWS);
}
})();
}
};
setupWebSocketConnection();
}, [conversationId]);
const handleConversationIdChange = (newConversationId: string) => {
setConversationID(newConversationId);
};
if (isLoading) {
return <Loading />;
}
@@ -260,7 +271,7 @@ export default function Chat() {
<title>
{title}
</title>
<div className={styles.sidePanel}>
<div>
<SidePanel
webSocketConnected={chatWS !== null}
conversationId={conversationId}