feat: add type display in key browser
This commit is contained in:
parent
b688ded610
commit
af6b4257f9
|
@ -516,6 +516,35 @@ func (b *browserService) LoadAllKeys(connName string, db int, match, keyType str
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *browserService) GetKeyType(param types.KeySummaryParam) (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)
|
||||||
|
var keyType string
|
||||||
|
keyType, err = client.Type(ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if keyType == "none" {
|
||||||
|
resp.Msg = "key not exists"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var data types.KeySummary
|
||||||
|
data.Type = strings.ToLower(keyType)
|
||||||
|
|
||||||
|
resp.Success = true
|
||||||
|
resp.Data = data
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// GetKeySummary get key summary info
|
// GetKeySummary get key summary info
|
||||||
func (b *browserService) GetKeySummary(param types.KeySummaryParam) (resp types.JSResp) {
|
func (b *browserService) GetKeySummary(param types.KeySummaryParam) (resp types.JSResp) {
|
||||||
item, err := b.getRedisClient(param.Server, param.DB)
|
item, err := b.getRedisClient(param.Server, param.DB)
|
||||||
|
|
|
@ -14,9 +14,9 @@ type KeySummaryParam struct {
|
||||||
|
|
||||||
type KeySummary struct {
|
type KeySummary struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
TTL int64 `json:"ttl"`
|
TTL int64 `json:"ttl,omitempty"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size,omitempty"`
|
||||||
Length int64 `json:"length"`
|
Length int64 `json:"length,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyDetailParam struct {
|
type KeyDetailParam struct {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import ContentPane from './components/content/ContentPane.vue'
|
import ContentPane from './components/content/ContentPane.vue'
|
||||||
import BrowserPane from './components/sidebar/BrowserPane.vue'
|
import BrowserPane from './components/sidebar/BrowserPane.vue'
|
||||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||||
import { debounce, get } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import { useThemeVars } from 'naive-ui'
|
import { useThemeVars } from 'naive-ui'
|
||||||
import Ribbon from './components/sidebar/Ribbon.vue'
|
import Ribbon from './components/sidebar/Ribbon.vue'
|
||||||
import ConnectionPane from './components/sidebar/ConnectionPane.vue'
|
import ConnectionPane from './components/sidebar/ConnectionPane.vue'
|
||||||
|
@ -139,7 +139,7 @@ onMounted(async () => {
|
||||||
<div style="min-width: 68px; font-weight: 800">Tiny RDM</div>
|
<div style="min-width: 68px; font-weight: 800">Tiny RDM</div>
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<n-text v-if="tabStore.nav === 'browser'" class="ellipsis" strong style="font-size: 13px">
|
<n-text v-if="tabStore.nav === 'browser'" class="ellipsis" strong style="font-size: 13px">
|
||||||
- {{ get(tabStore.currentTab, 'name') }}
|
- {{ tabStore.currentTabName }}
|
||||||
</n-text>
|
</n-text>
|
||||||
</transition>
|
</transition>
|
||||||
</n-space>
|
</n-space>
|
||||||
|
@ -174,13 +174,15 @@ onMounted(async () => {
|
||||||
@update:size="handleResize">
|
@update:size="handleResize">
|
||||||
<browser-pane
|
<browser-pane
|
||||||
v-for="t in tabStore.tabs"
|
v-for="t in tabStore.tabs"
|
||||||
v-show="get(tabStore.currentTab, 'name') === t.name"
|
v-show="tabStore.currentTabName === t.name"
|
||||||
:key="t.name"
|
:key="t.name"
|
||||||
|
:db="t.db"
|
||||||
|
:server="t.name"
|
||||||
class="app-side flex-item-expand" />
|
class="app-side flex-item-expand" />
|
||||||
</resizeable-wrapper>
|
</resizeable-wrapper>
|
||||||
<content-pane
|
<content-pane
|
||||||
v-for="t in tabStore.tabs"
|
v-for="t in tabStore.tabs"
|
||||||
v-show="get(tabStore.currentTab, 'name') === t.name"
|
v-show="tabStore.currentTabName === t.name"
|
||||||
:key="t.name"
|
:key="t.name"
|
||||||
:server="t.name"
|
:server="t.name"
|
||||||
class="flex-item-expand" />
|
class="flex-item-expand" />
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { computed, h } from 'vue'
|
||||||
import { useThemeVars } from 'naive-ui'
|
import { useThemeVars } from 'naive-ui'
|
||||||
import { types, typesBgColor, typesColor } from '@/consts/support_redis_type.js'
|
import { types, typesBgColor, typesColor } from '@/consts/support_redis_type.js'
|
||||||
import { get, map, toUpper } from 'lodash'
|
import { get, map, toUpper } from 'lodash'
|
||||||
|
import RedisTypeTag from '@/components/common/RedisTypeTag.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: {
|
value: {
|
||||||
|
@ -23,15 +24,24 @@ const options = computed(() => {
|
||||||
|
|
||||||
const themeVars = useThemeVars()
|
const themeVars = useThemeVars()
|
||||||
const renderIcon = (option) => {
|
const renderIcon = (option) => {
|
||||||
if (option.key === props.value) {
|
return h(RedisTypeTag, {
|
||||||
const backgroundColor = get(typesColor, option.key, themeVars.value.textColor3)
|
type: option.key,
|
||||||
return h('div', { style: { borderRadius: '999px', width: '10px', height: '10px', backgroundColor } }, '')
|
short: true,
|
||||||
}
|
size: 'small',
|
||||||
|
inverse: option.key === props.value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderLabel = (option) => {
|
const renderLabel = (option) => {
|
||||||
const color = get(typesColor, option.key, '')
|
return h(
|
||||||
return h('div', { style: { color, fontWeight: '450' } }, option.label)
|
'div',
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
fontWeight: option.key === props.value ? 'bold' : 'normal',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
option.label,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fontColor = computed(() => {
|
const fontColor = computed(() => {
|
||||||
|
|
|
@ -1,45 +1,69 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { typesBgColor, typesColor, validType } from '@/consts/support_redis_type.js'
|
import { typesBgColor, typesColor, typesShortName } from '@/consts/support_redis_type.js'
|
||||||
import Binary from '@/components/icons/Binary.vue'
|
import Binary from '@/components/icons/Binary.vue'
|
||||||
|
import { toUpper } from 'lodash'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
validator(value) {
|
|
||||||
return validType(value)
|
|
||||||
},
|
|
||||||
default: 'STRING',
|
default: 'STRING',
|
||||||
},
|
},
|
||||||
binaryKey: Boolean,
|
binaryKey: Boolean,
|
||||||
size: String,
|
size: String,
|
||||||
|
short: Boolean,
|
||||||
|
round: Boolean,
|
||||||
|
inverse: Boolean,
|
||||||
})
|
})
|
||||||
|
|
||||||
const fontColor = computed(() => {
|
const fontColor = computed(() => {
|
||||||
|
if (props.inverse) {
|
||||||
|
return typesBgColor[props.type]
|
||||||
|
} else {
|
||||||
return typesColor[props.type]
|
return typesColor[props.type]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const backgroundColor = computed(() => {
|
const backgroundColor = computed(() => {
|
||||||
|
if (props.inverse) {
|
||||||
|
return typesColor[props.type]
|
||||||
|
} else {
|
||||||
return typesBgColor[props.type]
|
return typesBgColor[props.type]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const label = computed(() => {
|
||||||
|
if (props.short) {
|
||||||
|
return typesShortName[toUpper(props.type)] || 'N'
|
||||||
|
}
|
||||||
|
return toUpper(props.type)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-tag
|
<n-tag
|
||||||
:class="[props.size === 'small' ? 'redis-type-tag-small' : 'redis-type-tag']"
|
:class="{
|
||||||
|
'redis-type-tag-normal': !props.short && props.size !== 'small',
|
||||||
|
'redis-type-tag-small': !props.short && props.size === 'small',
|
||||||
|
'redis-type-tag-round': props.round,
|
||||||
|
}"
|
||||||
:color="{ color: backgroundColor, textColor: fontColor }"
|
:color="{ color: backgroundColor, textColor: fontColor }"
|
||||||
:size="props.size"
|
:size="props.size"
|
||||||
|
bordered
|
||||||
strong>
|
strong>
|
||||||
{{ props.type }}
|
<b>{{ label }}</b>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<n-icon v-if="binaryKey" :component="Binary" size="18" />
|
<n-icon v-if="binaryKey" :component="Binary" size="18" />
|
||||||
</template>
|
</template>
|
||||||
</n-tag>
|
</n-tag>
|
||||||
<!-- <div class="redis-type-tag flex-box-h" :style="{backgroundColor: backgroundColor}">{{ props.type }}</div>-->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.redis-type-tag {
|
.redis-type-tag-round {
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.redis-type-tag-normal {
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ const renderTypeLabel = (option) => {
|
||||||
default: () => [
|
default: () => [
|
||||||
h('div', {
|
h('div', {
|
||||||
style: {
|
style: {
|
||||||
borderRadius: '50%',
|
borderRadius: '9999px',
|
||||||
backgroundColor: typesColor[option.value],
|
backgroundColor: typesColor[option.value],
|
||||||
width: '13px',
|
width: '13px',
|
||||||
height: '13px',
|
height: '13px',
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { useThemeVars } from 'naive-ui'
|
||||||
import BrowserTree from './BrowserTree.vue'
|
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 } from 'vue'
|
||||||
import { find, get, map } from 'lodash'
|
import { find, map } 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'
|
||||||
|
@ -24,6 +24,16 @@ import ListCheckbox from '@/components/icons/ListCheckbox.vue'
|
||||||
import Close from '@/components/icons/Close.vue'
|
import Close from '@/components/icons/Close.vue'
|
||||||
import More from '@/components/icons/More.vue'
|
import More from '@/components/icons/More.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
server: String,
|
||||||
|
db: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:db'])
|
||||||
|
|
||||||
const themeVars = useThemeVars()
|
const themeVars = useThemeVars()
|
||||||
const i18n = useI18n()
|
const i18n = useI18n()
|
||||||
const dialogStore = useDialogStore()
|
const dialogStore = useDialogStore()
|
||||||
|
@ -32,21 +42,16 @@ const tabStore = useTabStore()
|
||||||
const browserStore = useBrowserStore()
|
const browserStore = useBrowserStore()
|
||||||
const connectionStore = useConnectionStore()
|
const connectionStore = useConnectionStore()
|
||||||
const render = useRender()
|
const render = useRender()
|
||||||
const currentName = computed(() => get(tabStore.currentTab, 'name', ''))
|
|
||||||
const browserTreeRef = ref(null)
|
const browserTreeRef = ref(null)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const fullyLoaded = ref(false)
|
const fullyLoaded = ref(false)
|
||||||
const inCheckState = ref(false)
|
const inCheckState = ref(false)
|
||||||
const checkedCount = ref(0)
|
const checkedCount = ref(0)
|
||||||
|
|
||||||
const selectedDB = computed(() => {
|
|
||||||
return browserStore.selectedDatabases[currentName.value] || 0
|
|
||||||
})
|
|
||||||
|
|
||||||
const dbSelectOptions = computed(() => {
|
const dbSelectOptions = computed(() => {
|
||||||
const dblist = browserStore.getDBList(currentName.value)
|
const dblist = browserStore.getDBList(props.server)
|
||||||
return map(dblist, (db) => {
|
return map(dblist, (db) => {
|
||||||
if (selectedDB.value === db.db) {
|
if (props.db === db.db) {
|
||||||
return {
|
return {
|
||||||
value: db.db,
|
value: db.db,
|
||||||
label: `db${db.db} (${db.keys}/${db.maxKeys})`,
|
label: `db${db.db} (${db.keys}/${db.maxKeys})`,
|
||||||
|
@ -71,7 +76,7 @@ const moreOptions = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const loadProgress = computed(() => {
|
const loadProgress = computed(() => {
|
||||||
const db = browserStore.getDatabase(currentName.value, selectedDB.value)
|
const db = browserStore.getDatabase(props.server, props.db)
|
||||||
if (db.maxKeys <= 0) {
|
if (db.maxKeys <= 0) {
|
||||||
return 100
|
return 100
|
||||||
}
|
}
|
||||||
|
@ -79,29 +84,29 @@ const loadProgress = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const checkedTip = computed(() => {
|
const checkedTip = computed(() => {
|
||||||
const dblist = browserStore.getDBList(currentName.value)
|
const dblist = browserStore.getDBList(props.server)
|
||||||
const db = find(dblist, { db: selectedDB.value })
|
const db = find(dblist, { db: props.db })
|
||||||
return `${checkedCount.value} / ${db.maxKeys}`
|
return `${checkedCount.value} / ${db.maxKeys}`
|
||||||
})
|
})
|
||||||
|
|
||||||
const onReload = async () => {
|
const onReload = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
tabStore.setSelectedKeys(currentName.value)
|
tabStore.setSelectedKeys(props.server)
|
||||||
const db = selectedDB.value
|
const db = props.db
|
||||||
browserStore.closeDatabase(currentName.value, db)
|
browserStore.closeDatabase(props.server, db)
|
||||||
browserTreeRef.value?.resetExpandKey(currentName.value, db)
|
browserTreeRef.value?.resetExpandKey(props.server, db)
|
||||||
|
|
||||||
let matchType = unref(filterForm.type)
|
let matchType = unref(filterForm.type)
|
||||||
if (!types.hasOwnProperty(matchType)) {
|
if (!types.hasOwnProperty(matchType)) {
|
||||||
matchType = ''
|
matchType = ''
|
||||||
}
|
}
|
||||||
browserStore.setKeyFilter(currentName.value, {
|
browserStore.setKeyFilter(props.server, {
|
||||||
type: matchType,
|
type: matchType,
|
||||||
pattern: unref(filterForm.pattern),
|
pattern: unref(filterForm.pattern),
|
||||||
})
|
})
|
||||||
await browserStore.openDatabase(currentName.value, db)
|
await browserStore.openDatabase(props.server, db)
|
||||||
fullyLoaded.value = await browserStore.loadMoreKeys(currentName.value, db)
|
fullyLoaded.value = await browserStore.loadMoreKeys(props.server, db)
|
||||||
// $message.success(i18n.t('dialogue.reload_succ'))
|
// $message.success(i18n.t('dialogue.reload_succ'))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e)
|
console.warn(e)
|
||||||
|
@ -111,13 +116,13 @@ const onReload = async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onAddKey = () => {
|
const onAddKey = () => {
|
||||||
dialogStore.openNewKeyDialog('', currentName.value, selectedDB.value)
|
dialogStore.openNewKeyDialog('', props.server, props.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLoadMore = async () => {
|
const onLoadMore = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
fullyLoaded.value = await browserStore.loadMoreKeys(currentName.value, selectedDB.value)
|
fullyLoaded.value = await browserStore.loadMoreKeys(props.server, props.db)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$message.error(e.message)
|
$message.error(e.message)
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -128,7 +133,7 @@ const onLoadMore = async () => {
|
||||||
const onLoadAll = async () => {
|
const onLoadAll = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
await browserStore.loadAllKeys(currentName.value, selectedDB.value)
|
await browserStore.loadAllKeys(props.server, props.db)
|
||||||
fullyLoaded.value = true
|
fullyLoaded.value = true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$message.error(e.message)
|
$message.error(e.message)
|
||||||
|
@ -142,15 +147,31 @@ const onDeleteChecked = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onFlush = () => {
|
const onFlush = () => {
|
||||||
dialogStore.openFlushDBDialog(currentName.value, selectedDB.value)
|
dialogStore.openFlushDBDialog(props.server, props.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDisconnect = () => {
|
const onDisconnect = () => {
|
||||||
browserStore.closeConnection(currentName.value)
|
browserStore.closeConnection(props.server)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSelectDB = async (db, prevDB) => {
|
const handleSelectDB = async (db) => {
|
||||||
// watch 'browserStore.openedDB[currentName.value]' instead
|
try {
|
||||||
|
loading.value = true
|
||||||
|
browserStore.closeDatabase(props.server, props.db)
|
||||||
|
browserStore.setKeyFilter(props.server, {})
|
||||||
|
await browserStore.openDatabase(props.server, db)
|
||||||
|
// browserTreeRef.value?.resetExpandKey(props.server, db)
|
||||||
|
fullyLoaded.value = await browserStore.loadMoreKeys(props.server, db)
|
||||||
|
browserTreeRef.value?.refreshTree()
|
||||||
|
|
||||||
|
nextTick().then(() => connectionStore.saveLastDB(props.server, db))
|
||||||
|
} catch (e) {
|
||||||
|
$message.error(e.message)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
// emit('update:db', db)
|
||||||
|
// tabStore.switchTab()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterForm = reactive({
|
const filterForm = reactive({
|
||||||
|
@ -183,30 +204,30 @@ const onSelectOptions = (select) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
// watch(
|
||||||
() => browserStore.openedDB[currentName.value],
|
// () => props.db,
|
||||||
async (db, prevDB) => {
|
// async (db, prevDB) => {
|
||||||
if (db === undefined) {
|
// if (db === undefined) {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
loading.value = true
|
// loading.value = true
|
||||||
browserStore.closeDatabase(currentName.value, prevDB)
|
// browserStore.closeDatabase(props.server, prevDB)
|
||||||
browserStore.setKeyFilter(currentName.value, {})
|
// browserStore.setKeyFilter(props.server, {})
|
||||||
await browserStore.openDatabase(currentName.value, db)
|
// await browserStore.openDatabase(props.server, db)
|
||||||
// browserTreeRef.value?.resetExpandKey(currentName.value, db)
|
// // browserTreeRef.value?.resetExpandKey(props.server, db)
|
||||||
fullyLoaded.value = await browserStore.loadMoreKeys(currentName.value, db)
|
// fullyLoaded.value = await browserStore.loadMoreKeys(props.server, db)
|
||||||
browserTreeRef.value?.refreshTree()
|
// browserTreeRef.value?.refreshTree()
|
||||||
|
//
|
||||||
nextTick().then(() => connectionStore.saveLastDB(currentName.value, db))
|
// nextTick().then(() => connectionStore.saveLastDB(props.server, db))
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
$message.error(e.message)
|
// $message.error(e.message)
|
||||||
} finally {
|
// } finally {
|
||||||
loading.value = false
|
// loading.value = false
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
)
|
// )
|
||||||
|
|
||||||
onMounted(() => onReload())
|
onMounted(() => onReload())
|
||||||
// forbid dynamic switch key view due to performance issues
|
// forbid dynamic switch key view due to performance issues
|
||||||
|
@ -271,11 +292,11 @@ onMounted(() => onReload())
|
||||||
ref="browserTreeRef"
|
ref="browserTreeRef"
|
||||||
v-model:checked-count="checkedCount"
|
v-model:checked-count="checkedCount"
|
||||||
:check-mode="inCheckState"
|
:check-mode="inCheckState"
|
||||||
:db="browserStore.openedDB[currentName]"
|
:db="props.db"
|
||||||
:full-loaded="fullyLoaded"
|
:full-loaded="fullyLoaded"
|
||||||
:loading="loading && loadProgress <= 0"
|
:loading="loading && loadProgress <= 0"
|
||||||
:pattern="filterForm.filter"
|
:pattern="filterForm.filter"
|
||||||
:server="currentName" />
|
:server="props.server" />
|
||||||
<!-- bottom function bar -->
|
<!-- bottom function bar -->
|
||||||
<div class="nav-pane-bottom flex-box-v">
|
<div class="nav-pane-bottom flex-box-v">
|
||||||
<!-- <switch-button-->
|
<!-- <switch-button-->
|
||||||
|
@ -288,7 +309,7 @@ onMounted(() => onReload())
|
||||||
<transition mode="out-in" name="fade">
|
<transition mode="out-in" name="fade">
|
||||||
<div v-if="!inCheckState" class="flex-box-h nav-pane-func">
|
<div v-if="!inCheckState" class="flex-box-h nav-pane-func">
|
||||||
<n-select
|
<n-select
|
||||||
v-model:value="browserStore.openedDB[currentName]"
|
:value="props.db"
|
||||||
:consistent-menu-width="false"
|
:consistent-menu-width="false"
|
||||||
:filter="(pattern, option) => option.value.toString() === pattern"
|
:filter="(pattern, option) => option.value.toString() === pattern"
|
||||||
:options="dbSelectOptions"
|
:options="dbSelectOptions"
|
||||||
|
@ -372,16 +393,6 @@ onMounted(() => onReload())
|
||||||
border-color: #0000;
|
border-color: #0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-active,
|
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-enter-from,
|
|
||||||
.fade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-pane-top {
|
.nav-pane-top {
|
||||||
//@include bottom-shadow(0.1);
|
//@include bottom-shadow(0.1);
|
||||||
color: v-bind('themeVars.iconColor');
|
color: v-bind('themeVars.iconColor');
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { NIcon, NSpace, useThemeVars } from 'naive-ui'
|
||||||
import Key from '@/components/icons/Key.vue'
|
import Key from '@/components/icons/Key.vue'
|
||||||
import Binary from '@/components/icons/Binary.vue'
|
import Binary from '@/components/icons/Binary.vue'
|
||||||
import Database from '@/components/icons/Database.vue'
|
import Database from '@/components/icons/Database.vue'
|
||||||
import { filter, find, get, includes, indexOf, isEmpty, map, remove, size, startsWith } from 'lodash'
|
import { filter, find, get, includes, indexOf, isEmpty, map, remove, size, startsWith, toUpper } from 'lodash'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import Refresh from '@/components/icons/Refresh.vue'
|
import Refresh from '@/components/icons/Refresh.vue'
|
||||||
import CopyLink from '@/components/icons/CopyLink.vue'
|
import CopyLink from '@/components/icons/CopyLink.vue'
|
||||||
|
@ -23,6 +23,7 @@ import LoadList from '@/components/icons/LoadList.vue'
|
||||||
import LoadAll from '@/components/icons/LoadAll.vue'
|
import LoadAll from '@/components/icons/LoadAll.vue'
|
||||||
import useBrowserStore from 'stores/browser.js'
|
import useBrowserStore from 'stores/browser.js'
|
||||||
import { useRender } from '@/utils/render.js'
|
import { useRender } from '@/utils/render.js'
|
||||||
|
import RedisTypeTag from '@/components/common/RedisTypeTag.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
server: String,
|
server: String,
|
||||||
|
@ -364,6 +365,14 @@ const renderPrefix = ({ option }) => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
case ConnectionType.RedisValue:
|
case ConnectionType.RedisValue:
|
||||||
|
if (option.redisType == null || option.redisType === 'loading') {
|
||||||
|
browserStore.loadKeyType({
|
||||||
|
server: props.server,
|
||||||
|
db: option.db,
|
||||||
|
key: option.redisKey,
|
||||||
|
keyCode: option.redisKeyCode,
|
||||||
|
})
|
||||||
|
// in loading
|
||||||
return h(
|
return h(
|
||||||
NIcon,
|
NIcon,
|
||||||
{ size: 20 },
|
{ size: 20 },
|
||||||
|
@ -372,6 +381,13 @@ const renderPrefix = ({ option }) => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
return h(RedisTypeTag, {
|
||||||
|
type: toUpper(option.redisType),
|
||||||
|
short: true,
|
||||||
|
size: 'small',
|
||||||
|
inverse: includes(selectedKeys.value, option.key),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// render tree item label
|
// render tree item label
|
||||||
|
|
|
@ -11,6 +11,15 @@ export const types = {
|
||||||
STREAM: 'STREAM',
|
STREAM: 'STREAM',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const typesShortName = {
|
||||||
|
STRING: 'S',
|
||||||
|
HASH: 'H',
|
||||||
|
LIST: 'L',
|
||||||
|
SET: 'S',
|
||||||
|
ZSET: 'Z',
|
||||||
|
STREAM: 'X',
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mark color for redis types
|
* mark color for redis types
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import {
|
||||||
GetCmdHistory,
|
GetCmdHistory,
|
||||||
GetKeyDetail,
|
GetKeyDetail,
|
||||||
GetKeySummary,
|
GetKeySummary,
|
||||||
|
GetKeyType,
|
||||||
GetSlowLogs,
|
GetSlowLogs,
|
||||||
LoadAllKeys,
|
LoadAllKeys,
|
||||||
LoadNextKeys,
|
LoadNextKeys,
|
||||||
|
@ -72,6 +73,7 @@ const useBrowserStore = defineStore('browser', {
|
||||||
* @property {boolean} [opened] - redis db is opened, type == ConnectionType.RedisDB only
|
* @property {boolean} [opened] - redis db is opened, type == ConnectionType.RedisDB only
|
||||||
* @property {boolean} [expanded] - current node is expanded
|
* @property {boolean} [expanded] - current node is expanded
|
||||||
* @property {DatabaseItem[]} [children]
|
* @property {DatabaseItem[]} [children]
|
||||||
|
* @property {string} [redisType] - redis type name, 'loading' indicate that is in loading progress
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -339,6 +341,7 @@ const useBrowserStore = defineStore('browser', {
|
||||||
|
|
||||||
selDB.opened = true
|
selDB.opened = true
|
||||||
selDB.maxKeys = maxKeys
|
selDB.maxKeys = maxKeys
|
||||||
|
this.openedDB[server] = db
|
||||||
set(this.loadingState, 'fullLoaded', end)
|
set(this.loadingState, 'fullLoaded', end)
|
||||||
if (isEmpty(keys)) {
|
if (isEmpty(keys)) {
|
||||||
selDB.children = []
|
selDB.children = []
|
||||||
|
@ -465,6 +468,29 @@ const useBrowserStore = defineStore('browser', {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load key type
|
||||||
|
* @param {string} server
|
||||||
|
* @param {number} db
|
||||||
|
* @param {string} key
|
||||||
|
* @param {number[]} keyCode
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
async loadKeyType({ server, db, key, keyCode }) {
|
||||||
|
try {
|
||||||
|
const nodeMap = this._getNodeMap(server, db)
|
||||||
|
const node = nodeMap.get(`${ConnectionType.RedisValue}/${key}`)
|
||||||
|
if (node == null || node.redisType != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node.redisType = 'loading'
|
||||||
|
const { data } = await GetKeyType({ server, db, key: keyCode || key })
|
||||||
|
const { type } = data || {}
|
||||||
|
node.redisType = type
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reload key
|
* reload key
|
||||||
* @param {string} server
|
* @param {string} server
|
||||||
|
@ -752,6 +778,7 @@ const useBrowserStore = defineStore('browser', {
|
||||||
keys: 0,
|
keys: 0,
|
||||||
redisKey: k,
|
redisKey: k,
|
||||||
redisKeyCode: isBinaryKey ? key : undefined,
|
redisKeyCode: isBinaryKey ? key : undefined,
|
||||||
|
redisKeyType: undefined,
|
||||||
type: ConnectionType.RedisValue,
|
type: ConnectionType.RedisValue,
|
||||||
isLeaf: true,
|
isLeaf: true,
|
||||||
}
|
}
|
||||||
|
@ -818,6 +845,7 @@ const useBrowserStore = defineStore('browser', {
|
||||||
keys: 0,
|
keys: 0,
|
||||||
redisKey: handlePath,
|
redisKey: handlePath,
|
||||||
redisKeyCode: isBinaryKey ? key : undefined,
|
redisKeyCode: isBinaryKey ? key : undefined,
|
||||||
|
redisKeyType: undefined,
|
||||||
type: ConnectionType.RedisValue,
|
type: ConnectionType.RedisValue,
|
||||||
isLeaf: true,
|
isLeaf: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,10 @@ const useTabStore = defineStore('tab', {
|
||||||
// return current
|
// return current
|
||||||
},
|
},
|
||||||
|
|
||||||
|
currentTabName() {
|
||||||
|
return get(this.tabs, [this.activatedIndex, 'name'])
|
||||||
|
},
|
||||||
|
|
||||||
currentSelectedKeys() {
|
currentSelectedKeys() {
|
||||||
const tab = this.currentTab()
|
const tab = this.currentTab()
|
||||||
return get(tab, 'selectedKeys', [])
|
return get(tab, 'selectedKeys', [])
|
||||||
|
|
|
@ -157,3 +157,14 @@ body {
|
||||||
.n-tabs .n-tabs-nav {
|
.n-tabs .n-tabs-nav {
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// animations
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue