mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-26 00:46:52 +08:00
Feat: If a query variable in a data manipulation operator is deleted, a warning message should be displayed to the user. #10427 #11255 (#11384)
### What problem does this PR solve? Feat: If a query variable in a data manipulation operator is deleted, a warning message should be displayed to the user. #10427 #11255 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -11,11 +11,12 @@ export function DataOperationsNode({
|
||||
}: NodeProps<BaseNode<DataOperationsFormSchemaType>>) {
|
||||
const { data } = props;
|
||||
const { t } = useTranslation();
|
||||
const operations = data.form?.operations;
|
||||
|
||||
return (
|
||||
<RagNode {...props}>
|
||||
<LabelCard>
|
||||
{t(`flow.operationsOptions.${camelCase(data.form?.operations)}`)}
|
||||
{operations && t(`flow.operationsOptions.${camelCase(operations)}`)}
|
||||
</LabelCard>
|
||||
</RagNode>
|
||||
);
|
||||
|
||||
@ -7,17 +7,24 @@ export type FormListHeaderProps = {
|
||||
label: ReactNode;
|
||||
tooltip?: string;
|
||||
onClick?: () => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export function DynamicFormHeader({
|
||||
label,
|
||||
tooltip,
|
||||
onClick,
|
||||
disabled = false,
|
||||
}: FormListHeaderProps) {
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<FormLabel tooltip={tooltip}>{label}</FormLabel>
|
||||
<Button variant={'ghost'} type="button" onClick={onClick}>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -2,6 +2,10 @@ import { Button } from '@/components/ui/button';
|
||||
import { X } from 'lucide-react';
|
||||
import { useFieldArray, useFormContext } from 'react-hook-form';
|
||||
import { JsonSchemaDataType } from '../../constant';
|
||||
import {
|
||||
flatOptions,
|
||||
useFilterQueryVariableOptionsByTypes,
|
||||
} from '../../hooks/use-get-begin-query';
|
||||
import { DynamicFormHeader, FormListHeaderProps } from './dynamic-fom-header';
|
||||
import { QueryVariable } from './query-variable';
|
||||
|
||||
@ -16,6 +20,10 @@ export function QueryVariableList({
|
||||
const form = useFormContext();
|
||||
const name = 'query';
|
||||
|
||||
let options = useFilterQueryVariableOptionsByTypes(types);
|
||||
|
||||
const secondOptions = flatOptions(options);
|
||||
|
||||
const { fields, remove, append } = useFieldArray({
|
||||
name: name,
|
||||
control: form.control,
|
||||
@ -26,14 +34,15 @@ export function QueryVariableList({
|
||||
<DynamicFormHeader
|
||||
label={label}
|
||||
tooltip={tooltip}
|
||||
onClick={() => append({ input: '' })}
|
||||
onClick={() => append({ input: secondOptions.at(0)?.value })}
|
||||
disabled={!secondOptions.length}
|
||||
></DynamicFormHeader>
|
||||
<div className="space-y-5">
|
||||
{fields.map((field, index) => {
|
||||
const nameField = `${name}.${index}.input`;
|
||||
|
||||
return (
|
||||
<div key={field.id} className="flex items-center gap-2">
|
||||
<div key={field.id} className="flex gap-2">
|
||||
<QueryVariable
|
||||
name={nameField}
|
||||
hideLabel
|
||||
|
||||
@ -4,6 +4,7 @@ import { Form } from '@/components/ui/form';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { buildOptions } from '@/utils/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { t } from 'i18next';
|
||||
import { memo } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -25,7 +26,11 @@ import { SelectKeys } from './select-keys';
|
||||
import { Updates } from './updates';
|
||||
|
||||
export const RetrievalPartialSchema = {
|
||||
query: z.array(z.object({ input: z.string().optional() })),
|
||||
query: z.array(
|
||||
z.object({
|
||||
input: z.string().min(1, { message: t('flow.queryRequired') }),
|
||||
}),
|
||||
),
|
||||
operations: z.string(),
|
||||
select_keys: z.array(z.object({ name: z.string().optional() })).optional(),
|
||||
remove_keys: z.array(z.object({ name: z.string().optional() })).optional(),
|
||||
|
||||
@ -317,14 +317,18 @@ export const useGetComponentLabelByValue = (nodeId: string) => {
|
||||
return getLabel;
|
||||
};
|
||||
|
||||
export function flatOptions(options: DefaultOptionType[]) {
|
||||
return options.reduce<DefaultOptionType[]>((pre, cur) => {
|
||||
return [...pre, ...cur.options];
|
||||
}, []);
|
||||
}
|
||||
|
||||
export function useFlattenQueryVariableOptions(nodeId?: string) {
|
||||
const { getNode } = useGraphStore((state) => state);
|
||||
const nextOptions = useBuildQueryVariableOptions(getNode(nodeId));
|
||||
|
||||
const flattenOptions = useMemo(() => {
|
||||
return nextOptions.reduce<DefaultOptionType[]>((pre, cur) => {
|
||||
return [...pre, ...cur.options];
|
||||
}, []);
|
||||
return flatOptions(nextOptions);
|
||||
}, [nextOptions]);
|
||||
|
||||
return flattenOptions;
|
||||
|
||||
@ -12,9 +12,9 @@ import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg';
|
||||
import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg';
|
||||
import { ReactComponent as YahooFinanceIcon } from '@/assets/svg/yahoo-finance.svg';
|
||||
|
||||
import { IconFont } from '@/components/icon-font';
|
||||
import { IconFontFill } from '@/components/icon-font';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Columns3, Equal, FileCode, HousePlus, Variable } from 'lucide-react';
|
||||
import { FileCode, HousePlus } from 'lucide-react';
|
||||
import { Operator } from './constant';
|
||||
|
||||
interface IProps {
|
||||
@ -37,6 +37,9 @@ export const OperatorIconMap = {
|
||||
[Operator.ExeSQL]: 'executesql-0',
|
||||
[Operator.Invoke]: 'httprequest-0',
|
||||
[Operator.Email]: 'sendemail-0',
|
||||
[Operator.ListOperations]: 'a-listoperations',
|
||||
[Operator.VariableAssigner]: 'a-ariableassigner',
|
||||
[Operator.VariableAggregator]: 'aggregator',
|
||||
};
|
||||
|
||||
export const SVGIconMap = {
|
||||
@ -57,9 +60,6 @@ export const SVGIconMap = {
|
||||
};
|
||||
export const LucideIconMap = {
|
||||
[Operator.DataOperations]: FileCode,
|
||||
[Operator.ListOperations]: Columns3,
|
||||
[Operator.VariableAssigner]: Equal,
|
||||
[Operator.VariableAggregator]: Variable,
|
||||
};
|
||||
|
||||
const Empty = () => {
|
||||
@ -86,7 +86,10 @@ const OperatorIcon = ({ name, className }: IProps) => {
|
||||
|
||||
if (Icon) {
|
||||
return (
|
||||
<IconFont name={Icon} className={cn('size-5 ', className)}></IconFont>
|
||||
<IconFontFill
|
||||
name={Icon}
|
||||
className={cn('size-5 ', className)}
|
||||
></IconFontFill>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user