diff --git a/web/src/app/admin/models/llm/LLMProviderUpdateForm.tsx b/web/src/app/admin/models/llm/LLMProviderUpdateForm.tsx index a9ddb8e4dee..9b9b55d0187 100644 --- a/web/src/app/admin/models/llm/LLMProviderUpdateForm.tsx +++ b/web/src/app/admin/models/llm/LLMProviderUpdateForm.tsx @@ -222,7 +222,6 @@ export function LLMProviderUpdateForm({ name, value: name, }))} - direction="up" maxHeight="max-h-56" /> ) : ( @@ -246,7 +245,6 @@ export function LLMProviderUpdateForm({ value: name, }))} includeDefault - direction="up" maxHeight="max-h-56" /> ) : ( diff --git a/web/src/app/admin/settings/SettingsForm.tsx b/web/src/app/admin/settings/SettingsForm.tsx index 3be9e3cb7be..761eef0601a 100644 --- a/web/src/app/admin/settings/SettingsForm.tsx +++ b/web/src/app/admin/settings/SettingsForm.tsx @@ -51,7 +51,7 @@ function Selector({ {label && } {subtext && {subtext}} -
+
{ + const llmAcceptsImages = checkLLMSupportsImageInput( + ...getFinalLLM(llmProviders, livePersona) + ); + if (!llmAcceptsImages) { + setPopup({ + type: "error", + message: + "The current Assistant does not support image input. Please select an assistant with Vision support.", + }); + return; + } + uploadFilesForChat(acceptedFiles).then(([fileIds, error]) => { if (error) { setPopup({ @@ -690,11 +702,6 @@ export function ChatPage({ }); }} noClick - disabled={ - !checkLLMSupportsImageInput( - ...getFinalLLM(llmProviders, livePersona) - ) - } onDragLeave={() => console.log("buh")} onDragEnter={() => console.log("floppa")} > diff --git a/web/src/app/chat/sessionSidebar/AssistantsTab.tsx b/web/src/app/chat/sessionSidebar/AssistantsTab.tsx index 83d4a34f49f..404491961da 100644 --- a/web/src/app/chat/sessionSidebar/AssistantsTab.tsx +++ b/web/src/app/chat/sessionSidebar/AssistantsTab.tsx @@ -3,6 +3,7 @@ import { BasicSelectable } from "@/components/BasicClickable"; import { User } from "@/lib/types"; import { Text } from "@tremor/react"; import Link from "next/link"; +import { FaRobot } from "react-icons/fa"; import { FiEdit } from "react-icons/fi"; function AssistantDisplay({ @@ -24,7 +25,9 @@ function AssistantDisplay({
onSelect(persona)}>
-
{persona.name}
+
+ {persona.name} +
@@ -54,7 +57,7 @@ export function AssistantsTab({ const globalAssistants = personas.filter((persona) => persona.is_public); const personalAssistants = personas.filter( (persona) => - !user || (persona.users.includes(user.id) && !persona.is_public) + (!user || persona.users.includes(user.id)) && !persona.is_public ); return ( diff --git a/web/src/app/chat/sessionSidebar/SessionDisplay.tsx b/web/src/app/chat/sessionSidebar/SessionDisplay.tsx index a5070f58a73..1714bd8ce00 100644 --- a/web/src/app/chat/sessionSidebar/SessionDisplay.tsx +++ b/web/src/app/chat/sessionSidebar/SessionDisplay.tsx @@ -156,6 +156,7 @@ export function ChatSessionDisplay({ />
} + requiresContentPadding />
diff --git a/web/src/components/Dropdown.tsx b/web/src/components/Dropdown.tsx index 9b42ec56b3a..b88fe8693c5 100644 --- a/web/src/components/Dropdown.tsx +++ b/web/src/components/Dropdown.tsx @@ -286,78 +286,91 @@ export function DefaultDropdown({ selected, onSelect, includeDefault = false, - direction = "down", + side, maxHeight, }: { options: StringOrNumberOption[]; selected: string | null; onSelect: (value: string | number | null) => void; includeDefault?: boolean; - direction?: "up" | "down"; + side?: "top" | "right" | "bottom" | "left"; maxHeight?: string; }) { const selectedOption = options.find((option) => option.value === selected); + const [isOpen, setIsOpen] = useState(false); + + const Content = ( +
+

+ {selectedOption?.name || + (includeDefault ? "Default" : "Select an option...")} +

+ +
+ ); + + const Dropdown = ( +
+ {includeDefault && ( + { + onSelect(null); + }} + isSelected={selected === null} + /> + )} + {options.map((option, ind) => { + const isSelected = option.value === selected; + return ( + onSelect(option.value)} + isSelected={isSelected} + /> + ); + })} +
+ ); return ( - - {includeDefault && ( - { - onSelect(null); - }} - isSelected={selected === null} - /> - )} - {options.map((option, ind) => { - const isSelected = option.value === selected; - return ( - onSelect(option.value)} - isSelected={isSelected} - /> - ); - })} - - } - > -
-

- {selectedOption?.name || - (includeDefault ? "Default" : "Select an option...")} -

- -
-
+
setIsOpen(!isOpen)}> + setIsOpen(open)} + content={Content} + popover={Dropdown} + align="start" + side={side} + sideOffset={5} + matchWidth + /> +
); } diff --git a/web/src/components/admin/connectors/Field.tsx b/web/src/components/admin/connectors/Field.tsx index 825dc3ad811..39d280efd91 100644 --- a/web/src/components/admin/connectors/Field.tsx +++ b/web/src/components/admin/connectors/Field.tsx @@ -233,7 +233,7 @@ interface SelectorFormFieldProps { options: StringOrNumberOption[]; subtext?: string | JSX.Element; includeDefault?: boolean; - direction?: "up" | "down"; + side?: "top" | "right" | "bottom" | "left"; maxHeight?: string; onSelect?: (selected: string | number | null) => void; } @@ -244,7 +244,7 @@ export function SelectorFormField({ options, subtext, includeDefault = false, - direction = "down", + side = "bottom", maxHeight, onSelect, }: SelectorFormFieldProps) { @@ -262,7 +262,7 @@ export function SelectorFormField({ selected={field.value} onSelect={onSelect || ((selected) => setFieldValue(name, selected))} includeDefault={includeDefault} - direction={direction} + side={side} maxHeight={maxHeight} /> diff --git a/web/src/components/popover/Popover.tsx b/web/src/components/popover/Popover.tsx index ac5d5bcf2a5..22ae839c977 100644 --- a/web/src/components/popover/Popover.tsx +++ b/web/src/components/popover/Popover.tsx @@ -1,5 +1,7 @@ "use client"; +import "./styles.css"; + import * as RadixPopover from "@radix-ui/react-popover"; export function Popover({ @@ -7,11 +9,21 @@ export function Popover({ onOpenChange, content, popover, + side, + align, + sideOffset, + matchWidth, + requiresContentPadding, }: { open: boolean; onOpenChange: (open: boolean) => void; content: JSX.Element; popover: JSX.Element; + side?: "top" | "right" | "bottom" | "left"; + align?: "start" | "center" | "end"; + sideOffset?: number; + matchWidth?: boolean; + requiresContentPadding?: boolean; }) { /* This Popover is needed when we want to put a popup / dropdown in a component @@ -24,14 +36,30 @@ export function Popover({ return ( - + {/* NOTE: this weird `-mb-1.5` is needed to offset the Anchor, otherwise the content will shift up by 1.5px when the Popover is open. */} - {open ?
{content}
: content} + {open ? ( +
+ {content} +
+ ) : ( + content + )}
- - {popover} + + {popover} +
); diff --git a/web/src/components/popover/styles.css b/web/src/components/popover/styles.css new file mode 100644 index 00000000000..f35957ba847 --- /dev/null +++ b/web/src/components/popover/styles.css @@ -0,0 +1,9 @@ +/* styles.css */ + +.PopoverContentMatchWidth { + width: var(--radix-popover-trigger-width); +} + +.PopoverContent[data-side="top"] { + transform: translateY(var(--radix-popover-trigger-height) px); +}