balibabu
Feat: merge the begin operator's url and file into one field #3355 (#3521)
1800b7d
raw
history blame
7.55 kB
import { Authorization } from '@/constants/authorization';
import { useSetModalState } from '@/hooks/common-hooks';
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
import { useHandleSubmittable } from '@/hooks/login-hooks';
import { IModalProps } from '@/interfaces/common';
import api from '@/utils/api';
import { getAuthorization } from '@/utils/authorization-util';
import { UploadOutlined } from '@ant-design/icons';
import {
Button,
Drawer,
Form,
FormItemProps,
Input,
InputNumber,
Select,
Switch,
Upload,
} from 'antd';
import { pick } from 'lodash';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { BeginQueryType } from '../constant';
import {
useGetBeginNodeDataQuery,
useSaveGraphBeforeOpeningDebugDrawer,
} from '../hooks';
import { BeginQuery } from '../interface';
import useGraphStore from '../store';
import { getDrawerWidth } from '../utils';
import { PopoverForm } from './popover-form';
import { UploadChangeParam, UploadFile } from 'antd/es/upload';
import { Link } from 'lucide-react';
import styles from './index.less';
const RunDrawer = ({
hideModal,
showModal: showChatModal,
}: IModalProps<any>) => {
const { t } = useTranslation();
const [form] = Form.useForm();
const updateNodeForm = useGraphStore((state) => state.updateNodeForm);
const {
visible,
hideModal: hidePopover,
switchVisible,
showModal: showPopover,
} = useSetModalState();
const { setRecord, currentRecord } = useSetSelectedRecord<number>();
const { submittable } = useHandleSubmittable(form);
const [isUploading, setIsUploading] = useState(false);
const handleShowPopover = useCallback(
(idx: number) => () => {
setRecord(idx);
showPopover();
},
[setRecord, showPopover],
);
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
const query: BeginQuery[] = getBeginNodeDataQuery();
const normFile = (e: any) => {
if (Array.isArray(e)) {
return e;
}
return e?.fileList;
};
const onChange = useCallback(
(optional: boolean) =>
({ fileList }: UploadChangeParam<UploadFile>) => {
if (!optional) {
setIsUploading(fileList.some((x) => x.status === 'uploading'));
}
},
[],
);
const renderWidget = useCallback(
(q: BeginQuery, idx: number) => {
const props: FormItemProps & { key: number } = {
key: idx,
label: q.name,
name: idx,
};
if (q.optional === false) {
props.rules = [{ required: true }];
}
const urlList: { url: string; result: string }[] =
form.getFieldValue(idx) || [];
const BeginQueryTypeMap = {
[BeginQueryType.Line]: (
<Form.Item {...props}>
<Input></Input>
</Form.Item>
),
[BeginQueryType.Paragraph]: (
<Form.Item {...props}>
<Input.TextArea rows={4}></Input.TextArea>
</Form.Item>
),
[BeginQueryType.Options]: (
<Form.Item {...props}>
<Select
allowClear
options={q.options?.map((x) => ({ label: x, value: x })) ?? []}
></Select>
</Form.Item>
),
[BeginQueryType.File]: (
<React.Fragment key={idx}>
<Form.Item label={q.name} required={!q.optional}>
<div className="relative">
<Form.Item
{...props}
valuePropName="fileList"
getValueFromEvent={normFile}
noStyle
>
<Upload
name="file"
action={api.parse}
multiple
headers={{ [Authorization]: getAuthorization() }}
onChange={onChange(q.optional)}
>
<Button icon={<UploadOutlined />}>
{t('common.upload')}
</Button>
</Upload>
</Form.Item>
<Form.Item
{...pick(props, ['key', 'label', 'rules'])}
required={!q.optional}
className={urlList.length > 0 ? 'mb-1' : ''}
noStyle
>
<PopoverForm visible={visible} switchVisible={switchVisible}>
<Button
onClick={handleShowPopover(idx)}
className="absolute left-1/2 top-0"
icon={<Link className="size-3" />}
>
{t('flow.pasteFileLink')}
</Button>
</PopoverForm>
</Form.Item>
</div>
</Form.Item>
<Form.Item name={idx} noStyle {...pick(props, ['rules'])} />
</React.Fragment>
),
[BeginQueryType.Integer]: (
<Form.Item {...props}>
<InputNumber></InputNumber>
</Form.Item>
),
[BeginQueryType.Boolean]: (
<Form.Item valuePropName={'checked'} {...props}>
<Switch></Switch>
</Form.Item>
),
};
return BeginQueryTypeMap[q.type as BeginQueryType];
},
[form, handleShowPopover, onChange, switchVisible, t, visible],
);
const { handleRun } = useSaveGraphBeforeOpeningDebugDrawer(showChatModal!);
const handleRunAgent = useCallback(
(nextValues: Record<string, any>) => {
const currentNodes = updateNodeForm('begin', nextValues, ['query']);
handleRun(currentNodes);
hideModal?.();
},
[handleRun, hideModal, updateNodeForm],
);
const onOk = useCallback(async () => {
const values = await form.validateFields();
const nextValues = Object.entries(values).map(([key, value]) => {
const item = query[Number(key)];
let nextValue = value;
if (Array.isArray(value)) {
nextValue = ``;
value.forEach((x) => {
nextValue +=
x?.originFileObj instanceof File
? `${x.name}\n${x.response?.data}\n----\n`
: `${x.url}\n${x.result}\n----\n`;
});
}
return { ...item, value: nextValue };
});
handleRunAgent(nextValues);
}, [form, handleRunAgent, query]);
return (
<Drawer
title={t('flow.testRun')}
placement="right"
onClose={hideModal}
open
getContainer={false}
width={getDrawerWidth()}
mask={false}
>
<section className={styles.formWrapper}>
<Form.Provider
onFormFinish={(name, { values, forms }) => {
if (name === 'urlForm') {
const { basicForm } = forms;
const urlInfo = basicForm.getFieldValue(currentRecord) || [];
basicForm.setFieldsValue({
[currentRecord]: [...urlInfo, { ...values, name: values.url }],
});
hidePopover();
}
}}
>
<Form
name="basicForm"
autoComplete="off"
layout={'vertical'}
form={form}
>
{query.map((x, idx) => {
return renderWidget(x, idx);
})}
</Form>
</Form.Provider>
</section>
<Button
type={'primary'}
block
onClick={onOk}
disabled={!submittable || isUploading}
>
{t('common.next')}
</Button>
</Drawer>
);
};
export default RunDrawer;