mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-12 08:29:00 +08:00
### What problem does this PR solve? feat: Add input parameter to begin operator #3355 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
9fc092a911
commit
1fe9a2e6fd
@ -557,3 +557,24 @@ export const useHandleChunkMethodSelectChange = (form: FormInstance) => {
|
|||||||
|
|
||||||
return handleChange;
|
return handleChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// reset form fields when modal is form, closed
|
||||||
|
export const useResetFormOnCloseModal = ({
|
||||||
|
form,
|
||||||
|
visible,
|
||||||
|
}: {
|
||||||
|
form: FormInstance;
|
||||||
|
visible?: boolean;
|
||||||
|
}) => {
|
||||||
|
const prevOpenRef = useRef<boolean>();
|
||||||
|
useEffect(() => {
|
||||||
|
prevOpenRef.current = visible;
|
||||||
|
}, [visible]);
|
||||||
|
const prevOpen = prevOpenRef.current;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!visible && prevOpen) {
|
||||||
|
form.resetFields();
|
||||||
|
}
|
||||||
|
}, [form, prevOpen, visible]);
|
||||||
|
};
|
||||||
|
@ -2859,3 +2859,23 @@ export const TuShareSrcOptions = [
|
|||||||
'jinrongjie',
|
'jinrongjie',
|
||||||
];
|
];
|
||||||
export const CrawlerResultOptions = ['markdown', 'html', 'content'];
|
export const CrawlerResultOptions = ['markdown', 'html', 'content'];
|
||||||
|
|
||||||
|
export enum BeginQueryType {
|
||||||
|
Line = 'line',
|
||||||
|
Paragraph = 'paragraph',
|
||||||
|
Options = 'options',
|
||||||
|
File = 'file',
|
||||||
|
Integer = 'integer',
|
||||||
|
Boolean = 'boolean',
|
||||||
|
Url = 'url',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BeginQueryTypeMap = {
|
||||||
|
[BeginQueryType.Line]: 'input',
|
||||||
|
[BeginQueryType.Paragraph]: 'textarea',
|
||||||
|
[BeginQueryType.Options]: 'select',
|
||||||
|
[BeginQueryType.File]: 'file',
|
||||||
|
[BeginQueryType.Integer]: 'inputnumber',
|
||||||
|
[BeginQueryType.Boolean]: 'switch',
|
||||||
|
[BeginQueryType.Url]: 'input',
|
||||||
|
};
|
||||||
|
68
web/src/pages/flow/form/begin-form/begin-dynamic-options.tsx
Normal file
68
web/src/pages/flow/form/begin-form/begin-dynamic-options.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Form, Input } from 'antd';
|
||||||
|
|
||||||
|
const BeginDynamicOptions = () => {
|
||||||
|
return (
|
||||||
|
<Form.List
|
||||||
|
name="options"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
validator: async (_, names) => {
|
||||||
|
if (!names || names.length < 1) {
|
||||||
|
return Promise.reject(new Error('At least 1 option'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{(fields, { add, remove }, { errors }) => (
|
||||||
|
<>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Form.Item
|
||||||
|
label={index === 0 ? 'Options' : ''}
|
||||||
|
required={false}
|
||||||
|
key={field.key}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
{...field}
|
||||||
|
validateTrigger={['onChange', 'onBlur']}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
whitespace: true,
|
||||||
|
message: 'Please input option or delete this field.',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="option"
|
||||||
|
style={{ width: '90%', marginRight: 16 }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
{fields.length > 1 ? (
|
||||||
|
<MinusCircleOutlined
|
||||||
|
className="dynamic-delete-button"
|
||||||
|
onClick={() => remove(field.name)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</Form.Item>
|
||||||
|
))}
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
onClick={() => add()}
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
block
|
||||||
|
>
|
||||||
|
Add field
|
||||||
|
</Button>
|
||||||
|
<Form.ErrorList errors={errors} />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form.List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BeginDynamicOptions;
|
50
web/src/pages/flow/form/begin-form/hooks.ts
Normal file
50
web/src/pages/flow/form/begin-form/hooks.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
|
||||||
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
import { BeginQuery, IOperatorForm } from '../../interface';
|
||||||
|
|
||||||
|
export const useEditQueryRecord = ({ form, onValuesChange }: IOperatorForm) => {
|
||||||
|
const { setRecord, currentRecord } = useSetSelectedRecord<BeginQuery>();
|
||||||
|
const { visible, hideModal, showModal } = useSetModalState();
|
||||||
|
const [index, setIndex] = useState(-1);
|
||||||
|
|
||||||
|
const otherThanCurrentQuery = useMemo(() => {
|
||||||
|
const query: BeginQuery[] = form?.getFieldValue('query') || [];
|
||||||
|
return query.filter((item, idx) => idx !== index);
|
||||||
|
}, [form, index]);
|
||||||
|
|
||||||
|
const handleEditRecord = useCallback(
|
||||||
|
(record: BeginQuery) => {
|
||||||
|
const query: BeginQuery[] = form?.getFieldValue('query') || [];
|
||||||
|
|
||||||
|
const nextQuery: BeginQuery[] =
|
||||||
|
index > -1 ? query.toSpliced(index, 1, record) : [...query, record];
|
||||||
|
|
||||||
|
onValuesChange?.(
|
||||||
|
{ query: nextQuery },
|
||||||
|
{ query: nextQuery, prologue: form?.getFieldValue('prologue') },
|
||||||
|
);
|
||||||
|
hideModal();
|
||||||
|
},
|
||||||
|
[form, hideModal, index, onValuesChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleShowModal = useCallback(
|
||||||
|
(idx?: number, record?: BeginQuery) => {
|
||||||
|
setIndex(idx ?? -1);
|
||||||
|
setRecord(record ?? ({} as BeginQuery));
|
||||||
|
showModal();
|
||||||
|
},
|
||||||
|
[setRecord, showModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: handleEditRecord,
|
||||||
|
currentRecord,
|
||||||
|
setRecord,
|
||||||
|
visible,
|
||||||
|
hideModal,
|
||||||
|
showModal: handleShowModal,
|
||||||
|
otherThanCurrentQuery,
|
||||||
|
};
|
||||||
|
};
|
@ -1,6 +1,10 @@
|
|||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { Form, Input } from 'antd';
|
import { Button, Form, Input } from 'antd';
|
||||||
import { IOperatorForm } from '../../interface';
|
import { useCallback } from 'react';
|
||||||
|
import { BeginQuery, IOperatorForm } from '../../interface';
|
||||||
|
import { useEditQueryRecord } from './hooks';
|
||||||
|
import { ModalForm } from './paramater-modal';
|
||||||
|
import QueryTable from './query-table';
|
||||||
|
|
||||||
type FieldType = {
|
type FieldType = {
|
||||||
prologue?: string;
|
prologue?: string;
|
||||||
@ -8,25 +12,95 @@ type FieldType = {
|
|||||||
|
|
||||||
const BeginForm = ({ onValuesChange, form }: IOperatorForm) => {
|
const BeginForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||||
const { t } = useTranslate('chat');
|
const { t } = useTranslate('chat');
|
||||||
|
const {
|
||||||
|
ok,
|
||||||
|
currentRecord,
|
||||||
|
visible,
|
||||||
|
hideModal,
|
||||||
|
showModal,
|
||||||
|
otherThanCurrentQuery,
|
||||||
|
} = useEditQueryRecord({
|
||||||
|
form,
|
||||||
|
onValuesChange,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDeleteRecord = useCallback(
|
||||||
|
(idx: number) => {
|
||||||
|
const query = form?.getFieldValue('query') || [];
|
||||||
|
const nextQuery = query.filter(
|
||||||
|
(item: BeginQuery, index: number) => index !== idx,
|
||||||
|
);
|
||||||
|
onValuesChange?.(
|
||||||
|
{ query: nextQuery },
|
||||||
|
{ query: nextQuery, prologue: form?.getFieldValue('prologue') },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[form, onValuesChange],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form.Provider
|
||||||
name="basic"
|
onFormFinish={(name, { values }) => {
|
||||||
labelCol={{ span: 8 }}
|
if (name === 'queryForm') {
|
||||||
wrapperCol={{ span: 16 }}
|
ok(values as BeginQuery);
|
||||||
onValuesChange={onValuesChange}
|
}
|
||||||
autoComplete="off"
|
}}
|
||||||
form={form}
|
|
||||||
>
|
>
|
||||||
<Form.Item<FieldType>
|
<Form
|
||||||
name={'prologue'}
|
name="basicForm"
|
||||||
label={t('setAnOpener')}
|
onValuesChange={onValuesChange}
|
||||||
tooltip={t('setAnOpenerTip')}
|
autoComplete="off"
|
||||||
initialValue={t('setAnOpenerInitial')}
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
>
|
>
|
||||||
<Input.TextArea autoSize={{ minRows: 5 }} />
|
<Form.Item<FieldType>
|
||||||
</Form.Item>
|
name={'prologue'}
|
||||||
</Form>
|
label={t('setAnOpener')}
|
||||||
|
tooltip={t('setAnOpenerTip')}
|
||||||
|
initialValue={t('setAnOpenerInitial')}
|
||||||
|
>
|
||||||
|
<Input.TextArea autoSize={{ minRows: 5 }} />
|
||||||
|
</Form.Item>
|
||||||
|
{/* Create a hidden field to make Form instance record this */}
|
||||||
|
<Form.Item name="query" noStyle />
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label="Query List"
|
||||||
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
|
prevValues.query !== curValues.query
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{({ getFieldValue }) => {
|
||||||
|
const query: BeginQuery[] = getFieldValue('query') || [];
|
||||||
|
return (
|
||||||
|
<QueryTable
|
||||||
|
data={query}
|
||||||
|
showModal={showModal}
|
||||||
|
deleteRecord={handleDeleteRecord}
|
||||||
|
></QueryTable>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
htmlType="button"
|
||||||
|
style={{ margin: '0 8px' }}
|
||||||
|
onClick={() => showModal()}
|
||||||
|
block
|
||||||
|
>
|
||||||
|
Add +
|
||||||
|
</Button>
|
||||||
|
{visible && (
|
||||||
|
<ModalForm
|
||||||
|
visible={visible}
|
||||||
|
hideModal={hideModal}
|
||||||
|
initialValue={currentRecord}
|
||||||
|
onOk={ok}
|
||||||
|
otherThanCurrentQuery={otherThanCurrentQuery}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
</Form.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
113
web/src/pages/flow/form/begin-form/paramater-modal.tsx
Normal file
113
web/src/pages/flow/form/begin-form/paramater-modal.tsx
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import { useResetFormOnCloseModal } from '@/hooks/logic-hooks';
|
||||||
|
import { IModalProps } from '@/interfaces/common';
|
||||||
|
import { Form, Input, Modal, Select, Switch } from 'antd';
|
||||||
|
import { DefaultOptionType } from 'antd/es/select';
|
||||||
|
import { useEffect, useMemo } from 'react';
|
||||||
|
import { BeginQueryType } from '../../constant';
|
||||||
|
import { BeginQuery } from '../../interface';
|
||||||
|
import BeginDynamicOptions from './begin-dynamic-options';
|
||||||
|
|
||||||
|
export const ModalForm = ({
|
||||||
|
visible,
|
||||||
|
initialValue,
|
||||||
|
hideModal,
|
||||||
|
otherThanCurrentQuery,
|
||||||
|
}: IModalProps<BeginQuery> & {
|
||||||
|
initialValue: BeginQuery;
|
||||||
|
otherThanCurrentQuery: BeginQuery[];
|
||||||
|
}) => {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const options = useMemo(() => {
|
||||||
|
return Object.values(BeginQueryType).reduce<DefaultOptionType[]>(
|
||||||
|
(pre, cur) => {
|
||||||
|
return [
|
||||||
|
...pre,
|
||||||
|
{
|
||||||
|
label: cur,
|
||||||
|
value: cur,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useResetFormOnCloseModal({
|
||||||
|
form,
|
||||||
|
visible: visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
form.setFieldsValue(initialValue);
|
||||||
|
}, [form, initialValue]);
|
||||||
|
|
||||||
|
const onOk = () => {
|
||||||
|
form.submit();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="Begin query"
|
||||||
|
open={visible}
|
||||||
|
onOk={onOk}
|
||||||
|
onCancel={hideModal}
|
||||||
|
centered
|
||||||
|
>
|
||||||
|
<Form form={form} layout="vertical" name="queryForm" autoComplete="false">
|
||||||
|
<Form.Item
|
||||||
|
name="type"
|
||||||
|
label="Type"
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
initialValue={BeginQueryType.Line}
|
||||||
|
>
|
||||||
|
<Select options={options} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="key"
|
||||||
|
label="Key"
|
||||||
|
rules={[
|
||||||
|
{ required: true },
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (
|
||||||
|
!value ||
|
||||||
|
!otherThanCurrentQuery.some((x) => x.key === value)
|
||||||
|
) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error('The key cannot be repeated!'));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="name" label="Name" rules={[{ required: true }]}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="optional"
|
||||||
|
label={'Optional'}
|
||||||
|
valuePropName="checked"
|
||||||
|
initialValue={false}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
|
prevValues.type !== curValues.type
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{({ getFieldValue }) => {
|
||||||
|
const type: BeginQueryType = getFieldValue('type');
|
||||||
|
return (
|
||||||
|
type === BeginQueryType.Options && (
|
||||||
|
<BeginDynamicOptions></BeginDynamicOptions>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
71
web/src/pages/flow/form/begin-form/query-table.tsx
Normal file
71
web/src/pages/flow/form/begin-form/query-table.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
||||||
|
import type { TableProps } from 'antd';
|
||||||
|
import { Space, Table, Tooltip } from 'antd';
|
||||||
|
import { BeginQuery } from '../../interface';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
data: BeginQuery[];
|
||||||
|
deleteRecord(index: number): void;
|
||||||
|
showModal(index: number, record: BeginQuery): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QueryTable = ({ data, deleteRecord, showModal }: IProps) => {
|
||||||
|
const columns: TableProps<BeginQuery>['columns'] = [
|
||||||
|
{
|
||||||
|
title: 'Key',
|
||||||
|
dataIndex: 'key',
|
||||||
|
key: 'key',
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false,
|
||||||
|
},
|
||||||
|
render: (key) => (
|
||||||
|
<Tooltip placement="topLeft" title={key}>
|
||||||
|
{key}
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false,
|
||||||
|
},
|
||||||
|
render: (name) => (
|
||||||
|
<Tooltip placement="topLeft" title={name}>
|
||||||
|
{name}
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Type',
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Optional',
|
||||||
|
dataIndex: 'optional',
|
||||||
|
key: 'optional',
|
||||||
|
render: (optional) => (optional ? 'Yes' : 'No'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'action',
|
||||||
|
render: (_, record, idx) => (
|
||||||
|
<Space>
|
||||||
|
<EditOutlined onClick={() => showModal(idx, record)} />
|
||||||
|
<DeleteOutlined
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => deleteRecord(idx)}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table<BeginQuery> columns={columns} dataSource={data} pagination={false} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default QueryTable;
|
@ -100,3 +100,12 @@ export type NodeData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type IPosition = { top: number; right: number; idx: number };
|
export type IPosition = { top: number; right: number; idx: number };
|
||||||
|
|
||||||
|
export interface BeginQuery {
|
||||||
|
key: string;
|
||||||
|
type: string;
|
||||||
|
value: string;
|
||||||
|
optional: boolean;
|
||||||
|
name: string;
|
||||||
|
options: (number | string | boolean)[];
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user