@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,4 +1,4 @@
1
- import { Button, Center, Checkbox, Flexbox, Icon } from '@lobehub/ui';
1
+ import { Button, Center, Checkbox, ContextMenuTrigger, Flexbox, Icon } from '@lobehub/ui';
2
2
  import { App, Input } from 'antd';
3
3
  import { createStaticStyles, cssVar, cx } from 'antd-style';
4
4
  import dayjs from 'dayjs';
@@ -23,6 +23,7 @@ import { formatSize } from '@/utils/format';
23
23
  import { isChunkingUnsupported } from '@/utils/isChunkingUnsupported';
24
24
 
25
25
  import DropdownMenu from '../../ItemDropdown/DropdownMenu';
26
+ import { useFileItemDropdown } from '../../ItemDropdown/useFileItemDropdown';
26
27
  import ChunksBadge from './ChunkTag';
27
28
 
28
29
  dayjs.extend(relativeTime);
@@ -37,10 +38,6 @@ const styles = createStaticStyles(({ css }) => {
37
38
 
38
39
  &:hover {
39
40
  background: ${cssVar.colorFillTertiary};
40
-
41
- .file-list-item-hover {
42
- opacity: 1;
43
- }
44
41
  }
45
42
  `,
46
43
 
@@ -58,12 +55,14 @@ const styles = createStaticStyles(({ css }) => {
58
55
  opacity: 0.5;
59
56
  `,
60
57
 
61
- hover: cx(
62
- 'file-list-item-hover',
63
- css`
64
- opacity: 0;
65
- `,
66
- ),
58
+ hover: css`
59
+ opacity: 0;
60
+
61
+ &[data-popup-open],
62
+ .file-list-item-group:hover & {
63
+ opacity: 1;
64
+ }
65
+ `,
67
66
  item: css`
68
67
  padding-block: 0;
69
68
  padding-inline: 0 24px;
@@ -324,169 +323,172 @@ const FileListItem = memo<FileListItemProps>(
324
323
  }
325
324
  }, [pendingRenameItemId, id, isFolder, resourceManagerState]);
326
325
 
326
+ const { menuItems } = useFileItemDropdown({
327
+ fileType,
328
+ filename: name,
329
+ id,
330
+ knowledgeBaseId: resourceManagerState.libraryId,
331
+ onRenameStart: isFolder ? handleRenameStart : undefined,
332
+ sourceType,
333
+ url,
334
+ });
335
+
327
336
  return (
328
- <Flexbox
329
- align={'center'}
330
- className={cx(
331
- styles.container,
332
- selected && styles.selected,
333
- isDragging && styles.dragging,
334
- isOver && styles.dragOver,
335
- )}
336
- data-drop-target-id={id}
337
- data-is-folder={String(isFolder)}
338
- draggable={!!resourceManagerState.libraryId}
339
- height={48}
340
- horizontal
341
- onDragEnd={handleDragEnd}
342
- onDragLeave={handleDragLeave}
343
- onDragOver={handleDragOver}
344
- onDragStart={handleDragStart}
345
- onDrop={handleDrop}
346
- paddingInline={8}
347
- style={{
348
- borderBlockEnd: `1px solid ${cssVar.colorBorderSecondary}`,
349
- }}
350
- >
337
+ <ContextMenuTrigger items={menuItems}>
351
338
  <Flexbox
352
339
  align={'center'}
353
- className={styles.item}
354
- distribution={'space-between'}
355
- flex={1}
340
+ className={cx(
341
+ styles.container,
342
+ 'file-list-item-group',
343
+ selected && styles.selected,
344
+ isDragging && styles.dragging,
345
+ isOver && styles.dragOver,
346
+ )}
347
+ data-drop-target-id={id}
348
+ data-is-folder={String(isFolder)}
349
+ draggable={!!resourceManagerState.libraryId}
350
+ height={48}
356
351
  horizontal
357
- onClick={handleItemClick}
352
+ onDragEnd={handleDragEnd}
353
+ onDragLeave={handleDragLeave}
354
+ onDragOver={handleDragOver}
355
+ onDragStart={handleDragStart}
356
+ onDrop={handleDrop}
357
+ paddingInline={8}
358
+ style={{
359
+ borderBlockEnd: `1px solid ${cssVar.colorBorderSecondary}`,
360
+ }}
358
361
  >
359
- <Flexbox align={'center'} className={styles.nameContainer} horizontal>
360
- <Center
361
- height={48}
362
+ <Flexbox
363
+ align={'center'}
364
+ className={styles.item}
365
+ distribution={'space-between'}
366
+ flex={1}
367
+ horizontal
368
+ onClick={handleItemClick}
369
+ >
370
+ <Flexbox align={'center'} className={styles.nameContainer} horizontal>
371
+ <Center
372
+ height={48}
373
+ onClick={(e) => {
374
+ e.stopPropagation();
375
+
376
+ onSelectedChange(id, !selected, e.shiftKey, index);
377
+ }}
378
+ onPointerDown={(e) => e.stopPropagation()}
379
+ style={{ paddingInline: 4 }}
380
+ >
381
+ <Checkbox checked={selected} />
382
+ </Center>
383
+ <Flexbox
384
+ align={'center'}
385
+ justify={'center'}
386
+ style={{ fontSize: 24, marginInline: 8, width: 24 }}
387
+ >
388
+ {isFolder ? (
389
+ <Icon icon={FolderIcon} size={24} />
390
+ ) : isPage ? (
391
+ emoji ? (
392
+ <span style={{ fontSize: 24 }}>{emoji}</span>
393
+ ) : (
394
+ <Center height={24} width={24}>
395
+ <Icon icon={FileText} size={24} />
396
+ </Center>
397
+ )
398
+ ) : (
399
+ <FileIcon fileName={name} fileType={fileType} size={24} />
400
+ )}
401
+ </Flexbox>
402
+ {isRenaming && isFolder ? (
403
+ <Input
404
+ onBlur={handleRenameConfirm}
405
+ onChange={(e) => setRenamingValue(e.target.value)}
406
+ onClick={(e) => e.stopPropagation()}
407
+ onKeyDown={(e) => {
408
+ if (e.key === 'Enter') {
409
+ e.preventDefault();
410
+ handleRenameConfirm();
411
+ } else if (e.key === 'Escape') {
412
+ e.preventDefault();
413
+ handleRenameCancel();
414
+ }
415
+ }}
416
+ onPointerDown={(e) => e.stopPropagation()}
417
+ ref={inputRef}
418
+ size="small"
419
+ style={{ flex: 1, maxWidth: 400 }}
420
+ value={renamingValue}
421
+ />
422
+ ) : (
423
+ <span className={styles.name}>{name || t('file:pageList.untitled')}</span>
424
+ )}
425
+ </Flexbox>
426
+ <Flexbox
427
+ align={'center'}
428
+ gap={8}
429
+ horizontal
362
430
  onClick={(e) => {
363
431
  e.stopPropagation();
364
-
365
- onSelectedChange(id, !selected, e.shiftKey, index);
366
432
  }}
367
433
  onPointerDown={(e) => e.stopPropagation()}
368
- style={{ paddingInline: 4 }}
369
434
  >
370
- <Checkbox checked={selected} />
371
- </Center>
372
- <Flexbox
373
- align={'center'}
374
- justify={'center'}
375
- style={{ fontSize: 24, marginInline: 8, width: 24 }}
376
- >
377
- {isFolder ? (
378
- <Icon icon={FolderIcon} size={24} />
379
- ) : isPage ? (
380
- emoji ? (
381
- <span style={{ fontSize: 24 }}>{emoji}</span>
435
+ {!isFolder &&
436
+ (fileStoreState.isCreatingFileParseTask ||
437
+ isNull(chunkingStatus) ||
438
+ !chunkingStatus ? (
439
+ <div
440
+ className={fileStoreState.isCreatingFileParseTask ? undefined : styles.hover}
441
+ title={t(
442
+ isSupportedForChunking
443
+ ? 'FileManager.actions.chunkingTooltip'
444
+ : 'FileManager.actions.chunkingUnsupported',
445
+ )}
446
+ >
447
+ <Button
448
+ disabled={!isSupportedForChunking}
449
+ icon={FileBoxIcon}
450
+ loading={fileStoreState.isCreatingFileParseTask}
451
+ onClick={() => {
452
+ fileStoreState.parseFiles([id]);
453
+ }}
454
+ size={'small'}
455
+ type={'text'}
456
+ >
457
+ {t(
458
+ fileStoreState.isCreatingFileParseTask
459
+ ? 'FileManager.actions.createChunkingTask'
460
+ : 'FileManager.actions.chunking',
461
+ )}
462
+ </Button>
463
+ </div>
382
464
  ) : (
383
- <Center height={24} width={24}>
384
- <Icon icon={FileText} size={24} />
385
- </Center>
386
- )
387
- ) : (
388
- <FileIcon fileName={name} fileType={fileType} size={24} />
389
- )}
465
+ <div style={{ cursor: 'default' }}>
466
+ <ChunksBadge
467
+ chunkCount={chunkCount}
468
+ chunkingError={chunkingError}
469
+ chunkingStatus={chunkingStatus}
470
+ embeddingError={embeddingError}
471
+ embeddingStatus={embeddingStatus}
472
+ finishEmbedding={finishEmbedding}
473
+ id={id}
474
+ />
475
+ </div>
476
+ ))}
477
+ <DropdownMenu className={styles.hover} items={menuItems} />
390
478
  </Flexbox>
391
- {isRenaming && isFolder ? (
392
- <Input
393
- onBlur={handleRenameConfirm}
394
- onChange={(e) => setRenamingValue(e.target.value)}
395
- onClick={(e) => e.stopPropagation()}
396
- onKeyDown={(e) => {
397
- if (e.key === 'Enter') {
398
- e.preventDefault();
399
- handleRenameConfirm();
400
- } else if (e.key === 'Escape') {
401
- e.preventDefault();
402
- handleRenameCancel();
403
- }
404
- }}
405
- onPointerDown={(e) => e.stopPropagation()}
406
- ref={inputRef}
407
- size="small"
408
- style={{ flex: 1, maxWidth: 400 }}
409
- value={renamingValue}
410
- />
411
- ) : (
412
- <span className={styles.name}>{name || t('file:pageList.untitled')}</span>
413
- )}
414
- </Flexbox>
415
- <Flexbox
416
- align={'center'}
417
- gap={8}
418
- horizontal
419
- onClick={(e) => {
420
- e.stopPropagation();
421
- }}
422
- onPointerDown={(e) => e.stopPropagation()}
423
- >
424
- {!isFolder &&
425
- (fileStoreState.isCreatingFileParseTask ||
426
- isNull(chunkingStatus) ||
427
- !chunkingStatus ? (
428
- <div
429
- className={fileStoreState.isCreatingFileParseTask ? undefined : styles.hover}
430
- title={t(
431
- isSupportedForChunking
432
- ? 'FileManager.actions.chunkingTooltip'
433
- : 'FileManager.actions.chunkingUnsupported',
434
- )}
435
- >
436
- <Button
437
- disabled={!isSupportedForChunking}
438
- icon={FileBoxIcon}
439
- loading={fileStoreState.isCreatingFileParseTask}
440
- onClick={() => {
441
- fileStoreState.parseFiles([id]);
442
- }}
443
- size={'small'}
444
- type={'text'}
445
- >
446
- {t(
447
- fileStoreState.isCreatingFileParseTask
448
- ? 'FileManager.actions.createChunkingTask'
449
- : 'FileManager.actions.chunking',
450
- )}
451
- </Button>
452
- </div>
453
- ) : (
454
- <div style={{ cursor: 'default' }}>
455
- <ChunksBadge
456
- chunkCount={chunkCount}
457
- chunkingError={chunkingError}
458
- chunkingStatus={chunkingStatus}
459
- embeddingError={embeddingError}
460
- embeddingStatus={embeddingStatus}
461
- finishEmbedding={finishEmbedding}
462
- id={id}
463
- />
464
- </div>
465
- ))}
466
- <div className={styles.hover}>
467
- <DropdownMenu
468
- fileType={fileType}
469
- filename={name}
470
- id={id}
471
- knowledgeBaseId={resourceManagerState.libraryId}
472
- onRenameStart={isFolder ? handleRenameStart : undefined}
473
- sourceType={sourceType}
474
- url={url}
475
- />
476
- </div>
477
479
  </Flexbox>
480
+ {!isDragging && (
481
+ <>
482
+ <Flexbox className={styles.item} width={FILE_DATE_WIDTH}>
483
+ {displayTime}
484
+ </Flexbox>
485
+ <Flexbox className={styles.item} width={FILE_SIZE_WIDTH}>
486
+ {isFolder || isPage ? '-' : formatSize(size)}
487
+ </Flexbox>
488
+ </>
489
+ )}
478
490
  </Flexbox>
479
- {!isDragging && (
480
- <>
481
- <Flexbox className={styles.item} width={FILE_DATE_WIDTH}>
482
- {displayTime}
483
- </Flexbox>
484
- <Flexbox className={styles.item} width={FILE_SIZE_WIDTH}>
485
- {isFolder || isPage ? '-' : formatSize(size)}
486
- </Flexbox>
487
- </>
488
- )}
489
- </Flexbox>
491
+ </ContextMenuTrigger>
490
492
  );
491
493
  },
492
494
  );
@@ -1,4 +1,4 @@
1
- import { Checkbox } from '@lobehub/ui';
1
+ import { Checkbox, showContextMenu } from '@lobehub/ui';
2
2
  import { createStaticStyles, cssVar, cx } from 'antd-style';
3
3
  import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { useNavigate, useSearchParams } from 'react-router-dom';
@@ -13,6 +13,7 @@ import { documentService } from '@/services/document';
13
13
  import { type FileListItem } from '@/types/files';
14
14
 
15
15
  import DropdownMenu from '../../ItemDropdown/DropdownMenu';
16
+ import { useFileItemDropdown } from '../../ItemDropdown/useFileItemDropdown';
16
17
  import DefaultFileItem from './DefaultFileItem';
17
18
  import ImageFileItem from './ImageFileItem';
18
19
  import MarkdownFileItem from './MarkdownFileItem';
@@ -346,6 +347,15 @@ const MasonryFileItem = memo<MasonryFileItemProps>(
346
347
  }
347
348
  }, [isMarkdown, isPage, url, isInView, markdownContent, id]);
348
349
 
350
+ const { menuItems } = useFileItemDropdown({
351
+ fileType,
352
+ filename: name,
353
+ id,
354
+ knowledgeBaseId,
355
+ sourceType,
356
+ url,
357
+ });
358
+
349
359
  return (
350
360
  <div
351
361
  className={cx(
@@ -357,6 +367,10 @@ const MasonryFileItem = memo<MasonryFileItemProps>(
357
367
  data-drop-target-id={id}
358
368
  data-is-folder={isFolder}
359
369
  draggable={!!knowledgeBaseId}
370
+ onContextMenu={(e) => {
371
+ e.preventDefault();
372
+ showContextMenu(menuItems());
373
+ }}
360
374
  onDragEnd={handleDragEnd}
361
375
  onDragLeave={handleDragLeave}
362
376
  onDragOver={handleDragOver}
@@ -379,13 +393,7 @@ const MasonryFileItem = memo<MasonryFileItemProps>(
379
393
  onClick={(e) => e.stopPropagation()}
380
394
  onPointerDown={(e) => e.stopPropagation()}
381
395
  >
382
- <DropdownMenu
383
- fileType={fileType}
384
- filename={name}
385
- id={id}
386
- knowledgeBaseId={knowledgeBaseId}
387
- url={url}
388
- />
396
+ <DropdownMenu items={menuItems} />
389
397
  </div>
390
398
 
391
399
  <div
@@ -10,14 +10,15 @@ interface ActionIconWithChevronProps extends ComponentProps<typeof Button> {
10
10
  }
11
11
 
12
12
  const ActionIconWithChevron = memo<ActionIconWithChevronProps>(
13
- ({ icon, title, style, disabled, type = 'text', ...rest }) => {
13
+ ({ icon, title, style, disabled, className, ...rest }) => {
14
14
  return (
15
15
  <Button
16
+ {...rest}
17
+ className={className}
16
18
  disabled={disabled}
17
19
  style={{ paddingInline: 4, ...style }}
18
20
  title={title}
19
- type={type}
20
- {...rest}
21
+ type={'text'}
21
22
  >
22
23
  <Flexbox align={'center'} gap={4} horizontal>
23
24
  <Icon color={cssVar.colorIcon} icon={icon} size={18} />
@@ -1,6 +1,5 @@
1
- import { Icon } from '@lobehub/ui';
2
- import { App, Dropdown } from 'antd';
3
- import type { MenuProps } from 'antd';
1
+ import { type DropdownItem, DropdownMenu, Icon } from '@lobehub/ui';
2
+ import { App } from 'antd';
4
3
  import {
5
4
  BookMinusIcon,
6
5
  BookPlusIcon,
@@ -36,8 +35,8 @@ const BatchActionsDropdown = memo<BatchActionsDropdownProps>(
36
35
 
37
36
  const libraryId = useResourceManagerStore((s) => s.libraryId);
38
37
 
39
- const menuItems = useMemo<MenuProps['items']>(() => {
40
- const items: MenuProps['items'] = [];
38
+ const menuItems = useMemo<DropdownItem[]>(() => {
39
+ const items: DropdownItem[] = [];
41
40
 
42
41
  // Show delete library option only when in a knowledge base and no files selected
43
42
  if (libraryId && selectCount === 0) {
@@ -138,18 +137,13 @@ const BatchActionsDropdown = memo<BatchActionsDropdownProps>(
138
137
  }, [libraryId, selectCount, onActionClick, t, modal, message]);
139
138
 
140
139
  return (
141
- <Dropdown
142
- disabled={disabled}
143
- menu={{ items: menuItems }}
144
- placement="bottomLeft"
145
- trigger={['click']}
146
- >
140
+ <DropdownMenu items={menuItems} placement="bottomLeft" triggerProps={{ disabled }}>
147
141
  <ActionIconWithChevron
148
142
  disabled={disabled}
149
143
  icon={CircleEllipsisIcon}
150
144
  title={t('FileManager.actions.batchActions', 'Batch actions')}
151
145
  />
152
- </Dropdown>
146
+ </DropdownMenu>
153
147
  );
154
148
  },
155
149
  );
@@ -1,5 +1,4 @@
1
- import { Dropdown } from 'antd';
2
- import type { MenuProps } from 'antd';
1
+ import { type DropdownItem, DropdownMenu } from '@lobehub/ui';
3
2
  import { ArrowDownAZ } from 'lucide-react';
4
3
  import { memo, useMemo } from 'react';
5
4
  import { useTranslation } from 'react-i18next';
@@ -22,22 +21,23 @@ const SortDropdown = memo(() => {
22
21
  [t],
23
22
  );
24
23
 
25
- const menuItems: MenuProps['items'] = sortOptions.map((option) => ({
24
+ const menuItems: DropdownItem[] = sortOptions.map((option) => ({
26
25
  key: option.key,
27
26
  label: option.label,
28
27
  onClick: () => setSorter(option.key as 'name' | 'createdAt' | 'size'),
28
+ style:
29
+ option.key === (sorter || 'createdAt')
30
+ ? { backgroundColor: 'var(--ant-control-item-bg-active)' }
31
+ : {},
29
32
  }));
30
33
 
31
34
  const currentSortLabel =
32
35
  sortOptions.find((option) => option.key === sorter)?.label || t('FileManager.sort.dateAdded');
33
36
 
34
37
  return (
35
- <Dropdown
36
- menu={{ items: menuItems, selectedKeys: [sorter || 'createdAt'] }}
37
- trigger={['click']}
38
- >
38
+ <DropdownMenu items={menuItems}>
39
39
  <ActionIconWithChevron icon={ArrowDownAZ} title={currentSortLabel} />
40
- </Dropdown>
40
+ </DropdownMenu>
41
41
  );
42
42
  });
43
43
 
@@ -1,6 +1,4 @@
1
- import { Icon } from '@lobehub/ui';
2
- import { Dropdown } from 'antd';
3
- import type { MenuProps } from 'antd';
1
+ import { type DropdownItem, DropdownMenu, Icon } from '@lobehub/ui';
4
2
  import { Grid3x3Icon, ListIcon } from 'lucide-react';
5
3
  import { memo, useMemo } from 'react';
6
4
  import { useTranslation } from 'react-i18next';
@@ -20,31 +18,30 @@ const ViewSwitcher = memo(() => {
20
18
  const currentViewLabel =
21
19
  viewMode === 'list' ? t('FileManager.view.list') : t('FileManager.view.masonry');
22
20
 
23
- const menuItems = useMemo<MenuProps['items']>(() => {
21
+ const menuItems = useMemo<DropdownItem[]>(() => {
24
22
  return [
25
23
  {
26
24
  icon: <Icon icon={ListIcon} />,
27
25
  key: 'list',
28
26
  label: t('FileManager.view.list'),
29
27
  onClick: () => setViewMode('list'),
28
+ style: viewMode === 'list' ? { backgroundColor: 'var(--ant-control-item-bg-active)' } : {},
30
29
  },
31
30
  {
32
31
  icon: <Icon icon={Grid3x3Icon} />,
33
32
  key: 'masonry',
34
33
  label: t('FileManager.view.masonry'),
35
34
  onClick: () => setViewMode('masonry'),
35
+ style:
36
+ viewMode === 'masonry' ? { backgroundColor: 'var(--ant-control-item-bg-active)' } : {},
36
37
  },
37
38
  ];
38
- }, [setViewMode, t]);
39
+ }, [setViewMode, t, viewMode]);
39
40
 
40
41
  return (
41
- <Dropdown
42
- menu={{ items: menuItems, selectedKeys: [viewMode] }}
43
- placement="bottomRight"
44
- trigger={['click']}
45
- >
42
+ <DropdownMenu items={menuItems} placement="bottomRight">
46
43
  <ActionIconWithChevron icon={currentViewIcon} title={currentViewLabel} />
47
- </Dropdown>
44
+ </DropdownMenu>
48
45
  );
49
46
  });
50
47