feat: adjusted the content pane to accommodate more information (add sub content tabs).
This commit is contained in:
parent
6f5ea748f5
commit
5b4683a735
|
@ -1,16 +1,19 @@
|
|||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, reactive, watch } from 'vue'
|
||||
import { types } from '@/consts/support_redis_type.js'
|
||||
import ContentValueHash from '@/components/content_value/ContentValueHash.vue'
|
||||
import ContentValueList from '@/components/content_value/ContentValueList.vue'
|
||||
import ContentValueString from '@/components/content_value/ContentValueString.vue'
|
||||
import ContentValueSet from '@/components/content_value/ContentValueSet.vue'
|
||||
import ContentValueZset from '@/components/content_value/ContentValueZSet.vue'
|
||||
import { get, isEmpty, keyBy, map, size, toUpper } from 'lodash'
|
||||
import useTabStore from 'stores/tab.js'
|
||||
import useConnectionStore from 'stores/connections.js'
|
||||
import ContentServerStatus from '@/components/content_value/ContentServerStatus.vue'
|
||||
import ContentValueStream from '@/components/content_value/ContentValueStream.vue'
|
||||
import Status from '@/components/icons/Status.vue'
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
import { BrowserTabType } from '@/consts/browser_tab_type.js'
|
||||
import Terminal from '@/components/icons/Terminal.vue'
|
||||
import Log from '@/components/icons/Log.vue'
|
||||
import Detail from '@/components/icons/Detail.vue'
|
||||
import ContentValueWrapper from '@/components/content_value/ContentValueWrapper.vue'
|
||||
import ContentCli from '@/components/content_value/ContentCli.vue'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
/**
|
||||
* @typedef {Object} ServerStatusItem
|
||||
|
@ -112,15 +115,6 @@ onUnmounted(() => {
|
|||
clearInterval(intervalId)
|
||||
})
|
||||
|
||||
const valueComponents = {
|
||||
[types.STRING]: ContentValueString,
|
||||
[types.HASH]: ContentValueHash,
|
||||
[types.LIST]: ContentValueList,
|
||||
[types.SET]: ContentValueSet,
|
||||
[types.ZSET]: ContentValueZset,
|
||||
[types.STREAM]: ContentValueStream,
|
||||
}
|
||||
|
||||
const connectionStore = useConnectionStore()
|
||||
const tabStore = useTabStore()
|
||||
const tab = computed(() =>
|
||||
|
@ -162,6 +156,7 @@ const tabContent = computed(() => {
|
|||
}
|
||||
return {
|
||||
name: tab.name,
|
||||
subTab: tab.subTab,
|
||||
type: toUpper(tab.type),
|
||||
db: tab.db,
|
||||
keyPath: tab.key,
|
||||
|
@ -177,7 +172,7 @@ const showServerStatus = computed(() => {
|
|||
return tabContent.value == null || isEmpty(tabContent.value.keyPath)
|
||||
})
|
||||
|
||||
const showNonexists = computed(() => {
|
||||
const isBlankValue = computed(() => {
|
||||
return tabContent.value.value == null
|
||||
})
|
||||
|
||||
|
@ -192,38 +187,104 @@ const onReloadKey = async () => {
|
|||
}
|
||||
await connectionStore.loadKeyValue(tab.name, tab.db, tab.key, tab.viewAs)
|
||||
}
|
||||
|
||||
const selectedSubTab = computed(() => {
|
||||
const { subTab = 'status' } = tabStore.currentTab || {}
|
||||
return subTab
|
||||
})
|
||||
|
||||
const onSwitchSubTab = (name) => {
|
||||
tabStore.switchSubTab(name)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="content-container flex-box-v">
|
||||
<div v-if="showServerStatus" class="content-container flex-item-expand flex-box-v">
|
||||
<!-- select nothing or select server node, display server status -->
|
||||
<content-server-status
|
||||
v-model:auto-refresh="currentServer.autoRefresh"
|
||||
:auto-loading="currentServer.autoLoading"
|
||||
:info="currentServer.info"
|
||||
:loading="currentServer.loading"
|
||||
:server="currentServer.name"
|
||||
@refresh="refreshInfo(currentServer.name, true)" />
|
||||
</div>
|
||||
<div v-else-if="showNonexists" class="content-container flex-item-expand flex-box-v">
|
||||
<n-empty :description="$t('interface.nonexist_tab_content')" class="empty-content">
|
||||
<template #extra>
|
||||
<n-button :focusable="false" @click="onReloadKey">{{ $t('interface.reload') }}</n-button>
|
||||
<n-tabs
|
||||
:tabs-padding="5"
|
||||
:theme-overrides="{
|
||||
tabGapSmallLine: '10px',
|
||||
tabGapMediumLine: '10px',
|
||||
tabGapLargeLine: '10px',
|
||||
}"
|
||||
:value="selectedSubTab"
|
||||
class="content-sub-tab"
|
||||
default-value="status"
|
||||
pane-class="content-sub-tab-pane"
|
||||
placement="top"
|
||||
tab-style="padding-left: 10px; padding-right: 10px;"
|
||||
type="line"
|
||||
@update:value="onSwitchSubTab">
|
||||
<!-- server status pane -->
|
||||
<n-tab-pane :name="BrowserTabType.Status.toString()">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
<status :inverse="selectedSubTab === BrowserTabType.Status.toString()" stroke-width="4" />
|
||||
</n-icon>
|
||||
<span>{{ $t('interface.sub_tab.status') }}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-empty>
|
||||
</div>
|
||||
<component
|
||||
:is="valueComponents[tabContent.type]"
|
||||
v-else
|
||||
:db="tabContent.db"
|
||||
:key-code="tabContent.keyCode"
|
||||
:key-path="tabContent.keyPath"
|
||||
:name="tabContent.name"
|
||||
:size="tabContent.size"
|
||||
:ttl="tabContent.ttl"
|
||||
:value="tabContent.value"
|
||||
:view-as="tabContent.viewAs" />
|
||||
<content-server-status
|
||||
v-model:auto-refresh="currentServer.autoRefresh"
|
||||
:auto-loading="currentServer.autoLoading"
|
||||
:info="currentServer.info"
|
||||
:loading="currentServer.loading"
|
||||
:server="currentServer.name"
|
||||
@refresh="refreshInfo(currentServer.name, true)" />
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- key detail pane -->
|
||||
<n-tab-pane :name="BrowserTabType.KeyDetail.toString()">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
<detail
|
||||
:inverse="selectedSubTab === BrowserTabType.KeyDetail.toString()"
|
||||
fill-color="none" />
|
||||
</n-icon>
|
||||
<span>{{ $t('interface.sub_tab.key_detail') }}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
<content-value-wrapper
|
||||
:blank="isBlankValue"
|
||||
:type="tabContent.type"
|
||||
:db="tabContent.db"
|
||||
:key-code="tabContent.keyCode"
|
||||
:key-path="tabContent.keyPath"
|
||||
:name="tabContent.name"
|
||||
:size="tabContent.size"
|
||||
:ttl="tabContent.ttl"
|
||||
:value="tabContent.value"
|
||||
:view-as="tabContent.viewAs"
|
||||
@reload="onReloadKey" />
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- cli pane -->
|
||||
<n-tab-pane :name="BrowserTabType.Cli.toString()">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
<terminal :inverse="selectedSubTab === BrowserTabType.Cli.toString()" />
|
||||
</n-icon>
|
||||
<span>{{ $t('interface.sub_tab.cli') }}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
<content-cli />
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- slow log pane -->
|
||||
<n-tab-pane :name="BrowserTabType.SlowLog.toString()">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
<log :inverse="selectedSubTab === BrowserTabType.SlowLog.toString()" />
|
||||
</n-icon>
|
||||
<span>{{ $t('interface.sub_tab.slow_log') }}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -231,27 +292,24 @@ const onReloadKey = async () => {
|
|||
@import '@/styles/content';
|
||||
|
||||
.content-container {
|
||||
padding: 5px;
|
||||
//padding: 5px 5px 0;
|
||||
//padding-top: 0;
|
||||
box-sizing: border-box;
|
||||
background-color: v-bind('themeVars.tabColor');
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.content-sub-tab {
|
||||
margin-bottom: 5px;
|
||||
background-color: v-bind('themeVars.bodyColor');
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
//.tab-item {
|
||||
// gap: 5px;
|
||||
// padding: 0 5px 0 10px;
|
||||
// align-items: center;
|
||||
// max-width: 150px;
|
||||
//
|
||||
// transition: all var(--transition-duration-fast) var(--transition-function-ease-in-out-bezier);
|
||||
//
|
||||
// &-label {
|
||||
// font-size: 15px;
|
||||
// text-align: center;
|
||||
// }
|
||||
//
|
||||
// &-close {
|
||||
// &:hover {
|
||||
// background-color: rgb(176, 177, 182, 0.4);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
.content-sub-tab-pane {
|
||||
padding: 0 !important;
|
||||
height: 100%;
|
||||
background-color: v-bind('themeVars.tabColor');
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -83,7 +83,7 @@ const tab = computed(() =>
|
|||
@dblclick.stop="() => {}">
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="18">
|
||||
<server stroke-width="4" :inverse="tabStore.activatedIndex === i" />
|
||||
<server stroke-width="4" />
|
||||
</n-icon>
|
||||
<n-ellipsis style="max-width: 150px">{{ t.label }}</n-ellipsis>
|
||||
</n-space>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<n-empty description="coming soon" class="empty-content"></n-empty>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -75,7 +75,7 @@ const infoFilter = ref('')
|
|||
<template>
|
||||
<n-scrollbar ref="scrollRef">
|
||||
<n-back-top :listen-to="scrollRef" />
|
||||
<n-space vertical>
|
||||
<n-space vertical :wrap-item="false" :size="5" style="padding: 5px">
|
||||
<n-card>
|
||||
<template #header>
|
||||
<n-space :wrap-item="false" align="center" inline size="small">
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<script setup>
|
||||
import { types } from '@/consts/value_view_type.js'
|
||||
import { types as redisTypes } from '@/consts/support_redis_type.js'
|
||||
import ContentValueString from '@/components/content_value/ContentValueString.vue'
|
||||
import ContentValueHash from '@/components/content_value/ContentValueHash.vue'
|
||||
import ContentValueList from '@/components/content_value/ContentValueList.vue'
|
||||
import ContentValueSet from '@/components/content_value/ContentValueSet.vue'
|
||||
import ContentValueZset from '@/components/content_value/ContentValueZSet.vue'
|
||||
import ContentValueStream from '@/components/content_value/ContentValueStream.vue'
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
const props = defineProps({
|
||||
blank: Boolean,
|
||||
type: String,
|
||||
name: String,
|
||||
db: Number,
|
||||
keyPath: String,
|
||||
keyCode: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
ttl: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
value: [String, Object],
|
||||
size: Number,
|
||||
viewAs: {
|
||||
type: String,
|
||||
default: types.PLAIN_TEXT,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['reload'])
|
||||
|
||||
const valueComponents = {
|
||||
[redisTypes.STRING]: ContentValueString,
|
||||
[redisTypes.HASH]: ContentValueHash,
|
||||
[redisTypes.LIST]: ContentValueList,
|
||||
[redisTypes.SET]: ContentValueSet,
|
||||
[redisTypes.ZSET]: ContentValueZset,
|
||||
[redisTypes.STREAM]: ContentValueStream,
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-empty v-if="props.blank" :description="$t('interface.nonexist_tab_content')" class="empty-content">
|
||||
<template #extra>
|
||||
<n-button :focusable="false" @click="emit('reload')">{{ $t('interface.reload') }}</n-button>
|
||||
</template>
|
||||
</n-empty>
|
||||
<component
|
||||
class="content-value-wrapper"
|
||||
:is="valueComponents[props.type]"
|
||||
v-else
|
||||
:db="props.db"
|
||||
:key-code="props.keyCode"
|
||||
:key-path="props.keyPath"
|
||||
:name="props.name"
|
||||
:size="props.size"
|
||||
:ttl="props.ttl"
|
||||
:value="props.value"
|
||||
:view-as="props.viewAs" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-value-wrapper {
|
||||
background-color: v-bind('themeVars.bodyColor');
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,109 @@
|
|||
<script setup>
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const props = defineProps({
|
||||
inverse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
strokeWidth: {
|
||||
type: [Number, String],
|
||||
default: 3,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-if="props.inverse" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="6"
|
||||
y="6"
|
||||
width="36"
|
||||
height="36"
|
||||
rx="3"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<rect
|
||||
x="13"
|
||||
y="13"
|
||||
width="8"
|
||||
height="8"
|
||||
fill="#FFF"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M27 13L35 13"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M27 20L35 20"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M13 28L35 28"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M13 35H35"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
<svg v-else viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="6"
|
||||
y="6"
|
||||
width="36"
|
||||
height="36"
|
||||
rx="3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<rect
|
||||
x="13"
|
||||
y="13"
|
||||
width="8"
|
||||
height="8"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M27 13L35 13"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M27 20L35 20"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M13 28L35 28"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M13 35H35"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,67 @@
|
|||
<script setup>
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const props = defineProps({
|
||||
inverse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
strokeWidth: {
|
||||
type: [Number, String],
|
||||
default: 3,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-if="props.inverse" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="4"
|
||||
y="8"
|
||||
width="40"
|
||||
height="32"
|
||||
rx="2"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M12 18L19 24L12 30"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M23 32H36"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
<svg v-else viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="4"
|
||||
y="8"
|
||||
width="40"
|
||||
height="32"
|
||||
rx="2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M12 18L19 24L12 30"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M23 32H36"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* all types of Browser sub tabs
|
||||
* @enum {string}
|
||||
*/
|
||||
export const BrowserTabType = {
|
||||
Status: 'status',
|
||||
KeyDetail: 'key_detail',
|
||||
Cli: 'cli',
|
||||
SlowLog: 'slow_log',
|
||||
}
|
|
@ -87,13 +87,19 @@
|
|||
"load_more": "Load More Keys",
|
||||
"load_all": "Load All Left Keys",
|
||||
"more_action": "More Action",
|
||||
"nonexist_tab_content": "Selected key does not exist. Please retry",
|
||||
"nonexist_tab_content": "Selected key does not exist or no key is selected. Please retry",
|
||||
"empty_server_content": "Select and open a connection from the left",
|
||||
"empty_server_list": "No redis server",
|
||||
"action": "Action",
|
||||
"type": "Type",
|
||||
"score": "Score",
|
||||
"total": "Length: {size}"
|
||||
"total": "Length: {size}",
|
||||
"sub_tab": {
|
||||
"status": "Status",
|
||||
"key_detail": "Key Detail",
|
||||
"cli": "Command Line",
|
||||
"slow_log": "Slow Log"
|
||||
}
|
||||
},
|
||||
"ribbon": {
|
||||
"server": "Server",
|
||||
|
|
|
@ -87,13 +87,19 @@
|
|||
"load_more": "加载更多键",
|
||||
"load_all": "加载剩余所有键",
|
||||
"more_action": "更多操作",
|
||||
"nonexist_tab_content": "所选键不存在,请尝试刷新重试",
|
||||
"nonexist_tab_content": "所选键不存在或未选中任何键,请尝试刷新重试",
|
||||
"empty_server_content": "可以从左边选择并打开连接",
|
||||
"empty_server_list": "还没添加Redis服务器",
|
||||
"action": "操作",
|
||||
"type": "类型",
|
||||
"score": "分值",
|
||||
"total": "总数:{size}"
|
||||
"total": "总数:{size}",
|
||||
"sub_tab": {
|
||||
"status": "状态",
|
||||
"key_detail": "键详情",
|
||||
"cli": "命令行",
|
||||
"slow_log": "慢日志"
|
||||
}
|
||||
},
|
||||
"ribbon": {
|
||||
"server": "服务器",
|
||||
|
|
|
@ -52,7 +52,7 @@ import useTabStore from './tab.js'
|
|||
import { types } from '@/consts/support_redis_type.js'
|
||||
import { decodeRedisKey, nativeRedisKey } from '@/utils/key_convert.js'
|
||||
import { KeyViewType } from '@/consts/key_view_type.js'
|
||||
import { nextTick } from 'vue'
|
||||
import { BrowserTabType } from '@/consts/browser_tab_type.js'
|
||||
|
||||
const useConnectionStore = defineStore('connections', {
|
||||
/**
|
||||
|
@ -668,6 +668,7 @@ const useConnectionStore = defineStore('connections', {
|
|||
const k = decodeRedisKey(key)
|
||||
const binaryKey = k !== key
|
||||
tab.upsertTab({
|
||||
subTab: BrowserTabType.KeyDetail,
|
||||
server,
|
||||
db,
|
||||
type,
|
||||
|
@ -690,6 +691,7 @@ const useConnectionStore = defineStore('connections', {
|
|||
}
|
||||
|
||||
tab.upsertTab({
|
||||
subTab: BrowserTabType.Status,
|
||||
server,
|
||||
db,
|
||||
type: 'none',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { find, findIndex, get, size } from 'lodash'
|
||||
import { find, findIndex, get, isEmpty, set, size } from 'lodash'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
const useTabStore = defineStore('tab', {
|
||||
|
@ -6,6 +6,7 @@ const useTabStore = defineStore('tab', {
|
|||
* @typedef {Object} TabItem
|
||||
* @property {string} name connection name
|
||||
* @property {boolean} blank is blank tab
|
||||
* @property {string} subTab secondary tab value
|
||||
* @property {string} [title] tab title
|
||||
* @property {string} [icon] tab icon
|
||||
* @property {string[]} selectedKeys
|
||||
|
@ -64,12 +65,16 @@ const useTabStore = defineStore('tab', {
|
|||
*
|
||||
* @param idx
|
||||
* @param {boolean} [switchNav]
|
||||
* @param {string} [subTab]
|
||||
* @private
|
||||
*/
|
||||
_setActivatedIndex(idx, switchNav) {
|
||||
_setActivatedIndex(idx, switchNav, subTab) {
|
||||
this.activatedIndex = idx
|
||||
if (switchNav === true) {
|
||||
this.nav = idx >= 0 ? 'browser' : 'server'
|
||||
if (!isEmpty(subTab)) {
|
||||
set(this.tabList, [idx, 'subTab'], subTab)
|
||||
}
|
||||
} else {
|
||||
if (idx < 0) {
|
||||
this.nav = 'server'
|
||||
|
@ -79,6 +84,7 @@ const useTabStore = defineStore('tab', {
|
|||
|
||||
/**
|
||||
* update or insert a new tab if not exists with the same name
|
||||
* @param {string} subTab
|
||||
* @param {string} server
|
||||
* @param {number} [db]
|
||||
* @param {number} [type]
|
||||
|
@ -89,11 +95,13 @@ const useTabStore = defineStore('tab', {
|
|||
* @param {*} [value]
|
||||
* @param {string} [viewAs]
|
||||
*/
|
||||
upsertTab({ server, db, type, ttl, key, keyCode, size, value, viewAs }) {
|
||||
upsertTab({ subTab, server, db, type, ttl, key, keyCode, size, value, viewAs }) {
|
||||
let tabIndex = findIndex(this.tabList, { name: server })
|
||||
if (tabIndex === -1) {
|
||||
this.tabList.push({
|
||||
name: server,
|
||||
title: server,
|
||||
subTab,
|
||||
server,
|
||||
db,
|
||||
type,
|
||||
|
@ -105,21 +113,23 @@ const useTabStore = defineStore('tab', {
|
|||
viewAs,
|
||||
})
|
||||
tabIndex = this.tabList.length - 1
|
||||
} else {
|
||||
const tab = this.tabList[tabIndex]
|
||||
tab.blank = false
|
||||
tab.subTab = subTab
|
||||
// tab.title = db !== undefined ? `${server}/db${db}` : `${server}`
|
||||
tab.title = server
|
||||
tab.server = server
|
||||
tab.db = db
|
||||
tab.type = type
|
||||
tab.ttl = ttl
|
||||
tab.key = key
|
||||
tab.keyCode = keyCode
|
||||
tab.size = size
|
||||
tab.value = value
|
||||
tab.viewAs = viewAs
|
||||
}
|
||||
const tab = this.tabList[tabIndex]
|
||||
tab.blank = false
|
||||
// tab.title = db !== undefined ? `${server}/db${db}` : `${server}`
|
||||
tab.title = server
|
||||
tab.server = server
|
||||
tab.db = db
|
||||
tab.type = type
|
||||
tab.ttl = ttl
|
||||
tab.key = key
|
||||
tab.keyCode = keyCode
|
||||
tab.size = size
|
||||
tab.value = value
|
||||
tab.viewAs = viewAs
|
||||
this._setActivatedIndex(tabIndex, true)
|
||||
this._setActivatedIndex(tabIndex, true, subTab)
|
||||
// this.activatedTab = tab.name
|
||||
},
|
||||
|
||||
|
@ -162,6 +172,14 @@ const useTabStore = defineStore('tab', {
|
|||
// this.activatedIndex = tabIndex
|
||||
},
|
||||
|
||||
switchSubTab(name) {
|
||||
const tab = this.currentTab
|
||||
if (tab == null) {
|
||||
return
|
||||
}
|
||||
tab.subTab = name
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} tabIndex
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
.content-container {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ body {
|
|||
}
|
||||
|
||||
.content-wrapper {
|
||||
//height: 100%;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
gap: 5px;
|
||||
|
@ -95,6 +95,7 @@ body {
|
|||
.value-wrapper {
|
||||
//border-top: v-bind('themeVars.borderColor') 1px solid;
|
||||
user-select: text;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue