feat: add partial keys loading. #2
This commit is contained in:
parent
444f643d4a
commit
f3cd292af5
|
@ -6,3 +6,5 @@ const DEFAULT_WINDOW_WIDTH = 1024
|
||||||
const DEFAULT_WINDOW_HEIGHT = 768
|
const DEFAULT_WINDOW_HEIGHT = 768
|
||||||
const MIN_WINDOW_WIDTH = 960
|
const MIN_WINDOW_WIDTH = 960
|
||||||
const MIN_WINDOW_HEIGHT = 640
|
const MIN_WINDOW_HEIGHT = 640
|
||||||
|
const DEFAULT_LOAD_SIZE = 10000
|
||||||
|
const DEFAULT_SCAN_SIZE = 3000
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
"tinyrdm/backend/consts"
|
||||||
. "tinyrdm/backend/storage"
|
. "tinyrdm/backend/storage"
|
||||||
"tinyrdm/backend/types"
|
"tinyrdm/backend/types"
|
||||||
"tinyrdm/backend/utils/coll"
|
"tinyrdm/backend/utils/coll"
|
||||||
|
@ -43,6 +44,8 @@ type connectionItem struct {
|
||||||
client redis.UniversalClient
|
client redis.UniversalClient
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancelFunc context.CancelFunc
|
cancelFunc context.CancelFunc
|
||||||
|
cursor map[int]uint64 // current cursor of databases
|
||||||
|
stepSize int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyItem struct {
|
type keyItem struct {
|
||||||
|
@ -390,12 +393,13 @@ func (c *connectionService) DeleteGroup(name string, includeConn bool) (resp typ
|
||||||
|
|
||||||
// OpenConnection open redis server connection
|
// OpenConnection open redis server connection
|
||||||
func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(name, 0)
|
item, err := c.getRedisClient(name, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
// get connection config
|
// get connection config
|
||||||
selConn := c.conns.GetConnection(name)
|
selConn := c.conns.GetConnection(name)
|
||||||
|
|
||||||
|
@ -522,18 +526,18 @@ func (c *connectionService) CloseConnection(name string) (resp types.JSResp) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// get redis client from local cache or create a new open
|
// get a redis client from local cache or create a new open
|
||||||
// if db >= 0, will also switch to db index
|
// if db >= 0, will also switch to db index
|
||||||
func (c *connectionService) getRedisClient(connName string, db int) (redis.UniversalClient, context.Context, error) {
|
func (c *connectionService) getRedisClient(connName string, db int) (item connectionItem, err error) {
|
||||||
item, ok := c.connMap[connName]
|
var ok bool
|
||||||
var client redis.UniversalClient
|
var client redis.UniversalClient
|
||||||
var ctx context.Context
|
if item, ok = c.connMap[connName]; ok {
|
||||||
if ok {
|
client = item.client
|
||||||
client, ctx = item.client, item.ctx
|
|
||||||
} else {
|
} else {
|
||||||
selConn := c.conns.GetConnection(connName)
|
selConn := c.conns.GetConnection(connName)
|
||||||
if selConn == nil {
|
if selConn == nil {
|
||||||
return nil, nil, fmt.Errorf("no match connection \"%s\"", connName)
|
err = fmt.Errorf("no match connection \"%s\"", connName)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hook := redis2.NewHook(connName, func(cmd string, cost int64) {
|
hook := redis2.NewHook(connName, func(cmd string, cost int64) {
|
||||||
|
@ -550,10 +554,10 @@ func (c *connectionService) getRedisClient(connName string, db int) (redis.Unive
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
var err error
|
|
||||||
client, err = c.createRedisClient(selConn.ConnectionConfig)
|
client, err = c.createRedisClient(selConn.ConnectionConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("create conenction error: %s", err.Error())
|
err = fmt.Errorf("create conenction error: %s", err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// add hook to each node in cluster mode
|
// add hook to each node in cluster mode
|
||||||
var cluster *redis.ClusterClient
|
var cluster *redis.ClusterClient
|
||||||
|
@ -563,33 +567,51 @@ func (c *connectionService) getRedisClient(connName string, db int) (redis.Unive
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("get cluster nodes error: %s", err.Error())
|
err = fmt.Errorf("get cluster nodes error: %s", err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.AddHook(hook)
|
client.AddHook(hook)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = client.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
if _, err = client.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
||||||
return nil, nil, errors.New("can not connect to redis server:" + err.Error())
|
err = errors.New("can not connect to redis server:" + err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
var cancelFunc context.CancelFunc
|
ctx, cancelFunc := context.WithCancel(c.ctx)
|
||||||
ctx, cancelFunc = context.WithCancel(c.ctx)
|
item = connectionItem{
|
||||||
c.connMap[connName] = connectionItem{
|
|
||||||
client: client,
|
client: client,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancelFunc: cancelFunc,
|
cancelFunc: cancelFunc,
|
||||||
|
cursor: map[int]uint64{},
|
||||||
|
stepSize: int64(selConn.LoadSize),
|
||||||
}
|
}
|
||||||
|
if item.stepSize <= 0 {
|
||||||
|
item.stepSize = consts.DEFAULT_LOAD_SIZE
|
||||||
|
}
|
||||||
|
c.connMap[connName] = item
|
||||||
}
|
}
|
||||||
|
|
||||||
if db >= 0 {
|
if db >= 0 {
|
||||||
var rdb *redis.Client
|
var rdb *redis.Client
|
||||||
if rdb, ok = client.(*redis.Client); ok && rdb != nil {
|
if rdb, ok = client.(*redis.Client); ok && rdb != nil {
|
||||||
if err := rdb.Do(ctx, "select", strconv.Itoa(db)).Err(); err != nil {
|
if err = rdb.Do(item.ctx, "select", strconv.Itoa(db)).Err(); err != nil {
|
||||||
return nil, nil, err
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return client, ctx, nil
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// save current scan cursor
|
||||||
|
func (c *connectionService) setClientCursor(connName string, db int, cursor uint64) {
|
||||||
|
if _, ok := c.connMap[connName]; ok {
|
||||||
|
if cursor == 0 {
|
||||||
|
delete(c.connMap[connName].cursor, db)
|
||||||
|
} else {
|
||||||
|
c.connMap[connName].cursor[db] = cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse command response content which use "redis info"
|
// parse command response content which use "redis info"
|
||||||
|
@ -631,12 +653,13 @@ func (c *connectionService) parseDBItemInfo(info string) map[string]int {
|
||||||
|
|
||||||
// ServerInfo get server info
|
// ServerInfo get server info
|
||||||
func (c *connectionService) ServerInfo(name string) (resp types.JSResp) {
|
func (c *connectionService) ServerInfo(name string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(name, 0)
|
item, err := c.getRedisClient(name, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
// get database info
|
// get database info
|
||||||
res, err := client.Info(ctx).Result()
|
res, err := client.Info(ctx).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -652,31 +675,43 @@ func (c *connectionService) ServerInfo(name string) (resp types.JSResp) {
|
||||||
// OpenDatabase open select database, and list all keys
|
// OpenDatabase open select database, and list all keys
|
||||||
// @param path contain connection name and db name
|
// @param path contain connection name and db name
|
||||||
func (c *connectionService) OpenDatabase(connName string, db int, match string, keyType string) (resp types.JSResp) {
|
func (c *connectionService) OpenDatabase(connName string, db int, match string, keyType string) (resp types.JSResp) {
|
||||||
return c.ScanKeys(connName, db, match, keyType)
|
c.setClientCursor(connName, db, 0)
|
||||||
|
return c.LoadNextKeys(connName, db, match, keyType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanKeys scan all keys
|
// scan keys
|
||||||
func (c *connectionService) ScanKeys(connName string, db int, match, keyType string) (resp types.JSResp) {
|
// @return loaded keys
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
// @return next cursor
|
||||||
|
// @return scan error
|
||||||
|
func (c *connectionService) scanKeys(ctx context.Context, client redis.UniversalClient, match, keyType string, cursor uint64, count int64) ([]any, uint64, error) {
|
||||||
|
var err error
|
||||||
|
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 {
|
||||||
|
var loadedKey []string
|
||||||
|
var scanCount int64
|
||||||
|
for {
|
||||||
|
if filterType {
|
||||||
|
loadedKey, cursor, err = cli.ScanType(ctx, cursor, match, scanSize, keyType).Result()
|
||||||
|
} else {
|
||||||
|
loadedKey, cursor, err = cli.Scan(ctx, cursor, match, scanSize).Result()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
return err
|
||||||
return
|
} else {
|
||||||
|
ks := sliceutil.Map(loadedKey, func(i int) any {
|
||||||
|
return strutil.EncodeRedisKey(loadedKey[i])
|
||||||
|
})
|
||||||
|
scanCount += int64(len(ks))
|
||||||
|
appendFunc(ks)
|
||||||
}
|
}
|
||||||
|
|
||||||
filterType := len(keyType) > 0
|
if (count > 0 && scanCount > count) || cursor == 0 {
|
||||||
var countPerScan int64 = 10000
|
break
|
||||||
// define sub scan function
|
|
||||||
scan := func(ctx context.Context, cli redis.UniversalClient, appendFunc func(k any)) error {
|
|
||||||
var iter *redis.ScanIterator
|
|
||||||
if filterType {
|
|
||||||
iter = cli.ScanType(ctx, 0, match, countPerScan, keyType).Iterator()
|
|
||||||
} else {
|
|
||||||
iter = cli.Scan(ctx, 0, match, countPerScan).Iterator()
|
|
||||||
}
|
}
|
||||||
for iter.Next(ctx) {
|
|
||||||
appendFunc(strutil.EncodeRedisKey(iter.Val()))
|
|
||||||
}
|
}
|
||||||
return iter.Err()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys []any
|
var keys []any
|
||||||
|
@ -684,22 +719,64 @@ func (c *connectionService) ScanKeys(connName string, db int, match, keyType str
|
||||||
// cluster mode
|
// cluster mode
|
||||||
var mutex sync.Mutex
|
var mutex sync.Mutex
|
||||||
err = cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error {
|
err = cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error {
|
||||||
return scan(ctx, cli, func(k any) {
|
return scan(ctx, cli, func(k []any) {
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
keys = append(keys, k)
|
keys = append(keys, k...)
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
err = scan(ctx, client, func(k any) {
|
err = scan(ctx, client, func(k []any) {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, cursor, err
|
||||||
|
}
|
||||||
|
return keys, cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadNextKeys load next key from saved cursor
|
||||||
|
func (c *connectionService) LoadNextKeys(connName string, db int, match, keyType string) (resp types.JSResp) {
|
||||||
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx, count := item.client, item.ctx, item.stepSize
|
||||||
|
cursor := item.cursor[db]
|
||||||
|
keys, cursor, err := c.scanKeys(ctx, client, match, keyType, cursor, count)
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.setClientCursor(connName, db, cursor)
|
||||||
|
|
||||||
|
resp.Success = true
|
||||||
|
resp.Data = map[string]any{
|
||||||
|
"keys": keys,
|
||||||
|
"end": cursor == 0,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAllKeys load all keys
|
||||||
|
func (c *connectionService) LoadAllKeys(connName string, db int, match, keyType string) (resp types.JSResp) {
|
||||||
|
item, err := c.getRedisClient(connName, db)
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
|
keys, _, err := c.scanKeys(ctx, client, match, keyType, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.setClientCursor(connName, db, 0)
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = map[string]any{
|
||||||
"keys": keys,
|
"keys": keys,
|
||||||
|
@ -709,12 +786,13 @@ func (c *connectionService) ScanKeys(connName string, db int, match, keyType str
|
||||||
|
|
||||||
// GetKeyValue get value by key
|
// GetKeyValue get value by key
|
||||||
func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs string) (resp types.JSResp) {
|
func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var keyType string
|
var keyType string
|
||||||
var dur time.Duration
|
var dur time.Duration
|
||||||
|
@ -755,9 +833,10 @@ func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs s
|
||||||
case "hash":
|
case "hash":
|
||||||
//value, err = client.HGetAll(ctx, key).Result()
|
//value, err = client.HGetAll(ctx, key).Result()
|
||||||
items := map[string]string{}
|
items := map[string]string{}
|
||||||
|
scanSize := int64(Preferences().GetScanSize())
|
||||||
for {
|
for {
|
||||||
var loadedVal []string
|
var loadedVal []string
|
||||||
loadedVal, cursor, err = client.HScan(ctx, key, cursor, "*", 10000).Result()
|
loadedVal, cursor, err = client.HScan(ctx, key, cursor, "*", scanSize).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
|
@ -774,9 +853,10 @@ func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs s
|
||||||
case "set":
|
case "set":
|
||||||
//value, err = client.SMembers(ctx, key).Result()
|
//value, err = client.SMembers(ctx, key).Result()
|
||||||
items := []string{}
|
items := []string{}
|
||||||
|
scanSize := int64(Preferences().GetScanSize())
|
||||||
for {
|
for {
|
||||||
var loadedKey []string
|
var loadedKey []string
|
||||||
loadedKey, cursor, err = client.SScan(ctx, key, cursor, "*", 10000).Result()
|
loadedKey, cursor, err = client.SScan(ctx, key, cursor, "*", scanSize).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
|
@ -791,9 +871,10 @@ func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs s
|
||||||
case "zset":
|
case "zset":
|
||||||
//value, err = client.ZRangeWithScores(ctx, key, 0, -1).Result()
|
//value, err = client.ZRangeWithScores(ctx, key, 0, -1).Result()
|
||||||
var items []types.ZSetItem
|
var items []types.ZSetItem
|
||||||
|
scanSize := int64(Preferences().GetScanSize())
|
||||||
for {
|
for {
|
||||||
var loadedVal []string
|
var loadedVal []string
|
||||||
loadedVal, cursor, err = client.ZScan(ctx, key, cursor, "*", 10000).Result()
|
loadedVal, cursor, err = client.ZScan(ctx, key, cursor, "*", scanSize).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
|
@ -848,12 +929,13 @@ func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs s
|
||||||
// SetKeyValue set value by key
|
// SetKeyValue set value by key
|
||||||
// @param ttl <= 0 means keep current ttl
|
// @param ttl <= 0 means keep current ttl
|
||||||
func (c *connectionService) SetKeyValue(connName string, db int, k any, keyType string, value any, ttl int64, viewAs string) (resp types.JSResp) {
|
func (c *connectionService) SetKeyValue(connName string, db int, k any, keyType string, value any, ttl int64, viewAs string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var expiration time.Duration
|
var expiration time.Duration
|
||||||
if ttl < 0 {
|
if ttl < 0 {
|
||||||
|
@ -971,12 +1053,13 @@ func (c *connectionService) SetKeyValue(connName string, db int, k any, keyType
|
||||||
|
|
||||||
// SetHashValue set hash field
|
// SetHashValue set hash field
|
||||||
func (c *connectionService) SetHashValue(connName string, db int, k any, field, newField, value string) (resp types.JSResp) {
|
func (c *connectionService) SetHashValue(connName string, db int, k any, field, newField, value string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var removedField []string
|
var removedField []string
|
||||||
updatedField := map[string]string{}
|
updatedField := map[string]string{}
|
||||||
|
@ -1017,12 +1100,13 @@ func (c *connectionService) SetHashValue(connName string, db int, k any, field,
|
||||||
|
|
||||||
// AddHashField add or update hash field
|
// AddHashField add or update hash field
|
||||||
func (c *connectionService) AddHashField(connName string, db int, k any, action int, fieldItems []any) (resp types.JSResp) {
|
func (c *connectionService) AddHashField(connName string, db int, k any, action int, fieldItems []any) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
updated := map[string]any{}
|
updated := map[string]any{}
|
||||||
switch action {
|
switch action {
|
||||||
|
@ -1063,12 +1147,13 @@ func (c *connectionService) AddHashField(connName string, db int, k any, action
|
||||||
|
|
||||||
// AddListItem add item to list or remove from it
|
// AddListItem add item to list or remove from it
|
||||||
func (c *connectionService) AddListItem(connName string, db int, k any, action int, items []any) (resp types.JSResp) {
|
func (c *connectionService) AddListItem(connName string, db int, k any, action int, items []any) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var leftPush, rightPush []any
|
var leftPush, rightPush []any
|
||||||
switch action {
|
switch action {
|
||||||
|
@ -1096,12 +1181,13 @@ func (c *connectionService) AddListItem(connName string, db int, k any, action i
|
||||||
|
|
||||||
// SetListItem update or remove list item by index
|
// SetListItem update or remove list item by index
|
||||||
func (c *connectionService) SetListItem(connName string, db int, k any, index int64, value string) (resp types.JSResp) {
|
func (c *connectionService) SetListItem(connName string, db int, k any, index int64, value string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var removed []int64
|
var removed []int64
|
||||||
updated := map[int64]string{}
|
updated := map[int64]string{}
|
||||||
|
@ -1139,12 +1225,13 @@ func (c *connectionService) SetListItem(connName string, db int, k any, index in
|
||||||
|
|
||||||
// SetSetItem add members to set or remove from set
|
// SetSetItem add members to set or remove from set
|
||||||
func (c *connectionService) SetSetItem(connName string, db int, k any, remove bool, members []any) (resp types.JSResp) {
|
func (c *connectionService) SetSetItem(connName string, db int, k any, remove bool, members []any) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
if remove {
|
if remove {
|
||||||
_, err = client.SRem(ctx, key, members...).Result()
|
_, err = client.SRem(ctx, key, members...).Result()
|
||||||
|
@ -1162,12 +1249,13 @@ func (c *connectionService) SetSetItem(connName string, db int, k any, remove bo
|
||||||
|
|
||||||
// UpdateSetItem replace member of set
|
// UpdateSetItem replace member of set
|
||||||
func (c *connectionService) UpdateSetItem(connName string, db int, k any, value, newValue string) (resp types.JSResp) {
|
func (c *connectionService) UpdateSetItem(connName string, db int, k any, value, newValue string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
_, _ = client.SRem(ctx, key, value).Result()
|
_, _ = client.SRem(ctx, key, value).Result()
|
||||||
_, err = client.SAdd(ctx, key, newValue).Result()
|
_, err = client.SAdd(ctx, key, newValue).Result()
|
||||||
|
@ -1182,12 +1270,13 @@ func (c *connectionService) UpdateSetItem(connName string, db int, k any, value,
|
||||||
|
|
||||||
// UpdateZSetValue update value of sorted set member
|
// UpdateZSetValue update value of sorted set member
|
||||||
func (c *connectionService) UpdateZSetValue(connName string, db int, k any, value, newValue string, score float64) (resp types.JSResp) {
|
func (c *connectionService) UpdateZSetValue(connName string, db int, k any, value, newValue string, score float64) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
updated := map[string]any{}
|
updated := map[string]any{}
|
||||||
var removed []string
|
var removed []string
|
||||||
|
@ -1233,12 +1322,13 @@ func (c *connectionService) UpdateZSetValue(connName string, db int, k any, valu
|
||||||
|
|
||||||
// AddZSetValue add item to sorted set
|
// AddZSetValue add item to sorted set
|
||||||
func (c *connectionService) AddZSetValue(connName string, db int, k any, action int, valueScore map[string]float64) (resp types.JSResp) {
|
func (c *connectionService) AddZSetValue(connName string, db int, k any, action int, valueScore map[string]float64) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
members := maputil.ToSlice(valueScore, func(k string) redis.Z {
|
members := maputil.ToSlice(valueScore, func(k string) redis.Z {
|
||||||
return redis.Z{
|
return redis.Z{
|
||||||
|
@ -1266,12 +1356,13 @@ func (c *connectionService) AddZSetValue(connName string, db int, k any, action
|
||||||
|
|
||||||
// AddStreamValue add stream field
|
// AddStreamValue add stream field
|
||||||
func (c *connectionService) AddStreamValue(connName string, db int, k any, ID string, fieldItems []any) (resp types.JSResp) {
|
func (c *connectionService) AddStreamValue(connName string, db int, k any, ID string, fieldItems []any) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
_, err = client.XAdd(ctx, &redis.XAddArgs{
|
_, err = client.XAdd(ctx, &redis.XAddArgs{
|
||||||
Stream: key,
|
Stream: key,
|
||||||
|
@ -1289,12 +1380,13 @@ func (c *connectionService) AddStreamValue(connName string, db int, k any, ID st
|
||||||
|
|
||||||
// RemoveStreamValues remove stream values by id
|
// RemoveStreamValues remove stream values by id
|
||||||
func (c *connectionService) RemoveStreamValues(connName string, db int, k any, IDs []string) (resp types.JSResp) {
|
func (c *connectionService) RemoveStreamValues(connName string, db int, k any, IDs []string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
_, err = client.XDel(ctx, key, IDs...).Result()
|
_, err = client.XDel(ctx, key, IDs...).Result()
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
|
@ -1303,12 +1395,13 @@ func (c *connectionService) RemoveStreamValues(connName string, db int, k any, I
|
||||||
|
|
||||||
// SetKeyTTL set ttl of key
|
// SetKeyTTL set ttl of key
|
||||||
func (c *connectionService) SetKeyTTL(connName string, db int, k any, ttl int64) (resp types.JSResp) {
|
func (c *connectionService) SetKeyTTL(connName string, db int, k any, ttl int64) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var expiration time.Duration
|
var expiration time.Duration
|
||||||
if ttl < 0 {
|
if ttl < 0 {
|
||||||
|
@ -1330,12 +1423,13 @@ func (c *connectionService) SetKeyTTL(connName string, db int, k any, ttl int64)
|
||||||
|
|
||||||
// DeleteKey remove redis key
|
// DeleteKey remove redis key
|
||||||
func (c *connectionService) DeleteKey(connName string, db int, k any, async bool) (resp types.JSResp) {
|
func (c *connectionService) DeleteKey(connName string, db int, k any, async bool) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var deletedKeys []string
|
var deletedKeys []string
|
||||||
if strings.HasSuffix(key, "*") {
|
if strings.HasSuffix(key, "*") {
|
||||||
|
@ -1360,7 +1454,8 @@ func (c *connectionService) DeleteKey(connName string, db int, k any, async bool
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
iter := cli.Scan(ctx, 0, key, 10000).Iterator()
|
scanSize := int64(Preferences().GetScanSize())
|
||||||
|
iter := cli.Scan(ctx, 0, key, scanSize).Iterator()
|
||||||
resultKeys := make([]string, 0, 100)
|
resultKeys := make([]string, 0, 100)
|
||||||
for iter.Next(ctx) {
|
for iter.Next(ctx) {
|
||||||
resultKeys = append(resultKeys, iter.Val())
|
resultKeys = append(resultKeys, iter.Val())
|
||||||
|
@ -1414,12 +1509,13 @@ func (c *connectionService) DeleteKey(connName string, db int, k any, async bool
|
||||||
|
|
||||||
// RenameKey rename key
|
// RenameKey rename key
|
||||||
func (c *connectionService) RenameKey(connName string, db int, key, newKey string) (resp types.JSResp) {
|
func (c *connectionService) RenameKey(connName string, db int, key, newKey string) (resp types.JSResp) {
|
||||||
client, ctx, err := c.getRedisClient(connName, db)
|
item, err := c.getRedisClient(connName, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client, ctx := item.client, item.ctx
|
||||||
if _, ok := client.(*redis.ClusterClient); ok {
|
if _, ok := client.(*redis.ClusterClient); ok {
|
||||||
resp.Msg = "RENAME not support in cluster mode yet"
|
resp.Msg = "RENAME not support in cluster mode yet"
|
||||||
return
|
return
|
||||||
|
|
|
@ -133,6 +133,15 @@ func (p *preferencesService) GetWindowSize() (width, height int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *preferencesService) GetScanSize() int {
|
||||||
|
data := p.pref.GetPreferences()
|
||||||
|
size := data.General.ScanSize
|
||||||
|
if size <= 0 {
|
||||||
|
size = consts.DEFAULT_SCAN_SIZE
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
type latestRelease struct {
|
type latestRelease struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
TagName string `json:"tag_name"`
|
TagName string `json:"tag_name"`
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"sync"
|
"sync"
|
||||||
|
"tinyrdm/backend/consts"
|
||||||
"tinyrdm/backend/types"
|
"tinyrdm/backend/types"
|
||||||
sliceutil "tinyrdm/backend/utils/slice"
|
sliceutil "tinyrdm/backend/utils/slice"
|
||||||
)
|
)
|
||||||
|
@ -36,6 +37,7 @@ func (c *ConnectionsStorage) defaultConnectionItem() types.ConnectionConfig {
|
||||||
ExecTimeout: 60,
|
ExecTimeout: 60,
|
||||||
DBFilterType: "none",
|
DBFilterType: "none",
|
||||||
DBFilterList: []int{},
|
DBFilterList: []int{},
|
||||||
|
LoadSize: consts.DEFAULT_LOAD_SIZE,
|
||||||
MarkColor: "",
|
MarkColor: "",
|
||||||
Sentinel: types.ConnectionSentinel{
|
Sentinel: types.ConnectionSentinel{
|
||||||
Master: "mymaster",
|
Master: "mymaster",
|
||||||
|
|
|
@ -46,6 +46,7 @@ func (p *PreferencesStorage) GetPreferences() (ret types.Preferences) {
|
||||||
defer p.mutex.Unlock()
|
defer p.mutex.Unlock()
|
||||||
|
|
||||||
ret = p.getPreferences()
|
ret = p.getPreferences()
|
||||||
|
ret.General.ScanSize = max(ret.General.ScanSize, consts.DEFAULT_SCAN_SIZE)
|
||||||
ret.Behavior.AsideWidth = max(ret.Behavior.AsideWidth, consts.DEFAULT_ASIDE_WIDTH)
|
ret.Behavior.AsideWidth = max(ret.Behavior.AsideWidth, consts.DEFAULT_ASIDE_WIDTH)
|
||||||
ret.Behavior.WindowWidth = max(ret.Behavior.WindowWidth, consts.MIN_WINDOW_WIDTH)
|
ret.Behavior.WindowWidth = max(ret.Behavior.WindowWidth, consts.MIN_WINDOW_WIDTH)
|
||||||
ret.Behavior.WindowHeight = max(ret.Behavior.WindowHeight, consts.MIN_WINDOW_HEIGHT)
|
ret.Behavior.WindowHeight = max(ret.Behavior.WindowHeight, consts.MIN_WINDOW_HEIGHT)
|
||||||
|
|
|
@ -15,6 +15,7 @@ type ConnectionConfig struct {
|
||||||
ExecTimeout int `json:"execTimeout,omitempty" yaml:"exec_timeout,omitempty"`
|
ExecTimeout int `json:"execTimeout,omitempty" yaml:"exec_timeout,omitempty"`
|
||||||
DBFilterType string `json:"dbFilterType" yaml:"db_filter_type,omitempty"`
|
DBFilterType string `json:"dbFilterType" yaml:"db_filter_type,omitempty"`
|
||||||
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
||||||
|
LoadSize int `json:"loadSize,omitempty" yaml:"load_size,omitempty"`
|
||||||
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
||||||
SSL ConnectionSSL `json:"ssl,omitempty" yaml:"ssl,omitempty"`
|
SSL ConnectionSSL `json:"ssl,omitempty" yaml:"ssl,omitempty"`
|
||||||
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
||||||
|
|
|
@ -19,6 +19,7 @@ func NewPreferences() Preferences {
|
||||||
Theme: "auto",
|
Theme: "auto",
|
||||||
Language: "auto",
|
Language: "auto",
|
||||||
FontSize: consts.DEFAULT_FONT_SIZE,
|
FontSize: consts.DEFAULT_FONT_SIZE,
|
||||||
|
ScanSize: consts.DEFAULT_SCAN_SIZE,
|
||||||
CheckUpdate: true,
|
CheckUpdate: true,
|
||||||
},
|
},
|
||||||
Editor: PreferencesEditor{
|
Editor: PreferencesEditor{
|
||||||
|
@ -38,6 +39,7 @@ type PreferencesGeneral struct {
|
||||||
Language string `json:"language" yaml:"language"`
|
Language string `json:"language" yaml:"language"`
|
||||||
Font string `json:"font" yaml:"font,omitempty"`
|
Font string `json:"font" yaml:"font,omitempty"`
|
||||||
FontSize int `json:"fontSize" yaml:"font_size"`
|
FontSize int `json:"fontSize" yaml:"font_size"`
|
||||||
|
ScanSize int `json:"scanSize" yaml:"scan_size"`
|
||||||
UseSysProxy bool `json:"useSysProxy" yaml:"use_sys_proxy,omitempty"`
|
UseSysProxy bool `json:"useSysProxy" yaml:"use_sys_proxy,omitempty"`
|
||||||
UseSysProxyHttp bool `json:"useSysProxyHttp" yaml:"use_sys_proxy_http,omitempty"`
|
UseSysProxyHttp bool `json:"useSysProxyHttp" yaml:"use_sys_proxy_http,omitempty"`
|
||||||
CheckUpdate bool `json:"checkUpdate" yaml:"check_update"`
|
CheckUpdate bool `json:"checkUpdate" yaml:"check_update"`
|
||||||
|
|
|
@ -370,6 +370,9 @@ const onClose = () => {
|
||||||
</template>
|
</template>
|
||||||
</n-input-number>
|
</n-input-number>
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
|
<n-form-item-gi :span="12" :label="$t('dialogue.connection.advn.load_size')">
|
||||||
|
<n-input-number v-model:value="generalForm.loadSize" :min="0" />
|
||||||
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_type')">
|
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_type')">
|
||||||
<n-radio-group
|
<n-radio-group
|
||||||
v-model:value="generalForm.dbFilterType"
|
v-model:value="generalForm.dbFilterType"
|
||||||
|
|
|
@ -74,11 +74,11 @@ const onClose = () => {
|
||||||
:show-require-mark="false"
|
:show-require-mark="false"
|
||||||
label-placement="top"
|
label-placement="top"
|
||||||
style="padding-right: 15px">
|
style="padding-right: 15px">
|
||||||
<n-form-item :label="$t('server')" path="key">
|
<n-form-item :label="$t('dialogue.key.server')" path="key">
|
||||||
<n-text>{{ filterForm.server }}</n-text>
|
<n-input :value="filterForm.server" readonly></n-input>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('dialogue.key.db_index')" path="db">
|
<n-form-item :label="$t('dialogue.key.db_index')" path="db">
|
||||||
<n-text>{{ filterForm.db }}</n-text>
|
<n-input :value="filterForm.db + ''" readonly></n-input>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('interface.type')" path="type" required>
|
<n-form-item :label="$t('interface.type')" path="type" required>
|
||||||
<n-select v-model:value="filterForm.type" :options="typeOptions" />
|
<n-select v-model:value="filterForm.type" :options="typeOptions" />
|
||||||
|
@ -87,7 +87,10 @@ const onClose = () => {
|
||||||
<n-input-group>
|
<n-input-group>
|
||||||
<n-tooltip trigger="focus">
|
<n-tooltip trigger="focus">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<n-input v-model:value="filterForm.pattern" clearable placeholder="Filter Pattern" />
|
<n-input
|
||||||
|
v-model:value="filterForm.pattern"
|
||||||
|
clearable
|
||||||
|
:placeholder="$t('dialogue.filter.filter_pattern')" />
|
||||||
</template>
|
</template>
|
||||||
<div class="text-block">{{ $t('dialogue.filter.filter_pattern_tip') }}</div>
|
<div class="text-block">{{ $t('dialogue.filter.filter_pattern_tip') }}</div>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
|
|
|
@ -60,32 +60,43 @@ const onClose = () => {
|
||||||
:show-icon="false"
|
:show-icon="false"
|
||||||
:title="$t('preferences.name')"
|
:title="$t('preferences.name')"
|
||||||
preset="dialog"
|
preset="dialog"
|
||||||
|
style="width: 500px"
|
||||||
transform-origin="center">
|
transform-origin="center">
|
||||||
<!-- FIXME: set loading will slow down appear animation of dialog in linux -->
|
<!-- FIXME: set loading will slow down appear animation of dialog in linux -->
|
||||||
<!-- <n-spin :show="loading"> -->
|
<!-- <n-spin :show="loading"> -->
|
||||||
<n-tabs v-model:value="tab" animated type="line">
|
<n-tabs v-model:value="tab" animated type="line">
|
||||||
<n-tab-pane :tab="$t('preferences.general.name')" display-directive="show" name="general">
|
<n-tab-pane :tab="$t('preferences.general.name')" display-directive="show" name="general">
|
||||||
<n-form :disabled="loading" :model="prefStore.general" :show-require-mark="false" label-placement="top">
|
<n-form :disabled="loading" :model="prefStore.general" :show-require-mark="false" label-placement="top">
|
||||||
<n-form-item :label="$t('preferences.general.theme')" required>
|
<n-grid :x-gap="10">
|
||||||
|
<n-form-item-gi :span="24" :label="$t('preferences.general.theme')" required>
|
||||||
<n-radio-group v-model:value="prefStore.general.theme" name="theme" size="medium">
|
<n-radio-group v-model:value="prefStore.general.theme" name="theme" size="medium">
|
||||||
<n-radio-button v-for="opt in prefStore.themeOption" :key="opt.value" :value="opt.value">
|
<n-radio-button
|
||||||
|
v-for="opt in prefStore.themeOption"
|
||||||
|
:key="opt.value"
|
||||||
|
:value="opt.value">
|
||||||
{{ opt.label }}
|
{{ opt.label }}
|
||||||
</n-radio-button>
|
</n-radio-button>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item-gi>
|
||||||
<n-form-item :label="$t('preferences.general.language')" required>
|
<n-form-item-gi :span="24" :label="$t('preferences.general.language')" required>
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="prefStore.general.language"
|
v-model:value="prefStore.general.language"
|
||||||
:options="prefStore.langOption"
|
:options="prefStore.langOption"
|
||||||
filterable />
|
filterable />
|
||||||
</n-form-item>
|
</n-form-item-gi>
|
||||||
<n-form-item :label="$t('preferences.general.font')" required>
|
<n-form-item-gi :span="12" :label="$t('preferences.general.font')" required>
|
||||||
<n-select v-model:value="prefStore.general.font" :options="prefStore.fontOption" filterable />
|
<n-select
|
||||||
</n-form-item>
|
v-model:value="prefStore.general.font"
|
||||||
<n-form-item :label="$t('preferences.general.font_size')">
|
:options="prefStore.fontOption"
|
||||||
|
filterable />
|
||||||
|
</n-form-item-gi>
|
||||||
|
<n-form-item-gi :span="12" :label="$t('preferences.general.font_size')">
|
||||||
<n-input-number v-model:value="prefStore.general.fontSize" :max="65535" :min="1" />
|
<n-input-number v-model:value="prefStore.general.fontSize" :max="65535" :min="1" />
|
||||||
</n-form-item>
|
</n-form-item-gi>
|
||||||
<n-form-item :label="$t('preferences.general.proxy')">
|
<n-form-item-gi :span="12" :label="$t('preferences.general.scan_size')">
|
||||||
|
<n-input-number v-model:value="prefStore.general.scanSize" :min="1" />
|
||||||
|
</n-form-item-gi>
|
||||||
|
<n-form-item-gi :span="24" :label="$t('preferences.general.proxy')">
|
||||||
<n-space>
|
<n-space>
|
||||||
<n-checkbox v-model:checked="prefStore.general.useSysProxy">
|
<n-checkbox v-model:checked="prefStore.general.useSysProxy">
|
||||||
{{ $t('preferences.general.use_system_proxy') }}
|
{{ $t('preferences.general.use_system_proxy') }}
|
||||||
|
@ -94,12 +105,13 @@ const onClose = () => {
|
||||||
{{ $t('preferences.general.use_system_proxy_http') }}
|
{{ $t('preferences.general.use_system_proxy_http') }}
|
||||||
</n-checkbox>
|
</n-checkbox>
|
||||||
</n-space>
|
</n-space>
|
||||||
</n-form-item>
|
</n-form-item-gi>
|
||||||
<n-form-item :label="$t('preferences.general.update')">
|
<n-form-item-gi :span="24" :label="$t('preferences.general.update')">
|
||||||
<n-checkbox v-model:checked="prefStore.general.checkUpdate">
|
<n-checkbox v-model:checked="prefStore.general.checkUpdate">
|
||||||
{{ $t('preferences.general.auto_check_update') }}
|
{{ $t('preferences.general.auto_check_update') }}
|
||||||
</n-checkbox>
|
</n-checkbox>
|
||||||
</n-form-item>
|
</n-form-item-gi>
|
||||||
|
</n-grid>
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
strokeWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M23.9999 29.0001L12 17.0001L19.9999 17.0001L19.9999 6.00011L27.9999 6.00011L27.9999 17.0001L35.9999 17.0001L23.9999 29.0001Z"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path d="M42 37L6 37" stroke="currentColor" :stroke-width="props.strokeWidth" stroke-linecap="round" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
strokeWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M8 28H24"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path
|
||||||
|
d="M8 37H24"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path
|
||||||
|
d="M8 19H40"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path
|
||||||
|
d="M8 10H40"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path
|
||||||
|
d="M37 40V28"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<path
|
||||||
|
d="M33 36L37 40L41 36"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="props.strokeWidth"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
strokeWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
d="M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
:stroke-width="strokeWidth"
|
||||||
|
stroke-linejoin="round" />
|
||||||
|
<circle cx="14" cy="24" r="3" fill="currentColor" />
|
||||||
|
<circle cx="24" cy="24" r="3" fill="currentColor" />
|
||||||
|
<circle cx="34" cy="24" r="3" fill="currentColor" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -23,6 +23,8 @@ import { typesBgColor, typesColor } from '@/consts/support_redis_type.js'
|
||||||
import useTabStore from 'stores/tab.js'
|
import useTabStore from 'stores/tab.js'
|
||||||
import IconButton from '@/components/common/IconButton.vue'
|
import IconButton from '@/components/common/IconButton.vue'
|
||||||
import { parseHexColor } from '@/utils/rgb.js'
|
import { parseHexColor } from '@/utils/rgb.js'
|
||||||
|
import LoadList from '@/components/icons/LoadList.vue'
|
||||||
|
import LoadAll from '@/components/icons/LoadAll.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
server: String,
|
server: String,
|
||||||
|
@ -146,11 +148,11 @@ const menuOptions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ConnectionType.RedisKey]: () => [
|
[ConnectionType.RedisKey]: () => [
|
||||||
{
|
// {
|
||||||
key: 'key_reload',
|
// key: 'key_reload',
|
||||||
label: i18n.t('interface.reload'),
|
// label: i18n.t('interface.reload'),
|
||||||
icon: renderIcon(Refresh),
|
// icon: renderIcon(Refresh),
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
key: 'key_newkey',
|
key: 'key_newkey',
|
||||||
label: i18n.t('interface.new_key'),
|
label: i18n.t('interface.new_key'),
|
||||||
|
@ -259,9 +261,9 @@ const handleSelectContextMenu = (key) => {
|
||||||
const { match: pattern, type } = connectionStore.getKeyFilter(props.server, db)
|
const { match: pattern, type } = connectionStore.getKeyFilter(props.server, db)
|
||||||
dialogStore.openKeyFilterDialog(props.server, db, pattern, type)
|
dialogStore.openKeyFilterDialog(props.server, db, pattern, type)
|
||||||
break
|
break
|
||||||
case 'key_reload':
|
// case 'key_reload':
|
||||||
connectionStore.loadKeys(props.server, db, redisKey)
|
// connectionStore.loadKeys(props.server, db, redisKey)
|
||||||
break
|
// break
|
||||||
case 'value_reload':
|
case 'value_reload':
|
||||||
connectionStore.loadKeyValue(props.server, db, redisKey)
|
connectionStore.loadKeyValue(props.server, db, redisKey)
|
||||||
break
|
break
|
||||||
|
@ -289,6 +291,38 @@ const handleSelectContextMenu = (key) => {
|
||||||
$message.error(e.message)
|
$message.error(e.message)
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
case 'db_loadmore':
|
||||||
|
if (node != null && !!!node.loading && !!!node.fullLoaded) {
|
||||||
|
node.loading = true
|
||||||
|
connectionStore
|
||||||
|
.loadMoreKeys(props.server, db)
|
||||||
|
.then((end) => {
|
||||||
|
// fully loaded
|
||||||
|
node.fullLoaded = end === true
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
$message.error(e.message)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
delete node.loading
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'db_loadall':
|
||||||
|
if (node != null && !!!node.loading) {
|
||||||
|
node.loading = true
|
||||||
|
connectionStore
|
||||||
|
.loadAllKeys(props.server, db)
|
||||||
|
.catch((e) => {
|
||||||
|
$message.error(e.message)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
delete node.loading
|
||||||
|
node.fullLoaded = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'more_action':
|
||||||
default:
|
default:
|
||||||
console.warn('TODO: handle context menu:' + key)
|
console.warn('TODO: handle context menu:' + key)
|
||||||
}
|
}
|
||||||
|
@ -389,9 +423,14 @@ const renderLabel = ({ option }) => {
|
||||||
case ConnectionType.Server:
|
case ConnectionType.Server:
|
||||||
return h('b', {}, { default: () => option.label })
|
return h('b', {}, { default: () => option.label })
|
||||||
case ConnectionType.RedisDB:
|
case ConnectionType.RedisDB:
|
||||||
const { name: server, db } = option
|
const { name: server, db, opened = false } = option
|
||||||
let { match: matchPattern, type: typeFilter } = connectionStore.getKeyFilter(server, db)
|
let { match: matchPattern, type: typeFilter } = connectionStore.getKeyFilter(server, db)
|
||||||
const items = [`${option.label} (${option.keys || 0})`]
|
const items = []
|
||||||
|
if (opened) {
|
||||||
|
items.push(`${option.label} (${option.keys || 0}/${Math.max(option.maxKeys || 0, option.keys || 0)})`)
|
||||||
|
} else {
|
||||||
|
items.push(`${option.label} (${Math.max(option.maxKeys || 0, option.keys || 0)})`)
|
||||||
|
}
|
||||||
// show filter tag after label
|
// show filter tag after label
|
||||||
// type filter tag
|
// type filter tag
|
||||||
if (!isEmpty(typeFilter)) {
|
if (!isEmpty(typeFilter)) {
|
||||||
|
@ -460,30 +499,53 @@ const renderIconMenu = (items) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDatabaseMenu = (opened) => {
|
const getDatabaseMenu = (opened, loading, end) => {
|
||||||
const btns = []
|
const btns = []
|
||||||
if (opened) {
|
if (opened) {
|
||||||
btns.push(
|
btns.push(
|
||||||
h(IconButton, {
|
h(IconButton, {
|
||||||
tTooltip: 'interface.filter_key',
|
tTooltip: 'interface.filter_key',
|
||||||
icon: Filter,
|
icon: Filter,
|
||||||
|
disabled: loading === true,
|
||||||
onClick: () => handleSelectContextMenu('db_filter'),
|
onClick: () => handleSelectContextMenu('db_filter'),
|
||||||
}),
|
}),
|
||||||
h(IconButton, {
|
h(IconButton, {
|
||||||
tTooltip: 'interface.reload',
|
tTooltip: 'interface.reload',
|
||||||
icon: Refresh,
|
icon: Refresh,
|
||||||
|
disabled: loading === true,
|
||||||
onClick: () => handleSelectContextMenu('db_reload'),
|
onClick: () => handleSelectContextMenu('db_reload'),
|
||||||
}),
|
}),
|
||||||
h(IconButton, {
|
h(IconButton, {
|
||||||
tTooltip: 'interface.new_key',
|
tTooltip: 'interface.new_key',
|
||||||
icon: Add,
|
icon: Add,
|
||||||
|
disabled: loading === true,
|
||||||
onClick: () => handleSelectContextMenu('db_newkey'),
|
onClick: () => handleSelectContextMenu('db_newkey'),
|
||||||
}),
|
}),
|
||||||
|
h(IconButton, {
|
||||||
|
tTooltip: 'interface.load_more',
|
||||||
|
icon: LoadList,
|
||||||
|
disabled: end === true,
|
||||||
|
loading: loading === true,
|
||||||
|
onClick: () => handleSelectContextMenu('db_loadmore'),
|
||||||
|
}),
|
||||||
|
h(IconButton, {
|
||||||
|
tTooltip: 'interface.load_all',
|
||||||
|
icon: LoadAll,
|
||||||
|
disabled: end === true,
|
||||||
|
loading: loading === true,
|
||||||
|
onClick: () => handleSelectContextMenu('db_loadall'),
|
||||||
|
}),
|
||||||
h(IconButton, {
|
h(IconButton, {
|
||||||
tTooltip: 'interface.batch_delete',
|
tTooltip: 'interface.batch_delete',
|
||||||
icon: Delete,
|
icon: Delete,
|
||||||
|
disabled: loading === true,
|
||||||
onClick: () => handleSelectContextMenu('key_remove'),
|
onClick: () => handleSelectContextMenu('key_remove'),
|
||||||
}),
|
}),
|
||||||
|
// h(IconButton, {
|
||||||
|
// tTooltip: 'interface.more_action',
|
||||||
|
// icon: More,
|
||||||
|
// onClick: () => handleSelectContextMenu('more_action'),
|
||||||
|
// }),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
btns.push(
|
btns.push(
|
||||||
|
@ -499,11 +561,12 @@ const getDatabaseMenu = (opened) => {
|
||||||
|
|
||||||
const getLayerMenu = () => {
|
const getLayerMenu = () => {
|
||||||
return [
|
return [
|
||||||
h(IconButton, {
|
// disable reload by layer, due to conflict with partial loading keys
|
||||||
tTooltip: 'interface.reload',
|
// h(IconButton, {
|
||||||
icon: Refresh,
|
// tTooltip: 'interface.reload',
|
||||||
onClick: () => handleSelectContextMenu('key_reload'),
|
// icon: Refresh,
|
||||||
}),
|
// onClick: () => handleSelectContextMenu('key_reload'),
|
||||||
|
// }),
|
||||||
h(IconButton, {
|
h(IconButton, {
|
||||||
tTooltip: 'interface.new_key',
|
tTooltip: 'interface.new_key',
|
||||||
icon: Add,
|
icon: Add,
|
||||||
|
@ -532,7 +595,7 @@ const renderSuffix = ({ option }) => {
|
||||||
if ((option.type === ConnectionType.RedisDB && option.opened) || includes(selectedKeys.value, option.key)) {
|
if ((option.type === ConnectionType.RedisDB && option.opened) || includes(selectedKeys.value, option.key)) {
|
||||||
switch (option.type) {
|
switch (option.type) {
|
||||||
case ConnectionType.RedisDB:
|
case ConnectionType.RedisDB:
|
||||||
return renderIconMenu(getDatabaseMenu(option.opened))
|
return renderIconMenu(getDatabaseMenu(option.opened, option.loading, option.fullLoaded))
|
||||||
case ConnectionType.RedisKey:
|
case ConnectionType.RedisKey:
|
||||||
return renderIconMenu(getLayerMenu())
|
return renderIconMenu(getLayerMenu())
|
||||||
case ConnectionType.RedisValue:
|
case ConnectionType.RedisValue:
|
||||||
|
|
|
@ -10,7 +10,6 @@ import useDialogStore from 'stores/dialog.js'
|
||||||
import Github from '@/components/icons/Github.vue'
|
import Github from '@/components/icons/Github.vue'
|
||||||
import { BrowserOpenURL } from 'wailsjs/runtime/runtime.js'
|
import { BrowserOpenURL } from 'wailsjs/runtime/runtime.js'
|
||||||
import useConnectionStore from 'stores/connections.js'
|
import useConnectionStore from 'stores/connections.js'
|
||||||
import Help from '@/components/icons/Help.vue'
|
|
||||||
import usePreferencesStore from 'stores/preferences.js'
|
import usePreferencesStore from 'stores/preferences.js'
|
||||||
import Record from '@/components/icons/Record.vue'
|
import Record from '@/components/icons/Record.vue'
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"default": "Default",
|
"default": "Default",
|
||||||
"font": "Font",
|
"font": "Font",
|
||||||
"font_size": "Font Size",
|
"font_size": "Font Size",
|
||||||
|
"scan_size": "Default Size for SCAN Command",
|
||||||
"proxy": "Proxy",
|
"proxy": "Proxy",
|
||||||
"use_system_proxy": "Use system proxy",
|
"use_system_proxy": "Use system proxy",
|
||||||
"use_system_proxy_http": "Use system proxy only for HTTP(S) request",
|
"use_system_proxy_http": "Use system proxy only for HTTP(S) request",
|
||||||
|
@ -82,7 +83,10 @@
|
||||||
"copy_key": "Copy Key",
|
"copy_key": "Copy Key",
|
||||||
"binary_key": "Binary Key Name",
|
"binary_key": "Binary Key Name",
|
||||||
"remove_key": "Remove Key",
|
"remove_key": "Remove Key",
|
||||||
"new_key": "Add New Key",
|
"new_key": "Add Key",
|
||||||
|
"load_more": "Load More Keys",
|
||||||
|
"load_all": "Load All Keys",
|
||||||
|
"more_action": "More Action",
|
||||||
"nonexist_tab_content": "Selected key does not exist. Please retry",
|
"nonexist_tab_content": "Selected key does not exist. Please retry",
|
||||||
"empty_server_content": "Select and open a connection from the left",
|
"empty_server_content": "Select and open a connection from the left",
|
||||||
"empty_server_list": "No redis server",
|
"empty_server_list": "No redis server",
|
||||||
|
@ -145,6 +149,7 @@
|
||||||
"dbfilter_hide_title": "Select the Databases to Hide",
|
"dbfilter_hide_title": "Select the Databases to Hide",
|
||||||
"dbfilter_input": "Input Database Index",
|
"dbfilter_input": "Input Database Index",
|
||||||
"dbfilter_input_tip": "Press Enter to confirm",
|
"dbfilter_input_tip": "Press Enter to confirm",
|
||||||
|
"load_size": "Size of Keys Per Load",
|
||||||
"mark_color": "Mark Color"
|
"mark_color": "Mark Color"
|
||||||
},
|
},
|
||||||
"ssl": {
|
"ssl": {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"default": "默认",
|
"default": "默认",
|
||||||
"font": "字体",
|
"font": "字体",
|
||||||
"font_size": "字体尺寸",
|
"font_size": "字体尺寸",
|
||||||
|
"scan_size": "SCAN命令默认数量",
|
||||||
"proxy": "代理",
|
"proxy": "代理",
|
||||||
"use_system_proxy": "使用系统代理",
|
"use_system_proxy": "使用系统代理",
|
||||||
"use_system_proxy_http": "仅在HTTP请求时使用系统代理",
|
"use_system_proxy_http": "仅在HTTP请求时使用系统代理",
|
||||||
|
@ -83,6 +84,9 @@
|
||||||
"binary_key": "二进制键名",
|
"binary_key": "二进制键名",
|
||||||
"remove_key": "删除键",
|
"remove_key": "删除键",
|
||||||
"new_key": "添加新键",
|
"new_key": "添加新键",
|
||||||
|
"load_more": "加载更多键",
|
||||||
|
"load_all": "加载所有键",
|
||||||
|
"more_action": "更多操作",
|
||||||
"nonexist_tab_content": "所选键不存在,请尝试刷新重试",
|
"nonexist_tab_content": "所选键不存在,请尝试刷新重试",
|
||||||
"empty_server_content": "可以从左边选择并打开连接",
|
"empty_server_content": "可以从左边选择并打开连接",
|
||||||
"empty_server_list": "还没添加Redis服务器",
|
"empty_server_list": "还没添加Redis服务器",
|
||||||
|
@ -145,6 +149,7 @@
|
||||||
"dbfilter_hide_title": "需要隐藏的数据库",
|
"dbfilter_hide_title": "需要隐藏的数据库",
|
||||||
"dbfilter_input": "输入数据库索引",
|
"dbfilter_input": "输入数据库索引",
|
||||||
"dbfilter_input_tip": "按回车确认",
|
"dbfilter_input_tip": "按回车确认",
|
||||||
|
"load_size": "单次加载键数量",
|
||||||
"mark_color": "标记颜色"
|
"mark_color": "标记颜色"
|
||||||
},
|
},
|
||||||
"ssl": {
|
"ssl": {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
get,
|
get,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
join,
|
join,
|
||||||
map,
|
|
||||||
remove,
|
remove,
|
||||||
size,
|
size,
|
||||||
slice,
|
slice,
|
||||||
|
@ -30,6 +29,8 @@ import {
|
||||||
GetConnection,
|
GetConnection,
|
||||||
GetKeyValue,
|
GetKeyValue,
|
||||||
ListConnection,
|
ListConnection,
|
||||||
|
LoadAllKeys,
|
||||||
|
LoadNextKeys,
|
||||||
OpenConnection,
|
OpenConnection,
|
||||||
OpenDatabase,
|
OpenDatabase,
|
||||||
RemoveStreamValues,
|
RemoveStreamValues,
|
||||||
|
@ -37,7 +38,6 @@ import {
|
||||||
RenameKey,
|
RenameKey,
|
||||||
SaveConnection,
|
SaveConnection,
|
||||||
SaveSortedConnection,
|
SaveSortedConnection,
|
||||||
ScanKeys,
|
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
SetHashValue,
|
SetHashValue,
|
||||||
SetKeyTTL,
|
SetKeyTTL,
|
||||||
|
@ -77,6 +77,8 @@ const useConnectionStore = defineStore('connections', {
|
||||||
* @property {boolean} [opened] - redis db is opened, type == ConnectionType.RedisDB only
|
* @property {boolean} [opened] - redis db is opened, type == ConnectionType.RedisDB only
|
||||||
* @property {boolean} [expanded] - current node is expanded
|
* @property {boolean} [expanded] - current node is expanded
|
||||||
* @property {DatabaseItem[]} [children]
|
* @property {DatabaseItem[]} [children]
|
||||||
|
* @property {boolean} [loading] - indicated that is loading children now
|
||||||
|
* @property {boolean} [fullLoaded] - indicated that all children already loaded
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,6 +232,7 @@ const useConnectionStore = defineStore('connections', {
|
||||||
execTimeout: 60,
|
execTimeout: 60,
|
||||||
dbFilterType: 'none',
|
dbFilterType: 'none',
|
||||||
dbFilterList: [],
|
dbFilterList: [],
|
||||||
|
loadSize: 10000,
|
||||||
markColor: '',
|
markColor: '',
|
||||||
ssl: {
|
ssl: {
|
||||||
enable: false,
|
enable: false,
|
||||||
|
@ -407,7 +410,8 @@ const useConnectionStore = defineStore('connections', {
|
||||||
key: `${name}/${db[i].name}`,
|
key: `${name}/${db[i].name}`,
|
||||||
label: db[i].name,
|
label: db[i].name,
|
||||||
name: name,
|
name: name,
|
||||||
keys: db[i].keys,
|
keys: 0,
|
||||||
|
maxKeys: db[i].keys,
|
||||||
db: db[i].index,
|
db: db[i].index,
|
||||||
type: ConnectionType.RedisDB,
|
type: ConnectionType.RedisDB,
|
||||||
isLeaf: false,
|
isLeaf: false,
|
||||||
|
@ -535,13 +539,14 @@ const useConnectionStore = defineStore('connections', {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(msg)
|
throw new Error(msg)
|
||||||
}
|
}
|
||||||
const { keys = [] } = data
|
const { keys = [], end = false } = data
|
||||||
const selDB = this.getDatabase(connName, db)
|
const selDB = this.getDatabase(connName, db)
|
||||||
if (selDB == null) {
|
if (selDB == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selDB.opened = true
|
selDB.opened = true
|
||||||
|
selDB.fullLoaded = end
|
||||||
if (isEmpty(keys)) {
|
if (isEmpty(keys)) {
|
||||||
selDB.children = []
|
selDB.children = []
|
||||||
} else {
|
} else {
|
||||||
|
@ -658,44 +663,77 @@ const useConnectionStore = defineStore('connections', {
|
||||||
* scan keys with prefix
|
* scan keys with prefix
|
||||||
* @param {string} connName
|
* @param {string} connName
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string} [prefix] full reload database if prefix is null
|
* @param {string} match
|
||||||
* @returns {Promise<{keys: string[]}>}
|
* @param {string} matchType
|
||||||
|
* @param {boolean} [full]
|
||||||
|
* @returns {Promise<{keys: string[], end: boolean}>}
|
||||||
*/
|
*/
|
||||||
async scanKeys(connName, db, prefix) {
|
async scanKeys(connName, db, match, matchType, full) {
|
||||||
const { data, success, msg } = await ScanKeys(connName, db, prefix || '*')
|
let resp
|
||||||
|
if (full) {
|
||||||
|
resp = await LoadAllKeys(connName, db, match || '*', matchType)
|
||||||
|
} else {
|
||||||
|
resp = await LoadNextKeys(connName, db, match || '*', matchType)
|
||||||
|
}
|
||||||
|
const { data, success, msg } = resp || {}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(msg)
|
throw new Error(msg)
|
||||||
}
|
}
|
||||||
const { keys = [] } = data
|
const { keys = [], end } = data
|
||||||
return { keys, success }
|
return { keys, end, success }
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load keys with prefix
|
*
|
||||||
* @param {string} connName
|
* @param {string} connName
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string} [prefix]
|
* @param {string|null} prefix
|
||||||
* @returns {Promise<void>}
|
* @param {string|null} matchType
|
||||||
|
* @param {boolean} [all]
|
||||||
|
* @return {Promise<{keys: Array<string|number[]>, end: boolean}>}
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
async loadKeys(connName, db, prefix) {
|
async _loadKeys(connName, db, prefix, matchType, all) {
|
||||||
let scanPrefix = prefix
|
let match = prefix
|
||||||
if (isEmpty(scanPrefix)) {
|
if (isEmpty(match)) {
|
||||||
scanPrefix = '*'
|
match = '*'
|
||||||
} else {
|
} else {
|
||||||
const separator = this._getSeparator(connName)
|
const separator = this._getSeparator(connName)
|
||||||
if (!endsWith(prefix, separator + '*')) {
|
if (!endsWith(prefix, separator + '*')) {
|
||||||
scanPrefix = prefix + separator + '*'
|
match = prefix + separator + '*'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { keys, success } = await this.scanKeys(connName, db, scanPrefix)
|
return this.scanKeys(connName, db, match, matchType, all)
|
||||||
if (!success) {
|
},
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load more keys within the database
|
||||||
|
* @param {string} connName
|
||||||
|
* @param {number} db
|
||||||
|
* @return {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
async loadMoreKeys(connName, db) {
|
||||||
|
const { match, type: keyType } = this.getKeyFilter(connName, db)
|
||||||
|
const { keys, end } = await this._loadKeys(connName, db, match, keyType, false)
|
||||||
// remove current keys below prefix
|
// remove current keys below prefix
|
||||||
this._deleteKeyNode(connName, db, prefix, true)
|
|
||||||
this._addKeyNodes(connName, db, keys)
|
this._addKeyNodes(connName, db, keys)
|
||||||
this._tidyNode(connName, db, prefix)
|
this._tidyNode(connName, db, '')
|
||||||
|
return end
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load all left keys within the database
|
||||||
|
* @param {string} connName
|
||||||
|
* @param {number} db
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
async loadAllKeys(connName, db) {
|
||||||
|
const { match, type: keyType } = this.getKeyFilter(connName, db)
|
||||||
|
const { keys } = await this._loadKeys(connName, db, match, keyType, true)
|
||||||
|
// remove current keys below prefix
|
||||||
|
this._deleteKeyNode(connName, db, '', true)
|
||||||
|
this._addKeyNodes(connName, db, keys)
|
||||||
|
this._tidyNode(connName, db, '')
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,6 +42,7 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
language: 'auto',
|
language: 'auto',
|
||||||
font: '',
|
font: '',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
scanSize: 3000,
|
||||||
useSysProxy: false,
|
useSysProxy: false,
|
||||||
useSysProxyHttp: false,
|
useSysProxyHttp: false,
|
||||||
checkUpdate: false,
|
checkUpdate: false,
|
||||||
|
|
Loading…
Reference in New Issue