Feat: Modify the style of the query variable dropdown list. #10866 (#10903)

### What problem does this PR solve?

Feat: Modify the style of the query variable dropdown list. #10866

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-10-30 20:14:15 +08:00
committed by GitHub
parent a62a1a5012
commit ac75bcdf95
3 changed files with 46 additions and 26 deletions

View File

@ -124,7 +124,7 @@ const CommandItem = React.forwardRef<
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-bg-card data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
className,
)}
{...props}

View File

@ -16,10 +16,13 @@ import {
PopoverContent,
PopoverTrigger,
} from '@/components/ui/popover';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';
import { ChevronDown, X } from 'lucide-react';
import { get } from 'lodash';
import { ChevronDownIcon, XIcon } from 'lucide-react';
import * as React from 'react';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import {
useFilterStructuredOutputByValue,
useFindAgentStructuredOutputLabel,
@ -35,6 +38,7 @@ type Item = {
type Option = {
label: string;
value: string;
parentLabel?: string;
children?: Item[];
};
@ -54,8 +58,9 @@ export function GroupedSelectWithSecondaryMenu({
options,
value,
onChange,
placeholder = 'Select an option...',
placeholder,
}: GroupedSelectWithSecondaryMenuProps) {
const { t } = useTranslation();
const [open, setOpen] = React.useState(false);
const showSecondaryMenu = useShowSecondaryMenu();
@ -64,14 +69,12 @@ export function GroupedSelectWithSecondaryMenu({
// Find the label of the selected item
const flattenedOptions = options.flatMap((g) => g.options);
let selectedLabel =
flattenedOptions
.flatMap((o) => [o, ...(o.children || [])])
.find((o) => o.value === value)?.label || '';
let selectedItem = flattenedOptions
.flatMap((o) => [o, ...(o.children || [])])
.find((o) => o.value === value);
if (!selectedLabel && value) {
selectedLabel =
findAgentStructuredOutputLabel(value, flattenedOptions)?.label ?? '';
if (!selectedItem && value) {
selectedItem = findAgentStructuredOutputLabel(value, flattenedOptions);
}
// Handle clear click
@ -97,25 +100,45 @@ export function GroupedSelectWithSecondaryMenu({
role="combobox"
aria-expanded={open}
className={cn(
'w-full justify-between text-sm font-normal',
'!bg-bg-input hover:bg-background border-input w-full justify-between px-3 font-normal outline-offset-0 outline-none focus-visible:outline-[3px] [&_svg]:pointer-events-auto',
!value && 'text-muted-foreground',
)}
>
<span className="truncate">{selectedLabel || placeholder}</span>
<div className="flex items-center gap-1">
{value ? (
<div className="truncate flex items-center gap-1">
<span>{get(selectedItem, 'parentLabel')}</span>
<span className="text-text-disabled">/</span>
<span className="text-accent-primary">{selectedItem?.label}</span>
</div>
) : (
<span className="text-muted-foreground">
{placeholder || t('common.selectPlaceholder')}
</span>
)}
<div className="flex items-center justify-between">
{value && (
<X
className="h-4 w-4 text-muted-foreground hover:text-foreground cursor-pointer"
onClick={handleClear}
/>
<>
<XIcon
className="h-4 mx-2 cursor-pointer text-muted-foreground"
onClick={handleClear}
/>
<Separator
orientation="vertical"
className="flex min-h-6 h-full"
/>
</>
)}
<ChevronDown className="h-4 w-4 opacity-50" />
<ChevronDownIcon
size={16}
className="text-muted-foreground/80 shrink-0 ml-2"
aria-hidden="true"
/>
</div>
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="start">
<Command>
<Command value={value}>
<CommandInput placeholder="Search..." />
<CommandList className="overflow-visible">
{options.map((group, idx) => (
@ -166,7 +189,7 @@ export function GroupedSelectWithSecondaryMenu({
<div
key={child.value}
className={cn(
'cursor-pointer rounded-sm px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground',
'cursor-pointer rounded-sm px-2 py-1.5 text-sm hover:bg-bg-card hover:text-accent-foreground',
value === child.value &&
'bg-accent text-accent-foreground',
)}
@ -187,10 +210,6 @@ export function GroupedSelectWithSecondaryMenu({
onChange?.(option.value);
setOpen(false);
}}
className={cn(
value === option.value &&
'bg-accent text-accent-foreground',
)}
>
{option.label}
</CommandItem>

View File

@ -6,6 +6,7 @@ import {
} from '@/components/ui/hover-card';
import { cn } from '@/lib/utils';
import { get, isPlainObject } from 'lodash';
import { ChevronRight } from 'lucide-react';
import { PropsWithChildren, ReactNode, useCallback } from 'react';
type DataItem = { label: ReactNode; value: string; parentLabel?: ReactNode };
@ -59,8 +60,8 @@ export function StructuredOutputSecondaryMenu({
return (
<HoverCard key={data.value} openDelay={100} closeDelay={100}>
<HoverCardTrigger asChild>
<li className="hover:bg-bg-card p-1 text-text-primary rounded-sm">
{data.label}
<li className="hover:bg-bg-card py-1 px-2 text-text-primary rounded-sm text-sm flex justify-between items-center">
{data.label} <ChevronRight className="size-3.5 text-text-secondary" />
</li>
</HoverCardTrigger>
<HoverCardContent