diff --git a/web/src/components/OverflowTags/index.tsx b/web/src/components/OverflowTags/index.tsx index 03970320..9ad9cd92 100644 --- a/web/src/components/OverflowTags/index.tsx +++ b/web/src/components/OverflowTags/index.tsx @@ -1,5 +1,5 @@ import { useRef, useState, useLayoutEffect, useCallback, type ReactNode } from 'react' -import { Popover } from 'antd' +import { Popover, type PopoverProps } from 'antd' import Tag, { type TagProps } from '@/components/Tag' interface OverflowTagsProps { @@ -7,9 +7,10 @@ interface OverflowTagsProps { gap?: number; numTagColor?: TagProps['color']; numTag?: (num?: number) => ReactNode; + popoverProps?: PopoverProps | false; } -const OverflowTags = ({ items, gap = 8, numTagColor = 'default', numTag }: OverflowTagsProps) => { +const OverflowTags = ({ items, gap = 8, numTagColor = 'default', numTag, popoverProps }: OverflowTagsProps) => { const containerRef = useRef(null) const measureRef = useRef(null) const [visibleCount, setVisibleCount] = useState(items.length) @@ -66,11 +67,15 @@ const OverflowTags = ({ items, gap = 8, numTagColor = 'default', numTag }: Overf {items.map((item, i) => {item})} +0 - - {items.map((item, i) => {item})} - - }> + + {items.map((item, i) => {item})} + + } + {...(popoverProps || {})} + open={popoverProps === false ? false : undefined} + >
{items.slice(0, visibleCount).map((item, i) => {item})} {hidden > 0 && numTag diff --git a/web/src/components/Tag/index.tsx b/web/src/components/Tag/index.tsx index f07f5cad..d49c46ae 100644 --- a/web/src/components/Tag/index.tsx +++ b/web/src/components/Tag/index.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-02 15:29:57 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-02 15:29:57 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-04-22 11:39:15 */ /** * Tag Component @@ -23,6 +23,7 @@ export interface TagProps { children: ReactNode; /** Additional CSS classes */ className?: string; + variant?: 'outline' | 'borderless' } /** Color theme mappings with text, border, and background colors */ @@ -37,9 +38,9 @@ const colors = { } /** Custom tag component with color themes */ -const Tag: FC = ({ color = 'processing', children, className }) => { +const Tag: FC = ({ color = 'processing', children, className, variant = 'outline' }) => { return ( - + {children} ) diff --git a/web/src/views/ModelManagement/List.tsx b/web/src/views/ModelManagement/List.tsx index 7342ecd1..50342bd5 100644 --- a/web/src/views/ModelManagement/List.tsx +++ b/web/src/views/ModelManagement/List.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:50:10 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 19:18:55 + * @Last Modified time: 2026-04-22 10:31:49 */ /** * Model List View @@ -11,13 +11,14 @@ */ import { useRef, useState, useEffect, forwardRef, useImperativeHandle } from 'react'; -import { Button, Flex, Row, Col, Tooltip, Popover } from 'antd' +import { Button, Flex, Row, Col, Tooltip } from 'antd' import { useTranslation } from 'react-i18next'; import type { ProviderModelItem, KeyConfigModalRef, ModelListDetailRef, ModelListItem, BaseRef } from './types' import RbCard from '@/components/RbCard' import { getModelNewList } from '@/api/models' import PageEmpty from '@/components/Empty/PageEmpty'; +import OverflowTags from '@/components/OverflowTags'; import Tag from '@/components/Tag'; import KeyConfigModal from './components/KeyConfigModal' import ModelListDetail from './components/ModelListDetail' @@ -76,13 +77,9 @@ const ModelList = forwardRef{String(item.provider).charAt(0).toUpperCase() + String(item.provider).slice(1)}
- {item.tags.map(tag => {t(`modelNew.${tag}`)})} - }> - - {item.tags.map(tag => {t(`modelNew.${tag}`)})} - - + {t(`modelNew.${tag}`)})} + /> } isNeedTooltip={false} footer={ diff --git a/web/src/views/ModelManagement/components/ModelListDetail.tsx b/web/src/views/ModelManagement/components/ModelListDetail.tsx index 8d44a37f..7c50c086 100644 --- a/web/src/views/ModelManagement/components/ModelListDetail.tsx +++ b/web/src/views/ModelManagement/components/ModelListDetail.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 16:49:45 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 18:06:23 + * @Last Modified time: 2026-04-22 10:24:32 */ /** * Model List Detail Drawer @@ -12,12 +12,13 @@ import { useState, useImperativeHandle, forwardRef, useRef, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { Button, Switch, Row, Col, Space, Tooltip, Popover } from 'antd' +import { Button, Switch, Row, Col, Tooltip } from 'antd' import type { ProviderModelItem, ModelListItem, ModelListDetailRef, MultiKeyConfigModalRef } from '../types'; import RbDrawer from '@/components/RbDrawer'; import RbCard from '@/components/RbCard/Card' import Tag from '@/components/Tag'; +import OverflowTags from '@/components/OverflowTags'; import PageEmpty from '@/components/Empty/PageEmpty'; import MultiKeyConfigModal from './MultiKeyConfigModal' import { getModelNewList, updateModelStatus, modelTypeUrl } from '@/api/models' @@ -139,18 +140,13 @@ const ModelListDetail = forwardRef(({ key={item.id} title={item.name} subTitle={ - - {t(`modelNew.${item.type}`)} - {item.api_keys.length}{t('modelNew.apiKeyNum')} - {item.capability?.map(vo => {t(`modelNew.${vo}`)})} - }> - - {t(`modelNew.${item.type}`)} - {item.api_keys.length}{t('modelNew.apiKeyNum')} - {item.capability?.map(vo => {t(`modelNew.${vo}`)})} - - } + {t(`modelNew.${item.type}`)}, + {item.api_keys.length}{t('modelNew.apiKeyNum')}, + ...(item.capability ?? []).map(vo => {t(`modelNew.${vo}`)}) + ]} + />} avatarUrl={getLogoUrl(item.logo)} avatar={
diff --git a/web/src/views/Ontology/index.tsx b/web/src/views/Ontology/index.tsx index 7b98efea..1d4b9e94 100644 --- a/web/src/views/Ontology/index.tsx +++ b/web/src/views/Ontology/index.tsx @@ -2,13 +2,13 @@ * @Author: ZhaoYing * @Date: 2026-02-03 14:10:15 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-27 15:03:09 + * @Last Modified time: 2026-04-22 11:47:38 */ import { type FC, useState, useRef } from 'react'; import type { MenuInfo } from 'rc-menu/lib/interface'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { Row, Col, Flex, Space, App, Tooltip, Dropdown } from 'antd' +import { Row, Col, Flex, Space, Tooltip } from 'antd' import SearchInput from '@/components/SearchInput'; import OntologyModal from './components/OntologyModal' @@ -21,6 +21,9 @@ import { formatDateTime } from '@/utils/format' import OntologyImportModal from './components/OntologyImportModal' import OntologyExportModal from './components/OntologyExportModal' import RbButton from '@/components/RbButton' +import MoreDropdown from '@/components/MoreDropdown' +import useDeleteConfirm from '@/hooks/useDeleteConfirm' +import OverflowTags from '@/components/OverflowTags' /** * Ontology management page component @@ -30,7 +33,7 @@ const Ontology: FC = () => { // Hooks const { t } = useTranslation(); const navigate = useNavigate() - const { modal, message } = App.useApp(); + const deleteConfirm = useDeleteConfirm(); // State const [query, setQuery] = useState({}); @@ -65,18 +68,9 @@ const Ontology: FC = () => { */ const handleDelete = (item: OntologyItem, e: MenuInfo) => { e.domEvent.stopPropagation(); - modal.confirm({ - title: t('common.confirmDeleteDesc', { name: item.scene_name }), - okText: t('common.delete'), - cancelText: t('common.cancel'), - okType: 'danger', - onOk: () => { - deleteOntologyScene(item.scene_id) - .then(() => { - message.success(t('common.deleteSuccess')) - scrollListRef.current?.refresh() - }) - } + deleteConfirm({ + name: item.scene_name, + onOk: () => deleteOntologyScene(item.scene_id).then(() => scrollListRef.current?.refresh()), }) } @@ -145,27 +139,22 @@ const Ontology: FC = () => { {item.is_system_default && {t('common.default')}} - , - label: t('common.edit'), - onClick: (e: MenuInfo) => handleEdit(item, e), - }, - { - key: 'delete', - icon:
, - label: t('common.delete'), - onClick: (e: MenuInfo) => handleDelete(item, e), - }, - ] - }} - placement="bottomRight" - > -
e.stopPropagation()} className="rb:cursor-pointer rb:size-5.5 rb:bg-[url('@/assets/images/common/more.svg')] rb:hover:bg-[url('@/assets/images/common/more_hover.svg')]">
- + , + label: t('common.edit'), + onClick: (e: MenuInfo) => handleEdit(item, e), + }, + { + key: 'delete', + icon:
, + label: t('common.delete'), + onClick: (e: MenuInfo) => handleDelete(item, e), + }, + ]} + /> } isNeedTooltip={false} @@ -177,16 +166,13 @@ const Ontology: FC = () => {
{item.scene_description}
- - - {item.entity_type?.map((type, i) => ( - {type} - ))} - - {item.type_num > 3 && ( - +{item.type_num - 3} - )} - +
+ {type}), {`+${item.type_num - 3}`}]} + numTag={(num?: number) => {`+${item.type_num - 3 + (num ? num - 1 : 0)}`}} + /> +
{(['created_at', 'updated_at'] as const).map(key => ( diff --git a/web/src/views/ToolManagement/Custom.tsx b/web/src/views/ToolManagement/Custom.tsx index 64f0af8f..3c538f88 100644 --- a/web/src/views/ToolManagement/Custom.tsx +++ b/web/src/views/ToolManagement/Custom.tsx @@ -16,6 +16,8 @@ import BodyWrapper from '@/components/Empty/BodyWrapper' import RbCard from '@/components/RbCard' import { getTools, deleteTool } from '@/api/tools' import { formatDateTime } from '@/utils/format' +import OverflowTags from '@/components/OverflowTags' +import Tag from '@/components/Tag' const Custom = forwardRef ReactNode; keyword?: string | undefined }>(({ getStatusTag, keyword }, ref) => { const { t } = useTranslation(); @@ -110,24 +112,12 @@ const Custom = forwardRef ReactNo isNeedTooltip={false} > {item.tags?.length > 0 - ? - - {item.tags?.slice(0, 2).map((type, i) => ( -
{type}
- ))} -
- {item.tags.length > 2 && ( - {item.tags?.slice(2, item.tags.length).map((type, i) => ( -
{type}
- ))}
} - color="white" - placement="bottom" - > -
+{item.tags.length - 2}
- - )} - + ?
+ {type})} + numTag={(num?: number) => {`+${num}`}} + /> +
:
{t('tool.noTags')}
} diff --git a/web/src/views/ToolManagement/Inner.tsx b/web/src/views/ToolManagement/Inner.tsx index 67c3a6f5..956f8f28 100644 --- a/web/src/views/ToolManagement/Inner.tsx +++ b/web/src/views/ToolManagement/Inner.tsx @@ -17,6 +17,8 @@ import JsonToolModal from './components/JsonToolModal' import InnerToolModal from './components/InnerToolModal' import { getTools } from '@/api/tools' import { InnerConfigData } from './constant' +import OverflowTags from '@/components/OverflowTags' +import Tag from '@/components/Tag' const Inner: React.FC<{ getStatusTag: (status: string) => ReactNode; keyword?: string | undefined }> = ({ getStatusTag, keyword }) => { const { t } = useTranslation(); @@ -98,24 +100,12 @@ const Inner: React.FC<{ getStatusTag: (status: string) => ReactNode; keyword?: s
{t(`tool.${item.config_data.tool_class}_features`)}
- - - {InnerConfigData[item.config_data.tool_class].features?.slice(0, 2).map((type, i) => ( -
{t(`tool.${type}`)}
- ))} -
- {InnerConfigData[item.config_data.tool_class].features.length > 2 && ( - {InnerConfigData[item.config_data.tool_class].features?.slice(2, InnerConfigData[item.config_data.tool_class].features.length).map((type, i) => ( -
{t(`tool.${type}`)}
- ))}
} - color="white" - placement="bottom" - > -
+{InnerConfigData[item.config_data.tool_class].features.length - 2}
- - )} - +
+ {t(`tool.${type}`)})} + numTag={(num?: number) => {`+${num}`}} + /> +
{item.config_data.tool_class === 'DateTimeTool'