diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.vue b/apps/desktop/src/components/redis/RedisKeyBrowser.vue index 50c63c4b9..a4d38c625 100644 --- a/apps/desktop/src/components/redis/RedisKeyBrowser.vue +++ b/apps/desktop/src/components/redis/RedisKeyBrowser.vue @@ -447,6 +447,9 @@ async function runRedisCommand(command: string) { // reflects keys added/removed/renamed by SET/DEL/RENAME/... if (isRedisMutatingCommand(command)) { connectionStore.invalidateCompletionCache(props.connectionId, String(executedDb)); + // Refresh the sidebar db key counts (INFO keyspace) so `dbN (count)` stays accurate + // after the write. Fire-and-forget so the terminal stays responsive. + void connectionStore.refreshRedisDbKeyCounts(props.connectionId); } // Persist to history persistRedisHistory(command, true, result.value); diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts index c5000c438..87e129468 100644 --- a/apps/desktop/src/stores/connectionStore.ts +++ b/apps/desktop/src/stores/connectionStore.ts @@ -1067,6 +1067,24 @@ export const useConnectionStore = defineStore("connection", () => { node.label = redisDbLabel(db, node.loadedKeyCount, node.totalKeyCount); } + // Re-fetch the authoritative per-db key counts (INFO keyspace, lightweight) and update + // the sidebar db nodes' counts in place — WITHOUT rebuilding the tree, so already-loaded + // key trees under expanded db nodes are preserved. Used after a Redis write command so the + // `dbN (count)` labels reflect the new reality without a manual refresh. + async function refreshRedisDbKeyCounts(connectionId: string) { + const connNode = findNode(treeNodes.value, connectionId); + if (!connNode) return; + try { + await ensureConnected(connectionId); + const dbs = await api.redisListDatabases(connectionId); + for (const db of dbs) { + updateRedisDbKeyStats(connectionId, db.db, { total: db.keys }); + } + } catch { + // Best-effort: a failed count refresh must not disrupt the result view. + } + } + async function loadMongoDatabases(connectionId: string) { const node = findNode(treeNodes.value, connectionId); if (!node) return; @@ -2759,6 +2777,7 @@ export const useConnectionStore = defineStore("connection", () => { initFromDisk, loadDatabases, loadRedisDatabases, + refreshRedisDbKeyCounts, loadEtcdRoot, loadMqTenants, updateRedisDbKeyStats, diff --git a/apps/desktop/src/stores/queryStore.ts b/apps/desktop/src/stores/queryStore.ts index 8ca46aa19..aac569ccc 100644 --- a/apps/desktop/src/stores/queryStore.ts +++ b/apps/desktop/src/stores/queryStore.ts @@ -1197,6 +1197,7 @@ export const useQueryStore = defineStore("query", () => { const allResults: QueryResult[] = []; const skipSafety = options?.skipRedisSafetyCheck; + let hadMutatingCommand = false; for (const command of commands) { try { const result = await api.redisExecuteCommand(tab.connectionId, currentDb, command, skipSafety); @@ -1206,6 +1207,7 @@ export const useQueryStore = defineStore("query", () => { // Write commands (SET/DEL/...) mutate the key set — drop the cached key-name completion // for the db this command ran on so the next autocomplete fetch reflects the new keys. if (isRedisMutatingCommand(command)) { + hadMutatingCommand = true; connStore.invalidateCompletionCache(tab.connectionId, String(currentDb)); } } catch (e: any) { @@ -1241,6 +1243,12 @@ export const useQueryStore = defineStore("query", () => { current.database = String(currentDb); } } + // Refresh the sidebar db key counts (INFO keyspace) when at least one command in + // this batch mutated the key set, so `dbN (count)` stays accurate without a manual + // refresh. Fire-and-forget: never block result display. + if (hadMutatingCommand) { + void connStore.refreshRedisDbKeyCounts(tab.connectionId); + } return; }