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>
|
||||
|
||||
Reference in new issue
Block a user