feat: Redis browser overhaul — Navicat-style table, editing, and pagination

- Unified key table with columns: key, type, value preview, size, TTL
- Top-bottom split layout: key table above, value detail below
- Virtual scrolling via RecycleScroller for large key sets
- ZSet editing: add/remove members with scores
- TTL inline editing: click badge to modify expiration
- Batch key deletion with checkbox selection
- Paginated loading for Hash/Set/ZSet/List values (HSCAN/SSCAN/ZSCAN)
- Debounced auto-search (400ms) for key filtering
- Value previews fetched during key scan for instant display
This commit is contained in:
t8y2 committed 2026-05-09 11:45:50 +08:00
1 parent d6e273e136
commit 1a1f128f2b
11 files changed
+960 -212

No files matched your search

+5
View File
@@ -93,6 +93,11 @@ export const redisListPush = forward("redisListPush");
export const redisListRemove = forward("redisListRemove");
export const redisSetAdd = forward("redisSetAdd");
export const redisSetRemove = forward("redisSetRemove");
export const redisZadd = forward("redisZadd");
export const redisZrem = forward("redisZrem");
export const redisSetTtl = forward("redisSetTtl");
export const redisDeleteKeys = forward("redisDeleteKeys");
export const redisLoadMore = forward("redisLoadMore");
// MongoDB
export const mongoListDatabases = forward("mongoListDatabases");
+33
View File
@@ -498,6 +498,39 @@ export async function redisSetRemove(connectionId: string, db: number, keyRaw: s
return post("/api/redis/set-remove", { connectionId, db, keyRaw, member });
}
export async function redisZadd(
connectionId: string,
db: number,
keyRaw: string,
member: string,
score: number,
): Promise<void> {
return post("/api/redis/zadd", { connectionId, db, keyRaw, member, score });
}
export async function redisZrem(connectionId: string, db: number, keyRaw: string, member: string): Promise<void> {
return post("/api/redis/zrem", { connectionId, db, keyRaw, member });
}
export async function redisSetTtl(connectionId: string, db: number, keyRaw: string, ttl: number): Promise<void> {
return post("/api/redis/set-ttl", { connectionId, db, keyRaw, ttl });
}
export async function redisDeleteKeys(connectionId: string, db: number, keyRaws: string[]): Promise<number> {
return post("/api/redis/delete-keys", { connectionId, db, keyRaws });
}
export async function redisLoadMore(
connectionId: string,
db: number,
keyRaw: string,
keyType: string,
cursor: number,
count: number,
): Promise<RedisValue> {
return post("/api/redis/load-more", { connectionId, db, keyRaw, keyType, cursor, count });
}
// ---------------------------------------------------------------------------
// MongoDB
// ---------------------------------------------------------------------------
+6
View File
@@ -9,6 +9,8 @@ export interface RedisKeyTreeLeafNode {
db: number;
keyType: string;
ttl: number;
size: number;
valuePreview: string;
pathSegments: string[];
}
@@ -67,6 +69,8 @@ export function buildRedisKeyTree(keys: RedisKeyInfo[], db: number): RedisKeyTre
db,
keyType: key.key_type,
ttl: key.ttl,
size: key.size,
valuePreview: key.value_preview,
pathSegments,
});
continue;
@@ -101,6 +105,8 @@ export function buildRedisKeyTree(keys: RedisKeyInfo[], db: number): RedisKeyTre
db,
keyType: key.key_type,
ttl: key.ttl,
size: key.size,
valuePreview: key.value_preview,
pathSegments,
});
}
+37
View File
@@ -262,6 +262,8 @@ export interface RedisKeyInfo {
key_raw: string;
key_type: string;
ttl: number;
size: number;
value_preview: string;
}
export interface RedisValue {
@@ -271,6 +273,8 @@ export interface RedisValue {
ttl: number;
value_is_binary: boolean;
value: any;
total?: number;
scan_cursor?: number;
}
export interface RedisScanResult {
@@ -340,6 +344,39 @@ export async function redisSetRemove(connectionId: string, db: number, keyRaw: s
return invoke("redis_set_remove", { connectionId, db, keyRaw, member });
}
export async function redisZadd(
connectionId: string,
db: number,
keyRaw: string,
member: string,
score: number,
): Promise<void> {
return invoke("redis_zadd", { connectionId, db, keyRaw, member, score });
}
export async function redisZrem(connectionId: string, db: number, keyRaw: string, member: string): Promise<void> {
return invoke("redis_zrem", { connectionId, db, keyRaw, member });
}
export async function redisSetTtl(connectionId: string, db: number, keyRaw: string, ttl: number): Promise<void> {
return invoke("redis_set_ttl", { connectionId, db, keyRaw, ttl });
}
export async function redisDeleteKeys(connectionId: string, db: number, keyRaws: string[]): Promise<number> {
return invoke("redis_delete_keys", { connectionId, db, keyRaws });
}
export async function redisLoadMore(
connectionId: string,
db: number,
keyRaw: string,
keyType: string,
cursor: number,
count: number,
): Promise<RedisValue> {
return invoke("redis_load_more", { connectionId, db, keyRaw, keyType, cursor, count });
}
// --- MongoDB ---
export interface MongoDocumentResult {
documents: any[];