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 <CommandPrimitive.Item
ref={ref} ref={ref}
className={cn( 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, className,
)} )}
{...props} {...props}

View File

@ -16,10 +16,13 @@ import {
PopoverContent, PopoverContent,
PopoverTrigger, PopoverTrigger,
} from '@/components/ui/popover'; } from '@/components/ui/popover';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils'; 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 * as React from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { import {
useFilterStructuredOutputByValue, useFilterStructuredOutputByValue,
useFindAgentStructuredOutputLabel, useFindAgentStructuredOutputLabel,
@ -35,6 +38,7 @@ type Item = {
type Option = { type Option = {
label: string; label: string;
value: string; value: string;
parentLabel?: string;
children?: Item[]; children?: Item[];
}; };
@ -54,8 +58,9 @@ export function GroupedSelectWithSecondaryMenu({
options, options,
value, value,
onChange, onChange,
placeholder = 'Select an option...', placeholder,
}: GroupedSelectWithSecondaryMenuProps) { }: GroupedSelectWithSecondaryMenuProps) {
const { t } = useTranslation();
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const showSecondaryMenu = useShowSecondaryMenu(); const showSecondaryMenu = useShowSecondaryMenu();
@ -64,14 +69,12 @@ export function GroupedSelectWithSecondaryMenu({
// Find the label of the selected item // Find the label of the selected item
const flattenedOptions = options.flatMap((g) => g.options); const flattenedOptions = options.flatMap((g) => g.options);
let selectedLabel = let selectedItem = flattenedOptions
flattenedOptions .flatMap((o) => [o, ...(o.children || [])])
.flatMap((o) => [o, ...(o.children || [])]) .find((o) => o.value === value);
.find((o) => o.value === value)?.label || '';
if (!selectedLabel && value) { if (!selectedItem && value) {
selectedLabel = selectedItem = findAgentStructuredOutputLabel(value, flattenedOptions);
findAgentStructuredOutputLabel(value, flattenedOptions)?.label ?? '';
} }
// Handle clear click // Handle clear click
@ -97,25 +100,45 @@ export function GroupedSelectWithSecondaryMenu({
role="combobox" role="combobox"
aria-expanded={open} aria-expanded={open}
className={cn( 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', !value && 'text-muted-foreground',
)} )}
> >
<span className="truncate">{selectedLabel || placeholder}</span> {value ? (
<div className="flex items-center gap-1"> <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 && ( {value && (
<X <>
className="h-4 w-4 text-muted-foreground hover:text-foreground cursor-pointer" <XIcon
onClick={handleClear} 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> </div>
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="p-0" align="start"> <PopoverContent className="p-0" align="start">
<Command> <Command value={value}>
<CommandInput placeholder="Search..." /> <CommandInput placeholder="Search..." />
<CommandList className="overflow-visible"> <CommandList className="overflow-visible">
{options.map((group, idx) => ( {options.map((group, idx) => (
@ -166,7 +189,7 @@ export function GroupedSelectWithSecondaryMenu({
<div <div
key={child.value} key={child.value}
className={cn( 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 && value === child.value &&
'bg-accent text-accent-foreground', 'bg-accent text-accent-foreground',
)} )}
@ -187,10 +210,6 @@ export function GroupedSelectWithSecondaryMenu({
onChange?.(option.value); onChange?.(option.value);
setOpen(false); setOpen(false);
}} }}
className={cn(
value === option.value &&
'bg-accent text-accent-foreground',
)}
> >
{option.label} {option.label}
</CommandItem> </CommandItem>

View File

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