Compare commits
7 Commits
54864fe7d5
...
faad24d1d5
Author | SHA1 | Date |
---|---|---|
tiny-craft | faad24d1d5 | |
tiny-craft | 6fb0eadfbd | |
tiny-craft | 124627d724 | |
tiny-craft | b6eebda177 | |
tiny-craft | 33051f4e46 | |
tiny-craft | 85ab6e4377 | |
tiny-craft | 297286f150 |
|
@ -18,7 +18,7 @@ import { useI18n } from 'vue-i18n'
|
|||
import { darkTheme } from 'naive-ui'
|
||||
import KeyFilterDialog from './components/dialogs/KeyFilterDialog.vue'
|
||||
import { WindowSetDarkTheme, WindowSetLightTheme } from 'wailsjs/runtime/runtime.js'
|
||||
import { themeOverrides } from '@/utils/theme.js'
|
||||
import { darkThemeOverrides, themeOverrides } from '@/utils/theme.js'
|
||||
import AboutDialog from '@/components/dialogs/AboutDialog.vue'
|
||||
|
||||
hljs.registerLanguage('json', json)
|
||||
|
@ -60,7 +60,7 @@ watch(
|
|||
:inline-theme-disabled="true"
|
||||
:locale="prefStore.themeLocale"
|
||||
:theme="prefStore.isDark ? darkTheme : undefined"
|
||||
:theme-overrides="themeOverrides"
|
||||
:theme-overrides="prefStore.isDark ? darkThemeOverrides : themeOverrides"
|
||||
class="fill-height">
|
||||
<n-dialog-provider>
|
||||
<app-content :loading="initializing" />
|
||||
|
|
|
@ -16,6 +16,8 @@ import ToolbarControlWidget from '@/components/common/ToolbarControlWidget.vue'
|
|||
import { EventsOn, WindowIsFullscreen, WindowIsMaximised, WindowToggleMaximise } from 'wailsjs/runtime/runtime.js'
|
||||
import { isMacOS } from '@/utils/platform.js'
|
||||
import iconUrl from '@/assets/images/icon.png'
|
||||
import ResizeableWrapper from '@/components/common/ResizeableWrapper.vue'
|
||||
import { extraTheme } from '@/utils/extra_theme.js'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
|
@ -25,8 +27,6 @@ const props = defineProps({
|
|||
|
||||
const data = reactive({
|
||||
navMenuWidth: 60,
|
||||
hoverResize: false,
|
||||
resizing: false,
|
||||
toolbarHeight: 45,
|
||||
})
|
||||
|
||||
|
@ -34,37 +34,17 @@ const tabStore = useTabStore()
|
|||
const prefStore = usePreferencesStore()
|
||||
const connectionStore = useConnectionStore()
|
||||
const logPaneRef = ref(null)
|
||||
const exThemeVars = computed(() => {
|
||||
return extraTheme(prefStore.isDark)
|
||||
})
|
||||
// const preferences = ref({})
|
||||
// provide('preferences', preferences)
|
||||
|
||||
const saveSidebarWidth = debounce(prefStore.savePreferences, 1000, { trailing: true })
|
||||
const handleResize = (evt) => {
|
||||
if (data.resizing) {
|
||||
prefStore.setAsideWidth(Math.max(evt.clientX - data.navMenuWidth, 300))
|
||||
const handleResize = () => {
|
||||
saveSidebarWidth()
|
||||
}
|
||||
}
|
||||
|
||||
const stopResize = () => {
|
||||
data.resizing = false
|
||||
document.removeEventListener('mousemove', handleResize)
|
||||
document.removeEventListener('mouseup', stopResize)
|
||||
}
|
||||
|
||||
const startResize = () => {
|
||||
data.resizing = true
|
||||
document.addEventListener('mousemove', handleResize)
|
||||
document.addEventListener('mouseup', stopResize)
|
||||
}
|
||||
|
||||
const asideWidthVal = computed(() => {
|
||||
return prefStore.behavior.asideWidth + 'px'
|
||||
})
|
||||
|
||||
const dragging = computed(() => {
|
||||
return data.hoverResize || data.resizing
|
||||
})
|
||||
|
||||
watch(
|
||||
() => tabStore.nav,
|
||||
(nav) => {
|
||||
|
@ -75,8 +55,11 @@ watch(
|
|||
)
|
||||
|
||||
const border = computed(() => {
|
||||
const color = isMacOS() && false ? '#0000' : themeVars.value.borderColor
|
||||
return `1px solid ${color}`
|
||||
return isMacOS() ? 'none' : `1px solid ${themeVars.value.borderColor}`
|
||||
})
|
||||
|
||||
const logoWrapperWidth = computed(() => {
|
||||
return `${data.navMenuWidth + prefStore.behavior.asideWidth - 4}px`
|
||||
})
|
||||
|
||||
const borderRadius = ref(10)
|
||||
|
@ -128,15 +111,9 @@ onMounted(async () => {
|
|||
<!-- app content-->
|
||||
<n-spin
|
||||
:show="props.loading"
|
||||
:style="{ backgroundColor: themeVars.bodyColor, borderRadius: `${borderRadius}px`, border }"
|
||||
:style="{ borderRadius: `${borderRadius}px`, border }"
|
||||
:theme-overrides="{ opacitySpinning: 0 }">
|
||||
<div
|
||||
id="app-content-wrapper"
|
||||
:style="{
|
||||
backgroundColor: themeVars.bodyColor,
|
||||
color: themeVars.textColorBase,
|
||||
}"
|
||||
class="flex-box-v">
|
||||
<div id="app-content-wrapper" :style="{ color: themeVars.textColorBase }" class="flex-box-v">
|
||||
<!-- title bar -->
|
||||
<div
|
||||
id="app-toolbar"
|
||||
|
@ -148,7 +125,8 @@ onMounted(async () => {
|
|||
<div
|
||||
id="app-toolbar-title"
|
||||
:style="{
|
||||
width: `${data.navMenuWidth + prefStore.behavior.asideWidth - 4}px`,
|
||||
width: logoWrapperWidth,
|
||||
minWidth: logoWrapperWidth,
|
||||
paddingLeft: `${logoPaddingLeft}px`,
|
||||
}">
|
||||
<n-space :size="3" :wrap="false" :wrap-item="false" align="center">
|
||||
|
@ -161,15 +139,6 @@ onMounted(async () => {
|
|||
</transition>
|
||||
</n-space>
|
||||
</div>
|
||||
<div
|
||||
:class="{
|
||||
'resize-divider-hover': data.hoverResize,
|
||||
'resize-divider-drag': data.resizing,
|
||||
}"
|
||||
class="resize-divider resize-divider-hide"
|
||||
@mousedown="startResize"
|
||||
@mouseout="data.hoverResize = false"
|
||||
@mouseover="data.hoverResize = true" />
|
||||
<!-- browser tabs -->
|
||||
<div v-show="tabStore.nav === 'browser'" class="app-toolbar-tab flex-item-expand">
|
||||
<content-value-tab />
|
||||
|
@ -191,40 +160,37 @@ onMounted(async () => {
|
|||
style="--wails-draggable: none">
|
||||
<nav-menu v-model:value="tabStore.nav" :width="data.navMenuWidth" />
|
||||
<!-- browser page -->
|
||||
<div v-show="tabStore.nav === 'browser'" :class="{ dragging }" class="flex-box-h flex-item-expand">
|
||||
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
||||
<div v-show="tabStore.nav === 'browser'" class="flex-box-h flex-item-expand">
|
||||
<resizeable-wrapper
|
||||
v-model:size="prefStore.behavior.asideWidth"
|
||||
:min-size="300"
|
||||
:offset="data.navMenuWidth"
|
||||
class="flex-item"
|
||||
@update:size="handleResize">
|
||||
<browser-pane
|
||||
v-for="t in tabStore.tabs"
|
||||
v-show="get(tabStore.currentTab, 'name') === t.name"
|
||||
:key="t.name"
|
||||
class="app-side flex-item-expand" />
|
||||
</resizeable-wrapper>
|
||||
<content-pane
|
||||
v-for="t in tabStore.tabs"
|
||||
v-show="get(tabStore.currentTab, 'name') === t.name"
|
||||
:key="t.name"
|
||||
:server="t.name"
|
||||
class="flex-item-expand" />
|
||||
<div
|
||||
:class="{
|
||||
'resize-divider-hover': data.hoverResize,
|
||||
'resize-divider-drag': data.resizing,
|
||||
}"
|
||||
class="resize-divider"
|
||||
@mousedown="startResize"
|
||||
@mouseout="data.hoverResize = false"
|
||||
@mouseover="data.hoverResize = true" />
|
||||
</div>
|
||||
<content-pane class="flex-item-expand" />
|
||||
</div>
|
||||
|
||||
<!-- server list page -->
|
||||
<div v-show="tabStore.nav === 'server'" :class="{ dragging }" class="flex-box-h flex-item-expand">
|
||||
<div id="app-side" :style="{ width: asideWidthVal }" class="flex-box-h flex-item">
|
||||
<connection-pane class="flex-item-expand" />
|
||||
<div
|
||||
:class="{
|
||||
'resize-divider-hover': data.hoverResize,
|
||||
'resize-divider-drag': data.resizing,
|
||||
}"
|
||||
class="resize-divider"
|
||||
@mousedown="startResize"
|
||||
@mouseout="data.hoverResize = false"
|
||||
@mouseover="data.hoverResize = true" />
|
||||
</div>
|
||||
<div v-show="tabStore.nav === 'server'" class="flex-box-h flex-item-expand">
|
||||
<resizeable-wrapper
|
||||
v-model:size="prefStore.behavior.asideWidth"
|
||||
:min-size="300"
|
||||
:offset="data.navMenuWidth"
|
||||
class="flex-item"
|
||||
@update:size="handleResize">
|
||||
<connection-pane class="app-side flex-item-expand" />
|
||||
</resizeable-wrapper>
|
||||
<content-server-pane class="flex-item-expand" />
|
||||
</div>
|
||||
|
||||
|
@ -239,15 +205,16 @@ onMounted(async () => {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
#app-content-wrapper {
|
||||
width: calc(100vw - 2px);
|
||||
height: calc(100vh - 2px);
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
background-color: v-bind('themeVars.bodyColor');
|
||||
|
||||
#app-toolbar {
|
||||
background-color: v-bind('themeVars.tabColor');
|
||||
border-bottom: 1px solid v-bind('themeVars.borderColor');
|
||||
background-color: v-bind('exThemeVars.titleColor');
|
||||
border-bottom: 1px solid v-bind('exThemeVars.splitColor');
|
||||
|
||||
&-title {
|
||||
padding-left: 10px;
|
||||
|
@ -268,37 +235,14 @@ onMounted(async () => {
|
|||
height: calc(100% - 60px);
|
||||
}
|
||||
|
||||
#app-side {
|
||||
.app-side {
|
||||
//overflow: hidden;
|
||||
height: 100%;
|
||||
background-color: v-bind('themeVars.tabColor');
|
||||
background-color: v-bind('exThemeVars.sidebarColor');
|
||||
border-right: 1px solid v-bind('exThemeVars.splitColor');
|
||||
}
|
||||
}
|
||||
|
||||
.resize-divider {
|
||||
width: 3px;
|
||||
border-right: 1px solid v-bind('themeVars.borderColor');
|
||||
}
|
||||
|
||||
.resize-divider-hide {
|
||||
background-color: #0000;
|
||||
border-right-color: #0000;
|
||||
}
|
||||
|
||||
.resize-divider-hover {
|
||||
background-color: v-bind('themeVars.borderColor');
|
||||
border-right-color: v-bind('themeVars.borderColor');
|
||||
}
|
||||
|
||||
.resize-divider-drag {
|
||||
background-color: v-bind('themeVars.primaryColor');
|
||||
border-right-color: v-bind('themeVars.primaryColor');
|
||||
}
|
||||
|
||||
.dragging {
|
||||
cursor: col-resize !important;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
|
|
|
@ -28,4 +28,4 @@ const handleSelectFile = async () => {
|
|||
</n-input-group>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -14,7 +14,7 @@ const props = defineProps({
|
|||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'currentColor',
|
||||
default: '',
|
||||
},
|
||||
strokeWidth: {
|
||||
type: [Number, String],
|
||||
|
@ -38,9 +38,10 @@ const hasTooltip = computed(() => {
|
|||
:focusable="false"
|
||||
:loading="loading"
|
||||
:text="!border"
|
||||
:color="props.color"
|
||||
@click.prevent="emit('click')">
|
||||
<template #icon>
|
||||
<n-icon :color="props.color" :size="props.size">
|
||||
<n-icon :color="props.color || 'currentColor'" :size="props.size">
|
||||
<component :is="props.icon" :stroke-width="props.strokeWidth" />
|
||||
</n-icon>
|
||||
</template>
|
||||
|
@ -54,9 +55,10 @@ const hasTooltip = computed(() => {
|
|||
:focusable="false"
|
||||
:loading="loading"
|
||||
:text="!border"
|
||||
:color="props.color"
|
||||
@click.prevent="emit('click')">
|
||||
<template #icon>
|
||||
<n-icon :color="props.color" :size="props.size">
|
||||
<n-icon :color="props.color || 'currentColor'" :size="props.size">
|
||||
<component :is="props.icon" :stroke-width="props.strokeWidth" />
|
||||
</n-icon>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
<script setup>
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
/**
|
||||
* Resizeable component wrapper
|
||||
*/
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
const props = defineProps({
|
||||
size: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
minSize: {
|
||||
type: Number,
|
||||
default: 300,
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
offset: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
borderWidth: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:size'])
|
||||
|
||||
const resizing = ref(false)
|
||||
const hover = ref(false)
|
||||
|
||||
const handleResize = (evt) => {
|
||||
if (resizing.value) {
|
||||
let size = evt.clientX - props.offset
|
||||
if (size < props.minSize) {
|
||||
size = props.minSize
|
||||
}
|
||||
if (props.maxSize > 0 && size > props.maxSize) {
|
||||
size = props.maxSize
|
||||
}
|
||||
emit('update:size', size)
|
||||
}
|
||||
}
|
||||
|
||||
const stopResize = () => {
|
||||
resizing.value = false
|
||||
document.removeEventListener('mousemove', handleResize)
|
||||
document.removeEventListener('mouseup', stopResize)
|
||||
}
|
||||
|
||||
const startResize = () => {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
resizing.value = true
|
||||
document.addEventListener('mousemove', handleResize)
|
||||
document.addEventListener('mouseup', stopResize)
|
||||
}
|
||||
|
||||
const handleMouseOver = () => {
|
||||
if (props.disabled) {
|
||||
return
|
||||
}
|
||||
hover.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :style="{ width: props.size + 'px' }" class="resize-wrapper flex-box-h">
|
||||
<slot></slot>
|
||||
<div
|
||||
:class="{
|
||||
'resize-divider-hover': hover,
|
||||
'resize-divider-drag': resizing,
|
||||
dragging: hover || resizing,
|
||||
}"
|
||||
:style="{ width: props.borderWidth + 'px', right: Math.floor(-props.borderWidth / 2) + 'px' }"
|
||||
class="resize-divider"
|
||||
@mousedown="startResize"
|
||||
@mouseout="hover = false"
|
||||
@mouseover="handleMouseOver" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.resize-wrapper {
|
||||
position: relative;
|
||||
|
||||
.resize-divider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
transition: background-color 0.3s ease-in;
|
||||
}
|
||||
|
||||
.resize-divider-hide {
|
||||
background-color: #0000;
|
||||
}
|
||||
|
||||
.resize-divider-hover {
|
||||
background-color: v-bind('themeVars.borderColor');
|
||||
}
|
||||
|
||||
.resize-divider-drag {
|
||||
background-color: v-bind('themeVars.primaryColor');
|
||||
}
|
||||
|
||||
.dragging {
|
||||
cursor: col-resize !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -42,12 +42,12 @@ const handleSwitch = (idx) => {
|
|||
<template>
|
||||
<n-button-group>
|
||||
<n-tooltip
|
||||
:show-arrow="false"
|
||||
v-for="(icon, i) in props.icons"
|
||||
:key="i"
|
||||
:disabled="!(props.tTooltips && props.tTooltips[i])">
|
||||
:disabled="!(props.tTooltips && props.tTooltips[i])"
|
||||
:show-arrow="false">
|
||||
<template #trigger>
|
||||
<n-button :tertiary="i !== props.value" :focusable="false" :size="props.size" @click="handleSwitch(i)">
|
||||
<n-button :focusable="false" :size="props.size" :tertiary="i !== props.value" @click="handleSwitch(i)">
|
||||
<template #icon>
|
||||
<n-icon :size="props.iconSize">
|
||||
<component
|
||||
|
@ -62,4 +62,4 @@ const handleSwitch = (idx) => {
|
|||
</n-button-group>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -73,10 +73,10 @@ defineExpose({
|
|||
<template>
|
||||
<n-card
|
||||
:bordered="false"
|
||||
:theme-overrides="{ borderRadius: '0px' }"
|
||||
:title="$t('log.launch_log')"
|
||||
class="content-container flex-box-v"
|
||||
content-style="display: flex;flex-direction: column; overflow: hidden; backgroundColor: gray"
|
||||
:theme-overrides="{ borderRadius: '0px' }">
|
||||
content-style="display: flex;flex-direction: column; overflow: hidden; backgroundColor: gray">
|
||||
<n-form :disabled="data.loading" class="flex-item" inline>
|
||||
<n-form-item :label="$t('log.filter_server')">
|
||||
<n-select
|
||||
|
@ -162,6 +162,5 @@ defineExpose({
|
|||
.content-container {
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
border-left: 1px solid v-bind('themeVars.borderColor');
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, reactive, watch } from 'vue'
|
||||
import { get, isEmpty, keyBy, map, size, toUpper } from 'lodash'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import { find, map, toUpper } from 'lodash'
|
||||
import useTabStore from 'stores/tab.js'
|
||||
import useConnectionStore from 'stores/connections.js'
|
||||
import ContentServerStatus from '@/components/content_value/ContentServerStatus.vue'
|
||||
import Status from '@/components/icons/Status.vue'
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
|
@ -24,98 +23,10 @@ const themeVars = useThemeVars()
|
|||
* @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(() => {
|
||||
if (tabContent.value != null) {
|
||||
return tabContent.value.name
|
||||
}
|
||||
return ''
|
||||
})
|
||||
/**
|
||||
*
|
||||
* @type {ComputedRef<ServerStatusItem>}
|
||||
*/
|
||||
const currentServer = computed(() => {
|
||||
return getServerInfo(serverName.value)
|
||||
const props = defineProps({
|
||||
server: String,
|
||||
})
|
||||
|
||||
/**
|
||||
* refresh server status info
|
||||
* @param {string} serverName
|
||||
* @param {boolean} [force] force refresh will show loading indicator
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const refreshInfo = async (serverName, force) => {
|
||||
const info = getServerInfo(serverName)
|
||||
if (force) {
|
||||
info.loading = true
|
||||
} else {
|
||||
info.autoLoading = true
|
||||
}
|
||||
if (!isEmpty(serverName) && connectionStore.isConnected(serverName)) {
|
||||
try {
|
||||
info.info = await connectionStore.getServerInfo(serverName)
|
||||
} finally {
|
||||
info.loading = false
|
||||
info.autoLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const refreshAllInfo = async (force) => {
|
||||
for (const serverName in serverStatusTab) {
|
||||
await refreshInfo(serverName, force)
|
||||
}
|
||||
}
|
||||
|
||||
let intervalId
|
||||
onMounted(() => {
|
||||
refreshAllInfo(true)
|
||||
intervalId = setInterval(() => {
|
||||
for (const serverName in serverStatusTab) {
|
||||
if (get(serverStatusTab, [serverName, 'autoRefresh'])) {
|
||||
refreshInfo(serverName)
|
||||
}
|
||||
}
|
||||
}, 5000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(intervalId)
|
||||
})
|
||||
|
||||
const connectionStore = useConnectionStore()
|
||||
const tabStore = useTabStore()
|
||||
const tab = computed(() =>
|
||||
map(tabStore.tabs, (item) => ({
|
||||
|
@ -124,35 +35,10 @@ const tab = computed(() =>
|
|||
})),
|
||||
)
|
||||
|
||||
watch(
|
||||
() => tabStore.nav,
|
||||
(nav) => {
|
||||
if (nav === 'browser') {
|
||||
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 tab = tabStore.currentTab
|
||||
const tab = find(tabStore.tabs, { name: props.server })
|
||||
if (tab == null) {
|
||||
return null
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
name: tab.name,
|
||||
|
@ -168,39 +54,36 @@ const tabContent = computed(() => {
|
|||
}
|
||||
})
|
||||
|
||||
const showServerStatus = computed(() => {
|
||||
return tabContent.value == null || isEmpty(tabContent.value.keyPath)
|
||||
})
|
||||
|
||||
const isBlankValue = computed(() => {
|
||||
return tabContent.value.value == null
|
||||
})
|
||||
|
||||
/**
|
||||
* reload current selection key
|
||||
* @returns {Promise<null>}
|
||||
*/
|
||||
const onReloadKey = async () => {
|
||||
const tab = tabStore.currentTab
|
||||
if (tab == null || isEmpty(tab.key)) {
|
||||
return null
|
||||
}
|
||||
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)
|
||||
}
|
||||
// BUG: naive-ui tabs will set the bottom line to '0px' after switch to another page and back again
|
||||
// watch parent tabs' changing and call 'syncBarPosition' manually
|
||||
const tabsRef = ref(null)
|
||||
const cliRef = ref(null)
|
||||
watch(
|
||||
() => tabContent.value?.name,
|
||||
(name) => {
|
||||
if (name === props.server) {
|
||||
nextTick().then(() => {
|
||||
tabsRef.value?.syncBarPosition()
|
||||
cliRef.value?.resizeTerm()
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="content-container flex-box-v">
|
||||
<n-tabs
|
||||
ref="tabsRef"
|
||||
:tabs-padding="5"
|
||||
:theme-overrides="{
|
||||
tabFontWeightActive: 'normal',
|
||||
|
@ -215,9 +98,9 @@ const onSwitchSubTab = (name) => {
|
|||
placement="top"
|
||||
tab-style="padding-left: 10px; padding-right: 10px;"
|
||||
type="line"
|
||||
@update:value="onSwitchSubTab">
|
||||
@update:value="tabStore.switchSubTab">
|
||||
<!-- server status pane -->
|
||||
<n-tab-pane :name="BrowserTabType.Status.toString()">
|
||||
<n-tab-pane :name="BrowserTabType.Status.toString()" display-directive="show:lazy">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
|
@ -226,17 +109,11 @@ const onSwitchSubTab = (name) => {
|
|||
<span>{{ $t('interface.sub_tab.status') }}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
<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)" />
|
||||
<content-server-status :server="props.server" />
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- key detail pane -->
|
||||
<n-tab-pane :name="BrowserTabType.KeyDetail.toString()">
|
||||
<n-tab-pane :name="BrowserTabType.KeyDetail.toString()" display-directive="show:lazy">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
|
@ -249,20 +126,19 @@ const onSwitchSubTab = (name) => {
|
|||
</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"
|
||||
:type="tabContent.type"
|
||||
:value="tabContent.value"
|
||||
:view-as="tabContent.viewAs"
|
||||
@reload="onReloadKey" />
|
||||
:view-as="tabContent.viewAs" />
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- cli pane -->
|
||||
<n-tab-pane :name="BrowserTabType.Cli.toString()">
|
||||
<n-tab-pane :name="BrowserTabType.Cli.toString()" display-directive="show:lazy">
|
||||
<template #tab>
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="16">
|
||||
|
@ -271,7 +147,7 @@ const onSwitchSubTab = (name) => {
|
|||
<span>{{ $t('interface.sub_tab.cli') }}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
<content-cli :name="currentServer.name" />
|
||||
<content-cli ref="cliRef" :name="props.server" />
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- slow log pane -->
|
||||
|
@ -302,14 +178,18 @@ const onSwitchSubTab = (name) => {
|
|||
|
||||
<style lang="scss">
|
||||
.content-sub-tab {
|
||||
background-color: v-bind('themeVars.bodyColor');
|
||||
background-color: v-bind('themeVars.tabColor');
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content-sub-tab-pane {
|
||||
padding: 0 !important;
|
||||
height: 100%;
|
||||
background-color: v-bind('themeVars.tabColor');
|
||||
background-color: v-bind('themeVars.bodyColor');
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.n-tabs .n-tabs-bar {
|
||||
transition: none !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,33 +6,37 @@ import { useI18n } from 'vue-i18n'
|
|||
import { get, map } from 'lodash'
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
import useConnectionStore from 'stores/connections.js'
|
||||
import { extraTheme } from '@/utils/extra_theme.js'
|
||||
import usePreferencesStore from 'stores/preferences.js'
|
||||
|
||||
/**
|
||||
* Value content tab on head
|
||||
*/
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
const i18n = useI18n()
|
||||
const tabStore = useTabStore()
|
||||
const connectionStore = useConnectionStore()
|
||||
const prefStore = usePreferencesStore()
|
||||
|
||||
const onCloseTab = (tabIndex) => {
|
||||
$dialog.warning(i18n.t('dialogue.close_confirm'), () => {
|
||||
const tab = get(tabStore.tabs, tabIndex)
|
||||
if (tab != null) {
|
||||
$dialog.warning(i18n.t('dialogue.close_confirm', { name: tab.name }), () => {
|
||||
connectionStore.closeConnection(tab.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const activeTabStyle = computed(() => {
|
||||
const { name } = tabStore.currentTab
|
||||
const tabMarkColor = computed(() => {
|
||||
const { name } = tabStore?.currentTab || {}
|
||||
const { markColor = '' } = connectionStore.serverProfile[name] || {}
|
||||
return {
|
||||
borderTopWidth: markColor ? '3px' : '1px',
|
||||
borderTopColor: markColor || themeVars.value.borderColor,
|
||||
}
|
||||
return markColor
|
||||
})
|
||||
|
||||
const tabClass = (idx) => {
|
||||
if (tabStore.activatedIndex === idx) {
|
||||
return ['value-tab', 'value-tab-active']
|
||||
return ['value-tab', 'value-tab-active', tabMarkColor.value ? 'value-tab-active_mark' : '']
|
||||
} else if (tabStore.activatedIndex - 1 === idx) {
|
||||
return ['value-tab', 'value-tab-inactive']
|
||||
} else {
|
||||
|
@ -46,26 +50,23 @@ const tab = computed(() =>
|
|||
label: item.title,
|
||||
})),
|
||||
)
|
||||
|
||||
const exThemeVars = computed(() => {
|
||||
return extraTheme(prefStore.isDark)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-tabs
|
||||
v-model:value="tabStore.activatedIndex"
|
||||
:closable="true"
|
||||
:tabs-padding="0"
|
||||
:tab-style="{
|
||||
borderStyle: 'solid',
|
||||
borderWidth: '1px',
|
||||
borderLeftColor: themeVars.borderColor,
|
||||
borderRightColor: themeVars.borderColor,
|
||||
}"
|
||||
:tabs-padding="3"
|
||||
:theme-overrides="{
|
||||
tabFontWeightActive: 800,
|
||||
tabGapSmallCard: 0,
|
||||
tabGapMediumCard: 0,
|
||||
tabGapLargeCard: 0,
|
||||
tabColor: '#0000',
|
||||
// tabBorderColor: themeVars.borderColor,
|
||||
tabBorderColor: '#0000',
|
||||
tabTextColorCard: themeVars.closeIconColor,
|
||||
}"
|
||||
|
@ -73,14 +74,7 @@ const tab = computed(() =>
|
|||
type="card"
|
||||
@close="onCloseTab"
|
||||
@update:value="(tabIndex) => tabStore.switchTab(tabIndex)">
|
||||
<n-tab
|
||||
v-for="(t, i) in tab"
|
||||
:key="i"
|
||||
:closable="true"
|
||||
:name="i"
|
||||
:style="tabStore.activatedIndex === i ? activeTabStyle : undefined"
|
||||
:class="tabClass(i)"
|
||||
@dblclick.stop="() => {}">
|
||||
<n-tab v-for="(t, i) in tab" :key="i" :class="tabClass(i)" :closable="true" :name="i" @dblclick.stop="() => {}">
|
||||
<n-space :size="5" :wrap-item="false" align="center" inline justify="center">
|
||||
<n-icon size="18">
|
||||
<server stroke-width="4" />
|
||||
|
@ -95,18 +89,23 @@ const tab = computed(() =>
|
|||
.value-tab {
|
||||
--wails-draggable: none;
|
||||
position: relative;
|
||||
border: 1px solid v-bind('exThemeVars.splitColor') !important;
|
||||
}
|
||||
|
||||
.value-tab-active {
|
||||
background-color: v-bind('themeVars.bodyColor') !important;
|
||||
border-bottom-color: v-bind('themeVars.bodyColor') !important;
|
||||
background-color: v-bind('themeVars.tabColor') !important;
|
||||
border-bottom-color: v-bind('themeVars.tabColor') !important;
|
||||
|
||||
&_mark {
|
||||
border-top: 3px solid v-bind('tabMarkColor') !important;
|
||||
}
|
||||
}
|
||||
|
||||
.value-tab-inactive {
|
||||
border-color: #0000 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: v-bind('themeVars.borderColor') !important;
|
||||
background-color: v-bind('exThemeVars.splitColor') !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
import { Terminal } from 'xterm'
|
||||
import { FitAddon } from 'xterm-addon-fit'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, defineExpose, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import 'xterm/css/xterm.css'
|
||||
import { EventsEmit, EventsOff, EventsOn } from 'wailsjs/runtime/runtime.js'
|
||||
import { get, isEmpty, set, size } from 'lodash'
|
||||
|
@ -54,7 +54,6 @@ const newTerm = () => {
|
|||
return { term, fitAddon }
|
||||
}
|
||||
|
||||
let intervalID
|
||||
onMounted(() => {
|
||||
const { term, fitAddon } = newTerm()
|
||||
termInst = term
|
||||
|
@ -69,16 +68,9 @@ onMounted(() => {
|
|||
EventsOn(`cmd:output:${props.name}`, receiveTermOutput)
|
||||
fitAddon.fit()
|
||||
term.focus()
|
||||
|
||||
intervalID = setInterval(() => {
|
||||
if (props.activated) {
|
||||
resizeTerm()
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(intervalID)
|
||||
// window.removeEventListener('resize', resizeTerm)
|
||||
EventsOff(`cmd:output:${props.name}`)
|
||||
termInst.dispose()
|
||||
|
@ -92,6 +84,10 @@ const resizeTerm = () => {
|
|||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
resizeTerm,
|
||||
})
|
||||
|
||||
watch(
|
||||
() => prefStore.general.fontSize,
|
||||
(fontSize) => {
|
||||
|
@ -125,7 +121,6 @@ const onTermData = (data) => {
|
|||
|
||||
case 13: // enter
|
||||
// try to process local command first
|
||||
console.log('enter con', getCurrentInput())
|
||||
switch (getCurrentInput()) {
|
||||
case 'clear':
|
||||
case 'clr':
|
||||
|
@ -366,7 +361,7 @@ const receiveTermOutput = (data) => {
|
|||
<div ref="termRef" class="xterm" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.xterm {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
|
|
|
@ -1,36 +1,72 @@
|
|||
<script setup>
|
||||
import { get, isEmpty, map, mapValues, pickBy, split, sum, toArray, toNumber } from 'lodash'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import IconButton from '@/components/common/IconButton.vue'
|
||||
import Filter from '@/components/icons/Filter.vue'
|
||||
import Refresh from '@/components/icons/Refresh.vue'
|
||||
import useConnectionStore from 'stores/connections.js'
|
||||
|
||||
const props = defineProps({
|
||||
server: String,
|
||||
info: Object,
|
||||
autoRefresh: false,
|
||||
loading: false,
|
||||
autoLoading: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:autoRefresh', 'refresh'])
|
||||
const connectionStore = useConnectionStore()
|
||||
const serverInfo = ref({})
|
||||
const autoRefresh = ref(false)
|
||||
const loading = ref(false) // loading status for refresh
|
||||
const autoLoading = ref(false) // loading status for auto refresh
|
||||
|
||||
/**
|
||||
* refresh server status info
|
||||
* @param {boolean} [force] force refresh will show loading indicator
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const refreshInfo = async (force) => {
|
||||
if (force) {
|
||||
loading.value = true
|
||||
} else {
|
||||
autoLoading.value = true
|
||||
}
|
||||
if (!isEmpty(props.server) && connectionStore.isConnected(props.server)) {
|
||||
try {
|
||||
serverInfo.value = await connectionStore.getServerInfo(props.server)
|
||||
} finally {
|
||||
loading.value = false
|
||||
autoLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let intervalID
|
||||
onMounted(() => {
|
||||
refreshInfo()
|
||||
intervalID = setInterval(() => {
|
||||
if (autoRefresh.value === true) {
|
||||
refreshInfo()
|
||||
}
|
||||
}, 5000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(intervalID)
|
||||
})
|
||||
|
||||
const scrollRef = ref(null)
|
||||
const redisVersion = computed(() => {
|
||||
return get(props.info, 'Server.redis_version', '')
|
||||
return get(serverInfo.value, 'Server.redis_version', '')
|
||||
})
|
||||
|
||||
const redisMode = computed(() => {
|
||||
return get(props.info, 'Server.redis_mode', '')
|
||||
return get(serverInfo.value, 'Server.redis_mode', '')
|
||||
})
|
||||
|
||||
const role = computed(() => {
|
||||
return get(props.info, 'Replication.role', '')
|
||||
return get(serverInfo.value, 'Replication.role', '')
|
||||
})
|
||||
|
||||
const timeUnit = ['common.unit_minute', 'common.unit_hour', 'common.unit_day']
|
||||
const uptime = computed(() => {
|
||||
let seconds = get(props.info, 'Server.uptime_in_seconds', 0)
|
||||
let seconds = get(serverInfo.value, 'Server.uptime_in_seconds', 0)
|
||||
seconds /= 60
|
||||
if (seconds < 60) {
|
||||
// minutes
|
||||
|
@ -46,7 +82,7 @@ const uptime = computed(() => {
|
|||
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
const usedMemory = computed(() => {
|
||||
let size = get(props.info, 'Memory.used_memory', 0)
|
||||
let size = get(serverInfo.value, 'Memory.used_memory', 0)
|
||||
let unitIndex = 0
|
||||
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
|
@ -59,7 +95,7 @@ const usedMemory = computed(() => {
|
|||
|
||||
const totalKeys = computed(() => {
|
||||
const regex = /^db\d+$/
|
||||
const result = pickBy(props.info['Keyspace'], (value, key) => {
|
||||
const result = pickBy(serverInfo.value['Keyspace'], (value, key) => {
|
||||
return regex.test(key)
|
||||
})
|
||||
const nums = mapValues(result, (v) => {
|
||||
|
@ -75,8 +111,8 @@ const infoFilter = ref('')
|
|||
<template>
|
||||
<n-scrollbar ref="scrollRef">
|
||||
<n-back-top :listen-to="scrollRef" />
|
||||
<n-space vertical :wrap-item="false" :size="5" style="padding: 5px">
|
||||
<n-card>
|
||||
<n-space :size="5" :wrap-item="false" style="padding: 5px" vertical>
|
||||
<n-card embedded>
|
||||
<template #header>
|
||||
<n-space :wrap-item="false" align="center" inline size="small">
|
||||
{{ props.server }}
|
||||
|
@ -103,19 +139,16 @@ const infoFilter = ref('')
|
|||
<template #header-extra>
|
||||
<n-space align="center" inline>
|
||||
{{ $t('status.auto_refresh') }}
|
||||
<n-switch
|
||||
:loading="props.autoLoading"
|
||||
:value="props.autoRefresh"
|
||||
@update:value="(v) => emit('update:autoRefresh', v)" />
|
||||
<n-switch v-model:value="autoRefresh" :loading="autoLoading" />
|
||||
<n-tooltip>
|
||||
{{ $t('status.refresh') }}
|
||||
<template #trigger>
|
||||
<n-button
|
||||
:loading="props.autoLoading"
|
||||
:loading="autoLoading"
|
||||
circle
|
||||
size="small"
|
||||
tertiary
|
||||
@click="emit('refresh')">
|
||||
@click="refreshInfo(true)">
|
||||
<template #icon>
|
||||
<n-icon :component="Refresh" />
|
||||
</template>
|
||||
|
@ -124,7 +157,7 @@ const infoFilter = ref('')
|
|||
</n-tooltip>
|
||||
</n-space>
|
||||
</template>
|
||||
<n-spin :show="props.loading">
|
||||
<n-spin :show="loading">
|
||||
<n-grid style="min-width: 500px" x-gap="5">
|
||||
<n-gi :span="6">
|
||||
<n-statistic :label="$t('status.uptime')" :value="uptime[0]">
|
||||
|
@ -134,7 +167,7 @@ const infoFilter = ref('')
|
|||
<n-gi :span="6">
|
||||
<n-statistic
|
||||
:label="$t('status.connected_clients')"
|
||||
:value="get(props.info, 'Clients.connected_clients', 0)" />
|
||||
:value="get(serverInfo, 'Clients.connected_clients', 0)" />
|
||||
</n-gi>
|
||||
<n-gi :span="6">
|
||||
<n-statistic :value="totalKeys">
|
||||
|
@ -151,7 +184,7 @@ const infoFilter = ref('')
|
|||
</n-grid>
|
||||
</n-spin>
|
||||
</n-card>
|
||||
<n-card :title="$t('status.all_info')">
|
||||
<n-card :title="$t('status.all_info')" embedded>
|
||||
<template #header-extra>
|
||||
<n-input v-model:value="infoFilter" clearable placeholder="">
|
||||
<template #prefix>
|
||||
|
@ -159,9 +192,9 @@ const infoFilter = ref('')
|
|||
</template>
|
||||
</n-input>
|
||||
</template>
|
||||
<n-spin :show="props.loading">
|
||||
<n-spin :show="loading">
|
||||
<n-tabs default-value="CPU" placement="left" type="line">
|
||||
<n-tab-pane v-for="(v, k) in props.info" :key="k" :disabled="isEmpty(v)" :name="k">
|
||||
<n-tab-pane v-for="(v, k) in serverInfo" :key="k" :disabled="isEmpty(v)" :name="k">
|
||||
<n-data-table
|
||||
:columns="[
|
||||
{
|
||||
|
|
|
@ -8,8 +8,10 @@ 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'
|
||||
import useConnectionStore from 'stores/connections.js'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
const connectionStore = useConnectionStore()
|
||||
|
||||
const props = defineProps({
|
||||
blank: Boolean,
|
||||
|
@ -33,8 +35,6 @@ const props = defineProps({
|
|||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['reload'])
|
||||
|
||||
const valueComponents = {
|
||||
[redisTypes.STRING]: ContentValueString,
|
||||
[redisTypes.HASH]: ContentValueHash,
|
||||
|
@ -43,18 +43,25 @@ const valueComponents = {
|
|||
[redisTypes.ZSET]: ContentValueZset,
|
||||
[redisTypes.STREAM]: ContentValueStream,
|
||||
}
|
||||
|
||||
/**
|
||||
* reload current selection key
|
||||
* @returns {Promise<null>}
|
||||
*/
|
||||
const onReloadKey = async () => {
|
||||
await connectionStore.loadKeyValue(props.name, props.db, props.key, props.viewAs)
|
||||
}
|
||||
</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>
|
||||
<n-button :focusable="false" @click="onReloadKey">{{ $t('interface.reload') }}</n-button>
|
||||
</template>
|
||||
</n-empty>
|
||||
<keep-alive v-else>
|
||||
<component
|
||||
class="content-value-wrapper"
|
||||
:is="valueComponents[props.type]"
|
||||
v-else
|
||||
:db="props.db"
|
||||
:key-code="props.keyCode"
|
||||
:key-path="props.keyPath"
|
||||
|
@ -63,10 +70,7 @@ const valueComponents = {
|
|||
:ttl="props.ttl"
|
||||
:value="props.value"
|
||||
:view-as="props.viewAs" />
|
||||
</keep-alive>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content-value-wrapper {
|
||||
background-color: v-bind('themeVars.bodyColor');
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
@ -8,11 +8,13 @@ import Close from '@/components/icons/Close.vue'
|
|||
import useConnectionStore from 'stores/connections.js'
|
||||
import FileOpenInput from '@/components/common/FileOpenInput.vue'
|
||||
import { KeyViewType } from '@/consts/key_view_type.js'
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
|
||||
/**
|
||||
* Dialog for new or edit connection
|
||||
*/
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
const dialogStore = useDialog()
|
||||
const connectionStore = useConnectionStore()
|
||||
const i18n = useI18n()
|
||||
|
@ -396,10 +398,13 @@ const onClose = () => {
|
|||
<div
|
||||
v-for="color in predefineColors"
|
||||
:key="color"
|
||||
:class="{
|
||||
'color-preset-item_selected': generalForm.markColor === color,
|
||||
:style="{
|
||||
backgroundColor: color,
|
||||
borderColor:
|
||||
generalForm.markColor === color
|
||||
? themeVars.textColorBase
|
||||
: themeVars.borderColor,
|
||||
}"
|
||||
:style="{ backgroundColor: color }"
|
||||
class="color-preset-item"
|
||||
@click="generalForm.markColor = color">
|
||||
<n-icon v-if="isEmpty(color)" :component="Close" size="24" />
|
||||
|
@ -591,13 +596,9 @@ const onClose = () => {
|
|||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 2px;
|
||||
border: white 3px solid;
|
||||
border-width: 3px;
|
||||
border-style: solid;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
|
||||
&_selected,
|
||||
&:hover {
|
||||
border-color: #cdd0d6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,52 +16,52 @@ const props = defineProps({
|
|||
<template>
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="currentColor"
|
||||
height="8"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="8"
|
||||
x="4"
|
||||
y="34" />
|
||||
<rect
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="currentColor"
|
||||
height="12"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="32"
|
||||
x="8"
|
||||
y="6" />
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M24 34V18"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M8 34V26H40V34"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<rect
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="currentColor"
|
||||
height="8"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="8"
|
||||
x="36"
|
||||
y="34" />
|
||||
<rect
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="currentColor"
|
||||
height="8"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
width="8"
|
||||
|
|
|
@ -16,31 +16,31 @@ const props = defineProps({
|
|||
<template>
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M44.0001 11C44.0001 11 44 36.0623 44 38C44 41.3137 35.0457 44 24 44C12.9543 44 4.00003 41.3137 4.00003 38C4.00003 36.1423 4 11 4 11"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M44 29C44 32.3137 35.0457 35 24 35C12.9543 35 4 32.3137 4 29"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M44 20C44 23.3137 35.0457 26 24 26C12.9543 26 4 23.3137 4 20"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<ellipse
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
cx="24"
|
||||
cy="10"
|
||||
fill="currentColor"
|
||||
rx="20"
|
||||
ry="6"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
|
|
@ -14,93 +14,93 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-if="props.inverse" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="6"
|
||||
y="6"
|
||||
width="36"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="currentColor"
|
||||
height="36"
|
||||
rx="3"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
stroke-linejoin="round"
|
||||
width="36"
|
||||
x="6"
|
||||
y="6" />
|
||||
<rect
|
||||
x="13"
|
||||
y="13"
|
||||
width="8"
|
||||
height="8"
|
||||
fill="#FFF"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
fill="#FFF"
|
||||
height="8"
|
||||
stroke="#FFF"
|
||||
stroke-linejoin="round"
|
||||
width="8"
|
||||
x="13"
|
||||
y="13" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M27 13L35 13"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M27 20L35 20"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M13 28L35 28"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
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">
|
||||
<svg v-else fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="6"
|
||||
y="6"
|
||||
width="36"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="none"
|
||||
height="36"
|
||||
rx="3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
stroke-linejoin="round"
|
||||
width="36"
|
||||
x="6"
|
||||
y="6" />
|
||||
<rect
|
||||
x="13"
|
||||
y="13"
|
||||
width="8"
|
||||
height="8"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
fill="none"
|
||||
height="8"
|
||||
stroke="currentColor"
|
||||
stroke-linejoin="round"
|
||||
width="8"
|
||||
x="13"
|
||||
y="13" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M27 13L35 13"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M27 20L35 20"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M13 28L35 28"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M13 35H35"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
|
|
@ -8,38 +8,38 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M9 42C11.2091 42 13 40.2091 13 38C13 35.7909 11.2091 34 9 34C6.79086 34 5 35.7909 5 38C5 40.2091 6.79086 42 9 42Z"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M9 14C11.2091 14 13 12.2092 13 10C13 7.79086 11.2091 6 9 6C6.79086 6 5 7.79086 5 10C5 12.2092 6.79086 14 9 14Z"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M9 28C11.2091 28 13 26.2092 13 24C13 21.7908 11.2091 20 9 20C6.79086 20 5 21.7908 5 24C5 26.2092 6.79086 28 9 28Z"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M21 24H43"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M21 38H43"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M21 10H43"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
|
|
@ -12,24 +12,24 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-if="props.inverse" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="13"
|
||||
y="10"
|
||||
width="28"
|
||||
height="34"
|
||||
fill="currentColor"
|
||||
height="34"
|
||||
stroke="currentColor"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3"
|
||||
stroke-linejoin="round" />
|
||||
width="28"
|
||||
x="13"
|
||||
y="10" />
|
||||
<path
|
||||
d="M35 10V4H8C7.44772 4 7 4.44772 7 5V38H13"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M21 22H33" stroke="#FFF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M21 30H33" stroke="#FFF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3" />
|
||||
<path d="M21 22H33" stroke="#FFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" />
|
||||
<path d="M21 30H33" stroke="#FFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" />
|
||||
</svg>
|
||||
<svg v-else fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
|
|
|
@ -16,10 +16,10 @@ const props = defineProps({
|
|||
<template>
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M41 4H7C5.34315 4 4 5.34315 4 7V41C4 42.6569 5.34315 44 7 44H41C42.6569 44 44 42.6569 44 41V7C44 5.34315 42.6569 4 41 4Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path :stroke-width="props.strokeWidth" d="M4 32H44" stroke="#FFF" stroke-linecap="round" />
|
||||
|
@ -36,15 +36,15 @@ const props = defineProps({
|
|||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M44 37V27"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M4 37V27"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
|
|
@ -12,15 +12,15 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-if="props.inverse" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M42 8H6C4.89543 8 4 8.89543 4 10V38C4 39.1046 4.89543 40 6 40H42C43.1046 40 44 39.1046 44 38V10C44 8.89543 43.1046 8 42 8Z"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="3" />
|
||||
<path d="M24 17V31" stroke="#FFF" :stroke-width="props.strokeWidth" stroke-linecap="round" />
|
||||
<path d="M32 24V31" stroke="#FFF" :stroke-width="props.strokeWidth" stroke-linecap="round" />
|
||||
<path d="M16 22V31" stroke="#FFF" :stroke-width="props.strokeWidth" stroke-linecap="round" />
|
||||
<path :stroke-width="props.strokeWidth" d="M24 17V31" stroke="#FFF" stroke-linecap="round" />
|
||||
<path :stroke-width="props.strokeWidth" d="M32 24V31" stroke="#FFF" stroke-linecap="round" />
|
||||
<path :stroke-width="props.strokeWidth" d="M16 22V31" stroke="#FFF" stroke-linecap="round" />
|
||||
</svg>
|
||||
<svg v-else fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
|
|
|
@ -14,51 +14,51 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-if="props.inverse" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg v-if="props.inverse" fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="4"
|
||||
y="8"
|
||||
width="40"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="currentColor"
|
||||
height="32"
|
||||
rx="2"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
stroke-linejoin="round"
|
||||
width="40"
|
||||
x="4"
|
||||
y="8" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M12 18L19 24L12 30"
|
||||
stroke="#FFF"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
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">
|
||||
<svg v-else fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
x="4"
|
||||
y="8"
|
||||
width="40"
|
||||
:stroke-width="props.strokeWidth"
|
||||
fill="none"
|
||||
height="32"
|
||||
rx="2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
stroke-linejoin="round"
|
||||
width="40"
|
||||
x="4"
|
||||
y="8" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M12 18L19 24L12 30"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M23 32H36"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
|
|
@ -8,47 +8,47 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg fill="none" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M38 20H18V28H38V20Z"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M32 6H18V14H32V6Z"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M44 34H18V42H44V34Z"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M17 10H5"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M17 24H5"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M17 38H5"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
:stroke-width="props.strokeWidth"
|
||||
d="M5 44V4"
|
||||
stroke="currentColor"
|
||||
:stroke-width="props.strokeWidth"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
|
|
@ -12,24 +12,12 @@ import useConnectionStore from 'stores/connections.js'
|
|||
import { types } from '@/consts/support_redis_type.js'
|
||||
import Search from '@/components/icons/Search.vue'
|
||||
import Unlink from '@/components/icons/Unlink.vue'
|
||||
import Status from '@/components/icons/Status.vue'
|
||||
import SwitchButton from '@/components/common/SwitchButton.vue'
|
||||
import ListView from '@/components/icons/ListView.vue'
|
||||
import TreeView from '@/components/icons/TreeView.vue'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
const dialogStore = useDialogStore()
|
||||
const tabStore = useTabStore()
|
||||
const currentName = computed(() => get(tabStore.currentTab, 'name', ''))
|
||||
const browserTreeRef = ref(null)
|
||||
/**
|
||||
*
|
||||
* @type {ComputedRef<{server: string, db: number, key: string}>}
|
||||
*/
|
||||
const currentSelect = computed(() => {
|
||||
const { server, db, key } = tabStore.currentTab || {}
|
||||
return { server, db, key }
|
||||
})
|
||||
|
||||
const onInfo = () => {
|
||||
browserTreeRef.value?.handleSelectContextMenu('server_info')
|
||||
|
@ -99,7 +87,7 @@ const filterTypeOptions = computed(() => {
|
|||
<!-- stroke-width="4"-->
|
||||
<!-- unselect-stroke-width="3"-->
|
||||
<!-- @update:value="onSwitchView" />-->
|
||||
<icon-button :icon="Status" size="20" stroke-width="4" t-tooltip="interface.status" @click="onInfo" />
|
||||
<!-- <icon-button :icon="Status" size="20" stroke-width="4" t-tooltip="interface.status" @click="onInfo" />-->
|
||||
<icon-button :icon="Refresh" size="20" stroke-width="4" t-tooltip="interface.reload" @click="onRefresh" />
|
||||
<div class="flex-item-expand" />
|
||||
<icon-button
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
import { computed, h, nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { ConnectionType } from '@/consts/connection_type.js'
|
||||
import { NIcon, NSpace, NTag } from 'naive-ui'
|
||||
import { NIcon, NSpace, NTag, useThemeVars } from 'naive-ui'
|
||||
import Key from '@/components/icons/Key.vue'
|
||||
import Binary from '@/components/icons/Binary.vue'
|
||||
import Database from '@/components/icons/Database.vue'
|
||||
|
@ -31,6 +31,7 @@ const props = defineProps({
|
|||
keyView: String,
|
||||
})
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
const i18n = useI18n()
|
||||
const loading = ref(false)
|
||||
const loadingConnections = ref(false)
|
||||
|
@ -532,6 +533,7 @@ const getDatabaseMenu = (opened, loading, end) => {
|
|||
icon: LoadList,
|
||||
disabled: end === true,
|
||||
loading: loading === true,
|
||||
color: loading === true ? themeVars.value.primaryColor : '',
|
||||
onClick: () => handleSelectContextMenu('db_loadmore'),
|
||||
}),
|
||||
h(IconButton, {
|
||||
|
@ -539,6 +541,7 @@ const getDatabaseMenu = (opened, loading, end) => {
|
|||
icon: LoadAll,
|
||||
disabled: end === true,
|
||||
loading: loading === true,
|
||||
color: loading === true ? themeVars.value.primaryColor : '',
|
||||
onClick: () => handleSelectContextMenu('db_loadall'),
|
||||
}),
|
||||
h(IconButton, {
|
||||
|
|
|
@ -530,10 +530,10 @@ const onCancelOpen = () => {
|
|||
|
||||
<!-- context menu -->
|
||||
<n-dropdown
|
||||
:keyboard="true"
|
||||
:options="contextMenuParam.options"
|
||||
:render-label="renderContextLabel"
|
||||
:show="contextMenuParam.show"
|
||||
:keyboard="true"
|
||||
:x="contextMenuParam.x"
|
||||
:y="contextMenuParam.y"
|
||||
placement="bottom-start"
|
||||
|
|
|
@ -12,6 +12,7 @@ import { BrowserOpenURL } from 'wailsjs/runtime/runtime.js'
|
|||
import useConnectionStore from 'stores/connections.js'
|
||||
import usePreferencesStore from 'stores/preferences.js'
|
||||
import Record from '@/components/icons/Record.vue'
|
||||
import { extraTheme } from '@/utils/extra_theme.js'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
|
@ -88,14 +89,14 @@ const renderContextLabel = (option) => {
|
|||
}
|
||||
|
||||
const dialogStore = useDialogStore()
|
||||
const preferencesStore = usePreferencesStore()
|
||||
const prefStore = usePreferencesStore()
|
||||
const onSelectPreferenceMenu = (key) => {
|
||||
switch (key) {
|
||||
case 'preferences':
|
||||
dialogStore.openPreferencesDialog()
|
||||
break
|
||||
case 'update':
|
||||
preferencesStore.checkForUpdate(true)
|
||||
prefStore.checkForUpdate(true)
|
||||
break
|
||||
case 'about':
|
||||
dialogStore.openAboutDialog()
|
||||
|
@ -106,6 +107,10 @@ const onSelectPreferenceMenu = (key) => {
|
|||
const openGithub = () => {
|
||||
BrowserOpenURL('https://github.com/tiny-craft/tiny-rdm')
|
||||
}
|
||||
|
||||
const exThemeVars = computed(() => {
|
||||
return extraTheme(prefStore.isDark)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -139,7 +144,9 @@ const openGithub = () => {
|
|||
<style lang="scss">
|
||||
#app-nav-menu {
|
||||
//height: 100vh;
|
||||
//border-right: v-bind('themeVars.borderColor') solid 1px;
|
||||
border-right: v-bind('exThemeVars.splitColor') solid 1px;
|
||||
background-color: v-bind('exThemeVars.sidebarColor');
|
||||
box-sizing: border-box;
|
||||
|
||||
.nav-menu-item {
|
||||
align-items: center;
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
"log": "Log"
|
||||
},
|
||||
"dialogue": {
|
||||
"close_confirm": "Confirm close this tab and connection",
|
||||
"close_confirm": "Confirm close this tab and connection ({name})",
|
||||
"edit_close_confirm": "Please close the relevant connections before editing. Do you want to continue?",
|
||||
"opening_connection": "Opening Connection...",
|
||||
"interrupt_connection": "Cancel",
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
"log": "日志"
|
||||
},
|
||||
"dialogue": {
|
||||
"close_confirm": "是否关闭当前连接",
|
||||
"close_confirm": "是否关闭此连接({name})",
|
||||
"edit_close_confirm": "编辑前需要关闭相关连接,是否继续",
|
||||
"opening_connection": "正在打开连接...",
|
||||
"interrupt_connection": "中断连接",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { lang } from '@/langs/index.js'
|
||||
import { clone, find, get, isEmpty, map, pick, set, split } from 'lodash'
|
||||
import { cloneDeep, find, get, isEmpty, map, pick, set, split } from 'lodash'
|
||||
import {
|
||||
CheckForUpdate,
|
||||
GetFontList,
|
||||
|
@ -178,7 +178,7 @@ const usePreferencesStore = defineStore('preferences', {
|
|||
async loadPreferences() {
|
||||
const { success, data } = await GetPreferences()
|
||||
if (success) {
|
||||
this.lastPref = clone(data)
|
||||
this.lastPref = cloneDeep(data)
|
||||
this._applyPreferences(data)
|
||||
i18nGlobal.locale.value = this.currentLanguage
|
||||
}
|
||||
|
|
|
@ -234,7 +234,7 @@ const useTabStore = defineStore('tab', {
|
|||
/**
|
||||
* set selected keys of current display browser tree
|
||||
* @param {string} server
|
||||
* @param {string|string[]} keys
|
||||
* @param {string|string[]} [keys]
|
||||
*/
|
||||
setSelectedKeys(server, keys = null) {
|
||||
let tab = find(this.tabList, { name: server })
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* @typedef ExtraTheme
|
||||
* @property {string} titleColor
|
||||
* @property {string} sidebarColor
|
||||
* @property {string} splitColor
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @type ExtraTheme
|
||||
*/
|
||||
export const extraLightTheme = {
|
||||
titleColor: '#F0F0F4',
|
||||
sidebarColor: '#F6F6F6',
|
||||
splitColor: '#E0E0E6',
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @type ExtraTheme
|
||||
*/
|
||||
export const extraDarkTheme = {
|
||||
titleColor: '#202020',
|
||||
sidebarColor: '#202124',
|
||||
splitColor: '#323138',
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} dark
|
||||
* @return ExtraTheme
|
||||
*/
|
||||
export const extraTheme = (dark) => {
|
||||
return dark ? extraDarkTheme : extraLightTheme
|
||||
}
|
|
@ -5,6 +5,7 @@ import { padStart, size, startsWith } from 'lodash'
|
|||
* @property {number} r
|
||||
* @property {number} g
|
||||
* @property {number} b
|
||||
* @property {number} [a]
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -43,6 +44,28 @@ export function hexGammaCorrection(rgb, gamma) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mix two colors
|
||||
* @param rgba1
|
||||
* @param rgba2
|
||||
* @param weight
|
||||
* @return {{a: number, r: number, b: number, g: number}}
|
||||
*/
|
||||
export function mixColors(rgba1, rgba2, weight = 0.5) {
|
||||
if (rgba1.a === undefined) {
|
||||
rgba1.a = 255
|
||||
}
|
||||
if (rgba2.a === undefined) {
|
||||
rgba2.a = 255
|
||||
}
|
||||
return {
|
||||
r: Math.floor(rgba1.r * (1 - weight) + rgba2.r * weight),
|
||||
g: Math.floor(rgba1.g * (1 - weight) + rgba2.g * weight),
|
||||
b: Math.floor(rgba1.b * (1 - weight) + rgba2.b * weight),
|
||||
a: Math.floor(rgba1.a * (1 - weight) + rgba2.a * weight),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RGB object to hex color string
|
||||
* @param {RGB} rgb
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { merge } from 'lodash'
|
||||
|
||||
/**
|
||||
*
|
||||
* @type import('naive-ui').GlobalThemeOverrides
|
||||
|
@ -12,6 +14,7 @@ export const themeOverrides = {
|
|||
borderRadiusSmall: '3px',
|
||||
lineHeight: 1.5,
|
||||
scrollbarWidth: '8px',
|
||||
tabColor: '#FFFFFF',
|
||||
},
|
||||
Tag: {
|
||||
// borderRadius: '3px'
|
||||
|
@ -39,4 +42,27 @@ export const themeOverrides = {
|
|||
labelTextColor: 'rgb(113,120,128)',
|
||||
labelFontWeight: '450',
|
||||
},
|
||||
Radio: {
|
||||
buttonColorActive: '#D13B37',
|
||||
buttonTextColorActive: '#FFF',
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @type import('naive-ui').GlobalThemeOverrides
|
||||
*/
|
||||
const _darkThemeOverrides = {
|
||||
common: {
|
||||
bodyColor: '#1A1A1A',
|
||||
tabColor: '#18181C',
|
||||
},
|
||||
Tree: {
|
||||
nodeTextColor: '#ceced0',
|
||||
},
|
||||
Card: {
|
||||
colorEmbedded: '#18181C',
|
||||
},
|
||||
}
|
||||
|
||||
export const darkThemeOverrides = merge({}, themeOverrides, _darkThemeOverrides)
|
||||
|
|
4
main.go
4
main.go
|
@ -53,7 +53,7 @@ func main() {
|
|||
AssetServer: &assetserver.Options{
|
||||
Assets: assets,
|
||||
},
|
||||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 0},
|
||||
BackgroundColour: options.NewRGBA(27, 38, 54, 0),
|
||||
OnStartup: func(ctx context.Context) {
|
||||
sysSvc.Start(ctx)
|
||||
connSvc.Start(ctx)
|
||||
|
@ -80,7 +80,7 @@ func main() {
|
|||
Icon: icon,
|
||||
},
|
||||
WebviewIsTransparent: false,
|
||||
WindowIsTranslucent: false,
|
||||
WindowIsTranslucent: true,
|
||||
},
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: true,
|
||||
|
|
Loading…
Reference in New Issue