diff --git a/frontend/.gitignore b/frontend/.gitignore index 78720603424d46c6e9fee30a43d06ef521c01971..77e294d036e8f9ef7954c92d2b3da4936698c0f5 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -9,10 +9,8 @@ lerna-debug.log* node_modules dist -lib dist-ssr *.local -!frontend/components/lib # Editor directories and files .vscode/* diff --git a/frontend/src/components/Footer/index.jsx b/frontend/src/components/Footer/index.jsx index 10cd80cd5376baa3114a9e2f69b233a3a5129d0d..6e80f0dfe964d94cc74cc5a6f457b084777c7c06 100644 --- a/frontend/src/components/Footer/index.jsx +++ b/frontend/src/components/Footer/index.jsx @@ -14,6 +14,8 @@ import { import React, { useEffect, useState } from "react"; import SettingsButton from "../SettingsButton"; import { isMobile } from "react-device-detect"; +import { Tooltip } from "react-tooltip"; +import { v4 } from "uuid"; export const MAX_ICONS = 3; export const ICON_COMPONENTS = { @@ -47,36 +49,48 @@ export default function Footer() { return ( <div className="flex justify-center mb-2"> <div className="flex space-x-4"> - <a - href={paths.github()} - target="_blank" - rel="noreferrer" - className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" - aria-label="Find us on Github" - > - <GithubLogo weight="fill" className="h-5 w-5 " /> - </a> - <a - href={paths.docs()} - target="_blank" - rel="noreferrer" - className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" - aria-label="Docs" - > - <BookOpen weight="fill" className="h-5 w-5 " /> - </a> - <a - href={paths.discord()} - target="_blank" - rel="noreferrer" - className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" - aria-label="Join our Discord server" - > - <DiscordLogo - weight="fill" - className="h-5 w-5 stroke-slate-200 group-hover:stroke-slate-200" - /> - </a> + <ToolTipWrapper id="open-github"> + <a + href={paths.github()} + target="_blank" + rel="noreferrer" + className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" + aria-label="Find us on Github" + data-tooltip-id="open-github" + data-tooltip-content="View source code on Github" + > + <GithubLogo weight="fill" className="h-5 w-5 " /> + </a> + </ToolTipWrapper> + <ToolTipWrapper id="open-documentation"> + <a + href={paths.docs()} + target="_blank" + rel="noreferrer" + className="w-fit transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" + aria-label="Docs" + data-tooltip-id="open-documentation" + data-tooltip-content="Open AnythingLLM help docs" + > + <BookOpen weight="fill" className="h-5 w-5 " /> + </a> + </ToolTipWrapper> + <ToolTipWrapper id="open-discord"> + <a + href={paths.discord()} + target="_blank" + rel="noreferrer" + className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" + aria-label="Join our Discord server" + data-tooltip-id="open-discord" + data-tooltip-content="Join the AnythingLLM Discord" + > + <DiscordLogo + weight="fill" + className="h-5 w-5 stroke-slate-200 group-hover:stroke-slate-200" + /> + </a> + </ToolTipWrapper> {!isMobile && <SettingsButton />} </div> </div> @@ -105,3 +119,17 @@ export default function Footer() { </div> ); } + +export function ToolTipWrapper({ id = v4(), children }) { + return ( + <div className="flex w-fit"> + {children} + <Tooltip + id={id} + place="top" + delayShow={300} + className="tooltip !text-xs z-99" + /> + </div> + ); +} diff --git a/frontend/src/components/LLMSelection/GenericOpenAiOptions/index.jsx b/frontend/src/components/LLMSelection/GenericOpenAiOptions/index.jsx index ac143e94a9efb3d9f2cae0a0fb97371715265e6b..d1088063b34948de53749f7a1f43c8d5383dbb8e 100644 --- a/frontend/src/components/LLMSelection/GenericOpenAiOptions/index.jsx +++ b/frontend/src/components/LLMSelection/GenericOpenAiOptions/index.jsx @@ -1,80 +1,84 @@ export default function GenericOpenAiOptions({ settings }) { return ( - <div className="flex gap-4 flex-wrap"> - <div className="flex flex-col w-60"> - <label className="text-white text-sm font-semibold block mb-4"> - Base URL - </label> - <input - type="url" - name="GenericOpenAiBasePath" - className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" - placeholder="eg: https://proxy.openai.com" - defaultValue={settings?.GenericOpenAiBasePath} - required={true} - autoComplete="off" - spellCheck={false} - /> + <div className="flex flex-col gap-y-4"> + <div className="flex gap-4 flex-wrap"> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-4"> + Base URL + </label> + <input + type="url" + name="GenericOpenAiBasePath" + className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" + placeholder="eg: https://proxy.openai.com" + defaultValue={settings?.GenericOpenAiBasePath} + required={true} + autoComplete="off" + spellCheck={false} + /> + </div> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-4"> + API Key + </label> + <input + type="password" + name="GenericOpenAiKey" + className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" + placeholder="Generic service API Key" + defaultValue={settings?.GenericOpenAiKey ? "*".repeat(20) : ""} + required={false} + autoComplete="off" + spellCheck={false} + /> + </div> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-4"> + Chat Model Name + </label> + <input + type="text" + name="GenericOpenAiModelPref" + className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" + placeholder="Model id used for chat requests" + defaultValue={settings?.GenericOpenAiModelPref} + required={true} + autoComplete="off" + /> + </div> </div> - <div className="flex flex-col w-60"> - <label className="text-white text-sm font-semibold block mb-4"> - API Key - </label> - <input - type="password" - name="GenericOpenAiKey" - className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" - placeholder="Generic service API Key" - defaultValue={settings?.GenericOpenAiKey ? "*".repeat(20) : ""} - required={false} - autoComplete="off" - spellCheck={false} - /> - </div> - <div className="flex flex-col w-60"> - <label className="text-white text-sm font-semibold block mb-4"> - Chat Model Name - </label> - <input - type="text" - name="GenericOpenAiModelPref" - className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" - placeholder="Model id used for chat requests" - defaultValue={settings?.GenericOpenAiModelPref} - required={true} - autoComplete="off" - /> - </div> - <div className="flex flex-col w-60"> - <label className="text-white text-sm font-semibold block mb-4"> - Token context window - </label> - <input - type="number" - name="GenericOpenAiTokenLimit" - className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" - placeholder="Content window limit (eg: 4096)" - min={1} - onScroll={(e) => e.target.blur()} - defaultValue={settings?.GenericOpenAiTokenLimit} - required={true} - autoComplete="off" - /> - </div> - <div className="flex flex-col w-60"> - <label className="text-white text-sm font-semibold block mb-4"> - Max Tokens - </label> - <input - type="number" - name="GenericOpenAiMaxTokens" - className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" - placeholder="Max tokens per request (eg: 1024)" - min={1} - defaultValue={settings?.GenericOpenAiMaxTokens || 1024} - required={true} - autoComplete="off" - /> + <div className="flex gap-x-4 flex-wrap"> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-4"> + Token context window + </label> + <input + type="number" + name="GenericOpenAiTokenLimit" + className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" + placeholder="Content window limit (eg: 4096)" + min={1} + onScroll={(e) => e.target.blur()} + defaultValue={settings?.GenericOpenAiTokenLimit} + required={true} + autoComplete="off" + /> + </div> + <div className="flex flex-col w-60"> + <label className="text-white text-sm font-semibold block mb-4"> + Max Tokens + </label> + <input + type="number" + name="GenericOpenAiMaxTokens" + className="bg-zinc-900 text-white placeholder:text-white/20 text-sm rounded-lg focus:border-white block w-full p-2.5" + placeholder="Max tokens per request (eg: 1024)" + min={1} + defaultValue={settings?.GenericOpenAiMaxTokens || 1024} + required={true} + autoComplete="off" + /> + </div> </div> </div> ); diff --git a/frontend/src/components/SettingsButton/index.jsx b/frontend/src/components/SettingsButton/index.jsx index ac2d22cdd8a54d6817ed41983fad6e2475577588..19a4a17aa9521bb03f5ed0541b5583b5f0cd602a 100644 --- a/frontend/src/components/SettingsButton/index.jsx +++ b/frontend/src/components/SettingsButton/index.jsx @@ -3,6 +3,7 @@ import paths from "@/utils/paths"; import { ArrowUUpLeft, Wrench } from "@phosphor-icons/react"; import { Link } from "react-router-dom"; import { useMatch } from "react-router-dom"; +import { ToolTipWrapper } from "../Footer"; export default function SettingsButton() { const isInSettings = !!useMatch("/settings/*"); @@ -12,22 +13,32 @@ export default function SettingsButton() { if (isInSettings) return ( + <ToolTipWrapper id="go-home"> + <Link + to={paths.home()} + className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" + aria-label="Home" + data-tooltip-id="go-home" + data-tooltip-content="Back to workspaces" + > + <ArrowUUpLeft className="h-5 w-5" weight="fill" /> + </Link> + </ToolTipWrapper> + ); + + return ( + <ToolTipWrapper id="open-settings"> <Link - to={paths.home()} + to={ + !!user?.role ? paths.settings.system() : paths.settings.appearance() + } className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" - aria-label="Home" + aria-label="Settings" + data-tooltip-id="open-settings" + data-tooltip-content="Open settings" > - <ArrowUUpLeft className="h-5 w-5" weight="fill" /> + <Wrench className="h-5 w-5" weight="fill" /> </Link> - ); - - return ( - <Link - to={!!user?.role ? paths.settings.system() : paths.settings.appearance()} - className="transition-all duration-300 p-2 rounded-full text-white bg-sidebar-button hover:bg-menu-item-selected-gradient hover:border-slate-100 hover:border-opacity-50 border-transparent border" - aria-label="Settings" - > - <Wrench className="h-5 w-5" weight="fill" /> - </Link> + </ToolTipWrapper> ); } diff --git a/frontend/src/components/SettingsSidebar/index.jsx b/frontend/src/components/SettingsSidebar/index.jsx index 6b8f79e5eddfe8b28f530d65ed28b09f5644d09a..2d59d0ff928397a7840ed3c40012705aa5e02993 100644 --- a/frontend/src/components/SettingsSidebar/index.jsx +++ b/frontend/src/components/SettingsSidebar/index.jsx @@ -329,7 +329,7 @@ const SidebarOptions = ({ user = null }) => ( <Option href={paths.settings.embedSetup()} childLinks={[paths.settings.embedChats()]} - btnText="Embedded Chat" + btnText="Chat Embed Widgets" icon={<CodeBlock className="h-5 w-5 flex-shrink-0" />} user={user} flex={true} @@ -338,7 +338,7 @@ const SidebarOptions = ({ user = null }) => ( <> <Option href={paths.settings.embedChats()} - btnText="Embedded Chat History" + btnText="Chat Embed History" icon={<Barcode className="h-5 w-5 flex-shrink-0" />} user={user} flex={true} diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx index b67f5492fc81473cb88d928025c955d5499e13c3..fc46fbe9c783c4fde437cbccea2b5fb4a6b8387c 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx @@ -12,6 +12,7 @@ import AvailableAgentsButton, { } from "./AgentMenu"; import TextSizeButton from "./TextSizeMenu"; import SpeechToText from "./SpeechToText"; +import { Tooltip } from "react-tooltip"; export const PROMPT_INPUT_EVENT = "set_prompt_input"; export default function PromptInput({ @@ -134,14 +135,25 @@ export default function PromptInput({ {buttonDisabled ? ( <StopGenerationButton /> ) : ( - <button - ref={formRef} - type="submit" - className="inline-flex justify-center rounded-2xl cursor-pointer text-white/60 hover:text-white group ml-4" - > - <PaperPlaneRight className="w-7 h-7 my-3" weight="fill" /> - <span className="sr-only">Send message</span> - </button> + <> + <button + ref={formRef} + type="submit" + className="inline-flex justify-center rounded-2xl cursor-pointer text-white/60 hover:text-white group ml-4" + data-tooltip-id="send-prompt" + data-tooltip-content="Send prompt message to workspace" + aria-label="Send prompt message to workspace" + > + <PaperPlaneRight className="w-7 h-7 my-3" weight="fill" /> + <span className="sr-only">Send message</span> + </button> + <Tooltip + id="send-prompt" + place="bottom" + delayShow={300} + className="tooltip !text-xs z-99" + /> + </> )} </div> <div className="flex justify-between py-3.5">