@lobehub/lobehub 2.0.0-next.142 → 2.0.0-next.143
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 +25 -0
- package/apps/desktop/package.json +1 -0
- package/apps/desktop/src/main/core/ui/__tests__/MenuManager.test.ts +320 -0
- package/apps/desktop/src/main/core/ui/__tests__/Tray.test.ts +518 -0
- package/apps/desktop/src/main/core/ui/__tests__/TrayManager.test.ts +360 -0
- package/apps/desktop/src/main/menus/impls/BaseMenuPlatform.test.ts +49 -0
- package/apps/desktop/src/main/menus/impls/linux.test.ts +552 -0
- package/apps/desktop/src/main/menus/impls/macOS.test.ts +464 -0
- package/apps/desktop/src/main/menus/impls/windows.test.ts +429 -0
- package/apps/desktop/src/main/modules/fileSearch/__tests__/macOS.integration.test.ts +2 -2
- package/apps/desktop/src/main/services/__tests__/fileSearchSrv.test.ts +402 -0
- package/apps/desktop/src/main/utils/__tests__/file-system.test.ts +91 -0
- package/apps/desktop/src/main/utils/__tests__/logger.test.ts +229 -0
- package/apps/desktop/src/preload/electronApi.test.ts +142 -0
- package/apps/desktop/src/preload/invoke.test.ts +145 -0
- package/apps/desktop/src/preload/routeInterceptor.test.ts +374 -0
- package/apps/desktop/src/preload/streamer.test.ts +365 -0
- package/apps/desktop/vitest.config.mts +1 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/marketAuth.json +13 -0
- package/locales/bg-BG/marketAuth.json +13 -0
- package/locales/de-DE/marketAuth.json +13 -0
- package/locales/en-US/marketAuth.json +13 -0
- package/locales/es-ES/marketAuth.json +13 -0
- package/locales/fa-IR/marketAuth.json +13 -0
- package/locales/fr-FR/marketAuth.json +13 -0
- package/locales/it-IT/marketAuth.json +13 -0
- package/locales/ja-JP/marketAuth.json +13 -0
- package/locales/ko-KR/marketAuth.json +13 -0
- package/locales/nl-NL/marketAuth.json +13 -0
- package/locales/pl-PL/marketAuth.json +13 -0
- package/locales/pt-BR/marketAuth.json +13 -0
- package/locales/ru-RU/marketAuth.json +13 -0
- package/locales/tr-TR/marketAuth.json +13 -0
- package/locales/vi-VN/marketAuth.json +13 -0
- package/locales/zh-CN/marketAuth.json +13 -0
- package/locales/zh-TW/marketAuth.json +13 -0
- package/package.json +1 -1
- package/packages/database/src/models/user.ts +2 -0
- package/packages/types/src/discover/mcp.ts +2 -1
- package/packages/types/src/tool/plugin.ts +2 -1
- package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishButton.tsx +0 -2
- package/src/app/[variants]/(main)/discover/(detail)/mcp/features/Sidebar/ActionButton/index.tsx +33 -7
- package/src/features/PluginStore/McpList/List/Action.tsx +20 -1
- package/src/layout/AuthProvider/MarketAuth/MarketAuthConfirmModal.tsx +158 -0
- package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +130 -14
- package/src/libs/mcp/types.ts +8 -0
- package/src/locales/default/marketAuth.ts +13 -0
- package/src/server/routers/lambda/market/index.ts +85 -2
- package/src/server/services/discover/index.ts +45 -4
- package/src/services/discover.ts +1 -1
- package/src/services/mcp.ts +18 -3
- package/src/store/tool/slices/mcpStore/action.test.ts +141 -0
- package/src/store/tool/slices/mcpStore/action.ts +153 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.143](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.142...v2.0.0-next.143)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-12-02**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Support market cloud endpoint mcp.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Support market cloud endpoint mcp, closes [#10484](https://github.com/lobehub/lobe-chat/issues/10484) ([9c7ce44](https://github.com/lobehub/lobe-chat/commit/9c7ce44))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 2.0.0-next.142](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.141...v2.0.0-next.142)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2025-12-01**</sup>
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { Menu } from 'electron';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import type { App } from '../../App';
|
|
5
|
+
import { MenuManager } from '../MenuManager';
|
|
6
|
+
|
|
7
|
+
// Mock electron modules
|
|
8
|
+
vi.mock('electron', () => ({
|
|
9
|
+
Menu: {
|
|
10
|
+
buildFromTemplate: vi.fn(),
|
|
11
|
+
setApplicationMenu: vi.fn(),
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
// Mock logger
|
|
16
|
+
vi.mock('@/utils/logger', () => ({
|
|
17
|
+
createLogger: () => ({
|
|
18
|
+
debug: vi.fn(),
|
|
19
|
+
info: vi.fn(),
|
|
20
|
+
warn: vi.fn(),
|
|
21
|
+
error: vi.fn(),
|
|
22
|
+
}),
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
// Mock menu platform implementation
|
|
26
|
+
const mockBuildAndSetAppMenu = vi.fn();
|
|
27
|
+
const mockBuildContextMenu = vi.fn();
|
|
28
|
+
const mockBuildTrayMenu = vi.fn();
|
|
29
|
+
const mockRefresh = vi.fn();
|
|
30
|
+
|
|
31
|
+
vi.mock('@/menus', () => ({
|
|
32
|
+
createMenuImpl: vi.fn(() => ({
|
|
33
|
+
buildAndSetAppMenu: mockBuildAndSetAppMenu,
|
|
34
|
+
buildContextMenu: mockBuildContextMenu,
|
|
35
|
+
buildTrayMenu: mockBuildTrayMenu,
|
|
36
|
+
refresh: mockRefresh,
|
|
37
|
+
})),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
describe('MenuManager', () => {
|
|
41
|
+
let menuManager: MenuManager;
|
|
42
|
+
let mockApp: App;
|
|
43
|
+
let mockMenu: any;
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
vi.clearAllMocks();
|
|
47
|
+
|
|
48
|
+
// Mock Menu instance
|
|
49
|
+
mockMenu = {
|
|
50
|
+
popup: vi.fn(),
|
|
51
|
+
append: vi.fn(),
|
|
52
|
+
insert: vi.fn(),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Mock App
|
|
56
|
+
mockApp = {} as unknown as App;
|
|
57
|
+
|
|
58
|
+
// Setup mock returns
|
|
59
|
+
mockBuildContextMenu.mockReturnValue(mockMenu);
|
|
60
|
+
mockBuildTrayMenu.mockReturnValue(mockMenu);
|
|
61
|
+
|
|
62
|
+
menuManager = new MenuManager(mockApp);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('constructor', () => {
|
|
66
|
+
it('should initialize MenuManager with app instance', () => {
|
|
67
|
+
expect(menuManager.app).toBe(mockApp);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should create platform implementation', async () => {
|
|
71
|
+
const { createMenuImpl } = await import('@/menus');
|
|
72
|
+
expect(createMenuImpl).toHaveBeenCalledWith(mockApp);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('initialize', () => {
|
|
77
|
+
it('should initialize application menu without options', () => {
|
|
78
|
+
menuManager.initialize();
|
|
79
|
+
|
|
80
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith(undefined);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should initialize application menu with options', () => {
|
|
84
|
+
const options = { showDevItems: true };
|
|
85
|
+
|
|
86
|
+
menuManager.initialize(options);
|
|
87
|
+
|
|
88
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith(options);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should call buildAndSetAppMenu on platform implementation', () => {
|
|
92
|
+
menuManager.initialize();
|
|
93
|
+
|
|
94
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('showContextMenu', () => {
|
|
99
|
+
it('should build and show context menu', () => {
|
|
100
|
+
const type = 'text-input';
|
|
101
|
+
const data = { text: 'sample' };
|
|
102
|
+
|
|
103
|
+
const result = menuManager.showContextMenu(type, data);
|
|
104
|
+
|
|
105
|
+
expect(mockBuildContextMenu).toHaveBeenCalledWith(type, data);
|
|
106
|
+
expect(mockMenu.popup).toHaveBeenCalled();
|
|
107
|
+
expect(result).toEqual({ success: true });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should build context menu without data', () => {
|
|
111
|
+
const type = 'simple-menu';
|
|
112
|
+
|
|
113
|
+
const result = menuManager.showContextMenu(type);
|
|
114
|
+
|
|
115
|
+
expect(mockBuildContextMenu).toHaveBeenCalledWith(type, undefined);
|
|
116
|
+
expect(mockMenu.popup).toHaveBeenCalled();
|
|
117
|
+
expect(result).toEqual({ success: true });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should handle different menu types', () => {
|
|
121
|
+
const types = ['edit', 'view', 'selection', 'link'];
|
|
122
|
+
|
|
123
|
+
types.forEach((type) => {
|
|
124
|
+
vi.clearAllMocks();
|
|
125
|
+
menuManager.showContextMenu(type);
|
|
126
|
+
expect(mockBuildContextMenu).toHaveBeenCalledWith(type, undefined);
|
|
127
|
+
expect(mockMenu.popup).toHaveBeenCalled();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('buildTrayMenu', () => {
|
|
133
|
+
it('should build tray menu', () => {
|
|
134
|
+
const result = menuManager.buildTrayMenu();
|
|
135
|
+
|
|
136
|
+
expect(mockBuildTrayMenu).toHaveBeenCalled();
|
|
137
|
+
expect(result).toBe(mockMenu);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should return Menu instance', () => {
|
|
141
|
+
const result = menuManager.buildTrayMenu();
|
|
142
|
+
|
|
143
|
+
expect(result).toBeDefined();
|
|
144
|
+
expect(result).toBe(mockMenu);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe('refreshMenus', () => {
|
|
149
|
+
it('should refresh all menus without options', () => {
|
|
150
|
+
const result = menuManager.refreshMenus();
|
|
151
|
+
|
|
152
|
+
expect(mockRefresh).toHaveBeenCalledWith(undefined);
|
|
153
|
+
expect(result).toEqual({ success: true });
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should refresh all menus with options', () => {
|
|
157
|
+
const options = { showDevItems: false };
|
|
158
|
+
|
|
159
|
+
const result = menuManager.refreshMenus(options);
|
|
160
|
+
|
|
161
|
+
expect(mockRefresh).toHaveBeenCalledWith(options);
|
|
162
|
+
expect(result).toEqual({ success: true });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should call refresh on platform implementation', () => {
|
|
166
|
+
menuManager.refreshMenus();
|
|
167
|
+
|
|
168
|
+
expect(mockRefresh).toHaveBeenCalled();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('rebuildAppMenu', () => {
|
|
173
|
+
it('should rebuild application menu without options', () => {
|
|
174
|
+
const result = menuManager.rebuildAppMenu();
|
|
175
|
+
|
|
176
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith(undefined);
|
|
177
|
+
expect(result).toEqual({ success: true });
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should rebuild application menu with options', () => {
|
|
181
|
+
const options = { showDevItems: true };
|
|
182
|
+
|
|
183
|
+
const result = menuManager.rebuildAppMenu(options);
|
|
184
|
+
|
|
185
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith(options);
|
|
186
|
+
expect(result).toEqual({ success: true });
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should call buildAndSetAppMenu on platform implementation', () => {
|
|
190
|
+
menuManager.rebuildAppMenu();
|
|
191
|
+
|
|
192
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalled();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('integration tests', () => {
|
|
197
|
+
it('should handle complete menu lifecycle', () => {
|
|
198
|
+
// Initialize menus
|
|
199
|
+
menuManager.initialize({ showDevItems: true });
|
|
200
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith({ showDevItems: true });
|
|
201
|
+
|
|
202
|
+
// Show context menu
|
|
203
|
+
menuManager.showContextMenu('edit');
|
|
204
|
+
expect(mockBuildContextMenu).toHaveBeenCalledWith('edit', undefined);
|
|
205
|
+
expect(mockMenu.popup).toHaveBeenCalled();
|
|
206
|
+
|
|
207
|
+
// Build tray menu
|
|
208
|
+
const trayMenu = menuManager.buildTrayMenu();
|
|
209
|
+
expect(mockBuildTrayMenu).toHaveBeenCalled();
|
|
210
|
+
expect(trayMenu).toBe(mockMenu);
|
|
211
|
+
|
|
212
|
+
// Refresh menus
|
|
213
|
+
menuManager.refreshMenus({ showDevItems: false });
|
|
214
|
+
expect(mockRefresh).toHaveBeenCalledWith({ showDevItems: false });
|
|
215
|
+
|
|
216
|
+
// Rebuild app menu
|
|
217
|
+
menuManager.rebuildAppMenu({ showDevItems: true });
|
|
218
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith({ showDevItems: true });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should handle multiple context menu calls', () => {
|
|
222
|
+
menuManager.showContextMenu('edit');
|
|
223
|
+
menuManager.showContextMenu('view');
|
|
224
|
+
menuManager.showContextMenu('selection');
|
|
225
|
+
|
|
226
|
+
expect(mockBuildContextMenu).toHaveBeenCalledTimes(3);
|
|
227
|
+
expect(mockMenu.popup).toHaveBeenCalledTimes(3);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should handle menu toggling workflow', () => {
|
|
231
|
+
// Initialize with dev menu hidden
|
|
232
|
+
menuManager.initialize({ showDevItems: false });
|
|
233
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith({ showDevItems: false });
|
|
234
|
+
|
|
235
|
+
// Toggle dev menu on
|
|
236
|
+
menuManager.rebuildAppMenu({ showDevItems: true });
|
|
237
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith({ showDevItems: true });
|
|
238
|
+
|
|
239
|
+
// Toggle dev menu off
|
|
240
|
+
menuManager.rebuildAppMenu({ showDevItems: false });
|
|
241
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith({ showDevItems: false });
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('error handling', () => {
|
|
246
|
+
it('should handle errors from buildContextMenu gracefully', () => {
|
|
247
|
+
mockBuildContextMenu.mockImplementation(() => {
|
|
248
|
+
throw new Error('Failed to build context menu');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
expect(() => menuManager.showContextMenu('edit')).toThrow('Failed to build context menu');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should handle errors from buildTrayMenu gracefully', () => {
|
|
255
|
+
mockBuildTrayMenu.mockImplementation(() => {
|
|
256
|
+
throw new Error('Failed to build tray menu');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(() => menuManager.buildTrayMenu()).toThrow('Failed to build tray menu');
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('should handle errors from refresh gracefully', () => {
|
|
263
|
+
mockRefresh.mockImplementation(() => {
|
|
264
|
+
throw new Error('Failed to refresh menus');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(() => menuManager.refreshMenus()).toThrow('Failed to refresh menus');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should handle errors from buildAndSetAppMenu gracefully', () => {
|
|
271
|
+
mockBuildAndSetAppMenu.mockImplementation(() => {
|
|
272
|
+
throw new Error('Failed to build app menu');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(() => menuManager.initialize()).toThrow('Failed to build app menu');
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe('platform implementation delegation', () => {
|
|
280
|
+
beforeEach(() => {
|
|
281
|
+
vi.clearAllMocks();
|
|
282
|
+
// Reset mocks to default behavior
|
|
283
|
+
mockBuildAndSetAppMenu.mockImplementation(() => {});
|
|
284
|
+
mockBuildContextMenu.mockReturnValue(mockMenu);
|
|
285
|
+
mockBuildTrayMenu.mockReturnValue(mockMenu);
|
|
286
|
+
mockRefresh.mockImplementation(() => {});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should delegate all menu operations to platform implementation', () => {
|
|
290
|
+
const options = { showDevItems: true };
|
|
291
|
+
|
|
292
|
+
// Test each method delegates to platform impl
|
|
293
|
+
menuManager.initialize(options);
|
|
294
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith(options);
|
|
295
|
+
|
|
296
|
+
menuManager.showContextMenu('edit', { test: 'data' });
|
|
297
|
+
expect(mockBuildContextMenu).toHaveBeenCalledWith('edit', { test: 'data' });
|
|
298
|
+
|
|
299
|
+
menuManager.buildTrayMenu();
|
|
300
|
+
expect(mockBuildTrayMenu).toHaveBeenCalled();
|
|
301
|
+
|
|
302
|
+
menuManager.refreshMenus(options);
|
|
303
|
+
expect(mockRefresh).toHaveBeenCalledWith(options);
|
|
304
|
+
|
|
305
|
+
menuManager.rebuildAppMenu(options);
|
|
306
|
+
expect(mockBuildAndSetAppMenu).toHaveBeenCalledWith(options);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should maintain consistent interface across all operations', () => {
|
|
310
|
+
// All modification operations should return success response
|
|
311
|
+
expect(menuManager.showContextMenu('edit')).toEqual({ success: true });
|
|
312
|
+
expect(menuManager.refreshMenus()).toEqual({ success: true });
|
|
313
|
+
expect(menuManager.rebuildAppMenu()).toEqual({ success: true });
|
|
314
|
+
|
|
315
|
+
// buildTrayMenu should return Menu instance
|
|
316
|
+
const trayMenu = menuManager.buildTrayMenu();
|
|
317
|
+
expect(trayMenu).toBe(mockMenu);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
});
|