perf: add refresh interval option for server status page
This commit is contained in:
parent
a3f9c62f4e
commit
a663ecdeb5
|
@ -0,0 +1,69 @@
|
||||||
|
<script setup>
|
||||||
|
import { isNumber } from 'lodash'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
defaultValue: {
|
||||||
|
type: Number,
|
||||||
|
default: 2,
|
||||||
|
},
|
||||||
|
interval: {
|
||||||
|
type: Number,
|
||||||
|
default: 2,
|
||||||
|
},
|
||||||
|
onRefresh: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['toggle', 'update:on', 'update:interval'])
|
||||||
|
|
||||||
|
const onToggle = (on) => {
|
||||||
|
emit('update:on', on === true)
|
||||||
|
if (on) {
|
||||||
|
let interval = props.interval
|
||||||
|
if (!isNumber(interval)) {
|
||||||
|
interval = props.defaultValue
|
||||||
|
}
|
||||||
|
interval = Math.max(1, interval)
|
||||||
|
emit('update:interval', interval)
|
||||||
|
emit('toggle', true)
|
||||||
|
} else {
|
||||||
|
emit('toggle', false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-form :show-feedback="false" label-align="right" label-placement="left" label-width="auto" size="small">
|
||||||
|
<n-form-item :label="$t('interface.auto_refresh')">
|
||||||
|
<n-switch :loading="props.loading" :value="props.on" @update:value="onToggle" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item :label="$t('interface.refresh_interval')">
|
||||||
|
<n-input-number
|
||||||
|
:autofocus="false"
|
||||||
|
:default-value="props.defaultValue"
|
||||||
|
:disabled="props.on"
|
||||||
|
:max="9999"
|
||||||
|
:min="1"
|
||||||
|
:show-button="false"
|
||||||
|
:value="props.interval"
|
||||||
|
style="max-width: 100px"
|
||||||
|
@update:value="(val) => emit('update:interval', val)">
|
||||||
|
<template #suffix>
|
||||||
|
{{ $t('common.unit_second') }}
|
||||||
|
</template>
|
||||||
|
</n-input-number>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -6,16 +6,19 @@ import Filter from '@/components/icons/Filter.vue'
|
||||||
import Refresh from '@/components/icons/Refresh.vue'
|
import Refresh from '@/components/icons/Refresh.vue'
|
||||||
import useBrowserStore from 'stores/browser.js'
|
import useBrowserStore from 'stores/browser.js'
|
||||||
import { timeout } from '@/utils/promise.js'
|
import { timeout } from '@/utils/promise.js'
|
||||||
|
import AutoRefreshForm from '@/components/common/AutoRefreshForm.vue'
|
||||||
|
import { NIcon, useThemeVars } from 'naive-ui'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
server: String,
|
server: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
const browserStore = useBrowserStore()
|
const browserStore = useBrowserStore()
|
||||||
|
const themeVars = useThemeVars()
|
||||||
const serverInfo = ref({})
|
const serverInfo = ref({})
|
||||||
const pageState = reactive({
|
const pageState = reactive({
|
||||||
autoRefresh: false,
|
autoRefresh: false,
|
||||||
refreshInterval: 1,
|
refreshInterval: 5,
|
||||||
loading: false, // loading status for refresh
|
loading: false, // loading status for refresh
|
||||||
autoLoading: false, // loading status for auto refresh
|
autoLoading: false, // loading status for auto refresh
|
||||||
})
|
})
|
||||||
|
@ -41,15 +44,11 @@ const refreshInfo = async (force) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isLoading = computed(() => {
|
||||||
|
return pageState.loading || pageState.autoLoading
|
||||||
|
})
|
||||||
|
|
||||||
const startAutoRefresh = async () => {
|
const startAutoRefresh = async () => {
|
||||||
if (pageState.autoRefresh) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pageState.autoRefresh = true
|
|
||||||
if (!isNaN(pageState.refreshInterval)) {
|
|
||||||
pageState.refreshInterval = 5
|
|
||||||
}
|
|
||||||
pageState.refreshInterval = Math.min(pageState.refreshInterval, 1)
|
|
||||||
let lastExec = Date.now()
|
let lastExec = Date.now()
|
||||||
do {
|
do {
|
||||||
if (!pageState.autoRefresh) {
|
if (!pageState.autoRefresh) {
|
||||||
|
@ -171,28 +170,34 @@ const infoFilter = ref('')
|
||||||
</n-space>
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
<template #header-extra>
|
<template #header-extra>
|
||||||
<n-space align="center" inline>
|
<n-popover keep-alive-on-hover placement="bottom-end" trigger="hover">
|
||||||
{{ $t('status.auto_refresh') }}
|
<template #trigger>
|
||||||
<n-switch
|
<n-button
|
||||||
|
:loading="pageState.loading"
|
||||||
|
:type="isLoading ? 'primary' : 'default'"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
tertiary
|
||||||
|
@click="refreshInfo(true)">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon :size="props.size">
|
||||||
|
<refresh
|
||||||
|
:class="{
|
||||||
|
'auto-rotate': pageState.autoRefresh || isLoading,
|
||||||
|
}"
|
||||||
|
:color="pageState.autoRefresh ? themeVars.primaryColor : undefined"
|
||||||
|
:stroke-width="pageState.autoRefresh ? 6 : 3" />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
<auto-refresh-form
|
||||||
|
v-model:interval="pageState.refreshInterval"
|
||||||
|
v-model:on="pageState.autoRefresh"
|
||||||
|
:default-value="5"
|
||||||
:loading="pageState.autoLoading"
|
:loading="pageState.autoLoading"
|
||||||
:value="pageState.autoRefresh"
|
@toggle="onToggleRefresh" />
|
||||||
@update:value="onToggleRefresh" />
|
</n-popover>
|
||||||
<n-tooltip>
|
|
||||||
{{ $t('status.refresh') }}
|
|
||||||
<template #trigger>
|
|
||||||
<n-button
|
|
||||||
:loading="pageState.autoLoading"
|
|
||||||
circle
|
|
||||||
size="small"
|
|
||||||
tertiary
|
|
||||||
@click="refreshInfo(true)">
|
|
||||||
<template #icon>
|
|
||||||
<n-icon :component="Refresh" />
|
|
||||||
</template>
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
</n-tooltip>
|
|
||||||
</n-space>
|
|
||||||
</template>
|
</template>
|
||||||
<n-spin :show="pageState.loading">
|
<n-spin :show="pageState.loading">
|
||||||
<n-grid style="min-width: 500px" x-gap="5">
|
<n-grid style="min-width: 500px" x-gap="5">
|
||||||
|
|
|
@ -16,14 +16,14 @@ const props = defineProps({
|
||||||
<path
|
<path
|
||||||
:stroke-width="props.strokeWidth"
|
:stroke-width="props.strokeWidth"
|
||||||
d="M36.7279 36.7279C33.4706 39.9853 28.9706 42 24 42C14.0589 42 6 33.9411 6 24C6 14.0589 14.0589 6 24 6C28.9706 6 33.4706 8.01472 36.7279 11.2721C38.3859 12.9301 42 17 42 17"
|
d="M36.7279 36.7279C33.4706 39.9853 28.9706 42 24 42C14.0589 42 6 33.9411 6 24C6 14.0589 14.0589 6 24 6C28.9706 6 33.4706 8.01472 36.7279 11.2721C38.3859 12.9301 42 17 42 17"
|
||||||
stroke="currentColor"
|
:stroke="color"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round" />
|
stroke-linejoin="round" />
|
||||||
<path
|
<path
|
||||||
:stroke-width="props.strokeWidth"
|
:stroke-width="props.strokeWidth"
|
||||||
class="default-stroke"
|
class="default-stroke"
|
||||||
d="M42 8V17H33"
|
d="M42 8V17H33"
|
||||||
stroke="currentColor"
|
:stroke="color"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round" />
|
stroke-linejoin="round" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -359,9 +359,7 @@
|
||||||
"connected_clients": "Clients",
|
"connected_clients": "Clients",
|
||||||
"total_keys": "Keys",
|
"total_keys": "Keys",
|
||||||
"memory_used": "Memory",
|
"memory_used": "Memory",
|
||||||
"all_info": "Information",
|
"all_info": "Information"
|
||||||
"refresh": "Refresh",
|
|
||||||
"auto_refresh": "Auto Refresh"
|
|
||||||
},
|
},
|
||||||
"slog": {
|
"slog": {
|
||||||
"title": "Slow Log",
|
"title": "Slow Log",
|
||||||
|
|
|
@ -291,9 +291,7 @@
|
||||||
"connected_clients": "Clientes Conectados",
|
"connected_clients": "Clientes Conectados",
|
||||||
"total_keys": "Chaves Totais",
|
"total_keys": "Chaves Totais",
|
||||||
"memory_used": "Memória Usada",
|
"memory_used": "Memória Usada",
|
||||||
"all_info": "Informações",
|
"all_info": "Informações"
|
||||||
"refresh": "Atualizar",
|
|
||||||
"auto_refresh": "Atualização Automática"
|
|
||||||
},
|
},
|
||||||
"slog": {
|
"slog": {
|
||||||
"title": "Registro de Operações Lentas",
|
"title": "Registro de Operações Lentas",
|
||||||
|
|
|
@ -359,9 +359,7 @@
|
||||||
"connected_clients": "已连客户端",
|
"connected_clients": "已连客户端",
|
||||||
"total_keys": "键总数",
|
"total_keys": "键总数",
|
||||||
"memory_used": "内存使用",
|
"memory_used": "内存使用",
|
||||||
"all_info": "全部信息",
|
"all_info": "全部信息"
|
||||||
"refresh": "立即刷新",
|
|
||||||
"auto_refresh": "自动刷新"
|
|
||||||
},
|
},
|
||||||
"slog": {
|
"slog": {
|
||||||
"title": "慢日志",
|
"title": "慢日志",
|
||||||
|
|
|
@ -168,3 +168,13 @@ body {
|
||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auto-rotate {
|
||||||
|
animation: rotate 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue