@lobehub/lobehub 2.0.0-next.298 → 2.0.0-next.299

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 (82) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/changelog/v1.json +9 -0
  3. package/package.json +2 -2
  4. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/Actions.tsx +4 -13
  5. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/Actions.tsx +4 -13
  6. package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/index.tsx +2 -9
  7. package/src/app/[variants]/(main)/agent/features/Conversation/ConversationArea.tsx +2 -2
  8. package/src/app/[variants]/(main)/agent/features/Conversation/Header/Tags/KnowledgeTag.tsx +3 -4
  9. package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/MentionList/types.ts +4 -2
  10. package/src/app/[variants]/(main)/community/(detail)/model/features/Sidebar/ActionButton/ChatWithModel.tsx +3 -8
  11. package/src/app/[variants]/(main)/community/(list)/assistant/features/MarketSourceSwitch.tsx +44 -23
  12. package/src/app/[variants]/(main)/community/(list)/features/SortButton/index.tsx +40 -19
  13. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/Actions.tsx +4 -13
  14. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/index.tsx +2 -9
  15. package/src/app/[variants]/(main)/group/features/Conversation/ConversationArea.tsx +2 -2
  16. package/src/app/[variants]/(main)/group/features/Conversation/Header/Tags/KnowledgeTag.tsx +3 -4
  17. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/AgentBuilderProvider.tsx +2 -2
  18. package/src/app/[variants]/(main)/group/profile/features/MemberProfile/MentionList/types.ts +4 -2
  19. package/src/app/[variants]/(main)/home/_layout/Body/Agent/Actions.tsx +3 -11
  20. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Group/Actions.tsx +3 -12
  21. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Group/Item.tsx +2 -9
  22. package/src/app/[variants]/(main)/home/_layout/Body/Agent/index.tsx +2 -9
  23. package/src/app/[variants]/(main)/home/_layout/Body/Project/index.tsx +2 -9
  24. package/src/app/[variants]/(main)/home/features/CommunityAgents/index.tsx +11 -13
  25. package/src/app/[variants]/(main)/home/features/FeaturedPlugins/index.tsx +11 -13
  26. package/src/app/[variants]/(main)/home/features/RecentPage/index.tsx +12 -14
  27. package/src/app/[variants]/(main)/home/features/RecentResource/index.tsx +12 -14
  28. package/src/app/[variants]/(main)/memory/contexts/features/ContextDropdown.tsx +5 -3
  29. package/src/app/[variants]/(main)/memory/experiences/features/ExperienceDropdown.tsx +5 -3
  30. package/src/app/[variants]/(main)/memory/identities/features/IdentityDropdown.tsx +5 -3
  31. package/src/app/[variants]/(main)/memory/preferences/features/PreferenceDropdown.tsx +5 -3
  32. package/src/app/[variants]/(main)/page/_layout/Body/Actions.tsx +3 -13
  33. package/src/app/[variants]/(main)/page/_layout/Body/index.tsx +2 -9
  34. package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +1 -1
  35. package/src/app/[variants]/(main)/settings/profile/features/SSOProvidersList/index.tsx +3 -3
  36. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/Actions.tsx +3 -11
  37. package/src/app/[variants]/(main)/settings/provider/ProviderMenu/List.tsx +12 -28
  38. package/src/app/[variants]/(main)/settings/provider/features/ModelList/DisabledModels.tsx +7 -8
  39. package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelTitle/index.tsx +18 -20
  40. package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/CollapseGroup/Actions.tsx +10 -14
  41. package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/List/Item/Actions.tsx +3 -13
  42. package/src/app/[variants]/share/t/[id]/SharedMessageList.tsx +2 -2
  43. package/src/business/server/lambda-routers/file.ts +1 -1
  44. package/src/features/AgentBuilder/AgentBuilderProvider.tsx +2 -2
  45. package/src/features/ChatInput/ActionBar/History/index.tsx +1 -1
  46. package/src/features/ChatInput/ActionBar/STT/common.tsx +1 -1
  47. package/src/features/ChatInput/ActionBar/Search/index.tsx +1 -1
  48. package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +1 -0
  49. package/src/features/ChatInput/ActionBar/components/Action.tsx +4 -8
  50. package/src/features/ChatInput/ActionBar/components/ActionDropdown.tsx +225 -37
  51. package/src/features/Conversation/ConversationProvider.tsx +2 -1
  52. package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +10 -6
  53. package/src/features/Conversation/Messages/AssistantGroup/Actions/index.tsx +10 -6
  54. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Intervention/ApprovalActions.tsx +11 -13
  55. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Intervention/ModeSelector.tsx +8 -10
  56. package/src/features/Conversation/Messages/Supervisor/Actions/index.tsx +10 -6
  57. package/src/features/Conversation/Messages/Task/Actions/index.tsx +10 -6
  58. package/src/features/Conversation/Messages/User/Actions/index.tsx +10 -6
  59. package/src/features/Conversation/StoreUpdater.tsx +1 -1
  60. package/src/features/Conversation/store/initialState.ts +3 -1
  61. package/src/features/Conversation/store/slices/data/action.ts +6 -5
  62. package/src/features/LibraryModal/AssignKnowledgeBase/Item/Action.tsx +23 -26
  63. package/src/features/ModelSwitchPanel/components/List/MultipleProvidersModelItem.tsx +16 -18
  64. package/src/features/ModelSwitchPanel/styles.ts +18 -1
  65. package/src/features/PageEditor/Copilot/AgentSelector/Actions.tsx +6 -13
  66. package/src/features/PageEditor/PageAgentProvider.tsx +2 -2
  67. package/src/features/PluginStore/InstalledList/List/Item/Action.tsx +33 -36
  68. package/src/features/PluginStore/McpList/List/Action.tsx +25 -28
  69. package/src/features/PluginStore/PluginList/List/Action.tsx +25 -28
  70. package/src/features/PluginTag/index.tsx +3 -4
  71. package/src/features/Portal/Artifacts/Body/Renderer/SVG.tsx +14 -11
  72. package/src/features/Portal/Thread/Chat/index.tsx +2 -2
  73. package/src/features/ProfileEditor/AgentTool.tsx +1 -1
  74. package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +21 -18
  75. package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +7 -13
  76. package/src/features/ResourceManager/components/Header/AddButton.tsx +4 -11
  77. package/src/features/User/UserPanel/LangButton.tsx +56 -44
  78. package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +1 -1
  79. package/src/services/document/index.ts +11 -1
  80. package/src/store/page/slices/crud/action.ts +0 -48
  81. package/src/styles/global.ts +2 -2
  82. package/src/types/shim-lobe-ui.d.ts +7 -0
@@ -1,9 +1,8 @@
1
- import { Dropdown } from '@lobehub/ui';
1
+ import { DropdownMenu, type DropdownMenuCheckboxItem } from '@lobehub/ui';
2
2
  import { ArrowDownAZ } from 'lucide-react';
3
3
  import { memo, useMemo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
- import { type MenuProps } from '@/components/Menu';
7
6
  import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
8
7
 
9
8
  import ActionIconWithChevron from './ActionIconWithChevron';
@@ -22,30 +21,34 @@ const SortDropdown = memo(() => {
22
21
  [t],
23
22
  );
24
23
 
25
- const menuItems: MenuProps['items'] = useMemo(
24
+ const selectedKey = sorter || 'createdAt';
25
+
26
+ const menuItems = useMemo<DropdownMenuCheckboxItem[]>(
26
27
  () =>
27
- sortOptions.map((option) => ({
28
- key: option.key,
29
- label: option.label,
30
- onClick: () => setSorter(option.key as 'name' | 'createdAt' | 'size'),
31
- })),
32
- [setSorter, sortOptions],
28
+ sortOptions.map(
29
+ (option): DropdownMenuCheckboxItem => ({
30
+ checked: option.key === selectedKey,
31
+ closeOnClick: true,
32
+ key: option.key,
33
+ label: option.label,
34
+ onCheckedChange: (checked: boolean) => {
35
+ if (checked) {
36
+ setSorter(option.key as 'name' | 'createdAt' | 'size');
37
+ }
38
+ },
39
+ type: 'checkbox',
40
+ }),
41
+ ),
42
+ [selectedKey, setSorter, sortOptions],
33
43
  );
34
44
 
35
45
  const currentSortLabel =
36
46
  sortOptions.find((option) => option.key === sorter)?.label || t('FileManager.sort.dateAdded');
37
47
 
38
48
  return (
39
- <Dropdown
40
- arrow={false}
41
- menu={{
42
- items: menuItems,
43
- selectable: true,
44
- selectedKeys: [sorter || 'createdAt'],
45
- }}
46
- >
49
+ <DropdownMenu items={menuItems}>
47
50
  <ActionIconWithChevron icon={ArrowDownAZ} title={currentSortLabel} />
48
- </Dropdown>
51
+ </DropdownMenu>
49
52
  );
50
53
  });
51
54
 
@@ -1,5 +1,5 @@
1
- import { Dropdown, Icon } from '@lobehub/ui';
2
- import { Grid3x3Icon, ListIcon } from 'lucide-react';
1
+ import { DropdownMenu, Icon } from '@lobehub/ui';
2
+ import { Check, Grid3x3Icon, ListIcon } from 'lucide-react';
3
3
  import { memo, useMemo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
@@ -23,33 +23,27 @@ const ViewSwitcher = memo(() => {
23
23
  const menuItems: MenuProps['items'] = useMemo(
24
24
  () => [
25
25
  {
26
+ extra: viewMode === 'list' ? <Icon icon={Check} /> : undefined,
26
27
  icon: <Icon icon={ListIcon} />,
27
28
  key: 'list',
28
29
  label: t('FileManager.view.list'),
29
30
  onClick: () => setViewMode('list'),
30
31
  },
31
32
  {
33
+ extra: viewMode === 'masonry' ? <Icon icon={Check} /> : undefined,
32
34
  icon: <Icon icon={Grid3x3Icon} />,
33
35
  key: 'masonry',
34
36
  label: t('FileManager.view.masonry'),
35
37
  onClick: () => setViewMode('masonry'),
36
38
  },
37
39
  ],
38
- [setViewMode, t],
40
+ [setViewMode, t, viewMode],
39
41
  );
40
42
 
41
43
  return (
42
- <Dropdown
43
- arrow={false}
44
- menu={{
45
- items: menuItems,
46
- selectable: true,
47
- selectedKeys: [viewMode],
48
- }}
49
- placement="bottomRight"
50
- >
44
+ <DropdownMenu items={menuItems} placement="bottomRight">
51
45
  <ActionIconWithChevron icon={currentViewIcon} title={currentViewLabel} />
52
- </Dropdown>
46
+ </DropdownMenu>
53
47
  );
54
48
  });
55
49
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { FILE_URL } from '@lobechat/business-const';
4
4
  import { Notion } from '@lobehub/icons';
5
- import { Button, Dropdown, Icon, type MenuProps } from '@lobehub/ui';
5
+ import { Button, DropdownMenu, Icon, type MenuProps } from '@lobehub/ui';
6
6
  import { Upload } from 'antd';
7
7
  import { FilePenLine, FileUp, FolderIcon, FolderUp, Link, Plus } from 'lucide-react';
8
8
  import { useCallback, useMemo } from 'react';
@@ -211,18 +211,11 @@ const AddButton = () => {
211
211
 
212
212
  return (
213
213
  <>
214
- <Dropdown menu={{ items }} placement="bottomRight" trigger={['hover']}>
215
- <Button
216
- icon={Plus}
217
- onClick={(e) => {
218
- // Prevent default button behavior that might interfere with dropdown
219
- e.stopPropagation();
220
- }}
221
- type="primary"
222
- >
214
+ <DropdownMenu items={items} placement="bottomRight" trigger="both">
215
+ <Button data-no-highlight icon={Plus} type="primary">
223
216
  {t('addLibrary')}
224
217
  </Button>
225
- </Dropdown>
218
+ </DropdownMenu>
226
219
  <GuideModal
227
220
  cancelText={t('header.actions.notionGuide.cancel')}
228
221
  cover={<GuideVideo height={269} src={FILE_URL.importFromNotionGuide} width={358} />}
@@ -1,74 +1,86 @@
1
- import { ActionIcon, Dropdown, DropdownProps, Flexbox, Text } from '@lobehub/ui';
1
+ import {
2
+ ActionIcon,
3
+ DropdownMenu,
4
+ type DropdownMenuCheckboxItem,
5
+ type DropdownMenuProps,
6
+ Flexbox,
7
+ Text,
8
+ } from '@lobehub/ui';
2
9
  import { Languages } from 'lucide-react';
3
10
  import { memo, useMemo } from 'react';
4
11
  import { useTranslation } from 'react-i18next';
5
12
 
6
- import { type MenuProps } from '@/components/Menu';
7
13
  import { localeOptions } from '@/locales/resources';
8
14
  import { useGlobalStore } from '@/store/global';
9
15
  import { globalGeneralSelectors } from '@/store/global/selectors';
10
- import { type LocaleMode } from '@/types/locale';
11
16
 
12
- const LangButton = memo<{ placement?: DropdownProps['placement']; size?: number }>(
17
+ const LangButton = memo<{ placement?: DropdownMenuProps['placement']; size?: number }>(
13
18
  ({ placement, size }) => {
14
19
  const [language, switchLocale] = useGlobalStore((s) => [
15
20
  globalGeneralSelectors.language(s),
16
21
  s.switchLocale,
17
22
  ]);
18
23
 
19
- const handleLangChange = (value: LocaleMode) => {
20
- switchLocale(value);
21
- };
22
-
23
24
  const { t } = useTranslation(['setting', 'common']);
24
25
 
25
- const items: MenuProps['items'] = useMemo(
26
- () => [
27
- {
28
- key: 'auto',
29
- label: (
30
- <Flexbox gap={4}>
31
- <Text style={{ lineHeight: 1.2 }}>{t('settingCommon.lang.autoMode')}</Text>
32
- <Text fontSize={12} style={{ lineHeight: 1.2 }} type={'secondary'}>
33
- {t(`lang.auto` as any, { ns: 'common' })}
34
- </Text>
35
- </Flexbox>
36
- ),
37
- onClick: () => handleLangChange('auto'),
26
+ const items = useMemo<DropdownMenuCheckboxItem[]>(() => {
27
+ const autoItem: DropdownMenuCheckboxItem = {
28
+ checked: language === 'auto',
29
+ closeOnClick: true,
30
+ key: 'auto',
31
+ label: (
32
+ <Flexbox gap={4}>
33
+ <Text style={{ lineHeight: 1.2 }}>{t('settingCommon.lang.autoMode')}</Text>
34
+ <Text fontSize={12} style={{ lineHeight: 1.2 }} type={'secondary'}>
35
+ {t(`lang.auto` as any, { ns: 'common' })}
36
+ </Text>
37
+ </Flexbox>
38
+ ),
39
+ onCheckedChange: (checked: boolean) => {
40
+ if (checked) {
41
+ switchLocale('auto');
42
+ }
38
43
  },
39
- ...localeOptions.map((item) => ({
40
- key: item.value,
41
- label: (
42
- <Flexbox gap={4} key={item.value}>
43
- <Text style={{ lineHeight: 1.2 }}>{item.label}</Text>
44
- <Text fontSize={12} style={{ lineHeight: 1.2 }} type={'secondary'}>
45
- {t(`lang.${item.value}` as any, { ns: 'common' })}
46
- </Text>
47
- </Flexbox>
48
- ),
49
- onClick: () => handleLangChange(item.value),
50
- })),
51
- ],
52
- [t],
53
- );
44
+ type: 'checkbox',
45
+ };
46
+
47
+ const localeItems = localeOptions.map<DropdownMenuCheckboxItem>((item) => ({
48
+ checked: language === item.value,
49
+ closeOnClick: true,
50
+ key: item.value,
51
+ label: (
52
+ <Flexbox gap={4} key={item.value}>
53
+ <Text style={{ lineHeight: 1.2 }}>{item.label}</Text>
54
+ <Text fontSize={12} style={{ lineHeight: 1.2 }} type={'secondary'}>
55
+ {t(`lang.${item.value}` as any, { ns: 'common' })}
56
+ </Text>
57
+ </Flexbox>
58
+ ),
59
+ onCheckedChange: (checked: boolean) => {
60
+ if (checked) {
61
+ switchLocale(item.value);
62
+ }
63
+ },
64
+ type: 'checkbox',
65
+ }));
66
+
67
+ return [autoItem, ...localeItems];
68
+ }, [language, switchLocale, t]);
54
69
 
55
70
  return (
56
- <Dropdown
57
- arrow={false}
58
- menu={{
59
- items,
60
- selectable: true,
61
- selectedKeys: [language],
71
+ <DropdownMenu
72
+ items={items}
73
+ placement={placement}
74
+ popupProps={{
62
75
  style: {
63
76
  maxHeight: 360,
64
77
  minWidth: 240,
65
78
  overflow: 'auto',
66
79
  },
67
80
  }}
68
- placement={placement}
69
81
  >
70
82
  <ActionIcon icon={Languages} size={size || { blockSize: 32, size: 16 }} />
71
- </Dropdown>
83
+ </DropdownMenu>
72
84
  );
73
85
  },
74
86
  );
@@ -151,7 +151,7 @@ export const MarketAuthProvider = ({ children, isDesktop }: MarketAuthProviderPr
151
151
  null,
152
152
  );
153
153
  const [pendingProfileSuccessCallback, setPendingProfileSuccessCallback] = useState<
154
- ((profile: MarketUserProfile) => void) | null
154
+ ((_profile: MarketUserProfile) => void) | null
155
155
  >(null);
156
156
 
157
157
  // 订阅 user store 的初始化状态,当 isUserStateInit 为 true 时,settings 数据已加载完成
@@ -2,6 +2,8 @@ import { type DocumentItem } from '@lobechat/database/schemas';
2
2
 
3
3
  import { lambdaClient } from '@/libs/trpc/client';
4
4
 
5
+ import { abortableRequest } from '../utils/abortableRequest';
6
+
5
7
  export interface CreateDocumentParams {
6
8
  content?: string;
7
9
  editorData: string;
@@ -41,7 +43,15 @@ export class DocumentService {
41
43
  return lambdaClient.document.queryDocuments.query(params);
42
44
  }
43
45
 
44
- async getDocumentById(id: string): Promise<DocumentItem | undefined> {
46
+ async getDocumentById(id: string, uniqueKey?: string): Promise<DocumentItem | undefined> {
47
+ if (uniqueKey) {
48
+ // Use fixed key so switching documents cancels the previous request
49
+ // This prevents race conditions where old document's data overwrites new document's editor
50
+ return abortableRequest.execute(uniqueKey, async (signal) =>
51
+ lambdaClient.document.getDocumentById.query({ id }, { signal }),
52
+ );
53
+ }
54
+
45
55
  return lambdaClient.document.getDocumentById.query({ id });
46
56
  }
47
57
 
@@ -47,10 +47,6 @@ export interface CrudAction {
47
47
  * Duplicate an existing page
48
48
  */
49
49
  duplicatePage: (pageId: string) => Promise<{ [key: string]: any; id: string }>;
50
- /**
51
- * Fetch full page detail by ID and update documents array
52
- */
53
- fetchPageDetail: (pageId: string) => Promise<void>;
54
50
  navigateToPage: (pageId: string | null) => void;
55
51
  /**
56
52
  * Remove a page (deletes from documents table)
@@ -240,50 +236,6 @@ export const createCrudSlice: StateCreator<
240
236
  return newPage;
241
237
  },
242
238
 
243
- fetchPageDetail: async (pageId) => {
244
- try {
245
- const document = await documentService.getDocumentById(pageId);
246
-
247
- if (!document) {
248
- console.warn(`[fetchPageDetail] Page not found: ${pageId}`);
249
- return;
250
- }
251
-
252
- const fullPage: LobeDocument = {
253
- content: document.content || null,
254
- createdAt: document.createdAt ? new Date(document.createdAt) : new Date(),
255
- editorData:
256
- typeof document.editorData === 'string'
257
- ? JSON.parse(document.editorData)
258
- : document.editorData || null,
259
- fileType: document.fileType,
260
- filename: document.title || document.filename || 'Untitled',
261
- id: document.id,
262
- metadata: document.metadata || {},
263
- source: 'document',
264
- sourceType: DocumentSourceType.EDITOR,
265
- title: document.title || '',
266
- totalCharCount: document.content?.length || 0,
267
- totalLineCount: 0,
268
- updatedAt: document.updatedAt ? new Date(document.updatedAt) : new Date(),
269
- };
270
-
271
- // Update document via internal dispatch
272
- const { documents } = get();
273
- if (documents?.some((doc) => doc.id === pageId)) {
274
- get().internal_dispatchDocuments({
275
- document: fullPage,
276
- id: pageId,
277
- type: 'updateDocument',
278
- });
279
- } else {
280
- get().internal_dispatchDocuments({ document: fullPage, type: 'addDocument' });
281
- }
282
- } catch (error) {
283
- console.error('[fetchPageDetail] Failed to fetch page:', error);
284
- }
285
- },
286
-
287
239
  navigateToPage: (pageId) => {
288
240
  if (!pageId) {
289
241
  get().navigate?.('/page');
@@ -55,8 +55,8 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
55
55
  -webkit-app-region: no-drag;
56
56
  }
57
57
 
58
- .${CLASSNAMES.ContextTrigger}[data-popup-open],
59
- .${CLASSNAMES.DropdownMenuTrigger}[data-popup-open] {
58
+ .${CLASSNAMES.ContextTrigger}[data-popup-open]:not([data-no-highlight]),
59
+ .${CLASSNAMES.DropdownMenuTrigger}[data-popup-open]:not([data-no-highlight]) {
60
60
  background: ${token.colorFillTertiary};
61
61
  }
62
62
  `;
@@ -0,0 +1,7 @@
1
+ declare module '@lobehub/ui' {
2
+ export interface DropdownMenuProps {
3
+ 'data-no-highlight'?: boolean;
4
+ }
5
+ }
6
+
7
+ export {};