import React, { useEffect, useRef, useState } from "react";
import paths from "@/utils/paths";
import useLogo from "@/hooks/useLogo";
import {
House,
List,
Robot,
Flask,
Gear,
UserCircleGear,
PencilSimpleLine,
Nut,
Toolbox,
Globe,
} from "@phosphor-icons/react";
import useUser from "@/hooks/useUser";
import { isMobile } from "react-device-detect";
import Footer from "../Footer";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
import showToast from "@/utils/toast";
import System from "@/models/system";
import Option from "./MenuOption";
import { CanViewChatHistoryProvider } from "../CanViewChatHistory";
import useAppVersion from "@/hooks/useAppVersion";
export default function SettingsSidebar() {
const { t } = useTranslation();
const { logo } = useLogo();
const { user } = useUser();
const sidebarRef = useRef(null);
const [showSidebar, setShowSidebar] = useState(false);
const [showBgOverlay, setShowBgOverlay] = useState(false);
useEffect(() => {
function handleBg() {
if (showSidebar) {
setTimeout(() => {
setShowBgOverlay(true);
}, 300);
} else {
setShowBgOverlay(false);
}
}
handleBg();
}, [showSidebar]);
if (isMobile) {
return (
<>
setShowSidebar(false)}
/>
{/* Header Information */}
{/* Primary Body */}
>
);
}
return (
<>
>
);
}
function SupportEmail() {
const [supportEmail, setSupportEmail] = useState(paths.mailToMintplex());
const { t } = useTranslation();
useEffect(() => {
const fetchSupportEmail = async () => {
const supportEmail = await System.fetchSupportEmail();
setSupportEmail(
supportEmail?.email
? `mailto:${supportEmail.email}`
: paths.mailToMintplex()
);
};
fetchSupportEmail();
}, []);
return (
{t("settings.contact")}
);
}
const SidebarOptions = ({ user = null, t }) => (
{({ viewable: canViewChatHistory }) => (
<>
}
user={user}
childOptions={[
{
btnText: t("settings.llm"),
href: paths.settings.llmPreference(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.vector-database"),
href: paths.settings.vectorDatabase(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.embedder"),
href: paths.settings.embedder.modelPreference(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.text-splitting"),
href: paths.settings.embedder.chunkingPreference(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.voice-speech"),
href: paths.settings.audioPreference(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.transcription"),
href: paths.settings.transcriptionPreference(),
flex: true,
roles: ["admin"],
},
]}
/>
}
user={user}
childOptions={[
{
btnText: t("settings.users"),
href: paths.settings.users(),
roles: ["admin", "manager"],
},
{
btnText: t("settings.workspaces"),
href: paths.settings.workspaces(),
roles: ["admin", "manager"],
},
{
hidden: !canViewChatHistory,
btnText: t("settings.workspace-chats"),
href: paths.settings.chats(),
flex: true,
roles: ["admin", "manager"],
},
{
btnText: t("settings.invites"),
href: paths.settings.invites(),
roles: ["admin", "manager"],
},
]}
/>
}
href={paths.settings.agentSkills()}
user={user}
flex={true}
roles={["admin"]}
/>
}
childOptions={[
{
btnText: "Explore Trending",
href: paths.communityHub.trending(),
flex: true,
roles: ["admin"],
},
{
btnText: "Your Account",
href: paths.communityHub.authentication(),
flex: true,
roles: ["admin"],
},
{
btnText: "Import Item",
href: paths.communityHub.importItem(),
flex: true,
roles: ["admin"],
},
]}
/>
}
user={user}
childOptions={[
{
btnText: t("settings.interface"),
href: paths.settings.interface(),
flex: true,
roles: ["admin", "manager"],
},
{
btnText: t("settings.branding"),
href: paths.settings.branding(),
flex: true,
roles: ["admin", "manager"],
},
{
btnText: t("settings.chat"),
href: paths.settings.chat(),
flex: true,
roles: ["admin", "manager"],
},
]}
/>
}
user={user}
childOptions={[
{
hidden: !canViewChatHistory,
btnText: t("settings.embeds"),
href: paths.settings.embedChatWidgets(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.event-logs"),
href: paths.settings.logs(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.api-keys"),
href: paths.settings.apiKeys(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.system-prompt-variables"),
href: paths.settings.systemPromptVariables(),
flex: true,
roles: ["admin"],
},
{
btnText: t("settings.browser-extension"),
href: paths.settings.browserExtension(),
flex: true,
roles: ["admin", "manager"],
},
]}
/>
}
href={paths.settings.security()}
user={user}
flex={true}
roles={["admin", "manager"]}
hidden={user?.role}
/>
}
href={paths.settings.experimental()}
user={user}
flex={true}
roles={["admin"]}
/>
>
)}
);
function HoldToReveal({ children, holdForMs = 3_000 }) {
let timeout = null;
const [showing, setShowing] = useState(
window.localStorage.getItem(
"anythingllm_experimental_feature_preview_unlocked"
)
);
useEffect(() => {
const onPress = (e) => {
if (!["Control", "Meta"].includes(e.key) || timeout !== null) return;
timeout = setTimeout(() => {
setShowing(true);
// Setting toastId prevents hook spam from holding control too many times or the event not detaching
showToast("Experimental feature previews unlocked!");
window.localStorage.setItem(
"anythingllm_experimental_feature_preview_unlocked",
"enabled"
);
window.removeEventListener("keypress", onPress);
window.removeEventListener("keyup", onRelease);
clearTimeout(timeout);
}, holdForMs);
};
const onRelease = (e) => {
if (!["Control", "Meta"].includes(e.key)) return;
if (showing) {
window.removeEventListener("keypress", onPress);
window.removeEventListener("keyup", onRelease);
clearTimeout(timeout);
return;
}
clearTimeout(timeout);
};
if (!showing) {
window.addEventListener("keydown", onPress);
window.addEventListener("keyup", onRelease);
}
return () => {
window.removeEventListener("keydown", onPress);
window.removeEventListener("keyup", onRelease);
};
}, []);
if (!showing) return null;
return children;
}
function AppVersion() {
const { version, isLoading } = useAppVersion();
if (isLoading) return null;
return (
v{version}
);
}