@lobehub/lobehub 2.0.0-next.233 → 2.0.0-next.234
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/.github/workflows/e2e.yml +6 -12
- package/.github/workflows/test.yml +3 -3
- package/CHANGELOG.md +34 -0
- package/CLAUDE.md +1 -1
- package/changelog/v1.json +9 -0
- package/docs/development/basic/feature-development.mdx +4 -5
- package/docs/development/basic/feature-development.zh-CN.mdx +4 -5
- package/e2e/README.md +6 -6
- package/e2e/src/features/community/detail-pages.feature +9 -9
- package/e2e/src/features/community/interactions.feature +13 -13
- package/e2e/src/features/community/smoke.feature +6 -6
- package/e2e/src/steps/agent/conversation-mgmt.steps.ts +196 -25
- package/e2e/src/steps/agent/conversation.steps.ts +58 -0
- package/e2e/src/steps/agent/message-ops.steps.ts +20 -15
- package/e2e/src/steps/community/detail-pages.steps.ts +60 -19
- package/e2e/src/steps/community/interactions.steps.ts +145 -32
- package/e2e/src/steps/hooks.ts +12 -2
- package/locales/en-US/setting.json +3 -0
- package/locales/zh-CN/file.json +4 -0
- package/locales/zh-CN/setting.json +3 -0
- package/package.json +5 -5
- package/packages/const/src/index.ts +1 -0
- package/packages/const/src/lobehubSkill.ts +55 -0
- package/packages/types/package.json +1 -1
- package/packages/types/src/files/upload.ts +11 -1
- package/packages/types/src/message/common/tools.ts +1 -1
- package/packages/types/src/serverConfig.ts +1 -0
- package/public/not-compatible.html +1296 -0
- package/src/app/[variants]/(main)/resource/features/FileDetail.tsx +20 -12
- package/src/app/[variants]/(main)/resource/features/modal/FullscreenModal.tsx +2 -4
- package/src/app/[variants]/layout.tsx +50 -1
- package/src/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem.tsx +304 -0
- package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +74 -10
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Inspector/ToolTitle.tsx +9 -0
- package/src/features/FileViewer/Renderer/Code/index.tsx +224 -0
- package/src/features/FileViewer/Renderer/Image/index.tsx +8 -1
- package/src/features/FileViewer/Renderer/PDF/index.tsx +3 -1
- package/src/features/FileViewer/Renderer/PDF/style.ts +2 -1
- package/src/features/FileViewer/index.tsx +135 -24
- package/src/features/PageEditor/EditorCanvas/useSlashItems.tsx +7 -4
- package/src/features/PageEditor/store/initialState.ts +2 -1
- package/src/features/ResourceManager/components/Editor/FileContent.tsx +1 -4
- package/src/features/ResourceManager/components/Editor/FileCopilot.tsx +64 -0
- package/src/features/ResourceManager/components/Editor/index.tsx +98 -31
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +3 -2
- package/src/features/ResourceManager/components/Explorer/ListView/ColumnResizeHandle.tsx +119 -0
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +67 -22
- package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +46 -11
- package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +140 -81
- package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +20 -12
- package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +18 -10
- package/src/features/ResourceManager/components/UploadDock/Item.tsx +38 -6
- package/src/features/ResourceManager/components/UploadDock/index.tsx +62 -41
- package/src/features/ResourceManager/index.tsx +1 -0
- package/src/helpers/toolEngineering/index.test.ts +3 -0
- package/src/helpers/toolEngineering/index.ts +12 -1
- package/src/locales/default/file.ts +4 -0
- package/src/locales/default/setting.ts +3 -0
- package/src/server/globalConfig/index.ts +1 -0
- package/src/server/modules/ModelRuntime/index.test.ts +214 -1
- package/src/server/modules/ModelRuntime/index.ts +43 -7
- package/src/server/routers/lambda/document.ts +44 -0
- package/src/server/routers/tools/market.ts +261 -0
- package/src/server/services/document/index.ts +22 -0
- package/src/services/document/index.ts +4 -0
- package/src/services/upload.ts +22 -2
- package/src/store/chat/slices/plugin/actions/internals.ts +15 -2
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +104 -0
- package/src/store/file/slices/fileManager/action.test.ts +9 -3
- package/src/store/file/slices/fileManager/action.ts +165 -70
- package/src/store/file/slices/upload/action.ts +3 -0
- package/src/store/global/actions/general.ts +15 -0
- package/src/store/global/initialState.ts +13 -0
- package/src/store/serverConfig/selectors.ts +1 -0
- package/src/store/tool/initialState.ts +11 -2
- package/src/store/tool/selectors/index.ts +1 -0
- package/src/store/tool/selectors/tool.ts +3 -1
- package/src/store/tool/slices/lobehubSkillStore/action.ts +361 -0
- package/src/store/tool/slices/lobehubSkillStore/index.ts +4 -0
- package/src/store/tool/slices/lobehubSkillStore/initialState.ts +24 -0
- package/src/store/tool/slices/lobehubSkillStore/selectors.ts +145 -0
- package/src/store/tool/slices/lobehubSkillStore/types.ts +100 -0
- package/src/store/tool/store.ts +8 -2
- package/vitest.config.mts +1 -0
- package/src/features/FileViewer/Renderer/JavaScript/index.tsx +0 -66
- package/src/features/FileViewer/Renderer/TXT/index.tsx +0 -50
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Center, Flexbox, Highlighter } from '@lobehub/ui';
|
|
4
|
+
import { createStaticStyles } from 'antd-style';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
|
|
7
|
+
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
|
8
|
+
|
|
9
|
+
import { useTextFileLoader } from '../../hooks/useTextFileLoader';
|
|
10
|
+
|
|
11
|
+
const styles = createStaticStyles(({ css }) => ({
|
|
12
|
+
page: css`
|
|
13
|
+
width: 100%;
|
|
14
|
+
height: 100%;
|
|
15
|
+
padding-inline: 24px 4px;
|
|
16
|
+
`,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const getLanguage = (fileName?: string): string => {
|
|
20
|
+
if (!fileName) return 'txt';
|
|
21
|
+
|
|
22
|
+
const ext = fileName.toLowerCase().split('.').pop();
|
|
23
|
+
switch (ext) {
|
|
24
|
+
// JavaScript/TypeScript
|
|
25
|
+
case 'js':
|
|
26
|
+
case 'mjs':
|
|
27
|
+
case 'cjs': {
|
|
28
|
+
return 'javascript';
|
|
29
|
+
}
|
|
30
|
+
case 'ts': {
|
|
31
|
+
return 'typescript';
|
|
32
|
+
}
|
|
33
|
+
case 'tsx': {
|
|
34
|
+
return 'tsx';
|
|
35
|
+
}
|
|
36
|
+
case 'jsx': {
|
|
37
|
+
return 'jsx';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Python
|
|
41
|
+
case 'py':
|
|
42
|
+
case 'pyw': {
|
|
43
|
+
return 'python';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Java/JVM Languages
|
|
47
|
+
case 'java': {
|
|
48
|
+
return 'java';
|
|
49
|
+
}
|
|
50
|
+
case 'kt':
|
|
51
|
+
case 'kts': {
|
|
52
|
+
return 'kotlin';
|
|
53
|
+
}
|
|
54
|
+
case 'scala': {
|
|
55
|
+
return 'scala';
|
|
56
|
+
}
|
|
57
|
+
case 'groovy': {
|
|
58
|
+
return 'groovy';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// C/C++
|
|
62
|
+
case 'c':
|
|
63
|
+
case 'h': {
|
|
64
|
+
return 'c';
|
|
65
|
+
}
|
|
66
|
+
case 'cpp':
|
|
67
|
+
case 'cxx':
|
|
68
|
+
case 'cc':
|
|
69
|
+
case 'hpp':
|
|
70
|
+
case 'hxx': {
|
|
71
|
+
return 'cpp';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// C#
|
|
75
|
+
case 'cs': {
|
|
76
|
+
return 'csharp';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Go
|
|
80
|
+
case 'go': {
|
|
81
|
+
return 'go';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Rust
|
|
85
|
+
case 'rs': {
|
|
86
|
+
return 'rust';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Ruby
|
|
90
|
+
case 'rb': {
|
|
91
|
+
return 'ruby';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// PHP
|
|
95
|
+
case 'php': {
|
|
96
|
+
return 'php';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Swift
|
|
100
|
+
case 'swift': {
|
|
101
|
+
return 'swift';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Shell
|
|
105
|
+
case 'sh':
|
|
106
|
+
case 'bash':
|
|
107
|
+
case 'zsh': {
|
|
108
|
+
return 'bash';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Web
|
|
112
|
+
case 'html':
|
|
113
|
+
case 'htm': {
|
|
114
|
+
return 'html';
|
|
115
|
+
}
|
|
116
|
+
case 'css': {
|
|
117
|
+
return 'css';
|
|
118
|
+
}
|
|
119
|
+
case 'scss': {
|
|
120
|
+
return 'scss';
|
|
121
|
+
}
|
|
122
|
+
case 'sass': {
|
|
123
|
+
return 'sass';
|
|
124
|
+
}
|
|
125
|
+
case 'less': {
|
|
126
|
+
return 'less';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Data formats
|
|
130
|
+
case 'json': {
|
|
131
|
+
return 'json';
|
|
132
|
+
}
|
|
133
|
+
case 'xml': {
|
|
134
|
+
return 'xml';
|
|
135
|
+
}
|
|
136
|
+
case 'yaml':
|
|
137
|
+
case 'yml': {
|
|
138
|
+
return 'yaml';
|
|
139
|
+
}
|
|
140
|
+
case 'toml': {
|
|
141
|
+
return 'toml';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Markdown
|
|
145
|
+
case 'md':
|
|
146
|
+
case 'mdx': {
|
|
147
|
+
return 'markdown';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// SQL
|
|
151
|
+
case 'sql': {
|
|
152
|
+
return 'sql';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Other popular languages
|
|
156
|
+
case 'lua': {
|
|
157
|
+
return 'lua';
|
|
158
|
+
}
|
|
159
|
+
case 'r': {
|
|
160
|
+
return 'r';
|
|
161
|
+
}
|
|
162
|
+
case 'dart': {
|
|
163
|
+
return 'dart';
|
|
164
|
+
}
|
|
165
|
+
case 'elixir':
|
|
166
|
+
case 'ex':
|
|
167
|
+
case 'exs': {
|
|
168
|
+
return 'elixir';
|
|
169
|
+
}
|
|
170
|
+
case 'erl':
|
|
171
|
+
case 'hrl': {
|
|
172
|
+
return 'erlang';
|
|
173
|
+
}
|
|
174
|
+
case 'clj':
|
|
175
|
+
case 'cljs':
|
|
176
|
+
case 'cljc': {
|
|
177
|
+
return 'clojure';
|
|
178
|
+
}
|
|
179
|
+
case 'vim': {
|
|
180
|
+
return 'vim';
|
|
181
|
+
}
|
|
182
|
+
case 'dockerfile': {
|
|
183
|
+
return 'dockerfile';
|
|
184
|
+
}
|
|
185
|
+
case 'graphql':
|
|
186
|
+
case 'gql': {
|
|
187
|
+
return 'graphql';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
default: {
|
|
191
|
+
return 'txt';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
interface CodeViewerProps {
|
|
197
|
+
fileId: string;
|
|
198
|
+
fileName?: string;
|
|
199
|
+
url: string | null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Render any code file.
|
|
204
|
+
*/
|
|
205
|
+
const CodeViewer = memo<CodeViewerProps>(({ url, fileName }) => {
|
|
206
|
+
const { fileData, loading } = useTextFileLoader(url);
|
|
207
|
+
const language = getLanguage(fileName);
|
|
208
|
+
|
|
209
|
+
return (
|
|
210
|
+
<Flexbox className={styles.page}>
|
|
211
|
+
{!loading && fileData ? (
|
|
212
|
+
<Highlighter language={language} showLanguage={false} variant={'borderless'}>
|
|
213
|
+
{fileData}
|
|
214
|
+
</Highlighter>
|
|
215
|
+
) : (
|
|
216
|
+
<Center height={'100%'}>
|
|
217
|
+
<NeuralNetworkLoading size={36} />
|
|
218
|
+
</Center>
|
|
219
|
+
)}
|
|
220
|
+
</Flexbox>
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
export default CodeViewer;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Center } from '@lobehub/ui';
|
|
4
|
-
import { memo } from 'react';
|
|
4
|
+
import { memo, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
|
5
7
|
|
|
6
8
|
interface ImageViewerProps {
|
|
7
9
|
fileId: string;
|
|
@@ -9,15 +11,20 @@ interface ImageViewerProps {
|
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
const ImageViewer = memo<ImageViewerProps>(({ url }) => {
|
|
14
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
15
|
+
|
|
12
16
|
if (!url) return null;
|
|
13
17
|
|
|
14
18
|
return (
|
|
15
19
|
<Center height={'100%'} width={'100%'}>
|
|
20
|
+
{!isLoaded && <NeuralNetworkLoading size={36} />}
|
|
16
21
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
17
22
|
<img
|
|
18
23
|
alt="Image preview"
|
|
24
|
+
onLoad={() => setIsLoaded(true)}
|
|
19
25
|
src={url}
|
|
20
26
|
style={{
|
|
27
|
+
display: isLoaded ? 'block' : 'none',
|
|
21
28
|
height: '100%',
|
|
22
29
|
objectFit: 'contain',
|
|
23
30
|
overflow: 'hidden',
|
|
@@ -7,6 +7,7 @@ import { Document, Page, pdfjs } from 'react-pdf';
|
|
|
7
7
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
|
8
8
|
import 'react-pdf/dist/esm/Page/TextLayer.css';
|
|
9
9
|
|
|
10
|
+
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
|
10
11
|
import { lambdaQuery } from '@/libs/trpc/client';
|
|
11
12
|
|
|
12
13
|
import HighlightLayer from './HighlightLayer';
|
|
@@ -62,13 +63,14 @@ const PDFViewer = memo<PDFViewerProps>(({ url, fileId }) => {
|
|
|
62
63
|
<Flexbox
|
|
63
64
|
align={'center'}
|
|
64
65
|
className={styles.documentContainer}
|
|
66
|
+
justify={isLoaded ? undefined : 'center'}
|
|
65
67
|
padding={24}
|
|
66
68
|
ref={setContainerRef}
|
|
67
|
-
style={{ height: isLoaded ? undefined : '100%' }}
|
|
68
69
|
>
|
|
69
70
|
<Document
|
|
70
71
|
className={styles.document}
|
|
71
72
|
file={url}
|
|
73
|
+
loading={<NeuralNetworkLoading size={36} />}
|
|
72
74
|
onLoadSuccess={onDocumentLoadSuccess}
|
|
73
75
|
options={options}
|
|
74
76
|
>
|
|
@@ -2,12 +2,13 @@ import { createStaticStyles } from 'antd-style';
|
|
|
2
2
|
|
|
3
3
|
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
4
4
|
container: css`
|
|
5
|
-
|
|
5
|
+
height: 100%;
|
|
6
6
|
`,
|
|
7
7
|
document: css`
|
|
8
8
|
position: relative;
|
|
9
9
|
`,
|
|
10
10
|
documentContainer: css`
|
|
11
|
+
flex: 1;
|
|
11
12
|
padding-block: 10px;
|
|
12
13
|
background-color: ${cssVar.colorBgLayout};
|
|
13
14
|
`,
|
|
@@ -5,12 +5,10 @@ import { type CSSProperties, memo } from 'react';
|
|
|
5
5
|
import { type FileListItem } from '@/types/files';
|
|
6
6
|
|
|
7
7
|
import NotSupport from './NotSupport';
|
|
8
|
+
import CodeViewer from './Renderer/Code';
|
|
8
9
|
import ImageViewer from './Renderer/Image';
|
|
9
|
-
import JavaScriptViewer from './Renderer/JavaScript';
|
|
10
10
|
import MSDocViewer from './Renderer/MSDoc';
|
|
11
|
-
import MarkdownViewer from './Renderer/Markdown';
|
|
12
11
|
import PDFViewer from './Renderer/PDF';
|
|
13
|
-
import TXTViewer from './Renderer/TXT';
|
|
14
12
|
import VideoViewer from './Renderer/Video';
|
|
15
13
|
|
|
16
14
|
// File type definitions
|
|
@@ -27,8 +25,79 @@ const IMAGE_MIME_TYPES = new Set([
|
|
|
27
25
|
const VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogg'];
|
|
28
26
|
const VIDEO_MIME_TYPES = new Set(['video/mp4', 'video/webm', 'video/ogg', 'mp4', 'webm', 'ogg']);
|
|
29
27
|
|
|
30
|
-
const
|
|
31
|
-
|
|
28
|
+
const CODE_EXTENSIONS = [
|
|
29
|
+
// JavaScript/TypeScript
|
|
30
|
+
'.js',
|
|
31
|
+
'.jsx',
|
|
32
|
+
'.ts',
|
|
33
|
+
'.tsx',
|
|
34
|
+
'.mjs',
|
|
35
|
+
'.cjs',
|
|
36
|
+
// Python
|
|
37
|
+
'.py',
|
|
38
|
+
'.pyw',
|
|
39
|
+
// Java/JVM
|
|
40
|
+
'.java',
|
|
41
|
+
'.kt',
|
|
42
|
+
'.kts',
|
|
43
|
+
'.scala',
|
|
44
|
+
'.groovy',
|
|
45
|
+
// C/C++
|
|
46
|
+
'.c',
|
|
47
|
+
'.h',
|
|
48
|
+
'.cpp',
|
|
49
|
+
'.cxx',
|
|
50
|
+
'.cc',
|
|
51
|
+
'.hpp',
|
|
52
|
+
'.hxx',
|
|
53
|
+
// Other compiled languages
|
|
54
|
+
'.cs',
|
|
55
|
+
'.go',
|
|
56
|
+
'.rs',
|
|
57
|
+
'.rb',
|
|
58
|
+
'.php',
|
|
59
|
+
'.swift',
|
|
60
|
+
'.lua',
|
|
61
|
+
'.r',
|
|
62
|
+
'.dart',
|
|
63
|
+
// Shell
|
|
64
|
+
'.sh',
|
|
65
|
+
'.bash',
|
|
66
|
+
'.zsh',
|
|
67
|
+
// Web
|
|
68
|
+
'.html',
|
|
69
|
+
'.htm',
|
|
70
|
+
'.css',
|
|
71
|
+
'.scss',
|
|
72
|
+
'.sass',
|
|
73
|
+
'.less',
|
|
74
|
+
// Data formats
|
|
75
|
+
'.json',
|
|
76
|
+
'.xml',
|
|
77
|
+
'.yaml',
|
|
78
|
+
'.yml',
|
|
79
|
+
'.toml',
|
|
80
|
+
'.sql',
|
|
81
|
+
// Functional languages
|
|
82
|
+
'.ex',
|
|
83
|
+
'.exs',
|
|
84
|
+
'.erl',
|
|
85
|
+
'.hrl',
|
|
86
|
+
'.clj',
|
|
87
|
+
'.cljs',
|
|
88
|
+
'.cljc',
|
|
89
|
+
// Markdown
|
|
90
|
+
'.md',
|
|
91
|
+
'.mdx',
|
|
92
|
+
// Other
|
|
93
|
+
'.vim',
|
|
94
|
+
'.graphql',
|
|
95
|
+
'.gql',
|
|
96
|
+
'.txt',
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const CODE_MIME_TYPES = new Set([
|
|
100
|
+
// JavaScript/TypeScript
|
|
32
101
|
'js',
|
|
33
102
|
'jsx',
|
|
34
103
|
'ts',
|
|
@@ -38,14 +107,66 @@ const JS_MIME_TYPES = new Set([
|
|
|
38
107
|
'text/javascript',
|
|
39
108
|
'application/typescript',
|
|
40
109
|
'text/typescript',
|
|
110
|
+
// Python
|
|
111
|
+
'python',
|
|
112
|
+
'text/x-python',
|
|
113
|
+
'application/x-python-code',
|
|
114
|
+
// Java/JVM
|
|
115
|
+
'java',
|
|
116
|
+
'text/x-java-source',
|
|
117
|
+
'kotlin',
|
|
118
|
+
'scala',
|
|
119
|
+
// C/C++
|
|
120
|
+
'c',
|
|
121
|
+
'text/x-c',
|
|
122
|
+
'cpp',
|
|
123
|
+
'text/x-c++',
|
|
124
|
+
// Other languages
|
|
125
|
+
'csharp',
|
|
126
|
+
'go',
|
|
127
|
+
'rust',
|
|
128
|
+
'ruby',
|
|
129
|
+
'php',
|
|
130
|
+
'text/x-php',
|
|
131
|
+
'swift',
|
|
132
|
+
'lua',
|
|
133
|
+
'r',
|
|
134
|
+
'dart',
|
|
135
|
+
// Shell
|
|
136
|
+
'bash',
|
|
137
|
+
'shell',
|
|
138
|
+
'text/x-shellscript',
|
|
139
|
+
// Web
|
|
140
|
+
'html',
|
|
141
|
+
'text/html',
|
|
142
|
+
'css',
|
|
143
|
+
'text/css',
|
|
144
|
+
'scss',
|
|
145
|
+
'sass',
|
|
146
|
+
'less',
|
|
147
|
+
// Data
|
|
148
|
+
'json',
|
|
149
|
+
'application/json',
|
|
150
|
+
'xml',
|
|
151
|
+
'text/xml',
|
|
152
|
+
'application/xml',
|
|
153
|
+
'yaml',
|
|
154
|
+
'text/yaml',
|
|
155
|
+
'application/x-yaml',
|
|
156
|
+
'toml',
|
|
157
|
+
'sql',
|
|
158
|
+
'text/x-sql',
|
|
159
|
+
// Markdown
|
|
160
|
+
'md',
|
|
161
|
+
'mdx',
|
|
162
|
+
'text/markdown',
|
|
163
|
+
'text/x-markdown',
|
|
164
|
+
// Other
|
|
165
|
+
'graphql',
|
|
166
|
+
'txt',
|
|
167
|
+
'text/plain',
|
|
41
168
|
]);
|
|
42
169
|
|
|
43
|
-
const MARKDOWN_EXTENSIONS = ['.md', '.mdx'];
|
|
44
|
-
const MARKDOWN_MIME_TYPES = new Set(['md', 'mdx', 'text/markdown', 'text/x-markdown']);
|
|
45
|
-
|
|
46
|
-
const TXT_EXTENSIONS = ['.txt'];
|
|
47
|
-
const TXT_MIME_TYPES = new Set(['txt', 'text/plain']);
|
|
48
|
-
|
|
49
170
|
const MSDOC_EXTENSIONS = ['.doc', '.docx', '.odt', '.ppt', '.pptx', '.xls', '.xlsx'];
|
|
50
171
|
const MSDOC_MIME_TYPES = new Set([
|
|
51
172
|
'doc',
|
|
@@ -117,19 +238,9 @@ const FileViewer = memo<FileViewerProps>(({ id, style, fileType, url, name }) =>
|
|
|
117
238
|
return <VideoViewer fileId={id} url={url} />;
|
|
118
239
|
}
|
|
119
240
|
|
|
120
|
-
// JavaScript
|
|
121
|
-
if (matchesFileType(fileType, name,
|
|
122
|
-
return <
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Markdown files
|
|
126
|
-
if (matchesFileType(fileType, name, MARKDOWN_EXTENSIONS, MARKDOWN_MIME_TYPES)) {
|
|
127
|
-
return <MarkdownViewer fileId={id} url={url} />;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Text files
|
|
131
|
-
if (matchesFileType(fileType, name, TXT_EXTENSIONS, TXT_MIME_TYPES)) {
|
|
132
|
-
return <TXTViewer fileId={id} url={url} />;
|
|
241
|
+
// Code files (JavaScript, TypeScript, Python, Java, C++, Go, Rust, Markdown, etc.)
|
|
242
|
+
if (matchesFileType(fileType, name, CODE_EXTENSIONS, CODE_MIME_TYPES)) {
|
|
243
|
+
return <CodeViewer fileId={id} fileName={name} url={url} />;
|
|
133
244
|
}
|
|
134
245
|
|
|
135
246
|
// Microsoft Office documents
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type IEditor,
|
|
3
3
|
INSERT_CHECK_LIST_COMMAND,
|
|
4
|
+
INSERT_CODEMIRROR_COMMAND,
|
|
4
5
|
INSERT_HEADING_COMMAND,
|
|
5
6
|
INSERT_HORIZONTAL_RULE_COMMAND,
|
|
6
7
|
INSERT_IMAGE_COMMAND,
|
|
@@ -28,12 +29,11 @@ import { useMemo } from 'react';
|
|
|
28
29
|
import { useTranslation } from 'react-i18next';
|
|
29
30
|
|
|
30
31
|
import { openFileSelector } from '@/features/PageEditor/EditorCanvas/actions';
|
|
31
|
-
import { usePageEditorStore } from '@/features/PageEditor/store';
|
|
32
32
|
import { useFileStore } from '@/store/file';
|
|
33
33
|
|
|
34
34
|
export const useSlashItems = (editor: IEditor | undefined): SlashOptions['items'] => {
|
|
35
35
|
const { t } = useTranslation('editor');
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
const uploadWithProgress = useFileStore((s) => s.uploadWithProgress);
|
|
38
38
|
|
|
39
39
|
const handleImageUpload = async (file: File) => {
|
|
@@ -179,8 +179,11 @@ export const useSlashItems = (editor: IEditor | undefined): SlashOptions['items'
|
|
|
179
179
|
icon: SquareDashedBottomCodeIcon,
|
|
180
180
|
key: 'codeblock',
|
|
181
181
|
label: t('typobar.codeblock'),
|
|
182
|
-
onSelect: () => {
|
|
183
|
-
|
|
182
|
+
onSelect: (editor) => {
|
|
183
|
+
editor.dispatchCommand(INSERT_CODEMIRROR_COMMAND, undefined);
|
|
184
|
+
queueMicrotask(() => {
|
|
185
|
+
editor.focus();
|
|
186
|
+
});
|
|
184
187
|
},
|
|
185
188
|
},
|
|
186
189
|
{
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type IEditor } from '@lobehub/editor';
|
|
2
|
+
import { type EditorState } from '@lobehub/editor/react';
|
|
2
3
|
|
|
3
4
|
export interface PublicState {
|
|
4
5
|
autoSave?: boolean;
|
|
@@ -16,7 +17,7 @@ export interface State extends PublicState {
|
|
|
16
17
|
currentEmoji: string | undefined;
|
|
17
18
|
currentTitle: string;
|
|
18
19
|
editor?: IEditor;
|
|
19
|
-
editorState?:
|
|
20
|
+
editorState?: EditorState;
|
|
20
21
|
isDirty: boolean; // Track if there are unsaved changes
|
|
21
22
|
isLoadingContent: boolean; // Track if content is being loaded
|
|
22
23
|
lastSavedContent: string; // Last saved content hash for comparison
|
|
@@ -6,8 +6,6 @@ import { memo } from 'react';
|
|
|
6
6
|
import FileViewer from '@/features/FileViewer';
|
|
7
7
|
import { fileManagerSelectors, useFileStore } from '@/store/file';
|
|
8
8
|
|
|
9
|
-
import FileDetail from './FileDetail';
|
|
10
|
-
|
|
11
9
|
interface FilePreviewerProps {
|
|
12
10
|
fileId?: string;
|
|
13
11
|
}
|
|
@@ -22,11 +20,10 @@ const FilePreviewer = memo<FilePreviewerProps>(({ fileId }) => {
|
|
|
22
20
|
if (!fileId || !displayFile) return null;
|
|
23
21
|
|
|
24
22
|
return (
|
|
25
|
-
<Flexbox height={'100%'}
|
|
23
|
+
<Flexbox height={'100%'} width={'100%'}>
|
|
26
24
|
<Flexbox flex={1} height={'100%'} style={{ overflow: 'auto' }}>
|
|
27
25
|
<FileViewer {...displayFile} />
|
|
28
26
|
</Flexbox>
|
|
29
|
-
<FileDetail id={fileId} />
|
|
30
27
|
</Flexbox>
|
|
31
28
|
);
|
|
32
29
|
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Flexbox } from '@lobehub/ui';
|
|
4
|
+
import { memo, useEffect } from 'react';
|
|
5
|
+
|
|
6
|
+
import DragUploadZone, { useUploadFiles } from '@/components/DragUploadZone';
|
|
7
|
+
import type { ActionKeys } from '@/features/ChatInput';
|
|
8
|
+
import { ChatInput, ChatList } from '@/features/Conversation';
|
|
9
|
+
import RightPanel from '@/features/RightPanel';
|
|
10
|
+
import { useAgentStore } from '@/store/agent';
|
|
11
|
+
import { agentByIdSelectors, builtinAgentSelectors } from '@/store/agent/selectors';
|
|
12
|
+
import { useChatStore } from '@/store/chat';
|
|
13
|
+
|
|
14
|
+
const actions: ActionKeys[] = ['model', 'search'];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Help analyze and work with files
|
|
18
|
+
*/
|
|
19
|
+
const FileCopilot = memo(() => {
|
|
20
|
+
const pageAgentId = useAgentStore(builtinAgentSelectors.pageAgentId);
|
|
21
|
+
const [activeAgentId, setActiveAgentId, useFetchAgentConfig] = useAgentStore((s) => [
|
|
22
|
+
s.activeAgentId,
|
|
23
|
+
s.setActiveAgentId,
|
|
24
|
+
s.useFetchAgentConfig,
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
setActiveAgentId(pageAgentId);
|
|
29
|
+
// Also set the chat store's activeAgentId so topic selectors can work correctly
|
|
30
|
+
useChatStore.setState({ activeAgentId: pageAgentId });
|
|
31
|
+
}, [pageAgentId, setActiveAgentId]);
|
|
32
|
+
|
|
33
|
+
const currentAgentId = activeAgentId || pageAgentId;
|
|
34
|
+
|
|
35
|
+
// Fetch agent config when activeAgentId changes to ensure it's loaded in the store
|
|
36
|
+
useFetchAgentConfig(true, currentAgentId);
|
|
37
|
+
|
|
38
|
+
// Get agent's model info for vision support check
|
|
39
|
+
const model = useAgentStore((s) => agentByIdSelectors.getAgentModelById(currentAgentId)(s));
|
|
40
|
+
const provider = useAgentStore((s) =>
|
|
41
|
+
agentByIdSelectors.getAgentModelProviderById(currentAgentId)(s),
|
|
42
|
+
);
|
|
43
|
+
const { handleUploadFiles } = useUploadFiles({ model, provider });
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<RightPanel>
|
|
47
|
+
<DragUploadZone
|
|
48
|
+
onUploadFiles={handleUploadFiles}
|
|
49
|
+
style={{ flex: 1, height: '100%', minWidth: 300 }}
|
|
50
|
+
>
|
|
51
|
+
<Flexbox flex={1} height={'100%'}>
|
|
52
|
+
<Flexbox flex={1} style={{ overflow: 'hidden' }}>
|
|
53
|
+
<ChatList />
|
|
54
|
+
</Flexbox>
|
|
55
|
+
<ChatInput leftActions={actions} />
|
|
56
|
+
</Flexbox>
|
|
57
|
+
</DragUploadZone>
|
|
58
|
+
</RightPanel>
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
FileCopilot.displayName = 'FileCopilot';
|
|
63
|
+
|
|
64
|
+
export default FileCopilot;
|