mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-08-08 14:02:09 +02:00
Misc UI improvments
This commit is contained in:
@@ -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"
|
||||
/>
|
||||
) : (
|
||||
|
@@ -51,7 +51,7 @@ function Selector({
|
||||
{label && <Label>{label}</Label>}
|
||||
{subtext && <SubLabel>{subtext}</SubLabel>}
|
||||
|
||||
<div className="mt-2">
|
||||
<div className="mt-2 w-full max-w-96">
|
||||
<DefaultDropdown
|
||||
options={options}
|
||||
selected={selected}
|
||||
|
@@ -677,6 +677,18 @@ export function ChatPage({
|
||||
{documentSidebarInitialWidth !== undefined ? (
|
||||
<Dropzone
|
||||
onDrop={(acceptedFiles) => {
|
||||
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")}
|
||||
>
|
||||
|
@@ -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({
|
||||
<div className="w-full" onClick={() => onSelect(persona)}>
|
||||
<BasicSelectable selected={false} fullWidth>
|
||||
<div className="flex">
|
||||
<div className="truncate w-48 3xl:w-56">{persona.name}</div>
|
||||
<div className="truncate w-48 3xl:w-56 flex">
|
||||
<FaRobot className="mr-2 my-auto" size={16} /> {persona.name}
|
||||
</div>
|
||||
</div>
|
||||
</BasicSelectable>
|
||||
</div>
|
||||
@@ -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 (
|
||||
|
@@ -156,6 +156,7 @@ export function ChatSessionDisplay({
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
requiresContentPadding
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -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 = (
|
||||
<div
|
||||
className={`
|
||||
flex
|
||||
text-sm
|
||||
bg-background
|
||||
px-3
|
||||
py-1.5
|
||||
rounded-lg
|
||||
border
|
||||
border-border
|
||||
cursor-pointer`}
|
||||
>
|
||||
<p className="line-clamp-1">
|
||||
{selectedOption?.name ||
|
||||
(includeDefault ? "Default" : "Select an option...")}
|
||||
</p>
|
||||
<FiChevronDown className="my-auto ml-auto" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const Dropdown = (
|
||||
<div
|
||||
className={`
|
||||
border
|
||||
border
|
||||
rounded-lg
|
||||
flex
|
||||
flex-col
|
||||
bg-background
|
||||
${maxHeight || "max-h-96"}
|
||||
overflow-y-auto
|
||||
overscroll-contain`}
|
||||
>
|
||||
{includeDefault && (
|
||||
<DefaultDropdownElement
|
||||
key={-1}
|
||||
name="Default"
|
||||
onSelect={() => {
|
||||
onSelect(null);
|
||||
}}
|
||||
isSelected={selected === null}
|
||||
/>
|
||||
)}
|
||||
{options.map((option, ind) => {
|
||||
const isSelected = option.value === selected;
|
||||
return (
|
||||
<DefaultDropdownElement
|
||||
key={option.value}
|
||||
name={option.name}
|
||||
description={option.description}
|
||||
onSelect={() => onSelect(option.value)}
|
||||
isSelected={isSelected}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<CustomDropdown
|
||||
direction={direction}
|
||||
dropdown={
|
||||
<div
|
||||
className={`
|
||||
border
|
||||
border
|
||||
rounded-lg
|
||||
flex
|
||||
flex-col
|
||||
bg-background
|
||||
${maxHeight || "max-h-96"}
|
||||
overflow-y-auto
|
||||
overscroll-contain`}
|
||||
>
|
||||
{includeDefault && (
|
||||
<DefaultDropdownElement
|
||||
key={-1}
|
||||
name="Default"
|
||||
onSelect={() => {
|
||||
onSelect(null);
|
||||
}}
|
||||
isSelected={selected === null}
|
||||
/>
|
||||
)}
|
||||
{options.map((option, ind) => {
|
||||
const isSelected = option.value === selected;
|
||||
return (
|
||||
<DefaultDropdownElement
|
||||
key={option.value}
|
||||
name={option.name}
|
||||
description={option.description}
|
||||
onSelect={() => onSelect(option.value)}
|
||||
isSelected={isSelected}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
flex
|
||||
text-sm
|
||||
bg-background
|
||||
px-3
|
||||
py-1.5
|
||||
rounded-lg
|
||||
border
|
||||
border-border
|
||||
cursor-pointer`}
|
||||
>
|
||||
<p className="line-clamp-1">
|
||||
{selectedOption?.name ||
|
||||
(includeDefault ? "Default" : "Select an option...")}
|
||||
</p>
|
||||
<FiChevronDown className="my-auto ml-auto" />
|
||||
</div>
|
||||
</CustomDropdown>
|
||||
<div onClick={() => setIsOpen(!isOpen)}>
|
||||
<Popover
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => setIsOpen(open)}
|
||||
content={Content}
|
||||
popover={Dropdown}
|
||||
align="start"
|
||||
side={side}
|
||||
sideOffset={5}
|
||||
matchWidth
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
|
@@ -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 (
|
||||
<RadixPopover.Root open={open} onOpenChange={onOpenChange}>
|
||||
<RadixPopover.Trigger>
|
||||
<RadixPopover.Trigger style={{ width: "100%" }}>
|
||||
{/* 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 ? <div className="-mb-1.5">{content}</div> : content}
|
||||
{open ? (
|
||||
<div className={requiresContentPadding ? "-mb-1.5" : ""}>
|
||||
{content}
|
||||
</div>
|
||||
) : (
|
||||
content
|
||||
)}
|
||||
</RadixPopover.Trigger>
|
||||
<RadixPopover.Anchor />
|
||||
<RadixPopover.Portal>
|
||||
<RadixPopover.Content>{popover}</RadixPopover.Content>
|
||||
<RadixPopover.Content
|
||||
className={
|
||||
"PopoverContent z-[100] " +
|
||||
(matchWidth ? " PopoverContentMatchWidth" : "")
|
||||
}
|
||||
asChild
|
||||
side={side}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
>
|
||||
{popover}
|
||||
</RadixPopover.Content>
|
||||
</RadixPopover.Portal>
|
||||
</RadixPopover.Root>
|
||||
);
|
||||
|
9
web/src/components/popover/styles.css
Normal file
9
web/src/components/popover/styles.css
Normal file
@@ -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);
|
||||
}
|
Reference in New Issue
Block a user