@lobehub/lobehub 2.0.0-next.233 → 2.0.0-next.235

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 (169) hide show
  1. package/.github/workflows/e2e.yml +6 -12
  2. package/.github/workflows/test.yml +3 -3
  3. package/CHANGELOG.md +59 -0
  4. package/CLAUDE.md +1 -1
  5. package/changelog/v1.json +18 -0
  6. package/docs/development/basic/feature-development.mdx +4 -5
  7. package/docs/development/basic/feature-development.zh-CN.mdx +4 -5
  8. package/e2e/README.md +6 -6
  9. package/e2e/src/features/community/detail-pages.feature +9 -9
  10. package/e2e/src/features/community/interactions.feature +13 -13
  11. package/e2e/src/features/community/smoke.feature +6 -6
  12. package/e2e/src/steps/agent/conversation-mgmt.steps.ts +196 -25
  13. package/e2e/src/steps/agent/conversation.steps.ts +58 -0
  14. package/e2e/src/steps/agent/message-ops.steps.ts +20 -15
  15. package/e2e/src/steps/community/detail-pages.steps.ts +60 -19
  16. package/e2e/src/steps/community/interactions.steps.ts +145 -32
  17. package/e2e/src/steps/hooks.ts +12 -2
  18. package/locales/ar/components.json +1 -0
  19. package/locales/ar/file.json +4 -0
  20. package/locales/ar/models.json +29 -0
  21. package/locales/ar/setting.json +7 -0
  22. package/locales/bg-BG/components.json +1 -0
  23. package/locales/bg-BG/file.json +4 -0
  24. package/locales/bg-BG/models.json +1 -0
  25. package/locales/bg-BG/setting.json +7 -0
  26. package/locales/de-DE/components.json +1 -0
  27. package/locales/de-DE/file.json +4 -0
  28. package/locales/de-DE/models.json +29 -0
  29. package/locales/de-DE/setting.json +7 -0
  30. package/locales/en-US/common.json +0 -1
  31. package/locales/en-US/components.json +1 -0
  32. package/locales/en-US/file.json +4 -0
  33. package/locales/en-US/models.json +1 -0
  34. package/locales/en-US/setting.json +3 -0
  35. package/locales/es-ES/components.json +1 -0
  36. package/locales/es-ES/file.json +4 -0
  37. package/locales/es-ES/models.json +43 -0
  38. package/locales/es-ES/setting.json +7 -0
  39. package/locales/fa-IR/components.json +1 -0
  40. package/locales/fa-IR/file.json +4 -0
  41. package/locales/fa-IR/models.json +54 -0
  42. package/locales/fa-IR/setting.json +7 -0
  43. package/locales/fr-FR/components.json +1 -0
  44. package/locales/fr-FR/file.json +4 -0
  45. package/locales/fr-FR/models.json +31 -0
  46. package/locales/fr-FR/setting.json +7 -0
  47. package/locales/it-IT/components.json +1 -0
  48. package/locales/it-IT/file.json +4 -0
  49. package/locales/it-IT/models.json +43 -0
  50. package/locales/it-IT/setting.json +7 -0
  51. package/locales/ja-JP/components.json +1 -0
  52. package/locales/ja-JP/file.json +4 -0
  53. package/locales/ja-JP/models.json +28 -0
  54. package/locales/ja-JP/setting.json +7 -0
  55. package/locales/ko-KR/components.json +1 -0
  56. package/locales/ko-KR/file.json +4 -0
  57. package/locales/ko-KR/models.json +37 -0
  58. package/locales/ko-KR/setting.json +7 -0
  59. package/locales/nl-NL/components.json +1 -0
  60. package/locales/nl-NL/file.json +4 -0
  61. package/locales/nl-NL/models.json +13 -0
  62. package/locales/nl-NL/setting.json +7 -0
  63. package/locales/pl-PL/components.json +1 -0
  64. package/locales/pl-PL/file.json +4 -0
  65. package/locales/pl-PL/models.json +13 -0
  66. package/locales/pl-PL/setting.json +7 -0
  67. package/locales/pt-BR/components.json +1 -0
  68. package/locales/pt-BR/file.json +4 -0
  69. package/locales/pt-BR/models.json +29 -0
  70. package/locales/pt-BR/setting.json +7 -0
  71. package/locales/ru-RU/components.json +1 -0
  72. package/locales/ru-RU/file.json +4 -0
  73. package/locales/ru-RU/models.json +1 -0
  74. package/locales/ru-RU/setting.json +7 -0
  75. package/locales/tr-TR/components.json +1 -0
  76. package/locales/tr-TR/file.json +4 -0
  77. package/locales/tr-TR/models.json +29 -0
  78. package/locales/tr-TR/setting.json +7 -0
  79. package/locales/vi-VN/components.json +1 -0
  80. package/locales/vi-VN/file.json +4 -0
  81. package/locales/vi-VN/models.json +1 -0
  82. package/locales/vi-VN/setting.json +7 -0
  83. package/locales/zh-CN/file.json +4 -0
  84. package/locales/zh-CN/models.json +46 -0
  85. package/locales/zh-CN/setting.json +3 -0
  86. package/locales/zh-TW/components.json +1 -0
  87. package/locales/zh-TW/file.json +4 -0
  88. package/locales/zh-TW/models.json +35 -0
  89. package/locales/zh-TW/setting.json +7 -0
  90. package/package.json +5 -5
  91. package/packages/const/src/index.ts +1 -0
  92. package/packages/const/src/lobehubSkill.ts +55 -0
  93. package/packages/types/package.json +1 -1
  94. package/packages/types/src/files/upload.ts +11 -1
  95. package/packages/types/src/message/common/tools.ts +1 -1
  96. package/packages/types/src/serverConfig.ts +1 -0
  97. package/public/not-compatible.html +1296 -0
  98. package/src/app/[variants]/(main)/resource/features/FileDetail.tsx +20 -12
  99. package/src/app/[variants]/(main)/resource/features/modal/FullscreenModal.tsx +2 -4
  100. package/src/app/[variants]/layout.tsx +50 -1
  101. package/src/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem.tsx +304 -0
  102. package/src/features/ChatInput/ActionBar/Tools/useControls.tsx +74 -10
  103. package/src/features/Conversation/Messages/AssistantGroup/Tool/Inspector/ToolTitle.tsx +9 -0
  104. package/src/features/FileViewer/Renderer/Code/index.tsx +224 -0
  105. package/src/features/FileViewer/Renderer/Image/index.tsx +8 -1
  106. package/src/features/FileViewer/Renderer/PDF/index.tsx +3 -1
  107. package/src/features/FileViewer/Renderer/PDF/style.ts +2 -1
  108. package/src/features/FileViewer/index.tsx +135 -24
  109. package/src/features/PageEditor/EditorCanvas/useSlashItems.tsx +7 -4
  110. package/src/features/PageEditor/store/initialState.ts +2 -1
  111. package/src/features/ResourceManager/components/Editor/FileContent.tsx +1 -4
  112. package/src/features/ResourceManager/components/Editor/FileCopilot.tsx +64 -0
  113. package/src/features/ResourceManager/components/Editor/index.tsx +98 -31
  114. package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +3 -2
  115. package/src/features/ResourceManager/components/Explorer/ListView/ColumnResizeHandle.tsx +119 -0
  116. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +67 -22
  117. package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +46 -11
  118. package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +140 -81
  119. package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +20 -12
  120. package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +18 -10
  121. package/src/features/ResourceManager/components/UploadDock/Item.tsx +38 -6
  122. package/src/features/ResourceManager/components/UploadDock/index.tsx +62 -41
  123. package/src/features/ResourceManager/index.tsx +1 -0
  124. package/src/helpers/toolEngineering/index.test.ts +3 -0
  125. package/src/helpers/toolEngineering/index.ts +12 -1
  126. package/src/locales/default/file.ts +4 -0
  127. package/src/locales/default/setting.ts +3 -0
  128. package/src/server/globalConfig/index.ts +1 -0
  129. package/src/server/modules/ModelRuntime/index.test.ts +214 -1
  130. package/src/server/modules/ModelRuntime/index.ts +43 -7
  131. package/src/server/routers/lambda/_helpers/resolveContext.ts +8 -8
  132. package/src/server/routers/lambda/agent.ts +1 -1
  133. package/src/server/routers/lambda/aiModel.ts +1 -1
  134. package/src/server/routers/lambda/comfyui.ts +1 -1
  135. package/src/server/routers/lambda/document.ts +44 -0
  136. package/src/server/routers/lambda/exporter.ts +1 -1
  137. package/src/server/routers/lambda/image.ts +13 -13
  138. package/src/server/routers/lambda/klavis.ts +10 -10
  139. package/src/server/routers/lambda/market/index.ts +6 -6
  140. package/src/server/routers/lambda/message.ts +2 -2
  141. package/src/server/routers/lambda/plugin.ts +1 -1
  142. package/src/server/routers/lambda/ragEval.ts +2 -2
  143. package/src/server/routers/lambda/topic.ts +3 -3
  144. package/src/server/routers/lambda/user.ts +10 -10
  145. package/src/server/routers/lambda/userMemories.ts +6 -6
  146. package/src/server/routers/tools/market.ts +261 -0
  147. package/src/server/services/document/index.ts +22 -0
  148. package/src/services/document/index.ts +4 -0
  149. package/src/services/upload.ts +22 -2
  150. package/src/store/chat/slices/plugin/actions/internals.ts +15 -2
  151. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +104 -0
  152. package/src/store/file/slices/fileManager/action.test.ts +9 -3
  153. package/src/store/file/slices/fileManager/action.ts +165 -70
  154. package/src/store/file/slices/upload/action.ts +3 -0
  155. package/src/store/global/actions/general.ts +15 -0
  156. package/src/store/global/initialState.ts +13 -0
  157. package/src/store/serverConfig/selectors.ts +1 -0
  158. package/src/store/tool/initialState.ts +11 -2
  159. package/src/store/tool/selectors/index.ts +1 -0
  160. package/src/store/tool/selectors/tool.ts +3 -1
  161. package/src/store/tool/slices/lobehubSkillStore/action.ts +361 -0
  162. package/src/store/tool/slices/lobehubSkillStore/index.ts +4 -0
  163. package/src/store/tool/slices/lobehubSkillStore/initialState.ts +24 -0
  164. package/src/store/tool/slices/lobehubSkillStore/selectors.ts +145 -0
  165. package/src/store/tool/slices/lobehubSkillStore/types.ts +100 -0
  166. package/src/store/tool/store.ts +8 -2
  167. package/vitest.config.mts +1 -0
  168. package/src/features/FileViewer/Renderer/JavaScript/index.tsx +0 -66
  169. 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
- min-height: 100%;
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 JS_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx'];
31
- const JS_MIME_TYPES = new Set([
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/TypeScript files
121
- if (matchesFileType(fileType, name, JS_EXTENSIONS, JS_MIME_TYPES)) {
122
- return <JavaScriptViewer fileId={id} fileName={name} url={url} />;
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
- const editorState = usePageEditorStore((s) => s.editorState);
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
- editorState.codeblock();
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?: any; // EditorState from useEditorState hook
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%'} horizontal width={'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;