mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-24 07:26:47 +08:00
### What problem does this PR solve? feat: Add a note node to the agent canvas #2767 ### Type of change - [ ] Bug Fix (non-breaking change which fixes an issue) - [x] New Feature (non-breaking change which adds functionality) - [ ] Documentation Update - [ ] Refactoring - [ ] Performance Improvement - [ ] Other (please describe):
This commit is contained in:
20
web/src/pages/flow/form/akshare-form/index.tsx
Normal file
20
web/src/pages/flow/form/akshare-form/index.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { Form } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const AkShareForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10} max={99}></TopNItem>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AkShareForm;
|
||||
5
web/src/pages/flow/form/answer-form/index.tsx
Normal file
5
web/src/pages/flow/form/answer-form/index.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
const AnswerForm = () => {
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
export default AnswerForm;
|
||||
34
web/src/pages/flow/form/arxiv-form/index.tsx
Normal file
34
web/src/pages/flow/form/arxiv-form/index.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const ArXivForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const options = useMemo(() => {
|
||||
return ['submittedDate', 'lastUpdatedDate', 'relevance'].map((x) => ({
|
||||
value: x,
|
||||
label: t(x),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
<Form.Item label={t('sortBy')} name={'sort_by'}>
|
||||
<Select options={options}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default ArXivForm;
|
||||
70
web/src/pages/flow/form/baidu-fanyi-form/index.tsx
Normal file
70
web/src/pages/flow/form/baidu-fanyi-form/index.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
BaiduFanyiDomainOptions,
|
||||
BaiduFanyiSourceLangOptions,
|
||||
} from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const BaiduFanyiForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
const options = useMemo(() => {
|
||||
return ['translate', 'fieldtranslate'].map((x) => ({
|
||||
value: x,
|
||||
label: t(`baiduSecretKeyOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const baiduFanyiOptions = useMemo(() => {
|
||||
return BaiduFanyiDomainOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`baiduDomainOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const baiduFanyiSourceLangOptions = useMemo(() => {
|
||||
return BaiduFanyiSourceLangOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`baiduSourceLangOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item label={t('appid')} name={'appid'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('secretKey')} name={'secret_key'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('transType')} name={'trans_type'}>
|
||||
<Select options={options}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['model_type']}>
|
||||
{({ getFieldValue }) =>
|
||||
getFieldValue('trans_type') === 'fieldtranslate' && (
|
||||
<Form.Item label={t('domain')} name={'domain'}>
|
||||
<Select options={baiduFanyiOptions}></Select>
|
||||
</Form.Item>
|
||||
)
|
||||
}
|
||||
</Form.Item>
|
||||
<Form.Item label={t('sourceLang')} name={'source_lang'}>
|
||||
<Select options={baiduFanyiSourceLangOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('targetLang')} name={'target_lang'}>
|
||||
<Select options={baiduFanyiSourceLangOptions}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default BaiduFanyiForm;
|
||||
20
web/src/pages/flow/form/baidu-form/index.tsx
Normal file
20
web/src/pages/flow/form/baidu-form/index.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { Form } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const BaiduForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default BaiduForm;
|
||||
33
web/src/pages/flow/form/begin-form/index.tsx
Normal file
33
web/src/pages/flow/form/begin-form/index.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
type FieldType = {
|
||||
prologue?: string;
|
||||
};
|
||||
|
||||
const BeginForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('chat');
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
onValuesChange={onValuesChange}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
>
|
||||
<Form.Item<FieldType>
|
||||
name={'prologue'}
|
||||
label={t('setAnOpener')}
|
||||
tooltip={t('setAnOpenerTip')}
|
||||
initialValue={t('setAnOpenerInitial')}
|
||||
>
|
||||
<Input.TextArea autoSize={{ minRows: 5 }} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default BeginForm;
|
||||
41
web/src/pages/flow/form/bing-form/index.tsx
Normal file
41
web/src/pages/flow/form/bing-form/index.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { BingCountryOptions, BingLanguageOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const BingForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const options = useMemo(() => {
|
||||
return ['Webpages', 'News'].map((x) => ({ label: x, value: x }));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
<Form.Item label={t('channel')} name={'channel'}>
|
||||
<Select options={options}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('apiKey')} name={'api_key'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('country')} name={'country'}>
|
||||
<Select options={BingCountryOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('language')} name={'language'}>
|
||||
<Select options={BingLanguageOptions}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default BingForm;
|
||||
186
web/src/pages/flow/form/categorize-form/dynamic-categorize.tsx
Normal file
186
web/src/pages/flow/form/categorize-form/dynamic-categorize.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Button, Card, Form, FormListFieldData, Input, Select } from 'antd';
|
||||
import { FormInstance } from 'antd/lib';
|
||||
import { humanId } from 'human-id';
|
||||
import trim from 'lodash/trim';
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
FocusEventHandler,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useUpdateNodeInternals } from 'reactflow';
|
||||
import { Operator } from '../../constant';
|
||||
import { useBuildFormSelectOptions } from '../../form-hooks';
|
||||
|
||||
interface IProps {
|
||||
nodeId?: string;
|
||||
}
|
||||
|
||||
interface INameInputProps {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
otherNames?: string[];
|
||||
validate(errors: string[]): void;
|
||||
}
|
||||
|
||||
const getOtherFieldValues = (
|
||||
form: FormInstance,
|
||||
formListName: string = 'items',
|
||||
field: FormListFieldData,
|
||||
latestField: string,
|
||||
) =>
|
||||
(form.getFieldValue([formListName]) ?? [])
|
||||
.map((x: any) => x[latestField])
|
||||
.filter(
|
||||
(x: string) =>
|
||||
x !== form.getFieldValue([formListName, field.name, latestField]),
|
||||
);
|
||||
|
||||
const NameInput = ({
|
||||
value,
|
||||
onChange,
|
||||
otherNames,
|
||||
validate,
|
||||
}: INameInputProps) => {
|
||||
const [name, setName] = useState<string | undefined>();
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const handleNameChange: ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||
(e) => {
|
||||
const val = e.target.value;
|
||||
// trigger validation
|
||||
if (otherNames?.some((x) => x === val)) {
|
||||
validate([t('nameRepeatedMsg')]);
|
||||
} else if (trim(val) === '') {
|
||||
validate([t('nameRequiredMsg')]);
|
||||
} else {
|
||||
validate([]);
|
||||
}
|
||||
setName(val);
|
||||
},
|
||||
[otherNames, validate, t],
|
||||
);
|
||||
|
||||
const handleNameBlur: FocusEventHandler<HTMLInputElement> = useCallback(
|
||||
(e) => {
|
||||
const val = e.target.value;
|
||||
if (otherNames?.every((x) => x !== val) && trim(val) !== '') {
|
||||
onChange?.(val);
|
||||
}
|
||||
},
|
||||
[onChange, otherNames],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setName(value);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Input
|
||||
value={name}
|
||||
onChange={handleNameChange}
|
||||
onBlur={handleNameBlur}
|
||||
></Input>
|
||||
);
|
||||
};
|
||||
|
||||
const DynamicCategorize = ({ nodeId }: IProps) => {
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const form = Form.useFormInstance();
|
||||
const buildCategorizeToOptions = useBuildFormSelectOptions(
|
||||
Operator.Categorize,
|
||||
nodeId,
|
||||
);
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.List name="items">
|
||||
{(fields, { add, remove }) => {
|
||||
const handleAdd = () => {
|
||||
add({ name: humanId() });
|
||||
if (nodeId) updateNodeInternals(nodeId);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={{ display: 'flex', rowGap: 10, flexDirection: 'column' }}
|
||||
>
|
||||
{fields.map((field) => (
|
||||
<Card
|
||||
size="small"
|
||||
key={field.key}
|
||||
extra={
|
||||
<CloseOutlined
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Form.Item
|
||||
label={t('name')}
|
||||
name={[field.name, 'name']}
|
||||
validateTrigger={['onChange', 'onBlur']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: t('nameMessage'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<NameInput
|
||||
otherNames={getOtherFieldValues(
|
||||
form,
|
||||
'items',
|
||||
field,
|
||||
'name',
|
||||
)}
|
||||
validate={(errors: string[]) =>
|
||||
form.setFields([
|
||||
{
|
||||
name: ['items', field.name, 'name'],
|
||||
errors,
|
||||
},
|
||||
])
|
||||
}
|
||||
></NameInput>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('description')}
|
||||
name={[field.name, 'description']}
|
||||
>
|
||||
<Input.TextArea rows={3} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('examples')}
|
||||
name={[field.name, 'examples']}
|
||||
>
|
||||
<Input.TextArea rows={3} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('to')} name={[field.name, 'to']}>
|
||||
<Select
|
||||
allowClear
|
||||
options={buildCategorizeToOptions(
|
||||
getOtherFieldValues(form, 'items', field, 'to'),
|
||||
)}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
))}
|
||||
|
||||
<Button type="dashed" onClick={handleAdd} block>
|
||||
+ {t('addItem')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DynamicCategorize;
|
||||
88
web/src/pages/flow/form/categorize-form/hooks.ts
Normal file
88
web/src/pages/flow/form/categorize-form/hooks.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import get from 'lodash/get';
|
||||
import omit from 'lodash/omit';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import {
|
||||
ICategorizeItem,
|
||||
ICategorizeItemResult,
|
||||
IOperatorForm,
|
||||
} from '../../interface';
|
||||
import useGraphStore from '../../store';
|
||||
|
||||
/**
|
||||
* convert the following object into a list
|
||||
*
|
||||
* {
|
||||
"product_related": {
|
||||
"description": "The question is about product usage, appearance and how it works.",
|
||||
"examples": "Why it always beaming?\nHow to install it onto the wall?\nIt leaks, what to do?",
|
||||
"to": "generate:0"
|
||||
}
|
||||
}
|
||||
*/
|
||||
const buildCategorizeListFromObject = (
|
||||
categorizeItem: ICategorizeItemResult,
|
||||
) => {
|
||||
// Categorize's to field has two data sources, with edges as the data source.
|
||||
// Changes in the edge or to field need to be synchronized to the form field.
|
||||
return Object.keys(categorizeItem).reduce<Array<ICategorizeItem>>(
|
||||
(pre, cur) => {
|
||||
// synchronize edge data to the to field
|
||||
|
||||
pre.push({ name: cur, ...categorizeItem[cur] });
|
||||
return pre;
|
||||
},
|
||||
[],
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the list in the following form into an object
|
||||
* {
|
||||
"items": [
|
||||
{
|
||||
"name": "Categorize 1",
|
||||
"description": "111",
|
||||
"examples": "ddd",
|
||||
"to": "Retrieval:LazyEelsStick"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
const buildCategorizeObjectFromList = (list: Array<ICategorizeItem>) => {
|
||||
return list.reduce<ICategorizeItemResult>((pre, cur) => {
|
||||
if (cur?.name) {
|
||||
pre[cur.name] = omit(cur, 'name');
|
||||
}
|
||||
return pre;
|
||||
}, {});
|
||||
};
|
||||
|
||||
export const useHandleFormValuesChange = ({
|
||||
onValuesChange,
|
||||
form,
|
||||
nodeId,
|
||||
}: IOperatorForm) => {
|
||||
const getNode = useGraphStore((state) => state.getNode);
|
||||
const node = getNode(nodeId);
|
||||
|
||||
const handleValuesChange = useCallback(
|
||||
(changedValues: any, values: any) => {
|
||||
onValuesChange?.(changedValues, {
|
||||
...omit(values, 'items'),
|
||||
category_description: buildCategorizeObjectFromList(values.items),
|
||||
});
|
||||
},
|
||||
[onValuesChange],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const items = buildCategorizeListFromObject(
|
||||
get(node, 'data.form.category_description', {}),
|
||||
);
|
||||
form?.setFieldsValue({
|
||||
items,
|
||||
});
|
||||
}, [form, node]);
|
||||
|
||||
return { handleValuesChange };
|
||||
};
|
||||
40
web/src/pages/flow/form/categorize-form/index.tsx
Normal file
40
web/src/pages/flow/form/categorize-form/index.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import LLMSelect from '@/components/llm-select';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form } from 'antd';
|
||||
import { useSetLlmSetting } from '../../hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import DynamicCategorize from './dynamic-categorize';
|
||||
import { useHandleFormValuesChange } from './hooks';
|
||||
|
||||
const CategorizeForm = ({ form, onValuesChange, node }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
const { handleValuesChange } = useHandleFormValuesChange({
|
||||
form,
|
||||
nodeId: node?.id,
|
||||
onValuesChange,
|
||||
});
|
||||
useSetLlmSetting(form);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={handleValuesChange}
|
||||
initialValues={{ items: [{}] }}
|
||||
>
|
||||
<Form.Item
|
||||
name={'llm_id'}
|
||||
label={t('model', { keyPrefix: 'chat' })}
|
||||
tooltip={t('modelTip', { keyPrefix: 'chat' })}
|
||||
>
|
||||
<LLMSelect></LLMSelect>
|
||||
</Form.Item>
|
||||
<DynamicCategorize nodeId={node?.id}></DynamicCategorize>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default CategorizeForm;
|
||||
17
web/src/pages/flow/form/concentrator-form/index.tsx
Normal file
17
web/src/pages/flow/form/concentrator-form/index.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { Form } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const ConcentratorForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
></Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConcentratorForm;
|
||||
35
web/src/pages/flow/form/deepl-form/index.tsx
Normal file
35
web/src/pages/flow/form/deepl-form/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { DeepLSourceLangOptions, DeepLTargetLangOptions } from '../../constant';
|
||||
import { useBuildSortOptions } from '../../form-hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const DeepLForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
const options = useBuildSortOptions();
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={5}></TopNItem>
|
||||
<Form.Item label={t('authKey')} name={'auth_key'}>
|
||||
<Select options={options}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('sourceLang')} name={'source_lang'}>
|
||||
<Select options={DeepLSourceLangOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('targetLang')} name={'target_lang'}>
|
||||
<Select options={DeepLTargetLangOptions}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeepLForm;
|
||||
37
web/src/pages/flow/form/duckduckgo-form/index.tsx
Normal file
37
web/src/pages/flow/form/duckduckgo-form/index.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { Channel } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const DuckDuckGoForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const options = useMemo(() => {
|
||||
return Object.values(Channel).map((x) => ({ value: x, label: t(x) }));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
<Form.Item
|
||||
label={t('channel')}
|
||||
name={'channel'}
|
||||
tooltip={t('channelTip')}
|
||||
initialValue={'text'}
|
||||
>
|
||||
<Select options={options}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default DuckDuckGoForm;
|
||||
79
web/src/pages/flow/form/exesql-form/index.tsx
Normal file
79
web/src/pages/flow/form/exesql-form/index.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useTestDbConnect } from '@/hooks/flow-hooks';
|
||||
import { Button, Flex, Form, Input, InputNumber, Select } from 'antd';
|
||||
import { useCallback } from 'react';
|
||||
import { ExeSQLOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const ExeSQLForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
const { testDbConnect, loading } = useTestDbConnect();
|
||||
|
||||
const handleTest = useCallback(async () => {
|
||||
const ret = await form?.validateFields();
|
||||
testDbConnect(ret);
|
||||
}, [form, testDbConnect]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 7 }}
|
||||
wrapperCol={{ span: 17 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item
|
||||
label={t('dbType')}
|
||||
name={'db_type'}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Select options={ExeSQLOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('database')}
|
||||
name={'database'}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('username')}
|
||||
name={'username'}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('host')} name={'host'} rules={[{ required: true }]}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('port')} name={'port'} rules={[{ required: true }]}>
|
||||
<InputNumber></InputNumber>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('password')}
|
||||
name={'password'}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input.Password></Input.Password>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('loop')}
|
||||
name={'loop'}
|
||||
tooltip={t('loopTip')}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<InputNumber></InputNumber>
|
||||
</Form.Item>
|
||||
<TopNItem initialValue={30} max={1000}></TopNItem>
|
||||
<Flex justify={'end'}>
|
||||
<Button type={'primary'} loading={loading} onClick={handleTest}>
|
||||
Test
|
||||
</Button>
|
||||
</Flex>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExeSQLForm;
|
||||
98
web/src/pages/flow/form/generate-form/dynamic-parameters.tsx
Normal file
98
web/src/pages/flow/form/generate-form/dynamic-parameters.tsx
Normal file
@ -0,0 +1,98 @@
|
||||
import { EditableCell, EditableRow } from '@/components/editable-cell';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
import { Button, Flex, Select, Table, TableProps } from 'antd';
|
||||
import { IGenerateParameter } from '../../interface';
|
||||
|
||||
import { useBuildComponentIdSelectOptions } from '../../hooks';
|
||||
import { useHandleOperateParameters } from './hooks';
|
||||
import styles from './index.less';
|
||||
|
||||
interface IProps {
|
||||
nodeId?: string;
|
||||
}
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
|
||||
const DynamicParameters = ({ nodeId }: IProps) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const options = useBuildComponentIdSelectOptions(nodeId);
|
||||
const {
|
||||
dataSource,
|
||||
handleAdd,
|
||||
handleRemove,
|
||||
handleSave,
|
||||
handleComponentIdChange,
|
||||
} = useHandleOperateParameters(nodeId!);
|
||||
|
||||
const columns: TableProps<IGenerateParameter>['columns'] = [
|
||||
{
|
||||
title: t('key'),
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
width: 50,
|
||||
onCell: (record: IGenerateParameter) => ({
|
||||
record,
|
||||
editable: true,
|
||||
dataIndex: 'key',
|
||||
title: 'key',
|
||||
handleSave,
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: t('componentId'),
|
||||
dataIndex: 'component_id',
|
||||
key: 'component_id',
|
||||
align: 'center',
|
||||
render(text, record) {
|
||||
return (
|
||||
<Select
|
||||
style={{ width: '100%' }}
|
||||
allowClear
|
||||
options={options}
|
||||
value={text}
|
||||
onChange={handleComponentIdChange(record)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('operation'),
|
||||
dataIndex: 'operation',
|
||||
width: 20,
|
||||
key: 'operation',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
render(_, record) {
|
||||
return <DeleteOutlined onClick={handleRemove(record.id)} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section>
|
||||
<Flex justify="end">
|
||||
<Button size="small" onClick={handleAdd}>
|
||||
{t('add')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
rowKey={'id'}
|
||||
className={styles.variableTable}
|
||||
components={components}
|
||||
rowClassName={() => styles.editableRow}
|
||||
scroll={{ x: true }}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default DynamicParameters;
|
||||
70
web/src/pages/flow/form/generate-form/hooks.ts
Normal file
70
web/src/pages/flow/form/generate-form/hooks.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import get from 'lodash/get';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { IGenerateParameter } 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.parameters', []) as IGenerateParameter[],
|
||||
[node],
|
||||
);
|
||||
|
||||
const handleComponentIdChange = useCallback(
|
||||
(row: IGenerateParameter) => (value: string) => {
|
||||
const newData = [...dataSource];
|
||||
const index = newData.findIndex((item) => row.id === item.id);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
component_id: value,
|
||||
});
|
||||
|
||||
updateNodeForm(nodeId, { parameters: newData });
|
||||
},
|
||||
[updateNodeForm, nodeId, dataSource],
|
||||
);
|
||||
|
||||
const handleRemove = useCallback(
|
||||
(id?: string) => () => {
|
||||
const newData = dataSource.filter((item) => item.id !== id);
|
||||
updateNodeForm(nodeId, { parameters: newData });
|
||||
},
|
||||
[updateNodeForm, nodeId, dataSource],
|
||||
);
|
||||
|
||||
const handleAdd = useCallback(() => {
|
||||
updateNodeForm(nodeId, {
|
||||
parameters: [
|
||||
...dataSource,
|
||||
{
|
||||
id: uuid(),
|
||||
key: '',
|
||||
component_id: undefined,
|
||||
},
|
||||
],
|
||||
});
|
||||
}, [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, { parameters: newData });
|
||||
};
|
||||
|
||||
return {
|
||||
handleAdd,
|
||||
handleRemove,
|
||||
handleComponentIdChange,
|
||||
handleSave,
|
||||
dataSource,
|
||||
};
|
||||
};
|
||||
21
web/src/pages/flow/form/generate-form/index.less
Normal file
21
web/src/pages/flow/form/generate-form/index.less
Normal file
@ -0,0 +1,21 @@
|
||||
.variableTable {
|
||||
margin-top: 14px;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
web/src/pages/flow/form/generate-form/index.tsx
Normal file
65
web/src/pages/flow/form/generate-form/index.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import LLMSelect from '@/components/llm-select';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, InputNumber, Switch } from 'antd';
|
||||
import { useSetLlmSetting } from '../../hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import DynamicParameters from './dynamic-parameters';
|
||||
|
||||
const GenerateForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
useSetLlmSetting(form);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 10 }}
|
||||
wrapperCol={{ span: 14 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item
|
||||
name={'llm_id'}
|
||||
label={t('model', { keyPrefix: 'chat' })}
|
||||
tooltip={t('modelTip', { keyPrefix: 'chat' })}
|
||||
>
|
||||
<LLMSelect></LLMSelect>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={['prompt']}
|
||||
label={t('prompt', { keyPrefix: 'knowledgeConfiguration' })}
|
||||
initialValue={t('promptText')}
|
||||
tooltip={t('promptTip', { keyPrefix: 'knowledgeConfiguration' })}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('promptMessage'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.TextArea rows={8} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={['cite']}
|
||||
label={t('cite')}
|
||||
initialValue={true}
|
||||
valuePropName="checked"
|
||||
tooltip={t('citeTip')}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={'message_history_window_size'}
|
||||
label={t('messageHistoryWindowSize')}
|
||||
initialValue={12}
|
||||
tooltip={t('messageHistoryWindowSizeTip')}
|
||||
>
|
||||
<InputNumber style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<DynamicParameters nodeId={node?.id}></DynamicParameters>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default GenerateForm;
|
||||
20
web/src/pages/flow/form/github-form/index.tsx
Normal file
20
web/src/pages/flow/form/github-form/index.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { Form } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const GithubForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={5}></TopNItem>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default GithubForm;
|
||||
33
web/src/pages/flow/form/google-form/index.tsx
Normal file
33
web/src/pages/flow/form/google-form/index.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { GoogleCountryOptions, GoogleLanguageOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const GoogleForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
<Form.Item label={t('apiKey')} name={'api_key'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('country')} name={'country'}>
|
||||
<Select options={GoogleCountryOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('language')} name={'language'}>
|
||||
<Select options={GoogleLanguageOptions}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoogleForm;
|
||||
74
web/src/pages/flow/form/google-scholar-form/index.tsx
Normal file
74
web/src/pages/flow/form/google-scholar-form/index.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { DatePicker, DatePickerProps, Form, Select, Switch } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useBuildSortOptions } from '../../form-hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const YearPicker = ({
|
||||
onChange,
|
||||
value,
|
||||
}: {
|
||||
onChange?: (val: number | undefined) => void;
|
||||
value?: number | undefined;
|
||||
}) => {
|
||||
const handleChange: DatePickerProps['onChange'] = useCallback(
|
||||
(val: any) => {
|
||||
const nextVal = val?.format('YYYY');
|
||||
onChange?.(nextVal ? Number(nextVal) : undefined);
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
// The year needs to be converted into a number and saved to the backend
|
||||
const nextValue = useMemo(() => {
|
||||
if (value) {
|
||||
return dayjs(value.toString());
|
||||
}
|
||||
return undefined;
|
||||
}, [value]);
|
||||
|
||||
return <DatePicker picker="year" onChange={handleChange} value={nextValue} />;
|
||||
};
|
||||
|
||||
const GoogleScholarForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const options = useBuildSortOptions();
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={5}></TopNItem>
|
||||
<Form.Item
|
||||
label={t('sortBy')}
|
||||
name={'sort_by'}
|
||||
initialValue={'relevance'}
|
||||
>
|
||||
<Select options={options}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('yearLow')} name={'year_low'}>
|
||||
<YearPicker />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('yearHigh')} name={'year_high'}>
|
||||
<YearPicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('patents')}
|
||||
name={'patents'}
|
||||
valuePropName="checked"
|
||||
initialValue={true}
|
||||
>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoogleScholarForm;
|
||||
144
web/src/pages/flow/form/jin10-form/index.tsx
Normal file
144
web/src/pages/flow/form/jin10-form/index.tsx
Normal file
@ -0,0 +1,144 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
Jin10CalendarDatashapeOptions,
|
||||
Jin10CalendarTypeOptions,
|
||||
Jin10FlashTypeOptions,
|
||||
Jin10SymbolsDatatypeOptions,
|
||||
Jin10SymbolsTypeOptions,
|
||||
Jin10TypeOptions,
|
||||
} from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const Jin10Form = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const jin10TypeOptions = useMemo(() => {
|
||||
return Jin10TypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`jin10TypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const jin10FlashTypeOptions = useMemo(() => {
|
||||
return Jin10FlashTypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`jin10FlashTypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const jin10CalendarTypeOptions = useMemo(() => {
|
||||
return Jin10CalendarTypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`jin10CalendarTypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const jin10CalendarDatashapeOptions = useMemo(() => {
|
||||
return Jin10CalendarDatashapeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`jin10CalendarDatashapeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const jin10SymbolsTypeOptions = useMemo(() => {
|
||||
return Jin10SymbolsTypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`jin10SymbolsTypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const jin10SymbolsDatatypeOptions = useMemo(() => {
|
||||
return Jin10SymbolsDatatypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`jin10SymbolsDatatypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 9 }}
|
||||
wrapperCol={{ span: 15 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item label={t('type')} name={'type'} initialValue={'flash'}>
|
||||
<Select options={jin10TypeOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('secretKey')} name={'secret_key'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['type']}>
|
||||
{({ getFieldValue }) => {
|
||||
const type = getFieldValue('type');
|
||||
switch (type) {
|
||||
case 'flash':
|
||||
return (
|
||||
<>
|
||||
<Form.Item label={t('flashType')} name={'flash_type'}>
|
||||
<Select options={jin10FlashTypeOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('contain')} name={'contain'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('filter')} name={'filter'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
|
||||
case 'calendar':
|
||||
return (
|
||||
<>
|
||||
<Form.Item label={t('calendarType')} name={'calendar_type'}>
|
||||
<Select options={jin10CalendarTypeOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('calendarDatashape')}
|
||||
name={'calendar_datashape'}
|
||||
>
|
||||
<Select options={jin10CalendarDatashapeOptions}></Select>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
|
||||
case 'symbols':
|
||||
return (
|
||||
<>
|
||||
<Form.Item label={t('symbolsType')} name={'symbols_type'}>
|
||||
<Select options={jin10SymbolsTypeOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('symbolsDatatype')}
|
||||
name={'symbols_datatype'}
|
||||
>
|
||||
<Select options={jin10SymbolsDatatypeOptions}></Select>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
|
||||
case 'news':
|
||||
return (
|
||||
<>
|
||||
<Form.Item label={t('contain')} name={'contain'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('filter')} name={'filter'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
}}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default Jin10Form;
|
||||
34
web/src/pages/flow/form/keyword-extract-form/index.tsx
Normal file
34
web/src/pages/flow/form/keyword-extract-form/index.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import LLMSelect from '@/components/llm-select';
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form } from 'antd';
|
||||
import { useSetLlmSetting } from '../../hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const KeywordExtractForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
useSetLlmSetting(form);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item
|
||||
name={'llm_id'}
|
||||
label={t('model', { keyPrefix: 'chat' })}
|
||||
tooltip={t('modelTip', { keyPrefix: 'chat' })}
|
||||
>
|
||||
<LLMSelect></LLMSelect>
|
||||
</Form.Item>
|
||||
<TopNItem initialValue={1}></TopNItem>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default KeywordExtractForm;
|
||||
16
web/src/pages/flow/form/message-form/index.less
Normal file
16
web/src/pages/flow/form/message-form/index.less
Normal file
@ -0,0 +1,16 @@
|
||||
.dynamicDeleteButton {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin: 0 8px;
|
||||
color: #999;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
color: #777;
|
||||
}
|
||||
&[disabled] {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
87
web/src/pages/flow/form/message-form/index.tsx
Normal file
87
web/src/pages/flow/form/message-form/index.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import { Button, Form, Input } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
sm: { span: 6 },
|
||||
},
|
||||
wrapperCol: {
|
||||
sm: { span: 18 },
|
||||
},
|
||||
};
|
||||
|
||||
const formItemLayoutWithOutLabel = {
|
||||
wrapperCol: {
|
||||
sm: { span: 18, offset: 6 },
|
||||
},
|
||||
};
|
||||
|
||||
const MessageForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
{...formItemLayoutWithOutLabel}
|
||||
onValuesChange={onValuesChange}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
>
|
||||
<Form.List name="messages">
|
||||
{(fields, { add, remove }, {}) => (
|
||||
<>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item
|
||||
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
|
||||
label={index === 0 ? t('msg') : ''}
|
||||
required={false}
|
||||
key={field.key}
|
||||
>
|
||||
<Form.Item
|
||||
{...field}
|
||||
validateTrigger={['onChange', 'onBlur']}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
whitespace: true,
|
||||
message: t('messageMsg'),
|
||||
},
|
||||
]}
|
||||
noStyle
|
||||
>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder={t('messagePlaceholder')}
|
||||
style={{ width: '80%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
{fields.length > 1 ? (
|
||||
<MinusCircleOutlined
|
||||
className={styles.dynamicDeleteButton}
|
||||
onClick={() => remove(field.name)}
|
||||
/>
|
||||
) : null}
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => add()}
|
||||
style={{ width: '80%' }}
|
||||
icon={<PlusOutlined />}
|
||||
>
|
||||
{t('addMessage')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageForm;
|
||||
31
web/src/pages/flow/form/pubmed-form/index.tsx
Normal file
31
web/src/pages/flow/form/pubmed-form/index.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const PubMedForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
<Form.Item
|
||||
label={t('email')}
|
||||
name={'email'}
|
||||
tooltip={t('emailTip')}
|
||||
rules={[{ type: 'email' }]}
|
||||
>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default PubMedForm;
|
||||
87
web/src/pages/flow/form/qweather-form/index.tsx
Normal file
87
web/src/pages/flow/form/qweather-form/index.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
QWeatherLangOptions,
|
||||
QWeatherTimePeriodOptions,
|
||||
QWeatherTypeOptions,
|
||||
QWeatherUserTypeOptions,
|
||||
} from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const QWeatherForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
const qWeatherLangOptions = useMemo(() => {
|
||||
return QWeatherLangOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`qWeatherLangOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const qWeatherTypeOptions = useMemo(() => {
|
||||
return QWeatherTypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`qWeatherTypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const qWeatherUserTypeOptions = useMemo(() => {
|
||||
return QWeatherUserTypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`qWeatherUserTypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const getQWeatherTimePeriodOptions = useCallback(
|
||||
(userType: string) => {
|
||||
let options = QWeatherTimePeriodOptions;
|
||||
if (userType === 'free') {
|
||||
options = options.slice(0, 3);
|
||||
}
|
||||
return options.map((x) => ({
|
||||
value: x,
|
||||
label: t(`qWeatherTimePeriodOptions.${x}`),
|
||||
}));
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item label={t('webApiKey')} name={'web_apikey'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('lang')} name={'lang'}>
|
||||
<Select options={qWeatherLangOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('type')} name={'type'}>
|
||||
<Select options={qWeatherTypeOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('userType')} name={'user_type'}>
|
||||
<Select options={qWeatherUserTypeOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item noStyle dependencies={['type', 'user_type']}>
|
||||
{({ getFieldValue }) =>
|
||||
getFieldValue('type') === 'weather' && (
|
||||
<Form.Item label={t('timePeriod')} name={'time_period'}>
|
||||
<Select
|
||||
options={getQWeatherTimePeriodOptions(
|
||||
getFieldValue('user_type'),
|
||||
)}
|
||||
></Select>
|
||||
</Form.Item>
|
||||
)
|
||||
}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default QWeatherForm;
|
||||
53
web/src/pages/flow/form/relevant-form/hooks.ts
Normal file
53
web/src/pages/flow/form/relevant-form/hooks.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import pick from 'lodash/pick';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { Edge } from 'reactflow';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import useGraphStore from '../../store';
|
||||
|
||||
export const useBuildRelevantOptions = () => {
|
||||
const nodes = useGraphStore((state) => state.nodes);
|
||||
|
||||
const buildRelevantOptions = useCallback(
|
||||
(toList: string[]) => {
|
||||
return nodes
|
||||
.filter(
|
||||
(x) => !toList.some((y) => y === x.id), // filter out selected values in other to fields from the current drop-down box options
|
||||
)
|
||||
.map((x) => ({ label: x.data.name, value: x.id }));
|
||||
},
|
||||
[nodes],
|
||||
);
|
||||
|
||||
return buildRelevantOptions;
|
||||
};
|
||||
|
||||
const getTargetOfEdge = (edges: Edge[], sourceHandle: string) =>
|
||||
edges.find((x) => x.sourceHandle === sourceHandle)?.target;
|
||||
|
||||
/**
|
||||
* monitor changes in the connection and synchronize the target to the yes and no fields of the form
|
||||
* similar to the categorize-form's useHandleFormValuesChange method
|
||||
* @param param0
|
||||
*/
|
||||
export const useWatchConnectionChanges = ({ nodeId, form }: IOperatorForm) => {
|
||||
const edges = useGraphStore((state) => state.edges);
|
||||
const getNode = useGraphStore((state) => state.getNode);
|
||||
const node = getNode(nodeId);
|
||||
|
||||
const watchFormChanges = useCallback(() => {
|
||||
if (node) {
|
||||
form?.setFieldsValue(pick(node, ['yes', 'no']));
|
||||
}
|
||||
}, [node, form]);
|
||||
|
||||
const watchConnectionChanges = useCallback(() => {
|
||||
const edgeList = edges.filter((x) => x.source === nodeId);
|
||||
const yes = getTargetOfEdge(edgeList, 'yes');
|
||||
const no = getTargetOfEdge(edgeList, 'no');
|
||||
form?.setFieldsValue({ yes, no });
|
||||
}, [edges, nodeId, form]);
|
||||
|
||||
useEffect(() => {
|
||||
watchFormChanges();
|
||||
}, [watchFormChanges]);
|
||||
};
|
||||
51
web/src/pages/flow/form/relevant-form/index.tsx
Normal file
51
web/src/pages/flow/form/relevant-form/index.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import LLMSelect from '@/components/llm-select';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { Operator } from '../../constant';
|
||||
import { useBuildFormSelectOptions } from '../../form-hooks';
|
||||
import { useSetLlmSetting } from '../../hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
import { useWatchConnectionChanges } from './hooks';
|
||||
|
||||
const RelevantForm = ({ onValuesChange, form, node }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
useSetLlmSetting(form);
|
||||
const buildRelevantOptions = useBuildFormSelectOptions(
|
||||
Operator.Relevant,
|
||||
node?.id,
|
||||
);
|
||||
useWatchConnectionChanges({ nodeId: node?.id, form });
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 4 }}
|
||||
wrapperCol={{ span: 20 }}
|
||||
onValuesChange={onValuesChange}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
>
|
||||
<Form.Item
|
||||
name={'llm_id'}
|
||||
label={t('model', { keyPrefix: 'chat' })}
|
||||
tooltip={t('modelTip', { keyPrefix: 'chat' })}
|
||||
>
|
||||
<LLMSelect></LLMSelect>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('yes')} name={'yes'}>
|
||||
<Select
|
||||
allowClear
|
||||
options={buildRelevantOptions([form?.getFieldValue('no')])}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('no')} name={'no'}>
|
||||
<Select
|
||||
allowClear
|
||||
options={buildRelevantOptions([form?.getFieldValue('yes')])}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RelevantForm;
|
||||
53
web/src/pages/flow/form/retrieval-form/index.tsx
Normal file
53
web/src/pages/flow/form/retrieval-form/index.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import KnowledgeBaseItem from '@/components/knowledge-base-item';
|
||||
import Rerank from '@/components/rerank';
|
||||
import SimilaritySlider from '@/components/similarity-slider';
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import type { FormProps } from 'antd';
|
||||
import { Form, Input } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
type FieldType = {
|
||||
top_n?: number;
|
||||
};
|
||||
|
||||
const onFinish: FormProps<FieldType>['onFinish'] = (values) => {
|
||||
console.log('Success:', values);
|
||||
};
|
||||
|
||||
const onFinishFailed: FormProps<FieldType>['onFinishFailed'] = (errorInfo) => {
|
||||
console.log('Failed:', errorInfo);
|
||||
};
|
||||
|
||||
const RetrievalForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 12 }}
|
||||
wrapperCol={{ span: 12 }}
|
||||
onFinish={onFinish}
|
||||
onFinishFailed={onFinishFailed}
|
||||
autoComplete="off"
|
||||
onValuesChange={onValuesChange}
|
||||
form={form}
|
||||
>
|
||||
<SimilaritySlider
|
||||
isTooltipShown
|
||||
vectorSimilarityWeightName="keywords_similarity_weight"
|
||||
></SimilaritySlider>
|
||||
<TopNItem></TopNItem>
|
||||
<Rerank></Rerank>
|
||||
<KnowledgeBaseItem></KnowledgeBaseItem>
|
||||
<Form.Item
|
||||
name={'empty_response'}
|
||||
label={t('emptyResponse', { keyPrefix: 'chat' })}
|
||||
tooltip={t('emptyResponseTip', { keyPrefix: 'chat' })}
|
||||
>
|
||||
<Input.TextArea placeholder="" rows={4} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RetrievalForm;
|
||||
38
web/src/pages/flow/form/rewrite-question-form/index.tsx
Normal file
38
web/src/pages/flow/form/rewrite-question-form/index.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import LLMSelect from '@/components/llm-select';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, InputNumber } from 'antd';
|
||||
import { useSetLlmSetting } from '../../hooks';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const RewriteQuestionForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('chat');
|
||||
useSetLlmSetting(form);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 4 }}
|
||||
wrapperCol={{ span: 20 }}
|
||||
onValuesChange={onValuesChange}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
>
|
||||
<Form.Item
|
||||
name={'llm_id'}
|
||||
label={t('model', { keyPrefix: 'chat' })}
|
||||
tooltip={t('modelTip', { keyPrefix: 'chat' })}
|
||||
>
|
||||
<LLMSelect></LLMSelect>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('loop', { keyPrefix: 'flow' })}
|
||||
name="loop"
|
||||
initialValue={1}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RewriteQuestionForm;
|
||||
188
web/src/pages/flow/form/switch-form/index.tsx
Normal file
188
web/src/pages/flow/form/switch-form/index.tsx
Normal file
@ -0,0 +1,188 @@
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Button, Card, Divider, Form, Input, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Operator,
|
||||
SwitchElseTo,
|
||||
SwitchLogicOperatorOptions,
|
||||
SwitchOperatorOptions,
|
||||
} from '../../constant';
|
||||
import { useBuildFormSelectOptions } from '../../form-hooks';
|
||||
import { useBuildComponentIdSelectOptions } from '../../hooks';
|
||||
import { IOperatorForm, ISwitchForm } from '../../interface';
|
||||
import { getOtherFieldValues } from '../../utils';
|
||||
|
||||
const subLabelCol = {
|
||||
span: 11,
|
||||
};
|
||||
|
||||
const subWrapperCol = {
|
||||
span: 13,
|
||||
};
|
||||
|
||||
const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
|
||||
const { t } = useTranslation();
|
||||
const buildCategorizeToOptions = useBuildFormSelectOptions(
|
||||
Operator.Switch,
|
||||
node?.id,
|
||||
);
|
||||
|
||||
const getSelectedConditionTos = () => {
|
||||
const conditions: ISwitchForm['conditions'] =
|
||||
form?.getFieldValue('conditions');
|
||||
|
||||
return conditions?.filter((x) => !!x).map((x) => x?.to) ?? [];
|
||||
};
|
||||
|
||||
const switchOperatorOptions = useMemo(() => {
|
||||
return SwitchOperatorOptions.map((x) => ({
|
||||
value: x.value,
|
||||
label: t(`flow.switchOperatorOptions.${x.label}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const switchLogicOperatorOptions = useMemo(() => {
|
||||
return SwitchLogicOperatorOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`flow.switchLogicOperatorOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
const componentIdOptions = useBuildComponentIdSelectOptions(node?.id);
|
||||
|
||||
return (
|
||||
<Form
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
form={form}
|
||||
name="dynamic_form_complex"
|
||||
autoComplete="off"
|
||||
initialValues={{ conditions: [{}] }}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.List name="conditions">
|
||||
{(fields, { add, remove }) => (
|
||||
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
|
||||
{fields.map((field) => (
|
||||
<Card
|
||||
size="small"
|
||||
title={`Case ${field.name + 1}`}
|
||||
key={field.key}
|
||||
extra={
|
||||
<CloseOutlined
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Form.Item noStyle dependencies={[field.name, 'items']}>
|
||||
{({ getFieldValue }) =>
|
||||
getFieldValue(['conditions', field.name, 'items'])?.length >
|
||||
1 && (
|
||||
<Form.Item
|
||||
label={t('flow.logicalOperator')}
|
||||
name={[field.name, 'logical_operator']}
|
||||
>
|
||||
<Select options={switchLogicOperatorOptions} />
|
||||
</Form.Item>
|
||||
)
|
||||
}
|
||||
</Form.Item>
|
||||
<Form.Item label={t('flow.to')} name={[field.name, 'to']}>
|
||||
<Select
|
||||
allowClear
|
||||
options={buildCategorizeToOptions([
|
||||
form?.getFieldValue(SwitchElseTo),
|
||||
...getOtherFieldValues(form!, 'conditions', field, 'to'),
|
||||
])}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Condition">
|
||||
<Form.List name={[field.name, 'items']}>
|
||||
{(subFields, subOpt) => (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
rowGap: 16,
|
||||
}}
|
||||
>
|
||||
{subFields.map((subField) => (
|
||||
<Card
|
||||
key={subField.key}
|
||||
title={null}
|
||||
size="small"
|
||||
extra={
|
||||
<CloseOutlined
|
||||
onClick={() => {
|
||||
subOpt.remove(subField.name);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Form.Item
|
||||
label={t('flow.componentId')}
|
||||
name={[subField.name, 'cpn_id']}
|
||||
labelCol={subLabelCol}
|
||||
wrapperCol={subWrapperCol}
|
||||
>
|
||||
<Select
|
||||
placeholder={t('flow.componentId')}
|
||||
options={componentIdOptions}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('flow.operator')}
|
||||
name={[subField.name, 'operator']}
|
||||
labelCol={subLabelCol}
|
||||
wrapperCol={subWrapperCol}
|
||||
>
|
||||
<Select
|
||||
placeholder={t('flow.operator')}
|
||||
options={switchOperatorOptions}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('flow.value')}
|
||||
name={[subField.name, 'value']}
|
||||
labelCol={subLabelCol}
|
||||
wrapperCol={subWrapperCol}
|
||||
>
|
||||
<Input placeholder={t('flow.value')} />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
))}
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => subOpt.add()}
|
||||
block
|
||||
>
|
||||
+ Add Condition
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Form.List>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
))}
|
||||
|
||||
<Button type="dashed" onClick={() => add()} block>
|
||||
+ Add Case
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Form.List>
|
||||
<Divider />
|
||||
<Form.Item label={'ELSE'} name={[SwitchElseTo]}>
|
||||
<Select
|
||||
allowClear
|
||||
options={buildCategorizeToOptions(getSelectedConditionTos())}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default SwitchForm;
|
||||
82
web/src/pages/flow/form/tushare-form/index.tsx
Normal file
82
web/src/pages/flow/form/tushare-form/index.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { DatePicker, DatePickerProps, Form, Input, Select } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { TuShareSrcOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const DateTimePicker = ({
|
||||
onChange,
|
||||
value,
|
||||
}: {
|
||||
onChange?: (val: number | undefined) => void;
|
||||
value?: number | undefined;
|
||||
}) => {
|
||||
const handleChange: DatePickerProps['onChange'] = useCallback(
|
||||
(val: any) => {
|
||||
const nextVal = val?.format('YYYY-MM-DD HH:mm:ss');
|
||||
onChange?.(nextVal ? nextVal : undefined);
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
// The value needs to be converted into a string and saved to the backend
|
||||
const nextValue = useMemo(() => {
|
||||
if (value) {
|
||||
return dayjs(value);
|
||||
}
|
||||
return undefined;
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
showTime
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
onChange={handleChange}
|
||||
value={nextValue}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const TuShareForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const tuShareSrcOptions = useMemo(() => {
|
||||
return TuShareSrcOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`tuShareSrcOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item
|
||||
label={t('token')}
|
||||
name={'token'}
|
||||
tooltip={'Get from https://tushare.pro/'}
|
||||
>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('src')} name={'src'}>
|
||||
<Select options={tuShareSrcOptions}></Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('startDate')} name={'start_date'}>
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('endDate')} name={'end_date'}>
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('keyword')} name={'keyword'}>
|
||||
<Input></Input>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default TuShareForm;
|
||||
35
web/src/pages/flow/form/wencai-form/index.tsx
Normal file
35
web/src/pages/flow/form/wencai-form/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { useMemo } from 'react';
|
||||
import { WenCaiQueryTypeOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const WenCaiForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
const wenCaiQueryTypeOptions = useMemo(() => {
|
||||
return WenCaiQueryTypeOptions.map((x) => ({
|
||||
value: x,
|
||||
label: t(`wenCaiQueryTypeOptions.${x}`),
|
||||
}));
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={20} max={99}></TopNItem>
|
||||
<Form.Item label={t('queryType')} name={'query_type'}>
|
||||
<Select options={wenCaiQueryTypeOptions}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default WenCaiForm;
|
||||
27
web/src/pages/flow/form/wikipedia-form/index.tsx
Normal file
27
web/src/pages/flow/form/wikipedia-form/index.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import TopNItem from '@/components/top-n-item';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Select } from 'antd';
|
||||
import { LanguageOptions } from '../../constant';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const WikipediaForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('common');
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<TopNItem initialValue={10}></TopNItem>
|
||||
<Form.Item label={t('language')} name={'language'}>
|
||||
<Select options={LanguageOptions}></Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default WikipediaForm;
|
||||
39
web/src/pages/flow/form/yahoo-finance-form/index.tsx
Normal file
39
web/src/pages/flow/form/yahoo-finance-form/index.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { Form, Switch } from 'antd';
|
||||
import { IOperatorForm } from '../../interface';
|
||||
|
||||
const YahooFinanceForm = ({ onValuesChange, form }: IOperatorForm) => {
|
||||
const { t } = useTranslate('flow');
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="basic"
|
||||
labelCol={{ span: 10 }}
|
||||
wrapperCol={{ span: 14 }}
|
||||
autoComplete="off"
|
||||
form={form}
|
||||
onValuesChange={onValuesChange}
|
||||
>
|
||||
<Form.Item label={t('info')} name={'info'}>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('history')} name={'history'}>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('financials')} name={'financials'}>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('balanceSheet')} name={'balance_sheet'}>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('cashFlowStatement')} name={'cash_flow_statement'}>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
<Form.Item label={t('news')} name={'news'}>
|
||||
<Switch></Switch>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default YahooFinanceForm;
|
||||
Reference in New Issue
Block a user