feat(redis): delete leaf keys from the key list
This commit is contained in:
10 files changed
+58
-2
No files matched your search
@@ -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<HTMLButtonElement>('button[title="redis.deleteKey"]');
|
||||
deleteButton.click();
|
||||
await settle();
|
||||
|
||||
expect(mocks.redisDeleteKeys).not.toHaveBeenCalled();
|
||||
expect(requiredElement<HTMLElement>("[data-test-danger-details]").textContent).toContain("session:current");
|
||||
requiredElement<HTMLButtonElement>("[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();
|
||||
|
||||
@@ -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 });
|
||||
<Button v-if="row.node.kind === 'group' && !isFuzzyHierarchyView" variant="ghost" size="icon" class="h-5 w-5 shrink-0 text-destructive opacity-0 group-hover:opacity-100" :title="t('redis.deleteGroup')" :disabled="selectionBusy" @click="requestGroupDelete(row.node, $event)">
|
||||
<Trash2 class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="row.node.kind === 'leaf'"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-5 w-5 shrink-0 text-destructive opacity-0 group-hover:opacity-100"
|
||||
:title="t('redis.deleteKey')"
|
||||
:aria-label="t('redis.deleteKey')"
|
||||
:disabled="selectionBusy"
|
||||
@click="requestKeyDelete(row.node, $event)"
|
||||
>
|
||||
<Trash2 class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CustomContextMenu>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -4342,6 +4342,7 @@ export default withEnglishFallback({
|
||||
loadedGroupKeysPartial: "これまでに読み込まれたキー {count} 件 — このフォルダーにはさらにキーが存在する可能性があります",
|
||||
fuzzyTreeLimit: "ブラウザーの応答性を保つため、あいまい一致 {count} 件をフラットな一覧で表示しています。階層を表示するには検索条件を絞り込んでください。",
|
||||
deleteGroup: "グループを削除",
|
||||
deleteKey: "キーを削除",
|
||||
deleteGroupDetails: "{target}\n{count}個のキー",
|
||||
deleteLoadedSearchKeysDetails: "{target}\n読み込み済みの一致キー {count} 件",
|
||||
flushDb: "現在のDBをクリア",
|
||||
|
||||
@@ -3952,6 +3952,7 @@ export default withEnglishFallback({
|
||||
loadedGroupKeysPartial: "지금까지 로드된 {count}개 키 — 이 폴더에 더 많은 키가 있을 수 있습니다",
|
||||
fuzzyTreeLimit: "{count}개의 퍼지 일치가 브라우저 응답성을 유지하기 위해 평면 목록으로 표시됩니다. 계층 구조를 보려면 검색을 좁히세요.",
|
||||
deleteGroup: "그룹 삭제",
|
||||
deleteKey: "키 삭제",
|
||||
deleteGroupDetails: "{target}\n키 {count}개",
|
||||
deleteLoadedSearchKeysDetails: "{target}\n로드된 일치 키 {count}개",
|
||||
flushDb: "현재 DB 비우기",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user