diff --git a/web/src/app/chat/ChatPage.tsx b/web/src/app/chat/ChatPage.tsx index c31eae094a4..9efe562730e 100644 --- a/web/src/app/chat/ChatPage.tsx +++ b/web/src/app/chat/ChatPage.tsx @@ -2361,7 +2361,8 @@ export function ChatPage({ id={`message-${message.messageId}`} key={messageReactComponentKey} > - + {/* + /> */} ); } else if (message.type === "assistant") { @@ -2446,7 +2447,8 @@ export function ChatPage({ : null } > - + /> */} ); } else { return (
- } - /> + /> */}
); } })} - {(currentSessionChatState == "loading" || + {/* {(currentSessionChatState == "loading" || (loadingError && !currentSessionRegenerationState?.regenerating && messageHistory[messageHistory.length - 1] @@ -2656,13 +2658,13 @@ export function ChatPage({ messageId={-1} content={submittedMessage} /> - )} + )} */} {currentSessionChatState == "loading" && (
-
} - /> + /> */} )} {loadingError && (
- } - /> + /> */}
)} {messageHistory.length > 0 && ( diff --git a/web/src/app/chat/message/Messages.tsx b/web/src/app/chat/message/Messages.tsx index 75e583cfc59..afa82325157 100644 --- a/web/src/app/chat/message/Messages.tsx +++ b/web/src/app/chat/message/Messages.tsx @@ -162,523 +162,715 @@ function FileDisplay({ ); } -export const AIMessage = ({ - regenerate, - overriddenModel, - selectedMessageForDocDisplay, - continueGenerating, - shared, - isActive, - toggleDocumentSelection, - alternativeAssistant, - docs, - messageId, - documentSelectionToggled, - content, - files, - selectedDocuments, - query, - citedDocuments, - toolCall, - isComplete, - hasDocs, - handleFeedback, - handleShowRetrieved, - handleSearchQueryEdit, - handleForceSearch, - retrievalDisabled, - currentPersona, - otherMessagesCanSwitchTo, - onMessageSelection, - setPresentingDocument, - index, -}: { - index?: number; - selectedMessageForDocDisplay?: number | null; - shared?: boolean; - isActive?: boolean; - continueGenerating?: () => void; - otherMessagesCanSwitchTo?: number[]; - onMessageSelection?: (messageId: number) => void; - selectedDocuments?: DanswerDocument[] | null; - toggleDocumentSelection?: () => void; - docs?: DanswerDocument[] | null; - alternativeAssistant?: Persona | null; - currentPersona: Persona; - messageId: number | null; - content: string | JSX.Element; - documentSelectionToggled?: boolean; - files?: FileDescriptor[]; - query?: string; - citedDocuments?: [string, DanswerDocument][] | null; - toolCall?: ToolCallMetadata | null; - isComplete?: boolean; - hasDocs?: boolean; - handleFeedback?: (feedbackType: FeedbackType) => void; - handleShowRetrieved?: (messageNumber: number | null) => void; - handleSearchQueryEdit?: (query: string) => void; - handleForceSearch?: () => void; - retrievalDisabled?: boolean; - overriddenModel?: string; - regenerate?: (modelOverRide: LlmOverride) => Promise; - setPresentingDocument?: (document: DanswerDocument) => void; -}) => { - const toolCallGenerating = toolCall && !toolCall.tool_result; - const processContent = (content: string | JSX.Element) => { - if (typeof content !== "string") { - return content; - } - - const codeBlockRegex = /```(\w*)\n[\s\S]*?```|```[\s\S]*?$/g; - const matches = content.match(codeBlockRegex); - - if (matches) { - content = matches.reduce((acc, match) => { - if (!match.match(/```\w+/)) { - return acc.replace(match, match.replace("```", "```plaintext")); - } - return acc; - }, content); - - const lastMatch = matches[matches.length - 1]; - if (!lastMatch.endsWith("```")) { - return content; - } - } - - return content + (!isComplete && !toolCallGenerating ? " [*]() " : ""); - }; - const finalContent = processContent(content as string); - - const [isRegenerateHovered, setIsRegenerateHovered] = useState(false); - const [isRegenerateDropdownVisible, setIsRegenerateDropdownVisible] = - useState(false); - const { isHovering, trackedElementRef, hoverElementRef } = useMouseTracking(); - - const settings = useContext(SettingsContext); - // this is needed to give Prism a chance to load - - const selectedDocumentIds = - selectedDocuments?.map((document) => document.document_id) || []; - const citedDocumentIds: string[] = []; - - citedDocuments?.forEach((doc) => { - citedDocumentIds.push(doc[1].document_id); - }); - - if (!isComplete) { - const trimIncompleteCodeSection = ( - content: string | JSX.Element - ): string | JSX.Element => { - if (typeof content === "string") { - const pattern = /```[a-zA-Z]+[^\s]*$/; - const match = content.match(pattern); - if (match && match.index && match.index > 3) { - const newContent = content.slice(0, match.index - 3); - return newContent; - } - return content; - } - return content; - }; - content = trimIncompleteCodeSection(content); - } - - let filteredDocs: FilteredDanswerDocument[] = []; - - if (docs) { - filteredDocs = docs - .filter( - (doc, index, self) => - doc.document_id && - doc.document_id !== "" && - index === self.findIndex((d) => d.document_id === doc.document_id) - ) - .filter((doc) => { - return citedDocumentIds.includes(doc.document_id); - }) - .map((doc: DanswerDocument, ind: number) => { - return { - ...doc, - included: selectedDocumentIds.includes(doc.document_id), - }; - }); - } - - const paragraphCallback = useCallback( - (props: any) => {props.children}, - [] - ); - - const anchorCallback = useCallback( - (props: any) => ( - - {props.children} - - ), - [docs] - ); - - const currentMessageInd = messageId - ? otherMessagesCanSwitchTo?.indexOf(messageId) - : undefined; - - const uniqueSources: ValidSources[] = Array.from( - new Set((docs || []).map((doc) => doc.source_type)) - ).slice(0, 3); - - const markdownComponents = useMemo( - () => ({ - a: anchorCallback, - p: paragraphCallback, - code: ({ node, className, children }: any) => { - const codeText = extractCodeText( - node, - finalContent as string, - children - ); - - return ( - - {children} - - ); - }, - }), - [anchorCallback, paragraphCallback, finalContent] - ); +export const AIMessage = ({ humanText }: { humanText: string }) => { + // This message layout is directly taken from the Figma snippet provided. + // We'll render a static "Agentic Search" example to mimic the design. + // In a real scenario, you would dynamically insert content. - const renderedMarkdown = useMemo(() => { - return ( - - {finalContent as string} - - ); - }, [finalContent, markdownComponents]); - - const includeMessageSwitcher = - currentMessageInd !== undefined && - onMessageSelection && - otherMessagesCanSwitchTo && - otherMessagesCanSwitchTo.length > 1; return ( -
-
-
-
- - -
-
-
-
- {!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME ? ( - <> - {query !== undefined && - handleShowRetrieved !== undefined && - !retrievalDisabled && ( -
- -
- )} - {handleForceSearch && - content && - query === undefined && - !hasDocs && - !retrievalDisabled && ( -
- -
- )} - - ) : null} - - {toolCall && - !TOOLS_WITH_CUSTOM_HANDLING.includes( - toolCall.tool_name - ) && ( - - } - isRunning={!toolCall.tool_result || !content} - /> - )} +
+
+
+ {/* Assistant icon */} +
+
+ assistant +
+
- {toolCall && - (!files || files.length == 0) && - toolCall.tool_name === IMAGE_GENERATION_TOOL_NAME && - !toolCall.tool_result && } - - {toolCall && - toolCall.tool_name === INTERNET_SEARCH_TOOL_NAME && ( - - } - isRunning={!toolCall.tool_result} - /> - )} +
+
+ {/* The Question */} +

+ {humanText} +

+ + {/* Main answer container */} +
+
+

Agentic Search

+
- {docs && docs.length > 0 && ( -
-
-
- {!settings?.isMobile && - docs.length > 0 && - docs - .slice(0, 2) - .map((doc, ind) => ( - - ))} - + {/* Getting context section */} +
+

+ Getting context on typical sales processes +

+
+
+ Searching +
+
+
+ Web Search
- )} - - {content || files ? ( - <> - - - {typeof content === "string" ? ( -
- {renderedMarkdown} -
- ) : ( - content - )} - - ) : isComplete ? null : ( - <> - )} +
+ {[ + "Sales training materials", + "Sales playbook", + "Customer Journey", + ].map((item, index) => ( + + {item} + + ))} +
+
+
+ Reading +
+ {[ + "2024 sales process onboarding guide", + "2024 onyx sales playbook", + "Ramp customer journey record", + ].map((item, index) => ( + + {item} + + ))} +
+
- {handleFeedback && - (isActive ? ( -
- -
- {includeMessageSwitcher && ( -
- { - onMessageSelection( - otherMessagesCanSwitchTo[ - currentMessageInd - 1 - ] - ); - }} - handleNext={() => { - onMessageSelection( - otherMessagesCanSwitchTo[ - currentMessageInd + 1 - ] - ); - }} - /> -
- )} -
- - - - - } - onClick={() => handleFeedback("like")} - /> - - - } - onClick={() => handleFeedback("dislike")} - /> - - {regenerate && ( - - - - )} -
+ {/* Ramp difference section */} +
+

+ What was done differently at Ramp +

+
+ Searching +
+ {[ + "Ramp sales calls", + "Ramp deal sales email exchanges", + "Ramp win/loss analysis", + ].map((item, index) => ( + + {item} + + ))}
- ) : ( -
- -
- {includeMessageSwitcher && ( -
- { - onMessageSelection( - otherMessagesCanSwitchTo[ - currentMessageInd - 1 - ] - ); - }} - handleNext={() => { - onMessageSelection( - otherMessagesCanSwitchTo[ - currentMessageInd + 1 - ] - ); - }} - /> -
- )} -
- - - - - - } - onClick={() => handleFeedback("like")} - /> - - - - } - onClick={() => handleFeedback("dislike")} - /> - - {regenerate && ( - - - - )} -
+
+
+ Reading +
+ {[ + "Sales call with Ramp 2024/5/15", + "Sales call with Ramp 2024/4/16", + "Sales call with Ramp 2024/3/12", + "Ramp:Onyx Regarding the deal terms", + "Ramp:Onyx deal progress tracker", + ].map((item, index) => ( + + {item} + + ))}
- ))} +
+
+
+
+ + {/* Sources */} +
+

Sources

+
+ {[ + { + text: "a new in-app support experience for Ramp (recently rolled out to 50% of", + source: "Business Overview meeting", + }, + { + text: "Danswer Updates!!! Shiny New Things for Ramp! General Improvements APIs for Ramp use", + source: "Ramp (April)", + }, + { + text: "Existing solutions are so expensive that this isn't feasible. * Today's solutions don't meet those", + source: "Sales Pitch Deck Thoughts", + }, + { + text: "Show All", + source: "", + }, + ].map((item, index) => ( +
+

{item.text}

+ {item.source && ( +
+
+ {item.source} +
+ )} +
+ ))}
+ + {/* Conclusion */} +
+
+
+ Onyx logo +
+

Onyx

+
+

+ To win the deal at Ramp, the team made the product really easy + to access. After a successful demo... +

+
- {(!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME) && - !query && - continueGenerating && ( - - )}
); }; +// export const AIMessage = ({ +// regenerate, +// overriddenModel, +// selectedMessageForDocDisplay, +// continueGenerating, +// shared, +// isActive, +// toggleDocumentSelection, +// alternativeAssistant, +// docs, +// messageId, +// documentSelectionToggled, +// content, +// files, +// selectedDocuments, +// query, +// citedDocuments, +// toolCall, +// isComplete, +// hasDocs, +// handleFeedback, +// handleShowRetrieved, +// handleSearchQueryEdit, +// handleForceSearch, +// retrievalDisabled, +// currentPersona, +// otherMessagesCanSwitchTo, +// onMessageSelection, +// setPresentingDocument, +// index, +// }: { +// index?: number; +// selectedMessageForDocDisplay?: number | null; +// shared?: boolean; +// isActive?: boolean; +// continueGenerating?: () => void; +// otherMessagesCanSwitchTo?: number[]; +// onMessageSelection?: (messageId: number) => void; +// selectedDocuments?: DanswerDocument[] | null; +// toggleDocumentSelection?: () => void; +// docs?: DanswerDocument[] | null; +// alternativeAssistant?: Persona | null; +// currentPersona: Persona; +// messageId: number | null; +// content: string | JSX.Element; +// documentSelectionToggled?: boolean; +// files?: FileDescriptor[]; +// query?: string; +// citedDocuments?: [string, DanswerDocument][] | null; +// toolCall?: ToolCallMetadata | null; +// isComplete?: boolean; +// hasDocs?: boolean; +// handleFeedback?: (feedbackType: FeedbackType) => void; +// handleShowRetrieved?: (messageNumber: number | null) => void; +// handleSearchQueryEdit?: (query: string) => void; +// handleForceSearch?: () => void; +// retrievalDisabled?: boolean; +// overriddenModel?: string; +// regenerate?: (modelOverRide: LlmOverride) => Promise; +// setPresentingDocument?: (document: DanswerDocument) => void; +// }) => { +// const toolCallGenerating = toolCall && !toolCall.tool_result; +// const processContent = (content: string | JSX.Element) => { +// if (typeof content !== "string") { +// return content; +// } + +// const codeBlockRegex = /```(\w*)\n[\s\S]*?```|```[\s\S]*?$/g; +// const matches = content.match(codeBlockRegex); + +// if (matches) { +// content = matches.reduce((acc, match) => { +// if (!match.match(/```\w+/)) { +// return acc.replace(match, match.replace("```", "```plaintext")); +// } +// return acc; +// }, content); + +// const lastMatch = matches[matches.length - 1]; +// if (!lastMatch.endsWith("```")) { +// return content; +// } +// } + +// return content + (!isComplete && !toolCallGenerating ? " [*]() " : ""); +// }; +// const finalContent = processContent(content as string); + +// const [isRegenerateHovered, setIsRegenerateHovered] = useState(false); +// const [isRegenerateDropdownVisible, setIsRegenerateDropdownVisible] = +// useState(false); +// const { isHovering, trackedElementRef, hoverElementRef } = useMouseTracking(); + +// const settings = useContext(SettingsContext); +// // this is needed to give Prism a chance to load + +// const selectedDocumentIds = +// selectedDocuments?.map((document) => document.document_id) || []; +// const citedDocumentIds: string[] = []; + +// citedDocuments?.forEach((doc) => { +// citedDocumentIds.push(doc[1].document_id); +// }); + +// if (!isComplete) { +// const trimIncompleteCodeSection = ( +// content: string | JSX.Element +// ): string | JSX.Element => { +// if (typeof content === "string") { +// const pattern = /```[a-zA-Z]+[^\s]*$/; +// const match = content.match(pattern); +// if (match && match.index && match.index > 3) { +// const newContent = content.slice(0, match.index - 3); +// return newContent; +// } +// return content; +// } +// return content; +// }; +// content = trimIncompleteCodeSection(content); +// } + +// let filteredDocs: FilteredDanswerDocument[] = []; + +// if (docs) { +// filteredDocs = docs +// .filter( +// (doc, index, self) => +// doc.document_id && +// doc.document_id !== "" && +// index === self.findIndex((d) => d.document_id === doc.document_id) +// ) +// .filter((doc) => { +// return citedDocumentIds.includes(doc.document_id); +// }) +// .map((doc: DanswerDocument, ind: number) => { +// return { +// ...doc, +// included: selectedDocumentIds.includes(doc.document_id), +// }; +// }); +// } + +// const paragraphCallback = useCallback( +// (props: any) => {props.children}, +// [] +// ); + +// const anchorCallback = useCallback( +// (props: any) => ( +// +// {props.children} +// +// ), +// [docs] +// ); + +// const currentMessageInd = messageId +// ? otherMessagesCanSwitchTo?.indexOf(messageId) +// : undefined; + +// const uniqueSources: ValidSources[] = Array.from( +// new Set((docs || []).map((doc) => doc.source_type)) +// ).slice(0, 3); + +// const markdownComponents = useMemo( +// () => ({ +// a: anchorCallback, +// p: paragraphCallback, +// code: ({ node, className, children }: any) => { +// const codeText = extractCodeText( +// node, +// finalContent as string, +// children +// ); + +// return ( +// +// {children} +// +// ); +// }, +// }), +// [anchorCallback, paragraphCallback, finalContent] +// ); + +// const renderedMarkdown = useMemo(() => { +// return ( +// +// {finalContent as string} +// +// ); +// }, [finalContent, markdownComponents]); + +// const includeMessageSwitcher = +// currentMessageInd !== undefined && +// onMessageSelection && +// otherMessagesCanSwitchTo && +// otherMessagesCanSwitchTo.length > 1; +// return ( +//
+//
+//
+//
+// + +//
+//
+//
+//
+// {!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME ? ( +// <> +// {query !== undefined && +// handleShowRetrieved !== undefined && +// !retrievalDisabled && ( +//
+// +//
+// )} +// {handleForceSearch && +// content && +// query === undefined && +// !hasDocs && +// !retrievalDisabled && ( +//
+// +//
+// )} +// +// ) : null} + +// {toolCall && +// !TOOLS_WITH_CUSTOM_HANDLING.includes( +// toolCall.tool_name +// ) && ( +// +// } +// isRunning={!toolCall.tool_result || !content} +// /> +// )} + +// {toolCall && +// (!files || files.length == 0) && +// toolCall.tool_name === IMAGE_GENERATION_TOOL_NAME && +// !toolCall.tool_result && } + +// {toolCall && +// toolCall.tool_name === INTERNET_SEARCH_TOOL_NAME && ( +// +// } +// isRunning={!toolCall.tool_result} +// /> +// )} + +// {docs && docs.length > 0 && ( +//
+//
+//
+// {!settings?.isMobile && +// docs.length > 0 && +// docs +// .slice(0, 2) +// .map((doc, ind) => ( +// +// ))} +// +//
+//
+//
+// )} + +// {content || files ? ( +// <> +// + +// {typeof content === "string" ? ( +//
+// {renderedMarkdown} +//
+// ) : ( +// content +// )} +// +// ) : isComplete ? null : ( +// <> +// )} +//
+ +// {handleFeedback && +// (isActive ? ( +//
+// +//
+// {includeMessageSwitcher && ( +//
+// { +// onMessageSelection( +// otherMessagesCanSwitchTo[ +// currentMessageInd - 1 +// ] +// ); +// }} +// handleNext={() => { +// onMessageSelection( +// otherMessagesCanSwitchTo[ +// currentMessageInd + 1 +// ] +// ); +// }} +// /> +//
+// )} +//
+// +// +// +// +// } +// onClick={() => handleFeedback("like")} +// /> +// +// +// } +// onClick={() => handleFeedback("dislike")} +// /> +// +// {regenerate && ( +// +// +// +// )} +//
+//
+// ) : ( +//
+// +//
+// {includeMessageSwitcher && ( +//
+// { +// onMessageSelection( +// otherMessagesCanSwitchTo[ +// currentMessageInd - 1 +// ] +// ); +// }} +// handleNext={() => { +// onMessageSelection( +// otherMessagesCanSwitchTo[ +// currentMessageInd + 1 +// ] +// ); +// }} +// /> +//
+// )} +//
+// +// +// + +// +// } +// onClick={() => handleFeedback("like")} +// /> +// + +// +// } +// onClick={() => handleFeedback("dislike")} +// /> +// +// {regenerate && ( +// +// +// +// )} +//
+//
+// ))} +//
+//
+//
+//
+//
+// {(!toolCall || toolCall.tool_name === SEARCH_TOOL_NAME) && +// !query && +// continueGenerating && ( +// +// )} +//
+//
+// ); +// }; + function MessageSwitcher({ currentPage, totalPages, diff --git a/web/src/app/chat/sessionSidebar/ChatSessionDisplay.tsx b/web/src/app/chat/sessionSidebar/ChatSessionDisplay.tsx index 96eaa7e2edd..fe007d5bf5a 100644 --- a/web/src/app/chat/sessionSidebar/ChatSessionDisplay.tsx +++ b/web/src/app/chat/sessionSidebar/ChatSessionDisplay.tsx @@ -4,7 +4,6 @@ import { useRouter } from "next/navigation"; import { ChatSession } from "../interfaces"; import { useState, useEffect, useContext } from "react"; import { getChatRetentionInfo, renameChatSession } from "../lib"; -import { BasicSelectable } from "@/components/BasicClickable"; import Link from "next/link"; import { FiCheck, @@ -34,8 +33,6 @@ export function ChatSessionDisplay({ chatSession: ChatSession; isSelected: boolean; search?: boolean; - // needed when the parent is trying to apply some background effect - // if not set, the gradient will still be applied and cause weirdness skipGradient?: boolean; closeSidebar?: () => void; showShareModal?: (chatSession: ChatSession) => void; @@ -73,7 +70,7 @@ export function ChatSessionDisplay({ }; if (!settings) { - return <>; + return null; } const { daysUntilExpiration, showRetentionWarning } = getChatRetentionInfo( @@ -92,7 +89,11 @@ export function ChatSessionDisplay({ )} setIsHovering(true)} onMouseLeave={() => { @@ -122,147 +123,135 @@ export function ChatSessionDisplay({ ); }} > - - <> -
+
+ {isRenamingChat ? ( + setChatName(e.target.value)} + onKeyDown={(event) => { + if (event.key === "Enter") { + onRename(); + event.preventDefault(); + } + }} + className="px-1 mr-1 w-full rounded text-base font-normal leading-normal text-black border border-[#dcdad4]" + /> + ) : ( +
+ {chatName || `Chat ${chatSession.id}`} +
+ )} + + {isHovering && ( +
{isRenamingChat ? ( - setChatName(e.target.value)} - onKeyDown={(event) => { - if (event.key === "Enter") { - onRename(); - event.preventDefault(); - } - }} - className="-my-px px-1 mr-1 w-full rounded" - /> + <> +
+ +
+
{ + setChatName(chatSession.name); + setIsRenamingChat(false); + }} + className="hover:bg-black/10 p-1 rounded ml-2 cursor-pointer" + > + +
+ ) : ( -

- {chatName || `Chat ${chatSession.id}`} - -

- )} - - {isHovering && - (isRenamingChat ? ( -
-
+ {!showShareModal && showRetentionWarning && ( + + This chat will expire{" "} + {daysUntilExpiration < 1 + ? "today" + : `in ${daysUntilExpiration} day${ + daysUntilExpiration !== 1 ? "s" : "" + }`} +

+ } > - -
+
+ +
+ + )} + + {search ? ( + showDeleteModal && ( +
{ + e.preventDefault(); + showDeleteModal(chatSession); + }} + className="p-1 rounded ml-1 cursor-pointer hover:bg-black/10" + > + +
+ ) + ) : (
{ - setChatName(chatSession.name); - setIsRenamingChat(false); + onClick={(e) => { + e.preventDefault(); + setIsMoreOptionsDropdownOpen( + !isMoreOptionsDropdownOpen + ); }} - className={`hover:bg-black/10 p-1 -m-1 rounded ml-2`} + className="-my-1 cursor-pointer" > - -
-
- ) : ( -
- {!showShareModal && showRetentionWarning && ( - + setIsMoreOptionsDropdownOpen(open) + } content={ -

- This chat will expire{" "} - {daysUntilExpiration < 1 - ? "today" - : `in ${daysUntilExpiration} day${ - daysUntilExpiration !== 1 ? "s" : "" - }`} -

+
+ +
} - > -
- -
-
- )} -
- {search ? ( - showDeleteModal && ( -
{ - e.preventDefault(); - showDeleteModal(chatSession); - }} - className={`p-1 -m-1 rounded ml-1`} - > - + popover={ +
+ {showShareModal && ( + showShareModal(chatSession)} + /> + )} + {!search && ( + setIsRenamingChat(true)} + /> + )} + {showDeleteModal && ( + showDeleteModal(chatSession)} + /> + )}
- ) - ) : ( -
{ - e.preventDefault(); - setIsMoreOptionsDropdownOpen( - !isMoreOptionsDropdownOpen - ); - }} - className="-my-1" - > - - setIsMoreOptionsDropdownOpen(open) - } - content={ -
- -
- } - popover={ -
- {showShareModal && ( - showShareModal(chatSession)} - /> - )} - {!search && ( - setIsRenamingChat(true)} - /> - )} - {showDeleteModal && ( - - showDeleteModal(chatSession) - } - /> - )} -
- } - requiresContentPadding - sideOffset={6} - triggerMaxWidth - /> -
- )} + } + requiresContentPadding + sideOffset={6} + triggerMaxWidth + />
-
- ))} + )} + + )}
- - + )} +
); diff --git a/web/src/app/chat/sessionSidebar/HistorySidebar.tsx b/web/src/app/chat/sessionSidebar/HistorySidebar.tsx index 88002ee005a..87fdbe53291 100644 --- a/web/src/app/chat/sessionSidebar/HistorySidebar.tsx +++ b/web/src/app/chat/sessionSidebar/HistorySidebar.tsx @@ -10,7 +10,6 @@ import { Folder } from "../folders/interfaces"; import { createFolder } from "../folders/FolderManagement"; import { usePopup } from "@/components/admin/connectors/Popup"; import { SettingsContext } from "@/components/settings/SettingsProvider"; - import { AssistantsIconSkeleton, ClosedBookIcon, @@ -58,19 +57,10 @@ export const HistorySidebar = forwardRef( ) => { const router = useRouter(); const { popup, setPopup } = usePopup(); - - // For determining intial focus state const [newFolderId, setNewFolderId] = useState(null); - const currentChatId = currentChatSession?.id; - - // NOTE: do not do something like the below - assume that the parent - // will handle properly refreshing the existingChats - // useEffect(() => { - // router.refresh(); - // }, [currentChatId]); - const combinedSettings = useContext(SettingsContext); + if (!combinedSettings) { return null; } @@ -91,17 +81,14 @@ export const HistorySidebar = forwardRef(
( page={page} toggleSidebar={toggleSidebar} explicitlyUntoggle={explicitlyUntoggle} + // Customize LogoType if needed to match final design /> - {page == "chat" && ( -
+ + {page === "chat" && ( +
{ - if (e.metaKey || e.ctrlKey) { - return; - } - if (handleNewChat) { - handleNewChat(); - } + if (e.metaKey || e.ctrlKey) return; + handleNewChat(); }} > - -

New Chat

+ +

New Chat

- -

+ +

Manage Assistants

- -

+ +

Manage Prompts

)} -
+ +
+ (false); @@ -43,14 +42,14 @@ export function PagesTab({ event: React.DragEvent ) => { event.preventDefault(); - setIsDragOver(false); // Reset drag over state on drop + setIsDragOver(false); const chatSessionId = event.dataTransfer.getData(CHAT_SESSION_ID_KEY); const folderId = event.dataTransfer.getData(FOLDER_ID_KEY); if (folderId) { try { await removeChatFromFolder(parseInt(folderId, 10), chatSessionId); - router.refresh(); // Refresh the page to reflect the changes + router.refresh(); } catch (error) { setPopup({ message: "Failed to remove chat from folder", @@ -63,10 +62,13 @@ export function PagesTab({ const isHistoryEmpty = !existingChats || existingChats.length === 0; return ( -
+
{folders && folders.length > 0 && ( -
-
+
+
Chat Folders
)} +
{ event.preventDefault(); @@ -86,19 +89,17 @@ export function PagesTab({ }} onDragLeave={() => setIsDragOver(false)} onDrop={handleDropToRemoveFromFolder} - className={`pt-1 transition duration-300 ease-in-out mr-3 ${ - isDragOver ? "bg-hover" : "" - } rounded-md`} + className={`pt-3 pb-40 transition duration-300 ease-in-out ${ + isDragOver ? "bg-[#e6e3dd] rounded-md" : "" + }`} > - {(page == "chat" || page == "search") && ( -

- {page == "chat" && "Chat "} - {page == "search" && "Search "} - History + {(page === "chat" || page === "search") && ( +

+ {page === "chat" ? "Chat History" : "Search History"}

)} {isHistoryEmpty ? ( -

+

{page === "search" ? "Try running a search! Your search history will appear here." : "Try sending a message! Your chat history will appear here."} @@ -106,34 +107,31 @@ export function PagesTab({ ) : ( Object.entries(groupedChatSessions).map( ([dateRange, chatSessions], ind) => { - if (chatSessions.length > 0) { + const filteredSessions = chatSessions.filter( + (chat) => chat.folder_id === null + ); + if (filteredSessions.length > 0) { return ( -

-
+
+
{dateRange}
- {chatSessions - .filter((chat) => chat.folder_id === null) - .map((chat) => { - const isSelected = currentChatId === chat.id; - return ( -
- -
- ); - })} + {filteredSessions.map((chat) => { + const isSelected = currentChatId === chat.id; + return ( +
+ +
+ ); + })}
); } diff --git a/web/src/app/chat/shared_chat_search/FunctionalWrapper.tsx b/web/src/app/chat/shared_chat_search/FunctionalWrapper.tsx index 8a58c639136..f10457733c1 100644 --- a/web/src/app/chat/shared_chat_search/FunctionalWrapper.tsx +++ b/web/src/app/chat/shared_chat_search/FunctionalWrapper.tsx @@ -57,7 +57,7 @@ export default function FunctionalWrapper({ return ( <> {" "} -
+
{content(toggledSidebar, toggle)}