@lobehub/lobehub 2.0.0-next.296 → 2.0.0-next.297

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +2 -2
  4. package/packages/types/package.json +1 -1
  5. package/packages/types/src/discover/assistants.ts +4 -0
  6. package/packages/types/src/discover/groupAgents.ts +196 -0
  7. package/packages/types/src/discover/index.ts +5 -1
  8. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/DetailProvider.tsx +19 -0
  9. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Members/index.tsx +137 -0
  10. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Nav.tsx +88 -0
  11. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Overview/index.tsx +213 -0
  12. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Related/index.tsx +85 -0
  13. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/TagList.tsx +20 -0
  14. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/index.tsx +71 -0
  15. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Versions/index.tsx +119 -0
  16. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/index.tsx +51 -0
  17. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +253 -0
  18. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +222 -0
  19. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/index.tsx +34 -0
  20. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/Summary/index.tsx +42 -0
  21. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/index.tsx +41 -0
  22. package/src/app/[variants]/(main)/community/(detail)/group_agent/features/StatusPage/index.tsx +104 -0
  23. package/src/app/[variants]/(main)/community/(detail)/group_agent/index.tsx +103 -0
  24. package/src/app/[variants]/(main)/community/(detail)/group_agent/loading.tsx +1 -0
  25. package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +7 -1
  26. package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +2 -0
  27. package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +186 -0
  28. package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupList.tsx +59 -0
  29. package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
  30. package/src/app/[variants]/(main)/community/(list)/assistant/features/List/Item.tsx +26 -8
  31. package/src/app/[variants]/(main)/community/(list)/assistant/index.tsx +1 -0
  32. package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +2 -0
  33. package/src/app/[variants]/(main)/group/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +2 -1
  34. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupForkConfirmModal.tsx +60 -0
  35. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupPublishResultModal.tsx +62 -0
  36. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx +122 -0
  37. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/index.tsx +46 -0
  38. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/types.ts +12 -0
  39. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/useMarketGroupPublish.ts +211 -0
  40. package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/utils.ts +22 -0
  41. package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
  42. package/src/locales/default/setting.ts +12 -0
  43. package/src/server/routers/lambda/market/agentGroup.ts +296 -0
  44. package/src/server/routers/lambda/market/index.ts +134 -4
  45. package/src/server/services/discover/index.ts +123 -7
  46. package/src/services/discover.ts +55 -0
  47. package/src/store/discover/slices/groupAgent/action.ts +80 -0
  48. package/src/store/discover/store.ts +3 -0
@@ -0,0 +1,253 @@
1
+ 'use client';
2
+
3
+ import {
4
+ ActionIcon,
5
+ Avatar,
6
+ Button,
7
+ Flexbox,
8
+ Icon,
9
+ Text,
10
+ Tooltip,
11
+ TooltipGroup,
12
+ } from '@lobehub/ui';
13
+ import { App } from 'antd';
14
+ import { createStaticStyles, cssVar, useResponsive } from 'antd-style';
15
+ import { BookmarkCheckIcon, BookmarkIcon, DotIcon, HeartIcon, UsersIcon } from 'lucide-react';
16
+ import qs from 'query-string';
17
+ import { memo, useState } from 'react';
18
+ import { useTranslation } from 'react-i18next';
19
+ import { Link } from 'react-router-dom';
20
+ import useSWR from 'swr';
21
+ import urlJoin from 'url-join';
22
+
23
+ import PublishedTime from '@/components/PublishedTime';
24
+ import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
25
+ import { socialService } from '@/services/social';
26
+
27
+ import { useDetailContext } from './DetailProvider';
28
+
29
+ const styles = createStaticStyles(({ css, cssVar }) => ({
30
+ time: css`
31
+ font-size: 12px;
32
+ color: ${cssVar.colorTextDescription};
33
+ `,
34
+ }));
35
+
36
+ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
37
+ const { t } = useTranslation('discover');
38
+ const { message } = App.useApp();
39
+ const data = useDetailContext();
40
+ const { mobile = isMobile } = useResponsive();
41
+ const { isAuthenticated, signIn, session } = useMarketAuth();
42
+ const [favoriteLoading, setFavoriteLoading] = useState(false);
43
+ const [likeLoading, setLikeLoading] = useState(false);
44
+
45
+ const {
46
+ memberAgents = [],
47
+ author,
48
+ avatar,
49
+ title,
50
+ category,
51
+ identifier,
52
+ createdAt,
53
+ userName,
54
+ } = data;
55
+
56
+ const displayAvatar = avatar || title?.[0] || '👥';
57
+ const memberCount = memberAgents?.length || 0;
58
+
59
+ // Set access token for social service
60
+ if (session?.accessToken) {
61
+ socialService.setAccessToken(session.accessToken);
62
+ }
63
+
64
+ // TODO: Use 'group_agent' type when social service supports it
65
+ // Fetch favorite status
66
+ const { data: favoriteStatus, mutate: mutateFavorite } = useSWR(
67
+ identifier && isAuthenticated ? ['favorite-status', 'agent', identifier] : null,
68
+ () => socialService.checkFavoriteStatus('agent', identifier!),
69
+ { revalidateOnFocus: false },
70
+ );
71
+
72
+ const isFavorited = favoriteStatus?.isFavorited ?? false;
73
+
74
+ // Fetch like status
75
+ const { data: likeStatus, mutate: mutateLike } = useSWR(
76
+ identifier && isAuthenticated ? ['like-status', 'agent', identifier] : null,
77
+ () => socialService.checkLikeStatus('agent', identifier!),
78
+ { revalidateOnFocus: false },
79
+ );
80
+ const isLiked = likeStatus?.isLiked ?? false;
81
+
82
+ const handleFavoriteClick = async () => {
83
+ if (!isAuthenticated) {
84
+ await signIn();
85
+ return;
86
+ }
87
+
88
+ if (!identifier) return;
89
+
90
+ setFavoriteLoading(true);
91
+ try {
92
+ if (isFavorited) {
93
+ await socialService.removeFavorite('agent', identifier);
94
+ message.success(t('assistant.unfavoriteSuccess'));
95
+ } else {
96
+ await socialService.addFavorite('agent', identifier);
97
+ message.success(t('assistant.favoriteSuccess'));
98
+ }
99
+ await mutateFavorite();
100
+ } catch {
101
+ message.error(t('assistant.favoriteFailed'));
102
+ } finally {
103
+ setFavoriteLoading(false);
104
+ }
105
+ };
106
+
107
+ const handleLikeClick = async () => {
108
+ if (!isAuthenticated) {
109
+ await signIn();
110
+ return;
111
+ }
112
+
113
+ if (!identifier) return;
114
+
115
+ setLikeLoading(true);
116
+ try {
117
+ if (isLiked) {
118
+ await socialService.unlike('agent', identifier);
119
+ message.success(t('assistant.unlikeSuccess'));
120
+ } else {
121
+ await socialService.like('agent', identifier);
122
+ message.success(t('assistant.likeSuccess'));
123
+ }
124
+ await mutateLike();
125
+ } catch {
126
+ message.error(t('assistant.likeFailed'));
127
+ } finally {
128
+ setLikeLoading(false);
129
+ }
130
+ };
131
+
132
+ const cateButton = category ? (
133
+ <Link
134
+ to={qs.stringifyUrl({
135
+ query: { category },
136
+ url: '/community/group_agent',
137
+ })}
138
+ >
139
+ <Button size={'middle'} variant={'outlined'}>
140
+ {category}
141
+ </Button>
142
+ </Link>
143
+ ) : null;
144
+
145
+ return (
146
+ <Flexbox gap={12}>
147
+ <Flexbox align={'flex-start'} gap={16} horizontal width={'100%'}>
148
+ <Avatar avatar={displayAvatar} shape={'square'} size={mobile ? 48 : 64} />
149
+ <Flexbox
150
+ flex={1}
151
+ gap={4}
152
+ style={{
153
+ overflow: 'hidden',
154
+ }}
155
+ >
156
+ <Flexbox
157
+ align={'center'}
158
+ gap={8}
159
+ horizontal
160
+ justify={'space-between'}
161
+ style={{
162
+ overflow: 'hidden',
163
+ position: 'relative',
164
+ }}
165
+ >
166
+ <Flexbox
167
+ align={'center'}
168
+ flex={1}
169
+ gap={12}
170
+ horizontal
171
+ style={{
172
+ overflow: 'hidden',
173
+ position: 'relative',
174
+ }}
175
+ >
176
+ <Text
177
+ as={'h1'}
178
+ ellipsis
179
+ style={{ fontSize: mobile ? 18 : 24, margin: 0 }}
180
+ title={identifier}
181
+ >
182
+ {title}
183
+ </Text>
184
+ </Flexbox>
185
+ <Tooltip title={isLiked ? t('assistant.unlike') : t('assistant.like')}>
186
+ <ActionIcon
187
+ icon={HeartIcon}
188
+ loading={likeLoading}
189
+ onClick={handleLikeClick}
190
+ style={isLiked ? { color: '#ff4d4f' } : undefined}
191
+ />
192
+ </Tooltip>
193
+ <Tooltip title={isFavorited ? t('assistant.unfavorite') : t('assistant.favorite')}>
194
+ <ActionIcon
195
+ icon={isFavorited ? BookmarkCheckIcon : BookmarkIcon}
196
+ loading={favoriteLoading}
197
+ onClick={handleFavoriteClick}
198
+ variant={isFavorited ? 'outlined' : undefined}
199
+ />
200
+ </Tooltip>
201
+ </Flexbox>
202
+ <Flexbox align={'center'} gap={4} horizontal>
203
+ {(() => {
204
+ // API returns author as object {avatar, name, userName}, but type definition says string
205
+ const authorObj =
206
+ typeof author === 'object' && author !== null ? (author as any) : null;
207
+ const authorName = authorObj ? authorObj.name || authorObj.userName : author;
208
+
209
+ return authorName && userName ? (
210
+ <Link style={{ color: 'inherit' }} to={urlJoin('/community/user', userName)}>
211
+ {authorName}
212
+ </Link>
213
+ ) : (
214
+ authorName
215
+ );
216
+ })()}
217
+ <Icon icon={DotIcon} />
218
+ <PublishedTime
219
+ className={styles.time}
220
+ date={createdAt as string}
221
+ template={'MMM DD, YYYY'}
222
+ />
223
+ </Flexbox>
224
+ </Flexbox>
225
+ </Flexbox>
226
+ <TooltipGroup>
227
+ <Flexbox
228
+ align={'center'}
229
+ gap={mobile ? 12 : 24}
230
+ horizontal
231
+ style={{
232
+ color: cssVar.colorTextSecondary,
233
+ }}
234
+ >
235
+ {!mobile && cateButton}
236
+ {Boolean(memberCount) && (
237
+ <Tooltip
238
+ styles={{ root: { pointerEvents: 'none' } }}
239
+ title={t('groupAgents.memberCount', { defaultValue: 'Members' })}
240
+ >
241
+ <Flexbox align={'center'} gap={6} horizontal>
242
+ <Icon icon={UsersIcon} />
243
+ {memberCount}
244
+ </Flexbox>
245
+ </Tooltip>
246
+ )}
247
+ </Flexbox>
248
+ </TooltipGroup>
249
+ </Flexbox>
250
+ );
251
+ });
252
+
253
+ export default Header;
@@ -0,0 +1,222 @@
1
+ 'use client';
2
+
3
+ import { Button, DropdownMenu, Flexbox, Icon } from '@lobehub/ui';
4
+ import { App } from 'antd';
5
+ import { createStaticStyles } from 'antd-style';
6
+ import { ChevronDownIcon } from 'lucide-react';
7
+ import { memo, useState } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+ import { useNavigate } from 'react-router-dom';
10
+ import urlJoin from 'url-join';
11
+
12
+ import { chatGroupService } from '@/services/chatGroup';
13
+ import { discoverService } from '@/services/discover';
14
+ import { useAgentGroupStore } from '@/store/agentGroup';
15
+
16
+ import { useDetailContext } from '../../DetailProvider';
17
+
18
+ const styles = createStaticStyles(({ css }) => ({
19
+ buttonGroup: css`
20
+ width: 100%;
21
+ `,
22
+ menuButton: css`
23
+ padding-inline: 8px;
24
+ border-start-start-radius: 0 !important;
25
+ border-end-start-radius: 0 !important;
26
+ `,
27
+ primaryButton: css`
28
+ border-start-end-radius: 0 !important;
29
+ border-end-end-radius: 0 !important;
30
+ `,
31
+ }));
32
+
33
+ const AddGroupAgent = memo<{ mobile?: boolean }>(() => {
34
+ const {
35
+ avatar,
36
+ description,
37
+ tags,
38
+ title,
39
+ config,
40
+ backgroundColor,
41
+ identifier,
42
+ memberAgents = [],
43
+ } = useDetailContext();
44
+ const [isLoading, setIsLoading] = useState(false);
45
+ const { message, modal } = App.useApp();
46
+ const { t } = useTranslation('discover');
47
+ const navigate = useNavigate();
48
+ const loadGroups = useAgentGroupStore((s) => s.loadGroups);
49
+
50
+ const meta = {
51
+ avatar,
52
+ backgroundColor,
53
+ description,
54
+ tags,
55
+ title,
56
+ };
57
+
58
+ // Check if a group with the same title already exists
59
+ const checkDuplicateGroup = async () => {
60
+ if (!title) return false;
61
+ try {
62
+ const groups = await chatGroupService.getGroups();
63
+ return groups.some((g) => g.title === title);
64
+ } catch {
65
+ return false;
66
+ }
67
+ };
68
+
69
+ const showDuplicateConfirmation = (callback: () => void) => {
70
+ modal.confirm({
71
+ cancelText: t('cancel', { ns: 'common' }),
72
+ content: t('groupAgents.duplicateAdd.content', {
73
+ defaultValue: 'This group agent has already been added. Do you want to add it again?',
74
+ title,
75
+ }),
76
+ okText: t('groupAgents.duplicateAdd.ok', { defaultValue: 'Add Anyway' }),
77
+ onOk: callback,
78
+ title: t('groupAgents.duplicateAdd.title', { defaultValue: 'Group Already Added' }),
79
+ });
80
+ };
81
+
82
+ const createGroupFromMarket = async (shouldNavigate = true) => {
83
+ if (!config) {
84
+ message.error(
85
+ t('groupAgents.noConfig', { defaultValue: 'Group configuration not available' }),
86
+ );
87
+ return;
88
+ }
89
+
90
+ // Prepare group config
91
+ const groupConfig = {
92
+ config: {
93
+ allowDM: config.allowDM,
94
+ openingMessage: config.openingMessage,
95
+ openingQuestions: config.openingQuestions,
96
+ revealDM: config.revealDM,
97
+ },
98
+ content: config.systemRole,
99
+ ...meta,
100
+ };
101
+
102
+ // Prepare member agents from market data
103
+ const members = memberAgents.map((member: any) => {
104
+ const agent = member.agent || member;
105
+ const currentVersion = member.currentVersion || member;
106
+ return {
107
+ avatar: currentVersion.avatar,
108
+ backgroundColor: currentVersion.backgroundColor,
109
+ description: currentVersion.description,
110
+ model: currentVersion.model,
111
+ plugins: currentVersion.plugins,
112
+ provider: currentVersion.provider,
113
+ systemRole: currentVersion.systemRole || currentVersion.content,
114
+ tags: currentVersion.tags,
115
+ title: currentVersion.name || agent.name,
116
+ };
117
+ });
118
+
119
+ try {
120
+ // Create group with all members in one request
121
+ const result = await chatGroupService.createGroupWithMembers(groupConfig, members);
122
+
123
+ // Refresh group list
124
+ await loadGroups();
125
+
126
+ // Report installation to marketplace
127
+ if (identifier) {
128
+ discoverService.reportAgentInstall(identifier);
129
+ discoverService.reportAgentEvent({
130
+ event: 'add',
131
+ identifier,
132
+ source: location.pathname,
133
+ });
134
+ }
135
+
136
+ message.success(
137
+ t('groupAgents.addSuccess', { defaultValue: 'Group agent added successfully!' }),
138
+ );
139
+
140
+ if (shouldNavigate) {
141
+ navigate(urlJoin('/group', result.groupId));
142
+ }
143
+
144
+ return result;
145
+ } catch (error) {
146
+ console.error('Failed to create group from market:', error);
147
+ message.error(
148
+ t('groupAgents.addError', {
149
+ defaultValue: 'Failed to add group agent. Please try again.',
150
+ }),
151
+ );
152
+ throw error;
153
+ }
154
+ };
155
+
156
+ const handleAddAndConverse = async () => {
157
+ setIsLoading(true);
158
+ try {
159
+ const isDuplicate = await checkDuplicateGroup();
160
+ if (isDuplicate) {
161
+ showDuplicateConfirmation(() => createGroupFromMarket(true));
162
+ } else {
163
+ await createGroupFromMarket(true);
164
+ }
165
+ } finally {
166
+ setIsLoading(false);
167
+ }
168
+ };
169
+
170
+ const handleAdd = async () => {
171
+ setIsLoading(true);
172
+ try {
173
+ const isDuplicate = await checkDuplicateGroup();
174
+ if (isDuplicate) {
175
+ showDuplicateConfirmation(() => createGroupFromMarket(false));
176
+ } else {
177
+ await createGroupFromMarket(false);
178
+ }
179
+ } finally {
180
+ setIsLoading(false);
181
+ }
182
+ };
183
+
184
+ const menuItems = [
185
+ {
186
+ key: 'addGroup',
187
+ label: t('groupAgents.addGroup', { defaultValue: 'Add Group' }),
188
+ onClick: handleAdd,
189
+ },
190
+ ];
191
+
192
+ return (
193
+ <Flexbox className={styles.buttonGroup} gap={0} horizontal>
194
+ <Button
195
+ block
196
+ className={styles.primaryButton}
197
+ loading={isLoading}
198
+ onClick={handleAddAndConverse}
199
+ size={'large'}
200
+ style={{ flex: 1, width: 'unset' }}
201
+ type={'primary'}
202
+ >
203
+ {t('groupAgents.addAndConverse', { defaultValue: 'Add & Start Conversation' })}
204
+ </Button>
205
+ <DropdownMenu
206
+ items={menuItems}
207
+ popupProps={{ style: { minWidth: 267 } }}
208
+ triggerProps={{ disabled: isLoading }}
209
+ >
210
+ <Button
211
+ className={styles.menuButton}
212
+ disabled={isLoading}
213
+ icon={<Icon icon={ChevronDownIcon} />}
214
+ size={'large'}
215
+ type={'primary'}
216
+ />
217
+ </DropdownMenu>
218
+ </Flexbox>
219
+ );
220
+ });
221
+
222
+ export default AddGroupAgent;
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+
3
+ import { Flexbox } from '@lobehub/ui';
4
+ import { memo } from 'react';
5
+ import urlJoin from 'url-join';
6
+
7
+ import { OFFICIAL_URL } from '@/const/url';
8
+
9
+ import ShareButton from '../../../../features/ShareButton';
10
+ import { useDetailContext } from '../../DetailProvider';
11
+ import AddGroupAgent from './AddGroupAgent';
12
+
13
+ const ActionButton = memo<{ mobile?: boolean }>(({ mobile }) => {
14
+ const { avatar, title, description, tags, identifier } = useDetailContext();
15
+
16
+ return (
17
+ <Flexbox align={'center'} gap={8} horizontal>
18
+ <AddGroupAgent mobile={mobile} />
19
+ {identifier && (
20
+ <ShareButton
21
+ meta={{
22
+ avatar: avatar,
23
+ desc: description,
24
+ hashtags: tags,
25
+ title: title,
26
+ url: urlJoin(OFFICIAL_URL, '/community/group_agent', identifier),
27
+ }}
28
+ />
29
+ )}
30
+ </Flexbox>
31
+ );
32
+ });
33
+
34
+ export default ActionButton;
@@ -0,0 +1,42 @@
1
+ import { Collapse } from '@lobehub/ui';
2
+ import { cssVar } from 'antd-style';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import { useDetailContext } from '../../DetailProvider';
7
+
8
+ const Summary = memo(() => {
9
+ const { description, summary } = useDetailContext();
10
+ const { t } = useTranslation('discover');
11
+
12
+ const displayDescription = summary || description || 'No description provided';
13
+
14
+ return (
15
+ <Collapse
16
+ defaultActiveKey={['summary']}
17
+ expandIconPlacement={'end'}
18
+ items={[
19
+ {
20
+ children: (
21
+ <p
22
+ style={{
23
+ color: cssVar.colorTextSecondary,
24
+ margin: 0,
25
+ }}
26
+ >
27
+ {displayDescription}
28
+ </p>
29
+ ),
30
+ key: 'summary',
31
+ label: t('groupAgents.details.summary.title', {
32
+ defaultValue: 'What can you use this group for?',
33
+ }),
34
+ },
35
+ ]}
36
+ size={'small'}
37
+ variant={'borderless'}
38
+ />
39
+ );
40
+ });
41
+
42
+ export default Summary;
@@ -0,0 +1,41 @@
1
+ import { Flexbox, ScrollShadow } from '@lobehub/ui';
2
+ import { memo } from 'react';
3
+
4
+ import { useQuery } from '@/hooks/useQuery';
5
+
6
+ import { GroupAgentNavKey } from '../Details/Nav';
7
+ import ActionButton from './ActionButton';
8
+ import Summary from './Summary';
9
+
10
+ const Sidebar = memo<{ mobile?: boolean }>(({ mobile }) => {
11
+ const { activeTab = GroupAgentNavKey.Overview } = useQuery() as { activeTab: GroupAgentNavKey };
12
+
13
+ if (mobile) {
14
+ return (
15
+ <Flexbox gap={32}>
16
+ <ActionButton mobile />
17
+ </Flexbox>
18
+ );
19
+ }
20
+
21
+ return (
22
+ <ScrollShadow
23
+ flex={'none'}
24
+ gap={32}
25
+ hideScrollBar
26
+ size={4}
27
+ style={{
28
+ maxHeight: 'calc(100vh - 76px)',
29
+ paddingBottom: 24,
30
+ position: 'sticky',
31
+ top: 16,
32
+ }}
33
+ width={360}
34
+ >
35
+ <ActionButton />
36
+ {activeTab !== GroupAgentNavKey.Overview && <Summary />}
37
+ </ScrollShadow>
38
+ );
39
+ });
40
+
41
+ export default Sidebar;
@@ -0,0 +1,104 @@
1
+ 'use client';
2
+
3
+ import { ExclamationCircleOutlined, FolderOpenOutlined } from '@ant-design/icons';
4
+ import { Button, FluentEmoji, Text } from '@lobehub/ui';
5
+ import { Result } from 'antd';
6
+ import { memo } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { useNavigate } from 'react-router-dom';
9
+
10
+ interface StatusPageProps {
11
+ status: 'unpublished' | 'archived' | 'deprecated';
12
+ }
13
+
14
+ const StatusPage = memo<StatusPageProps>(({ status }) => {
15
+ const navigate = useNavigate();
16
+ const { t } = useTranslation('discover');
17
+
18
+ const handleBackToMarket = () => {
19
+ navigate('/community');
20
+ };
21
+
22
+ // Unpublished status
23
+ if (status === 'unpublished') {
24
+ return (
25
+ <div
26
+ style={{
27
+ alignItems: 'center',
28
+ display: 'flex',
29
+ flex: 1,
30
+ justifyContent: 'center',
31
+ minHeight: '60vh',
32
+ padding: '20px',
33
+ }}
34
+ >
35
+ <Result
36
+ extra={
37
+ <Button onClick={handleBackToMarket} size={'large'} type="primary">
38
+ {t('groupAgents.status.backToMarket', { defaultValue: 'Back to Market' })}
39
+ </Button>
40
+ }
41
+ icon={<FluentEmoji emoji={'⌛'} size={96} type={'anim'} />}
42
+ subTitle={
43
+ <Text fontSize={16} type={'secondary'}>
44
+ {t('groupAgents.status.unpublished.subtitle', {
45
+ defaultValue:
46
+ 'This group agent is under review. Please contact support@lobehub.com if you have questions.',
47
+ })}
48
+ </Text>
49
+ }
50
+ title={
51
+ <Text fontSize={28} weight={'bold'}>
52
+ {t('groupAgents.status.unpublished.title', { defaultValue: 'Under Review' })}
53
+ </Text>
54
+ }
55
+ />
56
+ </div>
57
+ );
58
+ }
59
+
60
+ // Archived/Deprecated status
61
+ const isArchived = status === 'archived';
62
+ const statusKey = isArchived ? 'archived' : 'deprecated';
63
+ const statusIcon = isArchived ? (
64
+ <FolderOpenOutlined style={{ color: '#8c8c8c' }} />
65
+ ) : (
66
+ <ExclamationCircleOutlined style={{ color: '#ff4d4f' }} />
67
+ );
68
+
69
+ return (
70
+ <div
71
+ style={{
72
+ alignItems: 'center',
73
+ display: 'flex',
74
+ flex: 1,
75
+ justifyContent: 'center',
76
+ minHeight: '60vh',
77
+ padding: '20px',
78
+ }}
79
+ >
80
+ <Result
81
+ extra={
82
+ <Button onClick={handleBackToMarket} type="primary">
83
+ {t('groupAgents.status.backToMarket', { defaultValue: 'Back to Market' })}
84
+ </Button>
85
+ }
86
+ icon={statusIcon}
87
+ subTitle={
88
+ <div style={{ color: '#666', lineHeight: 1.6 }}>
89
+ <p>
90
+ {t(`groupAgents.status.${statusKey}.subtitle`, {
91
+ defaultValue: `This group agent has been ${statusKey}.`,
92
+ })}
93
+ </p>
94
+ </div>
95
+ }
96
+ title={t(`groupAgents.status.${statusKey}.title`, {
97
+ defaultValue: isArchived ? 'Archived' : 'Deprecated',
98
+ })}
99
+ />
100
+ </div>
101
+ );
102
+ });
103
+
104
+ export default StatusPage;