Compare commits
2 Commits
bb1d9f316b
...
1a49db2450
Author | SHA1 | Date |
---|---|---|
tiny-craft | 1a49db2450 | |
tiny-craft | efc09a8745 |
|
@ -302,10 +302,6 @@ func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch selConn.DBFilterType {
|
switch selConn.DBFilterType {
|
||||||
case "none":
|
|
||||||
for idx := 0; idx < totaldb; idx++ {
|
|
||||||
dbs = append(dbs, queryDB(idx))
|
|
||||||
}
|
|
||||||
case "show":
|
case "show":
|
||||||
for _, idx := range selConn.DBFilterList {
|
for _, idx := range selConn.DBFilterList {
|
||||||
dbs = append(dbs, queryDB(idx))
|
dbs = append(dbs, queryDB(idx))
|
||||||
|
@ -316,6 +312,10 @@ func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
||||||
dbs = append(dbs, queryDB(idx))
|
dbs = append(dbs, queryDB(idx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
for idx := 0; idx < totaldb; idx++ {
|
||||||
|
dbs = append(dbs, queryDB(idx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
|
|
|
@ -1,55 +1,109 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { computed, onMounted, onUnmounted, reactive, watch } from 'vue'
|
||||||
import { types } from '@/consts/support_redis_type.js'
|
import { types } from '@/consts/support_redis_type.js'
|
||||||
import ContentValueHash from '@/components/content_value/ContentValueHash.vue'
|
import ContentValueHash from '@/components/content_value/ContentValueHash.vue'
|
||||||
import ContentValueList from '@/components/content_value/ContentValueList.vue'
|
import ContentValueList from '@/components/content_value/ContentValueList.vue'
|
||||||
import ContentValueString from '@/components/content_value/ContentValueString.vue'
|
import ContentValueString from '@/components/content_value/ContentValueString.vue'
|
||||||
import ContentValueSet from '@/components/content_value/ContentValueSet.vue'
|
import ContentValueSet from '@/components/content_value/ContentValueSet.vue'
|
||||||
import ContentValueZset from '@/components/content_value/ContentValueZSet.vue'
|
import ContentValueZset from '@/components/content_value/ContentValueZSet.vue'
|
||||||
import { isEmpty, map, toUpper } from 'lodash'
|
import { get, isEmpty, keyBy, map, size, toUpper } from 'lodash'
|
||||||
import useTabStore from 'stores/tab.js'
|
import useTabStore from 'stores/tab.js'
|
||||||
import useConnectionStore from 'stores/connections.js'
|
import useConnectionStore from 'stores/connections.js'
|
||||||
import ContentServerStatus from '@/components/content_value/ContentServerStatus.vue'
|
import ContentServerStatus from '@/components/content_value/ContentServerStatus.vue'
|
||||||
import ContentValueStream from '@/components/content_value/ContentValueStream.vue'
|
import ContentValueStream from '@/components/content_value/ContentValueStream.vue'
|
||||||
|
|
||||||
const serverInfo = ref({})
|
/**
|
||||||
const autoRefresh = ref(false)
|
* @typedef {Object} ServerStatusItem
|
||||||
|
* @property {string} name
|
||||||
|
* @property {Object} info
|
||||||
|
* @property {boolean} autoRefresh
|
||||||
|
* @property {boolean} loading loading status for refresh
|
||||||
|
* @property {boolean} autoLoading loading status for auto refresh
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {UnwrapNestedRefs<Object.<string, ServerStatusItem>>}
|
||||||
|
*/
|
||||||
|
const serverStatusTab = reactive({})
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} serverName
|
||||||
|
* @return {UnwrapRef<ServerStatusItem>}
|
||||||
|
*/
|
||||||
|
const getServerInfo = (serverName) => {
|
||||||
|
if (isEmpty(serverName)) {
|
||||||
|
return {
|
||||||
|
name: serverName,
|
||||||
|
info: {},
|
||||||
|
autoRefresh: false,
|
||||||
|
autoLoading: false,
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!serverStatusTab.hasOwnProperty(serverName)) {
|
||||||
|
serverStatusTab[serverName] = {
|
||||||
|
name: serverName,
|
||||||
|
info: {},
|
||||||
|
autoRefresh: false,
|
||||||
|
autoLoading: false,
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serverStatusTab[serverName]
|
||||||
|
}
|
||||||
const serverName = computed(() => {
|
const serverName = computed(() => {
|
||||||
if (tabContent.value != null) {
|
if (tabContent.value != null) {
|
||||||
return tabContent.value.name
|
return tabContent.value.name
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
const loadingServerInfo = ref(false)
|
/**
|
||||||
const autoLoadingServerInfo = ref(false)
|
*
|
||||||
|
* @type {ComputedRef<ServerStatusItem>}
|
||||||
|
*/
|
||||||
|
const currentServer = computed(() => {
|
||||||
|
return getServerInfo(serverName.value)
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* refresh server status info
|
* refresh server status info
|
||||||
|
* @param {string} serverName
|
||||||
* @param {boolean} [force] force refresh will show loading indicator
|
* @param {boolean} [force] force refresh will show loading indicator
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
const refreshInfo = async (force) => {
|
const refreshInfo = async (serverName, force) => {
|
||||||
|
const info = getServerInfo(serverName)
|
||||||
if (force) {
|
if (force) {
|
||||||
loadingServerInfo.value = true
|
info.loading = true
|
||||||
} else {
|
} else {
|
||||||
autoLoadingServerInfo.value = true
|
info.autoLoading = true
|
||||||
}
|
}
|
||||||
if (!isEmpty(serverName.value) && connectionStore.isConnected(serverName.value)) {
|
if (!isEmpty(serverName) && connectionStore.isConnected(serverName)) {
|
||||||
try {
|
try {
|
||||||
serverInfo.value = await connectionStore.getServerInfo(serverName.value)
|
info.info = await connectionStore.getServerInfo(serverName)
|
||||||
} finally {
|
} finally {
|
||||||
loadingServerInfo.value = false
|
info.loading = false
|
||||||
autoLoadingServerInfo.value = false
|
info.autoLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refreshAllInfo = async (force) => {
|
||||||
|
for (const serverName in serverStatusTab) {
|
||||||
|
await refreshInfo(serverName, force)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let intervalId
|
let intervalId
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
refreshInfo(true)
|
refreshAllInfo(true)
|
||||||
intervalId = setInterval(() => {
|
intervalId = setInterval(() => {
|
||||||
if (autoRefresh.value) {
|
for (const serverName in serverStatusTab) {
|
||||||
refreshInfo()
|
if (get(serverStatusTab, [serverName, 'autoRefresh'])) {
|
||||||
|
refreshInfo(serverName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 5000)
|
}, 5000)
|
||||||
})
|
})
|
||||||
|
@ -80,11 +134,27 @@ watch(
|
||||||
() => tabStore.nav,
|
() => tabStore.nav,
|
||||||
(nav) => {
|
(nav) => {
|
||||||
if (nav === 'browser') {
|
if (nav === 'browser') {
|
||||||
refreshInfo()
|
refreshInfo(serverName.value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => tabStore.tabList,
|
||||||
|
(tabs) => {
|
||||||
|
if (size(tabs) < size(serverStatusTab)) {
|
||||||
|
const tabMap = keyBy(tabs, 'name')
|
||||||
|
// remove unused server status tab
|
||||||
|
for (const t in serverStatusTab) {
|
||||||
|
if (!tabMap.hasOwnProperty(t)) {
|
||||||
|
delete serverStatusTab[t]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
const tabContent = computed(() => {
|
const tabContent = computed(() => {
|
||||||
const tab = tabStore.currentTab
|
const tab = tabStore.currentTab
|
||||||
if (tab == null) {
|
if (tab == null) {
|
||||||
|
@ -110,10 +180,6 @@ const showNonexists = computed(() => {
|
||||||
return tabContent.value.value == null
|
return tabContent.value.value == null
|
||||||
})
|
})
|
||||||
|
|
||||||
const onUpdateValue = (tabIndex) => {
|
|
||||||
tabStore.switchTab(tabIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reload current selection key
|
* reload current selection key
|
||||||
* @returns {Promise<null>}
|
* @returns {Promise<null>}
|
||||||
|
@ -132,12 +198,12 @@ const onReloadKey = async () => {
|
||||||
<div v-if="showServerStatus" class="content-container flex-item-expand 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 -->
|
<!-- select nothing or select server node, display server status -->
|
||||||
<content-server-status
|
<content-server-status
|
||||||
v-model:auto-refresh="autoRefresh"
|
v-model:auto-refresh="currentServer.autoRefresh"
|
||||||
:info="serverInfo"
|
:info="currentServer.info"
|
||||||
:loading="loadingServerInfo"
|
:loading="currentServer.loading"
|
||||||
:auto-loading="autoLoadingServerInfo"
|
:auto-loading="currentServer.autoLoading"
|
||||||
:server="serverName"
|
:server="currentServer.name"
|
||||||
@refresh="refreshInfo(true)" />
|
@refresh="refreshInfo(currentServer.name, true)" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="showNonexists" class="content-container flex-item-expand flex-box-v">
|
<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">
|
<n-empty :description="$t('interface.nonexist_tab_content')" class="empty-content">
|
||||||
|
|
|
@ -261,7 +261,7 @@ const onClose = () => {
|
||||||
path="keySeparator">
|
path="keySeparator">
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="generalForm.keySeparator"
|
v-model:value="generalForm.keySeparator"
|
||||||
:placeholder="$t('dialogue.connection.advn_separator_tip')" />
|
:placeholder="$t('dialogue.connection.advn.separator_tip')" />
|
||||||
</n-form-item-gi>
|
</n-form-item-gi>
|
||||||
<n-form-item-gi
|
<n-form-item-gi
|
||||||
:span="12"
|
:span="12"
|
||||||
|
|
|
@ -21,7 +21,7 @@ import usePreferencesStore from 'stores/preferences.js'
|
||||||
|
|
||||||
const themeVars = useThemeVars()
|
const themeVars = useThemeVars()
|
||||||
const i18n = useI18n()
|
const i18n = useI18n()
|
||||||
const openingConnection = ref(false)
|
const connectingServer = ref('')
|
||||||
const connectionStore = useConnectionStore()
|
const connectionStore = useConnectionStore()
|
||||||
const tabStore = useTabStore()
|
const tabStore = useTabStore()
|
||||||
const prefStore = usePreferencesStore()
|
const prefStore = usePreferencesStore()
|
||||||
|
@ -287,18 +287,21 @@ const onUpdateSelectedKeys = (keys, option) => {
|
||||||
*/
|
*/
|
||||||
const openConnection = async (name) => {
|
const openConnection = async (name) => {
|
||||||
try {
|
try {
|
||||||
|
connectingServer.value = name
|
||||||
if (!connectionStore.isConnected(name)) {
|
if (!connectionStore.isConnected(name)) {
|
||||||
openingConnection.value = true
|
|
||||||
await connectionStore.openConnection(name)
|
await connectionStore.openConnection(name)
|
||||||
}
|
}
|
||||||
tabStore.upsertTab({
|
// check if connection already canceled before finish open
|
||||||
server: name,
|
if (!isEmpty(connectingServer.value)) {
|
||||||
})
|
tabStore.upsertTab({
|
||||||
|
server: name,
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$message.error(e.message)
|
$message.error(e.message)
|
||||||
// node.isLeaf = undefined
|
// node.isLeaf = undefined
|
||||||
} finally {
|
} finally {
|
||||||
openingConnection.value = false
|
connectingServer.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,6 +470,13 @@ const handleDrop = ({ node, dragNode, dropPosition }) => {
|
||||||
connectionStore.connections = Array.from(connectionStore.connections)
|
connectionStore.connections = Array.from(connectionStore.connections)
|
||||||
saveSort()
|
saveSort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onCancelOpen = () => {
|
||||||
|
if (!isEmpty(connectingServer.value)) {
|
||||||
|
connectionStore.closeConnection(connectingServer.value)
|
||||||
|
connectingServer.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -496,7 +506,7 @@ const handleDrop = ({ node, dragNode, dropPosition }) => {
|
||||||
@update:expanded-keys="onUpdateExpandedKeys" />
|
@update:expanded-keys="onUpdateExpandedKeys" />
|
||||||
|
|
||||||
<!-- status display modal -->
|
<!-- status display modal -->
|
||||||
<n-modal :show="openingConnection" transform-origin="center">
|
<n-modal :show="connectingServer !== ''" transform-origin="center">
|
||||||
<n-card
|
<n-card
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:content-style="{ textAlign: 'center' }"
|
:content-style="{ textAlign: 'center' }"
|
||||||
|
@ -505,7 +515,12 @@ const handleDrop = ({ node, dragNode, dropPosition }) => {
|
||||||
style="width: 400px">
|
style="width: 400px">
|
||||||
<n-spin>
|
<n-spin>
|
||||||
<template #description>
|
<template #description>
|
||||||
{{ $t('dialogue.opening_connection') }}
|
<n-space vertical>
|
||||||
|
<n-text strong>{{ $t('dialogue.opening_connection') }}</n-text>
|
||||||
|
<n-button secondary size="small" :focusable="false" @click="onCancelOpen">
|
||||||
|
{{ $t('dialogue.interrupt_connection') }}
|
||||||
|
</n-button>
|
||||||
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
</n-spin>
|
</n-spin>
|
||||||
</n-card>
|
</n-card>
|
||||||
|
|
|
@ -99,6 +99,7 @@
|
||||||
"close_confirm": "Confirm close this tab and connection",
|
"close_confirm": "Confirm close this tab and connection",
|
||||||
"edit_close_confirm": "Please close the relevant connections before editing. Do you want to continue?",
|
"edit_close_confirm": "Please close the relevant connections before editing. Do you want to continue?",
|
||||||
"opening_connection": "Opening Connection...",
|
"opening_connection": "Opening Connection...",
|
||||||
|
"interrupt_connection": "Cancel",
|
||||||
"remove_tip": "{type} \"{name}\" will be deleted",
|
"remove_tip": "{type} \"{name}\" will be deleted",
|
||||||
"remove_group_tip": "Group \"{name}\" and all connections in it will be deleted",
|
"remove_group_tip": "Group \"{name}\" and all connections in it will be deleted",
|
||||||
"delete_key_succ": "\"{key}\" has been deleted",
|
"delete_key_succ": "\"{key}\" has been deleted",
|
||||||
|
|
|
@ -99,6 +99,7 @@
|
||||||
"close_confirm": "是否关闭当前连接",
|
"close_confirm": "是否关闭当前连接",
|
||||||
"edit_close_confirm": "编辑前需要关闭相关连接,是否继续",
|
"edit_close_confirm": "编辑前需要关闭相关连接,是否继续",
|
||||||
"opening_connection": "正在打开连接...",
|
"opening_connection": "正在打开连接...",
|
||||||
|
"interrupt_connection": "中断连接",
|
||||||
"remove_tip": "{type} \"{name}\" 将会被删除",
|
"remove_tip": "{type} \"{name}\" 将会被删除",
|
||||||
"remove_group_tip": "分组 \"{name}\"及其所有连接将会被删除",
|
"remove_group_tip": "分组 \"{name}\"及其所有连接将会被删除",
|
||||||
"delete_key_succ": "{key} 已被删除",
|
"delete_key_succ": "{key} 已被删除",
|
||||||
|
|
|
@ -105,6 +105,7 @@ export async function setupDiscreteApi() {
|
||||||
configProviderProps,
|
configProviderProps,
|
||||||
messageProviderProps: {
|
messageProviderProps: {
|
||||||
placement: 'bottom-right',
|
placement: 'bottom-right',
|
||||||
|
keepAliveOnHover: true,
|
||||||
},
|
},
|
||||||
notificationProviderProps: {
|
notificationProviderProps: {
|
||||||
max: 5,
|
max: 5,
|
||||||
|
|
Loading…
Reference in New Issue