Compare commits

..

3 Commits

Author SHA1 Message Date
Lykin b4405eb7db chore: update dependencies 2024-05-22 23:05:41 +08:00
Lykin 04bc103583 fix: line numbers in the monaco editor may wrapped 2024-05-22 22:43:54 +08:00
Lykin f17bb744f4 perf: support refresh field in hash (#260) 2024-05-22 17:24:38 +08:00
10 changed files with 129 additions and 19 deletions

View File

@ -1331,6 +1331,45 @@ func (b *browserService) SetKeyValue(param types.SetKeyParam) (resp types.JSResp
return return
} }
// GetHashValue get hash field
func (b *browserService) GetHashValue(param types.GetHashParam) (resp types.JSResp) {
item, err := b.getRedisClient(param.Server, param.DB)
if err != nil {
resp.Msg = err.Error()
return
}
client, ctx := item.client, item.ctx
key := strutil.DecodeRedisKey(param.Key)
val, err := client.HGet(ctx, key, param.Field).Result()
if errors.Is(err, redis.Nil) {
resp.Msg = "field in key not found"
return
}
if err != nil {
resp.Msg = err.Error()
return
}
var displayVal string
if (len(param.Decode) > 0 && param.Decode != types.DECODE_NONE) ||
(len(param.Format) > 0 && param.Format != types.FORMAT_RAW) {
decoder := Preferences().GetDecoder()
displayVal, _, _ = convutil.ConvertTo(val, param.Decode, param.Format, decoder)
if displayVal == val {
displayVal = ""
}
}
resp.Data = types.HashEntryItem{
Key: param.Field,
Value: val,
DisplayValue: displayVal,
}
resp.Success = true
return
}
// SetHashValue update hash field // SetHashValue update hash field
func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSResp) { func (b *browserService) SetHashValue(param types.SetHashParam) (resp types.JSResp) {
item, err := b.getRedisClient(param.Server, param.DB) item, err := b.getRedisClient(param.Server, param.DB)

View File

@ -101,3 +101,12 @@ type SetZSetParam struct {
RetFormat string `json:"retFormat,omitempty"` RetFormat string `json:"retFormat,omitempty"`
RetDecode string `json:"retDecode,omitempty"` RetDecode string `json:"retDecode,omitempty"`
} }
type GetHashParam struct {
Server string `json:"server"`
DB int `json:"db"`
Key any `json:"key"`
Field string `json:"field,omitempty"`
Format string `json:"format,omitempty"`
Decode string `json:"decode,omitempty"`
}

View File

@ -8,12 +8,12 @@
"name": "frontend", "name": "frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"chart.js": "^4.4.2", "chart.js": "^4.4.3",
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"monaco-editor": "^0.47.0", "monaco-editor": "^0.47.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"sass": "^1.77.1", "sass": "^1.77.2",
"vue": "^3.4.27", "vue": "^3.4.27",
"vue-chartjs": "^5.3.1", "vue-chartjs": "^5.3.1",
"vue-i18n": "^9.13.1", "vue-i18n": "^9.13.1",
@ -1009,9 +1009,9 @@
"dev": true "dev": true
}, },
"node_modules/chart.js": { "node_modules/chart.js": {
"version": "4.4.2", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz",
"integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==",
"dependencies": { "dependencies": {
"@kurkle/color": "^0.3.0" "@kurkle/color": "^0.3.0"
}, },
@ -1891,9 +1891,9 @@
} }
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.77.1", "version": "1.77.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.1.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz",
"integrity": "sha512-OMEyfirt9XEfyvocduUIOlUSkWOXS/LAt6oblR/ISXCTukyavjex+zQNm51pPCOiFKY1QpWvEH1EeCkgyV3I6w==", "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==",
"dependencies": { "dependencies": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0", "immutable": "^4.0.0",
@ -2998,9 +2998,9 @@
"dev": true "dev": true
}, },
"chart.js": { "chart.js": {
"version": "4.4.2", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz",
"integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==",
"requires": { "requires": {
"@kurkle/color": "^0.3.0" "@kurkle/color": "^0.3.0"
} }
@ -3625,9 +3625,9 @@
} }
}, },
"sass": { "sass": {
"version": "1.77.1", "version": "1.77.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.1.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz",
"integrity": "sha512-OMEyfirt9XEfyvocduUIOlUSkWOXS/LAt6oblR/ISXCTukyavjex+zQNm51pPCOiFKY1QpWvEH1EeCkgyV3I6w==", "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==",
"requires": { "requires": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0", "immutable": "^4.0.0",

View File

@ -9,12 +9,12 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"chart.js": "^4.4.2", "chart.js": "^4.4.3",
"dayjs": "^1.11.11", "dayjs": "^1.11.11",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"monaco-editor": "^0.47.0", "monaco-editor": "^0.47.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"sass": "^1.77.1", "sass": "^1.77.2",
"vue": "^3.4.27", "vue": "^3.4.27",
"vue-chartjs": "^5.3.1", "vue-chartjs": "^5.3.1",
"vue-i18n": "^9.13.1", "vue-i18n": "^9.13.1",

View File

@ -1 +1 @@
c560453a1ccab2d0c6910daad20e4009 76020c81d7419fcb32383b7b397a60c7

View File

@ -5,14 +5,16 @@ import Edit from '@/components/icons/Edit.vue'
import Close from '@/components/icons/Close.vue' import Close from '@/components/icons/Close.vue'
import Save from '@/components/icons/Save.vue' import Save from '@/components/icons/Save.vue'
import Copy from '@/components/icons/Copy.vue' import Copy from '@/components/icons/Copy.vue'
import Refresh from '@/components/icons/Refresh.vue'
const props = defineProps({ const props = defineProps({
bindKey: String, bindKey: String,
editing: Boolean, editing: Boolean,
readonly: Boolean, readonly: Boolean,
canRefresh: Boolean,
}) })
const emit = defineEmits(['edit', 'delete', 'copy', 'save', 'cancel']) const emit = defineEmits(['edit', 'delete', 'copy', 'refresh', 'save', 'cancel'])
</script> </script>
<template> <template>
@ -22,6 +24,7 @@ const emit = defineEmits(['edit', 'delete', 'copy', 'save', 'cancel'])
</div> </div>
<div v-else class="flex-box-h edit-column-func"> <div v-else class="flex-box-h edit-column-func">
<icon-button :icon="Copy" :title="$t('interface.copy_value')" @click="emit('copy')" /> <icon-button :icon="Copy" :title="$t('interface.copy_value')" @click="emit('copy')" />
<icon-button v-if="props.canRefresh" :icon="Refresh" :title="$t('interface.reload')" @click="emit('refresh')" />
<icon-button v-if="!props.readonly" :icon="Edit" :title="$t('interface.edit_row')" @click="emit('edit')" /> <icon-button v-if="!props.readonly" :icon="Edit" :title="$t('interface.edit_row')" @click="emit('edit')" />
<n-popconfirm <n-popconfirm
:negative-text="$t('common.cancel')" :negative-text="$t('common.cancel')"

View File

@ -249,4 +249,8 @@ onUnmounted(() => {
left: 2px; left: 2px;
right: 2px; right: 2px;
} }
:deep(.line-numbers) {
white-space: nowrap;
}
</style> </style>

View File

@ -92,11 +92,14 @@ const fieldColumn = computed(() => ({
lineClamp: 1, lineClamp: 1,
}, },
filterOptionValue: fieldFilterOption.value, filterOptionValue: fieldFilterOption.value,
className: inEdit.value ? 'clickable' : '', className: inEdit.value ? 'clickable wordline' : 'wordline',
filter: (value, row) => { filter: (value, row) => {
return !!~row.k.indexOf(value.toString()) return !!~row.k.indexOf(value.toString())
}, },
render: (row) => { render: (row) => {
if (row.rm === true) {
return h('s', {}, decodeRedisKey(row.k))
}
return decodeRedisKey(row.k) return decodeRedisKey(row.k)
}, },
})) }))
@ -135,6 +138,9 @@ const valueColumn = computed(() => ({
if (isCode.value) { if (isCode.value) {
return h('pre', {}, row.dv || row.v) return h('pre', {}, row.dv || row.v)
} }
if (row.rm === true) {
return h('s', {}, row.dv || row.v)
}
return row.dv || row.v return row.dv || row.v
}, },
})) }))
@ -204,6 +210,25 @@ const actionColumn = {
return h(EditableTableColumn, { return h(EditableTableColumn, {
editing: false, editing: false,
bindKey: row.k, bindKey: row.k,
canRefresh: true,
onRefresh: async () => {
const { updated, success, msg } = await browserStore.getHashField({
server: props.name,
db: props.db,
key: keyName.value,
field: row.k,
decode: props.decode,
format: props.format,
})
if (success) {
delete props.value[index]['rm']
$message.success(i18n.t('dialogue.reload_succ'))
} else {
// update fail, the key may have been deleted
$message.error(msg)
props.value[index]['rm'] = true
}
},
onCopy: async () => { onCopy: async () => {
try { try {
const succ = await ClipboardSetText(row.v) const succ = await ClipboardSetText(row.v)

View File

@ -15,6 +15,7 @@ import {
FlushDB, FlushDB,
GetClientList, GetClientList,
GetCmdHistory, GetCmdHistory,
GetHashValue,
GetKeyDetail, GetKeyDetail,
GetKeySummary, GetKeySummary,
GetKeyType, GetKeyType,
@ -987,6 +988,31 @@ const useBrowserStore = defineStore('browser', {
} }
}, },
/**
* get hash field
* @param {string} server
* @param {number} db
* @param {string} key
* @param {string} field
* @param {decodeTypes} [decode]
* @param {formatTypes} [format]
* @return {Promise<{{msg: string, success: boolean, updated: HashEntryItem[]}>}
*/
async getHashField({ server, db, key, field, decode = decodeTypes.NONE, format = formatTypes.RAW }) {
try {
const { data, success, msg } = await GetHashValue({ server, db, key, field, decode, format })
if (success && !isEmpty(data)) {
const tab = useTabStore()
tab.updateValueEntries({ server, db, key, type: 'hash', entries: [data] })
return { success, updated: data }
} else {
return { success: false, msg }
}
} catch (e) {
return { success: false, msg: e.message }
}
},
/** /**
* remove hash field * remove hash field
* @param {string} server * @param {string} server

View File

@ -63,6 +63,10 @@ body {
cursor: pointer; cursor: pointer;
} }
.wordline {
word-break: break-all;
}
.icon-btn { .icon-btn {
@extend .clickable; @extend .clickable;
line-height: 100%; line-height: 100%;