From cd029eb45b7a970113b81569d05628bc31efb58c Mon Sep 17 00:00:00 2001 From: Shinji-Li Date: Mon, 26 Jan 2026 15:10:23 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20the=20fork=20tag=20sh?= =?UTF-8?q?ow=20in=20community=20detail=20page=20(#11814)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add the fork tag show in community detail page * feat: add the isValidated to show under review * fix: add i18n * fix: remove the not used params --- locales/en-US/discover.json | 2 + locales/zh-CN/discover.json | 2 + packages/types/src/discover/assistants.ts | 2 + packages/types/src/discover/groupAgents.ts | 8 +++ .../(detail)/agent/features/AgentForkTag.tsx | 59 +++++++++++++++++++ .../(detail)/agent/features/Header.tsx | 45 +++----------- .../features/GroupAgentForkTag.tsx | 57 ++++++++++++++++++ .../(detail)/group_agent/features/Header.tsx | 20 ++++++- .../(detail)/user/features/UserAgentCard.tsx | 14 ++++- .../(detail)/user/features/UserGroupCard.tsx | 14 ++++- src/locales/default/discover.ts | 3 + src/server/services/discover/index.ts | 7 +++ 12 files changed, 189 insertions(+), 44 deletions(-) create mode 100644 src/app/[variants]/(main)/community/(detail)/agent/features/AgentForkTag.tsx create mode 100644 src/app/[variants]/(main)/community/(detail)/group_agent/features/GroupAgentForkTag.tsx diff --git a/locales/en-US/discover.json b/locales/en-US/discover.json index 5d70537972..f9dd658127 100644 --- a/locales/en-US/discover.json +++ b/locales/en-US/discover.json @@ -5,6 +5,7 @@ "assistant.like": "Like", "assistant.likeFailed": "Failed to like", "assistant.likeSuccess": "Liked", + "assistant.underReview": "Under Review", "assistant.unfavorite": "Unsave", "assistant.unfavoriteFailed": "Failed to unsave", "assistant.unfavoriteSuccess": "Unsaved", @@ -147,6 +148,7 @@ "fork.success": "Forked successfully!", "fork.viewAllForks": "View all forks", "groupAgents.tag": "Group", + "groupAgents.underReview": "Under Review", "home.communityAgents": "Community Agents", "home.featuredAssistants": "Featured Agents", "home.featuredModels": "Featured Models", diff --git a/locales/zh-CN/discover.json b/locales/zh-CN/discover.json index 29f8f9d74b..47b714a304 100644 --- a/locales/zh-CN/discover.json +++ b/locales/zh-CN/discover.json @@ -5,6 +5,7 @@ "assistant.like": "点赞", "assistant.likeFailed": "点赞失败", "assistant.likeSuccess": "已点赞", + "assistant.underReview": "审核中", "assistant.unfavorite": "取消收藏", "assistant.unfavoriteFailed": "取消收藏失败", "assistant.unfavoriteSuccess": "已取消收藏", @@ -147,6 +148,7 @@ "fork.success": "派生成功!", "fork.viewAllForks": "查看所有派生版本", "groupAgents.tag": "群组", + "groupAgents.underReview": "审核中", "home.communityAgents": "社区助理", "home.featuredAssistants": "推荐助理", "home.featuredModels": "推荐模型", diff --git a/packages/types/src/discover/assistants.ts b/packages/types/src/discover/assistants.ts index 57556ca26e..a4c44b8851 100644 --- a/packages/types/src/discover/assistants.ts +++ b/packages/types/src/discover/assistants.ts @@ -56,6 +56,7 @@ export interface DiscoverAssistantItem extends Omit, homepage: string; identifier: string; installCount?: number; + isValidated?: boolean; knowledgeCount: number; pluginCount: number; status?: AgentStatus; @@ -92,6 +93,7 @@ export interface DiscoverAssistantDetail extends DiscoverAssistantItem { currentVersion?: string; editorData?: any; examples?: FewShots; + isValidated?: boolean; related: DiscoverAssistantItem[]; summary?: string; versions?: DiscoverAssistantVersion[]; diff --git a/packages/types/src/discover/groupAgents.ts b/packages/types/src/discover/groupAgents.ts index d9fc238ed2..7364a05227 100644 --- a/packages/types/src/discover/groupAgents.ts +++ b/packages/types/src/discover/groupAgents.ts @@ -85,6 +85,10 @@ export interface DiscoverGroupAgentItem extends MetaData { installCount?: number; isFeatured?: boolean; isOfficial?: boolean; + /** + * Whether the agent group is validated + */ + isValidated?: boolean; /** * Number of knowledge bases across all member agents */ @@ -140,6 +144,10 @@ export interface DiscoverGroupAgentDetail extends DiscoverGroupAgentItem { * Example conversations (if available from config) */ examples?: any; + /** + * Whether the agent group is validated + */ + isValidated?: boolean; /** * Member agents in the group */ diff --git a/src/app/[variants]/(main)/community/(detail)/agent/features/AgentForkTag.tsx b/src/app/[variants]/(main)/community/(detail)/agent/features/AgentForkTag.tsx new file mode 100644 index 0000000000..17042c0da2 --- /dev/null +++ b/src/app/[variants]/(main)/community/(detail)/agent/features/AgentForkTag.tsx @@ -0,0 +1,59 @@ +'use client'; + +import { Icon, Tag } from '@lobehub/ui'; +import { GitFork } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import urlJoin from 'url-join'; +import useSWR from 'swr'; + +import { marketApiService } from '@/services/marketApi'; + +import { useDetailContext } from './DetailProvider'; + +/** + * Agent Fork Tag Component + * Displays fork source information if the agent is forked from another agent + */ +const AgentForkTag = memo(() => { + const { t } = useTranslation('discover'); + const navigate = useNavigate(); + const { identifier, forkedFromAgentId } = useDetailContext(); + + console.log('forkedFromAgentId', forkedFromAgentId); + + // Fetch fork source info + const { data: forkSource } = useSWR( + identifier && forkedFromAgentId ? ['fork-source', identifier] : null, + () => marketApiService.getAgentForkSource(identifier!), + { revalidateOnFocus: false }, + ); + + if (!forkSource?.source) return null; + + const handleClick = () => { + if (forkSource?.source?.identifier) { + navigate(urlJoin('/community/agent', forkSource.source.identifier)); + } + }; + + return ( + } + onClick={handleClick} + style={{ cursor: 'pointer' }} + title={t('fork.forkedFrom', { + defaultValue: `Forked from ${forkSource.source.name}`, + })} + > + {t('fork.forkedFrom')}: {forkSource.source.name} + + ); +}); + +AgentForkTag.displayName = 'AgentForkTag'; + +export default AgentForkTag; diff --git a/src/app/[variants]/(main)/community/(detail)/agent/features/Header.tsx b/src/app/[variants]/(main)/community/(detail)/agent/features/Header.tsx index 9c688d9636..a878818271 100644 --- a/src/app/[variants]/(main)/community/(detail)/agent/features/Header.tsx +++ b/src/app/[variants]/(main)/community/(detail)/agent/features/Header.tsx @@ -7,6 +7,7 @@ import { Button, Flexbox, Icon, + Tag, Text, Tooltip, TooltipGroup, @@ -20,7 +21,6 @@ import { CoinsIcon, DotIcon, GitBranchIcon, - GitForkIcon, HeartIcon, } from 'lucide-react'; import qs from 'query-string'; @@ -31,12 +31,12 @@ import useSWR from 'swr'; import urlJoin from 'url-join'; import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth'; -import { marketApiService } from '@/services/marketApi'; import { socialService } from '@/services/social'; import { formatIntergerNumber } from '@/utils/format'; import { useCategory } from '../../../(list)/agent/features/Category/useCategory'; import PublishedTime from '../../../../../../../components/PublishedTime'; +import AgentForkTag from './AgentForkTag'; import { useDetailContext } from './DetailProvider'; const styles = createStaticStyles(({ css, cssVar }) => ({ @@ -61,7 +61,6 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { knowledgeCount, userName, forkCount, - forkedFromAgentId, } = useDetailContext(); const { mobile = isMobile } = useResponsive(); const { isAuthenticated, signIn, session } = useMarketAuth(); @@ -90,13 +89,6 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { ); const isLiked = likeStatus?.isLiked ?? false; - // Fetch fork source info - const { data: forkSource } = useSWR( - identifier && forkedFromAgentId ? ['fork-source', identifier] : null, - () => marketApiService.getAgentForkSource(identifier!), - { revalidateOnFocus: false }, - ); - const handleFavoriteClick = async () => { if (!isAuthenticated) { await signIn(); @@ -220,7 +212,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { /> - + {author && userName ? ( {author} @@ -234,32 +226,13 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { date={createdAt as string} template={'MMM DD, YYYY'} /> + + {!!forkCount && forkCount > 0 && ( + }> + {forkCount} {t('fork.forks')} + + )} - - {/* Fork information */} - {(forkSource?.source || (forkCount && forkCount > 0)) && ( - - {forkSource?.source && ( - - - - {t('fork.forkedFrom')}:{' '} - - {forkSource.source.name} - - - - )} - {forkCount && forkCount > 0 && ( - - - - {forkCount} {t('fork.forks')} - - - )} - - )} diff --git a/src/app/[variants]/(main)/community/(detail)/group_agent/features/GroupAgentForkTag.tsx b/src/app/[variants]/(main)/community/(detail)/group_agent/features/GroupAgentForkTag.tsx new file mode 100644 index 0000000000..28ff1d571c --- /dev/null +++ b/src/app/[variants]/(main)/community/(detail)/group_agent/features/GroupAgentForkTag.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { Icon, Tag } from '@lobehub/ui'; +import { GitFork } from 'lucide-react'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import urlJoin from 'url-join'; +import useSWR from 'swr'; + +import { marketApiService } from '@/services/marketApi'; + +import { useDetailContext } from './DetailProvider'; + +/** + * Group Agent Fork Tag Component + * Displays fork source information if the group agent is forked from another group agent + */ +const GroupAgentForkTag = memo(() => { + const { t } = useTranslation('discover'); + const navigate = useNavigate(); + const { identifier, forkedFromGroupId } = useDetailContext(); + + // Fetch fork source info + const { data: forkSource } = useSWR( + identifier && forkedFromGroupId ? ['group-fork-source', identifier] : null, + () => marketApiService.getAgentGroupForkSource(identifier!), + { revalidateOnFocus: false }, + ); + + if (!forkSource?.source) return null; + + const handleClick = () => { + if (forkSource?.source?.identifier) { + navigate(urlJoin('/community/group_agent', forkSource.source.identifier)); + } + }; + + return ( + } + onClick={handleClick} + style={{ cursor: 'pointer' }} + title={t('fork.forkedFrom', { + defaultValue: `Forked from ${forkSource.source.name}`, + })} + > + {t('fork.forkedFrom')}: {forkSource.source.name} + + ); +}); + +GroupAgentForkTag.displayName = 'GroupAgentForkTag'; + +export default GroupAgentForkTag; diff --git a/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx b/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx index 8ce3a3afe7..5a215243e4 100644 --- a/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +++ b/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx @@ -6,13 +6,21 @@ import { Button, Flexbox, Icon, + Tag, Text, Tooltip, TooltipGroup, } from '@lobehub/ui'; import { App } from 'antd'; import { createStaticStyles, cssVar, useResponsive } from 'antd-style'; -import { BookmarkCheckIcon, BookmarkIcon, DotIcon, HeartIcon, UsersIcon } from 'lucide-react'; +import { + BookmarkCheckIcon, + BookmarkIcon, + DotIcon, + GitBranchIcon, + HeartIcon, + UsersIcon, +} from 'lucide-react'; import qs from 'query-string'; import { memo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -25,6 +33,7 @@ import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth'; import { socialService } from '@/services/social'; import { useDetailContext } from './DetailProvider'; +import GroupAgentForkTag from './GroupAgentForkTag'; const styles = createStaticStyles(({ css, cssVar }) => ({ time: css` @@ -51,6 +60,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { identifier, createdAt, userName, + forkCount, } = data; const displayAvatar = avatar || title?.[0] || '👥'; @@ -199,7 +209,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { /> - + {(() => { // API returns author as object {avatar, name, userName}, but type definition says string const authorObj = @@ -220,6 +230,12 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => { date={createdAt as string} template={'MMM DD, YYYY'} /> + + {!!forkCount && forkCount > 0 && ( + }> + {forkCount} {t('fork.forks')} + + )} diff --git a/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx b/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx index 2273794e19..e292cc0554 100644 --- a/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +++ b/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx @@ -130,6 +130,7 @@ const UserAgentCard = memo( installCount, status, identifier, + isValidated, }) => { const { t } = useTranslation(['discover', 'setting']); const navigate = useNavigate(); @@ -307,10 +308,17 @@ const UserAgentCard = memo( {title} - {isOwner && status && ( - - {t(`setting:myAgents.status.${status}`)} + {isValidated === false ? ( + + {t('assistant.underReview', { defaultValue: 'Under Review' })} + ) : ( + isOwner && + status && ( + + {t(`setting:myAgents.status.${status}`)} + + ) )} diff --git a/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx b/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx index 31461106c2..487379de8c 100644 --- a/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +++ b/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx @@ -120,6 +120,7 @@ const UserGroupCard = memo( identifier, memberCount, status, + isValidated, }) => { const { t } = useTranslation(['discover', 'setting']); const navigate = useNavigate(); @@ -235,10 +236,17 @@ const UserGroupCard = memo( {title} - {isOwner && status && ( - - {t(`setting:myAgents.status.${status}`)} + {isValidated === false ? ( + + {t('groupAgents.underReview', { defaultValue: 'Under Review' })} + ) : ( + isOwner && + status && ( + + {t(`setting:myAgents.status.${status}`)} + + ) )} diff --git a/src/locales/default/discover.ts b/src/locales/default/discover.ts index 7cd8e38e38..f37038d695 100644 --- a/src/locales/default/discover.ts +++ b/src/locales/default/discover.ts @@ -5,6 +5,7 @@ export default { 'assistant.like': 'Like', 'assistant.likeFailed': 'Failed to like', 'assistant.likeSuccess': 'Liked', + 'assistant.underReview': 'Under Review', 'assistant.unfavorite': 'Unsave', 'assistant.unfavoriteFailed': 'Failed to unsave', 'assistant.unfavoriteSuccess': 'Unsaved', @@ -168,6 +169,8 @@ export default { 'groupAgents.tag': 'Group', + 'groupAgents.underReview': 'Under Review', + 'home.communityAgents': 'Community Agents', 'home.featuredAssistants': 'Featured Agents', diff --git a/src/server/services/discover/index.ts b/src/server/services/discover/index.ts index 88cb971cac..a7c877ffec 100644 --- a/src/server/services/discover/index.ts +++ b/src/server/services/discover/index.ts @@ -577,10 +577,13 @@ export class DiscoverService { role: example.role || 'user', })) : [], + forkCount: (data as any).forkCount, + forkedFromAgentId: (data as any).forkedFromAgentId, homepage: (data as any).homepage || `https://lobehub.com/discover/assistant/${(data as any).identifier}`, identifier: (data as any).identifier, + isValidated: (data as any).isValidated, knowledgeCount: (data.config as any)?.knowledgeBases?.length || (data as any).knowledgeCount || 0, pluginCount: (data.config as any)?.plugins?.length || (data as any).pluginCount || 0, @@ -1725,6 +1728,7 @@ export class DiscoverService { homepage: `https://lobehub.com/discover/assistant/${agent.identifier}`, identifier: agent.identifier, installCount: agent.installCount, + isValidated: agent.isValidated, knowledgeCount: agent.knowledgeCount || 0, pluginCount: agent.pluginCount || 0, schemaVersion: 1, @@ -1746,6 +1750,7 @@ export class DiscoverService { installCount: group.installCount || 0, isFeatured: group.isFeatured || false, isOfficial: group.isOfficial || false, + isValidated: group.isValidated, memberCount: 0, // Will be populated from memberAgents in detail view schemaVersion: 1, status: group.status, @@ -1768,6 +1773,7 @@ export class DiscoverService { homepage: `https://lobehub.com/discover/assistant/${agent.identifier}`, identifier: agent.identifier, installCount: agent.installCount, + isValidated: agent.isValidated, knowledgeCount: agent.knowledgeCount || 0, pluginCount: agent.pluginCount || 0, schemaVersion: 1, @@ -1792,6 +1798,7 @@ export class DiscoverService { installCount: group.installCount || 0, isFeatured: group.isFeatured || false, isOfficial: group.isOfficial || false, + isValidated: group.isValidated, memberCount: 0, // Will be populated from memberAgents in detail view schemaVersion: 1, status: group.status,