### What problem does this PR solve? Feat: Wrap DynamicVariableForm with Collapsible. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.17.0
| @@ -1,5 +1,7 @@ | |||
| import { cn } from '@/lib/utils'; | |||
| import Icon from '@ant-design/icons'; | |||
| import { CustomIconComponentProps } from '@ant-design/icons/lib/components/Icon'; | |||
| import { ChevronDown } from 'lucide-react'; | |||
| type IconComponentProps = CustomIconComponentProps; | |||
| const currentColor = 'currentColor'; | |||
| @@ -276,3 +278,14 @@ export const SemicolonIcon = (props: Partial<IconComponentProps>) => ( | |||
| export const CommaIcon = (props: Partial<IconComponentProps>) => ( | |||
| <Icon component={CommaSvg} {...props} /> | |||
| ); | |||
| export function SideDown({ className }: { className?: string }) { | |||
| return ( | |||
| <ChevronDown | |||
| className={cn( | |||
| 'transition-transform group-data-[state=open]/collapsible:rotate-180', | |||
| className, | |||
| )} | |||
| /> | |||
| ); | |||
| } | |||
| @@ -190,7 +190,8 @@ type RAGFlowSelectProps = Partial<ControllerRenderProps> & { | |||
| FormControlComponent?: typeof FormControl; | |||
| options?: (RAGFlowSelectOptionType | RAGFlowSelectGroupOptionType)[]; | |||
| allowClear?: boolean; | |||
| }; | |||
| placeholder?: React.ReactNode; | |||
| } & SelectPrimitive.SelectProps; | |||
| /** | |||
| * | |||
| @@ -218,6 +219,7 @@ export const RAGFlowSelect = forwardRef< | |||
| FormControlComponent, | |||
| options = [], | |||
| allowClear, | |||
| placeholder, | |||
| }, | |||
| ref, | |||
| ) { | |||
| @@ -260,7 +262,7 @@ export const RAGFlowSelect = forwardRef< | |||
| allowClear={allowClear} | |||
| ref={ref} | |||
| > | |||
| <SelectValue placeholder="Select a verified email to display" /> | |||
| <SelectValue placeholder={placeholder} /> | |||
| </SelectTrigger> | |||
| </FormControlWidget> | |||
| <SelectContent> | |||
| @@ -292,3 +294,5 @@ export const RAGFlowSelect = forwardRef< | |||
| </Select> | |||
| ); | |||
| }); | |||
| RAGFlowSelect.displayName = 'RAGFlowSelect'; | |||
| @@ -1,3 +1,4 @@ | |||
| import { SideDown } from '@/assets/icon/Icon'; | |||
| import { Card, CardContent } from '@/components/ui/card'; | |||
| import { | |||
| Collapsible, | |||
| @@ -13,7 +14,6 @@ import { | |||
| SidebarHeader, | |||
| SidebarMenu, | |||
| } from '@/components/ui/sidebar'; | |||
| import { ChevronDown } from 'lucide-react'; | |||
| import { useMemo } from 'react'; | |||
| import { | |||
| AgentOperatorList, | |||
| @@ -23,12 +23,6 @@ import { | |||
| } from './constant'; | |||
| import OperatorIcon from './operator-icon'; | |||
| function SideDown() { | |||
| return ( | |||
| <ChevronDown className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" /> | |||
| ); | |||
| } | |||
| type OperatorItem = { | |||
| name: Operator; | |||
| }; | |||
| @@ -59,7 +53,7 @@ function OperatorCollapsible({ | |||
| <SidebarGroupLabel asChild className="mb-1"> | |||
| <CollapsibleTrigger> | |||
| <span className="font-bold text-base">{title}</span> | |||
| <SideDown /> | |||
| <SideDown className="ml-auto" /> | |||
| </CollapsibleTrigger> | |||
| </SidebarGroupLabel> | |||
| <CollapsibleContent className="px-2"> | |||
| @@ -87,7 +87,7 @@ const FormSheet = ({ | |||
| }, [visible, form, node?.data?.form, node?.id, node, operatorName]); | |||
| return ( | |||
| <Sheet onOpenChange={hideModal} open={visible} modal={false}> | |||
| <Sheet open={visible} modal={false}> | |||
| <SheetContent className="bg-white top-20" closeIcon={false}> | |||
| <SheetHeader> | |||
| <section className="flex-col border-b pb-2"> | |||
| @@ -1,6 +1,12 @@ | |||
| 'use client'; | |||
| import { SideDown } from '@/assets/icon/Icon'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { | |||
| Collapsible, | |||
| CollapsibleContent, | |||
| CollapsibleTrigger, | |||
| } from '@/components/ui/collapsible'; | |||
| import { | |||
| FormControl, | |||
| FormDescription, | |||
| @@ -11,7 +17,7 @@ import { | |||
| import { Input } from '@/components/ui/input'; | |||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | |||
| import { CircleMinus, Plus } from 'lucide-react'; | |||
| import { Plus, Trash2 } from 'lucide-react'; | |||
| import { useFieldArray, useFormContext } from 'react-hook-form'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query'; | |||
| @@ -61,9 +67,14 @@ export function DynamicVariableForm({ node }: IProps) { | |||
| <FormDescription /> | |||
| <FormControl> | |||
| <RAGFlowSelect | |||
| // placeholder={t('common.pleaseSelect')} | |||
| {...field} | |||
| placeholder={t('common.pleaseSelect')} | |||
| options={options} | |||
| onChange={(val) => { | |||
| field.onChange(val); | |||
| form.resetField(`query.${index}.value`); | |||
| form.resetField(`query.${index}.component_id`); | |||
| }} | |||
| ></RAGFlowSelect> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| @@ -79,7 +90,7 @@ export function DynamicVariableForm({ node }: IProps) { | |||
| <FormControl> | |||
| {typeValue === VariableType.Reference ? ( | |||
| <RAGFlowSelect | |||
| // placeholder={t('common.pleaseSelect')} | |||
| placeholder={t('common.pleaseSelect')} | |||
| {...field} | |||
| options={valueOptions} | |||
| ></RAGFlowSelect> | |||
| @@ -91,17 +102,37 @@ export function DynamicVariableForm({ node }: IProps) { | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| <CircleMinus | |||
| className="cursor-pointer" | |||
| <Trash2 | |||
| className="cursor-pointer mx-3 size-4 text-colors-text-functional-danger" | |||
| onClick={() => remove(index)} | |||
| /> | |||
| </div> | |||
| ); | |||
| })} | |||
| <Button onClick={append} className="w-full mt-4"> | |||
| <Button onClick={append} className="mt-4" variant={'outline'} size={'sm'}> | |||
| <Plus /> | |||
| {t('flow.addVariable')} | |||
| </Button> | |||
| </div> | |||
| ); | |||
| } | |||
| export function DynamicInputVariable({ node }: IProps) { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <Collapsible defaultOpen className="group/collapsible pt-4"> | |||
| <CollapsibleTrigger className="flex justify-between w-full pb-2"> | |||
| <span className="font-bold text-2xl text-colors-text-neutral-strong"> | |||
| {t('flow.input')} | |||
| </span> | |||
| <Button variant={'icon'} size={'icon'}> | |||
| <SideDown /> | |||
| </Button> | |||
| </CollapsibleTrigger> | |||
| <CollapsibleContent> | |||
| <DynamicVariableForm node={node}></DynamicVariableForm> | |||
| </CollapsibleContent> | |||
| </Collapsible> | |||
| ); | |||
| } | |||
| @@ -13,7 +13,7 @@ import { | |||
| import { Textarea } from '@/components/ui/textarea'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { DynamicVariableForm } from '../components/next-dynamic-input-variable'; | |||
| import { DynamicInputVariable } from '../components/next-dynamic-input-variable'; | |||
| const RetrievalForm = ({ form, node }: INextOperatorForm) => { | |||
| const { t } = useTranslation(); | |||
| @@ -25,7 +25,7 @@ const RetrievalForm = ({ form, node }: INextOperatorForm) => { | |||
| e.preventDefault(); | |||
| }} | |||
| > | |||
| <DynamicVariableForm></DynamicVariableForm> | |||
| <DynamicInputVariable node={node}></DynamicInputVariable> | |||
| <SimilaritySliderFormField vectorSimilarityWeightName="keywords_similarity_weight"></SimilaritySliderFormField> | |||
| <TopNFormField></TopNFormField> | |||
| <RerankFormFields></RerankFormFields> | |||