fix: patch all P2 quality/performance issues from project review
- ipc-handlers: withLog extracts actual connection ID from args[0] (P2#20) - updater: add initialized guard to prevent duplicate IPC registration (P2#25) - win-state: log writeFile errors instead of empty callback (P2#26) - format: detectFormat samples up to 4096 chars instead of 100 (P2#28) - commandLogger: add 30+ missing write commands to WRITE_COMMANDS (P2#32) - ReJsonEditor: bind Monaco theme to monacoTheme computed (P2#19) - keys: normalize empty SCAN pattern to '*' (P2#21) - SlowLogView: remove duplicate <style scoped> block (P2#29) - CliView: deduplicate XGROUP in writeCommands Set (P2#33) - key store: use connectionStore instead of IPC for separator (P2#22) - NewConnectionDialog: add visible guard after async watch (P2#30) - KeyList: remove dangerouslyUseHTMLString, use plain text + i18n (P2#31) - KeyList: batch DUMP export with Promise.allSettled (batch=20) (P2#23) - HashEditor: lazy load field TTL on click instead of bulk HTTL (P2#24) - P2#27 already fixed in P0#2; P2#34 is feature (N4); P2#35 not a bug - docs: update PROJECT_REVIEW.md with P2 fix status
This commit is contained in:
@@ -6,14 +6,15 @@ import * as redis from './redis'
|
||||
|
||||
// Helper: wrap handler with command logging
|
||||
function withLog(cmd: string, fn: (...args: any[]) => any) {
|
||||
return async (...args: any[]) => {
|
||||
return async (_e: any, ...args: any[]) => {
|
||||
const start = Date.now()
|
||||
const connId = args[0] || 'unknown'
|
||||
try {
|
||||
const result = await fn(...args)
|
||||
redis.log('current', cmd, Date.now() - start)
|
||||
const result = await fn(_e, ...args)
|
||||
redis.log(connId, cmd, Date.now() - start)
|
||||
return result
|
||||
} catch (err) {
|
||||
redis.log('current', cmd, Date.now() - start)
|
||||
redis.log(connId, cmd, Date.now() - start)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,15 @@ const WRITE_COMMANDS = new Set([
|
||||
'LPOP', 'RPOP', 'BLPOP', 'BRPOP',
|
||||
'ZINCRBY', 'ZREMRANGEBYRANK', 'ZREMRANGEBYSCORE',
|
||||
'UNLINK', 'MOVE', 'RENAMENX',
|
||||
'JSON.SET', 'JSON.DEL', 'JSON.ARRAPPEND', 'JSON.ARRINDEX', 'JSON.ARRINSERT',
|
||||
'JSON.ARRTRIM', 'JSON.ARRPOP', 'JSON.NUMINCRBY', 'JSON.STRAPPEND', 'JSON.STRLEN',
|
||||
'JSON.OBJSET', 'JSON.OBJDEL', 'COPY', 'RESTORE', 'MIGRATE',
|
||||
'PEXPIRE', 'PEXPIREAT', 'PSETEX', 'SETNX',
|
||||
'GEOADD', 'BITFIELD', 'SETBIT', 'HSETNX',
|
||||
'LINSERT', 'RPOPLPUSH', 'LMOVE',
|
||||
'SPOP', 'SMOVE', 'SDIFFSTORE', 'SINTERSTORE', 'SUNIONSTORE',
|
||||
'ZPOPMAX', 'ZPOPMIN', 'ZREMRANGEBYLEX',
|
||||
'XGROUP', 'XCLAIM', 'XSETID', 'SWAPDB',
|
||||
])
|
||||
|
||||
export function log(connection: string, command: string, duration: number): void {
|
||||
|
||||
@@ -43,7 +43,8 @@ export function detectFormat(value: string): FormatType {
|
||||
// Deflate (zlib) magic: 78 01/9c/da
|
||||
if (value.charCodeAt(0) === 0x78 && [0x01, 0x9c, 0xda, 0x5e].includes(value.charCodeAt(1))) return 'deflate'
|
||||
// Check for non-printable characters → binary/hex
|
||||
const hasNonPrintable = /[\x00-\x08\x0e-\x1f]/.test(value.substring(0, 100))
|
||||
const sample = value.length > 4096 ? value.substring(0, 4096) : value
|
||||
const hasNonPrintable = /[\x00-\x08\x0e-\x1f]/.test(sample)
|
||||
if (hasNonPrintable) return 'hex'
|
||||
return 'text'
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ export async function scanKeys(
|
||||
count: number
|
||||
): Promise<{ cursor: string; keys: string[] }> {
|
||||
const client = requireClient(id)
|
||||
if (!pattern || pattern === '') pattern = '*'
|
||||
const [nextCursor, keys] = await client.scan(cursor, 'MATCH', pattern, 'COUNT', count)
|
||||
return { cursor: nextCursor, keys }
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@ import electronUpdater from 'electron-updater'
|
||||
import { BrowserWindow, ipcMain } from 'electron'
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
let initialized = false
|
||||
|
||||
export function initUpdater(win: BrowserWindow): void {
|
||||
if (initialized) return
|
||||
initialized = true
|
||||
mainWindow = win
|
||||
const autoUpdater = electronUpdater.autoUpdater
|
||||
|
||||
|
||||
@@ -44,7 +44,9 @@ function getLastState(): WinState {
|
||||
function saveState(win: BrowserWindow): void {
|
||||
const bounds = win.getBounds()
|
||||
const state = { ...bounds, maximized: win.isMaximized() }
|
||||
writeFile(STATE_FILE, JSON.stringify(state), 'utf-8', () => {})
|
||||
writeFile(STATE_FILE, JSON.stringify(state), 'utf-8', (err) => {
|
||||
if (err) console.error('Failed to save window state:', err)
|
||||
})
|
||||
}
|
||||
|
||||
export function restoreAndTrack(win: BrowserWindow): void {
|
||||
|
||||
Reference in New Issue
Block a user