refactor(Constants): 优化一些常量和枚举值 (#3773)
* refactor(main): 使用枚举管理 IPC 通道 - 新增 IpcChannel 枚举,用于统一管理所有的 IPC 通道 - 修改相关代码,使用 IpcChannel 枚举替代硬编码的字符串通道名称 - 此改动有助于提高代码的可维护性和可读性,避免因通道名称变更导致的错误 * refactor(ipc): 将字符串通道名称替换为 IpcChannel 枚举 - 在多个文件中将硬编码的字符串通道名称替换为 IpcChannel 枚举值 - 更新了相关文件的导入,增加了对 IpcChannel 的引用 - 通过使用枚举来管理 IPC 通道名称,提高了代码的可维护性和可读性 * refactor(ipc): 调整 IPC 通道枚举和预加载脚本 - 移除了 IpcChannel 枚举中的未使用注释 - 更新了预加载脚本中 IpcChannel 的导入路径 * refactor(ipc): 更新 IpcChannel导入路径 - 将 IpcChannel 的导入路径从 @main/enum/IpcChannel 修改为 @shared/IpcChannel - 此修改涉及多个文件,包括 AppUpdater、BackupManager、EditMcpJsonPopup 等 - 同时移除了 tsconfig.web.json 中对 src/main/**/* 的引用 * refactor(ipc): 添加 ReduxStoreReady 事件并更新事件监听 - 在 IpcChannel 枚举中添加 ReduxStoreReady 事件 - 更新 ReduxService 中的事件监听,使用新的枚举值 * refactor(main): 重构 ReduxService 中的状态变化事件处理 - 将状态变化事件名称定义为常量 STATUS_CHANGE_EVENT - 更新事件监听和触发使用新的常量 - 优化了代码结构,提高了可维护性 * refactor(i18n): 优化国际化配置和语言选择逻辑 - 在多个文件中引入 defaultLanguage 常量,统一默认语言设置 - 调整 i18n 初始化和语言变更逻辑,使用新配置 - 更新相关组件和 Hook 中的语言选择逻辑 * refactor(ConfigManager): 重构配置管理器 - 添加 ConfigKeys 枚举,用于统一配置项的键名 - 引入 defaultLanguage,作为默认语言设置 - 重构 get 和 set 方法,使用 ConfigKeys 枚举作为键名 - 优化类型定义和方法签名,提高代码可读性和可维护性 * refactor(ConfigManager): 重命名配置键 ZoomFactor 将配置键 zoomFactor 重命名为 ZoomFactor,以符合命名规范。 更新了相关方法和属性以反映这一变更。 * refactor(shared): 重构常量定义并优化文件大小格式化逻辑 - 在 constant.ts 中添加 KB、MB、GB 常量定义 - 将 defaultLanguage 移至 constant.ts - 更新 ConfigManager、useAppInit、i18n、GeneralSettings 等文件中的导入路径 - 优化 formatFileSize 函数,使用新定义的常量 * refactor(FileSize): 使用 GB/MB/KB 等常量处理文件大小计算 * refactor(ipc): 将字符串通道名称替换为 IpcChannel 枚举 - 在多个文件中将硬编码的字符串通道名称替换为 IpcChannel 枚举值 - 更新了相关文件的导入,增加了对 IpcChannel 的引用 - 通过使用枚举来管理 IPC 通道名称,提高了代码的可维护性和可读性 * refactor(ipc): 更新 IpcChannel导入路径 - 将 IpcChannel 的导入路径从 @main/enum/IpcChannel 修改为 @shared/IpcChannel - 此修改涉及多个文件,包括 AppUpdater、BackupManager、EditMcpJsonPopup 等 - 同时移除了 tsconfig.web.json 中对 src/main/**/* 的引用 * refactor(i18n): 优化国际化配置和语言选择逻辑 - 在多个文件中引入 defaultLanguage 常量,统一默认语言设置 - 调整 i18n 初始化和语言变更逻辑,使用新配置 - 更新相关组件和 Hook 中的语言选择逻辑 * refactor(shared): 重构常量定义并优化文件大小格式化逻辑 - 在 constant.ts 中添加 KB、MB、GB 常量定义 - 将 defaultLanguage 移至 constant.ts - 更新 ConfigManager、useAppInit、i18n、GeneralSettings 等文件中的导入路径 - 优化 formatFileSize 函数,使用新定义的常量 * refactor: 移除重复的导入语句 - 在 HomeWindow.tsx 和 useAppInit.ts 文件中移除了重复的 defaultLanguage导入语句 - 这个改动简化了代码结构,提高了代码的可读性和维护性
This commit is contained in:
parent
ef8250ab72
commit
3290ac4b1b
150
packages/shared/IpcChannel.ts
Normal file
150
packages/shared/IpcChannel.ts
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
export enum IpcChannel {
|
||||||
|
App_ClearCache = 'app:clear-cache',
|
||||||
|
App_SetLaunchOnBoot = 'app:set-launch-on-boot',
|
||||||
|
App_SetLanguage = 'app:set-language',
|
||||||
|
App_ShowUpdateDialog = 'app:show-update-dialog',
|
||||||
|
App_CheckForUpdate = 'app:check-for-update',
|
||||||
|
App_Reload = 'app:reload',
|
||||||
|
App_Info = 'app:info',
|
||||||
|
App_Proxy = 'app:proxy',
|
||||||
|
App_SetLaunchToTray = 'app:set-launch-to-tray',
|
||||||
|
App_SetTray = 'app:set-tray',
|
||||||
|
App_SetTrayOnClose = 'app:set-tray-on-close',
|
||||||
|
App_RestartTray = 'app:restart-tray',
|
||||||
|
App_SetTheme = 'app:set-theme',
|
||||||
|
|
||||||
|
App_IsBinaryExist = 'app:is-binary-exist',
|
||||||
|
App_GetBinaryPath = 'app:get-binary-path',
|
||||||
|
App_InstallUvBinary = 'app:install-uv-binary',
|
||||||
|
App_InstallBunBinary = 'app:install-bun-binary',
|
||||||
|
|
||||||
|
// Open
|
||||||
|
Open_Path = 'open:path',
|
||||||
|
Open_Website = 'open:website',
|
||||||
|
|
||||||
|
Minapp = 'minapp',
|
||||||
|
|
||||||
|
Config_Set = 'config:set',
|
||||||
|
Config_Get = 'config:get',
|
||||||
|
|
||||||
|
MiniWindow_Show = 'miniwindow:show',
|
||||||
|
MiniWindow_Hide = 'miniwindow:hide',
|
||||||
|
MiniWindow_Close = 'miniwindow:close',
|
||||||
|
MiniWindow_Toggle = 'miniwindow:toggle',
|
||||||
|
MiniWindow_SetPin = 'miniwindow:set-pin',
|
||||||
|
|
||||||
|
// Mcp
|
||||||
|
Mcp_RemoveServer = 'mcp:remove-server',
|
||||||
|
Mcp_RestartServer = 'mcp:restart-server',
|
||||||
|
Mcp_StopServer = 'mcp:stop-server',
|
||||||
|
Mcp_ListTools = 'mcp:list-tools',
|
||||||
|
Mcp_CallTool = 'mcp:call-tool',
|
||||||
|
Mcp_GetInstallInfo = 'mcp:get-install-info',
|
||||||
|
Mcp_ServersChanged = 'mcp:servers-changed',
|
||||||
|
Mcp_ServersUpdated = 'mcp:servers-updated',
|
||||||
|
|
||||||
|
//copilot
|
||||||
|
Copilot_GetAuthMessage = 'copilot:get-auth-message',
|
||||||
|
Copilot_GetCopilotToken = 'copilot:get-copilot-token',
|
||||||
|
Copilot_SaveCopilotToken = 'copilot:save-copilot-token',
|
||||||
|
Copilot_GetToken = 'copilot:get-token',
|
||||||
|
Copilot_Logout = 'copilot:logout',
|
||||||
|
Copilot_GetUser = 'copilot:get-user',
|
||||||
|
|
||||||
|
// obsidian
|
||||||
|
Obsidian_GetVaults = 'obsidian:get-vaults',
|
||||||
|
Obsidian_GetFiles = 'obsidian:get-files',
|
||||||
|
|
||||||
|
// nutstore
|
||||||
|
Nutstore_GetSsoUrl = 'nutstore:get-sso-url',
|
||||||
|
Nutstore_DecryptToken = 'nutstore:decrypt-token',
|
||||||
|
Nutstore_GetDirectoryContents = 'nutstore:get-directory-contents',
|
||||||
|
|
||||||
|
//aes
|
||||||
|
Aes_Encrypt = 'aes:encrypt',
|
||||||
|
Aes_Decrypt = 'aes:decrypt',
|
||||||
|
|
||||||
|
Gemini_UploadFile = 'gemini:upload-file',
|
||||||
|
Gemini_Base64File = 'gemini:base64-file',
|
||||||
|
Gemini_RetrieveFile = 'gemini:retrieve-file',
|
||||||
|
Gemini_ListFiles = 'gemini:list-files',
|
||||||
|
Gemini_DeleteFile = 'gemini:delete-file',
|
||||||
|
|
||||||
|
Windows_ResetMinimumSize = 'window:reset-minimum-size',
|
||||||
|
Windows_SetMinimumSize = 'window:set-minimum-size',
|
||||||
|
|
||||||
|
SelectionMenu_Action = 'selection-menu:action',
|
||||||
|
|
||||||
|
KnowledgeBase_Create = 'knowledge-base:create',
|
||||||
|
KnowledgeBase_Reset = 'knowledge-base:reset',
|
||||||
|
KnowledgeBase_Delete = 'knowledge-base:delete',
|
||||||
|
KnowledgeBase_Add = 'knowledge-base:add',
|
||||||
|
KnowledgeBase_Remove = 'knowledge-base:remove',
|
||||||
|
KnowledgeBase_Search = 'knowledge-base:search',
|
||||||
|
KnowledgeBase_Rerank = 'knowledge-base:rerank',
|
||||||
|
|
||||||
|
//file
|
||||||
|
File_Open = 'file:open',
|
||||||
|
File_OpenPath = 'file:openPath',
|
||||||
|
File_Save = 'file:save',
|
||||||
|
File_Select = 'file:select',
|
||||||
|
File_Upload = 'file:upload',
|
||||||
|
File_Clear = 'file:clear',
|
||||||
|
File_Read = 'file:read',
|
||||||
|
File_Delete = 'file:delete',
|
||||||
|
File_Get = 'file:get',
|
||||||
|
File_SelectFolder = 'file:selectFolder',
|
||||||
|
File_Create = 'file:create',
|
||||||
|
File_Write = 'file:write',
|
||||||
|
File_SaveImage = 'file:saveImage',
|
||||||
|
File_Base64Image = 'file:base64Image',
|
||||||
|
File_Download = 'file:download',
|
||||||
|
File_Copy = 'file:copy',
|
||||||
|
File_BinaryFile = 'file:binaryFile',
|
||||||
|
|
||||||
|
Fs_Read = 'fs:read',
|
||||||
|
|
||||||
|
Export_Word = 'export:word',
|
||||||
|
|
||||||
|
Shortcuts_Update = 'shortcuts:update',
|
||||||
|
|
||||||
|
// backup
|
||||||
|
Backup_Backup = 'backup:backup',
|
||||||
|
Backup_Restore = 'backup:restore',
|
||||||
|
Backup_BackupToWebdav = 'backup:backupToWebdav',
|
||||||
|
Backup_RestoreFromWebdav = 'backup:restoreFromWebdav',
|
||||||
|
Backup_ListWebdavFiles = 'backup:listWebdavFiles',
|
||||||
|
Backup_CheckConnection = 'backup:checkConnection',
|
||||||
|
Backup_CreateDirectory = 'backup:createDirectory',
|
||||||
|
|
||||||
|
// zip
|
||||||
|
Zip_Compress = 'zip:compress',
|
||||||
|
Zip_Decompress = 'zip:decompress',
|
||||||
|
|
||||||
|
// system
|
||||||
|
System_GetDeviceType = 'system:getDeviceType',
|
||||||
|
|
||||||
|
// events
|
||||||
|
SelectionAction = 'selection-action',
|
||||||
|
BackupProgress = 'backup-progress',
|
||||||
|
ThemeChange = 'theme:change',
|
||||||
|
UpdateDownloadedCancelled = 'update-downloaded-cancelled',
|
||||||
|
RestoreProgress = 'restore-progress',
|
||||||
|
UpdateError = 'update-error',
|
||||||
|
UpdateAvailable = 'update-available',
|
||||||
|
UpdateNotAvailable = 'update-not-available',
|
||||||
|
DownloadProgress = 'download-progress',
|
||||||
|
UpdateDownloaded = 'update-downloaded',
|
||||||
|
DownloadUpdate = 'download-update',
|
||||||
|
|
||||||
|
DirectoryProcessingPercent = 'directory-processing-percent',
|
||||||
|
|
||||||
|
FullscreenStatusChanged = 'fullscreen-status-changed',
|
||||||
|
|
||||||
|
HideMiniWindow = 'hide-mini-window',
|
||||||
|
ShowMiniWindow = 'show-mini-window',
|
||||||
|
MiniWindowReload = 'miniwindow-reload',
|
||||||
|
|
||||||
|
ReduxStateChange = 'redux-state-change',
|
||||||
|
ReduxStoreReady = 'redux-store-ready',
|
||||||
|
}
|
||||||
@ -157,3 +157,8 @@ export const ZOOM_SHORTCUTS = [
|
|||||||
system: true
|
system: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const KB = 1024
|
||||||
|
export const MB = 1024 * KB
|
||||||
|
export const GB = 1024 * MB
|
||||||
|
export const defaultLanguage = 'en-US'
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { CHERRY_STUDIO_PROTOCOL, handleProtocolUrl, registerProtocolClient } fro
|
|||||||
import { registerShortcuts } from './services/ShortcutService'
|
import { registerShortcuts } from './services/ShortcutService'
|
||||||
import { TrayService } from './services/TrayService'
|
import { TrayService } from './services/TrayService'
|
||||||
import { windowService } from './services/WindowService'
|
import { windowService } from './services/WindowService'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
// Check for single instance lock
|
// Check for single instance lock
|
||||||
if (!app.requestSingleInstanceLock()) {
|
if (!app.requestSingleInstanceLock()) {
|
||||||
@ -52,7 +53,7 @@ if (!app.requestSingleInstanceLock()) {
|
|||||||
.then((name) => console.log(`Added Extension: ${name}`))
|
.then((name) => console.log(`Added Extension: ${name}`))
|
||||||
.catch((err) => console.log('An error occurred: ', err))
|
.catch((err) => console.log('An error occurred: ', err))
|
||||||
}
|
}
|
||||||
ipcMain.handle('system:getDeviceType', () => {
|
ipcMain.handle(IpcChannel.System_GetDeviceType, () => {
|
||||||
return process.platform === 'darwin' ? 'mac' : process.platform === 'win32' ? 'windows' : 'linux'
|
return process.platform === 'darwin' ? 'mac' : process.platform === 'win32' ? 'windows' : 'linux'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
191
src/main/ipc.ts
191
src/main/ipc.ts
@ -27,6 +27,7 @@ import { getResourcePath } from './utils'
|
|||||||
import { decrypt, encrypt } from './utils/aes'
|
import { decrypt, encrypt } from './utils/aes'
|
||||||
import { getFilesDir } from './utils/file'
|
import { getFilesDir } from './utils/file'
|
||||||
import { compress, decompress } from './utils/zip'
|
import { compress, decompress } from './utils/zip'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
const fileManager = new FileStorage()
|
const fileManager = new FileStorage()
|
||||||
const backupManager = new BackupManager()
|
const backupManager = new BackupManager()
|
||||||
@ -36,7 +37,7 @@ const obsidianVaultService = new ObsidianVaultService()
|
|||||||
export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||||
const appUpdater = new AppUpdater(mainWindow)
|
const appUpdater = new AppUpdater(mainWindow)
|
||||||
|
|
||||||
ipcMain.handle('app:info', () => ({
|
ipcMain.handle(IpcChannel.App_Info, () => ({
|
||||||
version: app.getVersion(),
|
version: app.getVersion(),
|
||||||
isPackaged: app.isPackaged,
|
isPackaged: app.isPackaged,
|
||||||
appPath: app.getAppPath(),
|
appPath: app.getAppPath(),
|
||||||
@ -46,7 +47,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
logsPath: log.transports.file.getFile().path
|
logsPath: log.transports.file.getFile().path
|
||||||
}))
|
}))
|
||||||
|
|
||||||
ipcMain.handle('app:proxy', async (_, proxy: string) => {
|
ipcMain.handle(IpcChannel.App_Proxy, async (_, proxy: string) => {
|
||||||
let proxyConfig: ProxyConfig
|
let proxyConfig: ProxyConfig
|
||||||
|
|
||||||
if (proxy === 'system') {
|
if (proxy === 'system') {
|
||||||
@ -60,19 +61,19 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
await proxyManager.configureProxy(proxyConfig)
|
await proxyManager.configureProxy(proxyConfig)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('app:reload', () => mainWindow.reload())
|
ipcMain.handle(IpcChannel.App_Reload, () => mainWindow.reload())
|
||||||
ipcMain.handle('open:website', (_, url: string) => shell.openExternal(url))
|
ipcMain.handle(IpcChannel.Open_Website, (_, url: string) => shell.openExternal(url))
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
ipcMain.handle('app:show-update-dialog', () => appUpdater.showUpdateDialog(mainWindow))
|
ipcMain.handle(IpcChannel.App_ShowUpdateDialog, () => appUpdater.showUpdateDialog(mainWindow))
|
||||||
|
|
||||||
// language
|
// language
|
||||||
ipcMain.handle('app:set-language', (_, language) => {
|
ipcMain.handle(IpcChannel.App_SetLanguage, (_, language) => {
|
||||||
configManager.setLanguage(language)
|
configManager.setLanguage(language)
|
||||||
})
|
})
|
||||||
|
|
||||||
// launch on boot
|
// launch on boot
|
||||||
ipcMain.handle('app:set-launch-on-boot', (_, openAtLogin: boolean) => {
|
ipcMain.handle(IpcChannel.App_SetLaunchOnBoot, (_, openAtLogin: boolean) => {
|
||||||
// Set login item settings for windows and mac
|
// Set login item settings for windows and mac
|
||||||
// linux is not supported because it requires more file operations
|
// linux is not supported because it requires more file operations
|
||||||
if (isWin || isMac) {
|
if (isWin || isMac) {
|
||||||
@ -81,32 +82,32 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// launch to tray
|
// launch to tray
|
||||||
ipcMain.handle('app:set-launch-to-tray', (_, isActive: boolean) => {
|
ipcMain.handle(IpcChannel.App_SetLaunchToTray, (_, isActive: boolean) => {
|
||||||
configManager.setLaunchToTray(isActive)
|
configManager.setLaunchToTray(isActive)
|
||||||
})
|
})
|
||||||
|
|
||||||
// tray
|
// tray
|
||||||
ipcMain.handle('app:set-tray', (_, isActive: boolean) => {
|
ipcMain.handle(IpcChannel.App_SetTray, (_, isActive: boolean) => {
|
||||||
configManager.setTray(isActive)
|
configManager.setTray(isActive)
|
||||||
})
|
})
|
||||||
|
|
||||||
// to tray on close
|
// to tray on close
|
||||||
ipcMain.handle('app:set-tray-on-close', (_, isActive: boolean) => {
|
ipcMain.handle(IpcChannel.App_SetTrayOnClose, (_, isActive: boolean) => {
|
||||||
configManager.setTrayOnClose(isActive)
|
configManager.setTrayOnClose(isActive)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('app:restart-tray', () => TrayService.getInstance().restartTray())
|
ipcMain.handle(IpcChannel.App_RestartTray, () => TrayService.getInstance().restartTray())
|
||||||
|
|
||||||
ipcMain.handle('config:set', (_, key: string, value: any) => {
|
ipcMain.handle(IpcChannel.Config_Set, (_, key: string, value: any) => {
|
||||||
configManager.set(key, value)
|
configManager.set(key, value)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('config:get', (_, key: string) => {
|
ipcMain.handle(IpcChannel.Config_Get, (_, key: string) => {
|
||||||
return configManager.get(key)
|
return configManager.get(key)
|
||||||
})
|
})
|
||||||
|
|
||||||
// theme
|
// theme
|
||||||
ipcMain.handle('app:set-theme', (event, theme: ThemeMode) => {
|
ipcMain.handle(IpcChannel.App_SetTheme, (event, theme: ThemeMode) => {
|
||||||
if (theme === configManager.getTheme()) return
|
if (theme === configManager.getTheme()) return
|
||||||
|
|
||||||
configManager.setTheme(theme)
|
configManager.setTheme(theme)
|
||||||
@ -117,7 +118,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
// 向其他窗口广播主题变化
|
// 向其他窗口广播主题变化
|
||||||
windows.forEach((win) => {
|
windows.forEach((win) => {
|
||||||
if (win.webContents.id !== senderWindowId) {
|
if (win.webContents.id !== senderWindowId) {
|
||||||
win.webContents.send('theme:change', theme)
|
win.webContents.send(IpcChannel.ThemeChange, theme)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// clear cache
|
// clear cache
|
||||||
ipcMain.handle('app:clear-cache', async () => {
|
ipcMain.handle(IpcChannel.App_ClearCache, async () => {
|
||||||
const sessions = [session.defaultSession, session.fromPartition('persist:webview')]
|
const sessions = [session.defaultSession, session.fromPartition('persist:webview')]
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -148,7 +149,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// check for update
|
// check for update
|
||||||
ipcMain.handle('app:check-for-update', async () => {
|
ipcMain.handle(IpcChannel.App_CheckForUpdate, async () => {
|
||||||
const update = await appUpdater.autoUpdater.checkForUpdates()
|
const update = await appUpdater.autoUpdater.checkForUpdates()
|
||||||
return {
|
return {
|
||||||
currentVersion: appUpdater.autoUpdater.currentVersion,
|
currentVersion: appUpdater.autoUpdater.currentVersion,
|
||||||
@ -157,42 +158,42 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// zip
|
// zip
|
||||||
ipcMain.handle('zip:compress', (_, text: string) => compress(text))
|
ipcMain.handle(IpcChannel.Zip_Compress, (_, text: string) => compress(text))
|
||||||
ipcMain.handle('zip:decompress', (_, text: Buffer) => decompress(text))
|
ipcMain.handle(IpcChannel.Zip_Decompress, (_, text: Buffer) => decompress(text))
|
||||||
|
|
||||||
// backup
|
// backup
|
||||||
ipcMain.handle('backup:backup', backupManager.backup)
|
ipcMain.handle(IpcChannel.Backup_Backup, backupManager.backup)
|
||||||
ipcMain.handle('backup:restore', backupManager.restore)
|
ipcMain.handle(IpcChannel.Backup_Restore, backupManager.restore)
|
||||||
ipcMain.handle('backup:backupToWebdav', backupManager.backupToWebdav)
|
ipcMain.handle(IpcChannel.Backup_BackupToWebdav, backupManager.backupToWebdav)
|
||||||
ipcMain.handle('backup:restoreFromWebdav', backupManager.restoreFromWebdav)
|
ipcMain.handle(IpcChannel.Backup_RestoreFromWebdav, backupManager.restoreFromWebdav)
|
||||||
ipcMain.handle('backup:listWebdavFiles', backupManager.listWebdavFiles)
|
ipcMain.handle(IpcChannel.Backup_ListWebdavFiles, backupManager.listWebdavFiles)
|
||||||
ipcMain.handle('backup:checkConnection', backupManager.checkConnection)
|
ipcMain.handle(IpcChannel.Backup_CheckConnection, backupManager.checkConnection)
|
||||||
ipcMain.handle('backup:createDirectory', backupManager.createDirectory)
|
ipcMain.handle(IpcChannel.Backup_CreateDirectory, backupManager.createDirectory)
|
||||||
|
|
||||||
// file
|
// file
|
||||||
ipcMain.handle('file:open', fileManager.open)
|
ipcMain.handle(IpcChannel.File_Open, fileManager.open)
|
||||||
ipcMain.handle('file:openPath', fileManager.openPath)
|
ipcMain.handle(IpcChannel.File_OpenPath, fileManager.openPath)
|
||||||
ipcMain.handle('file:save', fileManager.save)
|
ipcMain.handle(IpcChannel.File_Save, fileManager.save)
|
||||||
ipcMain.handle('file:select', fileManager.selectFile)
|
ipcMain.handle(IpcChannel.File_Select, fileManager.selectFile)
|
||||||
ipcMain.handle('file:upload', fileManager.uploadFile)
|
ipcMain.handle(IpcChannel.File_Upload, fileManager.uploadFile)
|
||||||
ipcMain.handle('file:clear', fileManager.clear)
|
ipcMain.handle(IpcChannel.File_Clear, fileManager.clear)
|
||||||
ipcMain.handle('file:read', fileManager.readFile)
|
ipcMain.handle(IpcChannel.File_Read, fileManager.readFile)
|
||||||
ipcMain.handle('file:delete', fileManager.deleteFile)
|
ipcMain.handle(IpcChannel.File_Delete, fileManager.deleteFile)
|
||||||
ipcMain.handle('file:get', fileManager.getFile)
|
ipcMain.handle(IpcChannel.File_Get, fileManager.getFile)
|
||||||
ipcMain.handle('file:selectFolder', fileManager.selectFolder)
|
ipcMain.handle(IpcChannel.File_SelectFolder, fileManager.selectFolder)
|
||||||
ipcMain.handle('file:create', fileManager.createTempFile)
|
ipcMain.handle(IpcChannel.File_Create, fileManager.createTempFile)
|
||||||
ipcMain.handle('file:write', fileManager.writeFile)
|
ipcMain.handle(IpcChannel.File_Write, fileManager.writeFile)
|
||||||
ipcMain.handle('file:saveImage', fileManager.saveImage)
|
ipcMain.handle(IpcChannel.File_SaveImage, fileManager.saveImage)
|
||||||
ipcMain.handle('file:base64Image', fileManager.base64Image)
|
ipcMain.handle(IpcChannel.File_Base64Image, fileManager.base64Image)
|
||||||
ipcMain.handle('file:download', fileManager.downloadFile)
|
ipcMain.handle(IpcChannel.File_Download, fileManager.downloadFile)
|
||||||
ipcMain.handle('file:copy', fileManager.copyFile)
|
ipcMain.handle(IpcChannel.File_Copy, fileManager.copyFile)
|
||||||
ipcMain.handle('file:binaryFile', fileManager.binaryFile)
|
ipcMain.handle(IpcChannel.File_BinaryFile, fileManager.binaryFile)
|
||||||
|
|
||||||
// fs
|
// fs
|
||||||
ipcMain.handle('fs:read', FileService.readFile)
|
ipcMain.handle(IpcChannel.Fs_Read, FileService.readFile)
|
||||||
|
|
||||||
// minapp
|
// minapp
|
||||||
ipcMain.handle('minapp', (_, args) => {
|
ipcMain.handle(IpcChannel.Minapp, (_, args) => {
|
||||||
windowService.createMinappWindow({
|
windowService.createMinappWindow({
|
||||||
url: args.url,
|
url: args.url,
|
||||||
parent: mainWindow,
|
parent: mainWindow,
|
||||||
@ -204,15 +205,15 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// export
|
// export
|
||||||
ipcMain.handle('export:word', exportService.exportToWord)
|
ipcMain.handle(IpcChannel.Export_Word, exportService.exportToWord)
|
||||||
|
|
||||||
// open path
|
// open path
|
||||||
ipcMain.handle('open:path', async (_, path: string) => {
|
ipcMain.handle(IpcChannel.Open_Path, async (_, path: string) => {
|
||||||
await shell.openPath(path)
|
await shell.openPath(path)
|
||||||
})
|
})
|
||||||
|
|
||||||
// shortcuts
|
// shortcuts
|
||||||
ipcMain.handle('shortcuts:update', (_, shortcuts: Shortcut[]) => {
|
ipcMain.handle(IpcChannel.Shortcuts_Update, (_, shortcuts: Shortcut[]) => {
|
||||||
configManager.setShortcuts(shortcuts)
|
configManager.setShortcuts(shortcuts)
|
||||||
// Refresh shortcuts registration
|
// Refresh shortcuts registration
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
@ -222,20 +223,20 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// knowledge base
|
// knowledge base
|
||||||
ipcMain.handle('knowledge-base:create', KnowledgeService.create)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Create, KnowledgeService.create)
|
||||||
ipcMain.handle('knowledge-base:reset', KnowledgeService.reset)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Reset, KnowledgeService.reset)
|
||||||
ipcMain.handle('knowledge-base:delete', KnowledgeService.delete)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Delete, KnowledgeService.delete)
|
||||||
ipcMain.handle('knowledge-base:add', KnowledgeService.add)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Add, KnowledgeService.add)
|
||||||
ipcMain.handle('knowledge-base:remove', KnowledgeService.remove)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Remove, KnowledgeService.remove)
|
||||||
ipcMain.handle('knowledge-base:search', KnowledgeService.search)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Search, KnowledgeService.search)
|
||||||
ipcMain.handle('knowledge-base:rerank', KnowledgeService.rerank)
|
ipcMain.handle(IpcChannel.KnowledgeBase_Rerank, KnowledgeService.rerank)
|
||||||
|
|
||||||
// window
|
// window
|
||||||
ipcMain.handle('window:set-minimum-size', (_, width: number, height: number) => {
|
ipcMain.handle(IpcChannel.Windows_SetMinimumSize, (_, width: number, height: number) => {
|
||||||
mainWindow?.setMinimumSize(width, height)
|
mainWindow?.setMinimumSize(width, height)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('window:reset-minimum-size', () => {
|
ipcMain.handle(IpcChannel.Windows_ResetMinimumSize, () => {
|
||||||
mainWindow?.setMinimumSize(1080, 600)
|
mainWindow?.setMinimumSize(1080, 600)
|
||||||
const [width, height] = mainWindow?.getSize() ?? [1080, 600]
|
const [width, height] = mainWindow?.getSize() ?? [1080, 600]
|
||||||
if (width < 1080) {
|
if (width < 1080) {
|
||||||
@ -244,59 +245,69 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// gemini
|
// gemini
|
||||||
ipcMain.handle('gemini:upload-file', GeminiService.uploadFile)
|
ipcMain.handle(IpcChannel.Gemini_UploadFile, GeminiService.uploadFile)
|
||||||
ipcMain.handle('gemini:base64-file', GeminiService.base64File)
|
ipcMain.handle(IpcChannel.Gemini_Base64File, GeminiService.base64File)
|
||||||
ipcMain.handle('gemini:retrieve-file', GeminiService.retrieveFile)
|
ipcMain.handle(IpcChannel.Gemini_RetrieveFile, GeminiService.retrieveFile)
|
||||||
ipcMain.handle('gemini:list-files', GeminiService.listFiles)
|
ipcMain.handle(IpcChannel.Gemini_ListFiles, GeminiService.listFiles)
|
||||||
ipcMain.handle('gemini:delete-file', GeminiService.deleteFile)
|
ipcMain.handle(IpcChannel.Gemini_DeleteFile, GeminiService.deleteFile)
|
||||||
|
|
||||||
// mini window
|
// mini window
|
||||||
ipcMain.handle('miniwindow:show', () => windowService.showMiniWindow())
|
ipcMain.handle(IpcChannel.MiniWindow_Show, () => windowService.showMiniWindow())
|
||||||
ipcMain.handle('miniwindow:hide', () => windowService.hideMiniWindow())
|
ipcMain.handle(IpcChannel.MiniWindow_Hide, () => windowService.hideMiniWindow())
|
||||||
ipcMain.handle('miniwindow:close', () => windowService.closeMiniWindow())
|
ipcMain.handle(IpcChannel.MiniWindow_Close, () => windowService.closeMiniWindow())
|
||||||
ipcMain.handle('miniwindow:toggle', () => windowService.toggleMiniWindow())
|
ipcMain.handle(IpcChannel.MiniWindow_Toggle, () => windowService.toggleMiniWindow())
|
||||||
ipcMain.handle('miniwindow:set-pin', (_, isPinned) => windowService.setPinMiniWindow(isPinned))
|
ipcMain.handle(IpcChannel.MiniWindow_SetPin, (_, isPinned) => windowService.setPinMiniWindow(isPinned))
|
||||||
|
|
||||||
// aes
|
// aes
|
||||||
ipcMain.handle('aes:encrypt', (_, text: string, secretKey: string, iv: string) => encrypt(text, secretKey, iv))
|
ipcMain.handle(IpcChannel.Aes_Encrypt, (_, text: string, secretKey: string, iv: string) =>
|
||||||
ipcMain.handle('aes:decrypt', (_, encryptedData: string, iv: string, secretKey: string) =>
|
encrypt(text, secretKey, iv)
|
||||||
|
)
|
||||||
|
ipcMain.handle(IpcChannel.Aes_Decrypt, (_, encryptedData: string, iv: string, secretKey: string) =>
|
||||||
decrypt(encryptedData, iv, secretKey)
|
decrypt(encryptedData, iv, secretKey)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Register MCP handlers
|
// Register MCP handlers
|
||||||
ipcMain.handle('mcp:remove-server', mcpService.removeServer)
|
ipcMain.handle(IpcChannel.Mcp_RemoveServer, mcpService.removeServer)
|
||||||
ipcMain.handle('mcp:restart-server', mcpService.restartServer)
|
ipcMain.handle(IpcChannel.Mcp_RestartServer, mcpService.restartServer)
|
||||||
ipcMain.handle('mcp:stop-server', mcpService.stopServer)
|
ipcMain.handle(IpcChannel.Mcp_StopServer, mcpService.stopServer)
|
||||||
ipcMain.handle('mcp:list-tools', mcpService.listTools)
|
ipcMain.handle(IpcChannel.Mcp_ListTools, mcpService.listTools)
|
||||||
ipcMain.handle('mcp:call-tool', mcpService.callTool)
|
ipcMain.handle(IpcChannel.Mcp_CallTool, mcpService.callTool)
|
||||||
ipcMain.handle('mcp:get-install-info', mcpService.getInstallInfo)
|
ipcMain.handle(IpcChannel.Mcp_GetInstallInfo, mcpService.getInstallInfo)
|
||||||
|
|
||||||
ipcMain.handle('app:is-binary-exist', (_, name: string) => isBinaryExists(name))
|
ipcMain.handle(IpcChannel.App_IsBinaryExist, (_, name: string) => isBinaryExists(name))
|
||||||
ipcMain.handle('app:get-binary-path', (_, name: string) => getBinaryPath(name))
|
ipcMain.handle(IpcChannel.App_GetBinaryPath, (_, name: string) => getBinaryPath(name))
|
||||||
ipcMain.handle('app:install-uv-binary', () => runInstallScript('install-uv.js'))
|
ipcMain.handle(IpcChannel.App_InstallUvBinary, () => runInstallScript('install-uv.js'))
|
||||||
ipcMain.handle('app:install-bun-binary', () => runInstallScript('install-bun.js'))
|
ipcMain.handle(IpcChannel.App_InstallBunBinary, () => runInstallScript('install-bun.js'))
|
||||||
|
|
||||||
//copilot
|
//copilot
|
||||||
ipcMain.handle('copilot:get-auth-message', CopilotService.getAuthMessage)
|
ipcMain.handle(IpcChannel.Copilot_GetAuthMessage, CopilotService.getAuthMessage)
|
||||||
ipcMain.handle('copilot:get-copilot-token', CopilotService.getCopilotToken)
|
ipcMain.handle(IpcChannel.Copilot_GetCopilotToken, CopilotService.getCopilotToken)
|
||||||
ipcMain.handle('copilot:save-copilot-token', CopilotService.saveCopilotToken)
|
ipcMain.handle(IpcChannel.Copilot_SaveCopilotToken, CopilotService.saveCopilotToken)
|
||||||
ipcMain.handle('copilot:get-token', CopilotService.getToken)
|
ipcMain.handle(IpcChannel.Copilot_GetToken, CopilotService.getToken)
|
||||||
ipcMain.handle('copilot:logout', CopilotService.logout)
|
ipcMain.handle(IpcChannel.Copilot_Logout, CopilotService.logout)
|
||||||
ipcMain.handle('copilot:get-user', CopilotService.getUser)
|
ipcMain.handle(IpcChannel.Copilot_GetUser, CopilotService.getUser)
|
||||||
|
|
||||||
// Obsidian service
|
// Obsidian service
|
||||||
ipcMain.handle('obsidian:get-vaults', () => {
|
ipcMain.handle(IpcChannel.Obsidian_GetVaults, () => {
|
||||||
return obsidianVaultService.getVaults()
|
return obsidianVaultService.getVaults()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('obsidian:get-files', (_event, vaultName) => {
|
ipcMain.handle(IpcChannel.Obsidian_GetFiles, (_event, vaultName) => {
|
||||||
return obsidianVaultService.getFilesByVaultName(vaultName)
|
return obsidianVaultService.getFilesByVaultName(vaultName)
|
||||||
})
|
})
|
||||||
|
|
||||||
// nutstore
|
// nutstore
|
||||||
ipcMain.handle('nutstore:get-sso-url', NutstoreService.getNutstoreSSOUrl)
|
ipcMain.handle(IpcChannel.Nutstore_GetSsoUrl, NutstoreService.getNutstoreSSOUrl)
|
||||||
ipcMain.handle('nutstore:decrypt-token', (_, token: string) => NutstoreService.decryptToken(token))
|
ipcMain.handle(IpcChannel.Nutstore_DecryptToken, (_, token: string) => NutstoreService.decryptToken(token))
|
||||||
ipcMain.handle('nutstore:get-directory-contents', (_, token: string, path: string) =>
|
ipcMain.handle(IpcChannel.Nutstore_GetDirectoryContents, (_, token: string, path: string) =>
|
||||||
NutstoreService.getDirectoryContents(token, path)
|
NutstoreService.getDirectoryContents(token, path)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen for changes in MCP servers and notify renderer
|
||||||
|
mcpService.on('servers-updated', (servers) => {
|
||||||
|
mainWindow?.webContents.send(IpcChannel.Mcp_ServersUpdated, servers)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('before-quit', () => mcpService.cleanup())
|
||||||
|
|
||||||
@ -4,6 +4,7 @@ import logger from 'electron-log'
|
|||||||
import { AppUpdater as _AppUpdater, autoUpdater } from 'electron-updater'
|
import { AppUpdater as _AppUpdater, autoUpdater } from 'electron-updater'
|
||||||
|
|
||||||
import icon from '../../../build/icon.png?asset'
|
import icon from '../../../build/icon.png?asset'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
export default class AppUpdater {
|
export default class AppUpdater {
|
||||||
autoUpdater: _AppUpdater = autoUpdater
|
autoUpdater: _AppUpdater = autoUpdater
|
||||||
@ -24,27 +25,27 @@ export default class AppUpdater {
|
|||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
time: new Date().toISOString()
|
time: new Date().toISOString()
|
||||||
})
|
})
|
||||||
mainWindow.webContents.send('update-error', error)
|
mainWindow.webContents.send(IpcChannel.UpdateError, error)
|
||||||
})
|
})
|
||||||
|
|
||||||
autoUpdater.on('update-available', (releaseInfo: UpdateInfo) => {
|
autoUpdater.on('update-available', (releaseInfo: UpdateInfo) => {
|
||||||
logger.info('检测到新版本', releaseInfo)
|
logger.info('检测到新版本', releaseInfo)
|
||||||
mainWindow.webContents.send('update-available', releaseInfo)
|
mainWindow.webContents.send(IpcChannel.UpdateAvailable, releaseInfo)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检测到不需要更新时
|
// 检测到不需要更新时
|
||||||
autoUpdater.on('update-not-available', () => {
|
autoUpdater.on('update-not-available', () => {
|
||||||
mainWindow.webContents.send('update-not-available')
|
mainWindow.webContents.send(IpcChannel.UpdateNotAvailable)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新下载进度
|
// 更新下载进度
|
||||||
autoUpdater.on('download-progress', (progress) => {
|
autoUpdater.on('download-progress', (progress) => {
|
||||||
mainWindow.webContents.send('download-progress', progress)
|
mainWindow.webContents.send(IpcChannel.DownloadProgress, progress)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当需要更新的内容下载完成后
|
// 当需要更新的内容下载完成后
|
||||||
autoUpdater.on('update-downloaded', (releaseInfo: UpdateInfo) => {
|
autoUpdater.on('update-downloaded', (releaseInfo: UpdateInfo) => {
|
||||||
mainWindow.webContents.send('update-downloaded', releaseInfo)
|
mainWindow.webContents.send(IpcChannel.UpdateDownloaded, releaseInfo)
|
||||||
this.releaseInfo = releaseInfo
|
this.releaseInfo = releaseInfo
|
||||||
logger.info('下载完成', releaseInfo)
|
logger.info('下载完成', releaseInfo)
|
||||||
})
|
})
|
||||||
@ -73,7 +74,7 @@ export default class AppUpdater {
|
|||||||
app.isQuitting = true
|
app.isQuitting = true
|
||||||
setImmediate(() => autoUpdater.quitAndInstall())
|
setImmediate(() => autoUpdater.quitAndInstall())
|
||||||
} else {
|
} else {
|
||||||
mainWindow.webContents.send('update-downloaded-cancelled')
|
mainWindow.webContents.send(IpcChannel.UpdateDownloadedCancelled)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { createClient, CreateDirectoryOptions, FileStat } from 'webdav'
|
|||||||
|
|
||||||
import WebDav from './WebDav'
|
import WebDav from './WebDav'
|
||||||
import { windowService } from './WindowService'
|
import { windowService } from './WindowService'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
class BackupManager {
|
class BackupManager {
|
||||||
private tempDir = path.join(app.getPath('temp'), 'cherry-studio', 'backup', 'temp')
|
private tempDir = path.join(app.getPath('temp'), 'cherry-studio', 'backup', 'temp')
|
||||||
@ -79,7 +80,7 @@ class BackupManager {
|
|||||||
const mainWindow = windowService.getMainWindow()
|
const mainWindow = windowService.getMainWindow()
|
||||||
|
|
||||||
const onProgress = (processData: { stage: string; progress: number; total: number }) => {
|
const onProgress = (processData: { stage: string; progress: number; total: number }) => {
|
||||||
mainWindow?.webContents.send('backup-progress', processData)
|
mainWindow?.webContents.send(IpcChannel.BackupProgress, processData)
|
||||||
Logger.log('[BackupManager] backup progress', processData)
|
Logger.log('[BackupManager] backup progress', processData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +140,7 @@ class BackupManager {
|
|||||||
const mainWindow = windowService.getMainWindow()
|
const mainWindow = windowService.getMainWindow()
|
||||||
|
|
||||||
const onProgress = (processData: { stage: string; progress: number; total: number }) => {
|
const onProgress = (processData: { stage: string; progress: number; total: number }) => {
|
||||||
mainWindow?.webContents.send('restore-progress', processData)
|
mainWindow?.webContents.send(IpcChannel.RestoreProgress, processData)
|
||||||
Logger.log('[BackupManager] restore progress', processData)
|
Logger.log('[BackupManager] restore progress', processData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,22 @@
|
|||||||
import { ZOOM_SHORTCUTS } from '@shared/config/constant'
|
import { defaultLanguage, ZOOM_SHORTCUTS } from '@shared/config/constant'
|
||||||
import { LanguageVarious, Shortcut, ThemeMode } from '@types'
|
import { LanguageVarious, Shortcut, ThemeMode } from '@types'
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import Store from 'electron-store'
|
import Store from 'electron-store'
|
||||||
|
|
||||||
import { locales } from '../utils/locales'
|
import { locales } from '../utils/locales'
|
||||||
|
|
||||||
|
enum ConfigKeys {
|
||||||
|
Language = 'language',
|
||||||
|
Theme = 'theme',
|
||||||
|
LaunchToTray = 'launchToTray',
|
||||||
|
Tray = 'tray',
|
||||||
|
TrayOnClose = 'trayOnClose',
|
||||||
|
ZoomFactor = 'ZoomFactor',
|
||||||
|
Shortcuts = 'shortcuts',
|
||||||
|
ClickTrayToShowQuickAssistant = 'clickTrayToShowQuickAssistant',
|
||||||
|
EnableQuickAssistant = 'enableQuickAssistant'
|
||||||
|
}
|
||||||
|
|
||||||
export class ConfigManager {
|
export class ConfigManager {
|
||||||
private store: Store
|
private store: Store
|
||||||
private subscribers: Map<string, Array<(newValue: any) => void>> = new Map()
|
private subscribers: Map<string, Array<(newValue: any) => void>> = new Map()
|
||||||
@ -14,54 +26,54 @@ export class ConfigManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getLanguage(): LanguageVarious {
|
getLanguage(): LanguageVarious {
|
||||||
const locale = Object.keys(locales).includes(app.getLocale()) ? app.getLocale() : 'en-US'
|
const locale = Object.keys(locales).includes(app.getLocale()) ? app.getLocale() : defaultLanguage
|
||||||
return this.store.get('language', locale) as LanguageVarious
|
return this.get(ConfigKeys.Language, locale) as LanguageVarious
|
||||||
}
|
}
|
||||||
|
|
||||||
setLanguage(theme: LanguageVarious) {
|
setLanguage(theme: LanguageVarious) {
|
||||||
this.store.set('language', theme)
|
this.set(ConfigKeys.Language, theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
getTheme(): ThemeMode {
|
getTheme(): ThemeMode {
|
||||||
return this.store.get('theme', ThemeMode.light) as ThemeMode
|
return this.get(ConfigKeys.Theme, ThemeMode.light)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTheme(theme: ThemeMode) {
|
setTheme(theme: ThemeMode) {
|
||||||
this.store.set('theme', theme)
|
this.set(ConfigKeys.Theme, theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
getLaunchToTray(): boolean {
|
getLaunchToTray(): boolean {
|
||||||
return !!this.store.get('launchToTray', false)
|
return !!this.get(ConfigKeys.LaunchToTray, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
setLaunchToTray(value: boolean) {
|
setLaunchToTray(value: boolean) {
|
||||||
this.store.set('launchToTray', value)
|
this.set(ConfigKeys.LaunchToTray, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
getTray(): boolean {
|
getTray(): boolean {
|
||||||
return !!this.store.get('tray', true)
|
return !!this.get(ConfigKeys.Tray, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTray(value: boolean) {
|
setTray(value: boolean) {
|
||||||
this.store.set('tray', value)
|
this.set(ConfigKeys.Tray, value)
|
||||||
this.notifySubscribers('tray', value)
|
this.notifySubscribers(ConfigKeys.Tray, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrayOnClose(): boolean {
|
getTrayOnClose(): boolean {
|
||||||
return !!this.store.get('trayOnClose', true)
|
return !!this.get(ConfigKeys.TrayOnClose, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTrayOnClose(value: boolean) {
|
setTrayOnClose(value: boolean) {
|
||||||
this.store.set('trayOnClose', value)
|
this.set(ConfigKeys.TrayOnClose, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
getZoomFactor(): number {
|
getZoomFactor(): number {
|
||||||
return this.store.get('zoomFactor', 1) as number
|
return this.get<number>(ConfigKeys.ZoomFactor, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
setZoomFactor(factor: number) {
|
setZoomFactor(factor: number) {
|
||||||
this.store.set('zoomFactor', factor)
|
this.set(ConfigKeys.ZoomFactor, factor)
|
||||||
this.notifySubscribers('zoomFactor', factor)
|
this.notifySubscribers(ConfigKeys.ZoomFactor, factor)
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe<T>(key: string, callback: (newValue: T) => void) {
|
subscribe<T>(key: string, callback: (newValue: T) => void) {
|
||||||
@ -89,39 +101,39 @@ export class ConfigManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getShortcuts() {
|
getShortcuts() {
|
||||||
return this.store.get('shortcuts', ZOOM_SHORTCUTS) as Shortcut[] | []
|
return this.get(ConfigKeys.Shortcuts, ZOOM_SHORTCUTS) as Shortcut[] | []
|
||||||
}
|
}
|
||||||
|
|
||||||
setShortcuts(shortcuts: Shortcut[]) {
|
setShortcuts(shortcuts: Shortcut[]) {
|
||||||
this.store.set(
|
this.set(
|
||||||
'shortcuts',
|
ConfigKeys.Shortcuts,
|
||||||
shortcuts.filter((shortcut) => shortcut.system)
|
shortcuts.filter((shortcut) => shortcut.system)
|
||||||
)
|
)
|
||||||
this.notifySubscribers('shortcuts', shortcuts)
|
this.notifySubscribers(ConfigKeys.Shortcuts, shortcuts)
|
||||||
}
|
}
|
||||||
|
|
||||||
getClickTrayToShowQuickAssistant(): boolean {
|
getClickTrayToShowQuickAssistant(): boolean {
|
||||||
return this.store.get('clickTrayToShowQuickAssistant', false) as boolean
|
return this.get<boolean>(ConfigKeys.ClickTrayToShowQuickAssistant, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
setClickTrayToShowQuickAssistant(value: boolean) {
|
setClickTrayToShowQuickAssistant(value: boolean) {
|
||||||
this.store.set('clickTrayToShowQuickAssistant', value)
|
this.set(ConfigKeys.ClickTrayToShowQuickAssistant, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
getEnableQuickAssistant(): boolean {
|
getEnableQuickAssistant(): boolean {
|
||||||
return this.store.get('enableQuickAssistant', false) as boolean
|
return this.get(ConfigKeys.EnableQuickAssistant, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
setEnableQuickAssistant(value: boolean) {
|
setEnableQuickAssistant(value: boolean) {
|
||||||
this.store.set('enableQuickAssistant', value)
|
this.set(ConfigKeys.EnableQuickAssistant, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
set(key: string, value: any) {
|
set(key: string, value: unknown) {
|
||||||
this.store.set(key, value)
|
this.store.set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
get(key: string) {
|
get<T>(key: string, defaultValue?: T) {
|
||||||
return this.store.get(key)
|
return this.store.get(key, defaultValue) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { getFilesDir, getFileType, getTempDir } from '@main/utils/file'
|
import { getFilesDir, getFileType, getTempDir } from '@main/utils/file'
|
||||||
import { documentExts, imageExts } from '@shared/config/constant'
|
import { documentExts, imageExts, MB } from '@shared/config/constant'
|
||||||
import { FileType } from '@types'
|
import { FileType } from '@types'
|
||||||
import * as crypto from 'crypto'
|
import * as crypto from 'crypto'
|
||||||
import {
|
import {
|
||||||
@ -122,7 +122,7 @@ class FileStorage {
|
|||||||
private async compressImage(sourcePath: string, destPath: string): Promise<void> {
|
private async compressImage(sourcePath: string, destPath: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const stats = fs.statSync(sourcePath)
|
const stats = fs.statSync(sourcePath)
|
||||||
const fileSizeInMB = stats.size / (1024 * 1024)
|
const fileSizeInMB = stats.size / MB
|
||||||
|
|
||||||
// 如果图片大于1MB才进行压缩
|
// 如果图片大于1MB才进行压缩
|
||||||
if (fileSizeInMB > 1) {
|
if (fileSizeInMB > 1) {
|
||||||
|
|||||||
@ -31,6 +31,8 @@ import { FileType, KnowledgeBaseParams, KnowledgeItem } from '@types'
|
|||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import Logger from 'electron-log'
|
import Logger from 'electron-log'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
import { MB } from '@shared/config/constant'
|
||||||
|
|
||||||
export interface KnowledgeBaseAddItemOptions {
|
export interface KnowledgeBaseAddItemOptions {
|
||||||
base: KnowledgeBaseParams
|
base: KnowledgeBaseParams
|
||||||
@ -91,7 +93,7 @@ class KnowledgeService {
|
|||||||
private workload = 0
|
private workload = 0
|
||||||
private processingItemCount = 0
|
private processingItemCount = 0
|
||||||
private knowledgeItemProcessingQueueMappingPromise: Map<LoaderTaskOfSet, () => void> = new Map()
|
private knowledgeItemProcessingQueueMappingPromise: Map<LoaderTaskOfSet, () => void> = new Map()
|
||||||
private static MAXIMUM_WORKLOAD = 1024 * 1024 * 80
|
private static MAXIMUM_WORKLOAD = 80 * MB
|
||||||
private static MAXIMUM_PROCESSING_ITEM_COUNT = 30
|
private static MAXIMUM_PROCESSING_ITEM_COUNT = 30
|
||||||
private static ERROR_LOADER_RETURN: LoaderReturn = { entriesAdded: 0, uniqueId: '', uniqueIds: [''], loaderType: '' }
|
private static ERROR_LOADER_RETURN: LoaderReturn = { entriesAdded: 0, uniqueId: '', uniqueIds: [''], loaderType: '' }
|
||||||
|
|
||||||
@ -194,7 +196,7 @@ class KnowledgeService {
|
|||||||
|
|
||||||
const sendDirectoryProcessingPercent = (totalFiles: number, processedFiles: number) => {
|
const sendDirectoryProcessingPercent = (totalFiles: number, processedFiles: number) => {
|
||||||
const mainWindow = windowService.getMainWindow()
|
const mainWindow = windowService.getMainWindow()
|
||||||
mainWindow?.webContents.send('directory-processing-percent', {
|
mainWindow?.webContents.send(IpcChannel.DirectoryProcessingPercent, {
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
percent: (processedFiles / totalFiles) * 100
|
percent: (processedFiles / totalFiles) * 100
|
||||||
})
|
})
|
||||||
@ -270,7 +272,7 @@ class KnowledgeService {
|
|||||||
return KnowledgeService.ERROR_LOADER_RETURN
|
return KnowledgeService.ERROR_LOADER_RETURN
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
evaluateTaskWorkload: { workload: 1024 * 1024 * 2 }
|
evaluateTaskWorkload: { workload: 2 * MB }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
loaderDoneReturn: null
|
loaderDoneReturn: null
|
||||||
@ -309,7 +311,7 @@ class KnowledgeService {
|
|||||||
Logger.error(err)
|
Logger.error(err)
|
||||||
return KnowledgeService.ERROR_LOADER_RETURN
|
return KnowledgeService.ERROR_LOADER_RETURN
|
||||||
}),
|
}),
|
||||||
evaluateTaskWorkload: { workload: 1024 * 1024 * 20 }
|
evaluateTaskWorkload: { workload: 20 * MB }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
loaderDoneReturn: null
|
loaderDoneReturn: null
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { ipcMain } from 'electron'
|
|||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events'
|
||||||
|
|
||||||
import { windowService } from './WindowService'
|
import { windowService } from './WindowService'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
type StoreValue = any
|
type StoreValue = any
|
||||||
type Unsubscribe = () => void
|
type Unsubscribe = () => void
|
||||||
@ -10,6 +11,8 @@ export class ReduxService extends EventEmitter {
|
|||||||
private stateCache: any = {}
|
private stateCache: any = {}
|
||||||
private isReady = false
|
private isReady = false
|
||||||
|
|
||||||
|
private readonly STATUS_CHANGE_EVENT = 'statusChange'
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.setupIpcHandlers()
|
this.setupIpcHandlers()
|
||||||
@ -17,15 +20,15 @@ export class ReduxService extends EventEmitter {
|
|||||||
|
|
||||||
private setupIpcHandlers() {
|
private setupIpcHandlers() {
|
||||||
// 监听 store 就绪事件
|
// 监听 store 就绪事件
|
||||||
ipcMain.handle('redux-store-ready', () => {
|
ipcMain.handle(IpcChannel.ReduxStoreReady, () => {
|
||||||
this.isReady = true
|
this.isReady = true
|
||||||
this.emit('ready')
|
this.emit('ready')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听 store 状态变化
|
// 监听 store 状态变化
|
||||||
ipcMain.on('redux-state-change', (_, newState) => {
|
ipcMain.on(IpcChannel.ReduxStateChange, (_, newState) => {
|
||||||
this.stateCache = newState
|
this.stateCache = newState
|
||||||
this.emit('stateChange', newState)
|
this.emit(this.STATUS_CHANGE_EVENT, newState)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,19 +125,23 @@ export class ReduxService extends EventEmitter {
|
|||||||
await this.waitForStoreReady(mainWindow.webContents)
|
await this.waitForStoreReady(mainWindow.webContents)
|
||||||
|
|
||||||
// 在渲染进程中设置监听
|
// 在渲染进程中设置监听
|
||||||
await mainWindow.webContents.executeJavaScript(`
|
await mainWindow.webContents.executeJavaScript(
|
||||||
|
`
|
||||||
if (!window._storeSubscriptions) {
|
if (!window._storeSubscriptions) {
|
||||||
window._storeSubscriptions = new Set();
|
window._storeSubscriptions = new Set();
|
||||||
|
|
||||||
// 设置全局状态变化监听
|
// 设置全局状态变化监听
|
||||||
const unsubscribe = window.store.subscribe(() => {
|
const unsubscribe = window.store.subscribe(() => {
|
||||||
const state = window.store.getState();
|
const state = window.store.getState();
|
||||||
window.electron.ipcRenderer.send('redux-state-change', state);
|
window.electron.ipcRenderer.send('` +
|
||||||
|
IpcChannel.ReduxStateChange +
|
||||||
|
`', state);
|
||||||
});
|
});
|
||||||
|
|
||||||
window._storeSubscriptions.add(unsubscribe);
|
window._storeSubscriptions.add(unsubscribe);
|
||||||
}
|
}
|
||||||
`)
|
`
|
||||||
|
)
|
||||||
|
|
||||||
// 在主进程中处理回调
|
// 在主进程中处理回调
|
||||||
const handler = async () => {
|
const handler = async () => {
|
||||||
@ -146,9 +153,9 @@ export class ReduxService extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.on('stateChange', handler)
|
this.on(this.STATUS_CHANGE_EVENT, handler)
|
||||||
return () => {
|
return () => {
|
||||||
this.off('stateChange', handler)
|
this.off(this.STATUS_CHANGE_EVENT, handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +187,7 @@ export class ReduxService extends EventEmitter {
|
|||||||
export const reduxService = new ReduxService()
|
export const reduxService = new ReduxService()
|
||||||
|
|
||||||
/** example
|
/** example
|
||||||
async function example() {
|
async function example() {
|
||||||
try {
|
try {
|
||||||
// 读取状态
|
// 读取状态
|
||||||
const settings = await reduxService.select('state.settings')
|
const settings = await reduxService.select('state.settings')
|
||||||
@ -216,5 +223,5 @@ async function example() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error)
|
console.error('Error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import icon from '../../../build/icon.png?asset'
|
|||||||
import { titleBarOverlayDark, titleBarOverlayLight } from '../config'
|
import { titleBarOverlayDark, titleBarOverlayLight } from '../config'
|
||||||
import { locales } from '../utils/locales'
|
import { locales } from '../utils/locales'
|
||||||
import { configManager } from './ConfigManager'
|
import { configManager } from './ConfigManager'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
export class WindowService {
|
export class WindowService {
|
||||||
private static instance: WindowService | null = null
|
private static instance: WindowService | null = null
|
||||||
@ -168,12 +169,12 @@ export class WindowService {
|
|||||||
// 处理全屏相关事件
|
// 处理全屏相关事件
|
||||||
mainWindow.on('enter-full-screen', () => {
|
mainWindow.on('enter-full-screen', () => {
|
||||||
this.wasFullScreen = true
|
this.wasFullScreen = true
|
||||||
mainWindow.webContents.send('fullscreen-status-changed', true)
|
mainWindow.webContents.send(IpcChannel.FullscreenStatusChanged, true)
|
||||||
})
|
})
|
||||||
|
|
||||||
mainWindow.on('leave-full-screen', () => {
|
mainWindow.on('leave-full-screen', () => {
|
||||||
this.wasFullScreen = false
|
this.wasFullScreen = false
|
||||||
mainWindow.webContents.send('fullscreen-status-changed', false)
|
mainWindow.webContents.send(IpcChannel.FullscreenStatusChanged, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
// set the zoom factor again when the window is going to resize
|
// set the zoom factor again when the window is going to resize
|
||||||
@ -434,14 +435,14 @@ export class WindowService {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.miniWindow.on('hide', () => {
|
this.miniWindow.on('hide', () => {
|
||||||
this.miniWindow?.webContents.send('hide-mini-window')
|
this.miniWindow?.webContents.send(IpcChannel.HideMiniWindow)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.miniWindow.on('show', () => {
|
this.miniWindow.on('show', () => {
|
||||||
this.miniWindow?.webContents.send('show-mini-window')
|
this.miniWindow?.webContents.send(IpcChannel.ShowMiniWindow)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.on('miniwindow-reload', () => {
|
ipcMain.on(IpcChannel.MiniWindowReload, () => {
|
||||||
this.miniWindow?.reload()
|
this.miniWindow?.reload()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -547,7 +548,7 @@ export class WindowService {
|
|||||||
// 点击其他地方时隐藏窗口
|
// 点击其他地方时隐藏窗口
|
||||||
this.selectionMenuWindow.on('blur', () => {
|
this.selectionMenuWindow.on('blur', () => {
|
||||||
this.selectionMenuWindow?.hide()
|
this.selectionMenuWindow?.hide()
|
||||||
this.miniWindow?.webContents.send('selection-action', {
|
this.miniWindow?.webContents.send(IpcChannel.SelectionAction, {
|
||||||
action: 'home',
|
action: 'home',
|
||||||
selectedText: this.lastSelectedText
|
selectedText: this.lastSelectedText
|
||||||
})
|
})
|
||||||
@ -565,12 +566,12 @@ export class WindowService {
|
|||||||
private setupSelectionMenuEvents() {
|
private setupSelectionMenuEvents() {
|
||||||
if (!this.selectionMenuWindow) return
|
if (!this.selectionMenuWindow) return
|
||||||
|
|
||||||
ipcMain.removeHandler('selection-menu:action')
|
ipcMain.removeHandler(IpcChannel.SelectionMenu_Action)
|
||||||
ipcMain.handle('selection-menu:action', (_, action) => {
|
ipcMain.handle(IpcChannel.SelectionMenu_Action, (_, action) => {
|
||||||
this.selectionMenuWindow?.hide()
|
this.selectionMenuWindow?.hide()
|
||||||
this.showMiniWindow()
|
this.showMiniWindow()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.miniWindow?.webContents.send('selection-action', {
|
this.miniWindow?.webContents.send(IpcChannel.SelectionAction, {
|
||||||
action,
|
action,
|
||||||
selectedText: this.lastSelectedText
|
selectedText: this.lastSelectedText
|
||||||
})
|
})
|
||||||
|
|||||||
@ -3,77 +3,78 @@ import { electronAPI } from '@electron-toolkit/preload'
|
|||||||
import { FileType, KnowledgeBaseParams, KnowledgeItem, MCPServer, Shortcut, WebDavConfig } from '@types'
|
import { FileType, KnowledgeBaseParams, KnowledgeItem, MCPServer, Shortcut, WebDavConfig } from '@types'
|
||||||
import { contextBridge, ipcRenderer, OpenDialogOptions, shell } from 'electron'
|
import { contextBridge, ipcRenderer, OpenDialogOptions, shell } from 'electron'
|
||||||
import { CreateDirectoryOptions } from 'webdav'
|
import { CreateDirectoryOptions } from 'webdav'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
// Custom APIs for renderer
|
// Custom APIs for renderer
|
||||||
const api = {
|
const api = {
|
||||||
getAppInfo: () => ipcRenderer.invoke('app:info'),
|
getAppInfo: () => ipcRenderer.invoke(IpcChannel.App_Info),
|
||||||
reload: () => ipcRenderer.invoke('app:reload'),
|
reload: () => ipcRenderer.invoke(IpcChannel.App_Reload),
|
||||||
setProxy: (proxy: string) => ipcRenderer.invoke('app:proxy', proxy),
|
setProxy: (proxy: string) => ipcRenderer.invoke(IpcChannel.App_Proxy, proxy),
|
||||||
checkForUpdate: () => ipcRenderer.invoke('app:check-for-update'),
|
checkForUpdate: () => ipcRenderer.invoke(IpcChannel.App_CheckForUpdate),
|
||||||
showUpdateDialog: () => ipcRenderer.invoke('app:show-update-dialog'),
|
showUpdateDialog: () => ipcRenderer.invoke(IpcChannel.App_ShowUpdateDialog),
|
||||||
setLanguage: (lang: string) => ipcRenderer.invoke('app:set-language', lang),
|
setLanguage: (lang: string) => ipcRenderer.invoke(IpcChannel.App_SetLanguage, lang),
|
||||||
setLaunchOnBoot: (isActive: boolean) => ipcRenderer.invoke('app:set-launch-on-boot', isActive),
|
setLaunchOnBoot: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetLaunchOnBoot, isActive),
|
||||||
setLaunchToTray: (isActive: boolean) => ipcRenderer.invoke('app:set-launch-to-tray', isActive),
|
setLaunchToTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetLaunchToTray, isActive),
|
||||||
setTray: (isActive: boolean) => ipcRenderer.invoke('app:set-tray', isActive),
|
setTray: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTray, isActive),
|
||||||
setTrayOnClose: (isActive: boolean) => ipcRenderer.invoke('app:set-tray-on-close', isActive),
|
setTrayOnClose: (isActive: boolean) => ipcRenderer.invoke(IpcChannel.App_SetTrayOnClose, isActive),
|
||||||
restartTray: () => ipcRenderer.invoke('app:restart-tray'),
|
restartTray: () => ipcRenderer.invoke(IpcChannel.App_RestartTray),
|
||||||
setTheme: (theme: 'light' | 'dark') => ipcRenderer.invoke('app:set-theme', theme),
|
setTheme: (theme: 'light' | 'dark') => ipcRenderer.invoke(IpcChannel.App_SetTheme, theme),
|
||||||
openWebsite: (url: string) => ipcRenderer.invoke('open:website', url),
|
openWebsite: (url: string) => ipcRenderer.invoke(IpcChannel.Open_Website, url),
|
||||||
minApp: (url: string) => ipcRenderer.invoke('minapp', url),
|
minApp: (url: string) => ipcRenderer.invoke(IpcChannel.Minapp, url),
|
||||||
clearCache: () => ipcRenderer.invoke('app:clear-cache'),
|
clearCache: () => ipcRenderer.invoke(IpcChannel.App_ClearCache),
|
||||||
system: {
|
system: {
|
||||||
getDeviceType: () => ipcRenderer.invoke('system:getDeviceType')
|
getDeviceType: () => ipcRenderer.invoke(IpcChannel.System_GetDeviceType)
|
||||||
},
|
},
|
||||||
zip: {
|
zip: {
|
||||||
compress: (text: string) => ipcRenderer.invoke('zip:compress', text),
|
compress: (text: string) => ipcRenderer.invoke(IpcChannel.Zip_Compress, text),
|
||||||
decompress: (text: Buffer) => ipcRenderer.invoke('zip:decompress', text)
|
decompress: (text: Buffer) => ipcRenderer.invoke(IpcChannel.Zip_Decompress, text)
|
||||||
},
|
},
|
||||||
backup: {
|
backup: {
|
||||||
backup: (fileName: string, data: string, destinationPath?: string) =>
|
backup: (fileName: string, data: string, destinationPath?: string) =>
|
||||||
ipcRenderer.invoke('backup:backup', fileName, data, destinationPath),
|
ipcRenderer.invoke(IpcChannel.Backup_Backup, fileName, data, destinationPath),
|
||||||
restore: (backupPath: string) => ipcRenderer.invoke('backup:restore', backupPath),
|
restore: (backupPath: string) => ipcRenderer.invoke(IpcChannel.Backup_Restore, backupPath),
|
||||||
backupToWebdav: (data: string, webdavConfig: WebDavConfig) =>
|
backupToWebdav: (data: string, webdavConfig: WebDavConfig) =>
|
||||||
ipcRenderer.invoke('backup:backupToWebdav', data, webdavConfig),
|
ipcRenderer.invoke(IpcChannel.Backup_BackupToWebdav, data, webdavConfig),
|
||||||
restoreFromWebdav: (webdavConfig: WebDavConfig) => ipcRenderer.invoke('backup:restoreFromWebdav', webdavConfig),
|
restoreFromWebdav: (webdavConfig: WebDavConfig) => ipcRenderer.invoke(IpcChannel.Backup_RestoreFromWebdav, webdavConfig),
|
||||||
listWebdavFiles: (webdavConfig: WebDavConfig) => ipcRenderer.invoke('backup:listWebdavFiles', webdavConfig),
|
listWebdavFiles: (webdavConfig: WebDavConfig) => ipcRenderer.invoke(IpcChannel.Backup_ListWebdavFiles, webdavConfig),
|
||||||
checkConnection: (webdavConfig: WebDavConfig) => ipcRenderer.invoke('backup:checkConnection', webdavConfig),
|
checkConnection: (webdavConfig: WebDavConfig) => ipcRenderer.invoke(IpcChannel.Backup_CheckConnection, webdavConfig),
|
||||||
createDirectory: (webdavConfig: WebDavConfig, path: string, options?: CreateDirectoryOptions) =>
|
createDirectory: (webdavConfig: WebDavConfig, path: string, options?: CreateDirectoryOptions) =>
|
||||||
ipcRenderer.invoke('backup:createDirectory', webdavConfig, path, options)
|
ipcRenderer.invoke(IpcChannel.Backup_CreateDirectory, webdavConfig, path, options)
|
||||||
},
|
},
|
||||||
file: {
|
file: {
|
||||||
select: (options?: OpenDialogOptions) => ipcRenderer.invoke('file:select', options),
|
select: (options?: OpenDialogOptions) => ipcRenderer.invoke(IpcChannel.File_Select, options),
|
||||||
upload: (filePath: string) => ipcRenderer.invoke('file:upload', filePath),
|
upload: (filePath: string) => ipcRenderer.invoke(IpcChannel.File_Upload, filePath),
|
||||||
delete: (fileId: string) => ipcRenderer.invoke('file:delete', fileId),
|
delete: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Delete, fileId),
|
||||||
read: (fileId: string) => ipcRenderer.invoke('file:read', fileId),
|
read: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Read, fileId),
|
||||||
clear: () => ipcRenderer.invoke('file:clear'),
|
clear: () => ipcRenderer.invoke(IpcChannel.File_Clear),
|
||||||
get: (filePath: string) => ipcRenderer.invoke('file:get', filePath),
|
get: (filePath: string) => ipcRenderer.invoke(IpcChannel.File_Get, filePath),
|
||||||
create: (fileName: string) => ipcRenderer.invoke('file:create', fileName),
|
create: (fileName: string) => ipcRenderer.invoke(IpcChannel.File_Create, fileName),
|
||||||
write: (filePath: string, data: Uint8Array | string) => ipcRenderer.invoke('file:write', filePath, data),
|
write: (filePath: string, data: Uint8Array | string) => ipcRenderer.invoke(IpcChannel.File_Write, filePath, data),
|
||||||
open: (options?: { decompress: boolean }) => ipcRenderer.invoke('file:open', options),
|
open: (options?: { decompress: boolean }) => ipcRenderer.invoke(IpcChannel.File_Open, options),
|
||||||
openPath: (path: string) => ipcRenderer.invoke('file:openPath', path),
|
openPath: (path: string) => ipcRenderer.invoke(IpcChannel.File_OpenPath, path),
|
||||||
save: (path: string, content: string, options?: { compress: boolean }) =>
|
save: (path: string, content: string, options?: { compress: boolean }) =>
|
||||||
ipcRenderer.invoke('file:save', path, content, options),
|
ipcRenderer.invoke(IpcChannel.File_Save, path, content, options),
|
||||||
selectFolder: () => ipcRenderer.invoke('file:selectFolder'),
|
selectFolder: () => ipcRenderer.invoke(IpcChannel.File_SelectFolder),
|
||||||
saveImage: (name: string, data: string) => ipcRenderer.invoke('file:saveImage', name, data),
|
saveImage: (name: string, data: string) => ipcRenderer.invoke(IpcChannel.File_SaveImage, name, data),
|
||||||
base64Image: (fileId: string) => ipcRenderer.invoke('file:base64Image', fileId),
|
base64Image: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Base64Image, fileId),
|
||||||
download: (url: string) => ipcRenderer.invoke('file:download', url),
|
download: (url: string) => ipcRenderer.invoke(IpcChannel.File_Download, url),
|
||||||
copy: (fileId: string, destPath: string) => ipcRenderer.invoke('file:copy', fileId, destPath),
|
copy: (fileId: string, destPath: string) => ipcRenderer.invoke(IpcChannel.File_Copy, fileId, destPath),
|
||||||
binaryFile: (fileId: string) => ipcRenderer.invoke('file:binaryFile', fileId)
|
binaryFile: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_BinaryFile, fileId)
|
||||||
},
|
},
|
||||||
fs: {
|
fs: {
|
||||||
read: (path: string) => ipcRenderer.invoke('fs:read', path)
|
read: (path: string) => ipcRenderer.invoke(IpcChannel.Fs_Read, path)
|
||||||
},
|
},
|
||||||
export: {
|
export: {
|
||||||
toWord: (markdown: string, fileName: string) => ipcRenderer.invoke('export:word', markdown, fileName)
|
toWord: (markdown: string, fileName: string) => ipcRenderer.invoke(IpcChannel.Export_Word, markdown, fileName)
|
||||||
},
|
},
|
||||||
openPath: (path: string) => ipcRenderer.invoke('open:path', path),
|
openPath: (path: string) => ipcRenderer.invoke(IpcChannel.Open_Path, path),
|
||||||
shortcuts: {
|
shortcuts: {
|
||||||
update: (shortcuts: Shortcut[]) => ipcRenderer.invoke('shortcuts:update', shortcuts)
|
update: (shortcuts: Shortcut[]) => ipcRenderer.invoke(IpcChannel.Shortcuts_Update, shortcuts)
|
||||||
},
|
},
|
||||||
knowledgeBase: {
|
knowledgeBase: {
|
||||||
create: (base: KnowledgeBaseParams) => ipcRenderer.invoke('knowledge-base:create', base),
|
create: (base: KnowledgeBaseParams) => ipcRenderer.invoke(IpcChannel.KnowledgeBase_Create, base),
|
||||||
reset: (base: KnowledgeBaseParams) => ipcRenderer.invoke('knowledge-base:reset', base),
|
reset: (base: KnowledgeBaseParams) => ipcRenderer.invoke(IpcChannel.KnowledgeBase_Reset, base),
|
||||||
delete: (id: string) => ipcRenderer.invoke('knowledge-base:delete', id),
|
delete: (id: string) => ipcRenderer.invoke(IpcChannel.KnowledgeBase_Delete, id),
|
||||||
add: ({
|
add: ({
|
||||||
base,
|
base,
|
||||||
item,
|
item,
|
||||||
@ -82,71 +83,74 @@ const api = {
|
|||||||
base: KnowledgeBaseParams
|
base: KnowledgeBaseParams
|
||||||
item: KnowledgeItem
|
item: KnowledgeItem
|
||||||
forceReload?: boolean
|
forceReload?: boolean
|
||||||
}) => ipcRenderer.invoke('knowledge-base:add', { base, item, forceReload }),
|
}) => ipcRenderer.invoke(IpcChannel.KnowledgeBase_Add, { base, item, forceReload }),
|
||||||
remove: ({ uniqueId, uniqueIds, base }: { uniqueId: string; uniqueIds: string[]; base: KnowledgeBaseParams }) =>
|
remove: ({ uniqueId, uniqueIds, base }: { uniqueId: string; uniqueIds: string[]; base: KnowledgeBaseParams }) =>
|
||||||
ipcRenderer.invoke('knowledge-base:remove', { uniqueId, uniqueIds, base }),
|
ipcRenderer.invoke(IpcChannel.KnowledgeBase_Remove, { uniqueId, uniqueIds, base }),
|
||||||
search: ({ search, base }: { search: string; base: KnowledgeBaseParams }) =>
|
search: ({ search, base }: { search: string; base: KnowledgeBaseParams }) =>
|
||||||
ipcRenderer.invoke('knowledge-base:search', { search, base }),
|
ipcRenderer.invoke(IpcChannel.KnowledgeBase_Search, { search, base }),
|
||||||
rerank: ({ search, base, results }: { search: string; base: KnowledgeBaseParams; results: ExtractChunkData[] }) =>
|
rerank: ({ search, base, results }: { search: string; base: KnowledgeBaseParams; results: ExtractChunkData[] }) =>
|
||||||
ipcRenderer.invoke('knowledge-base:rerank', { search, base, results })
|
ipcRenderer.invoke(IpcChannel.KnowledgeBase_Rerank, { search, base, results })
|
||||||
},
|
},
|
||||||
window: {
|
window: {
|
||||||
setMinimumSize: (width: number, height: number) => ipcRenderer.invoke('window:set-minimum-size', width, height),
|
setMinimumSize: (width: number, height: number) =>
|
||||||
resetMinimumSize: () => ipcRenderer.invoke('window:reset-minimum-size')
|
ipcRenderer.invoke(IpcChannel.Windows_SetMinimumSize, width, height),
|
||||||
|
resetMinimumSize: () => ipcRenderer.invoke(IpcChannel.Windows_ResetMinimumSize)
|
||||||
},
|
},
|
||||||
gemini: {
|
gemini: {
|
||||||
uploadFile: (file: FileType, apiKey: string) => ipcRenderer.invoke('gemini:upload-file', file, apiKey),
|
uploadFile: (file: FileType, apiKey: string) => ipcRenderer.invoke(IpcChannel.Gemini_UploadFile, file, apiKey),
|
||||||
base64File: (file: FileType) => ipcRenderer.invoke('gemini:base64-file', file),
|
base64File: (file: FileType) => ipcRenderer.invoke(IpcChannel.Gemini_Base64File, file),
|
||||||
retrieveFile: (file: FileType, apiKey: string) => ipcRenderer.invoke('gemini:retrieve-file', file, apiKey),
|
retrieveFile: (file: FileType, apiKey: string) => ipcRenderer.invoke(IpcChannel.Gemini_RetrieveFile, file, apiKey),
|
||||||
listFiles: (apiKey: string) => ipcRenderer.invoke('gemini:list-files', apiKey),
|
listFiles: (apiKey: string) => ipcRenderer.invoke(IpcChannel.Gemini_ListFiles, apiKey),
|
||||||
deleteFile: (apiKey: string, fileId: string) => ipcRenderer.invoke('gemini:delete-file', apiKey, fileId)
|
deleteFile: (apiKey: string, fileId: string) => ipcRenderer.invoke(IpcChannel.Gemini_DeleteFile, apiKey, fileId)
|
||||||
},
|
},
|
||||||
selectionMenu: {
|
selectionMenu: {
|
||||||
action: (action: string) => ipcRenderer.invoke('selection-menu:action', action)
|
action: (action: string) => ipcRenderer.invoke(IpcChannel.SelectionMenu_Action, action)
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
set: (key: string, value: any) => ipcRenderer.invoke('config:set', key, value),
|
set: (key: string, value: any) => ipcRenderer.invoke(IpcChannel.Config_Set, key, value),
|
||||||
get: (key: string) => ipcRenderer.invoke('config:get', key)
|
get: (key: string) => ipcRenderer.invoke(IpcChannel.Config_Get, key)
|
||||||
},
|
},
|
||||||
miniWindow: {
|
miniWindow: {
|
||||||
show: () => ipcRenderer.invoke('miniwindow:show'),
|
show: () => ipcRenderer.invoke(IpcChannel.MiniWindow_Show),
|
||||||
hide: () => ipcRenderer.invoke('miniwindow:hide'),
|
hide: () => ipcRenderer.invoke(IpcChannel.MiniWindow_Hide),
|
||||||
close: () => ipcRenderer.invoke('miniwindow:close'),
|
close: () => ipcRenderer.invoke(IpcChannel.MiniWindow_Close),
|
||||||
toggle: () => ipcRenderer.invoke('miniwindow:toggle'),
|
toggle: () => ipcRenderer.invoke(IpcChannel.MiniWindow_Toggle)
|
||||||
setPin: (isPinned: boolean) => ipcRenderer.invoke('miniwindow:set-pin', isPinned)
|
setPin: (isPinned: boolean) => ipcRenderer.invoke(IpcChannel.MiniWindow_SetPin, isPinned)
|
||||||
},
|
},
|
||||||
aes: {
|
aes: {
|
||||||
encrypt: (text: string, secretKey: string, iv: string) => ipcRenderer.invoke('aes:encrypt', text, secretKey, iv),
|
encrypt: (text: string, secretKey: string, iv: string) =>
|
||||||
|
ipcRenderer.invoke(IpcChannel.Aes_Encrypt, text, secretKey, iv),
|
||||||
decrypt: (encryptedData: string, iv: string, secretKey: string) =>
|
decrypt: (encryptedData: string, iv: string, secretKey: string) =>
|
||||||
ipcRenderer.invoke('aes:decrypt', encryptedData, iv, secretKey)
|
ipcRenderer.invoke(IpcChannel.Aes_Decrypt, encryptedData, iv, secretKey)
|
||||||
},
|
},
|
||||||
mcp: {
|
mcp: {
|
||||||
removeServer: (server: MCPServer) => ipcRenderer.invoke('mcp:remove-server', server),
|
removeServer: (server: MCPServer) => ipcRenderer.invoke(IpcChannel.Mcp_RemoveServer, server),
|
||||||
restartServer: (server: MCPServer) => ipcRenderer.invoke('mcp:restart-server', server),
|
restartServer: (server: MCPServer) => ipcRenderer.invoke(IpcChannel.Mcp_RestartServer, server),
|
||||||
stopServer: (server: MCPServer) => ipcRenderer.invoke('mcp:stop-server', server),
|
stopServer: (server: MCPServer) => ipcRenderer.invoke(IpcChannel.Mcp_StopServer, server),
|
||||||
listTools: (server: MCPServer) => ipcRenderer.invoke('mcp:list-tools', server),
|
listTools: (server: MCPServer) => ipcRenderer.invoke(IpcChannel.Mcp_ListTools, server),
|
||||||
callTool: ({ server, name, args }: { server: MCPServer; name: string; args: any }) =>
|
callTool: ({ server, name, args }: { server: MCPServer; name: string; args: any }) =>
|
||||||
ipcRenderer.invoke('mcp:call-tool', { server, name, args }),
|
ipcRenderer.invoke(IpcChannel.Mcp_CallTool, { server, name, args }),
|
||||||
getInstallInfo: () => ipcRenderer.invoke('mcp:get-install-info')
|
getInstallInfo: () => ipcRenderer.invoke(IpcChannel.Mcp_GetInstallInfo)
|
||||||
},
|
},
|
||||||
shell: {
|
shell: {
|
||||||
openExternal: shell.openExternal
|
openExternal: shell.openExternal
|
||||||
},
|
},
|
||||||
copilot: {
|
copilot: {
|
||||||
getAuthMessage: (headers?: Record<string, string>) => ipcRenderer.invoke('copilot:get-auth-message', headers),
|
getAuthMessage: (headers?: Record<string, string>) =>
|
||||||
|
ipcRenderer.invoke(IpcChannel.Copilot_GetAuthMessage, headers),
|
||||||
getCopilotToken: (device_code: string, headers?: Record<string, string>) =>
|
getCopilotToken: (device_code: string, headers?: Record<string, string>) =>
|
||||||
ipcRenderer.invoke('copilot:get-copilot-token', device_code, headers),
|
ipcRenderer.invoke(IpcChannel.Copilot_GetCopilotToken, device_code, headers),
|
||||||
saveCopilotToken: (access_token: string) => ipcRenderer.invoke('copilot:save-copilot-token', access_token),
|
saveCopilotToken: (access_token: string) => ipcRenderer.invoke(IpcChannel.Copilot_SaveCopilotToken, access_token),
|
||||||
getToken: (headers?: Record<string, string>) => ipcRenderer.invoke('copilot:get-token', headers),
|
getToken: (headers?: Record<string, string>) => ipcRenderer.invoke(IpcChannel.Copilot_GetToken, headers),
|
||||||
logout: () => ipcRenderer.invoke('copilot:logout'),
|
logout: () => ipcRenderer.invoke(IpcChannel.Copilot_Logout),
|
||||||
getUser: (token: string) => ipcRenderer.invoke('copilot:get-user', token)
|
getUser: (token: string) => ipcRenderer.invoke(IpcChannel.Copilot_GetUser, token)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Binary related APIs
|
// Binary related APIs
|
||||||
isBinaryExist: (name: string) => ipcRenderer.invoke('app:is-binary-exist', name),
|
isBinaryExist: (name: string) => ipcRenderer.invoke(IpcChannel.App_IsBinaryExist, name),
|
||||||
getBinaryPath: (name: string) => ipcRenderer.invoke('app:get-binary-path', name),
|
getBinaryPath: (name: string) => ipcRenderer.invoke(IpcChannel.App_GetBinaryPath, name),
|
||||||
installUVBinary: () => ipcRenderer.invoke('app:install-uv-binary'),
|
installUVBinary: () => ipcRenderer.invoke(IpcChannel.App_InstallUvBinary),
|
||||||
installBunBinary: () => ipcRenderer.invoke('app:install-bun-binary'),
|
installBunBinary: () => ipcRenderer.invoke(IpcChannel.App_InstallBunBinary)
|
||||||
protocol: {
|
protocol: {
|
||||||
onReceiveData: (callback: (data: { url: string; params: any }) => void) => {
|
onReceiveData: (callback: (data: { url: string; params: any }) => void) => {
|
||||||
const listener = (_event: Electron.IpcRendererEvent, data: { url: string; params: any }) => {
|
const listener = (_event: Electron.IpcRendererEvent, data: { url: string; params: any }) => {
|
||||||
@ -159,10 +163,10 @@ const api = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
nutstore: {
|
nutstore: {
|
||||||
getSSOUrl: () => ipcRenderer.invoke('nutstore:get-sso-url'),
|
getSSOUrl: () => ipcRenderer.invoke(IpcChannel.Nutstore_GetSsoUrl),
|
||||||
decryptToken: (token: string) => ipcRenderer.invoke('nutstore:decrypt-token', token),
|
decryptToken: (token: string) => ipcRenderer.invoke(IpcChannel.Nutstore_DecryptToken, token),
|
||||||
getDirectoryContents: (token: string, path: string) =>
|
getDirectoryContents: (token: string, path: string) =>
|
||||||
ipcRenderer.invoke('nutstore:get-directory-contents', token, path)
|
ipcRenderer.invoke(IpcChannel.Nutstore_GetDirectoryContents, token, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,9 +178,9 @@ if (process.contextIsolated) {
|
|||||||
contextBridge.exposeInMainWorld('electron', electronAPI)
|
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||||
contextBridge.exposeInMainWorld('api', api)
|
contextBridge.exposeInMainWorld('api', api)
|
||||||
contextBridge.exposeInMainWorld('obsidian', {
|
contextBridge.exposeInMainWorld('obsidian', {
|
||||||
getVaults: () => ipcRenderer.invoke('obsidian:get-vaults'),
|
getVaults: () => ipcRenderer.invoke(IpcChannel.Obsidian_GetVaults),
|
||||||
getFolders: (vaultName: string) => ipcRenderer.invoke('obsidian:get-files', vaultName),
|
getFolders: (vaultName: string) => ipcRenderer.invoke(IpcChannel.Obsidian_GetFiles, vaultName),
|
||||||
getFiles: (vaultName: string) => ipcRenderer.invoke('obsidian:get-files', vaultName)
|
getFiles: (vaultName: string) => ipcRenderer.invoke(IpcChannel.Obsidian_GetFiles, vaultName)
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { TopView } from '../TopView'
|
import { TopView } from '../TopView'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
resolve: (data: any) => void
|
resolve: (data: any) => void
|
||||||
@ -21,7 +22,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const removeListener = window.electron.ipcRenderer.on('backup-progress', (_, data: ProgressData) => {
|
const removeListener = window.electron.ipcRenderer.on(IpcChannel.BackupProgress, (_, data: ProgressData) => {
|
||||||
setProgressData(data)
|
setProgressData(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { TopView } from '../TopView'
|
import { TopView } from '../TopView'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
resolve: (data: any) => void
|
resolve: (data: any) => void
|
||||||
@ -21,7 +22,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const removeListener = window.electron.ipcRenderer.on('restore-progress', (_, data: ProgressData) => {
|
const removeListener = window.electron.ipcRenderer.on(IpcChannel.RestoreProgress, (_, data: ProgressData) => {
|
||||||
setProgressData(data)
|
setProgressData(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { isMac } from '@renderer/config/constant'
|
|||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { ThemeMode } from '@renderer/types'
|
import { ThemeMode } from '@renderer/types'
|
||||||
import React, { createContext, PropsWithChildren, use, useEffect, useState } from 'react'
|
import React, { createContext, PropsWithChildren, use, useEffect, useState } from 'react'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
interface ThemeContextType {
|
interface ThemeContextType {
|
||||||
theme: ThemeMode
|
theme: ThemeMode
|
||||||
@ -49,7 +50,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children, defaultT
|
|||||||
document.body.setAttribute('os', isMac ? 'mac' : 'windows')
|
document.body.setAttribute('os', isMac ? 'mac' : 'windows')
|
||||||
|
|
||||||
// listen theme change from main process from other windows
|
// listen theme change from main process from other windows
|
||||||
const themeChangeListenerRemover = window.electron.ipcRenderer.on('theme:change', (_, newTheme) => {
|
const themeChangeListenerRemover = window.electron.ipcRenderer.on(IpcChannel.ThemeChange, (_, newTheme) => {
|
||||||
setTheme(newTheme)
|
setTheme(newTheme)
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import { useRuntime } from './useRuntime'
|
|||||||
import { useSettings } from './useSettings'
|
import { useSettings } from './useSettings'
|
||||||
import useUpdateHandler from './useUpdateHandler'
|
import useUpdateHandler from './useUpdateHandler'
|
||||||
|
|
||||||
|
import { defaultLanguage } from '@shared/config/constant'
|
||||||
|
|
||||||
export function useAppInit() {
|
export function useAppInit() {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { proxyUrl, language, windowStyle, autoCheckUpdate, proxyMode, customCss } = useSettings()
|
const { proxyUrl, language, windowStyle, autoCheckUpdate, proxyMode, customCss } = useSettings()
|
||||||
@ -53,7 +55,7 @@ export function useAppInit() {
|
|||||||
}, [proxyUrl, proxyMode])
|
}, [proxyUrl, proxyMode])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
i18n.changeLanguage(language || navigator.language || 'en-US')
|
i18n.changeLanguage(language || navigator.language || defaultLanguage)
|
||||||
}, [language])
|
}, [language])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { isWindows } from '@renderer/config/constant'
|
import { isWindows } from '@renderer/config/constant'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
export function useFullScreenNotice() {
|
export function useFullScreenNotice() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const cleanup = window.electron.ipcRenderer.on('fullscreen-status-changed', (_, isFullscreen) => {
|
const cleanup = window.electron.ipcRenderer.on(IpcChannel.FullscreenStatusChanged, (_, isFullscreen) => {
|
||||||
if (isWindows && isFullscreen) {
|
if (isWindows && isFullscreen) {
|
||||||
window.message.info({
|
window.message.info({
|
||||||
content: t('common.fullscreen'),
|
content: t('common.fullscreen'),
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import { v4 as uuidv4 } from 'uuid'
|
|||||||
|
|
||||||
import { useAgents } from './useAgents'
|
import { useAgents } from './useAgents'
|
||||||
import { useAssistants } from './useAssistant'
|
import { useAssistants } from './useAssistant'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
export const useKnowledge = (baseId: string) => {
|
export const useKnowledge = (baseId: string) => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
@ -207,7 +208,7 @@ export const useKnowledge = (baseId: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cleanup = window.electron.ipcRenderer.on(
|
const cleanup = window.electron.ipcRenderer.on(
|
||||||
'directory-processing-percent',
|
IpcChannel.DirectoryProcessingPercent,
|
||||||
(_, { itemId: id, percent }: { itemId: string; percent: number }) => {
|
(_, { itemId: id, percent }: { itemId: string; percent: number }) => {
|
||||||
if (itemId === id) {
|
if (itemId === id) {
|
||||||
setPercent(percent)
|
setPercent(percent)
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import store, { useAppDispatch, useAppSelector } from '@renderer/store'
|
import store, { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||||
import { addMCPServer, deleteMCPServer, setMCPServers, updateMCPServer } from '@renderer/store/mcp'
|
import { addMCPServer, deleteMCPServer, setMCPServers, updateMCPServer } from '@renderer/store/mcp'
|
||||||
import { MCPServer } from '@renderer/types'
|
import { MCPServer } from '@renderer/types'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
const ipcRenderer = window.electron.ipcRenderer
|
const ipcRenderer = window.electron.ipcRenderer
|
||||||
|
|
||||||
// Listen for server changes from main process
|
// Listen for server changes from main process
|
||||||
ipcRenderer.on('mcp:servers-changed', (_event, servers) => {
|
ipcRenderer.on(IpcChannel.Mcp_ServersChanged, (_event, servers) => {
|
||||||
store.dispatch(setMCPServers(servers))
|
store.dispatch(setMCPServers(servers))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { setUpdateState } from '@renderer/store/runtime'
|
|||||||
import type { ProgressInfo, UpdateInfo } from 'builder-util-runtime'
|
import type { ProgressInfo, UpdateInfo } from 'builder-util-runtime'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
export default function useUpdateHandler() {
|
export default function useUpdateHandler() {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@ -14,13 +15,13 @@ export default function useUpdateHandler() {
|
|||||||
const ipcRenderer = window.electron.ipcRenderer
|
const ipcRenderer = window.electron.ipcRenderer
|
||||||
|
|
||||||
const removers = [
|
const removers = [
|
||||||
ipcRenderer.on('update-not-available', () => {
|
ipcRenderer.on(IpcChannel.UpdateNotAvailable, () => {
|
||||||
dispatch(setUpdateState({ checking: false }))
|
dispatch(setUpdateState({ checking: false }))
|
||||||
if (window.location.hash.includes('settings/about')) {
|
if (window.location.hash.includes('settings/about')) {
|
||||||
window.message.success(t('settings.about.updateNotAvailable'))
|
window.message.success(t('settings.about.updateNotAvailable'))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
ipcRenderer.on('update-available', (_, releaseInfo: UpdateInfo) => {
|
ipcRenderer.on(IpcChannel.UpdateAvailable, (_, releaseInfo: UpdateInfo) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setUpdateState({
|
setUpdateState({
|
||||||
checking: false,
|
checking: false,
|
||||||
@ -30,7 +31,7 @@ export default function useUpdateHandler() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
ipcRenderer.on('download-update', () => {
|
ipcRenderer.on(IpcChannel.DownloadUpdate, () => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setUpdateState({
|
setUpdateState({
|
||||||
checking: false,
|
checking: false,
|
||||||
@ -38,7 +39,7 @@ export default function useUpdateHandler() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
ipcRenderer.on('download-progress', (_, progress: ProgressInfo) => {
|
ipcRenderer.on(IpcChannel.DownloadProgress, (_, progress: ProgressInfo) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setUpdateState({
|
setUpdateState({
|
||||||
downloading: progress.percent < 100,
|
downloading: progress.percent < 100,
|
||||||
@ -46,7 +47,7 @@ export default function useUpdateHandler() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
ipcRenderer.on('update-downloaded', (_, releaseInfo: UpdateInfo) => {
|
ipcRenderer.on(IpcChannel.UpdateDownloaded, (_, releaseInfo: UpdateInfo) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setUpdateState({
|
setUpdateState({
|
||||||
downloading: false,
|
downloading: false,
|
||||||
@ -55,7 +56,7 @@ export default function useUpdateHandler() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
ipcRenderer.on('update-error', (_, error) => {
|
ipcRenderer.on(IpcChannel.UpdateError, (_, error) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
setUpdateState({
|
setUpdateState({
|
||||||
checking: false,
|
checking: false,
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import esES from './translate/es-es.json'
|
|||||||
import frFR from './translate/fr-fr.json'
|
import frFR from './translate/fr-fr.json'
|
||||||
import ptPT from './translate/pt-pt.json'
|
import ptPT from './translate/pt-pt.json'
|
||||||
|
|
||||||
|
import { defaultLanguage } from '@shared/config/constant'
|
||||||
|
|
||||||
const resources = {
|
const resources = {
|
||||||
'el-GR': elGR,
|
'el-GR': elGR,
|
||||||
'en-US': enUS,
|
'en-US': enUS,
|
||||||
@ -26,7 +28,7 @@ const resources = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getLanguage = () => {
|
export const getLanguage = () => {
|
||||||
return localStorage.getItem('language') || navigator.language || 'en-US'
|
return localStorage.getItem('language') || navigator.language || defaultLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getLanguageCode = () => {
|
export const getLanguageCode = () => {
|
||||||
@ -36,7 +38,7 @@ export const getLanguageCode = () => {
|
|||||||
i18n.use(initReactI18next).init({
|
i18n.use(initReactI18next).init({
|
||||||
resources,
|
resources,
|
||||||
lng: getLanguage(),
|
lng: getLanguage(),
|
||||||
fallbackLng: 'en-US',
|
fallbackLng: defaultLanguage,
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false
|
escapeValue: false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { FC, useCallback, useEffect, useState } from 'react'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import FileItem from './FileItem'
|
import FileItem from './FileItem'
|
||||||
|
import { MB } from '@shared/config/constant'
|
||||||
|
|
||||||
interface GeminiFilesProps {
|
interface GeminiFilesProps {
|
||||||
id: string
|
id: string
|
||||||
@ -60,7 +61,7 @@ const GeminiFiles: FC<GeminiFilesProps> = ({ id }) => {
|
|||||||
fileInfo={{
|
fileInfo={{
|
||||||
name: file.displayName,
|
name: file.displayName,
|
||||||
ext: `.${file.name.split('.').pop()}`,
|
ext: `.${file.name.split('.').pop()}`,
|
||||||
extra: `${dayjs(file.createTime).format('MM-DD HH:mm')} · ${(parseInt(file.sizeBytes) / 1024 / 1024).toFixed(2)} MB`,
|
extra: `${dayjs(file.createTime).format('MM-DD HH:mm')} · ${(parseInt(file.sizeBytes) / MB).toFixed(2)} MB`,
|
||||||
actions: (
|
actions: (
|
||||||
<DeleteOutlined
|
<DeleteOutlined
|
||||||
style={{ cursor: 'pointer', color: 'var(--color-error)' }}
|
style={{ cursor: 'pointer', color: 'var(--color-error)' }}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { FC, useState } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '.'
|
import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '.'
|
||||||
|
import { defaultLanguage } from '@shared/config/constant'
|
||||||
|
|
||||||
const GeneralSettings: FC = () => {
|
const GeneralSettings: FC = () => {
|
||||||
const {
|
const {
|
||||||
@ -112,7 +113,7 @@ const GeneralSettings: FC = () => {
|
|||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitle>{t('common.language')}</SettingRowTitle>
|
<SettingRowTitle>{t('common.language')}</SettingRowTitle>
|
||||||
<Select defaultValue={language || 'en-US'} style={{ width: 180 }} onChange={onSelectLanguage}>
|
<Select defaultValue={language || defaultLanguage} style={{ width: 180 }} onChange={onSelectLanguage}>
|
||||||
{languagesOptions.map((lang) => (
|
{languagesOptions.map((lang) => (
|
||||||
<Select.Option key={lang.value} value={lang.value}>
|
<Select.Option key={lang.value} value={lang.value}>
|
||||||
<Space.Compact direction="horizontal" block>
|
<Space.Compact direction="horizontal" block>
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import OpenAI from 'openai'
|
|||||||
|
|
||||||
import { ChunkCallbackData, CompletionsParams } from '.'
|
import { ChunkCallbackData, CompletionsParams } from '.'
|
||||||
import BaseProvider from './BaseProvider'
|
import BaseProvider from './BaseProvider'
|
||||||
|
import { MB } from '@shared/config/constant'
|
||||||
|
|
||||||
export default class GeminiProvider extends BaseProvider {
|
export default class GeminiProvider extends BaseProvider {
|
||||||
private sdk: GoogleGenerativeAI
|
private sdk: GoogleGenerativeAI
|
||||||
@ -70,7 +71,7 @@ export default class GeminiProvider extends BaseProvider {
|
|||||||
* @returns The part
|
* @returns The part
|
||||||
*/
|
*/
|
||||||
private async handlePdfFile(file: FileType): Promise<Part> {
|
private async handlePdfFile(file: FileType): Promise<Part> {
|
||||||
const smallFileSize = 20 * 1024 * 1024
|
const smallFileSize = 20 * MB
|
||||||
const isSmallFile = file.size < smallFileSize
|
const isSmallFile = file.size < smallFileSize
|
||||||
|
|
||||||
if (isSmallFile) {
|
if (isSmallFile) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { isLocalAi } from '@renderer/config/env'
|
|||||||
import { SYSTEM_MODELS } from '@renderer/config/models'
|
import { SYSTEM_MODELS } from '@renderer/config/models'
|
||||||
import { Model, Provider } from '@renderer/types'
|
import { Model, Provider } from '@renderer/types'
|
||||||
import { uniqBy } from 'lodash'
|
import { uniqBy } from 'lodash'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
type LlmSettings = {
|
type LlmSettings = {
|
||||||
ollama: {
|
ollama: {
|
||||||
@ -572,7 +573,7 @@ const settingsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
setDefaultModel: (state, action: PayloadAction<{ model: Model }>) => {
|
setDefaultModel: (state, action: PayloadAction<{ model: Model }>) => {
|
||||||
state.defaultModel = action.payload.model
|
state.defaultModel = action.payload.model
|
||||||
window.electron.ipcRenderer.send('miniwindow-reload')
|
window.electron.ipcRenderer.send(IpcChannel.MiniWindowReload)
|
||||||
},
|
},
|
||||||
setTopicNamingModel: (state, action: PayloadAction<{ model: Model }>) => {
|
setTopicNamingModel: (state, action: PayloadAction<{ model: Model }>) => {
|
||||||
state.topicNamingModel = action.payload.model
|
state.topicNamingModel = action.payload.model
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
|
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
|
||||||
import { CodeStyleVarious, LanguageVarious, ThemeMode, TranslateLanguageVarious } from '@renderer/types'
|
import { CodeStyleVarious, LanguageVarious, ThemeMode, TranslateLanguageVarious } from '@renderer/types'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
import { WebDAVSyncState } from './backup'
|
import { WebDAVSyncState } from './backup'
|
||||||
|
|
||||||
@ -208,7 +209,7 @@ const settingsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
setLanguage: (state, action: PayloadAction<LanguageVarious>) => {
|
setLanguage: (state, action: PayloadAction<LanguageVarious>) => {
|
||||||
state.language = action.payload
|
state.language = action.payload
|
||||||
window.electron.ipcRenderer.send('miniwindow-reload')
|
window.electron.ipcRenderer.send(IpcChannel.MiniWindowReload)
|
||||||
},
|
},
|
||||||
setTargetLanguage: (state, action: PayloadAction<TranslateLanguageVarious>) => {
|
setTargetLanguage: (state, action: PayloadAction<TranslateLanguageVarious>) => {
|
||||||
state.targetLanguage = action.payload
|
state.targetLanguage = action.payload
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import * as htmlToImage from 'html-to-image'
|
|||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
import { classNames } from './style'
|
import { classNames } from './style'
|
||||||
|
import { KB, MB } from '@shared/config/constant'
|
||||||
|
|
||||||
export const runAsyncFunction = async (fn: () => void) => {
|
export const runAsyncFunction = async (fn: () => void) => {
|
||||||
await fn()
|
await fn()
|
||||||
@ -421,15 +422,15 @@ export function hasPath(url: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function formatFileSize(size: number) {
|
export function formatFileSize(size: number) {
|
||||||
if (size > 1024 * 1024) {
|
if (size > MB) {
|
||||||
return (size / 1024 / 1024).toFixed(1) + ' MB'
|
return (size / MB).toFixed(1) + ' MB'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 1024) {
|
if (size > KB) {
|
||||||
return (size / 1024).toFixed(0) + ' KB'
|
return (size / KB).toFixed(0) + ' KB'
|
||||||
}
|
}
|
||||||
|
|
||||||
return (size / 1024).toFixed(2) + ' KB'
|
return (size / KB).toFixed(2) + ' KB'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortByEnglishFirst(a: string, b: string) {
|
export function sortByEnglishFirst(a: string, b: string) {
|
||||||
|
|||||||
@ -18,6 +18,9 @@ import ClipboardPreview from './components/ClipboardPreview'
|
|||||||
import FeatureMenus, { FeatureMenusRef } from './components/FeatureMenus'
|
import FeatureMenus, { FeatureMenusRef } from './components/FeatureMenus'
|
||||||
import Footer from './components/Footer'
|
import Footer from './components/Footer'
|
||||||
import InputBar from './components/InputBar'
|
import InputBar from './components/InputBar'
|
||||||
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
|
||||||
|
import { defaultLanguage } from '@shared/config/constant'
|
||||||
|
|
||||||
const HomeWindow: FC = () => {
|
const HomeWindow: FC = () => {
|
||||||
const [route, setRoute] = useState<'home' | 'chat' | 'translate' | 'summary' | 'explanation'>('home')
|
const [route, setRoute] = useState<'home' | 'chat' | 'translate' | 'summary' | 'explanation'>('home')
|
||||||
@ -68,7 +71,7 @@ const HomeWindow: FC = () => {
|
|||||||
}, [readClipboard])
|
}, [readClipboard])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
i18n.changeLanguage(language || navigator.language || 'en-US')
|
i18n.changeLanguage(language || navigator.language || defaultLanguage)
|
||||||
}, [language])
|
}, [language])
|
||||||
|
|
||||||
const onCloseWindow = () => window.api.miniWindow.hide()
|
const onCloseWindow = () => window.api.miniWindow.hide()
|
||||||
@ -181,16 +184,16 @@ const HomeWindow: FC = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.electron.ipcRenderer.on('show-mini-window', onWindowShow)
|
window.electron.ipcRenderer.on(IpcChannel.ShowMiniWindow, onWindowShow)
|
||||||
window.electron.ipcRenderer.on('selection-action', (_, { action, selectedText }) => {
|
window.electron.ipcRenderer.on(IpcChannel.SelectionAction, (_, { action, selectedText }) => {
|
||||||
selectedText && setSelectedText(selectedText)
|
selectedText && setSelectedText(selectedText)
|
||||||
action && setRoute(action)
|
action && setRoute(action)
|
||||||
action === 'chat' && onSendMessage()
|
action === 'chat' && onSendMessage()
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.electron.ipcRenderer.removeAllListeners('show-mini-window')
|
window.electron.ipcRenderer.removeAllListeners(IpcChannel.ShowMiniWindow)
|
||||||
window.electron.ipcRenderer.removeAllListeners('selection-action')
|
window.electron.ipcRenderer.removeAllListeners(IpcChannel.SelectionAction)
|
||||||
}
|
}
|
||||||
}, [onWindowShow, onSendMessage, setRoute])
|
}, [onWindowShow, onSendMessage, setRoute])
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user