### 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
| > | > | ||||
| <Slider | <Slider | ||||
| className={styles.variableSlider} | className={styles.variableSlider} | ||||
| max={2048} | |||||
| max={8192} | |||||
| disabled={disabled} | disabled={disabled} | ||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> | ||||
| <InputNumber | <InputNumber | ||||
| disabled={disabled} | disabled={disabled} | ||||
| className={styles.sliderInputNumber} | className={styles.sliderInputNumber} | ||||
| max={2048} | |||||
| max={8192} | |||||
| min={0} | min={0} | ||||
| /> | /> | ||||
| </Form.Item> | </Form.Item> |
| }, | }, | ||||
| operator: 'Operator', | operator: 'Operator', | ||||
| value: 'Value', | value: 'Value', | ||||
| useTemplate: 'Use this template', | |||||
| }, | }, | ||||
| footer: { | footer: { | ||||
| profile: 'All rights reserved @ React', | profile: 'All rights reserved @ React', |
| }, | }, | ||||
| operator: '操作符', | operator: '操作符', | ||||
| value: '值', | value: '值', | ||||
| useTemplate: '使用該模板', | |||||
| }, | }, | ||||
| footer: { | footer: { | ||||
| profile: '“保留所有權利 @ react”', | profile: '“保留所有權利 @ react”', |
| }, | }, | ||||
| operator: '操作符', | operator: '操作符', | ||||
| value: '值', | value: '值', | ||||
| useTemplate: '使用该模板', | |||||
| }, | }, | ||||
| footer: { | footer: { | ||||
| profile: 'All rights reserved @ React', | profile: 'All rights reserved @ React', |
| </span> | </span> | ||||
| {t('filesSelected')} | {t('filesSelected')} | ||||
| </Space> | </Space> | ||||
| <Space size={52}> | |||||
| <b>{t('hits')}</b> | |||||
| <b>{t('view')}</b> | |||||
| </Space> | |||||
| </Flex> | </Flex> | ||||
| ), | ), | ||||
| children: ( | children: ( |
| 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; |
| 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; |
| 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; |
| } | } | ||||
| } | } | ||||
| .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; | |||||
| } | } |
| import { PlusOutlined } from '@ant-design/icons'; | import { PlusOutlined } from '@ant-design/icons'; | ||||
| import { Button, Empty, Flex, Spin } from 'antd'; | 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 FlowCard from './flow-card'; | ||||
| import { useFetchDataOnMount, useSaveFlow } from './hooks'; | import { useFetchDataOnMount, useSaveFlow } from './hooks'; | ||||
| </Flex> | </Flex> | ||||
| </Spin> | </Spin> | ||||
| {flowSettingVisible && ( | {flowSettingVisible && ( | ||||
| <CreateFlowModal | |||||
| <AgentTemplateModal | |||||
| visible={flowSettingVisible} | visible={flowSettingVisible} | ||||
| onOk={onFlowOk} | onOk={onFlowOk} | ||||
| loading={flowSettingLoading} | loading={flowSettingLoading} | ||||
| hideModal={hideFlowSettingModal} | hideModal={hideFlowSettingModal} | ||||
| initialName="" | |||||
| ></CreateFlowModal> | |||||
| ></AgentTemplateModal> | |||||
| )} | )} | ||||
| </Flex> | </Flex> | ||||
| ); | ); |