feat: add filter database option #18
refactor: tidy struct of translation file
This commit is contained in:
parent
7937b5b0f8
commit
bb1d9f316b
|
@ -9,6 +9,7 @@ import (
|
|||
"golang.org/x/crypto/ssh"
|
||||
"net"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -261,11 +262,16 @@ func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
|||
return
|
||||
}
|
||||
|
||||
// get total databases
|
||||
// get connection config
|
||||
selConn := c.conns.GetConnection(name)
|
||||
|
||||
totaldb := 16
|
||||
if config, err := rdb.ConfigGet(ctx, "databases").Result(); err == nil {
|
||||
if total, err := strconv.Atoi(config["databases"]); err == nil {
|
||||
totaldb = total
|
||||
if selConn.DBFilterType == "none" {
|
||||
// get total databases
|
||||
if config, err := rdb.ConfigGet(ctx, "databases").Result(); err == nil {
|
||||
if total, err := strconv.Atoi(config["databases"]); err == nil {
|
||||
totaldb = total
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,21 +284,37 @@ func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
|||
// Parse all db, response content like below
|
||||
var dbs []types.ConnectionDB
|
||||
info := c.parseInfo(res)
|
||||
for i := 0; i < totaldb; i++ {
|
||||
dbName := "db" + strconv.Itoa(i)
|
||||
queryDB := func(idx int) types.ConnectionDB {
|
||||
dbName := "db" + strconv.Itoa(idx)
|
||||
dbInfoStr := info["Keyspace"][dbName]
|
||||
if len(dbInfoStr) > 0 {
|
||||
dbInfo := c.parseDBItemInfo(dbInfoStr)
|
||||
dbs = append(dbs, types.ConnectionDB{
|
||||
return types.ConnectionDB{
|
||||
Name: dbName,
|
||||
Keys: dbInfo["keys"],
|
||||
Expires: dbInfo["expires"],
|
||||
AvgTTL: dbInfo["avg_ttl"],
|
||||
})
|
||||
}
|
||||
} else {
|
||||
dbs = append(dbs, types.ConnectionDB{
|
||||
return types.ConnectionDB{
|
||||
Name: dbName,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
switch selConn.DBFilterType {
|
||||
case "none":
|
||||
for idx := 0; idx < totaldb; idx++ {
|
||||
dbs = append(dbs, queryDB(idx))
|
||||
}
|
||||
case "show":
|
||||
for _, idx := range selConn.DBFilterList {
|
||||
dbs = append(dbs, queryDB(idx))
|
||||
}
|
||||
case "hide":
|
||||
for idx := 0; idx < totaldb; idx++ {
|
||||
if !slices.Contains(selConn.DBFilterList, idx) {
|
||||
dbs = append(dbs, queryDB(idx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,7 +372,7 @@ func (c *connectionService) getRedisClient(connName string, db int) (*redis.Clie
|
|||
})
|
||||
}))
|
||||
|
||||
if _, err := rdb.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
||||
if _, err = rdb.Ping(c.ctx).Result(); err != nil && err != redis.Nil {
|
||||
return nil, nil, errors.New("can not connect to redis server:" + err.Error())
|
||||
}
|
||||
var cancelFunc context.CancelFunc
|
||||
|
|
|
@ -34,6 +34,8 @@ func (c *ConnectionsStorage) defaultConnectionItem() types.ConnectionConfig {
|
|||
KeySeparator: ":",
|
||||
ConnTimeout: 60,
|
||||
ExecTimeout: 60,
|
||||
DBFilterType: "none",
|
||||
DBFilterList: []int{},
|
||||
MarkColor: "",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ type ConnectionConfig struct {
|
|||
KeySeparator string `json:"keySeparator,omitempty" yaml:"key_separator,omitempty"`
|
||||
ConnTimeout int `json:"connTimeout,omitempty" yaml:"conn_timeout,omitempty"`
|
||||
ExecTimeout int `json:"execTimeout,omitempty" yaml:"exec_timeout,omitempty"`
|
||||
DBFilterType string `json:"dbFilterType" yaml:"db_filter_type,omitempty"`
|
||||
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
||||
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
||||
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { every, get, includes, isEmpty, map } from 'lodash'
|
||||
import { every, get, includes, isEmpty, map, sortBy, toNumber } from 'lodash'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { SelectKeyFile, TestConnection } from 'wailsjs/go/services/connectionService.js'
|
||||
|
@ -56,12 +56,24 @@ const groupOptions = computed(() => {
|
|||
return options
|
||||
})
|
||||
|
||||
const dbFilterList = ref([])
|
||||
const onUpdateDBFilterList = (list) => {
|
||||
const dbList = []
|
||||
for (const item of list) {
|
||||
const idx = toNumber(item)
|
||||
if (!isNaN(idx)) {
|
||||
dbList.push(idx)
|
||||
}
|
||||
}
|
||||
generalForm.value.dbFilterList = sortBy(dbList)
|
||||
}
|
||||
|
||||
const sshLoginType = computed(() => {
|
||||
return get(generalForm.value, 'ssh.loginType', 'pwd')
|
||||
})
|
||||
|
||||
const onChoosePKFile = async () => {
|
||||
const { success, data } = await SelectKeyFile(i18n.t('dialogue.connection.pkfile_selection_title'))
|
||||
const { success, data } = await SelectKeyFile(i18n.t('dialogue.connection.ssh.pkfile_selection_title'))
|
||||
if (!success) {
|
||||
generalForm.value.ssh.pkFile = ''
|
||||
} else {
|
||||
|
@ -139,6 +151,7 @@ watch(
|
|||
resetForm()
|
||||
editName.value = get(dialogStore.connParam, 'name', '')
|
||||
generalForm.value = dialogStore.connParam || connectionStore.newDefaultConnection()
|
||||
dbFilterList.value = map(generalForm.value.dbFilterList, (item) => item + '')
|
||||
generalForm.value.ssh.loginType = generalForm.value.ssh.loginType || 'pwd'
|
||||
}
|
||||
},
|
||||
|
@ -233,50 +246,91 @@ const onClose = () => {
|
|||
:rules="generalFormRules()"
|
||||
:show-require-mark="false"
|
||||
label-placement="top">
|
||||
<n-form-item :label="$t('dialogue.connection.advn_filter')" path="defaultFilter">
|
||||
<n-input
|
||||
v-model:value="generalForm.defaultFilter"
|
||||
:placeholder="$t('dialogue.connection.advn_filter_tip')" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('dialogue.connection.advn_separator')" path="keySeparator">
|
||||
<n-input
|
||||
v-model:value="generalForm.keySeparator"
|
||||
:placeholder="$t('dialogue.connection.advn_separator_tip')" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('dialogue.connection.advn_conn_timeout')" path="connTimeout">
|
||||
<n-input-number v-model:value="generalForm.connTimeout" :max="999999" :min="1">
|
||||
<template #suffix>
|
||||
{{ $t('common.second') }}
|
||||
</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('dialogue.connection.advn_exec_timeout')" path="execTimeout">
|
||||
<n-input-number v-model:value="generalForm.execTimeout" :max="999999" :min="1">
|
||||
<template #suffix>
|
||||
{{ $t('common.second') }}
|
||||
</template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('dialogue.connection.advn_mark_color')" path="markColor">
|
||||
<div
|
||||
v-for="color in predefineColors"
|
||||
:key="color"
|
||||
:class="{
|
||||
'color-preset-item_selected': generalForm.markColor === color,
|
||||
}"
|
||||
:style="{ backgroundColor: color }"
|
||||
class="color-preset-item"
|
||||
@click="generalForm.markColor = color">
|
||||
<n-icon v-if="isEmpty(color)" :component="Close" size="24" />
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-grid :x-gap="10">
|
||||
<n-form-item-gi
|
||||
:span="12"
|
||||
:label="$t('dialogue.connection.advn.filter')"
|
||||
path="defaultFilter">
|
||||
<n-input
|
||||
v-model:value="generalForm.defaultFilter"
|
||||
:placeholder="$t('dialogue.connection.advn.filter_tip')" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi
|
||||
:span="12"
|
||||
:label="$t('dialogue.connection.advn.separator')"
|
||||
path="keySeparator">
|
||||
<n-input
|
||||
v-model:value="generalForm.keySeparator"
|
||||
:placeholder="$t('dialogue.connection.advn_separator_tip')" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi
|
||||
:span="12"
|
||||
:label="$t('dialogue.connection.advn.conn_timeout')"
|
||||
path="connTimeout">
|
||||
<n-input-number v-model:value="generalForm.connTimeout" :max="999999" :min="1">
|
||||
<template #suffix>
|
||||
{{ $t('common.second') }}
|
||||
</template>
|
||||
</n-input-number>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi
|
||||
:span="12"
|
||||
:label="$t('dialogue.connection.advn.exec_timeout')"
|
||||
path="execTimeout">
|
||||
<n-input-number v-model:value="generalForm.execTimeout" :max="999999" :min="1">
|
||||
<template #suffix>
|
||||
{{ $t('common.second') }}
|
||||
</template>
|
||||
</n-input-number>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_type')">
|
||||
<n-radio-group v-model:value="generalForm.dbFilterType">
|
||||
<n-radio-button :label="$t('dialogue.connection.advn.dbfilter_all')" value="none" />
|
||||
<n-radio-button
|
||||
:label="$t('dialogue.connection.advn.dbfilter_show')"
|
||||
value="show" />
|
||||
<n-radio-button
|
||||
:label="$t('dialogue.connection.advn.dbfilter_hide')"
|
||||
value="hide" />
|
||||
</n-radio-group>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi :span="24" :label="$t('dialogue.connection.advn.dbfilter_input')">
|
||||
<n-select
|
||||
v-model:value="dbFilterList"
|
||||
:disabled="generalForm.dbFilterType === 'none'"
|
||||
filterable
|
||||
multiple
|
||||
tag
|
||||
:placeholder="$t('dialogue.connection.advn.dbfilter_input_tip')"
|
||||
:show-arrow="false"
|
||||
:show="false"
|
||||
:clearable="true"
|
||||
@update:value="onUpdateDBFilterList" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi
|
||||
:span="24"
|
||||
:label="$t('dialogue.connection.advn.mark_color')"
|
||||
path="markColor">
|
||||
<div
|
||||
v-for="color in predefineColors"
|
||||
:key="color"
|
||||
:class="{
|
||||
'color-preset-item_selected': generalForm.markColor === color,
|
||||
}"
|
||||
:style="{ backgroundColor: color }"
|
||||
class="color-preset-item"
|
||||
@click="generalForm.markColor = color">
|
||||
<n-icon v-if="isEmpty(color)" :component="Close" size="24" />
|
||||
</div>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane :tab="$t('dialogue.connection.ssh_tunnel')" display-directive="show" name="ssh">
|
||||
<n-tab-pane :tab="$t('dialogue.connection.ssh.tunnel')" display-directive="show" name="ssh">
|
||||
<n-form-item label-placement="left">
|
||||
<n-checkbox v-model:checked="generalForm.ssh.enable" size="medium">
|
||||
{{ $t('dialogue.connection.ssh_enable') }}
|
||||
{{ $t('dialogue.connection.ssh.enable') }}
|
||||
</n-checkbox>
|
||||
</n-form-item>
|
||||
<n-form
|
||||
|
@ -288,7 +342,7 @@ const onClose = () => {
|
|||
<n-form-item :label="$t('dialogue.connection.addr')" required>
|
||||
<n-input
|
||||
v-model:value="generalForm.ssh.addr"
|
||||
:placeholder="$t('dialogue.connection.ssh_addr_tip')" />
|
||||
:placeholder="$t('dialogue.connection.ssh.addr_tip')" />
|
||||
<n-text style="width: 40px; text-align: center">:</n-text>
|
||||
<n-input-number
|
||||
v-model:value="generalForm.ssh.port"
|
||||
|
@ -296,10 +350,10 @@ const onClose = () => {
|
|||
:min="1"
|
||||
style="width: 200px" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('dialogue.connection.login_type')">
|
||||
<n-form-item :label="$t('dialogue.connection.ssh.login_type')">
|
||||
<n-radio-group v-model:value="generalForm.ssh.loginType">
|
||||
<n-radio-button :label="$t('dialogue.connection.pwd')" value="pwd" />
|
||||
<n-radio-button :label="$t('dialogue.connection.pkfile')" value="pkfile" />
|
||||
<n-radio-button :label="$t('dialogue.connection.ssh.pkfile')" value="pkfile" />
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
|
@ -307,27 +361,27 @@ const onClose = () => {
|
|||
:label="$t('dialogue.connection.usr')">
|
||||
<n-input
|
||||
v-model:value="generalForm.ssh.username"
|
||||
:placeholder="$t('dialogue.connection.ssh_usr_tip')" />
|
||||
:placeholder="$t('dialogue.connection.ssh.usr_tip')" />
|
||||
</n-form-item>
|
||||
<n-form-item v-if="sshLoginType === 'pwd'" :label="$t('dialogue.connection.pwd')">
|
||||
<n-input
|
||||
v-model:value="generalForm.ssh.password"
|
||||
:placeholder="$t('dialogue.connection.ssh_pwd_tip')"
|
||||
:placeholder="$t('dialogue.connection.ssh.pwd_tip')"
|
||||
show-password-on="click"
|
||||
type="password" />
|
||||
</n-form-item>
|
||||
<n-form-item v-if="sshLoginType === 'pkfile'" :label="$t('dialogue.connection.pkfile')">
|
||||
<n-form-item v-if="sshLoginType === 'pkfile'" :label="$t('dialogue.connection.ssh.pkfile')">
|
||||
<n-input-group>
|
||||
<n-input
|
||||
v-model:value="generalForm.ssh.pkFile"
|
||||
:placeholder="$t('dialogue.connection.pkfile_tip')" />
|
||||
:placeholder="$t('dialogue.connection.ssh.pkfile_tip')" />
|
||||
<n-button :focusable="false" @click="onChoosePKFile">...</n-button>
|
||||
</n-input-group>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="sshLoginType === 'pkfile'" :label="$t('dialogue.connection.passphrase')">
|
||||
<n-form-item v-if="sshLoginType === 'pkfile'" :label="$t('dialogue.connection.ssh.passphrase')">
|
||||
<n-input
|
||||
v-model:value="generalForm.ssh.passphrase"
|
||||
:placeholder="$t('dialogue.connection.passphrase_tip')"
|
||||
:placeholder="$t('dialogue.connection.ssh.passphrase_tip')"
|
||||
show-password-on="click"
|
||||
type="password" />
|
||||
</n-form-item>
|
||||
|
|
|
@ -127,24 +127,36 @@
|
|||
"test": "Test Connection",
|
||||
"test_succ": "Successful connection to redis-server",
|
||||
"test_fail": "Fail Connection",
|
||||
"advn_filter": "Default Filter",
|
||||
"advn_filter_tip": "Pattern which defines loaded keys from redis server",
|
||||
"advn_separator": "Key Separator",
|
||||
"advn_separator_tip": "Separator used for key path item",
|
||||
"advn_conn_timeout": "Connection Timeout",
|
||||
"advn_exec_timeout": "Execution Timeout",
|
||||
"advn_mark_color": "Mark Color",
|
||||
"ssh_enable": "Enable SSH Tuntel",
|
||||
"ssh_tunnel": "SSH Tunnel",
|
||||
"login_type": "Login Type",
|
||||
"pkfile": "Private Key File",
|
||||
"passphrase": "Passphrase",
|
||||
"ssh_addr_tip": "SSH Server Host",
|
||||
"ssh_usr_tip": "SSH Username",
|
||||
"ssh_pwd_tip": "SSH Password",
|
||||
"pkfile_tip": "SSH Private Key File Path",
|
||||
"passphrase_tip": "(Optional) Passphrase for Private Key",
|
||||
"pkfile_selection_title": "Please Select Private Key File"
|
||||
"advn": {
|
||||
"filter": "Default Key Filter Pattern",
|
||||
"filter_tip": "Pattern which defines loaded keys from redis server",
|
||||
"separator": "Key Separator",
|
||||
"separator_tip":"Separator for key path item",
|
||||
"conn_timeout": "Connection Timeout",
|
||||
"exec_timeout": "Execution Timeout",
|
||||
"dbfilter_type": "Database Filter",
|
||||
"dbfilter_all": "Show All",
|
||||
"dbfilter_show": "Show Selected",
|
||||
"dbfilter_hide": "Hide Selected",
|
||||
"dbfilter_show_title": "Select the Databases to Show",
|
||||
"dbfilter_hide_title": "Select the Databases to Hide",
|
||||
"dbfilter_input": "Input Database Index",
|
||||
"dbfilter_input_tip": "Press Enter to confirm",
|
||||
"mark_color": "Mark Color"
|
||||
},
|
||||
"ssh": {
|
||||
"enable": "Enable SSH Tuntel",
|
||||
"tunnel": "SSH Tunnel",
|
||||
"login_type": "Login Type",
|
||||
"pkfile": "Private Key File",
|
||||
"passphrase": "Passphrase",
|
||||
"addr_tip": "SSH Server Host",
|
||||
"usr_tip": "SSH Username",
|
||||
"pwd_tip": "SSH Password",
|
||||
"pkfile_tip": "SSH Private Key File Path",
|
||||
"passphrase_tip": "(Optional) Passphrase for Private Key",
|
||||
"pkfile_selection_title": "Please Select Private Key File"
|
||||
}
|
||||
},
|
||||
"group": {
|
||||
"name": "Group Name",
|
||||
|
|
|
@ -127,24 +127,36 @@
|
|||
"test": "测试连接",
|
||||
"test_succ": "成功连接到Redis服务器",
|
||||
"test_fail": "连接失败",
|
||||
"advn_filter": "默认过滤",
|
||||
"advn_filter_tip": "需要加载的键名表达式",
|
||||
"advn_separator": "键分隔符",
|
||||
"advn_separator_tip": "键名路径分隔符",
|
||||
"advn_conn_timeout": "连接超时",
|
||||
"advn_exec_timeout": "执行超时",
|
||||
"advn_mark_color": "标记颜色",
|
||||
"ssh_enable": "启用SSH隧道",
|
||||
"ssh_tunnel": "SSH隧道",
|
||||
"login_type": "登录类型",
|
||||
"pkfile": "私钥文件",
|
||||
"passphrase": "私钥密码",
|
||||
"ssh_addr_tip": "SSH地址",
|
||||
"ssh_usr_tip": "SSH登录用户名",
|
||||
"ssh_pwd_tip": "SSH登录密码",
|
||||
"pkfile_tip": "SSH私钥文件路径",
|
||||
"passphrase_tip": "(可选)SSH私钥密码",
|
||||
"pkfile_selection_title": "请选择私钥文件"
|
||||
"advn": {
|
||||
"filter": "默认键过滤表达式",
|
||||
"filter_tip": "需要加载的键名表达式",
|
||||
"separator": "键分隔符",
|
||||
"separator_tip":"键名路径分隔符",
|
||||
"conn_timeout": "连接超时",
|
||||
"exec_timeout": "执行超时",
|
||||
"dbfilter_type": "数据库过滤方式",
|
||||
"dbfilter_all": "显示所有",
|
||||
"dbfilter_show": "显示指定",
|
||||
"dbfilter_hide": "隐藏指定",
|
||||
"dbfilter_show_title": "需要显示的数据库",
|
||||
"dbfilter_hide_title": "需要隐藏的数据库",
|
||||
"dbfilter_input": "输入数据库索引",
|
||||
"dbfilter_input_tip": "按回车确认",
|
||||
"mark_color": "标记颜色"
|
||||
},
|
||||
"ssh": {
|
||||
"enable": "启用SSH隧道",
|
||||
"tunnel": "SSH隧道",
|
||||
"login_type": "登录类型",
|
||||
"pkfile": "私钥文件",
|
||||
"passphrase": "私钥密码",
|
||||
"addr_tip": "SSH地址",
|
||||
"usr_tip": "SSH登录用户名",
|
||||
"pwd_tip": "SSH登录密码",
|
||||
"pkfile_tip": "SSH私钥文件路径",
|
||||
"passphrase_tip": "(可选)SSH私钥密码",
|
||||
"pkfile_selection_title": "请选择私钥文件"
|
||||
}
|
||||
},
|
||||
"group": {
|
||||
"name": "分组名",
|
||||
|
|
|
@ -208,6 +208,8 @@ const useConnectionStore = defineStore('connections', {
|
|||
keySeparator: ':',
|
||||
connTimeout: 60,
|
||||
execTimeout: 60,
|
||||
dbFilterType: 'none',
|
||||
dbFilterList: [],
|
||||
markColor: '',
|
||||
ssh: {
|
||||
enable: false,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import useConnectionStore from './connections.js'
|
||||
import { assignWith, isEmpty } from 'lodash'
|
||||
|
||||
/**
|
||||
* connection dialog type
|
||||
|
@ -81,7 +82,16 @@ const useDialogStore = defineStore('dialog', {
|
|||
async openEditDialog(name) {
|
||||
const connStore = useConnectionStore()
|
||||
const profile = await connStore.getConnectionProfile(name)
|
||||
this.connParam = profile || connStore.newDefaultConnection(name)
|
||||
const assignCustomizer = (objVal, srcVal, key) => {
|
||||
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.connDialogVisible = true
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue