Nav Menu Upgrades and Minor UX Improvements (#869)

* Converted navigation menu into a dropdown menu
* Moved collapsed side panel menu icons into top row
* Auto refresh when conversation is deleted to update side panel and route back to main page if deletion is on current conversation
* Highlight the current conversation in the side panel
* Dynamic homepage messages with current day and time of day.
* `colorutils` upgraded to have more expansive tailwind color options and dynamic class name generation.
* Converted create agent button alert into shadcn `ToolTip`
* Colored lines and icons for agents in chat window
* Cleaned up border styling in dark mode
* fixed three dot menu in side panel to be more easier to click
* Add the KhojLogo import in the nav menu and use a default user profile icon when not authenticated
* Get rid of custom --box-shadow CSS variable
* Pass the agent metadat through the chat body data in order to style the send button
* Add login to the unauthenticated login view, redirecto to home if conversation history not loaded
* Set a max height for the input text area
* Simplify tailwind class names

---------

Co-authored-by: sabaimran <narmiabas@gmail.com>
This commit is contained in:
Raghav Tirumale
2024-07-27 04:42:00 -04:00
committed by GitHub
parent 8503d7a07b
commit 1685c60e3c
33 changed files with 1790 additions and 7771 deletions

View File

@@ -17,7 +17,6 @@ div.main {
div.inputBox {
border: 1px solid var(--border-color);
border-radius: 16px;
box-shadow: 0 4px 10px var(--box-shadow-color);
margin-bottom: 20px;
gap: 12px;
padding-left: 20px;

View File

@@ -17,6 +17,7 @@ import { StreamMessage } from '../components/chatMessage/chatMessage';
import { welcomeConsole } from '../common/utils';
import ChatInputArea, { ChatOptions } from '../components/chatInputArea/chatInputArea';
import { useAuthenticatedData } from '../common/auth';
import { AgentData } from '../agents/page';
interface ChatBodyDataProps {
chatOptionsData: ChatOptions | null;
@@ -34,6 +35,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
const conversationId = searchParams.get('conversationId');
const [message, setMessage] = useState('');
const [processingMessage, setProcessingMessage] = useState(false);
const [agentMetadata, setAgentMetadata] = useState<AgentData | null>(null);
useEffect(() => {
const storedMessage = localStorage.getItem("message");
@@ -43,7 +45,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
}, []);
useEffect(() => {
if(message){
if (message) {
setProcessingMessage(true);
props.setQueryToProcess(message);
}
@@ -76,11 +78,14 @@ function ChatBodyData(props: ChatBodyDataProps) {
<ChatHistory
conversationId={conversationId}
setTitle={props.setTitle}
setAgent={setAgentMetadata}
pendingMessage={processingMessage ? message : ''}
incomingMessages={props.streamedMessages} />
incomingMessages={props.streamedMessages}
/>
</div>
<div className={`${styles.inputBox} bg-background align-middle items-center justify-center px-3 dark:bg-neutral-700 dark:border-0 dark:shadow-sm`}>
<div className={`${styles.inputBox} shadow-md bg-background align-middle items-center justify-center px-3 dark:bg-neutral-700 dark:border-0 dark:shadow-sm`}>
<ChatInputArea
agentColor={agentMetadata?.color}
isLoggedIn={props.isLoggedIn}
sendMessage={(message) => setMessage(message)}
sendDisabled={processingMessage}
@@ -92,7 +97,6 @@ function ChatBodyData(props: ChatBodyDataProps) {
</>
);
}
export default function Chat() {
const [chatOptionsData, setChatOptionsData] = useState<ChatOptions | null>(null);
const [isLoading, setLoading] = useState(true);
@@ -106,7 +110,6 @@ export default function Chat() {
const [isMobileWidth, setIsMobileWidth] = useState(false);
const authenticatedData = useAuthenticatedData();
welcomeConsole();
const handleWebSocketMessage = (event: MessageEvent) => {
@@ -195,9 +198,9 @@ export default function Chat() {
}, []);
useEffect(() => {
if (chatWS) {
chatWS.onmessage = handleWebSocketMessage;
}
if (chatWS) {
chatWS.onmessage = handleWebSocketMessage;
}
}, [chatWS, messages]);
//same as ChatBodyData for local storage message
@@ -209,13 +212,13 @@ export default function Chat() {
useEffect(() => {
if (chatWS && queryToProcess) {
const newStreamMessage: StreamMessage = {
rawResponse: "",
trainOfThought: [],
context: [],
onlineContext: {},
completed: false,
timestamp: (new Date()).toISOString(),
rawQuery: queryToProcess || "",
rawResponse: "",
trainOfThought: [],
context: [],
onlineContext: {},
completed: false,
timestamp: (new Date()).toISOString(),
rawQuery: queryToProcess || "",
};
setMessages(prevMessages => [...prevMessages, newStreamMessage]);
@@ -227,11 +230,11 @@ export default function Chat() {
console.error("WebSocket is not open. ReadyState:", chatWS.readyState);
}
setQueryToProcess('');
setQueryToProcess('');
}
}, [queryToProcess, chatWS]);
useEffect(() => {
useEffect(() => {
if (processQuerySignal && chatWS && chatWS.readyState === WebSocket.OPEN) {
setProcessQuerySignal(false);
chatWS.onmessage = handleWebSocketMessage;
@@ -242,17 +245,17 @@ export default function Chat() {
useEffect(() => {
const setupWebSocketConnection = async () => {
if (conversationId && (!chatWS || chatWS.readyState === WebSocket.CLOSED)) {
if(queryToProcess) {
const newWS = await setupWebSocket(conversationId, queryToProcess);
localStorage.removeItem("message");
setChatWS(newWS);
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);
}
}
else {
const newWS = await setupWebSocket(conversationId);
setChatWS(newWS);
}
}
};
setupWebSocketConnection();
}, [conversationId]);