mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-23 15:06:50 +08:00
### What problem does this PR solve? Feat: Add FormDrawer to agent page. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
130
web/src/pages/agent/form/invoke-form/dynamic-variables.tsx
Normal file
130
web/src/pages/agent/form/invoke-form/dynamic-variables.tsx
Normal file
@ -0,0 +1,130 @@
|
||||
import { EditableCell, EditableRow } from '@/components/editable-cell';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
import { Button, Collapse, Flex, Input, Select, Table, TableProps } from 'antd';
|
||||
import { trim } from 'lodash';
|
||||
import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
|
||||
import { IInvokeVariable, RAGFlowNodeType } from '../../interface';
|
||||
import { useHandleOperateParameters } from './hooks';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
interface IProps {
|
||||
node?: RAGFlowNodeType;
|
||||
}
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
|
||||
const DynamicVariablesForm = ({ node }: IProps) => {
|
||||
const nodeId = node?.id;
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const options = useBuildComponentIdSelectOptions(nodeId, node?.parentId);
|
||||
const {
|
||||
dataSource,
|
||||
handleAdd,
|
||||
handleRemove,
|
||||
handleSave,
|
||||
handleComponentIdChange,
|
||||
handleValueChange,
|
||||
} = useHandleOperateParameters(nodeId!);
|
||||
|
||||
const columns: TableProps<IInvokeVariable>['columns'] = [
|
||||
{
|
||||
title: t('key'),
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
onCell: (record: IInvokeVariable) => ({
|
||||
record,
|
||||
editable: true,
|
||||
dataIndex: 'key',
|
||||
title: 'key',
|
||||
handleSave,
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: t('componentId'),
|
||||
dataIndex: 'component_id',
|
||||
key: 'component_id',
|
||||
align: 'center',
|
||||
width: 140,
|
||||
render(text, record) {
|
||||
return (
|
||||
<Select
|
||||
style={{ width: '100%' }}
|
||||
allowClear
|
||||
options={options}
|
||||
value={text}
|
||||
disabled={trim(record.value) !== ''}
|
||||
onChange={handleComponentIdChange(record)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('value'),
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
align: 'center',
|
||||
width: 140,
|
||||
render(text, record) {
|
||||
return (
|
||||
<Input
|
||||
value={text}
|
||||
disabled={!!record.component_id}
|
||||
onChange={handleValueChange(record)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('operation'),
|
||||
dataIndex: 'operation',
|
||||
width: 20,
|
||||
key: 'operation',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
render(_, record) {
|
||||
return <DeleteOutlined onClick={handleRemove(record.id)} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
className={styles.dynamicParameterVariable}
|
||||
defaultActiveKey={['1']}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: (
|
||||
<Flex justify={'space-between'}>
|
||||
<span className={styles.title}>{t('parameter')}</span>
|
||||
<Button size="small" onClick={handleAdd}>
|
||||
{t('add')}
|
||||
</Button>
|
||||
</Flex>
|
||||
),
|
||||
children: (
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
rowKey={'id'}
|
||||
components={components}
|
||||
rowClassName={() => styles.editableRow}
|
||||
scroll={{ x: true }}
|
||||
bordered
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DynamicVariablesForm;
|
||||
97
web/src/pages/agent/form/invoke-form/hooks.ts
Normal file
97
web/src/pages/agent/form/invoke-form/hooks.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import get from 'lodash/get';
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
MouseEventHandler,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { IGenerateParameter, IInvokeVariable } from '../../interface';
|
||||
import useGraphStore from '../../store';
|
||||
|
||||
export const useHandleOperateParameters = (nodeId: string) => {
|
||||
const { getNode, updateNodeForm } = useGraphStore((state) => state);
|
||||
const node = getNode(nodeId);
|
||||
const dataSource: IGenerateParameter[] = useMemo(
|
||||
() => get(node, 'data.form.variables', []) as IGenerateParameter[],
|
||||
[node],
|
||||
);
|
||||
|
||||
const changeValue = useCallback(
|
||||
(row: IInvokeVariable, field: string, value: string) => {
|
||||
const newData = [...dataSource];
|
||||
const index = newData.findIndex((item) => row.id === item.id);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
[field]: value,
|
||||
});
|
||||
|
||||
updateNodeForm(nodeId, { variables: newData });
|
||||
},
|
||||
[dataSource, nodeId, updateNodeForm],
|
||||
);
|
||||
|
||||
const handleComponentIdChange = useCallback(
|
||||
(row: IInvokeVariable) => (value: string) => {
|
||||
changeValue(row, 'component_id', value);
|
||||
},
|
||||
[changeValue],
|
||||
);
|
||||
|
||||
const handleValueChange = useCallback(
|
||||
(row: IInvokeVariable): ChangeEventHandler<HTMLInputElement> =>
|
||||
(e) => {
|
||||
changeValue(row, 'value', e.target.value);
|
||||
},
|
||||
[changeValue],
|
||||
);
|
||||
|
||||
const handleRemove = useCallback(
|
||||
(id?: string) => () => {
|
||||
const newData = dataSource.filter((item) => item.id !== id);
|
||||
updateNodeForm(nodeId, { variables: newData });
|
||||
},
|
||||
[updateNodeForm, nodeId, dataSource],
|
||||
);
|
||||
|
||||
const handleAdd: MouseEventHandler = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
updateNodeForm(nodeId, {
|
||||
variables: [
|
||||
...dataSource,
|
||||
{
|
||||
id: uuid(),
|
||||
key: '',
|
||||
component_id: undefined,
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
[dataSource, nodeId, updateNodeForm],
|
||||
);
|
||||
|
||||
const handleSave = (row: IGenerateParameter) => {
|
||||
const newData = [...dataSource];
|
||||
const index = newData.findIndex((item) => row.id === item.id);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
...row,
|
||||
});
|
||||
|
||||
updateNodeForm(nodeId, { variables: newData });
|
||||
};
|
||||
|
||||
return {
|
||||
handleAdd,
|
||||
handleRemove,
|
||||
handleComponentIdChange,
|
||||
handleValueChange,
|
||||
handleSave,
|
||||
dataSource,
|
||||
};
|
||||
};
|
||||
44
web/src/pages/agent/form/invoke-form/index.less
Normal file
44
web/src/pages/agent/form/invoke-form/index.less
Normal file
@ -0,0 +1,44 @@
|
||||
.editableRow {
|
||||
:global(.editable-cell) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:global(.editable-cell-value-wrap) {
|
||||
padding: 5px 12px;
|
||||
cursor: pointer;
|
||||
height: 30px !important;
|
||||
}
|
||||
&:hover {
|
||||
:global(.editable-cell-value-wrap) {
|
||||
padding: 4px 11px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dynamicParameterVariable {
|
||||
background-color: #ebe9e950;
|
||||
:global(.ant-collapse-content) {
|
||||
background-color: #f6f6f634;
|
||||
}
|
||||
:global(.ant-collapse-content-box) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
.variableType {
|
||||
width: 30%;
|
||||
}
|
||||
.variableValue {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
color: rgb(22, 119, 255);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
78
web/src/pages/agent/form/invoke-form/index.tsx
Normal file
78
web/src/pages/agent/form/invoke-form/index.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import Editor, { loader } from '@monaco-editor/react';
|
||||
import { Form, Input, InputNumber, Select, Space, Switch } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import DynamicVariablesForm from './dynamic-variables';
|
||||
|
||||
loader.config({ paths: { vs: '/vs' } });
|
||||
|
||||
enum Method {
|
||||
GET = 'GET',
|
||||
POST = 'POST',
|
||||
PUT = 'PUT',
|
||||
}
|
||||
|
||||
const MethodOptions = [Method.GET, Method.POST, Method.PUT].map((x) => ({
|
||||
label: x,
|
||||
value: x,
|
||||
}));
|
||||
|
||||
interface TimeoutInputProps {
|
||||
value?: number;
|
||||
onChange?: (value: number | null) => void;
|
||||
}
|
||||
|
||||
const TimeoutInput = ({ value, onChange }: TimeoutInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Space>
|
||||
<InputNumber value={value} onChange={onChange} /> {t('common.s')}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
const InvokeForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
name="basic"
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
layout={'vertical'}
|
||||
>
|
||||
<Form.Item name={'url'} label={t('flow.url')}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={'method'}
|
||||
label={t('flow.method')}
|
||||
initialValue={Method.GET}
|
||||
>
|
||||
<Select options={MethodOptions} />
|
||||
</Form.Item>
|
||||
<Form.Item name={'timeout'} label={t('flow.timeout')}>
|
||||
<TimeoutInput></TimeoutInput>
|
||||
</Form.Item>
|
||||
<Form.Item name={'headers'} label={t('flow.headers')}>
|
||||
<Editor height={200} defaultLanguage="json" theme="vs-dark" />
|
||||
</Form.Item>
|
||||
<Form.Item name={'proxy'} label={t('flow.proxy')}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={'clean_html'}
|
||||
label={t('flow.cleanHtml')}
|
||||
tooltip={t('flow.cleanHtmlTip')}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<DynamicVariablesForm node={node}></DynamicVariablesForm>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InvokeForm;
|
||||
Reference in New Issue
Block a user