mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-12 03:33:33 +08:00
Feat: Edit the code of the code operator from a broad perspective. (#14116)
### What problem does this PR solve? Feat: Edit the code of the code operator from a broad perspective. ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
47
web/src/pages/agent/form/code-form/expanded-editor.tsx
Normal file
47
web/src/pages/agent/form/code-form/expanded-editor.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import { Minimize2 } from 'lucide-react';
|
||||
import { CodeEditorOptions } from './monaco-config';
|
||||
|
||||
interface ExpandedEditorProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
theme: string;
|
||||
language: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export function ExpandedEditor({
|
||||
visible,
|
||||
onClose,
|
||||
theme,
|
||||
language,
|
||||
value,
|
||||
onChange,
|
||||
}: ExpandedEditorProps) {
|
||||
if (!visible) return null;
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 z-10 flex flex-col bg-bg-base">
|
||||
<div className="flex items-center justify-between border-b px-5 py-3">
|
||||
<span className="font-medium">Code</span>
|
||||
<Button variant="ghost" onClick={onClose} type="button">
|
||||
<Minimize2 className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="min-h-0 flex-1 p-4">
|
||||
<Editor
|
||||
height="100%"
|
||||
theme={theme}
|
||||
language={language}
|
||||
options={CodeEditorOptions}
|
||||
value={value}
|
||||
onChange={(val) => {
|
||||
onChange(val ?? '');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { INextOperatorForm } from '../../interface';
|
||||
|
||||
import { FormContainer } from '@/components/form-container';
|
||||
import { useIsDarkTheme } from '@/components/theme-provider';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@@ -16,13 +17,15 @@ import { RAGFlowSelect } from '@/components/ui/select';
|
||||
import { ProgrammingLanguage } from '@/constants/agent';
|
||||
import { ICodeForm } from '@/interfaces/database/agent';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { AlertTriangle } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { AlertTriangle, Maximize2 } from 'lucide-react';
|
||||
import { memo, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { buildOutputList } from '../../utils/build-output-list';
|
||||
import { FormWrapper } from '../components/form-wrapper';
|
||||
import { Output } from '../components/output';
|
||||
import { ExpandedEditor } from './expanded-editor';
|
||||
import { CodeEditorOptions, RAGFlowMonacoTheme } from './monaco-config';
|
||||
import {
|
||||
DynamicInputVariable,
|
||||
TypeOptions,
|
||||
@@ -47,6 +50,8 @@ const options = [
|
||||
ProgrammingLanguage.Javascript,
|
||||
].map((x) => ({ value: x, label: x }));
|
||||
|
||||
const ScriptFieldName = 'script';
|
||||
|
||||
function CodeForm({ node }: INextOperatorForm) {
|
||||
const formData = node?.data.form as ICodeForm;
|
||||
const { t } = useTranslation();
|
||||
@@ -61,6 +66,7 @@ function CodeForm({ node }: INextOperatorForm) {
|
||||
useWatchFormChange(node?.id, form);
|
||||
|
||||
const handleLanguageChange = useHandleLanguageChange(node?.id, form);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const lang = form.watch('lang');
|
||||
const currentOutput = form.watch('output');
|
||||
const outputFieldDirty = !!form.formState.dirtyFields?.output;
|
||||
@@ -69,114 +75,136 @@ function CodeForm({ node }: INextOperatorForm) {
|
||||
? getBusinessOutputs(formData?.outputs)
|
||||
: serializeCodeOutputContract(currentOutput);
|
||||
|
||||
const theme = isDarkTheme
|
||||
? RAGFlowMonacoTheme.Dark
|
||||
: RAGFlowMonacoTheme.Light;
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<FormWrapper>
|
||||
<DynamicInputVariable
|
||||
node={node}
|
||||
title={t('flow.input')}
|
||||
isOutputs={false}
|
||||
></DynamicInputVariable>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="script"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="flex items-center justify-between">
|
||||
Code
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lang"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
onChange={(val) => {
|
||||
field.onChange(val);
|
||||
handleLanguageChange(val);
|
||||
}}
|
||||
options={options}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Editor
|
||||
height={300}
|
||||
theme={isDarkTheme ? 'vs-dark' : 'vs'}
|
||||
<div className="relative min-h-full">
|
||||
<FormWrapper>
|
||||
<DynamicInputVariable
|
||||
node={node}
|
||||
title={t('flow.input')}
|
||||
isOutputs={false}
|
||||
></DynamicInputVariable>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={ScriptFieldName}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<section className="flex items-center justify-between">
|
||||
Code
|
||||
<div className="flex items-center gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lang"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
onChange={(val) => {
|
||||
field.onChange(val);
|
||||
handleLanguageChange(val);
|
||||
}}
|
||||
options={options}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
onClick={() => setIsExpanded(true)}
|
||||
type="button"
|
||||
>
|
||||
<Maximize2 className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Editor
|
||||
height={300}
|
||||
theme={theme}
|
||||
language={lang}
|
||||
options={CodeEditorOptions}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<ExpandedEditor
|
||||
visible={isExpanded}
|
||||
onClose={() => setIsExpanded(false)}
|
||||
theme={theme}
|
||||
language={lang}
|
||||
options={{
|
||||
minimap: { enabled: false },
|
||||
automaticLayout: true,
|
||||
}}
|
||||
{...field}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="space-y-3">
|
||||
<VariableTitle title={'Return Value'}></VariableTitle>
|
||||
{legacyOutputs.length > 0 && (
|
||||
<div className="flex items-start gap-2 rounded-md border border-state-error/40 bg-state-error/10 px-3 py-2 text-sm text-text-primary">
|
||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-state-error" />
|
||||
<p>
|
||||
This CodeExec node uses the deprecated multi-output schema:{' '}
|
||||
{legacyOutputs.join(', ')}. Keep one business output here and
|
||||
move field extraction to downstream nodes.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<FormContainer className="space-y-5">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output.name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t('common.pleaseInput')}
|
||||
></Input>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output.type"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Type</FormLabel>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
placeholder={t('common.pleaseSelect')}
|
||||
options={TypeOptions}
|
||||
{...field}
|
||||
></RAGFlowSelect>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormContainer>
|
||||
<div className="space-y-3">
|
||||
<VariableTitle title={'Return Value'}></VariableTitle>
|
||||
{legacyOutputs.length > 0 && (
|
||||
<div className="flex items-start gap-2 rounded-md border border-state-error/40 bg-state-error/10 px-3 py-2 text-sm text-text-primary">
|
||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-state-error" />
|
||||
<p>
|
||||
This CodeExec node uses the deprecated multi-output schema:{' '}
|
||||
{legacyOutputs.join(', ')}. Keep one business output here and
|
||||
move field extraction to downstream nodes.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<FormContainer className="space-y-5">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output.name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t('common.pleaseInput')}
|
||||
></Input>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="output.type"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1">
|
||||
<FormLabel>Type</FormLabel>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
placeholder={t('common.pleaseSelect')}
|
||||
options={TypeOptions}
|
||||
{...field}
|
||||
></RAGFlowSelect>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormContainer>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
<div className="space-y-4 p-5">
|
||||
<Output list={buildOutputList(displayedBusinessOutputs)}>
|
||||
Business
|
||||
</Output>
|
||||
<Output list={buildOutputList(CodeExecPanelSystemOutputs)}>
|
||||
System
|
||||
</Output>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
<div className="space-y-4 p-5">
|
||||
<Output list={buildOutputList(displayedBusinessOutputs)}>
|
||||
Business
|
||||
</Output>
|
||||
<Output list={buildOutputList(CodeExecPanelSystemOutputs)}>
|
||||
System
|
||||
</Output>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
|
||||
13
web/src/pages/agent/form/code-form/monaco-config.ts
Normal file
13
web/src/pages/agent/form/code-form/monaco-config.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const CodeEditorOptions = {
|
||||
minimap: { enabled: false },
|
||||
automaticLayout: true,
|
||||
scrollbar: {
|
||||
verticalScrollbarSize: 10,
|
||||
horizontalScrollbarSize: 10,
|
||||
},
|
||||
};
|
||||
|
||||
export const RAGFlowMonacoTheme = {
|
||||
Light: 'vs',
|
||||
Dark: 'vs-dark',
|
||||
} as const;
|
||||
@@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import './index.less';
|
||||
import { RAGFlowLogo } from './ragflow-log';
|
||||
|
||||
export default function SearchPage({
|
||||
export default function SearchHome({
|
||||
isSearching,
|
||||
setIsSearching,
|
||||
searchText,
|
||||
|
||||
Reference in New Issue
Block a user