diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.infiniteScroll.spec.ts b/apps/desktop/src/components/redis/RedisKeyBrowser.infiniteScroll.spec.ts
index 0ea86016ca..767af10a9a 100644
--- a/apps/desktop/src/components/redis/RedisKeyBrowser.infiniteScroll.spec.ts
+++ b/apps/desktop/src/components/redis/RedisKeyBrowser.infiniteScroll.spec.ts
@@ -574,3 +574,40 @@ describe("RedisKeyBrowser loadMore failure handling (PR #6313 review)", () => {
expect(mocks.redisScanKeysBatch.mock.calls.length).toBeLessThanOrEqual(1 + AUTO_LOAD_MAX_CALLS);
});
});
+
+// A group's `loadedLeafCount` only reflects keys the SCAN happened to return
+// before auto-load stopped (see `redisKeyTree.ts`); when the cursor hasn't
+// reached 0 yet, that count is not the folder's real total. Issue #6392: a
+// user compared DBX's tree against `redis-cli --scan` and saw folder counts
+// far below the real per-prefix cardinality, with nothing in the UI hinting
+// the numbers were partial.
+describe("RedisKeyBrowser group key counts reflect incomplete loading (issue #6392)", () => {
+ it("marks a group's count as partial while more keys remain unscanned", async () => {
+ stubNonOverflowingViewport();
+ // cursor never returns to 0, so hasMore stays true even after the
+ // shared auto-load budget is exhausted.
+ mocks.redisScanKeysBatch.mockImplementation((_connectionId: string, _db: number, cursor: number) => {
+ if (cursor === 0) return Promise.resolve({ cursor: 1, keys: [keyInfo("grp:a"), keyInfo("grp:b")], total_keys: 500 });
+ return Promise.resolve({ cursor: cursor + 1, keys: [], total_keys: 0 });
+ });
+
+ const host = mountBrowser();
+ await settleThoroughly();
+
+ const countBadge = host.querySelector(".text-muted-foreground.ml-1");
+ expect(countBadge?.textContent).toBe("(2+)");
+ expect(countBadge?.getAttribute("title")).toBeTruthy();
+ });
+
+ it("shows an exact count once every key has actually been scanned", async () => {
+ stubNonOverflowingViewport();
+ mocks.redisScanKeysBatch.mockResolvedValue({ cursor: 0, keys: [keyInfo("grp:a"), keyInfo("grp:b")], total_keys: 2 });
+
+ const host = mountBrowser();
+ await settleThoroughly();
+
+ const countBadge = host.querySelector(".text-muted-foreground.ml-1");
+ expect(countBadge?.textContent).toBe("(2)");
+ expect(countBadge?.getAttribute("title")).toBeFalsy();
+ });
+});
diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.vue b/apps/desktop/src/components/redis/RedisKeyBrowser.vue
index 390ba43e35..d73ab0859f 100644
--- a/apps/desktop/src/components/redis/RedisKeyBrowser.vue
+++ b/apps/desktop/src/components/redis/RedisKeyBrowser.vue
@@ -2045,7 +2045,9 @@ defineExpose({ focusSearch, insertCommand, executeCommand: executeAiCommand });
{{ row.node.label }}
- ({{ row.node.loadedLeafCount }})
+ ({{ row.node.loadedLeafCount }}{{ !isFuzzyHierarchyView && hasMore ? "+" : "" }})
diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts
index 5b6b2c0edf..738a770a8a 100644
--- a/apps/desktop/src/i18n/locales/en.ts
+++ b/apps/desktop/src/i18n/locales/en.ts
@@ -4361,6 +4361,7 @@ export default {
deselectAll: "Clear",
selectLoadedGroupKeys: "Select {count} loaded keys in this folder",
loadedMatchingKeys: "{count} loaded matching keys",
+ loadedGroupKeysPartial: "{count} keys loaded so far — this folder may contain more",
fuzzyTreeLimit: "{count} fuzzy matches are shown as a flat list to keep the browser responsive. Refine the search to view the hierarchy.",
deleteGroup: "Delete group",
deleteGroupDetails: "{target}\n{count} keys",
diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts
index 8c20f28799..1962b7a9ab 100644
--- a/apps/desktop/src/i18n/locales/es.ts
+++ b/apps/desktop/src/i18n/locales/es.ts
@@ -4207,6 +4207,7 @@ export default withEnglishFallback({
deselectAll: "Borrar",
selectLoadedGroupKeys: "Seleccionar {count} claves coincidentes cargadas",
loadedMatchingKeys: "{count} claves coincidentes cargadas",
+ loadedGroupKeysPartial: "{count} claves cargadas hasta ahora — esta carpeta puede contener más",
fuzzyTreeLimit: "Se muestran {count} coincidencias difusas como lista plana para mantener el navegador responsivo. Refina la búsqueda para ver la jerarquía.",
deleteGroup: "Eliminar grupo",
deleteGroupDetails: "{target}\n{count} claves",
diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts
index 9b8aaa912e..13451f6e5e 100644
--- a/apps/desktop/src/i18n/locales/it.ts
+++ b/apps/desktop/src/i18n/locales/it.ts
@@ -4205,6 +4205,7 @@ export default withEnglishFallback({
deselectAll: "Cancella",
selectLoadedGroupKeys: "Seleziona {count} chiavi corrispondenti caricate",
loadedMatchingKeys: "{count} chiavi corrispondenti caricate",
+ loadedGroupKeysPartial: "{count} chiavi caricate finora — questa cartella potrebbe contenerne altre",
fuzzyTreeLimit: "{count} corrispondenze fuzzy sono mostrate come elenco piatto per mantenere il browser reattivo. Restringi la ricerca per vedere la gerarchia.",
deleteGroup: "Elimina gruppo",
deleteGroupDetails: "{target}\n{count} chiavi",
diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts
index 14050b1dc2..4bb10cd4cd 100644
--- a/apps/desktop/src/i18n/locales/ja.ts
+++ b/apps/desktop/src/i18n/locales/ja.ts
@@ -4235,6 +4235,7 @@ export default withEnglishFallback({
deselectAll: "クリア",
selectLoadedGroupKeys: "読み込み済みの一致キー {count} 件を選択",
loadedMatchingKeys: "読み込み済みの一致キー {count} 件",
+ loadedGroupKeysPartial: "これまでに読み込まれたキー {count} 件 — このフォルダーにはさらにキーが存在する可能性があります",
fuzzyTreeLimit: "ブラウザーの応答性を保つため、あいまい一致 {count} 件をフラットな一覧で表示しています。階層を表示するには検索条件を絞り込んでください。",
deleteGroup: "グループを削除",
deleteGroupDetails: "{target}\n{count}個のキー",
diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts
index c51080ed44..8b58a83dd1 100644
--- a/apps/desktop/src/i18n/locales/ko.ts
+++ b/apps/desktop/src/i18n/locales/ko.ts
@@ -3845,6 +3845,7 @@ export default withEnglishFallback({
deselectAll: "지우기",
selectLoadedGroupKeys: "로드된 {count}개 일치 키 선택",
loadedMatchingKeys: "로드된 일치 키 {count}개",
+ loadedGroupKeysPartial: "지금까지 로드된 {count}개 키 — 이 폴더에 더 많은 키가 있을 수 있습니다",
fuzzyTreeLimit: "{count}개의 퍼지 일치가 브라우저 응답성을 유지하기 위해 평면 목록으로 표시됩니다. 계층 구조를 보려면 검색을 좁히세요.",
deleteGroup: "그룹 삭제",
deleteGroupDetails: "{target}\n키 {count}개",
diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts
index 6f4247b84d..57d3542d85 100644
--- a/apps/desktop/src/i18n/locales/pt-BR.ts
+++ b/apps/desktop/src/i18n/locales/pt-BR.ts
@@ -4207,6 +4207,7 @@ export default withEnglishFallback({
deselectAll: "Limpar",
selectLoadedGroupKeys: "Selecionar {count} chaves correspondentes carregadas",
loadedMatchingKeys: "{count} chaves correspondentes carregadas",
+ loadedGroupKeysPartial: "{count} chaves carregadas até agora — esta pasta pode conter mais",
fuzzyTreeLimit: "{count} correspondências difusas são mostradas como uma lista plana para manter o navegador responsivo. Refine a busca para ver a hierarquia.",
deleteGroup: "Excluir grupo",
deleteGroupDetails: "{target}\n{count} chaves",
diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts
index 93266bed7b..c4b5d88b4f 100644
--- a/apps/desktop/src/i18n/locales/zh-CN.ts
+++ b/apps/desktop/src/i18n/locales/zh-CN.ts
@@ -4348,6 +4348,7 @@ export default withEnglishFallback({
deselectAll: "清除",
selectLoadedGroupKeys: "选择该文件夹下已加载的 {count} 个 key",
loadedMatchingKeys: "已加载的 {count} 个匹配 key",
+ loadedGroupKeysPartial: "目前已加载 {count} 个 key —— 该文件夹下可能还有更多",
fuzzyTreeLimit: "已加载 {count} 个模糊匹配 key。为保持浏览器响应,当前以扁平列表展示;请缩小搜索范围以查看层级。",
deleteGroup: "删除分组",
deleteGroupDetails: "{target}\n{count} 个 key",
diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts
index c65acf1228..30f370a8e4 100644
--- a/apps/desktop/src/i18n/locales/zh-TW.ts
+++ b/apps/desktop/src/i18n/locales/zh-TW.ts
@@ -3534,6 +3534,7 @@ export default withEnglishFallback({
deselectAll: "清除",
selectLoadedGroupKeys: "選取已載入的 {count} 個相符 key",
loadedMatchingKeys: "已載入的 {count} 個相符 key",
+ loadedGroupKeysPartial: "目前已載入 {count} 個 key —— 此資料夾下可能還有更多",
fuzzyTreeLimit: "已載入 {count} 個模糊相符 key。為保持瀏覽器回應,目前以扁平清單顯示;請縮小搜尋範圍以查看層級。",
deleteGroup: "刪除群組",
deleteGroupDetails: "{target}\n{count} 個 key",