Compare commits
7 Commits
45e9c49f26
...
aafa0c5432
Author | SHA1 | Date |
---|---|---|
Lykin | aafa0c5432 | |
Lykin | 2a57248228 | |
Lykin | 13f343977a | |
Lykin | ddc3868f22 | |
Lykin | 4db3909c6a | |
Lykin | 80e659e03a | |
Lykin | d88fd35e9d |
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,7 +17,6 @@ import (
|
||||||
"tinyrdm/backend/consts"
|
"tinyrdm/backend/consts"
|
||||||
"tinyrdm/backend/types"
|
"tinyrdm/backend/types"
|
||||||
"tinyrdm/backend/utils/coll"
|
"tinyrdm/backend/utils/coll"
|
||||||
maputil "tinyrdm/backend/utils/map"
|
|
||||||
redis2 "tinyrdm/backend/utils/redis"
|
redis2 "tinyrdm/backend/utils/redis"
|
||||||
sliceutil "tinyrdm/backend/utils/slice"
|
sliceutil "tinyrdm/backend/utils/slice"
|
||||||
strutil "tinyrdm/backend/utils/string"
|
strutil "tinyrdm/backend/utils/string"
|
||||||
|
@ -1081,7 +1081,7 @@ func (b *browserService) SetKeyValue(param types.SetKeyParam) (resp types.JSResp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHashValue set hash field
|
// SetHashValue update hash field
|
||||||
func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSResp) {
|
func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSResp) {
|
||||||
item, err := b.getRedisClient(param.Server, param.DB)
|
item, err := b.getRedisClient(param.Server, param.DB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1092,36 +1092,67 @@ func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSRe
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(param.Key)
|
key := strutil.DecodeRedisKey(param.Key)
|
||||||
str := strutil.DecodeRedisKey(param.Value)
|
str := strutil.DecodeRedisKey(param.Value)
|
||||||
var saveStr string
|
var saveStr, displayStr string
|
||||||
if saveStr, err = strutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
if saveStr, err = strutil.SaveAs(str, param.Format, param.Decode); err != nil {
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var removedField []string
|
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
||||||
updatedField := map[string]any{}
|
displayStr, _, _ = strutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
||||||
replacedField := map[string]any{}
|
}
|
||||||
if len(param.Field) <= 0 {
|
var updated, added, removed []types.HashEntryItem
|
||||||
// old filed is empty, add new field
|
var replaced []types.HashReplaceItem
|
||||||
_, err = client.HSet(ctx, key, param.NewField, saveStr).Result()
|
var affect int64
|
||||||
updatedField[param.NewField] = saveStr
|
if len(param.NewField) <= 0 {
|
||||||
} else if len(param.NewField) <= 0 {
|
|
||||||
// new field is empty, delete old field
|
// new field is empty, delete old field
|
||||||
_, err = client.HDel(ctx, key, param.Field).Result()
|
_, err = client.HDel(ctx, key, param.Field).Result()
|
||||||
removedField = append(removedField, param.Field)
|
removed = append(removed, types.HashEntryItem{
|
||||||
} else if param.Field == param.NewField {
|
Key: param.Field,
|
||||||
|
})
|
||||||
|
} else if len(param.Field) <= 0 || param.Field == param.NewField {
|
||||||
|
affect, err = client.HSet(ctx, key, param.NewField, saveStr).Result()
|
||||||
|
if affect <= 0 {
|
||||||
// update field value
|
// update field value
|
||||||
_, err = client.HSet(ctx, key, param.Field, saveStr).Result()
|
updated = append(updated, types.HashEntryItem{
|
||||||
updatedField[param.NewField] = saveStr
|
Key: param.NewField,
|
||||||
|
Value: saveStr,
|
||||||
|
DisplayValue: displayStr,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// add new field
|
||||||
|
added = append(added, types.HashEntryItem{
|
||||||
|
Key: param.NewField,
|
||||||
|
Value: saveStr,
|
||||||
|
DisplayValue: displayStr,
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// remove old field and add new field
|
// remove old field and add new field
|
||||||
if _, err = client.HDel(ctx, key, param.Field).Result(); err != nil {
|
if _, err = client.HDel(ctx, key, param.Field).Result(); err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = client.HSet(ctx, key, param.NewField, saveStr).Result()
|
|
||||||
removedField = append(removedField, param.Field)
|
affect, err = client.HSet(ctx, key, param.NewField, saveStr).Result()
|
||||||
updatedField[param.NewField] = saveStr
|
if affect <= 0 {
|
||||||
replacedField[param.Field] = param.NewField
|
// no new filed added, just update exists item
|
||||||
|
removed = append(removed, types.HashEntryItem{
|
||||||
|
Key: param.Field,
|
||||||
|
})
|
||||||
|
updated = append(updated, types.HashEntryItem{
|
||||||
|
Key: param.NewField,
|
||||||
|
Value: saveStr,
|
||||||
|
DisplayValue: displayStr,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// add new field
|
||||||
|
replaced = append(replaced, types.HashReplaceItem{
|
||||||
|
Key: param.Field,
|
||||||
|
NewKey: param.NewField,
|
||||||
|
Value: saveStr,
|
||||||
|
DisplayValue: displayStr,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
|
@ -1129,10 +1160,16 @@ func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSRe
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"removed": removedField,
|
Added []types.HashEntryItem `json:"added,omitempty"`
|
||||||
"updated": updatedField,
|
Removed []types.HashEntryItem `json:"removed,omitempty"`
|
||||||
"replaced": replacedField,
|
Updated []types.HashEntryItem `json:"updated,omitempty"`
|
||||||
|
Replaced []types.HashReplaceItem `json:"replaced,omitempty"`
|
||||||
|
}{
|
||||||
|
Added: added,
|
||||||
|
Removed: removed,
|
||||||
|
Updated: updated,
|
||||||
|
Replaced: replaced,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1147,28 +1184,40 @@ func (b *browserService) AddHashField(connName string, db int, k any, action int
|
||||||
|
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
updated := map[string]any{}
|
var updated []types.HashEntryItem
|
||||||
|
var added []types.HashEntryItem
|
||||||
switch action {
|
switch action {
|
||||||
case 1:
|
case 1:
|
||||||
// ignore duplicated fields
|
// ignore duplicated fields
|
||||||
for i := 0; i < len(fieldItems); i += 2 {
|
for i := 0; i < len(fieldItems); i += 2 {
|
||||||
_, err = client.HSetNX(ctx, key, fieldItems[i].(string), fieldItems[i+1]).Result()
|
field, value := strutil.DecodeRedisKey(fieldItems[i]), strutil.DecodeRedisKey(fieldItems[i+1])
|
||||||
if err == nil {
|
if succ, _ := client.HSetNX(ctx, key, field, value).Result(); succ {
|
||||||
updated[fieldItems[i].(string)] = fieldItems[i+1]
|
added = append(added, types.HashEntryItem{
|
||||||
|
Key: field,
|
||||||
|
Value: value,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// overwrite duplicated fields
|
// overwrite duplicated fields
|
||||||
total := len(fieldItems)
|
total := len(fieldItems)
|
||||||
if total > 1 {
|
if total > 1 {
|
||||||
_, err = client.Pipelined(ctx, func(pipe redis.Pipeliner) error {
|
|
||||||
for i := 0; i < total; i += 2 {
|
for i := 0; i < total; i += 2 {
|
||||||
client.HSet(ctx, key, fieldItems[i], fieldItems[i+1])
|
field, value := strutil.DecodeRedisKey(fieldItems[i]), strutil.DecodeRedisKey(fieldItems[i+1])
|
||||||
}
|
if affect, _ := client.HSet(ctx, key, field, value).Result(); affect > 0 {
|
||||||
return nil
|
added = append(added, types.HashEntryItem{
|
||||||
|
Key: field,
|
||||||
|
Value: value,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
})
|
})
|
||||||
for i := 0; i < total; i += 2 {
|
} else {
|
||||||
updated[fieldItems[i].(string)] = fieldItems[i+1]
|
updated = append(updated, types.HashEntryItem{
|
||||||
|
Key: field,
|
||||||
|
Value: value,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1178,8 +1227,12 @@ func (b *browserService) AddHashField(connName string, db int, k any, action int
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"updated": updated,
|
Added []types.HashEntryItem `json:"added,omitempty"`
|
||||||
|
Updated []types.HashEntryItem `json:"updated,omitempty"`
|
||||||
|
}{
|
||||||
|
Added: added,
|
||||||
|
Updated: updated,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1194,16 +1247,27 @@ func (b *browserService) AddListItem(connName string, db int, k any, action int,
|
||||||
|
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
var leftPush, rightPush []any
|
var leftPush, rightPush []types.ListEntryItem
|
||||||
switch action {
|
switch action {
|
||||||
case 0:
|
case 0:
|
||||||
// push to head
|
// push to head
|
||||||
|
slices.Reverse(items)
|
||||||
_, err = client.LPush(ctx, key, items...).Result()
|
_, err = client.LPush(ctx, key, items...).Result()
|
||||||
leftPush = append(leftPush, items...)
|
for i := len(items) - 1; i >= 0; i-- {
|
||||||
|
leftPush = append(leftPush, types.ListEntryItem{
|
||||||
|
Value: items[i],
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// append to tail
|
// append to tail
|
||||||
_, err = client.RPush(ctx, key, items...).Result()
|
_, err = client.RPush(ctx, key, items...).Result()
|
||||||
rightPush = append(rightPush, items...)
|
for _, it := range items {
|
||||||
|
rightPush = append(rightPush, types.ListEntryItem{
|
||||||
|
Value: it,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
|
@ -1211,9 +1275,12 @@ func (b *browserService) AddListItem(connName string, db int, k any, action int,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"left": leftPush,
|
Left []types.ListEntryItem `json:"left,omitempty"`
|
||||||
"right": rightPush,
|
Right []types.ListEntryItem `json:"right,omitempty"`
|
||||||
|
}{
|
||||||
|
Left: leftPush,
|
||||||
|
Right: rightPush,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1229,8 +1296,7 @@ func (b *browserService) SetListItem(param types.SetListParam) (resp types.JSRes
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(param.Key)
|
key := strutil.DecodeRedisKey(param.Key)
|
||||||
str := strutil.DecodeRedisKey(param.Value)
|
str := strutil.DecodeRedisKey(param.Value)
|
||||||
var removed []int64
|
var replaced, removed []types.ListReplaceItem
|
||||||
updated := map[int64]string{}
|
|
||||||
if len(str) <= 0 {
|
if len(str) <= 0 {
|
||||||
// remove from list
|
// remove from list
|
||||||
err = client.LSet(ctx, key, param.Index, "---VALUE_REMOVED_BY_TINY_RDM---").Err()
|
err = client.LSet(ctx, key, param.Index, "---VALUE_REMOVED_BY_TINY_RDM---").Err()
|
||||||
|
@ -1244,7 +1310,9 @@ func (b *browserService) SetListItem(param types.SetListParam) (resp types.JSRes
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
removed = append(removed, param.Index)
|
removed = append(removed, types.ListReplaceItem{
|
||||||
|
Index: param.Index,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// replace index value
|
// replace index value
|
||||||
var saveStr string
|
var saveStr string
|
||||||
|
@ -1257,13 +1325,24 @@ func (b *browserService) SetListItem(param types.SetListParam) (resp types.JSRes
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
updated[param.Index] = saveStr
|
var displayStr string
|
||||||
|
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
||||||
|
displayStr, _, _ = strutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
||||||
|
}
|
||||||
|
replaced = append(replaced, types.ListReplaceItem{
|
||||||
|
Index: param.Index,
|
||||||
|
Value: saveStr,
|
||||||
|
DisplayValue: displayStr,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"removed": removed,
|
Removed []types.ListReplaceItem `json:"removed,omitempty"`
|
||||||
"updated": updated,
|
Replaced []types.ListReplaceItem `json:"replaced,omitempty"`
|
||||||
|
}{
|
||||||
|
Removed: removed,
|
||||||
|
Replaced: replaced,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1278,11 +1357,25 @@ func (b *browserService) SetSetItem(server string, db int, k any, remove bool, m
|
||||||
|
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
|
var added, removed []types.SetEntryItem
|
||||||
var affected int64
|
var affected int64
|
||||||
if remove {
|
if remove {
|
||||||
affected, err = client.SRem(ctx, key, members...).Result()
|
for _, member := range members {
|
||||||
|
if affected, _ = client.SRem(ctx, key, member).Result(); affected > 0 {
|
||||||
|
removed = append(removed, types.SetEntryItem{
|
||||||
|
Value: member,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
affected, err = client.SAdd(ctx, key, members...).Result()
|
for _, member := range members {
|
||||||
|
if affected, _ = client.SAdd(ctx, key, member).Result(); affected > 0 {
|
||||||
|
added = append(added, types.SetEntryItem{
|
||||||
|
Value: member,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
|
@ -1290,8 +1383,14 @@ func (b *browserService) SetSetItem(server string, db int, k any, remove bool, m
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"affected": affected,
|
Added []types.SetEntryItem `json:"added,omitempty"`
|
||||||
|
Removed []types.SetEntryItem `json:"removed,omitempty"`
|
||||||
|
Affected int64 `json:"affected"`
|
||||||
|
}{
|
||||||
|
Added: added,
|
||||||
|
Removed: removed,
|
||||||
|
Affected: affected,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1306,9 +1405,15 @@ func (b *browserService) UpdateSetItem(param types.SetSetParam) (resp types.JSRe
|
||||||
|
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(param.Key)
|
key := strutil.DecodeRedisKey(param.Key)
|
||||||
|
var added, removed []types.SetEntryItem
|
||||||
|
var affect int64
|
||||||
// remove old value
|
// remove old value
|
||||||
str := strutil.DecodeRedisKey(param.Value)
|
str := strutil.DecodeRedisKey(param.Value)
|
||||||
_, _ = client.SRem(ctx, key, str).Result()
|
if affect, _ = client.SRem(ctx, key, str).Result(); affect > 0 {
|
||||||
|
removed = append(removed, types.SetEntryItem{
|
||||||
|
Value: str,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// insert new value
|
// insert new value
|
||||||
str = strutil.DecodeRedisKey(param.NewValue)
|
str = strutil.DecodeRedisKey(param.NewValue)
|
||||||
|
@ -1317,15 +1422,29 @@ func (b *browserService) UpdateSetItem(param types.SetSetParam) (resp types.JSRe
|
||||||
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
resp.Msg = fmt.Sprintf(`save to type "%s" fail: %s`, param.Format, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = client.SAdd(ctx, key, saveStr).Result()
|
if affect, _ = client.SAdd(ctx, key, saveStr).Result(); affect > 0 {
|
||||||
|
// add new item
|
||||||
|
var displayStr string
|
||||||
|
if len(param.RetDecode) > 0 && len(param.RetFormat) > 0 {
|
||||||
|
displayStr, _, _ = strutil.ConvertTo(saveStr, param.RetDecode, param.RetFormat)
|
||||||
|
}
|
||||||
|
added = append(added, types.SetEntryItem{
|
||||||
|
Value: saveStr,
|
||||||
|
DisplayValue: displayStr,
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"added": saveStr,
|
Added []types.SetEntryItem `json:"added,omitempty"`
|
||||||
|
Removed []types.SetEntryItem `json:"removed,omitempty"`
|
||||||
|
}{
|
||||||
|
Added: added,
|
||||||
|
Removed: removed,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1341,13 +1460,16 @@ func (b *browserService) UpdateZSetValue(param types.SetZSetParam) (resp types.J
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(param.Key)
|
key := strutil.DecodeRedisKey(param.Key)
|
||||||
val, newVal := strutil.DecodeRedisKey(param.Value), strutil.DecodeRedisKey(param.NewValue)
|
val, newVal := strutil.DecodeRedisKey(param.Value), strutil.DecodeRedisKey(param.NewValue)
|
||||||
updated := map[string]float64{}
|
var added, updated, removed []types.ZSetEntryItem
|
||||||
var removed []string
|
var replaced []types.ZSetReplaceItem
|
||||||
|
var affect int64
|
||||||
if len(newVal) <= 0 {
|
if len(newVal) <= 0 {
|
||||||
// no new value, delete value
|
// no new value, delete value
|
||||||
_, err = client.ZRem(ctx, key, val).Result()
|
if affect, err = client.ZRem(ctx, key, val).Result(); affect > 0 {
|
||||||
if err == nil {
|
//removed = append(removed, val)
|
||||||
removed = append(removed, val)
|
removed = append(removed, types.ZSetEntryItem{
|
||||||
|
Value: val,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var saveVal string
|
var saveVal string
|
||||||
|
@ -1357,27 +1479,57 @@ func (b *browserService) UpdateZSetValue(param types.SetZSetParam) (resp types.J
|
||||||
}
|
}
|
||||||
|
|
||||||
if saveVal == val {
|
if saveVal == val {
|
||||||
// update score only
|
affect, err = client.ZAdd(ctx, key, redis.Z{
|
||||||
_, err = client.ZAdd(ctx, key, redis.Z{
|
|
||||||
Score: param.Score,
|
Score: param.Score,
|
||||||
Member: saveVal,
|
Member: saveVal,
|
||||||
}).Result()
|
}).Result()
|
||||||
if err == nil {
|
displayValue, _, _ := strutil.ConvertTo(val, param.RetDecode, param.RetFormat)
|
||||||
updated[saveVal] = param.Score
|
if affect > 0 {
|
||||||
|
// add new item
|
||||||
|
added = append(added, types.ZSetEntryItem{
|
||||||
|
Score: param.Score,
|
||||||
|
Value: val,
|
||||||
|
DisplayValue: displayValue,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// update score only
|
||||||
|
updated = append(updated, types.ZSetEntryItem{
|
||||||
|
Score: param.Score,
|
||||||
|
Value: val,
|
||||||
|
DisplayValue: displayValue,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// remove old value and add new one
|
// remove old value and add new one
|
||||||
_, err = client.ZRem(ctx, key, val).Result()
|
_, err = client.ZRem(ctx, key, val).Result()
|
||||||
if err == nil {
|
if err != nil {
|
||||||
removed = append(removed, val)
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.ZAdd(ctx, key, redis.Z{
|
affect, err = client.ZAdd(ctx, key, redis.Z{
|
||||||
Score: param.Score,
|
Score: param.Score,
|
||||||
Member: saveVal,
|
Member: saveVal,
|
||||||
}).Result()
|
}).Result()
|
||||||
if err == nil {
|
displayValue, _, _ := strutil.ConvertTo(saveVal, param.RetDecode, param.RetFormat)
|
||||||
updated[saveVal] = param.Score
|
if affect <= 0 {
|
||||||
|
// no new value added, just update exists item
|
||||||
|
removed = append(removed, types.ZSetEntryItem{
|
||||||
|
Value: val,
|
||||||
|
})
|
||||||
|
updated = append(updated, types.ZSetEntryItem{
|
||||||
|
Score: param.Score,
|
||||||
|
Value: saveVal,
|
||||||
|
DisplayValue: displayValue,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// add new field
|
||||||
|
replaced = append(replaced, types.ZSetReplaceItem{
|
||||||
|
Score: param.Score,
|
||||||
|
Value: val,
|
||||||
|
NewValue: saveVal,
|
||||||
|
DisplayValue: displayValue,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1387,9 +1539,16 @@ func (b *browserService) UpdateZSetValue(param types.SetZSetParam) (resp types.J
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"updated": updated,
|
Added []types.ZSetEntryItem `json:"added,omitempty"`
|
||||||
"removed": removed,
|
Updated []types.ZSetEntryItem `json:"updated,omitempty"`
|
||||||
|
Replaced []types.ZSetReplaceItem `json:"replaced,omitempty"`
|
||||||
|
Removed []types.ZSetEntryItem `json:"removed,omitempty"`
|
||||||
|
}{
|
||||||
|
Added: added,
|
||||||
|
Updated: updated,
|
||||||
|
Replaced: replaced,
|
||||||
|
Removed: removed,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1404,20 +1563,37 @@ func (b *browserService) AddZSetValue(connName string, db int, k any, action int
|
||||||
|
|
||||||
client, ctx := item.client, item.ctx
|
client, ctx := item.client, item.ctx
|
||||||
key := strutil.DecodeRedisKey(k)
|
key := strutil.DecodeRedisKey(k)
|
||||||
members := maputil.ToSlice(valueScore, func(k string) redis.Z {
|
|
||||||
return redis.Z{
|
|
||||||
Score: valueScore[k],
|
|
||||||
Member: k,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
var added, updated []types.ZSetEntryItem
|
||||||
switch action {
|
switch action {
|
||||||
case 1:
|
case 1:
|
||||||
// ignore duplicated fields
|
// ignore duplicated fields
|
||||||
_, err = client.ZAddNX(ctx, key, members...).Result()
|
for m, s := range valueScore {
|
||||||
|
if affect, _ := client.ZAddNX(ctx, key, redis.Z{Score: s, Member: m}).Result(); affect > 0 {
|
||||||
|
added = append(added, types.ZSetEntryItem{
|
||||||
|
Score: s,
|
||||||
|
Value: m,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// overwrite duplicated fields
|
// overwrite duplicated fields
|
||||||
_, err = client.ZAdd(ctx, key, members...).Result()
|
for m, s := range valueScore {
|
||||||
|
if affect, _ := client.ZAdd(ctx, key, redis.Z{Score: s, Member: m}).Result(); affect > 0 {
|
||||||
|
added = append(added, types.ZSetEntryItem{
|
||||||
|
Score: s,
|
||||||
|
Value: m,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
updated = append(updated, types.ZSetEntryItem{
|
||||||
|
Score: s,
|
||||||
|
Value: m,
|
||||||
|
DisplayValue: "", // TODO: convert to display value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
|
@ -1425,6 +1601,13 @@ func (b *browserService) AddZSetValue(connName string, db int, k any, action int
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
|
resp.Data = struct {
|
||||||
|
Added []types.ZSetEntryItem `json:"added,omitempty"`
|
||||||
|
Updated []types.ZSetEntryItem `json:"updated,omitempty"`
|
||||||
|
}{
|
||||||
|
Added: added,
|
||||||
|
Updated: updated,
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1449,9 +1632,24 @@ func (b *browserService) AddStreamValue(connName string, db int, k any, ID strin
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateValues := make(map[string]any, len(fieldItems)/2)
|
||||||
|
for i := 0; i < len(fieldItems)/2; i += 2 {
|
||||||
|
updateValues[fieldItems[i].(string)] = fieldItems[i+1]
|
||||||
|
}
|
||||||
|
vb, _ := json.Marshal(updateValues)
|
||||||
|
displayValue, _, _ := strutil.ConvertTo(string(vb), types.DECODE_NONE, types.FORMAT_JSON)
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"updateID": updateID,
|
Added []types.StreamEntryItem `json:"added,omitempty"`
|
||||||
|
}{
|
||||||
|
Added: []types.StreamEntryItem{
|
||||||
|
{
|
||||||
|
ID: updateID,
|
||||||
|
Value: updateValues,
|
||||||
|
DisplayValue: displayValue, // TODO: convert to display value
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1475,8 +1673,10 @@ func (b *browserService) RemoveStreamValues(connName string, db int, k any, IDs
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
resp.Data = map[string]any{
|
resp.Data = struct {
|
||||||
"affected": affected,
|
Affected int64 `json:"affected"`
|
||||||
|
}{
|
||||||
|
Affected: affected,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ type SetListParam struct {
|
||||||
Value any `json:"value"`
|
Value any `json:"value"`
|
||||||
Format string `json:"format,omitempty"`
|
Format string `json:"format,omitempty"`
|
||||||
Decode string `json:"decode,omitempty"`
|
Decode string `json:"decode,omitempty"`
|
||||||
|
RetFormat string `json:"retFormat,omitempty"`
|
||||||
|
RetDecode string `json:"retDecode,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetHashParam struct {
|
type SetHashParam struct {
|
||||||
|
@ -68,6 +70,8 @@ type SetHashParam struct {
|
||||||
Value any `json:"value"`
|
Value any `json:"value"`
|
||||||
Format string `json:"format,omitempty"`
|
Format string `json:"format,omitempty"`
|
||||||
Decode string `json:"decode,omitempty"`
|
Decode string `json:"decode,omitempty"`
|
||||||
|
RetFormat string `json:"retFormat,omitempty"`
|
||||||
|
RetDecode string `json:"retDecode,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetSetParam struct {
|
type SetSetParam struct {
|
||||||
|
@ -78,6 +82,8 @@ type SetSetParam struct {
|
||||||
NewValue any `json:"newValue"`
|
NewValue any `json:"newValue"`
|
||||||
Format string `json:"format,omitempty"`
|
Format string `json:"format,omitempty"`
|
||||||
Decode string `json:"decode,omitempty"`
|
Decode string `json:"decode,omitempty"`
|
||||||
|
RetFormat string `json:"retFormat,omitempty"`
|
||||||
|
RetDecode string `json:"retDecode,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetZSetParam struct {
|
type SetZSetParam struct {
|
||||||
|
@ -89,4 +95,6 @@ type SetZSetParam struct {
|
||||||
Score float64 `json:"score"`
|
Score float64 `json:"score"`
|
||||||
Format string `json:"format,omitempty"`
|
Format string `json:"format,omitempty"`
|
||||||
Decode string `json:"decode,omitempty"`
|
Decode string `json:"decode,omitempty"`
|
||||||
|
RetFormat string `json:"retFormat,omitempty"`
|
||||||
|
RetDecode string `json:"retDecode,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,25 @@ type ListEntryItem struct {
|
||||||
DisplayValue string `json:"dv,omitempty"`
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ListReplaceItem struct {
|
||||||
|
Index int64 `json:"index"`
|
||||||
|
Value any `json:"v,omitempty"`
|
||||||
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type HashEntryItem struct {
|
type HashEntryItem struct {
|
||||||
Key string `json:"k"`
|
Key string `json:"k"`
|
||||||
Value any `json:"v"`
|
Value any `json:"v"`
|
||||||
DisplayValue string `json:"dv,omitempty"`
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HashReplaceItem struct {
|
||||||
|
Key any `json:"k"`
|
||||||
|
NewKey any `json:"nk"`
|
||||||
|
Value any `json:"v"`
|
||||||
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type SetEntryItem struct {
|
type SetEntryItem struct {
|
||||||
Value any `json:"v"`
|
Value any `json:"v"`
|
||||||
DisplayValue string `json:"dv,omitempty"`
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
|
@ -22,6 +35,13 @@ type ZSetEntryItem struct {
|
||||||
DisplayValue string `json:"dv,omitempty"`
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ZSetReplaceItem struct {
|
||||||
|
Score float64 `json:"s"`
|
||||||
|
Value string `json:"v"`
|
||||||
|
NewValue string `json:"nv"`
|
||||||
|
DisplayValue string `json:"dv,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type StreamEntryItem struct {
|
type StreamEntryItem struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Value map[string]any `json:"v"`
|
Value map[string]any `json:"v"`
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func containsBinary(str string) bool {
|
func containsBinary(str string) bool {
|
||||||
|
//buf := []byte(str)
|
||||||
//size := 0
|
//size := 0
|
||||||
//for start := 0; start < len(buf); start += size {
|
//for start := 0; start < len(buf); start += size {
|
||||||
// var r rune
|
// var r rune
|
||||||
|
@ -14,9 +15,25 @@ func containsBinary(str string) bool {
|
||||||
//}
|
//}
|
||||||
rs := []rune(str)
|
rs := []rune(str)
|
||||||
for _, r := range rs {
|
for _, r := range rs {
|
||||||
if !unicode.IsPrint(r) && r != '\n' {
|
if !unicode.IsPrint(r) && !unicode.IsSpace(r) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isSameChar(str string) bool {
|
||||||
|
if len(str) <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := []rune(str)
|
||||||
|
first := rs[0]
|
||||||
|
for _, r := range rs {
|
||||||
|
if r != first {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -109,10 +109,12 @@ func autoDecode(str string) (value, resultDecode string) {
|
||||||
// pure digit content may incorrect regard as some encoded type, skip decode
|
// pure digit content may incorrect regard as some encoded type, skip decode
|
||||||
if match, _ := regexp.MatchString(`^\d+$`, str); !match {
|
if match, _ := regexp.MatchString(`^\d+$`, str); !match {
|
||||||
var ok bool
|
var ok bool
|
||||||
|
if len(str)%4 == 0 && len(str) >= 12 && !isSameChar(str) {
|
||||||
if value, ok = decodeBase64(str); ok {
|
if value, ok = decodeBase64(str); ok {
|
||||||
resultDecode = types.DECODE_BASE64
|
resultDecode = types.DECODE_BASE64
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if value, ok = decodeGZip(str); ok {
|
if value, ok = decodeGZip(str); ok {
|
||||||
resultDecode = types.DECODE_GZIP
|
resultDecode = types.DECODE_GZIP
|
||||||
|
|
|
@ -34,39 +34,101 @@ const filterServerOption = computed(() => {
|
||||||
|
|
||||||
const tableRef = ref(null)
|
const tableRef = ref(null)
|
||||||
|
|
||||||
const loadHistory = () => {
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
title: i18n.t('log.exec_time'),
|
||||||
|
key: 'timestamp',
|
||||||
|
defaultSortOrder: 'ascend',
|
||||||
|
sorter: 'default',
|
||||||
|
width: 180,
|
||||||
|
align: 'center',
|
||||||
|
titleAlign: 'center',
|
||||||
|
render: ({ timestamp }, index) => {
|
||||||
|
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('log.server'),
|
||||||
|
key: 'server',
|
||||||
|
filterOptionValue: data.server,
|
||||||
|
filter: (value, row) => {
|
||||||
|
return value === '' || row.server === value.toString()
|
||||||
|
},
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
titleAlign: 'center',
|
||||||
|
ellipsis: {
|
||||||
|
tooltip: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('log.cmd'),
|
||||||
|
key: 'cmd',
|
||||||
|
titleAlign: 'center',
|
||||||
|
filterOptionValue: data.keyword,
|
||||||
|
resizable: true,
|
||||||
|
filter: (value, row) => {
|
||||||
|
return value === '' || !!~row.cmd.indexOf(value.toString())
|
||||||
|
},
|
||||||
|
render: ({ cmd }, index) => {
|
||||||
|
const cmdList = split(cmd, '\n')
|
||||||
|
if (size(cmdList) > 1) {
|
||||||
|
return h(
|
||||||
|
'div',
|
||||||
|
null,
|
||||||
|
map(cmdList, (c) => h('div', null, c)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('log.cost_time'),
|
||||||
|
key: 'cost',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
titleAlign: 'center',
|
||||||
|
render: ({ cost }, index) => {
|
||||||
|
const ms = dayjs.duration(cost).asMilliseconds()
|
||||||
|
if (ms < 1000) {
|
||||||
|
return `${ms} ms`
|
||||||
|
} else {
|
||||||
|
return `${Math.floor(ms / 1000)} s`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const loadHistory = async () => {
|
||||||
|
try {
|
||||||
|
await nextTick()
|
||||||
data.loading = true
|
data.loading = true
|
||||||
browserStore
|
const list = await browserStore.getCmdHistory()
|
||||||
.getCmdHistory()
|
|
||||||
.then((list) => {
|
|
||||||
data.history = list || []
|
data.history = list || []
|
||||||
})
|
} finally {
|
||||||
.finally(() => {
|
|
||||||
data.loading = false
|
data.loading = false
|
||||||
tableRef.value?.scrollTo({ top: 999999 })
|
tableRef.value?.scrollTo({ top: 999999 })
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanHistory = async () => {
|
const cleanHistory = async () => {
|
||||||
$dialog.warning(i18n.t('log.confirm_clean_log'), () => {
|
$dialog.warning(i18n.t('log.confirm_clean_log'), async () => {
|
||||||
|
try {
|
||||||
data.loading = true
|
data.loading = true
|
||||||
browserStore
|
const success = await browserStore.cleanCmdHistory()
|
||||||
.cleanCmdHistory()
|
|
||||||
.then((success) => {
|
|
||||||
if (success) {
|
if (success) {
|
||||||
data.history = []
|
data.history = []
|
||||||
tableRef.value?.scrollTo({ top: 0 })
|
tableRef.value?.scrollTo({ top: 0 })
|
||||||
$message.success(i18n.t('common.success'))
|
$message.success(i18n.t('common.success'))
|
||||||
}
|
}
|
||||||
})
|
} finally {
|
||||||
.finally(() => {
|
|
||||||
data.loading = false
|
data.loading = false
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
refresh: () => nextTick().then(loadHistory),
|
refresh: loadHistory,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -98,71 +160,12 @@ defineExpose({
|
||||||
<div class="content-value fill-height flex-box-h">
|
<div class="content-value fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:columns="[
|
:columns="columns"
|
||||||
{
|
|
||||||
title: $t('log.exec_time'),
|
|
||||||
key: 'timestamp',
|
|
||||||
defaultSortOrder: 'ascend',
|
|
||||||
sorter: 'default',
|
|
||||||
width: 180,
|
|
||||||
align: 'center',
|
|
||||||
titleAlign: 'center',
|
|
||||||
render: ({ timestamp }, index) => {
|
|
||||||
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: $t('log.server'),
|
|
||||||
key: 'server',
|
|
||||||
filterOptionValue: data.server,
|
|
||||||
filter: (value, row) => {
|
|
||||||
return value === '' || row.server === value.toString()
|
|
||||||
},
|
|
||||||
width: 150,
|
|
||||||
align: 'center',
|
|
||||||
titleAlign: 'center',
|
|
||||||
ellipsis: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: $t('log.cmd'),
|
|
||||||
key: 'cmd',
|
|
||||||
titleAlign: 'center',
|
|
||||||
filterOptionValue: data.keyword,
|
|
||||||
resizable: true,
|
|
||||||
filter: (value, row) => {
|
|
||||||
return value === '' || !!~row.cmd.indexOf(value.toString())
|
|
||||||
},
|
|
||||||
render: ({ cmd }, index) => {
|
|
||||||
const cmdList = split(cmd, '\n')
|
|
||||||
if (size(cmdList) > 1) {
|
|
||||||
return h(
|
|
||||||
'div',
|
|
||||||
null,
|
|
||||||
map(cmdList, (c) => h('div', null, c)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: $t('log.cost_time'),
|
|
||||||
key: 'cost',
|
|
||||||
width: 100,
|
|
||||||
align: 'center',
|
|
||||||
titleAlign: 'center',
|
|
||||||
render: ({ cost }, index) => {
|
|
||||||
const ms = dayjs.duration(cost).asMilliseconds()
|
|
||||||
if (ms < 1000) {
|
|
||||||
return `${ms} ms`
|
|
||||||
} else {
|
|
||||||
return `${Math.floor(ms / 1000)} s`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
:data="data.history"
|
:data="data.history"
|
||||||
|
:loading="data.loading"
|
||||||
class="flex-item-expand"
|
class="flex-item-expand"
|
||||||
flex-height />
|
flex-height
|
||||||
|
virtual-scroll />
|
||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -151,6 +151,7 @@ const onSave = () => {
|
||||||
<div class="editor-content-item-label">{{ props.fieldLabel }}</div>
|
<div class="editor-content-item-label">{{ props.fieldLabel }}</div>
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="viewAs.field"
|
v-model:value="viewAs.field"
|
||||||
|
:placeholder="props.field + ''"
|
||||||
:readonly="props.fieldReadonly"
|
:readonly="props.fieldReadonly"
|
||||||
class="editor-content-item-input"
|
class="editor-content-item-input"
|
||||||
type="text" />
|
type="text" />
|
||||||
|
@ -160,11 +161,12 @@ const onSave = () => {
|
||||||
<div class="editor-content-item flex-box-v flex-item-expand">
|
<div class="editor-content-item flex-box-v flex-item-expand">
|
||||||
<div class="editor-content-item-label">{{ props.valueLabel }}</div>
|
<div class="editor-content-item-label">{{ props.valueLabel }}</div>
|
||||||
<n-input
|
<n-input
|
||||||
|
:placeholder="props.value"
|
||||||
|
:resizable="false"
|
||||||
:value="displayValue"
|
:value="displayValue"
|
||||||
autofocus
|
autofocus
|
||||||
class="flex-item-expand"
|
class="flex-item-expand"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:resizable="false"
|
|
||||||
@update:value="onUpdateValue" />
|
@update:value="onUpdateValue" />
|
||||||
<format-selector
|
<format-selector
|
||||||
:decode="viewAs.decode"
|
:decode="viewAs.decode"
|
||||||
|
@ -216,11 +218,18 @@ const onSave = () => {
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.entry-editor {
|
.entry-editor {
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
.editor-content {
|
.editor-content {
|
||||||
&-item {
|
&-item {
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
margin-bottom: 18px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-label {
|
&-label {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { h, onMounted, onUnmounted, reactive, ref } from 'vue'
|
import { computed, h, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||||
import Refresh from '@/components/icons/Refresh.vue'
|
import Refresh from '@/components/icons/Refresh.vue'
|
||||||
import { debounce, isEmpty, map, size, split } from 'lodash'
|
import { debounce, isEmpty, map, size, split } from 'lodash'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
@ -33,6 +33,85 @@ const data = reactive({
|
||||||
|
|
||||||
const tableRef = ref(null)
|
const tableRef = ref(null)
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
title: i18n.t('slog.exec_time'),
|
||||||
|
key: 'timestamp',
|
||||||
|
sortOrder: data.sortOrder,
|
||||||
|
sorter: 'default',
|
||||||
|
width: 180,
|
||||||
|
align: 'center',
|
||||||
|
titleAlign: 'center',
|
||||||
|
render: ({ timestamp }, index) => {
|
||||||
|
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('slog.client'),
|
||||||
|
key: 'client',
|
||||||
|
filterOptionValue: data.client,
|
||||||
|
resizable: true,
|
||||||
|
filter: (value, row) => {
|
||||||
|
return value === '' || row.client === value.toString() || row.addr === value.toString()
|
||||||
|
},
|
||||||
|
width: 200,
|
||||||
|
align: 'center',
|
||||||
|
titleAlign: 'center',
|
||||||
|
ellipsis: {
|
||||||
|
tooltip: true,
|
||||||
|
},
|
||||||
|
render: ({ client, addr }, index) => {
|
||||||
|
let content = ''
|
||||||
|
if (!isEmpty(client)) {
|
||||||
|
content += client
|
||||||
|
}
|
||||||
|
if (!isEmpty(addr)) {
|
||||||
|
if (!isEmpty(content)) {
|
||||||
|
content += ' - '
|
||||||
|
}
|
||||||
|
content += addr
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('slog.cmd'),
|
||||||
|
key: 'cmd',
|
||||||
|
titleAlign: 'center',
|
||||||
|
filterOptionValue: data.keyword,
|
||||||
|
resizable: true,
|
||||||
|
filter: (value, row) => {
|
||||||
|
return value === '' || !!~row.cmd.indexOf(value.toString())
|
||||||
|
},
|
||||||
|
render: ({ cmd }, index) => {
|
||||||
|
const cmdList = split(cmd, '\n')
|
||||||
|
if (size(cmdList) > 1) {
|
||||||
|
return h(
|
||||||
|
'div',
|
||||||
|
null,
|
||||||
|
map(cmdList, (c) => h('div', null, c)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('slog.cost_time'),
|
||||||
|
key: 'cost',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
titleAlign: 'center',
|
||||||
|
render: ({ cost }, index) => {
|
||||||
|
const ms = dayjs.duration(cost).asMilliseconds()
|
||||||
|
if (ms < 1000) {
|
||||||
|
return `${ms} ms`
|
||||||
|
} else {
|
||||||
|
return `${Math.floor(ms / 1000)} s`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const _loadSlowLog = () => {
|
const _loadSlowLog = () => {
|
||||||
data.loading = true
|
data.loading = true
|
||||||
browserStore
|
browserStore
|
||||||
|
@ -103,86 +182,12 @@ const onListLimitChanged = (limit) => {
|
||||||
<div class="content-value fill-height flex-box-h">
|
<div class="content-value fill-height flex-box-h">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:columns="[
|
:columns="columns"
|
||||||
{
|
|
||||||
title: $t('slog.exec_time'),
|
|
||||||
key: 'timestamp',
|
|
||||||
sortOrder: data.sortOrder,
|
|
||||||
sorter: 'default',
|
|
||||||
width: 180,
|
|
||||||
align: 'center',
|
|
||||||
titleAlign: 'center',
|
|
||||||
render({ timestamp }, index) {
|
|
||||||
return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: $t('slog.client'),
|
|
||||||
key: 'client',
|
|
||||||
filterOptionValue: data.client,
|
|
||||||
resizable: true,
|
|
||||||
filter(value, row) {
|
|
||||||
return value === '' || row.client === value.toString() || row.addr === value.toString()
|
|
||||||
},
|
|
||||||
width: 200,
|
|
||||||
align: 'center',
|
|
||||||
titleAlign: 'center',
|
|
||||||
ellipsis: true,
|
|
||||||
render({ client, addr }, index) {
|
|
||||||
let content = ''
|
|
||||||
if (!isEmpty(client)) {
|
|
||||||
content += client
|
|
||||||
}
|
|
||||||
if (!isEmpty(addr)) {
|
|
||||||
if (!isEmpty(content)) {
|
|
||||||
content += ' - '
|
|
||||||
}
|
|
||||||
content += addr
|
|
||||||
}
|
|
||||||
return content
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: $t('slog.cmd'),
|
|
||||||
key: 'cmd',
|
|
||||||
titleAlign: 'center',
|
|
||||||
filterOptionValue: data.keyword,
|
|
||||||
resizable: true,
|
|
||||||
width: 100,
|
|
||||||
filter(value, row) {
|
|
||||||
return value === '' || !!~row.cmd.indexOf(value.toString())
|
|
||||||
},
|
|
||||||
render({ cmd }, index) {
|
|
||||||
const cmdList = split(cmd, '\n')
|
|
||||||
if (size(cmdList) > 1) {
|
|
||||||
return h(
|
|
||||||
'div',
|
|
||||||
null,
|
|
||||||
map(cmdList, (c) => h('div', null, c)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: $t('slog.cost_time'),
|
|
||||||
key: 'cost',
|
|
||||||
width: 100,
|
|
||||||
align: 'center',
|
|
||||||
titleAlign: 'center',
|
|
||||||
render({ cost }, index) {
|
|
||||||
const ms = dayjs.duration(cost).asMilliseconds()
|
|
||||||
if (ms < 1000) {
|
|
||||||
return `${ms} ms`
|
|
||||||
} else {
|
|
||||||
return `${Math.floor(ms / 1000)} s`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
:data="data.list"
|
:data="data.list"
|
||||||
|
:loading="data.loading"
|
||||||
class="flex-item-expand"
|
class="flex-item-expand"
|
||||||
flex-height
|
flex-height
|
||||||
|
virtual-scroll
|
||||||
@update:sorter="({ order }) => (data.sortOrder = order)" />
|
@update:sorter="({ order }) => (data.sortOrder = order)" />
|
||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
|
@ -190,9 +195,4 @@ const onListLimitChanged = (limit) => {
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '@/styles/content';
|
@import '@/styles/content';
|
||||||
|
|
||||||
.content-container {
|
|
||||||
padding: 5px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -89,9 +89,6 @@ const inEdit = computed(() => {
|
||||||
return currentEditRow.no > 0
|
return currentEditRow.no > 0
|
||||||
})
|
})
|
||||||
const fullEdit = ref(false)
|
const fullEdit = ref(false)
|
||||||
const inFullEdit = computed(() => {
|
|
||||||
return inEdit.value && fullEdit.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const tableRef = ref(null)
|
const tableRef = ref(null)
|
||||||
const fieldFilterOption = ref(null)
|
const fieldFilterOption = ref(null)
|
||||||
|
@ -158,7 +155,11 @@ const saveEdit = async (field, value, decode, format) => {
|
||||||
throw new Error('row not exists')
|
throw new Error('row not exists')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { updated, success, msg } = await browserStore.setHash({
|
if (isEmpty(field)) {
|
||||||
|
field = currentEditRow.key
|
||||||
|
}
|
||||||
|
|
||||||
|
const { success, msg } = await browserStore.setHash({
|
||||||
server: props.name,
|
server: props.name,
|
||||||
db: props.db,
|
db: props.db,
|
||||||
key: keyName.value,
|
key: keyName.value,
|
||||||
|
@ -167,16 +168,11 @@ const saveEdit = async (field, value, decode, format) => {
|
||||||
value,
|
value,
|
||||||
decode,
|
decode,
|
||||||
format,
|
format,
|
||||||
|
retDecode: props.decode,
|
||||||
|
retFormat: props.format,
|
||||||
|
index: [currentEditRow.no - 1],
|
||||||
})
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
row.k = field
|
|
||||||
row.v = updated[row.k] || ''
|
|
||||||
const { value: displayVal } = await browserStore.convertValue({
|
|
||||||
value: row.v,
|
|
||||||
decode: props.decode,
|
|
||||||
format: props.format,
|
|
||||||
})
|
|
||||||
row.dv = displayVal
|
|
||||||
$message.success(i18n.t('dialogue.save_value_succ'))
|
$message.success(i18n.t('dialogue.save_value_succ'))
|
||||||
} else {
|
} else {
|
||||||
$message.error(msg)
|
$message.error(msg)
|
||||||
|
@ -338,7 +334,6 @@ defineExpose({
|
||||||
<template>
|
<template>
|
||||||
<div class="content-wrapper flex-box-v">
|
<div class="content-wrapper flex-box-v">
|
||||||
<content-toolbar
|
<content-toolbar
|
||||||
v-show="!inFullEdit"
|
|
||||||
:db="props.db"
|
:db="props.db"
|
||||||
:key-code="props.keyCode"
|
:key-code="props.keyCode"
|
||||||
:key-path="props.keyPath"
|
:key-path="props.keyPath"
|
||||||
|
@ -350,7 +345,7 @@ defineExpose({
|
||||||
@delete="emit('delete')"
|
@delete="emit('delete')"
|
||||||
@reload="emit('reload')"
|
@reload="emit('reload')"
|
||||||
@rename="emit('rename')" />
|
@rename="emit('rename')" />
|
||||||
<div v-show="!inFullEdit" class="tb2 value-item-part flex-box-h">
|
<div class="tb2 value-item-part flex-box-h">
|
||||||
<div class="flex-box-h">
|
<div class="flex-box-h">
|
||||||
<n-input-group>
|
<n-input-group>
|
||||||
<n-select
|
<n-select
|
||||||
|
@ -384,7 +379,6 @@ defineExpose({
|
||||||
t-tooltip="interface.load_all_entries"
|
t-tooltip="interface.load_all_entries"
|
||||||
@click="emit('loadall')" />
|
@click="emit('loadall')" />
|
||||||
</n-button-group>
|
</n-button-group>
|
||||||
{{ valueColumn.align }}
|
|
||||||
<n-button :focusable="false" plain @click="onAddRow">
|
<n-button :focusable="false" plain @click="onAddRow">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<n-icon :component="AddLink" size="18" />
|
<n-icon :component="AddLink" size="18" />
|
||||||
|
@ -396,13 +390,12 @@ defineExpose({
|
||||||
<!-- table -->
|
<!-- table -->
|
||||||
<n-data-table
|
<n-data-table
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
v-show="!inFullEdit"
|
|
||||||
:row-key="(row) => row.k"
|
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:bottom-bordered="false"
|
:bottom-bordered="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="props.value"
|
:data="props.value"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
|
:row-key="(row) => row.k"
|
||||||
:row-props="rowProps"
|
:row-props="rowProps"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
@ -414,8 +407,12 @@ defineExpose({
|
||||||
@update:filters="onUpdateFilter" />
|
@update:filters="onUpdateFilter" />
|
||||||
|
|
||||||
<!-- edit pane -->
|
<!-- edit pane -->
|
||||||
<content-entry-editor
|
<div
|
||||||
v-show="inEdit"
|
v-show="inEdit"
|
||||||
|
:style="{ position: fullEdit ? 'static' : 'relative' }"
|
||||||
|
class="entry-editor-container flex-item-expand"
|
||||||
|
style="width: 100%">
|
||||||
|
<content-entry-editor
|
||||||
v-model:fullscreen="fullEdit"
|
v-model:fullscreen="fullEdit"
|
||||||
:decode="currentEditRow.decode"
|
:decode="currentEditRow.decode"
|
||||||
:field="currentEditRow.key"
|
:field="currentEditRow.key"
|
||||||
|
@ -428,6 +425,7 @@ defineExpose({
|
||||||
@close="resetEdit"
|
@close="resetEdit"
|
||||||
@save="saveEdit" />
|
@save="saveEdit" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="value-footer flex-box-h">
|
<div class="value-footer flex-box-h">
|
||||||
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
||||||
<n-divider v-if="!isNaN(props.length)" vertical />
|
<n-divider v-if="!isNaN(props.length)" vertical />
|
||||||
|
|
|
@ -75,9 +75,6 @@ const inEdit = computed(() => {
|
||||||
return currentEditRow.no > 0
|
return currentEditRow.no > 0
|
||||||
})
|
})
|
||||||
const fullEdit = ref(false)
|
const fullEdit = ref(false)
|
||||||
const inFullEdit = computed(() => {
|
|
||||||
return inEdit.value && fullEdit.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const displayCode = computed(() => {
|
const displayCode = computed(() => {
|
||||||
return props.format === formatTypes.JSON
|
return props.format === formatTypes.JSON
|
||||||
|
@ -130,7 +127,11 @@ const saveEdit = async (pos, value, decode, format) => {
|
||||||
throw new Error('row not exists')
|
throw new Error('row not exists')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { updated, success, msg } = await browserStore.updateListItem({
|
if (isEmpty(value)) {
|
||||||
|
value = currentEditRow.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const { success, msg } = await browserStore.updateListItem({
|
||||||
server: props.name,
|
server: props.name,
|
||||||
db: props.db,
|
db: props.db,
|
||||||
key: keyName.value,
|
key: keyName.value,
|
||||||
|
@ -140,13 +141,6 @@ const saveEdit = async (pos, value, decode, format) => {
|
||||||
format,
|
format,
|
||||||
})
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
row.v = updated[index] || ''
|
|
||||||
const { value: displayVal } = await browserStore.convertValue({
|
|
||||||
value: row.v,
|
|
||||||
decode: props.decode,
|
|
||||||
format: props.format,
|
|
||||||
})
|
|
||||||
row.dv = displayVal
|
|
||||||
$message.success(i18n.t('dialogue.save_value_succ'))
|
$message.success(i18n.t('dialogue.save_value_succ'))
|
||||||
} else {
|
} else {
|
||||||
$message.error(msg)
|
$message.error(msg)
|
||||||
|
@ -283,7 +277,6 @@ defineExpose({
|
||||||
<template>
|
<template>
|
||||||
<div class="content-wrapper flex-box-v">
|
<div class="content-wrapper flex-box-v">
|
||||||
<content-toolbar
|
<content-toolbar
|
||||||
v-show="!inFullEdit"
|
|
||||||
:db="props.db"
|
:db="props.db"
|
||||||
:key-code="props.keyCode"
|
:key-code="props.keyCode"
|
||||||
:key-path="props.keyPath"
|
:key-path="props.keyPath"
|
||||||
|
@ -295,7 +288,7 @@ defineExpose({
|
||||||
@delete="emit('delete')"
|
@delete="emit('delete')"
|
||||||
@reload="emit('reload')"
|
@reload="emit('reload')"
|
||||||
@rename="emit('rename')" />
|
@rename="emit('rename')" />
|
||||||
<div v-show="!inFullEdit" class="tb2 value-item-part flex-box-h">
|
<div class="tb2 value-item-part flex-box-h">
|
||||||
<div class="flex-box-h">
|
<div class="flex-box-h">
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="filterValue"
|
v-model:value="filterValue"
|
||||||
|
@ -331,13 +324,12 @@ defineExpose({
|
||||||
<div class="value-wrapper value-item-part flex-box-h flex-item-expand">
|
<div class="value-wrapper value-item-part flex-box-h flex-item-expand">
|
||||||
<!-- table -->
|
<!-- table -->
|
||||||
<n-data-table
|
<n-data-table
|
||||||
v-show="!inFullEdit"
|
|
||||||
:row-key="(row) => row.no"
|
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:bottom-bordered="false"
|
:bottom-bordered="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="props.value"
|
:data="props.value"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
|
:row-key="(row) => row.no"
|
||||||
:row-props="rowProps"
|
:row-props="rowProps"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
@ -349,8 +341,12 @@ defineExpose({
|
||||||
@update:filters="onUpdateFilter" />
|
@update:filters="onUpdateFilter" />
|
||||||
|
|
||||||
<!-- edit pane -->
|
<!-- edit pane -->
|
||||||
<content-entry-editor
|
<div
|
||||||
v-show="inEdit"
|
v-show="inEdit"
|
||||||
|
:style="{ position: fullEdit ? 'static' : 'relative' }"
|
||||||
|
class="entry-editor-container flex-item-expand"
|
||||||
|
style="width: 100%">
|
||||||
|
<content-entry-editor
|
||||||
v-model:fullscreen="fullEdit"
|
v-model:fullscreen="fullEdit"
|
||||||
:decode="currentEditRow.decode"
|
:decode="currentEditRow.decode"
|
||||||
:field="currentEditRow.no"
|
:field="currentEditRow.no"
|
||||||
|
@ -364,6 +360,7 @@ defineExpose({
|
||||||
@close="resetEdit"
|
@close="resetEdit"
|
||||||
@save="saveEdit" />
|
@save="saveEdit" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="value-footer flex-box-h">
|
<div class="value-footer flex-box-h">
|
||||||
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
||||||
<n-divider v-if="!isNaN(props.length)" vertical />
|
<n-divider v-if="!isNaN(props.length)" vertical />
|
||||||
|
|
|
@ -74,9 +74,6 @@ const inEdit = computed(() => {
|
||||||
return currentEditRow.no > 0
|
return currentEditRow.no > 0
|
||||||
})
|
})
|
||||||
const fullEdit = ref(false)
|
const fullEdit = ref(false)
|
||||||
const inFullEdit = computed(() => {
|
|
||||||
return inEdit.value && fullEdit.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const displayCode = computed(() => {
|
const displayCode = computed(() => {
|
||||||
return props.format === formatTypes.JSON
|
return props.format === formatTypes.JSON
|
||||||
|
@ -129,7 +126,7 @@ const saveEdit = async (pos, value, decode, format) => {
|
||||||
throw new Error('row not exists')
|
throw new Error('row not exists')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { added, success, msg } = await browserStore.updateSetItem({
|
const { success, msg } = await browserStore.updateSetItem({
|
||||||
server: props.name,
|
server: props.name,
|
||||||
db: props.db,
|
db: props.db,
|
||||||
key: keyName.value,
|
key: keyName.value,
|
||||||
|
@ -137,15 +134,10 @@ const saveEdit = async (pos, value, decode, format) => {
|
||||||
newValue: value,
|
newValue: value,
|
||||||
decode,
|
decode,
|
||||||
format,
|
format,
|
||||||
|
retDecode: props.decode,
|
||||||
|
retFormat: props.format,
|
||||||
})
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
row.v = added
|
|
||||||
const { value: displayVal } = await browserStore.convertValue({
|
|
||||||
value: row.v,
|
|
||||||
decode: props.decode,
|
|
||||||
format: props.format,
|
|
||||||
})
|
|
||||||
row.dv = displayVal
|
|
||||||
$message.success(i18n.t('dialogue.save_value_succ'))
|
$message.success(i18n.t('dialogue.save_value_succ'))
|
||||||
} else {
|
} else {
|
||||||
$message.error(msg)
|
$message.error(msg)
|
||||||
|
@ -183,7 +175,7 @@ const actionColumn = {
|
||||||
row.v,
|
row.v,
|
||||||
)
|
)
|
||||||
if (success) {
|
if (success) {
|
||||||
props.value.splice(index, 1)
|
// props.value.splice(index, 1)
|
||||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.v }))
|
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.v }))
|
||||||
} else {
|
} else {
|
||||||
$message.error(msg)
|
$message.error(msg)
|
||||||
|
@ -282,7 +274,6 @@ defineExpose({
|
||||||
<template>
|
<template>
|
||||||
<div class="content-wrapper flex-box-v">
|
<div class="content-wrapper flex-box-v">
|
||||||
<content-toolbar
|
<content-toolbar
|
||||||
v-show="!inFullEdit"
|
|
||||||
:db="props.db"
|
:db="props.db"
|
||||||
:key-code="props.keyCode"
|
:key-code="props.keyCode"
|
||||||
:key-path="props.keyPath"
|
:key-path="props.keyPath"
|
||||||
|
@ -294,7 +285,7 @@ defineExpose({
|
||||||
@delete="emit('delete')"
|
@delete="emit('delete')"
|
||||||
@reload="emit('reload')"
|
@reload="emit('reload')"
|
||||||
@rename="emit('rename')" />
|
@rename="emit('rename')" />
|
||||||
<div v-show="!inFullEdit" class="tb2 value-item-part flex-box-h">
|
<div class="tb2 value-item-part flex-box-h">
|
||||||
<div class="flex-box-h">
|
<div class="flex-box-h">
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="filterValue"
|
v-model:value="filterValue"
|
||||||
|
@ -330,13 +321,12 @@ defineExpose({
|
||||||
<div class="value-wrapper value-item-part flex-box-h flex-item-expand">
|
<div class="value-wrapper value-item-part flex-box-h flex-item-expand">
|
||||||
<!-- table -->
|
<!-- table -->
|
||||||
<n-data-table
|
<n-data-table
|
||||||
v-show="!inFullEdit"
|
|
||||||
:row-key="(row) => row.v"
|
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:bottom-bordered="false"
|
:bottom-bordered="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="props.value"
|
:data="props.value"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
|
:row-key="(row) => row.v"
|
||||||
:row-props="rowProps"
|
:row-props="rowProps"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
|
@ -348,8 +338,12 @@ defineExpose({
|
||||||
@update:filters="onUpdateFilter" />
|
@update:filters="onUpdateFilter" />
|
||||||
|
|
||||||
<!-- edit pane -->
|
<!-- edit pane -->
|
||||||
<content-entry-editor
|
<div
|
||||||
v-show="inEdit"
|
v-show="inEdit"
|
||||||
|
:style="{ position: fullEdit ? 'static' : 'relative' }"
|
||||||
|
class="entry-editor-container flex-item-expand"
|
||||||
|
style="width: 100%">
|
||||||
|
<content-entry-editor
|
||||||
v-model:fullscreen="fullEdit"
|
v-model:fullscreen="fullEdit"
|
||||||
:decode="currentEditRow.decode"
|
:decode="currentEditRow.decode"
|
||||||
:field="currentEditRow.no"
|
:field="currentEditRow.no"
|
||||||
|
@ -363,6 +357,7 @@ defineExpose({
|
||||||
@close="resetEdit"
|
@close="resetEdit"
|
||||||
@save="saveEdit" />
|
@save="saveEdit" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="value-footer flex-box-h">
|
<div class="value-footer flex-box-h">
|
||||||
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
||||||
<n-divider v-if="!isNaN(props.length)" vertical />
|
<n-divider v-if="!isNaN(props.length)" vertical />
|
||||||
|
|
|
@ -237,12 +237,12 @@ defineExpose({
|
||||||
</div>
|
</div>
|
||||||
<div class="value-wrapper value-item-part flex-box-v flex-item-expand">
|
<div class="value-wrapper value-item-part flex-box-v flex-item-expand">
|
||||||
<n-data-table
|
<n-data-table
|
||||||
:row-key="(row) => row.id"
|
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:bottom-bordered="false"
|
:bottom-bordered="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="props.value"
|
:data="props.value"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
|
:row-key="(row) => row.id"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
class="flex-item-expand"
|
class="flex-item-expand"
|
||||||
|
|
|
@ -6,7 +6,7 @@ import AddLink from '@/components/icons/AddLink.vue'
|
||||||
import { NButton, NCode, NIcon, NInput, useThemeVars } from 'naive-ui'
|
import { NButton, NCode, NIcon, NInput, useThemeVars } from 'naive-ui'
|
||||||
import { types, types as redisTypes } from '@/consts/support_redis_type.js'
|
import { types, types as redisTypes } from '@/consts/support_redis_type.js'
|
||||||
import EditableTableColumn from '@/components/common/EditableTableColumn.vue'
|
import EditableTableColumn from '@/components/common/EditableTableColumn.vue'
|
||||||
import { head, isEmpty, keys, size } from 'lodash'
|
import { isEmpty, size } from 'lodash'
|
||||||
import useDialogStore from 'stores/dialog.js'
|
import useDialogStore from 'stores/dialog.js'
|
||||||
import bytes from 'bytes'
|
import bytes from 'bytes'
|
||||||
import { decodeTypes, formatTypes } from '@/consts/value_view_type.js'
|
import { decodeTypes, formatTypes } from '@/consts/value_view_type.js'
|
||||||
|
@ -68,7 +68,7 @@ const filterOption = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 2,
|
value: 2,
|
||||||
label: i18n.t('interface.score'),
|
label: i18n.t('common.score'),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
const filterType = ref(1)
|
const filterType = ref(1)
|
||||||
|
@ -88,14 +88,11 @@ const inEdit = computed(() => {
|
||||||
return currentEditRow.no > 0
|
return currentEditRow.no > 0
|
||||||
})
|
})
|
||||||
const fullEdit = ref(false)
|
const fullEdit = ref(false)
|
||||||
const inFullEdit = computed(() => {
|
|
||||||
return inEdit.value && fullEdit.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const scoreFilterOption = ref(null)
|
const scoreFilterOption = ref(null)
|
||||||
const scoreColumn = computed(() => ({
|
const scoreColumn = computed(() => ({
|
||||||
key: 'score',
|
key: 'score',
|
||||||
title: i18n.t('interface.score'),
|
title: i18n.t('common.score'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
titleAlign: 'center',
|
titleAlign: 'center',
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
@ -183,7 +180,11 @@ const saveEdit = async (field, value, decode, format) => {
|
||||||
throw new Error('row not exists')
|
throw new Error('row not exists')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { updated, success, msg } = await browserStore.updateZSetItem({
|
if (isEmpty(value)) {
|
||||||
|
value = currentEditRow.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const { success, msg } = await browserStore.updateZSetItem({
|
||||||
server: props.name,
|
server: props.name,
|
||||||
db: props.db,
|
db: props.db,
|
||||||
key: keyName.value,
|
key: keyName.value,
|
||||||
|
@ -194,14 +195,6 @@ const saveEdit = async (field, value, decode, format) => {
|
||||||
format,
|
format,
|
||||||
})
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
row.v = head(keys(updated))
|
|
||||||
row.s = updated[row.v]
|
|
||||||
const { value: displayVal } = await browserStore.convertValue({
|
|
||||||
value: row.v,
|
|
||||||
decode: props.decode,
|
|
||||||
format: props.format,
|
|
||||||
})
|
|
||||||
row.dv = displayVal
|
|
||||||
$message.success(i18n.t('dialogue.save_value_succ'))
|
$message.success(i18n.t('dialogue.save_value_succ'))
|
||||||
} else {
|
} else {
|
||||||
$message.error(msg)
|
$message.error(msg)
|
||||||
|
@ -240,7 +233,7 @@ const actionColumn = {
|
||||||
row.v,
|
row.v,
|
||||||
)
|
)
|
||||||
if (success) {
|
if (success) {
|
||||||
props.value.splice(index, 1)
|
// props.value.splice(index, 1)
|
||||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.v }))
|
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.v }))
|
||||||
} else {
|
} else {
|
||||||
$message.error(msg)
|
$message.error(msg)
|
||||||
|
@ -354,7 +347,6 @@ defineExpose({
|
||||||
<template>
|
<template>
|
||||||
<div class="content-wrapper flex-box-v">
|
<div class="content-wrapper flex-box-v">
|
||||||
<content-toolbar
|
<content-toolbar
|
||||||
v-show="!inFullEdit"
|
|
||||||
:db="props.db"
|
:db="props.db"
|
||||||
:key-code="props.keyCode"
|
:key-code="props.keyCode"
|
||||||
:key-path="props.keyPath"
|
:key-path="props.keyPath"
|
||||||
|
@ -366,7 +358,7 @@ defineExpose({
|
||||||
@delete="emit('delete')"
|
@delete="emit('delete')"
|
||||||
@reload="emit('reload')"
|
@reload="emit('reload')"
|
||||||
@rename="emit('rename')" />
|
@rename="emit('rename')" />
|
||||||
<div v-show="!inFullEdit" class="tb2 value-item-part flex-box-h">
|
<div class="tb2 value-item-part flex-box-h">
|
||||||
<div class="flex-box-h">
|
<div class="flex-box-h">
|
||||||
<n-input-group>
|
<n-input-group>
|
||||||
<n-select
|
<n-select
|
||||||
|
@ -415,13 +407,12 @@ defineExpose({
|
||||||
<div class="value-wrapper value-item-part flex-box-h flex-item-expand">
|
<div class="value-wrapper value-item-part flex-box-h flex-item-expand">
|
||||||
<!-- table -->
|
<!-- table -->
|
||||||
<n-data-table
|
<n-data-table
|
||||||
v-show="!inFullEdit"
|
|
||||||
:row-key="(row) => row.v"
|
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:bottom-bordered="false"
|
:bottom-bordered="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="props.value"
|
:data="props.value"
|
||||||
:loading="props.loading"
|
:loading="props.loading"
|
||||||
|
:row-key="(row) => row.v"
|
||||||
:single-column="true"
|
:single-column="true"
|
||||||
:single-line="false"
|
:single-line="false"
|
||||||
class="flex-item-expand"
|
class="flex-item-expand"
|
||||||
|
@ -432,12 +423,16 @@ defineExpose({
|
||||||
@update:filters="onUpdateFilter" />
|
@update:filters="onUpdateFilter" />
|
||||||
|
|
||||||
<!-- edit pane -->
|
<!-- edit pane -->
|
||||||
<content-entry-editor
|
<div
|
||||||
v-show="inEdit"
|
v-show="inEdit"
|
||||||
|
:style="{ position: fullEdit ? 'static' : 'relative' }"
|
||||||
|
class="entry-editor-container flex-item-expand"
|
||||||
|
style="width: 100%">
|
||||||
|
<content-entry-editor
|
||||||
v-model:fullscreen="fullEdit"
|
v-model:fullscreen="fullEdit"
|
||||||
:decode="currentEditRow.decode"
|
:decode="currentEditRow.decode"
|
||||||
:field="currentEditRow.score"
|
:field="currentEditRow.score"
|
||||||
:field-label="$t('interface.score')"
|
:field-label="$t('common.score')"
|
||||||
:format="currentEditRow.format"
|
:format="currentEditRow.format"
|
||||||
:value="currentEditRow.value"
|
:value="currentEditRow.value"
|
||||||
:value-label="$t('common.value')"
|
:value-label="$t('common.value')"
|
||||||
|
@ -446,6 +441,7 @@ defineExpose({
|
||||||
@close="resetEdit"
|
@close="resetEdit"
|
||||||
@save="saveEdit" />
|
@save="saveEdit" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="value-footer flex-box-h">
|
<div class="value-footer flex-box-h">
|
||||||
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
<n-text v-if="!isNaN(props.length)">{{ $t('interface.entries') }}: {{ entries }}</n-text>
|
||||||
<n-divider v-if="!isNaN(props.length)" vertical />
|
<n-divider v-if="!isNaN(props.length)" vertical />
|
||||||
|
|
|
@ -50,7 +50,9 @@ const onUpdate = (val) => {
|
||||||
<n-radio-button v-for="(op, i) in updateOption" :key="i" :label="op.label" :value="op.value" />
|
<n-radio-button v-for="(op, i) in updateOption" :key="i" :label="op.label" :value="op.value" />
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('dialogue.field.element')" required>
|
<n-form-item
|
||||||
|
:label="$t('dialogue.field.element') + ' (' + $t('common.field') + ':' + $t('common.value') + ')'"
|
||||||
|
required>
|
||||||
<n-dynamic-input
|
<n-dynamic-input
|
||||||
v-model:value="kvList"
|
v-model:value="kvList"
|
||||||
:key-placeholder="$t('dialogue.field.enter_field')"
|
:key-placeholder="$t('dialogue.field.enter_field')"
|
||||||
|
|
|
@ -58,14 +58,17 @@ const onUpdate = () => {
|
||||||
<n-radio-button v-for="(op, i) in updateOption" :key="i" :label="op.label" :value="op.value" />
|
<n-radio-button v-for="(op, i) in updateOption" :key="i" :label="op.label" :value="op.value" />
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('dialogue.field.element')" required>
|
<n-form-item
|
||||||
|
:label="$t('dialogue.field.element') + ' (' + $t('common.value') + ':' + $t('common.score') + ')'"
|
||||||
|
required>
|
||||||
<n-dynamic-input v-model:value="zset" @create="onCreate" @update:value="onUpdate">
|
<n-dynamic-input v-model:value="zset" @create="onCreate" @update:value="onUpdate">
|
||||||
<template #default="{ value }">
|
<template #default="{ value }">
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="value.value"
|
v-model:value="value.value"
|
||||||
:placeholder="$t('dialogue.field.enter_elem')"
|
:placeholder="$t('dialogue.field.enter_value')"
|
||||||
type="text"
|
type="text"
|
||||||
@update:value="onUpdate" />
|
@update:value="onUpdate" />
|
||||||
|
<n-text>:</n-text>
|
||||||
<n-input-number
|
<n-input-number
|
||||||
v-model:value="value.score"
|
v-model:value="value.score"
|
||||||
:placeholder="$t('dialogue.field.enter_score')"
|
:placeholder="$t('dialogue.field.enter_score')"
|
||||||
|
|
|
@ -43,7 +43,7 @@ defineExpose({
|
||||||
<n-form-item label="ID">
|
<n-form-item label="ID">
|
||||||
<n-input v-model:value="id" />
|
<n-input v-model:value="id" />
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item :label="$t('dialogue.field.element')" required>
|
<n-form-item :label="$t('common.field') + ':' + $t('common.value')" required>
|
||||||
<n-dynamic-input
|
<n-dynamic-input
|
||||||
v-model:value="kvList"
|
v-model:value="kvList"
|
||||||
:key-placeholder="$t('dialogue.field.enter_field')"
|
:key-placeholder="$t('dialogue.field.enter_field')"
|
||||||
|
|
|
@ -132,7 +132,7 @@ const exThemeVars = computed(() => {
|
||||||
<n-tooltip :delay="2" :show-arrow="false" placement="right">
|
<n-tooltip :delay="2" :show-arrow="false" placement="right">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<n-icon :size="iconSize">
|
<n-icon :size="iconSize">
|
||||||
<component :is="m.icon" :stroke-width="3.5"></component>
|
<component :is="m.icon" :stroke-width="3.5" />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</template>
|
</template>
|
||||||
{{ m.label }}
|
{{ m.label }}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
"field": "Field",
|
"field": "Field",
|
||||||
|
"score": "Score",
|
||||||
"index": "Position"
|
"index": "Position"
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
|
@ -104,7 +105,6 @@
|
||||||
"empty_server_list": "No redis server",
|
"empty_server_list": "No redis server",
|
||||||
"action": "Action",
|
"action": "Action",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"score": "Score",
|
|
||||||
"cli_welcome": "Welcome to Tiny RDM Redis Console",
|
"cli_welcome": "Welcome to Tiny RDM Redis Console",
|
||||||
"sub_tab": {
|
"sub_tab": {
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"key": "Chave",
|
"key": "Chave",
|
||||||
"value": "Valor",
|
"value": "Valor",
|
||||||
"field": "Campo",
|
"field": "Campo",
|
||||||
|
"score": "Pontuação",
|
||||||
"index": "Posição"
|
"index": "Posição"
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
|
@ -98,7 +99,6 @@
|
||||||
"empty_server_list": "Nenhum servidor Redis",
|
"empty_server_list": "Nenhum servidor Redis",
|
||||||
"action": "Ação",
|
"action": "Ação",
|
||||||
"type": "Tipo",
|
"type": "Tipo",
|
||||||
"score": "Pontuação",
|
|
||||||
"cli_welcome": "Bem-vindo ao Console Redis Tiny RDM",
|
"cli_welcome": "Bem-vindo ao Console Redis Tiny RDM",
|
||||||
"sub_tab": {
|
"sub_tab": {
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"key": "键",
|
"key": "键",
|
||||||
"value": "值",
|
"value": "值",
|
||||||
"field": "字段",
|
"field": "字段",
|
||||||
|
"score": "分值",
|
||||||
"index": "位置"
|
"index": "位置"
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
|
@ -104,7 +105,6 @@
|
||||||
"empty_server_list": "还没添加Redis服务器",
|
"empty_server_list": "还没添加Redis服务器",
|
||||||
"action": "操作",
|
"action": "操作",
|
||||||
"type": "类型",
|
"type": "类型",
|
||||||
"score": "分值",
|
|
||||||
"cli_welcome": "欢迎使用Tiny RDM的Redis命令行控制台",
|
"cli_welcome": "欢迎使用Tiny RDM的Redis命令行控制台",
|
||||||
"sub_tab": {
|
"sub_tab": {
|
||||||
"status": "状态",
|
"status": "状态",
|
||||||
|
|
|
@ -1009,9 +1009,12 @@ const useBrowserStore = defineStore('browser', {
|
||||||
* @param {string} field
|
* @param {string} field
|
||||||
* @param {string} [newField]
|
* @param {string} [newField]
|
||||||
* @param {string} [value]
|
* @param {string} [value]
|
||||||
* @param {string} [decode]
|
* @param {decodeTypes} [decode]
|
||||||
* @param {string} [format]
|
* @param {formatTypes} [format]
|
||||||
|
* @param {decodeTypes} [retDecode]
|
||||||
|
* @param {formatTypes} [retFormat]
|
||||||
* @param {boolean} [refresh]
|
* @param {boolean} [refresh]
|
||||||
|
* @param {number} [index] index for retrieve affect entries quickly
|
||||||
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
|
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
|
||||||
*/
|
*/
|
||||||
async setHash({
|
async setHash({
|
||||||
|
@ -1023,7 +1026,9 @@ const useBrowserStore = defineStore('browser', {
|
||||||
value = '',
|
value = '',
|
||||||
decode = decodeTypes.NONE,
|
decode = decodeTypes.NONE,
|
||||||
format = formatTypes.RAW,
|
format = formatTypes.RAW,
|
||||||
refresh,
|
retDecode,
|
||||||
|
retFormat,
|
||||||
|
index,
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const { data, success, msg } = await SetHashValue({
|
const { data, success, msg } = await SetHashValue({
|
||||||
|
@ -1035,17 +1040,34 @@ const useBrowserStore = defineStore('browser', {
|
||||||
value,
|
value,
|
||||||
decode,
|
decode,
|
||||||
format,
|
format,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
})
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
const { updated = {}, removed = [], replaced = {} } = data
|
/**
|
||||||
if (refresh === true) {
|
* @type {{updated: HashEntryItem[], removed: HashEntryItem[], updated: HashEntryItem[], replaced: HashReplaceItem[]}}
|
||||||
|
*/
|
||||||
|
const { updated = [], removed = [], added = [], replaced = [] } = data
|
||||||
const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
if (!isEmpty(removed)) {
|
if (!isEmpty(removed)) {
|
||||||
tab.removeValueEntries({ server, db, key, type: 'hash', entries: removed })
|
const removedKeys = map(removed, 'k')
|
||||||
|
tab.removeValueEntries({ server, db, key, type: 'hash', entries: removedKeys })
|
||||||
}
|
}
|
||||||
if (!isEmpty(updated)) {
|
if (!isEmpty(updated)) {
|
||||||
tab.upsertValueEntries({ server, db, key, type: 'hash', entries: updated })
|
tab.updateValueEntries({ server, db, key, type: 'hash', entries: updated })
|
||||||
}
|
}
|
||||||
|
if (!isEmpty(added)) {
|
||||||
|
tab.insertValueEntries({ server, db, key, type: 'hash', entries: added })
|
||||||
|
}
|
||||||
|
if (!isEmpty(replaced)) {
|
||||||
|
tab.replaceValueEntries({
|
||||||
|
server,
|
||||||
|
db,
|
||||||
|
key,
|
||||||
|
type: 'hash',
|
||||||
|
entries: replaced,
|
||||||
|
index: [index],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return { success, updated }
|
return { success, updated }
|
||||||
} else {
|
} else {
|
||||||
|
@ -1058,21 +1080,26 @@ const useBrowserStore = defineStore('browser', {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* insert or update hash field item
|
* insert or update hash field item
|
||||||
* @param {string} connName
|
* @param {string} server
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string|number[]} key
|
* @param {string|number[]} key
|
||||||
* @param {number }action 0:ignore duplicated fields 1:overwrite duplicated fields
|
* @param {number }action 0:ignore duplicated fields 1:overwrite duplicated fields
|
||||||
* @param {string[]} fieldItems field1, value1, filed2, value2...
|
* @param {string[]} fieldItems field1, value1, filed2, value2...
|
||||||
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
|
* @returns {Promise<{[msg]: string, success: boolean, [updated]: [], [added]: []}>}
|
||||||
*/
|
*/
|
||||||
async addHashField(connName, db, key, action, fieldItems) {
|
async addHashField(server, db, key, action, fieldItems) {
|
||||||
try {
|
try {
|
||||||
const { data, success, msg } = await AddHashField(connName, db, key, action, fieldItems)
|
const { data, success, msg } = await AddHashField(server, db, key, action, fieldItems)
|
||||||
if (success) {
|
if (success) {
|
||||||
const { updated = {} } = data
|
const { updated = [], added = [] } = data
|
||||||
const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
tab.upsertValueEntries({ server: connName, db, key, type: 'hash', entries: updated })
|
if (!isEmpty(updated)) {
|
||||||
return { success, updated }
|
tab.updateValueEntries({ server, db, key, type: 'hash', entries: updated })
|
||||||
|
}
|
||||||
|
if (!isEmpty(added)) {
|
||||||
|
tab.insertValueEntries({ server, db, key, type: 'hash', entries: added })
|
||||||
|
}
|
||||||
|
return { success, updated, added }
|
||||||
} else {
|
} else {
|
||||||
return { success: false, msg }
|
return { success: false, msg }
|
||||||
}
|
}
|
||||||
|
@ -1138,15 +1165,13 @@ const useBrowserStore = defineStore('browser', {
|
||||||
if (success) {
|
if (success) {
|
||||||
const { left = [] } = data
|
const { left = [] } = data
|
||||||
if (!isEmpty(left)) {
|
if (!isEmpty(left)) {
|
||||||
// TODO: convert to display value
|
|
||||||
const entries = map(left, (v) => ({ v }))
|
|
||||||
const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
tab.upsertValueEntries({
|
tab.insertValueEntries({
|
||||||
server: server,
|
server: server,
|
||||||
db,
|
db,
|
||||||
key,
|
key,
|
||||||
type: 'list',
|
type: 'list',
|
||||||
entries,
|
entries: left,
|
||||||
prepend: true,
|
prepend: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1172,15 +1197,15 @@ const useBrowserStore = defineStore('browser', {
|
||||||
const { data, success, msg } = await AddListItem(server, db, key, 1, values)
|
const { data, success, msg } = await AddListItem(server, db, key, 1, values)
|
||||||
if (success) {
|
if (success) {
|
||||||
const { right = [] } = data
|
const { right = [] } = data
|
||||||
|
// FIXME: do not append items if not all items loaded
|
||||||
if (!isEmpty(right)) {
|
if (!isEmpty(right)) {
|
||||||
const entries = map(right, (v) => ({ v }))
|
|
||||||
const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
tab.upsertValueEntries({
|
tab.insertValueEntries({
|
||||||
server: server,
|
server: server,
|
||||||
db,
|
db,
|
||||||
key,
|
key,
|
||||||
type: 'list',
|
type: 'list',
|
||||||
entries,
|
entries: right,
|
||||||
prepend: false,
|
prepend: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1202,24 +1227,57 @@ const useBrowserStore = defineStore('browser', {
|
||||||
* @param {string|number[]} value
|
* @param {string|number[]} value
|
||||||
* @param {decodeTypes} decode
|
* @param {decodeTypes} decode
|
||||||
* @param {formatTypes} format
|
* @param {formatTypes} format
|
||||||
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
|
* @param {decodeTypes} [retDecode]
|
||||||
|
* @param {formatTypes} [retFormat]
|
||||||
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
||||||
*/
|
*/
|
||||||
async updateListItem({ server, db, key, index, value, decode = decodeTypes.NONE, format = formatTypes.RAW }) {
|
async updateListItem({
|
||||||
|
server,
|
||||||
|
db,
|
||||||
|
key,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
decode = decodeTypes.NONE,
|
||||||
|
format = formatTypes.RAW,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
|
}) {
|
||||||
try {
|
try {
|
||||||
const { data, success, msg } = await SetListItem({ server, db, key, index, value, decode, format })
|
const { data, success, msg } = await SetListItem({
|
||||||
|
server,
|
||||||
|
db,
|
||||||
|
key,
|
||||||
|
index,
|
||||||
|
value,
|
||||||
|
decode,
|
||||||
|
format,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
const { updated = {} } = data
|
/** @type {{replaced: ListReplaceItem[]}} **/
|
||||||
// if (!isEmpty(updated)) {
|
const { replaced = [], removed = [] } = data
|
||||||
// const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
// tab.upsertValueEntries({
|
if (!isEmpty(replaced)) {
|
||||||
// server,
|
tab.replaceValueEntries({
|
||||||
// db,
|
server,
|
||||||
// key,
|
db,
|
||||||
// type: 'list',
|
key,
|
||||||
// entries: updated,
|
type: 'list',
|
||||||
// })
|
entries: replaced,
|
||||||
// }
|
})
|
||||||
return { success, updated }
|
}
|
||||||
|
if (!isEmpty(removed)) {
|
||||||
|
const removedIndex = map(removed, 'index')
|
||||||
|
tab.removeValueEntries({
|
||||||
|
server,
|
||||||
|
db,
|
||||||
|
key,
|
||||||
|
type: 'list',
|
||||||
|
entries: removedIndex,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { success }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
}
|
}
|
||||||
|
@ -1241,16 +1299,17 @@ const useBrowserStore = defineStore('browser', {
|
||||||
const { data, success, msg } = await SetListItem({ server, db, key, index })
|
const { data, success, msg } = await SetListItem({ server, db, key, index })
|
||||||
if (success) {
|
if (success) {
|
||||||
const { removed = [] } = data
|
const { removed = [] } = data
|
||||||
// if (!isEmpty(removed)) {
|
const tab = useTabStore()
|
||||||
// const tab = useTabStore()
|
if (!isEmpty(removed)) {
|
||||||
// tab.removeValueEntries({
|
const removedIndexes = map(removed, 'index')
|
||||||
// server,
|
tab.removeValueEntries({
|
||||||
// db,
|
server,
|
||||||
// key,
|
db,
|
||||||
// type: 'list',
|
key,
|
||||||
// entries: removed,
|
type: 'list',
|
||||||
// })
|
entries: removedIndexes,
|
||||||
// }
|
})
|
||||||
|
}
|
||||||
return { success, removed }
|
return { success, removed }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
|
@ -1262,21 +1321,24 @@ const useBrowserStore = defineStore('browser', {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add item to set
|
* add item to set
|
||||||
* @param {string} connName
|
* @param {string} server
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string|number} key
|
* @param {string|number} key
|
||||||
* @param {string|string[]} value
|
* @param {string|string[]} value
|
||||||
* @returns {Promise<{[msg]: string, success: boolean}>}
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
||||||
*/
|
*/
|
||||||
async addSetItem(connName, db, key, value) {
|
async addSetItem(server, db, key, value) {
|
||||||
try {
|
try {
|
||||||
if ((!value) instanceof Array) {
|
if ((!value) instanceof Array) {
|
||||||
value = [value]
|
value = [value]
|
||||||
}
|
}
|
||||||
const { data, success, msg } = await SetSetItem(connName, db, key, false, value)
|
const { data, success, msg } = await SetSetItem(server, db, key, false, value)
|
||||||
if (success) {
|
if (success) {
|
||||||
|
const { added } = data
|
||||||
|
if (!isEmpty(added)) {
|
||||||
const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
tab.upsertValueEntries({ server: connName, db, key, type: 'set', entries: value })
|
tab.insertValueEntries({ server, db, key, type: 'set', entries: added })
|
||||||
|
}
|
||||||
return { success }
|
return { success }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
|
@ -1293,20 +1355,48 @@ const useBrowserStore = defineStore('browser', {
|
||||||
* @param {string|number[]} key
|
* @param {string|number[]} key
|
||||||
* @param {string|number[]} value
|
* @param {string|number[]} value
|
||||||
* @param {string|number[]} newValue
|
* @param {string|number[]} newValue
|
||||||
* @param {string} [decode]
|
* @param {decodeTypes} [decode]
|
||||||
* @param {string} [format]
|
* @param {formatTypes} [format]
|
||||||
* @returns {Promise<{[msg]: string, success: boolean, [added]: string|number[]}>}
|
* @param {decodeTypes} [retDecode]
|
||||||
|
* @param {formatTypes} [retFormat]
|
||||||
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
||||||
*/
|
*/
|
||||||
async updateSetItem({ server, db, key, value, newValue, decode = decodeTypes.NONE, format = formatTypes.RAW }) {
|
async updateSetItem({
|
||||||
|
server,
|
||||||
|
db,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
newValue,
|
||||||
|
decode = decodeTypes.NONE,
|
||||||
|
format = formatTypes.RAW,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
|
}) {
|
||||||
try {
|
try {
|
||||||
const { data, success, msg } = await UpdateSetItem({ server, db, key, value, newValue, decode, format })
|
const { data, success, msg } = await UpdateSetItem({
|
||||||
|
server,
|
||||||
|
db,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
newValue,
|
||||||
|
decode,
|
||||||
|
format,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
const { added } = data
|
const { added, removed } = data
|
||||||
// const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
// tab.upsertValueEntries({ server, db, key, type: 'set', entries: { [value]: newValue } })
|
if (!isEmpty(removed)) {
|
||||||
return { success: true, added }
|
const removedValues = map(removed, 'v')
|
||||||
|
tab.removeValueEntries({ server, db, key, type: 'set', entries: removedValues })
|
||||||
|
}
|
||||||
|
if (!isEmpty(added)) {
|
||||||
|
tab.insertValueEntries({ server, db, key, type: 'set', entries: added })
|
||||||
|
}
|
||||||
|
return { success }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success: false, msg }
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { success: false, msg: e.message }
|
return { success: false, msg: e.message }
|
||||||
|
@ -1323,10 +1413,14 @@ const useBrowserStore = defineStore('browser', {
|
||||||
*/
|
*/
|
||||||
async removeSetItem(server, db, key, value) {
|
async removeSetItem(server, db, key, value) {
|
||||||
try {
|
try {
|
||||||
const { success, msg } = await SetSetItem(server, db, key, true, [value])
|
const { data, success, msg } = await SetSetItem(server, db, key, true, [value])
|
||||||
if (success) {
|
if (success) {
|
||||||
// const tab = useTabStore()
|
const { removed } = data
|
||||||
// tab.removeValueEntries({ server: connName, db, key, type: 'set', entries: [value] })
|
const tab = useTabStore()
|
||||||
|
if (!isEmpty(removed)) {
|
||||||
|
const removedValues = map(removed, 'v')
|
||||||
|
tab.removeValueEntries({ server, db, key, type: 'set', entries: removedValues })
|
||||||
|
}
|
||||||
return { success }
|
return { success }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
|
@ -1338,19 +1432,25 @@ const useBrowserStore = defineStore('browser', {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add item to sorted set
|
* add item to sorted set
|
||||||
* @param {string} connName
|
* @param {string} server
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string|number[]} key
|
* @param {string|number[]} key
|
||||||
* @param {number} action
|
* @param {number} action
|
||||||
* @param {Object.<string, number>} vs value: score
|
* @param {Object.<string, number>} vs value: score
|
||||||
* @returns {Promise<{[msg]: string, success: boolean}>}
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
||||||
*/
|
*/
|
||||||
async addZSetItem(connName, db, key, action, vs) {
|
async addZSetItem(server, db, key, action, vs) {
|
||||||
try {
|
try {
|
||||||
const { success, msg } = await AddZSetValue(connName, db, key, action, vs)
|
const { data, success, msg } = await AddZSetValue(server, db, key, action, vs)
|
||||||
const tab = useTabStore()
|
|
||||||
tab.upsertValueEntries({ server: connName, db, key, type: 'zset', entries: vs })
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
const { added, updated } = data
|
||||||
|
const tab = useTabStore()
|
||||||
|
if (!isEmpty(added)) {
|
||||||
|
tab.insertValueEntries({ server, db, key, type: 'zset', entries: added })
|
||||||
|
}
|
||||||
|
if (!isEmpty(updated)) {
|
||||||
|
tab.updateValueEntries({ server, db, key, type: 'zset', entries: updated })
|
||||||
|
}
|
||||||
return { success }
|
return { success }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
|
@ -1370,7 +1470,10 @@ const useBrowserStore = defineStore('browser', {
|
||||||
* @param {number} score
|
* @param {number} score
|
||||||
* @param {decodeTypes} decode
|
* @param {decodeTypes} decode
|
||||||
* @param {formatTypes} format
|
* @param {formatTypes} format
|
||||||
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}, [removed]: []}>}
|
* @param {decodeTypes} [retDecode]
|
||||||
|
* @param {formatTypes} [retFormat]
|
||||||
|
* @param {number} [index] index for retrieve affect entries quickly
|
||||||
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
||||||
*/
|
*/
|
||||||
async updateZSetItem({
|
async updateZSetItem({
|
||||||
server,
|
server,
|
||||||
|
@ -1381,6 +1484,9 @@ const useBrowserStore = defineStore('browser', {
|
||||||
score,
|
score,
|
||||||
decode = decodeTypes.NONE,
|
decode = decodeTypes.NONE,
|
||||||
format = formatTypes.RAW,
|
format = formatTypes.RAW,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
|
index,
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const { data, success, msg } = await UpdateZSetValue({
|
const { data, success, msg } = await UpdateZSetValue({
|
||||||
|
@ -1392,16 +1498,25 @@ const useBrowserStore = defineStore('browser', {
|
||||||
score,
|
score,
|
||||||
decode,
|
decode,
|
||||||
format,
|
format,
|
||||||
|
retDecode,
|
||||||
|
retFormat,
|
||||||
})
|
})
|
||||||
if (success) {
|
if (success) {
|
||||||
const { updated, removed } = data
|
const { updated = [], added = [], removed = [], replaced = [] } = data
|
||||||
// const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
// if (!isEmpty(updated)) {
|
if (!isEmpty(removed)) {
|
||||||
// tab.upsertValueEntries({ server, db, key, type: 'zset', entries: updated })
|
const removedValues = map(removed, 'v')
|
||||||
// }
|
tab.removeValueEntries({ server, db, key, type: 'zset', entries: removedValues })
|
||||||
// if (!isEmpty(removed)) {
|
}
|
||||||
// tab.removeValueEntries({ server, db, key, type: 'zset', entries: removed })
|
if (!isEmpty(updated)) {
|
||||||
// }
|
tab.updateValueEntries({ server, db, key, type: 'zset', entries: updated })
|
||||||
|
}
|
||||||
|
if (!isEmpty(added)) {
|
||||||
|
tab.insertValueEntries({ server, db, key, type: 'zset', entries: added })
|
||||||
|
}
|
||||||
|
if (!isEmpty(replaced)) {
|
||||||
|
tab.replaceValueEntries({ server, db, key, type: 'zset', entries: replaced, index: [index] })
|
||||||
|
}
|
||||||
return { success, updated, removed }
|
return { success, updated, removed }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
|
@ -1424,10 +1539,11 @@ const useBrowserStore = defineStore('browser', {
|
||||||
const { data, success, msg } = await UpdateZSetValue({ server, db, key, value, newValue: '', score: 0 })
|
const { data, success, msg } = await UpdateZSetValue({ server, db, key, value, newValue: '', score: 0 })
|
||||||
if (success) {
|
if (success) {
|
||||||
const { removed } = data
|
const { removed } = data
|
||||||
// if (!isEmpty(removed)) {
|
const tab = useTabStore()
|
||||||
// const tab = useTabStore()
|
if (!isEmpty(removed)) {
|
||||||
// tab.removeValueEntries({ server: server, db, key, type: 'zset', entries: removed })
|
const removeValues = map(removed, 'v')
|
||||||
// }
|
tab.removeValueEntries({ server, db, key, type: 'zset', entries: removeValues })
|
||||||
|
}
|
||||||
return { success, removed }
|
return { success, removed }
|
||||||
} else {
|
} else {
|
||||||
return { success, msg }
|
return { success, msg }
|
||||||
|
@ -1439,26 +1555,28 @@ const useBrowserStore = defineStore('browser', {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* insert new stream field item
|
* insert new stream field item
|
||||||
* @param {string} connName
|
* @param {string} server
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string|number[]} key
|
* @param {string|number[]} key
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @param {string[]} values field1, value1, filed2, value2...
|
* @param {string[]} values field1, value1, filed2, value2...
|
||||||
* @returns {Promise<{[msg]: string, success: boolean}>}
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
||||||
*/
|
*/
|
||||||
async addStreamValue(connName, db, key, id, values) {
|
async addStreamValue(server, db, key, id, values) {
|
||||||
try {
|
try {
|
||||||
const { data = {}, success, msg } = await AddStreamValue(connName, db, key, id, values)
|
const { data = {}, success, msg } = await AddStreamValue(server, db, key, id, values)
|
||||||
if (success) {
|
if (success) {
|
||||||
const { updateID } = data
|
const { added = [] } = data
|
||||||
|
if (!isEmpty(added)) {
|
||||||
const tab = useTabStore()
|
const tab = useTabStore()
|
||||||
tab.upsertValueEntries({
|
tab.insertValueEntries({
|
||||||
server: connName,
|
server,
|
||||||
db,
|
db,
|
||||||
key,
|
key,
|
||||||
type: 'stream',
|
type: 'stream',
|
||||||
entries: [{ id: updateID, value: values }],
|
entries: added,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
return { success }
|
return { success }
|
||||||
} else {
|
} else {
|
||||||
return { success: false, msg }
|
return { success: false, msg }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { assign, find, findIndex, get, indexOf, isEmpty, pullAt, remove, set, size } from 'lodash'
|
import { assign, find, findIndex, get, isEmpty, pullAt, remove, set, size } from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
const useTabStore = defineStore('tab', {
|
const useTabStore = defineStore('tab', {
|
||||||
|
@ -25,6 +25,62 @@ const useTabStore = defineStore('tab', {
|
||||||
* @param {boolean} [loading]
|
* @param {boolean} [loading]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ListEntryItem
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ListReplaceItem
|
||||||
|
* @property {number} index
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} HashEntryItem
|
||||||
|
* @property {string} k field name
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} HashReplaceItem
|
||||||
|
* @property {string|number[]} k field name
|
||||||
|
* @property {string|number[]} nk new field name
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SetEntryItem
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ZSetEntryItem
|
||||||
|
* @property {number} s score
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ZSetReplaceItem
|
||||||
|
* @property {number} s score
|
||||||
|
* @property {string|number[]} v value
|
||||||
|
* @property {string|number[]} nv new value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} StreamEntryItem
|
||||||
|
* @property {string} id
|
||||||
|
* @property {Object.<string, *>} v value
|
||||||
|
* @property {string} [dv] display value
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {{tabList: TabItem[], activatedTab: string, activatedIndex: number}}
|
* @returns {{tabList: TabItem[], activatedTab: string, activatedIndex: number}}
|
||||||
|
@ -178,29 +234,22 @@ const useTabStore = defineStore('tab', {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update or insert value entries
|
* insert entries
|
||||||
* @param {string} server
|
* @param {string} server
|
||||||
* @param {number} db
|
* @param {number} db
|
||||||
* @param {string} key
|
* @param {string|number[]} key
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {string[]|Object.<string, number>|Object.<number, string>} entries
|
* @param {ListEntryItem[]|HashEntryItem[]|SetEntryItem[]|ZSetEntryItem[]|StreamEntryItem[]} entries
|
||||||
* @param {boolean} [prepend] for list only
|
* @param {boolean} [prepend] for list only
|
||||||
* @param {boolean} [reset]
|
|
||||||
* @param {boolean} [nocheck] ignore conflict checking for hash/set/zset
|
|
||||||
*/
|
*/
|
||||||
upsertValueEntries({ server, db, key, type, entries, prepend, reset, nocheck }) {
|
insertValueEntries({ server, db, key, type, entries, prepend }) {
|
||||||
const tab = find(this.tabList, { name: server, db, key })
|
const tab = find(this.tabList, { name: server, db, key })
|
||||||
if (tab == null) {
|
if (tab == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type.toLowerCase()) {
|
switch (type.toLowerCase()) {
|
||||||
case 'list': // string[] | Object.<number, string>
|
case 'list': // {v:string, dv:[string]}[]
|
||||||
if (entries instanceof Array) {
|
|
||||||
// append or prepend items
|
|
||||||
if (reset === true) {
|
|
||||||
tab.value = entries
|
|
||||||
} else {
|
|
||||||
tab.value = tab.value || []
|
tab.value = tab.value || []
|
||||||
if (prepend === true) {
|
if (prepend === true) {
|
||||||
tab.value = [...entries, ...tab.value]
|
tab.value = [...entries, ...tab.value]
|
||||||
|
@ -208,87 +257,188 @@ const useTabStore = defineStore('tab', {
|
||||||
tab.value.push(...entries)
|
tab.value.push(...entries)
|
||||||
}
|
}
|
||||||
tab.length += size(entries)
|
tab.length += size(entries)
|
||||||
}
|
break
|
||||||
} else {
|
|
||||||
// replace by index
|
case 'hash': // {k:string, v:string, dv:[string]}[]
|
||||||
|
case 'set': // {v: string, s: number}[]
|
||||||
|
case 'zset': // {v: string, s: number}[]
|
||||||
tab.value = tab.value || []
|
tab.value = tab.value || []
|
||||||
for (const idx in entries) {
|
tab.value.push(...entries)
|
||||||
set(tab.value, idx, entries[idx])
|
tab.length += size(entries)
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'hash': // Object.<string, string>
|
case 'stream': // {id: string, v: {}}[]
|
||||||
if (reset === true) {
|
|
||||||
tab.value = {}
|
|
||||||
tab.length = 0
|
|
||||||
} else {
|
|
||||||
tab.value = tab.value || {}
|
|
||||||
}
|
|
||||||
for (const k in entries) {
|
|
||||||
if (nocheck !== true && !tab.value.hasOwnProperty(k)) {
|
|
||||||
tab.length += 1
|
|
||||||
}
|
|
||||||
tab.value[k] = entries[k]
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'set': // string[] | Object.{string, string}
|
|
||||||
if (reset === true) {
|
|
||||||
tab.value = entries
|
|
||||||
} else {
|
|
||||||
tab.value = tab.value || []
|
|
||||||
if (entries instanceof Array) {
|
|
||||||
// add items
|
|
||||||
for (const elem of entries) {
|
|
||||||
if (nocheck !== true && indexOf(tab.value, elem) === -1) {
|
|
||||||
tab.value.push(elem)
|
|
||||||
tab.length += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// replace items
|
|
||||||
for (const k in entries) {
|
|
||||||
const idx = indexOf(tab.value, k)
|
|
||||||
if (idx !== -1) {
|
|
||||||
tab.value[idx] = entries[k]
|
|
||||||
} else {
|
|
||||||
tab.value.push(entries[k])
|
|
||||||
tab.length += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'zset': // {value: string, score: number}
|
|
||||||
if (reset === true) {
|
|
||||||
tab.value = Object.entries(entries).map(([value, score]) => ({ value, score }))
|
|
||||||
} else {
|
|
||||||
tab.value = tab.value || []
|
|
||||||
for (const val in entries) {
|
|
||||||
if (nocheck !== true) {
|
|
||||||
const ent = find(tab.value, (e) => e.value === val)
|
|
||||||
if (ent != null) {
|
|
||||||
ent.score = entries[val]
|
|
||||||
} else {
|
|
||||||
tab.value.push({ value: val, score: entries[val] })
|
|
||||||
tab.length += 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tab.value.push({ value: val, score: entries[val] })
|
|
||||||
tab.length += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'stream': // [{id: string, value: []any}]
|
|
||||||
if (reset === true) {
|
|
||||||
tab.value = entries
|
|
||||||
} else {
|
|
||||||
tab.value = tab.value || []
|
tab.value = tab.value || []
|
||||||
tab.value = [...entries, ...tab.value]
|
tab.value = [...entries, ...tab.value]
|
||||||
|
tab.length += size(entries)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update entries' value
|
||||||
|
* @param {string} server
|
||||||
|
* @param {number} db
|
||||||
|
* @param {string|number[]} key
|
||||||
|
* @param {string} type
|
||||||
|
* @param {ListEntryItem[]|HashEntryItem[]|SetEntryItem[]|ZSetEntryItem[]|StreamEntryItem[]} entries
|
||||||
|
*/
|
||||||
|
updateValueEntries({ server, db, key, type, entries }) {
|
||||||
|
const tab = find(this.tabList, { name: server, db, key })
|
||||||
|
if (tab == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type.toLowerCase()) {
|
||||||
|
case 'hash': // {k:string, v:string, dv:string}[]
|
||||||
|
tab.value = tab.value || []
|
||||||
|
for (const entry of entries) {
|
||||||
|
let updated = false
|
||||||
|
for (const val of tab.value) {
|
||||||
|
if (val.k === entry.k) {
|
||||||
|
val.v = entry.v
|
||||||
|
val.dv = entry.dv
|
||||||
|
updated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!updated) {
|
||||||
|
// no match element, append
|
||||||
|
tab.value.push(entry)
|
||||||
|
tab.length += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'zset': // {s:number, v:string, dv:string}[]
|
||||||
|
tab.value = tab.value || []
|
||||||
|
for (const entry of entries) {
|
||||||
|
let updated = false
|
||||||
|
for (const val of tab.value) {
|
||||||
|
if (val.v === entry.v) {
|
||||||
|
val.s = entry.s
|
||||||
|
val.dv = entry.dv
|
||||||
|
updated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!updated) {
|
||||||
|
// no match element, append
|
||||||
|
tab.value.push(entry)
|
||||||
|
tab.length += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* replace entry item key or field in value(modify the index key)
|
||||||
|
* @param {string} server
|
||||||
|
* @param {number} db
|
||||||
|
* @param {string|number[]} key
|
||||||
|
* @param {string} type
|
||||||
|
* @param {ListReplaceItem[]|HashReplaceItem[]|ZSetReplaceItem[]} entries
|
||||||
|
* @param {number[]} [index] indexes for replacement, can improve search efficiency if configured
|
||||||
|
*/
|
||||||
|
replaceValueEntries({ server, db, key, type, entries, index }) {
|
||||||
|
const tab = find(this.tabList, { name: server, db, key })
|
||||||
|
if (tab == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type.toLowerCase()) {
|
||||||
|
case 'list': // ListReplaceItem[]
|
||||||
|
tab.value = tab.value || []
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (size(tab.value) > entry.index) {
|
||||||
|
tab.value[entry.index] = {
|
||||||
|
v: entry.v,
|
||||||
|
dv: entry.dv,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// out of range, append
|
||||||
|
tab.value.push(entry)
|
||||||
|
tab.length += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'hash': // HashReplaceItem[]
|
||||||
|
tab.value = tab.value || []
|
||||||
|
for (const idx of index) {
|
||||||
|
const entry = get(tab.value, idx)
|
||||||
|
if (entry != null) {
|
||||||
|
/** @type HashReplaceItem[] **/
|
||||||
|
const replaceEntry = remove(entries, (e) => e.k === entry.k)
|
||||||
|
if (!isEmpty(replaceEntry)) {
|
||||||
|
entry.k = replaceEntry[0].nk
|
||||||
|
entry.v = replaceEntry[0].v
|
||||||
|
entry.dv = replaceEntry[0].dv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the left entries do not included in index list, try to retrieve the whole list
|
||||||
|
for (const entry of entries) {
|
||||||
|
let updated = false
|
||||||
|
for (const val of tab.value) {
|
||||||
|
if (val.k === entry.k) {
|
||||||
|
val.k = entry.nk
|
||||||
|
val.v = entry.v
|
||||||
|
val.dv = entry.dv
|
||||||
|
updated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!updated) {
|
||||||
|
// no match element, append
|
||||||
|
tab.value.push({
|
||||||
|
k: entry.nk,
|
||||||
|
v: entry.v,
|
||||||
|
dv: entry.dv,
|
||||||
|
})
|
||||||
|
tab.length += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'zset': // ZSetReplaceItem[]
|
||||||
|
tab.value = tab.value || []
|
||||||
|
for (const idx of index) {
|
||||||
|
const entry = get(tab.value, idx)
|
||||||
|
if (entry != null) {
|
||||||
|
/** @type ZSetReplaceItem[] **/
|
||||||
|
const replaceEntry = remove(entries, ({ v }) => v === entry.k)
|
||||||
|
if (!isEmpty(replaceEntry)) {
|
||||||
|
entry.s = replaceEntry[0].s
|
||||||
|
entry.v = replaceEntry[0].nv
|
||||||
|
entry.dv = replaceEntry[0].dv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the left entries do not included in index list, try to retrieve the whole list
|
||||||
|
for (const entry of entries) {
|
||||||
|
let updated = false
|
||||||
|
for (const val of tab.value) {
|
||||||
|
if (val.v === entry.v) {
|
||||||
|
val.s = entry.s
|
||||||
|
val.v = entry.nv
|
||||||
|
val.dv = entry.dv
|
||||||
|
updated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!updated) {
|
||||||
|
// no match element, append
|
||||||
|
tab.value.push({
|
||||||
|
s: entry.s,
|
||||||
|
v: entry.nv,
|
||||||
|
dv: entry.dv,
|
||||||
|
})
|
||||||
|
tab.length += 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -312,7 +462,7 @@ const useTabStore = defineStore('tab', {
|
||||||
case 'list': // string[] | number[]
|
case 'list': // string[] | number[]
|
||||||
tab.value = tab.value || []
|
tab.value = tab.value || []
|
||||||
if (typeof entries[0] === 'number') {
|
if (typeof entries[0] === 'number') {
|
||||||
// remove by index、
|
// remove by index, sort by desc first
|
||||||
entries.sort((a, b) => b - a)
|
entries.sort((a, b) => b - a)
|
||||||
const removed = pullAt(tab.value, ...entries)
|
const removed = pullAt(tab.value, ...entries)
|
||||||
tab.length -= size(removed)
|
tab.length -= size(removed)
|
||||||
|
@ -329,26 +479,41 @@ const useTabStore = defineStore('tab', {
|
||||||
case 'hash': // string[]
|
case 'hash': // string[]
|
||||||
tab.value = tab.value || {}
|
tab.value = tab.value || {}
|
||||||
for (const k of entries) {
|
for (const k of entries) {
|
||||||
if (tab.value.hasOwnProperty(k)) {
|
for (let i = 0; i < tab.value.length; i++) {
|
||||||
delete tab.value[k]
|
if (tab.value[i].k === k) {
|
||||||
|
tab.value.splice(i, 1)
|
||||||
tab.length -= 1
|
tab.length -= 1
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'set': // []string
|
case 'set': // string[]
|
||||||
tab.value = tab.value || []
|
|
||||||
tab.length -= size(remove(tab.value, (v) => entries.indexOf(v) >= 0))
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'zset': // string[]
|
case 'zset': // string[]
|
||||||
tab.value = tab.value || []
|
tab.value = tab.value || []
|
||||||
tab.length -= size(remove(tab.value, (v) => entries.indexOf(v.value) >= 0))
|
for (const v of entries) {
|
||||||
|
for (let i = 0; i < tab.value.length; i++) {
|
||||||
|
if (tab.value[i].v === v) {
|
||||||
|
tab.value.splice(i, 1)
|
||||||
|
tab.length -= 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'stream': // string[]
|
case 'stream': // string[]
|
||||||
tab.value = tab.value || []
|
tab.value = tab.value || []
|
||||||
tab.length -= size(remove(tab.value, (v) => entries.indexOf(v.id) >= 0))
|
for (const id of entries) {
|
||||||
|
for (let i = 0; i < tab.value.length; i++) {
|
||||||
|
if (tab.value[i].id === id) {
|
||||||
|
tab.value.splice(i, 1)
|
||||||
|
tab.length -= 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -86,6 +86,7 @@ body {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
//padding: 5px;
|
//padding: 5px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.tb2 {
|
.tb2 {
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import usePreferencesStore from 'stores/preferences.js'
|
import usePreferencesStore from 'stores/preferences.js'
|
||||||
import { createDiscreteApi, darkTheme } from 'naive-ui'
|
import { createDiscreteApi, darkTheme } from 'naive-ui'
|
||||||
import { themeOverrides } from '@/utils/theme.js'
|
import { darkThemeOverrides, themeOverrides } from '@/utils/theme.js'
|
||||||
import { i18nGlobal } from '@/utils/i18n.js'
|
import { i18nGlobal } from '@/utils/i18n.js'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
@ -106,6 +106,10 @@ export async function setupDiscreteApi() {
|
||||||
messageProviderProps: {
|
messageProviderProps: {
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
keepAliveOnHover: true,
|
keepAliveOnHover: true,
|
||||||
|
containerStyle: {
|
||||||
|
marginBottom: '38px',
|
||||||
|
},
|
||||||
|
themeOverrides: prefStore.isDark ? darkThemeOverrides.Message : themeOverrides.Message,
|
||||||
},
|
},
|
||||||
notificationProviderProps: {
|
notificationProviderProps: {
|
||||||
max: 5,
|
max: 5,
|
||||||
|
|
|
@ -57,9 +57,6 @@ export const themeOverrides = {
|
||||||
buttonColorActive: '#D13B37',
|
buttonColorActive: '#D13B37',
|
||||||
buttonTextColorActive: '#FFF',
|
buttonTextColorActive: '#FFF',
|
||||||
},
|
},
|
||||||
Message: {
|
|
||||||
margin: '0 0 38px 0',
|
|
||||||
},
|
|
||||||
DataTable: {
|
DataTable: {
|
||||||
thPaddingSmall: '6px 8px',
|
thPaddingSmall: '6px 8px',
|
||||||
tdPaddingSmall: '6px 8px',
|
tdPaddingSmall: '6px 8px',
|
||||||
|
|
Loading…
Reference in New Issue