@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,418 +0,0 @@
1
- 'use client';
2
-
3
- import { type UIChatMessage } from '@lobechat/types';
4
- import { ActionIcon } from '@lobehub/ui';
5
- import type { ActionIconGroupEvent, ActionIconGroupItemType } from '@lobehub/ui';
6
- import { Dropdown, type MenuProps } from 'antd';
7
- import { App } from 'antd';
8
- import { createStaticStyles } from 'antd-style';
9
- import isEqual from 'fast-deep-equal';
10
- import {
11
- type ComponentType,
12
- type ReactNode,
13
- type RefObject,
14
- isValidElement,
15
- memo,
16
- useCallback,
17
- useMemo,
18
- useState,
19
- } from 'react';
20
- import { createPortal } from 'react-dom';
21
- import { useTranslation } from 'react-i18next';
22
- import type { VListHandle } from 'virtua';
23
-
24
- import { useSessionStore } from '@/store/session';
25
- import { sessionSelectors } from '@/store/session/selectors';
26
-
27
- import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
28
- import {
29
- dataSelectors,
30
- messageStateSelectors,
31
- useConversationStore,
32
- useConversationStoreApi,
33
- } from '../store';
34
- import ShareMessageModal from './ShareMessageModal';
35
-
36
- interface ActionMenuItem extends ActionIconGroupItemType {
37
- children?: { key: string; label: ReactNode }[];
38
- disable?: boolean;
39
- popupClassName?: string;
40
- }
41
-
42
- type MenuItem = ActionMenuItem | { type: 'divider' };
43
- type ContextMenuEvent = ActionIconGroupEvent & { selectedText?: string };
44
-
45
- const styles = createStaticStyles(({ css }) => ({
46
- contextMenu: css`
47
- position: fixed;
48
- z-index: 1000;
49
- min-width: 160px;
50
-
51
- .ant-dropdown-menu {
52
- border: none;
53
- border-radius: 6px;
54
- box-shadow: 0 4px 12px color-mix(in srgb, black 15%, transparent);
55
- }
56
- `,
57
- trigger: css`
58
- pointer-events: none;
59
-
60
- position: fixed;
61
-
62
- width: 1px;
63
- height: 1px;
64
-
65
- opacity: 0;
66
- `,
67
- }));
68
-
69
- interface ContextMenuProps {
70
- id: string;
71
- inPortalThread: boolean;
72
- index: number;
73
- onClose: () => void;
74
- position: { x: number; y: number };
75
- selectedText?: string;
76
- topic?: string | null;
77
- virtuaRef?: RefObject<VListHandle | null> | null;
78
- visible: boolean;
79
- }
80
-
81
- const ContextMenu = memo<ContextMenuProps>(
82
- ({ visible, position, selectedText, id, index, inPortalThread, topic, virtuaRef, onClose }) => {
83
- const { message } = App.useApp();
84
- const { t } = useTranslation('common');
85
- const [shareMessage, setShareMessage] = useState<UIChatMessage | null>(null);
86
- const [isShareModalOpen, setShareModalOpen] = useState(false);
87
-
88
- const storeApi = useConversationStoreApi();
89
-
90
- const [role, error, isCollapsed, hasThread, isRegenerating] = useConversationStore((s) => {
91
- const item = dataSelectors.getDisplayMessageById(id)(s);
92
- return [
93
- item?.role,
94
- item?.error,
95
- messageStateSelectors.isMessageCollapsed(id)(s),
96
- messageStateSelectors.hasThreadBySourceMsgId(id)(s),
97
- messageStateSelectors.isMessageRegenerating(id)(s),
98
- ];
99
- }, isEqual);
100
-
101
- const isThreadMode = useConversationStore(messageStateSelectors.isThreadMode);
102
- const isGroupSession = useSessionStore(sessionSelectors.isCurrentSessionGroupSession);
103
- const actionsBar = useChatListActionsBar({ hasThread, isRegenerating });
104
- const inThread = isThreadMode || inPortalThread;
105
-
106
- const [
107
- toggleMessageEditing,
108
- deleteMessage,
109
- regenerateUserMessage,
110
- regenerateAssistantMessage,
111
- translateMessage,
112
- ttsMessage,
113
- delAndRegenerateMessage,
114
- copyMessage,
115
- openThreadCreator,
116
- resendThreadMessage,
117
- delAndResendThreadMessage,
118
- toggleMessageCollapsed,
119
- ] = useConversationStore((s) => [
120
- s.toggleMessageEditing,
121
- s.deleteMessage,
122
- s.regenerateUserMessage,
123
- s.regenerateAssistantMessage,
124
- s.translateMessage,
125
- s.ttsMessage,
126
- s.delAndRegenerateMessage,
127
- s.copyMessage,
128
- s.openThreadCreator,
129
- s.resendThreadMessage,
130
- s.delAndResendThreadMessage,
131
- s.toggleMessageCollapsed,
132
- ]);
133
-
134
- const getMessage = useCallback(
135
- () => dataSelectors.getDisplayMessageById(id)(storeApi.getState()),
136
- [id, storeApi],
137
- );
138
-
139
- const menuItems = useMemo<MenuItem[]>(() => {
140
- if (!role) return [];
141
-
142
- const {
143
- branching,
144
- collapse,
145
- copy,
146
- del,
147
- delAndRegenerate,
148
- divider,
149
- edit,
150
- expand,
151
- regenerate,
152
- share,
153
- translate,
154
- tts,
155
- } = actionsBar;
156
-
157
- if (role === 'assistant') {
158
- if (error) {
159
- return [edit, copy, divider, del, divider, regenerate].filter(Boolean) as MenuItem[];
160
- }
161
-
162
- const collapseAction = isCollapsed ? expand : collapse;
163
- const list: MenuItem[] = [edit, copy, collapseAction];
164
-
165
- if (!inThread && !isGroupSession) list.push(branching);
166
-
167
- list.push(
168
- divider,
169
- tts,
170
- translate,
171
- divider,
172
- share,
173
- divider,
174
- regenerate,
175
- delAndRegenerate,
176
- del,
177
- );
178
-
179
- return list.filter(Boolean) as MenuItem[];
180
- }
181
-
182
- if (role === 'assistantGroup') {
183
- if (error) {
184
- return [edit, copy, divider, del, divider, regenerate].filter(Boolean) as MenuItem[];
185
- }
186
-
187
- const collapseAction = isCollapsed ? expand : collapse;
188
- const list: MenuItem[] = [
189
- edit,
190
- copy,
191
- collapseAction,
192
- divider,
193
- share,
194
- divider,
195
- regenerate,
196
- del,
197
- ];
198
-
199
- return list.filter(Boolean) as MenuItem[];
200
- }
201
-
202
- if (role === 'user') {
203
- const list: MenuItem[] = [edit, copy];
204
-
205
- if (!inThread) list.push(branching);
206
-
207
- list.push(divider, tts, translate, divider, regenerate, del);
208
-
209
- return list.filter(Boolean) as MenuItem[];
210
- }
211
-
212
- return [];
213
- }, [actionsBar, error, inThread, isCollapsed, isGroupSession, role]);
214
-
215
- const handleShare = useCallback(() => {
216
- const item = getMessage();
217
- if (!item || item.role !== 'assistant') return;
218
-
219
- setShareMessage(item);
220
- setShareModalOpen(true);
221
- }, [getMessage]);
222
-
223
- const handleShareClose = useCallback(() => {
224
- setShareModalOpen(false);
225
- setShareMessage(null);
226
- }, []);
227
-
228
- const handleAction = useCallback(
229
- async (action: ContextMenuEvent) => {
230
- const item = getMessage();
231
- if (!item) return;
232
-
233
- switch (action.key) {
234
- case 'edit': {
235
- toggleMessageEditing(id, true);
236
- break;
237
- }
238
- case 'copy': {
239
- await copyMessage(id, item.content);
240
- message.success(t('copySuccess'));
241
- break;
242
- }
243
- case 'expand':
244
- case 'collapse': {
245
- toggleMessageCollapsed(id);
246
- break;
247
- }
248
- case 'branching': {
249
- if (!topic) {
250
- message.warning(t('branchingRequiresSavedTopic'));
251
- break;
252
- }
253
- openThreadCreator(id);
254
- break;
255
- }
256
- case 'del': {
257
- deleteMessage(id);
258
- break;
259
- }
260
- case 'regenerate': {
261
- if (inPortalThread) {
262
- resendThreadMessage(id);
263
- } else if (role === 'assistant') {
264
- regenerateAssistantMessage(id);
265
- } else {
266
- regenerateUserMessage(id);
267
- }
268
-
269
- if (item.error) deleteMessage(id);
270
- break;
271
- }
272
- case 'delAndRegenerate': {
273
- if (inPortalThread) {
274
- delAndResendThreadMessage(id);
275
- } else {
276
- delAndRegenerateMessage(id);
277
- }
278
- break;
279
- }
280
- case 'tts': {
281
- ttsMessage(id);
282
- break;
283
- }
284
- case 'share': {
285
- handleShare();
286
- break;
287
- }
288
- }
289
-
290
- if (action.keyPath?.at(-1) === 'translate') {
291
- const lang = action.keyPath[0];
292
- translateMessage(id, lang);
293
- }
294
- },
295
- [
296
- copyMessage,
297
- deleteMessage,
298
- delAndRegenerateMessage,
299
- delAndResendThreadMessage,
300
- getMessage,
301
- handleShare,
302
- id,
303
- index,
304
- inPortalThread,
305
- message,
306
- openThreadCreator,
307
- regenerateAssistantMessage,
308
- regenerateUserMessage,
309
- resendThreadMessage,
310
- role,
311
- t,
312
- toggleMessageCollapsed,
313
- toggleMessageEditing,
314
- topic,
315
- translateMessage,
316
- ttsMessage,
317
- virtuaRef,
318
- ],
319
- );
320
-
321
- const renderIcon = useCallback((iconComponent: ActionIconGroupItemType['icon']) => {
322
- if (!iconComponent) return null;
323
-
324
- if (isValidElement(iconComponent)) {
325
- return <ActionIcon icon={iconComponent} size={'small'} />;
326
- }
327
-
328
- const IconComponent = iconComponent as ComponentType<{ size?: number }>;
329
-
330
- return <ActionIcon icon={<IconComponent size={16} />} size={'small'} />;
331
- }, []);
332
-
333
- const dropdownMenuItems = useMemo(() => {
334
- return (menuItems ?? []).filter(Boolean).map((item) => {
335
- if ('type' in item && item.type === 'divider') return { type: 'divider' as const };
336
-
337
- const actionItem = item as ActionMenuItem;
338
- const children = actionItem.children?.map((child) => ({
339
- key: child.key,
340
- label: child.label,
341
- }));
342
- const disabled =
343
- actionItem.disabled ??
344
- (typeof actionItem.disable === 'boolean' ? actionItem.disable : undefined);
345
-
346
- return {
347
- children,
348
- danger: actionItem.danger,
349
- disabled,
350
- icon: renderIcon(actionItem.icon),
351
- key: actionItem.key,
352
- label: actionItem.label,
353
- popupClassName: actionItem.popupClassName,
354
- };
355
- });
356
- }, [menuItems, renderIcon]);
357
-
358
- const handleMenuClick = useCallback(
359
- (info: Parameters<NonNullable<MenuProps['onClick']>>[0]) => {
360
- const event = {
361
- ...info,
362
- selectedText,
363
- } as ContextMenuEvent;
364
-
365
- handleAction(event);
366
- onClose();
367
- },
368
- [handleAction, onClose, selectedText],
369
- );
370
-
371
- if (!visible || menuItems.length === 0) return null;
372
-
373
- return (
374
- <>
375
- {createPortal(
376
- <>
377
- <div
378
- className={styles.trigger}
379
- style={{
380
- left: position.x,
381
- top: position.y,
382
- }}
383
- />
384
- <Dropdown
385
- menu={{
386
- items: dropdownMenuItems,
387
- onClick: handleMenuClick,
388
- }}
389
- open={visible}
390
- placement="bottomLeft"
391
- trigger={[]}
392
- >
393
- <div
394
- className={styles.contextMenu}
395
- style={{
396
- left: position.x,
397
- top: position.y,
398
- }}
399
- />
400
- </Dropdown>
401
- </>,
402
- document.body,
403
- )}
404
- {shareMessage && (
405
- <ShareMessageModal
406
- message={shareMessage}
407
- onCancel={handleShareClose}
408
- open={isShareModalOpen}
409
- />
410
- )}
411
- </>
412
- );
413
- },
414
- );
415
-
416
- ContextMenu.displayName = 'ContextMenu';
417
-
418
- export default ContextMenu;