From 657be7ecfccce87670167c57f82be883fca6f67b Mon Sep 17 00:00:00 2001 From: Sean Hatfield <seanhatfield5@gmail.com> Date: Fri, 5 Apr 2024 13:54:12 -0700 Subject: [PATCH] [FEAT] Normalize UI for CTA buttons/UX improvements (#1021) * members workspace settings menu and admin users UI updates * implement CTAButton in all general/admin settings + ui tweaks * move CTAButton to components/lib * fix UI for security page to match rest of all settings pages * UX improvements * add CTAButton component * prevent components folder from being ignored * patch some UI fixes --------- Co-authored-by: timothycarambat <rambat1010@gmail.com> --- frontend/.gitignore | 1 + .../src/components/lib/CTAButton/index.jsx | 16 +++++ .../src/pages/Admin/Invitations/index.jsx | 16 ++--- frontend/src/pages/Admin/Logging/index.jsx | 17 +++-- frontend/src/pages/Admin/System/index.jsx | 25 +++---- frontend/src/pages/Admin/Users/index.jsx | 14 ++-- frontend/src/pages/Admin/Workspaces/index.jsx | 14 ++-- .../pages/GeneralSettings/ApiKeys/index.jsx | 15 +++-- .../src/pages/GeneralSettings/Chats/index.jsx | 2 +- .../GeneralSettings/EmbedConfigs/index.jsx | 14 ++-- .../EmbeddingPreference/index.jsx | 22 ++++--- .../GeneralSettings/LLMPreference/index.jsx | 22 ++++--- .../GeneralSettings/PrivacyAndData/index.jsx | 8 +-- .../pages/GeneralSettings/Security/index.jsx | 66 ++++++++++--------- .../TranscriptionPreference/index.jsx | 22 ++++--- .../GeneralSettings/VectorDatabase/index.jsx | 22 ++++--- .../Members/AddMemberModal/index.jsx | 20 +++--- .../pages/WorkspaceSettings/Members/index.jsx | 10 +-- 18 files changed, 176 insertions(+), 150 deletions(-) create mode 100644 frontend/src/components/lib/CTAButton/index.jsx diff --git a/frontend/.gitignore b/frontend/.gitignore index 196c8f691..787206034 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -12,6 +12,7 @@ dist lib dist-ssr *.local +!frontend/components/lib # Editor directories and files .vscode/* diff --git a/frontend/src/components/lib/CTAButton/index.jsx b/frontend/src/components/lib/CTAButton/index.jsx new file mode 100644 index 000000000..93427f0f9 --- /dev/null +++ b/frontend/src/components/lib/CTAButton/index.jsx @@ -0,0 +1,16 @@ +export default function CTAButton({ + children, + disabled = false, + onClick, + className = "", +}) { + return ( + <button + disabled={disabled} + onClick={() => onClick?.()} + className={`text-xs px-4 py-1 font-semibold rounded-lg bg-[#46C8FF] hover:bg-[#2C2F36] hover:text-white h-[34px] -mr-8 whitespace-nowrap shadow-[0_4px_14px_rgba(0,0,0,0.25)] w-fit ${className}`} + > + <div className="flex items-center justify-center gap-2">{children}</div> + </button> + ); +} diff --git a/frontend/src/pages/Admin/Invitations/index.jsx b/frontend/src/pages/Admin/Invitations/index.jsx index f81ccae52..599271ad9 100644 --- a/frontend/src/pages/Admin/Invitations/index.jsx +++ b/frontend/src/pages/Admin/Invitations/index.jsx @@ -10,6 +10,7 @@ import InviteRow from "./InviteRow"; import NewInviteModal from "./NewInviteModal"; import { useModal } from "@/hooks/useModal"; import ModalWrapper from "@/components/ModalWrapper"; +import CTAButton from "@/components/lib/CTAButton"; export default function AdminInvites() { const { isOpen, openModal, closeModal } = useModal(); @@ -21,25 +22,24 @@ export default function AdminInvites() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center flex gap-x-4"> <p className="text-lg leading-6 font-bold text-white"> Invitations </p> - <button - onClick={openModal} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - <EnvelopeSimple className="h-4 w-4" /> - Create Invite Link - </button> </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> Create invitation links for people in your organization to accept and sign up with. Invitations can only be used by a single user. </p> </div> + <div className="w-full justify-end flex"> + <CTAButton onClick={openModal} className="mt-3 mr-0 -mb-12 z-10"> + <EnvelopeSimple className="h-4 w-4" weight="bold" /> Create Invite + Link + </CTAButton> + </div> <InvitationsContainer /> </div> <ModalWrapper isOpen={isOpen}> diff --git a/frontend/src/pages/Admin/Logging/index.jsx b/frontend/src/pages/Admin/Logging/index.jsx index 5d8a90acb..69a81ab56 100644 --- a/frontend/src/pages/Admin/Logging/index.jsx +++ b/frontend/src/pages/Admin/Logging/index.jsx @@ -6,6 +6,7 @@ import { isMobile } from "react-device-detect"; import * as Skeleton from "react-loading-skeleton"; import LogRow from "./LogRow"; import showToast from "@/utils/toast"; +import CTAButton from "@/components/lib/CTAButton"; export default function AdminLogs() { const handleResetLogs = async () => { @@ -32,24 +33,26 @@ export default function AdminLogs() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="flex gap-x-4 items-center"> <p className="text-lg leading-6 font-bold text-white"> Event Logs </p> - <button - onClick={handleResetLogs} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - Clear event logs - </button> </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> View all actions and events happening on this instance for monitoring. </p> </div> + <div className="w-full justify-end flex"> + <CTAButton + onClick={handleResetLogs} + className="mt-3 mr-0 -mb-14 z-10" + > + Clear Event Logs + </CTAButton> + </div> <LogsContainer /> </div> </div> diff --git a/frontend/src/pages/Admin/System/index.jsx b/frontend/src/pages/Admin/System/index.jsx index 867276b0e..bdab765a5 100644 --- a/frontend/src/pages/Admin/System/index.jsx +++ b/frontend/src/pages/Admin/System/index.jsx @@ -3,6 +3,7 @@ import Sidebar from "@/components/SettingsSidebar"; import { isMobile } from "react-device-detect"; import Admin from "@/models/admin"; import showToast from "@/utils/toast"; +import CTAButton from "@/components/lib/CTAButton"; export default function AdminSystem() { const [saving, setSaving] = useState(false); @@ -49,7 +50,7 @@ export default function AdminSystem() { <form onSubmit={handleSubmit} onChange={() => setHasChanges(true)} - className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16" + className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16" > <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center"> @@ -62,8 +63,14 @@ export default function AdminSystem() { instance. </p> </div> - - <div className="mt-6 mb-8"> + {hasChanges && ( + <div className="flex justify-end"> + <CTAButton onClick={handleSubmit} className="mt-3 mr-0"> + {saving ? "Saving..." : "Save changes"} + </CTAButton> + </div> + )} + <div className="mt-4 mb-8"> <div className="flex flex-col gap-y-1"> <h2 className="text-base leading-6 font-bold text-white"> Users can delete workspaces @@ -141,18 +148,6 @@ export default function AdminSystem() { </div> )} </div> - - {hasChanges && ( - <div className="flex justify-start"> - <button - type="submit" - disabled={saving} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - {saving ? "Saving..." : "Save changes"} - </button> - </div> - )} </form> </div> </div> diff --git a/frontend/src/pages/Admin/Users/index.jsx b/frontend/src/pages/Admin/Users/index.jsx index 6824ee219..408e794aa 100644 --- a/frontend/src/pages/Admin/Users/index.jsx +++ b/frontend/src/pages/Admin/Users/index.jsx @@ -10,6 +10,7 @@ import useUser from "@/hooks/useUser"; import NewUserModal from "./NewUserModal"; import { useModal } from "@/hooks/useModal"; import ModalWrapper from "@/components/ModalWrapper"; +import CTAButton from "@/components/lib/CTAButton"; export default function AdminUsers() { const { isOpen, openModal, closeModal } = useModal(); @@ -21,16 +22,10 @@ export default function AdminUsers() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center flex gap-x-4"> <p className="text-lg leading-6 font-bold text-white">Users</p> - <button - onClick={openModal} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - <UserPlus className="h-4 w-4" /> Add user - </button> </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> These are all the accounts which have an account on this instance. @@ -38,6 +33,11 @@ export default function AdminUsers() { instance. </p> </div> + <div className="w-full justify-end flex"> + <CTAButton onClick={openModal} className="mt-3 mr-0 -mb-6 z-10"> + <UserPlus className="h-4 w-4" weight="bold" /> Add user + </CTAButton> + </div> <UsersContainer /> </div> <ModalWrapper isOpen={isOpen}> diff --git a/frontend/src/pages/Admin/Workspaces/index.jsx b/frontend/src/pages/Admin/Workspaces/index.jsx index 63b9fb346..5a7b128d2 100644 --- a/frontend/src/pages/Admin/Workspaces/index.jsx +++ b/frontend/src/pages/Admin/Workspaces/index.jsx @@ -9,6 +9,7 @@ import WorkspaceRow from "./WorkspaceRow"; import NewWorkspaceModal from "./NewWorkspaceModal"; import { useModal } from "@/hooks/useModal"; import ModalWrapper from "@/components/ModalWrapper"; +import CTAButton from "@/components/lib/CTAButton"; export default function AdminWorkspaces() { const { isOpen, openModal, closeModal } = useModal(); @@ -20,24 +21,23 @@ export default function AdminWorkspaces() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center flex gap-x-4"> <p className="text-lg leading-6 font-bold text-white"> Instance Workspaces </p> - <button - onClick={openModal} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - <BookOpen className="h-4 w-4" /> New Workspace - </button> </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> These are all the workspaces that exist on this instance. Removing a workspace will delete all of it's associated chats and settings. </p> </div> + <div className="w-full justify-end flex"> + <CTAButton onClick={openModal} className="mt-3 mr-0 -mb-14 z-10"> + <BookOpen className="h-4 w-4" weight="bold" /> New Workspace + </CTAButton> + </div> <WorkspacesContainer /> </div> <ModalWrapper isOpen={isOpen}> diff --git a/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx b/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx index 6df1d09dd..4cf3fa397 100644 --- a/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx +++ b/frontend/src/pages/GeneralSettings/ApiKeys/index.jsx @@ -12,6 +12,7 @@ import { userFromStorage } from "@/utils/request"; import System from "@/models/system"; import ModalWrapper from "@/components/ModalWrapper"; import { useModal } from "@/hooks/useModal"; +import CTAButton from "@/components/lib/CTAButton"; export default function AdminApiKeys() { const { isOpen, openModal, closeModal } = useModal(); @@ -23,16 +24,10 @@ export default function AdminApiKeys() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center flex gap-x-4"> <p className="text-lg leading-6 font-bold text-white">API Keys</p> - <button - onClick={openModal} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - <PlusCircle className="h-4 w-4" /> Generate New API Key - </button> </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> API keys allow the holder to programmatically access and manage @@ -47,6 +42,12 @@ export default function AdminApiKeys() { Read the API documentation → </a> </div> + <div className="w-full justify-end flex"> + <CTAButton onClick={openModal} className="mt-3 mr-0 -mb-14 z-10"> + <PlusCircle className="h-4 w-4" weight="bold" /> Generate New API + Key + </CTAButton> + </div> <ApiKeysContainer /> </div> <ModalWrapper isOpen={isOpen}> diff --git a/frontend/src/pages/GeneralSettings/Chats/index.jsx b/frontend/src/pages/GeneralSettings/Chats/index.jsx index e5da1a888..d5b3d5093 100644 --- a/frontend/src/pages/GeneralSettings/Chats/index.jsx +++ b/frontend/src/pages/GeneralSettings/Chats/index.jsx @@ -90,7 +90,7 @@ export default function WorkspaceChats() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="flex gap-x-4 items-center"> <p className="text-lg leading-6 font-bold text-white"> diff --git a/frontend/src/pages/GeneralSettings/EmbedConfigs/index.jsx b/frontend/src/pages/GeneralSettings/EmbedConfigs/index.jsx index a46a9d5e0..4d65e0d03 100644 --- a/frontend/src/pages/GeneralSettings/EmbedConfigs/index.jsx +++ b/frontend/src/pages/GeneralSettings/EmbedConfigs/index.jsx @@ -9,6 +9,7 @@ import NewEmbedModal from "./NewEmbedModal"; import { useModal } from "@/hooks/useModal"; import ModalWrapper from "@/components/ModalWrapper"; import Embed from "@/models/embed"; +import CTAButton from "@/components/lib/CTAButton"; export default function EmbedConfigs() { const { isOpen, openModal, closeModal } = useModal(); @@ -20,18 +21,12 @@ export default function EmbedConfigs() { style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center flex gap-x-4"> <p className="text-lg leading-6 font-bold text-white"> Embeddable Chat Widgets </p> - <button - onClick={openModal} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - <CodeBlock className="h-4 w-4" /> Create embed - </button> </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> Embeddable chat widgets are public facing chat interfaces that are @@ -39,6 +34,11 @@ export default function EmbedConfigs() { that then you can publish to the world. </p> </div> + <div className="w-full justify-end flex"> + <CTAButton onClick={openModal} className="mt-3 mr-0 -mb-14 z-10"> + <CodeBlock className="h-4 w-4" weight="bold" /> Create embed + </CTAButton> + </div> <EmbedContainer /> </div> <ModalWrapper isOpen={isOpen}> diff --git a/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx b/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx index d2b265560..ad7c08d35 100644 --- a/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx @@ -19,6 +19,7 @@ import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem"; import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react"; import { useModal } from "@/hooks/useModal"; import ModalWrapper from "@/components/ModalWrapper"; +import CTAButton from "@/components/lib/CTAButton"; export default function GeneralEmbeddingPreference() { const [saving, setSaving] = useState(false); @@ -165,21 +166,12 @@ export default function GeneralEmbeddingPreference() { onSubmit={handleSubmit} className="flex w-full" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="flex gap-x-4 items-center"> <p className="text-lg leading-6 font-bold text-white"> Embedding Preference </p> - {hasChanges && ( - <button - type="submit" - disabled={saving} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - {saving ? "Saving..." : "Save changes"} - </button> - )} </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> When using an LLM that does not natively support an embedding @@ -191,6 +183,16 @@ export default function GeneralEmbeddingPreference() { format which AnythingLLM can use to process. </p> </div> + <div className="w-full justify-end flex"> + {hasChanges && ( + <CTAButton + onClick={() => handleSubmit()} + className="mt-3 mr-0 -mb-14 z-10" + > + {saving ? "Saving..." : "Save changes"} + </CTAButton> + )} + </div> <div className="text-base font-bold text-white mt-6 mb-4"> Embedding Provider </div> diff --git a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx index ccc6508ba..5fbc826ca 100644 --- a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx @@ -35,6 +35,7 @@ import GroqAiOptions from "@/components/LLMSelection/GroqAiOptions"; import LLMItem from "@/components/LLMSelection/LLMItem"; import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react"; +import CTAButton from "@/components/lib/CTAButton"; export const AVAILABLE_LLM_PROVIDERS = [ { @@ -245,21 +246,12 @@ export default function GeneralLLMPreference() { className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > <form onSubmit={handleSubmit} className="flex w-full"> - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="flex gap-x-4 items-center"> <p className="text-lg leading-6 font-bold text-white"> LLM Preference </p> - {hasChanges && ( - <button - type="submit" - disabled={saving} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - {saving ? "Saving..." : "Save changes"} - </button> - )} </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> These are the credentials and settings for your preferred LLM @@ -268,6 +260,16 @@ export default function GeneralLLMPreference() { properly. </p> </div> + <div className="w-full justify-end flex"> + {hasChanges && ( + <CTAButton + onClick={() => handleSubmit()} + className="mt-3 mr-0 -mb-14 z-10" + > + {saving ? "Saving..." : "Save changes"} + </CTAButton> + )} + </div> <div className="text-base font-bold text-white mt-6 mb-4"> LLM Provider </div> diff --git a/frontend/src/pages/GeneralSettings/PrivacyAndData/index.jsx b/frontend/src/pages/GeneralSettings/PrivacyAndData/index.jsx index dfc4b29f9..c0cd2b199 100644 --- a/frontend/src/pages/GeneralSettings/PrivacyAndData/index.jsx +++ b/frontend/src/pages/GeneralSettings/PrivacyAndData/index.jsx @@ -29,16 +29,16 @@ export default function PrivacyAndDataHandling() { <Sidebar /> <div style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} - className="transition-all duration-500 relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll border-2 border-outline" + className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > - <div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="items-center flex gap-x-4"> - <p className="text-2xl font-semibold text-white"> + <p className="text-lg leading-6 font-bold text-white"> Privacy & Data-Handling </p> </div> - <p className="text-sm font-base text-white text-opacity-60"> + <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> This is your configuration for how connected third party providers and AnythingLLM handle your data. </p> diff --git a/frontend/src/pages/GeneralSettings/Security/index.jsx b/frontend/src/pages/GeneralSettings/Security/index.jsx index 298a81ad7..7d60aadad 100644 --- a/frontend/src/pages/GeneralSettings/Security/index.jsx +++ b/frontend/src/pages/GeneralSettings/Security/index.jsx @@ -6,6 +6,7 @@ import System from "@/models/system"; import paths from "@/utils/paths"; import { AUTH_TIMESTAMP, AUTH_TOKEN, AUTH_USER } from "@/utils/constants"; import PreLoader from "@/components/Preloader"; +import CTAButton from "@/components/lib/CTAButton"; export default function GeneralSecurity() { return ( @@ -13,7 +14,7 @@ export default function GeneralSecurity() { <Sidebar /> <div style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }} - className="transition-all duration-500 relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll border-2 border-outline" + className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > <MultiUserMode /> <PasswordProtection /> @@ -32,7 +33,7 @@ function MultiUserMode() { const handleSubmit = async (e) => { e.preventDefault(); setSaving(true); - + setHasChanges(false); if (useMultiUserMode) { const form = new FormData(e.target); const data = { @@ -83,27 +84,30 @@ function MultiUserMode() { <form onSubmit={handleSubmit} onChange={() => setHasChanges(true)} - className="flex w-full" + className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16" > - <div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16"> - <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> + <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> + <div className="w-full flex flex-col gap-y-1"> <div className="items-center flex gap-x-4"> - <p className="text-2xl font-semibold text-white">Multi-User Mode</p> - {hasChanges && ( - <button - type="submit" - disabled={saving} - className="border border-slate-200 px-4 py-1 rounded-lg text-slate-200 text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800" - > - {saving ? "Saving..." : "Save changes"} - </button> - )} + <p className="text-lg leading-6 font-bold text-white"> + Multi-User Mode + </p> </div> - <p className="text-sm font-base text-white text-opacity-60"> + <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> Set up your instance to support your team by activating Multi-User Mode. </p> </div> + {hasChanges && ( + <div className="flex justify-end"> + <CTAButton + onClick={() => handleSubmit()} + className="mt-3 mr-0 -mb-20 z-10" + > + {saving ? "Saving..." : "Save changes"} + </CTAButton> + </div> + )} <div className="relative w-full max-h-full"> <div className="relative rounded-lg"> <div className="flex items-start justify-between px-6 py-4"></div> @@ -198,6 +202,7 @@ function PasswordProtection() { if (multiUserModeEnabled) return false; setSaving(true); + setHasChanges(false); const form = new FormData(e.target); const data = { usePassword, @@ -248,29 +253,30 @@ function PasswordProtection() { <form onSubmit={handleSubmit} onChange={() => setHasChanges(true)} - className="flex w-full" + className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16" > - <div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16"> - <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> + <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> + <div className="w-full flex flex-col gap-y-1"> <div className="items-center flex gap-x-4"> - <p className="text-2xl font-semibold text-white"> + <p className="text-lg leading-6 font-bold text-white"> Password Protection </p> - {hasChanges && ( - <button - type="submit" - disabled={saving} - className="border border-slate-200 px-4 py-1 rounded-lg text-slate-200 text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800" - > - {saving ? "Saving..." : "Save changes"} - </button> - )} </div> - <p className="text-sm font-base text-white text-opacity-60"> + <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> Protect your AnythingLLM instance with a password. If you forget this there is no recovery method so ensure you save this password. </p> </div> + {hasChanges && ( + <div className="flex justify-end"> + <CTAButton + onClick={() => handleSubmit()} + className="mt-3 mr-0 -mb-20 z-10" + > + {saving ? "Saving..." : "Save changes"} + </CTAButton> + </div> + )} <div className="relative w-full max-h-full"> <div className="relative rounded-lg"> <div className="flex items-start justify-between px-6 py-4"></div> diff --git a/frontend/src/pages/GeneralSettings/TranscriptionPreference/index.jsx b/frontend/src/pages/GeneralSettings/TranscriptionPreference/index.jsx index c4d20ef4b..5fbd196c3 100644 --- a/frontend/src/pages/GeneralSettings/TranscriptionPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/TranscriptionPreference/index.jsx @@ -10,6 +10,7 @@ import OpenAiWhisperOptions from "@/components/TranscriptionSelection/OpenAiOpti import NativeTranscriptionOptions from "@/components/TranscriptionSelection/NativeTranscriptionOptions"; import LLMItem from "@/components/LLMSelection/LLMItem"; import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react"; +import CTAButton from "@/components/lib/CTAButton"; export default function TranscriptionModelPreference() { const [saving, setSaving] = useState(false); @@ -114,21 +115,12 @@ export default function TranscriptionModelPreference() { className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-main-gradient w-full h-full overflow-y-scroll" > <form onSubmit={handleSubmit} className="flex w-full"> - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="flex gap-x-4 items-center"> <p className="text-lg leading-6 font-bold text-white"> Transcription Model Preference </p> - {hasChanges && ( - <button - type="submit" - disabled={saving} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - {saving ? "Saving..." : "Save changes"} - </button> - )} </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> These are the credentials and settings for your preferred @@ -137,6 +129,16 @@ export default function TranscriptionModelPreference() { transcribe. </p> </div> + <div className="w-full justify-end flex"> + {hasChanges && ( + <CTAButton + onClick={() => handleSubmit()} + className="mt-3 mr-0 -mb-14 z-10" + > + {saving ? "Saving..." : "Save changes"} + </CTAButton> + )} + </div> <div className="text-base font-bold text-white mt-6 mb-4"> Transcription Provider </div> diff --git a/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx b/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx index df0307d11..a782410e5 100644 --- a/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx +++ b/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx @@ -25,6 +25,7 @@ import ZillizCloudOptions from "@/components/VectorDBSelection/ZillizCloudOption import { useModal } from "@/hooks/useModal"; import ModalWrapper from "@/components/ModalWrapper"; import AstraDBOptions from "@/components/VectorDBSelection/AstraDBOptions"; +import CTAButton from "@/components/lib/CTAButton"; export default function GeneralVectorDatabase() { const [saving, setSaving] = useState(false); @@ -189,21 +190,12 @@ export default function GeneralVectorDatabase() { onSubmit={handleSubmit} className="flex w-full" > - <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[86px] md:py-6 py-16"> + <div className="flex flex-col w-full px-1 md:pl-6 md:pr-[50px] md:py-6 py-16"> <div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10"> <div className="flex gap-x-4 items-center"> <p className="text-lg leading-6 font-bold text-white"> Vector Database </p> - {hasChanges && ( - <button - type="submit" - disabled={saving} - className="flex items-center gap-x-2 px-4 py-2 rounded-lg bg-[#2C2F36] text-white text-sm hover:bg-[#3D4147] shadow-md border border-[#3D4147]" - > - {saving ? "Saving..." : "Save changes"} - </button> - )} </div> <p className="text-xs leading-[18px] font-base text-white text-opacity-60"> These are the credentials and settings for how your @@ -211,6 +203,16 @@ export default function GeneralVectorDatabase() { are current and correct. </p> </div> + <div className="w-full justify-end flex"> + {hasChanges && ( + <CTAButton + onClick={() => handleSubmit()} + className="mt-3 mr-0 -mb-14 z-10" + > + {saving ? "Saving..." : "Save changes"} + </CTAButton> + )} + </div> <div className="text-base font-bold text-white mt-6 mb-4"> Vector Database Provider </div> diff --git a/frontend/src/pages/WorkspaceSettings/Members/AddMemberModal/index.jsx b/frontend/src/pages/WorkspaceSettings/Members/AddMemberModal/index.jsx index 0799e5486..e5410f403 100644 --- a/frontend/src/pages/WorkspaceSettings/Members/AddMemberModal/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/Members/AddMemberModal/index.jsx @@ -138,15 +138,17 @@ export default function AddMemberModal({ closeModal, workspace, users }) { </div> <p className="text-white text-sm font-medium">Select All</p> </button> - <button - type="button" - onClick={handleUnselect} - className="flex items-center gap-x-2 ml-2" - > - <p className="text-white/60 text-sm font-medium hover:text-white"> - Unselect - </p> - </button> + {selectedUsers.length > 0 && ( + <button + type="button" + onClick={handleUnselect} + className="flex items-center gap-x-2 ml-2" + > + <p className="text-white/60 text-sm font-medium hover:text-white"> + Unselect + </p> + </button> + )} </div> <button type="submit" diff --git a/frontend/src/pages/WorkspaceSettings/Members/index.jsx b/frontend/src/pages/WorkspaceSettings/Members/index.jsx index f315619a4..8767ea2da 100644 --- a/frontend/src/pages/WorkspaceSettings/Members/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/Members/index.jsx @@ -5,6 +5,7 @@ import { useEffect, useState } from "react"; import * as Skeleton from "react-loading-skeleton"; import AddMemberModal from "./AddMemberModal"; import WorkspaceMemberRow from "./WorkspaceMemberRow"; +import CTAButton from "@/components/lib/CTAButton"; export default function Members({ workspace }) { const [loading, setLoading] = useState(true); @@ -77,14 +78,7 @@ export default function Members({ workspace }) { )} </tbody> </table> - - <button - onClick={openModal} - className="text-xs px-2 py-1 font-semibold rounded-lg bg-[#46C8FF] hover:bg-[#2C2F36] hover:text-white h-[34px] w-[100px] -mr-8 whitespace-nowrap shadow-[0_4px_14px_rgba(0,0,0,0.25)]" - > - Manage Users - </button> - + <CTAButton onClick={openModal}>Manage Users</CTAButton> <ModalWrapper isOpen={isOpen}> <AddMemberModal closeModal={closeModal}