fix(redis): mark key-tree counts as partial while scanning
This commit is contained in:
1 parent
3c1813123d
commit
7be64f45a7
10 files changed
+48
-1
No files matched your search
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -2045,7 +2045,9 @@ defineExpose({ focusSearch, insertCommand, executeCommand: executeAiCommand });
|
||||
<component :is="expandedGroupIds.has(row.node.id) ? ChevronDown : ChevronRight" class="w-3 h-3 shrink-0 text-muted-foreground" />
|
||||
<component :is="expandedGroupIds.has(row.node.id) ? FolderOpen : FolderClosed" class="h-3.5 w-3.5 shrink-0 text-amber-500" />
|
||||
<span class="dbx-editor-font-family truncate">{{ row.node.label }}</span>
|
||||
<span class="text-muted-foreground ml-1" :title="isFuzzyHierarchyView ? t('redis.loadedMatchingKeys', { count: row.node.loadedLeafCount }) : undefined">({{ row.node.loadedLeafCount }})</span>
|
||||
<span class="text-muted-foreground ml-1" :title="isFuzzyHierarchyView ? t('redis.loadedMatchingKeys', { count: row.node.loadedLeafCount }) : hasMore ? t('redis.loadedGroupKeysPartial', { count: row.node.loadedLeafCount }) : undefined"
|
||||
>({{ row.node.loadedLeafCount }}{{ !isFuzzyHierarchyView && hasMore ? "+" : "" }})</span
|
||||
>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="relative flex h-4 w-4 shrink-0 items-center justify-center">
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -4235,6 +4235,7 @@ export default withEnglishFallback({
|
||||
deselectAll: "クリア",
|
||||
selectLoadedGroupKeys: "読み込み済みの一致キー {count} 件を選択",
|
||||
loadedMatchingKeys: "読み込み済みの一致キー {count} 件",
|
||||
loadedGroupKeysPartial: "これまでに読み込まれたキー {count} 件 — このフォルダーにはさらにキーが存在する可能性があります",
|
||||
fuzzyTreeLimit: "ブラウザーの応答性を保つため、あいまい一致 {count} 件をフラットな一覧で表示しています。階層を表示するには検索条件を絞り込んでください。",
|
||||
deleteGroup: "グループを削除",
|
||||
deleteGroupDetails: "{target}\n{count}個のキー",
|
||||
|
||||
@@ -3845,6 +3845,7 @@ export default withEnglishFallback({
|
||||
deselectAll: "지우기",
|
||||
selectLoadedGroupKeys: "로드된 {count}개 일치 키 선택",
|
||||
loadedMatchingKeys: "로드된 일치 키 {count}개",
|
||||
loadedGroupKeysPartial: "지금까지 로드된 {count}개 키 — 이 폴더에 더 많은 키가 있을 수 있습니다",
|
||||
fuzzyTreeLimit: "{count}개의 퍼지 일치가 브라우저 응답성을 유지하기 위해 평면 목록으로 표시됩니다. 계층 구조를 보려면 검색을 좁히세요.",
|
||||
deleteGroup: "그룹 삭제",
|
||||
deleteGroupDetails: "{target}\n키 {count}개",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user