diff --git a/backend/services/connection_service.go b/backend/services/connection_service.go index fad3c80..e519760 100644 --- a/backend/services/connection_service.go +++ b/backend/services/connection_service.go @@ -1521,6 +1521,45 @@ func (c *connectionService) DeleteKey(connName string, db int, k any, async bool return } +// FlushDB flush database +func (c *connectionService) FlushDB(connName string, db int, async bool) (resp types.JSResp) { + item, err := c.getRedisClient(connName, db) + if err != nil { + resp.Msg = err.Error() + return + } + + flush := func(ctx context.Context, cli redis.UniversalClient) { + cli.TxPipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Select(ctx, db) + if async { + pipe.FlushDBAsync(ctx) + } else { + pipe.FlushDB(ctx) + } + return nil + }) + } + + client, ctx := item.client, item.ctx + if cluster, ok := client.(*redis.ClusterClient); ok { + // cluster mode + err = cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error { + flush(ctx, cli) + return nil + }) + } else { + flush(ctx, client) + } + + if err != nil { + resp.Msg = err.Error() + return + } + resp.Success = true + return +} + // RenameKey rename key func (c *connectionService) RenameKey(connName string, db int, key, newKey string) (resp types.JSResp) { item, err := c.getRedisClient(connName, db) diff --git a/backend/utils/redis/log_hook.go b/backend/utils/redis/log_hook.go index a99c610..b3c2a8b 100644 --- a/backend/utils/redis/log_hook.go +++ b/backend/utils/redis/log_hook.go @@ -99,7 +99,7 @@ func (l *LogHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.Proc err := next(ctx, cmds) cost := time.Since(t).Milliseconds() b := make([]byte, 0, 64) - for _, cmd := range cmds { + for i, cmd := range cmds { log.Println("pipeline: ", cmd) if l.cmdExec != nil { for i, arg := range cmd.Args() { @@ -108,7 +108,9 @@ func (l *LogHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.Proc } b = appendArg(b, arg) } - b = append(b, '\n') + if i != len(cmds) { + b = append(b, '\n') + } } } if l.cmdExec != nil { diff --git a/frontend/src/App.vue b/frontend/src/App.vue index aceee79..0d95107 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -20,6 +20,7 @@ import KeyFilterDialog from './components/dialogs/KeyFilterDialog.vue' import { WindowSetDarkTheme, WindowSetLightTheme } from 'wailsjs/runtime/runtime.js' import { darkThemeOverrides, themeOverrides } from '@/utils/theme.js' import AboutDialog from '@/components/dialogs/AboutDialog.vue' +import FlushDbDialog from '@/components/dialogs/FlushDbDialog.vue' hljs.registerLanguage('json', json) hljs.registerLanguage('plaintext', plaintext) @@ -73,6 +74,7 @@ watch( + diff --git a/frontend/src/components/content/ContentLogPane.vue b/frontend/src/components/content/ContentLogPane.vue index fc2bcce..12714c3 100644 --- a/frontend/src/components/content/ContentLogPane.vue +++ b/frontend/src/components/content/ContentLogPane.vue @@ -1,9 +1,9 @@ + + + + diff --git a/frontend/src/components/icons/Pub.vue b/frontend/src/components/icons/Pub.vue index 1abc0c5..fe093a5 100644 --- a/frontend/src/components/icons/Pub.vue +++ b/frontend/src/components/icons/Pub.vue @@ -10,7 +10,7 @@ const props = defineProps({ }, strokeColor: { type: String, - default: '#FFF', + default: 'currentColor', }, }) diff --git a/frontend/src/components/sidebar/BrowserTree.vue b/frontend/src/components/sidebar/BrowserTree.vue index 0452ea1..fdafb5a 100644 --- a/frontend/src/components/sidebar/BrowserTree.vue +++ b/frontend/src/components/sidebar/BrowserTree.vue @@ -117,8 +117,8 @@ const menuOptions = { key: 'd1', }, { - key: 'key_remove', - label: i18n.t('interface.batch_delete'), + key: 'db_flush', + label: i18n.t('interface.flush_db'), icon: renderIcon(Delete), }, { @@ -163,7 +163,7 @@ const menuOptions = { }, { key: 'key_remove', - label: i18n.t('interface.batch_delete'), + label: i18n.t('interface.batch_delete_key'), icon: renderIcon(Delete), }, ], @@ -260,7 +260,7 @@ const handleSelectContextMenu = (key) => { connectionStore.closeDatabase(props.server, db) break case 'db_flush': - dialogStore.openDeleteKeyDialog(props.server, db, '*') + dialogStore.openFlushDBDialog(props.server, db) break case 'db_newkey': case 'key_newkey': @@ -548,7 +548,7 @@ const getDatabaseMenu = (opened, loading, end) => { onClick: () => handleSelectContextMenu('db_loadall'), }), h(IconButton, { - tTooltip: 'interface.batch_delete', + tTooltip: 'interface.flush_db', icon: Delete, disabled: loading === true, onClick: () => handleSelectContextMenu('db_flush'), @@ -585,7 +585,7 @@ const getLayerMenu = () => { onClick: () => handleSelectContextMenu('key_newkey'), }), h(IconButton, { - tTooltip: 'interface.batch_delete', + tTooltip: 'interface.batch_delete_key', icon: Delete, onClick: () => handleSelectContextMenu('key_remove'), }), diff --git a/frontend/src/langs/en-us.json b/frontend/src/langs/en-us.json index bd149f8..7fa28d4 100644 --- a/frontend/src/langs/en-us.json +++ b/frontend/src/langs/en-us.json @@ -65,6 +65,7 @@ "rename_key": "Rename Key", "delete_key": "Delete Key", "batch_delete_key": "Batch Delete Keys", + "flush_db": "Flush Database", "copy_value": "Copy Value", "edit_value": "Edit Value", "save_update": "Save Update", @@ -82,7 +83,6 @@ "decode_with": "Decode / Decompression", "reload": "Reload", "open_connection": "Open Connection", - "batch_delete": "Batch Delete", "copy_path": "Copy Path", "copy_key": "Copy Key", "binary_key": "Binary Key Name", @@ -214,14 +214,16 @@ "new": "New Key", "new_name": "New Key Name", "persist_key": "Persist Key", - "server": "Belong", + "server": "Connection", "db_index": "Database Index", "key_expression": "Key Expression", "affected_key": "Affected Keys", "show_affected_key": "Show Affected Keys", "confirm_delete_key": "Confirm Delete {num} Key(s)", "async_delete": "Asynchronously Execute", - "async_delete_title": "Do not waiting for the operation's result" + "async_delete_title": "Do not waiting for the operation's result", + "confirm_flush": "I know what I'm doing!", + "confirm_flush_db": "Confirm Flush Database" }, "field": { "new": "Add New Field", diff --git a/frontend/src/langs/zh-cn.json b/frontend/src/langs/zh-cn.json index a29b729..4fbbbb4 100644 --- a/frontend/src/langs/zh-cn.json +++ b/frontend/src/langs/zh-cn.json @@ -65,6 +65,7 @@ "rename_key": "重命名键", "delete_key": "删除键", "batch_delete_key": "批量删除键", + "flush_db": "清空数据库", "copy_value": "复制值", "edit_value": "修改值", "save_update": "保存修改", @@ -82,7 +83,6 @@ "decode_with": "解码/解压方式", "reload": "重新载入", "open_connection": "打开连接", - "batch_delete": "批量删除键", "copy_path": "复制路径", "copy_key": "复制键名", "binary_key": "二进制键名", @@ -220,7 +220,9 @@ "show_affected_key": "查看受影响的键名", "confirm_delete_key": "确认删除{num}个键", "async_delete": "异步执行", - "async_delete_title": "不等待操作结果" + "async_delete_title": "不等待操作结果", + "confirm_flush": "我知道我正在执行的操作!", + "confirm_flush_db": "确认清空数据库" }, "field": { "new": "添加新字段", diff --git a/frontend/src/stores/connections.js b/frontend/src/stores/connections.js index dfbfcf9..af4f06c 100644 --- a/frontend/src/stores/connections.js +++ b/frontend/src/stores/connections.js @@ -25,6 +25,7 @@ import { DeleteConnection, DeleteGroup, DeleteKey, + FlushDB, GetCmdHistory, GetConnection, GetKeyValue, @@ -1666,6 +1667,30 @@ const useConnectionStore = defineStore('connections', { return false }, + /** + * flush database + * @param connName + * @param db + * @param async + * @return {Promise} + */ + async flushDatabase(connName, db, async) { + try { + const { success = false } = await FlushDB(connName, db, async) + + if (success === true) { + // update tree view data + this._deleteKeyNode(connName, db) + // set tab content empty + const tab = useTabStore() + tab.emptyTab(connName) + return true + } + } finally { + } + return true + }, + /** * rename key * @param {string} connName diff --git a/frontend/src/stores/dialog.js b/frontend/src/stores/dialog.js index 3a4e311..e04310d 100644 --- a/frontend/src/stores/dialog.js +++ b/frontend/src/stores/dialog.js @@ -63,6 +63,12 @@ const useDialogStore = defineStore('dialog', { }, deleteKeyDialogVisible: false, + flushDBParam: { + server: '', + db: 0, + }, + flushDBDialogVisible: false, + selectTTL: -1, ttlDialogVisible: false, @@ -164,6 +170,15 @@ const useDialogStore = defineStore('dialog', { this.deleteKeyDialogVisible = false }, + openFlushDBDialog(server, db) { + this.flushDBParam.server = server + this.flushDBParam.db = db + this.flushDBDialogVisible = true + }, + closeFlushDBDialog() { + this.flushDBDialogVisible = false + }, + /** * * @param {string} prefix