refactor: move selectedKey to tab store

perf: add redis type color in new key type selection
perf: update selection after add new key
This commit is contained in:
tiny-craft 2023-07-21 11:14:40 +08:00
parent 9d897894b6
commit 7d3f5b9d9a
9 changed files with 447 additions and 396 deletions

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"log"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -548,61 +547,48 @@ func (c *connectionService) SetKeyValue(connName string, db int, key, keyType st
resp.Msg = "invalid hash value" resp.Msg = "invalid hash value"
return return
} else { } else {
_, err = rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
if len(strs) > 1 { if len(strs) > 1 {
kvs := map[string]any{}
for i := 0; i < len(strs); i += 2 { for i := 0; i < len(strs); i += 2 {
pipe.HSetNX(ctx, key, strs[i].(string), strs[i+1]) kvs[strs[i].(string)] = strs[i+1]
} }
} else { err = rdb.HSet(ctx, key, kvs).Err()
pipe.HSet(ctx, key) if err == nil && expiration > 0 {
rdb.Expire(ctx, key, expiration)
} }
if expiration > 0 {
pipe.Expire(ctx, key, expiration)
} }
return nil
})
} }
case "set": case "set":
if strs, ok := value.([]any); !ok || len(strs) <= 0 { if strs, ok := value.([]any); !ok || len(strs) <= 0 {
resp.Msg = "invalid set value" resp.Msg = "invalid set value"
return return
} else { } else {
_, err = rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { if len(strs) > 0 {
for _, str := range strs { err = rdb.SAdd(ctx, key, strs...).Err()
pipe.SAdd(ctx, key, str.(string)) if err == nil && expiration > 0 {
rdb.Expire(ctx, key, expiration)
} }
if expiration > 0 {
pipe.Expire(ctx, key, expiration)
} }
return nil
})
} }
case "zset": case "zset":
if strs, ok := value.([]any); !ok || len(strs) <= 0 { if strs, ok := value.([]any); !ok || len(strs) <= 0 {
resp.Msg = "invalid zset value" resp.Msg = "invalid zset value"
return return
} else { } else {
log.Println(strs) if len(strs) > 1 {
_, err = rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
var members []redis.Z var members []redis.Z
for i := 0; i < len(strs); i += 2 { for i := 0; i < len(strs); i += 2 {
score, _ := strconv.ParseFloat(strs[i].(string), 64) score, _ := strconv.ParseFloat(strs[i+1].(string), 64)
members = append(members, redis.Z{ members = append(members, redis.Z{
Score: score, Score: score,
Member: strs[i+1], Member: strs[i],
}) })
} }
err = rdb.ZAdd(ctx, key, members...).Err()
if len(members) > 0 { if err == nil && expiration > 0 {
pipe.ZAdd(ctx, key, members...) rdb.Expire(ctx, key, expiration)
} else {
pipe.ZAdd(ctx, key)
} }
if expiration > 0 {
pipe.Expire(ctx, key, expiration)
} }
return nil
})
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -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.4", "pinia": "^2.1.4",
"sass": "^1.63.6", "sass": "^1.64.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-i18n": "^9.2.2" "vue-i18n": "^9.2.2"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue": "^4.2.3",
"naive-ui": "^2.34.4", "naive-ui": "^2.34.4",
"prettier": "^2.8.8", "prettier": "^3.0.0",
"unplugin-auto-import": "^0.16.4", "unplugin-auto-import": "^0.16.6",
"unplugin-icons": "^0.16.3", "unplugin-icons": "^0.16.5",
"unplugin-vue-components": "^0.25.1", "unplugin-vue-components": "^0.25.1",
"vite": "^4.3.9" "vite": "^4.4.4"
} }
} }

View File

@ -1 +1 @@
5f51299692e0fa4f59808fc597b869bc a78b05ffa1b32562b864c79d62d5fc2e

View File

@ -1,6 +1,6 @@
<script setup> <script setup>
import { computed, reactive, ref, watch } from 'vue' import { computed, h, reactive, ref, watch } from 'vue'
import { types } from '../../consts/support_redis_type' import { types, typesColor } from '../../consts/support_redis_type'
import useDialog from '../../stores/dialog' import useDialog from '../../stores/dialog'
import { isEmpty, keys, map } from 'lodash' import { isEmpty, keys, map } from 'lodash'
import NewStringValue from '../new_value/NewStringValue.vue' import NewStringValue from '../new_value/NewStringValue.vue'
@ -10,7 +10,8 @@ import NewZSetValue from '../new_value/NewZSetValue.vue'
import NewSetValue from '../new_value/NewSetValue.vue' import NewSetValue from '../new_value/NewSetValue.vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import useConnectionStore from '../../stores/connections.js' import useConnectionStore from '../../stores/connections.js'
import { useMessage } from 'naive-ui' import { NSpace, useMessage } from 'naive-ui'
import useTabStore from '../../stores/tab.js'
const i18n = useI18n() const i18n = useI18n()
const newForm = reactive({ const newForm = reactive({
@ -33,7 +34,7 @@ const dbOptions = computed(() =>
map(keys(connectionStore.databases[newForm.server]), (key) => ({ map(keys(connectionStore.databases[newForm.server]), (key) => ({
label: key, label: key,
value: parseInt(key), value: parseInt(key),
})) })),
) )
const newFormRef = ref(null) const newFormRef = ref(null)
const subFormRef = ref(null) const subFormRef = ref(null)
@ -73,10 +74,32 @@ watch(
newForm.ttl = -1 newForm.ttl = -1
newForm.value = null newForm.value = null
} }
} },
) )
const renderTypeLabel = (option) => {
return h(
NSpace,
{ align: 'center', inline: true, size: 3 },
{
default: () => [
h('div', {
style: {
borderRadius: '50%',
backgroundColor: typesColor[option.value],
width: '13px',
height: '13px',
border: '2px solid white',
},
}),
option.value,
],
},
)
}
const connectionStore = useConnectionStore() const connectionStore = useConnectionStore()
const tabStore = useTabStore()
const message = useMessage() const message = useMessage()
const onAdd = async () => { const onAdd = async () => {
await newFormRef.value?.validate().catch((err) => { await newFormRef.value?.validate().catch((err) => {
@ -92,7 +115,14 @@ const onAdd = async () => {
if (value == null) { if (value == null) {
value = defaultValue[type] value = defaultValue[type]
} }
await connectionStore.setKey(server, db, key, type, value, ttl) const { success, msg, nodeKey } = await connectionStore.setKey(server, db, key, type, value, ttl)
if (success) {
// select current key
tabStore.setSelectedKeys(server, nodeKey)
connectionStore.loadKeyValue(server, db, key).then(() => {})
} else if (!isEmpty(msg)) {
message.error(msg)
}
dialogStore.closeNewKeyDialog() dialogStore.closeNewKeyDialog()
} catch (e) {} } catch (e) {}
} }
@ -138,7 +168,7 @@ const onClose = () => {
<n-select v-model:value="newForm.db" :options="dbOptions" /> <n-select v-model:value="newForm.db" :options="dbOptions" />
</n-form-item> </n-form-item>
<n-form-item :label="$t('type')" path="type" required> <n-form-item :label="$t('type')" path="type" required>
<n-select v-model:value="newForm.type" :options="options" /> <n-select v-model:value="newForm.type" :options="options" :render-label="renderTypeLabel" />
</n-form-item> </n-form-item>
<n-form-item :label="$t('ttl')" required> <n-form-item :label="$t('ttl')" required>
<n-input-group> <n-input-group>

View File

@ -29,7 +29,7 @@ const onUpdate = () => {
const val = reject(zset.value, (v) => v == null || isEmpty(v.value)) const val = reject(zset.value, (v) => v == null || isEmpty(v.value))
emit( emit(
'update:value', 'update:value',
flatMap(val, (item) => [item.value, item.score.toString()]) flatMap(val, (item) => [item.value, item.score.toString()]),
) )
} }

View File

@ -4,7 +4,7 @@ import { ConnectionType } from '../../consts/connection_type.js'
import { NIcon, NSpace, NTag, useDialog, useMessage } from 'naive-ui' import { NIcon, NSpace, NTag, useDialog, useMessage } from 'naive-ui'
import Key from '../icons/Key.vue' import Key from '../icons/Key.vue'
import ToggleDb from '../icons/ToggleDb.vue' import ToggleDb from '../icons/ToggleDb.vue'
import { get, indexOf, isEmpty, remove } from 'lodash' import { find, get, indexOf, isEmpty, remove } from 'lodash'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import Refresh from '../icons/Refresh.vue' import Refresh from '../icons/Refresh.vue'
import CopyLink from '../icons/CopyLink.vue' import CopyLink from '../icons/CopyLink.vue'
@ -21,6 +21,7 @@ import Unlink from '../icons/Unlink.vue'
import Filter from '../icons/Filter.vue' import Filter from '../icons/Filter.vue'
import Close from '../icons/Close.vue' import Close from '../icons/Close.vue'
import { typesBgColor, typesColor } from '../../consts/support_redis_type.js' import { typesBgColor, typesColor } from '../../consts/support_redis_type.js'
import useTabStore from '../../stores/tab.js'
const props = defineProps({ const props = defineProps({
server: String, server: String,
@ -30,10 +31,22 @@ const i18n = useI18n()
const loading = ref(false) const loading = ref(false)
const loadingConnections = ref(false) const loadingConnections = ref(false)
const expandedKeys = ref([props.server]) const expandedKeys = ref([props.server])
const selectedKeys = ref([props.server])
const connectionStore = useConnectionStore() const connectionStore = useConnectionStore()
const tabStore = useTabStore()
const dialogStore = useDialogStore() const dialogStore = useDialogStore()
/**
*
* @type {ComputedRef<string[]>}
*/
const selectedKeys = computed(() => {
const tab = find(tabStore.tabList, { name: props.server })
if (tab != null) {
return get(tab, 'selectedKeys', [props.server])
}
return [props.server]
})
const data = computed(() => { const data = computed(() => {
const dbs = get(connectionStore.databases, props.server, []) const dbs = get(connectionStore.databases, props.server, [])
return [ return [
@ -233,7 +246,7 @@ const onUpdateSelectedKeys = (keys, options) => {
connectionStore.loadKeyValue(props.server, 0) connectionStore.loadKeyValue(props.server, 0)
} }
} finally { } finally {
selectedKeys.value = keys tabStore.setSelectedKeys(props.server, keys)
} }
} }
@ -245,7 +258,7 @@ const renderPrefix = ({ option }) => {
{ size: 20 }, { size: 20 },
{ {
default: () => h(ToggleServer, { modelValue: false }), default: () => h(ToggleServer, { modelValue: false }),
} },
) )
case ConnectionType.RedisDB: case ConnectionType.RedisDB:
return h( return h(
@ -253,7 +266,7 @@ const renderPrefix = ({ option }) => {
{ size: 20 }, { size: 20 },
{ {
default: () => h(ToggleDb, { modelValue: option.opened === true }), default: () => h(ToggleDb, { modelValue: option.opened === true }),
} },
) )
case ConnectionType.RedisKey: case ConnectionType.RedisKey:
return h( return h(
@ -261,7 +274,7 @@ const renderPrefix = ({ option }) => {
{ size: 20 }, { size: 20 },
{ {
default: () => h(Layer), default: () => h(Layer),
} },
) )
case ConnectionType.RedisValue: case ConnectionType.RedisValue:
return h( return h(
@ -269,7 +282,7 @@ const renderPrefix = ({ option }) => {
{ size: 20 }, { size: 20 },
{ {
default: () => h(Key), default: () => h(Key),
} },
) )
} }
} }
@ -309,8 +322,8 @@ const renderSuffix = ({ option }) => {
connectionStore.reopenDatabase(server, db) connectionStore.reopenDatabase(server, db)
}, },
}, },
{ default: () => typeFilter } { default: () => typeFilter },
) ),
) )
} }
// match pattern tag // match pattern tag
@ -328,8 +341,8 @@ const renderSuffix = ({ option }) => {
connectionStore.reopenDatabase(server, db) connectionStore.reopenDatabase(server, db)
}, },
}, },
{ default: () => matchPattern } { default: () => matchPattern },
) ),
) )
} }
if (filterNodes.length > 0) { if (filterNodes.length > 0) {
@ -362,7 +375,7 @@ const nodeProps = ({ option }) => {
contextMenuParam.x = e.clientX contextMenuParam.x = e.clientX
contextMenuParam.y = e.clientY contextMenuParam.y = e.clientY
contextMenuParam.show = true contextMenuParam.show = true
selectedKeys.value = [option.key] tabStore.setSelectedKeys(props.server, option.key)
}) })
}, },
// onMouseover() { // onMouseover() {

View File

@ -525,6 +525,9 @@ const useConnectionStore = defineStore('connections', {
value, value,
}) })
return return
} else {
// key not exists, remove this key
await this.deleteKey(server, db, key)
} }
} }
@ -798,7 +801,7 @@ const useConnectionStore = defineStore('connections', {
* @param {string} keyType * @param {string} keyType
* @param {any} value * @param {any} value
* @param {number} ttl * @param {number} ttl
* @returns {Promise<{[msg]: string, success: boolean}>} * @returns {Promise<{[msg]: string, success: boolean, [nodeKey]: {string}}>}
*/ */
async setKey(connName, db, key, keyType, value, ttl) { async setKey(connName, db, key, keyType, value, ttl) {
try { try {
@ -809,7 +812,7 @@ const useConnectionStore = defineStore('connections', {
if (newKey > 0) { if (newKey > 0) {
this._tidyNode(connName, db, key) this._tidyNode(connName, db, key)
} }
return { success } return { success, nodeKey: `${connName}/db${db}#${ConnectionType.RedisValue}/${key}` }
} else { } else {
return { success, msg } return { success, msg }
} }

View File

@ -7,7 +7,8 @@ const useTabStore = defineStore('tab', {
* @property {string} name connection name * @property {string} name connection name
* @property {boolean} blank is blank tab * @property {boolean} blank is blank tab
* @property {string} [title] tab title * @property {string} [title] tab title
* @property {string} [icon] tab title * @property {string} [icon] tab icon
* @property {string[]} selectedKeys
* @property {string} [type] key type * @property {string} [type] key type
* @property {Object|Array} [value] key value * @property {Object|Array} [value] key value
* @property {string} [server] server name * @property {string} [server] server name
@ -51,20 +52,13 @@ const useTabStore = defineStore('tab', {
// } // }
// return current // return current
}, },
currentSelectedKeys() {
const tab = this.currentTab()
return get(tab, 'selectedKeys', [])
},
}, },
actions: { actions: {
/**
* create new blank tab to tail
*/
newBlankTab() {
this.tabList.push({
name: Date.now().toString(),
title: 'new tab',
blank: true,
})
this._setActivatedIndex(size(this.tabList) - 1)
},
/** /**
* *
* @param idx * @param idx
@ -208,6 +202,21 @@ const useTabStore = defineStore('tab', {
this.tabList = [] this.tabList = []
this._setActivatedIndex(-1, false) this._setActivatedIndex(-1, false)
}, },
/**
*
* @param {string} server
* @param {string|string[]} keys
*/
setSelectedKeys(server, keys) {
if (typeof keys === 'string') {
keys = [keys]
}
let tab = find(this.tabList, { name: server })
if (tab != null) {
tab.selectedKeys = keys
}
},
}, },
}) })