@lobehub/lobehub 2.0.0-next.188 → 2.0.0-next.189

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 (68) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/e2e/CLAUDE.md +109 -2
  4. package/e2e/docs/llm-mock.md +68 -0
  5. package/e2e/docs/local-setup.md +354 -0
  6. package/e2e/docs/testing-tips.md +94 -0
  7. package/e2e/src/features/journeys/agent/agent-conversation.feature +0 -32
  8. package/e2e/src/mocks/llm/index.ts +6 -6
  9. package/e2e/src/steps/agent/conversation.steps.ts +3 -471
  10. package/package.json +2 -2
  11. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/Actions.tsx +4 -13
  12. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/index.tsx +23 -29
  13. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/useDropdownMenu.tsx +3 -3
  14. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Actions.tsx +4 -13
  15. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/index.tsx +10 -18
  16. package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/useDropdownMenu.tsx +3 -3
  17. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Sidebar/ActionButton/AddAgent.tsx +47 -27
  18. package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +4 -3
  19. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/Actions.tsx +4 -13
  20. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/index.tsx +23 -29
  21. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/useDropdownMenu.tsx +3 -3
  22. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Actions.tsx +4 -13
  23. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/index.tsx +10 -18
  24. package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/useDropdownMenu.tsx +3 -3
  25. package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/TopicSelector.tsx +18 -20
  26. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentGroupItem/index.tsx +19 -25
  27. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/index.tsx +21 -26
  28. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Item/Actions.tsx +4 -13
  29. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Item/useDropdownMenu.tsx +3 -3
  30. package/src/app/[variants]/(main)/home/_layout/Body/Project/List/Actions.tsx +4 -13
  31. package/src/app/[variants]/(main)/home/_layout/Body/Project/List/Item.tsx +8 -15
  32. package/src/app/[variants]/(main)/home/_layout/Body/Project/List/useDropdownMenu.tsx +3 -3
  33. package/src/app/[variants]/(main)/home/_layout/Header/components/AddButton.tsx +3 -4
  34. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/Actions.tsx +4 -13
  35. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/index.tsx +13 -20
  36. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/useDropdownMenu.tsx +3 -3
  37. package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/Actions.tsx +4 -13
  38. package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/index.tsx +16 -23
  39. package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/useDropdownMenu.tsx +3 -3
  40. package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +4 -6
  41. package/src/features/AgentBuilder/TopicSelector.tsx +18 -17
  42. package/src/features/Conversation/ChatItem/style.ts +7 -0
  43. package/src/features/Conversation/Messages/Assistant/Actions/Error.tsx +1 -3
  44. package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +37 -16
  45. package/src/features/Conversation/Messages/AssistantGroup/Actions/index.tsx +36 -17
  46. package/src/features/Conversation/Messages/Supervisor/Actions/index.tsx +36 -17
  47. package/src/features/Conversation/Messages/Task/Actions/Error.tsx +1 -3
  48. package/src/features/Conversation/Messages/Task/Actions/index.tsx +31 -15
  49. package/src/features/Conversation/Messages/User/Actions/index.tsx +1 -1
  50. package/src/features/Conversation/Messages/index.tsx +8 -59
  51. package/src/features/Conversation/components/ShareMessageModal/index.tsx +1 -1
  52. package/src/features/Conversation/hooks/useChatItemContextMenu.tsx +313 -83
  53. package/src/features/NavPanel/components/NavItem.tsx +33 -3
  54. package/src/features/PageEditor/Copilot/TopicSelector/Actions.tsx +6 -14
  55. package/src/features/PageEditor/Copilot/TopicSelector/TopicItem.tsx +1 -0
  56. package/src/features/PageEditor/Copilot/TopicSelector/useDropdownMenu.tsx +6 -3
  57. package/src/features/ResourceManager/components/Explorer/ItemDropdown/DropdownMenu.tsx +12 -35
  58. package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -8
  59. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +162 -160
  60. package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/index.tsx +16 -8
  61. package/src/features/ResourceManager/components/Explorer/ToolBar/ActionIconWithChevron.tsx +4 -3
  62. package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +6 -12
  63. package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +8 -8
  64. package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +8 -11
  65. package/src/features/ResourceManager/components/Tree/index.tsx +121 -122
  66. package/src/layout/GlobalProvider/index.tsx +5 -2
  67. package/src/styles/global.ts +6 -0
  68. package/src/features/Conversation/components/ContextMenu.tsx +0 -418
@@ -1,10 +1,16 @@
1
1
  import { type AssistantContentBlock, type UIChatMessage } from '@lobechat/types';
2
- import { ActionIconGroup } from '@lobehub/ui';
2
+ import { ActionIconGroup, createRawModal } from '@lobehub/ui';
3
3
  import type { ActionIconGroupEvent, ActionIconGroupItemType } from '@lobehub/ui';
4
- import { memo, useCallback, useMemo, useState } from 'react';
5
-
6
- import ShareMessageModal from '../../../components/ShareMessageModal';
7
- import { messageStateSelectors, useConversationStore } from '../../../store';
4
+ import { memo, useCallback, useMemo } from 'react';
5
+
6
+ import ShareMessageModal, { type ShareModalProps } from '../../../components/ShareMessageModal';
7
+ import {
8
+ Provider,
9
+ createStore,
10
+ messageStateSelectors,
11
+ useConversationStore,
12
+ useConversationStoreApi,
13
+ } from '../../../store';
8
14
  import type {
9
15
  MessageActionItem,
10
16
  MessageActionItemOrDivider,
@@ -59,7 +65,29 @@ interface GroupActionsProps {
59
65
  */
60
66
  const WithContentId = memo<GroupActionsProps>(({ actionsConfig, id, data, contentBlock }) => {
61
67
  const { tools } = data;
62
- const [showShareModal, setShareModal] = useState(false);
68
+ const store = useConversationStoreApi();
69
+ const handleOpenShareModal = useCallback(() => {
70
+ createRawModal(
71
+ (props: ShareModalProps) => (
72
+ <Provider
73
+ createStore={() => {
74
+ const state = store.getState();
75
+ return createStore({
76
+ context: state.context,
77
+ hooks: state.hooks,
78
+ skipFetch: state.skipFetch,
79
+ });
80
+ }}
81
+ >
82
+ <ShareMessageModal {...props} />
83
+ </Provider>
84
+ ),
85
+ {
86
+ message: data,
87
+ },
88
+ { onCloseKey: 'onCancel', openKey: 'open' },
89
+ );
90
+ }, [data, store]);
63
91
 
64
92
  const isCollapsed = useConversationStore(messageStateSelectors.isMessageCollapsed(id));
65
93
 
@@ -67,7 +95,7 @@ const WithContentId = memo<GroupActionsProps>(({ actionsConfig, id, data, conten
67
95
  contentBlock,
68
96
  data,
69
97
  id,
70
- onOpenShareModal: () => setShareModal(true),
98
+ onOpenShareModal: handleOpenShareModal,
71
99
  });
72
100
 
73
101
  const hasTools = !!tools;
@@ -130,16 +158,7 @@ const WithContentId = memo<GroupActionsProps>(({ actionsConfig, id, data, conten
130
158
  [allActions],
131
159
  );
132
160
 
133
- return (
134
- <>
135
- <ActionIconGroup items={items} menu={{ items: menu }} onActionClick={handleAction} />
136
- <ShareMessageModal
137
- message={data}
138
- onCancel={() => setShareModal(false)}
139
- open={showShareModal}
140
- />
141
- </>
142
- );
161
+ return <ActionIconGroup items={items} menu={menu} onActionClick={handleAction} />;
143
162
  });
144
163
 
145
164
  WithContentId.displayName = 'GroupActionsWithContentId';
@@ -1,10 +1,16 @@
1
1
  import { type AssistantContentBlock, type UIChatMessage } from '@lobechat/types';
2
- import { ActionIconGroup } from '@lobehub/ui';
2
+ import { ActionIconGroup, createRawModal } from '@lobehub/ui';
3
3
  import type { ActionIconGroupEvent, ActionIconGroupItemType } from '@lobehub/ui';
4
- import { memo, useCallback, useMemo, useState } from 'react';
5
-
6
- import ShareMessageModal from '../../../components/ShareMessageModal';
7
- import { messageStateSelectors, useConversationStore } from '../../../store';
4
+ import { memo, useCallback, useMemo } from 'react';
5
+
6
+ import ShareMessageModal, { type ShareModalProps } from '../../../components/ShareMessageModal';
7
+ import {
8
+ Provider,
9
+ createStore,
10
+ messageStateSelectors,
11
+ useConversationStore,
12
+ useConversationStoreApi,
13
+ } from '../../../store';
8
14
  import type {
9
15
  MessageActionItem,
10
16
  MessageActionItemOrDivider,
@@ -58,7 +64,29 @@ interface GroupActionsProps {
58
64
  * Actions bar for group messages with content (has assistant message content)
59
65
  */
60
66
  const WithContentId = memo<GroupActionsProps>(({ actionsConfig, id, data, contentBlock }) => {
61
- const [showShareModal, setShareModal] = useState(false);
67
+ const store = useConversationStoreApi();
68
+ const handleOpenShareModal = useCallback(() => {
69
+ createRawModal(
70
+ (props: ShareModalProps) => (
71
+ <Provider
72
+ createStore={() => {
73
+ const state = store.getState();
74
+ return createStore({
75
+ context: state.context,
76
+ hooks: state.hooks,
77
+ skipFetch: state.skipFetch,
78
+ });
79
+ }}
80
+ >
81
+ <ShareMessageModal {...props} />
82
+ </Provider>
83
+ ),
84
+ {
85
+ message: data,
86
+ },
87
+ { onCloseKey: 'onCancel', openKey: 'open' },
88
+ );
89
+ }, [data, store]);
62
90
 
63
91
  const isCollapsed = useConversationStore(messageStateSelectors.isMessageCollapsed(id));
64
92
 
@@ -66,7 +94,7 @@ const WithContentId = memo<GroupActionsProps>(({ actionsConfig, id, data, conten
66
94
  contentBlock,
67
95
  data,
68
96
  id,
69
- onOpenShareModal: () => setShareModal(true),
97
+ onOpenShareModal: handleOpenShareModal,
70
98
  });
71
99
 
72
100
  // Get collapse/expand action based on current state
@@ -122,16 +150,7 @@ const WithContentId = memo<GroupActionsProps>(({ actionsConfig, id, data, conten
122
150
  [allActions],
123
151
  );
124
152
 
125
- return (
126
- <>
127
- <ActionIconGroup items={items} menu={{ items: menu }} onActionClick={handleAction} />
128
- <ShareMessageModal
129
- message={data}
130
- onCancel={() => setShareModal(false)}
131
- open={showShareModal}
132
- />
133
- </>
134
- );
153
+ return <ActionIconGroup items={items} menu={menu} onActionClick={handleAction} />;
135
154
  });
136
155
 
137
156
  WithContentId.displayName = 'GroupActionsWithContentId';
@@ -15,9 +15,7 @@ export const ErrorActionsBar = memo<ErrorActionsBarProps>(({ actions, onActionCl
15
15
  return (
16
16
  <ActionIconGroup
17
17
  items={[regenerate, del]}
18
- menu={{
19
- items: [edit, copy, divider, del],
20
- }}
18
+ menu={[edit, copy, divider, del]}
21
19
  onActionClick={onActionClick}
22
20
  />
23
21
  );
@@ -1,9 +1,12 @@
1
1
  import { type UIChatMessage } from '@lobechat/types';
2
- import { ActionIconGroup } from '@lobehub/ui';
2
+ import { ActionIconGroup, createRawModal } from '@lobehub/ui';
3
3
  import type { ActionIconGroupEvent, ActionIconGroupItemType } from '@lobehub/ui';
4
- import { memo, useCallback, useMemo, useState } from 'react';
4
+ import { memo, useCallback, useMemo } from 'react';
5
5
 
6
- import ShareMessageModal from '../../../components/ShareMessageModal';
6
+ import { useEventCallback } from '@/hooks/useEventCallback';
7
+
8
+ import ShareMessageModal, { type ShareModalProps } from '../../../components/ShareMessageModal';
9
+ import { Provider, createStore, useConversationStoreApi } from '../../../store';
7
10
  import type {
8
11
  MessageActionItem,
9
12
  MessageActionItemOrDivider,
@@ -56,13 +59,35 @@ interface AssistantActionsBarProps {
56
59
  export const AssistantActionsBar = memo<AssistantActionsBarProps>(
57
60
  ({ actionsConfig, id, data, index }) => {
58
61
  const { error, tools } = data;
59
- const [showShareModal, setShareModal] = useState(false);
62
+ const store = useConversationStoreApi();
63
+ const handleOpenShareModal = useEventCallback(() => {
64
+ createRawModal(
65
+ (props: ShareModalProps) => (
66
+ <Provider
67
+ createStore={() => {
68
+ const state = store.getState();
69
+ return createStore({
70
+ context: state.context,
71
+ hooks: state.hooks,
72
+ skipFetch: state.skipFetch,
73
+ });
74
+ }}
75
+ >
76
+ <ShareMessageModal {...props} />
77
+ </Provider>
78
+ ),
79
+ {
80
+ message: data,
81
+ },
82
+ { onCloseKey: 'onCancel', openKey: 'open' },
83
+ );
84
+ });
60
85
 
61
86
  const defaultActions = useAssistantActions({
62
87
  data,
63
88
  id,
64
89
  index,
65
- onOpenShareModal: () => setShareModal(true),
90
+ onOpenShareModal: handleOpenShareModal,
66
91
  });
67
92
 
68
93
  const hasTools = !!tools;
@@ -159,16 +184,7 @@ export const AssistantActionsBar = memo<AssistantActionsBarProps>(
159
184
 
160
185
  if (error) return <ErrorActionsBar actions={defaultActions} onActionClick={handleAction} />;
161
186
 
162
- return (
163
- <>
164
- <ActionIconGroup items={items} menu={{ items: menu }} onActionClick={handleAction} />
165
- <ShareMessageModal
166
- message={data}
167
- onCancel={() => setShareModal(false)}
168
- open={showShareModal}
169
- />
170
- </>
171
- );
187
+ return <ActionIconGroup items={items} menu={menu} onActionClick={handleAction} />;
172
188
  },
173
189
  );
174
190
 
@@ -135,7 +135,7 @@ export const UserActionsBar = memo<UserActionsProps>(({ actionsConfig, id, data
135
135
  [allActions],
136
136
  );
137
137
 
138
- return <ActionIconGroup items={items} menu={{ items: menu }} onActionClick={handleAction} />;
138
+ return <ActionIconGroup items={items} menu={menu} onActionClick={handleAction} />;
139
139
  });
140
140
 
141
141
  UserActionsBar.displayName = 'UserActionsBar';
@@ -4,29 +4,13 @@ import { isDesktop } from '@lobechat/const';
4
4
  import { Flexbox } from '@lobehub/ui';
5
5
  import { createStaticStyles, cx } from 'antd-style';
6
6
  import isEqual from 'fast-deep-equal';
7
- import {
8
- type MouseEvent,
9
- type ReactNode,
10
- type RefObject,
11
- Suspense,
12
- memo,
13
- useCallback,
14
- useMemo,
15
- useRef,
16
- } from 'react';
17
- import type { VListHandle } from 'virtua';
7
+ import { type MouseEvent, type ReactNode, Suspense, memo, useCallback } from 'react';
18
8
 
19
9
  import BubblesLoading from '@/components/BubblesLoading';
20
10
 
21
- import ContextMenu from '../components/ContextMenu';
22
11
  import History from '../components/History';
23
12
  import { useChatItemContextMenu } from '../hooks/useChatItemContextMenu';
24
- import {
25
- dataSelectors,
26
- messageStateSelectors,
27
- useConversationStore,
28
- virtuaListSelectors,
29
- } from '../store';
13
+ import { dataSelectors, messageStateSelectors, useConversationStore } from '../store';
30
14
  import AgentCouncilMessage from './AgentCouncil';
31
15
  import AssistantMessage from './Assistant';
32
16
  import AssistantGroupMessage from './AssistantGroup';
@@ -73,13 +57,10 @@ const MessageItem = memo<MessageItemProps>(
73
57
  index,
74
58
  isLatestItem,
75
59
  }) => {
76
- const containerRef = useRef<HTMLDivElement | null>(null);
77
-
78
60
  const topic = useConversationStore((s) => s.context.topicId);
79
61
 
80
- // Get message and actionsBar from ConversationStore
62
+ // Get message from ConversationStore
81
63
  const message = useConversationStore(dataSelectors.getDisplayMessageById(id), isEqual);
82
- const actionsBar = useConversationStore((s) => s.actionsBar);
83
64
  const role = message?.role;
84
65
 
85
66
  const [editing, isMessageCreating] = useConversationStore((s) => [
@@ -87,24 +68,13 @@ const MessageItem = memo<MessageItemProps>(
87
68
  messageStateSelectors.isMessageCreating(id)(s),
88
69
  ]);
89
70
 
90
- const {
91
- containerRef: contextMenuContainerRef,
92
- contextMenuState,
93
- handleContextMenu,
94
- hideContextMenu,
95
- } = useChatItemContextMenu({
71
+ const { handleContextMenu } = useChatItemContextMenu({
96
72
  editing,
97
- onActionClick: () => {},
73
+ id,
74
+ inPortalThread,
75
+ topic,
98
76
  });
99
77
 
100
- const setContainerRef = useCallback(
101
- (node: HTMLDivElement | null) => {
102
- containerRef.current = node;
103
- contextMenuContainerRef.current = node;
104
- },
105
- [contextMenuContainerRef],
106
- );
107
-
108
78
  const onContextMenu = useCallback(
109
79
  async (event: MouseEvent<HTMLDivElement>) => {
110
80
  if (!role || (role !== 'user' && role !== 'assistant' && role !== 'assistantGroup')) return;
@@ -129,15 +99,6 @@ const MessageItem = memo<MessageItemProps>(
129
99
  },
130
100
  [handleContextMenu, id, role, message],
131
101
  );
132
- // Get virtuaScrollMethods from ConversationStore
133
- const virtuaScrollMethods = useConversationStore(virtuaListSelectors.virtuaScrollMethods);
134
-
135
- // Create a ref-like object for ContextMenu compatibility
136
- // VirtuaScrollMethods is a subset of VListHandle with the methods ContextMenu needs
137
- const virtuaRef = useMemo<RefObject<VListHandle | null>>(
138
- () => ({ current: virtuaScrollMethods as VListHandle | null }),
139
- [virtuaScrollMethods],
140
- );
141
102
 
142
103
  const renderContent = useCallback(() => {
143
104
  switch (role) {
@@ -202,7 +163,7 @@ const MessageItem = memo<MessageItemProps>(
202
163
  }
203
164
 
204
165
  return null;
205
- }, [role, disableEditing, id, index, isLatestItem, actionsBar]);
166
+ }, [role, disableEditing, id, index, isLatestItem]);
206
167
 
207
168
  if (!role) return;
208
169
 
@@ -213,22 +174,10 @@ const MessageItem = memo<MessageItemProps>(
213
174
  className={cx(styles.message, className, isMessageCreating && styles.loading)}
214
175
  data-index={index}
215
176
  onContextMenu={onContextMenu}
216
- ref={setContainerRef}
217
177
  >
218
178
  <Suspense fallback={<BubblesLoading />}>{renderContent()}</Suspense>
219
179
  {endRender}
220
180
  </Flexbox>
221
- <ContextMenu
222
- id={id}
223
- inPortalThread={inPortalThread}
224
- index={index}
225
- onClose={hideContextMenu}
226
- position={contextMenuState.position}
227
- selectedText={contextMenuState.selectedText}
228
- topic={topic}
229
- virtuaRef={virtuaRef}
230
- visible={contextMenuState.visible}
231
- />
232
181
  </>
233
182
  );
234
183
  },
@@ -15,7 +15,7 @@ enum Tab {
15
15
  Text = 'text',
16
16
  }
17
17
 
18
- interface ShareModalProps {
18
+ export interface ShareModalProps {
19
19
  message: UIChatMessage;
20
20
  onCancel: () => void;
21
21
  open: boolean;