mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-14 23:25:59 +08:00
### What problem does this PR solve? Feat: Add RAGFlowSelect component #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
cdb3e6434a
commit
392f28882f
@ -1,10 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import * as SelectPrimitive from '@radix-ui/react-select';
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
||||||
import { Check, ChevronDown, ChevronUp } from 'lucide-react';
|
import { Check, ChevronDown, ChevronUp, X } from 'lucide-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { ControllerRenderProps } from 'react-hook-form';
|
||||||
|
|
||||||
|
import { FormControl } from '@/components/ui/form';
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root;
|
const Select = SelectPrimitive.Root;
|
||||||
|
|
||||||
@ -14,8 +18,10 @@ const SelectValue = SelectPrimitive.Value;
|
|||||||
|
|
||||||
const SelectTrigger = React.forwardRef<
|
const SelectTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & {
|
||||||
>(({ className, children, ...props }, ref) => (
|
onReset?: () => void;
|
||||||
|
}
|
||||||
|
>(({ className, children, value, onReset, ...props }, ref) => (
|
||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -25,8 +31,17 @@ const SelectTrigger = React.forwardRef<
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<SelectPrimitive.Icon asChild>
|
<SelectPrimitive.Icon
|
||||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
asChild
|
||||||
|
onPointerDown={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value ? (
|
||||||
|
<X className="h-4 w-4 opacity-50 cursor-pointer" onClick={onReset} />
|
||||||
|
) : (
|
||||||
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
|
)}
|
||||||
</SelectPrimitive.Icon>
|
</SelectPrimitive.Icon>
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
));
|
));
|
||||||
@ -158,3 +173,111 @@ export {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RAGFlowSelectOptionType = {
|
||||||
|
label: React.ReactNode;
|
||||||
|
value: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RAGFlowSelectGroupOptionType = {
|
||||||
|
label: React.ReactNode;
|
||||||
|
options: RAGFlowSelectOptionType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type RAGFlowSelectProps = Partial<ControllerRenderProps> & {
|
||||||
|
FormControlComponent?: typeof FormControl;
|
||||||
|
options?: (RAGFlowSelectOptionType | RAGFlowSelectGroupOptionType)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Reference:
|
||||||
|
* https://github.com/shadcn-ui/ui/discussions/638
|
||||||
|
* https://github.com/radix-ui/primitives/discussions/2645#discussioncomment-8343397
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {(Partial<ControllerRenderProps> & {
|
||||||
|
* FormControlComponent?: typeof FormControl;
|
||||||
|
* })} {
|
||||||
|
* value: initialValue,
|
||||||
|
* onChange,
|
||||||
|
* FormControlComponent,
|
||||||
|
* }
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export function RAGFlowSelect({
|
||||||
|
value: initialValue,
|
||||||
|
onChange,
|
||||||
|
FormControlComponent,
|
||||||
|
options = [],
|
||||||
|
}: RAGFlowSelectProps) {
|
||||||
|
const [key, setKey] = React.useState(+new Date());
|
||||||
|
const [value, setValue] = React.useState<string | undefined>(undefined);
|
||||||
|
|
||||||
|
const FormControlWidget = FormControlComponent
|
||||||
|
? FormControlComponent
|
||||||
|
: React.Fragment;
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(val?: string) => {
|
||||||
|
setValue(val);
|
||||||
|
onChange?.(val);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleReset = useCallback(() => {
|
||||||
|
handleChange(undefined);
|
||||||
|
setKey(+new Date());
|
||||||
|
}, [handleChange]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue((preValue) => {
|
||||||
|
if (preValue !== initialValue) {
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
return preValue;
|
||||||
|
});
|
||||||
|
}, [initialValue]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select onValueChange={handleChange} value={value} key={key}>
|
||||||
|
<FormControlWidget>
|
||||||
|
<SelectTrigger
|
||||||
|
className="bg-colors-background-inverse-weak"
|
||||||
|
value={value}
|
||||||
|
onReset={handleReset}
|
||||||
|
>
|
||||||
|
<SelectValue placeholder="Select a verified email to display" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControlWidget>
|
||||||
|
<SelectContent>
|
||||||
|
{options.map((o, idx) => {
|
||||||
|
if ('value' in o) {
|
||||||
|
return (
|
||||||
|
<SelectItem
|
||||||
|
value={o.value as RAGFlowSelectOptionType['value']}
|
||||||
|
key={o.value}
|
||||||
|
disabled={o.disabled}
|
||||||
|
>
|
||||||
|
{o.label}
|
||||||
|
</SelectItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SelectGroup key={idx}>
|
||||||
|
<SelectLabel>{o.label}</SelectLabel>
|
||||||
|
{o.options.map((x) => (
|
||||||
|
<SelectItem value={x.value} key={x.value} disabled={x.disabled}>
|
||||||
|
{x.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -14,16 +14,20 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import {
|
import { RAGFlowSelect } from '@/components/ui/select';
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from '@/components/ui/select';
|
|
||||||
import { FormSlider } from '@/components/ui/slider';
|
import { FormSlider } from '@/components/ui/slider';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ label: 'xx', value: 'xx' },
|
||||||
|
{ label: 'ii', value: 'ii' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const groupOptions = [
|
||||||
|
{ label: 'scsdv', options },
|
||||||
|
{ label: 'thtyu', options: [{ label: 'jj', value: 'jj' }] },
|
||||||
|
];
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
username: z.number().min(2, {
|
username: z.number().min(2, {
|
||||||
message: 'Username must be at least 2 characters.',
|
message: 'Username must be at least 2 characters.',
|
||||||
@ -95,18 +99,12 @@ export default function TestingForm() {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Username</FormLabel>
|
<FormLabel>Username</FormLabel>
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
<RAGFlowSelect
|
||||||
<FormControl>
|
value={field.value}
|
||||||
<SelectTrigger className="bg-colors-background-inverse-weak">
|
onChange={field.onChange}
|
||||||
<SelectValue placeholder="Select a verified email to display" />
|
FormControlComponent={FormControl}
|
||||||
</SelectTrigger>
|
options={groupOptions}
|
||||||
</FormControl>
|
></RAGFlowSelect>
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="m@example.com">m@example.com</SelectItem>
|
|
||||||
<SelectItem value="m@google.com">m@google.com</SelectItem>
|
|
||||||
<SelectItem value="m@support.com">m@support.com</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
This is your public display name.
|
This is your public display name.
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
|
@ -59,7 +59,7 @@ const NodeHeader = ({
|
|||||||
>
|
>
|
||||||
<OperatorIcon
|
<OperatorIcon
|
||||||
name={label as Operator}
|
name={label as Operator}
|
||||||
color={operatorMap[label as Operator].color}
|
color={operatorMap[label as Operator]?.color}
|
||||||
></OperatorIcon>
|
></OperatorIcon>
|
||||||
<span className="truncate text-center font-semibold text-sm">
|
<span className="truncate text-center font-semibold text-sm">
|
||||||
{name}
|
{name}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user