### What problem does this PR solve? feat: Modify the modal style of creating an agent so that there are more templates in the field of view #2122 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.11.0
| @@ -272,7 +272,7 @@ const LlmSettingItems = ({ prefix, formItemLayout = {} }: IProps) => { | |||
| > | |||
| <Slider | |||
| className={styles.variableSlider} | |||
| max={2048} | |||
| max={8192} | |||
| disabled={disabled} | |||
| /> | |||
| </Form.Item> | |||
| @@ -281,7 +281,7 @@ const LlmSettingItems = ({ prefix, formItemLayout = {} }: IProps) => { | |||
| <InputNumber | |||
| disabled={disabled} | |||
| className={styles.sliderInputNumber} | |||
| max={2048} | |||
| max={8192} | |||
| min={0} | |||
| /> | |||
| </Form.Item> | |||
| @@ -857,6 +857,7 @@ The above is the content you need to summarize.`, | |||
| }, | |||
| operator: 'Operator', | |||
| value: 'Value', | |||
| useTemplate: 'Use this template', | |||
| }, | |||
| footer: { | |||
| profile: 'All rights reserved @ React', | |||
| @@ -812,6 +812,7 @@ export default { | |||
| }, | |||
| operator: '操作符', | |||
| value: '值', | |||
| useTemplate: '使用該模板', | |||
| }, | |||
| footer: { | |||
| profile: '“保留所有權利 @ react”', | |||
| @@ -830,6 +830,7 @@ export default { | |||
| }, | |||
| operator: '操作符', | |||
| value: '值', | |||
| useTemplate: '使用该模板', | |||
| }, | |||
| footer: { | |||
| profile: 'All rights reserved @ React', | |||
| @@ -86,10 +86,6 @@ const TestingResult = ({ handleTesting }: IProps) => { | |||
| </span> | |||
| {t('filesSelected')} | |||
| </Space> | |||
| <Space size={52}> | |||
| <b>{t('hits')}</b> | |||
| <b>{t('view')}</b> | |||
| </Space> | |||
| </Flex> | |||
| ), | |||
| children: ( | |||
| @@ -0,0 +1,116 @@ | |||
| import { IModalManagerChildrenProps } from '@/components/modal-manager'; | |||
| import { useSetModalState, useTranslate } from '@/hooks/common-hooks'; | |||
| import { useFetchFlowTemplates } from '@/hooks/flow-hooks'; | |||
| import { useSelectItem } from '@/hooks/logic-hooks'; | |||
| import { Button, Card, Flex, List, Modal, Typography } from 'antd'; | |||
| import { useCallback, useState } from 'react'; | |||
| import CreateAgentModal from './create-agent-modal'; | |||
| import GraphAvatar from './graph-avatar'; | |||
| import styles from './index.less'; | |||
| const { Title, Text, Paragraph } = Typography; | |||
| interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> { | |||
| loading: boolean; | |||
| onOk: (name: string, templateId: string) => void; | |||
| showModal?(): void; | |||
| } | |||
| const AgentTemplateModal = ({ visible, hideModal, loading, onOk }: IProps) => { | |||
| const { t } = useTranslate('common'); | |||
| const { data: list } = useFetchFlowTemplates(); | |||
| const { selectedId, handleItemClick } = useSelectItem(''); | |||
| const [checkedId, setCheckedId] = useState<string>(''); | |||
| const { | |||
| visible: creatingVisible, | |||
| hideModal: hideCreatingModal, | |||
| showModal: showCreatingModal, | |||
| } = useSetModalState(); | |||
| const handleOk = useCallback( | |||
| async (name: string) => { | |||
| return onOk(name, checkedId); | |||
| }, | |||
| [onOk, checkedId], | |||
| ); | |||
| const onShowCreatingModal = useCallback( | |||
| (id: string) => () => { | |||
| showCreatingModal(); | |||
| setCheckedId(id); | |||
| }, | |||
| [showCreatingModal], | |||
| ); | |||
| return ( | |||
| <Modal | |||
| title={t('createGraph', { keyPrefix: 'flow' })} | |||
| open={visible} | |||
| width={'100vw'} | |||
| onCancel={hideModal} | |||
| okButtonProps={{ loading }} | |||
| confirmLoading={loading} | |||
| className={styles.agentTemplateModal} | |||
| wrapClassName={styles.agentTemplateModalWrapper} | |||
| footer={null} | |||
| > | |||
| <section className={styles.createModalContent}> | |||
| <Title level={5}> | |||
| {t('createFromTemplates', { keyPrefix: 'flow' })} | |||
| </Title> | |||
| <List | |||
| grid={{ gutter: 16, column: 4 }} | |||
| dataSource={list} | |||
| renderItem={(x) => ( | |||
| <List.Item> | |||
| <Card | |||
| key={x.id} | |||
| onMouseEnter={handleItemClick(x.id)} | |||
| onMouseLeave={handleItemClick('')} | |||
| className={styles.flowTemplateCard} | |||
| > | |||
| <Flex gap={'middle'} align="center"> | |||
| <GraphAvatar avatar={x.avatar}></GraphAvatar> | |||
| <b className={styles.agentTitleWrapper}> | |||
| <Text | |||
| style={{ width: '96%' }} | |||
| ellipsis={{ tooltip: x.title }} | |||
| > | |||
| {x.title} | |||
| </Text> | |||
| </b> | |||
| </Flex> | |||
| <div className={styles.agentDescription}> | |||
| <Paragraph ellipsis={{ tooltip: x.description, rows: 5 }}> | |||
| {x.description} | |||
| </Paragraph> | |||
| </div> | |||
| {selectedId === x.id && ( | |||
| <Button | |||
| type={'primary'} | |||
| block | |||
| onClick={onShowCreatingModal(x.id)} | |||
| className={styles.useButton} | |||
| > | |||
| {t('useTemplate', { keyPrefix: 'flow' })} | |||
| </Button> | |||
| )} | |||
| </Card> | |||
| </List.Item> | |||
| )} | |||
| /> | |||
| </section> | |||
| {creatingVisible && ( | |||
| <CreateAgentModal | |||
| loading={loading} | |||
| visible={creatingVisible} | |||
| hideModal={hideCreatingModal} | |||
| onOk={handleOk} | |||
| ></CreateAgentModal> | |||
| )} | |||
| </Modal> | |||
| ); | |||
| }; | |||
| export default AgentTemplateModal; | |||
| @@ -0,0 +1,54 @@ | |||
| import { IModalManagerChildrenProps } from '@/components/modal-manager'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { Form, Input, Modal } from 'antd'; | |||
| interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> { | |||
| loading: boolean; | |||
| onOk: (name: string) => void; | |||
| showModal?(): void; | |||
| } | |||
| const CreateAgentModal = ({ visible, hideModal, loading, onOk }: IProps) => { | |||
| const [form] = Form.useForm(); | |||
| const { t } = useTranslate('common'); | |||
| type FieldType = { | |||
| name?: string; | |||
| }; | |||
| const handleOk = async () => { | |||
| const ret = await form.validateFields(); | |||
| return onOk(ret.name); | |||
| }; | |||
| return ( | |||
| <Modal | |||
| title={t('createGraph', { keyPrefix: 'flow' })} | |||
| open={visible} | |||
| onOk={handleOk} | |||
| onCancel={hideModal} | |||
| okButtonProps={{ loading }} | |||
| confirmLoading={loading} | |||
| > | |||
| <Form | |||
| name="basic" | |||
| labelCol={{ span: 4 }} | |||
| wrapperCol={{ span: 20 }} | |||
| style={{ maxWidth: 600 }} | |||
| autoComplete="off" | |||
| form={form} | |||
| > | |||
| <Form.Item<FieldType> | |||
| label={t('name')} | |||
| name="name" | |||
| rules={[{ required: true, message: t('namePlaceholder') }]} | |||
| > | |||
| <Input /> | |||
| </Form.Item> | |||
| </Form> | |||
| </Modal> | |||
| ); | |||
| }; | |||
| export default CreateAgentModal; | |||
| @@ -1,95 +0,0 @@ | |||
| import { IModalManagerChildrenProps } from '@/components/modal-manager'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { useFetchFlowTemplates } from '@/hooks/flow-hooks'; | |||
| import { useSelectItem } from '@/hooks/logic-hooks'; | |||
| import { Card, Flex, Form, Input, Modal, Space, Typography } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| import { useEffect } from 'react'; | |||
| import GraphAvatar from './graph-avatar'; | |||
| import styles from './index.less'; | |||
| const { Title } = Typography; | |||
| interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> { | |||
| loading: boolean; | |||
| initialName: string; | |||
| onOk: (name: string, templateId: string) => void; | |||
| showModal?(): void; | |||
| } | |||
| const CreateFlowModal = ({ | |||
| visible, | |||
| hideModal, | |||
| loading, | |||
| initialName, | |||
| onOk, | |||
| }: IProps) => { | |||
| const [form] = Form.useForm(); | |||
| const { t } = useTranslate('common'); | |||
| const { data: list } = useFetchFlowTemplates(); | |||
| const { selectedId, handleItemClick } = useSelectItem(list?.at(0)?.id); | |||
| type FieldType = { | |||
| name?: string; | |||
| }; | |||
| const handleOk = async () => { | |||
| const ret = await form.validateFields(); | |||
| return onOk(ret.name, selectedId); | |||
| }; | |||
| useEffect(() => { | |||
| if (visible) { | |||
| form.setFieldValue('name', initialName); | |||
| } | |||
| }, [initialName, form, visible]); | |||
| return ( | |||
| <Modal | |||
| title={t('createGraph', { keyPrefix: 'flow' })} | |||
| open={visible} | |||
| onOk={handleOk} | |||
| width={600} | |||
| onCancel={hideModal} | |||
| okButtonProps={{ loading }} | |||
| confirmLoading={loading} | |||
| > | |||
| <Form | |||
| name="basic" | |||
| labelCol={{ span: 4 }} | |||
| wrapperCol={{ span: 20 }} | |||
| autoComplete="off" | |||
| layout={'vertical'} | |||
| form={form} | |||
| > | |||
| <Form.Item<FieldType> | |||
| label={<b>{t('name')}</b>} | |||
| name="name" | |||
| rules={[{ required: true, message: t('namePlaceholder') }]} | |||
| > | |||
| <Input /> | |||
| </Form.Item> | |||
| </Form> | |||
| <Title level={5}>{t('createFromTemplates', { keyPrefix: 'flow' })}</Title> | |||
| <Flex vertical gap={16} className={styles.templatesBox}> | |||
| {list?.map((x) => ( | |||
| <Card | |||
| key={x.id} | |||
| className={classNames(styles.flowTemplateCard, { | |||
| [styles.selectedFlowTemplateCard]: selectedId === x.id, | |||
| })} | |||
| onClick={handleItemClick(x.id)} | |||
| > | |||
| <Space size={'middle'}> | |||
| <GraphAvatar avatar={x.avatar}></GraphAvatar> | |||
| <b>{x.title}</b> | |||
| </Space> | |||
| <p>{x.description}</p> | |||
| </Card> | |||
| ))} | |||
| </Flex> | |||
| </Modal> | |||
| ); | |||
| }; | |||
| export default CreateFlowModal; | |||
| @@ -47,15 +47,53 @@ | |||
| } | |||
| } | |||
| .flowTemplateCard { | |||
| cursor: pointer; | |||
| .templatesBox { | |||
| max-height: 70vh; | |||
| overflow: auto; | |||
| } | |||
| .selectedFlowTemplateCard { | |||
| background-color: @selectedBackgroundColor; | |||
| .agentTemplateModal { | |||
| top: 0; | |||
| margin: 0; | |||
| width: 100%; | |||
| max-width: 100%; | |||
| height: 100vh; | |||
| max-height: 100vh; | |||
| padding: 0; | |||
| :global(.ant-modal-content) { | |||
| // width: 100vw; | |||
| height: 100%; | |||
| border-radius: 0; | |||
| } | |||
| .agentDescription { | |||
| padding-top: 18px; | |||
| height: 110px; | |||
| } | |||
| .createModalContent { | |||
| height: 90vh; | |||
| } | |||
| .agentTitleWrapper { | |||
| width: 80%; | |||
| } | |||
| .flowTemplateCard { | |||
| position: relative; | |||
| cursor: pointer; | |||
| } | |||
| .selectedFlowTemplateCard { | |||
| background-color: @selectedBackgroundColor; | |||
| } | |||
| .useButton { | |||
| position: absolute; | |||
| width: 84%; | |||
| left: 0; | |||
| right: 0; | |||
| bottom: 10px; | |||
| margin: auto; | |||
| } | |||
| } | |||
| .templatesBox { | |||
| max-height: 70vh; | |||
| overflow: auto; | |||
| .agentTemplateModalWrapper { | |||
| margin: 0; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| import { PlusOutlined } from '@ant-design/icons'; | |||
| import { Button, Empty, Flex, Spin } from 'antd'; | |||
| import CreateFlowModal from './create-flow-modal'; | |||
| import AgentTemplateModal from './agent-template-modal'; | |||
| import FlowCard from './flow-card'; | |||
| import { useFetchDataOnMount, useSaveFlow } from './hooks'; | |||
| @@ -42,13 +42,12 @@ const FlowList = () => { | |||
| </Flex> | |||
| </Spin> | |||
| {flowSettingVisible && ( | |||
| <CreateFlowModal | |||
| <AgentTemplateModal | |||
| visible={flowSettingVisible} | |||
| onOk={onFlowOk} | |||
| loading={flowSettingLoading} | |||
| hideModal={hideFlowSettingModal} | |||
| initialName="" | |||
| ></CreateFlowModal> | |||
| ></AgentTemplateModal> | |||
| )} | |||
| </Flex> | |||
| ); | |||