refactor: restructure project layout

- Move main process to electron/main/
- Move preload to electron/preload/
- Add shared types in electron/shared/
- Split redis-service into modular redis/ directory
- Flatten renderer to src/ (remove src/renderer/ nesting)
- Update electron.vite.config.ts paths
- Update tsconfig paths
- Output to electron-dist/
This commit is contained in:
2026-07-04 21:12:50 +08:00
parent bb885c6d6d
commit bdcf4fe299
59 changed files with 654 additions and 624 deletions
+182
View File
@@ -0,0 +1,182 @@
// src/renderer/src/stores/connection.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export interface ConnectionConfig {
id: string
name: string
host: string
port: number
auth: string
username: string
tls: boolean
tlsCaPath: string
tlsCertPath: string
tlsKeyPath: string
sshEnabled: boolean
sshHost: string
sshPort: number
sshUsername: string
sshPassword: string
sshPrivateKeyPath: string
cluster: boolean
sentinelMasterName: string
separator: string
order: number
createdAt: number
color?: string
}
export const useConnectionStore = defineStore('connection', () => {
const connections = ref<ConnectionConfig[]>([])
const activeId = ref<string | null>(null)
const connecting = ref(false)
const error = ref<string | null>(null)
const serverInfo = ref<string | null>(null)
const healthOk = ref(true)
let healthTimer: ReturnType<typeof setInterval> | null = null
const activeConnection = computed(() =>
connections.value.find((c: ConnectionConfig) => c.id === activeId.value) ?? null
)
const isConnected = computed(() => activeId.value !== null)
async function loadConnections() {
connections.value = await window.electronAPI.storage.getConnections()
}
async function saveConnection(conn: ConnectionConfig) {
if (conn.auth && !conn.auth.startsWith('enc:')) {
conn.auth = 'enc:' + await window.electronAPI.credential.encrypt(conn.auth)
}
connections.value = await window.electronAPI.storage.saveConnection(conn)
}
async function deleteConnection(id: string) {
if (activeId.value === id) await disconnect()
connections.value = await window.electronAPI.storage.deleteConnection(id)
}
async function reorderConnections(ids: string[]) {
connections.value = await window.electronAPI.storage.reorderConnections(ids)
}
async function connect(conn: ConnectionConfig) {
connecting.value = true
error.value = null
try {
let auth = conn.auth
if (auth.startsWith('enc:')) {
auth = await window.electronAPI.credential.decrypt(auth.slice(4))
}
const result = await window.electronAPI.redis.connect(conn.id, {
host: conn.host,
port: conn.port,
password: auth || undefined,
username: conn.username || undefined,
tls: conn.tls,
})
if (result.success) {
activeId.value = conn.id
serverInfo.value = await window.electronAPI.redis.getInfo(conn.id)
startHealthCheck(conn.id)
} else {
error.value = result.error || 'Connection failed'
}
} catch (err: any) {
error.value = err.message
} finally {
connecting.value = false
}
}
async function disconnect() {
stopHealthCheck()
if (activeId.value) {
await window.electronAPI.redis.disconnect(activeId.value)
activeId.value = null
serverInfo.value = null
}
}
function startHealthCheck(connId: string) {
stopHealthCheck()
healthOk.value = true
healthTimer = setInterval(async () => {
try {
const ok = await window.electronAPI.redis.isConnected(connId)
healthOk.value = ok
if (!ok && activeId.value === connId) {
// Connection lost
error.value = 'Connection lost'
}
} catch {
healthOk.value = false
}
}, 5000)
}
function stopHealthCheck() {
if (healthTimer) {
clearInterval(healthTimer)
healthTimer = null
}
}
async function testConnection(opts: {
host: string; port: number; auth?: string; username?: string; tls?: boolean
}): Promise<{ success: boolean; error?: string }> {
if (!window.electronAPI) {
return { success: false, error: 'Electron API not ready' }
}
const testId = `test_${Date.now()}`
try {
const result = await window.electronAPI.redis.connect(testId, {
host: opts.host,
port: opts.port,
password: opts.auth || undefined,
username: opts.username || undefined,
tls: opts.tls,
})
if (result.success) {
await window.electronAPI.redis.disconnect(testId)
return { success: true }
}
return { success: false, error: result.error }
} catch (err: any) {
return { success: false, error: err.message }
}
}
async function exportConnections(): Promise<string> {
const data = JSON.stringify(connections.value, null, 2)
return data
}
async function importConnections(jsonStr: string): Promise<number> {
try {
const imported = JSON.parse(jsonStr) as ConnectionConfig[]
if (!Array.isArray(imported)) throw new Error('Invalid format')
let count = 0
for (const conn of imported) {
if (conn.id && conn.name && conn.host) {
const exists = connections.value.find((c: ConnectionConfig) => c.id === conn.id)
if (!exists) {
await saveConnection(conn)
count++
}
}
}
return count
} catch (err: any) {
throw new Error('Import failed: ' + err.message)
}
}
return {
connections, activeId, connecting, error, serverInfo, healthOk,
activeConnection, isConnected,
loadConnections, saveConnection, deleteConnection, reorderConnections,
connect, disconnect, testConnection, exportConnections, importConnections,
}
})