diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.expiry.spec.ts b/apps/desktop/src/components/redis/RedisKeyBrowser.expiry.spec.ts index b8be04618e..6b606e4e91 100644 --- a/apps/desktop/src/components/redis/RedisKeyBrowser.expiry.spec.ts +++ b/apps/desktop/src/components/redis/RedisKeyBrowser.expiry.spec.ts @@ -400,11 +400,12 @@ function resetApiMocks() { mocks.canBuildRedisFuzzyTree.mockImplementation((loadedKeyCount: number) => loadedKeyCount <= 200_000); } -function mountBrowser() { +function mountBrowser(withDeleteDetails = false) { const host = document.createElement("div"); document.body.append(host); const app = createApp(RedisKeyBrowser, { connectionId: "connection", db: 0, blockDangerousRedisCommands: false }); - app.use(createI18n({ legacy: false, locale: "en", messages: { en: {} }, missingWarn: false, fallbackWarn: false })); + const messages = { en: { redis: { deleteGroupDetails: withDeleteDetails ? "{target}\n{count} keys" : "redis.deleteGroupDetails" } } }; + app.use(createI18n({ legacy: false, locale: "en", messages, missingWarn: false, fallbackWarn: false })); app.mount(host); mountedApps.push({ unmount: () => app.unmount(), host }); return host; @@ -1126,6 +1127,29 @@ describe("RedisKeyBrowser expiry creation", () => { }); describe("RedisKeyBrowser fuzzy key hierarchy", () => { + it("deletes a leaf directly from the key list after confirmation", async () => { + const key = { key_display: "session:current", key_raw: "c2Vzc2lvbjpjdXJyZW50", key_type: "string", ttl: -1 }; + mocks.redisScanKeysBatch.mockResolvedValue({ cursor: 0, keys: [key], total_keys: 1 }); + mocks.redisDeleteKeys.mockResolvedValue(1); + mountBrowser(true); + await settle(); + + groupRow("session").dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true })); + await settle(); + + const deleteButton = requiredElement('button[title="redis.deleteKey"]'); + deleteButton.click(); + await settle(); + + expect(mocks.redisDeleteKeys).not.toHaveBeenCalled(); + expect(requiredElement("[data-test-danger-details]").textContent).toContain("session:current"); + requiredElement("[data-test-danger-confirm]").click(); + await settle(); + + expect(mocks.redisDeleteKeys).toHaveBeenCalledWith("connection", 0, [key.key_raw]); + expect(document.body.textContent).not.toContain("session:current"); + }); + it("preserves the cursor and finds a sparse fuzzy match after a bounded continuation", async () => { mocks.redisScanPageSize = 1_000; mountBrowser(); diff --git a/apps/desktop/src/components/redis/RedisKeyBrowser.vue b/apps/desktop/src/components/redis/RedisKeyBrowser.vue index 2132599119..477263e96b 100644 --- a/apps/desktop/src/components/redis/RedisKeyBrowser.vue +++ b/apps/desktop/src/components/redis/RedisKeyBrowser.vue @@ -1046,6 +1046,18 @@ function requestGroupDelete(node: RedisKeyTreeNode, event: Event) { showDangerConfirm.value = true; } +function requestKeyDelete(node: RedisKeyTreeNode, event: Event) { + event.stopPropagation(); + if (node.kind !== "leaf" || selectionBusy.value) return; + pendingDanger.value = { + kind: "delete-keys", + title: node.fullKeyDisplay, + keyRaws: [node.keyRaw], + loadedSearchResults: false, + }; + showDangerConfirm.value = true; +} + async function copyRedisKeyName(keyName: string) { try { await copyToClipboard(keyName); @@ -2192,6 +2204,18 @@ defineExpose({ focusSearch, insertCommand, executeCommand: executeAiCommand }); + diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 57dd4c9e31..03389df226 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -4482,6 +4482,7 @@ export default { 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", + deleteKey: "Delete key", deleteGroupDetails: "{target}\n{count} keys", deleteLoadedSearchKeysDetails: "{target}\n{count} loaded matching keys", flushDb: "Clear current DB", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 8d0ccb7957..181840652c 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -4314,6 +4314,7 @@ export default withEnglishFallback({ 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", + deleteKey: "Eliminar clave", deleteGroupDetails: "{target}\n{count} claves", deleteLoadedSearchKeysDetails: "{target}\n{count} claves coincidentes cargadas", flushDb: "Limpiar DB actual", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index a8426e6650..fd7b8db039 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -4312,6 +4312,7 @@ export default withEnglishFallback({ 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", + deleteKey: "Elimina chiave", deleteGroupDetails: "{target}\n{count} chiavi", deleteLoadedSearchKeysDetails: "{target}\n{count} chiavi corrispondenti caricate", flushDb: "Pulisci DB corrente", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index 77898b948b..7ebb34ab0e 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -4342,6 +4342,7 @@ export default withEnglishFallback({ loadedGroupKeysPartial: "これまでに読み込まれたキー {count} 件 — このフォルダーにはさらにキーが存在する可能性があります", fuzzyTreeLimit: "ブラウザーの応答性を保つため、あいまい一致 {count} 件をフラットな一覧で表示しています。階層を表示するには検索条件を絞り込んでください。", deleteGroup: "グループを削除", + deleteKey: "キーを削除", deleteGroupDetails: "{target}\n{count}個のキー", deleteLoadedSearchKeysDetails: "{target}\n読み込み済みの一致キー {count} 件", flushDb: "現在のDBをクリア", diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts index 14c4cc6a9d..1e5a6edbd9 100644 --- a/apps/desktop/src/i18n/locales/ko.ts +++ b/apps/desktop/src/i18n/locales/ko.ts @@ -3952,6 +3952,7 @@ export default withEnglishFallback({ loadedGroupKeysPartial: "지금까지 로드된 {count}개 키 — 이 폴더에 더 많은 키가 있을 수 있습니다", fuzzyTreeLimit: "{count}개의 퍼지 일치가 브라우저 응답성을 유지하기 위해 평면 목록으로 표시됩니다. 계층 구조를 보려면 검색을 좁히세요.", deleteGroup: "그룹 삭제", + deleteKey: "키 삭제", deleteGroupDetails: "{target}\n키 {count}개", deleteLoadedSearchKeysDetails: "{target}\n로드된 일치 키 {count}개", flushDb: "현재 DB 비우기", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index 0f866cb32c..f870e7ea5e 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -4314,6 +4314,7 @@ export default withEnglishFallback({ 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", + deleteKey: "Excluir chave", deleteGroupDetails: "{target}\n{count} chaves", deleteLoadedSearchKeysDetails: "{target}\n{count} chaves correspondentes carregadas", flushDb: "Limpar DB atual", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 464bc1604a..267cba6f17 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -4469,6 +4469,7 @@ export default withEnglishFallback({ loadedGroupKeysPartial: "目前已加载 {count} 个 key —— 该文件夹下可能还有更多", fuzzyTreeLimit: "已加载 {count} 个模糊匹配 key。为保持浏览器响应,当前以扁平列表展示;请缩小搜索范围以查看层级。", deleteGroup: "删除分组", + deleteKey: "删除 key", deleteGroupDetails: "{target}\n{count} 个 key", deleteLoadedSearchKeysDetails: "{target}\n已加载的 {count} 个匹配 key", flushDb: "清空当前 DB", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 5dafec837b..14cbd3cbb5 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -3641,6 +3641,7 @@ export default withEnglishFallback({ loadedGroupKeysPartial: "目前已載入 {count} 個 key —— 此資料夾下可能還有更多", fuzzyTreeLimit: "已載入 {count} 個模糊相符 key。為保持瀏覽器回應,目前以扁平清單顯示;請縮小搜尋範圍以查看層級。", deleteGroup: "刪除群組", + deleteKey: "刪除 key", deleteGroupDetails: "{target}\n{count} 個 key", deleteLoadedSearchKeysDetails: "{target}\n已載入的 {count} 個相符 key", flushDb: "清空目前 DB",