diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 8007b5ad13..fa74d434e4 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -19,28 +19,28 @@ const AdminInvites = lazy(() => import("@/pages/Admin/Invitations")); const AdminWorkspaces = lazy(() => import("@/pages/Admin/Workspaces")); const AdminSystem = lazy(() => import("@/pages/Admin/System")); const GeneralChats = lazy(() => import("@/pages/GeneralSettings/Chats")); -const GeneralAppearance = lazy(() => - import("@/pages/GeneralSettings/Appearance") +const GeneralAppearance = lazy( + () => import("@/pages/GeneralSettings/Appearance") ); const GeneralApiKeys = lazy(() => import("@/pages/GeneralSettings/ApiKeys")); -const GeneralLLMPreference = lazy(() => - import("@/pages/GeneralSettings/LLMPreference") +const GeneralLLMPreference = lazy( + () => import("@/pages/GeneralSettings/LLMPreference") ); -const GeneralEmbeddingPreference = lazy(() => - import("@/pages/GeneralSettings/EmbeddingPreference") +const GeneralEmbeddingPreference = lazy( + () => import("@/pages/GeneralSettings/EmbeddingPreference") ); -const GeneralVectorDatabase = lazy(() => - import("@/pages/GeneralSettings/VectorDatabase") +const GeneralVectorDatabase = lazy( + () => import("@/pages/GeneralSettings/VectorDatabase") ); -const GeneralExportImport = lazy(() => - import("@/pages/GeneralSettings/ExportImport") +const GeneralExportImport = lazy( + () => import("@/pages/GeneralSettings/ExportImport") ); const GeneralSecurity = lazy(() => import("@/pages/GeneralSettings/Security")); -const DataConnectors = lazy(() => - import("@/pages/GeneralSettings/DataConnectors") +const DataConnectors = lazy( + () => import("@/pages/GeneralSettings/DataConnectors") ); -const DataConnectorSetup = lazy(() => - import("@/pages/GeneralSettings/DataConnectors/Connectors") +const DataConnectorSetup = lazy( + () => import("@/pages/GeneralSettings/DataConnectors/Connectors") ); const OnboardingFlow = lazy(() => import("@/pages/OnboardingFlow")); diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx index 1de2504b72..4a7cd48274 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx @@ -24,16 +24,14 @@ export default function ChatHistory({ history = [], workspace }) { }; const debouncedScroll = debounce(handleScroll, 100); - useEffect(() => { - if (!chatHistoryRef.current) return null; - const chatHistoryElement = chatHistoryRef.current; - chatHistoryElement.addEventListener("scroll", debouncedScroll); - - return () => { - chatHistoryElement.removeEventListener("scroll", debouncedScroll); - debouncedScroll.cancel(); - }; + function watchScrollEvent() { + if (!chatHistoryRef.current) return null; + const chatHistoryElement = chatHistoryRef.current; + if (!chatHistoryElement) return null; + chatHistoryElement.addEventListener("scroll", debouncedScroll); + } + watchScrollEvent(); }, []); const scrollToBottom = () => { @@ -49,11 +47,11 @@ export default function ChatHistory({ history = [], workspace }) { return (
-

+

Welcome to your new workspace.

-

+

To get started either{" "} + + + diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/SlashCommands/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/SlashCommands/index.jsx new file mode 100644 index 0000000000..0e4f26aa92 --- /dev/null +++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/SlashCommands/index.jsx @@ -0,0 +1,68 @@ +import { useEffect, useRef, useState } from "react"; +import SlashCommandIcon from "./icons/slash-commands-icon.svg"; + +export default function SlashCommandsButton({ showing, setShowSlashCommand }) { + return ( +

setShowSlashCommand(!showing)} + className={`flex justify-center items-center opacity-60 hover:opacity-100 cursor-pointer ${ + showing ? "!opacity-100" : "" + }`} + > + Slash commands button +
+ ); +} + +export function SlashCommands({ showing, setShowing, sendCommand }) { + const cmdRef = useRef(null); + useEffect(() => { + function listenForOutsideClick() { + if (!showing || !cmdRef.current) return false; + document.addEventListener("click", closeIfOutside); + } + listenForOutsideClick(); + }, [showing, cmdRef.current]); + + if (!showing) return null; + const closeIfOutside = ({ target }) => { + if (target.id === "slash-cmd-btn") return; + const isOutside = !cmdRef?.current?.contains(target); + if (!isOutside) return; + setShowing(false); + }; + + return ( +
+
+ +
+
+ ); +} + +export function useSlashCommands() { + const [showSlashCommand, setShowSlashCommand] = useState(false); + return { showSlashCommand, setShowSlashCommand }; +} diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx index 14daff8095..e141cc0a43 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx @@ -11,6 +11,10 @@ import ManageWorkspace, { useManageWorkspaceModal, } from "../../../Modals/MangeWorkspace"; import useUser from "@/hooks/useUser"; +import SlashCommandsButton, { + SlashCommands, + useSlashCommands, +} from "./SlashCommands"; export default function PromptInput({ workspace, @@ -19,7 +23,9 @@ export default function PromptInput({ onChange, inputDisabled, buttonDisabled, + sendCommand, }) { + const { showSlashCommand, setShowSlashCommand } = useSlashCommands(); const { showing, showModal, hideModal } = useManageWorkspaceModal(); const formRef = useRef(null); const [_, setFocused] = useState(false); @@ -49,7 +55,12 @@ export default function PromptInput({ }; return ( -
+
+
)} - - {/* */} +
- {/* */}
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx index 34ae8de9af..6dd1cdf503 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx @@ -10,7 +10,6 @@ export default function ChatContainer({ workspace, knownHistory = [] }) { const [message, setMessage] = useState(""); const [loadingResponse, setLoadingResponse] = useState(false); const [chatHistory, setChatHistory] = useState(knownHistory); - const handleMessageChange = (event) => { setMessage(event.target.value); }; @@ -36,6 +35,30 @@ export default function ChatContainer({ workspace, knownHistory = [] }) { setLoadingResponse(true); }; + const sendCommand = async (command, submit = false) => { + if (!command || command === "") return false; + if (!submit) { + setMessage(command); + return; + } + + const prevChatHistory = [ + ...chatHistory, + { content: command, role: "user" }, + { + content: "", + role: "assistant", + pending: true, + userMessage: command, + animate: true, + }, + ]; + + setChatHistory(prevChatHistory); + setMessage(""); + setLoadingResponse(true); + }; + useEffect(() => { async function fetchReply() { const promptMessage = @@ -97,6 +120,7 @@ export default function ChatContainer({ workspace, knownHistory = [] }) { onChange={handleMessageChange} inputDisabled={loadingResponse} buttonDisabled={loadingResponse} + sendCommand={sendCommand} />
diff --git a/frontend/src/index.css b/frontend/src/index.css index a7aef9a7ed..1d1b2da853 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -6,8 +6,18 @@ html, body { padding: 0; margin: 0; - font-family: "plus-jakarta-sans", -apple-system, BlinkMacSystemFont, Segoe UI, - Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, + font-family: + "plus-jakarta-sans", + -apple-system, + BlinkMacSystemFont, + Segoe UI, + Roboto, + Oxygen, + Ubuntu, + Cantarell, + Fira Sans, + Droid Sans, + Helvetica Neue, sans-serif; background-color: white; }