Compare commits
5 Commits
1a49db2450
...
30e7016aa3
Author | SHA1 | Date |
---|---|---|
tiny-craft | 30e7016aa3 | |
tiny-craft | b5dfe377fa | |
tiny-craft | ee68d699fa | |
tiny-craft | 477ed19d20 | |
tiny-craft | d2aa9317b9 |
|
@ -9,15 +9,16 @@ import (
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
. "tinyrdm/backend/storage"
|
. "tinyrdm/backend/storage"
|
||||||
"tinyrdm/backend/types"
|
"tinyrdm/backend/types"
|
||||||
|
"tinyrdm/backend/utils/coll"
|
||||||
maputil "tinyrdm/backend/utils/map"
|
maputil "tinyrdm/backend/utils/map"
|
||||||
redis2 "tinyrdm/backend/utils/redis"
|
redis2 "tinyrdm/backend/utils/redis"
|
||||||
|
sliceutil "tinyrdm/backend/utils/slice"
|
||||||
strutil "tinyrdm/backend/utils/string"
|
strutil "tinyrdm/backend/utils/string"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ func (c *connectionService) Stop(ctx context.Context) {
|
||||||
c.connMap = map[string]connectionItem{}
|
c.connMap = map[string]connectionItem{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connectionService) createRedisClient(config types.ConnectionConfig) (*redis.Client, error) {
|
func (c *connectionService) buildOption(config types.ConnectionConfig) (*redis.Options, error) {
|
||||||
var sshClient *ssh.Client
|
var sshClient *ssh.Client
|
||||||
if config.SSH.Enable {
|
if config.SSH.Enable {
|
||||||
sshConfig := &ssh.ClientConfig{
|
sshConfig := &ssh.ClientConfig{
|
||||||
|
@ -127,10 +128,70 @@ func (c *connectionService) createRedisClient(config types.ConnectionConfig) (*r
|
||||||
option.ReadTimeout = -2
|
option.ReadTimeout = -2
|
||||||
option.WriteTimeout = -2
|
option.WriteTimeout = -2
|
||||||
}
|
}
|
||||||
|
return option, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *connectionService) createRedisClient(config types.ConnectionConfig) (*redis.Client, error) {
|
||||||
|
option, err := c.buildOption(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Sentinel.Enable {
|
||||||
|
sentinel := redis.NewSentinelClient(option)
|
||||||
|
defer sentinel.Close()
|
||||||
|
|
||||||
|
var addr []string
|
||||||
|
addr, err = sentinel.GetMasterAddrByName(c.ctx, config.Sentinel.Master).Result()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(addr) < 2 {
|
||||||
|
return nil, errors.New("cannot get master address")
|
||||||
|
}
|
||||||
|
option.Addr = fmt.Sprintf("%s:%s", addr[0], addr[1])
|
||||||
|
option.Username = config.Sentinel.Username
|
||||||
|
option.Password = config.Sentinel.Password
|
||||||
|
}
|
||||||
|
|
||||||
rdb := redis.NewClient(option)
|
rdb := redis.NewClient(option)
|
||||||
return rdb, nil
|
return rdb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListSentinelMasters list all master info by sentinel
|
||||||
|
func (c *connectionService) ListSentinelMasters(config types.ConnectionConfig) (resp types.JSResp) {
|
||||||
|
option, err := c.buildOption(config)
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.DialTimeout > 0 {
|
||||||
|
option.DialTimeout = 10 * time.Second
|
||||||
|
}
|
||||||
|
sentinel := redis.NewSentinelClient(option)
|
||||||
|
defer sentinel.Close()
|
||||||
|
|
||||||
|
var retInfo []map[string]string
|
||||||
|
masterInfos, err := sentinel.Masters(c.ctx).Result()
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, info := range masterInfos {
|
||||||
|
if infoMap, ok := info.(map[any]any); ok {
|
||||||
|
retInfo = append(retInfo, map[string]string{
|
||||||
|
"name": infoMap["name"].(string),
|
||||||
|
"addr": fmt.Sprintf("%s:%s", infoMap["ip"].(string), infoMap["port"].(string)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Data = retInfo
|
||||||
|
resp.Success = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (c *connectionService) TestConnection(config types.ConnectionConfig) (resp types.JSResp) {
|
func (c *connectionService) TestConnection(config types.ConnectionConfig) (resp types.JSResp) {
|
||||||
rdb, err := c.createRedisClient(config)
|
rdb, err := c.createRedisClient(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -138,7 +199,8 @@ func (c *connectionService) TestConnection(config types.ConnectionConfig) (resp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer rdb.Close()
|
defer rdb.Close()
|
||||||
if _, err := rdb.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
|
||||||
|
if _, err = rdb.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
||||||
resp.Msg = err.Error()
|
resp.Msg = err.Error()
|
||||||
} else {
|
} else {
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
|
@ -291,6 +353,7 @@ func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
||||||
dbInfo := c.parseDBItemInfo(dbInfoStr)
|
dbInfo := c.parseDBItemInfo(dbInfoStr)
|
||||||
return types.ConnectionDB{
|
return types.ConnectionDB{
|
||||||
Name: dbName,
|
Name: dbName,
|
||||||
|
Index: idx,
|
||||||
Keys: dbInfo["keys"],
|
Keys: dbInfo["keys"],
|
||||||
Expires: dbInfo["expires"],
|
Expires: dbInfo["expires"],
|
||||||
AvgTTL: dbInfo["avg_ttl"],
|
AvgTTL: dbInfo["avg_ttl"],
|
||||||
|
@ -298,17 +361,20 @@ func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
||||||
} else {
|
} else {
|
||||||
return types.ConnectionDB{
|
return types.ConnectionDB{
|
||||||
Name: dbName,
|
Name: dbName,
|
||||||
|
Index: idx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch selConn.DBFilterType {
|
switch selConn.DBFilterType {
|
||||||
case "show":
|
case "show":
|
||||||
for _, idx := range selConn.DBFilterList {
|
filterList := sliceutil.Unique(selConn.DBFilterList)
|
||||||
|
for _, idx := range filterList {
|
||||||
dbs = append(dbs, queryDB(idx))
|
dbs = append(dbs, queryDB(idx))
|
||||||
}
|
}
|
||||||
case "hide":
|
case "hide":
|
||||||
|
hiddenList := coll.NewSet(selConn.DBFilterList...)
|
||||||
for idx := 0; idx < totaldb; idx++ {
|
for idx := 0; idx < totaldb; idx++ {
|
||||||
if !slices.Contains(selConn.DBFilterList, idx) {
|
if !hiddenList.Contains(idx) {
|
||||||
dbs = append(dbs, queryDB(idx))
|
dbs = append(dbs, queryDB(idx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,9 @@ func (c *ConnectionsStorage) defaultConnectionItem() types.ConnectionConfig {
|
||||||
DBFilterType: "none",
|
DBFilterType: "none",
|
||||||
DBFilterList: []int{},
|
DBFilterList: []int{},
|
||||||
MarkColor: "",
|
MarkColor: "",
|
||||||
|
Sentinel: types.ConnectionSentinel{
|
||||||
|
Master: "mymaster",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,8 +195,7 @@ func (c *ConnectionsStorage) UpdateConnection(name string, param types.Connectio
|
||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err := retrieve(conn.Connections, name, param)
|
if err := retrieve(conn.Connections, name, param); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +286,7 @@ func (c *ConnectionsStorage) SaveSortedConnection(sortedConns types.Connections)
|
||||||
return c.saveConnections(conns)
|
return c.saveConnections(conns)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateGroup create new group
|
// CreateGroup create a new group
|
||||||
func (c *ConnectionsStorage) CreateGroup(name string) error {
|
func (c *ConnectionsStorage) CreateGroup(name string) error {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
|
@ -330,7 +332,7 @@ func (c *ConnectionsStorage) RenameGroup(name, newName string) error {
|
||||||
return c.saveConnections(conns)
|
return c.saveConnections(conns)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteGroup remove special group, include all connections under it
|
// DeleteGroup remove specified group, include all connections under it
|
||||||
func (c *ConnectionsStorage) DeleteGroup(group string, includeConnection bool) error {
|
func (c *ConnectionsStorage) DeleteGroup(group string, includeConnection bool) error {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
|
|
|
@ -17,6 +17,7 @@ type ConnectionConfig struct {
|
||||||
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
||||||
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
||||||
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
||||||
|
Sentinel ConnectionSentinel `json:"sentinel,omitempty" yaml:"sentinel,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
|
@ -34,6 +35,7 @@ type ConnectionGroup struct {
|
||||||
|
|
||||||
type ConnectionDB struct {
|
type ConnectionDB struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Index int `json:"index"`
|
||||||
Keys int `json:"keys"`
|
Keys int `json:"keys"`
|
||||||
Expires int `json:"expires,omitempty"`
|
Expires int `json:"expires,omitempty"`
|
||||||
AvgTTL int `json:"avgTtl,omitempty"`
|
AvgTTL int `json:"avgTtl,omitempty"`
|
||||||
|
@ -44,8 +46,15 @@ type ConnectionSSH struct {
|
||||||
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
|
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
|
||||||
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
||||||
LoginType string `json:"loginType" yaml:"login_type"`
|
LoginType string `json:"loginType" yaml:"login_type"`
|
||||||
Username string `json:"username" yaml:"username"`
|
Username string `json:"username" yaml:"username,omitempty"`
|
||||||
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
||||||
PKFile string `json:"pkFile,omitempty" yaml:"pk_file,omitempty"`
|
PKFile string `json:"pkFile,omitempty" yaml:"pk_file,omitempty"`
|
||||||
Passphrase string `json:"passphrase,omitempty" yaml:"passphrase,omitempty"`
|
Passphrase string `json:"passphrase,omitempty" yaml:"passphrase,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConnectionSentinel struct {
|
||||||
|
Enable bool `json:"enable" yaml:"enable"`
|
||||||
|
Master string `json:"master" yaml:"master"`
|
||||||
|
Username string `json:"username,omitempty" yaml:"username,omitempty"`
|
||||||
|
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
||||||
|
}
|
||||||
|
|
|
@ -178,11 +178,11 @@ func decodeBinary(str string) (string, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeHex(str string) (string, bool) {
|
func decodeHex(str string) (string, bool) {
|
||||||
encodeStr := hex.EncodeToString([]byte(str))
|
decodeStr := hex.EncodeToString([]byte(str))
|
||||||
var resultStr strings.Builder
|
var resultStr strings.Builder
|
||||||
for i := 0; i < len(encodeStr); i += 2 {
|
for i := 0; i < len(decodeStr); i += 2 {
|
||||||
resultStr.WriteString("\\x")
|
resultStr.WriteString("\\x")
|
||||||
resultStr.WriteString(encodeStr[i : i+2])
|
resultStr.WriteString(decodeStr[i : i+2])
|
||||||
}
|
}
|
||||||
return resultStr.String(), true
|
return resultStr.String(), true
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,18 @@
|
||||||
"highlight.js": "^11.8.0",
|
"highlight.js": "^11.8.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"sass": "^1.68.0",
|
"sass": "^1.69.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.4.1"
|
"vue-i18n": "^9.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.3.4",
|
"@vitejs/plugin-vue": "^4.4.0",
|
||||||
"naive-ui": "^2.34.4",
|
"naive-ui": "^2.35.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"unplugin-auto-import": "^0.16.6",
|
"unplugin-auto-import": "^0.16.6",
|
||||||
"unplugin-icons": "^0.17.0",
|
"unplugin-icons": "^0.17.0",
|
||||||
"unplugin-vue-components": "^0.25.2",
|
"unplugin-vue-components": "^0.25.2",
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@antfu/install-pkg": {
|
"node_modules/@antfu/install-pkg": {
|
||||||
|
@ -54,9 +54,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.22.15",
|
"version": "7.23.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.15.tgz",
|
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.1.tgz",
|
||||||
"integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
|
"integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
@ -462,23 +462,23 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/core-base": {
|
"node_modules/@intlify/core-base": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.5.0.tgz",
|
||||||
"integrity": "sha512-WIwx+elsZbxSMxRG5+LC+utRohFvmZMoDevfKOfnYMLbpCjCSavqTfHJAtfsY6ruowzqXeKkeLhRHbYbjoJx5g==",
|
"integrity": "sha512-y3ufM1RJbI/DSmJf3lYs9ACq3S/iRvaSsE3rPIk0MGH7fp+JxU6rdryv/EYcwfcr3Y1aHFlCBir6S391hRZ57w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/message-compiler": "9.4.1",
|
"@intlify/message-compiler": "9.5.0",
|
||||||
"@intlify/shared": "9.4.1"
|
"@intlify/shared": "9.5.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16"
|
"node": ">= 16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/message-compiler": {
|
"node_modules/@intlify/message-compiler": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.5.0.tgz",
|
||||||
"integrity": "sha512-aN2N+dUx320108QhH51Ycd2LEpZ+NKbzyQ2kjjhqMcxhHdxtOnkgdx+MDBhOy/CObwBmhC3Nygzc6hNlfKvPNw==",
|
"integrity": "sha512-CAhVNfEZcOVFg0/5MNyt+OFjvs4J/ARjCj2b+54/FvFP0EDJI5lIqMTSDBE7k0atMROSP0SvWCkwu/AZ5xkK1g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/shared": "9.4.1",
|
"@intlify/shared": "9.5.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -486,9 +486,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/shared": {
|
"node_modules/@intlify/shared": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.5.0.tgz",
|
||||||
"integrity": "sha512-A51elBmZWf1FS80inf/32diO9DeXoqg9GR9aUDHFcfHoNDuT46Q+fpPOdj8jiJnSHSBh8E1E+6qWRhAZXdK3Ng==",
|
"integrity": "sha512-tAxV14LMXZDZbu32XzLMTsowNlgJNmLwWHYzvMUl6L8gvQeoYiZONjY7AUsqZW8TOZDX9lfvF6adPkk9FSRdDA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16"
|
"node": ">= 16"
|
||||||
}
|
}
|
||||||
|
@ -568,9 +568,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/katex": {
|
"node_modules/@types/katex": {
|
||||||
"version": "0.14.0",
|
"version": "0.16.3",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.14.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.16.3.tgz",
|
||||||
"integrity": "sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==",
|
"integrity": "sha512-CeVMX9EhVUW8MWnei05eIRks4D5Wscw/W9Byz1s3PA+yJvcdvq9SaDjiUKvRvEgjpdTyJMjQA43ae4KTwsvOPg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
|
@ -589,9 +589,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
"version": "4.3.4",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz",
|
||||||
"integrity": "sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==",
|
"integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.18.0 || >=16.0.0"
|
"node": "^14.18.0 || >=16.0.0"
|
||||||
|
@ -840,9 +840,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/date-fns-tz": {
|
"node_modules/date-fns-tz": {
|
||||||
"version": "1.3.8",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-1.3.8.tgz",
|
"resolved": "https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-2.0.0.tgz",
|
||||||
"integrity": "sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==",
|
"integrity": "sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"date-fns": ">=2.0.0"
|
"date-fns": ">=2.0.0"
|
||||||
|
@ -1254,22 +1254,22 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/naive-ui": {
|
"node_modules/naive-ui": {
|
||||||
"version": "2.34.4",
|
"version": "2.35.0",
|
||||||
"resolved": "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.34.4.tgz",
|
"resolved": "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.35.0.tgz",
|
||||||
"integrity": "sha512-aPG8PDfhSzIzn/jSC9y3Jb3Pe2wHJ7F0cFV1EWlbImSrZECeUmoc+fIcOSWbizoztkKfaUAeKwYdMl09MKkj1g==",
|
"integrity": "sha512-PdnLpOip1LQaKs5+rXLZoPDPQkTq26TnHWeABvUA2eOQjtHxE4+TQvj0Jq/W8clM2On/7jptoGmenLt48G3Bhg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@css-render/plugin-bem": "^0.15.10",
|
"@css-render/plugin-bem": "^0.15.12",
|
||||||
"@css-render/vue3-ssr": "^0.15.10",
|
"@css-render/vue3-ssr": "^0.15.12",
|
||||||
"@types/katex": "^0.14.0",
|
"@types/katex": "^0.16.2",
|
||||||
"@types/lodash": "^4.14.181",
|
"@types/lodash": "^4.14.198",
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.9",
|
||||||
"async-validator": "^4.0.7",
|
"async-validator": "^4.2.5",
|
||||||
"css-render": "^0.15.10",
|
"css-render": "^0.15.12",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.30.0",
|
||||||
"date-fns-tz": "^1.3.3",
|
"date-fns-tz": "^2.0.0",
|
||||||
"evtd": "^0.2.4",
|
"evtd": "^0.2.4",
|
||||||
"highlight.js": "^11.5.0",
|
"highlight.js": "^11.8.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"seemly": "^0.3.6",
|
"seemly": "^0.3.6",
|
||||||
|
@ -1545,9 +1545,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.68.0",
|
"version": "1.69.0",
|
||||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.68.0.tgz",
|
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.69.0.tgz",
|
||||||
"integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==",
|
"integrity": "sha512-l3bbFpfTOGgQZCLU/gvm1lbsQ5mC/WnLz3djL2v4WCJBDrWm58PO+jgngcGRNnKUh6wSsdm50YaovTqskZ0xDQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
"immutable": "^4.0.0",
|
"immutable": "^4.0.0",
|
||||||
|
@ -1805,9 +1805,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.4.9",
|
"version": "4.4.11",
|
||||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-4.4.9.tgz",
|
"resolved": "https://registry.npmmirror.com/vite/-/vite-4.4.11.tgz",
|
||||||
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
|
"integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
|
@ -1881,12 +1881,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-i18n": {
|
"node_modules/vue-i18n": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.5.0.tgz",
|
||||||
"integrity": "sha512-vnQyYE9LBuNOqPpETIcCaGnAyLEqfeIvDcyZ9T+WBCWFTqWw1J8FuF1jfeDwpHBi5JKgAwgXyq1mt8jp/x/GPA==",
|
"integrity": "sha512-NiI3Ph1qMstNf7uhYh8trQBOBFLxeJgcOxBq51pCcZ28Vs18Y7BDS58r8HGDKCYgXdLUYqPDXdKatIF4bvBVZg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/core-base": "9.4.1",
|
"@intlify/core-base": "9.5.0",
|
||||||
"@intlify/shared": "9.4.1",
|
"@intlify/shared": "9.5.0",
|
||||||
"@vue/devtools-api": "^6.5.0"
|
"@vue/devtools-api": "^6.5.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1977,9 +1977,9 @@
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA=="
|
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA=="
|
||||||
},
|
},
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.22.15",
|
"version": "7.23.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.15.tgz",
|
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.1.tgz",
|
||||||
"integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
|
"integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
@ -2180,27 +2180,27 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@intlify/core-base": {
|
"@intlify/core-base": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.5.0.tgz",
|
||||||
"integrity": "sha512-WIwx+elsZbxSMxRG5+LC+utRohFvmZMoDevfKOfnYMLbpCjCSavqTfHJAtfsY6ruowzqXeKkeLhRHbYbjoJx5g==",
|
"integrity": "sha512-y3ufM1RJbI/DSmJf3lYs9ACq3S/iRvaSsE3rPIk0MGH7fp+JxU6rdryv/EYcwfcr3Y1aHFlCBir6S391hRZ57w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@intlify/message-compiler": "9.4.1",
|
"@intlify/message-compiler": "9.5.0",
|
||||||
"@intlify/shared": "9.4.1"
|
"@intlify/shared": "9.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@intlify/message-compiler": {
|
"@intlify/message-compiler": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-9.5.0.tgz",
|
||||||
"integrity": "sha512-aN2N+dUx320108QhH51Ycd2LEpZ+NKbzyQ2kjjhqMcxhHdxtOnkgdx+MDBhOy/CObwBmhC3Nygzc6hNlfKvPNw==",
|
"integrity": "sha512-CAhVNfEZcOVFg0/5MNyt+OFjvs4J/ARjCj2b+54/FvFP0EDJI5lIqMTSDBE7k0atMROSP0SvWCkwu/AZ5xkK1g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@intlify/shared": "9.4.1",
|
"@intlify/shared": "9.5.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@intlify/shared": {
|
"@intlify/shared": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.5.0.tgz",
|
||||||
"integrity": "sha512-A51elBmZWf1FS80inf/32diO9DeXoqg9GR9aUDHFcfHoNDuT46Q+fpPOdj8jiJnSHSBh8E1E+6qWRhAZXdK3Ng=="
|
"integrity": "sha512-tAxV14LMXZDZbu32XzLMTsowNlgJNmLwWHYzvMUl6L8gvQeoYiZONjY7AUsqZW8TOZDX9lfvF6adPkk9FSRdDA=="
|
||||||
},
|
},
|
||||||
"@jridgewell/sourcemap-codec": {
|
"@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
|
@ -2257,9 +2257,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/katex": {
|
"@types/katex": {
|
||||||
"version": "0.14.0",
|
"version": "0.16.3",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.14.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/katex/-/katex-0.16.3.tgz",
|
||||||
"integrity": "sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==",
|
"integrity": "sha512-CeVMX9EhVUW8MWnei05eIRks4D5Wscw/W9Byz1s3PA+yJvcdvq9SaDjiUKvRvEgjpdTyJMjQA43ae4KTwsvOPg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/lodash": {
|
"@types/lodash": {
|
||||||
|
@ -2278,9 +2278,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vitejs/plugin-vue": {
|
"@vitejs/plugin-vue": {
|
||||||
"version": "4.3.4",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz",
|
||||||
"integrity": "sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==",
|
"integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
@ -2496,9 +2496,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"date-fns-tz": {
|
"date-fns-tz": {
|
||||||
"version": "1.3.8",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-1.3.8.tgz",
|
"resolved": "https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-2.0.0.tgz",
|
||||||
"integrity": "sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==",
|
"integrity": "sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
@ -2820,22 +2820,22 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"naive-ui": {
|
"naive-ui": {
|
||||||
"version": "2.34.4",
|
"version": "2.35.0",
|
||||||
"resolved": "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.34.4.tgz",
|
"resolved": "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.35.0.tgz",
|
||||||
"integrity": "sha512-aPG8PDfhSzIzn/jSC9y3Jb3Pe2wHJ7F0cFV1EWlbImSrZECeUmoc+fIcOSWbizoztkKfaUAeKwYdMl09MKkj1g==",
|
"integrity": "sha512-PdnLpOip1LQaKs5+rXLZoPDPQkTq26TnHWeABvUA2eOQjtHxE4+TQvj0Jq/W8clM2On/7jptoGmenLt48G3Bhg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@css-render/plugin-bem": "^0.15.10",
|
"@css-render/plugin-bem": "^0.15.12",
|
||||||
"@css-render/vue3-ssr": "^0.15.10",
|
"@css-render/vue3-ssr": "^0.15.12",
|
||||||
"@types/katex": "^0.14.0",
|
"@types/katex": "^0.16.2",
|
||||||
"@types/lodash": "^4.14.181",
|
"@types/lodash": "^4.14.198",
|
||||||
"@types/lodash-es": "^4.17.6",
|
"@types/lodash-es": "^4.17.9",
|
||||||
"async-validator": "^4.0.7",
|
"async-validator": "^4.2.5",
|
||||||
"css-render": "^0.15.10",
|
"css-render": "^0.15.12",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.30.0",
|
||||||
"date-fns-tz": "^1.3.3",
|
"date-fns-tz": "^2.0.0",
|
||||||
"evtd": "^0.2.4",
|
"evtd": "^0.2.4",
|
||||||
"highlight.js": "^11.5.0",
|
"highlight.js": "^11.8.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"seemly": "^0.3.6",
|
"seemly": "^0.3.6",
|
||||||
|
@ -3025,9 +3025,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"version": "1.68.0",
|
"version": "1.69.0",
|
||||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.68.0.tgz",
|
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.69.0.tgz",
|
||||||
"integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==",
|
"integrity": "sha512-l3bbFpfTOGgQZCLU/gvm1lbsQ5mC/WnLz3djL2v4WCJBDrWm58PO+jgngcGRNnKUh6wSsdm50YaovTqskZ0xDQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
"immutable": "^4.0.0",
|
"immutable": "^4.0.0",
|
||||||
|
@ -3203,9 +3203,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vite": {
|
"vite": {
|
||||||
"version": "4.4.9",
|
"version": "4.4.11",
|
||||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-4.4.9.tgz",
|
"resolved": "https://registry.npmmirror.com/vite/-/vite-4.4.11.tgz",
|
||||||
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
|
"integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
|
@ -3236,12 +3236,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vue-i18n": {
|
"vue-i18n": {
|
||||||
"version": "9.4.1",
|
"version": "9.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.5.0.tgz",
|
||||||
"integrity": "sha512-vnQyYE9LBuNOqPpETIcCaGnAyLEqfeIvDcyZ9T+WBCWFTqWw1J8FuF1jfeDwpHBi5JKgAwgXyq1mt8jp/x/GPA==",
|
"integrity": "sha512-NiI3Ph1qMstNf7uhYh8trQBOBFLxeJgcOxBq51pCcZ28Vs18Y7BDS58r8HGDKCYgXdLUYqPDXdKatIF4bvBVZg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@intlify/core-base": "9.4.1",
|
"@intlify/core-base": "9.5.0",
|
||||||
"@intlify/shared": "9.4.1",
|
"@intlify/shared": "9.5.0",
|
||||||
"@vue/devtools-api": "^6.5.0"
|
"@vue/devtools-api": "^6.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,17 +13,17 @@
|
||||||
"highlight.js": "^11.8.0",
|
"highlight.js": "^11.8.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"sass": "^1.68.0",
|
"sass": "^1.69.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.4.1"
|
"vue-i18n": "^9.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.3.4",
|
"@vitejs/plugin-vue": "^4.4.0",
|
||||||
"naive-ui": "^2.34.4",
|
"naive-ui": "^2.35.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"unplugin-auto-import": "^0.16.6",
|
"unplugin-auto-import": "^0.16.6",
|
||||||
"unplugin-icons": "^0.17.0",
|
"unplugin-icons": "^0.17.0",
|
||||||
"unplugin-vue-components": "^0.25.2",
|
"unplugin-vue-components": "^0.25.2",
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
a65375421b9b10cadef51ed8edc1c6f1
|
82f42b67ae979cb1af64c05c79c5251f
|
|
@ -2,7 +2,7 @@
|
||||||
import { every, get, includes, isEmpty, map, sortBy, toNumber } from 'lodash'
|
import { every, get, includes, isEmpty, map, sortBy, toNumber } from 'lodash'
|
||||||
import { computed, nextTick, ref, watch } from 'vue'
|
import { computed, nextTick, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { SelectKeyFile, TestConnection } from 'wailsjs/go/services/connectionService.js'
|
import { ListSentinelMasters, SelectKeyFile, TestConnection } from 'wailsjs/go/services/connectionService.js'
|
||||||
import useDialog, { ConnDialogType } from 'stores/dialog'
|
import useDialog, { ConnDialogType } from 'stores/dialog'
|
||||||
import Close from '@/components/icons/Close.vue'
|
import Close from '@/components/icons/Close.vue'
|
||||||
import useConnectionStore from 'stores/connections.js'
|
import useConnectionStore from 'stores/connections.js'
|
||||||
|
@ -57,17 +57,27 @@ const groupOptions = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const dbFilterList = ref([])
|
const dbFilterList = ref([])
|
||||||
const onUpdateDBFilterList = (list) => {
|
const onUpdateDBFilterType = (t) => {
|
||||||
const dbList = []
|
if (t !== 'none') {
|
||||||
for (const item of list) {
|
// set default filter index if empty
|
||||||
const idx = toNumber(item)
|
if (isEmpty(dbFilterList.value)) {
|
||||||
if (!isNaN(idx)) {
|
dbFilterList.value = ['0']
|
||||||
dbList.push(idx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generalForm.value.dbFilterList = sortBy(dbList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => dbFilterList.value,
|
||||||
|
(list) => {
|
||||||
|
const dbList = map(list, (item) => {
|
||||||
|
const idx = toNumber(item)
|
||||||
|
return isNaN(idx) ? 0 : idx
|
||||||
|
})
|
||||||
|
generalForm.value.dbFilterList = sortBy(dbList)
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
const sshLoginType = computed(() => {
|
const sshLoginType = computed(() => {
|
||||||
return get(generalForm.value, 'ssh.loginType', 'pwd')
|
return get(generalForm.value, 'ssh.loginType', 'pwd')
|
||||||
})
|
})
|
||||||
|
@ -81,6 +91,36 @@ const onChoosePKFile = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadingSentinelMaster = ref(false)
|
||||||
|
const masterNameOptions = ref([])
|
||||||
|
const onLoadSentinelMasters = async () => {
|
||||||
|
try {
|
||||||
|
loadingSentinelMaster.value = true
|
||||||
|
const { success, data, msg } = await ListSentinelMasters(generalForm.value)
|
||||||
|
if (!success || isEmpty(data)) {
|
||||||
|
$message.error(msg || 'list sentinel master fail')
|
||||||
|
} else {
|
||||||
|
const options = []
|
||||||
|
for (const m of data) {
|
||||||
|
options.push({
|
||||||
|
label: m['name'],
|
||||||
|
value: m['name'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// select default names
|
||||||
|
if (!isEmpty(options)) {
|
||||||
|
generalForm.value.sentinel.master = options[0].value
|
||||||
|
}
|
||||||
|
masterNameOptions.value = options
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$message.error(e.message)
|
||||||
|
} finally {
|
||||||
|
loadingSentinelMaster.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const tab = ref('general')
|
const tab = ref('general')
|
||||||
const testing = ref(false)
|
const testing = ref(false)
|
||||||
const showTestResult = ref(false)
|
const showTestResult = ref(false)
|
||||||
|
@ -104,6 +144,11 @@ const onSaveConnection = async () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// trim advance data
|
||||||
|
if (get(generalForm.value, 'dbFilterType', 'none') === 'none') {
|
||||||
|
generalForm.value.dbFilterList = []
|
||||||
|
}
|
||||||
|
|
||||||
// trim ssh login data
|
// trim ssh login data
|
||||||
if (generalForm.value.ssh.enable) {
|
if (generalForm.value.ssh.enable) {
|
||||||
switch (generalForm.value.ssh.loginType) {
|
switch (generalForm.value.ssh.loginType) {
|
||||||
|
@ -121,6 +166,13 @@ const onSaveConnection = async () => {
|
||||||
generalForm.value.ssh = ssh
|
generalForm.value.ssh = ssh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim sentinel data
|
||||||
|
if (!generalForm.value.sentinel.enable) {
|
||||||
|
generalForm.value.sentinel.master = ''
|
||||||
|
generalForm.value.sentinel.username = ''
|
||||||
|
generalForm.value.sentinel.password = ''
|
||||||
|
}
|
||||||
|
|
||||||
// store new connection
|
// store new connection
|
||||||
const { success, msg } = await connectionStore.saveConnection(
|
const { success, msg } = await connectionStore.saveConnection(
|
||||||
isEditMode.value ? editName.value : null,
|
isEditMode.value ? editName.value : null,
|
||||||
|
@ -142,6 +194,7 @@ const resetForm = () => {
|
||||||
showTestResult.value = false
|
showTestResult.value = false
|
||||||
testResult.value = ''
|
testResult.value = ''
|
||||||
tab.value = 'general'
|
tab.value = 'general'
|
||||||
|
loadingSentinelMaster.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -198,6 +251,7 @@ const onClose = () => {
|
||||||
transform-origin="center">
|
transform-origin="center">
|
||||||
<n-spin :show="closingConnection">
|
<n-spin :show="closingConnection">
|
||||||
<n-tabs v-model:value="tab" animated type="line">
|
<n-tabs v-model:value="tab" animated type="line">
|
||||||
|
<!-- General pane -->
|
||||||
<n-tab-pane :tab="$t('dialogue.connection.general')" display-directive="show" name="general">
|
<n-tab-pane :tab="$t('dialogue.connection.general')" display-directive="show" name="general">
|
||||||
<n-form
|
<n-form
|
||||||
ref="generalFormRef"
|
ref="generalFormRef"
|
||||||
|
@ -239,7 +293,8 @@ const onClose = () => {
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
<n-tab-pane :tab="$t('dialogue.connection.advanced')" display-directive="show" name="advanced">
|
<!-- Advance pane -->
|
||||||
|
<n-tab-pane :tab="$t('dialogue.connection.advn.title')" display-directive="show" name="advanced">
|
||||||
<n-form
|
<n-form
|
||||||
ref="advanceFormRef"
|
ref="advanceFormRef"
|
||||||
:model="generalForm"
|
:model="generalForm"
|
||||||
|
@ -284,7 +339,9 @@ const onClose = () => {
|
||||||
</n-input-number>
|
</n-input-number>
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_type')">
|
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_type')">
|
||||||
<n-radio-group v-model:value="generalForm.dbFilterType">
|
<n-radio-group
|
||||||
|
v-model:value="generalForm.dbFilterType"
|
||||||
|
@update:value="onUpdateDBFilterType">
|
||||||
<n-radio-button :label="$t('dialogue.connection.advn.dbfilter_all')" value="none" />
|
<n-radio-button :label="$t('dialogue.connection.advn.dbfilter_all')" value="none" />
|
||||||
<n-radio-button
|
<n-radio-button
|
||||||
:label="$t('dialogue.connection.advn.dbfilter_show')"
|
:label="$t('dialogue.connection.advn.dbfilter_show')"
|
||||||
|
@ -294,7 +351,10 @@ const onClose = () => {
|
||||||
value="hide" />
|
value="hide" />
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_input')">
|
<n-form-item-gi
|
||||||
|
v-show="generalForm.dbFilterType !== 'none'"
|
||||||
|
:span="24"
|
||||||
|
:label="$t('dialogue.connection.advn.dbfilter_input')">
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="dbFilterList"
|
v-model:value="dbFilterList"
|
||||||
:disabled="generalForm.dbFilterType === 'none'"
|
:disabled="generalForm.dbFilterType === 'none'"
|
||||||
|
@ -304,8 +364,7 @@ const onClose = () => {
|
||||||
:placeholder="$t('dialogue.connection.advn.dbfilter_input_tip')"
|
:placeholder="$t('dialogue.connection.advn.dbfilter_input_tip')"
|
||||||
:show-arrow="false"
|
:show-arrow="false"
|
||||||
:show="false"
|
:show="false"
|
||||||
:clearable="true"
|
:clearable="true" />
|
||||||
@update:value="onUpdateDBFilterList" />
|
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi
|
<n-form-item-gi
|
||||||
:span="24"
|
:span="24"
|
||||||
|
@ -327,14 +386,14 @@ const onClose = () => {
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
<n-tab-pane :tab="$t('dialogue.connection.ssh.tunnel')" display-directive="show" name="ssh">
|
<!-- SSH pane -->
|
||||||
|
<n-tab-pane :tab="$t('dialogue.connection.ssh.title')" display-directive="show" name="ssh">
|
||||||
<n-form-item label-placement="left">
|
<n-form-item label-placement="left">
|
||||||
<n-checkbox v-model:checked="generalForm.ssh.enable" size="medium">
|
<n-checkbox v-model:checked="generalForm.ssh.enable" size="medium">
|
||||||
{{ $t('dialogue.connection.ssh.enable') }}
|
{{ $t('dialogue.connection.ssh.enable') }}
|
||||||
</n-checkbox>
|
</n-checkbox>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form
|
<n-form
|
||||||
ref="sshFormRef"
|
|
||||||
:model="generalForm.ssh"
|
:model="generalForm.ssh"
|
||||||
:show-require-mark="false"
|
:show-require-mark="false"
|
||||||
:disabled="!generalForm.ssh.enable"
|
:disabled="!generalForm.ssh.enable"
|
||||||
|
@ -388,8 +447,46 @@ const onClose = () => {
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
|
<!-- Sentinel pane -->
|
||||||
|
<n-tab-pane :tab="$t('dialogue.connection.sentinel.title')" display-directive="show" name="sentinel">
|
||||||
|
<n-form-item label-placement="left">
|
||||||
|
<n-checkbox v-model:checked="generalForm.sentinel.enable" size="medium">
|
||||||
|
{{ $t('dialogue.connection.sentinel.enable') }}
|
||||||
|
</n-checkbox>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form
|
||||||
|
:model="generalForm.sentinel"
|
||||||
|
:show-require-mark="false"
|
||||||
|
:disabled="!generalForm.sentinel.enable"
|
||||||
|
label-placement="top">
|
||||||
|
<n-form-item :label="$t('dialogue.connection.sentinel.master')">
|
||||||
|
<n-input-group>
|
||||||
|
<n-select
|
||||||
|
v-model:value="generalForm.sentinel.master"
|
||||||
|
filterable
|
||||||
|
tag
|
||||||
|
:options="masterNameOptions" />
|
||||||
|
<n-button :loading="loadingSentinelMaster" @click="onLoadSentinelMasters">
|
||||||
|
{{ $t('dialogue.connection.sentinel.auto_discover') }}
|
||||||
|
</n-button>
|
||||||
|
</n-input-group>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item :label="$t('dialogue.connection.sentinel.password')">
|
||||||
|
<n-input
|
||||||
|
v-model:value="generalForm.sentinel.password"
|
||||||
|
:placeholder="$t('dialogue.connection.sentinel.pwd_tip')"
|
||||||
|
show-password-on="click"
|
||||||
|
type="password" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item :label="$t('dialogue.connection.sentinel.username')">
|
||||||
|
<n-input
|
||||||
|
v-model:value="generalForm.sentinel.username"
|
||||||
|
:placeholder="$t('dialogue.connection.sentinel.usr_tip')" />
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</n-tab-pane>
|
||||||
|
|
||||||
<!-- TODO: SSL tab pane -->
|
<!-- TODO: SSL tab pane -->
|
||||||
<!-- TODO: Sentinel tab pane -->
|
|
||||||
<!-- TODO: Cluster tab pane -->
|
<!-- TODO: Cluster tab pane -->
|
||||||
</n-tabs>
|
</n-tabs>
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,6 @@
|
||||||
"new_title": "New Connection",
|
"new_title": "New Connection",
|
||||||
"edit_title": "Edit Connection",
|
"edit_title": "Edit Connection",
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"advanced": "Advanced",
|
|
||||||
"no_group": "No Group",
|
"no_group": "No Group",
|
||||||
"group": "Group",
|
"group": "Group",
|
||||||
"conn_name": "Name",
|
"conn_name": "Name",
|
||||||
|
@ -123,12 +122,13 @@
|
||||||
"pwd": "Password",
|
"pwd": "Password",
|
||||||
"name_tip": "Connection name",
|
"name_tip": "Connection name",
|
||||||
"addr_tip": "Redis server host",
|
"addr_tip": "Redis server host",
|
||||||
"usr_tip": "(Optional) Redis server username",
|
"usr_tip": "(Optional) Authentication username",
|
||||||
"pwd_tip": "(Optional) Redis server authentication password (Redis > 6.0)",
|
"pwd_tip": "(Optional) Authentication password (Redis > 6.0)",
|
||||||
"test": "Test Connection",
|
"test": "Test Connection",
|
||||||
"test_succ": "Successful connection to redis-server",
|
"test_succ": "Successful connection to redis-server",
|
||||||
"test_fail": "Fail Connection",
|
"test_fail": "Fail Connection",
|
||||||
"advn": {
|
"advn": {
|
||||||
|
"title": "Advanced",
|
||||||
"filter": "Default Key Filter Pattern",
|
"filter": "Default Key Filter Pattern",
|
||||||
"filter_tip": "Pattern which defines loaded keys from redis server",
|
"filter_tip": "Pattern which defines loaded keys from redis server",
|
||||||
"separator": "Key Separator",
|
"separator": "Key Separator",
|
||||||
|
@ -146,8 +146,8 @@
|
||||||
"mark_color": "Mark Color"
|
"mark_color": "Mark Color"
|
||||||
},
|
},
|
||||||
"ssh": {
|
"ssh": {
|
||||||
|
"title": "SSH Tunnel",
|
||||||
"enable": "Enable SSH Tuntel",
|
"enable": "Enable SSH Tuntel",
|
||||||
"tunnel": "SSH Tunnel",
|
|
||||||
"login_type": "Login Type",
|
"login_type": "Login Type",
|
||||||
"pkfile": "Private Key File",
|
"pkfile": "Private Key File",
|
||||||
"passphrase": "Passphrase",
|
"passphrase": "Passphrase",
|
||||||
|
@ -157,6 +157,16 @@
|
||||||
"pkfile_tip": "SSH Private Key File Path",
|
"pkfile_tip": "SSH Private Key File Path",
|
||||||
"passphrase_tip": "(Optional) Passphrase for Private Key",
|
"passphrase_tip": "(Optional) Passphrase for Private Key",
|
||||||
"pkfile_selection_title": "Please Select Private Key File"
|
"pkfile_selection_title": "Please Select Private Key File"
|
||||||
|
},
|
||||||
|
"sentinel": {
|
||||||
|
"title": "Sentinel",
|
||||||
|
"enable": "Serve as Sentinel Node",
|
||||||
|
"master": "Master Group Name",
|
||||||
|
"auto_discover": "Auto Discover",
|
||||||
|
"password": "Password for Master Node",
|
||||||
|
"username": "Username for Master Node",
|
||||||
|
"pwd_tip": "(Optional) Authentication username for master node",
|
||||||
|
"usr_tip": "(Optional) Authentication password for master node (Redis > 6.0)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
|
|
|
@ -114,7 +114,6 @@
|
||||||
"new_title": "新建连接",
|
"new_title": "新建连接",
|
||||||
"edit_title": "编辑连接",
|
"edit_title": "编辑连接",
|
||||||
"general": "常规配置",
|
"general": "常规配置",
|
||||||
"advanced": "高级配置",
|
|
||||||
"no_group": "无分组",
|
"no_group": "无分组",
|
||||||
"group": "分组",
|
"group": "分组",
|
||||||
"conn_name": "连接名",
|
"conn_name": "连接名",
|
||||||
|
@ -129,10 +128,11 @@
|
||||||
"test_succ": "成功连接到Redis服务器",
|
"test_succ": "成功连接到Redis服务器",
|
||||||
"test_fail": "连接失败",
|
"test_fail": "连接失败",
|
||||||
"advn": {
|
"advn": {
|
||||||
|
"title": "高级配置",
|
||||||
"filter": "默认键过滤表达式",
|
"filter": "默认键过滤表达式",
|
||||||
"filter_tip": "需要加载的键名表达式",
|
"filter_tip": "需要加载的键名表达式",
|
||||||
"separator": "键分隔符",
|
"separator": "键分隔符",
|
||||||
"separator_tip":"键名路径分隔符",
|
"separator_tip": "键名路径分隔符",
|
||||||
"conn_timeout": "连接超时",
|
"conn_timeout": "连接超时",
|
||||||
"exec_timeout": "执行超时",
|
"exec_timeout": "执行超时",
|
||||||
"dbfilter_type": "数据库过滤方式",
|
"dbfilter_type": "数据库过滤方式",
|
||||||
|
@ -147,7 +147,7 @@
|
||||||
},
|
},
|
||||||
"ssh": {
|
"ssh": {
|
||||||
"enable": "启用SSH隧道",
|
"enable": "启用SSH隧道",
|
||||||
"tunnel": "SSH隧道",
|
"title": "SSH隧道",
|
||||||
"login_type": "登录类型",
|
"login_type": "登录类型",
|
||||||
"pkfile": "私钥文件",
|
"pkfile": "私钥文件",
|
||||||
"passphrase": "私钥密码",
|
"passphrase": "私钥密码",
|
||||||
|
@ -157,6 +157,16 @@
|
||||||
"pkfile_tip": "SSH私钥文件路径",
|
"pkfile_tip": "SSH私钥文件路径",
|
||||||
"passphrase_tip": "(可选)SSH私钥密码",
|
"passphrase_tip": "(可选)SSH私钥密码",
|
||||||
"pkfile_selection_title": "请选择私钥文件"
|
"pkfile_selection_title": "请选择私钥文件"
|
||||||
|
},
|
||||||
|
"sentinel": {
|
||||||
|
"title": "哨兵模式",
|
||||||
|
"enable": "当前为哨兵节点",
|
||||||
|
"master": "主节点组名",
|
||||||
|
"auto_discover": "自动查询组名",
|
||||||
|
"password": "主节点密码",
|
||||||
|
"username": "主节点用户名",
|
||||||
|
"pwd_tip": "(可选)主节点服务授权用户名",
|
||||||
|
"usr_tip": "(可选)主节点服务授权密码 (Redis > 6.0)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
|
@ -200,7 +210,7 @@
|
||||||
"ttl": {
|
"ttl": {
|
||||||
"title": "设置键存活时间"
|
"title": "设置键存活时间"
|
||||||
},
|
},
|
||||||
"upgrade":{
|
"upgrade": {
|
||||||
"title": "有可用新版本",
|
"title": "有可用新版本",
|
||||||
"new_version_tip": "新版本({ver}),是否立即下载",
|
"new_version_tip": "新版本({ver}),是否立即下载",
|
||||||
"no_update": "当前已是最新版",
|
"no_update": "当前已是最新版",
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { endsWith, get, isEmpty, join, remove, size, slice, sortedIndexBy, split, sumBy, toUpper, uniq } from 'lodash'
|
import {
|
||||||
|
endsWith,
|
||||||
|
find,
|
||||||
|
get,
|
||||||
|
isEmpty,
|
||||||
|
join,
|
||||||
|
remove,
|
||||||
|
size,
|
||||||
|
slice,
|
||||||
|
sortedIndexBy,
|
||||||
|
split,
|
||||||
|
sumBy,
|
||||||
|
toUpper,
|
||||||
|
uniq,
|
||||||
|
} from 'lodash'
|
||||||
import {
|
import {
|
||||||
AddHashField,
|
AddHashField,
|
||||||
AddListItem,
|
AddListItem,
|
||||||
|
@ -221,9 +235,34 @@ const useConnectionStore = defineStore('connections', {
|
||||||
pkFile: '',
|
pkFile: '',
|
||||||
passphrase: '',
|
passphrase: '',
|
||||||
},
|
},
|
||||||
|
sentinel: {
|
||||||
|
enable: false,
|
||||||
|
master: 'mymaster',
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mergeConnectionProfile(dest, src) {
|
||||||
|
const mergeObj = (destObj, srcObj) => {
|
||||||
|
for (const k in srcObj) {
|
||||||
|
const t = typeof srcObj[k]
|
||||||
|
if (t === 'string') {
|
||||||
|
destObj[k] = srcObj[k] || destObj[k] || ''
|
||||||
|
} else if (t === 'number') {
|
||||||
|
destObj[k] = srcObj[k] || destObj[k] || 0
|
||||||
|
} else if (t === 'object') {
|
||||||
|
mergeObj(destObj[k], srcObj[k] || {})
|
||||||
|
} else {
|
||||||
|
destObj[k] = srcObj[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return destObj
|
||||||
|
}
|
||||||
|
return mergeObj(dest, src)
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get database server by name
|
* get database server by name
|
||||||
* @param name
|
* @param name
|
||||||
|
@ -246,6 +285,23 @@ const useConnectionStore = defineStore('connections', {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get database by server name and index
|
||||||
|
* @param {string} connName
|
||||||
|
* @param {number} db
|
||||||
|
* @return {{}|null}
|
||||||
|
*/
|
||||||
|
getDatabase(connName, db) {
|
||||||
|
const dbs = this.databases[connName]
|
||||||
|
if (dbs != null) {
|
||||||
|
const selDB = find(dbs, (item) => item.db === db)
|
||||||
|
if (selDB != null) {
|
||||||
|
return selDB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create a new connection or update current connection profile
|
* create a new connection or update current connection profile
|
||||||
* @param {string} name set null if create a new connection
|
* @param {string} name set null if create a new connection
|
||||||
|
@ -337,7 +393,7 @@ const useConnectionStore = defineStore('connections', {
|
||||||
label: db[i].name,
|
label: db[i].name,
|
||||||
name: name,
|
name: name,
|
||||||
keys: db[i].keys,
|
keys: db[i].keys,
|
||||||
db: i,
|
db: db[i].index,
|
||||||
type: ConnectionType.RedisDB,
|
type: ConnectionType.RedisDB,
|
||||||
isLeaf: false,
|
isLeaf: false,
|
||||||
children: undefined,
|
children: undefined,
|
||||||
|
@ -465,10 +521,14 @@ const useConnectionStore = defineStore('connections', {
|
||||||
throw new Error(msg)
|
throw new Error(msg)
|
||||||
}
|
}
|
||||||
const { keys = [] } = data
|
const { keys = [] } = data
|
||||||
const dbs = this.databases[connName]
|
const selDB = this.getDatabase(connName, db)
|
||||||
dbs[db].opened = true
|
if (selDB == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selDB.opened = true
|
||||||
if (isEmpty(keys)) {
|
if (isEmpty(keys)) {
|
||||||
dbs[db].children = []
|
selDB.children = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,9 +544,12 @@ const useConnectionStore = defineStore('connections', {
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async reopenDatabase(connName, db) {
|
async reopenDatabase(connName, db) {
|
||||||
const dbs = this.databases[connName]
|
const selDB = this.getDatabase(connName, db)
|
||||||
dbs[db].children = undefined
|
if (selDB == null) {
|
||||||
dbs[db].isLeaf = false
|
return
|
||||||
|
}
|
||||||
|
selDB.children = undefined
|
||||||
|
selDB.isLeaf = false
|
||||||
|
|
||||||
this._getNodeMap(connName, db).clear()
|
this._getNodeMap(connName, db).clear()
|
||||||
},
|
},
|
||||||
|
@ -497,10 +560,13 @@ const useConnectionStore = defineStore('connections', {
|
||||||
* @param db
|
* @param db
|
||||||
*/
|
*/
|
||||||
closeDatabase(connName, db) {
|
closeDatabase(connName, db) {
|
||||||
const dbs = this.databases[connName]
|
const selDB = this.getDatabase(connName, db)
|
||||||
delete dbs[db].children
|
if (selDB == null) {
|
||||||
dbs[db].isLeaf = false
|
return
|
||||||
dbs[db].opened = false
|
}
|
||||||
|
delete selDB.children
|
||||||
|
selDB.isLeaf = false
|
||||||
|
selDB.opened = false
|
||||||
|
|
||||||
this._getNodeMap(connName, db).clear()
|
this._getNodeMap(connName, db).clear()
|
||||||
},
|
},
|
||||||
|
@ -658,12 +724,16 @@ const useConnectionStore = defineStore('connections', {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const separator = this._getSeparator(connName)
|
const separator = this._getSeparator(connName)
|
||||||
const dbs = this.databases[connName]
|
const selDB = this.getDatabase(connName, db)
|
||||||
if (dbs[db].children == null) {
|
if (selDB == null) {
|
||||||
dbs[db].children = []
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selDB.children == null) {
|
||||||
|
selDB.children = []
|
||||||
}
|
}
|
||||||
const nodeMap = this._getNodeMap(connName, db)
|
const nodeMap = this._getNodeMap(connName, db)
|
||||||
const rootChildren = dbs[db].children
|
const rootChildren = selDB.children
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
const keyParts = split(key, separator)
|
const keyParts = split(key, separator)
|
||||||
const len = size(keyParts)
|
const len = size(keyParts)
|
||||||
|
@ -757,7 +827,7 @@ const useConnectionStore = defineStore('connections', {
|
||||||
*/
|
*/
|
||||||
_tidyNode(connName, db, key, skipResort) {
|
_tidyNode(connName, db, key, skipResort) {
|
||||||
const nodeMap = this._getNodeMap(connName, db)
|
const nodeMap = this._getNodeMap(connName, db)
|
||||||
const dbNode = get(this.databases, [connName, db], {})
|
const dbNode = this.getDatabase(connName, db) || {}
|
||||||
const separator = this._getSeparator(connName)
|
const separator = this._getSeparator(connName)
|
||||||
const keyParts = split(key, separator)
|
const keyParts = split(key, separator)
|
||||||
const totalParts = size(keyParts)
|
const totalParts = size(keyParts)
|
||||||
|
@ -848,7 +918,7 @@ const useConnectionStore = defineStore('connections', {
|
||||||
const nodeMap = this._getNodeMap(server, db)
|
const nodeMap = this._getNodeMap(server, db)
|
||||||
return nodeMap.get(keyPart)
|
return nodeMap.get(keyPart)
|
||||||
} else {
|
} else {
|
||||||
return this.databases[server][db]
|
return this.getDatabase(server, db)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1266,7 +1336,7 @@ const useConnectionStore = defineStore('connections', {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_deleteKeyNode(connName, db, key, isLayer) {
|
_deleteKeyNode(connName, db, key, isLayer) {
|
||||||
const dbRoot = get(this.databases, [connName, db], {})
|
const dbRoot = this.getDatabase(connName, db) || {}
|
||||||
const separator = this._getSeparator(connName)
|
const separator = this._getSeparator(connName)
|
||||||
|
|
||||||
if (dbRoot == null) {
|
if (dbRoot == null) {
|
||||||
|
|
|
@ -82,16 +82,7 @@ const useDialogStore = defineStore('dialog', {
|
||||||
async openEditDialog(name) {
|
async openEditDialog(name) {
|
||||||
const connStore = useConnectionStore()
|
const connStore = useConnectionStore()
|
||||||
const profile = await connStore.getConnectionProfile(name)
|
const profile = await connStore.getConnectionProfile(name)
|
||||||
const assignCustomizer = (objVal, srcVal, key) => {
|
this.connParam = connStore.mergeConnectionProfile(connStore.newDefaultConnection(name), profile)
|
||||||
if (isEmpty(objVal)) {
|
|
||||||
return srcVal
|
|
||||||
}
|
|
||||||
if (isEmpty(srcVal)) {
|
|
||||||
return objVal
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
this.connParam = assignWith({}, connStore.newDefaultConnection(name), profile, assignCustomizer)
|
|
||||||
this.connType = ConnDialogType.EDIT
|
this.connType = ConnDialogType.EDIT
|
||||||
this.connDialogVisible = true
|
this.connDialogVisible = true
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { BrowserOpenURL } from 'wailsjs/runtime/runtime.js'
|
||||||
import { i18nGlobal } from '@/utils/i18n.js'
|
import { i18nGlobal } from '@/utils/i18n.js'
|
||||||
import { enUS, NButton, NSpace, useOsTheme, zhCN } from 'naive-ui'
|
import { enUS, NButton, NSpace, useOsTheme, zhCN } from 'naive-ui'
|
||||||
import { h, nextTick } from 'vue'
|
import { h, nextTick } from 'vue'
|
||||||
|
import { compareVersion } from '@/utils/version.js'
|
||||||
|
|
||||||
const osTheme = useOsTheme()
|
const osTheme = useOsTheme()
|
||||||
const usePreferencesStore = defineStore('preferences', {
|
const usePreferencesStore = defineStore('preferences', {
|
||||||
|
@ -244,7 +245,11 @@ const usePreferencesStore = defineStore('preferences', {
|
||||||
const { success, data = {} } = await CheckForUpdate()
|
const { success, data = {} } = await CheckForUpdate()
|
||||||
if (success) {
|
if (success) {
|
||||||
const { version = 'v1.0.0', latest, page_url: pageUrl } = data
|
const { version = 'v1.0.0', latest, page_url: pageUrl } = data
|
||||||
if ((manual || latest > this.general.skipVersion) && latest > version && !isEmpty(pageUrl)) {
|
if (
|
||||||
|
(manual || latest > this.general.skipVersion) &&
|
||||||
|
compareVersion(latest, version) > 0 &&
|
||||||
|
!isEmpty(pageUrl)
|
||||||
|
) {
|
||||||
const notiRef = $notification.show({
|
const notiRef = $notification.show({
|
||||||
title: i18nGlobal.t('dialogue.upgrade.title'),
|
title: i18nGlobal.t('dialogue.upgrade.title'),
|
||||||
content: i18nGlobal.t('dialogue.upgrade.new_version_tip', { ver: latest }),
|
content: i18nGlobal.t('dialogue.upgrade.new_version_tip', { ver: latest }),
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { get, isEmpty, map, size, split, trimStart } from 'lodash'
|
||||||
|
|
||||||
|
const toVerArr = (ver) => {
|
||||||
|
const v = trimStart(ver, 'v')
|
||||||
|
let vParts = split(v, '.')
|
||||||
|
if (isEmpty(vParts)) {
|
||||||
|
vParts = ['0']
|
||||||
|
}
|
||||||
|
return map(vParts, (v) => {
|
||||||
|
let vNum = parseInt(v)
|
||||||
|
return isNaN(vNum) ? 0 : vNum
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compare two version strings
|
||||||
|
* @param {string} v1
|
||||||
|
* @param {string} v2
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export const compareVersion = (v1, v2) => {
|
||||||
|
if (v1 !== v2) {
|
||||||
|
const v1Nums = toVerArr(v1)
|
||||||
|
const v2Nums = toVerArr(v2)
|
||||||
|
const length = Math.max(size(v1Nums), size(v2Nums))
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
const num1 = get(v1Nums, i, 0)
|
||||||
|
const num2 = get(v2Nums, i, 0)
|
||||||
|
if (num1 !== num2) {
|
||||||
|
return num1 > num2 ? 1 : -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
8
go.mod
8
go.mod
|
@ -4,10 +4,10 @@ go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/adrg/sysfont v0.1.2
|
github.com/adrg/sysfont v0.1.2
|
||||||
github.com/redis/go-redis/v9 v9.2.0
|
github.com/redis/go-redis/v9 v9.2.1
|
||||||
github.com/vrischmann/userdir v0.0.0-20151206171402-20f291cebd68
|
github.com/vrischmann/userdir v0.0.0-20151206171402-20f291cebd68
|
||||||
github.com/wailsapp/wails/v2 v2.6.0
|
github.com/wailsapp/wails/v2 v2.6.0
|
||||||
golang.org/x/crypto v0.12.0
|
golang.org/x/crypto v0.14.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,8 +40,8 @@ require (
|
||||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
||||||
golang.org/x/net v0.14.0 // indirect
|
golang.org/x/net v0.14.0 // indirect
|
||||||
golang.org/x/sys v0.11.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
golang.org/x/text v0.12.0 // indirect
|
golang.org/x/text v0.13.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
20
go.sum
20
go.sum
|
@ -58,8 +58,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/redis/go-redis/v9 v9.2.0 h1:zwMdX0A4eVzse46YN18QhuDiM4uf3JmkOB4VZrdt5uI=
|
github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg=
|
||||||
github.com/redis/go-redis/v9 v9.2.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
@ -86,8 +86,8 @@ github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhw
|
||||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||||
github.com/wailsapp/wails/v2 v2.6.0 h1:EyH0zR/EO6dDiqNy8qU5spaXDfkluiq77xrkabPYD4c=
|
github.com/wailsapp/wails/v2 v2.6.0 h1:EyH0zR/EO6dDiqNy8qU5spaXDfkluiq77xrkabPYD4c=
|
||||||
github.com/wailsapp/wails/v2 v2.6.0/go.mod h1:WBG9KKWuw0FKfoepBrr/vRlyTmHaMibWesK3yz6nNiM=
|
github.com/wailsapp/wails/v2 v2.6.0/go.mod h1:WBG9KKWuw0FKfoepBrr/vRlyTmHaMibWesK3yz6nNiM=
|
||||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
@ -104,14 +104,14 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
|
Loading…
Reference in New Issue