feat: support database alias

This commit is contained in:
Lykin 2024-01-18 17:15:34 +08:00
parent 42fa24debd
commit 6d3526c765
10 changed files with 114 additions and 22 deletions

View File

@ -179,8 +179,13 @@ func (b *browserService) OpenConnection(name string) (resp types.JSResp) {
dbInfoStr := info["Keyspace"][dbName] dbInfoStr := info["Keyspace"][dbName]
if len(dbInfoStr) > 0 { if len(dbInfoStr) > 0 {
dbInfo := b.parseDBItemInfo(dbInfoStr) dbInfo := b.parseDBItemInfo(dbInfoStr)
var alias string
if selConn.Alias != nil {
alias = selConn.Alias[idx]
}
return types.ConnectionDB{ return types.ConnectionDB{
Name: dbName, Name: dbName,
Alias: alias,
Index: idx, Index: idx,
MaxKeys: dbInfo["keys"], MaxKeys: dbInfo["keys"],
Expires: dbInfo["expires"], Expires: dbInfo["expires"],

View File

@ -20,6 +20,7 @@ type ConnectionConfig struct {
LoadSize int `json:"loadSize,omitempty" yaml:"load_size,omitempty"` LoadSize int `json:"loadSize,omitempty" yaml:"load_size,omitempty"`
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"` MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
RefreshInterval int `json:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty"` RefreshInterval int `json:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty"`
Alias map[int]string `json:"alias,omitempty" yaml:"alias,omitempty"`
SSL ConnectionSSL `json:"ssl,omitempty" yaml:"ssl,omitempty"` SSL ConnectionSSL `json:"ssl,omitempty" yaml:"ssl,omitempty"`
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"` SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
Sentinel ConnectionSentinel `json:"sentinel,omitempty" yaml:"sentinel,omitempty"` Sentinel ConnectionSentinel `json:"sentinel,omitempty" yaml:"sentinel,omitempty"`
@ -36,6 +37,7 @@ type Connections []Connection
type ConnectionDB struct { type ConnectionDB struct {
Name string `json:"name"` Name string `json:"name"`
Alias string `json:"alias,omitempty"`
Index int `json:"index"` Index int `json:"index"`
MaxKeys int `json:"maxKeys"` MaxKeys int `json:"maxKeys"`
Expires int `json:"expires,omitempty"` Expires int `json:"expires,omitempty"`

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { every, get, includes, isEmpty, map, sortBy, toNumber } from 'lodash' import { every, get, includes, isEmpty, map, reject, 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 { ListSentinelMasters, TestConnection } from 'wailsjs/go/services/connectionService.js' import { ListSentinelMasters, TestConnection } from 'wailsjs/go/services/connectionService.js'
@ -10,6 +10,9 @@ import FileOpenInput from '@/components/common/FileOpenInput.vue'
import { KeyViewType } from '@/consts/key_view_type.js' import { KeyViewType } from '@/consts/key_view_type.js'
import { useThemeVars } from 'naive-ui' import { useThemeVars } from 'naive-ui'
import useBrowserStore from 'stores/browser.js' import useBrowserStore from 'stores/browser.js'
import Delete from '@/components/icons/Delete.vue'
import Add from '@/components/icons/Add.vue'
import IconButton from '@/components/common/IconButton.vue'
/** /**
* Dialog for new or edit connection * Dialog for new or edit connection
@ -72,6 +75,24 @@ const onUpdateDBFilterType = (t) => {
} }
} }
const aliasPair = ref([
/*{ db: 0, alias: '' }*/
])
const onCreateAlias = () => {
return {
db: 0,
alias: '',
}
}
const onUpdateAlias = () => {
const val = reject(aliasPair.value, (v) => v == null || isEmpty(v.alias))
const result = {}
for (const elem of val) {
result[elem.db] = elem.alias
}
generalForm.value.alias = result
}
watch( watch(
() => dbFilterList.value, () => dbFilterList.value,
(list) => { (list) => {
@ -210,6 +231,13 @@ watch(
generalForm.value = dialogStore.connParam || connectionStore.newDefaultConnection() generalForm.value = dialogStore.connParam || connectionStore.newDefaultConnection()
dbFilterList.value = map(generalForm.value.dbFilterList, (item) => item + '') dbFilterList.value = map(generalForm.value.dbFilterList, (item) => item + '')
generalForm.value.ssh.loginType = generalForm.value.ssh.loginType || 'pwd' generalForm.value.ssh.loginType = generalForm.value.ssh.loginType || 'pwd'
// update alias display
const alias = get(generalForm.value, 'alias', {})
const pairs = []
for (const db in alias) {
pairs.push({ db: parseInt(db), alias: alias[db] })
}
aliasPair.value = pairs
} }
}, },
) )
@ -254,9 +282,15 @@ const onClose = () => {
style="width: 600px" style="width: 600px"
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
pane-style="min-height: 50vh;"
placement="left"
tab-style="justify-content: right;"
type="line">
<!-- General pane --> <!-- 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:lazy" name="general">
<n-form <n-form
ref="generalFormRef" ref="generalFormRef"
:model="generalForm" :model="generalForm"
@ -434,8 +468,42 @@ const onClose = () => {
</n-form> </n-form>
</n-tab-pane> </n-tab-pane>
<n-tab-pane :tab="$t('dialogue.connection.alias.title')" display-directive="show:lazy" name="alias">
<n-form
:model="generalForm.alias"
:show-label="false"
:show-require-mark="false"
label-placement="top">
<n-form-item required>
<n-dynamic-input
v-model:value="aliasPair"
@create="onCreateAlias"
@update:value="onUpdateAlias">
<template #default="{ value }">
<n-input-number
v-model:value="value.db"
:min="0"
:placeholder="$t('dialogue.connection.alias.db')"
:show-button="false"
@update:value="onUpdateAlias" />
<n-text>:</n-text>
<n-input
v-model:value="value.alias"
:placeholder="$t('dialogue.connection.alias.value')"
type="text"
@update:value="onUpdateAlias" />
</template>
<template #action="{ index, create, remove, move }">
<icon-button :icon="Delete" size="18" @click="() => remove(index)" />
<icon-button :icon="Add" size="18" @click="() => create(index)" />
</template>
</n-dynamic-input>
</n-form-item>
</n-form>
</n-tab-pane>
<!-- SSL pane --> <!-- SSL pane -->
<n-tab-pane :tab="$t('dialogue.connection.ssl.title')" display-directive="show" name="ssl"> <n-tab-pane :tab="$t('dialogue.connection.ssl.title')" display-directive="show:lazy" name="ssl">
<n-form-item label-placement="left"> <n-form-item label-placement="left">
<n-checkbox v-model:checked="generalForm.ssl.enable" size="medium"> <n-checkbox v-model:checked="generalForm.ssl.enable" size="medium">
{{ $t('dialogue.connection.ssl.enable') }} {{ $t('dialogue.connection.ssl.enable') }}
@ -478,7 +546,7 @@ const onClose = () => {
</n-tab-pane> </n-tab-pane>
<!-- SSH pane --> <!-- SSH pane -->
<n-tab-pane :tab="$t('dialogue.connection.ssh.title')" display-directive="show" name="ssh"> <n-tab-pane :tab="$t('dialogue.connection.ssh.title')" display-directive="show:lazy" 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') }}
@ -538,7 +606,10 @@ const onClose = () => {
</n-tab-pane> </n-tab-pane>
<!-- Sentinel pane --> <!-- Sentinel pane -->
<n-tab-pane :tab="$t('dialogue.connection.sentinel.title')" display-directive="show" name="sentinel"> <n-tab-pane
:tab="$t('dialogue.connection.sentinel.title')"
display-directive="show:lazy"
name="sentinel">
<n-form-item label-placement="left"> <n-form-item label-placement="left">
<n-checkbox v-model:checked="generalForm.sentinel.enable" size="medium"> <n-checkbox v-model:checked="generalForm.sentinel.enable" size="medium">
{{ $t('dialogue.connection.sentinel.enable') }} {{ $t('dialogue.connection.sentinel.enable') }}
@ -580,7 +651,7 @@ const onClose = () => {
</n-tab-pane> </n-tab-pane>
<!-- Cluster pane --> <!-- Cluster pane -->
<n-tab-pane :tab="$t('dialogue.connection.cluster.title')" display-directive="show" name="cluster"> <n-tab-pane :tab="$t('dialogue.connection.cluster.title')" display-directive="show:lazy" name="cluster">
<n-form-item label-placement="left"> <n-form-item label-placement="left">
<n-checkbox v-model:checked="generalForm.cluster.enable" size="medium"> <n-checkbox v-model:checked="generalForm.cluster.enable" size="medium">
{{ $t('dialogue.connection.cluster.enable') }} {{ $t('dialogue.connection.cluster.enable') }}

View File

@ -25,11 +25,6 @@ const updateOption = [
}, },
] ]
/**
* @typedef ZSetItem
* @property {string} value
* @property {string} score
*/
const zset = ref([{ value: '', score: 0 }]) const zset = ref([{ value: '', score: 0 }])
const onCreate = () => { const onCreate = () => {
return { return {

View File

@ -4,7 +4,7 @@ import BrowserTree from './BrowserTree.vue'
import IconButton from '@/components/common/IconButton.vue' import IconButton from '@/components/common/IconButton.vue'
import useTabStore from 'stores/tab.js' import useTabStore from 'stores/tab.js'
import { computed, nextTick, onMounted, reactive, ref, unref, watch } from 'vue' import { computed, nextTick, onMounted, reactive, ref, unref, watch } from 'vue'
import { find, get, map, size } from 'lodash' import { find, get, isEmpty, map, size } from 'lodash'
import Refresh from '@/components/icons/Refresh.vue' import Refresh from '@/components/icons/Refresh.vue'
import useDialogStore from 'stores/dialog.js' import useDialogStore from 'stores/dialog.js'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@ -50,16 +50,22 @@ const inCheckState = ref(false)
const dbSelectOptions = computed(() => { const dbSelectOptions = computed(() => {
const dblist = browserStore.getDBList(props.server) const dblist = browserStore.getDBList(props.server)
return map(dblist, (db) => { return map(dblist, ({ db, alias, keyCount, maxKeys }) => {
if (props.db === db.db) { let label
return { if (!isEmpty(alias)) {
value: db.db, // has alias
label: `db${db.db} (${db.keyCount}/${db.maxKeys})`, label = `${alias}[${db}]`
} else {
label = `db${db}`
} }
if (props.db === db) {
label += ` (${keyCount}/${maxKeys})`
} else {
label += ` (${maxKeys})`
} }
return { return {
value: db.db, value: db,
label: `db${db.db} (${db.maxKeys})`, label: label,
} }
}) })
}) })

View File

@ -201,6 +201,11 @@
"load_size": "Size of Keys Per Load", "load_size": "Size of Keys Per Load",
"mark_color": "Mark Color" "mark_color": "Mark Color"
}, },
"alias": {
"title": "Database Alias",
"db": "Input Database Index",
"value": "Input Database Alias"
},
"ssl": { "ssl": {
"title": "SSL/TLS", "title": "SSL/TLS",
"enable": "Enable SSL/TLS", "enable": "Enable SSL/TLS",

View File

@ -201,6 +201,11 @@
"load_size": "单次加载键数量", "load_size": "单次加载键数量",
"mark_color": "标记颜色" "mark_color": "标记颜色"
}, },
"alias": {
"title": "数据库别名",
"db": "输入数据库索引",
"value": "输入别名"
},
"ssl": { "ssl": {
"title": "SSL/TLS", "title": "SSL/TLS",
"enable": "启用SSL", "enable": "启用SSL",

View File

@ -2,8 +2,9 @@
* redis database item * redis database item
*/ */
export class RedisDatabaseItem { export class RedisDatabaseItem {
constructor({ db = 0, keyCount = 0, maxKeys = 0 }) { constructor({ db = 0, alias = '', keyCount = 0, maxKeys = 0 }) {
this.db = db this.db = db
this.alias = alias
this.keyCount = keyCount this.keyCount = keyCount
this.maxKeys = maxKeys this.maxKeys = maxKeys
} }

View File

@ -252,6 +252,7 @@ const useBrowserStore = defineStore('browser', {
for (const dbItem of db) { for (const dbItem of db) {
databases[dbItem.index] = new RedisDatabaseItem({ databases[dbItem.index] = new RedisDatabaseItem({
db: dbItem.index, db: dbItem.index,
alias: dbItem.alias,
maxKeys: dbItem.maxKeys, maxKeys: dbItem.maxKeys,
}) })
if (dbItem.index === lastDB) { if (dbItem.index === lastDB) {

View File

@ -164,6 +164,7 @@ const useConnectionStore = defineStore('connections', {
keyView: KeyViewType.Tree, keyView: KeyViewType.Tree,
loadSize: 10000, loadSize: 10000,
markColor: '', markColor: '',
alias: {},
ssl: { ssl: {
enable: false, enable: false,
allowInsecure: true, allowInsecure: true,