mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ feat: add the fork tag show in community detail page (#11814)
* 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
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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": "推荐模型",
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface DiscoverAssistantItem extends Omit<LobeAgentSettings, 'meta'>,
|
||||
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[];
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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 (
|
||||
<Tag
|
||||
bordered={false}
|
||||
color="default"
|
||||
icon={<Icon icon={GitFork} />}
|
||||
onClick={handleClick}
|
||||
style={{ cursor: 'pointer' }}
|
||||
title={t('fork.forkedFrom', {
|
||||
defaultValue: `Forked from ${forkSource.source.name}`,
|
||||
})}
|
||||
>
|
||||
{t('fork.forkedFrom')}: {forkSource.source.name}
|
||||
</Tag>
|
||||
);
|
||||
});
|
||||
|
||||
AgentForkTag.displayName = 'AgentForkTag';
|
||||
|
||||
export default AgentForkTag;
|
||||
@@ -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 }) => {
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flexbox>
|
||||
<Flexbox align={'center'} gap={4} horizontal>
|
||||
<Flexbox align={'center'} gap={8} horizontal wrap={'wrap'}>
|
||||
{author && userName ? (
|
||||
<Link style={{ color: 'inherit' }} to={urlJoin('/community/user', userName)}>
|
||||
{author}
|
||||
@@ -234,32 +226,13 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
|
||||
date={createdAt as string}
|
||||
template={'MMM DD, YYYY'}
|
||||
/>
|
||||
<AgentForkTag />
|
||||
{!!forkCount && forkCount > 0 && (
|
||||
<Tag bordered={false} color="default" icon={<Icon icon={GitBranchIcon} />}>
|
||||
{forkCount} {t('fork.forks')}
|
||||
</Tag>
|
||||
)}
|
||||
</Flexbox>
|
||||
|
||||
{/* Fork information */}
|
||||
{(forkSource?.source || (forkCount && forkCount > 0)) && (
|
||||
<Flexbox align={'center'} gap={12} horizontal>
|
||||
{forkSource?.source && (
|
||||
<Flexbox align={'center'} gap={6} horizontal>
|
||||
<Icon icon={GitForkIcon} size={'small'} />
|
||||
<Text className={styles.time} type={'secondary'}>
|
||||
{t('fork.forkedFrom')}:{' '}
|
||||
<Link to={urlJoin('/community/agent', forkSource.source.identifier)}>
|
||||
{forkSource.source.name}
|
||||
</Link>
|
||||
</Text>
|
||||
</Flexbox>
|
||||
)}
|
||||
{forkCount && forkCount > 0 && (
|
||||
<Flexbox align={'center'} gap={6} horizontal>
|
||||
<Icon icon={GitBranchIcon} size={'small'} />
|
||||
<Text className={styles.time} type={'secondary'}>
|
||||
{forkCount} {t('fork.forks')}
|
||||
</Text>
|
||||
</Flexbox>
|
||||
)}
|
||||
</Flexbox>
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
<TooltipGroup>
|
||||
|
||||
@@ -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 (
|
||||
<Tag
|
||||
bordered={false}
|
||||
color="default"
|
||||
icon={<Icon icon={GitFork} />}
|
||||
onClick={handleClick}
|
||||
style={{ cursor: 'pointer' }}
|
||||
title={t('fork.forkedFrom', {
|
||||
defaultValue: `Forked from ${forkSource.source.name}`,
|
||||
})}
|
||||
>
|
||||
{t('fork.forkedFrom')}: {forkSource.source.name}
|
||||
</Tag>
|
||||
);
|
||||
});
|
||||
|
||||
GroupAgentForkTag.displayName = 'GroupAgentForkTag';
|
||||
|
||||
export default GroupAgentForkTag;
|
||||
@@ -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 }) => {
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flexbox>
|
||||
<Flexbox align={'center'} gap={4} horizontal>
|
||||
<Flexbox align={'center'} gap={8} horizontal wrap={'wrap'}>
|
||||
{(() => {
|
||||
// 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'}
|
||||
/>
|
||||
<GroupAgentForkTag />
|
||||
{!!forkCount && forkCount > 0 && (
|
||||
<Tag bordered={false} color="default" icon={<Icon icon={GitBranchIcon} />}>
|
||||
{forkCount} {t('fork.forks')}
|
||||
</Tag>
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
|
||||
@@ -130,6 +130,7 @@ const UserAgentCard = memo<UserAgentCardProps>(
|
||||
installCount,
|
||||
status,
|
||||
identifier,
|
||||
isValidated,
|
||||
}) => {
|
||||
const { t } = useTranslation(['discover', 'setting']);
|
||||
const navigate = useNavigate();
|
||||
@@ -307,10 +308,17 @@ const UserAgentCard = memo<UserAgentCardProps>(
|
||||
{title}
|
||||
</Text>
|
||||
</Link>
|
||||
{isOwner && status && (
|
||||
<AntTag color={getStatusTagColor(status)} style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t(`setting:myAgents.status.${status}`)}
|
||||
{isValidated === false ? (
|
||||
<AntTag color="orange" style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t('assistant.underReview', { defaultValue: 'Under Review' })}
|
||||
</AntTag>
|
||||
) : (
|
||||
isOwner &&
|
||||
status && (
|
||||
<AntTag color={getStatusTagColor(status)} style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t(`setting:myAgents.status.${status}`)}
|
||||
</AntTag>
|
||||
)
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
|
||||
@@ -120,6 +120,7 @@ const UserGroupCard = memo<UserGroupCardProps>(
|
||||
identifier,
|
||||
memberCount,
|
||||
status,
|
||||
isValidated,
|
||||
}) => {
|
||||
const { t } = useTranslation(['discover', 'setting']);
|
||||
const navigate = useNavigate();
|
||||
@@ -235,10 +236,17 @@ const UserGroupCard = memo<UserGroupCardProps>(
|
||||
{title}
|
||||
</Text>
|
||||
</Link>
|
||||
{isOwner && status && (
|
||||
<AntTag color={getStatusTagColor(status)} style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t(`setting:myAgents.status.${status}`)}
|
||||
{isValidated === false ? (
|
||||
<AntTag color="orange" style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t('groupAgents.underReview', { defaultValue: 'Under Review' })}
|
||||
</AntTag>
|
||||
) : (
|
||||
isOwner &&
|
||||
status && (
|
||||
<AntTag color={getStatusTagColor(status)} style={{ flexShrink: 0, margin: 0 }}>
|
||||
{t(`setting:myAgents.status.${status}`)}
|
||||
</AntTag>
|
||||
)
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user