Download frontend/src/components/SettingsSidebar/MenuOption/index.jsx from leowuming/rag: direct link, hf CLI and curl.
- Browser
- Download file 5.65 kB
-
https://huggingface.co/spaces/leowuming/rag/resolve/main/frontend/src/components/SettingsSidebar/MenuOption/index.jsx
- Command line
-
hf download hf://spaces/leowuming/rag/frontend/src/components/SettingsSidebar/MenuOption/index.jsx
-
curl -L -o index.jsx https://huggingface.co/spaces/leowuming/rag/resolve/main/frontend/src/components/SettingsSidebar/MenuOption/index.jsx
5.65 kB
| import React, { useEffect, useState } from "react"; | |
| import { CaretRight } from "@phosphor-icons/react"; | |
| import { Link, useLocation } from "react-router-dom"; | |
| export default function MenuOption({ | |
| btnText, | |
| icon, | |
| href, | |
| childOptions = [], | |
| flex = false, | |
| user = null, | |
| roles = [], | |
| hidden = false, | |
| isChild = false, | |
| }) { | |
| const storageKey = generateStorageKey({ key: btnText }); | |
| const location = useLocation(); | |
| const hasChildren = childOptions.length > 0; | |
| const hasVisibleChildren = hasVisibleOptions(user, childOptions); | |
| const { isExpanded, setIsExpanded } = useIsExpanded({ | |
| storageKey, | |
| hasVisibleChildren, | |
| childOptions, | |
| location: location.pathname, | |
| }); | |
| if (hidden) return null; | |
| // If this option is a parent level option | |
| if (!isChild) { | |
| // and has no children then use its flex props and roles prop directly | |
| if (!hasChildren) { | |
| if (!flex && !roles.includes(user?.role)) return null; | |
| if (flex && !!user && !roles.includes(user?.role)) return null; | |
| } | |
| // if has children and no visible children - remove it. | |
| if (hasChildren && !hasVisibleChildren) return null; | |
| } else { | |
| // is a child so we use it's permissions | |
| if (!flex && !roles.includes(user?.role)) return null; | |
| if (flex && !!user && !roles.includes(user?.role)) return null; | |
| } | |
| const isActive = hasChildren | |
| ? (!isExpanded && | |
| childOptions.some((child) => child.href === location.pathname)) || | |
| location.pathname === href | |
| : location.pathname === href; | |
| const handleClick = (e) => { | |
| if (hasChildren) { | |
| e.preventDefault(); | |
| const newExpandedState = !isExpanded; | |
| setIsExpanded(newExpandedState); | |
| localStorage.setItem(storageKey, JSON.stringify(newExpandedState)); | |
| } | |
| }; | |
| return ( | |
| <div> | |
| <div | |
| className={` | |
| flex items-center justify-between w-full | |
| transition-all duration-300 | |
| rounded-[6px] | |
| ${ | |
| isActive | |
| ? "bg-theme-sidebar-subitem-selected font-medium border-outline" | |
| : "hover:bg-theme-sidebar-subitem-hover" | |
| } | |
| `} | |
| > | |
| <Link | |
| to={href} | |
| className={`flex flex-grow items-center px-[12px] h-[32px] font-medium ${ | |
| isChild ? "hover:text-white" : "text-white light:text-black" | |
| }`} | |
| onClick={hasChildren ? handleClick : undefined} | |
| > | |
| {icon} | |
| <p | |
| className={`${ | |
| isChild ? "text-xs" : "text-sm" | |
| } leading-loose whitespace-nowrap overflow-hidden ml-2 ${ | |
| isActive | |
| ? "text-white font-semibold" | |
| : "text-white light:text-black" | |
| } ${!icon && "pl-5"}`} | |
| > | |
| {btnText} | |
| </p> | |
| </Link> | |
| {hasChildren && ( | |
| <button onClick={handleClick} className="p-2 text-white"> | |
| <CaretRight | |
| size={16} | |
| weight="bold" | |
| // color={isExpanded ? "#000000" : "var(--theme-sidebar-subitem-icon)"} | |
| className={`transition-transform text-white light:text-black ${ | |
| isExpanded ? "rotate-90" : "" | |
| }`} | |
| /> | |
| </button> | |
| )} | |
| </div> | |
| {isExpanded && hasChildren && ( | |
| <div className="mt-1 rounded-r-lg w-full"> | |
| {childOptions.map((childOption, index) => ( | |
| <MenuOption | |
| key={index} | |
| {...childOption} // flex and roles go here. | |
| user={user} | |
| isChild={true} | |
| /> | |
| ))} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| function useIsExpanded({ | |
| storageKey = "", | |
| hasVisibleChildren = false, | |
| childOptions = [], | |
| location = null, | |
| }) { | |
| const [isExpanded, setIsExpanded] = useState(() => { | |
| if (hasVisibleChildren) { | |
| const storedValue = localStorage.getItem(storageKey); | |
| if (storedValue !== null) { | |
| return JSON.parse(storedValue); | |
| } | |
| return childOptions.some((child) => child.href === location); | |
| } | |
| return false; | |
| }); | |
| useEffect(() => { | |
| if (hasVisibleChildren) { | |
| const shouldExpand = childOptions.some( | |
| (child) => child.href === location | |
| ); | |
| if (shouldExpand && !isExpanded) { | |
| setIsExpanded(true); | |
| localStorage.setItem(storageKey, JSON.stringify(true)); | |
| } | |
| } | |
| }, [location]); | |
| return { isExpanded, setIsExpanded }; | |
| } | |
| /** | |
| * Checks if the child options are visible to the user. | |
| * This hides the top level options if the child options are not visible | |
| * for either the users permissions or the child options hidden prop is set to true by other means. | |
| * If all child options return false for `isVisible` then the parent option will not be visible as well. | |
| * @param {object} user - The user object. | |
| * @param {array} childOptions - The child options. | |
| * @returns {boolean} - True if the child options are visible, false otherwise. | |
| */ | |
| function hasVisibleOptions(user = null, childOptions = []) { | |
| if (!Array.isArray(childOptions) || childOptions?.length === 0) return false; | |
| function isVisible({ | |
| roles = [], | |
| user = null, | |
| flex = false, | |
| hidden = false, | |
| }) { | |
| if (hidden) return false; | |
| if (!flex && !roles.includes(user?.role)) return false; | |
| if (flex && !!user && !roles.includes(user?.role)) return false; | |
| return true; | |
| } | |
| return childOptions.some((opt) => | |
| isVisible({ roles: opt.roles, user, flex: opt.flex, hidden: opt.hidden }) | |
| ); | |
| } | |
| function generateStorageKey({ key = "" }) { | |
| const _key = key.replace(/\s+/g, "_").toLowerCase(); | |
| return `anything_llm_menu_${_key}_expanded`; | |
| } | |