This commit is contained in:
2026-07-10 23:05:10 +08:00
parent b280e59377
commit fe7801062f
30 changed files with 129 additions and 213 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ function createWindow(): void {
icon: nativeImage.createFromPath(iconPath),
backgroundColor: nativeTheme.shouldUseDarkColors ? '#0f0f1a' : '#f8fafc',
webPreferences: {
preload: join(__dirname, '../preload/index.mjs'),
preload: join(__dirname, '../preload.js'),
contextIsolation: true,
nodeIntegration: false,
sandbox: false,
-136
View File
@@ -1,136 +0,0 @@
// src/preload/index.d.ts
export interface ConnectionConfig {
id: string
name: string
host: string
port: number
auth: string
username: string
tls: boolean
tlsCaPath: string
tlsCertPath: string
tlsKeyPath: string
tlsRejectUnauthorized: boolean
sshEnabled: boolean
sshHost: string
sshPort: number
sshUsername: string
sshPassword: string
sshPrivateKeyPath: string
sshPassphrase: string
cluster: boolean
sentinelEnabled: boolean
sentinelHost: string
sentinelPort: number
sentinelMasterName: string
sentinelNodePassword: string
separator: string
order: number
createdAt: number
color?: string
}
export interface ElectronAPI {
window: {
minimize: () => void
maximize: () => void
close: () => void
}
theme: {
get: () => Promise<boolean>
set: (theme: 'system' | 'dark' | 'light') => void
onOsUpdated: (callback: (isDark: boolean) => void) => void
}
dialog: {
openFile: (options: { title?: string; filters?: { name: string; extensions: string[] }[] }) =>
Promise<{ path: string; content: string } | null>
}
credential: {
encrypt: (text: string) => Promise<string>
decrypt: (encoded: string) => Promise<string>
}
storage: {
getConnections: () => Promise<ConnectionConfig[]>
saveConnection: (conn: ConnectionConfig) => Promise<ConnectionConfig[]>
deleteConnection: (id: string) => Promise<ConnectionConfig[]>
reorderConnections: (ids: string[]) => Promise<ConnectionConfig[]>
getSettings: () => Promise<any>
saveSettings: (settings: any) => Promise<void>
}
redis: {
connect: (id: string, opts: any) => Promise<{ success: boolean; error?: string }>
disconnect: (id: string) => Promise<void>
execute: (id: string, command: string, args: string[]) => Promise<any>
getInfo: (id: string) => Promise<string>
scanKeys: (id: string, cursor: string, pattern: string, count: number) =>
Promise<{ cursor: string; keys: string[] }>
getKeyType: (id: string, key: string) => Promise<string>
getKeyTTL: (id: string, key: string) => Promise<number>
getString: (id: string, key: string) => Promise<string | null>
setString: (id: string, key: string, value: string) => Promise<void>
rejsonGet: (id: string, key: string, path: string) => Promise<string>
rejsonSet: (id: string, key: string, path: string, value: string) => Promise<void>
deleteKey: (id: string, key: string) => Promise<void>
hashScan: (id: string, key: string, cursor: string, count: number) =>
Promise<{ cursor: string; fields: [string, string][] }>
hashSet: (id: string, key: string, field: string, value: string) => Promise<void>
hashDel: (id: string, key: string, field: string) => Promise<void>
setTTL: (id: string, key: string, ttl: number) => Promise<void>
selectDb: (id: string, db: number) => Promise<void>
dbSize: (id: string) => Promise<number>
listRange: (id: string, key: string, start: number, stop: number) => Promise<string[]>
listLength: (id: string, key: string) => Promise<number>
listPush: (id: string, key: string, values: string[]) => Promise<number>
listSet: (id: string, key: string, index: number, value: string) => Promise<void>
listRemove: (id: string, key: string, count: number, value: string) => Promise<number>
setMembers: (id: string, key: string) => Promise<string[]>
setSize: (id: string, key: string) => Promise<number>
setAdd: (id: string, key: string, members: string[]) => Promise<number>
setRemove: (id: string, key: string, members: string[]) => Promise<number>
zsetRange: (id: string, key: string, start: number, stop: number, withScores: boolean) => Promise<string[]>
zsetSize: (id: string, key: string) => Promise<number>
zsetAdd: (id: string, key: string, score: number, member: string) => Promise<number>
zsetRemove: (id: string, key: string, members: string[]) => Promise<number>
slowLogGet: (id: string, count: number) => Promise<any[]>
slowLogLen: (id: string) => Promise<number>
memoryUsage: (id: string, key: string) => Promise<number | null>
batchDelete: (id: string, keys: string[]) => Promise<number>
streamInfo: (id: string, key: string) => Promise<any>
streamRange: (id: string, key: string, start: string, end: string, count: number) => Promise<any[]>
streamAdd: (id: string, key: string, streamId: string, fieldValues: string[]) => Promise<string>
streamTrim: (id: string, key: string, maxLen: number) => Promise<number>
streamDel: (id: string, key: string, ids: string[]) => Promise<number>
streamGroups: (id: string, key: string) => Promise<any[]>
streamConsumers: (id: string, key: string, group: string) => Promise<any[]>
streamGroupCreate: (id: string, key: string, group: string, startId: string, mkstream: boolean) => Promise<any>
streamGroupDestroy: (id: string, key: string, group: string) => Promise<number>
streamAck: (id: string, key: string, group: string, ids: string[]) => Promise<number>
renameKey: (id: string, oldKey: string, newKey: string) => Promise<void>
existsKey: (id: string, key: string) => Promise<boolean>
ping: (id: string) => Promise<string>
isConnected: (id: string) => Promise<boolean>
getCommandLog: () => Promise<any[]>
clearCommandLog: () => Promise<void>
decodeValue: (value: string, format: string) => Promise<string>
detectFormat: (value: string) => Promise<string>
customFormat: (value: string, command: string, key: string) => Promise<string>
subscribe: (id: string, channels: string[], isPattern: boolean) => Promise<{ success: boolean; error?: string }>
unsubscribe: (id: string) => Promise<void>
onSubscribeMessage: (callback: (msg: any) => void) => void
monitor: (id: string) => Promise<{ success: boolean; error?: string }>
monitorStop: (id: string) => Promise<void>
onMonitorMessage: (callback: (msg: any) => void) => void
}
updater: {
check: () => Promise<{ available: boolean; version?: string }>
download: () => Promise<{ success: boolean; error?: string }>
install: () => void
onStatus: (callback: (status: any) => void) => void
}
}
declare global {
interface Window {
electronAPI: ElectronAPI
}
}
+42
View File
@@ -0,0 +1,42 @@
import js from '@eslint/js'
import globals from 'globals'
import tseslint from 'typescript-eslint'
import vue from 'eslint-plugin-vue'
import vueParser from 'vue-eslint-parser'
const commonLanguageOptions = {
ecmaVersion: 2023,
globals: {
...globals.browser,
...globals.node,
},
}
export default tseslint.config(
{ ignores: ['dist', 'dist-electron', 'release', 'coverage', 'node_modules'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.ts'],
languageOptions: commonLanguageOptions,
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
},
},
...vue.configs['flat/essential'],
{
extends: [...tseslint.configs.recommended],
files: ['**/*.vue'],
languageOptions: {
...commonLanguageOptions,
parser: vueParser,
parserOptions: {
parser: tseslint.parser,
sourceType: 'module',
},
},
rules: {
'@typescript-eslint/no-unused-vars': 'warn',
'vue/multi-word-component-names': 'off',
},
}
)
+37 -28
View File
@@ -1,11 +1,15 @@
{
"name": "jredis-desktop",
"version": "2.0.0",
"description": "A modern Redis desktop manager built with Electron + Vue 3 + Vite",
"author": "Jokul",
"private": true,
"main": "./electron-dist/main/index.js",
"version": "2.0.0",
"description": "简约时尚的Redis客户端管理工具",
"author": {
"name": "Jokul",
"email": "wangshengshan011@163.com"
},
"homepage": "http://git.jokul.space/Jokul/JRedisDesktop",
"type": "module",
"main": "./dist-electron/main.js",
"allowScripts": {
"electron": true,
"esbuild": true,
@@ -23,15 +27,43 @@
"build:mac": "npm run build && electron-builder --mac",
"build:linux": "npm run build && electron-builder --linux",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue --fix"
},
"dependencies": {
"@guolao/vue-monaco-editor": "^1.6.0",
"@tanstack/vue-virtual": "^3.13.31",
"electron-store": "^11.0.2",
"electron-updater": "^6.8.9",
"ioredis": "^5.7.0",
"monaco-editor": "^0.55.1",
"pinia": "^3.0.4",
"ssh2": "^1.17.0"
},
"devDependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@types/ssh2": "^1.15.5",
"@vitejs/plugin-vue": "^5.2.0",
"electron": "^33.4.0",
"electron-builder": "^25.1.0",
"electron-vite": "^3.0.0",
"element-plus": "^2.9.0",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vue": "^3.5.0",
"vue-router": "^4.5.0"
},
"build": {
"appId": "com.jokul.jredis-desktop",
"productName": "JRedisDesktop",
"icon": "build/icons/icon_256.png",
"npmRebuild": false,
"directories": {
"output": "release"
},
"files": [
"electron-dist/**/*",
"dist/**/*",
"dist-electron/**/*",
"!**/*.map",
"!dist-electron/**/*.map",
"package.json"
],
"publish": {
@@ -62,28 +94,5 @@
],
"icon": "build/icon.ico"
}
},
"dependencies": {
"@guolao/vue-monaco-editor": "^1.6.0",
"@tanstack/vue-virtual": "^3.13.31",
"electron-store": "^11.0.2",
"electron-updater": "^6.8.9",
"ioredis": "^5.7.0",
"monaco-editor": "^0.55.1",
"pinia": "^3.0.4",
"ssh2": "^1.17.0"
},
"devDependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@types/ssh2": "^1.15.5",
"@vitejs/plugin-vue": "^5.2.0",
"electron": "^33.4.0",
"electron-builder": "^25.1.0",
"electron-vite": "^3.0.0",
"element-plus": "^2.9.0",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vue": "^3.5.0",
"vue-router": "^4.5.0"
}
}
View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

+23
View File
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "es2023",
"lib": ["ESNext", "DOM"],
"module": "ESNext",
"types": ["vite/client"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
+3 -16
View File
@@ -1,20 +1,7 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vite/client"]
},
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.web.json" }
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
+18 -9
View File
@@ -1,14 +1,23 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./electron-dist",
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "es2023",
"lib": ["ES2023"],
"module": "esnext",
"types": ["node"],
"composite": true
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["electron/main/**/*", "electron/preload/**/*", "electron/shared/**/*", "electron.vite.config.ts"]
"include": ["vite.config.ts", "electron"]
}
-17
View File
@@ -1,17 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "preserve",
"esModuleInterop": true,
"skipLibCheck": true,
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"composite": true,
"paths": {
"@renderer/*": ["./src/*"]
}
},
"include": ["src/**/*", "electron/preload/index.d.ts"]
}
File diff suppressed because one or more lines are too long
+5 -5
View File
@@ -6,10 +6,10 @@ export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()],
build: {
outDir: 'electron-dist/main',
outDir: 'dist-electron',
rollupOptions: {
input: {
index: resolve(__dirname, 'electron/main/index.ts')
index: resolve(__dirname, 'electron/main.ts')
}
}
}
@@ -17,10 +17,10 @@ export default defineConfig({
preload: {
plugins: [externalizeDepsPlugin()],
build: {
outDir: 'electron-dist/preload',
outDir: 'dist-electron',
rollupOptions: {
input: {
index: resolve(__dirname, 'electron/preload/index.ts')
index: resolve(__dirname, 'electron/preload.ts')
}
}
}
@@ -28,7 +28,7 @@ export default defineConfig({
renderer: {
root: 'src',
build: {
outDir: resolve(__dirname, 'electron-dist/renderer'),
outDir: resolve(__dirname, 'dist-electron/renderer'),
rollupOptions: {
input: {
index: resolve(__dirname, 'src/index.html')