From 3321fbf6fd8600e65e775de167d099285a10e0c4 Mon Sep 17 00:00:00 2001
From: Lykin <137850705+tiny-craft@users.noreply.github.com>
Date: Mon, 27 May 2024 16:05:13 +0800
Subject: [PATCH 01/17] style: fix the width and height of the redis type tag
---
frontend/src/components/common/RedisTypeTag.vue | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/frontend/src/components/common/RedisTypeTag.vue b/frontend/src/components/common/RedisTypeTag.vue
index 596add16..059409d4 100644
--- a/frontend/src/components/common/RedisTypeTag.vue
+++ b/frontend/src/components/common/RedisTypeTag.vue
@@ -68,6 +68,7 @@ const label = computed(() => {
'redis-type-tag-small': !props.short && props.size === 'small',
'redis-type-tag-round': props.round,
'redis-type-tag-loading': props.loading,
+ 'redis-type-tag': props.short,
}"
:color="{ color: backgroundColor, textColor: fontColor }"
:size="props.size"
@@ -112,4 +113,13 @@ const label = computed(() => {
opacity: 0.4;
}
}
+
+.redis-type-tag {
+ width: 22px;
+ height: 22px;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ vertical-align: middle;
+}
From eefa7b13463b6ef83c3682026948296ac2e0636c Mon Sep 17 00:00:00 2001
From: Lykin <137850705+tiny-craft@users.noreply.github.com>
Date: Mon, 27 May 2024 16:52:20 +0800
Subject: [PATCH 02/17] style: change chart time to 24-hour format
---
frontend/src/components/content_value/ContentServerStatus.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontend/src/components/content_value/ContentServerStatus.vue b/frontend/src/components/content_value/ContentServerStatus.vue
index b05dff62..d72dbe68 100644
--- a/frontend/src/components/content_value/ContentServerStatus.vue
+++ b/frontend/src/components/content_value/ContentServerStatus.vue
@@ -94,7 +94,7 @@ const refreshInfo = async (force) => {
const _updateChart = (info) => {
let timeLabels = toRaw(cmdRate.value.labels)
- timeLabels = timeLabels.concat(dayjs().format('hh:mm:ss'))
+ timeLabels = timeLabels.concat(dayjs().format('HH:mm:ss'))
timeLabels = slice(timeLabels, Math.max(0, timeLabels.length - statusHistory))
// commands per seconds
@@ -146,7 +146,7 @@ const _updateChart = (info) => {
const _mockChart = () => {
const timeLabels = []
for (let i = 0; i < 5; i++) {
- timeLabels.push(dayjs().add(5, 'seconds').format('hh:mm:ss'))
+ timeLabels.push(dayjs().add(5, 'seconds').format('HH:mm:ss'))
}
// commands per seconds
From 028a240f49e33242d4c7ec7a5d13478f0bdf29dd Mon Sep 17 00:00:00 2001
From: Lykin <137850705+tiny-craft@users.noreply.github.com>
Date: Tue, 4 Jun 2024 10:34:42 +0800
Subject: [PATCH 03/17] perf: evenly divide the number of scans for each
cluster node
---
backend/services/browser_service.go | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/backend/services/browser_service.go b/backend/services/browser_service.go
index a85fac98..09f1e3df 100644
--- a/backend/services/browser_service.go
+++ b/backend/services/browser_service.go
@@ -445,7 +445,7 @@ func (b *browserService) scanKeys(ctx context.Context, client redis.UniversalCli
filterType := len(keyType) > 0
scanSize := int64(Preferences().GetScanSize())
// define sub scan function
- scan := func(ctx context.Context, cli redis.UniversalClient, appendFunc func(k []any)) error {
+ scan := func(ctx context.Context, cli redis.UniversalClient, count int64, appendFunc func(k []any)) error {
var loadedKey []string
var scanCount int64
for {
@@ -475,16 +475,22 @@ func (b *browserService) scanKeys(ctx context.Context, client redis.UniversalCli
if cluster, ok := client.(*redis.ClusterClient); ok {
// cluster mode
var mutex sync.Mutex
+ var totalMaster int64
+ cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error {
+ totalMaster += 1
+ return nil
+ })
+ partCount := count / max(totalMaster, 1)
err = cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error {
// FIXME: BUG? can not fully load in cluster mode? maybe remove the shared "cursor"
- return scan(ctx, cli, func(k []any) {
+ return scan(ctx, cli, partCount, func(k []any) {
mutex.Lock()
keys = append(keys, k...)
mutex.Unlock()
})
})
} else {
- err = scan(ctx, client, func(k []any) {
+ err = scan(ctx, client, count, func(k []any) {
keys = append(keys, k...)
})
}
From 6eeb701439ae5bd346c0160f26be16ddea3b11e1 Mon Sep 17 00:00:00 2001
From: Lykin <137850705+tiny-craft@users.noreply.github.com>
Date: Tue, 4 Jun 2024 10:43:49 +0800
Subject: [PATCH 04/17] fix: the overflow tab cannot be fully display
---
frontend/src/AppContent.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/frontend/src/AppContent.vue b/frontend/src/AppContent.vue
index dba16a38..6089e265 100644
--- a/frontend/src/AppContent.vue
+++ b/frontend/src/AppContent.vue
@@ -160,7 +160,7 @@ const onKeyShortcut = (e) => {
-
+
{
align-self: flex-end;
margin-bottom: -1px;
margin-left: 3px;
+ overflow: auto;
}
#app-content {
From 88e2c6cb439d82305b533b1b1150b15d22d63771 Mon Sep 17 00:00:00 2001
From: Lykin <137850705+tiny-craft@users.noreply.github.com>
Date: Wed, 5 Jun 2024 10:46:38 +0800
Subject: [PATCH 05/17] fix: incorrect binary value convert (#279)
---
backend/utils/convert/binary_convert.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/utils/convert/binary_convert.go b/backend/utils/convert/binary_convert.go
index b2fc6b75..98b97f61 100644
--- a/backend/utils/convert/binary_convert.go
+++ b/backend/utils/convert/binary_convert.go
@@ -24,7 +24,7 @@ func (BinaryConvert) Encode(str string) (string, bool) {
func (BinaryConvert) Decode(str string) (string, bool) {
var binary strings.Builder
- for _, char := range str {
+ for _, char := range []byte(str) {
binary.WriteString(fmt.Sprintf("%08b", int(char)))
}
return binary.String(), true
From bf71c6db0e4efde02951d7392594ae6fc5a03c92 Mon Sep 17 00:00:00 2001
From: Lykin <137850705+tiny-craft@users.noreply.github.com>
Date: Tue, 11 Jun 2024 11:47:52 +0800
Subject: [PATCH 06/17] perf: trim spaces of connection address(#281)
---
frontend/src/components/dialogs/ConnectionDialog.vue | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/frontend/src/components/dialogs/ConnectionDialog.vue b/frontend/src/components/dialogs/ConnectionDialog.vue
index f04ceddf..e1424378 100644
--- a/frontend/src/components/dialogs/ConnectionDialog.vue
+++ b/frontend/src/components/dialogs/ConnectionDialog.vue
@@ -1,5 +1,5 @@
-
+
Date: Mon, 17 Jun 2024 18:29:56 +0800
Subject: [PATCH 08/17] perf: support batch delete keys without scan confirm
(#283)
---
backend/services/browser_service.go | 78 +++++++++++++++++++
.../components/dialogs/DeleteKeyDialog.vue | 58 ++++++++++----
frontend/src/langs/en-us.json | 2 +
frontend/src/langs/es-es.json | 2 +
frontend/src/langs/fr-fr.json | 2 +
frontend/src/langs/ja-jp.json | 2 +
frontend/src/langs/ko-kr.json | 2 +
frontend/src/langs/pt-br.json | 2 +
frontend/src/langs/ru-ru.json | 2 +
frontend/src/langs/zh-cn.json | 2 +
frontend/src/langs/zh-tw.json | 2 +
frontend/src/stores/browser.js | 61 +++++++++++++++
12 files changed, 198 insertions(+), 17 deletions(-)
diff --git a/backend/services/browser_service.go b/backend/services/browser_service.go
index 09f1e3df..fb5cc08b 100644
--- a/backend/services/browser_service.go
+++ b/backend/services/browser_service.go
@@ -2292,6 +2292,84 @@ func (b *browserService) DeleteKeys(server string, db int, ks []any, serialNo st
return
}
+// DeleteKeysByPattern delete keys by pattern
+func (b *browserService) DeleteKeysByPattern(server string, db int, pattern string) (resp types.JSResp) {
+ conf := Connection().getConnection(server)
+ if conf == nil {
+ resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
+ return
+ }
+ var client redis.UniversalClient
+ var err error
+ var connConfig = conf.ConnectionConfig
+ connConfig.LastDB = db
+ if client, err = b.createRedisClient(connConfig); err != nil {
+ resp.Msg = err.Error()
+ return
+ }
+ ctx, cancelFunc := context.WithCancel(b.ctx)
+ defer client.Close()
+ defer cancelFunc()
+
+ var ks []any
+ ks, _, err = b.scanKeys(ctx, client, pattern, "", 0, 0)
+ if err != nil {
+ resp.Msg = err.Error()
+ return
+ }
+
+ total := len(ks)
+ var canceled bool
+ var deletedKeys = make([]any, 0, total)
+ var mutex sync.Mutex
+ del := func(ctx context.Context, cli redis.UniversalClient) error {
+ const batchSize = 1000
+ for i := 0; i < total; i += batchSize {
+ pipe := cli.Pipeline()
+ for j := 0; j < batchSize; j++ {
+ if i+j < total {
+ pipe.Del(ctx, strutil.DecodeRedisKey(ks[i+j]))
+ }
+ }
+ cmders, delErr := pipe.Exec(ctx)
+ for j, cmder := range cmders {
+ if cmder.(*redis.IntCmd).Val() == 1 {
+ // save deleted key
+ mutex.Lock()
+ deletedKeys = append(deletedKeys, ks[i+j])
+ mutex.Unlock()
+ }
+ }
+ if errors.Is(delErr, context.Canceled) || canceled {
+ canceled = true
+ break
+ }
+ }
+ return nil
+ }
+
+ if cluster, ok := client.(*redis.ClusterClient); ok {
+ // cluster mode
+ err = cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error {
+ return del(ctx, cli)
+ })
+ } else {
+ err = del(ctx, client)
+ }
+
+ resp.Success = true
+ resp.Data = struct {
+ Canceled bool `json:"canceled"`
+ Deleted any `json:"deleted"`
+ Failed int `json:"failed"`
+ }{
+ Canceled: canceled,
+ Deleted: deletedKeys,
+ Failed: len(ks) - len(deletedKeys),
+ }
+ return
+}
+
// ExportKey export keys
func (b *browserService) ExportKey(server string, db int, ks []any, path string, includeExpire bool) (resp types.JSResp) {
// connect a new connection to export keys
diff --git a/frontend/src/components/dialogs/DeleteKeyDialog.vue b/frontend/src/components/dialogs/DeleteKeyDialog.vue
index 8723e1ad..e5a43f2e 100644
--- a/frontend/src/components/dialogs/DeleteKeyDialog.vue
+++ b/frontend/src/components/dialogs/DeleteKeyDialog.vue
@@ -1,7 +1,6 @@