Feat: The keys for data manipulation operators can only be numbers, letters, and underscores. #10427 (#11130)

### What problem does this PR solve?

Feat: The keys for data manipulation operators can only be numbers,
letters, and underscores. #10427

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-11-10 13:27:09 +08:00
committed by GitHub
parent d016a06fd5
commit 86af330f06
8 changed files with 40 additions and 13 deletions

View File

@ -79,7 +79,7 @@ export function AccordionOperators({
Operator.Code, Operator.Code,
Operator.StringTransform, Operator.StringTransform,
Operator.DataOperations, Operator.DataOperations,
Operator.VariableAssigner, // Operator.VariableAssigner,
Operator.VariableAggregator, Operator.VariableAggregator,
]} ]}
isCustomDropdown={isCustomDropdown} isCustomDropdown={isCustomDropdown}

View File

@ -22,7 +22,7 @@ export function VariableAggregatorNode({
<span className="text-text-secondary">{x.type}</span> <span className="text-text-secondary">{x.type}</span>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
{x.variables.map((y, index) => ( {x.variables?.map((y, index) => (
<LabelCard key={index} className="truncate"> <LabelCard key={index} className="truncate">
{getLabel(y.value)} {getLabel(y.value)}
</LabelCard> </LabelCard>

View File

@ -0,0 +1,25 @@
import { Input } from '@/components/ui/input';
import { ChangeEvent, useCallback } from 'react';
type KeyInputProps = {
value?: string;
onChange?: (value: string) => void;
searchValue?: string | RegExp;
};
export function KeyInput({
value,
onChange,
searchValue = /[^a-zA-Z0-9_]/g,
}: KeyInputProps) {
const handleChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
const value = e.target.value ?? '';
const filteredValue = value.replace(searchValue, '');
onChange?.(filteredValue);
},
[onChange, searchValue],
);
return <Input value={value} onChange={handleChange} />;
}

View File

@ -1,7 +1,6 @@
import { SelectWithSearch } from '@/components/originui/select-with-search'; import { SelectWithSearch } from '@/components/originui/select-with-search';
import { RAGFlowFormItem } from '@/components/ragflow-form'; import { RAGFlowFormItem } from '@/components/ragflow-form';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-operator-options'; import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-operator-options';
import { X } from 'lucide-react'; import { X } from 'lucide-react';
@ -9,6 +8,7 @@ import { ReactNode } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form'; import { useFieldArray, useFormContext } from 'react-hook-form';
import { DataOperationsOperatorOptions } from '../../constant'; import { DataOperationsOperatorOptions } from '../../constant';
import { DynamicFormHeader } from '../components/dynamic-fom-header'; import { DynamicFormHeader } from '../components/dynamic-fom-header';
import { KeyInput } from '../components/key-input';
import { PromptEditor } from '../components/prompt-editor'; import { PromptEditor } from '../components/prompt-editor';
type SelectKeysProps = { type SelectKeysProps = {
@ -55,7 +55,7 @@ export function FilterValues({
return ( return (
<div key={field.id} className="flex items-center gap-2"> <div key={field.id} className="flex items-center gap-2">
<RAGFlowFormItem name={keyFieldAlias} className="flex-1"> <RAGFlowFormItem name={keyFieldAlias} className="flex-1">
<Input></Input> <KeyInput></KeyInput>
</RAGFlowFormItem> </RAGFlowFormItem>
<Separator className="w-2" /> <Separator className="w-2" />

View File

@ -1,11 +1,11 @@
import { RAGFlowFormItem } from '@/components/ragflow-form'; import { RAGFlowFormItem } from '@/components/ragflow-form';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
import { X } from 'lucide-react'; import { X } from 'lucide-react';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form'; import { useFieldArray, useFormContext } from 'react-hook-form';
import { DynamicFormHeader } from '../components/dynamic-fom-header'; import { DynamicFormHeader } from '../components/dynamic-fom-header';
import { KeyInput } from '../components/key-input';
import { PromptEditor } from '../components/prompt-editor'; import { PromptEditor } from '../components/prompt-editor';
type SelectKeysProps = { type SelectKeysProps = {
@ -44,7 +44,7 @@ export function Updates({
return ( return (
<div key={field.id} className="flex items-center gap-2"> <div key={field.id} className="flex items-center gap-2">
<RAGFlowFormItem name={keyFieldAlias} className="flex-1"> <RAGFlowFormItem name={keyFieldAlias} className="flex-1">
<Input></Input> <KeyInput></KeyInput>
</RAGFlowFormItem> </RAGFlowFormItem>
<Separator className="w-2" /> <Separator className="w-2" />
<RAGFlowFormItem name={valueFieldAlias} className="flex-1"> <RAGFlowFormItem name={valueFieldAlias} className="flex-1">

View File

@ -21,8 +21,10 @@ export const useHandleNameChange = (previousName: string) => {
return name; return name;
}, [form, name, previousName]); }, [form, name, previousName]);
const handleNameChange = useCallback((e: ChangeEvent<any>) => { const handleNameChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setName(e.target.value); const value = e.target.value;
const filteredValue = value.replace(/[^a-zA-Z0-9_]/g, '');
setName(filteredValue);
}, []); }, []);
useEffect(() => { useEffect(() => {

View File

@ -80,13 +80,13 @@ export default function McpServer() {
)} )}
{t(`mcp.${isSelectionMode ? 'exitBulkManage' : 'bulkManage'}`)} {t(`mcp.${isSelectionMode ? 'exitBulkManage' : 'bulkManage'}`)}
</Button> </Button>
<Button variant={'secondary'} onClick={showEditModal('')}> <Button variant={'secondary'} onClick={showImportModal}>
<Plus className="size-3.5" /> {t('mcp.addMCP')}
</Button>
<Button onClick={showImportModal}>
<Download className="size-3.5" /> <Download className="size-3.5" />
{t('mcp.import')} {t('mcp.import')}
</Button> </Button>
<Button onClick={showEditModal('')}>
<Plus className="size-3.5" /> {t('mcp.addMCP')}
</Button>
</div> </div>
</section> </section>
</> </>