From 9b9d0e3c7c7e385c3aa5a8938d5c154f0fb34c06 Mon Sep 17 00:00:00 2001
From: tiny-craft <137850705+tiny-craft@users.noreply.github.com>
Date: Thu, 2 Nov 2023 18:17:54 +0800
Subject: [PATCH] feat: add flush db operation
---
backend/services/connection_service.go | 39 +++++++++
backend/utils/redis/log_hook.go | 6 +-
frontend/src/App.vue | 2 +
.../src/components/content/ContentLogPane.vue | 15 +++-
.../src/components/dialogs/FlushDbDialog.vue | 85 +++++++++++++++++++
frontend/src/components/icons/Pub.vue | 2 +-
.../src/components/sidebar/BrowserTree.vue | 12 +--
frontend/src/langs/en-us.json | 8 +-
frontend/src/langs/zh-cn.json | 6 +-
frontend/src/stores/connections.js | 25 ++++++
frontend/src/stores/dialog.js | 15 ++++
11 files changed, 199 insertions(+), 16 deletions(-)
create mode 100644 frontend/src/components/dialogs/FlushDbDialog.vue
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 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('dialogue.key.async_delete_title') }}
+
+
+
+ {{ $t('dialogue.key.confirm_flush') }}
+
+
+
+
+
+ {{ $t('common.cancel') }}
+
+ {{ $t('dialogue.key.confirm_flush_db') }}
+
+
+
+
+
+
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