@lobehub/lobehub 2.0.0-next.54 → 2.0.0-next.55
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.
- package/CHANGELOG.md +27 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/common.json +1 -0
- package/locales/ar/file.json +85 -2
- package/locales/bg-BG/common.json +1 -0
- package/locales/bg-BG/file.json +85 -2
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/file.json +85 -2
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/file.json +85 -2
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/file.json +85 -2
- package/locales/fa-IR/common.json +1 -0
- package/locales/fa-IR/file.json +85 -2
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/file.json +85 -2
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/file.json +85 -2
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/file.json +85 -2
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/file.json +85 -2
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/file.json +85 -2
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/file.json +85 -2
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/file.json +85 -2
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/file.json +85 -2
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/file.json +85 -2
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/file.json +85 -2
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/file.json +85 -2
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/file.json +85 -2
- package/package.json +1 -1
- package/packages/database/src/models/__tests__/file.test.ts +94 -29
- package/packages/database/src/models/file.ts +15 -4
- package/packages/database/src/repositories/knowledge/index.test.ts +300 -0
- package/packages/database/src/repositories/knowledge/index.ts +420 -0
- package/packages/model-bank/src/aiModels/aihubmix.ts +1 -0
- package/packages/model-bank/src/aiModels/google.ts +9 -5
- package/packages/model-bank/src/aiModels/openai.ts +2 -35
- package/packages/model-bank/src/aiModels/openrouter.ts +1 -0
- package/packages/model-bank/src/aiModels/vertexai.ts +2 -0
- package/packages/model-bank/src/types/aiModel.ts +15 -2
- package/packages/model-runtime/src/core/usageConverters/index.ts +1 -0
- package/packages/model-runtime/src/core/usageConverters/utils/resolveImageSinglePrice.ts +34 -0
- package/packages/types/src/document/index.ts +14 -2
- package/packages/types/src/files/index.ts +2 -0
- package/packages/types/src/files/list.ts +10 -0
- package/packages/types/src/llm.ts +1 -1
- package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/ModelSelect/ImageModelItem.tsx +93 -0
- package/src/app/[variants]/(main)/image/@menu/features/ConfigPanel/components/{ModelSelect.tsx → ModelSelect/index.tsx} +17 -2
- package/src/app/[variants]/(main)/knowledge/KnowledgeRouter.tsx +2 -1
- package/src/app/[variants]/(main)/knowledge/components/KnowledgeBaseItem/index.tsx +0 -2
- package/src/app/[variants]/(main)/knowledge/hooks/useFileCategory.ts +6 -3
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeBaseDetail/index.tsx +2 -2
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeBaseDetail/menu/{MenuItems.tsx → CategoryMenu.tsx} +3 -3
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeBaseDetail/menu/Menu.tsx +2 -2
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/index.tsx +40 -18
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/layout/Container.tsx +1 -1
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/menu/CategoryMenu.tsx +148 -0
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/menu/KnowledgeBase.tsx +20 -7
- package/src/components/FileIcon/index.tsx +3 -1
- package/src/features/ChatInput/ActionBar/Knowledge/index.tsx +2 -2
- package/src/features/FileSidePanel/index.tsx +1 -1
- package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/MasonryItem.tsx +80 -0
- package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/Item/MasonryItemWrapper.tsx +27 -0
- package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/List.tsx +104 -23
- package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/MasonrySkeleton.tsx +62 -0
- package/src/features/KnowledgeBaseModal/AssignKnowledgeBase/index.tsx +3 -2
- package/src/features/KnowledgeBaseModal/CreateNew/CreateForm.tsx +1 -1
- package/src/features/KnowledgeManager/DocumentExplorer/DocumentActions.tsx +111 -0
- package/src/features/KnowledgeManager/DocumentExplorer/DocumentEditor.tsx +723 -0
- package/src/features/KnowledgeManager/DocumentExplorer/DocumentEditorPlaceholder.tsx +169 -0
- package/src/features/KnowledgeManager/DocumentExplorer/DocumentListItem.tsx +148 -0
- package/src/features/KnowledgeManager/DocumentExplorer/DocumentListSkeleton.tsx +39 -0
- package/src/features/KnowledgeManager/DocumentExplorer/NoteEditorModal.tsx +348 -0
- package/src/features/KnowledgeManager/DocumentExplorer/RenamePopover.tsx +163 -0
- package/src/features/KnowledgeManager/DocumentExplorer/index.tsx +318 -0
- package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/FileListItem/index.tsx +48 -9
- package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/DefaultFileItem.tsx +149 -0
- package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/ImageFileItem.tsx +245 -0
- package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/MarkdownFileItem.tsx +232 -0
- package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/NoteFileItem.tsx +230 -0
- package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/index.tsx +398 -0
- package/src/features/KnowledgeManager/FileExplorer/ToolBar/ViewSwitcher.tsx +45 -0
- package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/index.tsx +68 -16
- package/src/features/KnowledgeManager/Header/AddButton.tsx +107 -0
- package/src/features/KnowledgeManager/Header/NewNoteButton.tsx +33 -0
- package/src/features/{FileManager → KnowledgeManager}/Header/index.tsx +3 -9
- package/src/features/KnowledgeManager/Home/RecentDocumentCard.tsx +116 -0
- package/src/features/KnowledgeManager/Home/RecentDocuments.tsx +77 -0
- package/src/features/KnowledgeManager/Home/RecentFileCard.tsx +121 -0
- package/src/features/KnowledgeManager/Home/RecentFiles.tsx +73 -0
- package/src/features/KnowledgeManager/Home/RecentFilesSkeleton.tsx +83 -0
- package/src/features/KnowledgeManager/Home/UploadEntries.tsx +208 -0
- package/src/features/KnowledgeManager/Home/index.tsx +221 -0
- package/src/features/KnowledgeManager/index.tsx +75 -0
- package/src/features/Portal/FilePreview/Body/index.tsx +1 -1
- package/src/features/Portal/FilePreview/Header.tsx +1 -1
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/file.ts +85 -2
- package/src/server/routers/lambda/__tests__/file.test.ts +85 -6
- package/src/server/routers/lambda/document.ts +57 -0
- package/src/server/routers/lambda/file.ts +72 -0
- package/src/server/routers/lambda/knowledge.ts +94 -0
- package/src/server/services/document/index.ts +103 -0
- package/src/services/document/index.ts +44 -0
- package/src/services/file/index.ts +5 -3
- package/src/store/aiInfra/slices/aiProvider/__tests__/action.test.ts +125 -229
- package/src/store/aiInfra/slices/aiProvider/action.ts +113 -33
- package/src/store/file/initialState.ts +6 -1
- package/src/store/file/slices/chat/action.ts +3 -3
- package/src/store/file/slices/document/action.ts +359 -0
- package/src/store/file/slices/document/index.ts +3 -0
- package/src/store/file/slices/document/initialState.ts +22 -0
- package/src/store/file/slices/document/selectors.ts +25 -0
- package/src/store/file/slices/fileManager/action.test.ts +16 -9
- package/src/store/file/slices/fileManager/action.ts +11 -11
- package/src/store/file/store.ts +3 -0
- package/src/store/global/initialState.ts +3 -1
- package/src/app/[variants]/(main)/knowledge/routes/KnowledgeHome/menu/FileMenu.tsx +0 -75
- package/src/features/FileManager/FileList/MasonryFileItem/index.tsx +0 -582
- package/src/features/FileManager/index.tsx +0 -36
- /package/src/features/{FileManager/FileList/ToolBar → KnowledgeBaseModal/AssignKnowledgeBase}/ViewSwitcher.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/ChunkList/ChunkItem.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/ChunkList/index.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/Content.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/Loading/index.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/SimilaritySearchList/Item.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/SimilaritySearchList/index.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/ChunkDrawer/index.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/EmptyStatus.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/FileListItem/ChunkTag.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/FileListItem/DropdownMenu.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/FileSkeleton.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/MasonryFileItem/MasonryItemWrapper.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/MasonrySkeleton.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/ToolBar/Config.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/ToolBar/MultiSelectActions.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/ToolBar/index.tsx +0 -0
- /package/src/features/{FileManager/FileList → KnowledgeManager/FileExplorer}/useCheckTaskStatus.ts +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/Header/FilesSearchBar.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/Header/TogglePanelButton.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/Header/UploadFileButton.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/UploadDock/Item.tsx +0 -0
- /package/src/features/{FileManager → KnowledgeManager}/UploadDock/index.tsx +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import { FileListItem } from '@/types/files';
|
|
7
|
+
|
|
8
|
+
import RecentFileCard from './RecentFileCard';
|
|
9
|
+
import RecentFilesSkeleton from './RecentFilesSkeleton';
|
|
10
|
+
|
|
11
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
12
|
+
container: css`
|
|
13
|
+
position: relative;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
`,
|
|
16
|
+
fadeEdge: css`
|
|
17
|
+
pointer-events: none;
|
|
18
|
+
|
|
19
|
+
position: absolute;
|
|
20
|
+
inset-block: 0 0;
|
|
21
|
+
inset-inline-end: 0;
|
|
22
|
+
|
|
23
|
+
width: 80px;
|
|
24
|
+
|
|
25
|
+
background: linear-gradient(to left, ${token.colorBgContainerSecondary}, transparent);
|
|
26
|
+
`,
|
|
27
|
+
scrollContainer: css`
|
|
28
|
+
scroll-behavior: smooth;
|
|
29
|
+
|
|
30
|
+
/* Hide scrollbar */
|
|
31
|
+
scrollbar-width: none;
|
|
32
|
+
|
|
33
|
+
overflow: auto hidden;
|
|
34
|
+
display: flex;
|
|
35
|
+
gap: 16px;
|
|
36
|
+
|
|
37
|
+
padding-block-end: 8px;
|
|
38
|
+
padding-inline-end: 80px;
|
|
39
|
+
|
|
40
|
+
-ms-overflow-style: none;
|
|
41
|
+
|
|
42
|
+
&::-webkit-scrollbar {
|
|
43
|
+
display: none;
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
interface RecentFilesProps {
|
|
49
|
+
files: FileListItem[];
|
|
50
|
+
isLoading?: boolean;
|
|
51
|
+
onOpenFile: (id: string) => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const RecentFiles = memo<RecentFilesProps>(({ files, isLoading, onOpenFile }) => {
|
|
55
|
+
const { styles } = useStyles();
|
|
56
|
+
|
|
57
|
+
if (isLoading) {
|
|
58
|
+
return <RecentFilesSkeleton />;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className={styles.container}>
|
|
63
|
+
<div className={styles.scrollContainer}>
|
|
64
|
+
{files.map((file) => (
|
|
65
|
+
<RecentFileCard file={file} key={file.id} onClick={() => onOpenFile(file.id)} />
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
<div className={styles.fadeEdge} />
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export default RecentFiles;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Skeleton } from 'antd';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
9
|
+
card: css`
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
|
|
12
|
+
width: 280px;
|
|
13
|
+
padding: 12px;
|
|
14
|
+
border: 1px solid ${token.colorBorderSecondary};
|
|
15
|
+
border-radius: ${token.borderRadiusLG}px;
|
|
16
|
+
|
|
17
|
+
background: ${token.colorBgContainer};
|
|
18
|
+
`,
|
|
19
|
+
container: css`
|
|
20
|
+
position: relative;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
`,
|
|
23
|
+
fadeEdge: css`
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset-block: 0 0;
|
|
28
|
+
inset-inline-end: 0;
|
|
29
|
+
|
|
30
|
+
width: 80px;
|
|
31
|
+
|
|
32
|
+
background: linear-gradient(to left, ${token.colorBgLayout}, transparent);
|
|
33
|
+
`,
|
|
34
|
+
previewSkeleton: css`
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: 160px;
|
|
37
|
+
margin-block-end: 12px;
|
|
38
|
+
border-radius: ${token.borderRadius}px;
|
|
39
|
+
|
|
40
|
+
background: ${token.colorFillQuaternary};
|
|
41
|
+
`,
|
|
42
|
+
scrollContainer: css`
|
|
43
|
+
|
|
44
|
+
/* Hide scrollbar */
|
|
45
|
+
scrollbar-width: none;
|
|
46
|
+
|
|
47
|
+
overflow-x: auto;
|
|
48
|
+
display: flex;
|
|
49
|
+
gap: 16px;
|
|
50
|
+
|
|
51
|
+
padding-block-end: 8px;
|
|
52
|
+
|
|
53
|
+
-ms-overflow-style: none;
|
|
54
|
+
|
|
55
|
+
&::-webkit-scrollbar {
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
`,
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
const RecentFilesSkeleton = memo(() => {
|
|
62
|
+
const { styles } = useStyles();
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className={styles.container}>
|
|
66
|
+
<div className={styles.scrollContainer}>
|
|
67
|
+
{Array.from({ length: 10 }).map((_, index) => (
|
|
68
|
+
<Flexbox className={styles.card} gap={12} key={index}>
|
|
69
|
+
<div className={styles.previewSkeleton} />
|
|
70
|
+
<Flexbox gap={6}>
|
|
71
|
+
<Skeleton active paragraph={false} title={{ width: '90%' }} />
|
|
72
|
+
<Skeleton active paragraph={false} title={{ style: { height: 12 }, width: '70%' }} />
|
|
73
|
+
</Flexbox>
|
|
74
|
+
</Flexbox>
|
|
75
|
+
))}
|
|
76
|
+
</div>
|
|
77
|
+
<div className={styles.fadeEdge} />
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export default RecentFilesSkeleton;
|
|
83
|
+
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { FileTypeIcon, Icon } from '@lobehub/ui';
|
|
4
|
+
import { Upload } from 'antd';
|
|
5
|
+
import { createStyles, useTheme } from 'antd-style';
|
|
6
|
+
import { ArrowUpIcon, FolderUp, PlusIcon } from 'lucide-react';
|
|
7
|
+
import { memo } from 'react';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
import { Flexbox } from 'react-layout-kit';
|
|
10
|
+
import { useNavigate } from 'react-router-dom';
|
|
11
|
+
|
|
12
|
+
import { useFileStore } from '@/store/file';
|
|
13
|
+
|
|
14
|
+
const ICON_SIZE = 64;
|
|
15
|
+
|
|
16
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
17
|
+
actionTitle: css`
|
|
18
|
+
margin-block-start: 12px;
|
|
19
|
+
font-size: 14px;
|
|
20
|
+
font-weight: 500;
|
|
21
|
+
color: ${token.colorTextSecondary};
|
|
22
|
+
`,
|
|
23
|
+
card: css`
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
|
|
26
|
+
position: relative;
|
|
27
|
+
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
|
|
30
|
+
width: 200px;
|
|
31
|
+
min-height: 120px;
|
|
32
|
+
padding: 16px;
|
|
33
|
+
border: 1px solid ${token.colorBorderSecondary};
|
|
34
|
+
border-radius: ${token.borderRadiusLG}px;
|
|
35
|
+
|
|
36
|
+
font-weight: 500;
|
|
37
|
+
text-align: center;
|
|
38
|
+
|
|
39
|
+
background: ${token.colorBgContainer};
|
|
40
|
+
|
|
41
|
+
transition: all ${token.motionDurationMid} ${token.motionEaseInOut};
|
|
42
|
+
|
|
43
|
+
&:hover {
|
|
44
|
+
border-color: ${token.colorPrimary};
|
|
45
|
+
box-shadow: ${token.boxShadowTertiary};
|
|
46
|
+
}
|
|
47
|
+
`,
|
|
48
|
+
glow: css`
|
|
49
|
+
position: absolute;
|
|
50
|
+
inset-block-end: -12px;
|
|
51
|
+
inset-inline-end: 0;
|
|
52
|
+
|
|
53
|
+
width: 48px;
|
|
54
|
+
height: 48px;
|
|
55
|
+
|
|
56
|
+
opacity: 0.3;
|
|
57
|
+
filter: blur(24px);
|
|
58
|
+
`,
|
|
59
|
+
grid: css`
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-wrap: wrap;
|
|
62
|
+
gap: 16px;
|
|
63
|
+
justify-content: left;
|
|
64
|
+
`,
|
|
65
|
+
icon: css`
|
|
66
|
+
position: absolute;
|
|
67
|
+
z-index: 1;
|
|
68
|
+
inset-block-end: -16px;
|
|
69
|
+
inset-inline-end: 8px;
|
|
70
|
+
|
|
71
|
+
flex: none;
|
|
72
|
+
`,
|
|
73
|
+
uploadWrapper: css`
|
|
74
|
+
/* Make the wrapper transparent so hover passes through to the card */
|
|
75
|
+
& > span {
|
|
76
|
+
display: block;
|
|
77
|
+
}
|
|
78
|
+
`,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
interface UploadEntriesProps {
|
|
82
|
+
knowledgeBaseId?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const UploadEntries = memo<UploadEntriesProps>(({ knowledgeBaseId }) => {
|
|
86
|
+
const { t } = useTranslation('file');
|
|
87
|
+
const theme = useTheme();
|
|
88
|
+
const { styles } = useStyles();
|
|
89
|
+
const navigate = useNavigate();
|
|
90
|
+
|
|
91
|
+
const createDocument = useFileStore((s) => s.createDocument);
|
|
92
|
+
const pushDockFileList = useFileStore((s) => s.pushDockFileList);
|
|
93
|
+
// const { open } = useCreateNewModal();
|
|
94
|
+
|
|
95
|
+
const handleCreateNote = async () => {
|
|
96
|
+
try {
|
|
97
|
+
const newDoc = await createDocument({
|
|
98
|
+
content: '',
|
|
99
|
+
knowledgeBaseId,
|
|
100
|
+
title: t('home.uploadEntries.newDocument.title'),
|
|
101
|
+
});
|
|
102
|
+
// Navigate to the newly created document
|
|
103
|
+
// The KnowledgeHomePage will automatically set category to 'documents' when it detects the id param
|
|
104
|
+
navigate(`/${newDoc.id}`);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('Failed to create document:', error);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// const handleCreateKnowledgeBase = () => {
|
|
111
|
+
// open({
|
|
112
|
+
// onSuccess: (id) => {
|
|
113
|
+
// navigate(`/bases/${id}`);
|
|
114
|
+
// },
|
|
115
|
+
// });
|
|
116
|
+
// };
|
|
117
|
+
|
|
118
|
+
const handleUploadFiles = async (file: File) => {
|
|
119
|
+
try {
|
|
120
|
+
await pushDockFileList([file], knowledgeBaseId);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Failed to upload file:', error);
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const handleUploadFolder = async (file: File) => {
|
|
128
|
+
try {
|
|
129
|
+
await pushDockFileList([file], knowledgeBaseId);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('Failed to upload folder:', error);
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<div className={styles.grid}>
|
|
138
|
+
{/* Create New Note */}
|
|
139
|
+
<Flexbox className={styles.card} onClick={handleCreateNote} padding={16}>
|
|
140
|
+
<span className={styles.actionTitle}>{t('home.uploadEntries.newDocument.title')}</span>
|
|
141
|
+
<div className={styles.glow} style={{ background: theme.purple }} />
|
|
142
|
+
<FileTypeIcon
|
|
143
|
+
className={styles.icon}
|
|
144
|
+
color={theme.purple}
|
|
145
|
+
icon={<Icon color={'#fff'} icon={PlusIcon} />}
|
|
146
|
+
size={ICON_SIZE}
|
|
147
|
+
type={'file'}
|
|
148
|
+
/>
|
|
149
|
+
</Flexbox>
|
|
150
|
+
|
|
151
|
+
{/* Create Knowledge Base */}
|
|
152
|
+
{/* <Flexbox className={styles.card} onClick={handleCreateKnowledgeBase} padding={16}>
|
|
153
|
+
<span className={styles.actionTitle}>{t('home.uploadEntries.knowledgeBase.title')}</span>
|
|
154
|
+
<div className={styles.glow} style={{ background: theme.colorPrimary }} />
|
|
155
|
+
<FileTypeIcon
|
|
156
|
+
className={styles.icon}
|
|
157
|
+
color={theme.colorPrimary}
|
|
158
|
+
icon={<Icon color={'#fff'} icon={LibraryBig} />}
|
|
159
|
+
size={ICON_SIZE}
|
|
160
|
+
type={'file'}
|
|
161
|
+
/>
|
|
162
|
+
</Flexbox> */}
|
|
163
|
+
|
|
164
|
+
{/* Upload Files */}
|
|
165
|
+
<Upload
|
|
166
|
+
beforeUpload={handleUploadFiles}
|
|
167
|
+
className={styles.uploadWrapper}
|
|
168
|
+
multiple
|
|
169
|
+
showUploadList={false}
|
|
170
|
+
>
|
|
171
|
+
<Flexbox className={styles.card} padding={16}>
|
|
172
|
+
<span className={styles.actionTitle}>{t('home.uploadEntries.files.title')}</span>
|
|
173
|
+
<div className={styles.glow} style={{ background: theme.geekblue }} />
|
|
174
|
+
<FileTypeIcon
|
|
175
|
+
className={styles.icon}
|
|
176
|
+
color={theme.geekblue}
|
|
177
|
+
icon={<Icon color={'#fff'} icon={ArrowUpIcon} />}
|
|
178
|
+
size={ICON_SIZE}
|
|
179
|
+
type={'file'}
|
|
180
|
+
/>
|
|
181
|
+
</Flexbox>
|
|
182
|
+
</Upload>
|
|
183
|
+
|
|
184
|
+
{/* Upload Folder */}
|
|
185
|
+
<Upload
|
|
186
|
+
beforeUpload={handleUploadFolder}
|
|
187
|
+
className={styles.uploadWrapper}
|
|
188
|
+
directory
|
|
189
|
+
multiple
|
|
190
|
+
showUploadList={false}
|
|
191
|
+
>
|
|
192
|
+
<Flexbox className={styles.card} padding={16}>
|
|
193
|
+
<span className={styles.actionTitle}>{t('home.uploadEntries.folder.title')}</span>
|
|
194
|
+
<div className={styles.glow} style={{ background: theme.green }} />
|
|
195
|
+
<FileTypeIcon
|
|
196
|
+
className={styles.icon}
|
|
197
|
+
color={theme.green}
|
|
198
|
+
icon={<Icon color={'#fff'} icon={FolderUp} />}
|
|
199
|
+
size={ICON_SIZE}
|
|
200
|
+
type={'file'}
|
|
201
|
+
/>
|
|
202
|
+
</Flexbox>
|
|
203
|
+
</Upload>
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
export default UploadEntries;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ActionIcon, Dropdown, Text } from '@lobehub/ui';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
5
|
+
import { Clock, FileTextIcon, MoreHorizontal } from 'lucide-react';
|
|
6
|
+
import { memo, useMemo, useState } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
|
9
|
+
import { useNavigate } from 'react-router-dom';
|
|
10
|
+
|
|
11
|
+
import { useFileCategory } from '@/app/[variants]/(main)/knowledge/hooks/useFileCategory';
|
|
12
|
+
import { useFileStore } from '@/store/file';
|
|
13
|
+
import { FilesTabs } from '@/types/files';
|
|
14
|
+
|
|
15
|
+
import RecentDocuments from './RecentDocuments';
|
|
16
|
+
import RecentFiles from './RecentFiles';
|
|
17
|
+
import UploadEntries from './UploadEntries';
|
|
18
|
+
|
|
19
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
20
|
+
container: css`
|
|
21
|
+
padding-block: 20px 48px;
|
|
22
|
+
padding-inline: 24px;
|
|
23
|
+
`,
|
|
24
|
+
content: css`
|
|
25
|
+
width: 100%;
|
|
26
|
+
max-width: 1200px;
|
|
27
|
+
margin-block: 0;
|
|
28
|
+
margin-inline: auto;
|
|
29
|
+
`,
|
|
30
|
+
greeting: css`
|
|
31
|
+
font-size: 24px;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
color: ${token.colorText};
|
|
34
|
+
text-align: start;
|
|
35
|
+
`,
|
|
36
|
+
section: css`
|
|
37
|
+
margin-block: 6px 36px;
|
|
38
|
+
`,
|
|
39
|
+
sectionActions: css`
|
|
40
|
+
transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};
|
|
41
|
+
`,
|
|
42
|
+
sectionTitle: css`
|
|
43
|
+
display: flex;
|
|
44
|
+
gap: 8px;
|
|
45
|
+
align-items: center;
|
|
46
|
+
|
|
47
|
+
margin-block-end: 24px;
|
|
48
|
+
|
|
49
|
+
font-size: 18px;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
color: ${token.colorTextSecondary};
|
|
52
|
+
text-align: start;
|
|
53
|
+
`,
|
|
54
|
+
sectionTitleWrapper: css`
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
|
|
59
|
+
min-height: 36px;
|
|
60
|
+
margin-block-end: 24px;
|
|
61
|
+
`,
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
interface HomeProps {
|
|
65
|
+
knowledgeBaseId?: string;
|
|
66
|
+
onOpenFile: (id: string) => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const Home = memo<HomeProps>(({ knowledgeBaseId, onOpenFile }) => {
|
|
70
|
+
const { t } = useTranslation('file');
|
|
71
|
+
const { styles } = useStyles();
|
|
72
|
+
const navigate = useNavigate();
|
|
73
|
+
const [, setActiveKey] = useFileCategory();
|
|
74
|
+
const [isDocumentsMenuOpen, setIsDocumentsMenuOpen] = useState(false);
|
|
75
|
+
const [isDocumentsSectionHovered, setIsDocumentsSectionHovered] = useState(false);
|
|
76
|
+
const [isFilesMenuOpen, setIsFilesMenuOpen] = useState(false);
|
|
77
|
+
const [isFilesSectionHovered, setIsFilesSectionHovered] = useState(false);
|
|
78
|
+
|
|
79
|
+
const useFetchKnowledgeItems = useFileStore((s) => s.useFetchKnowledgeItems);
|
|
80
|
+
|
|
81
|
+
// Fetch all items (all categories, sorted by updatedAt)
|
|
82
|
+
const { data: allItems, isLoading } = useFetchKnowledgeItems({
|
|
83
|
+
category: FilesTabs.All,
|
|
84
|
+
knowledgeBaseId,
|
|
85
|
+
sortType: 'desc',
|
|
86
|
+
sorter: 'createdAt',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Get top 10 recent files (filter by sourceType === 'file')
|
|
90
|
+
const topRecentFiles = useMemo(() => {
|
|
91
|
+
if (!allItems) return [];
|
|
92
|
+
const files = allItems.filter((item) => item.sourceType === 'file');
|
|
93
|
+
return files.slice(0, 10);
|
|
94
|
+
}, [allItems]);
|
|
95
|
+
|
|
96
|
+
// Get top 10 recent documents (filter by sourceType === 'document')
|
|
97
|
+
const topRecentDocuments = useMemo(() => {
|
|
98
|
+
if (!allItems) return [];
|
|
99
|
+
const documents = allItems.filter((item) => item.sourceType === 'document');
|
|
100
|
+
return documents.slice(0, 10);
|
|
101
|
+
}, [allItems]);
|
|
102
|
+
|
|
103
|
+
// Handle document click - navigate to document explorer
|
|
104
|
+
const handleDocumentClick = (documentId: string) => {
|
|
105
|
+
// Navigate to the document in the explorer
|
|
106
|
+
// The KnowledgeHomePage will automatically set category to 'documents' when it detects the id param
|
|
107
|
+
navigate(`/${documentId}`);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div className={styles.container}>
|
|
112
|
+
<Flexbox className={styles.content}>
|
|
113
|
+
{/* Greeting Section */}
|
|
114
|
+
<Flexbox className={styles.section}>
|
|
115
|
+
<Text className={styles.greeting}>{t('home.greeting')}</Text>
|
|
116
|
+
</Flexbox>
|
|
117
|
+
|
|
118
|
+
{/* Upload Entries Section */}
|
|
119
|
+
<Flexbox className={styles.section}>
|
|
120
|
+
<UploadEntries knowledgeBaseId={knowledgeBaseId} />
|
|
121
|
+
</Flexbox>
|
|
122
|
+
|
|
123
|
+
{/* Recent Files Section */}
|
|
124
|
+
{(isLoading || topRecentFiles.length > 0) && (
|
|
125
|
+
<div
|
|
126
|
+
className={styles.section}
|
|
127
|
+
onMouseEnter={() => {
|
|
128
|
+
setIsFilesSectionHovered(true);
|
|
129
|
+
}}
|
|
130
|
+
onMouseLeave={() => {
|
|
131
|
+
setIsFilesSectionHovered(false);
|
|
132
|
+
}}
|
|
133
|
+
>
|
|
134
|
+
<div className={styles.sectionTitleWrapper}>
|
|
135
|
+
<Text className={styles.sectionTitle} style={{ marginBottom: 0 }}>
|
|
136
|
+
<Clock size={18} />
|
|
137
|
+
{t('home.recentFiles')}
|
|
138
|
+
</Text>
|
|
139
|
+
<div
|
|
140
|
+
className={styles.sectionActions}
|
|
141
|
+
style={{
|
|
142
|
+
opacity: isFilesSectionHovered || isFilesMenuOpen ? 1 : 0,
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
<Dropdown
|
|
146
|
+
menu={{
|
|
147
|
+
items: [
|
|
148
|
+
{
|
|
149
|
+
key: 'all-files',
|
|
150
|
+
label: t('menu.allFiles'),
|
|
151
|
+
onClick: () => {
|
|
152
|
+
setActiveKey(FilesTabs.All);
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
}}
|
|
157
|
+
onOpenChange={setIsFilesMenuOpen}
|
|
158
|
+
open={isFilesMenuOpen}
|
|
159
|
+
>
|
|
160
|
+
<ActionIcon icon={MoreHorizontal} size="small" />
|
|
161
|
+
</Dropdown>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
<RecentFiles files={topRecentFiles} isLoading={isLoading} onOpenFile={onOpenFile} />
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
167
|
+
|
|
168
|
+
{/* Recent Documents Section */}
|
|
169
|
+
{(isLoading || topRecentDocuments.length > 0) && (
|
|
170
|
+
<div
|
|
171
|
+
className={styles.section}
|
|
172
|
+
onMouseEnter={() => {
|
|
173
|
+
setIsDocumentsSectionHovered(true);
|
|
174
|
+
}}
|
|
175
|
+
onMouseLeave={() => {
|
|
176
|
+
setIsDocumentsSectionHovered(false);
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
<div className={styles.sectionTitleWrapper}>
|
|
180
|
+
<Text className={styles.sectionTitle} style={{ marginBottom: 0 }}>
|
|
181
|
+
<FileTextIcon size={18} />
|
|
182
|
+
{t('home.recentDocuments')}
|
|
183
|
+
</Text>
|
|
184
|
+
<div
|
|
185
|
+
className={styles.sectionActions}
|
|
186
|
+
style={{
|
|
187
|
+
opacity: isDocumentsSectionHovered || isDocumentsMenuOpen ? 1 : 0,
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
<Dropdown
|
|
191
|
+
menu={{
|
|
192
|
+
items: [
|
|
193
|
+
{
|
|
194
|
+
key: 'all-documents',
|
|
195
|
+
label: t('menu.allDocuments'),
|
|
196
|
+
onClick: () => {
|
|
197
|
+
setActiveKey(FilesTabs.Documents);
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
}}
|
|
202
|
+
onOpenChange={setIsDocumentsMenuOpen}
|
|
203
|
+
open={isDocumentsMenuOpen}
|
|
204
|
+
>
|
|
205
|
+
<ActionIcon icon={MoreHorizontal} size="small" />
|
|
206
|
+
</Dropdown>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
<RecentDocuments
|
|
210
|
+
documents={topRecentDocuments}
|
|
211
|
+
isLoading={isLoading}
|
|
212
|
+
onOpenDocument={handleDocumentClick}
|
|
213
|
+
/>
|
|
214
|
+
</div>
|
|
215
|
+
)}
|
|
216
|
+
</Flexbox>
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
export default Home;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Text } from '@lobehub/ui';
|
|
4
|
+
import dynamic from 'next/dynamic';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { FilesTabs } from '@/types/files';
|
|
9
|
+
|
|
10
|
+
import DocumentExplorer from './DocumentExplorer';
|
|
11
|
+
import FileExplorer from './FileExplorer';
|
|
12
|
+
import Header from './Header';
|
|
13
|
+
import Home from './Home';
|
|
14
|
+
import UploadDock from './UploadDock';
|
|
15
|
+
|
|
16
|
+
const ChunkDrawer = dynamic(() => import('./ChunkDrawer'), { ssr: false });
|
|
17
|
+
|
|
18
|
+
interface KnowledgeManagerProps {
|
|
19
|
+
category?: string;
|
|
20
|
+
// Directly open a document if provided
|
|
21
|
+
documentId?: string;
|
|
22
|
+
knowledgeBaseId?: string;
|
|
23
|
+
onOpenFile: (id: string) => void;
|
|
24
|
+
title: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Manage knowledge items. Can be all items or certian knowledge base.
|
|
29
|
+
*
|
|
30
|
+
* DocumentExplorer: For the "documents" category.
|
|
31
|
+
* Home: For the "home" category.
|
|
32
|
+
* FileExplorer: For other categories.
|
|
33
|
+
*/
|
|
34
|
+
const KnowledgeManager = memo<KnowledgeManagerProps>(
|
|
35
|
+
({ title, knowledgeBaseId, category, onOpenFile, documentId }) => {
|
|
36
|
+
const isDocumentsView = category === FilesTabs.Pages;
|
|
37
|
+
const isHomeView = category === FilesTabs.Home;
|
|
38
|
+
|
|
39
|
+
if (isHomeView) {
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<Home knowledgeBaseId={knowledgeBaseId} onOpenFile={onOpenFile} />
|
|
43
|
+
<UploadDock />
|
|
44
|
+
<ChunkDrawer />
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
{!isDocumentsView && <Header knowledgeBaseId={knowledgeBaseId} />}
|
|
52
|
+
<Flexbox gap={12} height={'100%'}>
|
|
53
|
+
{!isDocumentsView && (
|
|
54
|
+
<Text strong style={{ fontSize: 16, marginBlock: 16, marginInline: 24 }}>
|
|
55
|
+
{title}
|
|
56
|
+
</Text>
|
|
57
|
+
)}
|
|
58
|
+
{isDocumentsView ? (
|
|
59
|
+
<DocumentExplorer documentId={documentId} knowledgeBaseId={knowledgeBaseId} />
|
|
60
|
+
) : (
|
|
61
|
+
<FileExplorer
|
|
62
|
+
category={category}
|
|
63
|
+
knowledgeBaseId={knowledgeBaseId}
|
|
64
|
+
onOpenFile={onOpenFile}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
</Flexbox>
|
|
68
|
+
<UploadDock />
|
|
69
|
+
<ChunkDrawer />
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
export default KnowledgeManager;
|
|
@@ -18,7 +18,7 @@ enum FilePreviewTab {
|
|
|
18
18
|
const FilePreview = () => {
|
|
19
19
|
const previewFileId = useChatStore(chatPortalSelectors.previewFileId);
|
|
20
20
|
const chunkText = useChatStore(chatPortalSelectors.chunkText);
|
|
21
|
-
const useFetchFileItem = useFileStore((s) => s.
|
|
21
|
+
const useFetchFileItem = useFileStore((s) => s.useFetchKnowledgeItem);
|
|
22
22
|
const { t } = useTranslation('portal');
|
|
23
23
|
|
|
24
24
|
const [tab, setTab] = useState<FilePreviewTab>(FilePreviewTab.File);
|
|
@@ -14,7 +14,7 @@ const Header = () => {
|
|
|
14
14
|
chatPortalSelectors.previewFileId(s),
|
|
15
15
|
]);
|
|
16
16
|
|
|
17
|
-
const useFetchFileItem = useFileStore((s) => s.
|
|
17
|
+
const useFetchFileItem = useFileStore((s) => s.useFetchKnowledgeItem);
|
|
18
18
|
|
|
19
19
|
const { data, isLoading } = useFetchFileItem(previewFileId);
|
|
20
20
|
|