### What problem does this PR solve? Feat: Add RunSheet component #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.1
| ReactFlow, | ReactFlow, | ||||
| } from '@xyflow/react'; | } from '@xyflow/react'; | ||||
| import '@xyflow/react/dist/style.css'; | import '@xyflow/react/dist/style.css'; | ||||
| // import ChatDrawer from '../chat/drawer'; | |||||
| import { ChatSheet } from '../chat/chat-sheet'; | |||||
| import FormSheet from '../form-sheet/next'; | import FormSheet from '../form-sheet/next'; | ||||
| import { | import { | ||||
| useHandleDrop, | useHandleDrop, | ||||
| } from '../hooks'; | } from '../hooks'; | ||||
| import { useBeforeDelete } from '../hooks/use-before-delete'; | import { useBeforeDelete } from '../hooks/use-before-delete'; | ||||
| import { useShowDrawer } from '../hooks/use-show-drawer'; | import { useShowDrawer } from '../hooks/use-show-drawer'; | ||||
| // import RunDrawer from '../run-drawer'; | |||||
| import RunSheet from '../run-sheet'; | |||||
| import { ButtonEdge } from './edge'; | import { ButtonEdge } from './edge'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| import { RagNode } from './node'; | import { RagNode } from './node'; | ||||
| hideDrawer(): void; | hideDrawer(): void; | ||||
| } | } | ||||
| function FlowCanvas({ drawerVisible, hideDrawer }: IProps) { | |||||
| function AgentCanvas({ drawerVisible, hideDrawer }: IProps) { | |||||
| const { | const { | ||||
| nodes, | nodes, | ||||
| edges, | edges, | ||||
| showSingleDebugDrawer={showSingleDebugDrawer} | showSingleDebugDrawer={showSingleDebugDrawer} | ||||
| ></FormSheet> | ></FormSheet> | ||||
| )} | )} | ||||
| {/* {chatVisible && ( | |||||
| <ChatDrawer | |||||
| {chatVisible && ( | |||||
| <ChatSheet | |||||
| visible={chatVisible} | visible={chatVisible} | ||||
| hideModal={hideRunOrChatDrawer} | hideModal={hideRunOrChatDrawer} | ||||
| ></ChatDrawer> | |||||
| ></ChatSheet> | |||||
| )} | )} | ||||
| {runVisible && ( | {runVisible && ( | ||||
| <RunDrawer | |||||
| <RunSheet | |||||
| hideModal={hideRunOrChatDrawer} | hideModal={hideRunOrChatDrawer} | ||||
| showModal={showChatModal} | showModal={showChatModal} | ||||
| ></RunDrawer> | |||||
| )} */} | |||||
| ></RunSheet> | |||||
| )} | |||||
| </div> | </div> | ||||
| ); | ); | ||||
| } | } | ||||
| export default FlowCanvas; | |||||
| export default AgentCanvas; |
| import { | |||||
| Sheet, | |||||
| SheetContent, | |||||
| SheetDescription, | |||||
| SheetHeader, | |||||
| SheetTitle, | |||||
| SheetTrigger, | |||||
| } from '@/components/ui/sheet'; | |||||
| import { IModalProps } from '@/interfaces/common'; | |||||
| export function ChatSheet({ visible }: IModalProps<any>) { | |||||
| return ( | |||||
| <Sheet open={visible} modal={false}> | |||||
| <SheetTrigger>Open</SheetTrigger> | |||||
| <SheetContent> | |||||
| <SheetHeader> | |||||
| <SheetTitle>Are you absolutely sure?</SheetTitle> | |||||
| <SheetDescription> | |||||
| This action cannot be undone. This will permanently delete your | |||||
| account and remove your data from our servers. | |||||
| </SheetDescription> | |||||
| </SheetHeader> | |||||
| </SheetContent> | |||||
| </Sheet> | |||||
| ); | |||||
| } |
| import { Authorization } from '@/constants/authorization'; | |||||
| import { useSetModalState } from '@/hooks/common-hooks'; | |||||
| import { useSetSelectedRecord } from '@/hooks/logic-hooks'; | |||||
| import { useHandleSubmittable } from '@/hooks/login-hooks'; | |||||
| import api from '@/utils/api'; | |||||
| import { getAuthorization } from '@/utils/authorization-util'; | |||||
| import { UploadOutlined } from '@ant-design/icons'; | |||||
| import { FileUploader } from '@/components/file-uploader'; | |||||
| import { ButtonLoading } from '@/components/ui/button'; | |||||
| import { | import { | ||||
| Button, | |||||
| Form, | Form, | ||||
| FormItemProps, | |||||
| Input, | |||||
| InputNumber, | |||||
| Select, | |||||
| Switch, | |||||
| Upload, | |||||
| } from 'antd'; | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from '@/components/ui/form'; | |||||
| import { Input } from '@/components/ui/input'; | |||||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||||
| import { Switch } from '@/components/ui/switch'; | |||||
| import { Textarea } from '@/components/ui/textarea'; | |||||
| import { useSetModalState } from '@/hooks/common-hooks'; | |||||
| import { useSetSelectedRecord } from '@/hooks/logic-hooks'; | |||||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||||
| import { UploadChangeParam, UploadFile } from 'antd/es/upload'; | import { UploadChangeParam, UploadFile } from 'antd/es/upload'; | ||||
| import { pick } from 'lodash'; | |||||
| import { Link } from 'lucide-react'; | |||||
| import React, { useCallback, useState } from 'react'; | |||||
| import React, { useCallback, useMemo, useState } from 'react'; | |||||
| import { useForm } from 'react-hook-form'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { z } from 'zod'; | |||||
| import { BeginQueryType } from '../constant'; | import { BeginQueryType } from '../constant'; | ||||
| import { BeginQuery } from '../interface'; | import { BeginQuery } from '../interface'; | ||||
| import { PopoverForm } from './popover-form'; | |||||
| import styles from './index.less'; | |||||
| interface IProps { | interface IProps { | ||||
| parameters: BeginQuery[]; | parameters: BeginQuery[]; | ||||
| submitButtonDisabled?: boolean; | submitButtonDisabled?: boolean; | ||||
| } | } | ||||
| const values = {}; | |||||
| const DebugContent = ({ | const DebugContent = ({ | ||||
| parameters, | parameters, | ||||
| ok, | ok, | ||||
| submitButtonDisabled = false, | submitButtonDisabled = false, | ||||
| }: IProps) => { | }: IProps) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const [form] = Form.useForm(); | |||||
| const FormSchema = useMemo(() => { | |||||
| const obj = parameters.reduce((pre, cur, idx) => { | |||||
| pre[idx] = z.string().optional(); | |||||
| return pre; | |||||
| }, {}); | |||||
| return z.object(obj); | |||||
| }, [parameters]); | |||||
| const form = useForm({ | |||||
| defaultValues: values, | |||||
| resolver: zodResolver(FormSchema), | |||||
| }); | |||||
| const { | const { | ||||
| visible, | visible, | ||||
| hideModal: hidePopover, | hideModal: hidePopover, | ||||
| showModal: showPopover, | showModal: showPopover, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const { setRecord, currentRecord } = useSetSelectedRecord<number>(); | const { setRecord, currentRecord } = useSetSelectedRecord<number>(); | ||||
| const { submittable } = useHandleSubmittable(form); | |||||
| // const { submittable } = useHandleSubmittable(form); | |||||
| const submittable = true; | |||||
| const [isUploading, setIsUploading] = useState(false); | const [isUploading, setIsUploading] = useState(false); | ||||
| const handleShowPopover = useCallback( | const handleShowPopover = useCallback( | ||||
| ); | ); | ||||
| const renderWidget = useCallback( | const renderWidget = useCallback( | ||||
| (q: BeginQuery, idx: number) => { | |||||
| const props: FormItemProps & { key: number } = { | |||||
| (q: BeginQuery, idx: string) => { | |||||
| const props = { | |||||
| key: idx, | key: idx, | ||||
| label: q.name ?? q.key, | label: q.name ?? q.key, | ||||
| name: idx, | name: idx, | ||||
| props.rules = [{ required: true }]; | props.rules = [{ required: true }]; | ||||
| } | } | ||||
| const urlList: { url: string; result: string }[] = | |||||
| form.getFieldValue(idx) || []; | |||||
| // const urlList: { url: string; result: string }[] = | |||||
| // form.getFieldValue(idx) || []; | |||||
| const urlList: { url: string; result: string }[] = []; | |||||
| const BeginQueryTypeMap = { | const BeginQueryTypeMap = { | ||||
| [BeginQueryType.Line]: ( | [BeginQueryType.Line]: ( | ||||
| <Form.Item {...props}> | |||||
| <Input></Input> | |||||
| </Form.Item> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={props.name} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>{props.label}</FormLabel> | |||||
| <FormControl> | |||||
| <Input {...field}></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ), | ), | ||||
| [BeginQueryType.Paragraph]: ( | [BeginQueryType.Paragraph]: ( | ||||
| <Form.Item {...props}> | |||||
| <Input.TextArea rows={1}></Input.TextArea> | |||||
| </Form.Item> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={props.name} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>{props.label}</FormLabel> | |||||
| <FormControl> | |||||
| <Textarea rows={1} {...field}></Textarea> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ), | ), | ||||
| [BeginQueryType.Options]: ( | [BeginQueryType.Options]: ( | ||||
| <Form.Item {...props}> | |||||
| <Select | |||||
| allowClear | |||||
| options={q.options?.map((x) => ({ label: x, value: x })) ?? []} | |||||
| ></Select> | |||||
| </Form.Item> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={props.name} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>{props.label}</FormLabel> | |||||
| <FormControl> | |||||
| <RAGFlowSelect | |||||
| allowClear | |||||
| options={ | |||||
| q.options?.map((x) => ({ label: x, value: x })) ?? [] | |||||
| } | |||||
| {...field} | |||||
| ></RAGFlowSelect> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ), | ), | ||||
| [BeginQueryType.File]: ( | [BeginQueryType.File]: ( | ||||
| <React.Fragment key={idx}> | <React.Fragment key={idx}> | ||||
| <Form.Item label={q.name ?? q.key} 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'])} /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'file'} | |||||
| render={({ field }) => ( | |||||
| <div className="space-y-6"> | |||||
| <FormItem className="w-full"> | |||||
| <FormLabel>{t('assistantAvatar')}</FormLabel> | |||||
| <FormControl> | |||||
| <FileUploader | |||||
| value={field.value} | |||||
| onValueChange={field.onChange} | |||||
| maxFileCount={1} | |||||
| maxSize={4 * 1024 * 1024} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| </div> | |||||
| )} | |||||
| /> | |||||
| </React.Fragment> | </React.Fragment> | ||||
| ), | ), | ||||
| [BeginQueryType.Integer]: ( | [BeginQueryType.Integer]: ( | ||||
| <Form.Item {...props}> | |||||
| <InputNumber></InputNumber> | |||||
| </Form.Item> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={props.name} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>{props.label}</FormLabel> | |||||
| <FormControl> | |||||
| <Input type="number" {...field}></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ), | ), | ||||
| [BeginQueryType.Boolean]: ( | [BeginQueryType.Boolean]: ( | ||||
| <Form.Item valuePropName={'checked'} {...props}> | |||||
| <Switch></Switch> | |||||
| </Form.Item> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={props.name} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormLabel>{props.label}</FormLabel> | |||||
| <FormControl> | |||||
| <Switch | |||||
| checked={field.value} | |||||
| onCheckedChange={field.onChange} | |||||
| ></Switch> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ), | ), | ||||
| }; | }; | ||||
| BeginQueryTypeMap[BeginQueryType.Paragraph] | BeginQueryTypeMap[BeginQueryType.Paragraph] | ||||
| ); | ); | ||||
| }, | }, | ||||
| [form, handleShowPopover, onChange, switchVisible, t, visible], | |||||
| [form, t], | |||||
| ); | ); | ||||
| const onOk = useCallback(async () => { | const onOk = useCallback(async () => { | ||||
| const values = await form.validateFields(); | |||||
| // const values = await form.validateFields(); | |||||
| const nextValues = Object.entries(values).map(([key, value]) => { | const nextValues = Object.entries(values).map(([key, value]) => { | ||||
| const item = parameters[Number(key)]; | const item = parameters[Number(key)]; | ||||
| let nextValue = value; | let nextValue = value; | ||||
| }); | }); | ||||
| ok(nextValues); | ok(nextValues); | ||||
| }, [form, ok, parameters]); | |||||
| }, [ok, parameters]); | |||||
| const onSubmit = useCallback( | |||||
| (values: z.infer<typeof FormSchema>) => { | |||||
| const nextValues = Object.entries(values).map(([key, value]) => { | |||||
| const item = parameters[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 }; | |||||
| }); | |||||
| ok(nextValues); | |||||
| }, | |||||
| [ok, parameters], | |||||
| ); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <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} | |||||
| > | |||||
| <section> | |||||
| <Form {...form}> | |||||
| <form onSubmit={form.handleSubmit(onSubmit)}> | |||||
| {parameters.map((x, idx) => { | {parameters.map((x, idx) => { | ||||
| return renderWidget(x, idx); | |||||
| return <div key={idx}>{renderWidget(x, idx.toString())}</div>; | |||||
| })} | })} | ||||
| </Form> | |||||
| </Form.Provider> | |||||
| </form> | |||||
| </Form> | |||||
| </section> | </section> | ||||
| <Button | |||||
| type={'primary'} | |||||
| block | |||||
| <ButtonLoading | |||||
| onClick={onOk} | onClick={onOk} | ||||
| loading={loading} | loading={loading} | ||||
| disabled={!submittable || isUploading || submitButtonDisabled} | disabled={!submittable || isUploading || submitButtonDisabled} | ||||
| > | > | ||||
| {t(isNext ? 'common.next' : 'flow.run')} | {t(isNext ? 'common.next' : 'flow.run')} | ||||
| </Button> | |||||
| </ButtonLoading> | |||||
| </> | </> | ||||
| ); | ); | ||||
| }; | }; |
| import { | |||||
| Form, | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormMessage, | |||||
| } from '@/components/ui/form'; | |||||
| import { Input } from '@/components/ui/input'; | |||||
| import { Popover, PopoverContent } from '@/components/ui/popover'; | |||||
| import { useParseDocument } from '@/hooks/document-hooks'; | import { useParseDocument } from '@/hooks/document-hooks'; | ||||
| import { useResetFormOnCloseModal } from '@/hooks/logic-hooks'; | |||||
| import { IModalProps } from '@/interfaces/common'; | import { IModalProps } from '@/interfaces/common'; | ||||
| import { Button, Form, Input, Popover } from 'antd'; | |||||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||||
| import { PropsWithChildren } from 'react'; | import { PropsWithChildren } from 'react'; | ||||
| import { useForm } from 'react-hook-form'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { z } from 'zod'; | |||||
| const reg = | const reg = | ||||
| /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/; | /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/; | ||||
| const FormSchema = z.object({ | |||||
| url: z.string(), | |||||
| result: z.any(), | |||||
| }); | |||||
| const values = { | |||||
| url: '', | |||||
| result: null, | |||||
| }; | |||||
| export const PopoverForm = ({ | export const PopoverForm = ({ | ||||
| children, | children, | ||||
| visible, | visible, | ||||
| switchVisible, | switchVisible, | ||||
| }: PropsWithChildren<IModalProps<any>>) => { | }: PropsWithChildren<IModalProps<any>>) => { | ||||
| const [form] = Form.useForm(); | |||||
| const form = useForm({ | |||||
| defaultValues: values, | |||||
| resolver: zodResolver(FormSchema), | |||||
| }); | |||||
| const { parseDocument, loading } = useParseDocument(); | const { parseDocument, loading } = useParseDocument(); | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| useResetFormOnCloseModal({ | |||||
| form, | |||||
| visible, | |||||
| }); | |||||
| // useResetFormOnCloseModal({ | |||||
| // form, | |||||
| // visible, | |||||
| // }); | |||||
| const onOk = async () => { | |||||
| const values = await form.validateFields(); | |||||
| async function onSubmit(values: z.infer<typeof FormSchema>) { | |||||
| const val = values.url; | const val = values.url; | ||||
| if (reg.test(val)) { | if (reg.test(val)) { | ||||
| const ret = await parseDocument(val); | const ret = await parseDocument(val); | ||||
| if (ret?.data?.code === 0) { | if (ret?.data?.code === 0) { | ||||
| form.setFieldValue('result', ret?.data?.data); | |||||
| form.submit(); | |||||
| form.setValue('result', ret?.data?.data); | |||||
| } | } | ||||
| } | } | ||||
| }; | |||||
| } | |||||
| const content = ( | const content = ( | ||||
| <Form form={form} name="urlForm"> | |||||
| <Form.Item | |||||
| name="url" | |||||
| rules={[{ required: true, type: 'url' }]} | |||||
| className="m-0" | |||||
| > | |||||
| <Input | |||||
| onPressEnter={(e) => e.preventDefault()} | |||||
| placeholder={t('flow.pasteFileLink')} | |||||
| suffix={ | |||||
| <Button | |||||
| type="primary" | |||||
| onClick={onOk} | |||||
| size={'small'} | |||||
| loading={loading} | |||||
| > | |||||
| {t('common.submit')} | |||||
| </Button> | |||||
| } | |||||
| <Form {...form}> | |||||
| <form onSubmit={form.handleSubmit(onSubmit)}> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={`url`} | |||||
| render={({ field }) => ( | |||||
| <FormItem className="flex-1"> | |||||
| <FormControl> | |||||
| <Input | |||||
| {...field} | |||||
| // onPressEnter={(e) => e.preventDefault()} | |||||
| placeholder={t('flow.pasteFileLink')} | |||||
| // suffix={ | |||||
| // <Button | |||||
| // type="primary" | |||||
| // onClick={onOk} | |||||
| // size={'small'} | |||||
| // loading={loading} | |||||
| // > | |||||
| // {t('common.submit')} | |||||
| // </Button> | |||||
| // } | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={`result`} | |||||
| render={() => <></>} | |||||
| /> | /> | ||||
| </Form.Item> | |||||
| <Form.Item name={'result'} noStyle /> | |||||
| </form> | |||||
| </Form> | </Form> | ||||
| ); | ); | ||||
| return ( | return ( | ||||
| <Popover | |||||
| content={content} | |||||
| open={visible} | |||||
| trigger={'click'} | |||||
| onOpenChange={switchVisible} | |||||
| > | |||||
| <Popover open={visible} onOpenChange={switchVisible}> | |||||
| {children} | {children} | ||||
| <PopoverContent>{content}</PopoverContent> | |||||
| </Popover> | </Popover> | ||||
| ); | ); | ||||
| }; | }; |
| import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | ||||
| import { ReactFlowProvider } from '@xyflow/react'; | import { ReactFlowProvider } from '@xyflow/react'; | ||||
| import { CodeXml, EllipsisVertical, Forward, Import, Key } from 'lucide-react'; | import { CodeXml, EllipsisVertical, Forward, Import, Key } from 'lucide-react'; | ||||
| import { ComponentPropsWithoutRef } from 'react'; | |||||
| import { ComponentPropsWithoutRef, useCallback } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { AgentSidebar } from './agent-sidebar'; | import { AgentSidebar } from './agent-sidebar'; | ||||
| import FlowCanvas from './canvas'; | |||||
| import AgentCanvas from './canvas'; | |||||
| import { useHandleExportOrImportJsonFile } from './hooks/use-export-json'; | import { useHandleExportOrImportJsonFile } from './hooks/use-export-json'; | ||||
| import { useFetchDataOnMount } from './hooks/use-fetch-data'; | import { useFetchDataOnMount } from './hooks/use-fetch-data'; | ||||
| import { useGetBeginNodeDataQuery } from './hooks/use-get-begin-query'; | |||||
| import { useOpenDocument } from './hooks/use-open-document'; | import { useOpenDocument } from './hooks/use-open-document'; | ||||
| import { useSaveGraph } from './hooks/use-save-graph'; | |||||
| import { | |||||
| useSaveGraph, | |||||
| useSaveGraphBeforeOpeningDebugDrawer, | |||||
| } from './hooks/use-save-graph'; | |||||
| import { BeginQuery } from './interface'; | |||||
| import { UploadAgentDialog } from './upload-agent-dialog'; | import { UploadAgentDialog } from './upload-agent-dialog'; | ||||
| function AgentDropdownMenuItem({ | function AgentDropdownMenuItem({ | ||||
| const { saveGraph, loading } = useSaveGraph(); | const { saveGraph, loading } = useSaveGraph(); | ||||
| const { flowDetail } = useFetchDataOnMount(); | const { flowDetail } = useFetchDataOnMount(); | ||||
| const getBeginNodeDataQuery = useGetBeginNodeDataQuery(); | |||||
| const { handleRun } = useSaveGraphBeforeOpeningDebugDrawer(showChatDrawer); | |||||
| const handleRunAgent = useCallback(() => { | |||||
| const query: BeginQuery[] = getBeginNodeDataQuery(); | |||||
| if (query.length > 0) { | |||||
| showChatDrawer(); | |||||
| } else { | |||||
| handleRun(); | |||||
| } | |||||
| }, [getBeginNodeDataQuery, handleRun, showChatDrawer]); | |||||
| return ( | return ( | ||||
| <section> | <section> | ||||
| > | > | ||||
| Save | Save | ||||
| </ButtonLoading> | </ButtonLoading> | ||||
| <Button variant={'outline'}>Run app</Button> | |||||
| <Button variant={'outline'} onClick={handleRunAgent}> | |||||
| Run app | |||||
| </Button> | |||||
| <Button variant={'outline'}>Publish</Button> | <Button variant={'outline'}>Publish</Button> | ||||
| <DropdownMenu> | <DropdownMenu> | ||||
| <div className="w-full"> | <div className="w-full"> | ||||
| <SidebarTrigger /> | <SidebarTrigger /> | ||||
| <div className="w-full h-full"> | <div className="w-full h-full"> | ||||
| <FlowCanvas | |||||
| <AgentCanvas | |||||
| drawerVisible={chatDrawerVisible} | drawerVisible={chatDrawerVisible} | ||||
| hideDrawer={hideChatDrawer} | hideDrawer={hideChatDrawer} | ||||
| ></FlowCanvas> | |||||
| ></AgentCanvas> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </SidebarProvider> | </SidebarProvider> |
| import { IModalProps } from '@/interfaces/common'; | |||||
| import { Drawer } from 'antd'; | |||||
| import { useCallback } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { BeginId } from '../constant'; | |||||
| import DebugContent from '../debug-content'; | |||||
| import { useGetBeginNodeDataQuery } from '../hooks/use-get-begin-query'; | |||||
| import { useSaveGraphBeforeOpeningDebugDrawer } from '../hooks/use-save-graph'; | |||||
| import { BeginQuery } from '../interface'; | |||||
| import useGraphStore from '../store'; | |||||
| import { getDrawerWidth } from '../utils'; | |||||
| const RunSheet = ({ | |||||
| hideModal, | |||||
| showModal: showChatModal, | |||||
| }: IModalProps<any>) => { | |||||
| const { t } = useTranslation(); | |||||
| const updateNodeForm = useGraphStore((state) => state.updateNodeForm); | |||||
| const getBeginNodeDataQuery = useGetBeginNodeDataQuery(); | |||||
| const query: BeginQuery[] = getBeginNodeDataQuery(); | |||||
| const { handleRun, loading } = useSaveGraphBeforeOpeningDebugDrawer( | |||||
| showChatModal!, | |||||
| ); | |||||
| const handleRunAgent = useCallback( | |||||
| (nextValues: Record<string, any>) => { | |||||
| const currentNodes = updateNodeForm(BeginId, nextValues, ['query']); | |||||
| handleRun(currentNodes); | |||||
| hideModal?.(); | |||||
| }, | |||||
| [handleRun, hideModal, updateNodeForm], | |||||
| ); | |||||
| const onOk = useCallback( | |||||
| async (nextValues: any[]) => { | |||||
| handleRunAgent(nextValues); | |||||
| }, | |||||
| [handleRunAgent], | |||||
| ); | |||||
| return ( | |||||
| <Drawer | |||||
| title={t('flow.testRun')} | |||||
| placement="right" | |||||
| onClose={hideModal} | |||||
| open | |||||
| getContainer={false} | |||||
| width={getDrawerWidth()} | |||||
| mask={false} | |||||
| > | |||||
| <DebugContent | |||||
| ok={onOk} | |||||
| parameters={query} | |||||
| loading={loading} | |||||
| ></DebugContent> | |||||
| </Drawer> | |||||
| ); | |||||
| }; | |||||
| export default RunSheet; |