@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,7 +1,7 @@
1
1
  import { Icon, type MenuProps } from '@lobehub/ui';
2
2
  import { App } from 'antd';
3
3
  import { ExternalLink, LucideCopy, PencilLine, Trash, Wand2 } from 'lucide-react';
4
- import { useMemo } from 'react';
4
+ import { useCallback } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { isDesktop } from '@/const/version';
@@ -17,7 +17,7 @@ interface TopicItemDropdownMenuProps {
17
17
  export const useTopicItemDropdownMenu = ({
18
18
  id,
19
19
  toggleEditing,
20
- }: TopicItemDropdownMenuProps): MenuProps['items'] => {
20
+ }: TopicItemDropdownMenuProps): (() => MenuProps['items']) => {
21
21
  const { t } = useTranslation(['topic', 'common']);
22
22
  const { modal } = App.useApp();
23
23
 
@@ -30,7 +30,7 @@ export const useTopicItemDropdownMenu = ({
30
30
  s.removeTopic,
31
31
  ]);
32
32
 
33
- return useMemo(() => {
33
+ return useCallback(() => {
34
34
  if (!id) return [];
35
35
 
36
36
  return [
@@ -1,25 +1,16 @@
1
- import { ActionIcon, Dropdown, type MenuProps } from '@lobehub/ui';
1
+ import { ActionIcon, type DropdownItem, DropdownMenu } from '@lobehub/ui';
2
2
  import { MoreHorizontalIcon } from 'lucide-react';
3
3
  import { memo } from 'react';
4
4
 
5
5
  interface ActionProps {
6
- dropdownMenu: MenuProps['items'];
6
+ dropdownMenu: DropdownItem[] | (() => DropdownItem[]);
7
7
  }
8
8
 
9
9
  const Actions = memo<ActionProps>(({ dropdownMenu }) => {
10
10
  return (
11
- <Dropdown
12
- arrow={false}
13
- menu={{
14
- items: dropdownMenu,
15
- onClick: ({ domEvent }) => {
16
- domEvent.stopPropagation();
17
- },
18
- }}
19
- trigger={['click']}
20
- >
11
+ <DropdownMenu items={dropdownMenu}>
21
12
  <ActionIcon icon={MoreHorizontalIcon} size={'small'} />
22
- </Dropdown>
13
+ </DropdownMenu>
23
14
  );
24
15
  });
25
16
 
@@ -1,4 +1,4 @@
1
- import { Dropdown, Icon } from '@lobehub/ui';
1
+ import { Icon } from '@lobehub/ui';
2
2
  import { TreeDownRightIcon } from '@lobehub/ui/icons';
3
3
  import { cssVar } from 'antd-style';
4
4
  import { memo, useCallback } from 'react';
@@ -46,23 +46,15 @@ const ThreadItem = memo<ThreadItemProps>(({ title, id }) => {
46
46
 
47
47
  return (
48
48
  <>
49
- <Dropdown
50
- menu={{
51
- items: dropdownMenu,
52
- }}
53
- trigger={['contextMenu']}
54
- >
55
- <NavItem
56
- actions={<Actions dropdownMenu={dropdownMenu} />}
57
- active={active && !isInAgentSubRoute}
58
- disabled={editing}
59
- icon={
60
- <Icon color={cssVar.colorTextDescription} icon={TreeDownRightIcon} size={'small'} />
61
- }
62
- onClick={handleClick}
63
- title={title}
64
- />
65
- </Dropdown>
49
+ <NavItem
50
+ actions={<Actions dropdownMenu={dropdownMenu} />}
51
+ active={active && !isInAgentSubRoute}
52
+ contextMenuItems={dropdownMenu}
53
+ disabled={editing}
54
+ icon={<Icon color={cssVar.colorTextDescription} icon={TreeDownRightIcon} size={'small'} />}
55
+ onClick={handleClick}
56
+ title={title}
57
+ />
66
58
  <Editing id={id} title={title} toggleEditing={toggleEditing} />
67
59
  </>
68
60
  );
@@ -1,7 +1,7 @@
1
1
  import { Icon, type MenuProps } from '@lobehub/ui';
2
2
  import { App } from 'antd';
3
3
  import { PencilLine, Trash } from 'lucide-react';
4
- import { useMemo } from 'react';
4
+ import { useCallback } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { useChatStore } from '@/store/chat';
@@ -14,13 +14,13 @@ interface ThreadItemDropdownMenuProps {
14
14
  export const useThreadItemDropdownMenu = ({
15
15
  id,
16
16
  toggleEditing,
17
- }: ThreadItemDropdownMenuProps): MenuProps['items'] => {
17
+ }: ThreadItemDropdownMenuProps): (() => MenuProps['items']) => {
18
18
  const { t } = useTranslation(['thread', 'common']);
19
19
  const { modal } = App.useApp();
20
20
 
21
21
  const [removeThread] = useChatStore((s) => [s.removeThread]);
22
22
 
23
- return useMemo(() => {
23
+ return useCallback(() => {
24
24
  return [
25
25
  {
26
26
  icon: <Icon icon={PencilLine} />,
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { Icon } from '@lobehub/ui';
4
- import { App, Dropdown } from 'antd';
3
+ import { Button, DropdownMenu, Flexbox, Icon } from '@lobehub/ui';
4
+ import { App } from 'antd';
5
5
  import { createStaticStyles } from 'antd-style';
6
6
  import { ChevronDownIcon } from 'lucide-react';
7
7
  import { memo, useState } from 'react';
@@ -17,10 +17,17 @@ import { useHomeStore } from '@/store/home';
17
17
  import { useDetailContext } from '../../DetailProvider';
18
18
 
19
19
  const styles = createStaticStyles(({ css }) => ({
20
- button: css`
21
- button {
22
- width: 100%;
23
- }
20
+ buttonGroup: css`
21
+ width: 100%;
22
+ `,
23
+ menuButton: css`
24
+ padding-inline: 8px;
25
+ border-start-start-radius: 0 !important;
26
+ border-end-start-radius: 0 !important;
27
+ `,
28
+ primaryButton: css`
29
+ border-start-end-radius: 0 !important;
30
+ border-end-end-radius: 0 !important;
24
31
  `,
25
32
  }));
26
33
 
@@ -127,28 +134,41 @@ const AddAgent = memo<{ mobile?: boolean }>(({ mobile }) => {
127
134
  }
128
135
  };
129
136
 
137
+ const menuItems = [
138
+ {
139
+ key: 'addAgent',
140
+ label: t('assistants.addAgent'),
141
+ onClick: handleAddAgent,
142
+ },
143
+ ];
144
+
130
145
  return (
131
- <Dropdown.Button
132
- className={styles.button}
133
- icon={<Icon icon={ChevronDownIcon} />}
134
- loading={isLoading}
135
- menu={{
136
- items: [
137
- {
138
- key: 'addAgent',
139
- label: t('assistants.addAgent'),
140
- onClick: handleAddAgent,
141
- },
142
- ],
143
- }}
144
- onClick={handleAddAgentAndConverse}
145
- overlayStyle={{ minWidth: 267 }}
146
- size={'large'}
147
- style={{ flex: 1, width: 'unset' }}
148
- type={'primary'}
149
- >
150
- {t('assistants.addAgentAndConverse')}
151
- </Dropdown.Button>
146
+ <Flexbox className={styles.buttonGroup} gap={0} horizontal>
147
+ <Button
148
+ block
149
+ className={styles.primaryButton}
150
+ loading={isLoading}
151
+ onClick={handleAddAgentAndConverse}
152
+ size={'large'}
153
+ style={{ flex: 1, width: 'unset' }}
154
+ type={'primary'}
155
+ >
156
+ {t('assistants.addAgentAndConverse')}
157
+ </Button>
158
+ <DropdownMenu
159
+ items={menuItems}
160
+ popupProps={{ style: { minWidth: 267 } }}
161
+ triggerProps={{ disabled: isLoading }}
162
+ >
163
+ <Button
164
+ className={styles.menuButton}
165
+ disabled={isLoading}
166
+ icon={<Icon icon={ChevronDownIcon} />}
167
+ size={'large'}
168
+ type={'primary'}
169
+ />
170
+ </DropdownMenu>
171
+ </Flexbox>
152
172
  );
153
173
  });
154
174
 
@@ -4,6 +4,7 @@ import {
4
4
  Tag as AntTag,
5
5
  Avatar,
6
6
  Block,
7
+ DropdownMenu,
7
8
  Flexbox,
8
9
  Icon,
9
10
  Tag,
@@ -11,7 +12,7 @@ import {
11
12
  Tooltip,
12
13
  TooltipGroup,
13
14
  } from '@lobehub/ui';
14
- import { App, Dropdown } from 'antd';
15
+ import { App } from 'antd';
15
16
  import { createStaticStyles, cx } from 'antd-style';
16
17
  import {
17
18
  AlertTriangle,
@@ -258,14 +259,14 @@ const UserAgentCard = memo<UserAgentCardProps>(
258
259
  width={'100%'}
259
260
  >
260
261
  {isOwner && (
261
- <Dropdown menu={{ items: menuItems }} trigger={['click']}>
262
+ <DropdownMenu items={menuItems}>
262
263
  <div
263
264
  className={cx('more-button', styles.moreButton)}
264
265
  onClick={(e) => e.stopPropagation()}
265
266
  >
266
267
  <Icon icon={MoreVerticalIcon} size={16} style={{ cursor: 'pointer' }} />
267
268
  </div>
268
- </Dropdown>
269
+ </DropdownMenu>
269
270
  )}
270
271
  <Flexbox
271
272
  align={'flex-start'}
@@ -1,25 +1,16 @@
1
- import { ActionIcon, Dropdown, type MenuProps } from '@lobehub/ui';
1
+ import { ActionIcon, type DropdownItem, DropdownMenu } from '@lobehub/ui';
2
2
  import { MoreHorizontalIcon } from 'lucide-react';
3
3
  import { memo } from 'react';
4
4
 
5
5
  interface ActionProps {
6
- dropdownMenu: MenuProps['items'];
6
+ dropdownMenu: DropdownItem[] | (() => DropdownItem[]);
7
7
  }
8
8
 
9
9
  const Actions = memo<ActionProps>(({ dropdownMenu }) => {
10
10
  return (
11
- <Dropdown
12
- arrow={false}
13
- menu={{
14
- items: dropdownMenu,
15
- onClick: ({ domEvent }) => {
16
- domEvent.stopPropagation();
17
- },
18
- }}
19
- trigger={['click']}
20
- >
11
+ <DropdownMenu items={dropdownMenu}>
21
12
  <ActionIcon icon={MoreHorizontalIcon} size={'small'} />
22
- </Dropdown>
13
+ </DropdownMenu>
23
14
  );
24
15
  });
25
16
 
@@ -1,4 +1,4 @@
1
- import { ActionIcon, Dropdown, Flexbox, Icon, Skeleton, Tag } from '@lobehub/ui';
1
+ import { ActionIcon, Flexbox, Icon, Skeleton, Tag } from '@lobehub/ui';
2
2
  import { cssVar } from 'antd-style';
3
3
  import { MessageSquareDashed, Star } from 'lucide-react';
4
4
  import { Suspense, memo, useCallback } from 'react';
@@ -92,34 +92,28 @@ const TopicItem = memo<TopicItemProps>(({ id, title, fav, active, threadId }) =>
92
92
 
93
93
  return (
94
94
  <Flexbox style={{ position: 'relative' }}>
95
- <Dropdown
96
- menu={{
97
- items: dropdownMenu,
98
- }}
99
- trigger={['contextMenu']}
100
- >
101
- <NavItem
102
- actions={<Actions dropdownMenu={dropdownMenu} />}
103
- active={active && !threadId && !isInAgentSubRoute}
104
- disabled={editing}
105
- icon={
106
- <ActionIcon
107
- color={fav ? cssVar.colorWarning : undefined}
108
- fill={fav ? cssVar.colorWarning : 'transparent'}
109
- icon={Star}
110
- onClick={(e) => {
111
- e.stopPropagation();
112
- favoriteTopic(id, !fav);
113
- }}
114
- size={'small'}
115
- />
116
- }
117
- loading={isLoading}
118
- onClick={handleClick}
119
- onDoubleClick={handleDoubleClick}
120
- title={title}
121
- />
122
- </Dropdown>
95
+ <NavItem
96
+ actions={<Actions dropdownMenu={dropdownMenu} />}
97
+ active={active && !threadId && !isInAgentSubRoute}
98
+ contextMenuItems={dropdownMenu}
99
+ disabled={editing}
100
+ icon={
101
+ <ActionIcon
102
+ color={fav ? cssVar.colorWarning : undefined}
103
+ fill={fav ? cssVar.colorWarning : 'transparent'}
104
+ icon={Star}
105
+ onClick={(e) => {
106
+ e.stopPropagation();
107
+ favoriteTopic(id, !fav);
108
+ }}
109
+ size={'small'}
110
+ />
111
+ }
112
+ loading={isLoading}
113
+ onClick={handleClick}
114
+ onDoubleClick={handleDoubleClick}
115
+ title={title}
116
+ />
123
117
  <Editing id={id} title={title} toggleEditing={toggleEditing} />
124
118
  {active && (
125
119
  <Suspense
@@ -1,7 +1,7 @@
1
1
  import { Icon, type MenuProps } from '@lobehub/ui';
2
2
  import { App } from 'antd';
3
3
  import { ExternalLink, LucideCopy, PencilLine, Trash, Wand2 } from 'lucide-react';
4
- import { useMemo } from 'react';
4
+ import { useCallback } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { isDesktop } from '@/const/version';
@@ -17,7 +17,7 @@ interface TopicItemDropdownMenuProps {
17
17
  export const useTopicItemDropdownMenu = ({
18
18
  id,
19
19
  toggleEditing,
20
- }: TopicItemDropdownMenuProps): MenuProps['items'] => {
20
+ }: TopicItemDropdownMenuProps): (() => MenuProps['items']) => {
21
21
  const { t } = useTranslation(['topic', 'common']);
22
22
  const { modal } = App.useApp();
23
23
 
@@ -30,7 +30,7 @@ export const useTopicItemDropdownMenu = ({
30
30
  s.removeTopic,
31
31
  ]);
32
32
 
33
- return useMemo(() => {
33
+ return useCallback(() => {
34
34
  if (!id) return [];
35
35
 
36
36
  return [
@@ -1,25 +1,16 @@
1
- import { ActionIcon, Dropdown, type MenuProps } from '@lobehub/ui';
1
+ import { ActionIcon, type DropdownItem, DropdownMenu } from '@lobehub/ui';
2
2
  import { MoreHorizontalIcon } from 'lucide-react';
3
3
  import { memo } from 'react';
4
4
 
5
5
  interface ActionProps {
6
- dropdownMenu: MenuProps['items'];
6
+ dropdownMenu: DropdownItem[] | (() => DropdownItem[]);
7
7
  }
8
8
 
9
9
  const Actions = memo<ActionProps>(({ dropdownMenu }) => {
10
10
  return (
11
- <Dropdown
12
- arrow={false}
13
- menu={{
14
- items: dropdownMenu,
15
- onClick: ({ domEvent }) => {
16
- domEvent.stopPropagation();
17
- },
18
- }}
19
- trigger={['click']}
20
- >
11
+ <DropdownMenu items={dropdownMenu}>
21
12
  <ActionIcon icon={MoreHorizontalIcon} size={'small'} />
22
- </Dropdown>
13
+ </DropdownMenu>
23
14
  );
24
15
  });
25
16
 
@@ -1,4 +1,4 @@
1
- import { Dropdown, Icon } from '@lobehub/ui';
1
+ import { Icon } from '@lobehub/ui';
2
2
  import { TreeDownRightIcon } from '@lobehub/ui/icons';
3
3
  import { cssVar } from 'antd-style';
4
4
  import { memo, useCallback } from 'react';
@@ -46,23 +46,15 @@ const ThreadItem = memo<ThreadItemProps>(({ title, id }) => {
46
46
 
47
47
  return (
48
48
  <>
49
- <Dropdown
50
- menu={{
51
- items: dropdownMenu,
52
- }}
53
- trigger={['contextMenu']}
54
- >
55
- <NavItem
56
- actions={<Actions dropdownMenu={dropdownMenu} />}
57
- active={active && !isInAgentSubRoute}
58
- disabled={editing}
59
- icon={
60
- <Icon color={cssVar.colorTextDescription} icon={TreeDownRightIcon} size={'small'} />
61
- }
62
- onClick={handleClick}
63
- title={title}
64
- />
65
- </Dropdown>
49
+ <NavItem
50
+ actions={<Actions dropdownMenu={dropdownMenu} />}
51
+ active={active && !isInAgentSubRoute}
52
+ contextMenuItems={dropdownMenu}
53
+ disabled={editing}
54
+ icon={<Icon color={cssVar.colorTextDescription} icon={TreeDownRightIcon} size={'small'} />}
55
+ onClick={handleClick}
56
+ title={title}
57
+ />
66
58
  <Editing id={id} title={title} toggleEditing={toggleEditing} />
67
59
  </>
68
60
  );
@@ -1,7 +1,7 @@
1
1
  import { Icon, type MenuProps } from '@lobehub/ui';
2
2
  import { App } from 'antd';
3
3
  import { PencilLine, Trash } from 'lucide-react';
4
- import { useMemo } from 'react';
4
+ import { useCallback } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { useChatStore } from '@/store/chat';
@@ -14,13 +14,13 @@ interface ThreadItemDropdownMenuProps {
14
14
  export const useThreadItemDropdownMenu = ({
15
15
  id,
16
16
  toggleEditing,
17
- }: ThreadItemDropdownMenuProps): MenuProps['items'] => {
17
+ }: ThreadItemDropdownMenuProps): (() => MenuProps['items']) => {
18
18
  const { t } = useTranslation(['thread', 'common']);
19
19
  const { modal } = App.useApp();
20
20
 
21
21
  const [removeThread] = useChatStore((s) => [s.removeThread]);
22
22
 
23
- return useMemo(() => {
23
+ return useCallback(() => {
24
24
  return [
25
25
  {
26
26
  icon: <Icon icon={PencilLine} />,
@@ -1,6 +1,4 @@
1
- import { ActionIcon, Tag } from '@lobehub/ui';
2
- import { Dropdown } from 'antd';
3
- import type { ItemType } from 'antd/es/menu/interface';
1
+ import { ActionIcon, DropdownMenu, type DropdownMenuCheckboxItem, Tag } from '@lobehub/ui';
4
2
  import { Clock3Icon, PlusIcon } from 'lucide-react';
5
3
  import { memo, useMemo } from 'react';
6
4
  import { useTranslation } from 'react-i18next';
@@ -32,15 +30,23 @@ const TopicSelector = memo<TopicSelectorProps>(({ agentId }) => {
32
30
  [topics, activeTopicId],
33
31
  );
34
32
 
35
- const items = useMemo<ItemType[]>(
33
+ const items = useMemo<DropdownMenuCheckboxItem[]>(
36
34
  () =>
37
35
  (topics || []).map((topic) => ({
36
+ checked: topic.id === activeTopicId,
37
+ closeOnClick: true,
38
38
  key: topic.id,
39
39
  label: topic.title,
40
- onClick: () => switchTopic(topic.id),
40
+ onCheckedChange: (checked) => {
41
+ if (checked) {
42
+ switchTopic(topic.id);
43
+ }
44
+ },
45
+ type: 'checkbox',
41
46
  })),
42
- [topics, t, switchTopic],
47
+ [topics, switchTopic, activeTopicId],
43
48
  );
49
+ const isEmpty = !topics || topics.length === 0;
44
50
 
45
51
  return (
46
52
  <NavHeader
@@ -53,22 +59,14 @@ const TopicSelector = memo<TopicSelectorProps>(({ agentId }) => {
53
59
  size={DESKTOP_HEADER_ICON_SIZE}
54
60
  title={t('actions.addNewTopic')}
55
61
  />
56
- <Dropdown
57
- disabled={!topics || topics.length === 0}
58
- menu={{
59
- items,
60
- selectedKeys: activeTopicId ? [activeTopicId] : [],
61
- }}
62
- overlayStyle={{
63
- maxHeight: 600,
64
- minWidth: 200,
65
- overflowY: 'auto',
66
- }}
62
+ <DropdownMenu
63
+ items={items}
67
64
  placement="bottomRight"
68
- trigger={['click']}
65
+ popupProps={{ style: { maxHeight: 600, minWidth: 200, overflowY: 'auto' } }}
66
+ triggerProps={{ disabled: isEmpty }}
69
67
  >
70
- <ActionIcon disabled={!topics || topics.length === 0} icon={Clock3Icon} />
71
- </Dropdown>
68
+ <ActionIcon disabled={isEmpty} icon={Clock3Icon} />
69
+ </DropdownMenu>
72
70
  </>
73
71
  }
74
72
  showTogglePanelButton={false}
@@ -1,6 +1,6 @@
1
1
  import { GROUP_CHAT_URL } from '@lobechat/const';
2
2
  import type { SidebarAgentItem } from '@lobechat/types';
3
- import { ActionIcon, Dropdown, Icon, type MenuProps } from '@lobehub/ui';
3
+ import { ActionIcon, Icon } from '@lobehub/ui';
4
4
  import { cssVar } from 'antd-style';
5
5
  import { Loader2, PinIcon } from 'lucide-react';
6
6
  import { type CSSProperties, type DragEvent, memo, useCallback, useMemo } from 'react';
@@ -85,7 +85,7 @@ const GroupItem = memo<GroupItemProps>(({ item, style, className }) => {
85
85
  return <GroupAvatar avatars={(avatar as any) || []} size={22} />;
86
86
  }, [isUpdating, avatar]);
87
87
 
88
- const dropdownMenu: MenuProps['items'] = useDropdownMenu({
88
+ const dropdownMenu = useDropdownMenu({
89
89
  group: undefined,
90
90
  id,
91
91
  openCreateGroupModal: () => {}, // Groups don't need this
@@ -97,29 +97,23 @@ const GroupItem = memo<GroupItemProps>(({ item, style, className }) => {
97
97
 
98
98
  return (
99
99
  <>
100
- <Dropdown
101
- menu={{
102
- items: dropdownMenu,
103
- }}
104
- trigger={['contextMenu']}
105
- >
106
- <Link aria-label={id} to={groupUrl}>
107
- <NavItem
108
- actions={<Actions dropdownMenu={dropdownMenu} />}
109
- className={className}
110
- disabled={editing || isUpdating}
111
- draggable={!editing && !isUpdating}
112
- extra={pinIcon}
113
- icon={avatarIcon}
114
- key={id}
115
- onDoubleClick={handleDoubleClick}
116
- onDragEnd={handleDragEnd}
117
- onDragStart={handleDragStart}
118
- style={style}
119
- title={displayTitle}
120
- />
121
- </Link>
122
- </Dropdown>
100
+ <Link aria-label={id} to={groupUrl}>
101
+ <NavItem
102
+ actions={<Actions dropdownMenu={dropdownMenu} />}
103
+ className={className}
104
+ contextMenuItems={dropdownMenu}
105
+ disabled={editing || isUpdating}
106
+ draggable={!editing && !isUpdating}
107
+ extra={pinIcon}
108
+ icon={avatarIcon}
109
+ key={id}
110
+ onDoubleClick={handleDoubleClick}
111
+ onDragEnd={handleDragEnd}
112
+ onDragStart={handleDragStart}
113
+ style={style}
114
+ title={displayTitle}
115
+ />
116
+ </Link>
123
117
  <Editing id={id} title={displayTitle} toggleEditing={toggleEditing} />
124
118
  </>
125
119
  );
@@ -1,6 +1,6 @@
1
1
  import { SESSION_CHAT_URL } from '@lobechat/const';
2
2
  import type { SidebarAgentItem } from '@lobechat/types';
3
- import { ActionIcon, Dropdown, Icon, type MenuProps } from '@lobehub/ui';
3
+ import { ActionIcon, Icon } from '@lobehub/ui';
4
4
  import { cssVar } from 'antd-style';
5
5
  import { Loader2, PinIcon } from 'lucide-react';
6
6
  import { type CSSProperties, type DragEvent, memo, useCallback, useMemo } from 'react';
@@ -96,7 +96,7 @@ const AgentItem = memo<AgentItemProps>(({ item, style, className }) => {
96
96
  return <Avatar avatar={typeof avatar === 'string' ? avatar : undefined} />;
97
97
  }, [isUpdating, avatar]);
98
98
 
99
- const dropdownMenu: MenuProps['items'] = useDropdownMenu({
99
+ const dropdownMenu = useDropdownMenu({
100
100
  group: undefined, // TODO: pass group from parent if needed
101
101
  id,
102
102
  openCreateGroupModal: handleOpenCreateGroupModal,
@@ -108,30 +108,25 @@ const AgentItem = memo<AgentItemProps>(({ item, style, className }) => {
108
108
 
109
109
  return (
110
110
  <>
111
- <Dropdown
112
- menu={{
113
- items: dropdownMenu,
114
- }}
115
- trigger={['contextMenu']}
116
- >
117
- <Link aria-label={id} to={agentUrl}>
118
- <NavItem
119
- actions={<Actions dropdownMenu={dropdownMenu} />}
120
- className={className}
121
- disabled={editing || isUpdating}
122
- draggable={!editing && !isUpdating}
123
- extra={pinIcon}
124
- icon={avatarIcon}
125
- key={id}
126
- loading={isLoading}
127
- onDoubleClick={handleDoubleClick}
128
- onDragEnd={handleDragEnd}
129
- onDragStart={handleDragStart}
130
- style={style}
131
- title={displayTitle}
132
- />
133
- </Link>
134
- </Dropdown>
111
+ <Link aria-label={id} to={agentUrl}>
112
+ <NavItem
113
+ actions={<Actions dropdownMenu={dropdownMenu} />}
114
+ className={className}
115
+ contextMenuItems={dropdownMenu}
116
+ disabled={editing || isUpdating}
117
+ draggable={!editing && !isUpdating}
118
+ extra={pinIcon}
119
+ icon={avatarIcon}
120
+ key={id}
121
+ loading={isLoading}
122
+ onDoubleClick={handleDoubleClick}
123
+ onDragEnd={handleDragEnd}
124
+ onDragStart={handleDragStart}
125
+ style={style}
126
+ title={displayTitle}
127
+ />
128
+ </Link>
129
+
135
130
  <Editing
136
131
  avatar={typeof avatar === 'string' ? avatar : undefined}
137
132
  id={id}