@lobehub/lobehub 2.0.0-next.226 → 2.0.0-next.228

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 (51) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +50 -0
  3. package/CLAUDE.md +4 -0
  4. package/changelog/v1.json +18 -0
  5. package/docs/self-hosting/server-database/docker-compose.mdx +11 -0
  6. package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +11 -0
  7. package/package.json +2 -2
  8. package/packages/model-bank/src/aiModels/lobehub.ts +28 -0
  9. package/packages/utils/src/platform.test.ts +26 -1
  10. package/packages/utils/src/platform.ts +22 -0
  11. package/src/app/[variants]/(main)/_layout/DesktopLayoutContainer/style.ts +4 -0
  12. package/src/app/[variants]/(main)/_layout/DesktopLayoutContainer.tsx +8 -4
  13. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Header/Agent/SwitchPanel.tsx +37 -23
  14. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/Editing.tsx +4 -7
  15. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Editing.tsx +4 -7
  16. package/src/app/[variants]/(main)/chat/features/Conversation/Header/HeaderActions/index.tsx +3 -13
  17. package/src/app/[variants]/(main)/chat/features/Conversation/Header/WorkingDirectory/index.tsx +2 -4
  18. package/src/app/[variants]/(main)/community/(list)/model/features/List/Item.tsx +1 -3
  19. package/src/app/[variants]/(main)/group/_layout/Sidebar/GroupConfig/AgentProfilePopup.tsx +3 -5
  20. package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/Agent/SwitchPanel.tsx +4 -6
  21. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/Editing.tsx +4 -7
  22. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Editing.tsx +4 -7
  23. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentGroupItem/Editing.tsx +4 -7
  24. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/Editing.tsx +4 -7
  25. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Group/Editing.tsx +4 -7
  26. package/src/app/[variants]/(main)/home/_layout/Body/Project/List/Editing.tsx +4 -7
  27. package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ModelSelect/ImageModelItem.tsx +1 -6
  28. package/src/app/[variants]/(main)/image/_layout/Topics/TopicItem.tsx +3 -4
  29. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/Editing.tsx +5 -7
  30. package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/Editing.tsx +4 -7
  31. package/src/business/client/hooks/useBusinessErrorAlertConfig.ts +9 -0
  32. package/src/business/client/hooks/useBusinessErrorContent.ts +13 -0
  33. package/src/business/server/lambda-routers/file.ts +12 -0
  34. package/src/components/ManifestPreviewer/index.tsx +2 -5
  35. package/src/components/TipGuide/index.tsx +3 -4
  36. package/src/features/ChatInput/ActionBar/Search/index.tsx +1 -1
  37. package/src/features/ChatInput/ActionBar/components/Action.tsx +5 -1
  38. package/src/features/ChatInput/ActionBar/components/ActionPopover.tsx +27 -23
  39. package/src/features/ChatMiniMap/MinimapIndicator.tsx +2 -4
  40. package/src/features/ChatMiniMap/index.tsx +16 -14
  41. package/src/features/Conversation/Error/index.tsx +13 -3
  42. package/src/features/Conversation/Markdown/plugins/Mention/Render.tsx +2 -4
  43. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/Intervention/ApprovalActions.tsx +2 -3
  44. package/src/features/Conversation/Messages/components/Extras/Usage/UsageDetail/index.tsx +3 -4
  45. package/src/features/LocalFile/LocalFile.tsx +4 -5
  46. package/src/features/MCPPluginDetail/Deployment/index.tsx +13 -4
  47. package/src/features/MCPPluginDetail/Score/TotalScore.tsx +10 -5
  48. package/src/features/ModelSwitchPanel/index.tsx +2 -4
  49. package/src/features/PageEditor/Copilot/Toolbar.tsx +5 -8
  50. package/src/server/routers/lambda/__tests__/file.test.ts +7 -7
  51. package/src/server/routers/lambda/file.ts +12 -3
@@ -1,5 +1,5 @@
1
- import { Button, Dropdown, Flexbox } from '@lobehub/ui';
2
- import { Input, Popover, Space } from 'antd';
1
+ import { Button, Dropdown, Flexbox, Popover } from '@lobehub/ui';
2
+ import { Input, Space } from 'antd';
3
3
  import { ChevronDown } from 'lucide-react';
4
4
  import { memo, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
@@ -80,7 +80,6 @@ const ApprovalActions = memo<ApprovalActionsProps>(
80
80
  return (
81
81
  <Flexbox gap={8} horizontal>
82
82
  <Popover
83
- arrow={false}
84
83
  content={
85
84
  <Flexbox gap={12} style={{ width: 400 }}>
86
85
  <Flexbox align={'center'} horizontal justify={'space-between'}>
@@ -1,6 +1,6 @@
1
1
  import { type ModelPerformance, type ModelUsage } from '@lobechat/types';
2
- import { Center, Flexbox, Icon } from '@lobehub/ui';
3
- import { Divider, Popover } from 'antd';
2
+ import { Center, Flexbox, Icon, Popover } from '@lobehub/ui';
3
+ import { Divider } from 'antd';
4
4
  import { cssVar } from 'antd-style';
5
5
  import { BadgeCent, CoinsIcon } from 'lucide-react';
6
6
  import { memo } from 'react';
@@ -132,7 +132,6 @@ const TokenDetail = memo<TokenDetailProps>(({ usage, performance, model, provide
132
132
 
133
133
  return (
134
134
  <Popover
135
- arrow={false}
136
135
  content={
137
136
  <Flexbox gap={8} style={{ minWidth: 200 }}>
138
137
  {modelCard && <ModelCard {...modelCard} provider={provider} />}
@@ -214,7 +213,7 @@ const TokenDetail = memo<TokenDetailProps>(({ usage, performance, model, provide
214
213
  </Flexbox>
215
214
  }
216
215
  placement={'top'}
217
- trigger={['hover']}
216
+ trigger="hover"
218
217
  >
219
218
  <Center
220
219
  gap={2}
@@ -1,5 +1,5 @@
1
- import { Button, Flexbox } from '@lobehub/ui';
2
- import { Popover, Space } from 'antd';
1
+ import { Button, Flexbox, Popover } from '@lobehub/ui';
2
+ import { Space } from 'antd';
3
3
  import { createStaticStyles, cssVar } from 'antd-style';
4
4
  import { ExternalLink, FolderOpen } from 'lucide-react';
5
5
  import React from 'react';
@@ -98,12 +98,11 @@ export const LocalFile = ({ name, path, isDirectory = false }: LocalFileProps) =
98
98
 
99
99
  return (
100
100
  <Popover
101
- arrow={false}
102
101
  content={popoverContent}
103
102
  styles={{
104
- container: { padding: 0 },
103
+ content: { padding: 0 },
105
104
  }}
106
- trigger={['hover']}
105
+ trigger="hover"
107
106
  >
108
107
  {fileContent}
109
108
  </Popover>
@@ -1,7 +1,17 @@
1
1
  import { SiApple, SiLinux } from '@icons-pack/react-simple-icons';
2
2
  import { Microsoft } from '@lobehub/icons';
3
- import { ActionIcon, Block, Collapse, Empty, Flexbox, Icon, Snippet, Tag } from '@lobehub/ui';
4
- import { Divider, Popover, Steps } from 'antd';
3
+ import {
4
+ ActionIcon,
5
+ Block,
6
+ Collapse,
7
+ Empty,
8
+ Flexbox,
9
+ Icon,
10
+ Popover,
11
+ Snippet,
12
+ Tag,
13
+ } from '@lobehub/ui';
14
+ import { Divider, Steps } from 'antd';
5
15
  import { createStaticStyles, cssVar } from 'antd-style';
6
16
  import { startCase } from 'es-toolkit/compat';
7
17
  import {
@@ -220,7 +230,6 @@ const Deployment = memo<{ mobile?: boolean }>(({ mobile }) => {
220
230
  </span>
221
231
  {dep.installInstructions && (
222
232
  <Popover
223
- arrow={false}
224
233
  content={
225
234
  <Flexbox gap={8}>
226
235
  <Descriptions
@@ -265,7 +274,7 @@ const Deployment = memo<{ mobile?: boolean }>(({ mobile }) => {
265
274
  )}
266
275
  </Flexbox>
267
276
  }
268
- trigger={['hover']}
277
+ trigger="hover"
269
278
  >
270
279
  <ActionIcon
271
280
  color={cssVar.colorTextDescription}
@@ -1,5 +1,5 @@
1
- import { Block, Center, Flexbox } from '@lobehub/ui';
2
- import { Popover, Progress } from 'antd';
1
+ import { Block, Center, Flexbox, Popover } from '@lobehub/ui';
2
+ import { Progress } from 'antd';
3
3
  import { createStaticStyles, cssVar } from 'antd-style';
4
4
  import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
@@ -248,10 +248,15 @@ const TotalScore = memo<TotalScoreProps>(({ scoreResult, scoreItems = [], isVali
248
248
 
249
249
  <div className={styles.progressContainer}>
250
250
  <Popover
251
- arrow={false}
252
- content={renderTooltipContent()}
251
+ content={
252
+ <div>
253
+ <div style={{ fontWeight: 'bold', marginBottom: 8 }}>
254
+ {t('mcp.details.totalScore.popover.title')}
255
+ </div>
256
+ {renderTooltipContent()}
257
+ </div>
258
+ }
253
259
  placement="bottom"
254
- title={t('mcp.details.totalScore.popover.title')}
255
260
  trigger={['hover', 'click']}
256
261
  >
257
262
  <Progress
@@ -1,5 +1,4 @@
1
- import { TooltipGroup } from '@lobehub/ui';
2
- import { Popover } from 'antd';
1
+ import { Popover, TooltipGroup } from '@lobehub/ui';
3
2
  import { memo, useCallback, useState } from 'react';
4
3
 
5
4
  import { PanelContent } from './components/PanelContent';
@@ -32,9 +31,8 @@ const ModelSwitchPanel = memo<ModelSwitchPanelProps>(
32
31
  return (
33
32
  <TooltipGroup>
34
33
  <Popover
35
- arrow={false}
36
34
  classNames={{
37
- container: styles.container,
35
+ content: styles.container,
38
36
  }}
39
37
  content={
40
38
  <PanelContent
@@ -1,5 +1,4 @@
1
- import { ActionIcon, Block, Flexbox } from '@lobehub/ui';
2
- import { Popover } from 'antd';
1
+ import { ActionIcon, Block, Flexbox, Popover } from '@lobehub/ui';
3
2
  import { createStaticStyles, cx } from 'antd-style';
4
3
  import { ChevronsUpDownIcon, Clock3Icon, PanelRightCloseIcon, PlusIcon } from 'lucide-react';
5
4
  import { Suspense, memo, useMemo, useState } from 'react';
@@ -108,7 +107,6 @@ const AgentSelector = memo<AgentSelectorProps>(({ agentId, onAgentChange }) => {
108
107
 
109
108
  return (
110
109
  <Popover
111
- arrow={false}
112
110
  content={
113
111
  <Suspense fallback={<SkeletonList rows={6} />}>
114
112
  <AgentModalProvider>
@@ -120,12 +118,12 @@ const AgentSelector = memo<AgentSelectorProps>(({ agentId, onAgentChange }) => {
120
118
  open={open}
121
119
  placement="bottomLeft"
122
120
  styles={{
123
- container: {
121
+ content: {
124
122
  padding: 0,
125
123
  width: 240,
126
124
  },
127
125
  }}
128
- trigger={['click']}
126
+ trigger="click"
129
127
  >
130
128
  <Block
131
129
  align={'center'}
@@ -197,7 +195,6 @@ const CopilotToolbar = memo<CopilotToolbarProps>(({ agentId, isHovered }) => {
197
195
  />
198
196
  {!hideHistory && (
199
197
  <Popover
200
- arrow={false}
201
198
  content={
202
199
  <Flexbox
203
200
  gap={4}
@@ -224,12 +221,12 @@ const CopilotToolbar = memo<CopilotToolbarProps>(({ agentId, isHovered }) => {
224
221
  open={topicPopoverOpen}
225
222
  placement="bottomRight"
226
223
  styles={{
227
- container: {
224
+ content: {
228
225
  padding: 0,
229
226
  width: 240,
230
227
  },
231
228
  }}
232
- trigger={['click']}
229
+ trigger="click"
233
230
  >
234
231
  <ActionIcon icon={Clock3Icon} size={DESKTOP_HEADER_ICON_SIZE} />
235
232
  </Popover>
@@ -273,7 +273,7 @@ describe('fileRouter', () => {
273
273
  );
274
274
  });
275
275
 
276
- it('should throw error when getFileMetadata fails and input size is less than 1', async () => {
276
+ it('should throw error when getFileMetadata fails and input size is negative', async () => {
277
277
  mockFileModelCheckHash.mockResolvedValue({ isExist: false });
278
278
  mockFileServiceGetFileMetadata.mockRejectedValue(new Error('File not found in S3'));
279
279
 
@@ -282,11 +282,11 @@ describe('fileRouter', () => {
282
282
  hash: 'test-hash',
283
283
  fileType: 'text',
284
284
  name: 'test.txt',
285
- size: 0,
285
+ size: -1,
286
286
  url: 'files/non-existent.txt',
287
287
  metadata: {},
288
288
  }),
289
- ).rejects.toThrow('File size must be at least 1 byte');
289
+ ).rejects.toThrow('File size cannot be negative');
290
290
  });
291
291
 
292
292
  it('should use input size when getFileMetadata returns contentLength less than 1', async () => {
@@ -315,10 +315,10 @@ describe('fileRouter', () => {
315
315
  );
316
316
  });
317
317
 
318
- it('should throw error when both getFileMetadata contentLength and input size are less than 1', async () => {
318
+ it('should throw error when both getFileMetadata contentLength and input size are negative', async () => {
319
319
  mockFileModelCheckHash.mockResolvedValue({ isExist: false });
320
320
  mockFileServiceGetFileMetadata.mockResolvedValue({
321
- contentLength: 0,
321
+ contentLength: -1,
322
322
  contentType: 'text/plain',
323
323
  });
324
324
 
@@ -327,11 +327,11 @@ describe('fileRouter', () => {
327
327
  hash: 'test-hash',
328
328
  fileType: 'text',
329
329
  name: 'test.txt',
330
- size: 0,
330
+ size: -1,
331
331
  url: 'files/test.txt',
332
332
  metadata: {},
333
333
  }),
334
- ).rejects.toThrow('File size must be at least 1 byte');
334
+ ).rejects.toThrow('File size cannot be negative');
335
335
  });
336
336
  });
337
337
 
@@ -1,6 +1,7 @@
1
1
  import { TRPCError } from '@trpc/server';
2
2
  import { z } from 'zod';
3
3
 
4
+ import { businessFileUploadCheck } from '@/business/server/lambda-routers/file';
4
5
  import { checkFileStorageUsage } from '@/business/server/trpc-middlewares/lambda';
5
6
  import { serverDBEnv } from '@/config/db';
6
7
  import { AsyncTaskModel } from '@/database/models/asyncTask';
@@ -74,8 +75,16 @@ export const fileRouter = router({
74
75
  // If metadata fetch fails, use original size from input
75
76
  }
76
77
 
77
- if (actualSize < 1) {
78
- throw new TRPCError({ code: 'BAD_REQUEST', message: 'File size must be at least 1 byte' });
78
+ await businessFileUploadCheck({
79
+ actualSize,
80
+ clientIp: ctx.clientIp ?? undefined,
81
+ inputSize: input.size,
82
+ url: input.url,
83
+ userId: ctx.userId,
84
+ });
85
+
86
+ if (actualSize < 0) {
87
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'File size cannot be negative' });
79
88
  }
80
89
 
81
90
  const { id } = await ctx.fileModel.create(
@@ -367,7 +376,7 @@ export const fileRouter = router({
367
376
 
368
377
  if (!file) return;
369
378
 
370
- // delele the file from remove from S3 if it is not used by other files
379
+ // delete the file from S3 if it is not used by other files
371
380
  await ctx.fileService.deleteFile(file.url!);
372
381
  }),
373
382